bare-module-traverse 2.5.3 → 2.5.4

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
  }
@@ -400,6 +414,7 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
400
414
  url: exports.alias(url, opts),
401
415
  source,
402
416
  type,
417
+ naturalType: type,
403
418
  imports: compressImportsMap(imports),
404
419
  lexer
405
420
  }
@@ -810,6 +825,17 @@ function* postresolve(url) {
810
825
  return (yield { resolution: url }) || url
811
826
  }
812
827
 
828
+ // The type a module has on its own, ignoring import attributes. A JavaScript
829
+ // data: URL has no type of its own, so this returns 0; its type depends on how
830
+ // it is imported.
831
+ function naturalModuleType(url, attributes, info, type, opts) {
832
+ if (attributes.type === undefined) return type
833
+
834
+ if (url.protocol === 'data:') return 0
835
+
836
+ return moduleType(url, {}, info, opts)
837
+ }
838
+
813
839
  function moduleType(url, attributes, info, opts = {}) {
814
840
  const { defaultType = constants.SCRIPT, aliases = null } = opts
815
841
 
@@ -857,6 +883,46 @@ function moduleType(url, attributes, info, opts = {}) {
857
883
  return defaultType
858
884
  }
859
885
 
886
+ // A URL has a single type within a graph, and the first import to reach it
887
+ // decides what that is. Later imports have to agree, so an attribute on one
888
+ // import cannot quietly change the type another import sees.
889
+ function assertTypeAgrees(url, attributes, recorded, opts) {
890
+ if (recorded === undefined) return
891
+ if (attributes.type === recorded.asserted) return
892
+
893
+ const expected =
894
+ typeof attributes.type === 'string'
895
+ ? typeForAttribute(attributes.type)
896
+ : moduleType(url, {}, recorded.info, opts)
897
+
898
+ if (expected === recorded.type) return
899
+
900
+ throw errors.TYPE_INCOMPATIBLE(
901
+ `Module '${url.href}' is already of type '${attributeForType(recorded.type)}' in the graph`
902
+ )
903
+ }
904
+
905
+ function attributeForType(type) {
906
+ switch (type) {
907
+ case constants.SCRIPT:
908
+ return 'script'
909
+ case constants.MODULE:
910
+ return 'module'
911
+ case constants.JSON:
912
+ return 'json'
913
+ case constants.BUNDLE:
914
+ return 'bundle'
915
+ case constants.ADDON:
916
+ return 'addon'
917
+ case constants.BINARY:
918
+ return 'binary'
919
+ case constants.TEXT:
920
+ return 'text'
921
+ }
922
+
923
+ return 'unknown'
924
+ }
925
+
860
926
  function typeForAttribute(type) {
861
927
  switch (type) {
862
928
  case 'script':
@@ -918,11 +984,11 @@ function dataURLModuleType(url, attributes, opts = {}) {
918
984
  return type
919
985
  }
920
986
 
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`.
987
+ // A data URL has no extension, and 'text/javascript' covers both module
988
+ // systems, so the type follows how the module was imported: `require()` means a
989
+ // script and `import` a module. A dynamic `import()` could mean either, so it
990
+ // has to say which. When there is no import to read at all, `defaultType`
991
+ // decides.
926
992
  function javaScriptDataURLModuleType(url, opts) {
927
993
  const { defaultType = constants.SCRIPT, importType = 0 } = opts
928
994
 
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.4",
4
4
  "description": "Low-level module graph traversal for Bare",
5
5
  "exports": {
6
6
  ".": {