@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.
- package/lib/app/gjs.d.ts +28 -54
- package/lib/app/gjs.js +124 -211
- package/lib/app/node.d.ts +31 -41
- package/lib/app/node.js +118 -221
- package/lib/plugins/css-as-string.js +10 -2
- package/lib/plugins/napi-node-addon.d.ts +46 -83
- package/lib/plugins/napi-node-addon.js +188 -308
- package/lib/plugins/process-stub.js +27 -1
- package/lib/plugins/rewrite-node-modules-paths.d.ts +12 -36
- package/lib/plugins/rewrite-node-modules-paths.js +60 -144
- package/lib/plugins/unresolved-workspace-import.d.ts +20 -38
- package/lib/plugins/unresolved-workspace-import.js +65 -157
- package/lib/shims/console-gjs.js +11 -19
- package/lib/utils/auto-globals.d.ts +56 -102
- package/lib/utils/auto-globals.js +100 -171
- package/lib/utils/detect-free-globals.d.ts +27 -46
- package/lib/utils/detect-free-globals.js +106 -185
- package/package.json +7 -7
|
@@ -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
|
|
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
|
|
16
|
-
* `node_modules/` segment
|
|
17
|
-
* `createRequire(...).resolve
|
|
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
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
|
|
53
|
-
*
|
|
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
|
-
//
|
|
7
|
+
// Four cases, dispatched in `rewriteContents`; each strategy's rationale sits on its
|
|
8
|
+
// `rewrite*` function:
|
|
8
9
|
//
|
|
9
|
-
// 1. on-disk ESM
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
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
|
-
//
|
|
20
|
-
//
|
|
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
|
-
//
|
|
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
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
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
|
|
101
|
-
* `node_modules/` segment
|
|
102
|
-
* `createRequire(...).resolve
|
|
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
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
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
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
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
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
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
|
|
163
|
-
*
|
|
164
|
-
*
|
|
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
|
|
179
|
-
//
|
|
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.
|
|
202
|
-
*
|
|
203
|
-
*
|
|
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
|
-
//
|
|
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,
|
|
226
|
-
*
|
|
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.
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
* the
|
|
260
|
-
*
|
|
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
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
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,
|
|
294
|
-
*
|
|
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
|
|
309
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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`,
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
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
|
|
80
|
-
*
|
|
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
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
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;
|