diff --git a/apps/docs/markdown-pages/docs/manual/build-configuration.mdx b/apps/docs/markdown-pages/docs/manual/build-configuration.mdx index 9872f648a..cabc933d9 100644 --- a/apps/docs/markdown-pages/docs/manual/build-configuration.mdx +++ b/apps/docs/markdown-pages/docs/manual/build-configuration.mdx @@ -91,26 +91,24 @@ Note that only sources marked with `"type":"dev"` will be able to resolve module ## js-post-build -Hook that's invoked every time a file is recompiled. Good for JS build system interop, but please use it **sparingly**. Calling your custom command for every recompiled file slows down your build and worsens the building experience for even third-party users of your lib. +Hook that's invoked for every JavaScript file emitted by a build. It can be useful for JavaScript build-system interop, but use it **sparingly**. Starting another process for every recompiled file can noticeably slow down builds for both applications and libraries. Example: ```json { "js-post-build": { - "cmd": "/path/to/node ../../postProcessTheFile.js" + "cmd": "node ./postProcess.mjs" } } ``` -Note that the path resolution for the command (`node` in this case) is done so: +The build system appends the absolute path to the generated JavaScript file as the command's final argument. The path points: -- `/myCommand` is resolved into `/myCommand` -- `package/myCommand` is resolved into `node_modules/package/myCommand` -- `./myCommand` is resolved into `myProjectRoot/myCommand` -- `myCommand` is just called as `myCommand`, aka a globally available executable. But note that ReScript doesn't read into your shell's environment, so if you put e.g. `node`, it won't find it unless you specify an absolute path. Alternatively, add `#!/usr/local/bin/node` to the top of your script to directly call it without prepending `node`. +- next to the source file when `"in-source": true` +- into the corresponding `lib//` output directory when `"in-source": false` -The command itself is called from inside `lib/bs`. +Since ReScript 12.2, the command runs from the directory containing the `rescript.json` where the hook is defined, and output written to stdout or stderr is forwarded to the build output. This makes relative paths predictable in nested packages and monorepos. ## jsx diff --git a/apps/docs/markdown-pages/docs/manual/build-overview.mdx b/apps/docs/markdown-pages/docs/manual/build-overview.mdx index a505c05e6..1641dd7bd 100644 --- a/apps/docs/markdown-pages/docs/manual/build-overview.mdx +++ b/apps/docs/markdown-pages/docs/manual/build-overview.mdx @@ -9,62 +9,60 @@ order: 1 # Build System Overview -ReScript comes with a build system, [`rescript`](https://www.npmjs.com/package/rescript), that's fast, lean and used as the authoritative build system of the community. +ReScript comes with a fast, native build system through the [`rescript`](https://www.npmjs.com/package/rescript) package. Every ReScript project needs a build description file, `rescript.json`. -## Options +The current build system was introduced in ReScript 12. It tracks dependencies across packages and schedules only the work affected by a change. See [Reforging the Build System](../../blog/reforging-build-system.mdx) for a deeper look at its architecture. -See `rescript help`: +## Commands + +Run `rescript help` to see the available commands: ``` ❯ rescript help -Usage: rescript - -`rescript` is equivalent to `rescript build` - -Options: - -v, -version display version number - -h, -help display help - -Subcommands: - build - clean - format - convert - dump - help - -Run `rescript -h` for subcommand help. Examples: - rescript build -h - rescript format -h +Usage: rescript [OPTIONS] + +Commands: + build Build the project (default command) + watch Build, then start a watcher + clean Clean the build artifacts + format Format ReScript files + compiler-args Print the compiler arguments for a ReScript source file + help Print this message or the help of the given subcommand(s) ``` -## Build Project +Use `rescript help ` for the options of a particular command. + +## Build a Project Each build will create build artifacts from your project's source files. -**To build a project (including its dependencies)**, run: +To build a project, including its dependencies, run: ```sh rescript ``` -Which is an alias for `rescript build`. +This is an alias for `rescript build`. -To keep a build watcher, run: +To build once and then watch for changes, run: ```sh -rescript -w +rescript watch ``` Any new file change will be picked up and the build will re-run. -**Note**: third-party libraries in `node_modules` aren't watched, as doing so may exceed the node.js watcher count limit. +Third-party libraries in `node_modules` aren't watched. For monorepo setup in ReScript 12+, see [Setting up a monorepo](./build-monorepo-setup.mdx). -## Clean Project +### Incremental Builds + +The build system recompiles only files affected by a change. Interface files (`.resi`) can reduce this work further: if an implementation change doesn't alter the corresponding interface, dependent modules don't need to be recompiled. See [Module signatures](./module.mdx#signatures) and [Build Performance](./build-performance.mdx). + +## Clean a Project If you ever get into a stale build for edge-case reasons, use: @@ -72,14 +70,24 @@ If you ever get into a stale build for edge-case reasons, use: rescript clean ``` -## Compile with stricter errors in CI +## Format Source Files + +Format the project's ReScript files with: + +```sh +rescript format +``` + +Use `rescript format --check` in CI to check formatting without writing changes. You can also format selected files by passing their paths, or format standard input with `--stdin .res` or `--stdin .resi`. + +## Compile with Stricter Errors in CI **Since 11.1** -You may want to compile your project with stricter rules for production, than when developing. With the `-warn-error` build flag, this can easily be done, for instance in a continuous integration script. E.g.: +You may want to compile your project with stricter rules in CI than during development. Use the `--warn-error` build flag: ```sh -rescript -warn-error +110 +rescript build --warn-error "+110" ``` Here, warning number 110, which is triggered when a [`%todo`](../../syntax-lookup/extension_todo.mdx) has been found, gets promoted to an error. The full list of warning numbers can be found [here](./warning-numbers.mdx). diff --git a/apps/docs/markdown-pages/docs/manual/build-performance.mdx b/apps/docs/markdown-pages/docs/manual/build-performance.mdx index f1097f4a8..12d8fe06c 100644 --- a/apps/docs/markdown-pages/docs/manual/build-performance.mdx +++ b/apps/docs/markdown-pages/docs/manual/build-performance.mdx @@ -11,6 +11,17 @@ order: 7 ReScript considers performance at install time, build time and run time as a serious feature; it's one of those things you don't notice until you realize it's missing. +## Measuring Build Times + +When investigating a slowdown, compare the same kinds of build under the same conditions: + +- a clean build +- a no-op build, with no source changes +- an incremental build after changing a leaf module +- an incremental build after changing a widely used module + +Build times depend on the dependency graph, hardware, filesystem, and surrounding tools. Compare ReScript's build time with the duration of the entire development command: bundling, code generation, and tests can take more time than compilation itself. + ## Under the Hood Since ReScript v12, `rescript build` uses a native build system written in Rust. It reads `rescript.json`, tracks dependencies between modules and packages, and invokes the compiler directly. See [Reforging the ReScript Build System](../../blog/reforging-build-system.mdx) for more about its architecture. @@ -77,6 +88,10 @@ Unfortunately, JS build systems are usually the bottleneck for building a JS pro - Convert more files into ReScript =). Fewer files going through fewer parts of the JS pipeline helps a ton. - Careful with bringing in more dependencies: libraries, syntax transforms (e.g. the unofficially supported PPX), build step loaders, etc. The bulk of these dragging down the editing & building experience might out-weight the API benefits they provide. +Keep compiler artifacts between builds unless you specifically need a clean build. Cleaning before every compilation prevents incremental builds from doing their job. + +Commands configured through [`js-post-build`](./build-configuration.mdx#js-post-build) run once per emitted JavaScript file. Starting another process for each file can slow down an otherwise fast incremental build. + ## Hot Reloading Hot reloading refers to maintaining a dev server and listening to file changes in a way that allows the server to pipe some delta changes right into the currently running browser page. This provides a relatively fast iteration workflow while working in specific frameworks. diff --git a/apps/docs/markdown-pages/docs/manual/converting-from-js.mdx b/apps/docs/markdown-pages/docs/manual/converting-from-js.mdx index b27d5f249..81cc1b679 100644 --- a/apps/docs/markdown-pages/docs/manual/converting-from-js.mdx +++ b/apps/docs/markdown-pages/docs/manual/converting-from-js.mdx @@ -18,7 +18,7 @@ ReScript offers a unique project conversion methodology which: ## Step 1: Install ReScript -Run `npm install rescript` on your project, then imitate our [New Project](./installation.mdx#new-project) workflow by adding a `rescript.json` at the root. Then start `npx rescript -w`. +Run `npm install rescript` in your project, then follow the [New Project](./installation.mdx#new-project) workflow by adding a `rescript.json` at the root. Start the compiler in watch mode with `npx rescript watch`. ## Step 2: Copy Paste the Entire JS File diff --git a/apps/docs/markdown-pages/docs/manual/editor-code-analysis.mdx b/apps/docs/markdown-pages/docs/manual/editor-code-analysis.mdx index e96913068..e0b2ccbd4 100644 --- a/apps/docs/markdown-pages/docs/manual/editor-code-analysis.mdx +++ b/apps/docs/markdown-pages/docs/manual/editor-code-analysis.mdx @@ -17,7 +17,7 @@ Dead code refers to code that's present in your codebase but is never executed. - Confusion during development - Misleading assumptions about functionality -ReScript’s language design allows for accurate and efficient dead code analysis using the **ReScript Code Analyzer**, available via the official VSCode extension. +ReScript’s language design allows for accurate and efficient dead code analysis using the **ReScript Code Analyzer**. It is available through the official VS Code extension and the `rescript-tools` executable bundled with ReScript. ### Prerequisites @@ -37,9 +37,23 @@ ReScript’s language design allows for accurate and efficient dead code analysi - The “Problems” pane populates with dead code warnings and suggestions. -### Reactive Updates (New) +### Command-Line Analysis -Reactive dead code updates are a newer enhancement of Editor Code Analysis and require ReScript VSCode extension v1.73.9 or higher (pre-release). +To run the analyses configured in `rescript.json` from the command line: + +```sh +rescript-tools reanalyze -config +``` + +ReScript 12.1 added a reactive mode that caches unchanged analysis data: + +```sh +rescript-tools reanalyze -config -reactive +``` + +The diagnostic flags `-runs ` and `-churn ` can benchmark cache effectiveness and incremental correctness. `-mermaid` prints a Mermaid diagram of the reactive pipeline. + +`reanalyze-server` keeps the analysis process alive between requests. JSON analysis requests delegate to it transparently, so integrations can use `rescript-tools reanalyze -json` without managing the server themselves. ## Real-World Use Cases @@ -135,6 +149,28 @@ type user = {name: string} let getUserName = user => user.name ``` +### Scoped `@@live` and `@@dead` + +ReScript 12.2 added standalone forms that set the default for the remainder of the current file or module: + +```res +module PublicApi = { + @@live + + let load = () => "loaded" + let save = _value => () +} + +module DeferredCleanup = { + @@dead + + let oldParser = input => input + let oldSerializer = value => value +} +``` + +Items under `@@live` are treated as live roots and can keep their dependencies alive. Items under `@@dead` are suppressed but don't keep their dependencies alive. A later `@@live` or `@@dead` changes the default again, and nested modules inherit the active setting. + ## Configuration Add to your `rescript.json`: @@ -142,8 +178,8 @@ Add to your `rescript.json`: ```json "reanalyze": { "analysis": ["dce"], - "suppress": ["src/bindings", "src/stories", "src/routes"], - "unsuppress": [], + "suppress": ["src/generated/**", "src/stories/**"], + "unsuppress": ["src/generated/handwritten/**"], "transitive": false } ``` @@ -151,10 +187,12 @@ Add to your `rescript.json`: ### Options: - **analysis**: Enables dead code analysis (`"dce"`) -- **suppress**: Silences reporting for paths (still analyzes) -- **unsuppress**: Re-enables reports within suppressed paths +- **suppress**: Silences reporting for matching paths (they are still analyzed) +- **unsuppress**: Re-enables reports for matching paths within a suppressed area - **transitive**: Controls reporting of indirectly dead code +Since ReScript 12.3, `suppress` and `unsuppress` accept glob patterns such as `src/generated/**`. Plain path prefixes continue to work. + **Recommendation:** Set `transitive: false` for incremental cleanup. ## Summary diff --git a/apps/docs/markdown-pages/docs/manual/function.mdx b/apps/docs/markdown-pages/docs/manual/function.mdx index 0eee8b99d..97da51115 100644 --- a/apps/docs/markdown-pages/docs/manual/function.mdx +++ b/apps/docs/markdown-pages/docs/manual/function.mdx @@ -104,6 +104,31 @@ export { greet, greetMore }; If your function has no argument, just write `let greetMore = () => {...}`. +## Function Directives + +Use `@directive` directly before a function expression to emit a JavaScript directive at the start of that function. This works with synchronous and asynchronous functions, including functions with labeled arguments. + + + +```res +let greet = @directive("'use server'") async name => { + "Hello " + name +} +``` + +```js +async function greet(name) { + "use server"; + return "Hello " + name; +} + +export { greet }; +``` + + + +The attribute belongs to the function expression, after the `=` rather than before the `let` binding. File-level directives use the separate `@@directive` form. See the [`@directive` syntax reference](../../syntax-lookup/decorator_directive.mdx). + ## Labeled Arguments
diff --git a/apps/docs/markdown-pages/docs/manual/installation.mdx b/apps/docs/markdown-pages/docs/manual/installation.mdx index f02c9ba87..db2352b88 100644 --- a/apps/docs/markdown-pages/docs/manual/installation.mdx +++ b/apps/docs/markdown-pages/docs/manual/installation.mdx @@ -133,6 +133,8 @@ bun create rescript-app + ReScript's native executables are distributed as optional, platform-specific packages such as `@rescript/darwin-arm64`, `@rescript/linux-x64`, and `@rescript/win32-x64`. Package managers install the matching package automatically. Make sure optional dependencies are enabled; if ReScript reports that its platform package is missing, reinstall dependencies without an option such as npm's `--omit=optional`. + **pnpm users:** ReScript-compiled JS imports from `@rescript/runtime` directly, but pnpm's strict isolation does not expose transitive dependencies at the app root. Either install the runtime as a direct dependency (`pnpm add @rescript/runtime`), or hoist it by adding the following to `pnpm-workspace.yaml`: diff --git a/apps/docs/markdown-pages/docs/manual/interop-with-js-build-systems.mdx b/apps/docs/markdown-pages/docs/manual/interop-with-js-build-systems.mdx index 704281986..1e862bf03 100644 --- a/apps/docs/markdown-pages/docs/manual/interop-with-js-build-systems.mdx +++ b/apps/docs/markdown-pages/docs/manual/interop-with-js-build-systems.mdx @@ -50,10 +50,6 @@ This will: Loaders are indeed troublesome; in the meantime, please use e.g. `%raw("require('./myStyles.css')")` at the top of your file. This just uses [`raw`](./embed-raw-javascript.mdx) to compile the snippet into an actual JS require. -## Getting Project's Dependencies - -`rescript` generates one `MyFile.d` file per `MyFile` source file; you'll find them in `lib/bs`. These are human readable, machine-friendly list of the dependencies of said `MyFile`. You can read into them for your purpose (though mind the IO overhead). Use these files instead of creating your own dependency graph; we did the hard work of tracking the dependencies as best as possible (including inner modules, `open`s, module names overlap, etc). - ## Run Script Per File Built See [js-post-build](./build-configuration.mdx#js-post-build). Though please use it sparingly; if you hook up a node.js script after each file built, you'll incur the node startup time per file! diff --git a/apps/docs/markdown-pages/docs/manual/migrate-to-v12.mdx b/apps/docs/markdown-pages/docs/manual/migrate-to-v12.mdx index 946e428ea..830363ade 100644 --- a/apps/docs/markdown-pages/docs/manual/migrate-to-v12.mdx +++ b/apps/docs/markdown-pages/docs/manual/migrate-to-v12.mdx @@ -281,7 +281,7 @@ Below is a consolidated excerpt of all the breaking changes from the compiler ch ### Build system & CLI -- The new Rust-based `rewatch` build system now powers the `rescript` command. The old Ninja-based builder system moved behind `rescript legacy`, and `--compiler-args` became the `compiler-args` subcommand. https://github.com/rescript-lang/rescript/pull/7551 https://github.com/rescript-lang/rescript/pull/7593 https://github.com/rescript-lang/rescript/pull/7928 +- The new Rust-based `rewatch` build system now powers the `rescript` command. The old Ninja-based builder is available through the separate `rescript-legacy` executable, and `--compiler-args` became the `compiler-args` subcommand. https://github.com/rescript-lang/rescript/pull/7551 https://github.com/rescript-lang/rescript/pull/7593 https://github.com/rescript-lang/rescript/pull/7928 - `rescript format` was reimplemented in Rust, its options now use the `--check` / `--stdin` long-form spelling, and the `--all` flag was removed because every tracked file (non-dev by default) is formatted automatically. https://github.com/rescript-lang/rescript/pull/7603 https://github.com/rescript-lang/rescript/pull/7752 - The `rescript dump` command was removed; call `bsc` directly if you need to inspect `.cmi` files. https://github.com/rescript-lang/rescript/pull/7710 diff --git a/apps/docs/markdown-pages/docs/manual/module.mdx b/apps/docs/markdown-pages/docs/manual/module.mdx index 052d242e8..789ccc686 100644 --- a/apps/docs/markdown-pages/docs/manual/module.mdx +++ b/apps/docs/markdown-pages/docs/manual/module.mdx @@ -422,7 +422,38 @@ This also means that the compiler can't make assumptions about the type. In certain cases, when working with abstract types and `option` for example, the compiler doesn't know whether the abstract type can be the JavaScript value `undefined` or not. This can lead to less optimal code being generated. For this reason, you can use the `@notUndefined` decorator to tell the compiler that the abstract type can never be `undefined` -(use with caution and see the `@notUndefined` decorator documentation for more details and caveats). +(use with caution and see the [`@notUndefined` decorator documentation](../../syntax-lookup/decorator_not_undefined.mdx) for more details and caveats). + +### Refining Module Types with Constraints + +A `with type` constraint can refine an abstract type in an existing module type: + +```res prelude +module type Storage = { + type t + let make: string => t + let serialize: t => string +} + +module type PrivateStringStorage = Storage with type t = private string +``` + +The `private` constraint exposes that `t` is represented as `string`, so a `t` can be coerced to `string`, while preventing callers from constructing a `t` from any string. Only functions exposed by the module, such as `make`, can create one. + +```res +module StringStorage: PrivateStringStorage = { + type t = string + let make = value => value + let serialize = value => value +} + +let unwrap = value => { + let _ = StringStorage.serialize(value) + (value :> string) +} +``` + +The call to `serialize` is enough for the compiler to infer `value` as `StringStorage.t`; ReScript 12 allows that inferred type variable to be resolved while checking the coercion. ### Extending module signatures diff --git a/apps/docs/markdown-pages/docs/manual/polymorphic-variant.mdx b/apps/docs/markdown-pages/docs/manual/polymorphic-variant.mdx index c41cfe9a6..f19c537e0 100644 --- a/apps/docs/markdown-pages/docs/manual/polymorphic-variant.mdx +++ b/apps/docs/markdown-pages/docs/manual/polymorphic-variant.mdx @@ -419,6 +419,18 @@ export { myColor, theCompany, message }; **Note**: for the coercion to work, the poly variant type needs to be closed; you'd need to annotate it, since otherwise, `theCompany` would be inferred as `[> #Apple]`. +Since ReScript 12, a closed polymorphic variant can also be coerced to a regular variant when their possible constructors have matching runtime representations: + +```res +type command = [#Start | #Stop] +type event = Start | Stop | Pause + +let command: command = #Start +let event: event = (command :> event) +``` + +Here, `#Start` and `Start` are both represented by the string `"Start"`, and every value in `command` can be represented by `event`. The coercion therefore has no runtime cost. + ## Tips & Tricks ### Variant vs Polymorphic Variant diff --git a/apps/docs/markdown-pages/docs/manual/primitive-types.mdx b/apps/docs/markdown-pages/docs/manual/primitive-types.mdx index 4355fc55e..cdd353066 100644 --- a/apps/docs/markdown-pages/docs/manual/primitive-types.mdx +++ b/apps/docs/markdown-pages/docs/manual/primitive-types.mdx @@ -34,12 +34,12 @@ export { greeting, multilineGreeting }; -To concatenate strings, use `++`: +Use `+` to concatenate strings. The older `++` operator is still supported: ```res -let greetings = "Hello " ++ "world!" +let greetings = "Hello " + "world!" ``` ```js @@ -164,13 +164,30 @@ A ReScript boolean has the type `bool` and can be either `true` or `false`. Comm ReScript's `true/false` compiles into a JavaScript `true/false`. +## Arithmetic Operators + +The unified arithmetic operators `+`, `-`, `*`, `/`, `%`, and `**` work with `int`, `float`, and `bigint`. `+` also works with `string`. + +The compiler specializes an operator from the types around it: + +```res +let intSum = 1 + 2 +let floatSum = 1.5 + 2.5 +let stringSum = "Re" + "Script" + +let addFloats = (left: float, right) => left + right +let addMoreFloats = (left, right: float) => left + right +``` + +Both operands must have the same type. If neither operand provides a primitive type, the expression defaults to `int`. + ## Integers 32-bits, truncated when necessary. We provide the usual operations on them: `+`, `-`, `*`, `/`, etc. See [Int](/docs/manual/api/stdlib/int) for helper functions. Integer operators include `+`, `-`, `*`, `/`, `**`, and `%`. -`%` keeps the familiar `mod` naming, but its semantics are remainder (same behavior as JavaScript `%`). +`%` computes the remainder, as in JavaScript. For example, `-7 % 4` is `-3`. Bitwise operators for `int`: `~~~`, `&&&`, `|||`, `^^^`, `<<`, `>>`, `>>>`. @@ -180,7 +197,7 @@ To improve readability, you may place underscores in the middle of numeric liter ## Floats -Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`. Like `0.5 + 0.6`. See [Float](/docs/manual/api/stdlib/float) for helper functions. +Arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`) work for both `int` and `float`, as in `0.5 + 0.6`. See [Float](/docs/manual/api/stdlib/float) for helper functions. As with integers, you may use underscores within literals to improve readability. diff --git a/apps/docs/markdown-pages/docs/manual/typescript-integration.mdx b/apps/docs/markdown-pages/docs/manual/typescript-integration.mdx index d06aa934a..09f71960c 100644 --- a/apps/docs/markdown-pages/docs/manual/typescript-integration.mdx +++ b/apps/docs/markdown-pages/docs/manual/typescript-integration.mdx @@ -247,6 +247,29 @@ Any values exported from `MyComponent.res` can then be imported from TypeScript. import { make } from "./components/MyComponent.gen.js"; ``` +## Built-in Type Mappings + +genType recognizes the ReScript 12 standard library directly, so common types don't require TypeScript shims. Important mappings include: + +| ReScript | TypeScript | +| ----------------------------------------------- | --------------------------------------- | +| `int`, `float` | `number` | +| `string`, `bool`, `bigint`, `unit` | `string`, `boolean`, `bigint`, `void` | +| `array<'a>`, tuples | arrays and tuples | +| `option<'a>` | `a \| undefined` | +| `Null.t<'a>` | `a \| null` | +| `Nullable.t<'a>` | `a \| null \| undefined` | +| `dict<'a>` | `{[id: string]: a}` | +| `JSON.t` | `unknown` | +| `Promise.t<'a>` | `Promise` | +| `Date.t`, `RegExp.t`, `Symbol.t` | `Date`, `RegExp`, `symbol` | +| `Map.t`, `WeakMap.t`, `Set.t`, `WeakSet.t` | the corresponding TypeScript collection | +| `ArrayBuffer.t`, `DataView.t`, and typed arrays | the corresponding JavaScript built-in | +| `JsError.t` | `Error` | +| `Intl.*.t` | the corresponding `Intl.*` type | + +ReScript records, variants, `result`, `ref`, and other language-level types are translated to equivalent structural TypeScript types. + ## Experimental features These features are for experimentation only. They could be changed/removed any time, and not be considered breaking changes. diff --git a/apps/docs/markdown-pages/docs/manual/variant.mdx b/apps/docs/markdown-pages/docs/manual/variant.mdx index 15ac73760..714914497 100644 --- a/apps/docs/markdown-pages/docs/manual/variant.mdx +++ b/apps/docs/markdown-pages/docs/manual/variant.mdx @@ -370,6 +370,10 @@ Here's a list of all possible things you can unbox: - `Blob.t`: `Blob(Blob.t)`. A JavaScript blob. - `File.t`: `File(File.t)`. A JavaScript file. - `RegExp.t`: `RegExp(RegExp.t)`. A JavaScript regexp instance. +- `ArrayBuffer.t` and `DataView.t` +- Typed arrays: `Int8Array.t`, `Uint8Array.t`, `Uint8ClampedArray.t`, `Int16Array.t`, `Uint16Array.t`, `Int32Array.t`, `Uint32Array.t`, `Float32Array.t`, `Float64Array.t`, `BigInt64Array.t`, and `BigUint64Array.t` +- `Set.t<'value>` and `Map.t<'key, 'value>` (since ReScript 12.1) +- `WeakSet.t<'value>` and `WeakMap.t<'key, 'value>` (since ReScript 12.1) Again notice that the constructor names can be anything, what matters is what's in the payload. @@ -616,6 +620,8 @@ let four: b = Four let oneAsTypeB = (one :> b) ``` +A closed [polymorphic variant](./polymorphic-variant.mdx) can also be coerced to a regular variant when every possible source constructor has the same runtime representation in the target. + ### Coercing Variants to Primitives Variants that are guaranteed to always be represented by a single primitive at runtime can be coerced to that primitive. diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_dead.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_dead.mdx index 9601476c3..f4808f7a1 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_dead.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_dead.mdx @@ -1,15 +1,25 @@ --- id: "dead-decorator" -keywords: ["dead", "decorator"] -name: "@dead" -summary: "This is the `@dead` decorator." +keywords: ["dead", "decorator", "reanalyze", "dead code"] +name: "@dead / @@dead" +summary: "These decorators suppress dead-code reports." category: "decorators" --- -> This decorator requires [`reanalyze`](https://github.com/rescript-lang/reanalyze), a code analysis tool for ReScript, to be installed. [Click here to read about how you get started with reanalyze.](https://github.com/rescript-lang/reanalyze). - `@dead` is picked up by reanalyze's dead code analysis, and suppresses reporting on the value/type, but can also be used to force the analysis to consider a value as dead. Typically used to acknowledge cases of dead code you are not planning to address right now, but can be searched easily later. +Since ReScript 12.2, standalone `@@dead` suppresses reports for all following items in the current file or module until another scoped annotation overrides it: + +```res +module DeferredCleanup = { + @@dead + let oldParser = input => input + let oldSerializer = value => value +} +``` + +Unlike `@@live`, suppressed items aren't liveness roots and don't keep their dependencies alive. + ### References -- [Reanalyze: Controlling reports with Annotations](https://github.com/rescript-lang/reanalyze#dce-controlling-reports-with-annotations) +- [Dead Code Analysis](../docs/manual/editor-code-analysis.mdx#keeping-some-dead-code) diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_directive.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_directive.mdx index a01c293bb..a2adc9d7e 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_directive.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_directive.mdx @@ -1,18 +1,18 @@ --- id: "directive-decorator" -keywords: ["directive", "decorator"] -name: "@@directive" -summary: "This is the `@@directive` decorator." +keywords: ["directive", "decorator", "function", "use server", "use client"] +name: "@@directive / @directive" +summary: "These decorators emit JavaScript directives at file or function scope." category: "decorators" --- -`@@directive` takes a string literal payload, and will output that string verbatim at the very top of the generated JavaScript file, before any imports. +`@@directive` takes a string literal payload and emits it at the very top of the generated JavaScript file, before any imports. -Useful for outputing directives like [`'use client'`](https://beta.nextjs.org/docs/rendering/server-and-client-components#convention) for React Server Components. +This is useful for directives such as `'use client'` in React Server Components. _Available since ReScript `10.1.4`._ -### Example +### File-Level Example @@ -26,3 +26,31 @@ _Available since ReScript `10.1.4`._ ``` + +Since ReScript 12, `@directive` can also annotate a function expression. The directive is emitted at the start of the generated function: + + + +```res +let serverAction = @directive("'use server'") async (~name) => { + "Hello " + name +} +``` + +```js +async function serverAction(name) { + "use server"; + return "Hello " + name; +} + +export { serverAction }; +``` + + + +Place the attribute after the binding's `=` and directly before the function. Function directives work with synchronous and asynchronous functions and with multiple or labeled parameters. + +### References + +- [Function directives](../docs/manual/function.mdx#function-directives) +- [React Server Components](../docs/react/server-components.mdx) diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_live.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_live.mdx index d0ba6017e..efccd32ab 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_live.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_live.mdx @@ -1,16 +1,24 @@ --- id: "live-decorator" -keywords: ["live", "decorator"] -name: "@live" -summary: "This is the `@live` decorator." +keywords: ["live", "decorator", "reanalyze", "dead code"] +name: "@live / @@live" +summary: "These decorators mark code as live for dead-code analysis." category: "decorators" --- -> This decorator requires [`reanalyze`](https://github.com/rescript-lang/reanalyze), a code analysis tool for ReScript, to be installed. [Click here to read about how you get started with reanalyze.](https://github.com/rescript-lang/reanalyze). - `@live` tells reanalyze's dead code analysis that the value should be considered live, even though it might appear to be dead. This is typically used in case of FFI where there are indirect ways to access values. It can be added to everything that could otherwise be considered unused by the dead code analysis - values, functions, arguments, records, individual record fields, and so on. +Since ReScript 12.2, standalone `@@live` marks all following items in the current file or module as live roots until another scoped annotation overrides it: + +```res +module PublicApi = { + @@live + let load = () => "loaded" + let save = _value => () +} +``` + ### References -- [Reanalyze: Controlling reports with Annotations](https://github.com/rescript-lang/reanalyze#dce-controlling-reports-with-annotations) +- [Dead Code Analysis](../docs/manual/editor-code-analysis.mdx#keeping-some-dead-code) diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_react_component.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_react_component.mdx index 788894bec..ffce1653a 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_react_component.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_react_component.mdx @@ -11,7 +11,7 @@ The `@react.component` decorator is used to annotate functions that are [React]( You will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions. > **Note** -> The `@react.component` decorator requires the [react-jsx or jsx config](../docs/react/installation.mdx) to be set in your `rescript.json` to enable the required React transformations. +> The `@react.component` decorator requires the [`jsx` config](../docs/react/installation.mdx) to be set in your `rescript.json` to enable the required React transformations. ### Example diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_react_component_with_props.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_react_component_with_props.mdx index a798f745e..f8230125a 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_react_component_with_props.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_react_component_with_props.mdx @@ -10,7 +10,7 @@ The `@react.componentWithProps` decorator is used to annotate functions that are This decorator will ensure your component gets an uppercased name. > **Note** -> The `@react.componentWithProps` decorator requires the [react-jsx or jsx config](../docs/react/installation.mdx) to be set in your `rescript.json` to enable the required React transformations. +> The `@react.componentWithProps` decorator requires the [`jsx` config](../docs/react/installation.mdx) to be set in your `rescript.json` to enable the required React transformations. ### Example diff --git a/apps/docs/markdown-pages/syntax-lookup/decorator_unboxed.mdx b/apps/docs/markdown-pages/syntax-lookup/decorator_unboxed.mdx index a41488dfe..07871e682 100644 --- a/apps/docs/markdown-pages/syntax-lookup/decorator_unboxed.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/decorator_unboxed.mdx @@ -35,6 +35,8 @@ export { myArray, hi }; _`@unboxed` for variants with multiple constructors is available since ReScript `11.0.0`._ +ReScript 12 adds runtime discrimination for `ArrayBuffer.t`, `DataView.t`, and typed array payloads. ReScript 12.1 also supports `Set.t`, `Map.t`, `WeakSet.t`, and `WeakMap.t`. Each distinct JavaScript built-in can occupy its own constructor without overlapping the others. + ### References - [Untagged variants doc](../docs/manual/variant.mdx#untagged-variants) diff --git a/apps/docs/markdown-pages/syntax-lookup/language_module_type.mdx b/apps/docs/markdown-pages/syntax-lookup/language_module_type.mdx index 972772571..b1be2f390 100644 --- a/apps/docs/markdown-pages/syntax-lookup/language_module_type.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/language_module_type.mdx @@ -40,6 +40,19 @@ export { IntShow, rendered }; +### Type Constraints + +Use `with type` to refine an abstract type from another module type. A `private` constraint exposes the underlying representation for safe coercion without allowing callers to construct values directly: + +```res +module type Storage = { + type t + let make: string => t +} + +module type PrivateStringStorage = Storage with type t = private string +``` + ### References -- [Module](../docs/manual/module.mdx) +- [Module](../docs/manual/module.mdx#refining-module-types-with-constraints) diff --git a/apps/docs/markdown-pages/syntax-lookup/language_record_type.mdx b/apps/docs/markdown-pages/syntax-lookup/language_record_type.mdx index 24c09f16d..ad490a75a 100644 --- a/apps/docs/markdown-pages/syntax-lookup/language_record_type.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/language_record_type.mdx @@ -44,6 +44,22 @@ export { myRecord, label }; +### Nested Record Types + +Since ReScript 12, record types can be declared inline inside another record type: + +```res +type profile = { + name: string, + settings: { + notifications: bool, + theme: string, + }, +} +``` + +Nested record types are useful when the inner shape belongs only to its parent. If it needs to be referenced independently, give it a separate named type. + ### References - [Record](../docs/manual/record.mdx) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_integer_addition.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_integer_addition.mdx index 54214a6f2..1be9e6040 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_integer_addition.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_integer_addition.mdx @@ -1,25 +1,36 @@ --- id: "integer-addition" -keywords: ["plus", "add", "addition", "sum", "int", "integer"] +keywords: + ["plus", "add", "addition", "sum", "int", "integer", "float", "string"] name: "+" -summary: "This is the `integer addition` operator." +summary: "This is the unified `addition` and `string concatenation` operator." category: "operators-arithmetic" --- -This operator performs _integers_ addition. +Since ReScript 12, `+` works with `int`, `float`, and `bigint`, and concatenates `string` values. The compiler specializes the operator from its operands. ```res -let result = 1 + 2 +let intResult = 1 + 2 +let floatResult = 1.5 + 2.5 +let stringResult = "Re" + "Script" ``` ```js -let result = 3; +let floatResult = 1.5 + 2.5; -export { result }; +let stringResult = "ReScript"; + +let intResult = 3; + +export { intResult, floatResult, stringResult }; ``` -For contatenating _strings_ see the [`++`](./operators_string_concatenation.mdx) operator. +The older [`++`](./operators_string_concatenation.mdx) string concatenation operator is still supported. + +### References + +- [Primitive Types](../docs/manual/primitive-types.mdx#arithmetic-operators) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_integer_division.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_integer_division.mdx index d9f9079f2..2e21b2c42 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_integer_division.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_integer_division.mdx @@ -1,25 +1,33 @@ --- id: "integer-division" -keywords: ["divide", "division", "int", "integer"] +keywords: ["divide", "division", "int", "integer", "float"] name: "/" -summary: "This is the `integer division` operator." +summary: "This is the unified `division` operator." category: "operators-arithmetic" --- -This operator performs _integer_ division, with the result truncated to an integer value. +Since ReScript 12, `/` works with `int`, `float`, and `bigint`. The compiler specializes the operator from its operands. -If the second argument is _zero_ then a `Division_by_zero` exception is thrown. Read about [exception](../docs/manual/exception.mdx) +Integer division truncates the result to an integer. Dividing an integer by zero throws a `Division_by_zero` exception. ```res -let result = 3 / 2 +let intResult = 3 / 2 +let floatResult = 3.0 / 2.0 ``` ```js -let result = 1; +let floatResult = 3.0 / 2.0; -export { result }; +let intResult = 1; + +export { intResult, floatResult }; ``` + +### References + +- [Primitive Types](../docs/manual/primitive-types.mdx#arithmetic-operators) +- [Exception](../docs/manual/exception.mdx) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_integer_multiplication.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_integer_multiplication.mdx index fece41fac..6b51b67f7 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_integer_multiplication.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_integer_multiplication.mdx @@ -1,23 +1,30 @@ --- id: "integer-multiplication" -keywords: ["multiply", "multiplication", "int", "integer"] +keywords: ["multiply", "multiplication", "int", "integer", "float"] name: "*" -summary: "This is the `integer multiplication` operator." +summary: "This is the unified `multiplication` operator." category: "operators-arithmetic" --- -This operator performs _integer_ multiplication. +Since ReScript 12, `*` works with `int`, `float`, and `bigint`. The compiler specializes the operator from its operands. ```res -let result = 2 * 3 +let intResult = 2 * 3 +let floatResult = 2.5 * 3.0 ``` ```js -let result = 6; +let floatResult = 2.5 * 3.0; -export { result }; +let intResult = 6; + +export { intResult, floatResult }; ``` + +### References + +- [Primitive Types](../docs/manual/primitive-types.mdx#arithmetic-operators) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_integer_subtraction.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_integer_subtraction.mdx index 271ffd2b0..0ebcef3a7 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_integer_subtraction.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_integer_subtraction.mdx @@ -1,23 +1,30 @@ --- id: "integer-subtraction" -keywords: ["subtract", "minus", "subtraction", "int", "integer"] +keywords: ["subtract", "minus", "subtraction", "int", "integer", "float"] name: "-" -summary: "This is the `integer subtraction` operator." +summary: "This is the unified `subtraction` operator." category: "operators-arithmetic" --- -This operator performs _integer_ subtraction. +Since ReScript 12, `-` works with `int`, `float`, and `bigint`. The compiler specializes the operator from its operands. ```res -let result = 3 - 2 +let intResult = 3 - 2 +let floatResult = 3.5 - 2.0 ``` ```js -let result = 1; +let floatResult = 3.5 - 2.0; -export { result }; +let intResult = 1; + +export { intResult, floatResult }; ``` + +### References + +- [Primitive Types](../docs/manual/primitive-types.mdx#arithmetic-operators) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_mod.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_mod.mdx index 0df6d5bb7..4df23e75d 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_mod.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_mod.mdx @@ -2,11 +2,11 @@ id: "%" keywords: ["mod", "modulo", "operator", "%", "remainder"] name: "%" -summary: "This is the `mod` operator (remainder semantics)." +summary: "This is the `%` operator (remainder semantics)." category: "operators-arithmetic" --- -The `%` operator has `mod` naming in ReScript, but its semantics are _remainder_ (like JavaScript `%`). +The `%` operator computes the _remainder_, like JavaScript `%`. It supports `int`, `float`, and `bigint`. @@ -15,13 +15,20 @@ It supports `int`, `float`, and `bigint`. ```res -let result = mod(7, 4) +let intResult = 7 % 4 +let floatResult = 7.5 % 4.0 ``` ```js -let result = 3; +let floatResult = 7.5 % 4.0; -export { result }; +let intResult = 3; + +export { intResult, floatResult }; ``` + +### References + +- [Primitive Types](../docs/manual/primitive-types.mdx#arithmetic-operators) diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_string_concatenation.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_string_concatenation.mdx index 5b9b1da37..fd380e796 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_string_concatenation.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_string_concatenation.mdx @@ -6,7 +6,7 @@ summary: "This is the `string concatenation` operator." category: "operators" --- -This operator concatenates two _strings_ together. +This operator concatenates two `string` values. It remains supported, but since ReScript 12 the unified [`+`](./operators_integer_addition.mdx) operator can also concatenate strings and is preferred in new code. diff --git a/apps/docs/markdown-pages/syntax-lookup/operators_type_coercion.mdx b/apps/docs/markdown-pages/syntax-lookup/operators_type_coercion.mdx index fe78af246..a4014ed0e 100644 --- a/apps/docs/markdown-pages/syntax-lookup/operators_type_coercion.mdx +++ b/apps/docs/markdown-pages/syntax-lookup/operators_type_coercion.mdx @@ -27,6 +27,11 @@ _Since ReScript `11.0.0`_ coercion also works for converting - from variant to `string`/`int`/`float` when applicable - for invariant type arguments such as array payloads when the runtime representation is guaranteed to be exactly the same +Since ReScript 12, coercion also supports: + +- a closed polymorphic variant to a regular variant when all possible source constructors have matching target constructors +- resolving type variables from the surrounding expression while checking the coercion + ### Example 1 @@ -136,6 +141,31 @@ export { v, v2, x, y, f }; +### Polymorphic Variant to Regular Variant + +```res +type command = [#Start | #Stop] +type event = Start | Stop | Pause + +let command: command = #Start +let event: event = (command :> event) +``` + +### Inferred Source Type + +```res +type userId = private string + +let inspect = (_: userId) => () + +let unwrap = value => { + inspect(value) + (value :> string) +} +``` + +The call to `inspect` determines the otherwise-unannotated `value` parameter's type, and the coercion is checked with that inferred type. + ### References - [Int-to-Float Coercion](../docs/manual/primitive-types.mdx#int-to-float-coercion)