From 02f60b8b6c232704276adbbec54a17b0fccafc5a Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 1 Dec 2024 15:07:37 -0300 Subject: [PATCH 01/25] add docstrings tests --- runtime/Belt_Array.resi | 1 + runtime/Exn.resi | 5 +- runtime/Js_dict.resi | 6 + runtime/Js_types.resi | 6 +- scripts/test.js | 18 ++ tests/docstrings_examples/DocTest.res | 345 +++++++++++++++++++++ tests/docstrings_examples/DocTest.res.mjs | 361 ++++++++++++++++++++++ tests/docstrings_examples/rescript.json | 11 + 8 files changed, 748 insertions(+), 5 deletions(-) create mode 100644 tests/docstrings_examples/DocTest.res create mode 100644 tests/docstrings_examples/DocTest.res.mjs create mode 100644 tests/docstrings_examples/rescript.json diff --git a/runtime/Belt_Array.resi b/runtime/Belt_Array.resi index 4443dd1ff9..4674f4f80f 100644 --- a/runtime/Belt_Array.resi +++ b/runtime/Belt_Array.resi @@ -362,6 +362,7 @@ arr == [0, 1, 9, 9, 4] Belt.Array.fill(arr, ~offset=7, ~len=2, 8) arr == [0, 1, 9, 9, 4] +``` */ let fill: (t<'a>, ~offset: int, ~len: int, 'a) => unit diff --git a/runtime/Exn.resi b/runtime/Exn.resi index 31e8751e5f..b8c5d7077b 100644 --- a/runtime/Exn.resi +++ b/runtime/Exn.resi @@ -52,12 +52,13 @@ a value passed to a Promise.catch callback) ## Examples ```rescript -switch (Js.Exn.unsafeAnyToExn("test")) { +switch (Js.Exn.anyToExnInternal("test")) { | Js.Exn.Error(v) => switch(Js.Exn.message(v)) { - | Some(str) => Js.log("We won't end up here") + | Some(_) => Js.log("We won't end up here") | None => Js.log2("We will land here: ", v) } +| _ => assert(false) } ``` */ diff --git a/runtime/Js_dict.resi b/runtime/Js_dict.resi index 8baa9407d0..834be4b206 100644 --- a/runtime/Js_dict.resi +++ b/runtime/Js_dict.resi @@ -53,6 +53,7 @@ type key = string ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.get(ages, "Vinh") == Some(22) Js.Dict.get(ages, "Paul") == None ``` @@ -66,6 +67,7 @@ let get: (t<'a>, key) => option<'a> ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.unsafeGet(ages, "Fred") == 49 Js.Dict.unsafeGet(ages, "Paul") // returns undefined ``` @@ -82,6 +84,7 @@ the key does not exist, and entry will be created for it. ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.set(ages, "Maria", 31) Js.log(ages == Js.Dict.fromList(list{("Maria", 31), ("Vinh", 22), ("Fred", 49)})) @@ -98,6 +101,7 @@ Returns all the keys in the dictionary `dict`. ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.keys(ages) == ["Maria", "Vinh", "Fred"] ``` */ @@ -115,6 +119,7 @@ Returns an array of key/value pairs in the given dictionary (ES2017). ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.entries(ages) == [("Maria", 30), ("Vinh", 22), ("Fred", 49)] ``` */ @@ -126,6 +131,7 @@ Returns the values in the given dictionary (ES2017). ## Examples ```rescript +let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.values(ages) == [30, 22, 49] ``` */ diff --git a/runtime/Js_types.resi b/runtime/Js_types.resi index a2faaf8afe..fd969fb9e7 100644 --- a/runtime/Js_types.resi +++ b/runtime/Js_types.resi @@ -55,9 +55,9 @@ This is useful for doing runtime reflection on any given value. ## Examples ```rescript -test("test", String) == true -test(() => true, Function) == true -test("test", Boolean) == false +Js.Types.test("test", String) == true +Js.Types.test(() => true, Function) == true +Js.Types.test("test", Boolean) == false ``` */ let test: ('a, t<'b>) => bool diff --git a/scripts/test.js b/scripts/test.js index 8a88795650..95d48cf43d 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -12,6 +12,7 @@ let ounitTest = false; let mochaTest = false; let bsbTest = false; let formatTest = false; +let runtimeDocstrings = false; if (process.argv.includes("-ounit")) { ounitTest = true; @@ -29,11 +30,16 @@ if (process.argv.includes("-format")) { formatTest = true; } +if (process.argv.includes("-docstrings")) { + runtimeDocstrings = true; +} + if (process.argv.includes("-all")) { ounitTest = true; mochaTest = true; bsbTest = true; formatTest = true; + runtimeDocstrings = true; } async function runTests() { @@ -120,6 +126,18 @@ async function runTests() { process.exit(1); } } + + if (runtimeDocstrings) { + console.log("Running runtime docstrings tests"); + cp.execSync(`${rescript_exe} build`, { + cwd: path.join(__dirname, "..", "tests/docstrings_examples"), + stdio: [0, 1, 2], + }); + cp.execSync("node tests/docstrings_examples/DocTest.res.mjs", { + cwd: path.join(__dirname, ".."), + stdio: [0, 1, 2], + }); + } } runTests(); diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res new file mode 100644 index 0000000000..755a78dca0 --- /dev/null +++ b/tests/docstrings_examples/DocTest.res @@ -0,0 +1,345 @@ +module Node = { + module Path = { + @module("path") external join2: (string, string) => string = "join" + @module("path") @variadic external join: array => string = "join" + @module("path") external dirname: string => string = "dirname" + } + + module URL = { + @module("url") external fileURLToPath: string => string = "fileURLToPath" + } + + module Process = { + @scope("process") external exit: int => unit = "exit" + @scope(("process", "stderr")) + external stderrWrite: string => unit = "write" + @scope("process") external cwd: unit => string = "cwd" + } + + module Fs = { + @module("fs") external readFileSync: string => string = "readFileSync" + @module("fs") external writeFileSync: (string, string) => unit = "writeFileSync" + @module("fs") external mkdirSync: string => option = "mkdirSync" + @module("fs") external existsSync: string => bool = "existsSync" + @module("fs") external readdirSync: string => array = "readdirSync" + @module("node:fs/promises") external writeFile: (string, string) => promise = "writeFile" + @module("node:fs/promises") external unlink: string => promise = "unlink" + @module("node:fs/promises") external lstat: string => promise<'a> = "lstat" + } + + module Buffer = { + type t + @send external toString: t => string = "toString" + } + + module ChildProcess = { + type execSyncOpts = {stdio?: string, cwd?: string} + @module("child_process") + external execFileSync: (string, array, execSyncOpts) => Buffer.t = "execFileSync" + + type spawnSyncReturns = {stdout: Buffer.t} + @module("child_process") + external spawnSync: (string, array) => spawnSyncReturns = "spawnSync" + + type readable + type spawnReturns = {stderr: readable} + @module("child_process") + external spawn: (string, array) => spawnReturns = "spawn" + + @send external on: (readable, string, Buffer.t => unit) => unit = "on" + @send + external once: (spawnReturns, string, (Js.Null.t, Js.Null.t) => unit) => unit = + "once" + } + + module OS = { + @module("os") + external tmpdir: unit => string = "tmpdir" + } +} + +open Node + +module Docgen = RescriptTools.Docgen + +@val @scope(("import", "meta")) external url: string = "url" + +let dirname = + url + ->URL.fileURLToPath + ->Path.dirname + +let compilerDir = Path.join([dirname, "..", ".examples-tests"]) + +let rescriptBin = Path.join([compilerDir, "node_modules", ".bin", "rescript"]) + +let bscBin = Path.join(["cli", "bsc"]) + +let rescriptCoreCompiled = Path.join([ + compilerDir, + "node_modules", + "@rescript", + "core", + "lib", + "ocaml", +]) + +let makePackageJson = coreVersion => + `{ + "name": "test-compiler-examples", + "version": "1.0.0", + "dependencies": { + "@rescript/core": "file:rescript-core-${coreVersion}.tgz", + "rescript": "11.1.4" + } +} +` + +let rescriptJson = `{ + "name": "dummy", + "sources": { + "dir": "dummy", + "subdirs": true + }, + "bs-dependencies": [ + "@rescript/core" + ], + "bsc-flags": [ + "-open RescriptCore" + ] +}` + +let prepareCompiler = () => { + let corePath = Path.join([compilerDir, ".."]) + + if !Fs.existsSync(compilerDir) { + Fs.mkdirSync(compilerDir)->ignore + } + + ChildProcess.execFileSync("npm", ["pack", corePath], {cwd: compilerDir, stdio: "ignore"})->ignore + + let currentCoreVersion = switch Path.join2(corePath, "package.json") + ->Fs.readFileSync + ->JSON.parseExn { + | Object(dict) => + switch dict->Dict.getUnsafe("version") { + | String(s) => s + | _ => assert(false) + } + | _ => assert(false) + } + + Path.join2(compilerDir, "package.json")->Fs.writeFileSync(makePackageJson(currentCoreVersion)) + Path.join2(compilerDir, "rescript.json")->Fs.writeFileSync(rescriptJson) + + let dummyFolder = Path.join2(compilerDir, "dummy") + + if !Fs.existsSync(dummyFolder) { + Fs.mkdirSync(dummyFolder)->ignore + } + + ChildProcess.execFileSync("npm", ["install"], {cwd: compilerDir})->ignore + + ChildProcess.execFileSync(rescriptBin, ["build"], {cwd: compilerDir})->ignore +} + +// prepareCompiler() + +type example = { + id: string, + kind: string, + name: string, + docstrings: array, +} + +let createFileInTempDir = id => Path.join2(OS.tmpdir(), id) + +let testCode = async (~id, ~code) => { + let id = id->String.includes("/") ? String.replace(id, "/", "slash_op") : id + let tempFileName = createFileInTempDir(id) + + let () = await Fs.writeFile(tempFileName ++ ".res", code) + + let args = [tempFileName ++ ".res", "-I", rescriptCoreCompiled, "-w", "-3-109"] + + let promise = await Promise.make((resolve, _reject) => { + let spawn = ChildProcess.spawn(bscBin, args) + let stderr = [] + spawn.stderr->ChildProcess.on("data", data => { + Array.push(stderr, data) + }) + spawn->ChildProcess.once("close", (_code, _signal) => { + resolve(stderr) + }) + }) + + switch Array.length(promise) > 0 { + | true => + promise + ->Array.map(e => e->Buffer.toString) + ->Array.join("") + ->Error + | false => Ok() + } +} + +let extractDocFromFile = file => { + let toolsBin = Path.join([Process.cwd(), "cli", "rescript-tools"]) + let spawn = ChildProcess.spawnSync(toolsBin, ["doc", file]) + + spawn.stdout + ->Buffer.toString + ->JSON.parseExn + ->Docgen.decodeFromJson +} + +let getExamples = ({items}: Docgen.doc) => { + let rec loop = (items: list, acc: list) => { + switch items { + | list{Value({docstrings, id, name}), ...rest} => + loop(rest, list{{id, name, docstrings, kind: "value"}, ...acc}) + | list{Type({docstrings, id, name}), ...rest} => + loop(rest, list{{id, name, docstrings, kind: "type"}, ...acc}) + | list{Module({id, name, docstrings, items}), ...rest} => + loop( + list{...rest, ...List.fromArray(items)}, + list{{id, name, docstrings, kind: "module"}, ...acc}, + ) + | list{ModuleType({id, name, docstrings, items}), ...rest} => + loop( + list{...rest, ...List.fromArray(items)}, + list{{id, name, docstrings, kind: "moduleType"}, ...acc}, + ) + | list{ModuleAlias({id, name, docstrings, items}), ...rest} => + loop( + list{...rest, ...List.fromArray(items)}, + list{{id, name, docstrings, kind: "moduleAlias"}, ...acc}, + ) + | list{} => acc + } + } + + items + ->List.fromArray + ->loop(list{}) + ->List.toArray + ->Array.filter(({docstrings}) => Array.length(docstrings) > 0) +} + +let getCodeBlocks = example => { + let rec loopEndCodeBlock = (lines, acc) => { + switch lines { + | list{hd, ...rest} => + if ( + hd + ->String.trim + ->String.endsWith("```") + ) { + acc + } else { + loopEndCodeBlock(rest, list{hd, ...acc}) + } + | list{} => panic(`Failed to find end of code block for ${example.kind}: ${example.id}`) + } + } + + let rec loop = (lines: list, acc: list) => { + switch lines { + | list{hd, ...rest} => + switch hd + ->String.trim + ->String.startsWith("```res") { + | true => + let code = loopEndCodeBlock(rest, list{}) + loop( + rest, + list{ + code + ->List.reverse + ->List.toArray + ->Array.join("\n"), + ...acc, + }, + ) + | false => loop(rest, acc) + } + | list{} => acc + } + } + + example.docstrings + ->Array.reduce([], (acc, docstring) => acc->Array.concat(docstring->String.split("\n"))) + ->List.fromArray + ->loop(list{}) + ->List.toArray +} + +let main = async () => { + let modules = + Fs.readdirSync("runtime") + ->Array.filter(f => f->String.endsWith(".resi") && !(f->String.startsWith("Belt"))) + ->Array.map(f => extractDocFromFile(Path.join(["runtime", f]))->getExamples) + ->Array.flat + + let results = + await modules + ->Array.map(async example => { + let id = example.id->String.replaceAll(".", "_") + let codes = example->getCodeBlocks + let results = + await codes + ->Array.mapWithIndex(async (code, int) => { + let id = `${id}_${Int.toString(int)}` + await testCode(~id, ~code) + }) + ->Promise.all + (example, results) + }) + ->Promise.all + + let errors = results->Belt.Array.keepMap(((example, results)) => { + let errors = results->Belt.Array.keepMap(result => + switch result { + | Ok() => None + | Error(msg) => Some(msg) + } + ) + + if Array.length(errors) > 0 { + Some((example, errors)) + } else { + None + } + }) + + // Print Errors + let () = errors->Array.forEach(((test, errors)) => { + let red = s => `\x1B[1;31m${s}\x1B[0m` + let cyan = s => `\x1b[36m${s}\x1b[0m` + let kind = switch test.kind { + | "moduleAlias" => "module alias" + | other => other + } + + let errorMessage = + errors + ->Array.map(e => { + // Drop line from path file + e + ->String.split("\n") + ->Array.filterWithIndex((_, i) => i !== 2) + ->Array.join("\n") + }) + ->Array.join("\n") + + let message = `${"error"->red}: failed to compile examples from ${kind} ${test.id->cyan}\n${errorMessage}` + + Process.stderrWrite(message) + }) + + errors->Array.length == 0 ? 0 : 1 +} + +let exitCode = await main() + +Process.exit(exitCode) diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs new file mode 100644 index 0000000000..a443fbbdce --- /dev/null +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -0,0 +1,361 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Fs from "fs"; +import * as Os from "os"; +import * as Url from "url"; +import * as List from "rescript/lib/es6/List.js"; +import * as Path from "path"; +import * as $$Array from "rescript/lib/es6/Array.js"; +import * as Belt_List from "rescript/lib/es6/Belt_List.js"; +import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; +import * as Pervasives from "rescript/lib/es6/Pervasives.js"; +import * as Child_process from "child_process"; +import * as Promises from "node:fs/promises"; +import * as RescriptTools_Docgen from "rescript/lib/es6/RescriptTools_Docgen.js"; + +let Path$1 = {}; + +let URL = {}; + +let Process = {}; + +let Fs$1 = {}; + +let Buffer = {}; + +let ChildProcess = {}; + +let OS = {}; + +let Node = { + Path: Path$1, + URL: URL, + Process: Process, + Fs: Fs$1, + Buffer: Buffer, + ChildProcess: ChildProcess, + OS: OS +}; + +let dirname = Path.dirname(Url.fileURLToPath(import.meta.url)); + +let compilerDir = Path.join(dirname, "..", ".examples-tests"); + +let rescriptBin = Path.join(compilerDir, "node_modules", ".bin", "rescript"); + +let bscBin = Path.join("cli", "bsc"); + +let rescriptCoreCompiled = Path.join(compilerDir, "node_modules", "@rescript", "core", "lib", "ocaml"); + +function makePackageJson(coreVersion) { + return "{\n \"name\": \"test-compiler-examples\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@rescript/core\": \"file:rescript-core-" + coreVersion + ".tgz\",\n \"rescript\": \"11.1.4\"\n }\n}\n"; +} + +let rescriptJson = "{\n \"name\": \"dummy\",\n \"sources\": {\n \"dir\": \"dummy\",\n \"subdirs\": true\n },\n \"bs-dependencies\": [\n \"@rescript/core\"\n ],\n \"bsc-flags\": [\n \"-open RescriptCore\"\n ]\n}"; + +function prepareCompiler() { + let corePath = Path.join(compilerDir, ".."); + if (!Fs.existsSync(compilerDir)) { + Fs.mkdirSync(compilerDir); + } + Child_process.execFileSync("npm", [ + "pack", + corePath + ], { + stdio: "ignore", + cwd: compilerDir + }); + let dict = JSON.parse(Fs.readFileSync(Path.join(corePath, "package.json"))); + let currentCoreVersion; + if (typeof dict === "object" && !Array.isArray(dict)) { + let s = dict["version"]; + if (typeof s === "string") { + currentCoreVersion = s; + } else { + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "DocTest.res", + 127, + 11 + ], + Error: new Error() + }; + } + } else { + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "DocTest.res", + 129, + 9 + ], + Error: new Error() + }; + } + Fs.writeFileSync(Path.join(compilerDir, "package.json"), makePackageJson(currentCoreVersion)); + Fs.writeFileSync(Path.join(compilerDir, "rescript.json"), rescriptJson); + let dummyFolder = Path.join(compilerDir, "dummy"); + if (!Fs.existsSync(dummyFolder)) { + Fs.mkdirSync(dummyFolder); + } + Child_process.execFileSync("npm", ["install"], { + cwd: compilerDir + }); + Child_process.execFileSync(rescriptBin, ["build"], { + cwd: compilerDir + }); +} + +function createFileInTempDir(id) { + return Path.join(Os.tmpdir(), id); +} + +async function testCode(id, code) { + let id$1 = id.includes("/") ? id.replace("/", "slash_op") : id; + let tempFileName = Path.join(Os.tmpdir(), id$1); + await Promises.writeFile(tempFileName + ".res", code); + let args = [ + tempFileName + ".res", + "-I", + rescriptCoreCompiled, + "-w", + "-3-109" + ]; + let promise = await new Promise((resolve, _reject) => { + let spawn = Child_process.spawn(bscBin, args); + let stderr = []; + spawn.stderr.on("data", data => { + stderr.push(data); + }); + spawn.once("close", (_code, _signal) => resolve(stderr)); + }); + if (promise.length > 0) { + return { + TAG: "Error", + _0: promise.map(e => e.toString()).join("") + }; + } else { + return { + TAG: "Ok", + _0: undefined + }; + } +} + +function extractDocFromFile(file) { + let toolsBin = Path.join(process.cwd(), "cli", "rescript-tools"); + let spawn = Child_process.spawnSync(toolsBin, [ + "doc", + file + ]); + return RescriptTools_Docgen.decodeFromJson(JSON.parse(spawn.stdout.toString())); +} + +function getExamples(param) { + let loop = (_items, _acc) => { + while (true) { + let acc = _acc; + let items = _items; + if (!items) { + return acc; + } + let match = items.hd; + switch (match.kind) { + case "value" : + _acc = { + hd: { + id: match.id, + kind: "value", + name: match.name, + docstrings: match.docstrings + }, + tl: acc + }; + _items = items.tl; + continue; + case "type" : + _acc = { + hd: { + id: match.id, + kind: "type", + name: match.name, + docstrings: match.docstrings + }, + tl: acc + }; + _items = items.tl; + continue; + case "module" : + _acc = { + hd: { + id: match.id, + kind: "module", + name: match.name, + docstrings: match.docstrings + }, + tl: acc + }; + _items = Belt_List.concatMany([ + items.tl, + List.fromArray(match.items) + ]); + continue; + case "moduleType" : + _acc = { + hd: { + id: match.id, + kind: "moduleType", + name: match.name, + docstrings: match.docstrings + }, + tl: acc + }; + _items = Belt_List.concatMany([ + items.tl, + List.fromArray(match.items) + ]); + continue; + case "moduleAlias" : + _acc = { + hd: { + id: match.id, + kind: "moduleAlias", + name: match.name, + docstrings: match.docstrings + }, + tl: acc + }; + _items = Belt_List.concatMany([ + items.tl, + List.fromArray(match.items) + ]); + continue; + } + }; + }; + return List.toArray(loop(List.fromArray(param.items), /* [] */0)).filter(param => param.docstrings.length > 0); +} + +function getCodeBlocks(example) { + let loopEndCodeBlock = (_lines, _acc) => { + while (true) { + let acc = _acc; + let lines = _lines; + if (!lines) { + return Pervasives.panic("Failed to find end of code block for " + example.kind + ": " + example.id); + } + let hd = lines.hd; + if (hd.trim().endsWith("```")) { + return acc; + } + _acc = { + hd: hd, + tl: acc + }; + _lines = lines.tl; + continue; + }; + }; + let loop = (_lines, _acc) => { + while (true) { + let acc = _acc; + let lines = _lines; + if (!lines) { + return acc; + } + let rest = lines.tl; + if (lines.hd.trim().startsWith("```res")) { + let code = loopEndCodeBlock(rest, /* [] */0); + _acc = { + hd: List.toArray(List.reverse(code)).join("\n"), + tl: acc + }; + _lines = rest; + continue; + } + _lines = rest; + continue; + }; + }; + return List.toArray(loop(List.fromArray($$Array.reduce(example.docstrings, [], (acc, docstring) => acc.concat(docstring.split("\n")))), /* [] */0)); +} + +async function main() { + let modules = Fs.readdirSync("runtime").filter(f => { + if (f.endsWith(".resi")) { + return !f.startsWith("Belt"); + } else { + return false; + } + }).map(f => getExamples(extractDocFromFile(Path.join("runtime", f)))).flat(); + let results = await Promise.all(modules.map(async example => { + let id = example.id.replaceAll(".", "_"); + let codes = getCodeBlocks(example); + let results = await Promise.all(codes.map(async (code, int) => { + let id$1 = id + "_" + int.toString(); + return await testCode(id$1, code); + })); + return [ + example, + results + ]; + })); + let errors = Belt_Array.keepMap(results, param => { + let errors = Belt_Array.keepMap(param[1], result => { + if (result.TAG === "Ok") { + return; + } else { + return result._0; + } + }); + if (errors.length > 0) { + return [ + param[0], + errors + ]; + } + + }); + errors.forEach(param => { + let test = param[0]; + let cyan = s => "\x1b[36m" + s + "\x1b[0m"; + let other = test.kind; + let kind = other === "moduleAlias" ? "module alias" : other; + let errorMessage = param[1].map(e => e.split("\n").filter((param, i) => i !== 2).join("\n")).join("\n"); + let message = "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(test.id) + "\n" + errorMessage; + process.stderr.write(message); + }); + if (errors.length === 0) { + return 0; + } else { + return 1; + } +} + +let exitCode = await main(); + +process.exit(exitCode); + +let Docgen; + +export { + Node, + Docgen, + dirname, + compilerDir, + rescriptBin, + bscBin, + rescriptCoreCompiled, + makePackageJson, + rescriptJson, + prepareCompiler, + createFileInTempDir, + testCode, + extractDocFromFile, + getExamples, + getCodeBlocks, + main, + exitCode, +} +/* dirname Not a pure module */ diff --git a/tests/docstrings_examples/rescript.json b/tests/docstrings_examples/rescript.json new file mode 100644 index 0000000000..cb7ab948e4 --- /dev/null +++ b/tests/docstrings_examples/rescript.json @@ -0,0 +1,11 @@ +{ + "name": "core-doc-examples", + "sources": { + "dir": "." + }, + "package-specs": { + "module": "esmodule", + "in-source": true + }, + "suffix": ".res.mjs" +} From 02f4467826c5dcc160b3c0a26b80ee3dfe272ea8 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 1 Dec 2024 15:13:38 -0300 Subject: [PATCH 02/25] remove prepareCompiler --- tests/docstrings_examples/DocTest.res | 83 +---------------------- tests/docstrings_examples/DocTest.res.mjs | 80 +--------------------- 2 files changed, 2 insertions(+), 161 deletions(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 755a78dca0..45f2dfa3c1 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -62,89 +62,8 @@ open Node module Docgen = RescriptTools.Docgen -@val @scope(("import", "meta")) external url: string = "url" - -let dirname = - url - ->URL.fileURLToPath - ->Path.dirname - -let compilerDir = Path.join([dirname, "..", ".examples-tests"]) - -let rescriptBin = Path.join([compilerDir, "node_modules", ".bin", "rescript"]) - let bscBin = Path.join(["cli", "bsc"]) -let rescriptCoreCompiled = Path.join([ - compilerDir, - "node_modules", - "@rescript", - "core", - "lib", - "ocaml", -]) - -let makePackageJson = coreVersion => - `{ - "name": "test-compiler-examples", - "version": "1.0.0", - "dependencies": { - "@rescript/core": "file:rescript-core-${coreVersion}.tgz", - "rescript": "11.1.4" - } -} -` - -let rescriptJson = `{ - "name": "dummy", - "sources": { - "dir": "dummy", - "subdirs": true - }, - "bs-dependencies": [ - "@rescript/core" - ], - "bsc-flags": [ - "-open RescriptCore" - ] -}` - -let prepareCompiler = () => { - let corePath = Path.join([compilerDir, ".."]) - - if !Fs.existsSync(compilerDir) { - Fs.mkdirSync(compilerDir)->ignore - } - - ChildProcess.execFileSync("npm", ["pack", corePath], {cwd: compilerDir, stdio: "ignore"})->ignore - - let currentCoreVersion = switch Path.join2(corePath, "package.json") - ->Fs.readFileSync - ->JSON.parseExn { - | Object(dict) => - switch dict->Dict.getUnsafe("version") { - | String(s) => s - | _ => assert(false) - } - | _ => assert(false) - } - - Path.join2(compilerDir, "package.json")->Fs.writeFileSync(makePackageJson(currentCoreVersion)) - Path.join2(compilerDir, "rescript.json")->Fs.writeFileSync(rescriptJson) - - let dummyFolder = Path.join2(compilerDir, "dummy") - - if !Fs.existsSync(dummyFolder) { - Fs.mkdirSync(dummyFolder)->ignore - } - - ChildProcess.execFileSync("npm", ["install"], {cwd: compilerDir})->ignore - - ChildProcess.execFileSync(rescriptBin, ["build"], {cwd: compilerDir})->ignore -} - -// prepareCompiler() - type example = { id: string, kind: string, @@ -160,7 +79,7 @@ let testCode = async (~id, ~code) => { let () = await Fs.writeFile(tempFileName ++ ".res", code) - let args = [tempFileName ++ ".res", "-I", rescriptCoreCompiled, "-w", "-3-109"] + let args = [tempFileName ++ ".res", "-w", "-3-109"] let promise = await Promise.make((resolve, _reject) => { let spawn = ChildProcess.spawn(bscBin, args) diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index a443fbbdce..1b36292484 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -2,7 +2,6 @@ import * as Fs from "fs"; import * as Os from "os"; -import * as Url from "url"; import * as List from "rescript/lib/es6/List.js"; import * as Path from "path"; import * as $$Array from "rescript/lib/es6/Array.js"; @@ -37,76 +36,8 @@ let Node = { OS: OS }; -let dirname = Path.dirname(Url.fileURLToPath(import.meta.url)); - -let compilerDir = Path.join(dirname, "..", ".examples-tests"); - -let rescriptBin = Path.join(compilerDir, "node_modules", ".bin", "rescript"); - let bscBin = Path.join("cli", "bsc"); -let rescriptCoreCompiled = Path.join(compilerDir, "node_modules", "@rescript", "core", "lib", "ocaml"); - -function makePackageJson(coreVersion) { - return "{\n \"name\": \"test-compiler-examples\",\n \"version\": \"1.0.0\",\n \"dependencies\": {\n \"@rescript/core\": \"file:rescript-core-" + coreVersion + ".tgz\",\n \"rescript\": \"11.1.4\"\n }\n}\n"; -} - -let rescriptJson = "{\n \"name\": \"dummy\",\n \"sources\": {\n \"dir\": \"dummy\",\n \"subdirs\": true\n },\n \"bs-dependencies\": [\n \"@rescript/core\"\n ],\n \"bsc-flags\": [\n \"-open RescriptCore\"\n ]\n}"; - -function prepareCompiler() { - let corePath = Path.join(compilerDir, ".."); - if (!Fs.existsSync(compilerDir)) { - Fs.mkdirSync(compilerDir); - } - Child_process.execFileSync("npm", [ - "pack", - corePath - ], { - stdio: "ignore", - cwd: compilerDir - }); - let dict = JSON.parse(Fs.readFileSync(Path.join(corePath, "package.json"))); - let currentCoreVersion; - if (typeof dict === "object" && !Array.isArray(dict)) { - let s = dict["version"]; - if (typeof s === "string") { - currentCoreVersion = s; - } else { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "DocTest.res", - 127, - 11 - ], - Error: new Error() - }; - } - } else { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "DocTest.res", - 129, - 9 - ], - Error: new Error() - }; - } - Fs.writeFileSync(Path.join(compilerDir, "package.json"), makePackageJson(currentCoreVersion)); - Fs.writeFileSync(Path.join(compilerDir, "rescript.json"), rescriptJson); - let dummyFolder = Path.join(compilerDir, "dummy"); - if (!Fs.existsSync(dummyFolder)) { - Fs.mkdirSync(dummyFolder); - } - Child_process.execFileSync("npm", ["install"], { - cwd: compilerDir - }); - Child_process.execFileSync(rescriptBin, ["build"], { - cwd: compilerDir - }); -} - function createFileInTempDir(id) { return Path.join(Os.tmpdir(), id); } @@ -117,8 +48,6 @@ async function testCode(id, code) { await Promises.writeFile(tempFileName + ".res", code); let args = [ tempFileName + ".res", - "-I", - rescriptCoreCompiled, "-w", "-3-109" ]; @@ -342,14 +271,7 @@ let Docgen; export { Node, Docgen, - dirname, - compilerDir, - rescriptBin, bscBin, - rescriptCoreCompiled, - makePackageJson, - rescriptJson, - prepareCompiler, createFileInTempDir, testCode, extractDocFromFile, @@ -358,4 +280,4 @@ export { main, exitCode, } -/* dirname Not a pure module */ +/* bscBin Not a pure module */ From 319ff9b52566fd18b64048d96dad2e720c27bae5 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 1 Dec 2024 15:16:55 -0300 Subject: [PATCH 03/25] update output --- biome.json | 1 + tests/analysis_tests/tests/package-lock.json | 3 ++- tests/analysis_tests/tests/src/expected/Completion.res.txt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/biome.json b/biome.json index 44dd98952b..de13644025 100644 --- a/biome.json +++ b/biome.json @@ -25,6 +25,7 @@ "tests/tests/**", "tests/tools_tests/**", "tests/analysis_tests/**", + "tests/docstrings_examples/**", "analysis/examples/**", "analysis/reanalyze/examples/**", "lib/**", diff --git a/tests/analysis_tests/tests/package-lock.json b/tests/analysis_tests/tests/package-lock.json index cdb575c401..fc1d7e517e 100644 --- a/tests/analysis_tests/tests/package-lock.json +++ b/tests/analysis_tests/tests/package-lock.json @@ -34,13 +34,14 @@ }, "../../..": { "name": "rescript", - "version": "12.0.0-alpha.5", + "version": "12.0.0-alpha.6", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", "bin": { "bsc": "cli/bsc", "bstracing": "lib/bstracing", "rescript": "cli/rescript", + "rescript-tools": "cli/rescript-tools", "rewatch": "cli/rewatch" }, "devDependencies": { diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index da4248ef4d..db9a85d7bc 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -745,7 +745,7 @@ Path Js.Dict.u "kind": 12, "tags": [], "detail": "(t<'a>, key) => 'a", - "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n## Examples\n\n```rescript\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n## Examples\n\n```rescript\nlet ages = dict{\"Maria\": 30, \"Vinh\": 22, \"Fred\": 49}\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"} }, { "label": "unsafeDeleteKey", "kind": 12, From d5ce578e4f8fc8d346e9e1e3fc40b53a6bf6a773 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 3 Dec 2024 10:51:47 -0300 Subject: [PATCH 04/25] add node runtime tests --- tests/docstrings_examples/DocTest.res | 217 ++++++++++++++++---- tests/docstrings_examples/DocTest.res.mjs | 228 ++++++++++++++++++---- 2 files changed, 369 insertions(+), 76 deletions(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 45f2dfa3c1..544e52c427 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -14,6 +14,8 @@ module Node = { @scope(("process", "stderr")) external stderrWrite: string => unit = "write" @scope("process") external cwd: unit => string = "cwd" + @val @scope("process") + external argv: array = "argv" } module Fs = { @@ -42,9 +44,10 @@ module Node = { external spawnSync: (string, array) => spawnSyncReturns = "spawnSync" type readable - type spawnReturns = {stderr: readable} + type spawnReturns = {stderr: readable, stdout: readable} + type options = {cwd?: string, env?: Dict.t, timeout?: int} @module("child_process") - external spawn: (string, array) => spawnReturns = "spawn" + external spawn: (string, array, ~options: options=?) => spawnReturns = "spawn" @send external on: (readable, string, Buffer.t => unit) => unit = "on" @send @@ -56,6 +59,19 @@ module Node = { @module("os") external tmpdir: unit => string = "tmpdir" } + + module Util = { + type arg = {@as("type") type_: string} + type config = { + args: array, + options: Dict.t, + } + type parsed = { + values: Dict.t, + positionals: array, + } + @module("node:util") external parseArgs: config => parsed = "parseArgs" + } } open Node @@ -64,6 +80,45 @@ module Docgen = RescriptTools.Docgen let bscBin = Path.join(["cli", "bsc"]) +let options = Dict.fromArray([("ignore-runtime-tests", {Util.type_: "string"})]) + +let {Util.values: values} = Util.parseArgs({ + args: Process.argv->Array.sliceToEnd(~start=2), + options, +}) + +let ignoreRuntimeTests = switch values->Dict.get("ignore-runtime-tests") { +| Some(v) => + v + ->String.split(",") + ->Array.map(s => s->String.trim) +| None => [] +} + +module SpawnAsync = { + type t = { + stdout: array, + stderr: array, + code: Null.t, + } + let run = async (~command, ~args, ~options=?) => { + await Promise.make((resolve, _reject) => { + let spawn = ChildProcess.spawn(command, args, ~options?) + let stdout = [] + let stderr = [] + spawn.stdout->ChildProcess.on("data", data => { + Array.push(stdout, data) + }) + spawn.stderr->ChildProcess.on("data", data => { + Array.push(stderr, data) + }) + spawn->ChildProcess.once("close", (code, _signal) => { + resolve({stdout, stderr, code}) + }) + }) + } +} + type example = { id: string, kind: string, @@ -73,7 +128,7 @@ type example = { let createFileInTempDir = id => Path.join2(OS.tmpdir(), id) -let testCode = async (~id, ~code) => { +let compileTest = async (~id, ~code) => { let id = id->String.includes("/") ? String.replace(id, "/", "slash_op") : id let tempFileName = createFileInTempDir(id) @@ -81,27 +136,67 @@ let testCode = async (~id, ~code) => { let args = [tempFileName ++ ".res", "-w", "-3-109"] - let promise = await Promise.make((resolve, _reject) => { - let spawn = ChildProcess.spawn(bscBin, args) - let stderr = [] - spawn.stderr->ChildProcess.on("data", data => { - Array.push(stderr, data) - }) - spawn->ChildProcess.once("close", (_code, _signal) => { - resolve(stderr) - }) - }) + let {stderr, stdout} = await SpawnAsync.run(~command=bscBin, ~args) - switch Array.length(promise) > 0 { + switch Array.length(stderr) > 0 { | true => - promise + stderr ->Array.map(e => e->Buffer.toString) ->Array.join("") ->Error - | false => Ok() + | false => + stdout + ->Array.map(e => e->Buffer.toString) + ->Array.join("") + ->Ok } } +let runtimeTests = async code => { + let {stdout, stderr, code: exitCode} = await SpawnAsync.run( + ~command="node", + ~args=["-e", code], + ~options={ + cwd: Process.cwd(), + timeout: 2000, + }, + ) + + // Some expressions, like, `console.error("error")` is printed to stderr but + // exit code is 0 + let std = switch exitCode->Null.toOption { + | Some(exitCode) if exitCode == 0.0 && Array.length(stderr) > 0 => stderr->Ok + | Some(exitCode) if exitCode == 0.0 => stdout->Ok + | None | Some(_) => Error(Array.length(stderr) > 0 ? stderr : stdout) + } + + switch std { + | Ok(buf) => + buf + ->Array.map(e => e->Buffer.toString) + ->Array.join("") + ->Ok + | Error(buf) => + buf + ->Array.map(e => e->Buffer.toString) + ->Array.join("") + ->Error + } +} + +let indentOutputCode = code => { + let indent = String.repeat(" ", 2) + + code + ->String.split("\n") + ->Array.map(s => `${indent}${s}`) + ->Array.join("\n") +} + +type error = + | ReScript({error: string}) + | Runtime({rescript: string, js: string, error: string}) + let extractDocFromFile = file => { let toolsBin = Path.join([Process.cwd(), "cli", "rescript-tools"]) let spawn = ChildProcess.spawnSync(toolsBin, ["doc", file]) @@ -209,54 +304,90 @@ let main = async () => { await codes ->Array.mapWithIndex(async (code, int) => { let id = `${id}_${Int.toString(int)}` - await testCode(~id, ~code) + (code, await compileTest(~id, ~code)) }) ->Promise.all (example, results) }) ->Promise.all - let errors = results->Belt.Array.keepMap(((example, results)) => { - let errors = results->Belt.Array.keepMap(result => + let examples = results->Array.map(((example, results)) => { + let (compiled, errors) = results->Array.reduce(([], []), (acc, (resCode, result)) => { + let (oks, errors) = acc switch result { - | Ok() => None - | Error(msg) => Some(msg) + | Ok(jsCode) => ([...oks, (resCode, jsCode)], errors) + | Error(output) => (oks, [...errors, ReScript({error: output})]) } - ) - - if Array.length(errors) > 0 { - Some((example, errors)) - } else { - None - } + }) + (example, (compiled, errors)) }) + let exampleErrors = + await examples + ->Array.filter((({id}, _)) => !Array.includes(ignoreRuntimeTests, id)) + ->Array.map(async ((example, (compiled, errors))) => { + let nodeTests = + await compiled + ->Array.map(async ((res, js)) => (res, js, await runtimeTests(js))) + ->Promise.all + + let runtimeErrors = nodeTests->Belt.Array.keepMap(((res, js, output)) => + switch output { + | Ok(_) => None + | Error(error) => Some(Runtime({rescript: res, js, error})) + } + ) + + (example, Array.concat(runtimeErrors, errors)) + }) + ->Promise.all + // Print Errors - let () = errors->Array.forEach(((test, errors)) => { + let () = exampleErrors->Array.forEach(((example, errors)) => { let red = s => `\x1B[1;31m${s}\x1B[0m` let cyan = s => `\x1b[36m${s}\x1b[0m` - let kind = switch test.kind { + let kind = switch example.kind { | "moduleAlias" => "module alias" | other => other } - let errorMessage = - errors - ->Array.map(e => { - // Drop line from path file - e - ->String.split("\n") - ->Array.filterWithIndex((_, i) => i !== 2) - ->Array.join("\n") - }) - ->Array.join("\n") + let errorMessage = errors->Array.map(err => + switch err { + | ReScript({error}) => + let err = + error + ->String.split("\n") + ->Array.filterWithIndex((_, i) => i !== 2) + ->Array.join("\n") + + `${"error"->red}: failed to compile examples from ${kind} ${example.id->cyan} +${err}` + | Runtime({rescript, js, error}) => + let indent = String.repeat(" ", 2) + + `${"runtime error"->red}: failed to run examples from ${kind} ${example.id->cyan} + +${indent}${"ReScript"->cyan} - let message = `${"error"->red}: failed to compile examples from ${kind} ${test.id->cyan}\n${errorMessage}` +${rescript->indentOutputCode} - Process.stderrWrite(message) +${indent}${"Compiled Js"->cyan} + +${js->indentOutputCode} + +${indent}${"stacktrace"->red} + +${error->indentOutputCode} +` + } + ) + + errorMessage->Array.forEach(e => Process.stderrWrite(e)) }) - errors->Array.length == 0 ? 0 : 1 + let someError = exampleErrors->Array.some(((_, err)) => Array.length(err) > 0) + + someError ? 1 : 0 } let exitCode = await main() diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index 1b36292484..ae14e8e22f 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -6,9 +6,11 @@ import * as List from "rescript/lib/es6/List.js"; import * as Path from "path"; import * as $$Array from "rescript/lib/es6/Array.js"; import * as Belt_List from "rescript/lib/es6/Belt_List.js"; +import * as Nodeutil from "node:util"; import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; import * as Pervasives from "rescript/lib/es6/Pervasives.js"; import * as Child_process from "child_process"; +import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; import * as Promises from "node:fs/promises"; import * as RescriptTools_Docgen from "rescript/lib/es6/RescriptTools_Docgen.js"; @@ -26,6 +28,8 @@ let ChildProcess = {}; let OS = {}; +let Util = {}; + let Node = { Path: Path$1, URL: URL, @@ -33,16 +37,58 @@ let Node = { Fs: Fs$1, Buffer: Buffer, ChildProcess: ChildProcess, - OS: OS + OS: OS, + Util: Util }; let bscBin = Path.join("cli", "bsc"); +let options = Object.fromEntries([[ + "ignore-runtime-tests", + { + type: "string" + } + ]]); + +let match = Nodeutil.parseArgs({ + args: process.argv.slice(2), + options: options +}); + +let values = match.values; + +let v = values["ignore-runtime-tests"]; + +let ignoreRuntimeTests = v !== undefined ? v.split(",").map(s => s.trim()) : []; + +async function run(command, args, options) { + return await new Promise((resolve, _reject) => { + let spawn = Child_process.spawn(command, args, options !== undefined ? Primitive_option.valFromOption(options) : undefined); + let stdout = []; + let stderr = []; + spawn.stdout.on("data", data => { + stdout.push(data); + }); + spawn.stderr.on("data", data => { + stderr.push(data); + }); + spawn.once("close", (code, _signal) => resolve({ + stdout: stdout, + stderr: stderr, + code: code + })); + }); +} + +let SpawnAsync = { + run: run +}; + function createFileInTempDir(id) { return Path.join(Os.tmpdir(), id); } -async function testCode(id, code) { +async function compileTest(id, code) { let id$1 = id.includes("/") ? id.replace("/", "slash_op") : id; let tempFileName = Path.join(Os.tmpdir(), id$1); await Promises.writeFile(tempFileName + ".res", code); @@ -51,27 +97,73 @@ async function testCode(id, code) { "-w", "-3-109" ]; - let promise = await new Promise((resolve, _reject) => { - let spawn = Child_process.spawn(bscBin, args); - let stderr = []; - spawn.stderr.on("data", data => { - stderr.push(data); - }); - spawn.once("close", (_code, _signal) => resolve(stderr)); - }); - if (promise.length > 0) { + let match = await run(bscBin, args, undefined); + let stderr = match.stderr; + if (stderr.length > 0) { return { TAG: "Error", - _0: promise.map(e => e.toString()).join("") + _0: stderr.map(e => e.toString()).join("") }; } else { return { TAG: "Ok", - _0: undefined + _0: match.stdout.map(e => e.toString()).join("") }; } } +async function runtimeTests(code) { + let match = await run("node", [ + "-e", + code + ], { + cwd: process.cwd(), + timeout: 2000 + }); + let exitCode = match.code; + let stderr = match.stderr; + let stdout = match.stdout; + let std; + let exit = 0; + if (exitCode == null) { + exit = 1; + } else if (exitCode === 0.0 && stderr.length > 0) { + std = { + TAG: "Ok", + _0: stderr + }; + } else if (exitCode === 0.0) { + std = { + TAG: "Ok", + _0: stdout + }; + } else { + exit = 1; + } + if (exit === 1) { + std = { + TAG: "Error", + _0: stderr.length > 0 ? stderr : stdout + }; + } + if (std.TAG === "Ok") { + return { + TAG: "Ok", + _0: std._0.map(e => e.toString()).join("") + }; + } else { + return { + TAG: "Error", + _0: std._0.map(e => e.toString()).join("") + }; + } +} + +function indentOutputCode(code) { + let indent = " ".repeat(2); + return code.split("\n").map(s => indent + s).join("\n"); +} + function extractDocFromFile(file) { let toolsBin = Path.join(process.cwd(), "cli", "rescript-tools"); let spawn = Child_process.spawnSync(toolsBin, [ @@ -223,42 +315,106 @@ async function main() { let codes = getCodeBlocks(example); let results = await Promise.all(codes.map(async (code, int) => { let id$1 = id + "_" + int.toString(); - return await testCode(id$1, code); + return [ + code, + await compileTest(id$1, code) + ]; })); return [ example, results ]; })); - let errors = Belt_Array.keepMap(results, param => { - let errors = Belt_Array.keepMap(param[1], result => { + let examples = results.map(param => { + let match = $$Array.reduce(param[1], [ + [], + [] + ], (acc, param) => { + let errors = acc[1]; + let oks = acc[0]; + let result = param[1]; if (result.TAG === "Ok") { - return; + return [ + Belt_Array.concatMany([ + oks, + [[ + param[0], + result._0 + ]] + ]), + errors + ]; } else { - return result._0; + return [ + oks, + Belt_Array.concatMany([ + errors, + [{ + TAG: "ReScript", + error: result._0 + }] + ]) + ]; } }); - if (errors.length > 0) { + return [ + param[0], + [ + match[0], + match[1] + ] + ]; + }); + let exampleErrors = await Promise.all(examples.filter(param => !ignoreRuntimeTests.includes(param[0].id)).map(async param => { + let match = param[1]; + let nodeTests = await Promise.all(match[0].map(async param => { + let js = param[1]; return [ param[0], - errors + js, + await runtimeTests(js) ]; - } - - }); - errors.forEach(param => { - let test = param[0]; + })); + let runtimeErrors = Belt_Array.keepMap(nodeTests, param => { + let output = param[2]; + if (output.TAG === "Ok") { + return; + } else { + return { + TAG: "Runtime", + rescript: param[0], + js: param[1], + error: output._0 + }; + } + }); + return [ + param[0], + runtimeErrors.concat(match[1]) + ]; + })); + exampleErrors.forEach(param => { + let example = param[0]; let cyan = s => "\x1b[36m" + s + "\x1b[0m"; - let other = test.kind; + let other = example.kind; let kind = other === "moduleAlias" ? "module alias" : other; - let errorMessage = param[1].map(e => e.split("\n").filter((param, i) => i !== 2).join("\n")).join("\n"); - let message = "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(test.id) + "\n" + errorMessage; - process.stderr.write(message); + let errorMessage = param[1].map(err => { + if (err.TAG === "ReScript") { + let err$1 = err.error.split("\n").filter((param, i) => i !== 2).join("\n"); + return "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(example.id) + "\n" + err$1; + } + let indent = " ".repeat(2); + return "\x1B[1;31mruntime error\x1B[0m: failed to run examples from " + kind + " " + cyan(example.id) + "\n\n" + indent + "\x1b[36mReScript\x1b[0m\n\n" + indentOutputCode(err.rescript) + "\n\n" + indent + "\x1b[36mCompiled Js\x1b[0m\n\n" + indentOutputCode(err.js) + "\n\n" + indent + "\x1B[1;31mstacktrace\x1B[0m\n\n" + indentOutputCode(err.error) + "\n"; + }); + errorMessage.forEach(e => { + process.stderr.write(e); + }); }); - if (errors.length === 0) { - return 0; - } else { + let someError = exampleErrors.some(param => param[1].length > 0); + if (someError) { return 1; + } else { + return 0; } } @@ -272,8 +428,14 @@ export { Node, Docgen, bscBin, + options, + values, + ignoreRuntimeTests, + SpawnAsync, createFileInTempDir, - testCode, + compileTest, + runtimeTests, + indentOutputCode, extractDocFromFile, getExamples, getCodeBlocks, From dd04fec54b96fbef45ba0f6354a16a8596dd3751 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 00:34:32 -0300 Subject: [PATCH 05/25] add more docstrings --- lib/es6/Pervasives.js | 17 + lib/js/Pervasives.js | 17 + runtime/Array.resi | 534 ++++++++++++++-------- runtime/AsyncIterator.resi | 146 +++--- runtime/Dict.resi | 18 +- runtime/Error.resi | 12 +- runtime/Exn.resi | 13 - runtime/Iterator.resi | 36 +- runtime/JSON.resi | 173 ++++--- runtime/List.resi | 23 +- runtime/Map.resi | 20 +- runtime/Null.resi | 13 +- runtime/Nullable.resi | 17 +- runtime/Object.res | 26 +- runtime/Option.resi | 14 +- runtime/Pervasives.res | 64 ++- runtime/Promise.resi | 11 +- runtime/RescriptTools.res | 15 +- runtime/Set.resi | 16 +- runtime/String.resi | 10 +- scripts/test.js | 12 +- tests/docstrings_examples/DocTest.res | 41 +- tests/docstrings_examples/DocTest.res.mjs | 49 +- tests/tests/src/test_pervasive.mjs | 3 +- tests/tests/src/test_pervasives3.mjs | 1 + 25 files changed, 886 insertions(+), 415 deletions(-) diff --git a/lib/es6/Pervasives.js b/lib/es6/Pervasives.js index ee989cf955..932c8dc2b3 100644 --- a/lib/es6/Pervasives.js +++ b/lib/es6/Pervasives.js @@ -1,6 +1,7 @@ import * as $$Error from "./Error.js"; +import * as Primitive_object from "./Primitive_object.js"; import * as Primitive_exceptions from "./Primitive_exceptions.js"; function failwith(s) { @@ -116,6 +117,21 @@ function $at(l1, l2) { } } +function assert_eq(a, b) { + if (!Primitive_object.notequal(a, b)) { + return; + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "Pervasives.res", + 596, + 4 + ], + Error: new Error() + }; +} + let max_int = 2147483647; let infinity = Infinity; @@ -151,5 +167,6 @@ export { int_of_string_opt, $at, panic, + assert_eq, } /* No side effect */ diff --git a/lib/js/Pervasives.js b/lib/js/Pervasives.js index fa6d5f7e68..1b227be7dd 100644 --- a/lib/js/Pervasives.js +++ b/lib/js/Pervasives.js @@ -1,6 +1,7 @@ 'use strict'; let $$Error = require("./Error.js"); +let Primitive_object = require("./Primitive_object.js"); let Primitive_exceptions = require("./Primitive_exceptions.js"); function failwith(s) { @@ -116,6 +117,21 @@ function $at(l1, l2) { } } +function assert_eq(a, b) { + if (!Primitive_object.notequal(a, b)) { + return; + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "Pervasives.res", + 596, + 4 + ], + Error: new Error() + }; +} + let max_int = 2147483647; let infinity = Infinity; @@ -150,4 +166,5 @@ exports.bool_of_string_opt = bool_of_string_opt; exports.int_of_string_opt = int_of_string_opt; exports.$at = $at; exports.panic = panic; +exports.assert_eq = assert_eq; /* No side effect */ diff --git a/runtime/Array.resi b/runtime/Array.resi index 8b57906b27..b47749f988 100644 --- a/runtime/Array.resi +++ b/runtime/Array.resi @@ -1,14 +1,17 @@ /** - `fromIterator(iterator)` +`fromIterator(iterator)` - Creates an array from the provided `iterator` +Creates an array from the provided `iterator` - ```res example - let map = Map.fromArray([("foo", 1), ("bar", 2)]) +## Examples - Array.fromIterator(map->Map.values) // [1, 2] - ``` - */ +```rescript +Map.fromArray([("foo", 1), ("bar", 2)]) +->Map.values +->Array.fromIterator +->assert_eq([1, 2]) +``` +*/ @val external fromIterator: Iterator.t<'a> => array<'a> = "Array.from" @@ -20,24 +23,31 @@ external fromIterator: Iterator.t<'a> => array<'a> = "Array.from" external fromArrayLikeWithMap: (Js.Array2.array_like<'a>, 'a => 'b) => array<'b> = "Array.from" /** - `make(~length, init)` +`make(~length, init)` + +Creates an array of length `length` initialized with the value of `init`. - Creates an array of length `length` initialized with the value of `init`. +## Examples - ```res example - Array.make(~length=3, #apple) == [#apple, #apple, #apple] - ``` +```rescript +Array.make(~length=3, #apple)->assert_eq([#apple, #apple, #apple]) +Array.make(~length=6, 7)->assert_eq([7, 7, 7, 7, 7, 7]) +``` */ let make: (~length: int, 'a) => array<'a> /** - `fromInitializer(~length, f)` +`fromInitializer(~length, f)` + +Creates an array of length `length` initialized with the value returned from `f ` for each index. + +## Examples - Creates an array of length `length` initialized with the value returned from `f ` for each index. +```rescript +Array.fromInitializer(~length=3, i => i + 3)->assert_eq([3, 4, 5]) - ```res example - Array.fromInitializer(~length=3, i => i + 3) == [3, 4, 5] - ``` +Array.fromInitializer(~length=7, i => i + 3)->assert_eq([3, 4, 5, 6, 7, 8, 9]) +``` */ let fromInitializer: (~length: int, int => 'a) => array<'a> @@ -53,10 +63,13 @@ let compare: (array<'a>, array<'a>, ('a, 'a) => Ordering.t) => Ordering.t See [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] -Console.log(someArray->Array.length) // 2 +someArray +->Array.length +->assert_eq(2) ``` */ @get @@ -81,11 +94,11 @@ Beware this will *mutate* the array. See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. ## Examples + ```rescript let myArray = [1, 2, 3, 4] myArray->Array.fillAll(9) - -Console.log(myArray) // [9, 9, 9, 9] +myArray->assert_eq([9, 9, 9, 9]) ``` */ @send @@ -99,11 +112,11 @@ Beware this will *mutate* the array. See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. ## Examples + ```rescript let myArray = [1, 2, 3, 4] myArray->Array.fillToEnd(9, ~start=1) - -Console.log(myArray) // [1, 9, 9, 9] +myArray->assert_eq([1, 9, 9, 9]) ``` */ @send @@ -117,11 +130,13 @@ Beware this will *mutate* the array. See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. ## Examples + ```rescript let myArray = [1, 2, 3, 4] -myArray->Array.fill(9, ~start=1, ~end=2) -Console.log(myArray) // [1, 9, 9, 4] +myArray->Array.fill(9, ~start=1, ~end=3) + +myArray->assert_eq([1, 9, 9, 4]) ``` */ @send @@ -135,11 +150,15 @@ Beware this will *mutate* the array. See [`Array.pop`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] -let lastItem = someArray->Array.pop // "hello" -Console.log(someArray) // ["hi"]. Notice last item is gone. +someArray +->Array.pop +->assert_eq(Some("hello")) + +someArray->assert_eq(["hi"]) // Notice last item is gone. ``` */ @send @@ -153,11 +172,13 @@ Beware this will *mutate* the array. See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] + someArray->Array.push("yay") -Console.log(someArray) // ["hi", "hello", "yay"] +someArray->assert_eq(["hi", "hello", "yay"]) ``` */ @send @@ -171,11 +192,12 @@ Beware this will *mutate* the array. See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] -someArray->Array.pushMany(["yay", "wehoo"]) -Console.log(someArray) // ["hi", "hello", "yay", "wehoo"] +someArray->Array.pushMany(["yay", "wehoo"]) +someArray->assert_eq(["hi", "hello", "yay", "wehoo"]) ``` */ @variadic @@ -190,11 +212,12 @@ Beware this will *mutate* the array. See [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] someArray->Array.reverse -Console.log(someArray) // ["hello", "h1"] +someArray->assert_eq(["hello", "hi"]) ``` */ @send @@ -208,11 +231,15 @@ Beware this will *mutate* the array. See [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] -let lastItem = someArray->Array.shift // "hi" -Console.log(someArray) // ["hello"]. Notice first item is gone. +someArray +->Array.shift +->assert_eq(Some("hi")) + +someArray->assert_eq(["hello"]) // Notice first item is gone. ``` */ @send @@ -224,12 +251,15 @@ external shift: array<'a> => option<'a> = "shift" See [`Array.toSorted`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) on MDN. ## Examples + ```rescript let someArray = [3, 2, 1] -let sorted = someArray->Array.toSorted(Int.compare) -Console.log(sorted) // [1, 2, 3] -Console.log(someArray) // [3, 2, 1]. Original unchanged +someArray +->Array.toSorted(Int.compare) +->assert_eq([1, 2, 3]) + +someArray->assert_eq([3, 2, 1]) // Original unchanged ``` */ @send @@ -243,11 +273,11 @@ Beware this will *mutate* the array. See [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) on MDN. ## Examples -```rescript -let someArray = [3, 2, 1] -someArray->Array.sort((a, b) => float(a - b)) -Console.log(someArray) // [1, 2, 3] +```rescript +let array = [3, 2, 1] +array->Array.sort((a, b) => float(a - b)) +array->assert_eq([1, 2, 3]) ``` */ @send @@ -270,11 +300,11 @@ Beware this will *mutate* the array. See [`Array.unshift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] someArray->Array.unshift("yay") - -Console.log(someArray) // ["yay", "hi", "hello"] +someArray->assert_eq(["yay", "hi", "hello"]) ``` */ @send @@ -288,11 +318,11 @@ Beware this will *mutate* the array. See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] someArray->Array.unshiftMany(["yay", "wehoo"]) - -Console.log(someArray) // ["yay", "wehoo", "hi", "hello"] +someArray->assert_eq(["yay", "wehoo", "hi", "hello"]) ``` */ @variadic @@ -305,13 +335,14 @@ external unshiftMany: (array<'a>, array<'a>) => unit = "unshift" See [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN. ## Examples + ```rescript let array1 = ["hi", "hello"] let array2 = ["yay", "wehoo"] let someArray = array1->Array.concat(array2) -Console.log(someArray) // ["hi", "hello", "yay", "wehoo"] +someArray->assert_eq(["hi", "hello", "yay", "wehoo"]) ``` */ @send @@ -343,8 +374,11 @@ external concatMany: (array<'a>, array>) => array<'a> = "concat" See [`Array.flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) on MDN. ## Examples + ```rescript -Console.log([[1], [2], [3, 4]]->Array.flat) // [1, 2, 3, 4] +[[1], [2], [3, 4]] +->Array.flat +->assert_eq([1, 2, 3, 4]) ``` */ @send @@ -356,10 +390,14 @@ external flat: array> => array<'a> = "flat" See [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN. ## Examples + ```rescript -Console.log([1, 2]->Array.includes(1)) // true -Console.log([1, 2]->Array.includes(3)) // false -Console.log([{"language": "ReScript"}]->Array.includes({"language": "ReScript"})) // false, because of strict equality +[1, 2]->Array.includes(1)->assert_eq(true) +[1, 2]->Array.includes(3)->assert_eq(false) + +[{"language": "ReScript"}] +->Array.includes({"language": "ReScript"}) +->assert_eq(false) // false, because of strict equality ``` */ @send @@ -373,10 +411,14 @@ Returns `-1` if the item doesn not exist. Check out `Array.indexOfOpt` for a ver See [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN. ## Examples + ```rescript -Console.log([1, 2]->Array.indexOf(2)) // 1 -Console.log([1, 2]->Array.indexOf(3)) // -1 -Console.log([{"language": "ReScript"}]->Array.indexOf({"language": "ReScript"})) // -1, because of strict equality +[1, 2]->Array.indexOf(2)->assert_eq(1) +[1, 2]->Array.indexOf(3)->assert_eq(-1) + +[{"language": "ReScript"}] +->Array.indexOf({"language": "ReScript"}) +->assert_eq(-1) // -1, because of strict equality ``` */ @send @@ -388,10 +430,13 @@ external indexOf: (array<'a>, 'a) => int = "indexOf" See [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN. ## Examples + ```rescript -Console.log([1, 2]->Array.indexOfOpt(2)) // Some(1) -Console.log([1, 2]->Array.indexOfOpt(3)) // None -Console.log([{"language": "ReScript"}]->Array.indexOfOpt({"language": "ReScript"})) // None, because of strict equality +[1, 2]->Array.indexOfOpt(2)->assert_eq(Some(1)) +[1, 2]->Array.indexOfOpt(3)->assert_eq(None) +[{"language": "ReScript"}] +->Array.indexOfOpt({"language": "ReScript"}) +->assert_eq(None) // None, because of strict equality ``` */ let indexOfOpt: (array<'a>, 'a) => option @@ -403,10 +448,11 @@ let indexOfOpt: (array<'a>, 'a) => option See [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) ## Examples -```rescript -let array = ["One", "Two", "Three"] -Console.log(array->Array.join(" -- ")) // One -- Two -- Three +```rescript +["One", "Two", "Three"] +->Array.join(" -- ") +->assert_eq("One -- Two -- Three") ``` */ @send @@ -416,10 +462,11 @@ external join: (array, string) => string = "join" `joinWith(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinWithUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items. ## Examples -```rescript -let array = ["One", "Two", "Three"] -Console.log(array->Array.joinWith(" -- ")) // One -- Two -- Three +```rescript +["One", "Two", "Three"] +->Array.joinWith(" -- ") +->assert_eq("One -- Two -- Three") ``` */ @deprecated("Use `join` instead") @@ -432,10 +479,11 @@ external joinWith: (array, string) => string = "join" See [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) ## Examples -```rescript -let array = [1, 2, 3] -Console.log(array->Array.joinUnsafe(" -- ")) // 1 -- 2 -- 3 +```rescript +[1, 2, 3] +->Array.joinUnsafe(" -- ") +->assert_eq("1 -- 2 -- 3") ``` */ @send @@ -445,10 +493,11 @@ external joinUnsafe: (array<'a>, string) => string = "join" `joinWithUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items. ## Examples -```rescript -let array = [1, 2, 3] -Console.log(array->Array.joinWithUnsafe(" -- ")) // 1 -- 2 -- 3 +```rescript +[1, 2, 3] +->Array.joinWithUnsafe(" -- ") +->assert_eq("1 -- 2 -- 3") ``` */ @deprecated("Use `joinUnsafe` instead") @@ -464,10 +513,11 @@ let lastIndexOfOpt: (array<'a>, 'a) => option See [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN. ## Examples -```rescript -let myArray = [1, 2, 3, 4] -Console.log(myArray->Array.slice(~start=1, ~end=3)) // [2, 3] +```rescript +[1, 2, 3, 4] +->Array.slice(~start=1, ~end=3) +->assert_eq([2, 3]) ``` */ @send @@ -479,10 +529,11 @@ external slice: (array<'a>, ~start: int, ~end: int) => array<'a> = "slice" See [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN. ## Examples -```rescript -let myArray = [1, 2, 3, 4] -Console.log(myArray->Array.sliceToEnd(~start=1)) // [2, 3, 4] +```rescript +[1, 2, 3, 4] +->Array.sliceToEnd(~start=1) +->assert_eq([2, 3, 4]) ``` */ @send @@ -491,12 +542,13 @@ external sliceToEnd: (array<'a>, ~start: int) => array<'a> = "slice" `copy(array)` makes a copy of the array with the items in it, but does not make copies of the items themselves. ## Examples + ```rescript let myArray = [1, 2, 3] let copyOfMyArray = myArray->Array.copy -Console.log(copyOfMyArray) // [1, 2, 3] -Console.log(myArray === copyOfMyArray) // false +copyOfMyArray->assert_eq([1, 2, 3]) +assert_eq(myArray === copyOfMyArray, false) ``` */ @send @@ -508,10 +560,11 @@ external copy: array<'a> => array<'a> = "slice" See [`Array.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) on MDN. ## Examples -```rescript -let array = [1, 2, 3, 4] -Console.log(array->Array.toString) // "1,2,3,4" +```rescript +[1, 2, 3, 4] +->Array.toString +->assert_eq("1,2,3,4") ``` */ @send @@ -525,11 +578,17 @@ external toString: array<'a> => string = "toString" See [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN. ## Examples + ```rescript let array = [1, 2, 3, 4] -Console.log(array->Array.every(num => num <= 4)) // true -Console.log(array->Array.every(num => num === 1)) // false +array +->Array.every(num => num <= 4) +->assert_eq(true) + +array +->Array.every(num => num === 1) +->assert_eq(false) ``` */ @send @@ -541,11 +600,17 @@ external every: (array<'a>, 'a => bool) => bool = "every" See [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN. ## Examples + ```rescript let array = [1, 2, 3, 4] -Console.log(array->Array.everyWithIndex((num, index) => index < 2 && num <= 2)) // true -Console.log(array->Array.everyWithIndex((num, index) => index < 2 && num >= 2)) // false +array +->Array.everyWithIndex((num, index) => index < 5 && num <= 4) +->assert_eq(true) + +array +->Array.everyWithIndex((num, index) => index < 2 && num >= 2) +->assert_eq(false) ``` */ @send @@ -557,10 +622,11 @@ external everyWithIndex: (array<'a>, ('a, int) => bool) => bool = "every" See [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN. ## Examples -```rescript -let array = [1, 2, 3, 4] -Console.log(array->Array.filter(num => num > 2)) // [3, 4] +```rescript +[1, 2, 3, 4] +->Array.filter(num => num > 2) +->assert_eq([3, 4]) ``` */ @send @@ -572,10 +638,11 @@ external filter: (array<'a>, 'a => bool) => array<'a> = "filter" See [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN. ## Examples -```rescript -let array = [1, 2, 3, 4] -Console.log(array->Array.filterWithIndex((num, index) => index === 0 || num === 2)) // [1, 2] +```rescript +[1, 2, 3, 4] +->Array.filterWithIndex((num, index) => index === 0 || num === 2) +->assert_eq([1, 2]) ``` */ @send @@ -587,15 +654,15 @@ external filterWithIndex: (array<'a>, ('a, int) => bool) => array<'a> = "filter" See [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN. ## Examples + ```rescript type languages = ReScript | TypeScript | JavaScript let array = [ReScript, TypeScript, JavaScript] -switch array->Array.find(item => item == ReScript) { -| None => Console.log("No item...") -| Some(_) => Console.log("Yay, ReScript!") -} +array +->Array.find(item => item == ReScript) +->assert_eq(Some(ReScript)) ``` */ @send @@ -607,15 +674,15 @@ external find: (array<'a>, 'a => bool) => option<'a> = "find" See [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN. ## Examples + ```rescript type languages = ReScript | TypeScript | JavaScript let array = [TypeScript, JavaScript, ReScript] -switch array->Array.findWithIndex((item, index) => index > 1 && item == ReScript) { -| None => Console.log("No item...") -| Some(_) => Console.log("Yay, ReScript exists in a later position!") -} +array +->Array.findWithIndex((item, index) => index > 1 && item == ReScript) +->assert_eq(Some(ReScript)) ``` */ @send @@ -629,13 +696,18 @@ Returns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. ## Examples + ```rescript type languages = ReScript | TypeScript | JavaScript let array = [ReScript, JavaScript] -Console.log(array->Array.findIndex(item => item == ReScript)) // 0 -Console.log(array->Array.findIndex(item => item == TypeScript)) // -1 +array +->Array.findIndex(item => item == ReScript) +->assert_eq(0) + +array->Array.findIndex(item => item == TypeScript) +->assert_eq(-1) ``` */ @send @@ -649,6 +721,7 @@ Returns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. ## Examples + ```rescript type languages = ReScript | TypeScript | JavaScript @@ -657,8 +730,8 @@ let array = [ReScript, JavaScript] let isReScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == ReScript) let isTypeScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == TypeScript) -Console.log(isReScriptFirst) // 0 -Console.log(isTypeScriptFirst) // -1 +assert_eq(isReScriptFirst, 0) +assert_eq(isTypeScriptFirst, -1) ``` */ @send @@ -687,6 +760,7 @@ external forEach: (array<'a>, 'a => unit) => unit = "forEach" See [`Array.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) on MDN. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] @@ -704,11 +778,12 @@ external forEachWithIndex: (array<'a>, ('a, int) => unit) => unit = "forEach" See [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] let mappedArray = array->Array.map(greeting => greeting ++ " to you") -Console.log(mappedArray) // ["Hello to you", "Hi to you", "Good bye to you"] +assert_eq(mappedArray, ["Hello to you", "Hi to you", "Good bye to you"]) ``` */ @send @@ -720,6 +795,7 @@ external map: (array<'a>, 'a => 'b) => array<'b> = "map" See [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] let mappedArray = @@ -727,55 +803,79 @@ let mappedArray = greeting ++ " at position " ++ Int.toString(index) ) -Console.log(mappedArray) // ["Hello at position 0", "Hi at position 1", "Good bye at position 2"] +assert_eq(mappedArray, ["Hello at position 0", "Hi at position 1", "Good bye at position 2"]) ``` */ @send external mapWithIndex: (array<'a>, ('a, int) => 'b) => array<'b> = "map" /** - `reduce(xs, init, fn)` +`reduce(xs, init, fn)` - Applies `fn` to each element of `xs` from beginning to end. Function `fn` has two parameters: the item from the list and an “accumulator”; which starts with a value of `init`. `reduce` returns the final value of the accumulator. +Applies `fn` to each element of `xs` from beginning to end. Function `fn` has two parameters: the item from the list and an “accumulator”; which starts with a value of `init`. `reduce` returns the final value of the accumulator. - ```res example - Array.reduce([2, 3, 4], 1, (a, b) => a + b) == 10 +## Examples + +```rescript +Array.reduce([2, 3, 4], 1, (a, b) => a + b)->assert_eq(10) + +Array.reduce(["a", "b", "c", "d"], "", (a, b) => a ++ b)->assert_eq("abcd") + +[1, 2, 3] +->Array.reduce(list{}, List.add) +->assert_eq(list{3, 2, 1}) - Array.reduce(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "abcd" - ``` +Array.reduce([], list{}, List.add)->assert_eq(list{}) +``` */ let reduce: (array<'a>, 'b, ('b, 'a) => 'b) => 'b /** - `reduceWithIndex(x, init, fn)` +`reduceWithIndex(x, init, fn)` + +Applies `fn` to each element of `xs` from beginning to end. Function `fn` has three parameters: the item from the array and an “accumulator”, which starts with a value of `init` and the index of each element. `reduceWithIndex` returns the final value of the accumulator. - Applies `fn` to each element of `xs` from beginning to end. Function `fn` has three parameters: the item from the array and an “accumulator”, which starts with a value of `init` and the index of each element. `reduceWithIndex` returns the final value of the accumulator. +## Examples + +```rescript +Array.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i)->assert_eq(16) - ```res example - Array.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16 - ``` +Array.reduceWithIndex([1, 2, 3], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{5, 3, 1}) + +Array.reduceWithIndex([], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{}) +``` */ let reduceWithIndex: (array<'a>, 'b, ('b, 'a, int) => 'b) => 'b /** - `reduceRight(xs, init, fn)` +`reduceRight(xs, init, fn)` + +Works like `Array.reduce`; except that function `fn` is applied to each item of `xs` from the last back to the first. + +## Examples - Works like `Array.reduce`; except that function `fn` is applied to each item of `xs` from the last back to the first. +```rescript +Array.reduceRight(["a", "b", "c", "d"], "", (a, b) => a ++ b)->assert_eq("dcba") + +Array.reduceRight([1, 2, 3], list{}, List.add)->assert_eq(list{1, 2, 3}) - ```res example - Array.reduceRight(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "dcba" - ``` +Array.reduceRight([], list{}, List.add)->assert_eq(list{}) +``` */ let reduceRight: (array<'a>, 'b, ('b, 'a) => 'b) => 'b /** - `reduceRightWithIndex(xs, init, fn)` +`reduceRightWithIndex(xs, init, fn)` - Like `reduceRight`, but with an additional index argument on the callback function. +Like `reduceRight`, but with an additional index argument on the callback function. + +## Examples - ```res example - Array.reduceRightWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16 - ``` +```rescript +Array.reduceRightWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i)->assert_eq(16) + +Array.reduceRightWithIndex([], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{}) +``` */ let reduceRightWithIndex: (array<'a>, 'b, ('b, 'a, int) => 'b) => 'b @@ -785,10 +885,13 @@ let reduceRightWithIndex: (array<'a>, 'b, ('b, 'a, int) => 'b) => 'b See [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] -Console.log(array->Array.some(greeting => greeting === "Hello")) // true +array +->Array.some(greeting => greeting === "Hello") +->assert_eq(true) ``` */ @send @@ -800,10 +903,13 @@ external some: (array<'a>, 'a => bool) => bool = "some" See [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] -Console.log(array->Array.someWithIndex((greeting, index) => greeting === "Hello" && index === 0)) // true +array +->Array.someWithIndex((greeting, index) => greeting === "Hello" && index === 0) +->assert_eq(true) ``` */ @send @@ -815,11 +921,17 @@ external someWithIndex: (array<'a>, ('a, int) => bool) => bool = "some" Returns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] -array->Array.get(0) == Some("Hello") // true -array->Array.get(3) == None // true +array +->Array.get(0) +->assert_eq(Some("Hello")) + +array +->Array.get(3) +->assert_eq(None) ``` */ @get_index @@ -831,11 +943,12 @@ external get: (array<'a>, int) => option<'a> = "" Beware this will *mutate* the array. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] array->Array.set(1, "Hello") -Console.log(array[1]) // "Hello" +array[1]->assert_eq(Some("Hello")) ``` */ @set_index @@ -870,6 +983,7 @@ This is _unsafe_, meaning it will return `undefined` value if `index` does not e Use `Array.unsafe_get` only when you are sure the `index` exists (i.e. when using for-loop). ## Examples + ```rescript let array = [1, 2, 3] for index in 0 to array->Array.length - 1 { @@ -887,11 +1001,12 @@ external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" Beware this will *mutate* the array, and is *unsafe*. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] array->Array.setUnsafe(1, "Hello") -Console.log(array[1]) // "Hello" +assert_eq(array[1], Some("Hello")) ``` */ external setUnsafe: (array<'a>, int, 'a) => unit = "%array_unsafe_set" @@ -904,15 +1019,15 @@ Returns `None` if no item matches. See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. ## Examples + ```rescript type languages = ReScript | TypeScript | JavaScript let array = [ReScript, TypeScript, JavaScript] -switch array->Array.findIndexOpt(item => item == ReScript) { -| None => Console.log("Ahh, no ReScript...") -| Some(index) => Console.log("Yay, ReScript at index " ++ Int.toString(index)) -} +array +->Array.findIndexOpt(item => item == ReScript) +->assert_eq(Some(0)) ``` */ let findIndexOpt: (array<'a>, 'a => bool) => option @@ -923,12 +1038,13 @@ let findIndexOpt: (array<'a>, 'a => bool) => option See [`Array.toReversed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) on MDN. ## Examples + ```rescript let someArray = ["hi", "hello"] let reversed = someArray->Array.toReversed -Console.log(reversed) // ["hello", "h1"] -Console.log(someArray) // ["h1", "hello"]. Original unchanged +reversed->assert_eq(["hello", "hi"]) +someArray->assert_eq(["h1", "hello"]) // Original unchanged ``` */ @send @@ -940,30 +1056,45 @@ external toReversed: array<'a> => array<'a> = "toReversed" Calls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`. ## Examples + ```rescript -let array = ["Hello", "Hi", "Good bye"] +["Hello", "Hi", "Good bye"] +->Array.filterMap(item => + switch item { + | "Hello" => Some(item->String.length) + | _ => None + } +) +->assert_eq([5]) + +[1, 2, 3, 4, 5, 6] +->Array.filterMap(n => mod(n, 2) == 0 ? Some(n * n) : None) +->assert_eq([4, 16, 36]) -Console.log( - array->Array.filterMap(item => - switch item { - | "Hello" => Some(item->String.length) - | _ => None - } - ), -) // [5] +Array.filterMap([1, 2, 3, 4, 5, 6], _ => None)->assert_eq([]) + +Array.filterMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assert_eq([]) ``` */ let filterMap: (array<'a>, 'a => option<'b>) => array<'b> /** - `keepSome(arr)` +`keepSome(arr)` + +Returns a new array containing `value` for all elements that are `Some(value)` +and ignoring every value that is `None` - Returns a new array containing `value` for all elements that are `Some(value)` - and ignoring every value that is `None` +## Examples + +```rescript +Array.keepSome([Some(1), None, Some(3)])->assert_eq([1, 3]) + +Array.keepSome([Some(1), Some(2), Some(3)])->assert_eq([1, 2, 3]) + +Array.keepSome([None, None, None])->assert_eq([]) - ```res example - Array.keepSome([Some(1), None, Some(3)]) == [1, 3] - ``` +Array.keepSome([])->assert_eq([]) +``` */ let keepSome: array> => array<'a> @@ -971,11 +1102,15 @@ let keepSome: array> => array<'a> `toShuffled(array)` returns a new array with all items in `array` in a random order. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] let shuffledArray = array->Array.toShuffled - Console.log(shuffledArray) + +Array.toShuffled([1, 2, 3]) +->Array.length +->assert_eq(3) ``` */ let toShuffled: array<'a> => array<'a> @@ -986,11 +1121,18 @@ let toShuffled: array<'a> => array<'a> Beware this will *mutate* the array. ## Examples + ```rescript let array = ["Hello", "Hi", "Good bye"] array->Array.shuffle - Console.log(array) + +let array2 = [1, 2, 3] +array2->Array.shuffle + +array2 +->Array.length +->assert_eq(3) ``` */ let shuffle: array<'a> => unit @@ -999,21 +1141,21 @@ let shuffle: array<'a> => unit `flatMap(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`. ## Examples + ```rescript type language = ReScript | TypeScript | JavaScript let array = [ReScript, TypeScript, JavaScript] -Console.log( - array->Array.flatMap(item => - switch item { - | ReScript => [1, 2, 3] - | TypeScript => [4, 5, 6] - | JavaScript => [7, 8, 9] - } - ), +array +->Array.flatMap(item => + switch item { + | ReScript => [1, 2, 3] + | TypeScript => [4, 5, 6] + | JavaScript => [7, 8, 9] + } ) -// [1, 2, 3, 4, 5, 6, 7, 8, 9] +->assert_eq([1, 2, 3, 4, 5, 6, 7, 8, 9]) ``` */ @send @@ -1023,52 +1165,62 @@ external flatMap: (array<'a>, 'a => array<'b>) => array<'b> = "flatMap" `flatMapWithIndex(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`. ## Examples + ```rescript type language = ReScript | TypeScript | JavaScript let array = [ReScript, TypeScript, JavaScript] -Console.log( - array->Array.flatMapWithIndex((item, index) => - switch item { - | ReScript => [index] - | TypeScript => [index, index + 1] - | JavaScript => [index, index + 1, index + 2] - } - ), + +array +->Array.flatMapWithIndex((item, index) => + switch item { + | ReScript => [index] + | TypeScript => [index, index + 1] + | JavaScript => [index, index + 1, index + 2] + } ) -// [0, 1, 2, 2, 3, 4] +->assert_eq([0, 1, 2, 2, 3, 4]) ``` */ @send external flatMapWithIndex: (array<'a>, ('a, int) => array<'b>) => array<'b> = "flatMap" /** - `findMap(arr, fn)` +`findMap(arr, fn)` + +Calls `fn` for each element and returns the first value from `fn` that is `Some(_)`. +Otherwise returns `None` - Calls `fn` for each element and returns the first value from `fn` that is `Some(_)`. - Otherwise returns `None` +## Examples + +```rescript +Array.findMap([1, 2, 3], n => mod(n, 2) == 0 ? Some(n - 2) : None)->assert_eq(Some(0)) - ```res example - Array.findMap([1, 2, 3], n => mod(n, 2) == 0 ? Some(n - 2) : None) == Some(0) // true - ``` +Array.findMap([1, 2, 3, 4, 5, 6], n => mod(n, 2) == 0 ? Some(n - 8) : None)->assert_eq(Some(-6)) + +Array.findMap([1, 2, 3, 4, 5, 6], _ => None)->assert_eq(None) + +Array.findMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assert_eq(None) +``` */ let findMap: (array<'a>, 'a => option<'b>) => option<'b> /** - `at(array, index)` +`at(array, index)` - Get an element by its index. Negative indices count backwards from the last item. +Get an element by its index. Negative indices count backwards from the last item. + +## Examples - ## Examples - ```rescript - ["a", "b", "c"]->Array.at(0) // Some("a") - ["a", "b", "c"]->Array.at(2) // Some("c") - ["a", "b", "c"]->Array.at(3) // None - ["a", "b", "c"]->Array.at(-1) // Some("c") - ["a", "b", "c"]->Array.at(-3) // Some("a") - ["a", "b", "c"]->Array.at(-4) // None - ``` +```rescript +["a", "b", "c"]->Array.at(0)->assert_eq(Some("a")) +["a", "b", "c"]->Array.at(2)->assert_eq(Some("c")) +["a", "b", "c"]->Array.at(3)->assert_eq(None) +["a", "b", "c"]->Array.at(-1)->assert_eq(Some("c")) +["a", "b", "c"]->Array.at(-3)->assert_eq(Some("a")) +["a", "b", "c"]->Array.at(-4)->assert_eq(None) +``` */ @send external at: (array<'a>, int) => option<'a> = "at" @@ -1079,11 +1231,15 @@ external at: (array<'a>, int) => option<'a> = "at" Returns `None` if the array is empty. ## Examples + ```rescript -let array = ["Hello", "Hi", "Good bye"] +["Hello", "Hi", "Good bye"] +->Array.last +->assert_eq(Some("Good bye")) -array->Array.last == Some("Good bye") // true -[]->Array.last == None // true +[] +->Array.last +->assert_eq(None) ``` */ let last: array<'a> => option<'a> diff --git a/runtime/AsyncIterator.resi b/runtime/AsyncIterator.resi index bbe8de3b09..ccebf21f9e 100644 --- a/runtime/AsyncIterator.resi +++ b/runtime/AsyncIterator.resi @@ -20,59 +20,64 @@ type value<'a> = { } /** - `make(nextFn)` +`make(nextFn)` - Creates an async iterator from a function that returns the next value of the iterator. +Creates an async iterator from a function that returns the next value of the iterator. - ## Examples - - A simple example, creating an async iterator that returns 1, 2, 3: - ```rescript - let context = ref(0) +## Examples - let asyncIterator = AsyncIterator.make(async () => { - let currentValue = context.contents - // Increment current value - context := currentValue + 1 - - { - AsyncIterator.value: Some(currentValue), - done: currentValue >= 3 - } - }) +- A simple example, creating an async iterator that returns 1, 2, 3: - // This will log 1, 2, 3 - await asyncIterator->AsyncIterator.forEach(value => - switch value { - | Some(value) => Console.log(value) - | None => () - } - ) - ``` - */ +```rescript +let context = ref(0) + +let asyncIterator = AsyncIterator.make(async () => { + let currentValue = context.contents + // Increment current value + context := currentValue + 1 + + { + AsyncIterator.value: Some(currentValue), + done: currentValue >= 3 + } +}) + +// This will log 1, 2, 3 +let main = async () => await asyncIterator->AsyncIterator.forEach(value => + switch value { + | Some(value) => Console.log(value) + | None => () + } +) + +main()->ignore +``` +*/ let make: (unit => promise>) => t<'value> /** - `value(value)` +`value(value)` - Shorthand for creating a value object with the provided value, and the `done` property set to false. +Shorthand for creating a value object with the provided value, and the `done` property set to false. - ## Examples - ```rescript - let context = ref(0) +## Examples - let asyncIterator = AsyncIterator.make(async () => { - let currentValue = context.contents - // Increment current value - context := currentValue + 1 - - if currentValue >= 3 { - AsyncIterator.done() - } else { - AsyncIterator.value(currentValue) - } - }) - ``` - */ +```rescript +let context = ref(0) + +let asyncIterator = AsyncIterator.make(async () => { + let currentValue = context.contents + // Increment current value + context := currentValue + 1 + + if currentValue >= 3 { + AsyncIterator.done() + } else { + AsyncIterator.value(currentValue) + } +}) +``` +*/ let value: 'value => value<'value> /** @@ -107,17 +112,21 @@ Returns the next value of the iterator, if any. See [async iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols) on MDN. ## Examples + - A simple example, getting the next value: -```rescript -@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" -let value = await asyncIterator->AsyncIterator.next -``` -- Complete example, including looping over all values: ```rescript -// Let's pretend we get an async iterator returning ints from somewhere. -@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" +let asyncIterator: AsyncIterator.t<(string, string)> = %raw(` + (() => { + var map1 = new Map(); + + map1.set('first', '1'); + map1.set('second', '2'); + var iterator1 = map1[Symbol.iterator](); + return iterator1; + })() +`) let processMyAsyncIterator = async () => { // ReScript doesn't have `for ... of` loops, but it's easy to mimic using a while loop. @@ -130,10 +139,15 @@ let processMyAsyncIterator = async () => { // Exit the while loop if the iterator says it's done break := done - // This will log the (int) value of the current async iteration, if a value was returned. - Console.log(value) + if done { + value + ->Option.isNone + ->assert_eq(true) + } } } + +processMyAsyncIterator()->ignore ``` */ @send @@ -145,16 +159,30 @@ external next: t<'a> => promise> = "next" See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. ## Examples + ```rescript // Let's pretend we get an async iterator returning ints from somewhere. -@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" +let asyncIterator: AsyncIterator.t<(string, string)> = %raw(` + (() => { + var map1 = new Map(); + + map1.set('first', '1'); + map1.set('second', '2'); + + var iterator1 = map1[Symbol.iterator](); + return iterator1; + })() +`) + +let main = async () => + await asyncIterator->AsyncIterator.forEach(v => { + switch v { + | Some(("second", value)) => assert_eq(value, "2") + | _ => () + } + }) -await asyncIterator->AsyncIterator.forEach(value => - switch value { - | Some(value) if value > 10 => Console.log("More than 10!") - | _ => () - } -) +main()->ignore ``` */ let forEach: (t<'a>, option<'a> => unit) => promise diff --git a/runtime/Dict.resi b/runtime/Dict.resi index 77bb7e6d72..2a1baca699 100644 --- a/runtime/Dict.resi +++ b/runtime/Dict.resi @@ -95,11 +95,21 @@ external fromArray: array<(string, 'a)> => dict<'a> = "Object.fromEntries" `fromIterator(entries)` creates a new dictionary from the provided iterator of key/value pairs. ## Examples -```rescript -// Pretend we have an iterator of the correct shape -@val external someIterator: Iterator.t<(string, int)> = "someIterator" -let dict = Dict.fromIterator(someIterator) // dict +```rescript +let iterator: Iterator.t<(string, int)> = %raw(` + (() => { + var map1 = new Map(); + map1.set('first', 1); + map1.set('second', 2); + var iterator1 = map1[Symbol.iterator](); + return iterator1; + })() +`) +iterator +->Dict.fromIterator +->Dict.valuesToArray +->assert_eq([1, 2]) ``` */ @val diff --git a/runtime/Error.resi b/runtime/Error.resi index 21ce6da011..8636a9c4ee 100644 --- a/runtime/Error.resi +++ b/runtime/Error.resi @@ -165,8 +165,18 @@ handled. Compared to a ReScript exception this will give a better stack trace an debugging experience. ## Examples + ```rescript -Error.panic("Uh oh. This was unexpected!") +try { + Error.panic("Uh oh. This was unexpected!") +} catch { +| Exn.Error(obj) => + switch Exn.message(obj) { + | Some(m) => assert(m == "Panic! Uh oh. This was unexpected!") + | None => assert(false) + } +| _ => assert(false) +} ``` */ let panic: string => 'a diff --git a/runtime/Exn.resi b/runtime/Exn.resi index b8c5d7077b..e8dc04855b 100644 --- a/runtime/Exn.resi +++ b/runtime/Exn.resi @@ -48,19 +48,6 @@ that potentially is either exn, a JS error, or any other JS value really (e.g. f a value passed to a Promise.catch callback) **IMPORTANT**: This is an internal API and may be changed / removed any time in the future. - -## Examples - -```rescript -switch (Js.Exn.anyToExnInternal("test")) { -| Js.Exn.Error(v) => - switch(Js.Exn.message(v)) { - | Some(_) => Js.log("We won't end up here") - | None => Js.log2("We will land here: ", v) - } -| _ => assert(false) -} -``` */ external anyToExnInternal: 'a => exn = "%wrap_exn" diff --git a/runtime/Iterator.resi b/runtime/Iterator.resi index 300d4fca7b..516bbdf03c 100644 --- a/runtime/Iterator.resi +++ b/runtime/Iterator.resi @@ -29,11 +29,17 @@ Returns the next value of the iterator, if any. See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. ## Examples -```rescript -@val external someIterator: Iterator.t = "someIterator" -// Pulls out the next value of the iterator -let {Iterator.done, value} = someIterator->Iterator.next +```rescript +let iterator: Iterator.t = %raw(` + (() => { + var array1 = ['a']; + var iterator1 = array1[Symbol.iterator](); + return iterator1 + })() +`) +(iterator->Iterator.next).done->assert_eq(false) +(iterator->Iterator.next).done->assert_eq(true) ``` */ @send @@ -88,14 +94,22 @@ See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript ## Examples ```rescript -@val external someIterator: Iterator.t = "someIterator" - -someIterator->Iterator.forEach(value => - switch value { - | Some(value) if value > 10 => Console.log("More than 10!") - | _ => () +let iterator: Iterator.t = %raw(` + (() => { + var array1 = ['a', 'b', 'c']; + var iterator1 = array1[Symbol.iterator](); + return iterator1 + })() +`) +iterator->Iterator.forEach(v => { + switch v { + | Some("a" | "b" | "c") => assert(true) + | other => + other + ->Option.isNone + ->assert_eq(true) } -) +}) ``` */ let forEach: (t<'a>, option<'a> => unit) => unit diff --git a/runtime/JSON.resi b/runtime/JSON.resi index 02f8b8793f..c282ca9ff6 100644 --- a/runtime/JSON.resi +++ b/runtime/JSON.resi @@ -297,7 +297,7 @@ JSON.stringifyWithFilterAndIndent(json, ["foo", "someNumber"], 2) external stringifyWithFilterAndIndent: (t, array, int) => string = "JSON.stringify" /** -`stringifyAny(any, ~replacer=?, ~space=?)` +`stringifyAny(any, ~replacer=?, ~space=?)` Converts any type to a JSON string. The replacer describes how the value should be transformed. It is a function which receives a key and a value. @@ -306,6 +306,7 @@ If the value contains circular references or `BigInt`s, the function will throw If you want to stringify a JSON object, use `JSON.stringify` instead. ## Examples + ```rescript let dict = Dict.fromArray([ ("foo", JSON.Encode.string("bar")), @@ -313,18 +314,24 @@ let dict = Dict.fromArray([ ("someNumber", JSON.Encode.int(42)), ]) -JSON.stringifyAny(dict) -// {"foo":"bar","hello":"world","someNumber":42} - -JSON.stringifyAny(dict, ~space=2) -// { -// "foo": "bar", -// "hello": "world", -// "someNumber": 42 -// } - -JSON.stringifyAny(dict, ~replacer=Keys(["foo", "someNumber"])) -// {"foo":"bar","someNumber":42} +dict +->JSON.stringifyAny +->Option.getUnsafe +->assert_eq(`{"foo":"bar","hello":"world","someNumber":42}`) + +dict +->JSON.stringifyAny(~space=2) +->Option.getUnsafe +->assert_eq(`{ + "foo": "bar", + "hello": "world", + "someNumber": 42 +}`) + +dict +->JSON.stringifyAny(~replacer=Keys(["foo", "someNumber"])) +->Option.getUnsafe +->assert_eq(`{"foo":"bar","someNumber":42}`) let replacer = JSON.Replacer((_, value) => { let decodedValue = value->JSON.Decode.string @@ -335,17 +342,22 @@ let replacer = JSON.Replacer((_, value) => { } }) -JSON.stringifyAny(dict, ~replacer) -// {"foo":"BAR","hello":"WORLD","someNumber":42} +dict +->JSON.stringifyAny(~replacer) +->Option.getUnsafe +->assert_eq(`{"foo":"BAR","hello":"WORLD","someNumber":42}`) JSON.stringifyAny(() => "hello world") -// None +->assert_eq(None) -BigInt.fromInt(0)->JSON.stringifyAny -// exception +// Raise a exception +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` -## Exceptions +## Exceptions - Raises a TypeError if the value contains circular references. - Raises a TypeError if the value contains `BigInt`s. @@ -356,7 +368,7 @@ external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => optionJSON.stringifyAnyWithIndent(2) +->Option.getUnsafe +->assert_eq(`{ + "foo": "bar", + "hello": "world", + "someNumber": 42 +}`) -JSON.stringifyAny(() => "hello world") -// None +JSON.stringifyAny(() => "hello world")->assert_eq(None) -BigInt.fromInt(0)->JSON.stringifyAny -// exception +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` ## Exceptions @@ -421,17 +437,20 @@ let replacer = (_, value) => { } } -JSON.stringifyAnyWithReplacer(dict, replacer) -// {"foo":"BAR","hello":"WORLD","someNumber":42} +dict +->JSON.stringifyAnyWithReplacer(replacer) +->Option.getUnsafe +->assert_eq(`{"foo":"BAR","hello":"WORLD","someNumber":42}`) -JSON.stringifyAny(() => "hello world") -// None +JSON.stringifyAny(() => "hello world")->assert_eq(None) -BigInt.fromInt(0)->JSON.stringifyAny -// exception +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` -## Exceptions +## Exceptions - Raises a TypeError if the value contains circular references. - Raises a TypeError if the value contains `BigInt`s. @@ -442,7 +461,7 @@ BigInt.fromInt(0)->JSON.stringifyAny external stringifyAnyWithReplacer: ('a, (string, t) => t) => option = "JSON.stringify" /** -`stringifyAnyWithReplacerAndIndent(json, replacer, indentation)` +`stringifyAnyWithReplacerAndIndent(json, replacer, indentation)` Converts any type to a JSON string. The output will be indented. The replacer describes how the value should be transformed. It is a function which receives a key and a value. @@ -451,6 +470,7 @@ If the value contains circular references or `BigInt`s, the function will throw If you want to stringify a JSON object, use `JSON.stringifyWithReplacerAndIndent` instead. ## Examples + ```rescript let dict = Dict.fromArray([ ("foo", JSON.Encode.string("bar")), @@ -467,18 +487,17 @@ let replacer = (_, value) => { } } -JSON.stringifyAnyWithReplacerAndIndent(dict, replacer, 2) -// { -// "foo": "BAR", -// "hello": "WORLD", -// "someNumber": 42 -// } +dict +->JSON.stringifyAnyWithReplacer(replacer) +->Option.getUnsafe +->assert_eq(`{"foo":"BAR","hello":"WORLD","someNumber":42}`) -JSON.stringifyAny(() => "hello world") -// None +JSON.stringifyAny(() => "hello world")->assert_eq(None) -BigInt.fromInt(0)->JSON.stringifyAny -// exception +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` ## Exceptions @@ -493,7 +512,7 @@ external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => optio "JSON.stringify" /** -`stringifyAnyWithFilter(json, filter)` +`stringifyAnyWithFilter(json, filter)` Converts any type to a JSON string. The filter is an array of keys, which should be included in the output. @@ -502,6 +521,7 @@ If the value contains circular references or `BigInt`s, the function will throw If you want to stringify a JSON object, use `JSON.stringifyWithFilter` instead. ## Examples + ```rescript let dict = Dict.fromArray([ ("foo", JSON.Encode.string("bar")), @@ -509,17 +529,19 @@ let dict = Dict.fromArray([ ("someNumber", JSON.Encode.int(42)), ]) -JSON.stringifyAnyWithFilter(dict, ["foo", "someNumber"]) -// {"foo": "bar","someNumber": 42} +dict +->JSON.stringifyAnyWithFilter(["foo", "someNumber"]) +->assert_eq(`{"foo":"bar","someNumber":42}`) -JSON.stringifyAny(() => "hello world") -// None +JSON.stringifyAny(() => "hello world")->assert_eq(None) -BigInt.fromInt(0)->JSON.stringifyAny -// exception +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` -## Exceptions +## Exceptions - Raises a TypeError if the value contains circular references. - Raises a TypeError if the value contains `BigInt`s. @@ -530,7 +552,7 @@ BigInt.fromInt(0)->JSON.stringifyAny external stringifyAnyWithFilter: ('a, array) => string = "JSON.stringify" /** -`stringifyAnyWithFilterAndIndent(json, filter, indentation)` +`stringifyAnyWithFilterAndIndent(json, filter, indentation)` Converts any type to a JSON string. The output will be indented. The filter is an array of keys, which should be included in the output. @@ -539,6 +561,7 @@ If the value contains circular references or `BigInt`s, the function will throw If you want to stringify a JSON object, use `JSON.stringifyWithFilterAndIndent` instead. ## Examples + ```rescript let dict = Dict.fromArray([ ("foo", JSON.Encode.string("bar")), @@ -546,17 +569,31 @@ let dict = Dict.fromArray([ ("someNumber", JSON.Encode.int(42)), ]) -JSON.stringifyAnyWithFilterAndIndent(dict, ["foo", "someNumber"], 2) -// { -// "foo": "bar", -// "someNumber": 42 -// } - -JSON.stringifyAny(() => "hello world") -// None - -BigInt.fromInt(0)->JSON.stringifyAny -// exception +dict +->JSON.stringifyAny +->Option.getUnsafe +->assert_eq(`{"foo":"bar","hello":"world","someNumber":42}`) + +dict +->JSON.stringifyAny(~space=2) +->Option.getUnsafe +->assert_eq(`{ + "foo": "bar", + "hello": "world", + "someNumber": 42 +}`) + +dict +->JSON.stringifyAny(~replacer=Keys(["foo", "someNumber"])) +->Option.getUnsafe +->assert_eq(`{"foo":"bar","someNumber":42}`) + +JSON.stringifyAny(() => "hello world")->assert_eq(None) + +switch BigInt.fromInt(0)->JSON.stringifyAny { +| exception _ => assert(true) +| _ => assert(false) +} ``` ## Exceptions diff --git a/runtime/List.resi b/runtime/List.resi index 095a31d693..973d130499 100644 --- a/runtime/List.resi +++ b/runtime/List.resi @@ -75,9 +75,12 @@ let head: t<'a> => option<'a> ## Examples ```rescript -List.headExn(list{1, 2, 3}) // 1 +List.headExn(list{1, 2, 3})->assert_eq(1) -List.headExn(list{}) // Raises an Error +switch List.headExn(list{}) { +| exception Not_found => assert(true) +| _ => assert(false) +} ``` ## Exceptions @@ -107,9 +110,12 @@ let tail: t<'a> => option> ## Examples ```rescript -List.tailExn(list{1, 2, 3}) // list{2, 3} +List.tailExn(list{1, 2, 3})->assert_eq(list{2, 3}) -List.tailExn(list{}) // Raises an Error +switch List.tailExn(list{}) { +| exception Not_found => assert(true) +| _ => assert(false) +} ``` ## Exceptions @@ -155,9 +161,14 @@ let get: (t<'a>, int) => option<'a> ```rescript let abc = list{"A", "B", "C"} -abc->List.getExn(1) // "B" +abc +->List.getExn(1) +->assert_eq("B") -abc->List.getExn(4) // Raises an Error +switch abc->List.getExn(4) { +| exception Not_found => assert(true) +| _ => assert(false) +} ``` ## Exceptions diff --git a/runtime/Map.resi b/runtime/Map.resi index f1067a8abb..6afeeed23f 100644 --- a/runtime/Map.resi +++ b/runtime/Map.resi @@ -56,11 +56,25 @@ external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" Turns an iterator in the shape of `('key, 'value)` into a `Map`. ## Examples + ```rescript // Let's pretend we have an interator in the correct shape -@val external someIterator: Iterator.t<(string, int)> = "someIterator" - -let map = Map.fromIterator(someIterator) // Map.t +let iterator: Iterator.t<(string, string)> = %raw(` + (() => { + var map1 = new Map(); + + map1.set('first', '1'); + map1.set('second', '2'); + + var iterator1 = map1[Symbol.iterator](); + return iterator1; + })() +`) + +iterator +->Map.fromIterator +->Map.size +->assert_eq(2) ``` */ @new diff --git a/runtime/Null.resi b/runtime/Null.resi index 7d3f6a22fc..5da278ffd9 100644 --- a/runtime/Null.resi +++ b/runtime/Null.resi @@ -105,8 +105,17 @@ let getWithDefault: (t<'a>, 'a) => 'a `getExn(value)` raises an exception if `null`, otherwise returns the value. ```rescript -Null.getExn(Null.make(3)) // 3 -Null.getExn(Null.null) /* Raises an Error */ +Null.getExn(Null.make(3))->assert_eq(3) + +switch Null.getExn(%raw("'ReScript'")) { +| exception Invalid_argument(_) => assert(false) +| value => assert_eq(value, "ReScript") +} + +switch Null.getExn(%raw("null")) { +| exception Invalid_argument(_) => assert(true) +| _ => assert(false) +} ``` ## Exceptions diff --git a/runtime/Nullable.resi b/runtime/Nullable.resi index 30d92195e6..1e388aa83f 100644 --- a/runtime/Nullable.resi +++ b/runtime/Nullable.resi @@ -137,8 +137,21 @@ let getWithDefault: (t<'a>, 'a) => 'a `getExn(value)` raises an exception if `null` or `undefined`, otherwise returns the value. ```rescript -Nullable.getExn(Nullable.make(3)) // 3 -Nullable.getExn(Nullable.null) /* Raises an Error */ +switch Nullable.getExn(%raw("'Hello'")) { +| exception Invalid_argument(_) => assert(false) +| value => assert_eq(value, "Hello") +} + +switch Nullable.getExn(%raw("null")) { +| exception Invalid_argument(_) => assert(true) +| _ => assert(false) +} + +// TODO(aspeddro): This example dont pass +// switch Nullable.getExn(%raw("undefined")) { +// | exception Invalid_argument(_) => assert(true) +// | _ => assert(false) +// } ``` ## Exceptions diff --git a/runtime/Object.res b/runtime/Object.res index 434621df86..6646088c0a 100644 --- a/runtime/Object.res +++ b/runtime/Object.res @@ -186,7 +186,14 @@ See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundam let point = {"x": 1, "y": 2} point->Object.set("x", -7) // succeeds point->Object.seal->ignore -point->Object.set("z", 9) // fails + +try { + point->Object.set("z", 9) // fails +} catch { +| Exn.Error(_) => assert(true) +| _ => assert(false) +} + point->Object.set("x", 13) // succeeds ``` */ @@ -204,7 +211,12 @@ See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundam let obj = {"a": 1} obj->Object.set("b", 2) // succeeds obj->Object.preventExtensions->ignore -obj->Object.set("c", 3) // fails +try { + obj->Object.set("c", 3) // fails +} catch { +| Exn.Error(_) => assert(true) +| _ => assert(false) +} ``` */ @val @@ -219,11 +231,17 @@ See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundam ## Examples - ```rescript +```rescript let obj = {"a": 1} obj->Object.set("a", 2) // succeeds obj->Object.freeze->ignore -obj->Object.set("a", 3) // fails + +try { + obj->Object.set("a", 3) // fails +} catch { +| Exn.Error(_) => assert(true) +| _ => assert(false) +} ``` */ @val diff --git a/runtime/Option.resi b/runtime/Option.resi index 16efdba52c..896a3ebc13 100644 --- a/runtime/Option.resi +++ b/runtime/Option.resi @@ -69,9 +69,17 @@ let forEach: (option<'a>, 'a => unit) => unit `getExn(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception with the message provided, or a generic message if no message was provided. ```rescript -Option.getExn(Some(3)) // 3 -Option.getExn(None) /* Raises an Error */ -Option.getExn(None, ~message="was None!") /* Raises an Error with the message "was None!" */ +Option.getExn(Some(3))->assert_eq(3) + +switch Option.getExn(None) { +| exception _ => assert(true) +| _ => assert(false) +} + +switch Option.getExn(None, ~message="was None!") { +| exception _ => assert(true) // Raises an Error with the message "was None!" +| _ => assert(false) +} ``` ## Exceptions diff --git a/runtime/Pervasives.res b/runtime/Pervasives.res index a19348538d..adcea07610 100644 --- a/runtime/Pervasives.res +++ b/runtime/Pervasives.res @@ -337,11 +337,12 @@ type timeoutId = Js_global.timeoutId See [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) on MDN. ## Examples + ```rescript -// Log to the console after 2 seconds (2000 milliseconds). +// Log to the console after 200 milliseconds. let timeoutId = setTimeout(() => { - Console.log("This prints in 2 seconds.") -}, 2000) + Console.log("This prints in 200 ms.") +}, 200) ``` */ @val @@ -355,11 +356,12 @@ The same as `setTimeout`, but allows you to pass a `float` instead of an `int` f See [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) on MDN. ## Examples + ```rescript -// Log to the console after 2 seconds (2000 milliseconds). +// Log to the console after 200 milliseconds. let timeoutId = setTimeoutFloat(() => { - Console.log("This prints in 2 seconds.") -}, 2000.) + Console.log("This prints in 200 ms.") +}, 200.) ``` */ @val @@ -371,6 +373,7 @@ external setTimeoutFloat: (unit => unit, float) => timeoutId = "setTimeout" See [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) on MDN. ## Examples + ```rescript let timeoutId = setTimeout(() => { Console.log("This prints in 2 seconds.") @@ -396,11 +399,16 @@ type intervalId = Js_global.intervalId See [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) on MDN. ## Examples + ```rescript -// Log to the console ever 2 seconds (2000 milliseconds). +// Log to the console ever 200 ms (200 milliseconds). let intervalId = setInterval(() => { - Console.log("This prints every 2 seconds.") -}, 2000) + Console.log("This prints every 200 ms.") +}, 200) + +let timeoutId = setTimeout(() => { + clearInterval(intervalId) +}, 500) ``` */ @val @@ -414,11 +422,17 @@ The same as `setInterval`, but allows you to pass a `float` instead of an `int` See [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) on MDN. ## Examples + ```rescript -// Log to the console ever 2 seconds (2000 milliseconds). +// Log to the console ever 2 seconds (200 milliseconds). let intervalId = setIntervalFloat(() => { - Console.log("This prints every 2 seconds.") -}, 2000.) + Console.log("This prints every 200 ms") +}, 200.) + +// Stop the interval after 500 ms +let timeoutId = setTimeoutFloat(() => { + clearInterval(intervalId) +}, 500.0) ``` */ @val @@ -430,15 +444,16 @@ external setIntervalFloat: (unit => unit, float) => intervalId = "setInterval" See [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) on MDN. ## Examples + ```rescript let intervalId = setInterval(() => { - Console.log("This prints in 2 seconds.") -}, 2000) + Console.log("This prints in 100 ms") +}, 100) -// Stop the interval after 10 seconds +// Stop the interval after 500 ms let timeoutId = setTimeout(() => { clearInterval(intervalId) -}, 10000) +}, 500) ``` */ @val @@ -564,3 +579,20 @@ type undefined<+'a> = Js.undefined<'a> type nullable<+'a> = Js.nullable<'a> let panic = Error.panic + +/** +`assert_eq(a, b)` check if `a` is equal `b`. If not raise a panic exception + +## Examples + +```rescript +list{1, 2} +->List.tailExn +->assert_eq(list{2}) +``` +*/ +let assert_eq = (a, b) => { + if a != b { + assert(false) + } +} diff --git a/runtime/Promise.resi b/runtime/Promise.resi index 5468bf9370..64e1cdb442 100644 --- a/runtime/Promise.resi +++ b/runtime/Promise.resi @@ -37,7 +37,16 @@ See [`Promise.reject`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/R ```rescript exception TestError(string) -let p = Promise.reject(TestError("some rejected value")) +TestError("some rejected value") +->Promise.reject +->Promise.catch(v => { + switch v { + | TestError(msg) => assert_eq(msg, "some rejected value") + | _ => assert(false) + } + Promise.resolve() +}) +->ignore ``` */ @scope("Promise") diff --git a/runtime/RescriptTools.res b/runtime/RescriptTools.res index a636f55225..6ad891d51b 100644 --- a/runtime/RescriptTools.res +++ b/runtime/RescriptTools.res @@ -2,13 +2,14 @@ module Docgen = RescriptTools_Docgen /** Returns the full file system path to the `rescript-tools` binary for the current platform, side stepping the JS that wraps the CLI. - You can use this when you're already running a JS process and want to avoid the overhead of starting another one. +You can use this when you're already running a JS process and want to avoid the overhead of starting another one. - ## Examples - ```rescript - // Prints the current ReScript Tools version. - let stringifiedJson = ChildProcess.execFileSync(RescriptTools.binaryPath, ["-v"]) - ``` - */ +## Examples + +```rescript +// Prints the current ReScript Tools version. +let stringifiedJson = ChildProcess.execFileSync(RescriptTools.binaryPath, ["-v"]) +``` +*/ @module("../../cli/bin_path.js") external binaryPath: string = "rescript_tools_exe" diff --git a/runtime/Set.resi b/runtime/Set.resi index e1246faef6..f9e4b64328 100644 --- a/runtime/Set.resi +++ b/runtime/Set.resi @@ -55,11 +55,21 @@ external fromArray: array<'a> => t<'a> = "Set" Turns an iterator into a `Set`. ## Examples + ```rescript // Let's pretend we have an interator -@val external someIterator: Iterator.t = "someIterator" - -let set = Set.fromIterator(someIterator) // Set.t +let iterator: Iterator.t = %raw(` + (() => { + var array1 = ['a', 'b', 'c']; + var iterator1 = array1[Symbol.iterator](); + return iterator1 + })() +`) + +iterator +->Set.fromIterator +->Set.size +->assert_eq(3) ``` */ @new diff --git a/runtime/String.resi b/runtime/String.resi index c9121179fb..ae161b1c94 100644 --- a/runtime/String.resi +++ b/runtime/String.resi @@ -453,13 +453,11 @@ See also [Unicode technical report #15](https://unicode.org/reports/tr15/) for d ## Examples ```rescript -let string1 = "\uFB00" -let string2 = "\u0066\u0066" -Console.log(string1 === string2) // false +let string1 = "\u00F1" +let string2 = "\u006E\u0303" -let normalizeString1 = String.normalize(string1) -let normalizeString2 = String.normalize(string2) -assert(normalizeString1 === normalizeString2) +assert(string1 != string2) // true +assert_eq(String.normalize(string1), String.normalize(string2)) ``` */ @send diff --git a/scripts/test.js b/scripts/test.js index 95d48cf43d..5d83893b53 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -133,10 +133,14 @@ async function runTests() { cwd: path.join(__dirname, "..", "tests/docstrings_examples"), stdio: [0, 1, 2], }); - cp.execSync("node tests/docstrings_examples/DocTest.res.mjs", { - cwd: path.join(__dirname, ".."), - stdio: [0, 1, 2], - }); + // Ignore some tests not supported by node v18 + cp.execSync( + "node tests/docstrings_examples/DocTest.res.mjs --ignore-runtime-tests 'Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference'", + { + cwd: path.join(__dirname, ".."), + stdio: [0, 1, 2], + }, + ); } } diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 544e52c427..94dc93906f 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -155,7 +155,7 @@ let compileTest = async (~id, ~code) => { let runtimeTests = async code => { let {stdout, stderr, code: exitCode} = await SpawnAsync.run( ~command="node", - ~args=["-e", code], + ~args=["-e", code, "--input-type", "commonjs"], ~options={ cwd: Process.cwd(), timeout: 2000, @@ -201,10 +201,16 @@ let extractDocFromFile = file => { let toolsBin = Path.join([Process.cwd(), "cli", "rescript-tools"]) let spawn = ChildProcess.spawnSync(toolsBin, ["doc", file]) - spawn.stdout - ->Buffer.toString - ->JSON.parseExn - ->Docgen.decodeFromJson + let output = spawn.stdout->Buffer.toString + + try { + output + ->JSON.parseExn + ->Docgen.decodeFromJson + } catch { + | Exn.Error(_) => Error.panic(`Failed to generate docstrings from ${file}`) + | _ => assert(false) + } } let getExamples = ({items}: Docgen.doc) => { @@ -289,9 +295,30 @@ let getCodeBlocks = example => { } let main = async () => { + let files = Fs.readdirSync("runtime") + let modules = - Fs.readdirSync("runtime") - ->Array.filter(f => f->String.endsWith(".resi") && !(f->String.startsWith("Belt"))) + files + // Ignore Belt, Js modules and RescriptTools for now + ->Array.filter(f => + !String.startsWith(f, "Belt") && + !String.startsWith(f, "Js") && + !String.startsWith(f, "RescriptTools") + ) + ->Array.filter(f => f->String.endsWith(".res") || f->String.endsWith(".resi")) + ->Array.reduce([], (acc, cur) => { + let isInterface = cur->String.endsWith(".resi") + + let resi = Path.join2("runtime", cur ++ "i") + + // If .resi files exists append to array + if !isInterface && Fs.existsSync(resi) { + Array.concat(acc, [cur ++ "i"]) + } else { + let a = !Array.includes(acc, cur) ? Array.concat(acc, [cur]) : acc + a + } + }) ->Array.map(f => extractDocFromFile(Path.join(["runtime", f]))->getExamples) ->Array.flat diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index ae14e8e22f..e387a35bb8 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -2,9 +2,11 @@ import * as Fs from "fs"; import * as Os from "os"; +import * as Exn from "rescript/lib/es6/Exn.js"; import * as List from "rescript/lib/es6/List.js"; import * as Path from "path"; import * as $$Array from "rescript/lib/es6/Array.js"; +import * as $$Error from "rescript/lib/es6/Error.js"; import * as Belt_List from "rescript/lib/es6/Belt_List.js"; import * as Nodeutil from "node:util"; import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; @@ -12,6 +14,7 @@ import * as Pervasives from "rescript/lib/es6/Pervasives.js"; import * as Child_process from "child_process"; import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; import * as Promises from "node:fs/promises"; +import * as Primitive_exceptions from "rescript/lib/es6/Primitive_exceptions.js"; import * as RescriptTools_Docgen from "rescript/lib/es6/RescriptTools_Docgen.js"; let Path$1 = {}; @@ -115,7 +118,9 @@ async function compileTest(id, code) { async function runtimeTests(code) { let match = await run("node", [ "-e", - code + code, + "--input-type", + "commonjs" ], { cwd: process.cwd(), timeout: 2000 @@ -170,7 +175,24 @@ function extractDocFromFile(file) { "doc", file ]); - return RescriptTools_Docgen.decodeFromJson(JSON.parse(spawn.stdout.toString())); + let output = spawn.stdout.toString(); + try { + return RescriptTools_Docgen.decodeFromJson(JSON.parse(output)); + } catch (raw_exn) { + let exn = Primitive_exceptions.internalToException(raw_exn); + if (exn.RE_EXN_ID === Exn.$$Error) { + return $$Error.panic("Failed to generate docstrings from " + file); + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "DocTest.res", + 212, + 9 + ], + Error: new Error() + }; + } } function getExamples(param) { @@ -303,12 +325,29 @@ function getCodeBlocks(example) { } async function main() { - let modules = Fs.readdirSync("runtime").filter(f => { - if (f.endsWith(".resi")) { - return !f.startsWith("Belt"); + let files = Fs.readdirSync("runtime"); + let modules = $$Array.reduce(files.filter(f => { + if (!f.startsWith("Belt") && !f.startsWith("Js")) { + return !f.startsWith("RescriptTools"); } else { return false; } + }).filter(f => { + if (f.endsWith(".res")) { + return true; + } else { + return f.endsWith(".resi"); + } + }), [], (acc, cur) => { + let isInterface = cur.endsWith(".resi"); + let resi = Path.join("runtime", cur + "i"); + if (!isInterface && Fs.existsSync(resi)) { + return acc.concat([cur + "i"]); + } else if (acc.includes(cur)) { + return acc; + } else { + return acc.concat([cur]); + } }).map(f => getExamples(extractDocFromFile(Path.join("runtime", f)))).flat(); let results = await Promise.all(modules.map(async example => { let id = example.id.replaceAll(".", "_"); diff --git a/tests/tests/src/test_pervasive.mjs b/tests/tests/src/test_pervasive.mjs index 0653322903..bb7d1621ba 100644 --- a/tests/tests/src/test_pervasive.mjs +++ b/tests/tests/src/test_pervasive.mjs @@ -111,7 +111,8 @@ let Pervasives$1 = { bool_of_string_opt: Pervasives.bool_of_string_opt, int_of_string_opt: Pervasives.int_of_string_opt, $at: Pervasives.$at, - panic: Pervasives.panic + panic: Pervasives.panic, + assert_eq: Pervasives.assert_eq }; function a0(prim) { diff --git a/tests/tests/src/test_pervasives3.mjs b/tests/tests/src/test_pervasives3.mjs index 6b8a65b676..510eb13235 100644 --- a/tests/tests/src/test_pervasives3.mjs +++ b/tests/tests/src/test_pervasives3.mjs @@ -24,6 +24,7 @@ let Pervasives$1 = { int_of_string_opt: Pervasives.int_of_string_opt, $at: Pervasives.$at, panic: Pervasives.panic, + assert_eq: Pervasives.assert_eq, length: Belt_List.length, size: Belt_List.size, head: Belt_List.head, From 61550e88ce4840a6c88cda0295faa224ca50ca5d Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 00:45:42 -0300 Subject: [PATCH 06/25] update analysis_tests --- .../tests/src/expected/Completion.res.txt | 128 +++++++++--------- .../tests/src/expected/SignatureHelp.res.txt | 2 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index db9a85d7bc..1acfee24d4 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -91,25 +91,25 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, array<'a>) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`concat(array1, array2)` concatenates the two arrays, creating a new array.\n\nSee [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN.\n\n## Examples\n```rescript\nlet array1 = [\"hi\", \"hello\"]\nlet array2 = [\"yay\", \"wehoo\"]\n\nlet someArray = array1->Array.concat(array2)\n\nConsole.log(someArray) // [\"hi\", \"hello\", \"yay\", \"wehoo\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`concat(array1, array2)` concatenates the two arrays, creating a new array.\n\nSee [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN.\n\n## Examples\n\n```rescript\nlet array1 = [\"hi\", \"hello\"]\nlet array2 = [\"yay\", \"wehoo\"]\n\nlet someArray = array1->Array.concat(array2)\n\nsomeArray->assert_eq([\"hi\", \"hello\", \"yay\", \"wehoo\"])\n```\n"} }, { "label": "filterMap", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => option<'b>) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`filterMap(array, fn)`\n\nCalls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\nConsole.log(\n array->Array.filterMap(item =>\n switch item {\n | \"Hello\" => Some(item->String.length)\n | _ => None\n }\n ),\n) // [5]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`filterMap(array, fn)`\n\nCalls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`.\n\n## Examples\n\n```rescript\n[\"Hello\", \"Hi\", \"Good bye\"]\n->Array.filterMap(item =>\n switch item {\n | \"Hello\" => Some(item->String.length)\n | _ => None\n }\n)\n->assert_eq([5])\n\n[1, 2, 3, 4, 5, 6]\n->Array.filterMap(n => mod(n, 2) == 0 ? Some(n * n) : None)\n->assert_eq([4, 16, 36])\n\nArray.filterMap([1, 2, 3, 4, 5, 6], _ => None)->assert_eq([])\n\nArray.filterMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assert_eq([])\n```\n"} }, { "label": "shift", "kind": 12, "tags": [], "detail": "array<'a> => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`shift(array)` removes the first item in the array, and returns it.\n\nBeware this will *mutate* the array.\n\nSee [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nlet lastItem = someArray->Array.shift // \"hi\"\n\nConsole.log(someArray) // [\"hello\"]. Notice first item is gone.\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`shift(array)` removes the first item in the array, and returns it.\n\nBeware this will *mutate* the array.\n\nSee [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray\n->Array.shift\n->assert_eq(Some(\"hi\"))\n\nsomeArray->assert_eq([\"hello\"]) // Notice first item is gone.\n```\n"} }, { "label": "findMap", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => option<'b>) => option<'b>", - "documentation": {"kind": "markdown", "value": "\n `findMap(arr, fn)`\n\n Calls `fn` for each element and returns the first value from `fn` that is `Some(_)`.\n Otherwise returns `None`\n\n ```res example\n Array.findMap([1, 2, 3], n => mod(n, 2) == 0 ? Some(n - 2) : None) == Some(0) // true\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`findMap(arr, fn)`\n\nCalls `fn` for each element and returns the first value from `fn` that is `Some(_)`.\nOtherwise returns `None`\n\n## Examples\n\n```rescript\nArray.findMap([1, 2, 3], n => mod(n, 2) == 0 ? Some(n - 2) : None)->assert_eq(Some(0))\n\nArray.findMap([1, 2, 3, 4, 5, 6], n => mod(n, 2) == 0 ? Some(n - 8) : None)->assert_eq(Some(-6))\n\nArray.findMap([1, 2, 3, 4, 5, 6], _ => None)->assert_eq(None)\n\nArray.findMap([], n => mod(n, 2) == 0 ? Some(n * n) : None)->assert_eq(None)\n```\n"} }, { "label": "concatMany", "kind": 12, @@ -121,31 +121,31 @@ Path Array. "kind": 12, "tags": [1], "detail": "(array, string) => string", - "documentation": {"kind": "markdown", "value": "Deprecated: Use `join` instead\n\n\n`joinWith(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinWithUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items.\n\n## Examples\n```rescript\nlet array = [\"One\", \"Two\", \"Three\"]\n\nConsole.log(array->Array.joinWith(\" -- \")) // One -- Two -- Three\n```\n"} + "documentation": {"kind": "markdown", "value": "Deprecated: Use `join` instead\n\n\n`joinWith(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinWithUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items.\n\n## Examples\n\n```rescript\n[\"One\", \"Two\", \"Three\"]\n->Array.joinWith(\" -- \")\n->assert_eq(\"One -- Two -- Three\")\n```\n"} }, { "label": "joinWithUnsafe", "kind": 12, "tags": [1], "detail": "(array<'a>, string) => string", - "documentation": {"kind": "markdown", "value": "Deprecated: Use `joinUnsafe` instead\n\n\n`joinWithUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items.\n\n## Examples\n```rescript\nlet array = [1, 2, 3]\n\nConsole.log(array->Array.joinWithUnsafe(\" -- \")) // 1 -- 2 -- 3\n```\n"} + "documentation": {"kind": "markdown", "value": "Deprecated: Use `joinUnsafe` instead\n\n\n`joinWithUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items.\n\n## Examples\n\n```rescript\n[1, 2, 3]\n->Array.joinWithUnsafe(\" -- \")\n->assert_eq(\"1 -- 2 -- 3\")\n```\n"} }, { "label": "reduceRight", "kind": 12, "tags": [], "detail": "(array<'a>, 'b, ('b, 'a) => 'b) => 'b", - "documentation": {"kind": "markdown", "value": "\n `reduceRight(xs, init, fn)`\n\n Works like `Array.reduce`; except that function `fn` is applied to each item of `xs` from the last back to the first.\n\n ```res example\n Array.reduceRight([\"a\", \"b\", \"c\", \"d\"], \"\", (a, b) => a ++ b) == \"dcba\"\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`reduceRight(xs, init, fn)`\n\nWorks like `Array.reduce`; except that function `fn` is applied to each item of `xs` from the last back to the first.\n\n## Examples\n\n```rescript\nArray.reduceRight([\"a\", \"b\", \"c\", \"d\"], \"\", (a, b) => a ++ b)->assert_eq(\"dcba\")\n\nArray.reduceRight([1, 2, 3], list{}, List.add)->assert_eq(list{1, 2, 3})\n\nArray.reduceRight([], list{}, List.add)->assert_eq(list{})\n```\n"} }, { "label": "reduceRightWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, 'b, ('b, 'a, int) => 'b) => 'b", - "documentation": {"kind": "markdown", "value": "\n `reduceRightWithIndex(xs, init, fn)`\n\n Like `reduceRight`, but with an additional index argument on the callback function.\n\n ```res example\n Array.reduceRightWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`reduceRightWithIndex(xs, init, fn)`\n\nLike `reduceRight`, but with an additional index argument on the callback function.\n\n## Examples\n\n```rescript\nArray.reduceRightWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i)->assert_eq(16)\n\nArray.reduceRightWithIndex([], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{})\n```\n"} }, { "label": "toShuffled", "kind": 12, "tags": [], "detail": "array<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`toShuffled(array)` returns a new array with all items in `array` in a random order.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet shuffledArray = array->Array.toShuffled\n\nConsole.log(shuffledArray)\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`toShuffled(array)` returns a new array with all items in `array` in a random order.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet shuffledArray = array->Array.toShuffled\nConsole.log(shuffledArray)\n\nArray.toShuffled([1, 2, 3])\n->Array.length\n->assert_eq(3)\n```\n"} }, { "label": "getSymbol", "kind": 12, @@ -163,73 +163,73 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => option", - "documentation": {"kind": "markdown", "value": "\n`findIndexOpt(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `None` if no item matches.\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\nswitch array->Array.findIndexOpt(item => item == ReScript) {\n| None => Console.log(\"Ahh, no ReScript...\")\n| Some(index) => Console.log(\"Yay, ReScript at index \" ++ Int.toString(index))\n}\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`findIndexOpt(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `None` if no item matches.\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\narray\n->Array.findIndexOpt(item => item == ReScript)\n->assert_eq(Some(0))\n```\n"} }, { "label": "shuffle", "kind": 12, "tags": [], "detail": "array<'a> => unit", - "documentation": {"kind": "markdown", "value": "\n`shuffle(array)` randomizes the position of all items in `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.shuffle\n\nConsole.log(array)\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`shuffle(array)` randomizes the position of all items in `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.shuffle\nConsole.log(array)\n\nlet array2 = [1, 2, 3]\narray2->Array.shuffle\n\narray2\n->Array.length\n->assert_eq(3)\n```\n"} }, { "label": "copy", "kind": 12, "tags": [], "detail": "array<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`copy(array)` makes a copy of the array with the items in it, but does not make copies of the items themselves.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3]\nlet copyOfMyArray = myArray->Array.copy\n\nConsole.log(copyOfMyArray) // [1, 2, 3]\nConsole.log(myArray === copyOfMyArray) // false\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`copy(array)` makes a copy of the array with the items in it, but does not make copies of the items themselves.\n\n## Examples\n\n```rescript\nlet myArray = [1, 2, 3]\nlet copyOfMyArray = myArray->Array.copy\n\ncopyOfMyArray->assert_eq([1, 2, 3])\nassert_eq(myArray === copyOfMyArray, false)\n```\n"} }, { "label": "setUnsafe", "kind": 12, "tags": [], "detail": "(array<'a>, int, 'a) => unit", - "documentation": {"kind": "markdown", "value": "\n`setUnsafe(array, index, item)` sets the provided `item` at `index` of `array`.\n\nBeware this will *mutate* the array, and is *unsafe*.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.setUnsafe(1, \"Hello\")\n\nConsole.log(array[1]) // \"Hello\"\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`setUnsafe(array, index, item)` sets the provided `item` at `index` of `array`.\n\nBeware this will *mutate* the array, and is *unsafe*.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.setUnsafe(1, \"Hello\")\n\nassert_eq(array[1], Some(\"Hello\"))\n```\n"} }, { "label": "findIndexWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => bool) => int", - "documentation": {"kind": "markdown", "value": "\n`findIndexWithIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript]\n\nlet isReScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == ReScript)\nlet isTypeScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == TypeScript)\n\nConsole.log(isReScriptFirst) // 0\nConsole.log(isTypeScriptFirst) // -1\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`findIndexWithIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript]\n\nlet isReScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == ReScript)\nlet isTypeScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == TypeScript)\n\nassert_eq(isReScriptFirst, 0)\nassert_eq(isTypeScriptFirst, -1)\n```\n"} }, { "label": "someWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n`someWithIndex(array, checker)` returns true if running the provided `checker` function on any element in `array` returns true.\n\nSee [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\nConsole.log(array->Array.someWithIndex((greeting, index) => greeting === \"Hello\" && index === 0)) // true\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`someWithIndex(array, checker)` returns true if running the provided `checker` function on any element in `array` returns true.\n\nSee [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray\n->Array.someWithIndex((greeting, index) => greeting === \"Hello\" && index === 0)\n->assert_eq(true)\n```\n"} }, { "label": "slice", "kind": 12, "tags": [], "detail": "(array<'a>, ~start: int, ~end: int) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`slice(array, ~start, ~end)` creates a new array of items copied from `array` from `start` until (but not including) `end`.\n\nSee [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3, 4]\n\nConsole.log(myArray->Array.slice(~start=1, ~end=3)) // [2, 3]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`slice(array, ~start, ~end)` creates a new array of items copied from `array` from `start` until (but not including) `end`.\n\nSee [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]\n->Array.slice(~start=1, ~end=3)\n->assert_eq([2, 3])\n```\n"} }, { "label": "fillToEnd", "kind": 12, "tags": [], "detail": "(array<'a>, 'a, ~start: int) => unit", - "documentation": {"kind": "markdown", "value": "\n`fillToEnd(array, value, ~start)` fills `array` with `value` from the `start` index.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3, 4]\nmyArray->Array.fillToEnd(9, ~start=1)\n\nConsole.log(myArray) // [1, 9, 9, 9]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`fillToEnd(array, value, ~start)` fills `array` with `value` from the `start` index.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n\n```rescript\nlet myArray = [1, 2, 3, 4]\nmyArray->Array.fillToEnd(9, ~start=1)\nmyArray->assert_eq([1, 9, 9, 9])\n```\n"} }, { "label": "includes", "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => bool", - "documentation": {"kind": "markdown", "value": "\n`includes(array, item)` checks whether `array` includes `item`, by doing a [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality).\n\nSee [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN.\n\n## Examples\n```rescript\nConsole.log([1, 2]->Array.includes(1)) // true\nConsole.log([1, 2]->Array.includes(3)) // false\nConsole.log([{\"language\": \"ReScript\"}]->Array.includes({\"language\": \"ReScript\"})) // false, because of strict equality\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`includes(array, item)` checks whether `array` includes `item`, by doing a [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality).\n\nSee [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN.\n\n## Examples\n\n```rescript\n[1, 2]->Array.includes(1)->assert_eq(true)\n[1, 2]->Array.includes(3)->assert_eq(false)\n\n[{\"language\": \"ReScript\"}]\n->Array.includes({\"language\": \"ReScript\"})\n->assert_eq(false) // false, because of strict equality\n```\n"} }, { "label": "fromInitializer", "kind": 12, "tags": [], "detail": "(~length: int, int => 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n `fromInitializer(~length, f)`\n\n Creates an array of length `length` initialized with the value returned from `f ` for each index.\n\n ```res example\n Array.fromInitializer(~length=3, i => i + 3) == [3, 4, 5]\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`fromInitializer(~length, f)`\n\nCreates an array of length `length` initialized with the value returned from `f ` for each index.\n\n## Examples\n\n```rescript\nArray.fromInitializer(~length=3, i => i + 3)->assert_eq([3, 4, 5])\n\nArray.fromInitializer(~length=7, i => i + 3)->assert_eq([3, 4, 5, 6, 7, 8, 9])\n```\n"} }, { "label": "find", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`find(array, checker)` returns the first element of `array` where the provided `checker` function returns true.\n\nSee [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN.\n\n## Examples\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\nswitch array->Array.find(item => item == ReScript) {\n| None => Console.log(\"No item...\")\n| Some(_) => Console.log(\"Yay, ReScript!\")\n}\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`find(array, checker)` returns the first element of `array` where the provided `checker` function returns true.\n\nSee [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\narray\n->Array.find(item => item == ReScript)\n->assert_eq(Some(ReScript))\n```\n"} }, { "label": "make", "kind": 12, "tags": [], "detail": "(~length: int, 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n `make(~length, init)`\n\n Creates an array of length `length` initialized with the value of `init`.\n\n ```res example\n Array.make(~length=3, #apple) == [#apple, #apple, #apple]\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`make(~length, init)`\n\nCreates an array of length `length` initialized with the value of `init`.\n\n## Examples\n\n```rescript\nArray.make(~length=3, #apple)->assert_eq([#apple, #apple, #apple])\nArray.make(~length=6, 7)->assert_eq([7, 7, 7, 7, 7, 7])\n```\n"} }, { "label": "lastIndexOfFrom", "kind": 12, @@ -253,31 +253,31 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, ('a, 'a) => Ordering.t) => unit", - "documentation": {"kind": "markdown", "value": "\n`sort(array, comparator)` sorts `array` in-place using the `comparator` function.\n\nBeware this will *mutate* the array.\n\nSee [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) on MDN.\n\n## Examples\n```rescript\nlet someArray = [3, 2, 1]\nsomeArray->Array.sort((a, b) => float(a - b))\n\nConsole.log(someArray) // [1, 2, 3]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`sort(array, comparator)` sorts `array` in-place using the `comparator` function.\n\nBeware this will *mutate* the array.\n\nSee [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) on MDN.\n\n## Examples\n\n```rescript\nlet array = [3, 2, 1]\narray->Array.sort((a, b) => float(a - b))\narray->assert_eq([1, 2, 3])\n```\n"} }, { "label": "length", "kind": 12, "tags": [], "detail": "array<'a> => int", - "documentation": {"kind": "markdown", "value": "\n`length(array)` returns the length of (i.e. number of items in) the array.\n\nSee [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nConsole.log(someArray->Array.length) // 2\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`length(array)` returns the length of (i.e. number of items in) the array.\n\nSee [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray\n->Array.length\n->assert_eq(2)\n```\n"} }, { "label": "every", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n`every(array, predicate)` returns true if `predicate` returns true for all items in `array`.\n\nSee [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN.\n\n## Examples\n```rescript\nlet array = [1, 2, 3, 4]\n\nConsole.log(array->Array.every(num => num <= 4)) // true\nConsole.log(array->Array.every(num => num === 1)) // false\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`every(array, predicate)` returns true if `predicate` returns true for all items in `array`.\n\nSee [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3, 4]\n\narray\n->Array.every(num => num <= 4)\n->assert_eq(true)\n\narray\n->Array.every(num => num === 1)\n->assert_eq(false)\n```\n"} }, { "label": "flat", "kind": 12, "tags": [], "detail": "array> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`flat(arrays)` concatenates an array of arrays into a single array.\n\nSee [`Array.flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) on MDN.\n\n## Examples\n```rescript\nConsole.log([[1], [2], [3, 4]]->Array.flat) // [1, 2, 3, 4]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`flat(arrays)` concatenates an array of arrays into a single array.\n\nSee [`Array.flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) on MDN.\n\n## Examples\n\n```rescript\n[[1], [2], [3, 4]]\n->Array.flat\n->assert_eq([1, 2, 3, 4])\n```\n"} }, { "label": "map", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => 'b) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nConsole.log(mappedArray) // [\"Hello to you\", \"Hi to you\", \"Good bye to you\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nassert_eq(mappedArray, [\"Hello to you\", \"Hi to you\", \"Good bye to you\"])\n```\n"} }, { "label": "with", "kind": 12, @@ -295,7 +295,7 @@ Path Array. "kind": 12, "tags": [], "detail": "array<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`toReversed(array)` creates a new array with all items from `array` in reversed order.\n\nSee [`Array.toReversed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nlet reversed = someArray->Array.toReversed\n\nConsole.log(reversed) // [\"hello\", \"h1\"]\nConsole.log(someArray) // [\"h1\", \"hello\"]. Original unchanged\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`toReversed(array)` creates a new array with all items from `array` in reversed order.\n\nSee [`Array.toReversed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nlet reversed = someArray->Array.toReversed\n\nreversed->assert_eq([\"hello\", \"hi\"])\nsomeArray->assert_eq([\"h1\", \"hello\"]) // Original unchanged\n```\n"} }, { "label": "copyWithin", "kind": 12, @@ -307,31 +307,31 @@ Path Array. "kind": 12, "tags": [], "detail": "array<'a> => string", - "documentation": {"kind": "markdown", "value": "\n`toString(array)` stringifies `array` by running `toString` on all of the array elements and joining them with \",\".\n\nSee [`Array.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) on MDN.\n\n## Examples\n```rescript\nlet array = [1, 2, 3, 4]\n\nConsole.log(array->Array.toString) // \"1,2,3,4\"\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`toString(array)` stringifies `array` by running `toString` on all of the array elements and joining them with \",\".\n\nSee [`Array.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]\n->Array.toString\n->assert_eq(\"1,2,3,4\")\n```\n"} }, { "label": "everyWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n`everyWithIndex(array, checker)` returns true if all items in `array` returns true when running the provided `checker` function.\n\nSee [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN.\n\n## Examples\n```rescript\nlet array = [1, 2, 3, 4]\n\nConsole.log(array->Array.everyWithIndex((num, index) => index < 2 && num <= 2)) // true\nConsole.log(array->Array.everyWithIndex((num, index) => index < 2 && num >= 2)) // false\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`everyWithIndex(array, checker)` returns true if all items in `array` returns true when running the provided `checker` function.\n\nSee [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN.\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3, 4]\n\narray\n->Array.everyWithIndex((num, index) => index < 5 && num <= 4)\n->assert_eq(true)\n\narray\n->Array.everyWithIndex((num, index) => index < 2 && num >= 2)\n->assert_eq(false)\n```\n"} }, { "label": "fill", "kind": 12, "tags": [], "detail": "(array<'a>, 'a, ~start: int, ~end: int) => unit", - "documentation": {"kind": "markdown", "value": "\n`fill(array, value, ~start, ~end)` fills `array` with `value` from `start` to `end`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3, 4]\nmyArray->Array.fill(9, ~start=1, ~end=2)\n\nConsole.log(myArray) // [1, 9, 9, 4]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`fill(array, value, ~start, ~end)` fills `array` with `value` from `start` to `end`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n\n```rescript\nlet myArray = [1, 2, 3, 4]\n\nmyArray->Array.fill(9, ~start=1, ~end=3)\n\nmyArray->assert_eq([1, 9, 9, 4])\n```\n"} }, { "label": "findWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => bool) => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`findWithIndex(array, checker)` returns the first element of `array` where the provided `checker` function returns true.\n\nSee [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN.\n\n## Examples\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [TypeScript, JavaScript, ReScript]\n\nswitch array->Array.findWithIndex((item, index) => index > 1 && item == ReScript) {\n| None => Console.log(\"No item...\")\n| Some(_) => Console.log(\"Yay, ReScript exists in a later position!\")\n}\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`findWithIndex(array, checker)` returns the first element of `array` where the provided `checker` function returns true.\n\nSee [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [TypeScript, JavaScript, ReScript]\n\narray\n->Array.findWithIndex((item, index) => index > 1 && item == ReScript)\n->assert_eq(Some(ReScript))\n```\n"} }, { "label": "reverse", "kind": 12, "tags": [], "detail": "array<'a> => unit", - "documentation": {"kind": "markdown", "value": "\n`reverse(array)` reverses the order of the items in `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.reverse\n\nConsole.log(someArray) // [\"hello\", \"h1\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`reverse(array)` reverses the order of the items in `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.reverse\n\nsomeArray->assert_eq([\"hello\", \"hi\"])\n```\n"} }, { "label": "getUnsafe", "kind": 12, @@ -343,7 +343,7 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": "\n`unshiftMany(array, itemsArray)` inserts many new items to the start of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.unshiftMany([\"yay\", \"wehoo\"])\n\nConsole.log(someArray) // [\"yay\", \"wehoo\", \"hi\", \"hello\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`unshiftMany(array, itemsArray)` inserts many new items to the start of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.unshiftMany([\"yay\", \"wehoo\"])\nsomeArray->assert_eq([\"yay\", \"wehoo\", \"hi\", \"hello\"])\n```\n"} }, { "label": "lastIndexOf", "kind": 12, @@ -355,7 +355,7 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`filter(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true.\n\nSee [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN.\n\n## Examples\n```rescript\nlet array = [1, 2, 3, 4]\n\nConsole.log(array->Array.filter(num => num > 2)) // [3, 4]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`filter(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true.\n\nSee [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]\n->Array.filter(num => num > 2)\n->assert_eq([3, 4])\n```\n"} }, { "label": "compare", "kind": 12, @@ -367,13 +367,13 @@ Path Array. "kind": 12, "tags": [], "detail": "(array, string) => string", - "documentation": {"kind": "markdown", "value": "\n`join(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items.\n\nSee [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join)\n\n## Examples\n```rescript\nlet array = [\"One\", \"Two\", \"Three\"]\n\nConsole.log(array->Array.join(\" -- \")) // One -- Two -- Three\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`join(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items.\n\nSee [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join)\n\n## Examples\n\n```rescript\n[\"One\", \"Two\", \"Three\"]\n->Array.join(\" -- \")\n->assert_eq(\"One -- Two -- Three\")\n```\n"} }, { "label": "last", "kind": 12, "tags": [], "detail": "array<'a> => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`last(array)` returns the last element of `array`.\n\nReturns `None` if the array is empty.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray->Array.last == Some(\"Good bye\") // true\n[]->Array.last == None // true\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`last(array)` returns the last element of `array`.\n\nReturns `None` if the array is empty.\n\n## Examples\n\n```rescript\n[\"Hello\", \"Hi\", \"Good bye\"]\n->Array.last\n->assert_eq(Some(\"Good bye\"))\n\n[]\n->Array.last\n->assert_eq(None)\n```\n"} }, { "label": "isArray", "kind": 12, @@ -385,25 +385,25 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => option", - "documentation": {"kind": "markdown", "value": "\n`indexOfOpt(array, item)` returns an option of the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items.\n\nSee [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN.\n\n## Examples\n```rescript\nConsole.log([1, 2]->Array.indexOfOpt(2)) // Some(1)\nConsole.log([1, 2]->Array.indexOfOpt(3)) // None\nConsole.log([{\"language\": \"ReScript\"}]->Array.indexOfOpt({\"language\": \"ReScript\"})) // None, because of strict equality\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`indexOfOpt(array, item)` returns an option of the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items.\n\nSee [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN.\n\n## Examples\n\n```rescript\n[1, 2]->Array.indexOfOpt(2)->assert_eq(Some(1))\n[1, 2]->Array.indexOfOpt(3)->assert_eq(None)\n[{\"language\": \"ReScript\"}]\n->Array.indexOfOpt({\"language\": \"ReScript\"})\n->assert_eq(None) // None, because of strict equality\n```\n"} }, { "label": "forEachWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => unit) => unit", - "documentation": {"kind": "markdown", "value": "\n`forEachWithIndex(array, fn)` runs the provided `fn` on every element of `array`.\n\nSee [`Array.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray->Array.forEachWithIndex((item, index) => {\n Console.log(\"At item \" ++ Int.toString(index) ++ \": \" ++ item)\n})\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`forEachWithIndex(array, fn)` runs the provided `fn` on every element of `array`.\n\nSee [`Array.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray->Array.forEachWithIndex((item, index) => {\n Console.log(\"At item \" ++ Int.toString(index) ++ \": \" ++ item)\n})\n```\n"} }, { "label": "reduce", "kind": 12, "tags": [], "detail": "(array<'a>, 'b, ('b, 'a) => 'b) => 'b", - "documentation": {"kind": "markdown", "value": "\n `reduce(xs, init, fn)`\n\n Applies `fn` to each element of `xs` from beginning to end. Function `fn` has two parameters: the item from the list and an “accumulator”; which starts with a value of `init`. `reduce` returns the final value of the accumulator.\n\n ```res example\n Array.reduce([2, 3, 4], 1, (a, b) => a + b) == 10\n\n Array.reduce([\"a\", \"b\", \"c\", \"d\"], \"\", (a, b) => a ++ b) == \"abcd\"\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`reduce(xs, init, fn)`\n\nApplies `fn` to each element of `xs` from beginning to end. Function `fn` has two parameters: the item from the list and an “accumulator”; which starts with a value of `init`. `reduce` returns the final value of the accumulator.\n\n## Examples\n\n```rescript\nArray.reduce([2, 3, 4], 1, (a, b) => a + b)->assert_eq(10)\n\nArray.reduce([\"a\", \"b\", \"c\", \"d\"], \"\", (a, b) => a ++ b)->assert_eq(\"abcd\")\n\n[1, 2, 3]\n->Array.reduce(list{}, List.add)\n->assert_eq(list{3, 2, 1})\n\nArray.reduce([], list{}, List.add)->assert_eq(list{})\n```\n"} }, { "label": "sliceToEnd", "kind": 12, "tags": [], "detail": "(array<'a>, ~start: int) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`sliceToEnd(array, start)` creates a new array from `array`, with all items from `array` starting from `start`.\n\nSee [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3, 4]\n\nConsole.log(myArray->Array.sliceToEnd(~start=1)) // [2, 3, 4]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`sliceToEnd(array, start)` creates a new array from `array`, with all items from `array` starting from `start`.\n\nSee [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]\n->Array.sliceToEnd(~start=1)\n->assert_eq([2, 3, 4])\n```\n"} }, { "label": "fromArrayLikeWithMap", "kind": 12, @@ -415,25 +415,25 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => unit", - "documentation": {"kind": "markdown", "value": "\n`fillAll(array, value)` fills the entire `array` with `value`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n```rescript\nlet myArray = [1, 2, 3, 4]\nmyArray->Array.fillAll(9)\n\nConsole.log(myArray) // [9, 9, 9, 9]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`fillAll(array, value)` fills the entire `array` with `value`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN.\n\n## Examples\n\n```rescript\nlet myArray = [1, 2, 3, 4]\nmyArray->Array.fillAll(9)\nmyArray->assert_eq([9, 9, 9, 9])\n```\n"} }, { "label": "set", "kind": 12, "tags": [], "detail": "(array<'a>, int, 'a) => unit", - "documentation": {"kind": "markdown", "value": "\n`set(array, index, item)` sets the provided `item` at `index` of `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.set(1, \"Hello\")\n\nConsole.log(array[1]) // \"Hello\"\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`set(array, index, item)` sets the provided `item` at `index` of `array`.\n\nBeware this will *mutate* the array.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\narray->Array.set(1, \"Hello\")\n\narray[1]->assert_eq(Some(\"Hello\"))\n```\n"} }, { "label": "filterWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => bool) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`filterWithIndex(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true.\n\nSee [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN.\n\n## Examples\n```rescript\nlet array = [1, 2, 3, 4]\n\nConsole.log(array->Array.filterWithIndex((num, index) => index === 0 || num === 2)) // [1, 2]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`filterWithIndex(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true.\n\nSee [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 3, 4]\n->Array.filterWithIndex((num, index) => index === 0 || num === 2)\n->assert_eq([1, 2])\n```\n"} }, { "label": "findIndex", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => int", - "documentation": {"kind": "markdown", "value": "\n`findIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript]\n\nConsole.log(array->Array.findIndex(item => item == ReScript)) // 0\nConsole.log(array->Array.findIndex(item => item == TypeScript)) // -1\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`findIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true.\n\nReturns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`).\n\nSee [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN.\n\n## Examples\n\n```rescript\ntype languages = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, JavaScript]\n\narray\n->Array.findIndex(item => item == ReScript)\n->assert_eq(0)\n\narray->Array.findIndex(item => item == TypeScript)\n->assert_eq(-1)\n```\n"} }, { "label": "setSymbol", "kind": 12, @@ -451,19 +451,19 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, string) => string", - "documentation": {"kind": "markdown", "value": "\n`joinUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items.\n\nSee [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join)\n\n## Examples\n```rescript\nlet array = [1, 2, 3]\n\nConsole.log(array->Array.joinUnsafe(\" -- \")) // 1 -- 2 -- 3\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`joinUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items.\n\nSee [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join)\n\n## Examples\n\n```rescript\n[1, 2, 3]\n->Array.joinUnsafe(\" -- \")\n->assert_eq(\"1 -- 2 -- 3\")\n```\n"} }, { "label": "mapWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => 'b) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`mapWithIndex(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray =\n array->Array.mapWithIndex((greeting, index) =>\n greeting ++ \" at position \" ++ Int.toString(index)\n )\n\nConsole.log(mappedArray) // [\"Hello at position 0\", \"Hi at position 1\", \"Good bye at position 2\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`mapWithIndex(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray =\n array->Array.mapWithIndex((greeting, index) =>\n greeting ++ \" at position \" ++ Int.toString(index)\n )\n\nassert_eq(mappedArray, [\"Hello at position 0\", \"Hi at position 1\", \"Good bye at position 2\"])\n```\n"} }, { "label": "flatMapWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => array<'b>) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`flatMapWithIndex(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`.\n\n## Examples\n```rescript\ntype language = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\nConsole.log(\n array->Array.flatMapWithIndex((item, index) =>\n switch item {\n | ReScript => [index]\n | TypeScript => [index, index + 1]\n | JavaScript => [index, index + 1, index + 2]\n }\n ),\n)\n// [0, 1, 2, 2, 3, 4]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`flatMapWithIndex(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`.\n\n## Examples\n\n```rescript\ntype language = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\n\narray\n->Array.flatMapWithIndex((item, index) =>\n switch item {\n | ReScript => [index]\n | TypeScript => [index, index + 1]\n | JavaScript => [index, index + 1, index + 2]\n }\n)\n->assert_eq([0, 1, 2, 2, 3, 4])\n```\n"} }, { "label": "copyWithinToEnd", "kind": 12, @@ -475,43 +475,43 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => unit", - "documentation": {"kind": "markdown", "value": "\n`unshift(array, item)` inserts a new item at the start of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.unshift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.unshift(\"yay\")\n\nConsole.log(someArray) // [\"yay\", \"hi\", \"hello\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`unshift(array, item)` inserts a new item at the start of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.unshift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.unshift(\"yay\")\nsomeArray->assert_eq([\"yay\", \"hi\", \"hello\"])\n```\n"} }, { "label": "indexOf", "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => int", - "documentation": {"kind": "markdown", "value": "\n`indexOf(array, item)` returns the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items.\n\nReturns `-1` if the item doesn not exist. Check out `Array.indexOfOpt` for a version that returns `None` instead of `-1` if the item does not exist.\n\nSee [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN.\n\n## Examples\n```rescript\nConsole.log([1, 2]->Array.indexOf(2)) // 1\nConsole.log([1, 2]->Array.indexOf(3)) // -1\nConsole.log([{\"language\": \"ReScript\"}]->Array.indexOf({\"language\": \"ReScript\"})) // -1, because of strict equality\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`indexOf(array, item)` returns the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items.\n\nReturns `-1` if the item doesn not exist. Check out `Array.indexOfOpt` for a version that returns `None` instead of `-1` if the item does not exist.\n\nSee [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN.\n\n## Examples\n\n```rescript\n[1, 2]->Array.indexOf(2)->assert_eq(1)\n[1, 2]->Array.indexOf(3)->assert_eq(-1)\n\n[{\"language\": \"ReScript\"}]\n->Array.indexOf({\"language\": \"ReScript\"})\n->assert_eq(-1) // -1, because of strict equality\n```\n"} }, { "label": "push", "kind": 12, "tags": [], "detail": "(array<'a>, 'a) => unit", - "documentation": {"kind": "markdown", "value": "\n`push(array, item)` appends `item` to the end of `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.push(\"yay\")\n\nConsole.log(someArray) // [\"hi\", \"hello\", \"yay\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`push(array, item)` appends `item` to the end of `array`.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray->Array.push(\"yay\")\n\nsomeArray->assert_eq([\"hi\", \"hello\", \"yay\"])\n```\n"} }, { "label": "toSorted", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, 'a) => Ordering.t) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`toSorted(array, comparator)` returns a new, sorted array from `array`, using the `comparator` function.\n\nSee [`Array.toSorted`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) on MDN.\n\n## Examples\n```rescript\nlet someArray = [3, 2, 1]\nlet sorted = someArray->Array.toSorted(Int.compare)\n\nConsole.log(sorted) // [1, 2, 3]\nConsole.log(someArray) // [3, 2, 1]. Original unchanged\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`toSorted(array, comparator)` returns a new, sorted array from `array`, using the `comparator` function.\n\nSee [`Array.toSorted`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [3, 2, 1]\n\nsomeArray\n->Array.toSorted(Int.compare)\n->assert_eq([1, 2, 3])\n\nsomeArray->assert_eq([3, 2, 1]) // Original unchanged\n```\n"} }, { "label": "reduceWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, 'b, ('b, 'a, int) => 'b) => 'b", - "documentation": {"kind": "markdown", "value": "\n `reduceWithIndex(x, init, fn)`\n\n Applies `fn` to each element of `xs` from beginning to end. Function `fn` has three parameters: the item from the array and an “accumulator”, which starts with a value of `init` and the index of each element. `reduceWithIndex` returns the final value of the accumulator.\n\n ```res example\n Array.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`reduceWithIndex(x, init, fn)`\n\nApplies `fn` to each element of `xs` from beginning to end. Function `fn` has three parameters: the item from the array and an “accumulator”, which starts with a value of `init` and the index of each element. `reduceWithIndex` returns the final value of the accumulator.\n\n## Examples\n\n```rescript\nArray.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i)->assert_eq(16)\n\nArray.reduceWithIndex([1, 2, 3], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{5, 3, 1})\n\nArray.reduceWithIndex([], list{}, (acc, v, i) => list{v + i, ...acc})->assert_eq(list{})\n```\n"} }, { "label": "some", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n`some(array, predicate)` returns true if `predicate` returns true for any element in `array`.\n\nSee [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\nConsole.log(array->Array.some(greeting => greeting === \"Hello\")) // true\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`some(array, predicate)` returns true if `predicate` returns true for any element in `array`.\n\nSee [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray\n->Array.some(greeting => greeting === \"Hello\")\n->assert_eq(true)\n```\n"} }, { "label": "unsafe_get", "kind": 12, "tags": [1], "detail": "(array<'a>, int) => 'a", - "documentation": {"kind": "markdown", "value": "Deprecated: Use getUnsafe instead. This will be removed in v13\n\n\n`unsafe_get(array, index)` returns the element at `index` of `array`.\n\nThis is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `array`.\n\nUse `Array.unsafe_get` only when you are sure the `index` exists (i.e. when using for-loop).\n\n## Examples\n```rescript\nlet array = [1, 2, 3]\nfor index in 0 to array->Array.length - 1 {\n let value = array->Array.unsafe_get(index)\n Console.log(value)\n}\n```\n"} + "documentation": {"kind": "markdown", "value": "Deprecated: Use getUnsafe instead. This will be removed in v13\n\n\n`unsafe_get(array, index)` returns the element at `index` of `array`.\n\nThis is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `array`.\n\nUse `Array.unsafe_get` only when you are sure the `index` exists (i.e. when using for-loop).\n\n## Examples\n\n```rescript\nlet array = [1, 2, 3]\nfor index in 0 to array->Array.length - 1 {\n let value = array->Array.unsafe_get(index)\n Console.log(value)\n}\n```\n"} }, { "label": "copyAllWithin", "kind": 12, @@ -523,37 +523,37 @@ Path Array. "kind": 12, "tags": [], "detail": "array> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n `keepSome(arr)`\n\n Returns a new array containing `value` for all elements that are `Some(value)`\n and ignoring every value that is `None`\n\n ```res example\n Array.keepSome([Some(1), None, Some(3)]) == [1, 3]\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`keepSome(arr)`\n\nReturns a new array containing `value` for all elements that are `Some(value)`\nand ignoring every value that is `None`\n\n## Examples\n\n```rescript\nArray.keepSome([Some(1), None, Some(3)])->assert_eq([1, 3])\n\nArray.keepSome([Some(1), Some(2), Some(3)])->assert_eq([1, 2, 3])\n\nArray.keepSome([None, None, None])->assert_eq([])\n\nArray.keepSome([])->assert_eq([])\n```\n"} }, { "label": "at", "kind": 12, "tags": [], "detail": "(array<'a>, int) => option<'a>", - "documentation": {"kind": "markdown", "value": "\n `at(array, index)`\n\n Get an element by its index. Negative indices count backwards from the last item.\n\n ## Examples\n ```rescript\n [\"a\", \"b\", \"c\"]->Array.at(0) // Some(\"a\")\n [\"a\", \"b\", \"c\"]->Array.at(2) // Some(\"c\")\n [\"a\", \"b\", \"c\"]->Array.at(3) // None\n [\"a\", \"b\", \"c\"]->Array.at(-1) // Some(\"c\")\n [\"a\", \"b\", \"c\"]->Array.at(-3) // Some(\"a\")\n [\"a\", \"b\", \"c\"]->Array.at(-4) // None\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`at(array, index)`\n\nGet an element by its index. Negative indices count backwards from the last item.\n\n## Examples\n\n```rescript\n[\"a\", \"b\", \"c\"]->Array.at(0)->assert_eq(Some(\"a\"))\n[\"a\", \"b\", \"c\"]->Array.at(2)->assert_eq(Some(\"c\"))\n[\"a\", \"b\", \"c\"]->Array.at(3)->assert_eq(None)\n[\"a\", \"b\", \"c\"]->Array.at(-1)->assert_eq(Some(\"c\"))\n[\"a\", \"b\", \"c\"]->Array.at(-3)->assert_eq(Some(\"a\"))\n[\"a\", \"b\", \"c\"]->Array.at(-4)->assert_eq(None)\n```\n"} }, { "label": "pop", "kind": 12, "tags": [], "detail": "array<'a> => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`pop(array)` removes the last item from `array` and returns it.\n\nBeware this will *mutate* the array.\n\nSee [`Array.pop`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nlet lastItem = someArray->Array.pop // \"hello\"\n\nConsole.log(someArray) // [\"hi\"]. Notice last item is gone.\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`pop(array)` removes the last item from `array` and returns it.\n\nBeware this will *mutate* the array.\n\nSee [`Array.pop`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray\n->Array.pop\n->assert_eq(Some(\"hello\"))\n\nsomeArray->assert_eq([\"hi\"]) // Notice last item is gone.\n```\n"} }, { "label": "get", "kind": 12, "tags": [], "detail": "(array<'a>, int) => option<'a>", - "documentation": {"kind": "markdown", "value": "\n`get(array, index)` returns the element at `index` of `array`.\n\nReturns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray->Array.get(0) == Some(\"Hello\") // true\narray->Array.get(3) == None // true\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`get(array, index)` returns the element at `index` of `array`.\n\nReturns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray\n->Array.get(0)\n->assert_eq(Some(\"Hello\"))\n\narray\n->Array.get(3)\n->assert_eq(None)\n```\n"} }, { "label": "pushMany", "kind": 12, "tags": [], "detail": "(array<'a>, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": "\n`pushMany(array, itemsArray)` appends many new items to the end of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN.\n\n## Examples\n```rescript\nlet someArray = [\"hi\", \"hello\"]\nsomeArray->Array.pushMany([\"yay\", \"wehoo\"])\n\nConsole.log(someArray) // [\"hi\", \"hello\", \"yay\", \"wehoo\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`pushMany(array, itemsArray)` appends many new items to the end of the array.\n\nBeware this will *mutate* the array.\n\nSee [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN.\n\n## Examples\n\n```rescript\nlet someArray = [\"hi\", \"hello\"]\n\nsomeArray->Array.pushMany([\"yay\", \"wehoo\"])\nsomeArray->assert_eq([\"hi\", \"hello\", \"yay\", \"wehoo\"])\n```\n"} }, { "label": "fromIterator", "kind": 12, "tags": [], "detail": "Iterator.t<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n `fromIterator(iterator)`\n\n Creates an array from the provided `iterator`\n\n ```res example\n let map = Map.fromArray([(\"foo\", 1), (\"bar\", 2)])\n\n Array.fromIterator(map->Map.values) // [1, 2]\n ```\n "} + "documentation": {"kind": "markdown", "value": "\n`fromIterator(iterator)`\n\nCreates an array from the provided `iterator`\n\n## Examples\n\n```rescript\nMap.fromArray([(\"foo\", 1), (\"bar\", 2)])\n->Map.values\n->Array.fromIterator\n->assert_eq([1, 2])\n```\n"} }, { "label": "forEach", "kind": 12, @@ -565,7 +565,7 @@ Path Array. "kind": 12, "tags": [], "detail": "(array<'a>, 'a => array<'b>) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`flatMap(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`.\n\n## Examples\n```rescript\ntype language = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\nConsole.log(\n array->Array.flatMap(item =>\n switch item {\n | ReScript => [1, 2, 3]\n | TypeScript => [4, 5, 6]\n | JavaScript => [7, 8, 9]\n }\n ),\n)\n// [1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`flatMap(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`.\n\n## Examples\n\n```rescript\ntype language = ReScript | TypeScript | JavaScript\n\nlet array = [ReScript, TypeScript, JavaScript]\n\narray\n->Array.flatMap(item =>\n switch item {\n | ReScript => [1, 2, 3]\n | TypeScript => [4, 5, 6]\n | JavaScript => [7, 8, 9]\n }\n)\n->assert_eq([1, 2, 3, 4, 5, 6, 7, 8, 9])\n```\n"} }, { "label": "fromArrayLike", "kind": 12, @@ -592,19 +592,19 @@ Path Array.m "kind": 12, "tags": [], "detail": "(~length: int, 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": "\n `make(~length, init)`\n\n Creates an array of length `length` initialized with the value of `init`.\n\n ```res example\n Array.make(~length=3, #apple) == [#apple, #apple, #apple]\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n`make(~length, init)`\n\nCreates an array of length `length` initialized with the value of `init`.\n\n## Examples\n\n```rescript\nArray.make(~length=3, #apple)->assert_eq([#apple, #apple, #apple])\nArray.make(~length=6, 7)->assert_eq([7, 7, 7, 7, 7, 7])\n```\n"} }, { "label": "map", "kind": 12, "tags": [], "detail": "(array<'a>, 'a => 'b) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nConsole.log(mappedArray) // [\"Hello to you\", \"Hi to you\", \"Good bye to you\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nassert_eq(mappedArray, [\"Hello to you\", \"Hi to you\", \"Good bye to you\"])\n```\n"} }, { "label": "mapWithIndex", "kind": 12, "tags": [], "detail": "(array<'a>, ('a, int) => 'b) => array<'b>", - "documentation": {"kind": "markdown", "value": "\n`mapWithIndex(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray =\n array->Array.mapWithIndex((greeting, index) =>\n greeting ++ \" at position \" ++ Int.toString(index)\n )\n\nConsole.log(mappedArray) // [\"Hello at position 0\", \"Hi at position 1\", \"Good bye at position 2\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`mapWithIndex(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray =\n array->Array.mapWithIndex((greeting, index) =>\n greeting ++ \" at position \" ++ Int.toString(index)\n )\n\nassert_eq(mappedArray, [\"Hello at position 0\", \"Hi at position 1\", \"Good bye at position 2\"])\n```\n"} }] Complete src/Completion.res 15:17 diff --git a/tests/analysis_tests/tests/src/expected/SignatureHelp.res.txt b/tests/analysis_tests/tests/src/expected/SignatureHelp.res.txt index 09576665b9..1eae31ee1b 100644 --- a/tests/analysis_tests/tests/src/expected/SignatureHelp.res.txt +++ b/tests/analysis_tests/tests/src/expected/SignatureHelp.res.txt @@ -454,7 +454,7 @@ extracted params: "signatures": [{ "label": "(array, int => int) => array", "parameters": [{"label": [1, 11], "documentation": {"kind": "markdown", "value": ""}}, {"label": [13, 23], "documentation": {"kind": "markdown", "value": ""}}], - "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nConsole.log(mappedArray) // [\"Hello to you\", \"Hi to you\", \"Good bye to you\"]\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`.\n\nSee [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\nlet mappedArray = array->Array.map(greeting => greeting ++ \" to you\")\n\nassert_eq(mappedArray, [\"Hello to you\", \"Hi to you\", \"Good bye to you\"])\n```\n"} }], "activeSignature": 0, "activeParameter": 1 From f0c36828e01df4f1c5749ca64847fe1fc92d100b Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 01:14:29 -0300 Subject: [PATCH 07/25] test script: use path.join --- scripts/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.js b/scripts/test.js index 5d83893b53..5b5bac4d68 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -135,7 +135,7 @@ async function runTests() { }); // Ignore some tests not supported by node v18 cp.execSync( - "node tests/docstrings_examples/DocTest.res.mjs --ignore-runtime-tests 'Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference'", + `node ${path.join("tests", "docstrings_examples", "DocTest.res.mjs")} --ignore-runtime-tests 'Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference'`, { cwd: path.join(__dirname, ".."), stdio: [0, 1, 2], From f9bba99f4c88cec0190dd1e3563795e66c0daf15 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 01:20:40 -0300 Subject: [PATCH 08/25] revert changes in Js_{dict,types}.resi --- runtime/Js_dict.resi | 6 ------ runtime/Js_types.resi | 6 +++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/runtime/Js_dict.resi b/runtime/Js_dict.resi index 834be4b206..8baa9407d0 100644 --- a/runtime/Js_dict.resi +++ b/runtime/Js_dict.resi @@ -53,7 +53,6 @@ type key = string ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.get(ages, "Vinh") == Some(22) Js.Dict.get(ages, "Paul") == None ``` @@ -67,7 +66,6 @@ let get: (t<'a>, key) => option<'a> ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.unsafeGet(ages, "Fred") == 49 Js.Dict.unsafeGet(ages, "Paul") // returns undefined ``` @@ -84,7 +82,6 @@ the key does not exist, and entry will be created for it. ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.set(ages, "Maria", 31) Js.log(ages == Js.Dict.fromList(list{("Maria", 31), ("Vinh", 22), ("Fred", 49)})) @@ -101,7 +98,6 @@ Returns all the keys in the dictionary `dict`. ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.keys(ages) == ["Maria", "Vinh", "Fred"] ``` */ @@ -119,7 +115,6 @@ Returns an array of key/value pairs in the given dictionary (ES2017). ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.entries(ages) == [("Maria", 30), ("Vinh", 22), ("Fred", 49)] ``` */ @@ -131,7 +126,6 @@ Returns the values in the given dictionary (ES2017). ## Examples ```rescript -let ages = dict{"Maria": 30, "Vinh": 22, "Fred": 49} Js.Dict.values(ages) == [30, 22, 49] ``` */ diff --git a/runtime/Js_types.resi b/runtime/Js_types.resi index fd969fb9e7..a2faaf8afe 100644 --- a/runtime/Js_types.resi +++ b/runtime/Js_types.resi @@ -55,9 +55,9 @@ This is useful for doing runtime reflection on any given value. ## Examples ```rescript -Js.Types.test("test", String) == true -Js.Types.test(() => true, Function) == true -Js.Types.test("test", Boolean) == false +test("test", String) == true +test(() => true, Function) == true +test("test", Boolean) == false ``` */ let test: ('a, t<'b>) => bool From bf58e7a7be405c11dfba29f293fc5ea6966cde6b Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 01:25:00 -0300 Subject: [PATCH 09/25] use double quotes --- scripts/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.js b/scripts/test.js index 5b5bac4d68..1848f6d2a2 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -135,7 +135,7 @@ async function runTests() { }); // Ignore some tests not supported by node v18 cp.execSync( - `node ${path.join("tests", "docstrings_examples", "DocTest.res.mjs")} --ignore-runtime-tests 'Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference'`, + `node ${path.join("tests", "docstrings_examples", "DocTest.res.mjs")} --ignore-runtime-tests "Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference"`, { cwd: path.join(__dirname, ".."), stdio: [0, 1, 2], From b6a9672793740304b5a354899331f9cfa888dc1f Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 01:29:19 -0300 Subject: [PATCH 10/25] update analysis_tests --- tests/analysis_tests/tests/src/expected/Completion.res.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 1acfee24d4..95a4849357 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -745,7 +745,7 @@ Path Js.Dict.u "kind": 12, "tags": [], "detail": "(t<'a>, key) => 'a", - "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n## Examples\n\n```rescript\nlet ages = dict{\"Maria\": 30, \"Vinh\": 22, \"Fred\": 49}\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n## Examples\n\n```rescript\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"} }, { "label": "unsafeDeleteKey", "kind": 12, From 56d9eaae09b91413bfeb154f055738bcabdf8d31 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 5 Dec 2024 10:45:41 -0300 Subject: [PATCH 11/25] fix Nullable.getExn --- runtime/Nullable.resi | 9 ++++---- tests/docstrings_examples/DocTest.res.mjs | 26 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/runtime/Nullable.resi b/runtime/Nullable.resi index 1e388aa83f..3b93ee1a59 100644 --- a/runtime/Nullable.resi +++ b/runtime/Nullable.resi @@ -147,11 +147,10 @@ switch Nullable.getExn(%raw("null")) { | _ => assert(false) } -// TODO(aspeddro): This example dont pass -// switch Nullable.getExn(%raw("undefined")) { -// | exception Invalid_argument(_) => assert(true) -// | _ => assert(false) -// } +switch Nullable.getExn(%raw("undefined")) { +| exception Invalid_argument(_) => assert(true) +| _ => assert(false) +} ``` ## Exceptions diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index e387a35bb8..b1b7b32794 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -130,18 +130,20 @@ async function runtimeTests(code) { let stdout = match.stdout; let std; let exit = 0; - if (exitCode == null) { - exit = 1; - } else if (exitCode === 0.0 && stderr.length > 0) { - std = { - TAG: "Ok", - _0: stderr - }; - } else if (exitCode === 0.0) { - std = { - TAG: "Ok", - _0: stdout - }; + if (exitCode !== null) { + if (exitCode === 0.0 && stderr.length > 0) { + std = { + TAG: "Ok", + _0: stderr + }; + } else if (exitCode === 0.0) { + std = { + TAG: "Ok", + _0: stdout + }; + } else { + exit = 1; + } } else { exit = 1; } From a6a314954cc4af4768ee9a364d261401ad853d91 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sat, 7 Dec 2024 13:35:19 -0300 Subject: [PATCH 12/25] rename project name --- tests/docstrings_examples/rescript.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docstrings_examples/rescript.json b/tests/docstrings_examples/rescript.json index cb7ab948e4..e987791ab6 100644 --- a/tests/docstrings_examples/rescript.json +++ b/tests/docstrings_examples/rescript.json @@ -1,5 +1,5 @@ { - "name": "core-doc-examples", + "name": "doc-test-examples", "sources": { "dir": "." }, From a18e6049ec7611defbc681d4cc0289df1ccaf943 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sat, 7 Dec 2024 13:39:58 -0300 Subject: [PATCH 13/25] ignore windows --- scripts/test.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/scripts/test.js b/scripts/test.js index 1848f6d2a2..467c647ed3 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -128,19 +128,23 @@ async function runTests() { } if (runtimeDocstrings) { - console.log("Running runtime docstrings tests"); - cp.execSync(`${rescript_exe} build`, { - cwd: path.join(__dirname, "..", "tests/docstrings_examples"), - stdio: [0, 1, 2], - }); - // Ignore some tests not supported by node v18 - cp.execSync( - `node ${path.join("tests", "docstrings_examples", "DocTest.res.mjs")} --ignore-runtime-tests "Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference"`, - { - cwd: path.join(__dirname, ".."), + if (process.platform === "win32") { + console.log("Skipping docstrings tests on Windows"); + } else { + console.log("Running runtime docstrings tests"); + cp.execSync(`${rescript_exe} build`, { + cwd: path.join(__dirname, "..", "tests/docstrings_examples"), stdio: [0, 1, 2], - }, - ); + }); + // Ignore some tests not supported by node v18 + cp.execSync( + `node ${path.join("tests", "docstrings_examples", "DocTest.res.mjs")} --ignore-runtime-tests "Array.toReversed, Array.toSorted, Promise.withResolvers, Set.union, Set.isSupersetOf, Set.isSubsetOf, Set.isDisjointFrom, Set.intersection, Set.symmetricDifference, Set.difference"`, + { + cwd: path.join(__dirname, ".."), + stdio: [0, 1, 2], + }, + ); + } } } From 63e0ea294ef92c32cbce2193510d8dd05fbfab09 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sat, 7 Dec 2024 20:37:48 -0300 Subject: [PATCH 14/25] fix tests for Belt modules --- runtime/Belt_Float.resi | 8 +- runtime/Belt_HashMap.resi | 24 +- runtime/Belt_HashSet.resi | 2 +- runtime/Belt_Id.resi | 11 - runtime/Belt_Int.resi | 16 +- runtime/Belt_List.resi | 37 ++- runtime/Belt_Map.resi | 4 +- runtime/Belt_MapInt.resi | 9 +- runtime/Belt_MapString.resi | 9 +- runtime/Belt_Option.resi | 11 +- runtime/Belt_Result.resi | 10 +- runtime/Belt_Set.resi | 274 ++++++++++++++---- .../tests/src/expected/Completion.res.txt | 10 +- .../expected/CompletionInferValues.res.txt | 16 +- .../tests/src/expected/CompletionJsx.res.txt | 32 +- .../src/expected/CompletionPipeChain.res.txt | 4 +- tests/docstrings_examples/DocTest.res | 10 +- tests/docstrings_examples/DocTest.res.mjs | 8 +- 18 files changed, 345 insertions(+), 150 deletions(-) diff --git a/runtime/Belt_Float.resi b/runtime/Belt_Float.resi index bc6fbf9915..c26327a231 100644 --- a/runtime/Belt_Float.resi +++ b/runtime/Belt_Float.resi @@ -77,7 +77,7 @@ Can be opened in a module to avoid dot-notation (`+.`), however this yields a sh ```rescript open Belt.Float -Js.log(2.0 + 2.0 === 4.0) /* true */ +assert_eq(2.0 + 2.0, 4.0) ``` */ external \"+": (float, float) => float = "%addfloat" @@ -90,7 +90,7 @@ Can be opened in a module to avoid dot-notation (`-.`), however this yields a sh ```rescript open Belt.Float -Js.log(2.0 - 1.0 === 1.0) /* true */ +assert_eq(2.0 - 1.0, 1.0) ``` */ external \"-": (float, float) => float = "%subfloat" @@ -103,7 +103,7 @@ Can be opened in a module to avoid dot-notation (`*.`), however this yields a sh ```rescript open Belt.Float -Js.log(2.0 * 2.0 === 4.0) /* true */ +assert_eq(2.0 * 2.0, 4.0) ``` */ external \"*": (float, float) => float = "%mulfloat" @@ -116,7 +116,7 @@ Can be opened in a module to avoid dot-notation (`/.`), however this yields a sh ```rescript open Belt.Float -Js.log(4.0 / 2.0 === 2.0) /* true */ +assert_eq(4.0 / 2.0, 2.0) ``` */ external \"/": (float, float) => float = "%divfloat" diff --git a/runtime/Belt_HashMap.resi b/runtime/Belt_HashMap.resi index 5a577dd188..790155c65a 100644 --- a/runtime/Belt_HashMap.resi +++ b/runtime/Belt_HashMap.resi @@ -33,11 +33,11 @@ _hash_ functions will have different type. ```rescript type t = int -module I0 = unpack(Belt.Id.hashable(~hash=(a: t) => "&"(a, 0xff_ff), ~eq=(a, b) => a == b)) -let s0: t<_, string, _> = make(~hintSize=40, ~id=module(I0)) +module I0 = unpack(Belt.Id.hashable(~hash=(_: t) => 0xff_ff, ~eq=(a, b) => a == b)) +let s0: Belt.HashMap.t = Belt.HashMap.make(~hintSize=40, ~id=module(I0)) -module I1 = unpack(Belt.Id.hashable(~hash=(a: t) => "&"(a, 0xff), ~eq=(a, b) => a == b)) -let s1: t<_, string, _> = make(~hintSize=40, ~id=module(I1)) +module I1 = unpack(Belt.Id.hashable(~hash=(_: t) => 0xff, ~eq=(a, b) => a == b)) +let s1: Belt.HashMap.t = Belt.HashMap.make(~hintSize=40, ~id=module(I1)) ``` The invariant must be held: for two elements who are _equal_, @@ -48,7 +48,7 @@ it would not mix. ## Examples -```rescript +``` let s0: t let s1: t ``` @@ -58,10 +58,11 @@ We can add elements to the collection: ## Examples ```rescript -let () = { - add(s1, 0, "3") - add(s1, 1, "3") -} +// TODO(aspeddro): doctests should unique for all examples in one docstrins +// let () = { +// Belt.HashMap.set(s0, 0, 3) +// Belt.HashMap.set(s1, 1, "3") +// } ``` Since this is an mutable data strucure, `s1` will contain two pairs. @@ -282,10 +283,13 @@ module IntHash = Belt.Id.MakeHashable({ }) let s0 = Belt.HashMap.make(~hintSize=10, ~id=module(IntHash)) + Belt.HashMap.set(s0, 1, "value1") Belt.HashMap.set(s0, 2, "value2") -Belt.HashMap.reduce(s0, "", (acc, key, value) => acc ++ (", " ++ value)) == "value1, value2" +s0 +->Belt.HashMap.reduce("", (acc, _, value) => acc ++ (", " ++ value)) +->assert_eq(", value1, value2") ``` */ let reduce: (t<'key, 'value, 'id>, 'c, ('c, 'key, 'value) => 'c) => 'c diff --git a/runtime/Belt_HashSet.resi b/runtime/Belt_HashSet.resi index b971f168d6..d4d23c7c5a 100644 --- a/runtime/Belt_HashSet.resi +++ b/runtime/Belt_HashSet.resi @@ -62,7 +62,7 @@ would not mix. ## Examples -```rescript +``` let s0: Belt.HashSet.t let s1: Belt.HashSet.t ``` diff --git a/runtime/Belt_Id.resi b/runtime/Belt_Id.resi index ca23d171b6..1da64ea212 100644 --- a/runtime/Belt_Id.resi +++ b/runtime/Belt_Id.resi @@ -93,17 +93,6 @@ module MakeComparable: ( @deprecated("Use `comparable` instead") let comparableU: (~cmp: ('a, 'a) => int) => module(Comparable with type t = 'a) -/** -## Examples - -```rescript -module C = ( - val Belt.Id.comparable ~cmp:(compare : int -> int -> int) -) -let m = Belt.Set.make(module C) -``` -Note that the name of C can not be ignored -*/ let comparable: (~cmp: ('a, 'a) => int) => module(Comparable with type t = 'a) module type Hashable = { diff --git a/runtime/Belt_Int.resi b/runtime/Belt_Int.resi index 0d64b76458..deafebb67e 100644 --- a/runtime/Belt_Int.resi +++ b/runtime/Belt_Int.resi @@ -32,7 +32,7 @@ Converts a given `int` to a `float`. ## Examples ```rescript -Js.log(Belt.Int.toFloat(1) === 1.0) /* true */ +Belt.Int.toFloat(1)->assert_eq(1.0) ``` */ external toFloat: int => float = "%identity" @@ -43,7 +43,7 @@ Converts a given `float` to an `int`. ## Examples ```rescript -Js.log(Belt.Int.fromFloat(1.0) === 1) /* true */ +Belt.Int.fromFloat(1.0)->assert_eq(1) ``` */ external fromFloat: float => int = "%intoffloat" @@ -54,7 +54,7 @@ Converts a given `string` to an `int`. Returns `Some(int)` when the input is a n ## Examples ```rescript -Js.log(Belt.Int.fromString("1") === Some(1)) /* true */ +Belt.Int.fromString("1")->assert_eq(Some(1)) ``` */ let fromString: string => option @@ -65,7 +65,7 @@ Converts a given `int` to a `string`. Uses the JavaScript `String` constructor u ## Examples ```rescript -Js.log(Belt.Int.toString(1) === "1") /* true */ +Belt.Int.toString(1)->assert_eq("1") ``` */ @val @@ -78,7 +78,7 @@ Addition of two `int` values. Same as the addition from `Pervasives`. ```rescript open Belt.Int -Js.log(2 + 2 === 4) /* true */ +assert_eq(2 + 2, 4) ``` */ external \"+": (int, int) => int = "%addint" @@ -90,7 +90,7 @@ Subtraction of two `int` values. Same as the subtraction from `Pervasives`. ```rescript open Belt.Int -Js.log(2 - 1 === 1) /* true */ +assert_eq(2 - 1, 1) ``` */ external \"-": (int, int) => int = "%subint" @@ -102,7 +102,7 @@ Multiplication of two `int` values. Same as the multiplication from `Pervasives` ```rescript open Belt.Int -Js.log(2 * 2 === 4) /* true */ +assert_eq(2 * 2, 4) ``` */ external \"*": (int, int) => int = "%mulint" @@ -114,7 +114,7 @@ Division of two `int` values. Same as the division from `Pervasives`. ```rescript open Belt.Int -Js.log(4 / 2 === 2); /* true */ +assert_eq(4 / 2, 2) ``` */ external \"/": (int, int) => int = "%divint" diff --git a/runtime/Belt_List.resi b/runtime/Belt_List.resi index 6a29b27b8d..4f66f59f7c 100644 --- a/runtime/Belt_List.resi +++ b/runtime/Belt_List.resi @@ -69,9 +69,12 @@ with care. ## Examples ```rescript -Belt.List.headExn(list{1, 2, 3}) // 1 +Belt.List.headExn(list{1, 2, 3})->assert_eq(1) -Belt.List.headExn(list{}) // Raises an Error +switch Belt.List.headExn(list{}) { // Raises an Error +| exception _ => assert(true) +| _ => assert(false) +} ``` */ let headExn: t<'a> => 'a @@ -97,9 +100,12 @@ with care. ## Examples ```rescript -Belt.List.tailExn(list{1, 2, 3}) // list{2, 3} +Belt.List.tailExn(list{1, 2, 3})->assert_eq(list{2, 3}) -Belt.List.tailExn(list{}) // Raises an Error +switch Belt.List.tailExn(list{}) { // Raises an Error +| exception _ => assert(true) +| _ => assert(false) +} ``` */ let tailExn: t<'a> => t<'a> @@ -142,9 +148,12 @@ length. Use with care. ```rescript let abc = list{"A", "B", "C"} -abc->Belt.List.getExn(1) // "B" +abc->Belt.List.getExn(1)->assert_eq("B") -abc->Belt.List.getExn(4) // Raises an Error +switch abc->Belt.List.getExn(4) { // Raises an Error +| exception _ => assert(true) +| _ => assert(false) +} ``` */ let getExn: (t<'a>, int) => 'a @@ -377,16 +386,14 @@ let reverse: t<'a> => t<'a> let mapReverseU: (t<'a>, 'a => 'b) => t<'b> /** -Equivalent to: - -```res -map(someList, f)->reverse -``` +Equivalent to `Belt.List.map(someList, f)->Belt.List.reverse` ## Examples ```rescript -list{3, 4, 5}->Belt.List.mapReverse(x => x * x) /* list{25, 16, 9} */ +list{3, 4, 5} +->Belt.List.mapReverse(x => x * x) +->assert_eq(list{25, 16, 9}) ``` */ let mapReverse: (t<'a>, 'a => 'b) => t<'b> @@ -861,14 +868,16 @@ Creates a pair of lists; the first list consists of all elements of `someList` t In other words: -```rescript +``` (elementsThatSatisfies, elementsThatDoesNotSatisfy) ``` ## Examples ```rescript -Belt.List.partition(list{1, 2, 3, 4}, x => x > 2) /* (list{3, 4}, list{1, 2}) */ +list{1, 2, 3, 4} +->Belt.List.partition(x => x > 2) +->assert_eq((list{3, 4}, list{1, 2})) ``` */ let partition: (t<'a>, 'a => bool) => (t<'a>, t<'a>) diff --git a/runtime/Belt_Map.resi b/runtime/Belt_Map.resi index 59841d81f1..4b52d5e97c 100644 --- a/runtime/Belt_Map.resi +++ b/runtime/Belt_Map.resi @@ -131,7 +131,9 @@ module IntCmp = Belt.Id.MakeComparable({ let s0 = Belt.Map.fromArray(~id=module(IntCmp), [(4, "4"), (1, "1"), (2, "2"), (3, "")]) -Belt.Map.findFirstBy(s0, (k, v) => k == 4) /* (4, "4") */ +s0 +->Belt.Map.findFirstBy((k, _) => k == 4) +->assert_eq(Some(4, "4")) ``` */ let findFirstBy: (t<'k, 'v, 'id>, ('k, 'v) => bool) => option<('k, 'v)> diff --git a/runtime/Belt_MapInt.resi b/runtime/Belt_MapInt.resi index 34e1fb807c..07042d3bb4 100644 --- a/runtime/Belt_MapInt.resi +++ b/runtime/Belt_MapInt.resi @@ -30,9 +30,14 @@ let findFirstByU: (t<'v>, (key, 'v) => bool) => option<(key, 'v)> `findFirstBy(m, p)` uses funcion `f` to find the first key value pair to match predicate `p`. +## Examples + ```rescript -let s0 = fromArray(~id=module(IntCmp), [(4, "4"), (1, "1"), (2, "2,"(3, ""))]) -findFirstBy(s0, (k, v) => k == 4) == option((4, "4")) +let mapInt = Belt.Map.Int.fromArray([(1, "one"), (2, "two"), (3, "three")]) + +mapInt-> +Belt.Map.Int.findFirstBy((k, v) => k == 1 && v == "one") +->assert_eq(Some(1, "one")) ``` */ let findFirstBy: (t<'v>, (key, 'v) => bool) => option<(key, 'v)> diff --git a/runtime/Belt_MapString.resi b/runtime/Belt_MapString.resi index 3a66652ca4..3080ebc078 100644 --- a/runtime/Belt_MapString.resi +++ b/runtime/Belt_MapString.resi @@ -30,9 +30,14 @@ let findFirstByU: (t<'v>, (key, 'v) => bool) => option<(key, 'v)> `findFirstBy(m, p)` uses funcion `f` to find the first key value pair to match predicate `p`. +## Examples + ```rescript -let s0 = fromArray(~id=module(IntCmp), [(4, "4"), (1, "1"), (2, "2,"(3, ""))]) -findFirstBy(s0, (k, v) => k == 4) == option((4, "4")) +let mapString = Belt.Map.String.fromArray([("1", "one"), ("2", "two"), ("3", "three")]) + +mapString-> +Belt.Map.String.findFirstBy((k, v) => k == "1" && v == "one") +->assert_eq(Some("1", "one")) ``` */ let findFirstBy: (t<'v>, (key, 'v) => bool) => option<(key, 'v)> diff --git a/runtime/Belt_Option.resi b/runtime/Belt_Option.resi index 97f2a5934d..fce7c8f07b 100644 --- a/runtime/Belt_Option.resi +++ b/runtime/Belt_Option.resi @@ -79,9 +79,14 @@ Raises an Error in case `None` is provided. Use with care. ## Examples ```rescript -Belt.Option.getExn(Some(3)) /* 3 */ - -Belt.Option.getExn(None) /* Raises an Error */ +Some(3) +->Belt.Option.getExn +->assert_eq(3) + +switch Belt.Option.getExn(None) { // Raises an exception +| exception _ => assert(true) +| _ => assert(false) +} ``` */ let getExn: option<'a> => 'a diff --git a/runtime/Belt_Result.resi b/runtime/Belt_Result.resi index f3949d7577..1cf6f82b15 100644 --- a/runtime/Belt_Result.resi +++ b/runtime/Belt_Result.resi @@ -39,9 +39,15 @@ type t<'a, 'b> = result<'a, 'b> = ## Examples ```rescript -Belt.Result.getExn(Belt.Result.Ok(42)) == 42 +Belt.Result.Ok(42) +->Belt.Result.getExn +->assert_eq(42) -Belt.Result.getExn(Belt.Result.Error("Invalid data")) /* raises exception */ + +switch Belt.Result.getExn(Belt.Result.Error("Invalid data")) { // raise a exception +| exception _ => assert(true) +| _ => assert(false) +} ``` */ let getExn: t<'a, 'b> => 'a diff --git a/runtime/Belt_Set.resi b/runtime/Belt_Set.resi index 343c7dd0e3..a7cbc9564d 100644 --- a/runtime/Belt_Set.resi +++ b/runtime/Belt_Set.resi @@ -97,7 +97,14 @@ Creates a new set by taking in the comparator ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let set = Belt.Set.make(~id=module(IntCmp)) + +Belt.Set.isEmpty(set)->assert_eq(true) ``` */ let make: (~id: id<'value, 'id>) => t<'value, 'id> @@ -108,9 +115,14 @@ Creates new set from array of elements. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([1, 3, 2, 4], ~id=module(IntCmp)) -s0->Belt.Set.toArray /* [1, 2, 3, 4] */ +s0->Belt.Set.toArray->assert_eq([1, 2, 3, 4]) ``` */ let fromArray: (array<'value>, ~id: id<'value, 'id>) => t<'value, 'id> @@ -127,11 +139,16 @@ Checks if set is empty. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let empty = Belt.Set.fromArray([], ~id=module(IntCmp)) -let notEmpty = Belt.Set.fromArray([1],~id=module(IntCmp)) +let notEmpty = Belt.Set.fromArray([1], ~id=module(IntCmp)) -Belt.Set.isEmpty(empty) /* true */ -Belt.Set.isEmpty(notEmpty) /* false */ +Belt.Set.isEmpty(empty)->assert_eq(true) +Belt.Set.isEmpty(notEmpty)->assert_eq(false) ``` */ let isEmpty: t<_> => bool @@ -142,10 +159,15 @@ Checks if element exists in set. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let set = Belt.Set.fromArray([1, 4, 2, 5], ~id=module(IntCmp)) -set->Belt.Set.has(3) /* false */ -set->Belt.Set.has(1) /* true */ +set->Belt.Set.has(3)->assert_eq(false) +set->Belt.Set.has(1)->assert_eq(true) ``` */ let has: (t<'value, 'id>, 'value) => bool @@ -156,15 +178,22 @@ Adds element to set. If element existed in set, value is unchanged. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.make(~id=module(IntCmp)) + let s1 = s0->Belt.Set.add(1) let s2 = s1->Belt.Set.add(2) let s3 = s2->Belt.Set.add(2) -s0->Belt.Set.toArray /* [] */ -s1->Belt.Set.toArray /* [1] */ -s2->Belt.Set.toArray /* [1, 2] */ -s3->Belt.Set.toArray /* [1,2 ] */ -s2 == s3 /* true */ + +s0->Belt.Set.toArray->assert_eq([]) +s1->Belt.Set.toArray->assert_eq([1]) +s2->Belt.Set.toArray->assert_eq([1, 2]) +s3->Belt.Set.toArray->assert_eq([1, 2]) +assert_eq(s2, s3) ``` */ let add: (t<'value, 'id>, 'value) => t<'value, 'id> @@ -175,10 +204,18 @@ Adds each element of array to set. Unlike `Belt.Set.add`](#add), the reference o ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let set = Belt.Set.make(~id=module(IntCmp)) let newSet = set->Belt.Set.mergeMany([5, 4, 3, 2, 1]) -newSet->Belt.Set.toArray /* [1, 2, 3, 4, 5] */ + +newSet +->Belt.Set.toArray +->assert_eq([1, 2, 3, 4, 5]) ``` */ let mergeMany: (t<'value, 'id>, array<'value>) => t<'value, 'id> @@ -189,14 +226,19 @@ Removes element from set. If element did not exist in set, value is unchanged. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([2,3,1,4,5], ~id=module(IntCmp)) let s1 = s0->Belt.Set.remove(1) let s2 = s1->Belt.Set.remove(3) let s3 = s2->Belt.Set.remove(3) -s1->Belt.Set.toArray /* [2,3,4,5] */ -s2->Belt.Set.toArray /* [2,4,5] */ -s2 == s3 /* true */ +s1->Belt.Set.toArray->assert_eq([2,3,4,5]) +s2->Belt.Set.toArray->assert_eq([2,4,5]) +assert_eq(s2, s3) ``` */ let remove: (t<'value, 'id>, 'value) => t<'value, 'id> @@ -207,10 +249,18 @@ Removes each element of array from set. Unlike [remove](#remove), the reference ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let set = Belt.Set.fromArray([1, 2, 3, 4],~id=module(IntCmp)) let newSet = set->Belt.Set.removeMany([5, 4, 3, 2, 1]) -newSet->Belt.Set.toArray /* [] */ + +newSet +->Belt.Set.toArray +->assert_eq([]) ``` */ let removeMany: (t<'value, 'id>, array<'value>) => t<'value, 'id> @@ -221,10 +271,18 @@ let removeMany: (t<'value, 'id>, array<'value>) => t<'value, 'id> ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) let s1 = Belt.Set.fromArray([5,2,3,1,5,4], ~id=module(IntCmp)) let union = Belt.Set.union(s0, s1) -union->Belt.Set.toArray /* [1,2,3,4,5,6] */ + +union +->Belt.Set.toArray +->assert_eq([1,2,3,4,5,6]) ``` */ let union: (t<'value, 'id>, t<'value, 'id>) => t<'value, 'id> @@ -235,10 +293,19 @@ Returns intersection of two sets. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) let s1 = Belt.Set.fromArray([5,2,3,1,5,4], ~id=module(IntCmp)) + let intersect = Belt.Set.intersect(s0, s1) -intersect->Belt.Set.toArray /* [2,3,5] */ + +intersect +->Belt.Set.toArray +->assert_eq([2,3,5]) ``` */ let intersect: (t<'value, 'id>, t<'value, 'id>) => t<'value, 'id> @@ -249,10 +316,21 @@ Returns elements from first set, not existing in second set. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) let s1 = Belt.Set.fromArray([5,2,3,1,5,4], ~id=module(IntCmp)) -Belt.Set.toArray(Belt.Set.diff(s0, s1)) /* [6] */ -Belt.Set.toArray(Belt.Set.diff(s1,s0)) /* [1,4] */ + +Belt.Set.diff(s0, s1) +->Belt.Set.toArray +->assert_eq([6]) + +Belt.Set.diff(s1,s0) +->Belt.Set.toArray +->assert_eq([1,4]) ``` */ let diff: (t<'value, 'id>, t<'value, 'id>) => t<'value, 'id> @@ -263,12 +341,18 @@ Checks if second set is subset of first set. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) let s1 = Belt.Set.fromArray([5,2,3,1,5,4], ~id=module(IntCmp)) let s2 = Belt.Set.intersect(s0, s1) -Belt.Set.subset(s2, s0) /* true */ -Belt.Set.subset(s2, s1) /* true */ -Belt.Set.subset(s1, s0) /* false */ + +Belt.Set.subset(s2, s0)->assert_eq(true) +Belt.Set.subset(s2, s1)->assert_eq(true) +Belt.Set.subset(s1, s0)->assert_eq(false) ``` */ let subset: (t<'value, 'id>, t<'value, 'id>) => bool @@ -286,10 +370,15 @@ Checks if two sets are equal. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3], ~id=module(IntCmp)) let s1 = Belt.Set.fromArray([3,2,5], ~id=module(IntCmp)) -Belt.Set.eq(s0, s1) /* true */ +Belt.Set.eq(s0, s1)->assert_eq(true) ``` */ let eq: (t<'value, 'id>, t<'value, 'id>) => bool @@ -306,12 +395,20 @@ Applies function `f` in turn to all elements of set in increasing order. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) + let acc = ref(list{}) + s0->Belt.Set.forEach(x => { acc := Belt.List.add(acc.contents, x) }) -acc /* [6,5,3,2] */ + +acc.contents->assert_eq(list{6,5,3,2}) ``` */ let forEach: (t<'value, 'id>, 'value => unit) => unit @@ -325,10 +422,16 @@ Applies function `f` to each element of set in increasing order. Function `f` ha ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([5,2,3,5,6], ~id=module(IntCmp)) -s0->Belt.Set.reduce(list{}, (acc, element) => +s0 +->Belt.Set.reduce(list{}, (acc, element) => acc->Belt.List.add(element) -) /* [6,5,3,2] */ +)->assert_eq(list{6,5,3,2}) ``` */ let reduce: (t<'value, 'id>, 'a, ('a, 'value) => 'a) => 'a @@ -342,10 +445,15 @@ Checks if all elements of the set satisfy the predicate. Order unspecified. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let isEven = x => mod(x, 2) == 0 let s0 = Belt.Set.fromArray([2,4,6,8], ~id=module(IntCmp)) -s0->Belt.Set.every(isEven) /* true */ +s0->Belt.Set.every(isEven)->assert_eq(true) ``` */ let every: (t<'value, 'id>, 'value => bool) => bool @@ -359,10 +467,15 @@ Checks if at least one element of the set satisfies the predicate. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let isOdd = x => mod(x, 2) != 0 let s0 = Belt.Set.fromArray([1,2,4,6,8], ~id=module(IntCmp)) -s0->Belt.Set.some(isOdd) /* true */ +s0->Belt.Set.some(isOdd)->assert_eq(true) ``` */ let some: (t<'value, 'id>, 'value => bool) => bool @@ -376,12 +489,17 @@ Returns the set of all elements that satisfy the predicate. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let isEven = x => mod(x, 2) == 0 let s0 = Belt.Set.fromArray([1,2,3,4,5], ~id=module(IntCmp)) let s1 = s0->Belt.Set.keep(isEven) -s1->Belt.Set.toArray /* [2,4] */ +s1->Belt.Set.toArray->assert_eq([2, 4]) ``` */ let keep: (t<'value, 'id>, 'value => bool) => t<'value, 'id> @@ -395,13 +513,18 @@ Returns a pair of sets, where first is the set of all the elements of set that s ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let isOdd = x => mod(x, 2) != 0 let s0 = Belt.Set.fromArray([1,2,3,4,5], ~id=module(IntCmp)) let (s1, s2) = s0->Belt.Set.partition(isOdd) -s1->Belt.Set.toArray /* [1,3,5] */ -s2->Belt.Set.toArray /* [2,4] */ +s1->Belt.Set.toArray->assert_eq([1,3,5]) +s2->Belt.Set.toArray->assert_eq([2,4]) ``` */ let partition: (t<'value, 'id>, 'value => bool) => (t<'value, 'id>, t<'value, 'id>) @@ -412,9 +535,14 @@ Returns size of the set. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([1,2,3,4], ~id=module(IntCmp)) -s0->Belt.Set.size /* 4 */ +s0->Belt.Set.size->assert_eq(4) ``` */ let size: t<'value, 'id> => int @@ -425,9 +553,14 @@ Returns array of ordered set elements. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.toArray /* [1,2,3,5] */ +s0->Belt.Set.toArray->assert_eq([1,2,3,5]) ``` */ let toArray: t<'value, 'id> => array<'value> @@ -438,9 +571,14 @@ Returns list of ordered set elements. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.toList /* [1,2,3,5] */ +s0->Belt.Set.toList->assert_eq(list{1,2,3,5}) ``` */ let toList: t<'value, 'id> => list<'value> @@ -451,11 +589,16 @@ Returns minimum value of the collection. `None` if collection is empty. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.make(~id=module(IntCmp)) let s1 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.minimum /* None */ -s1->Belt.Set.minimum /* Some(1) */ +s0->Belt.Set.minimum->assert_eq(None) +s1->Belt.Set.minimum->assert_eq(Some(1)) ``` */ let minimum: t<'value, 'id> => option<'value> @@ -466,11 +609,16 @@ Returns minimum value of the collection. `undefined` if collection is empty. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.make(~id=module(IntCmp)) let s1 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.minUndefined /* undefined */ -s1->Belt.Set.minUndefined /* 1 */ +s0->Belt.Set.minUndefined->Js.Undefined.toOption->assert_eq(None) +s1->Belt.Set.minUndefined->Js.Undefined.toOption->assert_eq(Some(1)) ``` */ let minUndefined: t<'value, 'id> => Js.undefined<'value> @@ -481,11 +629,16 @@ Returns maximum value of the collection. `None` if collection is empty. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.make(~id=module(IntCmp)) let s1 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.maximum /* None */ -s1->Belt.Set.maximum /* Some(5) */ +s0->Belt.Set.maximum->assert_eq(None) +s1->Belt.Set.maximum->assert_eq(Some(5)) ``` */ let maximum: t<'value, 'id> => option<'value> @@ -496,11 +649,23 @@ Returns maximum value of the collection. `undefined` if collection is empty. ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.make(~id=module(IntCmp)) let s1 = Belt.Set.fromArray([3,2,1,5], ~id=module(IntCmp)) -s0->Belt.Set.maxUndefined /* undefined */ -s1->Belt.Set.maxUndefined /* 5 */ +s0 +->Belt.Set.maxUndefined +->Js.Undefined.toOption +->assert_eq(None) + +s1 +->Belt.Set.maxUndefined +->Js.Undefined.toOption +->assert_eq(Some(5)) ``` */ let maxUndefined: t<'value, 'id> => Js.undefined<'value> @@ -511,10 +676,15 @@ Returns the reference of the value which is equivalent to value using the compar ## Examples ```rescript +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) + let s0 = Belt.Set.fromArray([1,2,3,4,5], ~id=module(IntCmp)) -s0->Belt.Set.get(3) /* Some(3) */ -s0->Belt.Set.get(20) /* None */ +s0->Belt.Set.get(3)->assert_eq(Some(3)) +s0->Belt.Set.get(20)->assert_eq(None) ``` */ let get: (t<'value, 'id>, 'value) => option<'value> @@ -535,14 +705,18 @@ Returns a tuple `((smaller, larger), present)`, `present` is true when element e ## Examples ```rescript -let s0 = Belt.Set.fromArray([1,2,3,4,5], ~id=module(IntCmp)) +module IntCmp = Belt.Id.MakeComparable({ + type t = int + let cmp = Pervasives.compare +}) -let ((smaller, larger), present) = s0->Belt.Set.split(3) +let s0 = Belt.Set.fromArray([1, 2, 3, 4, 5], ~id=module(IntCmp)) -present /* true */ -smaller->Belt.Set.toArray /* [1,2] */ -larger->Belt.Set.toArray /* [4,5] */ +let ((smaller, larger), present) = s0->Belt.Set.split(3) +present->assert_eq(true) +smaller->Belt.Set.toArray->assert_eq([1,2]) +larger->Belt.Set.toArray->assert_eq([4,5]) ``` */ let split: (t<'value, 'id>, 'value) => ((t<'value, 'id>, t<'value, 'id>), bool) diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 95a4849357..648bf3c2c8 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -10,7 +10,7 @@ Path MyList.m "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nEquivalent to:\n\n```res\nmap(someList, f)->reverse\n```\n\n## Examples\n\n```rescript\nlist{3, 4, 5}->Belt.List.mapReverse(x => x * x) /* list{25, 16, 9} */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nEquivalent to `Belt.List.map(someList, f)->Belt.List.reverse`\n\n## Examples\n\n```rescript\nlist{3, 4, 5}\n->Belt.List.mapReverse(x => x * x)\n->assert_eq(list{25, 16, 9})\n```\n"} }, { "label": "makeBy", "kind": 12, @@ -2340,13 +2340,13 @@ Path Belt.Int.t "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }, { "label": "Belt.Int.toFloat", "kind": 12, "tags": [], "detail": "int => float", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toFloat(1) === 1.0) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nBelt.Int.toFloat(1)->assert_eq(1.0)\n```\n"} }] Complete src/Completion.res 423:19 @@ -2389,7 +2389,7 @@ Path Belt.Result.g "kind": 12, "tags": [], "detail": "t<'a, 'b> => 'a", - "documentation": {"kind": "markdown", "value": "\n`getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception\n\n## Examples\n\n```rescript\nBelt.Result.getExn(Belt.Result.Ok(42)) == 42\n\nBelt.Result.getExn(Belt.Result.Error(\"Invalid data\")) /* raises exception */\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception\n\n## Examples\n\n```rescript\nBelt.Result.Ok(42)\n->Belt.Result.getExn\n->assert_eq(42)\n\n\nswitch Belt.Result.getExn(Belt.Result.Error(\"Invalid data\")) { // raise a exception\n| exception _ => assert(true)\n| _ => assert(false)\n}\n```\n"} }, { "label": "Belt.Result.getWithDefault", "kind": 12, @@ -2473,7 +2473,7 @@ Path Belt.Int.toS "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }] Complete src/Completion.res 463:30 diff --git a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt index ee5375d92f..eeb79e8f04 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt @@ -15,13 +15,13 @@ Path Belt.Int.f "kind": 12, "tags": [], "detail": "string => option", - "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nBelt.Int.fromString(\"1\")->assert_eq(Some(1))\n```\n"} }, { "label": "Belt.Int.fromFloat", "kind": 12, "tags": [], "detail": "float => int", - "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nBelt.Int.fromFloat(1.0)->assert_eq(1)\n```\n"} }] Complete src/CompletionInferValues.res 18:30 @@ -244,13 +244,13 @@ Path Belt.Int.t "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }, { "label": "Belt.Int.toFloat", "kind": 12, "tags": [], "detail": "int => float", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toFloat(1) === 1.0) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nBelt.Int.toFloat(1)->assert_eq(1.0)\n```\n"} }] Complete src/CompletionInferValues.res 50:108 @@ -473,7 +473,7 @@ Path Belt.Int.toS "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }] Complete src/CompletionInferValues.res 98:109 @@ -498,7 +498,7 @@ Path Belt.Int.toS "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }] Complete src/CompletionInferValues.res 102:102 @@ -524,7 +524,7 @@ Path Belt.Int.toS "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }] Complete src/CompletionInferValues.res 106:88 @@ -656,7 +656,7 @@ Path Belt.Int.toSt "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }] Complete src/CompletionInferValues.res 130:26 diff --git a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt index cbb97152b8..e13443b51d 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt @@ -230,49 +230,49 @@ Path Belt.Int. "kind": 12, "tags": [], "detail": "string => option", - "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nBelt.Int.fromString(\"1\")->assert_eq(Some(1))\n```\n"} }, { "label": "Belt.Int.*", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nMultiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 * 2 === 4) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nMultiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 * 2, 4)\n```\n"} }, { "label": "Belt.Int./", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nDivision of two `int` values. Same as the division from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(4 / 2 === 2); /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nDivision of two `int` values. Same as the division from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(4 / 2, 2)\n```\n"} }, { "label": "Belt.Int.toString", "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }, { "label": "Belt.Int.toFloat", "kind": 12, "tags": [], "detail": "int => float", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toFloat(1) === 1.0) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nBelt.Int.toFloat(1)->assert_eq(1.0)\n```\n"} }, { "label": "Belt.Int.fromFloat", "kind": 12, "tags": [], "detail": "float => int", - "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nBelt.Int.fromFloat(1.0)->assert_eq(1)\n```\n"} }, { "label": "Belt.Int.-", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nSubtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 - 1 === 1) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nSubtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 - 1, 1)\n```\n"} }, { "label": "Belt.Int.+", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nAddition of two `int` values. Same as the addition from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 + 2 === 4) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nAddition of two `int` values. Same as the addition from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 + 2, 4)\n```\n"} }] Complete src/CompletionJsx.res 26:14 @@ -310,49 +310,49 @@ Path Belt.Int. "kind": 12, "tags": [], "detail": "string => option", - "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromString(\"1\") === Some(1)) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `string` to an `int`. Returns `Some(int)` when the input is a number, `None` otherwise.\n\n## Examples\n\n```rescript\nBelt.Int.fromString(\"1\")->assert_eq(Some(1))\n```\n"} }, { "label": "Belt.Int.*", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nMultiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 * 2 === 4) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nMultiplication of two `int` values. Same as the multiplication from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 * 2, 4)\n```\n"} }, { "label": "Belt.Int./", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nDivision of two `int` values. Same as the division from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(4 / 2 === 2); /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nDivision of two `int` values. Same as the division from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(4 / 2, 2)\n```\n"} }, { "label": "Belt.Int.toString", "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }, { "label": "Belt.Int.toFloat", "kind": 12, "tags": [], "detail": "int => float", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toFloat(1) === 1.0) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nBelt.Int.toFloat(1)->assert_eq(1.0)\n```\n"} }, { "label": "Belt.Int.fromFloat", "kind": 12, "tags": [], "detail": "float => int", - "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.fromFloat(1.0) === 1) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `float` to an `int`.\n\n## Examples\n\n```rescript\nBelt.Int.fromFloat(1.0)->assert_eq(1)\n```\n"} }, { "label": "Belt.Int.-", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nSubtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 - 1 === 1) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nSubtraction of two `int` values. Same as the subtraction from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 - 1, 1)\n```\n"} }, { "label": "Belt.Int.+", "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": {"kind": "markdown", "value": "\nAddition of two `int` values. Same as the addition from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nJs.log(2 + 2 === 4) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nAddition of two `int` values. Same as the addition from `Pervasives`.\n\n## Examples\n\n```rescript\nopen Belt.Int\nassert_eq(2 + 2, 4)\n```\n"} }] Complete src/CompletionJsx.res 28:20 diff --git a/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt b/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt index 24521a5cf3..e8c6c7036f 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt @@ -351,13 +351,13 @@ Path Belt.Int.t "kind": 12, "tags": [], "detail": "int => string", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toString(1) === \"1\") /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `string`. Uses the JavaScript `String` constructor under the hood.\n\n## Examples\n\n```rescript\nBelt.Int.toString(1)->assert_eq(\"1\")\n```\n"} }, { "label": "Belt.Int.toFloat", "kind": 12, "tags": [], "detail": "int => float", - "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nJs.log(Belt.Int.toFloat(1) === 1.0) /* true */\n```\n"} + "documentation": {"kind": "markdown", "value": "\nConverts a given `int` to a `float`.\n\n## Examples\n\n```rescript\nBelt.Int.toFloat(1)->assert_eq(1.0)\n```\n"} }] Complete src/CompletionPipeChain.res 70:12 diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 94dc93906f..4f6d873a4d 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -134,7 +134,7 @@ let compileTest = async (~id, ~code) => { let () = await Fs.writeFile(tempFileName ++ ".res", code) - let args = [tempFileName ++ ".res", "-w", "-3-109"] + let args = [tempFileName ++ ".res", "-w", "-3-109-44"] let {stderr, stdout} = await SpawnAsync.run(~command=bscBin, ~args) @@ -299,12 +299,8 @@ let main = async () => { let modules = files - // Ignore Belt, Js modules and RescriptTools for now - ->Array.filter(f => - !String.startsWith(f, "Belt") && - !String.startsWith(f, "Js") && - !String.startsWith(f, "RescriptTools") - ) + // Ignore Js modules and RescriptTools for now + ->Array.filter(f => !String.startsWith(f, "Js") && !String.startsWith(f, "RescriptTools")) ->Array.filter(f => f->String.endsWith(".res") || f->String.endsWith(".resi")) ->Array.reduce([], (acc, cur) => { let isInterface = cur->String.endsWith(".resi") diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index b1b7b32794..5c3eae873a 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -98,7 +98,7 @@ async function compileTest(id, code) { let args = [ tempFileName + ".res", "-w", - "-3-109" + "-3-109-44" ]; let match = await run(bscBin, args, undefined); let stderr = match.stderr; @@ -329,10 +329,10 @@ function getCodeBlocks(example) { async function main() { let files = Fs.readdirSync("runtime"); let modules = $$Array.reduce(files.filter(f => { - if (!f.startsWith("Belt") && !f.startsWith("Js")) { - return !f.startsWith("RescriptTools"); - } else { + if (f.startsWith("Js")) { return false; + } else { + return !f.startsWith("RescriptTools"); } }).filter(f => { if (f.endsWith(".res")) { From 2e3b448d1ce6339c078c0ab148d2d4d4b5b25536 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sat, 7 Dec 2024 23:28:25 -0300 Subject: [PATCH 15/25] initial --- runtime/Belt_HashMap.resi | 15 ++- runtime/Belt_HashSet.resi | 2 +- tests/docstrings_examples/DocTest.res | 119 +++++++++-------- tests/docstrings_examples/DocTest.res.mjs | 148 ++++++++++------------ 4 files changed, 143 insertions(+), 141 deletions(-) diff --git a/runtime/Belt_HashMap.resi b/runtime/Belt_HashMap.resi index 790155c65a..2a270a6ec6 100644 --- a/runtime/Belt_HashMap.resi +++ b/runtime/Belt_HashMap.resi @@ -58,11 +58,10 @@ We can add elements to the collection: ## Examples ```rescript -// TODO(aspeddro): doctests should unique for all examples in one docstrins -// let () = { -// Belt.HashMap.set(s0, 0, 3) -// Belt.HashMap.set(s1, 1, "3") -// } +let () = { + Belt.HashMap.set(s0, 0, 3) + Belt.HashMap.set(s1, 1, "3") +} ``` Since this is an mutable data strucure, `s1` will contain two pairs. @@ -291,6 +290,12 @@ s0 ->Belt.HashMap.reduce("", (acc, _, value) => acc ++ (", " ++ value)) ->assert_eq(", value1, value2") ``` + +## More Examples + +```rescript +Console.log("lol") +``` */ let reduce: (t<'key, 'value, 'id>, 'c, ('c, 'key, 'value) => 'c) => 'c diff --git a/runtime/Belt_HashSet.resi b/runtime/Belt_HashSet.resi index d4d23c7c5a..68309c8cbe 100644 --- a/runtime/Belt_HashSet.resi +++ b/runtime/Belt_HashSet.resi @@ -60,7 +60,7 @@ value should be the same. Here the compiler would infer `s0` and `s1` having different type so that it would not mix. -## Examples +Signatures: ``` let s0: Belt.HashSet.t diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 4f6d873a4d..760fa18c32 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -292,6 +292,7 @@ let getCodeBlocks = example => { ->List.fromArray ->loop(list{}) ->List.toArray + ->Array.join("\n") } let main = async () => { @@ -302,6 +303,7 @@ let main = async () => { // Ignore Js modules and RescriptTools for now ->Array.filter(f => !String.startsWith(f, "Js") && !String.startsWith(f, "RescriptTools")) ->Array.filter(f => f->String.endsWith(".res") || f->String.endsWith(".resi")) + // ->Array.filter(f => f == "Belt_HashMap.resi") ->Array.reduce([], (acc, cur) => { let isInterface = cur->String.endsWith(".resi") @@ -322,51 +324,66 @@ let main = async () => { await modules ->Array.map(async example => { let id = example.id->String.replaceAll(".", "_") - let codes = example->getCodeBlocks - let results = - await codes - ->Array.mapWithIndex(async (code, int) => { - let id = `${id}_${Int.toString(int)}` - (code, await compileTest(~id, ~code)) - }) - ->Promise.all - (example, results) + let rescriptCode = example->getCodeBlocks + let jsCode = await compileTest(~id, ~code=rescriptCode) + // let id = `${id}_${Int.toString(int)}` + // let results = + // await [codes] + // ->Array.mapWithIndex(async (code, int) => { + // let id = `${id}_${Int.toString(int)}` + // (code, await compileTest(~id, ~code)) + // }) + // ->Promise.all + (example, (rescriptCode, jsCode)) }) ->Promise.all - let examples = results->Array.map(((example, results)) => { - let (compiled, errors) = results->Array.reduce(([], []), (acc, (resCode, result)) => { - let (oks, errors) = acc - switch result { - | Ok(jsCode) => ([...oks, (resCode, jsCode)], errors) - | Error(output) => (oks, [...errors, ReScript({error: output})]) - } - }) - (example, (compiled, errors)) + // let examples = results->Array.map(((example, result)) => { + // let (compiled, errors) = results->Array.reduce(([], []), (acc, (resCode, result)) => { + // let (oks, errors) = acc + // switch result { + // | Ok(jsCode) => ([...oks, (resCode, jsCode)], errors) + // | Error(output) => (oks, [...errors, ReScript({error: output})]) + // } + // }) + // (example, (compiled, errors)) + // }) + + let (compiled, notCompiled) = results->Array.reduce(([], []), ( + acc, + (example, (rescriptCode, compiled)), + ) => { + let (lhs, rhs) = acc + switch compiled { + | Ok(jsCode) => lhs->Array.push((example, rescriptCode, jsCode)) + | Error(err) => rhs->Array.push((example, ReScript({error: err}))) + } + (lhs, rhs) }) let exampleErrors = - await examples - ->Array.filter((({id}, _)) => !Array.includes(ignoreRuntimeTests, id)) - ->Array.map(async ((example, (compiled, errors))) => { - let nodeTests = - await compiled - ->Array.map(async ((res, js)) => (res, js, await runtimeTests(js))) - ->Promise.all - - let runtimeErrors = nodeTests->Belt.Array.keepMap(((res, js, output)) => - switch output { - | Ok(_) => None - | Error(error) => Some(Runtime({rescript: res, js, error})) - } - ) - - (example, Array.concat(runtimeErrors, errors)) + await compiled + ->Array.filter((({id}, _, _)) => !Array.includes(ignoreRuntimeTests, id)) + ->Array.map(async ((example, compiled, errors)) => { + let nodeTests = await errors->runtimeTests + switch nodeTests { + | Ok(_) => None + | Error(err) => Some(example, Runtime({rescript: compiled, js: errors, error: err})) + } }) ->Promise.all + let exampleErrors = exampleErrors->Array.filterMap(i => + switch i { + | Some(i) => Some(i) + | None => None + } + ) + + let allErros = Array.concat(exampleErrors, notCompiled) + // Print Errors - let () = exampleErrors->Array.forEach(((example, errors)) => { + let () = allErros->Array.forEach(((example, errors)) => { let red = s => `\x1B[1;31m${s}\x1B[0m` let cyan = s => `\x1b[36m${s}\x1b[0m` let kind = switch example.kind { @@ -374,21 +391,21 @@ let main = async () => { | other => other } - let errorMessage = errors->Array.map(err => - switch err { - | ReScript({error}) => - let err = - error - ->String.split("\n") - ->Array.filterWithIndex((_, i) => i !== 2) - ->Array.join("\n") + // let errorMessage = errors->Array.map(err => + let a = switch errors { + | ReScript({error}) => + let err = + error + ->String.split("\n") + ->Array.filterWithIndex((_, i) => i !== 2) + ->Array.join("\n") - `${"error"->red}: failed to compile examples from ${kind} ${example.id->cyan} + `${"error"->red}: failed to compile examples from ${kind} ${example.id->cyan} ${err}` - | Runtime({rescript, js, error}) => - let indent = String.repeat(" ", 2) + | Runtime({rescript, js, error}) => + let indent = String.repeat(" ", 2) - `${"runtime error"->red}: failed to run examples from ${kind} ${example.id->cyan} + `${"runtime error"->red}: failed to run examples from ${kind} ${example.id->cyan} ${indent}${"ReScript"->cyan} @@ -402,13 +419,13 @@ ${indent}${"stacktrace"->red} ${error->indentOutputCode} ` - } - ) + } - errorMessage->Array.forEach(e => Process.stderrWrite(e)) + Process.stderrWrite(a) + // errorMessage->Array.forEach(e => Process.stderrWrite(e)) }) - let someError = exampleErrors->Array.some(((_, err)) => Array.length(err) > 0) + let someError = allErros->Array.length > 0 someError ? 1 : 0 } diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index 5c3eae873a..4385b2ce46 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -9,7 +9,6 @@ import * as $$Array from "rescript/lib/es6/Array.js"; import * as $$Error from "rescript/lib/es6/Error.js"; import * as Belt_List from "rescript/lib/es6/Belt_List.js"; import * as Nodeutil from "node:util"; -import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; import * as Pervasives from "rescript/lib/es6/Pervasives.js"; import * as Child_process from "child_process"; import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; @@ -323,7 +322,7 @@ function getCodeBlocks(example) { continue; }; }; - return List.toArray(loop(List.fromArray($$Array.reduce(example.docstrings, [], (acc, docstring) => acc.concat(docstring.split("\n")))), /* [] */0)); + return List.toArray(loop(List.fromArray($$Array.reduce(example.docstrings, [], (acc, docstring) => acc.concat(docstring.split("\n")))), /* [] */0)).join("\n"); } async function main() { @@ -353,105 +352,86 @@ async function main() { }).map(f => getExamples(extractDocFromFile(Path.join("runtime", f)))).flat(); let results = await Promise.all(modules.map(async example => { let id = example.id.replaceAll(".", "_"); - let codes = getCodeBlocks(example); - let results = await Promise.all(codes.map(async (code, int) => { - let id$1 = id + "_" + int.toString(); - return [ - code, - await compileTest(id$1, code) - ]; - })); + let rescriptCode = getCodeBlocks(example); + let jsCode = await compileTest(id, rescriptCode); return [ example, - results + [ + rescriptCode, + jsCode + ] ]; })); - let examples = results.map(param => { - let match = $$Array.reduce(param[1], [ - [], - [] - ], (acc, param) => { - let errors = acc[1]; - let oks = acc[0]; - let result = param[1]; - if (result.TAG === "Ok") { - return [ - Belt_Array.concatMany([ - oks, - [[ - param[0], - result._0 - ]] - ]), - errors - ]; - } else { - return [ - oks, - Belt_Array.concatMany([ - errors, - [{ - TAG: "ReScript", - error: result._0 - }] - ]) - ]; - } - }); - return [ - param[0], - [ + let match = $$Array.reduce(results, [ + [], + [] + ], (acc, param) => { + let rhs = acc[1]; + let lhs = acc[0]; + let match = param[1]; + let compiled = match[1]; + let example = param[0]; + if (compiled.TAG === "Ok") { + lhs.push([ + example, match[0], - match[1] - ] + compiled._0 + ]); + } else { + rhs.push([ + example, + { + TAG: "ReScript", + error: compiled._0 + } + ]); + } + return [ + lhs, + rhs ]; }); - let exampleErrors = await Promise.all(examples.filter(param => !ignoreRuntimeTests.includes(param[0].id)).map(async param => { - let match = param[1]; - let nodeTests = await Promise.all(match[0].map(async param => { - let js = param[1]; + let exampleErrors = await Promise.all(match[0].filter(param => !ignoreRuntimeTests.includes(param[0].id)).map(async param => { + let errors = param[2]; + let nodeTests = await runtimeTests(errors); + if (nodeTests.TAG === "Ok") { + return; + } else { return [ param[0], - js, - await runtimeTests(js) - ]; - })); - let runtimeErrors = Belt_Array.keepMap(nodeTests, param => { - let output = param[2]; - if (output.TAG === "Ok") { - return; - } else { - return { + { TAG: "Runtime", - rescript: param[0], - js: param[1], - error: output._0 - }; - } - }); - return [ - param[0], - runtimeErrors.concat(match[1]) - ]; + rescript: param[1], + js: errors, + error: nodeTests._0 + } + ]; + } })); - exampleErrors.forEach(param => { + let exampleErrors$1 = $$Array.filterMap(exampleErrors, i => { + if (i !== undefined) { + return i; + } + + }); + let allErros = exampleErrors$1.concat(match[1]); + allErros.forEach(param => { + let errors = param[1]; let example = param[0]; let cyan = s => "\x1b[36m" + s + "\x1b[0m"; let other = example.kind; let kind = other === "moduleAlias" ? "module alias" : other; - let errorMessage = param[1].map(err => { - if (err.TAG === "ReScript") { - let err$1 = err.error.split("\n").filter((param, i) => i !== 2).join("\n"); - return "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(example.id) + "\n" + err$1; - } + let a; + if (errors.TAG === "ReScript") { + let err = errors.error.split("\n").filter((param, i) => i !== 2).join("\n"); + a = "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(example.id) + "\n" + err; + } else { let indent = " ".repeat(2); - return "\x1B[1;31mruntime error\x1B[0m: failed to run examples from " + kind + " " + cyan(example.id) + "\n\n" + indent + "\x1b[36mReScript\x1b[0m\n\n" + indentOutputCode(err.rescript) + "\n\n" + indent + "\x1b[36mCompiled Js\x1b[0m\n\n" + indentOutputCode(err.js) + "\n\n" + indent + "\x1B[1;31mstacktrace\x1B[0m\n\n" + indentOutputCode(err.error) + "\n"; - }); - errorMessage.forEach(e => { - process.stderr.write(e); - }); + a = "\x1B[1;31mruntime error\x1B[0m: failed to run examples from " + kind + " " + cyan(example.id) + "\n\n" + indent + "\x1b[36mReScript\x1b[0m\n\n" + indentOutputCode(errors.rescript) + "\n\n" + indent + "\x1b[36mCompiled Js\x1b[0m\n\n" + indentOutputCode(errors.js) + "\n\n" + indent + "\x1B[1;31mstacktrace\x1B[0m\n\n" + indentOutputCode(errors.error) + "\n"; + } + process.stderr.write(a); }); - let someError = exampleErrors.some(param => param[1].length > 0); + let someError = allErros.length > 0; if (someError) { return 1; } else { From 90cde203e4932ea61fc1e21328bc2ec165033915 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 01:13:03 -0300 Subject: [PATCH 16/25] fix tests --- tests/docstrings_examples/DocTest.res | 78 +++++++++-------------- tests/docstrings_examples/DocTest.res.mjs | 38 +++++------ 2 files changed, 48 insertions(+), 68 deletions(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 760fa18c32..90534adb47 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -194,8 +194,8 @@ let indentOutputCode = code => { } type error = - | ReScript({error: string}) - | Runtime({rescript: string, js: string, error: string}) + | ReScriptError(string) + | RuntimeError({rescript: string, js: string, error: string}) let extractDocFromFile = file => { let toolsBin = Path.join([Process.cwd(), "cli", "rescript-tools"]) @@ -292,7 +292,8 @@ let getCodeBlocks = example => { ->List.fromArray ->loop(list{}) ->List.toArray - ->Array.join("\n") + ->Belt.Array.reverse + ->Array.join("\n\n") } let main = async () => { @@ -303,7 +304,6 @@ let main = async () => { // Ignore Js modules and RescriptTools for now ->Array.filter(f => !String.startsWith(f, "Js") && !String.startsWith(f, "RescriptTools")) ->Array.filter(f => f->String.endsWith(".res") || f->String.endsWith(".resi")) - // ->Array.filter(f => f == "Belt_HashMap.resi") ->Array.reduce([], (acc, cur) => { let isInterface = cur->String.endsWith(".resi") @@ -312,75 +312,56 @@ let main = async () => { // If .resi files exists append to array if !isInterface && Fs.existsSync(resi) { Array.concat(acc, [cur ++ "i"]) + } else if !Array.includes(acc, cur) { + Array.concat(acc, [cur]) } else { - let a = !Array.includes(acc, cur) ? Array.concat(acc, [cur]) : acc - a + acc } }) ->Array.map(f => extractDocFromFile(Path.join(["runtime", f]))->getExamples) ->Array.flat - let results = + let compilationResults = await modules ->Array.map(async example => { - let id = example.id->String.replaceAll(".", "_") + let id = example.id->String.replaceAll(".", "__") let rescriptCode = example->getCodeBlocks let jsCode = await compileTest(~id, ~code=rescriptCode) - // let id = `${id}_${Int.toString(int)}` - // let results = - // await [codes] - // ->Array.mapWithIndex(async (code, int) => { - // let id = `${id}_${Int.toString(int)}` - // (code, await compileTest(~id, ~code)) - // }) - // ->Promise.all (example, (rescriptCode, jsCode)) }) ->Promise.all - // let examples = results->Array.map(((example, result)) => { - // let (compiled, errors) = results->Array.reduce(([], []), (acc, (resCode, result)) => { - // let (oks, errors) = acc - // switch result { - // | Ok(jsCode) => ([...oks, (resCode, jsCode)], errors) - // | Error(output) => (oks, [...errors, ReScript({error: output})]) - // } - // }) - // (example, (compiled, errors)) - // }) - - let (compiled, notCompiled) = results->Array.reduce(([], []), ( + let (compiled, compilationErrors) = compilationResults->Array.reduce(([], []), ( acc, - (example, (rescriptCode, compiled)), + (example, (rescriptCode, jsCode)), ) => { let (lhs, rhs) = acc - switch compiled { + switch jsCode { | Ok(jsCode) => lhs->Array.push((example, rescriptCode, jsCode)) - | Error(err) => rhs->Array.push((example, ReScript({error: err}))) + | Error(err) => rhs->Array.push((example, ReScriptError(err))) } (lhs, rhs) }) - let exampleErrors = - await compiled + let runtimeErrors = + (await compiled ->Array.filter((({id}, _, _)) => !Array.includes(ignoreRuntimeTests, id)) - ->Array.map(async ((example, compiled, errors)) => { - let nodeTests = await errors->runtimeTests + ->Array.map(async ((example, rescriptCode, jsCode)) => { + let nodeTests = await jsCode->runtimeTests switch nodeTests { | Ok(_) => None - | Error(err) => Some(example, Runtime({rescript: compiled, js: errors, error: err})) + | Error(error) => Some(example, RuntimeError({rescript: rescriptCode, js: jsCode, error})) } }) - ->Promise.all - - let exampleErrors = exampleErrors->Array.filterMap(i => - switch i { - | Some(i) => Some(i) - | None => None - } - ) + ->Promise.all) + ->Array.filterMap(i => + switch i { + | Some(i) => Some(i) + | None => None + } + ) - let allErros = Array.concat(exampleErrors, notCompiled) + let allErros = Array.concat(runtimeErrors, compilationErrors) // Print Errors let () = allErros->Array.forEach(((example, errors)) => { @@ -391,18 +372,18 @@ let main = async () => { | other => other } - // let errorMessage = errors->Array.map(err => let a = switch errors { - | ReScript({error}) => + | ReScriptError(error) => let err = error ->String.split("\n") + // Drop line of filename ->Array.filterWithIndex((_, i) => i !== 2) ->Array.join("\n") `${"error"->red}: failed to compile examples from ${kind} ${example.id->cyan} ${err}` - | Runtime({rescript, js, error}) => + | RuntimeError({rescript, js, error}) => let indent = String.repeat(" ", 2) `${"runtime error"->red}: failed to run examples from ${kind} ${example.id->cyan} @@ -422,7 +403,6 @@ ${error->indentOutputCode} } Process.stderrWrite(a) - // errorMessage->Array.forEach(e => Process.stderrWrite(e)) }) let someError = allErros->Array.length > 0 diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index 4385b2ce46..18c4b208e5 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -9,6 +9,7 @@ import * as $$Array from "rescript/lib/es6/Array.js"; import * as $$Error from "rescript/lib/es6/Error.js"; import * as Belt_List from "rescript/lib/es6/Belt_List.js"; import * as Nodeutil from "node:util"; +import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; import * as Pervasives from "rescript/lib/es6/Pervasives.js"; import * as Child_process from "child_process"; import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; @@ -322,7 +323,7 @@ function getCodeBlocks(example) { continue; }; }; - return List.toArray(loop(List.fromArray($$Array.reduce(example.docstrings, [], (acc, docstring) => acc.concat(docstring.split("\n")))), /* [] */0)).join("\n"); + return Belt_Array.reverse(List.toArray(loop(List.fromArray($$Array.reduce(example.docstrings, [], (acc, docstring) => acc.concat(docstring.split("\n")))), /* [] */0))).join("\n\n"); } async function main() { @@ -350,8 +351,8 @@ async function main() { return acc.concat([cur]); } }).map(f => getExamples(extractDocFromFile(Path.join("runtime", f)))).flat(); - let results = await Promise.all(modules.map(async example => { - let id = example.id.replaceAll(".", "_"); + let compilationResults = await Promise.all(modules.map(async example => { + let id = example.id.replaceAll(".", "__"); let rescriptCode = getCodeBlocks(example); let jsCode = await compileTest(id, rescriptCode); return [ @@ -362,27 +363,27 @@ async function main() { ] ]; })); - let match = $$Array.reduce(results, [ + let match = $$Array.reduce(compilationResults, [ [], [] ], (acc, param) => { let rhs = acc[1]; let lhs = acc[0]; let match = param[1]; - let compiled = match[1]; + let jsCode = match[1]; let example = param[0]; - if (compiled.TAG === "Ok") { + if (jsCode.TAG === "Ok") { lhs.push([ example, match[0], - compiled._0 + jsCode._0 ]); } else { rhs.push([ example, { - TAG: "ReScript", - error: compiled._0 + TAG: "ReScriptError", + _0: jsCode._0 } ]); } @@ -391,30 +392,29 @@ async function main() { rhs ]; }); - let exampleErrors = await Promise.all(match[0].filter(param => !ignoreRuntimeTests.includes(param[0].id)).map(async param => { - let errors = param[2]; - let nodeTests = await runtimeTests(errors); + let runtimeErrors = $$Array.filterMap(await Promise.all(match[0].filter(param => !ignoreRuntimeTests.includes(param[0].id)).map(async param => { + let jsCode = param[2]; + let nodeTests = await runtimeTests(jsCode); if (nodeTests.TAG === "Ok") { return; } else { return [ param[0], { - TAG: "Runtime", + TAG: "RuntimeError", rescript: param[1], - js: errors, + js: jsCode, error: nodeTests._0 } ]; } - })); - let exampleErrors$1 = $$Array.filterMap(exampleErrors, i => { + })), i => { if (i !== undefined) { return i; } }); - let allErros = exampleErrors$1.concat(match[1]); + let allErros = runtimeErrors.concat(match[1]); allErros.forEach(param => { let errors = param[1]; let example = param[0]; @@ -422,8 +422,8 @@ async function main() { let other = example.kind; let kind = other === "moduleAlias" ? "module alias" : other; let a; - if (errors.TAG === "ReScript") { - let err = errors.error.split("\n").filter((param, i) => i !== 2).join("\n"); + if (errors.TAG === "ReScriptError") { + let err = errors._0.split("\n").filter((param, i) => i !== 2).join("\n"); a = "\x1B[1;31merror\x1B[0m: failed to compile examples from " + kind + " " + cyan(example.id) + "\n" + err; } else { let indent = " ".repeat(2); From eb83930586276598a78db4d0d1ce47dfc4a50a0d Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 01:16:38 -0300 Subject: [PATCH 17/25] cleanup --- tests/docstrings_examples/DocTest.res | 14 -------------- tests/docstrings_examples/DocTest.res.mjs | 5 +---- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 90534adb47..0226e67c61 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -2,11 +2,6 @@ module Node = { module Path = { @module("path") external join2: (string, string) => string = "join" @module("path") @variadic external join: array => string = "join" - @module("path") external dirname: string => string = "dirname" - } - - module URL = { - @module("url") external fileURLToPath: string => string = "fileURLToPath" } module Process = { @@ -19,14 +14,9 @@ module Node = { } module Fs = { - @module("fs") external readFileSync: string => string = "readFileSync" - @module("fs") external writeFileSync: (string, string) => unit = "writeFileSync" - @module("fs") external mkdirSync: string => option = "mkdirSync" @module("fs") external existsSync: string => bool = "existsSync" @module("fs") external readdirSync: string => array = "readdirSync" @module("node:fs/promises") external writeFile: (string, string) => promise = "writeFile" - @module("node:fs/promises") external unlink: string => promise = "unlink" - @module("node:fs/promises") external lstat: string => promise<'a> = "lstat" } module Buffer = { @@ -35,10 +25,6 @@ module Node = { } module ChildProcess = { - type execSyncOpts = {stdio?: string, cwd?: string} - @module("child_process") - external execFileSync: (string, array, execSyncOpts) => Buffer.t = "execFileSync" - type spawnSyncReturns = {stdout: Buffer.t} @module("child_process") external spawnSync: (string, array) => spawnSyncReturns = "spawnSync" diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index 18c4b208e5..f8467c4e64 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -19,8 +19,6 @@ import * as RescriptTools_Docgen from "rescript/lib/es6/RescriptTools_Docgen.js" let Path$1 = {}; -let URL = {}; - let Process = {}; let Fs$1 = {}; @@ -35,7 +33,6 @@ let Util = {}; let Node = { Path: Path$1, - URL: URL, Process: Process, Fs: Fs$1, Buffer: Buffer, @@ -189,7 +186,7 @@ function extractDocFromFile(file) { RE_EXN_ID: "Assert_failure", _1: [ "DocTest.res", - 212, + 198, 9 ], Error: new Error() From 4b64114124c4bbc6968140bbe6842f70652d96f8 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 01:56:50 -0300 Subject: [PATCH 18/25] use on method --- tests/docstrings_examples/DocTest.res | 3 ++- tests/docstrings_examples/DocTest.res.mjs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 0226e67c61..93f0d4d59d 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -36,6 +36,7 @@ module Node = { external spawn: (string, array, ~options: options=?) => spawnReturns = "spawn" @send external on: (readable, string, Buffer.t => unit) => unit = "on" + @send external onFromSpawn: (spawnReturns, string, Js.Null.t => unit) => unit = "on" @send external once: (spawnReturns, string, (Js.Null.t, Js.Null.t) => unit) => unit = "once" @@ -98,7 +99,7 @@ module SpawnAsync = { spawn.stderr->ChildProcess.on("data", data => { Array.push(stderr, data) }) - spawn->ChildProcess.once("close", (code, _signal) => { + spawn->ChildProcess.onFromSpawn("close", (code) => { resolve({stdout, stderr, code}) }) }) diff --git a/tests/docstrings_examples/DocTest.res.mjs b/tests/docstrings_examples/DocTest.res.mjs index f8467c4e64..4b969fbcb1 100644 --- a/tests/docstrings_examples/DocTest.res.mjs +++ b/tests/docstrings_examples/DocTest.res.mjs @@ -72,7 +72,7 @@ async function run(command, args, options) { spawn.stderr.on("data", data => { stderr.push(data); }); - spawn.once("close", (code, _signal) => resolve({ + spawn.on("close", code => resolve({ stdout: stdout, stderr: stderr, code: code @@ -186,7 +186,7 @@ function extractDocFromFile(file) { RE_EXN_ID: "Assert_failure", _1: [ "DocTest.res", - 198, + 199, 9 ], Error: new Error() From 87605d69e54dec76e39dee275d2175c326add3b9 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 01:59:32 -0300 Subject: [PATCH 19/25] format code --- tests/docstrings_examples/DocTest.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docstrings_examples/DocTest.res b/tests/docstrings_examples/DocTest.res index 93f0d4d59d..c813df6683 100644 --- a/tests/docstrings_examples/DocTest.res +++ b/tests/docstrings_examples/DocTest.res @@ -99,7 +99,7 @@ module SpawnAsync = { spawn.stderr->ChildProcess.on("data", data => { Array.push(stderr, data) }) - spawn->ChildProcess.onFromSpawn("close", (code) => { + spawn->ChildProcess.onFromSpawn("close", code => { resolve({stdout, stderr, code}) }) }) From 46a5d3c4d7b2ec5852ba6b72797200fe953eb3f8 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 13:30:14 -0300 Subject: [PATCH 20/25] test: increase file descriptor limit --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d52e13f72a..cdf20b836a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,6 +314,10 @@ jobs: - name: Version Check run: ./scripts/prebuilt.js + - name: Increase file descriptor limit + if: runner.os == 'macOS' + run: ulimit -n 4096 + - name: Run tests run: node scripts/test.js -all From 945e168d5066a46cd437086b24f24552594a2f71 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 13:41:15 -0300 Subject: [PATCH 21/25] debug --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdf20b836a..07425e2d21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,9 +314,8 @@ jobs: - name: Version Check run: ./scripts/prebuilt.js - - name: Increase file descriptor limit - if: runner.os == 'macOS' - run: ulimit -n 4096 + - name: Debug + run: ulimit -a - name: Run tests run: node scripts/test.js -all From 268c521f7f9911deecc01968b7dc88524dd8b3d1 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 14:11:07 -0300 Subject: [PATCH 22/25] increase max user proc --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07425e2d21..fcbb780350 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -317,6 +317,13 @@ jobs: - name: Debug run: ulimit -a + - name: Increase max user processes + if: runner.os == 'macOS' + run: ulimit -u 62080 + + - name: Debug + run: ulimit -a + - name: Run tests run: node scripts/test.js -all From 16cf8dff97a3c806d37356e45b474943b258daa3 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 14:39:28 -0300 Subject: [PATCH 23/25] tests only on linux --- .github/workflows/ci.yml | 10 ---------- scripts/test.js | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcbb780350..d52e13f72a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,16 +314,6 @@ jobs: - name: Version Check run: ./scripts/prebuilt.js - - name: Debug - run: ulimit -a - - - name: Increase max user processes - if: runner.os == 'macOS' - run: ulimit -u 62080 - - - name: Debug - run: ulimit -a - - name: Run tests run: node scripts/test.js -all diff --git a/scripts/test.js b/scripts/test.js index 467c647ed3..2a50b38567 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -128,8 +128,8 @@ async function runTests() { } if (runtimeDocstrings) { - if (process.platform === "win32") { - console.log("Skipping docstrings tests on Windows"); + if (process.platform !== "linux") { + console.log(`Skipping docstrings tests on ${process.platform}`); } else { console.log("Running runtime docstrings tests"); cp.execSync(`${rescript_exe} build`, { From eef0be67c6a8a94f731c8943659659d753079341 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 14:58:11 -0300 Subject: [PATCH 24/25] new cache --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d52e13f72a..225cc08479 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,7 +151,7 @@ jobs: # matrix.ocaml_compiler may contain commas - name: Get OPAM cache key shell: bash - run: echo "opam_cache_key=opam-env-v5-${{ matrix.os }}-${{ matrix.ocaml_compiler }}-${{ hashFiles('dune-project') }}" | sed 's/,/-/g' >> $GITHUB_ENV + run: echo "opam_cache_key=opam-env-v6-${{ matrix.os }}-${{ matrix.ocaml_compiler }}-${{ hashFiles('dune-project') }}" | sed 's/,/-/g' >> $GITHUB_ENV - name: Restore OPAM environment id: cache-opam-env From 21f88c1a352e60a9480bedff79d6b3092fdbdd52 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Sun, 8 Dec 2024 15:24:07 -0300 Subject: [PATCH 25/25] back to v5 cache --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 225cc08479..d52e13f72a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,7 +151,7 @@ jobs: # matrix.ocaml_compiler may contain commas - name: Get OPAM cache key shell: bash - run: echo "opam_cache_key=opam-env-v6-${{ matrix.os }}-${{ matrix.ocaml_compiler }}-${{ hashFiles('dune-project') }}" | sed 's/,/-/g' >> $GITHUB_ENV + run: echo "opam_cache_key=opam-env-v5-${{ matrix.os }}-${{ matrix.ocaml_compiler }}-${{ hashFiles('dune-project') }}" | sed 's/,/-/g' >> $GITHUB_ENV - name: Restore OPAM environment id: cache-opam-env