diff --git a/CHANGELOG.md b/CHANGELOG.md index 52cf9afa00..40a15df06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,16 @@ > - :house: [Internal] > - :nail_care: [Polish] +# 10.1.0-rc.4 + +#### :rocket: New Feature + +- Support format check with `rescript format -check`. https://github.com/rescript-lang/rescript-compiler/pull/5760 + +#### :bug: Bug Fix + +- Fix issue where the last line of `rescript format --help` usage was being swallowed https://github.com/rescript-lang/rescript-compiler/pull/5760 + # 10.1.0-rc.3 #### :rocket: New Feature diff --git a/scripts/rescript_arg.js b/scripts/rescript_arg.js index 05a6339ea1..86454ae612 100644 --- a/scripts/rescript_arg.js +++ b/scripts/rescript_arg.js @@ -26,7 +26,7 @@ function bad_arg(s) { /** * @typedef {{val : string}} stringref * @typedef {{val : boolean}} boolref - * @typedef {{kind:"Unit_call",data : ()=>void } | {kind : "Unit_set", data : boolref}}unit_action + * @typedef {{kind:"Unit_call",data : ()=>void } | {kind : "Unit_set", data : boolref}} unit_action * @typedef {{kind:"String_call",data:(s : string)=>void} | {kind : "String_set",data: stringref}} string_action * @typedef {{kind:"Unit",data : unit_action } | {kind:"String", data: string_action}} action * @typedef {Array<[string,action,string]>} specs @@ -67,9 +67,7 @@ function usage_b(b, usage, specs) { cur = i + 1; } } - if (i < specs.length - 1) { - b.add("\n"); - } + b.add("\n"); } } } diff --git a/scripts/rescript_format.js b/scripts/rescript_format.js index 9d8baa9395..b4ac8d587a 100644 --- a/scripts/rescript_format.js +++ b/scripts/rescript_format.js @@ -5,8 +5,11 @@ var format_usage = `Usage: rescript format [files] \`rescript format\` formats the current directory `; var child_process = require("child_process"); +var util = require("node:util"); +var asyncExecFile = util.promisify(child_process.execFile); var path = require("path"); var fs = require("fs"); +var asyncFs = fs.promises; /** * @type {arg.stringref} */ @@ -17,6 +20,11 @@ var stdin = { val: undefined }; */ var format = { val: undefined }; +/** + * @type {arg.boolref} + */ +var check = { val: undefined }; + /** * @type{arg.specs} */ @@ -27,12 +35,16 @@ var specs = [ `[.res|.resi|.ml|.mli] Read the code from stdin and print the formatted code to stdout in ReScript syntax`, ], - // ml|mli [ "-all", { kind: "Unit", data: { kind: "Unit_set", data: format } }, "Format the whole project ", ], + [ + "-check", + { kind: "Unit", data: { kind: "Unit_set", data: check } }, + "Check formatting only", + ], ]; var formattedStdExtensions = [".res", ".resi", ".ml", ".mli"]; var formattedFileExtensions = [".res", ".resi"]; @@ -55,12 +67,55 @@ async function readStdin() { return Buffer.concat(chunks).toString("utf8"); } +/** + * @param {string[]} files + * @param {string} bsc_exe + * @param {(x: string) => boolean} isSupportedFile + * @param {boolean} checkFormatting + */ +async function formatFiles(files, bsc_exe, isSupportedFile, checkFormatting) { + var incorrectlyFormattedFiles = 0; + try { + const _promises = await Promise.all( + files.map(async file => { + if (isSupportedFile(file)) { + const flags = checkFormatting + ? ["-format", file] + : ["-o", file, "-format", file]; + const { stdout } = await asyncExecFile(bsc_exe, flags); + if (check.val) { + const original = await asyncFs.readFile(file, "utf-8"); + if (original != stdout) { + console.error("[format check]", file); + incorrectlyFormattedFiles++; + } + } + } + return null; + }) + ); + } catch (err) { + console.error(err); + process.exit(2); + } + if (incorrectlyFormattedFiles > 0) { + if (incorrectlyFormattedFiles == 1) { + console.error("The file listed above needs formatting"); + } else { + console.error( + `The ${incorrectlyFormattedFiles} files listed above need formatting` + ); + } + process.exit(3); + } +} + /** * @param {string[]} argv * @param {string} rescript_exe * @param {string} bsc_exe */ -function main(argv, rescript_exe, bsc_exe) { +async function main(argv, rescript_exe, bsc_exe) { var isSupportedFile = hasExtension(formattedFileExtensions); var isSupportedStd = hasExtension(formattedStdExtensions); @@ -95,26 +150,12 @@ function main(argv, rescript_exe, bsc_exe) { process.exit(2); } files = output.stdout.split("\n").map(x => x.trim()); - var hasError = false; - for (let arg of files) { - if (isSupportedFile(arg)) { - // console.log(`processing ${arg}`); - child_process.execFile( - bsc_exe, - ["-o", arg, "-format", arg], - (error, _stdout, stderr) => { - if (error !== null) { - console.error(stderr); - hasError = true; - } - } - ); - } - } - if (hasError) { + await formatFiles(files, bsc_exe, isSupportedFile, check.val); + } else if (use_stdin) { + if (check.val) { + console.error("format -stdin cannot be used with -check flag"); process.exit(2); } - } else if (use_stdin) { if (isSupportedStd(use_stdin)) { var crypto = require("crypto"); var os = require("os"); @@ -144,7 +185,7 @@ function main(argv, rescript_exe, bsc_exe) { ); })(); } else { - console.error(`Unsupported exetnsion ${use_stdin}`); + console.error(`Unsupported extension ${use_stdin}`); console.error(`Supported extensions: ${formattedStdExtensions} `); process.exit(2); } @@ -163,24 +204,7 @@ function main(argv, rescript_exe, bsc_exe) { process.exit(2); } } - var hasError = false; - files.forEach(file => { - var write = isSupportedFile(file); - var flags = write ? ["-o", file, "-format", file] : ["-format", file]; - child_process.execFile(bsc_exe, flags, (error, stdout, stderr) => { - if (error === null) { - if (!write) { - process.stdout.write(stdout); - } - } else { - console.error(stderr); - hasError = true; - } - }); - }); - if (hasError) { - process.exit(2); - } + await formatFiles(files, bsc_exe, isSupportedFile, check.val); } } catch (e) { if (e instanceof arg.ArgError) {