CLI Migration Plan
Unify around a single ohm CLI shipped by @ohm-js/compiler, with compile
(wasm-first batch compilation), match (wasm-first), and type generation as the
stable surface.
End-State CLI Surface
Binary name: ohm (from @ohm-js/compiler)
ohm compile <patterns...>
Compiles .ohm sources to wasm artifacts in batch (glob-aware), plus optional
type generation. This is the v18 successor to generateBundles.
Flags:
--cwd <dir>— base directory for glob expansion-o, --outDir <dir>— where to write outputs (default: alongside source)-t, --withTypes— generate corresponding.d.ts-g, --grammarName <name>— compile only one grammar from a multi-grammar file (default: compile all)-n, --dryRun— print/plan without writing--quiet/--verbose
Output naming:
path/to/foo.ohm→path/to/foo.ohm.wasm- With
--withTypes:path/to/foo.ohm.d.ts
ohm match <inputPath>
Wasm-first matching. Accepts either a .wasm artifact or a source .ohm file
(compile-then-match).
Flags:
-g, --grammar <path>—.ohm(compile in-memory, then match) or.wasm(load directly)--grammarName <name>— select grammar from multi-grammar file--startRule <rule>— optional start rule selection
Behavior: exit 0 on success, non-zero with failure message on mismatch.
ohm types <patterns...> (optional)
Standalone type generation, useful when you want .d.ts without emitting wasm.
Flags: --cwd, --outDir, --grammarName, --dryRun
Naming
- Primary verb:
ohm compile(notbuild), since "compile to wasm" is the core v18 story. - No default action — bare
ohmshows help.
Migration Phases
Phase 0: Today
@ohm-js/compilershipsohm2wasm(single-file, no globs/batch)@ohm-js/clishipsohmwithgenerateBundles(v17 recipes) andmatch(v17 runtime)
Phase 1: Introduce unified ohm in the compiler (v18 alpha → early beta)
Goal: make @ohm-js/compiler fully usable as the official CLI.
- Add
ohmbin entry to@ohm-js/compiler, alongsideohm2wasm. - Refactor
ohm2wasmimplementation intoohm compile:- Add glob support via
fast-glob - Add
--outDir,--cwd,--withTypes, batch compilation - If invoked as
ohm2wasm, behave likeohm compile <file>with a deprecation warning.
- Add glob support via
- Implement
ohm matchwasm-first:--grammaraccepts.wasm(load directly) or.ohm(compile-then-match)
- Move
generateTypesinto@ohm-js/compiler(the compiler already bundlesohm-js-legacyinternally via esbuild — use that for type generation without exposing it publicly). - Update docs to recommend
pnpm add -D @ohm-js/compilerandohm compile.
Phase 2: Deprecate @ohm-js/cli (v18 beta)
Goal: keep the old install path working while steering users to the compiler.
- Release a new major of
@ohm-js/clithat:- Depends on
@ohm-js/compiler - Forwards all args to the compiler's
ohmCLI - Prints deprecation warning
- Depends on
- Compatibility mapping:
ohm generateBundles …→ forwards toohm compile …ohm match …→ forwards to compiler'sohm match …
- Deprecate the package on npm.
Phase 3: Compiler CLI is the only real CLI (v18 stable)
@ohm-js/compiler'sohmis the official CLI in all docs.@ohm-js/cliremains as deprecated wrapper only — no new features.generateBundleskept as deprecated alias for one stable cycle.
Phase 4: Clean up (v19 or later)
- Stop publishing
@ohm-js/cli, or keep as permanent thin wrapper. - Optionally remove
ohm2wasmalias, or keep it (low maintenance cost).
Type Generation in v18
The compiler already bundles ohm-js-legacy via esbuild for internal use. Type
generation can reuse this internal representation to produce .d.ts files
without exposing legacy APIs publicly.
- Primary:
ohm compile --withTypes - Optional:
ohm types <patterns...>for CI workflows that want types without wasm
Risks and Guardrails
- Artifact format churn: lock down output naming (
.ohm.wasm,.ohm.d.ts) early. - Multi-grammar files: default is compile all;
--grammarNameselects one. - Dependencies: anything needed at runtime by the CLI (
commander,fast-glob) must be independenciesof@ohm-js/compiler, notdevDependencies. - Node version:
ohm matchwith.ohminput requires Node 24 (same as the compiler). Document clearly.
Future Considerations (not now)
--emit wasm+jsfor generating JS loader modules (depends on v18 runtime loading API stabilizing)--watchmode- Incremental compilation / caching via
--cacheDir