mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
- The bundler-CJS rewrite erases recognized __toESM(require("x")) wrappers — module-scope bindings, the `, 1` node-mode variant, inline member reads — down to the bare require at its original offsets; .default accesses pad to the binding where Node's answer is the module (plain-CJS targets, node mode) and stay member reads for __esModule-stamped targets, decided by a require-resolution probe over the target's shipped source (forwarding chains followed)
- Interop the recognizer cannot finish — deviant helper text, escaping interop objects, non-literal arguments, ESM-output calls — answers { degrade }: the fs shadow reports the package as an offender with a note naming the construct and the fallback loop islands it, never a failed build and never the silent alternative (a live helper chain's `var __create = Object.create;` fences at module load while the report claims static); auto and explicit opt-ins share the path
- Bare requires of opted-in packages now behave like relative ones end to end: requireInitStmt emits the dep's inline %init (previously the module never initialized before its exports were read), and cjsLocalModuleBindingOf/resolveValueSymbol resolve member reads and namespace method calls through the npm-static dep's export table
- Erased wrappers join the neutralize set so the helper sweep drops the whole dead chain, hoisted canonical-table texts copied off the source drop .default on module-valued bindings exactly like the pads do, and a file with interop pads but no canonical table still rewrites pads-only
- Fixtures gtcore/gtwrap/gtdrift with cases 2556-toesm-external (byte-matches Node across both dep shapes and the comma-call spelling) and 2557-toesm-drift (construct-naming degrade under explicit and auto opt-ins), excluded from the flagless island lane like the 246x family
77 lines
3.2 KiB
TypeScript
77 lines
3.2 KiB
TypeScript
/* The npm differential case table — npm.test.ts's list, extracted so the
|
|
* Linux lane runs the IDENTICAL cases (same entries, same argv lists)
|
|
* against the in-container Linux Node oracle. The fixture node_modules
|
|
* are COMMITTED TEST DATA; binaries embed the package sources at build
|
|
* time, the Node lane resolves them from the repo mount. */
|
|
import { globSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
export interface NpmCase {
|
|
name: string;
|
|
entry: string;
|
|
/** Every argv list runs both sides; default: one run with no args. */
|
|
argvs?: string[][];
|
|
}
|
|
|
|
export function npmCases(fixturesRoot: string): NpmCase[] {
|
|
return [
|
|
...globSync(join(fixturesRoot, "npm/cases/*/main.ts"))
|
|
.sort()
|
|
// 2465-2469 and 2556-2557 are the --npm-static bundler-emitted-CJS
|
|
// cases (npm-static.test.ts drives them with the opt-in): their
|
|
// consumers exercise the static rewrite's surface (lexer-visible
|
|
// names the shipped .d.ts never declares, the __toESM interop
|
|
// family), so they stay out of the flagless island lane by design.
|
|
.filter((entry) => !/\/(246[5-9]|255[67])-[^/]+\/main\.ts$/.test(entry))
|
|
.map((entry) => ({ name: entry.split("/").at(-2)!, entry })),
|
|
{
|
|
// THE acceptance test: a calculator CLI on the real commander package
|
|
// (pinned in the fixture; see its README), across the happy paths,
|
|
// --version/--help (island process.exit), and the error exits.
|
|
name: "commander-calc",
|
|
entry: join(fixturesRoot, "commander-calc/calc.ts"),
|
|
argvs: [
|
|
["add", "2", "3"],
|
|
["sub", "10", "4.25"],
|
|
["mul", "4", "2.5"],
|
|
["div", "9", "2"],
|
|
["add", "0.1", "0.2"],
|
|
["add", "1e3", "-0.5"],
|
|
// The typed async action (string|undefined + options record + async
|
|
// body): omitted argument -> the undefined arm; option flags ->
|
|
// record fields (missing ones take their undefined arms); the
|
|
// trailing Command argument drops.
|
|
["echo", "hello"],
|
|
["echo"],
|
|
["echo", "hello", "--upper"],
|
|
["echo", "hello", "-p", "say: "],
|
|
["echo", "--upper", "-p", "p: ", "mixed"],
|
|
["--version"],
|
|
["--help"],
|
|
["add", "2"], // missing argument: usage error, exit 1
|
|
["boom"], // unknown command: suggestion error, exit 1
|
|
[], // no command: help to stderr, exit 1
|
|
// The rejecting async action under plain parse(): nobody observes
|
|
// the rejection — the unhandled-rejection report fires, exit 1.
|
|
["fail", "flat tire"],
|
|
],
|
|
},
|
|
{
|
|
// The classic CLI ENTRY LINE: parseAsync's engine promise bridges into a
|
|
// static one; the rejecting async action reaches the inline .catch
|
|
// handler (typed-catch narrowing, stderr message, exit 1) — the full
|
|
// round trip through BOTH promise bridges (the action's static
|
|
// promise wraps into the engine, commander's result promise bridges
|
|
// back out).
|
|
name: "commander-calc-async",
|
|
entry: join(fixturesRoot, "commander-calc/calc-async.ts"),
|
|
argvs: [
|
|
["double", "21"],
|
|
["fail", "flat tire"],
|
|
["--help"],
|
|
["boom"], // unknown command: island process.exit path, exit 1
|
|
],
|
|
},
|
|
];
|
|
}
|