import-in-the-middle 1.3.4 → 1.3.5

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/.editorconfig ADDED
@@ -0,0 +1,14 @@
1
+ # http://editorconfig.org
2
+
3
+ root = true
4
+
5
+ [*]
6
+ indent_style = space
7
+ indent_size = 2
8
+ end_of_line = lf
9
+ charset = utf-8
10
+ trim_trailing_whitespace = true
11
+ insert_final_newline = true
12
+
13
+ [*.md]
14
+ trim_trailing_whitespace = false
package/hook.js ADDED
@@ -0,0 +1,179 @@
1
+ // Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
2
+ //
3
+ // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
4
+
5
+ const specifiers = new Map()
6
+ const isWin = process.platform === "win32"
7
+
8
+ // FIXME: Typescript extensions are added temporarily until we find a better
9
+ // way of supporting arbitrary extensions
10
+ const EXTENSION_RE = /\.(js|mjs|cjs|ts|mts|cts)$/
11
+ const NODE_VERSION = process.versions.node.split('.')
12
+ const NODE_MAJOR = Number(NODE_VERSION[0])
13
+ const NODE_MINOR = Number(NODE_VERSION[1])
14
+
15
+ let entrypoint
16
+
17
+ function hasIitm (url) {
18
+ try {
19
+ return new URL(url).searchParams.has('iitm')
20
+ } catch {
21
+ return false
22
+ }
23
+ }
24
+
25
+ function isIitm (url, meta) {
26
+ return url === meta.url || url === meta.url.replace('hook.mjs', 'hook.js')
27
+ }
28
+
29
+ function deleteIitm (url) {
30
+ let resultUrl
31
+ try {
32
+ const urlObj = new URL(url)
33
+ if (urlObj.searchParams.has('iitm')) {
34
+ urlObj.searchParams.delete('iitm')
35
+ resultUrl = urlObj.href
36
+ if (resultUrl.startsWith('file:node:')) {
37
+ resultUrl = resultUrl.replace('file:', '')
38
+ }
39
+ if (resultUrl.startsWith('file:///node:')) {
40
+ resultUrl = resultUrl.replace('file:///', '')
41
+ }
42
+ } else {
43
+ resultUrl = urlObj.href
44
+ }
45
+ } catch {
46
+ resultUrl = url
47
+ }
48
+ return resultUrl
49
+ }
50
+
51
+ function isNode16AndBiggerOrEqualsThan16_17_0() {
52
+ return NODE_MAJOR === 16 && NODE_MINOR >= 17
53
+ }
54
+
55
+ function isFileProtocol (urlObj) {
56
+ return urlObj.protocol === 'file:'
57
+ }
58
+
59
+ function isNodeProtocol (urlObj) {
60
+ return urlObj.protocol === 'node:'
61
+ }
62
+
63
+ function needsToAddFileProtocol(urlObj) {
64
+ if (NODE_MAJOR === 17) {
65
+ return !isFileProtocol(urlObj)
66
+ }
67
+ if (isNode16AndBiggerOrEqualsThan16_17_0()) {
68
+ return !isFileProtocol(urlObj) && !isNodeProtocol(urlObj)
69
+ }
70
+ return !isFileProtocol(urlObj) && NODE_MAJOR < 18
71
+ }
72
+
73
+
74
+ function addIitm (url) {
75
+ const urlObj = new URL(url)
76
+ urlObj.searchParams.set('iitm', 'true')
77
+ return needsToAddFileProtocol(urlObj) ? 'file:' + urlObj.href : urlObj.href
78
+ }
79
+
80
+ function createHook (meta) {
81
+ async function resolve (specifier, context, parentResolve) {
82
+ const { parentURL = '' } = context
83
+ const newSpecifier = deleteIitm(specifier)
84
+ if (isWin && parentURL.indexOf('file:node') === 0) {
85
+ context.parentURL = ''
86
+ }
87
+ const url = await parentResolve(newSpecifier, context, parentResolve)
88
+ if (parentURL === '' && !EXTENSION_RE.test(url.url)) {
89
+ entrypoint = url.url
90
+ return { url: url.url, format: 'commonjs' }
91
+ }
92
+
93
+ if (isIitm(parentURL, meta) || hasIitm(parentURL)) {
94
+ return url
95
+ }
96
+
97
+ if (context.importAssertions && context.importAssertions.type === 'json') {
98
+ return url
99
+ }
100
+
101
+
102
+ specifiers.set(url.url, specifier)
103
+
104
+ return {
105
+ url: addIitm(url.url),
106
+ shortCircuit: true
107
+ }
108
+ }
109
+
110
+ const iitmURL = new URL('lib/register.js', meta.url).toString()
111
+ async function getSource (url, context, parentGetSource) {
112
+ if (hasIitm(url)) {
113
+ const realUrl = deleteIitm(url)
114
+ const realModule = await import(realUrl)
115
+ const exportNames = Object.keys(realModule)
116
+ return {
117
+ source: `
118
+ import { register } from '${iitmURL}'
119
+ import * as namespace from '${url}'
120
+ const set = {}
121
+ ${exportNames.map((n) => `
122
+ let $${n} = namespace.${n}
123
+ export { $${n} as ${n} }
124
+ set.${n} = (v) => {
125
+ $${n} = v
126
+ return true
127
+ }
128
+ `).join('\n')}
129
+ register('${realUrl}', namespace, set, '${specifiers.get(realUrl)}')
130
+ `
131
+ }
132
+ }
133
+
134
+ return parentGetSource(url, context, parentGetSource)
135
+ }
136
+
137
+ // For Node.js 16.12.0 and higher.
138
+ async function load (url, context, parentLoad) {
139
+ if (hasIitm(url)) {
140
+ const { source } = await getSource(url, context)
141
+ return {
142
+ source,
143
+ shortCircuit: true,
144
+ format: 'module'
145
+ }
146
+ }
147
+
148
+ return parentLoad(url, context, parentLoad)
149
+ }
150
+
151
+ if (NODE_MAJOR >= 20) {
152
+ process.emitWarning('import-in-the-middle is currently unsupported on Node.js v20 and has been disabled.')
153
+ return {} // TODO: Add support for Node >=20
154
+ } else if (NODE_MAJOR >= 17 || (NODE_MAJOR === 16 && NODE_MINOR >= 12)) {
155
+ return { load, resolve }
156
+ } else {
157
+ return {
158
+ load,
159
+ resolve,
160
+ getSource,
161
+ getFormat (url, context, parentGetFormat) {
162
+ if (hasIitm(url)) {
163
+ return {
164
+ format: 'module'
165
+ }
166
+ }
167
+ if (url === entrypoint) {
168
+ return {
169
+ format: 'commonjs'
170
+ }
171
+ }
172
+
173
+ return parentGetFormat(url, context, parentGetFormat)
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ module.exports = { createHook }
package/hook.mjs CHANGED
@@ -2,160 +2,8 @@
2
2
  //
3
3
  // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
4
4
 
5
- const specifiers = new Map()
6
- const isWin = process.platform === "win32"
5
+ import { createHook } from './hook.js'
7
6
 
7
+ const { load, resolve, getFormat, getSource } = createHook(import.meta)
8
8
 
9
- // FIXME: Typescript extensions are added temporarily until we find a better
10
- // way of supporting arbitrary extensions
11
- const EXTENSION_RE = /\.(js|mjs|cjs|ts|mts|cts)$/
12
- const NODE_VERSION = process.versions.node.split('.')
13
- const NODE_MAJOR = Number(NODE_VERSION[0])
14
- const NODE_MINOR = Number(NODE_VERSION[1])
15
-
16
- let entrypoint
17
-
18
- function hasIitm (url) {
19
- try {
20
- return new URL(url).searchParams.has('iitm')
21
- } catch {
22
- return false
23
- }
24
- }
25
-
26
- function deleteIitm (url) {
27
- let resultUrl
28
- try {
29
- const urlObj = new URL(url)
30
- if (urlObj.searchParams.has('iitm')) {
31
- urlObj.searchParams.delete('iitm')
32
- resultUrl = urlObj.href
33
- if (resultUrl.startsWith('file:node:')) {
34
- resultUrl = resultUrl.replace('file:', '')
35
- }
36
- if (resultUrl.startsWith('file:///node:')) {
37
- resultUrl = resultUrl.replace('file:///', '')
38
- }
39
- } else {
40
- resultUrl = urlObj.href
41
- }
42
- } catch {
43
- resultUrl = url
44
- }
45
- return resultUrl
46
- }
47
-
48
- function isNode16AndBiggerOrEqualsThan16_17_0() {
49
- return NODE_MAJOR === 16 && NODE_MINOR >= 17
50
- }
51
-
52
- function isFileProtocol (urlObj) {
53
- return urlObj.protocol === 'file:'
54
- }
55
-
56
- function isNodeProtocol (urlObj) {
57
- return urlObj.protocol === 'node:'
58
- }
59
-
60
- function needsToAddFileProtocol(urlObj) {
61
- if (NODE_MAJOR === 17) {
62
- return !isFileProtocol(urlObj)
63
- }
64
- if (isNode16AndBiggerOrEqualsThan16_17_0()) {
65
- return !isFileProtocol(urlObj) && !isNodeProtocol(urlObj)
66
- }
67
- return !isFileProtocol(urlObj) && NODE_MAJOR < 18
68
- }
69
-
70
-
71
- function addIitm (url) {
72
- const urlObj = new URL(url)
73
- urlObj.searchParams.set('iitm', 'true')
74
- return needsToAddFileProtocol(urlObj) ? 'file:' + urlObj.href : urlObj.href
75
- }
76
-
77
- export async function resolve (specifier, context, parentResolve) {
78
- const { parentURL = '' } = context
79
- const newSpecifier = deleteIitm(specifier)
80
- if (isWin && parentURL.indexOf('file:node') === 0) {
81
- context.parentURL = ''
82
- }
83
- const url = await parentResolve(newSpecifier, context, parentResolve)
84
- if (parentURL === '' && !EXTENSION_RE.test(url.url)) {
85
- entrypoint = url.url
86
- return { url: url.url, format: 'commonjs' }
87
- }
88
-
89
- if (parentURL === import.meta.url || hasIitm(parentURL)) {
90
- return url
91
- }
92
-
93
- if (context.importAssertions && context.importAssertions.type === 'json') {
94
- return url
95
- }
96
-
97
-
98
- specifiers.set(url.url, specifier)
99
-
100
- return {
101
- url: addIitm(url.url),
102
- shortCircuit: true
103
- }
104
- }
105
-
106
- export function getFormat (url, context, parentGetFormat) {
107
- if (hasIitm(url)) {
108
- return {
109
- format: 'module'
110
- }
111
- }
112
- if (url === entrypoint) {
113
- return {
114
- format: 'commonjs'
115
- }
116
- }
117
-
118
- return parentGetFormat(url, context, parentGetFormat)
119
- }
120
-
121
- const iitmURL = new URL('lib/register.js', import.meta.url).toString()
122
- export async function getSource (url, context, parentGetSource) {
123
- if (hasIitm(url)) {
124
- const realUrl = deleteIitm(url)
125
- const realModule = await import(realUrl)
126
- const exportNames = Object.keys(realModule)
127
- return {
128
- source: `
129
- import { register } from '${iitmURL}'
130
- import * as namespace from '${url}'
131
- const set = {}
132
- ${exportNames.map((n) => `
133
- let $${n} = namespace.${n}
134
- export { $${n} as ${n} }
135
- set.${n} = (v) => {
136
- $${n} = v
137
- return true
138
- }
139
- `).join('\n')}
140
- register('${realUrl}', namespace, set, '${specifiers.get(realUrl)}')
141
- `
142
- }
143
- }
144
-
145
- return parentGetSource(url, context, parentGetSource)
146
- }
147
-
148
- // For Node.js 16.12.0 and higher.
149
- export async function load (url, context, parentLoad) {
150
- if (hasIitm(url)) {
151
- const { source } = await getSource(url, context)
152
- return {
153
- source,
154
- shortCircuit: true,
155
- format: 'module'
156
- }
157
- }
158
-
159
- return parentLoad(url, context, parentLoad)
160
- }
161
-
9
+ export { load, resolve, getFormat, getSource }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "import-in-the-middle",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "Intercept imports in Node.js",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "c8 --check-coverage --lines 88 imhotap --runner test/runtest --files test/{hook,low-level,other}/*",
8
- "test-win": "c8 --check-coverage --lines 88 imhotap --runner test\\runtest.bat --files test/{hook,low-level,other}/*",
7
+ "test": "c8 --check-coverage --lines 85 imhotap --runner test/runtest --files test/{hook,low-level,other}/*",
8
+ "test:unsupported": "imhotap --runner test/runtest --files test/hook/loader.mjs",
9
+ "test-win": "c8 --check-coverage --lines 85 imhotap --runner test\\runtest.bat --files test/{hook,low-level,other}/*",
9
10
  "test:ts": "c8 imhotap --runner test/runtest --files test/typescript/*.test.mts",
10
11
  "test-win:ts": "c8 imhotap --runner test\\runtest.bat --files test/typescript/*.test.mts",
11
12
  "coverage": "c8 --reporter html imhotap --runner test/runtest --files test/{hook,low-level,other}/* && echo '\nNow open coverage/index.html\n'"
@@ -0,0 +1,5 @@
1
+ // Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
2
+ //
3
+ // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
4
+
5
+ // Empty file just to validate the loader is not crashing.