Skip to content

Commit 17e3b0a

Browse files
committed
Add initial contributing section
1 parent cc9363c commit 17e3b0a

File tree

9 files changed

+360
-7
lines changed

9 files changed

+360
-7
lines changed

astro.config.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ export default defineConfig({
2323
editLink: {
2424
baseUrl: 'https://github.com/rescript-lang/experimental-rescript-webapi/edit/main/',
2525
},
26+
sidebar: [
27+
{
28+
slug: '',
29+
},
30+
{
31+
slug: 'design-philosophy',
32+
},
33+
{
34+
slug: 'project-status',
35+
},
36+
{
37+
label: 'Contributing',
38+
autogenerate: { directory: 'contributing' },
39+
},
40+
],
2641
customCss: ["./docs/styles/fonts.css", "./docs/styles/theme.css"],
2742
expressiveCode: {
2843
shiki: {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
title: Code Generation
3+
description: Learn more about the code generation process for @rescript/webapi.
4+
slug: "03-code-generation"
5+
---
6+
7+
The original bindings were generated using a modified version of [TypeScript-DOM-lib-generator](https://github.com/microsoft/TypeScript-DOM-lib-generator).
8+
These bindings were a great starting point, but they are not perfect.
9+
It is more than likely that you will need to **tweak the generated bindings by hand** to make them more idiomatic to ReScript.
10+
11+
For example the `window.fetch` function was generated as:
12+
13+
```ReScript
14+
/**
15+
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Window/fetch)
16+
*/
17+
@send
18+
external fetch: (window, ~input: request, ~init: requestInit=?)
19+
=> Promise.t<response> = "fetch"
20+
21+
/**
22+
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Window/fetch)
23+
*/
24+
@send
25+
external fetch2: (window, ~input: string, ~init: requestInit=?)
26+
=> Promise.t<response> = "fetch"
27+
```
28+
29+
While not that bad and usable, it can be improved:
30+
31+
- Rename `fetch2` to `fetch` because it is the more common usage of the function.
32+
- Rename `fetch` to `fetch_with_request` for clarity that this is the "overload" with a `Request` object.
33+
- Consider removing the named `~input` and `~init` arguments and use positional arguments instead.
34+
Motivation: If the function does not have any parameters with the same type, it is more ergonomic to use positional arguments.
35+
This heuristic is not set in stone and can be adjusted based on the specific function.
36+
- The documentation can be improved.
37+
38+
```ReScript
39+
/** TODO: add better docs */
40+
@send
41+
external fetch: (window, string, ~init: requestInit=?)
42+
=> Promise.t<response> = "fetch"
43+
44+
/** TODO: add better docs */
45+
@send
46+
external fetch_with_request: (window, request, ~init: requestInit=?)
47+
=> Promise.t<response> = "fetch"
48+
```
49+
50+
Once these changes are made, the bindings can be tested and then committed to the repository.
51+
The generation does no longer happen automatically, so manual improvements will not be overwritten.
52+
53+
## Sandboxed Code Generation
54+
55+
Not every API was covered by the TypeScript-DOM-lib-generator.
56+
Potentially, you want to add a new API to the bindings and star from code generation.
57+
58+
In [emitter.ts](https://github.com/rescript-lang/experimental-rescript-webapi/blob/main/tools/TypeScript-DOM-lib-generator/src/build/emitter.ts),
59+
you can override the `interfaceHierarchy` with any new interface or type you want to add.
60+
61+
```typescript
62+
interfaceHierarchy = [
63+
{
64+
name: "Temp",
65+
entries: [
66+
enums(["WebGLPowerPreference"]),
67+
dictionaries([
68+
"ImageBitmapRenderingContextSettings",
69+
"WebGLContextAttributes",
70+
]),
71+
],
72+
opens: [],
73+
},
74+
];
75+
```
76+
77+
After running the generator (in `tools/TypeScript-DOM-lib-generator`):
78+
79+
```shell
80+
npm run build
81+
```
82+
83+
All the generated files will be in the `tmp` folder. You can use this as inspiration for your own bindings.
84+
85+
To figure out if you need `enums`, `dictionaries`, or `interfaces`, you can look at the [JSON dump](https://github.com/rescript-lang/experimental-rescript-webapi/blob/main/tools/TypeScript-DOM-lib-generator/dom-dump.json) file
86+
and see how the TypeScript-DOM-lib-generator represents the shape you are after.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
title: "Documentation"
3+
description: Learn more about the relevance of adding documentation to @rescript/webapi.
4+
slug: "05-documentation"
5+
---
6+
7+
After the bindings are generated, all you got was a link to the MDN documentation.
8+
While again, not that bad, it can be improved by adding the core of the binding to the documentation.
9+
And explain how it is supposed to be used.
10+
11+
## Importance
12+
13+
One could wonder how important documentation is in this case?
14+
A link to MDN is enough, right? Well, not always.
15+
When a method has multiple overloads, it can be hard to understand which one to use.
16+
By adding an example usage, the user can see easily see which one to use.
17+
It keeps the user inside the IDE and avoids context switching.
18+
19+
## Structure
20+
21+
The documentation for each binding should roughly follow this structure:
22+
23+
- signature
24+
- key description (tip: check MDN for inspiration)
25+
- example usage
26+
- link to the MDN documentation
27+
28+
For example, the `window.fetch` function could be documented as:
29+
30+
````ReScript
31+
/*
32+
`fetch(string, init)`
33+
34+
Starts the process of fetching a resource from the network,
35+
returning a promise that is fulfilled once the response is available.
36+
37+
```res
38+
window->Window.fetch("https://rescript-lang.org")
39+
```
40+
41+
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Window/fetch)
42+
*/
43+
@send
44+
external fetch: (window, string, ~init: requestInit=?)
45+
=> Promise.t<response> = "fetch"
46+
````
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
title: Project setup
3+
description: Practical information on how to get started to contribute to the project.
4+
slug: "01-getting-started"
5+
---
6+
7+
import { Aside } from "@astrojs/starlight/components";
8+
9+
<Aside type="caution">
10+
**Real talk**: First time diving into this project? Might feel like a letdown.
11+
But hey, the upside? It’s stupid easy to toss us a PR and make it better!
12+
</Aside>
13+
14+
The [WebAPI](https://developer.mozilla.org/en-US/docs/Web/API) are vast and ever-growing. We need your help to make them better.
15+
There is no way our [contributors](https://github.com/rescript-lang/experimental-rescript-webapi/graphs/contributors) can cover everything.
16+
And that's where you come in! A small PR, focused on what you want to get out of this project can make a huge difference.
17+
18+
## Recommended workflow
19+
20+
We recommend the following overall workflow when developing for this repository:
21+
22+
- Fork this repository
23+
- Always work in your fork
24+
- Always keep your fork up to date
25+
26+
Before updating your fork, run this command:
27+
28+
```shell
29+
git remote add upstream https://github.com/rescript-lang/experimental-rescript-webapi.git
30+
```
31+
32+
This will make management of multiple forks and your own work easier over time.
33+
34+
### Updating your fork
35+
36+
We recommend the following commands to update your fork:
37+
38+
```shell
39+
git checkout main
40+
git clean -xdf
41+
git fetch upstream
42+
git rebase upstream/main
43+
git push
44+
```
45+
46+
Or more succinctly:
47+
48+
```shell
49+
git checkout main && git clean -xdf && git fetch upstream && git rebase upstream/main && git push
50+
```
51+
52+
This will update your fork with the latest from `rescript-lang/experimental-rescript-webapi` on your machine and push those updates to your remote fork.
53+
54+
## Initial build
55+
56+
Install the dependencies and compile the bindings using [Rewatch](https://github.com/rescript-lang/rewatch):
57+
58+
```shell
59+
npm install && npm run build
60+
```
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
title: Module Structure
3+
description: Learn more about the module structure of @rescript/webapi.
4+
slug: "02-module-structure"
5+
---
6+
7+
import { Aside } from "@astrojs/starlight/components";
8+
import { FileTree } from "@astrojs/starlight/components";
9+
10+
The bindings are organized by the Web API they represent. Each API has its interfaces and auxiliary types in a module named after the API, suffixed with `API` to prevent collisions with the type module.
11+
12+
<FileTree>
13+
14+
- package.json
15+
- src
16+
- DOMAPI.res
17+
- DOMAPI/
18+
- HTMLElement.res
19+
20+
</FileTree>
21+
22+
Within the API module, the structure is roughly as follows:
23+
24+
- Enum Types
25+
- Interfaces
26+
- Auxiliary Types
27+
28+
## Enum types
29+
30+
Enum types are used to represent constants in the Web API. They are typically used as arguments to methods or properties.
31+
In ReScript terms these are variants:
32+
33+
```ReScript
34+
type scrollBehavior =
35+
| @as("auto") Auto
36+
| @as("instant") Instant
37+
| @as("smooth") Smooth
38+
```
39+
40+
Enums come first as they are always self-contained and do not depend on other types.
41+
42+
## Interfaces
43+
44+
[Interfaces](https://developer.mozilla.org/en-US/docs/Web/API#interfaces) are modeled as record types and are the core of the bindings.
45+
They represent the properties and methods of the Web API. If an interface inherits from another interface, the base interface is spread into the inheriting interface.
46+
47+
```ReScript
48+
type htmlSpanElement = {
49+
...htmlElement,
50+
}
51+
```
52+
53+
<Aside>
54+
Properties spreading is not possible in recursive types! When a circular
55+
reference is detected, the base properties are duplicated instead.
56+
</Aside>
57+
58+
```ReScript
59+
type rec node = {
60+
nodeName: string
61+
// ... more properties
62+
}
63+
64+
and element = {
65+
// duplicated property from node
66+
nodeName: string
67+
// ... more properties
68+
}
69+
```
70+
71+
## Auxiliary Types
72+
73+
Auxiliary types are used to represent types that are not directly related to the Web API but are used in the bindings.
74+
These can occur both before interfaces and after interfaces, depending on the context.
75+
76+
```ReScript
77+
type eventListenerOptions = {mutable capture?: bool}
78+
79+
// Model after the documentation of
80+
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options
81+
type addEventListenerOptions = {
82+
...eventListenerOptions,
83+
mutable passive?: bool,
84+
mutable once?: bool,
85+
mutable signal?: abortSignal,
86+
}
87+
```
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: Testing
3+
description: Learn more about testing the bindings for @rescript/webapi.
4+
slug: "04-testing"
5+
---
6+
7+
import { Aside } from "@astrojs/starlight/components";
8+
9+
Adding some unit tests is a great way to ensure that the bindings work as expected.
10+
It illustrates how the bindings are supposed to be used and can help to catch regressions.
11+
12+
## Testing the bindings
13+
14+
Create a new help in the `test` folder with the same name as the module you want to test, followed by `_test.res`.
15+
16+
import { FileTree } from "@astrojs/starlight/components";
17+
18+
<FileTree>
19+
- src - DOMAPI.res - DOMAPI/ - HTMLCanvasElement.res - test - DOMAPI/ -
20+
HTMLCanvasElement_test.res
21+
</FileTree>
22+
23+
Add a small sample of valid code that uses the bindings you've changed.
24+
Add it to source control and run
25+
26+
```shell
27+
git add tests
28+
npm test
29+
```
30+
31+
If any of the existing tests have different ouput JavaScript, you will see a diff in the output and the test will fail.
32+
33+
<Aside>
34+
Depending on your use-case, it might be okay to have slightly different output
35+
JavaScript. The maintainers will help you to decide if the change is
36+
acceptable.
37+
</Aside>
38+
39+
## Why add tests?
40+
41+
Sometimes adding a test can feel like a bit of a hassle. But we insist that you add tests for the following reasons:
42+
43+
- **Documentation**: Tests are a form of documentation. They show how the bindings are supposed to be used.
44+
- **Regression**: Tests help to catch regressions. If a change breaks something, the test will fail.
45+
- **Awareness**: Tests make you aware of the API you are using.
46+
In the future we might trim down the generated bindings to only include the most used APIs.
47+
If you have a test, you can be sure that the API is not going away.

docs/content/docs/index.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
---
22
title: Getting started
33
description: Learn more about @rescript/webapi.
4+
hero:
5+
title: "ReScript WebAPI"
6+
tagline: ReScript bindings for everything you need in the browser.
7+
actions:
8+
- text: Let's go!
9+
link: "#installation"
10+
icon: right-arrow
11+
- text: View on GitHub
12+
link: https://github.com/rescript-lang/experimental-rescript-webapi
13+
icon: external
14+
variant: minimal
15+
attrs:
16+
rel: me
17+
tableOfContents: false
418
---
519

620
import { Tabs, TabItem, Code } from "@astrojs/starlight/components";

docs/content/docs/philosophy.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Design Philosophy
33
description: Learn more about the design philosophy of @rescript/webapi.
4+
slug: "design-philosophy"
45
---
56

67
The core idea of these ReScript bindings is that each interface is modeled as a record type. Where possible, inheritance is represented using record spreading, and methods are modeled as functions in a separate module. This design allows for greater familiarity with the underlying JavaScript APIs, making it more friendly for newcomers.

0 commit comments

Comments
 (0)