bare-module-traverse 2.5.9 → 2.7.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/README.md +5 -1
- package/index.d.ts +18 -2
- package/index.js +245 -43
- package/lib/conditions.js +23 -0
- package/lib/errors.js +12 -0
- package/lib/resolve/bare.d.ts +9 -2
- package/lib/resolve/bare.js +8 -2
- package/lib/resolve/default.d.ts +5 -1
- package/lib/resolve/node.d.ts +9 -2
- package/lib/resolve/node.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -219,12 +219,16 @@ Options are the same as `traverse()` for all functions.
|
|
|
219
219
|
|
|
220
220
|
### `const generator = traverse.package(url, source, artifacts, visited[, options])`
|
|
221
221
|
|
|
222
|
-
### `const generator = traverse.preresolved(url, source, resolutions, artifacts, visited[, options])`
|
|
222
|
+
### `const generator = traverse.preresolved(url, source, attributes, resolutions, artifacts, visited[, options])`
|
|
223
223
|
|
|
224
224
|
### `const generator = traverse.imports(parentURL, source, imports, artifacts, lexer, visited[, options])`
|
|
225
225
|
|
|
226
226
|
### `const generator = traverse.link(entry, specifier, condition, parentURL, imports, artifacts, visited[, options])`
|
|
227
227
|
|
|
228
|
+
### `traverse.assertAddonContext(url, scope, context, addonContexts)`
|
|
229
|
+
|
|
230
|
+
Record in `addonContexts` that the package at `scope` loads its addons in `context`, an object of the `host` and the URL of the `wasi` provider, either `null` for the defaults. Throws if it was recorded for another context, or if `url` doesn't load on `context.host`.
|
|
231
|
+
|
|
228
232
|
### `const generator = traverse.addons(parentURL, artifacts, visited[, options])`
|
|
229
233
|
|
|
230
234
|
### `const generator = traverse.assets(patterns, parentURL, artifacts, visited[, options])`
|
package/index.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import Buffer from 'bare-buffer'
|
|
|
3
3
|
import {
|
|
4
4
|
type ConditionalSpecifier,
|
|
5
5
|
type ImportsMap,
|
|
6
|
-
type ResolutionsMap
|
|
6
|
+
type ResolutionsMap,
|
|
7
|
+
type ResolveOptions as ModuleResolveOptions
|
|
7
8
|
} from 'bare-module-resolve'
|
|
8
|
-
import { type ResolveOptions, type Resolver } from 'bare-addon-resolve'
|
|
9
|
+
import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
|
|
9
10
|
import { type Import, type Export } from 'bare-module-lexer'
|
|
10
11
|
|
|
11
12
|
interface Dependency {
|
|
@@ -41,6 +42,8 @@ type AliasableExtension =
|
|
|
41
42
|
| '.bin'
|
|
42
43
|
| '.txt'
|
|
43
44
|
|
|
45
|
+
interface ResolveOptions extends ModuleResolveOptions, AddonResolveOptions {}
|
|
46
|
+
|
|
44
47
|
interface TraverseOptions extends ResolveOptions {
|
|
45
48
|
/**
|
|
46
49
|
* The type to assume for a module that has no type of its own, such as one
|
|
@@ -174,9 +177,22 @@ declare namespace traverse {
|
|
|
174
177
|
opts?: TraverseOptions
|
|
175
178
|
): Traversal
|
|
176
179
|
|
|
180
|
+
interface AddonContext {
|
|
181
|
+
host: string | null
|
|
182
|
+
wasi: string | null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function assertAddonContext(
|
|
186
|
+
url: URL,
|
|
187
|
+
scope: string,
|
|
188
|
+
context: Partial<AddonContext>,
|
|
189
|
+
addonContexts: Map<string, AddonContext>
|
|
190
|
+
): void
|
|
191
|
+
|
|
177
192
|
export function preresolved(
|
|
178
193
|
url: URL,
|
|
179
194
|
source: string | Buffer,
|
|
195
|
+
attributes: Record<string, string> | null,
|
|
180
196
|
resolution: ResolutionsMap,
|
|
181
197
|
artifacts: Artifacts,
|
|
182
198
|
visited: Set<string>,
|
package/index.js
CHANGED
|
@@ -98,7 +98,7 @@ module.exports = exports = function traverse(
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
while (queue.length > 0 || deferred.length > 0) {
|
|
101
|
-
yield* drive(queue.length > 0 ? queue.
|
|
101
|
+
yield* drive(queue.length > 0 ? queue.shift() : deferred.shift())
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
return artifacts
|
|
@@ -160,7 +160,7 @@ module.exports = exports = function traverse(
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
while (queue.length > 0 || deferred.length > 0) {
|
|
163
|
-
yield* drive(queue.length > 0 ? queue.
|
|
163
|
+
yield* drive(queue.length > 0 ? queue.shift() : deferred.shift())
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
return artifacts
|
|
@@ -192,10 +192,36 @@ exports.alias = function alias(url, opts = {}) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
exports.module = function* (url, source, attributes, artifacts, visited, opts = {}) {
|
|
195
|
-
const { resolutions = null, asset = false, probed, types } = opts
|
|
196
|
-
|
|
197
195
|
attributes = attributes || {}
|
|
198
196
|
|
|
197
|
+
if (opts.contexts === undefined) opts = { ...opts, contexts: new Map() }
|
|
198
|
+
if (opts.addonContexts === undefined) opts = { ...opts, addonContexts: new Map() }
|
|
199
|
+
if (opts.resolvedImports === undefined) opts = { ...opts, resolvedImports: new Map() }
|
|
200
|
+
|
|
201
|
+
// The host and WASI attributes set the context that the addons of the module
|
|
202
|
+
// and everything it imports load in. A graph is walked again for each context
|
|
203
|
+
// it is imported under, even where it was visited before. The conditions of
|
|
204
|
+
// the host are added to those that may be targeted, so that the order of the
|
|
205
|
+
// conditions in a package still decides between them and the native ones.
|
|
206
|
+
if (attributes.host !== undefined || attributes.wasi !== undefined) {
|
|
207
|
+
const { addonHost = null, addonWASI = null } = opts
|
|
208
|
+
|
|
209
|
+
const host = attributes.host === undefined ? addonHost : addonHostForAttribute(attributes.host)
|
|
210
|
+
const wasi = attributes.wasi === undefined ? addonWASI : attributes.wasi
|
|
211
|
+
|
|
212
|
+
if (host !== addonHost || wasi !== addonWASI) {
|
|
213
|
+
opts = { ...opts, addonHost: host, addonWASI: wasi }
|
|
214
|
+
|
|
215
|
+
if (host !== addonHost) {
|
|
216
|
+
opts.conditions = withConditions(opts.conditions, host.split('-'))
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
visited = visitedFor(opts.contexts, host, wasi)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const { resolutions = null, asset = false, probed, types } = opts
|
|
224
|
+
|
|
199
225
|
if (visited.has(url.href)) {
|
|
200
226
|
// An asset is only read for its bytes, so it doesn't care what type the
|
|
201
227
|
// module is imported as elsewhere.
|
|
@@ -214,7 +240,9 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
214
240
|
if (opts.prefixes === undefined) opts = { ...opts, prefixes: new Map() }
|
|
215
241
|
if (opts.types === undefined) opts = { ...opts, types: new Map() }
|
|
216
242
|
|
|
217
|
-
const artifact =
|
|
243
|
+
const artifact =
|
|
244
|
+
asset === true ||
|
|
245
|
+
(moduleType(url, attributes, null, opts) === constants.ADDON && !isWebAssembly(url))
|
|
218
246
|
|
|
219
247
|
if (source === null) {
|
|
220
248
|
if (url.protocol === 'data:') {
|
|
@@ -234,8 +262,17 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
234
262
|
}
|
|
235
263
|
}
|
|
236
264
|
|
|
237
|
-
|
|
238
|
-
|
|
265
|
+
// A module resolves its imports once, however many contexts it is loaded in,
|
|
266
|
+
// so a context that reaches it after another walks what the other resolved.
|
|
267
|
+
// The addons that are reached are then checked against the context.
|
|
268
|
+
const resolved = opts.resolvedImports.get(url.href)
|
|
269
|
+
|
|
270
|
+
const preresolved = resolved === undefined ? resolutions : { [url.href]: resolved }
|
|
271
|
+
|
|
272
|
+
if (preresolved) {
|
|
273
|
+
if (
|
|
274
|
+
yield* exports.preresolved(url, source, attributes, preresolved, artifacts, visited, opts)
|
|
275
|
+
) {
|
|
239
276
|
return true
|
|
240
277
|
}
|
|
241
278
|
}
|
|
@@ -290,15 +327,22 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
290
327
|
}
|
|
291
328
|
}
|
|
292
329
|
|
|
330
|
+
const compressed = compressImportsMap(imports)
|
|
331
|
+
|
|
332
|
+
opts.resolvedImports.set(url.href, compressed)
|
|
333
|
+
|
|
293
334
|
yield {
|
|
294
|
-
dependency:
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
335
|
+
dependency: withWASI(
|
|
336
|
+
{
|
|
337
|
+
url: exports.alias(url, opts),
|
|
338
|
+
source,
|
|
339
|
+
type,
|
|
340
|
+
naturalType,
|
|
341
|
+
imports: compressed,
|
|
342
|
+
lexer
|
|
343
|
+
},
|
|
344
|
+
opts
|
|
345
|
+
)
|
|
302
346
|
}
|
|
303
347
|
|
|
304
348
|
return true
|
|
@@ -342,7 +386,15 @@ exports.package = function* (url, source, artifacts, visited, opts = {}) {
|
|
|
342
386
|
return false
|
|
343
387
|
}
|
|
344
388
|
|
|
345
|
-
exports.preresolved = function* (
|
|
389
|
+
exports.preresolved = function* (
|
|
390
|
+
url,
|
|
391
|
+
source,
|
|
392
|
+
attributes,
|
|
393
|
+
resolutions,
|
|
394
|
+
artifacts,
|
|
395
|
+
visited,
|
|
396
|
+
opts = {}
|
|
397
|
+
) {
|
|
346
398
|
const {
|
|
347
399
|
builtinProtocol = 'builtin:',
|
|
348
400
|
linkedProtocol = 'linked:',
|
|
@@ -353,6 +405,17 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
353
405
|
|
|
354
406
|
if (typeof imports !== 'object' || imports === null) return false
|
|
355
407
|
|
|
408
|
+
attributes = attributes || {}
|
|
409
|
+
|
|
410
|
+
const parentURL = url
|
|
411
|
+
|
|
412
|
+
// The resolutions map leaves out the import attributes, so they are read
|
|
413
|
+
// from the source instead.
|
|
414
|
+
const lexed =
|
|
415
|
+
opts.asset !== true && isJavaScript(moduleType(url, attributes, null, opts))
|
|
416
|
+
? lex(source)
|
|
417
|
+
: null
|
|
418
|
+
|
|
356
419
|
let info = null
|
|
357
420
|
|
|
358
421
|
for (const [specifier, entry] of Object.entries(imports)) {
|
|
@@ -382,7 +445,11 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
382
445
|
} else if (url.protocol === deferredProtocol) {
|
|
383
446
|
continue
|
|
384
447
|
} else if (url.protocol === builtinProtocol || url.protocol === linkedProtocol) {
|
|
385
|
-
if (addon
|
|
448
|
+
if (addon) {
|
|
449
|
+
assertImportedAddonContext(url, imports, parentURL, opts)
|
|
450
|
+
|
|
451
|
+
if (artifacts !== null) addURL(artifacts.addons, url)
|
|
452
|
+
}
|
|
386
453
|
} else if (asset) {
|
|
387
454
|
if (artifacts !== null) {
|
|
388
455
|
const expanded = yield* expandAsset(url, artifacts, visited, { ...opts, importType: 0 })
|
|
@@ -402,13 +469,24 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
402
469
|
}
|
|
403
470
|
}
|
|
404
471
|
} else {
|
|
405
|
-
if (addon
|
|
472
|
+
if (addon) {
|
|
473
|
+
assertImportedAddonContext(url, imports, parentURL, opts)
|
|
474
|
+
|
|
475
|
+
if (artifacts !== null) addURL(artifacts.addons, url)
|
|
476
|
+
}
|
|
406
477
|
|
|
407
478
|
yield {
|
|
408
|
-
children: exports.module(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
479
|
+
children: exports.module(
|
|
480
|
+
url,
|
|
481
|
+
null,
|
|
482
|
+
addon ? { type: 'addon' } : importAttributes(lexed, specifier, imports),
|
|
483
|
+
artifacts,
|
|
484
|
+
visited,
|
|
485
|
+
{
|
|
486
|
+
...opts,
|
|
487
|
+
importType: 0
|
|
488
|
+
}
|
|
489
|
+
),
|
|
412
490
|
deferred: false
|
|
413
491
|
}
|
|
414
492
|
}
|
|
@@ -424,26 +502,27 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
424
502
|
}
|
|
425
503
|
}
|
|
426
504
|
|
|
427
|
-
const type = moduleType(url,
|
|
505
|
+
const type = moduleType(url, attributes, info, opts)
|
|
428
506
|
|
|
429
507
|
const lexer = { imports: [], exports: [] }
|
|
430
508
|
|
|
431
|
-
if (
|
|
432
|
-
const lexed = lex(source)
|
|
433
|
-
|
|
509
|
+
if (lexed !== null && isJavaScript(type)) {
|
|
434
510
|
lexer.imports = lexed.imports
|
|
435
511
|
lexer.exports = lexed.exports
|
|
436
512
|
}
|
|
437
513
|
|
|
438
514
|
yield {
|
|
439
|
-
dependency:
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
515
|
+
dependency: withWASI(
|
|
516
|
+
{
|
|
517
|
+
url: exports.alias(url, opts),
|
|
518
|
+
source,
|
|
519
|
+
type,
|
|
520
|
+
naturalType: naturalModuleType(url, attributes, info, type, opts),
|
|
521
|
+
imports: compressImportsMap(imports),
|
|
522
|
+
lexer
|
|
523
|
+
},
|
|
524
|
+
opts
|
|
525
|
+
)
|
|
447
526
|
}
|
|
448
527
|
|
|
449
528
|
return true
|
|
@@ -491,8 +570,10 @@ exports.link = function* (
|
|
|
491
570
|
visited,
|
|
492
571
|
opts = {}
|
|
493
572
|
) {
|
|
494
|
-
|
|
495
|
-
const specifier = entry.attributes
|
|
573
|
+
for (const name of ['imports', 'wasi']) {
|
|
574
|
+
const specifier = entry.attributes[name]
|
|
575
|
+
|
|
576
|
+
if (!specifier) continue
|
|
496
577
|
|
|
497
578
|
yield* resolveImport(
|
|
498
579
|
{ type: 0, specifier, names: [], attributes: {}, position: [0, 0, 0] },
|
|
@@ -515,7 +596,8 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
515
596
|
builtinProtocol = 'builtin:',
|
|
516
597
|
linkedProtocol = 'linked:',
|
|
517
598
|
deferredProtocol = 'deferred:',
|
|
518
|
-
deferUnresolved = false
|
|
599
|
+
deferUnresolved = false,
|
|
600
|
+
loadable = null
|
|
519
601
|
} = opts
|
|
520
602
|
|
|
521
603
|
const matchedConditions = []
|
|
@@ -524,7 +606,11 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
524
606
|
|
|
525
607
|
matchedConditions.push(condition)
|
|
526
608
|
|
|
527
|
-
const resolver = resolve(
|
|
609
|
+
const resolver = resolve(
|
|
610
|
+
entry,
|
|
611
|
+
parentURL,
|
|
612
|
+
condition === 'addon' && opts.addonHost ? { ...opts, hosts: [opts.addonHost] } : opts
|
|
613
|
+
)
|
|
528
614
|
const candidates = []
|
|
529
615
|
|
|
530
616
|
let next = resolver.next()
|
|
@@ -548,6 +634,8 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
548
634
|
url.protocol === linkedProtocol ||
|
|
549
635
|
url.protocol === deferredProtocol
|
|
550
636
|
) {
|
|
637
|
+
if (condition === 'addon') assertImportedAddonContext(url, imports, parentURL, opts)
|
|
638
|
+
|
|
551
639
|
addResolution(imports, specifier, matchedConditions, url)
|
|
552
640
|
|
|
553
641
|
resolved = true
|
|
@@ -565,7 +653,7 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
565
653
|
condition === 'addon' ||
|
|
566
654
|
moduleType(url, entry.attributes, null, opts) === constants.ADDON
|
|
567
655
|
) {
|
|
568
|
-
let exists = yield { probe: url }
|
|
656
|
+
let exists = isWebAssembly(url) ? undefined : yield { probe: url }
|
|
569
657
|
let source = null
|
|
570
658
|
|
|
571
659
|
if (exists === undefined) {
|
|
@@ -573,13 +661,15 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
573
661
|
exists = source !== null
|
|
574
662
|
}
|
|
575
663
|
|
|
576
|
-
if (exists)
|
|
577
|
-
|
|
664
|
+
if (exists) resolution = yield* postresolve(url)
|
|
665
|
+
|
|
666
|
+
if (exists && (loadable === null || loadable(resolution))) {
|
|
667
|
+
assertImportedAddonContext(resolution, imports, parentURL, opts)
|
|
578
668
|
|
|
579
669
|
addResolution(imports, specifier, matchedConditions, exports.alias(resolution, opts))
|
|
580
670
|
|
|
581
671
|
yield {
|
|
582
|
-
children: exports.module(resolution, source, {}, artifacts, visited, {
|
|
672
|
+
children: exports.module(resolution, source, { type: 'addon' }, artifacts, visited, {
|
|
583
673
|
...opts,
|
|
584
674
|
probed: true
|
|
585
675
|
}),
|
|
@@ -608,6 +698,10 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
608
698
|
attributes = { ...attributes, imports: imports[attributes.imports].default }
|
|
609
699
|
}
|
|
610
700
|
|
|
701
|
+
if (attributes.wasi) {
|
|
702
|
+
attributes = { ...attributes, wasi: imports[attributes.wasi].default }
|
|
703
|
+
}
|
|
704
|
+
|
|
611
705
|
yield {
|
|
612
706
|
children: exports.module(resolution, source, attributes, artifacts, visited, {
|
|
613
707
|
...opts,
|
|
@@ -657,7 +751,115 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
657
751
|
}
|
|
658
752
|
}
|
|
659
753
|
|
|
660
|
-
const ADDON_EXTENSION = /\.(bare|node)$/
|
|
754
|
+
const ADDON_EXTENSION = /\.(bare|node|wasm)$/
|
|
755
|
+
|
|
756
|
+
function importAttributes(lexed, specifier, imports) {
|
|
757
|
+
const attributes = {}
|
|
758
|
+
|
|
759
|
+
if (lexed === null) return attributes
|
|
760
|
+
|
|
761
|
+
for (const entry of lexed.imports) {
|
|
762
|
+
if (entry.specifier !== specifier) continue
|
|
763
|
+
|
|
764
|
+
for (const name of ['type', 'host', 'wasi']) {
|
|
765
|
+
if (typeof entry.attributes[name] === 'string') attributes[name] = entry.attributes[name]
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (attributes.wasi !== undefined) attributes.wasi = defaultResolution(imports[attributes.wasi])
|
|
770
|
+
|
|
771
|
+
return attributes
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function defaultResolution(entry) {
|
|
775
|
+
return typeof entry === 'string' ? entry : entry.default
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Only hosts that load on any platform may be asked for, so that an import
|
|
779
|
+
// can't pick the native addons of another platform.
|
|
780
|
+
const portableHosts = ['wasi-wasm32']
|
|
781
|
+
|
|
782
|
+
function addonHostForAttribute(host) {
|
|
783
|
+
if (portableHosts.includes(host)) return host
|
|
784
|
+
|
|
785
|
+
throw errors.UNKNOWN_ADDON_HOST(`Addon host '${host}' is not supported`)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function withConditions(conditions = [], added) {
|
|
789
|
+
if (conditions.every((condition) => typeof condition === 'string')) {
|
|
790
|
+
return [...conditions, ...added]
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return conditions.map((subset) => withConditions(subset, added))
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function visitedFor(contexts, host, wasi) {
|
|
797
|
+
const key = JSON.stringify([host, wasi])
|
|
798
|
+
|
|
799
|
+
let context = contexts.get(key)
|
|
800
|
+
|
|
801
|
+
if (context === undefined) contexts.set(key, (context = { host, wasi, visited: new Set() }))
|
|
802
|
+
|
|
803
|
+
return context.visited
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function withWASI(dependency, opts) {
|
|
807
|
+
const { addonWASI = null } = opts
|
|
808
|
+
|
|
809
|
+
if (addonWASI !== null && dependency.type === constants.ADDON && isWebAssembly(dependency.url)) {
|
|
810
|
+
dependency.wasi = addonWASI
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
return dependency
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
function assertImportedAddonContext(url, imports, parentURL, opts) {
|
|
817
|
+
const { addonHost = null, addonWASI = null, addonContexts } = opts
|
|
818
|
+
|
|
819
|
+
exports.assertAddonContext(
|
|
820
|
+
url,
|
|
821
|
+
imports['#package'] || parentURL.href,
|
|
822
|
+
{ host: addonHost, wasi: addonWASI },
|
|
823
|
+
addonContexts
|
|
824
|
+
)
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
exports.assertAddonContext = function assertAddonContext(url, scope, context, addonContexts) {
|
|
828
|
+
if (url.protocol === 'builtin:') return
|
|
829
|
+
|
|
830
|
+
const { host = null } = context
|
|
831
|
+
|
|
832
|
+
if (host !== null && !isWebAssembly(url)) {
|
|
833
|
+
throw errors.ADDON_HOST_INCOMPATIBLE(
|
|
834
|
+
`Addon '${url.href}' is not a WebAssembly addon, but '${host}' was asked for`
|
|
835
|
+
)
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Only WebAssembly addons are given WASI capabilities.
|
|
839
|
+
const wasi = isWebAssembly(url) ? context.wasi || null : null
|
|
840
|
+
|
|
841
|
+
const recorded = addonContexts.get(scope)
|
|
842
|
+
|
|
843
|
+
if (recorded === undefined) {
|
|
844
|
+
addonContexts.set(scope, { host, wasi })
|
|
845
|
+
} else if (recorded.host !== host) {
|
|
846
|
+
throw errors.ADDON_HOST_INCOMPATIBLE(
|
|
847
|
+
`Addons of '${scope}' are already resolved for ${recorded.host === null ? 'the default hosts' : `'${recorded.host}'`}`
|
|
848
|
+
)
|
|
849
|
+
} else if (recorded.wasi !== wasi) {
|
|
850
|
+
throw errors.ADDON_WASI_INCOMPATIBLE(
|
|
851
|
+
`Addons of '${scope}' are already given ${recorded.wasi === null ? 'the default WASI capabilities' : `the WASI capabilities of '${recorded.wasi}'`}`
|
|
852
|
+
)
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function isJavaScript(type) {
|
|
857
|
+
return type === constants.SCRIPT || type === constants.MODULE
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function isWebAssembly(url) {
|
|
861
|
+
return url.pathname.endsWith('.wasm')
|
|
862
|
+
}
|
|
661
863
|
|
|
662
864
|
exports.addons = function* (parentURL, artifacts, visited, opts = {}) {
|
|
663
865
|
let yielded = false
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// One set of conditions for each host, each with the targeted conditions. A
|
|
2
|
+
// host whose conditions are targeted in every set already has its resolutions,
|
|
3
|
+
// so it gets no set of its own.
|
|
4
|
+
module.exports = function conditions(base, hosts, targets) {
|
|
5
|
+
const subsets = leaves(targets)
|
|
6
|
+
|
|
7
|
+
const own = hosts.filter(
|
|
8
|
+
(host) =>
|
|
9
|
+
!subsets.every((subset) => host.split('-').every((condition) => subset.includes(condition)))
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
return (own.length > 0 ? own : hosts).flatMap((host) =>
|
|
13
|
+
subsets.map((subset) => [...base, ...host.split('-'), ...subset])
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Conditions nest to any depth and are tried depth first, so they match as
|
|
18
|
+
// their innermost lists would in order.
|
|
19
|
+
function leaves(conditions) {
|
|
20
|
+
if (conditions.every((condition) => typeof condition === 'string')) return [conditions]
|
|
21
|
+
|
|
22
|
+
return conditions.flatMap(leaves)
|
|
23
|
+
}
|
package/lib/errors.js
CHANGED
|
@@ -49,6 +49,18 @@ module.exports = class ModuleTraverseError extends Error {
|
|
|
49
49
|
return new ModuleTraverseError(msg, ModuleTraverseError.TYPE_INCOMPATIBLE)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
static UNKNOWN_ADDON_HOST(msg) {
|
|
53
|
+
return new ModuleTraverseError(msg, ModuleTraverseError.UNKNOWN_ADDON_HOST)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static ADDON_HOST_INCOMPATIBLE(msg) {
|
|
57
|
+
return new ModuleTraverseError(msg, ModuleTraverseError.ADDON_HOST_INCOMPATIBLE)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static ADDON_WASI_INCOMPATIBLE(msg) {
|
|
61
|
+
return new ModuleTraverseError(msg, ModuleTraverseError.ADDON_WASI_INCOMPATIBLE)
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
static AMBIGUOUS_MODULE_TYPE(msg) {
|
|
53
65
|
return new ModuleTraverseError(msg, ModuleTraverseError.AMBIGUOUS_MODULE_TYPE)
|
|
54
66
|
}
|
package/lib/resolve/bare.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import URL from 'bare-url'
|
|
1
2
|
import { type Import } from 'bare-module-lexer'
|
|
2
|
-
import { type
|
|
3
|
+
import { type Conditions, type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
|
|
4
|
+
import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
|
|
3
5
|
|
|
4
|
-
interface BareResolveOptions extends
|
|
6
|
+
interface BareResolveOptions extends ModuleResolveOptions, AddonResolveOptions {
|
|
5
7
|
linked?: boolean
|
|
6
8
|
host?: string
|
|
7
9
|
hosts?: string[]
|
|
10
|
+
/**
|
|
11
|
+
* The conditions that may be targeted in addition to those of each host,
|
|
12
|
+
* either a list or nested lists to try in turn.
|
|
13
|
+
*/
|
|
14
|
+
conditions?: Conditions
|
|
8
15
|
}
|
|
9
16
|
|
|
10
17
|
/**
|
package/lib/resolve/bare.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
const lex = require('bare-module-lexer')
|
|
2
2
|
const resolve = require('../resolve')
|
|
3
3
|
const runtime = require('../runtime')
|
|
4
|
+
const hostConditions = require('../conditions')
|
|
4
5
|
|
|
5
6
|
module.exports = function (entry, parentURL, opts = {}) {
|
|
6
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
linked = false,
|
|
9
|
+
host = runtime.host,
|
|
10
|
+
hosts = [host, 'wasi-wasm32'],
|
|
11
|
+
conditions: targets = []
|
|
12
|
+
} = opts
|
|
7
13
|
|
|
8
14
|
let directories = false
|
|
9
15
|
let extensions
|
|
10
|
-
let conditions =
|
|
16
|
+
let conditions = hostConditions(['bare', 'node'], hosts, targets)
|
|
11
17
|
|
|
12
18
|
if (entry.type & lex.constants.ADDON) {
|
|
13
19
|
extensions = linked ? [] : ['.bare', '.node']
|
package/lib/resolve/default.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import URL from 'bare-url'
|
|
1
2
|
import { type Import } from 'bare-module-lexer'
|
|
2
|
-
import { type ResolveOptions
|
|
3
|
+
import { type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
|
|
4
|
+
import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
|
|
5
|
+
|
|
6
|
+
interface ResolveOptions extends ModuleResolveOptions, AddonResolveOptions {}
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* @param entry - The import to resolve, as produced by `bare-module-lexer`.
|
package/lib/resolve/node.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import URL from 'bare-url'
|
|
1
2
|
import { type Import } from 'bare-module-lexer'
|
|
2
|
-
import { type
|
|
3
|
+
import { type Conditions, type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
|
|
4
|
+
import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
|
|
3
5
|
|
|
4
|
-
interface NodeResolveOptions extends
|
|
6
|
+
interface NodeResolveOptions extends ModuleResolveOptions, AddonResolveOptions {
|
|
5
7
|
host?: string
|
|
6
8
|
hosts?: string[]
|
|
9
|
+
/**
|
|
10
|
+
* The conditions that may be targeted in addition to those of each host,
|
|
11
|
+
* either a list or nested lists to try in turn.
|
|
12
|
+
*/
|
|
13
|
+
conditions?: Conditions
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
/**
|
package/lib/resolve/node.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
const lex = require('bare-module-lexer')
|
|
2
2
|
const resolve = require('../resolve')
|
|
3
3
|
const runtime = require('../runtime')
|
|
4
|
+
const hostConditions = require('../conditions')
|
|
4
5
|
|
|
5
6
|
module.exports = function (entry, parentURL, opts = {}) {
|
|
6
|
-
const { host = runtime.host, hosts = [host] } = opts
|
|
7
|
+
const { host = runtime.host, hosts = [host], conditions: targets = [] } = opts
|
|
7
8
|
|
|
8
9
|
let directories = false
|
|
9
10
|
let extensions
|
|
10
|
-
let conditions =
|
|
11
|
+
let conditions = hostConditions(['node'], hosts, targets)
|
|
11
12
|
|
|
12
13
|
if (entry.type & lex.constants.ADDON) {
|
|
13
14
|
extensions = ['.node']
|