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 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 prebuilds(
153
- packageURL: URL,
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
- packageURL: URL,
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
- const exists = probed !== undefined ? probed : artifact ? yield { probe: url } : undefined
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
- if (exists === false) {
202
- throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`, url.href)
203
- }
205
+ if (exists === false) {
206
+ throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`, url.href)
207
+ }
204
208
 
205
- source = yield { module: url }
209
+ source = yield { module: url, artifact }
206
210
 
207
- if (exists !== true && source === null) {
208
- throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`, url.href)
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
- for (const packageURL of lookupPackageScope(url, opts)) {
223
- const source = yield { module: packageURL }
227
+ if (url.protocol !== 'data:') {
228
+ for (const packageURL of lookupPackageScope(url, opts)) {
229
+ const source = yield { module: packageURL, artifact: false }
224
230
 
225
- if (source !== null) {
226
- info = JSON.parse(source)
231
+ if (source !== null) {
232
+ info = JSON.parse(source)
227
233
 
228
- imports['#package'] = packageURL.href
234
+ imports['#package'] = packageURL.href
229
235
 
230
- yield {
231
- children: exports.package(packageURL, source, artifacts, visited, opts),
232
- deferred: false
233
- }
236
+ yield {
237
+ children: exports.package(packageURL, source, artifacts, visited, opts),
238
+ deferred: false
239
+ }
234
240
 
235
- break
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, opts)
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
- const source = yield { module: url }
343
-
344
- if (source !== null) {
345
- yield {
346
- children: exports.module(url, source, {}, artifacts, visited, {
347
- ...opts,
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 (condition === 'addon') {
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
- const source = yield { module: url }
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 source = yield { module: url }
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
- yield {
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
- yielded = true
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.0",
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
  },