bare-module-traverse 2.5.3 → 2.5.5

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
@@ -128,6 +128,9 @@ next.value = {
128
128
  url: URL,
129
129
  source: 'string' | Buffer,
130
130
  type: constants.SCRIPT,
131
+ // The type the module has on its own, ignoring import attributes, or 0 if
132
+ // it has no type of its own.
133
+ naturalType: constants.SCRIPT,
131
134
  imports: {
132
135
  // See https://github.com/holepunchto/bare-module#imports
133
136
  },
package/index.d.ts CHANGED
@@ -11,7 +11,15 @@ import { type Import, type Export } from 'bare-module-lexer'
11
11
  interface Dependency {
12
12
  url: URL
13
13
  source: string | Buffer
14
+ /** The type the module is loaded as. See `constants` for possible values. */
14
15
  type: number
16
+ /**
17
+ * The type the module has on its own, ignoring import attributes, or `0` if
18
+ * it has no type of its own. This differs from `type` only when an import
19
+ * attribute asked for a different type, so a loader can use it to tell
20
+ * whether an attribute changed the type.
21
+ */
22
+ naturalType: number
15
23
  imports: ImportsMap
16
24
  lexer: {
17
25
  imports: Import[]
@@ -35,15 +43,16 @@ type AliasableExtension =
35
43
 
36
44
  interface TraverseOptions extends ResolveOptions {
37
45
  /**
38
- * The type assumed for a module that names none of its own, such as an
39
- * ambiguous extension or a `data:` URL that no import reaches. See
46
+ * The type to assume for a module that has no type of its own, such as one
47
+ * with an ambiguous extension or a `data:` URL that no import reaches. See
40
48
  * `constants` for possible values.
41
49
  */
42
50
  defaultType?: number
43
51
  /**
44
- * The type of the import that names the entry. A `data:` URL of JavaScript
45
- * takes its type from this: `REQUIRE` names a script and `IMPORT` a module,
46
- * while `IMPORT | DYNAMIC` names either and so must carry a `type` attribute.
52
+ * The type of the import that led to the entry. A JavaScript `data:` URL
53
+ * takes its type from this: `REQUIRE` means a script and `IMPORT` a module,
54
+ * while `IMPORT | DYNAMIC` could mean either and so needs a `type`
55
+ * attribute.
47
56
  */
48
57
  importType?: number
49
58
  artifacts?: boolean
package/index.js CHANGED
@@ -192,9 +192,19 @@ 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 } = opts
195
+ const { resolutions = null, asset = false, probed, types } = opts
196
196
 
197
- if (visited.has(url.href)) return false
197
+ attributes = attributes || {}
198
+
199
+ if (visited.has(url.href)) {
200
+ // An asset is only read for its bytes, so it doesn't care what type the
201
+ // module is imported as elsewhere.
202
+ if (asset === false && types !== undefined) {
203
+ assertTypeAgrees(url, attributes, types.get(url.href), opts)
204
+ }
205
+
206
+ return false
207
+ }
198
208
 
199
209
  visited.add(url.href)
200
210
 
@@ -202,8 +212,7 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
202
212
 
203
213
  if (opts.packages === undefined) opts = { ...opts, packages: new Map() }
204
214
  if (opts.prefixes === undefined) opts = { ...opts, prefixes: new Map() }
205
-
206
- attributes = attributes || {}
215
+ if (opts.types === undefined) opts = { ...opts, types: new Map() }
207
216
 
208
217
  const artifact = asset === true || moduleType(url, attributes, null, opts) === constants.ADDON
209
218
 
@@ -264,6 +273,9 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
264
273
  }
265
274
 
266
275
  const type = moduleType(url, attributes, info, opts)
276
+ const naturalType = naturalModuleType(url, attributes, info, type, opts)
277
+
278
+ if (asset === false) opts.types.set(url.href, { type, asserted: attributes.type, info })
267
279
 
268
280
  const lexer = { imports: [], exports: [] }
269
281
 
@@ -283,6 +295,7 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
283
295
  url: exports.alias(url, opts),
284
296
  source,
285
297
  type,
298
+ naturalType,
286
299
  imports: compressImportsMap(imports),
287
300
  lexer
288
301
  }
@@ -310,6 +323,7 @@ exports.package = function* (url, source, artifacts, visited, opts = {}) {
310
323
  url,
311
324
  source,
312
325
  type: constants.JSON,
326
+ naturalType: constants.JSON,
313
327
  imports: {},
314
328
  lexer: { imports: [], exports: [] }
315
329
  }
@@ -392,7 +406,10 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
392
406
  const lexer = { imports: [], exports: [] }
393
407
 
394
408
  if (type === constants.SCRIPT || type === constants.MODULE) {
395
- lexer.exports = lex(source).exports
409
+ const lexed = lex(source)
410
+
411
+ lexer.imports = lexed.imports
412
+ lexer.exports = lexed.exports
396
413
  }
397
414
 
398
415
  yield {
@@ -400,6 +417,7 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
400
417
  url: exports.alias(url, opts),
401
418
  source,
402
419
  type,
420
+ naturalType: type,
403
421
  imports: compressImportsMap(imports),
404
422
  lexer
405
423
  }
@@ -810,6 +828,17 @@ function* postresolve(url) {
810
828
  return (yield { resolution: url }) || url
811
829
  }
812
830
 
831
+ // The type a module has on its own, ignoring import attributes. A JavaScript
832
+ // data: URL has no type of its own, so this returns 0; its type depends on how
833
+ // it is imported.
834
+ function naturalModuleType(url, attributes, info, type, opts) {
835
+ if (attributes.type === undefined) return type
836
+
837
+ if (url.protocol === 'data:') return 0
838
+
839
+ return moduleType(url, {}, info, opts)
840
+ }
841
+
813
842
  function moduleType(url, attributes, info, opts = {}) {
814
843
  const { defaultType = constants.SCRIPT, aliases = null } = opts
815
844
 
@@ -857,6 +886,46 @@ function moduleType(url, attributes, info, opts = {}) {
857
886
  return defaultType
858
887
  }
859
888
 
889
+ // A URL has a single type within a graph, and the first import to reach it
890
+ // decides what that is. Later imports have to agree, so an attribute on one
891
+ // import cannot quietly change the type another import sees.
892
+ function assertTypeAgrees(url, attributes, recorded, opts) {
893
+ if (recorded === undefined) return
894
+ if (attributes.type === recorded.asserted) return
895
+
896
+ const expected =
897
+ typeof attributes.type === 'string'
898
+ ? typeForAttribute(attributes.type)
899
+ : moduleType(url, {}, recorded.info, opts)
900
+
901
+ if (expected === recorded.type) return
902
+
903
+ throw errors.TYPE_INCOMPATIBLE(
904
+ `Module '${url.href}' is already of type '${attributeForType(recorded.type)}' in the graph`
905
+ )
906
+ }
907
+
908
+ function attributeForType(type) {
909
+ switch (type) {
910
+ case constants.SCRIPT:
911
+ return 'script'
912
+ case constants.MODULE:
913
+ return 'module'
914
+ case constants.JSON:
915
+ return 'json'
916
+ case constants.BUNDLE:
917
+ return 'bundle'
918
+ case constants.ADDON:
919
+ return 'addon'
920
+ case constants.BINARY:
921
+ return 'binary'
922
+ case constants.TEXT:
923
+ return 'text'
924
+ }
925
+
926
+ return 'unknown'
927
+ }
928
+
860
929
  function typeForAttribute(type) {
861
930
  switch (type) {
862
931
  case 'script':
@@ -918,11 +987,11 @@ function dataURLModuleType(url, attributes, opts = {}) {
918
987
  return type
919
988
  }
920
989
 
921
- // A data URL carries no extension and 'text/javascript' spans both module
922
- // systems, so the type follows how the module was named: `require()` names a
923
- // script and `import` a module. A dynamic `import()` names either and so must
924
- // say which, as must a caller naming a data URL with no import to read, who
925
- // answers with `defaultType`.
990
+ // A data URL has no extension, and 'text/javascript' covers both module
991
+ // systems, so the type follows how the module was imported: `require()` means a
992
+ // script and `import` a module. A dynamic `import()` could mean either, so it
993
+ // has to say which. When there is no import to read at all, `defaultType`
994
+ // decides.
926
995
  function javaScriptDataURLModuleType(url, opts) {
927
996
  const { defaultType = constants.SCRIPT, importType = 0 } = opts
928
997
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-module-traverse",
3
- "version": "2.5.3",
3
+ "version": "2.5.5",
4
4
  "description": "Low-level module graph traversal for Bare",
5
5
  "exports": {
6
6
  ".": {