bare-module-traverse 2.4.0 → 2.4.2
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 +9 -4
- package/index.d.ts +8 -4
- package/index.js +105 -50
- package/lib/errors.js +8 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -72,6 +72,8 @@ options = {
|
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
When a module URL uses the `data:` protocol, its source is decoded directly from the specifier rather than read via `readModule()`, so no source module effect is emitted for it. base64 encoded data is decoded to a `Buffer`, other data is percent-decoded to a string, and the module type is derived from the media type (`text/javascript` and `application/javascript` map to a script or module, `application/json` to JSON, and anything else to `defaultType`). A JavaScript `data:` URL inherits the type of the module that imports it, so it is a script when imported from a script and a module when imported from a module, falling back to `defaultType` when it has no referrer, such as a `data:` entry. Only the UTF-8 charset is supported; a `data:` URL specifying any other charset throws.
|
|
76
|
+
|
|
75
77
|
`visited` is a `Set` of already visited module hrefs. If provided, modules whose href is already in the set are skipped and the set is updated in place as traversal proceeds. This allows a single set to be shared across several traversals so that a later traversal, such as one rooted at a dynamically imported module, does not revisit modules already seen by an earlier one.
|
|
76
78
|
|
|
77
79
|
Options supported by <https://github.com/holepunchto/bare-module-resolve> and <https://github.com/holepunchto/bare-addon-resolve> may also be specified.
|
|
@@ -165,11 +167,12 @@ The following generator functions implement the traversal algorithm. The yielded
|
|
|
165
167
|
|
|
166
168
|
**Source module**
|
|
167
169
|
|
|
168
|
-
A module to be read. The driver returns its source if it exists, otherwise `null`.
|
|
170
|
+
A module to be read. The driver returns its source if it exists, otherwise `null`. When `artifact` is `true`, the module is an addon or asset whose contents are loaded lazily and referenced by path. A driver that only needs to locate such artifacts, such as a module loader, may return `null` without reading, having already established existence by probing; a driver that embeds their contents, such as a bundler, reads them as normal.
|
|
169
171
|
|
|
170
172
|
```js
|
|
171
173
|
next.value = {
|
|
172
|
-
module: URL
|
|
174
|
+
module: URL,
|
|
175
|
+
artifact: boolean
|
|
173
176
|
}
|
|
174
177
|
```
|
|
175
178
|
|
|
@@ -265,7 +268,9 @@ function drive(generator) {
|
|
|
265
268
|
const value = next.value
|
|
266
269
|
|
|
267
270
|
if (value.module) {
|
|
268
|
-
// Read `value.module` if it exists, otherwise `null
|
|
271
|
+
// Read `value.module` if it exists, otherwise `null`. When
|
|
272
|
+
// `value.artifact` is `true`, the module is an addon or asset that may be
|
|
273
|
+
// left unread, returning `null`, unless its contents are needed
|
|
269
274
|
let source
|
|
270
275
|
|
|
271
276
|
next = generator.next(source)
|
|
@@ -322,7 +327,7 @@ Options are the same as `traverse()` for all functions.
|
|
|
322
327
|
|
|
323
328
|
#### `const generator = traverse.preresolved(url, source, resolutions, artifacts, visited[, options])`
|
|
324
329
|
|
|
325
|
-
#### `const generator = traverse.imports(parentURL, source, imports, artifacts, visited[, options])`
|
|
330
|
+
#### `const generator = traverse.imports(parentURL, source, imports, artifacts, lexer, visited[, options])`
|
|
326
331
|
|
|
327
332
|
#### `const generator = traverse.link(entry, specifier, condition, parentURL, imports, artifacts, visited[, options])`
|
|
328
333
|
|
package/index.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ declare namespace traverse {
|
|
|
77
77
|
export { type TraverseOptions }
|
|
78
78
|
|
|
79
79
|
export type Traversal = Generator<
|
|
80
|
-
| { module: URL }
|
|
80
|
+
| { module: URL; artifact: boolean }
|
|
81
81
|
| { probe: URL }
|
|
82
82
|
| { resolution: URL }
|
|
83
83
|
| { prefix: URL }
|
|
@@ -134,6 +134,10 @@ declare namespace traverse {
|
|
|
134
134
|
source: string | Buffer,
|
|
135
135
|
imports: ImportsMap,
|
|
136
136
|
artifacts: Artifacts,
|
|
137
|
+
lexer: {
|
|
138
|
+
imports: Import[]
|
|
139
|
+
exports: Export[]
|
|
140
|
+
},
|
|
137
141
|
visited: Set<string>,
|
|
138
142
|
opts?: TraverseOptions
|
|
139
143
|
): Traversal
|
|
@@ -149,8 +153,8 @@ declare namespace traverse {
|
|
|
149
153
|
opts?: TraverseOptions
|
|
150
154
|
): Traversal
|
|
151
155
|
|
|
152
|
-
export function
|
|
153
|
-
|
|
156
|
+
export function addons(
|
|
157
|
+
parentURL: URL,
|
|
154
158
|
artifacts: Artifacts,
|
|
155
159
|
visited: Set<string>,
|
|
156
160
|
opts?: TraverseOptions
|
|
@@ -158,7 +162,7 @@ declare namespace traverse {
|
|
|
158
162
|
|
|
159
163
|
export function assets(
|
|
160
164
|
patterns: ConditionalSpecifier,
|
|
161
|
-
|
|
165
|
+
parentURL: URL,
|
|
162
166
|
artifacts: Artifacts,
|
|
163
167
|
visited: Set<string>,
|
|
164
168
|
opts?: TraverseOptions
|
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { lookupPackageScope, conditionMatches } = require('bare-module-resolve')
|
|
2
2
|
const lex = require('bare-module-lexer')
|
|
3
|
+
const MIME = require('bare-mime')
|
|
3
4
|
const resolve = require('./lib/resolve')
|
|
4
5
|
const errors = require('./lib/errors')
|
|
5
6
|
|
|
@@ -196,16 +197,20 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
196
197
|
const artifact = asset === true || moduleType(url, attributes, null, opts) === constants.ADDON
|
|
197
198
|
|
|
198
199
|
if (source === null) {
|
|
199
|
-
|
|
200
|
+
if (url.protocol === 'data:') {
|
|
201
|
+
source = decodeDataURL(url)
|
|
202
|
+
} else {
|
|
203
|
+
const exists = probed !== undefined ? probed : artifact ? yield { probe: url } : undefined
|
|
200
204
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
205
|
+
if (exists === false) {
|
|
206
|
+
throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`, url.href)
|
|
207
|
+
}
|
|
204
208
|
|
|
205
|
-
|
|
209
|
+
source = yield { module: url, artifact }
|
|
206
210
|
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
if (exists !== true && source === null) {
|
|
212
|
+
throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`, url.href)
|
|
213
|
+
}
|
|
209
214
|
}
|
|
210
215
|
}
|
|
211
216
|
|
|
@@ -219,27 +224,29 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
219
224
|
|
|
220
225
|
let info = null
|
|
221
226
|
|
|
222
|
-
|
|
223
|
-
const
|
|
227
|
+
if (url.protocol !== 'data:') {
|
|
228
|
+
for (const packageURL of lookupPackageScope(url, opts)) {
|
|
229
|
+
const source = yield { module: packageURL, artifact: false }
|
|
224
230
|
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
if (source !== null) {
|
|
232
|
+
info = JSON.parse(source)
|
|
227
233
|
|
|
228
|
-
|
|
234
|
+
imports['#package'] = packageURL.href
|
|
229
235
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
yield {
|
|
237
|
+
children: exports.package(packageURL, source, artifacts, visited, opts),
|
|
238
|
+
deferred: false
|
|
239
|
+
}
|
|
234
240
|
|
|
235
|
-
|
|
241
|
+
break
|
|
242
|
+
}
|
|
236
243
|
}
|
|
237
244
|
}
|
|
238
245
|
|
|
239
246
|
if (typeof attributes.imports === 'string') {
|
|
240
247
|
const url = new URL(attributes.imports)
|
|
241
248
|
|
|
242
|
-
const source = yield { module: url }
|
|
249
|
+
const source = yield { module: url, artifact: false }
|
|
243
250
|
|
|
244
251
|
if (source !== null) {
|
|
245
252
|
opts = {
|
|
@@ -255,7 +262,10 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
255
262
|
|
|
256
263
|
if (asset === false) {
|
|
257
264
|
if (type === constants.SCRIPT || type === constants.MODULE) {
|
|
258
|
-
yield* exports.imports(url, source, imports, artifacts, lexer, visited,
|
|
265
|
+
yield* exports.imports(url, source, imports, artifacts, lexer, visited, {
|
|
266
|
+
...opts,
|
|
267
|
+
referrerType: type
|
|
268
|
+
})
|
|
259
269
|
} else if (type === constants.ADDON) {
|
|
260
270
|
yield* exports.addons(url, artifacts, visited, opts)
|
|
261
271
|
}
|
|
@@ -280,7 +290,7 @@ exports.package = function* (url, source, artifacts, visited, opts = {}) {
|
|
|
280
290
|
visited.add(url.href)
|
|
281
291
|
|
|
282
292
|
if (source === null) {
|
|
283
|
-
source = yield { module: url }
|
|
293
|
+
source = yield { module: url, artifact: false }
|
|
284
294
|
|
|
285
295
|
if (source === null) return false
|
|
286
296
|
}
|
|
@@ -339,16 +349,12 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
339
349
|
} else if (asset) {
|
|
340
350
|
addURL(artifacts.assets, url)
|
|
341
351
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
asset: true
|
|
349
|
-
}),
|
|
350
|
-
deferred: true
|
|
351
|
-
}
|
|
352
|
+
yield {
|
|
353
|
+
children: exports.module(url, null, {}, artifacts, visited, {
|
|
354
|
+
...opts,
|
|
355
|
+
asset: true
|
|
356
|
+
}),
|
|
357
|
+
deferred: true
|
|
352
358
|
}
|
|
353
359
|
} else if (
|
|
354
360
|
url.protocol !== builtinProtocol &&
|
|
@@ -473,7 +479,7 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
473
479
|
const value = next.value
|
|
474
480
|
|
|
475
481
|
if (value.package) {
|
|
476
|
-
next = resolver.next(JSON.parse(yield { module: value.package }))
|
|
482
|
+
next = resolver.next(JSON.parse(yield { module: value.package, artifact: false }))
|
|
477
483
|
} else {
|
|
478
484
|
const url = value.resolution
|
|
479
485
|
|
|
@@ -510,19 +516,22 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
510
516
|
}
|
|
511
517
|
|
|
512
518
|
if (resolved) addResolution(imports, specifier, matchedConditions, url)
|
|
513
|
-
} else if (
|
|
519
|
+
} else if (
|
|
520
|
+
condition === 'addon' ||
|
|
521
|
+
moduleType(url, entry.attributes, null, opts) === constants.ADDON
|
|
522
|
+
) {
|
|
514
523
|
let exists = yield { probe: url }
|
|
515
524
|
let source = null
|
|
516
525
|
|
|
517
526
|
if (exists === undefined) {
|
|
518
|
-
source = yield { module: url }
|
|
527
|
+
source = yield { module: url, artifact: false }
|
|
519
528
|
exists = source !== null
|
|
520
529
|
}
|
|
521
530
|
|
|
522
531
|
if (exists) {
|
|
523
532
|
resolution = yield* postresolve(url)
|
|
524
533
|
|
|
525
|
-
addResolution(imports, specifier, matchedConditions, resolution)
|
|
534
|
+
addResolution(imports, specifier, matchedConditions, exports.alias(resolution, opts))
|
|
526
535
|
|
|
527
536
|
yield {
|
|
528
537
|
children: exports.module(resolution, source, {}, artifacts, visited, {
|
|
@@ -535,7 +544,13 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
535
544
|
resolved = true
|
|
536
545
|
}
|
|
537
546
|
} else {
|
|
538
|
-
|
|
547
|
+
let source
|
|
548
|
+
|
|
549
|
+
if (url.protocol === 'data:') {
|
|
550
|
+
source = decodeDataURL(url)
|
|
551
|
+
} else {
|
|
552
|
+
source = yield { module: url, artifact: false }
|
|
553
|
+
}
|
|
539
554
|
|
|
540
555
|
if (source !== null) {
|
|
541
556
|
resolution = yield* postresolve(url)
|
|
@@ -621,23 +636,19 @@ exports.assets = function* (patterns, parentURL, artifacts, visited, opts = {})
|
|
|
621
636
|
let yielded = false
|
|
622
637
|
|
|
623
638
|
for (const url of matches) {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
if (source !== null) {
|
|
627
|
-
const resolution = yield* postresolve(url)
|
|
628
|
-
|
|
629
|
-
addURL(artifacts.assets, resolution)
|
|
639
|
+
const resolution = yield* postresolve(url)
|
|
630
640
|
|
|
631
|
-
|
|
632
|
-
children: exports.module(resolution, source, {}, artifacts, visited, {
|
|
633
|
-
...opts,
|
|
634
|
-
asset: true
|
|
635
|
-
}),
|
|
636
|
-
deferred: true
|
|
637
|
-
}
|
|
641
|
+
addURL(artifacts.assets, resolution)
|
|
638
642
|
|
|
639
|
-
|
|
643
|
+
yield {
|
|
644
|
+
children: exports.module(resolution, null, {}, artifacts, visited, {
|
|
645
|
+
...opts,
|
|
646
|
+
asset: true
|
|
647
|
+
}),
|
|
648
|
+
deferred: true
|
|
640
649
|
}
|
|
650
|
+
|
|
651
|
+
yielded = true
|
|
641
652
|
}
|
|
642
653
|
|
|
643
654
|
return yielded
|
|
@@ -711,7 +722,7 @@ function* postresolve(url) {
|
|
|
711
722
|
}
|
|
712
723
|
|
|
713
724
|
function moduleType(url, attributes, info, opts = {}) {
|
|
714
|
-
const { defaultType = constants.SCRIPT, aliases = null } = opts
|
|
725
|
+
const { defaultType = constants.SCRIPT, referrerType, aliases = null } = opts
|
|
715
726
|
|
|
716
727
|
if (typeof attributes.type === 'string') {
|
|
717
728
|
switch (attributes.type) {
|
|
@@ -734,6 +745,20 @@ function moduleType(url, attributes, info, opts = {}) {
|
|
|
734
745
|
return 0
|
|
735
746
|
}
|
|
736
747
|
|
|
748
|
+
if (url.protocol === 'data:') {
|
|
749
|
+
const { mime } = parseDataURL(url)
|
|
750
|
+
|
|
751
|
+
if (mime === null || mime.subtype === 'javascript') {
|
|
752
|
+
if (referrerType) return referrerType
|
|
753
|
+
|
|
754
|
+
return defaultType === constants.MODULE ? constants.MODULE : constants.SCRIPT
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (mime.subtype === 'json') return constants.JSON
|
|
758
|
+
|
|
759
|
+
return defaultType
|
|
760
|
+
}
|
|
761
|
+
|
|
737
762
|
const match = url.pathname.match(/\.[a-z]+$/)
|
|
738
763
|
|
|
739
764
|
if (match === null) return defaultType
|
|
@@ -770,6 +795,36 @@ function moduleType(url, attributes, info, opts = {}) {
|
|
|
770
795
|
return defaultType
|
|
771
796
|
}
|
|
772
797
|
|
|
798
|
+
function parseDataURL(url) {
|
|
799
|
+
const { pathname } = url
|
|
800
|
+
|
|
801
|
+
const comma = pathname.indexOf(',')
|
|
802
|
+
|
|
803
|
+
const meta = comma === -1 ? pathname : pathname.slice(0, comma)
|
|
804
|
+
const data = comma === -1 ? '' : pathname.slice(comma + 1)
|
|
805
|
+
|
|
806
|
+
const base64 = /;base64$/i.test(meta)
|
|
807
|
+
|
|
808
|
+
return { mime: MIME.parse(meta), base64, data }
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function decodeDataURL(url) {
|
|
812
|
+
const { mime, base64, data } = parseDataURL(url)
|
|
813
|
+
|
|
814
|
+
const charset = mime === null ? undefined : mime.parameters.get('charset')
|
|
815
|
+
|
|
816
|
+
if (charset !== undefined && !/^utf-?8$/i.test(charset)) {
|
|
817
|
+
throw errors.UNKNOWN_DATA_URL_CHARSET(
|
|
818
|
+
`Unsupported charset '${charset}' in data URL '${url.href}'`,
|
|
819
|
+
charset
|
|
820
|
+
)
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (base64) return Buffer.from(data, 'base64')
|
|
824
|
+
|
|
825
|
+
return decodeURIComponent(data)
|
|
826
|
+
}
|
|
827
|
+
|
|
773
828
|
function addURL(collection, url) {
|
|
774
829
|
if (Array.isArray(collection)) {
|
|
775
830
|
let lo = 0
|
package/lib/errors.js
CHANGED
|
@@ -45,4 +45,12 @@ module.exports = class ModuleTraverseError extends Error {
|
|
|
45
45
|
static INVALID_IMPORTS_MAP(msg) {
|
|
46
46
|
return new ModuleTraverseError(msg, ModuleTraverseError.INVALID_IMPORTS_MAP)
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
static UNKNOWN_DATA_URL_CHARSET(msg, charset) {
|
|
50
|
+
const err = new ModuleTraverseError(msg, ModuleTraverseError.UNKNOWN_DATA_URL_CHARSET)
|
|
51
|
+
|
|
52
|
+
err.charset = charset
|
|
53
|
+
|
|
54
|
+
return err
|
|
55
|
+
}
|
|
48
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bare-module-traverse",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Low-level module graph traversal for Bare",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"homepage": "https://github.com/holepunchto/bare-module-traverse#readme",
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"bare-addon-resolve": "^1.5.0",
|
|
58
|
+
"bare-mime": "^1.0.0",
|
|
58
59
|
"bare-module-lexer": "^1.6.0",
|
|
59
60
|
"bare-module-resolve": "^1.7.0"
|
|
60
61
|
},
|