bare-module-traverse 1.0.0 → 1.1.0

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
@@ -50,6 +50,16 @@ for await (const dependency of traverse(new URL('file:///directory/file.js'), re
50
50
 
51
51
  Traverse the module graph rooted at `url`, which must be a WHATWG `URL` instance. `readModule` is called with a `URL` instance for every module to be read and must either return the module source, if it exists, or `null`. `listPrefix` is called with a `URL` instance of every prefix to be listed and must return a list of `URL` instances that have the specified `URL` as a prefix. If not provided, prefixes won't be traversed. If one or both of `readModule` or `listPrefix` returns a promise, synchronous iteration is not supported.
52
52
 
53
+ Options include:
54
+
55
+ ```js
56
+ {
57
+ resolve: resolve.default
58
+ }
59
+ ```
60
+
61
+ Options supported by <https://github.com/holepunchto/bare-module-resolve> and <https://github.com/holepunchto/bare-addon-resolve> may also be specified.
62
+
53
63
  #### `for (const dependency of dependencies)`
54
64
 
55
65
  Synchronously iterate the module graph. Each yielded dependency has the following shape:
@@ -68,6 +78,28 @@ Synchronously iterate the module graph. Each yielded dependency has the followin
68
78
 
69
79
  Asynchronously iterate the module graph. If one or both of `readModule` or `listPrefix` returns promises, these will be awaited. The same comments as `for (const dependency of dependencies)` apply.
70
80
 
81
+ ### Resolution
82
+
83
+ #### `resolve.module`
84
+
85
+ Convenience export from <https://github.com/holepunchto/bare-module-resolve>.
86
+
87
+ #### `resolve.addon`
88
+
89
+ Convenience export from <https://github.com/holepunchto/bare-addon-resolve>.
90
+
91
+ #### `resolve.default`
92
+
93
+ The default resolver, which simply forwards to <https://github.com/holepunchto/bare-module-resolve> and <https://github.com/holepunchto/bare-addon-resolve> with the literal options passed by the caller.
94
+
95
+ #### `resolve.bare`
96
+
97
+ The Bare resolver, which matches the options used by the Bare module system.
98
+
99
+ #### `resolve.node`
100
+
101
+ The Node.js resolver, which matches the options used by the Node.js module system.
102
+
71
103
  ### Algorithm
72
104
 
73
105
  The following generator functions implement the traversal algorithm. To drive the generator functions, a loop like the following can be used:
@@ -106,13 +138,18 @@ while (queue.length > 0) {
106
138
 
107
139
  Options are the same as `traverse()` for all functions.
108
140
 
141
+ > [!WARNING]
142
+ > These functions are currently subject to change between minor releases. If using them directly, make sure to specify a tilde range (`~1.2.3`) when declaring the module dependency.
143
+
109
144
  #### `const generator = traverse.module(url, source, artifacts, visited[, options])`
110
145
 
111
146
  #### `const generator = traverse.package(url, source, artifacts, visited[, options])`
112
147
 
113
148
  #### `const generator = traverse.preresolved(url, source, resolutions, artifacts, visited[, options])`
114
149
 
115
- #### `const generator = traverse.imports(url, source, imports, artifacts, visited[, options])`
150
+ #### `const generator = traverse.imports(parentURL, source, imports, artifacts, visited[, options])`
151
+
152
+ #### `const generator = traverse.prebuilds(packageURL, artifacts, visited[, options])`
116
153
 
117
154
  #### `const generator = traverse.assets(patterns, parentURL, artifacts, visited[, options])`
118
155
 
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  const { lookupPackageScope } = require('bare-module-resolve')
2
+ const { lookupPrebuildsScope } = require('bare-addon-resolve')
2
3
  const lex = require('bare-module-lexer')
3
4
  const resolve = require('./lib/resolve')
5
+ const errors = require('./lib/errors')
4
6
 
5
7
  module.exports = exports = function traverse (entry, opts, readModule, listPrefix) {
6
8
  if (typeof opts === 'function') {
@@ -15,9 +17,9 @@ module.exports = exports = function traverse (entry, opts, readModule, listPrefi
15
17
 
16
18
  return {
17
19
  * [Symbol.iterator] () {
18
- const artifacts = createArtifacts()
20
+ const artifacts = { addons: [], assets: [] }
19
21
 
20
- const queue = [exports.module(entry, readModule(entry), artifacts, new Set(), opts)]
22
+ const queue = [exports.module(entry, null, artifacts, new Set(), opts)]
21
23
 
22
24
  while (queue.length > 0) {
23
25
  const generator = queue.pop()
@@ -44,9 +46,9 @@ module.exports = exports = function traverse (entry, opts, readModule, listPrefi
44
46
  },
45
47
 
46
48
  async * [Symbol.asyncIterator] () {
47
- const artifacts = createArtifacts()
49
+ const artifacts = { addons: [], assets: [] }
48
50
 
49
- const queue = [exports.module(entry, await readModule(entry), artifacts, new Set(), opts)]
51
+ const queue = [exports.module(entry, null, artifacts, new Set(), opts)]
50
52
 
51
53
  while (queue.length > 0) {
52
54
  const generator = queue.pop()
@@ -78,19 +80,27 @@ function defaultListPrefix () {
78
80
  return []
79
81
  }
80
82
 
81
- function defaultResolve (entry, parentURL, opts) {
82
- if (entry.type & lex.constants.ADDON) {
83
- return resolve.addon(entry.specifier, parentURL, opts)
84
- } else {
85
- return resolve.module(entry.specifier, parentURL, opts)
83
+ function addURL (array, url) {
84
+ let lo = 0
85
+ let hi = array.length - 1
86
+
87
+ while (lo <= hi) {
88
+ const mid = lo + ((hi - lo) >> 1)
89
+ const found = array[mid]
90
+
91
+ if (found.href === url.href) return
92
+
93
+ if (found.href < url.href) {
94
+ lo = mid + 1
95
+ } else {
96
+ hi = mid - 1
97
+ }
86
98
  }
87
- }
88
99
 
89
- function createArtifacts () {
90
- return { addons: [], assets: [] }
100
+ array.splice(lo, 0, url)
91
101
  }
92
102
 
93
- function addURL (array, url) {
103
+ function removeURL (array, url) {
94
104
  let lo = 0
95
105
  let hi = array.length - 1
96
106
 
@@ -98,7 +108,7 @@ function addURL (array, url) {
98
108
  const mid = lo + ((hi - lo) >> 1)
99
109
  const found = array[mid]
100
110
 
101
- if (found.href === url.href) return
111
+ if (found.href === url.href) break
102
112
 
103
113
  if (found.href < url.href) {
104
114
  lo = mid + 1
@@ -107,7 +117,7 @@ function addURL (array, url) {
107
117
  }
108
118
  }
109
119
 
110
- array.splice(lo, 0, url)
120
+ if (array[lo].href === url.href) array.splice(lo, 1)
111
121
  }
112
122
 
113
123
  exports.resolve = resolve
@@ -117,6 +127,14 @@ exports.module = function * (url, source, artifacts, visited, opts = {}) {
117
127
 
118
128
  if (visited.has(url.href)) return false
119
129
 
130
+ if (source === null) {
131
+ source = yield { module: url }
132
+
133
+ if (source === null) {
134
+ throw errors.MODULE_NOT_FOUND(`Cannot find module '${url.href}'`)
135
+ }
136
+ }
137
+
120
138
  visited.add(url.href)
121
139
 
122
140
  if (resolutions) {
@@ -154,6 +172,10 @@ exports.package = function * (url, source, artifacts, visited, opts = {}) {
154
172
  if (info) {
155
173
  yield { dependency: { url, source, imports: {} } }
156
174
 
175
+ if (info.addon) {
176
+ yield { children: exports.prebuilds(url, artifacts, visited, opts) }
177
+ }
178
+
157
179
  if (info.assets) {
158
180
  yield { children: exports.assets(info.assets, url, artifacts, visited, opts) }
159
181
  }
@@ -177,14 +199,11 @@ exports.preresolved = function * (url, source, resolutions, artifacts, visited,
177
199
 
178
200
  if (typeof entry === 'string') {
179
201
  const url = new URL(entry)
180
- const source = yield { module: url }
181
-
182
- if (source === null) continue
183
202
 
184
203
  if (specifier === '#package') {
185
- yield { children: exports.package(url, source, artifacts, visited, opts) }
204
+ yield { children: exports.package(url, null, artifacts, visited, opts) }
186
205
  } else {
187
- yield { children: exports.module(url, source, artifacts, visited, opts) }
206
+ yield { children: exports.module(url, null, artifacts, visited, opts) }
188
207
  }
189
208
  } else {
190
209
  stack.unshift(...Object.values(entry))
@@ -197,13 +216,16 @@ exports.preresolved = function * (url, source, resolutions, artifacts, visited,
197
216
  return true
198
217
  }
199
218
 
200
- exports.imports = function * (url, source, imports, artifacts, visited, opts = {}) {
201
- const { resolve = defaultResolve } = opts
219
+ exports.imports = function * (parentURL, source, imports, artifacts, visited, opts = {}) {
220
+ const { resolve = exports.resolve.default } = opts
221
+
222
+ let yielded = false
202
223
 
203
224
  for (const entry of lex(source).imports) {
204
- const resolver = resolve(entry, url, opts)
225
+ const resolver = resolve(entry, parentURL, opts)
205
226
 
206
227
  let next = resolver.next()
228
+ let resolved = false
207
229
 
208
230
  while (next.done !== true) {
209
231
  const value = next.value
@@ -232,22 +254,51 @@ exports.imports = function * (url, source, imports, artifacts, visited, opts = {
232
254
 
233
255
  yield { children: exports.module(url, source, artifacts, visited, opts) }
234
256
 
257
+ resolved = yielded = true
258
+
235
259
  break
236
260
  }
237
261
 
238
262
  next = resolver.next()
239
263
  }
240
264
  }
265
+
266
+ if (!resolved) {
267
+ throw errors.MODULE_NOT_FOUND(`Cannot find module '${entry.specifier}' imported from '${parentURL.href}'`)
268
+ }
241
269
  }
270
+
271
+ return yielded
272
+ }
273
+
274
+ exports.prebuilds = function * (packageURL, artifacts, visited, opts = {}) {
275
+ const [prefix = null] = lookupPrebuildsScope(packageURL, opts)
276
+
277
+ if (prefix === null) return false
278
+
279
+ let yielded = false
280
+
281
+ for (const url of yield { prefix }) {
282
+ const source = yield { module: url }
283
+
284
+ if (source !== null) {
285
+ addURL(artifacts.addons, url)
286
+
287
+ yield { children: exports.module(url, source, artifacts, visited, opts) }
288
+
289
+ yielded = true
290
+ }
291
+ }
292
+
293
+ return yielded
242
294
  }
243
295
 
244
296
  exports.assets = function * (patterns, parentURL, artifacts, visited, opts = {}) {
245
- const matches = yield * exports.matches(patterns, parentURL, opts)
297
+ const matches = yield * exports.patternMatches(patterns, parentURL, [], opts)
246
298
 
247
299
  let yielded = false
248
300
 
249
- for (const href of matches) {
250
- const url = new URL(href)
301
+ for (const url of matches) {
251
302
  const source = yield { module: url }
252
303
 
253
304
  if (source !== null) {
@@ -262,10 +313,10 @@ exports.assets = function * (patterns, parentURL, artifacts, visited, opts = {})
262
313
  return yielded
263
314
  }
264
315
 
265
- exports.matches = function * (patterns, parentURL) {
266
- const matches = new Set()
316
+ exports.patternMatches = function * (pattern, parentURL, matches, opts = {}) {
317
+ const { conditions = [] } = opts
267
318
 
268
- for (let pattern of patterns) {
319
+ if (typeof pattern === 'string') {
269
320
  let patternNegate = false
270
321
  let patternBase
271
322
  let patternTrailer
@@ -289,12 +340,26 @@ exports.matches = function * (patterns, parentURL) {
289
340
 
290
341
  for (const url of yield { prefix }) {
291
342
  if (patternIndex === -1) {
292
- if (patternNegate) matches.delete(url.href)
293
- else matches.add(url.href)
343
+ if (patternNegate) removeURL(matches, url)
344
+ else addURL(matches, url)
294
345
  } else if (patternTrailer === '' || url.href.endsWith(patternTrailer)) {
295
- matches.add(url.href)
346
+ addURL(matches, url)
296
347
  } else if (patternNegate) {
297
- matches.delete(url.href)
348
+ removeURL(matches, url)
349
+ }
350
+ }
351
+ } else if (Array.isArray(pattern)) {
352
+ for (const patternValue of pattern) {
353
+ yield * exports.patternMatches(patternValue, parentURL, matches, opts)
354
+ }
355
+ } else if (typeof pattern === 'object' && pattern !== null) {
356
+ const keys = Object.keys(pattern)
357
+
358
+ for (const p of keys) {
359
+ if (p === 'default' || conditions.includes(p)) {
360
+ const patternValue = pattern[p]
361
+
362
+ return yield * exports.patternMatches(patternValue, parentURL, matches, opts)
298
363
  }
299
364
  }
300
365
  }
package/lib/errors.js ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = class ModuleTraverseError extends Error {
2
+ constructor (msg, code, fn = ModuleTraverseError) {
3
+ super(`${code}: ${msg}`)
4
+ this.code = code
5
+
6
+ if (Error.captureStackTrace) {
7
+ Error.captureStackTrace(this, fn)
8
+ }
9
+ }
10
+
11
+ get name () {
12
+ return 'ModuleTraverseError'
13
+ }
14
+
15
+ static MODULE_NOT_FOUND (msg) {
16
+ return new ModuleTraverseError(msg, 'MODULE_NOT_FOUND', ModuleTraverseError.MODULE_NOT_FOUND)
17
+ }
18
+ }
package/lib/resolve.js CHANGED
@@ -1,2 +1,68 @@
1
+ const lex = require('bare-module-lexer')
2
+
1
3
  exports.module = require('bare-module-resolve').module
2
4
  exports.addon = require('bare-addon-resolve').addon
5
+
6
+ exports.default = function resolve (entry, parentURL, opts) {
7
+ if (entry.type & lex.constants.ADDON) {
8
+ return exports.addon(entry.specifier, parentURL, opts)
9
+ }
10
+
11
+ return exports.module(entry.specifier, parentURL, opts)
12
+ }
13
+
14
+ exports.bare = function resolve (entry, parentURL, opts = {}) {
15
+ const runtime = require('#runtime')
16
+
17
+ const {
18
+ platform = runtime.platform,
19
+ arch = runtime.arch,
20
+ simulator = false
21
+ } = opts
22
+
23
+ let extensions
24
+ let conditions = ['bare', 'node', platform, arch]
25
+
26
+ if (simulator) conditions = [...conditions, 'simulator']
27
+
28
+ if (entry.type & lex.constants.ADDON) {
29
+ extensions = ['.bare', '.node']
30
+ conditions = ['addon', ...conditions]
31
+
32
+ return exports.addon(entry.specifier, parentURL, { extensions, conditions, ...opts })
33
+ }
34
+
35
+ if (entry.type & lex.constants.ASSET) {
36
+ conditions = ['asset', ...conditions]
37
+ } else {
38
+ extensions = ['.js', '.cjs', '.mjs', '.json', '.bare', '.node']
39
+
40
+ if (entry.type & lex.constants.REQUIRE) {
41
+ conditions = ['require', ...conditions]
42
+ } else if (entry.type & lex.constants.IMPORT) {
43
+ conditions = ['import', ...conditions]
44
+ }
45
+ }
46
+
47
+ return exports.module(entry.specifier, parentURL, { extensions, conditions, ...opts })
48
+ }
49
+
50
+ exports.node = function resolve (entry, parentURL, opts) {
51
+ let extensions
52
+ let conditions
53
+
54
+ if (entry.type & lex.constants.ADDON) {
55
+ extensions = ['.node']
56
+
57
+ return exports.addon(entry.specifier, parentURL, { extensions, conditions, ...opts })
58
+ }
59
+
60
+ if (entry.type & lex.constants.REQUIRE) {
61
+ extensions = ['.js', '.json', '.node']
62
+ conditions = ['node', 'require']
63
+ } else if (entry.type & lex.constants.IMPORT) {
64
+ conditions = ['node', 'import']
65
+ }
66
+
67
+ return exports.module(entry.specifier, parentURL, { extensions, conditions, ...opts })
68
+ }
@@ -0,0 +1,3 @@
1
+ /* global Bare */
2
+ exports.platform = Bare.platform
3
+ exports.arch = Bare.arch
@@ -0,0 +1,2 @@
1
+ exports.platform = process.platform
2
+ exports.arch = process.arch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-module-traverse",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Low-level module graph traversal for Bare",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -11,6 +11,12 @@
11
11
  "index.js",
12
12
  "lib"
13
13
  ],
14
+ "imports": {
15
+ "#runtime": {
16
+ "bare": "./lib/runtime/bare.js",
17
+ "node": "./lib/runtime/node.js"
18
+ }
19
+ },
14
20
  "scripts": {
15
21
  "test": "standard && bare test.js"
16
22
  },