import-in-the-middle 1.9.0 → 1.10.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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.9.0"
2
+ ".": "1.10.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.10.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.9.1...import-in-the-middle-v1.10.0) (2024-07-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * Allow regex for `include` and `exclude` options ([#148](https://github.com/nodejs/import-in-the-middle/issues/148)) ([697b0d2](https://github.com/nodejs/import-in-the-middle/commit/697b0d239b9a738f4952bb0f77c521c4a398ac79))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Use correct `format` when resolving exports from relative paths ([#145](https://github.com/nodejs/import-in-the-middle/issues/145)) ([632802f](https://github.com/nodejs/import-in-the-middle/commit/632802f4e7c797215b4e052ffdfa0fbda1780166))
14
+
15
+ ## [1.9.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.9.0...import-in-the-middle-v1.9.1) (2024-07-15)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * Don't wrap native modules ([#142](https://github.com/nodejs/import-in-the-middle/issues/142)) ([f3278a3](https://github.com/nodejs/import-in-the-middle/commit/f3278a3c76af78fe369b599d5b2bf1d87edf0a7a))
21
+ * Use correct `format` when resolving exports from sub-modules ([#140](https://github.com/nodejs/import-in-the-middle/issues/140)) ([1db08ef](https://github.com/nodejs/import-in-the-middle/commit/1db08ef5f51346c20b4b3c313bf993e9cf1ca7d5))
22
+
3
23
  ## [1.9.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.8.1...import-in-the-middle-v1.9.0) (2024-07-08)
4
24
 
5
25
 
package/README.md CHANGED
@@ -54,9 +54,9 @@ node --import=./my-loader.mjs ./my-code.mjs
54
54
  ```
55
55
 
56
56
  When registering the loader hook programmatically, it's possible to pass a list
57
- of modules or file URLs to either exclude or specifically include which modules
58
- are intercepted. This is useful if a module is not compatible with the loader
59
- hook.
57
+ of modules, file URLs or regular expressions to either exclude or specifically
58
+ include which modules are intercepted. This is useful if a module is not
59
+ compatible with the loader hook.
60
60
  ```js
61
61
  import * as module from 'module'
62
62
 
package/hook.js CHANGED
@@ -116,7 +116,11 @@ function isBareSpecifier (specifier) {
116
116
  }
117
117
  }
118
118
 
119
- function isBareSpecifierOrFileUrl (input) {
119
+ function isBareSpecifierFileUrlOrRegex (input) {
120
+ if (input instanceof RegExp) {
121
+ return true
122
+ }
123
+
120
124
  // Relative and absolute paths
121
125
  if (
122
126
  input.startsWith('.') ||
@@ -134,15 +138,15 @@ function isBareSpecifierOrFileUrl (input) {
134
138
  }
135
139
  }
136
140
 
137
- function ensureArrayWithBareSpecifiersAndFileUrls (array, type) {
141
+ function ensureArrayWithBareSpecifiersFileUrlsAndRegex (array, type) {
138
142
  if (!Array.isArray(array)) {
139
143
  return undefined
140
144
  }
141
145
 
142
- const invalid = array.filter(s => !isBareSpecifierOrFileUrl(s))
146
+ const invalid = array.filter(s => !isBareSpecifierFileUrlOrRegex(s))
143
147
 
144
148
  if (invalid.length) {
145
- throw new Error(`'${type}' option only supports bare specifiers and file URLs. Invalid entries: ${inspect(invalid)}`)
149
+ throw new Error(`'${type}' option only supports bare specifiers, file URLs or regular expressions. Invalid entries: ${inspect(invalid)}`)
146
150
  }
147
151
 
148
152
  return array
@@ -206,23 +210,23 @@ async function processModule ({ srcUrl, context, parentGetSource, parentResolve,
206
210
  if (isStarExportLine(n) === true) {
207
211
  const [, modFile] = n.split('* from ')
208
212
 
209
- let modUrl
210
- if (isBareSpecifier(modFile)) {
211
- // Bare specifiers need to be resolved relative to the parent module.
212
- const result = await parentResolve(modFile, { parentURL: srcUrl })
213
- modUrl = result.url
214
- } else {
215
- modUrl = new URL(modFile, srcUrl).href
216
- }
217
-
218
- const setters = await processModule({
219
- srcUrl: modUrl,
220
- context,
213
+ // Relative paths need to be resolved relative to the parent module
214
+ const newSpecifier = isBareSpecifier(modFile) ? modFile : new URL(modFile, srcUrl).href
215
+ // We need to call `parentResolve` to resolve bare specifiers to a full
216
+ // URL. We also need to call `parentResolve` for all sub-modules to get
217
+ // the `format`. We can't rely on the parents `format` to know if this
218
+ // sub-module is ESM or CJS!
219
+ const result = await parentResolve(newSpecifier, { parentURL: srcUrl })
220
+
221
+ const subSetters = await processModule({
222
+ srcUrl: result.url,
223
+ context: { ...context, format: result.format },
221
224
  parentGetSource,
222
225
  parentResolve,
223
226
  excludeDefault: true
224
227
  })
225
- for (const [name, setter] of setters.entries()) {
228
+
229
+ for (const [name, setter] of subSetters.entries()) {
226
230
  addSetter(name, setter, true)
227
231
  }
228
232
  } else {
@@ -253,8 +257,8 @@ function createHook (meta) {
253
257
 
254
258
  async function initialize (data) {
255
259
  if (data) {
256
- includeModules = ensureArrayWithBareSpecifiersAndFileUrls(data.include, 'include')
257
- excludeModules = ensureArrayWithBareSpecifiersAndFileUrls(data.exclude, 'exclude')
260
+ includeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.include, 'include')
261
+ excludeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.exclude, 'exclude')
258
262
  }
259
263
  }
260
264
 
@@ -283,13 +287,21 @@ function createHook (meta) {
283
287
  // For included/excluded modules, we check the specifier to match libraries
284
288
  // that are loaded with bare specifiers from node_modules.
285
289
  //
286
- // For non-bare specifier imports, we only support matching file URL strings
287
- // because using relative paths would be very error prone!
288
- if (includeModules && !includeModules.some(lib => lib === specifier || lib === result.url.url)) {
290
+ // For non-bare specifier imports, we match to the full file URL because
291
+ // using relative paths would be very error prone!
292
+ function match (each) {
293
+ if (each instanceof RegExp) {
294
+ return each.test(result.url)
295
+ }
296
+
297
+ return each === specifier || each === result.url
298
+ }
299
+
300
+ if (includeModules && !includeModules.some(match)) {
289
301
  return result
290
302
  }
291
303
 
292
- if (excludeModules && excludeModules.some(lib => lib === specifier || lib === result.url.url)) {
304
+ if (excludeModules && excludeModules.some(match)) {
293
305
  return result
294
306
  }
295
307
 
@@ -297,6 +309,11 @@ function createHook (meta) {
297
309
  return result
298
310
  }
299
311
 
312
+ // We don't want to attempt to wrap native modules
313
+ if (result.url.endsWith('.node')) {
314
+ return result
315
+ }
316
+
300
317
  // Node.js v21 renames importAssertions to importAttributes
301
318
  if (
302
319
  (context.importAssertions && context.importAssertions.type === 'json') ||
@@ -48,6 +48,11 @@ async function getCjsExports (url, context, parentLoad, source) {
48
48
  }
49
49
  // Resolve the re-exported module relative to the current module.
50
50
  const newUrl = pathToFileURL(require.resolve(re, { paths: [dirname(fileURLToPath(url))] })).href
51
+
52
+ if (newUrl.endsWith('.node')) {
53
+ return
54
+ }
55
+
51
56
  for (const each of await getExports(newUrl, context, parentLoad)) {
52
57
  full.add(each)
53
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "import-in-the-middle",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Intercept imports in Node.js",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -37,6 +37,7 @@
37
37
  "@babel/core": "^7.23.7",
38
38
  "@babel/eslint-parser": "^7.23.3",
39
39
  "@babel/plugin-syntax-import-assertions": "^7.23.3",
40
+ "@node-rs/crc32": "^1.10.3",
40
41
  "@react-email/components": "^0.0.19",
41
42
  "@types/node": "^18.0.6",
42
43
  "c8": "^7.8.0",
@@ -51,7 +52,8 @@
51
52
  "imhotap": "^2.1.0",
52
53
  "openai": "^4.47.2",
53
54
  "ts-node": "^10.9.1",
54
- "typescript": "^4.7.4"
55
+ "typescript": "^4.7.4",
56
+ "vue": "^3.4.31"
55
57
  },
56
58
  "dependencies": {
57
59
  "acorn": "^8.8.2",
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-darwin-arm64')
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-darwin-x64')
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-linux-arm64-gnu')
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-linux-x64-gnu')
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-win32-arm64-msvc')
@@ -0,0 +1 @@
1
+ module.exports = require('@node-rs/crc32-win32-x64-msvc')
@@ -0,0 +1,10 @@
1
+ import { strictEqual } from 'assert'
2
+
3
+ // We dynamically import a specific file that imports the
4
+ // native module for this platform and architecture.
5
+ //
6
+ // This way we know the file exists and the native module can
7
+ // be loaded.
8
+ const lib = await import(`../fixtures/native-modules/${process.platform}-${process.arch}.js`)
9
+
10
+ strictEqual(typeof lib.default.crc32, 'function')
@@ -0,0 +1,8 @@
1
+ import { strictEqual } from 'assert'
2
+ // https://github.com/nodejs/import-in-the-middle/issues/139
3
+ import * as libServer from 'vue/server-renderer'
4
+ // https://github.com/nodejs/import-in-the-middle/issues/144
5
+ import * as lib from 'vue'
6
+
7
+ strictEqual(typeof libServer.renderToString, 'function')
8
+ strictEqual(typeof lib.ref, 'function')
@@ -0,0 +1,16 @@
1
+ import { register } from 'module'
2
+ import Hook from '../../index.js'
3
+ import { strictEqual } from 'assert'
4
+
5
+ register('../../hook.mjs', import.meta.url, { data: { exclude: [/openai/] } })
6
+
7
+ const hooked = new Set()
8
+
9
+ Hook((_, name) => {
10
+ hooked.add(name)
11
+ })
12
+
13
+ await import('openai')
14
+
15
+ strictEqual(hooked.has('openai'), false)
16
+ strictEqual(hooked.has('fs'), true)