Recursive AI

The oneecma command

All oneecma recipes

Run, check and repair JavaScript from a terminal or a CI job with the oneecma command: the same reports as the library on stderr, JSON on stdout, exit status 1 on an error, and a REPL.

Install

Terminal
dotnet tool install -g RecursiveAI.OneEcma.Cli --version 1.0.0

The 1.0.0 tool needs the .NET runtime 10.0.14 or later; on an older runtime it stops with “You must install or update .NET to run this application.” Without .NET, use a self-contained NativeAOT binary from the v1.0.0 release: win-x64, linux-x64, linux-arm64 and osx-arm64, each with a .sha256 file.

Terminal
curl -sSLO https://github.com/recursive-ai-oss/oneecma-csharp/releases/download/v1.0.0/oneecma-1.0.0-linux-x64.tar.gz
curl -sSL https://github.com/recursive-ai-oss/oneecma-csharp/releases/download/v1.0.0/oneecma-1.0.0-linux-x64.tar.gz.sha256
sha256sum oneecma-1.0.0-linux-x64.tar.gz
tar -xzf oneecma-1.0.0-linux-x64.tar.gz
Text
62ceaf3a44b1e0cdfe3ac255b0d020a79db9023aa9d498220dd0036ab4c04046  oneecma-1.0.0-linux-x64.tar.gz
62ceaf3a44b1e0cdfe3ac255b0d020a79db9023aa9d498220dd0036ab4c04046  oneecma-1.0.0-linux-x64.tar.gz

The binary prints the same reports as the tool. Every example below was run with NO_COLOR=1; on a terminal the reports are in color.

Run a script

area.js misspells a variable:

JS
function area(shape) {
  const { width, height } = shape;
  return width * heigth;
}
area({ width: 3, height: 4 });
Terminal
oneecma run --locals area.js
Text
error[ReferenceError]: heigth is not defined
 --> area.js:3:18
  |
3 |   return width * heigth;
  |                  ^^^^^^ `heigth` is not declared in this scope
  |
  = help: did you mean `height`? (number)
  = stack: area (area.js:3) ← <top-level> (area.js:5)
  = locals in area: shape = { width, height }, width = 3, height = 4

The report goes to stderr and the exit status is 1. --locals adds each frame’s bindings; leave it off for the shorter report. --module runs the file as a module. Scripts get a print function for output:

Text
$ oneecma run fixed.js
2,4,6

The compact report

--compact prints the short form, for a model’s context or a CI log. On the checkout.js from Error reports:

Terminal
oneecma run --compact checkout.js
Text
error[TypeError]: Cannot read properties of undefined (reading 'reduce')
 --> checkout.js:7:23
6 |   const order = await loadOrder(7);
  |                 ------------------ `order` comes from here: { id, lineItems, total }
7 |   const total = order.items.reduce((sum, i) => sum + i.price, 0);
  |                       ^^^^^ `order.items` is undefined
  = help: did you mean `order.lineItems`? (Array, 2 items)

Check without running

check parses and runs the early errors only, and reports every error of the file at once. two.js:

JS
let a = 1;
let a = 2;
let b = ;
Terminal
oneecma check two.js
Text
error[SyntaxError]: Identifier 'a' has already been declared
 --> two.js:2:5
  |
1 | let a = 1;
  |     ----- first declared here
2 | let a = 2;
  |     ^^^^^ declared again here
  |
  = help: rename one of them, or assign with `a = 2` if `a` should change
  = note: not repaired automatically: every fix changes what the program means
  = note: a second error follows: both are reported from one parse
 
error[SyntaxError]: Unexpected token ';'
 --> two.js:3:9
  |
3 | let b = ;
  |         ^ expected an expression before `;`
  |
  = help: give `b` a value, or remove the declaration
 
error: aborting due to 2 syntax errors

The exit status is 1; a file that parses exits 0 with no output. --format json writes the JSON report to stdout instead:

Terminal
oneecma check --format json two.js
Text
{"version":1,"format":"oneecma.report","summary":{"errors":2,"warnings":0,"repairs":0},"diagnostics":[{"kind":"SyntaxError","code":"redeclaration","severity":"error","headline":"Identifier 'a' has already been declared",…

Repair

--repair applies only the syntax fixes that are the single plausible one and still parse. extra.js has one ) too many:

JS
const items = [1, 2, 3];
const doubled = items.map(x => x * 2));
print(doubled);
Terminal
oneecma check --repair --out fixed.js extra.js
Text
repair[R001]: removed an extra closing delimiter
 --> extra.js:2:38
  |
2 | const doubled = items.map(x => x * 2));
  |                                      ^ removed
  |
  = note: the repaired source parses and is returned with this report

The exit status is 0 and fixed.js holds the repaired source. Without --out, the repaired source is printed after the report. The duplicate let a above is not repaired: every fix would change what the program means.

The REPL

oneecma repl takes multi-line input and top-level await; .exit leaves. Here the input is piped in:

Terminal
printf 'let rate;\nrate = await Promise.resolve(0.92);\nconst prices = [10, 25];\nprices.map(p => (p * rate).toFixed(2))\nfunction total(xs) {\n  return xs.reduce((a, b) => a + b, 0);\n}\ntotal(prices)\n.exit\n' | oneecma repl
Text
0.92
[
  "9.20",
  "23.00"
]
35

In 1.0.0 a declaration in an input that uses await doesn’t carry over to the next input, so declare first and assign with await on its own line, as above.

Options

Text
oneecma run [--module] [--locals] [--compact] <file>
oneecma check [--module] [--compact] [--format text|json] [--source-map <map>] [--repair [--out <path>]] <file>
oneecma repl
  • --source-map <map> remaps syntax errors in generated code to the original; check also follows a map comment in the file. See source maps.
  • Color is used only on a terminal and never when NO_COLOR is set.
  • Each repair rule is in the auto-repair table.