@gjsify/rolldown-plugin-gjsify 0.4.20 → 0.4.22
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.
|
@@ -44,6 +44,60 @@ const METHOD_MARKERS = {
|
|
|
44
44
|
// @gjsify/node-globals/register/url in GJS_GLOBALS_MAP) already pulls in
|
|
45
45
|
// the correct register module.
|
|
46
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* wasm-bindgen-generated function-name patterns that imply a global
|
|
49
|
+
* identifier should be injected. wasm-bindgen emits its host-API
|
|
50
|
+
* import bindings as top-level functions named
|
|
51
|
+
* `__wbg_<jsName>_<hash>` where `<jsName>` is the property name of the
|
|
52
|
+
* JS API the WASM module wants to call. The body looks like:
|
|
53
|
+
*
|
|
54
|
+
* function __wbg_crypto_574e78ad8b13b65f(arg0) {
|
|
55
|
+
* const ret = getObject(arg0).crypto;
|
|
56
|
+
* return addHeapObject(ret);
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* `getObject(arg0)` is a runtime heap dereference (the object is one
|
|
60
|
+
* of the host bridges registered by wasm-bindgen at init time —
|
|
61
|
+
* typically `globalThis`, `window`, or `self`). The MemberExpression
|
|
62
|
+
* visitor can't follow that — `node.object` is a CallExpression, not
|
|
63
|
+
* an Identifier — so the underlying `.crypto` access is invisible to
|
|
64
|
+
* the static scan.
|
|
65
|
+
*
|
|
66
|
+
* Matching on the FUNCTION-NAME pattern instead is high precision
|
|
67
|
+
* (no false positives — `__wbg_` is wasm-bindgen-reserved) and high
|
|
68
|
+
* recall (the names are extremely stable across wasm-bindgen
|
|
69
|
+
* versions). Add an entry whenever a new wasm-bindgen-built npm
|
|
70
|
+
* package surfaces a needed global that the static scan misses.
|
|
71
|
+
*
|
|
72
|
+
* Keyed by the `<jsName>` extracted from the `__wbg_<jsName>_<hash>`
|
|
73
|
+
* function name; value is the gjsify global to inject.
|
|
74
|
+
*/
|
|
75
|
+
const WASM_BINDGEN_MARKERS = {
|
|
76
|
+
// crypto.getRandomValues chain — wasm-bindgen's canonical
|
|
77
|
+
// crypto-import binding pattern. Used by ed25519-dalek, ring, rand
|
|
78
|
+
// (when targeting wasm), and most Rust crates that touch
|
|
79
|
+
// randomness or hashing. Loro is the driving real-world consumer:
|
|
80
|
+
// its CRDT operations need crypto.getRandomValues for peer-id
|
|
81
|
+
// generation and ChangeID nonces.
|
|
82
|
+
crypto: 'crypto',
|
|
83
|
+
getRandomValues: 'crypto',
|
|
84
|
+
// Legacy IE prefix path — wasm-bindgen probes for `msCrypto` as a
|
|
85
|
+
// fallback when `crypto` isn't available. Doesn't apply to GJS
|
|
86
|
+
// (we ship a real `crypto`), but flagging the marker keeps the
|
|
87
|
+
// detector self-documenting.
|
|
88
|
+
msCrypto: 'crypto',
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Match the wasm-bindgen function-name shape — return the `<jsName>`
|
|
92
|
+
* part of `__wbg_<jsName>_<hash>` or `null`. wasm-bindgen hashes are
|
|
93
|
+
* 8–16 hex chars in practice, but we accept any alphanumeric trailer
|
|
94
|
+
* so the pattern survives future format tweaks.
|
|
95
|
+
*/
|
|
96
|
+
const WBG_NAME_RE = /^__wbg_([A-Za-z][A-Za-z0-9]*)_[A-Za-z0-9]+$/;
|
|
97
|
+
function wbgJsNameFor(fnName) {
|
|
98
|
+
const match = fnName.match(WBG_NAME_RE);
|
|
99
|
+
return match?.[1] ?? null;
|
|
100
|
+
}
|
|
47
101
|
/**
|
|
48
102
|
* Extract all bound names from a binding pattern
|
|
49
103
|
* (Identifier, ObjectPattern, ArrayPattern, AssignmentPattern, RestElement).
|
|
@@ -192,6 +246,24 @@ export function detectFreeGlobals(code) {
|
|
|
192
246
|
freeGlobals.add(markerTarget);
|
|
193
247
|
}
|
|
194
248
|
},
|
|
249
|
+
FunctionDeclaration(node) {
|
|
250
|
+
// Pattern C: wasm-bindgen marker hook. The function name
|
|
251
|
+
// matches `__wbg_<jsName>_<hash>` and `<jsName>` is a known
|
|
252
|
+
// host API. The body would be `getObject(arg0).<jsName>` —
|
|
253
|
+
// an unfollowable runtime heap dereference — but the
|
|
254
|
+
// function NAME tells us exactly which global is needed.
|
|
255
|
+
// See WASM_BINDGEN_MARKERS for the why + which jsNames are
|
|
256
|
+
// mapped.
|
|
257
|
+
if (!node.id)
|
|
258
|
+
return;
|
|
259
|
+
const jsName = wbgJsNameFor(node.id.name);
|
|
260
|
+
if (!jsName)
|
|
261
|
+
return;
|
|
262
|
+
const target = WASM_BINDGEN_MARKERS[jsName];
|
|
263
|
+
if (target && KNOWN_GLOBALS.has(target)) {
|
|
264
|
+
freeGlobals.add(target);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
195
267
|
Identifier(node, ancestors) {
|
|
196
268
|
const name = node.name;
|
|
197
269
|
// Quick filter: only check known globals
|
|
@@ -151,6 +151,12 @@ function tryInlineCall(node, ctx, src) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
if (calleeName === 'readdirSync') {
|
|
154
|
+
// We inline as a plain string[] — refuse if the caller asks for
|
|
155
|
+
// Dirent[] via { withFileTypes: true }. Otherwise the consumer's
|
|
156
|
+
// child.isFile() call would throw at runtime ("isFile is not a
|
|
157
|
+
// function" on a string).
|
|
158
|
+
if (hasWithFileTypes(node.arguments[1]))
|
|
159
|
+
return undefined;
|
|
154
160
|
const path = evalPathExpr(node.arguments[0], ctx);
|
|
155
161
|
if (path && existsSyncSafe(path) && isDirectorySafe(path)) {
|
|
156
162
|
try {
|
|
@@ -476,6 +482,30 @@ function evalEncodingExpr(node) {
|
|
|
476
482
|
}
|
|
477
483
|
return undefined;
|
|
478
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Detect `{ withFileTypes: true }` in a readdirSync options argument.
|
|
487
|
+
* Any non-literal or absence returns `false` (safe — we only abort
|
|
488
|
+
* inlining for an unambiguous `true`).
|
|
489
|
+
*/
|
|
490
|
+
function hasWithFileTypes(node) {
|
|
491
|
+
if (!node || node.type !== 'ObjectExpression')
|
|
492
|
+
return false;
|
|
493
|
+
for (const p of node.properties) {
|
|
494
|
+
if (p.type !== 'Property' || p.computed)
|
|
495
|
+
continue;
|
|
496
|
+
const key = p.key.type === 'Identifier'
|
|
497
|
+
? p.key.name
|
|
498
|
+
: p.key.type === 'Literal'
|
|
499
|
+
? String(p.key.value)
|
|
500
|
+
: undefined;
|
|
501
|
+
if (key !== 'withFileTypes')
|
|
502
|
+
continue;
|
|
503
|
+
if (p.value.type === 'Literal' && p.value.value === true)
|
|
504
|
+
return true;
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
479
509
|
function canonicalEncoding(v) {
|
|
480
510
|
const lc = v.toLowerCase();
|
|
481
511
|
if (lc === 'utf8' || lc === 'utf-8')
|
|
@@ -488,12 +518,20 @@ function canonicalEncoding(v) {
|
|
|
488
518
|
}
|
|
489
519
|
/**
|
|
490
520
|
* Get the leaf identifier name of a callee. Recognises:
|
|
491
|
-
* `foo` → "foo"
|
|
492
|
-
* `path.foo` → "foo"
|
|
493
|
-
* `
|
|
494
|
-
*
|
|
521
|
+
* `foo` → "foo" (assumed named import)
|
|
522
|
+
* `path.foo` → "foo" (path module namespace/default import)
|
|
523
|
+
* `fs.foo` → "foo" (fs module — caller validates context)
|
|
524
|
+
*
|
|
525
|
+
* For MemberExpression callees, the object identifier is restricted to a
|
|
526
|
+
* known module namespace name (`path`, `fs`, `JSON`). Otherwise `arr.join(',')`
|
|
527
|
+
* (Array.prototype.join) would resolve to `path.join`, and our static
|
|
528
|
+
* evaluator would happily treat a free `dir.join('/')` array call as
|
|
529
|
+
* `path.join('/')` → `'/'` → catastrophic root-directory scan. See PR for
|
|
530
|
+
* the TypeDoc bundling incident this prevents.
|
|
531
|
+
*
|
|
495
532
|
* Returns `undefined` for computed/dynamic callees.
|
|
496
533
|
*/
|
|
534
|
+
const PATH_NAMESPACE_OBJECTS = new Set(['path', 'fs']);
|
|
497
535
|
function identifierName(node) {
|
|
498
536
|
if (!node)
|
|
499
537
|
return undefined;
|
|
@@ -501,8 +539,17 @@ function identifierName(node) {
|
|
|
501
539
|
return node.name;
|
|
502
540
|
if (node.type === 'MemberExpression' && !node.computed) {
|
|
503
541
|
const me = node;
|
|
504
|
-
if (me.property.type
|
|
505
|
-
return
|
|
542
|
+
if (me.property.type !== 'Identifier')
|
|
543
|
+
return undefined;
|
|
544
|
+
// The object must be a known namespace identifier — otherwise we
|
|
545
|
+
// misidentify Array.prototype methods (`arr.join`, `arr.includes`)
|
|
546
|
+
// and userland method calls as path/fs functions.
|
|
547
|
+
if (me.object.type !== 'Identifier')
|
|
548
|
+
return undefined;
|
|
549
|
+
const obj = me.object.name;
|
|
550
|
+
if (!PATH_NAMESPACE_OBJECTS.has(obj))
|
|
551
|
+
return undefined;
|
|
552
|
+
return me.property.name;
|
|
506
553
|
}
|
|
507
554
|
return undefined;
|
|
508
555
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/rolldown-plugin-gjsify",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
4
4
|
"description": "Rolldown / Rollup / Vite plugin orchestrator for GJS, Node, and Browser targets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
],
|
|
46
46
|
"license": "MIT",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@gjsify/console": "^0.4.
|
|
49
|
-
"@gjsify/resolve-npm": "^0.4.
|
|
50
|
-
"@gjsify/rolldown-plugin-deepkit": "^0.4.
|
|
51
|
-
"@gjsify/rolldown-plugin-pnp": "^0.4.
|
|
52
|
-
"@gjsify/vite-plugin-blueprint": "^0.4.
|
|
48
|
+
"@gjsify/console": "^0.4.22",
|
|
49
|
+
"@gjsify/resolve-npm": "^0.4.22",
|
|
50
|
+
"@gjsify/rolldown-plugin-deepkit": "^0.4.22",
|
|
51
|
+
"@gjsify/rolldown-plugin-pnp": "^0.4.22",
|
|
52
|
+
"@gjsify/vite-plugin-blueprint": "^0.4.22",
|
|
53
53
|
"@rollup/pluginutils": "^5.3.0",
|
|
54
54
|
"acorn": "^8.16.0",
|
|
55
55
|
"acorn-walk": "^8.3.5",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"lightningcss": "^1.32.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@gjsify/lightningcss-native": "^0.4.
|
|
60
|
+
"@gjsify/lightningcss-native": "^0.4.22",
|
|
61
61
|
"rolldown": "^1.0.0-rc.18"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@types/node": "^25.
|
|
72
|
+
"@types/node": "^25.9.1",
|
|
73
73
|
"rolldown": "^1.0.0",
|
|
74
74
|
"typescript": "^6.0.3"
|
|
75
75
|
}
|