From 92b424305d19e3507f107a86b81eb2377f65cfc8 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sat, 20 Sep 2025 23:27:28 +0200 Subject: [PATCH 1/4] Wrap docstring tests in async context to make "toplevel" await work --- tests/docstring_tests/DocTest.res | 4 ++-- tests/docstring_tests/DocTest.res.js | 2 +- tests/docstring_tests/Mocha.res | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/docstring_tests/DocTest.res b/tests/docstring_tests/DocTest.res index dff139cf0f..62b9d3c43b 100644 --- a/tests/docstring_tests/DocTest.res +++ b/tests/docstring_tests/DocTest.res @@ -141,9 +141,9 @@ let main = async () => { } else { // Let's add the examples inside a Test module because some examples // have type definitions that are not supported inside a block. - // Also add unit type `()` + // Also add unit type `()`. Also wrap in async to make top-level awaits work. Some( - `test("${example.name}", () => { + `testAsync("${example.name}", async () => { module Test = { ${code} } diff --git a/tests/docstring_tests/DocTest.res.js b/tests/docstring_tests/DocTest.res.js index cd00b651ac..8a46eff061 100644 --- a/tests/docstring_tests/DocTest.res.js +++ b/tests/docstring_tests/DocTest.res.js @@ -127,7 +127,7 @@ async function main() { if (code.length === 0) { return; } else { - return `test("` + example.name + `", () => { + return `testAsync("` + example.name + `", async () => { module Test = { ` + code + ` } diff --git a/tests/docstring_tests/Mocha.res b/tests/docstring_tests/Mocha.res index a7fc8c9ed3..4988a83959 100644 --- a/tests/docstring_tests/Mocha.res +++ b/tests/docstring_tests/Mocha.res @@ -1,5 +1,8 @@ @module("mocha") external test: (string, unit => unit) => unit = "test" +@module("mocha") +external testAsync: (string, unit => promise) => unit = "test" + @module("mocha") external describe: (string, unit => unit) => unit = "describe" From 42f68a8649c8402787b3fd08d982b2f0e6f5e3d6 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sat, 20 Sep 2025 23:27:53 +0200 Subject: [PATCH 2/4] Fix result example tests --- packages/@rescript/runtime/Stdlib_Result.resi | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/@rescript/runtime/Stdlib_Result.resi b/packages/@rescript/runtime/Stdlib_Result.resi index e676de49cf..ba4396fe4d 100644 --- a/packages/@rescript/runtime/Stdlib_Result.resi +++ b/packages/@rescript/runtime/Stdlib_Result.resi @@ -330,10 +330,16 @@ When `res` is `Error`, returns the error unchanged. ## Examples ```rescript -let asyncSquare = async x => x * x + let square = x => x * x -let result1 = Result.mapOkAsync(Promise.resolve(Ok(4)), asyncSquare) // Returns promise that resolves to Ok(16) -let result2 = Result.mapOkAsync(Promise.resolve(Error("invalid")), asyncSquare) // Returns promise that resolves to Error("invalid") + let result1 = await Result.mapOkAsync(Promise.resolve(Ok(4)), square) + result1 == Ok(16) + + let result2 = await Result.mapOkAsync( + Promise.resolve(Error("invalid")), + square, + ) + result2 == Error("invalid") ``` */ let mapOkAsync: ( @@ -349,10 +355,13 @@ When `res` is `Ok`, returns the ok value unchanged. ## Examples ```rescript -let asyncFormatError = async e => `Error: ${e}` +let formatError = e => `Error: ${e}` -let result1 = Result.mapErrorAsync(Promise.resolve(Ok(42)), asyncFormatError) // Returns promise that resolves to Ok(42) -let result2 = Result.mapErrorAsync(Promise.resolve(Error("invalid")), asyncFormatError) // Returns promise that resolves to Error("Error: invalid") +let result1 = await Result.mapErrorAsync(Promise.resolve(Ok(42)), formatError) +result1 == Ok(42) + +let result2 = await Result.mapErrorAsync(Promise.resolve(Error("invalid")), formatError) +result2 == Error("Error: invalid") ``` */ let mapErrorAsync: ( @@ -368,15 +377,21 @@ When `res` is `Error`, returns the error unchanged. ## Examples ```rescript -let asyncValidate = async x => +let asyncValidate = async x => if x > 0 { Ok(x * 2) } else { Error("Must be positive") } -let result1 = Result.flatMapOkAsync(Promise.resolve(Ok(5)), asyncValidate) // Returns promise that resolves to Ok(10) -let result2 = Result.flatMapOkAsync(Promise.resolve(Error("Already failed")), asyncValidate) // Returns promise that resolves to Error("Already failed") +let result1 = await Result.flatMapOkAsync(Promise.resolve(Ok(5)), asyncValidate) +result1 == Ok(10) + +let result2 = await Result.flatMapOkAsync( + Promise.resolve(Error("Already failed")), + asyncValidate, +) +result2 == Error("Already failed") ``` */ let flatMapOkAsync: ( @@ -392,15 +407,24 @@ When `res` is `Ok`, returns the ok value unchanged. ## Examples ```rescript -let asyncRecover = async error => +let asyncRecover = async error => if error === "timeout" { Ok("default") } else { Error(error) } -let result1 = Result.flatMapErrorAsync(Promise.resolve(Error("timeout")), asyncRecover) // Returns promise that resolves to Ok("default") -let result2 = Result.flatMapErrorAsync(Promise.resolve(Ok("default")), asyncRecover) // Returns promise that resolves to Ok("default") +let result1 = await Result.flatMapErrorAsync( + Promise.resolve(Error("timeout")), + asyncRecover, +) +result1 == Ok("default") + +let result2 = await Result.flatMapErrorAsync( + Promise.resolve(Ok("default")), + asyncRecover, +) +result2 == Ok("default") ``` */ let flatMapErrorAsync: ( From 8f904fd27b8e092fcecf3779d44fc6609d635210 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sun, 21 Sep 2025 00:09:21 +0200 Subject: [PATCH 3/4] Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5aae99b2b..a77cb78b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ #### :bug: Bug fix +- Fix result examples. https://github.com/rescript-lang/rescript/pull/7914 + #### :memo: Documentation #### :nail_care: Polish From dfb2f848fcb8372a29c64b3592dfc1586b9c3fb3 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sun, 21 Sep 2025 09:40:59 +0200 Subject: [PATCH 4/4] Gate testAsync in naive await detection --- tests/docstring_tests/DocTest.res | 14 ++++++++++++-- tests/docstring_tests/DocTest.res.js | 9 ++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/docstring_tests/DocTest.res b/tests/docstring_tests/DocTest.res index 62b9d3c43b..1be44d98eb 100644 --- a/tests/docstring_tests/DocTest.res +++ b/tests/docstring_tests/DocTest.res @@ -138,12 +138,22 @@ let main = async () => { if code->String.length === 0 { None + } else if code->String.includes("await") { + // Same as below, but wrap in async to make top-level awaits work. + Some( + `testAsync("${example.name}", async () => { + module Test = { + ${code} + } + () +})`, + ) } else { // Let's add the examples inside a Test module because some examples // have type definitions that are not supported inside a block. - // Also add unit type `()`. Also wrap in async to make top-level awaits work. + // Also add unit type `()`. Some( - `testAsync("${example.name}", async () => { + `test("${example.name}", () => { module Test = { ${code} } diff --git a/tests/docstring_tests/DocTest.res.js b/tests/docstring_tests/DocTest.res.js index 8a46eff061..0e9d1e216c 100644 --- a/tests/docstring_tests/DocTest.res.js +++ b/tests/docstring_tests/DocTest.res.js @@ -126,12 +126,19 @@ async function main() { let code = example.code; if (code.length === 0) { return; - } else { + } else if (code.includes("await")) { return `testAsync("` + example.name + `", async () => { module Test = { ` + code + ` } () +})`; + } else { + return `test("` + example.name + `", () => { + module Test = { + ` + code + ` + } + () })`; } });