Skip to content

Commit 39f16bd

Browse files
committed
Use CommonJS on the playground test, due to the limit of JSOO
1 parent 0067a89 commit 39f16bd

File tree

9 files changed

+318
-11
lines changed

9 files changed

+318
-11
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ jobs:
364364
365365
- name: Test playground compiler
366366
if: matrix.build_playground
367-
run: node playground/playground_test.js
367+
run: node playground/playground_test.cjs
368368

369369
- name: Upload playground compiler to CDN
370370
if: ${{ matrix.build_playground && startsWith(github.ref, 'refs/tags/v') }}

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ playground/stdlib/
7272
playground/*.cmj
7373
playground/*.cmi
7474
playground/.netrc
75-
playground/compiler.js
75+
playground/compiler.*js
7676

7777
rewatch/target/
7878
rewatch/rewatch

CONTRIBUTING.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ $ node
262262

263263
### Testing the Playground bundle
264264

265-
Run `node playground/playground_test.js` for a quick sanity check to see if all the build artifacts are working together correctly. When releasing the playground bundle, the test will always be executed before publishing to catch regressions.
265+
Run `node playground/playground_test.cjs` for a quick sanity check to see if all the build artifacts are working together correctly. When releasing the playground bundle, the test will always be executed before publishing to catch regressions.
266266

267267
### Working on the Playground JS API
268268

@@ -272,7 +272,7 @@ Whenever you are modifying any files in the ReScript compiler, or in the `jsoo_p
272272
make playground
273273
274274
# optionally run your test / arbitrary node script to verify your changes
275-
node playground/playground_test.js
275+
node playground/playground_test.cjs
276276
```
277277

278278
### Publishing the Playground Bundle on our KeyCDN

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ artifacts: lib
6464
# Builds the core playground bundle (without the relevant cmijs files for the runtime)
6565
playground:
6666
dune build --profile browser
67-
cp ./_build/default/compiler/jsoo/jsoo_playground_main.bc.js playground/compiler.js
67+
cp ./_build/default/compiler/jsoo/jsoo_playground_main.bc.js playground/compiler.cjs
6868

6969
# Creates all the relevant core and third party cmij files to side-load together with the playground bundle
7070
playground-cmijs: artifacts
@@ -73,7 +73,7 @@ playground-cmijs: artifacts
7373
# Builds the playground, runs some e2e tests and releases the playground to the
7474
# CDN (requires KEYCDN_USER and KEYCDN_PASSWORD set in the env variables)
7575
playground-release: playground playground-cmijs
76-
node playground/playground_test.js
76+
node playground/playground_test.cjs
7777
sh playground/upload_bundle.sh
7878

7979
format:

cli/rescript/rescript_dump.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// @ts-check
2+
3+
import * as child_process from "node:child_process";
4+
import * as path from "node:path";
5+
6+
import * as arg from "../_args.js";
7+
8+
const dump_usage = `Usage: rescript dump <options> [target]
9+
\`rescript dump\` dumps the information for the target
10+
`;
11+
12+
/**
13+
* @type {arg.specs}
14+
*/
15+
const specs = [];
16+
17+
/**
18+
* @param {string[]} argv
19+
* @param {string} rescript_exe
20+
* @param {string} bsc_exe
21+
*/
22+
export function main(argv, rescript_exe, bsc_exe) {
23+
let target;
24+
arg.parse_exn(dump_usage, argv, specs, xs => {
25+
if (xs.length !== 1) {
26+
arg.bad_arg(`Expect only one target, ${xs.length} found`);
27+
}
28+
target = xs[0];
29+
});
30+
31+
const { ext } = path.parse(target);
32+
if (ext !== ".cmi") {
33+
console.error("Only .cmi target allowed");
34+
process.exit(2);
35+
}
36+
37+
let output = child_process.spawnSync(rescript_exe, ["build", "--", target], {
38+
encoding: "utf-8",
39+
});
40+
if (output.status !== 0) {
41+
console.log(output.stdout);
42+
console.error(output.stderr);
43+
process.exit(2);
44+
}
45+
output = child_process.spawnSync(bsc_exe, [path.join("lib", "bs", target)], {
46+
encoding: "utf-8",
47+
});
48+
console.log(output.stdout.trimEnd());
49+
if (output.status !== 0) {
50+
console.error(output.stderr);
51+
process.exit(2);
52+
}
53+
}

cli/rescript/rescript_format.js

+253
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// @ts-check
2+
3+
import * as child_process from "node:child_process";
4+
import * as crypto from "node:crypto";
5+
import * as fs from "node:fs";
6+
import * as asyncFs from "node:fs/promises";
7+
import * as os from "node:os";
8+
import * as path from "node:path";
9+
import { promisify } from "node:util";
10+
11+
import * as arg from "../_args.js";
12+
13+
const asyncExecFile = promisify(child_process.execFile);
14+
15+
const format_usage = `Usage: rescript format <options> [files]
16+
17+
\`rescript format\` formats the current directory
18+
`;
19+
20+
/**
21+
* @type {arg.stringref}
22+
*/
23+
const stdin = { val: "" };
24+
25+
/**
26+
* @type {arg.boolref}
27+
*/
28+
const format = { val: false };
29+
30+
/**
31+
* @type {arg.boolref}
32+
*/
33+
const check = { val: false };
34+
35+
/**
36+
* @type{arg.specs}
37+
*/
38+
const specs = [
39+
[
40+
"-stdin",
41+
{ kind: "String", data: { kind: "String_set", data: stdin } },
42+
`[.res|.resi] Read the code from stdin and print
43+
the formatted code to stdout in ReScript syntax`,
44+
],
45+
[
46+
"-all",
47+
{ kind: "Unit", data: { kind: "Unit_set", data: format } },
48+
"Format the whole project ",
49+
],
50+
[
51+
"-check",
52+
{ kind: "Unit", data: { kind: "Unit_set", data: check } },
53+
"Check formatting for file or the whole project. Use `-all` to check the whole project",
54+
],
55+
];
56+
const formattedStdExtensions = [".res", ".resi"];
57+
const formattedFileExtensions = [".res", ".resi"];
58+
59+
/**
60+
*
61+
* @param {string[]} extensions
62+
*/
63+
function hasExtension(extensions) {
64+
/**
65+
* @param {string} x
66+
*/
67+
const pred = x => extensions.some(ext => x.endsWith(ext));
68+
return pred;
69+
}
70+
async function readStdin() {
71+
const stream = process.stdin;
72+
const chunks = [];
73+
for await (const chunk of stream) chunks.push(chunk);
74+
return Buffer.concat(chunks).toString("utf8");
75+
}
76+
77+
const _numThreads = os.cpus().length;
78+
79+
/**
80+
* Splits an array into smaller chunks of a specified size.
81+
*
82+
* @template T
83+
* @param {T[]} array - The array to split into chunks.
84+
* @param {number} chunkSize - The size of each chunk.
85+
* @returns {T[][]} - An array of chunks, where each chunk is an array of type T.
86+
*/
87+
function chunkArray(array, chunkSize) {
88+
/** @type {T[][]} */
89+
const result = [];
90+
91+
for (let i = 0; i < array.length; i += chunkSize) {
92+
result.push(array.slice(i, i + chunkSize));
93+
}
94+
95+
return result;
96+
}
97+
98+
/**
99+
* @param {string[]} files
100+
* @param {string} bsc_exe
101+
* @param {(x: string) => boolean} isSupportedFile
102+
* @param {boolean} checkFormatting
103+
*/
104+
async function formatFiles(files, bsc_exe, isSupportedFile, checkFormatting) {
105+
const supportedFiles = files.filter(isSupportedFile);
106+
const batchSize = 4 * os.cpus().length;
107+
const batches = chunkArray(supportedFiles, batchSize);
108+
109+
let incorrectlyFormattedFiles = 0;
110+
try {
111+
for (const batch of batches) {
112+
await Promise.all(
113+
batch.map(async file => {
114+
const flags = checkFormatting
115+
? ["-format", file]
116+
: ["-o", file, "-format", file];
117+
const { stdout } = await asyncExecFile(bsc_exe, flags);
118+
if (check.val) {
119+
const original = await asyncFs.readFile(file, "utf-8");
120+
if (original !== stdout) {
121+
console.error("[format check]", file);
122+
incorrectlyFormattedFiles++;
123+
}
124+
}
125+
}),
126+
);
127+
}
128+
} catch (err) {
129+
console.error(err);
130+
process.exit(2);
131+
}
132+
if (incorrectlyFormattedFiles > 0) {
133+
if (incorrectlyFormattedFiles === 1) {
134+
console.error("The file listed above needs formatting");
135+
} else {
136+
console.error(
137+
`The ${incorrectlyFormattedFiles} files listed above need formatting`,
138+
);
139+
}
140+
process.exit(3);
141+
}
142+
}
143+
144+
/**
145+
* @param {string[]} argv
146+
* @param {string} rescript_exe
147+
* @param {string} bsc_exe
148+
*/
149+
export async function main(argv, rescript_exe, bsc_exe) {
150+
const isSupportedFile = hasExtension(formattedFileExtensions);
151+
const isSupportedStd = hasExtension(formattedStdExtensions);
152+
153+
try {
154+
/**
155+
* @type {string[]}
156+
*/
157+
let files = [];
158+
arg.parse_exn(format_usage, argv, specs, xs => {
159+
files = xs;
160+
});
161+
162+
const format_project = format.val;
163+
const use_stdin = stdin.val;
164+
165+
// Only -check arg
166+
// Require: -all or path to a file
167+
if (check.val && !format_project && files.length === 0) {
168+
console.error(
169+
"format check require path to a file or use `-all` to check the whole project",
170+
);
171+
process.exit(2);
172+
}
173+
174+
if (format_project) {
175+
if (use_stdin || files.length !== 0) {
176+
console.error("format -all can not be in use with other flags");
177+
process.exit(2);
178+
}
179+
// -all
180+
// TODO: check the rest arguments
181+
const output = child_process.spawnSync(
182+
rescript_exe,
183+
["info", "-list-files"],
184+
{
185+
encoding: "utf-8",
186+
},
187+
);
188+
if (output.status !== 0) {
189+
console.error(output.stdout);
190+
console.error(output.stderr);
191+
process.exit(2);
192+
}
193+
files = output.stdout.split("\n").map(x => x.trim());
194+
await formatFiles(files, bsc_exe, isSupportedFile, check.val);
195+
} else if (use_stdin) {
196+
if (check.val) {
197+
console.error("format -stdin cannot be used with -check flag");
198+
process.exit(2);
199+
}
200+
if (isSupportedStd(use_stdin)) {
201+
const filename = path.join(
202+
os.tmpdir(),
203+
`rescript_${crypto.randomBytes(8).toString("hex")}${path.parse(use_stdin).base}`,
204+
);
205+
(async () => {
206+
const content = await readStdin();
207+
const fd = fs.openSync(filename, "wx", 0o600); // Avoid overwriting existing file
208+
fs.writeFileSync(fd, content, "utf8");
209+
fs.closeSync(fd);
210+
process.addListener("exit", () => fs.unlinkSync(filename));
211+
child_process.execFile(
212+
bsc_exe,
213+
["-format", filename],
214+
(error, stdout, stderr) => {
215+
if (error === null) {
216+
process.stdout.write(stdout);
217+
} else {
218+
console.error(stderr);
219+
process.exit(2);
220+
}
221+
},
222+
);
223+
})();
224+
} else {
225+
console.error(`Unsupported extension ${use_stdin}`);
226+
console.error(`Supported extensions: ${formattedStdExtensions} `);
227+
process.exit(2);
228+
}
229+
} else {
230+
if (files.length === 0) {
231+
// none of argumets set
232+
// format the current directory
233+
files = fs.readdirSync(process.cwd()).filter(isSupportedFile);
234+
}
235+
236+
for (const file of files) {
237+
if (!isSupportedStd(file)) {
238+
console.error(`Don't know what do with ${file}`);
239+
console.error(`Supported extensions: ${formattedFileExtensions}`);
240+
process.exit(2);
241+
}
242+
}
243+
await formatFiles(files, bsc_exe, isSupportedFile, check.val);
244+
}
245+
} catch (e) {
246+
if (e instanceof arg.ArgError) {
247+
console.error(e.message);
248+
process.exit(2);
249+
} else {
250+
throw e;
251+
}
252+
}
253+
}

packages/playground-bundling/scripts/generate_cmijs.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function buildCompilerCmij() {
7171

7272
const outputFolder = path.join(PACKAGES_DIR, "compiler-builtins");
7373

74-
const cmijFile = path.join(outputFolder, "cmij.js");
74+
const cmijFile = path.join(outputFolder, "cmij.cjs");
7575

7676
if (!fs.existsSync(outputFolder)) {
7777
fs.mkdirSync(outputFolder, { recursive: true });
@@ -100,7 +100,7 @@ function buildThirdPartyCmijs() {
100100
);
101101
const outputFolder = path.join(PACKAGES_DIR, pkg);
102102

103-
const cmijFile = path.join(outputFolder, "cmij.js");
103+
const cmijFile = path.join(outputFolder, "cmij.cjs");
104104

105105
if (!fs.existsSync(outputFolder)) {
106106
fs.mkdirSync(outputFolder, { recursive: true });

playground/playground_test.js renamed to playground/playground_test.cjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import "./compiler.js";
2-
import "./packages/compiler-builtins/cmij.js";
3-
import "./packages/@rescript/react/cmij.js";
1+
require("./compiler.cjs");
2+
require("./packages/compiler-builtins/cmij.cjs");
3+
require("./packages/@rescript/react/cmij.cjs");
44

55
const compiler = rescript_compiler.make();
66

scripts/test.js

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ if (mochaTest) {
8585
await mocha(["-t", "10000", "tests/tests/**/*_test.mjs"], {
8686
cwd: projectDir,
8787
stdio: "inherit",
88+
shell: true,
8889
});
8990

9091
await node(["tests/tests/src/core/Core_TestSuite.mjs"], {

0 commit comments

Comments
 (0)