@gjsify/resolve-npm 0.21.0 → 0.23.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/globals-map.mjs +30 -0
- package/lib/index.mjs +83 -1
- package/lib/register-globals-closure.mjs +83 -3
- package/lib/runtime-aliases.mjs +74 -4
- package/package.json +1 -1
package/lib/globals-map.mjs
CHANGED
|
@@ -214,6 +214,23 @@ export const GJS_GLOBALS_MAP = {
|
|
|
214
214
|
matchMedia: '@gjsify/dom-elements/register/match-media',
|
|
215
215
|
location: '@gjsify/dom-elements/register/location',
|
|
216
216
|
navigator: '@gjsify/dom-elements/register/navigator',
|
|
217
|
+
|
|
218
|
+
// --- Canvas 2D + IFrame + WebGL (GTK/WebKit-backed DOM classes) --------
|
|
219
|
+
//
|
|
220
|
+
// These live in `packages/framework/*` rather than a Web/DOM pillar because
|
|
221
|
+
// their implementations are GTK/Cairo-, WebKit- and Gwebgl/GLArea-bound
|
|
222
|
+
// (ADR 0012). They are DELIBERATELY NOT members of `GJS_GLOBALS_GROUPS.dom`:
|
|
223
|
+
// that group is the coarse `--globals auto,dom` safety net, and pulling
|
|
224
|
+
// these into it would make every `auto,dom` build hard-require
|
|
225
|
+
// `@gjsify/canvas2d` / `@gjsify/iframe` / `@gjsify/webgl` (and, for the
|
|
226
|
+
// second, WebKitGTK) as an installed dependency. Auto-detection injects them
|
|
227
|
+
// only when the identifier is actually referenced in the bundled,
|
|
228
|
+
// tree-shaken output.
|
|
229
|
+
ImageData: '@gjsify/canvas2d/register',
|
|
230
|
+
Path2D: '@gjsify/canvas2d/register',
|
|
231
|
+
HTMLIFrameElement: '@gjsify/iframe/register',
|
|
232
|
+
WebGLRenderingContext: '@gjsify/webgl/register',
|
|
233
|
+
WebGL2RenderingContext: '@gjsify/webgl/register',
|
|
217
234
|
};
|
|
218
235
|
|
|
219
236
|
/**
|
|
@@ -268,6 +285,19 @@ export const GJS_GI_BACKED_REGISTERS = {
|
|
|
268
285
|
'@gjsify/webaudio/register': ['Gst', 'GstApp'],
|
|
269
286
|
'@gjsify/webrtc/register': ['Gst', 'GstWebRTC', 'GstSdp'],
|
|
270
287
|
'@gjsify/gamepad/register': ['Manette'],
|
|
288
|
+
// Imports `@gjsify/dom-elements/register/canvas` (Gdk/GdkPixbuf/Pango/
|
|
289
|
+
// PangoCairo) plus `@gjsify/canvas2d-core`, which uses the `cairo` foreign
|
|
290
|
+
// struct module.
|
|
291
|
+
'@gjsify/canvas2d/register': ['Gdk', 'GdkPixbuf', 'Pango', 'PangoCairo'],
|
|
292
|
+
'@gjsify/iframe/register': ['WebKit'],
|
|
293
|
+
// The WebGL context classes reach the GL driver through the `gwebgl` Vala
|
|
294
|
+
// bridge shipped as this package's own prebuild, and decode `texImage2D`
|
|
295
|
+
// sources via GdkPixbuf. Gtk/Gdk are NOT listed: they are pulled by
|
|
296
|
+
// `webgl-bridge.ts` (the `Gtk.GLArea` widget), which the register does not
|
|
297
|
+
// import — its chain is the two context classes only. As with the entries
|
|
298
|
+
// above, the always-present base namespaces (GLib) are omitted; only the
|
|
299
|
+
// ones whose absence breaks a GTK-less host are worth naming.
|
|
300
|
+
'@gjsify/webgl/register': ['GdkPixbuf', 'Gwebgl'],
|
|
271
301
|
};
|
|
272
302
|
|
|
273
303
|
// ─── Browser target ────────────────────────────────────────────────────────
|
package/lib/index.mjs
CHANGED
|
@@ -11,6 +11,68 @@ export {
|
|
|
11
11
|
resetRuntimeAliasesCache,
|
|
12
12
|
} from './runtime-aliases.mjs';
|
|
13
13
|
|
|
14
|
+
import { getDerivedAliasesSync as _getDerivedAliasesSync } from './runtime-aliases.mjs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Wrap a bare-specifier alias table so its `@gjsify/<X>` VALUES are passed
|
|
18
|
+
* through the derived per-target slot routing before the caller sees them.
|
|
19
|
+
*
|
|
20
|
+
* ## Why this exists (ADR 0014)
|
|
21
|
+
*
|
|
22
|
+
* The alias layer was designed as a TWO-PASS chain, and `app/browser.ts` says
|
|
23
|
+
* so in its own comment: the curated table maps a bare specifier
|
|
24
|
+
* (`os`, `node:os`) to `@gjsify/<X>`, and "the dynamic per-runtimes-triplet
|
|
25
|
+
* resolver (`getDerivedAliasesSync`) finishes the routing in a second pass".
|
|
26
|
+
*
|
|
27
|
+
* That second pass never fires for a bare specifier. `aliasPlugin` resolves a
|
|
28
|
+
* hit via `this.resolve(target, importer, { skipSelf: true })`, and `skipSelf`
|
|
29
|
+
* deliberately excludes the gjsify alias plugin from the nested resolution —
|
|
30
|
+
* so `os` → `@gjsify/os` lands on the package ROOT and the derived entry
|
|
31
|
+
* `@gjsify/os` → `@gjsify/os/browser` is never consulted. A direct
|
|
32
|
+
* `import … from '@gjsify/os'` in source DOES route (single hop, verified);
|
|
33
|
+
* a browser bundle importing bare `os` does not. Since every browser bundle
|
|
34
|
+
* reaches these packages through the bare/`node:` form, the platform-entry
|
|
35
|
+
* routing of ADR 0014 would have been inert without this.
|
|
36
|
+
*
|
|
37
|
+
* Composing the two maps here — at the point the bare table is materialised —
|
|
38
|
+
* collapses the chain to a single hop, keeps the curated table itself a pure
|
|
39
|
+
* bare-name → package statement (no slot policy duplicated into it), and needs
|
|
40
|
+
* no change in the bundler plugins.
|
|
41
|
+
*
|
|
42
|
+
* Evaluated LAZILY (on property read) and cached: `getDerivedAliasesSync` walks
|
|
43
|
+
* the workspace, and importing `@gjsify/resolve-npm` must not pay for a
|
|
44
|
+
* filesystem scan that a `--app gjs` build never needs. The trap set covers
|
|
45
|
+
* everything a consumer does with these tables — `Object.entries`, spread and
|
|
46
|
+
* direct indexing.
|
|
47
|
+
*
|
|
48
|
+
* @param {Record<string,string>} table
|
|
49
|
+
* @param {'gjs'|'node'|'browser'|'nativescript'} target
|
|
50
|
+
* @returns {Record<string,string>}
|
|
51
|
+
*/
|
|
52
|
+
function withDerivedSlotRouting(table, target) {
|
|
53
|
+
/** @type {Record<string,string>|null} */
|
|
54
|
+
let routed = null;
|
|
55
|
+
const materialise = () => {
|
|
56
|
+
if (routed) return routed;
|
|
57
|
+
const derived = _getDerivedAliasesSync(target);
|
|
58
|
+
/** @type {Record<string,string>} */
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const [bare, pkg] of Object.entries(table)) {
|
|
61
|
+
out[bare] = Object.prototype.hasOwnProperty.call(derived, pkg) ? derived[pkg] : pkg;
|
|
62
|
+
}
|
|
63
|
+
routed = out;
|
|
64
|
+
return routed;
|
|
65
|
+
};
|
|
66
|
+
return new Proxy(table, {
|
|
67
|
+
get: (_t, prop) =>
|
|
68
|
+
typeof prop === 'string' ? materialise()[prop] : Reflect.get(table, prop),
|
|
69
|
+
has: (_t, prop) => Reflect.has(materialise(), prop),
|
|
70
|
+
ownKeys: () => Reflect.ownKeys(materialise()),
|
|
71
|
+
getOwnPropertyDescriptor: (_t, prop) =>
|
|
72
|
+
Reflect.getOwnPropertyDescriptor(materialise(), prop),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
14
76
|
/** Array of Node.js build in module names */
|
|
15
77
|
export const EXTERNALS_NODE = [
|
|
16
78
|
'assert',
|
|
@@ -202,7 +264,7 @@ export const ALIASES_NODE_FOR_GJS = {
|
|
|
202
264
|
* baubable `@gjsify/{process,buffer,stream,...}` builds. Adopt only when the
|
|
203
265
|
* per-package browser slots are R1-validated.
|
|
204
266
|
*/
|
|
205
|
-
|
|
267
|
+
const ALIASES_NODE_FOR_BROWSER_TABLE = {
|
|
206
268
|
'assert': '@gjsify/assert',
|
|
207
269
|
'assert/strict': '@gjsify/assert/strict',
|
|
208
270
|
'async_hooks': '@gjsify/async_hooks',
|
|
@@ -263,6 +325,18 @@ export const ALIASES_NODE_FOR_BROWSER = {
|
|
|
263
325
|
'isomorphic-ws': '@gjsify/empty',
|
|
264
326
|
}
|
|
265
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Bare Node-builtin specifier → polyfill / empty-stub mapping for `--app
|
|
330
|
+
* browser`, with ADR-0014 platform-entry routing already applied to the values
|
|
331
|
+
* (`os` → `@gjsify/os/browser` when that package's browser slot is `polyfill`
|
|
332
|
+
* and it exports a `./browser` subpath). See `withDerivedSlotRouting` above for
|
|
333
|
+
* why the two-pass chain has to be collapsed here.
|
|
334
|
+
*/
|
|
335
|
+
export const ALIASES_NODE_FOR_BROWSER = withDerivedSlotRouting(
|
|
336
|
+
ALIASES_NODE_FOR_BROWSER_TABLE,
|
|
337
|
+
'browser',
|
|
338
|
+
);
|
|
339
|
+
|
|
266
340
|
/**
|
|
267
341
|
* Bare Node-builtin specifier → polyfill / empty-stub mapping for `--app
|
|
268
342
|
* nativescript` builds. Mirrors `ALIASES_NODE_FOR_BROWSER` in shape, with
|
|
@@ -559,6 +633,14 @@ export const ALIASES_WEB_FOR_NODE = {
|
|
|
559
633
|
'@gjsify/dom-elements/register/match-media': '@gjsify/empty',
|
|
560
634
|
'@gjsify/dom-elements/register/location': '@gjsify/empty',
|
|
561
635
|
'@gjsify/dom-elements/register/navigator': '@gjsify/empty',
|
|
636
|
+
// Canvas 2D + IFrame + WebGL registers (GTK/Cairo-, WebKit- and
|
|
637
|
+
// Gwebgl/GLArea-backed, ADR 0012) — no-op on Node, exactly like the
|
|
638
|
+
// dom-elements registers above. Only the `@gjsify/*`-qualified form is
|
|
639
|
+
// mirrored: per ADR 0012 no bare-specifier `/register` alias is invented for
|
|
640
|
+
// a framework package.
|
|
641
|
+
'@gjsify/canvas2d/register': '@gjsify/empty',
|
|
642
|
+
'@gjsify/iframe/register': '@gjsify/empty',
|
|
643
|
+
'@gjsify/webgl/register': '@gjsify/empty',
|
|
562
644
|
'@gjsify/buffer/register': '@gjsify/empty',
|
|
563
645
|
|
|
564
646
|
// xmlhttprequest + DOMParser — no-op on Node
|
|
@@ -33,6 +33,32 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
33
33
|
"setTimeout",
|
|
34
34
|
"structuredClone"
|
|
35
35
|
],
|
|
36
|
+
"@gjsify/canvas2d/register": [
|
|
37
|
+
"AbortController",
|
|
38
|
+
"AbortSignal",
|
|
39
|
+
"Blob",
|
|
40
|
+
"Buffer",
|
|
41
|
+
"ByteLengthQueuingStrategy",
|
|
42
|
+
"CountQueuingStrategy",
|
|
43
|
+
"DOMException",
|
|
44
|
+
"File",
|
|
45
|
+
"HTMLCanvasElement",
|
|
46
|
+
"Path2D",
|
|
47
|
+
"ReadableStream",
|
|
48
|
+
"TextDecoderStream",
|
|
49
|
+
"TextEncoderStream",
|
|
50
|
+
"TransformStream",
|
|
51
|
+
"WritableStream",
|
|
52
|
+
"atob",
|
|
53
|
+
"btoa",
|
|
54
|
+
"clearTimeout",
|
|
55
|
+
"document",
|
|
56
|
+
"performance",
|
|
57
|
+
"process",
|
|
58
|
+
"queueMicrotask",
|
|
59
|
+
"setTimeout",
|
|
60
|
+
"structuredClone"
|
|
61
|
+
],
|
|
36
62
|
"@gjsify/dom-elements/register/canvas": [
|
|
37
63
|
"AbortController",
|
|
38
64
|
"AbortSignal",
|
|
@@ -43,6 +69,7 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
43
69
|
"DOMException",
|
|
44
70
|
"File",
|
|
45
71
|
"HTMLCanvasElement",
|
|
72
|
+
"Path2D",
|
|
46
73
|
"ReadableStream",
|
|
47
74
|
"TextDecoderStream",
|
|
48
75
|
"TextEncoderStream",
|
|
@@ -68,6 +95,7 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
68
95
|
"DOMException",
|
|
69
96
|
"File",
|
|
70
97
|
"HTMLCanvasElement",
|
|
98
|
+
"Path2D",
|
|
71
99
|
"ReadableStream",
|
|
72
100
|
"TextDecoderStream",
|
|
73
101
|
"TextEncoderStream",
|
|
@@ -115,6 +143,7 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
115
143
|
"DOMException",
|
|
116
144
|
"File",
|
|
117
145
|
"HTMLCanvasElement",
|
|
146
|
+
"Path2D",
|
|
118
147
|
"ReadableStream",
|
|
119
148
|
"TextDecoderStream",
|
|
120
149
|
"TextEncoderStream",
|
|
@@ -262,6 +291,33 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
262
291
|
"setTimeout",
|
|
263
292
|
"structuredClone"
|
|
264
293
|
],
|
|
294
|
+
"@gjsify/iframe/register": [
|
|
295
|
+
"AbortController",
|
|
296
|
+
"AbortSignal",
|
|
297
|
+
"Blob",
|
|
298
|
+
"Buffer",
|
|
299
|
+
"ByteLengthQueuingStrategy",
|
|
300
|
+
"CountQueuingStrategy",
|
|
301
|
+
"DOMException",
|
|
302
|
+
"File",
|
|
303
|
+
"HTMLCanvasElement",
|
|
304
|
+
"HTMLIFrameElement",
|
|
305
|
+
"Path2D",
|
|
306
|
+
"ReadableStream",
|
|
307
|
+
"TextDecoderStream",
|
|
308
|
+
"TextEncoderStream",
|
|
309
|
+
"TransformStream",
|
|
310
|
+
"WritableStream",
|
|
311
|
+
"atob",
|
|
312
|
+
"btoa",
|
|
313
|
+
"clearTimeout",
|
|
314
|
+
"document",
|
|
315
|
+
"performance",
|
|
316
|
+
"process",
|
|
317
|
+
"queueMicrotask",
|
|
318
|
+
"setTimeout",
|
|
319
|
+
"structuredClone"
|
|
320
|
+
],
|
|
265
321
|
"@gjsify/node-globals/register/buffer": [
|
|
266
322
|
"AbortController",
|
|
267
323
|
"AbortSignal",
|
|
@@ -489,6 +545,33 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
489
545
|
"setTimeout",
|
|
490
546
|
"structuredClone"
|
|
491
547
|
],
|
|
548
|
+
"@gjsify/webgl/register": [
|
|
549
|
+
"AbortController",
|
|
550
|
+
"AbortSignal",
|
|
551
|
+
"Blob",
|
|
552
|
+
"Buffer",
|
|
553
|
+
"ByteLengthQueuingStrategy",
|
|
554
|
+
"CountQueuingStrategy",
|
|
555
|
+
"DOMException",
|
|
556
|
+
"File",
|
|
557
|
+
"HTMLCanvasElement",
|
|
558
|
+
"Path2D",
|
|
559
|
+
"ReadableStream",
|
|
560
|
+
"TextDecoderStream",
|
|
561
|
+
"TextEncoderStream",
|
|
562
|
+
"TransformStream",
|
|
563
|
+
"WebGL2RenderingContext",
|
|
564
|
+
"WritableStream",
|
|
565
|
+
"atob",
|
|
566
|
+
"btoa",
|
|
567
|
+
"clearTimeout",
|
|
568
|
+
"document",
|
|
569
|
+
"performance",
|
|
570
|
+
"process",
|
|
571
|
+
"queueMicrotask",
|
|
572
|
+
"setTimeout",
|
|
573
|
+
"structuredClone"
|
|
574
|
+
],
|
|
492
575
|
"@gjsify/webrtc/register/data-channel": [
|
|
493
576
|
"AbortController",
|
|
494
577
|
"AbortSignal",
|
|
@@ -831,11 +914,8 @@ export const REGISTER_GLOBALS_CLOSURE = {
|
|
|
831
914
|
"CountQueuingStrategy",
|
|
832
915
|
"DOMException",
|
|
833
916
|
"DecompressionStream",
|
|
834
|
-
"Event",
|
|
835
|
-
"EventTarget",
|
|
836
917
|
"File",
|
|
837
918
|
"Headers",
|
|
838
|
-
"ProgressEvent",
|
|
839
919
|
"ReadableStream",
|
|
840
920
|
"Request",
|
|
841
921
|
"Response",
|
package/lib/runtime-aliases.mjs
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
// The bundler's alias resolver consults this triplet when routing bare
|
|
17
17
|
// `@gjsify/<X>` specifiers per `--app <target>`:
|
|
18
18
|
//
|
|
19
|
-
// slot=polyfill →
|
|
19
|
+
// slot=polyfill → `@gjsify/<X>/<target>` when the package's `exports` map
|
|
20
|
+
// declares that platform-entry subpath (ADR 0014), else keep
|
|
21
|
+
// as-is (`@gjsify/<X>` — the shared impl ships)
|
|
20
22
|
// slot=native → redirect to `@gjsify/<X>/globals` (re-exports native value)
|
|
21
23
|
// slot=partial → keep as-is (our impl, gracefully degrades at runtime)
|
|
22
24
|
// slot=none → no rewrite (the package's polyfill resolves normally;
|
|
@@ -32,6 +34,30 @@
|
|
|
32
34
|
// When a slot=native package is missing the corresponding `globals.mjs`
|
|
33
35
|
// re-export file, the resolver emits a warn-once log and falls back to
|
|
34
36
|
// `@gjsify/empty` (the current behavior) — surfacing the gap is desirable.
|
|
37
|
+
//
|
|
38
|
+
// ── Platform-entry routing (ADR 0014) ──────────────────────────────────────
|
|
39
|
+
//
|
|
40
|
+
// `polyfill` is the STRONG promise: "our implementation fully covers this API
|
|
41
|
+
// on this runtime". A package can only keep that promise off GJS if the code
|
|
42
|
+
// the target actually resolves is free of GLib/Gio. Several packages already
|
|
43
|
+
// ship a real per-target implementation (`src/browser.ts` → the `./browser`
|
|
44
|
+
// export subpath) but nothing ever routed to it: the root `.` export has no
|
|
45
|
+
// `"browser"` condition and the alias layer kept `polyfill` as a no-op, so the
|
|
46
|
+
// GJS body was bundled for the browser and every GLib call TypeError'd against
|
|
47
|
+
// the `{}` that `gjsImportsEmptyPlugin` substitutes for `@girs/*`.
|
|
48
|
+
//
|
|
49
|
+
// So: on a NON-gjs target, `slot=polyfill` routes to `@gjsify/<X>/<target>`
|
|
50
|
+
// whenever the package's `exports` map declares that subpath. The `gjs` target
|
|
51
|
+
// is never rerouted (`src/index.ts` IS the GJS implementation).
|
|
52
|
+
//
|
|
53
|
+
// `partial` deliberately does NOT route. `partial` is the weak promise ("works
|
|
54
|
+
// here, degrades") and the shared body's degradation IS its contract; the
|
|
55
|
+
// `partial` packages' platform entries are also not yet at export parity with
|
|
56
|
+
// their root entry (`@gjsify/fs`'s `src/browser.ts` is missing 34 value
|
|
57
|
+
// exports), so routing them would turn a call-time degradation into a
|
|
58
|
+
// build-time MISSING_EXPORT. Reaching parity is exactly the work that promotes
|
|
59
|
+
// a package from `partial` to `polyfill`; `scripts/audit-runtimes.mjs`
|
|
60
|
+
// (`platform-entry-parity` probe) gates that promotion.
|
|
35
61
|
|
|
36
62
|
import { readdir, readFile } from 'node:fs/promises';
|
|
37
63
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
@@ -41,6 +67,28 @@ import { fileURLToPath } from 'node:url';
|
|
|
41
67
|
const VALID_SLOTS = new Set(['polyfill', 'native', 'partial', 'none']);
|
|
42
68
|
const VALID_TARGETS = new Set(['gjs', 'node', 'browser', 'nativescript']);
|
|
43
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Collect the target names for which `exports` declares a `./<target>`
|
|
72
|
+
* platform-entry subpath. Shared by the sync + async package ingesters so the
|
|
73
|
+
* two paths cannot drift.
|
|
74
|
+
*
|
|
75
|
+
* @param {unknown} exportsField
|
|
76
|
+
* @returns {Set<string>}
|
|
77
|
+
*/
|
|
78
|
+
function collectPlatformEntries(exportsField) {
|
|
79
|
+
/** @type {Set<string>} */
|
|
80
|
+
const found = new Set();
|
|
81
|
+
if (!exportsField || typeof exportsField !== 'object') return found;
|
|
82
|
+
for (const target of VALID_TARGETS) {
|
|
83
|
+
// The `gjs` target is never a platform entry — `.` IS the GJS impl.
|
|
84
|
+
if (target === 'gjs') continue;
|
|
85
|
+
if (Object.prototype.hasOwnProperty.call(exportsField, `./${target}`)) {
|
|
86
|
+
found.add(target);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return found;
|
|
90
|
+
}
|
|
91
|
+
|
|
44
92
|
/** @typedef {'polyfill'|'native'|'partial'|'none'} Slot */
|
|
45
93
|
/**
|
|
46
94
|
* Per-package runtime slot declaration. Quadruplet (gjs / node / browser /
|
|
@@ -50,7 +98,14 @@ const VALID_TARGETS = new Set(['gjs', 'node', 'browser', 'nativescript']);
|
|
|
50
98
|
*
|
|
51
99
|
* @typedef {{gjs?:Slot, node?:Slot, browser?:Slot, nativescript?:Slot}} RuntimeTriplet
|
|
52
100
|
*/
|
|
53
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* @typedef {{name:string, dir:string, runtimes:RuntimeTriplet, hasGlobals:boolean,
|
|
103
|
+
* platformEntries:Set<string>}} PackageRecord
|
|
104
|
+
*
|
|
105
|
+
* `platformEntries` holds the target names (`browser` / `nativescript` / …)
|
|
106
|
+
* for which the package's `exports` map declares a `./<target>` subpath — the
|
|
107
|
+
* per-runtime implementation entry that `slot=polyfill` routes to (ADR 0014).
|
|
108
|
+
*/
|
|
54
109
|
|
|
55
110
|
let _cache = null;
|
|
56
111
|
const _warned = new Set();
|
|
@@ -145,7 +200,8 @@ async function ingestPackageDir(dir, out) {
|
|
|
145
200
|
}
|
|
146
201
|
}
|
|
147
202
|
const hasGlobals = existsSync(join(dir, 'globals.mjs'));
|
|
148
|
-
|
|
203
|
+
const platformEntries = collectPlatformEntries(json?.exports);
|
|
204
|
+
out.set(name, { name, dir, runtimes: triplet, hasGlobals, platformEntries });
|
|
149
205
|
}
|
|
150
206
|
} catch {
|
|
151
207
|
// Ignore unreadable / invalid package.json
|
|
@@ -180,7 +236,8 @@ function ingestPackageDirSync(dir, out) {
|
|
|
180
236
|
}
|
|
181
237
|
}
|
|
182
238
|
const hasGlobals = existsSync(join(dir, 'globals.mjs'));
|
|
183
|
-
|
|
239
|
+
const platformEntries = collectPlatformEntries(json?.exports);
|
|
240
|
+
out.set(name, { name, dir, runtimes: triplet, hasGlobals, platformEntries });
|
|
184
241
|
}
|
|
185
242
|
} catch {
|
|
186
243
|
// Ignore unreadable / invalid package.json
|
|
@@ -328,8 +385,21 @@ function resolveSlot(rec, target) {
|
|
|
328
385
|
if (!slot) return null; // Slot undeclared → no opinion, leave to hardcoded maps.
|
|
329
386
|
switch (slot) {
|
|
330
387
|
case 'polyfill':
|
|
388
|
+
// ADR 0014 — platform-entry routing. `polyfill` promises a FULL
|
|
389
|
+
// implementation on this runtime; when the package ships a
|
|
390
|
+
// per-target entry (`exports["./<target>"]`), that entry IS the
|
|
391
|
+
// implementation for the target and the shared `.` body (which on
|
|
392
|
+
// most packages is the GLib/Gio-backed GJS impl) must not be
|
|
393
|
+
// bundled. Never applies to `gjs` — `.` is the GJS impl.
|
|
394
|
+
if (target !== 'gjs' && rec.platformEntries?.has(target)) {
|
|
395
|
+
return `${rec.name}/${target}`;
|
|
396
|
+
}
|
|
397
|
+
// No platform entry → the shared body is the implementation.
|
|
398
|
+
return null;
|
|
331
399
|
case 'partial':
|
|
332
400
|
// Keep as-is — bundler resolves `@gjsify/<X>` to its `lib/esm/index.js`.
|
|
401
|
+
// `partial` does NOT route to a platform entry even when one exists;
|
|
402
|
+
// see the header note (parity is the promotion gate to `polyfill`).
|
|
333
403
|
return null;
|
|
334
404
|
case 'native':
|
|
335
405
|
if (rec.hasGlobals) {
|