bare-module-traverse 2.5.2 → 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 +3 -0
- package/index.d.ts +20 -0
- package/index.js +104 -14
- package/lib/errors.js +8 -0
- package/package.json +1 -1
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[]
|
|
@@ -34,7 +42,19 @@ type AliasableExtension =
|
|
|
34
42
|
| '.txt'
|
|
35
43
|
|
|
36
44
|
interface TraverseOptions extends ResolveOptions {
|
|
45
|
+
/**
|
|
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
|
|
48
|
+
* `constants` for possible values.
|
|
49
|
+
*/
|
|
37
50
|
defaultType?: number
|
|
51
|
+
/**
|
|
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.
|
|
56
|
+
*/
|
|
57
|
+
importType?: number
|
|
38
58
|
artifacts?: boolean
|
|
39
59
|
aliases?: Record<string, AliasableExtension>
|
|
40
60
|
/**
|
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
|
-
|
|
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
|
|
|
@@ -271,7 +283,7 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
|
|
|
271
283
|
if (type === constants.SCRIPT || type === constants.MODULE) {
|
|
272
284
|
yield* exports.imports(url, source, imports, artifacts, lexer, visited, {
|
|
273
285
|
...opts,
|
|
274
|
-
|
|
286
|
+
importType: 0
|
|
275
287
|
})
|
|
276
288
|
} else if (type === constants.ADDON && artifacts !== null) {
|
|
277
289
|
yield* exports.addons(url, artifacts, visited, opts)
|
|
@@ -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
|
}
|
|
@@ -363,7 +377,7 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
363
377
|
children: exports.module(url, null, {}, artifacts, visited, {
|
|
364
378
|
...opts,
|
|
365
379
|
asset: true,
|
|
366
|
-
|
|
380
|
+
importType: 0
|
|
367
381
|
}),
|
|
368
382
|
deferred: true
|
|
369
383
|
}
|
|
@@ -376,7 +390,7 @@ exports.preresolved = function* (url, source, resolutions, artifacts, visited, o
|
|
|
376
390
|
yield {
|
|
377
391
|
children: exports.module(url, null, {}, artifacts, visited, {
|
|
378
392
|
...opts,
|
|
379
|
-
|
|
393
|
+
importType: 0
|
|
380
394
|
}),
|
|
381
395
|
deferred: false
|
|
382
396
|
}
|
|
@@ -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
|
}
|
|
@@ -611,7 +626,10 @@ function* resolveImport(entry, specifier, condition, parentURL, imports, artifac
|
|
|
611
626
|
}
|
|
612
627
|
|
|
613
628
|
yield {
|
|
614
|
-
children: exports.module(resolution, source, attributes, artifacts, visited,
|
|
629
|
+
children: exports.module(resolution, source, attributes, artifacts, visited, {
|
|
630
|
+
...opts,
|
|
631
|
+
importType: entry.type
|
|
632
|
+
}),
|
|
615
633
|
deferred: false
|
|
616
634
|
}
|
|
617
635
|
|
|
@@ -807,6 +825,17 @@ function* postresolve(url) {
|
|
|
807
825
|
return (yield { resolution: url }) || url
|
|
808
826
|
}
|
|
809
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
|
+
|
|
810
839
|
function moduleType(url, attributes, info, opts = {}) {
|
|
811
840
|
const { defaultType = constants.SCRIPT, aliases = null } = opts
|
|
812
841
|
|
|
@@ -854,6 +883,46 @@ function moduleType(url, attributes, info, opts = {}) {
|
|
|
854
883
|
return defaultType
|
|
855
884
|
}
|
|
856
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
|
+
|
|
857
926
|
function typeForAttribute(type) {
|
|
858
927
|
switch (type) {
|
|
859
928
|
case 'script':
|
|
@@ -876,22 +945,22 @@ function typeForAttribute(type) {
|
|
|
876
945
|
}
|
|
877
946
|
|
|
878
947
|
function dataURLModuleType(url, attributes, opts = {}) {
|
|
879
|
-
const { defaultType = constants.SCRIPT, referrerType } = opts
|
|
880
|
-
|
|
881
948
|
const { mime } = parseDataURL(url)
|
|
882
949
|
|
|
950
|
+
if (mime === null) {
|
|
951
|
+
throw errors.UNKNOWN_DATA_URL_MEDIA_TYPE(`Data URL '${url.href}' does not declare a media type`)
|
|
952
|
+
}
|
|
953
|
+
|
|
883
954
|
const asserted = typeof attributes.type === 'string' ? typeForAttribute(attributes.type) : null
|
|
884
955
|
|
|
885
|
-
if (mime
|
|
956
|
+
if (mime.subtype === 'javascript') {
|
|
886
957
|
if (asserted === constants.SCRIPT || asserted === constants.MODULE) return asserted
|
|
887
958
|
|
|
888
959
|
if (asserted !== null) {
|
|
889
960
|
throw errors.TYPE_INCOMPATIBLE(`Module '${url.href}' is not of type '${attributes.type}'`)
|
|
890
961
|
}
|
|
891
962
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
return defaultType === constants.MODULE ? constants.MODULE : constants.SCRIPT
|
|
963
|
+
return javaScriptDataURLModuleType(url, opts)
|
|
895
964
|
}
|
|
896
965
|
|
|
897
966
|
let type
|
|
@@ -915,6 +984,27 @@ function dataURLModuleType(url, attributes, opts = {}) {
|
|
|
915
984
|
return type
|
|
916
985
|
}
|
|
917
986
|
|
|
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.
|
|
992
|
+
function javaScriptDataURLModuleType(url, opts) {
|
|
993
|
+
const { defaultType = constants.SCRIPT, importType = 0 } = opts
|
|
994
|
+
|
|
995
|
+
if (importType & lex.constants.REQUIRE) return constants.SCRIPT
|
|
996
|
+
|
|
997
|
+
if (importType & lex.constants.IMPORT) {
|
|
998
|
+
if ((importType & lex.constants.DYNAMIC) === 0) return constants.MODULE
|
|
999
|
+
|
|
1000
|
+
throw errors.AMBIGUOUS_MODULE_TYPE(
|
|
1001
|
+
`Module '${url.href}' must declare whether it is of type 'script' or 'module'`
|
|
1002
|
+
)
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return defaultType === constants.MODULE ? constants.MODULE : constants.SCRIPT
|
|
1006
|
+
}
|
|
1007
|
+
|
|
918
1008
|
function parseDataURL(url) {
|
|
919
1009
|
const { pathname } = url
|
|
920
1010
|
|
package/lib/errors.js
CHANGED
|
@@ -49,6 +49,14 @@ module.exports = class ModuleTraverseError extends Error {
|
|
|
49
49
|
return new ModuleTraverseError(msg, ModuleTraverseError.TYPE_INCOMPATIBLE)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
static AMBIGUOUS_MODULE_TYPE(msg) {
|
|
53
|
+
return new ModuleTraverseError(msg, ModuleTraverseError.AMBIGUOUS_MODULE_TYPE)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static UNKNOWN_DATA_URL_MEDIA_TYPE(msg) {
|
|
57
|
+
return new ModuleTraverseError(msg, ModuleTraverseError.UNKNOWN_DATA_URL_MEDIA_TYPE)
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
static UNKNOWN_DATA_URL_CHARSET(msg, charset) {
|
|
53
61
|
const err = new ModuleTraverseError(msg, ModuleTraverseError.UNKNOWN_DATA_URL_CHARSET)
|
|
54
62
|
|