@gjsify/rolldown-plugin-gjsify 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,8 +18,34 @@ export const GJS_PROCESS_STUB = 'if(typeof globalThis.process==="undefined"){' +
18
18
  // perf-tracking libs, …). Build it as a named local so we can
19
19
  // attach the property before stashing it on the stub object.
20
20
  'const _h=t=>t?[0,0]:[0,0];_h.bigint=()=>0n;' +
21
+ // `platform`/`arch`, answered LAZILY by the same `uname -sm` probe
22
+ // `@gjsify/process` uses (`packages/node/process/src/internal/uname.ts`),
23
+ // with `@gjsify/utils`' `platform-names.ts` mapping tables inlined minimally
24
+ // — a banner runs before the module system exists and cannot import the
25
+ // canonical ones. Those two are the source of truth; keep this in step or a
26
+ // bundle answers differently depending on whether it pulled
27
+ // `@gjsify/process` in. These used to be the literals `"linux"`/`"x64"`,
28
+ // which is a WRONG answer on two of three OSes rather than a missing one.
29
+ // Lazy, so the cost falls only on a bundle that reads the field AND never
30
+ // loads `@gjsify/process` (whose register replaces this object): nothing is
31
+ // spawned at load. Windows is answered from the environment — `uname` is not
32
+ // on a native Windows PATH, and the env answer is exact.
33
+ 'let _pc;const _p=()=>{if(_pc)return _pc;_pc={platform:"linux",arch:"x64"};' +
34
+ 'try{' +
35
+ 'if(_G.getenv("OS")==="Windows_NT"||_G.getenv("SystemRoot")){' +
36
+ 'const a=(_G.getenv("PROCESSOR_ARCHITECTURE")||"").toLowerCase();' +
37
+ '_pc={platform:"win32",arch:a==="arm64"?"arm64":a==="x86"?"ia32":"x64"};return _pc}' +
38
+ 'const _r=_G.spawn_sync(null,["uname","-sm"],null,_G.SpawnFlags.SEARCH_PATH,null);' +
39
+ 'if(_r&&_r[0]&&_r[1]){const _t=new TextDecoder().decode(_r[1]).trim().split(/\\s+/);' +
40
+ 'if(_t.length>1){const s=_t[0],m=_t[_t.length-1].toLowerCase();' +
41
+ '_pc={platform:s==="Linux"?"linux":s==="Darwin"?"darwin":/^CYGWIN/i.test(s)?"cygwin":' +
42
+ '/^(MINGW|MSYS|Windows)/i.test(s)?"win32":s.toLowerCase(),' +
43
+ 'arch:m==="x86_64"||m==="amd64"?"x64":m==="aarch64"||m==="arm64"?"arm64":' +
44
+ '/^i[3-6]86$/.test(m)?"ia32":m.startsWith("arm")?"arm":m}}}' +
45
+ '}catch(e){/* no GLib spawn, or spawn refused: the linux/x64 fallback stands */}' +
46
+ 'return _pc};' +
21
47
  'globalThis.process={' +
22
- 'platform:"linux",arch:"x64",version:"v20.0.0",' +
48
+ 'get platform(){return _p().platform},get arch(){return _p().arch},version:"v20.0.0",' +
23
49
  'env:new Proxy({},{' +
24
50
  'get(_,p){return typeof p==="string"?(_G.getenv(p)??undefined):undefined},' +
25
51
  'set(_,p,v){if(typeof p==="string")_G.setenv(p,String(v),true);return true},' +
@@ -2,45 +2,25 @@ import type { Plugin } from 'rolldown';
2
2
  export declare const REWRITE_FILTER: RegExp;
3
3
  /** True when the rewriter wants to look at this path — node_modules + supported ext. */
4
4
  export declare function shouldRewrite(path: string): boolean;
5
- /**
6
- * Compute the directory the bundle's outfile lives in (used for the zip-resident
7
- * check and the legacy relative paths). Both `output.file` and `output.dir` are
8
- * accepted.
9
- */
5
+ /** The directory the bundle's outfile lives in, from `output.file` or `output.dir`. */
10
6
  export declare function getBundleDirFromOutput(opts: {
11
7
  file?: string;
12
8
  dir?: string;
13
9
  }): string;
14
10
  /**
15
- * The package-qualified spec for a node_modules file: everything after the LAST
16
- * `node_modules/` segment. This is what the runtime resolver feeds to
17
- * `createRequire(...).resolve` (via the package root).
11
+ * The package-qualified spec for a node_modules file — everything after the LAST
12
+ * `node_modules/` segment, which is what the runtime resolver feeds to
13
+ * `createRequire(...).resolve`. Always a module SPECIFIER, so always `/`-separated:
18
14
  *
19
- * ".../node_modules/typedoc/dist/lib/app.js" → "typedoc/dist/lib/app.js"
20
15
  * ".../node_modules/@scope/name/sub.js" → "@scope/name/sub.js"
21
16
  * ".../node_modules/a/node_modules/b/file.js" → "b/file.js"
22
17
  *
23
- * The result is a module SPECIFIER, not a path, so it is always `/`-separated.
24
- *
25
- * On win32 the incoming path is `C:\…\node_modules\typescript\lib\_tsc.js` and
26
- * the `node_modules/` marker never matched, so this returned the ABSOLUTE
27
- * BUILD-MACHINE PATH unchanged — and `shouldRewrite` above tests
28
- * `includes('node_modules')` without a separator, so the rewriter still fired
29
- * and baked that path into the bundle as the runtime resolve spec. Measured on
30
- * win32 x64 building `@gjsify/tsc`:
31
- *
32
- * linux: To(`typescript/lib/_tsc.js`) → retargets
33
- * win32: To(`C:\\src\\werkstatt\\gjsify\\gjsify\\node_mod…`) → unshippable
34
- *
35
- * `@gjsify/tsc`'s `scripts/build-bundle.mjs` caught it ("expected runtime
36
- * path-rewrite spec … not found in bundle — has the node-modules path rewriter
37
- * changed?") and refused to ship, which is why this surfaced as a build failure
38
- * rather than as a bundle that resolves nothing on someone else's machine.
39
- *
40
- * The conversion is win32-ONLY: on POSIX a backslash is a legitimate FILENAME
41
- * character, so rewriting it there would corrupt a real path. `platform` is
42
- * injected so both branches are unit-testable from either host — the same shape
43
- * `utils/entry-points.ts` and `cli/src/utils/win32-command.ts` use.
18
+ * The separator conversion is win32-ONLY (on POSIX a backslash is a legitimate FILENAME
19
+ * character). Without it a win32 path never matched the `node_modules/` marker and this
20
+ * returned the absolute BUILD-MACHINE path — which `shouldRewrite`, testing
21
+ * `includes('node_modules')` with no separator, still let through into the bundle as
22
+ * the runtime resolve spec. `platform` is injected so both branches are unit-testable
23
+ * from either host.
44
24
  */
45
25
  export declare function extractPackageSpec(path: string, platform?: string): string;
46
26
  export interface RewriteResult {
@@ -49,12 +29,8 @@ export interface RewriteResult {
49
29
  map?: null;
50
30
  }
51
31
  /**
52
- * Pure rewriter. Returns the rewritten code (and module type for re-parsing) or
53
- * `null` if the file references none of the patterns we care about.
54
- *
55
- * @param runtimeResolve When true (ESM output, banner present), on-disk ESM
56
- * files resolve their location at runtime (case 1). When false, they fall back
57
- * to the legacy build-relative rewrite (case 2).
32
+ * Pure rewriter: the rewritten code plus the module type to re-parse it with, or `null`
33
+ * when the file references none of the tokens.
58
34
  */
59
35
  export declare function rewriteContents(args: {
60
36
  path: string;
@@ -4,75 +4,32 @@
4
4
  // runtime data-file reads (a dep loading its own i18n JSON, `package.json`,
5
5
  // templates, …) still resolve.
6
6
  //
7
- // Cases, each with its own strategy:
7
+ // Four cases, dispatched in `rewriteContents`; each strategy's rationale sits on its
8
+ // `rewrite*` function:
8
9
  //
9
- // 1. on-disk ESM, runtime-resolve (`import.meta.url` present, not zip-resident,
10
- // `format === 'esm'`)
11
- // → rewrite to RUNTIME resolution via the `module-resolve` shim. The shim
12
- // resolves the file's `<pkg>/<subpath>` from the bundle's actual location
13
- // at run time, so the bundle works wherever it ends up — crucially, after
14
- // being PUBLISHED in an npm package (where it sits at a different
15
- // `node_modules` depth than at build time). See module-resolve.ts. Relies
16
- // on the bundle-URL banner (bundle-url-banner.ts) having captured the
17
- // anchor, hence the `runtimeResolve` gate.
10
+ // 1. on-disk ESM + `runtimeResolve` → resolve at RUNTIME via the module-resolve shim
11
+ // (location-independent, survives publishing). Needs the bundle-URL banner, hence
12
+ // the gate.
13
+ // 2. on-disk ESM, non-ESM output (no banner) → legacy path relative to the bundle's
14
+ // BUILD location.
15
+ // 3. PnP zip-resident → `import.meta.url` stays the bundle's own URL.
16
+ // 4. CJS (no `import.meta.url`) → 4a runtime-resolve when the banner is available AND
17
+ // the file is a genuinely installed package, else 4b baked absolute path.
18
18
  //
19
- // 2. on-disk ESM, legacy (same, but a non-ESM output format where the banner
20
- // can't run)
21
- // → the original behavior: rewrite to a path relative to the bundle's BUILD
22
- // location. Correct only while bundle ↔ node_modules keep their build-time
23
- // arrangement; preserved unchanged for the rare `--format iife|cjs` app
24
- // build that can't host the `import.meta.url` anchor banner.
25
- //
26
- // 3. PnP zip-resident (`import.meta.url`, path inside a `.zip/`)
27
- // → the file lives inside a Yarn-PnP zip; `import.meta.url` stays the
28
- // bundle's own URL and `__dirname`/`__filename` derive from it.
29
- //
30
- // 4. CJS (`__dirname`/`__filename` only, no `import.meta.url`)
31
- // → case 4a (runtime-resolve) when `runtimeResolve` is on (ESM output +
32
- // bundle-URL banner present) AND the file is a genuinely resolvable
33
- // installed package (`isRuntimeResolvable`). Declares `__dirname`/
34
- // `__filename` from the RUNTIME module-resolve shim — the same
35
- // location-independent strategy as case (1), so the bundle works after
36
- // being published/relocated. This is what lets `@gjsify/tsc` find its
37
- // `lib.*.d.ts` files relative to the INSTALLED bundle (via
38
- // `getExecutingFilePath()` → `__filename`) instead of the build
39
- // machine's `node_modules` path. The shim functions are pulled in with a
40
- // CJS `require(...)`, NOT an ESM `import` header: Rolldown classifies a
41
- // node_modules file by its own heuristics, and a genuine CommonJS file
42
- // (a `.cjs`, or a `.js` with `module.exports` like `typescript/lib/
43
- // _tsc.js`) is parsed as a CJS script — a prepended ESM `import` there
44
- // throws `Cannot use import statement outside a module`. `require(...)`
45
- // is the native CJS idiom Rolldown resolves + links to the bundled shim.
46
- // → case 4b (legacy baked absolute path) otherwise: when `runtimeResolve`
47
- // is OFF (the rare `--format iife|cjs` build that can't host the
48
- // bundle-URL banner) OR the file is NOT a resolvable installed package
49
- // (a relative-imported module under a `node_modules`-named dir that the
50
- // package manager — Yarn PnP especially — does not resolve). Runtime
51
- // resolution of such a file would collapse `__filename` to the bundle's
52
- // own location, so the build-time absolute path is the correct value for
53
- // an in-place run. Build-location-coupled — shares the "breaks when
54
- // published" class of bug, but a non-installed file can't be published
55
- // as a package anyway.
56
- //
57
- // Hosting: a Rolldown `transform(code, id)` hook with `order: 'post'` — runs
58
- // after deepkit/blueprint/css pre-transforms but still during module loading,
59
- // before chunking.
19
+ // Hosted as a `transform(code, id)` hook with `order: 'post'`: after the
20
+ // deepkit/blueprint/css pre-transforms, still during module loading, before chunking.
60
21
  import { createRequire } from 'node:module';
61
22
  import { dirname, join, relative, resolve } from 'node:path';
62
23
  import { inlineStaticReads } from '../utils/inline-static-reads.js';
63
24
  export const REWRITE_FILTER = /\.(m?js|cjs|[cm]?tsx?)$/;
64
25
  const DIRNAME_DECL_RE = /(?:var|let|const)\s+__dirname\b|export\s+(?:var|let|const)\s+__dirname\b/;
65
26
  const FILENAME_DECL_RE = /(?:var|let|const)\s+__filename\b|export\s+(?:var|let|const)\s+__filename\b/;
66
- // Bare specifier of the runtime module-path resolver shim (see module-resolve.ts).
67
- // No `.js` — must match the package's `exports` subpath key (exports maps are
68
- // exact-match), mirroring the `./shims/console-gjs` convention.
27
+ // No `.js`: must match the package's `exports` subpath key, which is exact-match.
69
28
  const MODULE_RESOLVE_SHIM = '@gjsify/rolldown-plugin-gjsify/shims/module-resolve';
70
- // Our own shims (module-resolve, console-gjs) get bundled into user output, so
71
- // they live in `node_modules/@gjsify/rolldown-plugin-gjsify/{lib,src}/shims/`
72
- // when consumed — but they must NEVER be rewritten. In particular the
73
- // module-resolve shim DECLARES `__gjsifyModule*` and its comments mention
74
- // `import.meta.url`; the naive token check below would otherwise treat that as
75
- // a rewrite target and prepend a self-import that collides with its exports.
29
+ // Our own shims are bundled into user output and so live under a `node_modules/…/shims/`
30
+ // path when consumed, but must NEVER be rewritten: the module-resolve shim DECLARES
31
+ // `__gjsifyModule*` and mentions `import.meta.url`, so the token check below would
32
+ // prepend a self-import that collides with its own exports.
76
33
  const GJSIFY_SHIM_RE = /[\\/]rolldown-plugin-gjsify[\\/](?:lib|src)[\\/]shims[\\/]/;
77
34
  /** True when the rewriter wants to look at this path — node_modules + supported ext. */
78
35
  export function shouldRewrite(path) {
@@ -82,11 +39,7 @@ export function shouldRewrite(path) {
82
39
  return false;
83
40
  return true;
84
41
  }
85
- /**
86
- * Compute the directory the bundle's outfile lives in (used for the zip-resident
87
- * check and the legacy relative paths). Both `output.file` and `output.dir` are
88
- * accepted.
89
- */
42
+ /** The directory the bundle's outfile lives in, from `output.file` or `output.dir`. */
90
43
  export function getBundleDirFromOutput(opts) {
91
44
  const outFile = opts.file ?? join(opts.dir ?? '.', 'bundle.mjs');
92
45
  return dirname(resolve(outFile));
@@ -97,35 +50,19 @@ function moduleTypeForPath(path) {
97
50
  return ['ts', 'mts', 'cts', 'tsx'].includes(ext) ? 'ts' : 'js';
98
51
  }
99
52
  /**
100
- * The package-qualified spec for a node_modules file: everything after the LAST
101
- * `node_modules/` segment. This is what the runtime resolver feeds to
102
- * `createRequire(...).resolve` (via the package root).
53
+ * The package-qualified spec for a node_modules file — everything after the LAST
54
+ * `node_modules/` segment, which is what the runtime resolver feeds to
55
+ * `createRequire(...).resolve`. Always a module SPECIFIER, so always `/`-separated:
103
56
  *
104
- * ".../node_modules/typedoc/dist/lib/app.js" → "typedoc/dist/lib/app.js"
105
57
  * ".../node_modules/@scope/name/sub.js" → "@scope/name/sub.js"
106
58
  * ".../node_modules/a/node_modules/b/file.js" → "b/file.js"
107
59
  *
108
- * The result is a module SPECIFIER, not a path, so it is always `/`-separated.
109
- *
110
- * On win32 the incoming path is `C:\…\node_modules\typescript\lib\_tsc.js` and
111
- * the `node_modules/` marker never matched, so this returned the ABSOLUTE
112
- * BUILD-MACHINE PATH unchanged — and `shouldRewrite` above tests
113
- * `includes('node_modules')` without a separator, so the rewriter still fired
114
- * and baked that path into the bundle as the runtime resolve spec. Measured on
115
- * win32 x64 building `@gjsify/tsc`:
116
- *
117
- * linux: To(`typescript/lib/_tsc.js`) → retargets
118
- * win32: To(`C:\\src\\werkstatt\\gjsify\\gjsify\\node_mod…`) → unshippable
119
- *
120
- * `@gjsify/tsc`'s `scripts/build-bundle.mjs` caught it ("expected runtime
121
- * path-rewrite spec … not found in bundle — has the node-modules path rewriter
122
- * changed?") and refused to ship, which is why this surfaced as a build failure
123
- * rather than as a bundle that resolves nothing on someone else's machine.
124
- *
125
- * The conversion is win32-ONLY: on POSIX a backslash is a legitimate FILENAME
126
- * character, so rewriting it there would corrupt a real path. `platform` is
127
- * injected so both branches are unit-testable from either host — the same shape
128
- * `utils/entry-points.ts` and `cli/src/utils/win32-command.ts` use.
60
+ * The separator conversion is win32-ONLY (on POSIX a backslash is a legitimate FILENAME
61
+ * character). Without it a win32 path never matched the `node_modules/` marker and this
62
+ * returned the absolute BUILD-MACHINE path — which `shouldRewrite`, testing
63
+ * `includes('node_modules')` with no separator, still let through into the bundle as
64
+ * the runtime resolve spec. `platform` is injected so both branches are unit-testable
65
+ * from either host.
129
66
  */
130
67
  export function extractPackageSpec(path, platform = process.platform) {
131
68
  const normalized = platform === 'win32' ? path.replaceAll('\\', '/') : path;
@@ -144,26 +81,19 @@ function packageNameOf(spec) {
144
81
  return parts.slice(0, segments).join('/');
145
82
  }
146
83
  /**
147
- * Whether the runtime module-resolve shim can actually resolve this file's
148
- * package at runtime — i.e. it is a genuinely *installed*, resolvable package
149
- * rather than a file that merely lives under a `node_modules`-named directory.
84
+ * Can the runtime module-resolve shim actually resolve this file's package — is it a
85
+ * genuinely INSTALLED package rather than a file merely living under a
86
+ * `node_modules`-named directory?
150
87
  *
151
- * The CJS runtime-resolve (case 4a) resolves `__dirname`/`__filename` by
152
- * resolving the dep's package root from the bundle's location. That only works
153
- * for a real installed package (`typescript`, `@gjsify/tsc`, a normal npm dep).
154
- * A file reached via a RELATIVE import into a `node_modules`-named folder that
155
- * is NOT a resolvable package (e.g. a test fixture at
156
- * `fixtures/node_modules/fake-cjs/index.cjs`, or any dir not in the
157
- * package manager's resolution graph — Yarn PnP especially rejects these)
158
- * would resolve to the bundle's own location at runtime → wrong `__filename`.
159
- * For those we fall back to the legacy baked-absolute-path rewrite (case 4b),
160
- * which is build-location-coupled but correct for an in-place run.
88
+ * Case 4a resolves `__dirname`/`__filename` through the dep's package root, which only
89
+ * works for a real installed package. A file reached by a relative import into a
90
+ * `node_modules`-named folder outside the package manager's resolution graph (a test
91
+ * fixture; Yarn PnP especially rejects these) would resolve to the BUNDLE's own location
92
+ * at runtime, so those take the build-location-coupled case 4b instead.
161
93
  *
162
- * Probed at BUILD time with `createRequire(<file>).resolve("<pkg>/package.json")`
163
- * anchored at the file itself — succeeds iff the package is installed and
164
- * reachable (honours node_modules walking AND Yarn PnP, since the build runs
165
- * under the consumer's loader). Best-effort: any throw → treat as not
166
- * resolvable (fall back to the absolute rewrite, never crash the build).
94
+ * Probed at BUILD time via `createRequire(<file>).resolve(...)` anchored at the file, so
95
+ * it honours node_modules walking AND Yarn PnP. Best-effort: any throw counts as not
96
+ * resolvable rather than crashing the build.
167
97
  */
168
98
  function isRuntimeResolvable(path) {
169
99
  const pkg = packageNameOf(extractPackageSpec(path));
@@ -175,8 +105,8 @@ function isRuntimeResolvable(path) {
175
105
  }
176
106
  catch {
177
107
  try {
178
- // Some strict `exports` maps block `<pkg>/package.json` — fall back
179
- // to resolving the package's main entry, which is always exported.
108
+ // Some strict `exports` maps block `<pkg>/package.json`; the main entry is
109
+ // always exported.
180
110
  createRequire(path).resolve(pkg);
181
111
  return true;
182
112
  }
@@ -198,15 +128,13 @@ function withPreamble(src, lines, importHeader) {
198
128
  return parts.join('\n');
199
129
  }
200
130
  /**
201
- * Case 1 — on-disk ESM, runtime-resolve. Rewrite the file to resolve its own
202
- * location at runtime via the module-resolve shim — location-independent, so it
203
- * survives being published/relocated. The fix for the "works in the workspace,
204
- * crashes once installed" class of bug.
131
+ * Case 1 — on-disk ESM, runtime-resolve. The file resolves its own location at runtime
132
+ * via the module-resolve shim, so it survives being published or relocated: the fix for
133
+ * the "works in the workspace, crashes once installed" class of bug.
205
134
  */
206
135
  function rewriteOnDiskEsm(src, path, flags) {
207
136
  const spec = JSON.stringify(extractPackageSpec(path));
208
- // Collect only the named imports we actually use — tree-shaking has nothing
209
- // to prune and the import line stays honest.
137
+ // Import only what is used, so tree-shaking has nothing to prune.
210
138
  const used = ['__gjsifyModuleUrl'];
211
139
  const preamble = [];
212
140
  if (needsDirnameDecl(src, flags)) {
@@ -222,8 +150,9 @@ function rewriteOnDiskEsm(src, path, flags) {
222
150
  return { code: withPreamble(code, preamble, header), moduleType: moduleTypeForPath(path) };
223
151
  }
224
152
  /**
225
- * Case 2 — on-disk ESM, legacy. Original build-relative behavior, kept for the
226
- * rare non-ESM output format that can't host the bundle-URL anchor banner.
153
+ * Case 2 — on-disk ESM, build-relative. Only correct while bundle ↔ node_modules keep
154
+ * their build-time arrangement; used for the non-ESM output formats that cannot host
155
+ * the bundle-URL anchor banner.
227
156
  */
228
157
  function rewriteOnDiskEsmLegacy(src, path, bundleDir, flags) {
229
158
  const relPath = relative(bundleDir, path);
@@ -253,23 +182,16 @@ function rewriteZipResident(src, path, flags) {
253
182
  return { code: withPreamble(src, preamble), moduleType: moduleTypeForPath(path) };
254
183
  }
255
184
  /**
256
- * Case 4a — CJS, runtime-resolve. Declare `__dirname`/`__filename` from the
257
- * module-resolve shim so they point at the file's location relative to the
258
- * INSTALLED bundle, not the build machine. Location-independent — the fix for
259
- * the "works in the workspace, crashes once published" class of bug for CJS
260
- * deps (e.g. `@gjsify/tsc`'s `typescript/lib/_tsc.js` resolving its sibling
261
- * `lib.*.d.ts` files). Mirrors `rewriteOnDiskEsm` minus the `import.meta.url`
262
- * rewrite (a CJS file has none).
185
+ * Case 4a — CJS, runtime-resolve. `__dirname`/`__filename` come from the module-resolve
186
+ * shim, so they point at the file's location relative to the INSTALLED bundle rather
187
+ * than the build machine — what lets `@gjsify/tsc` find its `lib.*.d.ts` files beside
188
+ * the shipped `typescript/lib/_tsc.js`. Mirrors `rewriteOnDiskEsm` minus the
189
+ * `import.meta.url` rewrite (a CJS file has none).
263
190
  *
264
- * Unlike the ESM case we pull the shim functions in via a CJS `require(...)`,
265
- * NOT an ESM `import { … } from …` header. Rolldown classifies a `node_modules`
266
- * file by its own heuristics (extension + `module.exports`/`require` content),
267
- * and a genuine CommonJS file — a `.cjs`, or a `.js` with `module.exports` like
268
- * `typescript/lib/_tsc.js` — is parsed as a CJS script. Prepending an ESM
269
- * `import` statement there makes Rolldown's parser throw
270
- * `[PARSE_ERROR] Cannot use import statement outside a module`. `require(...)`
271
- * is the native CJS idiom Rolldown resolves + links to the bundled shim, so the
272
- * preamble parses in either classification.
191
+ * The shim comes in via a CJS `require(...)`, NOT an ESM `import` header: Rolldown
192
+ * classifies a node_modules file by its own heuristics, and a genuine CommonJS file is
193
+ * parsed as a script, where a prepended `import` throws `[PARSE_ERROR] Cannot use import
194
+ * statement outside a module`. `require(...)` parses under either classification.
273
195
  */
274
196
  function rewriteCjsRuntime(src, path, flags) {
275
197
  const spec = JSON.stringify(extractPackageSpec(path));
@@ -290,9 +212,8 @@ function rewriteCjsRuntime(src, path, flags) {
290
212
  return { code: withPreamble(src, preamble, header), moduleType: moduleTypeForPath(path) };
291
213
  }
292
214
  /**
293
- * Case 4b — CJS, legacy. Declare `__dirname`/`__filename` from the absolute
294
- * build path. Build-location-coupled — see file header note. Used only for the
295
- * non-ESM output formats that can't host the bundle-URL anchor banner.
215
+ * Case 4b — CJS, baked absolute build path. Build-location-coupled, but correct for an
216
+ * in-place run, and a file that is not an installed package cannot be published anyway.
296
217
  */
297
218
  function rewriteCjsAbsolute(src, path, flags) {
298
219
  const preamble = [];
@@ -305,17 +226,12 @@ function rewriteCjsAbsolute(src, path, flags) {
305
226
  return { code: withPreamble(src, preamble), moduleType: moduleTypeForPath(path) };
306
227
  }
307
228
  /**
308
- * Pure rewriter. Returns the rewritten code (and module type for re-parsing) or
309
- * `null` if the file references none of the patterns we care about.
310
- *
311
- * @param runtimeResolve When true (ESM output, banner present), on-disk ESM
312
- * files resolve their location at runtime (case 1). When false, they fall back
313
- * to the legacy build-relative rewrite (case 2).
229
+ * Pure rewriter: the rewritten code plus the module type to re-parse it with, or `null`
230
+ * when the file references none of the tokens.
314
231
  */
315
232
  export function rewriteContents(args, srcInput, bundleDir, runtimeResolve) {
316
233
  if (!shouldRewrite(args.path))
317
234
  return null;
318
- // Step 1: inline statically-resolvable filesystem reads.
319
235
  const inlined = inlineStaticReads(srcInput, args.path);
320
236
  const src = inlined.contents;
321
237
  const flags = {
@@ -18,11 +18,9 @@ export interface WorkspaceImportGuardOptions {
18
18
  isExternal?: (id: string) => boolean;
19
19
  }
20
20
  /**
21
- * Is `id` a bare `@gjsify/*` package specifier (root or subpath)?
22
- *
23
- * Deliberately excludes disk paths and synthetic ids: a resolved
24
- * `/…/node_modules/@gjsify/fs/lib/esm/index.js` is already resolved, and a
25
- * `\0gjsify-*` virtual id belongs to the plugin that emitted it.
21
+ * Is `id` a bare `@gjsify/*` package specifier (root or subpath)? Excludes disk
22
+ * paths and synthetic ids: a resolved `…/node_modules/@gjsify/fs/…` is already
23
+ * resolved, and a `\0gjsify-*` virtual id belongs to the plugin that emitted it.
26
24
  */
27
25
  export declare function isWorkspaceSpecifier(id: string): boolean;
28
26
  /** What the guard decided about one specifier. */
@@ -41,10 +39,9 @@ export interface ClassifyImportInput {
41
39
  isExternal?: (id: string) => boolean;
42
40
  }
43
41
  /**
44
- * Pure decision: does this import edge have to resolve, and to what?
45
- *
46
- * Split out from the plugin so the legitimate-vs-broken line is unit-testable
47
- * without a bundler (`packages/infra/cli/src/unresolved-workspace-import.spec.ts`).
42
+ * Pure decision: does this import edge have to resolve, and to what? Split out from
43
+ * the plugin so the legitimate-vs-broken line is unit-testable without a bundler
44
+ * (`packages/infra/cli/src/unresolved-workspace-import.spec.ts`).
48
45
  */
49
46
  export declare function classifyImport(input: ClassifyImportInput): ImportVerdict;
50
47
  export interface UnresolvedWorkspaceImportDetails {
@@ -56,16 +53,12 @@ export interface UnresolvedWorkspaceImportDetails {
56
53
  /** Set when `source` was rewritten by the substitution table. */
57
54
  aliasTarget?: string;
58
55
  /**
59
- * Specifiers whose substitution-table entry names `candidate`, discovered by
60
- * REVERSE lookup — the half of the story `source` alone cannot tell.
61
- *
62
- * `aliasPlugin` resolves its target through `this.resolve(target, importer)`,
63
- * so when `node:fs` → `@gjsify/fs` fails, the id that reaches THIS hook is
64
- * `@gjsify/fs` with no alias entry of its own: the message would name the
65
- * missing package but not the `node:fs` the user actually wrote, which is
66
- * the specifier that survives into the bundle and the one they will grep
67
- * for. Reversing the table recovers it (`['fs', 'node:fs']` — both forms
68
- * route to the same target, and naming both is accurate).
56
+ * Specifiers whose substitution-table entry names `candidate`, by REVERSE lookup.
57
+ * `aliasPlugin` resolves its target through `this.resolve(target, importer)`, so
58
+ * when `node:fs` → `@gjsify/fs` fails the id reaching this hook is `@gjsify/fs`
59
+ * with no alias entry of its own — the message would name the missing package but
60
+ * not the `node:fs` the user wrote, which is what survives into the bundle and
61
+ * what they will grep for.
69
62
  */
70
63
  aliasedFrom?: readonly string[];
71
64
  importer: string;
@@ -76,30 +69,19 @@ export declare class UnresolvedWorkspaceImportError extends Error {
76
69
  constructor(details: UnresolvedWorkspaceImportDetails);
77
70
  }
78
71
  /**
79
- * The actionable message. Names the specifier, the importer and the likely
80
- * cause — the three things `UNRESOLVED_IMPORT` (and the post-hoc `node:` guard)
81
- * cannot tell you.
72
+ * The actionable message: names the specifier, the importer and the likely cause —
73
+ * the three things `UNRESOLVED_IMPORT` and the post-hoc `node:` guard cannot.
82
74
  */
83
75
  export declare function formatUnresolvedWorkspaceImport(details: UnresolvedWorkspaceImportDetails): string;
84
- /**
85
- * Reverse the substitution table: alias TARGET → the specifiers that route to it.
86
- *
87
- * Built once per plugin instance (the tables run to ~150 entries per target, and
88
- * the guard only consults this on the failure path).
89
- */
76
+ /** Reverse the substitution table: alias TARGET → the specifiers that route to it. */
90
77
  export declare function buildReverseAliasIndex(aliases: Record<string, string> | undefined): Map<string, string[]>;
91
78
  /**
92
79
  * Refuse a build whose `@gjsify/*` substitution could not be resolved.
93
80
  *
94
- * `order: 'post'` so every deliberate claim — `aliasPlugin` (`pre`),
95
- * `napiNodeAddonPlugin` (`pre`), `gjsGiNodePlugin` (`pre`),
96
- * `gjsImportsEmptyPlugin`, `externalsPlugin` — gets first refusal. Only ids that
97
- * NOTHING claimed reach this hook, i.e. exactly the ones headed for the
98
- * unresolved-import fallback.
99
- *
100
- * The hook re-runs the full resolution chain via `this.resolve(…, { skipSelf })`
101
- * — which is what Rolldown's builtin resolver would have done next — and returns
102
- * its result when it succeeds, so a healthy build resolves the specifier exactly
103
- * once and behaves identically. Only a genuine `null` throws.
81
+ * `order: 'post'` so every deliberate claim (alias/napi/gi-node at `pre`,
82
+ * imports-empty/externals at normal) gets first refusal — only ids NOTHING claimed
83
+ * reach this hook. It then re-runs the resolution Rolldown would have run next
84
+ * (`this.resolve(…, { skipSelf })`) and returns that, so a healthy build resolves
85
+ * each specifier exactly once and behaves identically. Only a genuine `null` throws.
104
86
  */
105
87
  export declare function unresolvedWorkspaceImportPlugin(options: WorkspaceImportGuardOptions): Plugin;