import-in-the-middle 1.9.1 → 1.11.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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +45 -7
- package/hook.js +82 -25
- package/index.d.ts +36 -0
- package/index.js +75 -0
- package/package.json +1 -1
- package/test/fixtures/import-after.mjs +16 -0
- package/test/fixtures/import.mjs +23 -0
- package/test/hook/vue-server-renderer.mjs +6 -3
- package/test/register/v18.19-exclude-regex.mjs +16 -0
- package/test/register/v18.19-include-builtin.mjs +20 -0
- package/test/register/v18.19-include-message-port.mjs +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.11.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.10.0...import-in-the-middle-v1.11.0) (2024-07-29)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Optionally only wrap modules hooked in `--import` ([#146](https://github.com/nodejs/import-in-the-middle/issues/146)) ([71c8d7b](https://github.com/nodejs/import-in-the-middle/commit/71c8d7bac512df94566d12c96fc2e438b4de2e2a))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* `node:` prefixed build-in modules with `include`/`exclude` ([#149](https://github.com/nodejs/import-in-the-middle/issues/149)) ([736a944](https://github.com/nodejs/import-in-the-middle/commit/736a9446e209bc8649801a27cb431df663551dc5))
|
|
14
|
+
|
|
15
|
+
## [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)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* 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))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* 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))
|
|
26
|
+
|
|
3
27
|
## [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)
|
|
4
28
|
|
|
5
29
|
|
package/README.md
CHANGED
|
@@ -34,14 +34,14 @@ console.log(foo) // 1 more than whatever that module exported
|
|
|
34
34
|
This requires the use of an ESM loader hook, which can be added with the following
|
|
35
35
|
command-line option.
|
|
36
36
|
|
|
37
|
-
```
|
|
38
|
-
--loader=import-in-the-middle/hook.mjs
|
|
37
|
+
```shell
|
|
38
|
+
node --loader=import-in-the-middle/hook.mjs my-app.mjs
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Since `--loader` has been deprecated you can also register the loader hook programmatically via the Node
|
|
42
42
|
[`module.register()`](https://nodejs.org/api/module.html#moduleregisterspecifier-parenturl-options)
|
|
43
43
|
API. However, for this to be able to hook non-dynamic imports, it needs to be
|
|
44
|
-
|
|
44
|
+
registered before your app code is evaluated via the `--import` command-line option.
|
|
45
45
|
|
|
46
46
|
`my-loader.mjs`
|
|
47
47
|
```js
|
|
@@ -54,9 +54,12 @@ 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
|
|
58
|
-
are intercepted. This is useful if a module is not
|
|
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
|
+
|
|
61
|
+
> **Note:** This feature is incompatible with the `{internals: true}` Hook option
|
|
62
|
+
|
|
60
63
|
```js
|
|
61
64
|
import * as module from 'module'
|
|
62
65
|
|
|
@@ -71,6 +74,41 @@ module.register('import-in-the-middle/hook.mjs', import.meta.url, {
|
|
|
71
74
|
})
|
|
72
75
|
```
|
|
73
76
|
|
|
77
|
+
### Only Intercepting Hooked modules
|
|
78
|
+
> **Note:** This feature is experimental and is incompatible with the `{internals: true}` Hook option
|
|
79
|
+
|
|
80
|
+
If you are `Hook`'ing all modules before they are imported, for example in a
|
|
81
|
+
module loaded via the Node.js `--import` CLI argument, you can configure the
|
|
82
|
+
loader to intercept only modules that were specifically hooked.
|
|
83
|
+
|
|
84
|
+
`instrument.mjs`
|
|
85
|
+
```js
|
|
86
|
+
import { register } from 'module'
|
|
87
|
+
import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
|
|
88
|
+
|
|
89
|
+
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
|
|
90
|
+
|
|
91
|
+
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
|
|
92
|
+
|
|
93
|
+
Hook(['fs'], (exported, name, baseDir) => {
|
|
94
|
+
// Instrument the fs module
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// Ensure that the loader has acknowledged all the modules
|
|
98
|
+
// before we allow execution to continue
|
|
99
|
+
await waitForAllMessagesAcknowledged()
|
|
100
|
+
```
|
|
101
|
+
`my-app.mjs`
|
|
102
|
+
```js
|
|
103
|
+
import * as fs from 'fs'
|
|
104
|
+
// fs will be instrumented!
|
|
105
|
+
fs.readFileSync('file.txt')
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```shell
|
|
109
|
+
node --import=./instrument.mjs ./my-app.mjs
|
|
110
|
+
```
|
|
111
|
+
|
|
74
112
|
## Limitations
|
|
75
113
|
|
|
76
114
|
* You cannot add new exports to a module. You can only modify existing ones.
|
package/hook.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const { URL } = require('url')
|
|
6
6
|
const { inspect } = require('util')
|
|
7
|
+
const { builtinModules } = require('module')
|
|
7
8
|
const specifiers = new Map()
|
|
8
9
|
const isWin = process.platform === 'win32'
|
|
9
10
|
|
|
@@ -116,7 +117,16 @@ function isBareSpecifier (specifier) {
|
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Determines whether the input is a bare specifier, file URL or a regular expression.
|
|
122
|
+
*
|
|
123
|
+
* - node: prefixed URL strings are considered bare specifiers in this context.
|
|
124
|
+
*/
|
|
125
|
+
function isBareSpecifierFileUrlOrRegex (input) {
|
|
126
|
+
if (input instanceof RegExp) {
|
|
127
|
+
return true
|
|
128
|
+
}
|
|
129
|
+
|
|
120
130
|
// Relative and absolute paths
|
|
121
131
|
if (
|
|
122
132
|
input.startsWith('.') ||
|
|
@@ -127,22 +137,38 @@ function isBareSpecifierOrFileUrl (input) {
|
|
|
127
137
|
try {
|
|
128
138
|
// eslint-disable-next-line no-new
|
|
129
139
|
const url = new URL(input)
|
|
130
|
-
|
|
140
|
+
// We consider node: URLs bare specifiers in this context
|
|
141
|
+
return url.protocol === 'file:' || url.protocol === 'node:'
|
|
131
142
|
} catch (err) {
|
|
132
143
|
// Anything that fails parsing is a bare specifier
|
|
133
144
|
return true
|
|
134
145
|
}
|
|
135
146
|
}
|
|
136
147
|
|
|
137
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Ensure an array only contains bare specifiers, file URLs or regular expressions.
|
|
150
|
+
*
|
|
151
|
+
* - We consider node: prefixed URL string as bare specifiers in this context.
|
|
152
|
+
* - For node built-in modules, we add additional node: prefixed modules to the
|
|
153
|
+
* output array.
|
|
154
|
+
*/
|
|
155
|
+
function ensureArrayWithBareSpecifiersFileUrlsAndRegex (array, type) {
|
|
138
156
|
if (!Array.isArray(array)) {
|
|
139
157
|
return undefined
|
|
140
158
|
}
|
|
141
159
|
|
|
142
|
-
const invalid = array.filter(s => !
|
|
160
|
+
const invalid = array.filter(s => !isBareSpecifierFileUrlOrRegex(s))
|
|
143
161
|
|
|
144
162
|
if (invalid.length) {
|
|
145
|
-
throw new Error(`'${type}' option only supports bare specifiers
|
|
163
|
+
throw new Error(`'${type}' option only supports bare specifiers, file URLs or regular expressions. Invalid entries: ${inspect(invalid)}`)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Rather than evaluate whether we have a node: scoped built-in-module for
|
|
167
|
+
// every call to resolve, we just add them to include/exclude now.
|
|
168
|
+
for (const each of array) {
|
|
169
|
+
if (typeof each === 'string' && !each.startsWith('node:') && builtinModules.includes(each)) {
|
|
170
|
+
array.push(`node:${each}`)
|
|
171
|
+
}
|
|
146
172
|
}
|
|
147
173
|
|
|
148
174
|
return array
|
|
@@ -206,19 +232,24 @@ async function processModule ({ srcUrl, context, parentGetSource, parentResolve,
|
|
|
206
232
|
if (isStarExportLine(n) === true) {
|
|
207
233
|
const [, modFile] = n.split('* from ')
|
|
208
234
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
235
|
+
// Relative paths need to be resolved relative to the parent module
|
|
236
|
+
const newSpecifier = isBareSpecifier(modFile) ? modFile : new URL(modFile, srcUrl).href
|
|
237
|
+
// We need to call `parentResolve` to resolve bare specifiers to a full
|
|
238
|
+
// URL. We also need to call `parentResolve` for all sub-modules to get
|
|
239
|
+
// the `format`. We can't rely on the parents `format` to know if this
|
|
240
|
+
// sub-module is ESM or CJS!
|
|
241
|
+
const result = await parentResolve(newSpecifier, { parentURL: srcUrl })
|
|
242
|
+
|
|
243
|
+
const subSetters = await processModule({
|
|
244
|
+
srcUrl: result.url,
|
|
245
|
+
context: { ...context, format: result.format },
|
|
246
|
+
parentGetSource,
|
|
247
|
+
parentResolve,
|
|
248
|
+
excludeDefault: true
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
for (const [name, setter] of subSetters.entries()) {
|
|
252
|
+
addSetter(name, setter, true)
|
|
222
253
|
}
|
|
223
254
|
} else {
|
|
224
255
|
addSetter(n, `
|
|
@@ -248,15 +279,33 @@ function createHook (meta) {
|
|
|
248
279
|
|
|
249
280
|
async function initialize (data) {
|
|
250
281
|
if (data) {
|
|
251
|
-
includeModules =
|
|
252
|
-
excludeModules =
|
|
282
|
+
includeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.include, 'include')
|
|
283
|
+
excludeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.exclude, 'exclude')
|
|
284
|
+
|
|
285
|
+
if (data.addHookMessagePort) {
|
|
286
|
+
data.addHookMessagePort.on('message', (modules) => {
|
|
287
|
+
if (includeModules === undefined) {
|
|
288
|
+
includeModules = []
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for (const each of modules) {
|
|
292
|
+
if (!each.startsWith('node:') && builtinModules.includes(each)) {
|
|
293
|
+
includeModules.push(`node:${each}`)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
includeModules.push(each)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
data.addHookMessagePort.postMessage('ack')
|
|
300
|
+
}).unref()
|
|
301
|
+
}
|
|
253
302
|
}
|
|
254
303
|
}
|
|
255
304
|
|
|
256
305
|
async function resolve (specifier, context, parentResolve) {
|
|
257
306
|
cachedResolve = parentResolve
|
|
258
307
|
|
|
259
|
-
// See github.com/nodejs/import-in-the-middle/pull/76.
|
|
308
|
+
// See https://github.com/nodejs/import-in-the-middle/pull/76.
|
|
260
309
|
if (specifier === iitmURL) {
|
|
261
310
|
return {
|
|
262
311
|
url: specifier,
|
|
@@ -278,13 +327,21 @@ function createHook (meta) {
|
|
|
278
327
|
// For included/excluded modules, we check the specifier to match libraries
|
|
279
328
|
// that are loaded with bare specifiers from node_modules.
|
|
280
329
|
//
|
|
281
|
-
// For non-bare specifier imports, we
|
|
282
|
-
//
|
|
283
|
-
|
|
330
|
+
// For non-bare specifier imports, we match to the full file URL because
|
|
331
|
+
// using relative paths would be very error prone!
|
|
332
|
+
function match (each) {
|
|
333
|
+
if (each instanceof RegExp) {
|
|
334
|
+
return each.test(result.url)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return each === specifier || each === result.url
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (includeModules && !includeModules.some(match)) {
|
|
284
341
|
return result
|
|
285
342
|
}
|
|
286
343
|
|
|
287
|
-
if (excludeModules && excludeModules.some(
|
|
344
|
+
if (excludeModules && excludeModules.some(match)) {
|
|
288
345
|
return result
|
|
289
346
|
}
|
|
290
347
|
|
package/index.d.ts
CHANGED
|
@@ -84,3 +84,39 @@ export declare function addHook(hookFn: HookFunction): void
|
|
|
84
84
|
* @param {HookFunction} hookFn The function to be removed.
|
|
85
85
|
*/
|
|
86
86
|
export declare function removeHook(hookFn: HookFunction): void
|
|
87
|
+
|
|
88
|
+
type CreateAddHookMessageChannelReturn<Data> = {
|
|
89
|
+
addHookMessagePort: MessagePort,
|
|
90
|
+
waitForAllMessagesAcknowledged: Promise<void>
|
|
91
|
+
registerOptions: { data?: Data; transferList?: any[]; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* EXPERIMENTAL
|
|
96
|
+
* This feature is experimental and may change in minor versions.
|
|
97
|
+
* **NOTE** This feature is incompatible with the {internals: true} Hook option.
|
|
98
|
+
*
|
|
99
|
+
* Creates a message channel with a port that can be used to add hooks to the
|
|
100
|
+
* list of exclusively included modules.
|
|
101
|
+
*
|
|
102
|
+
* This can be used to only wrap modules that are Hook'ed, however modules need
|
|
103
|
+
* to be hooked before they are imported.
|
|
104
|
+
*
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { register } from 'module'
|
|
107
|
+
* import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
|
|
108
|
+
*
|
|
109
|
+
* const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
|
|
110
|
+
*
|
|
111
|
+
* register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
|
|
112
|
+
*
|
|
113
|
+
* Hook(['fs'], (exported, name, baseDir) => {
|
|
114
|
+
* // Instrument the fs module
|
|
115
|
+
* })
|
|
116
|
+
*
|
|
117
|
+
* // Ensure that the loader has acknowledged all the modules
|
|
118
|
+
* // before we allow execution to continue
|
|
119
|
+
* await waitForAllMessagesAcknowledged()
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function createAddHookMessageChannel<Data = any>(): CreateAddHookMessageChannelReturn<Data>;
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const path = require('path')
|
|
6
6
|
const parse = require('module-details-from-path')
|
|
7
7
|
const { fileURLToPath } = require('url')
|
|
8
|
+
const { MessageChannel } = require('worker_threads')
|
|
8
9
|
|
|
9
10
|
const {
|
|
10
11
|
importHooks,
|
|
@@ -31,6 +32,75 @@ function callHookFn (hookFn, namespace, name, baseDir) {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
let sendModulesToLoader
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* EXPERIMENTAL
|
|
39
|
+
* This feature is experimental and may change in minor versions.
|
|
40
|
+
* **NOTE** This feature is incompatible with the {internals: true} Hook option.
|
|
41
|
+
*
|
|
42
|
+
* Creates a message channel with a port that can be used to add hooks to the
|
|
43
|
+
* list of exclusively included modules.
|
|
44
|
+
*
|
|
45
|
+
* This can be used to only wrap modules that are Hook'ed, however modules need
|
|
46
|
+
* to be hooked before they are imported.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { register } from 'module'
|
|
50
|
+
* import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
|
|
51
|
+
*
|
|
52
|
+
* const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
|
|
53
|
+
*
|
|
54
|
+
* register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
|
|
55
|
+
*
|
|
56
|
+
* Hook(['fs'], (exported, name, baseDir) => {
|
|
57
|
+
* // Instrument the fs module
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // Ensure that the loader has acknowledged all the modules
|
|
61
|
+
* // before we allow execution to continue
|
|
62
|
+
* await waitForAllMessagesAcknowledged()
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function createAddHookMessageChannel () {
|
|
66
|
+
const { port1, port2 } = new MessageChannel()
|
|
67
|
+
let pendingAckCount = 0
|
|
68
|
+
let resolveFn
|
|
69
|
+
|
|
70
|
+
sendModulesToLoader = (modules) => {
|
|
71
|
+
pendingAckCount++
|
|
72
|
+
port1.postMessage(modules)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
port1.on('message', () => {
|
|
76
|
+
pendingAckCount--
|
|
77
|
+
|
|
78
|
+
if (resolveFn && pendingAckCount <= 0) {
|
|
79
|
+
resolveFn()
|
|
80
|
+
}
|
|
81
|
+
}).unref()
|
|
82
|
+
|
|
83
|
+
function waitForAllMessagesAcknowledged () {
|
|
84
|
+
// This timer is to prevent the process from exiting with code 13:
|
|
85
|
+
// 13: Unsettled Top-Level Await.
|
|
86
|
+
const timer = setInterval(() => { }, 1000)
|
|
87
|
+
const promise = new Promise((resolve) => {
|
|
88
|
+
resolveFn = resolve
|
|
89
|
+
}).then(() => { clearInterval(timer) })
|
|
90
|
+
|
|
91
|
+
if (pendingAckCount === 0) {
|
|
92
|
+
resolveFn()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return promise
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const addHookMessagePort = port2
|
|
99
|
+
const registerOptions = { data: { addHookMessagePort, include: [] }, transferList: [addHookMessagePort] }
|
|
100
|
+
|
|
101
|
+
return { registerOptions, addHookMessagePort, waitForAllMessagesAcknowledged }
|
|
102
|
+
}
|
|
103
|
+
|
|
34
104
|
function Hook (modules, options, hookFn) {
|
|
35
105
|
if ((this instanceof Hook) === false) return new Hook(modules, options, hookFn)
|
|
36
106
|
if (typeof modules === 'function') {
|
|
@@ -43,6 +113,10 @@ function Hook (modules, options, hookFn) {
|
|
|
43
113
|
}
|
|
44
114
|
const internals = options ? options.internals === true : false
|
|
45
115
|
|
|
116
|
+
if (sendModulesToLoader && Array.isArray(modules)) {
|
|
117
|
+
sendModulesToLoader(modules)
|
|
118
|
+
}
|
|
119
|
+
|
|
46
120
|
this._iitmHook = (name, namespace) => {
|
|
47
121
|
const filename = name
|
|
48
122
|
const isBuiltin = name.startsWith('node:')
|
|
@@ -92,3 +166,4 @@ module.exports = Hook
|
|
|
92
166
|
module.exports.Hook = Hook
|
|
93
167
|
module.exports.addHook = addHook
|
|
94
168
|
module.exports.removeHook = removeHook
|
|
169
|
+
module.exports.createAddHookMessageChannel = createAddHookMessageChannel
|
package/package.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { strictEqual } from 'assert'
|
|
2
|
+
import { sep } from 'path'
|
|
3
|
+
import * as os from 'node:os'
|
|
4
|
+
import { Hook } from '../../index.js'
|
|
5
|
+
|
|
6
|
+
const hooked = []
|
|
7
|
+
|
|
8
|
+
Hook((_, name) => {
|
|
9
|
+
hooked.push(name)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
strictEqual(hooked.length, 2)
|
|
13
|
+
strictEqual(hooked[0], 'path')
|
|
14
|
+
strictEqual(hooked[1], 'os')
|
|
15
|
+
strictEqual(sep, '@')
|
|
16
|
+
strictEqual(os.arch(), 'new_crazy_arch')
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { register } from 'module'
|
|
2
|
+
import { Hook, createAddHookMessageChannel } from '../../index.js'
|
|
3
|
+
// We've imported path here to ensure that the hook is still applied later even
|
|
4
|
+
// if the library is used here.
|
|
5
|
+
import * as path from 'path'
|
|
6
|
+
|
|
7
|
+
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
|
|
8
|
+
|
|
9
|
+
register('../../hook.mjs', import.meta.url, registerOptions)
|
|
10
|
+
|
|
11
|
+
Hook(['path'], (exports) => {
|
|
12
|
+
exports.sep = '@'
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
Hook(['os'], (exports) => {
|
|
16
|
+
exports.arch = function () {
|
|
17
|
+
return 'new_crazy_arch'
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
console.assert(path.sep !== '@')
|
|
22
|
+
|
|
23
|
+
await waitForAllMessagesAcknowledged()
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
// https://github.com/nodejs/import-in-the-middle/issues/139
|
|
2
1
|
import { strictEqual } from 'assert'
|
|
3
|
-
|
|
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'
|
|
4
6
|
|
|
5
|
-
strictEqual(typeof
|
|
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)
|
|
@@ -0,0 +1,20 @@
|
|
|
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: { include: ['node:util', 'os'] } })
|
|
6
|
+
|
|
7
|
+
const hooked = []
|
|
8
|
+
|
|
9
|
+
Hook((exports, name) => {
|
|
10
|
+
hooked.push(name)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
await import('util')
|
|
14
|
+
await import('node:os')
|
|
15
|
+
await import('fs')
|
|
16
|
+
await import('path')
|
|
17
|
+
|
|
18
|
+
strictEqual(hooked.length, 2)
|
|
19
|
+
strictEqual(hooked[0], 'util')
|
|
20
|
+
strictEqual(hooked[1], 'os')
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process'
|
|
2
|
+
|
|
3
|
+
const out = spawnSync(process.execPath,
|
|
4
|
+
['--import', './test/fixtures/import.mjs', './test/fixtures/import-after.mjs'],
|
|
5
|
+
{ stdio: 'inherit', env: {} }
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
if (out.error) {
|
|
9
|
+
console.error(out.error)
|
|
10
|
+
}
|
|
11
|
+
if (out.status !== 0) {
|
|
12
|
+
console.error(`Expected exit code 0, got ${out.status}`)
|
|
13
|
+
}
|
|
14
|
+
process.exit(out.status)
|