bare-module-traverse 2.6.0 → 2.7.1

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/index.d.ts CHANGED
@@ -3,9 +3,10 @@ import Buffer from 'bare-buffer'
3
3
  import {
4
4
  type ConditionalSpecifier,
5
5
  type ImportsMap,
6
- type ResolutionsMap
6
+ type ResolutionsMap,
7
+ type ResolveOptions as ModuleResolveOptions
7
8
  } from 'bare-module-resolve'
8
- import { type ResolveOptions, type Resolver } from 'bare-addon-resolve'
9
+ import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
9
10
  import { type Import, type Export } from 'bare-module-lexer'
10
11
 
11
12
  interface Dependency {
@@ -41,6 +42,8 @@ type AliasableExtension =
41
42
  | '.bin'
42
43
  | '.txt'
43
44
 
45
+ interface ResolveOptions extends ModuleResolveOptions, AddonResolveOptions {}
46
+
44
47
  interface TraverseOptions extends ResolveOptions {
45
48
  /**
46
49
  * The type to assume for a module that has no type of its own, such as one
@@ -71,6 +74,12 @@ interface TraverseOptions extends ResolveOptions {
71
74
  * system; a tool that only links wants the error.
72
75
  */
73
76
  deferUnresolved?: boolean
77
+ /**
78
+ * The URL the entry is mounted at when it is a bundle, for consumers that
79
+ * load it with an explicit mount. The addons and assets it declares resolve
80
+ * relative to this. Defaults to the URL of the entry itself.
81
+ */
82
+ mount?: URL | string
74
83
  }
75
84
 
76
85
  /**
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ const Bundle = require('bare-bundle')
1
2
  const { lookupPackageScope, conditionMatches } = require('bare-module-resolve')
2
3
  const lex = require('bare-module-lexer')
3
4
  const MIME = require('bare-mime')
@@ -98,7 +99,7 @@ module.exports = exports = function traverse(
98
99
  }
99
100
 
100
101
  while (queue.length > 0 || deferred.length > 0) {
101
- yield* drive(queue.length > 0 ? queue.pop() : deferred.shift())
102
+ yield* drive(queue.length > 0 ? queue.shift() : deferred.shift())
102
103
  }
103
104
 
104
105
  return artifacts
@@ -160,7 +161,7 @@ module.exports = exports = function traverse(
160
161
  }
161
162
 
162
163
  while (queue.length > 0 || deferred.length > 0) {
163
- yield* drive(queue.length > 0 ? queue.pop() : deferred.shift())
164
+ yield* drive(queue.length > 0 ? queue.shift() : deferred.shift())
164
165
  }
165
166
 
166
167
  return artifacts
@@ -194,12 +195,20 @@ exports.alias = function alias(url, opts = {}) {
194
195
  exports.module = function* (url, source, attributes, artifacts, visited, opts = {}) {
195
196
  attributes = attributes || {}
196
197
 
198
+ // The mount only applies to the module the traversal starts from.
199
+ const { mount } = opts
200
+
201
+ if (mount !== undefined) opts = { ...opts, mount: undefined }
202
+
197
203
  if (opts.contexts === undefined) opts = { ...opts, contexts: new Map() }
198
204
  if (opts.addonContexts === undefined) opts = { ...opts, addonContexts: new Map() }
205
+ if (opts.resolvedImports === undefined) opts = { ...opts, resolvedImports: new Map() }
199
206
 
200
207
  // The host and WASI attributes set the context that the addons of the module
201
208
  // and everything it imports load in. A graph is walked again for each context
202
- // it is imported under, even where it was visited before.
209
+ // it is imported under, even where it was visited before. The conditions of
210
+ // the host are added to those that may be targeted, so that the order of the
211
+ // conditions in a package still decides between them and the native ones.
203
212
  if (attributes.host !== undefined || attributes.wasi !== undefined) {
204
213
  const { addonHost = null, addonWASI = null } = opts
205
214
 
@@ -209,7 +218,11 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
209
218
  if (host !== addonHost || wasi !== addonWASI) {
210
219
  opts = { ...opts, addonHost: host, addonWASI: wasi }
211
220
 
212
- visited = visitedFor(opts.contexts, contextKey(host, wasi))
221
+ if (host !== addonHost) {
222
+ opts.conditions = withConditions(opts.conditions, host.split('-'))
223
+ }
224
+
225
+ visited = visitedFor(opts.contexts, host, wasi)
213
226
  }
214
227
  }
215
228
 
@@ -255,9 +268,26 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
255
268
  }
256
269
  }
257
270
 
258
- if (resolutions) {
271
+ // A bundle declares its own artifacts, whether or not its imports have been
272
+ // resolved before.
273
+ if (
274
+ asset === false &&
275
+ artifacts !== null &&
276
+ moduleType(url, attributes, null, opts) === constants.BUNDLE
277
+ ) {
278
+ addBundleArtifacts(source, mountFor(url, mount), artifacts)
279
+ }
280
+
281
+ // A module resolves its imports once, however many contexts it is loaded in,
282
+ // so a context that reaches it after another walks what the other resolved.
283
+ // The addons that are reached are then checked against the context.
284
+ const resolved = opts.resolvedImports.get(url.href)
285
+
286
+ const preresolved = resolved === undefined ? resolutions : { [url.href]: resolved }
287
+
288
+ if (preresolved) {
259
289
  if (
260
- yield* exports.preresolved(url, source, attributes, resolutions, artifacts, visited, opts)
290
+ yield* exports.preresolved(url, source, attributes, preresolved, artifacts, visited, opts)
261
291
  ) {
262
292
  return true
263
293
  }
@@ -313,6 +343,10 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
313
343
  }
314
344
  }
315
345
 
346
+ const compressed = compressImportsMap(imports)
347
+
348
+ opts.resolvedImports.set(url.href, compressed)
349
+
316
350
  yield {
317
351
  dependency: withWASI(
318
352
  {
@@ -320,7 +354,7 @@ exports.module = function* (url, source, attributes, artifacts, visited, opts =
320
354
  source,
321
355
  type,
322
356
  naturalType,
323
- imports: compressImportsMap(imports),
357
+ imports: compressed,
324
358
  lexer
325
359
  },
326
360
  opts
@@ -767,16 +801,22 @@ function addonHostForAttribute(host) {
767
801
  throw errors.UNKNOWN_ADDON_HOST(`Addon host '${host}' is not supported`)
768
802
  }
769
803
 
770
- function contextKey(host, wasi) {
771
- return JSON.stringify([host, wasi])
804
+ function withConditions(conditions = [], added) {
805
+ if (conditions.every((condition) => typeof condition === 'string')) {
806
+ return [...conditions, ...added]
807
+ }
808
+
809
+ return conditions.map((subset) => withConditions(subset, added))
772
810
  }
773
811
 
774
- function visitedFor(contexts, key) {
775
- let visited = contexts.get(key)
812
+ function visitedFor(contexts, host, wasi) {
813
+ const key = JSON.stringify([host, wasi])
776
814
 
777
- if (visited === undefined) contexts.set(key, (visited = new Set()))
815
+ let context = contexts.get(key)
778
816
 
779
- return visited
817
+ if (context === undefined) contexts.set(key, (context = { host, wasi, visited: new Set() }))
818
+
819
+ return context.visited
780
820
  }
781
821
 
782
822
  function withWASI(dependency, opts) {
@@ -829,6 +869,19 @@ exports.assertAddonContext = function assertAddonContext(url, scope, context, ad
829
869
  }
830
870
  }
831
871
 
872
+ function addBundleArtifacts(source, mount, artifacts) {
873
+ const bundle = Bundle.from(source).mount(mount)
874
+
875
+ for (const href of bundle.addons) addURL(artifacts.addons, new URL(href))
876
+ for (const href of bundle.assets) addURL(artifacts.assets, new URL(href))
877
+ }
878
+
879
+ function mountFor(url, mount) {
880
+ const href = mount === undefined ? url.href : new URL(mount).href
881
+
882
+ return href.endsWith('/') ? href : href + '/'
883
+ }
884
+
832
885
  function isJavaScript(type) {
833
886
  return type === constants.SCRIPT || type === constants.MODULE
834
887
  }
@@ -0,0 +1,23 @@
1
+ // One set of conditions for each host, each with the targeted conditions. A
2
+ // host whose conditions are targeted in every set already has its resolutions,
3
+ // so it gets no set of its own.
4
+ module.exports = function conditions(base, hosts, targets) {
5
+ const subsets = leaves(targets)
6
+
7
+ const own = hosts.filter(
8
+ (host) =>
9
+ !subsets.every((subset) => host.split('-').every((condition) => subset.includes(condition)))
10
+ )
11
+
12
+ return (own.length > 0 ? own : hosts).flatMap((host) =>
13
+ subsets.map((subset) => [...base, ...host.split('-'), ...subset])
14
+ )
15
+ }
16
+
17
+ // Conditions nest to any depth and are tried depth first, so they match as
18
+ // their innermost lists would in order.
19
+ function leaves(conditions) {
20
+ if (conditions.every((condition) => typeof condition === 'string')) return [conditions]
21
+
22
+ return conditions.flatMap(leaves)
23
+ }
@@ -1,10 +1,17 @@
1
+ import URL from 'bare-url'
1
2
  import { type Import } from 'bare-module-lexer'
2
- import { type ResolveOptions, type Resolver } from 'bare-addon-resolve'
3
+ import { type Conditions, type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
4
+ import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
3
5
 
4
- interface BareResolveOptions extends ResolveOptions {
6
+ interface BareResolveOptions extends ModuleResolveOptions, AddonResolveOptions {
5
7
  linked?: boolean
6
8
  host?: string
7
9
  hosts?: string[]
10
+ /**
11
+ * The conditions that may be targeted in addition to those of each host,
12
+ * either a list or nested lists to try in turn.
13
+ */
14
+ conditions?: Conditions
8
15
  }
9
16
 
10
17
  /**
@@ -1,13 +1,19 @@
1
1
  const lex = require('bare-module-lexer')
2
2
  const resolve = require('../resolve')
3
3
  const runtime = require('../runtime')
4
+ const hostConditions = require('../conditions')
4
5
 
5
6
  module.exports = function (entry, parentURL, opts = {}) {
6
- const { linked = false, host = runtime.host, hosts = [host, 'wasi-wasm32'] } = opts
7
+ const {
8
+ linked = false,
9
+ host = runtime.host,
10
+ hosts = [host, 'wasi-wasm32'],
11
+ conditions: targets = []
12
+ } = opts
7
13
 
8
14
  let directories = false
9
15
  let extensions
10
- let conditions = hosts.map((host) => ['bare', 'node', ...host.split('-')])
16
+ let conditions = hostConditions(['bare', 'node'], hosts, targets)
11
17
 
12
18
  if (entry.type & lex.constants.ADDON) {
13
19
  extensions = linked ? [] : ['.bare', '.node']
@@ -1,5 +1,9 @@
1
+ import URL from 'bare-url'
1
2
  import { type Import } from 'bare-module-lexer'
2
- import { type ResolveOptions, type Resolver } from 'bare-addon-resolve'
3
+ import { type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
4
+ import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
5
+
6
+ interface ResolveOptions extends ModuleResolveOptions, AddonResolveOptions {}
3
7
 
4
8
  /**
5
9
  * @param entry - The import to resolve, as produced by `bare-module-lexer`.
@@ -1,9 +1,16 @@
1
+ import URL from 'bare-url'
1
2
  import { type Import } from 'bare-module-lexer'
2
- import { type ResolveOptions, type Resolver } from 'bare-addon-resolve'
3
+ import { type Conditions, type ResolveOptions as ModuleResolveOptions } from 'bare-module-resolve'
4
+ import { type ResolveOptions as AddonResolveOptions, type Resolver } from 'bare-addon-resolve'
3
5
 
4
- interface NodeResolveOptions extends ResolveOptions {
6
+ interface NodeResolveOptions extends ModuleResolveOptions, AddonResolveOptions {
5
7
  host?: string
6
8
  hosts?: string[]
9
+ /**
10
+ * The conditions that may be targeted in addition to those of each host,
11
+ * either a list or nested lists to try in turn.
12
+ */
13
+ conditions?: Conditions
7
14
  }
8
15
 
9
16
  /**
@@ -1,13 +1,14 @@
1
1
  const lex = require('bare-module-lexer')
2
2
  const resolve = require('../resolve')
3
3
  const runtime = require('../runtime')
4
+ const hostConditions = require('../conditions')
4
5
 
5
6
  module.exports = function (entry, parentURL, opts = {}) {
6
- const { host = runtime.host, hosts = [host] } = opts
7
+ const { host = runtime.host, hosts = [host], conditions: targets = [] } = opts
7
8
 
8
9
  let directories = false
9
10
  let extensions
10
- let conditions = hosts.map((host) => ['node', ...host.split('-')])
11
+ let conditions = hostConditions(['node'], hosts, targets)
11
12
 
12
13
  if (entry.type & lex.constants.ADDON) {
13
14
  extensions = ['.node']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-module-traverse",
3
- "version": "2.6.0",
3
+ "version": "2.7.1",
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-bundle": "^1.11.0",
58
59
  "bare-mime": "^1.0.0",
59
60
  "bare-module-lexer": "^1.6.0",
60
61
  "bare-module-resolve": "^1.7.0"