Rulebearing Playground Coverage Schemas GitHub

ADR-0062: The Node binding answers extractTSConfig and extractBabelConfig with the caller's own TypeScript and Babel; every other export is the command line's code through rb-node

Context

The coverage tab promises dependency-cruiser's programmatic API under the same names in the Node binding: cruise, format, allExtensions, getAvailableTranspilers, and the four configuration extractors at config-utl/extract-*. Step 22 says each export delegates to rb-cli.

Six of the eight are dependency-cruiser logic that Rulebearing already has in Rust. cruise and format are the command line's cruise and fmt. extractDepcruiseConfig is rb-config's loader with extends merged. extractWebpackResolveConfig is rb-config's sandboxed webpack evaluation. allExtensions and getAvailableTranspilers describe what the extractor reads.

The other two are not dependency-cruiser logic. Upstream's extractTSConfig is TypeScript's own readConfigFile and parseJsonConfigFileContent over the file. It returns TypeScript's ParsedCommandLine, with option enums as numbers, absolute paths, lib as file names, fileNames from files, include and exclude globbing, wildcardDirectories and raw. Upstream's extractBabelConfig is Babel's own loadOptionsSync. It returns Babel's resolved options, with plugins and presets loaded as ConfigItems from the caller's node_modules. Both return {} when the package is not installed. Rulebearing's extractor never needs either object: oxc parses every syntax, and the extractor reads tsconfig.json and Babel's JSON configurations itself.

A Rust version would reimplement TypeScript's and Babel's configuration parsers. Its output could only approximate theirs, and Babel's plugin resolution would need the plugin packages anyway.

Decision

Six exports are Rust, through rb-node. rb-node is a thin napi-rs layer over rb_cli::api, which reaches the command line's own code without argv:

extractTSConfig and extractBabelConfig are upstream's code, ported line for line, run with the caller's typescript and @babel/core.

cruise accepts their results by the file they record. A TypeScript object records options.configFilePath and a Babel object records filename. cruise reads that file itself, so options.tsConfig.fileName or babelConfig.fileName is set from it. An object that records no file is refused, because Rulebearing cannot apply an object it does not read. So is an object whose file differs from the one the options name. Nothing passed in transpileOptions is accepted and then ignored.

The addon ships in each platform package beside the binary, as rulebearing.node. RULEBEARING_ADDON names one to load instead, as RULEBEARING_BINARY does for the launcher. The package's main export becomes the API. The launcher moves to rulebearing/launcher.

unsafe_code is deny in rb-node, not forbid. #[napi] puts its own #[allow(unsafe_code)] on the glue it generates, which forbid refuses. Hand-written unsafe remains an error, and no other crate changes.

Consequences

Alternatives considered

Option Why not
Reimplement TypeScript's and Babel's configuration parsing in Rust Three to four more days for output that could only approximate TypeScript's ParsedCommandLine and Babel's resolved options. Babel's plugin and preset resolution needs the plugin packages regardless. Rulebearing's own extraction never uses either object.
Ship six exports and leave the two out Breaks the coverage tab's "same names" promise for two names that cost a few lines each when they call the caller's own packages, as upstream does.
Apply transpileOptions objects directly Rulebearing's extractor reads files, not TypeScript's or Babel's objects. Applying an object would mean translating TypeScript's and Babel's option models into Rulebearing's, which is the reimplementation above. Ignoring the object silently is forbidden.
A separate @rulebearing/node package @rulebearing is not verified on npm (ADR-0020), and a second package would split one install into two.