@exodus/stasis 1.0.0-beta.2 → 1.0.0-beta.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/README.md +23 -3
- package/bin/stasis.js +375 -170
- package/package.json +44 -11
- package/src/audit-corrections.js +68 -0
- package/src/audit.js +243 -59
- package/src/babel-worker.cjs +65 -0
- package/src/babel.js +131 -0
- package/src/bundle-from-lockfile.js +12 -18
- package/src/bundle-reader.js +77 -0
- package/src/cmd/build.js +95 -128
- package/src/cmd/bundle.js +877 -641
- package/src/cmd/diff.js +2 -19
- package/src/cmd/github-bundle.js +39 -0
- package/src/cmd/output.js +36 -0
- package/src/cmd/sbom.js +4 -18
- package/src/diff.js +67 -124
- package/src/json-stream.js +283 -0
- package/src/loader-mock.js +8 -15
- package/src/loaders/bash.js +49 -116
- package/src/loaders/cargo.js +1699 -0
- package/src/loaders/foundry.js +923 -0
- package/src/loaders/paths.js +33 -0
- package/src/loaders/php.js +339 -394
- package/src/loaders/rust.js +3254 -242
- package/src/loaders/solidity-ownership.js +531 -0
- package/src/loaders/solidity.js +412 -162
- package/src/loaders/toml.js +68 -0
- package/src/metro-resolver.js +150 -0
- package/src/mock.js +57 -165
- package/src/parse.js +4 -16
- package/src/resolve-fields.js +331 -0
- package/src/resolve-node.js +416 -0
- package/src/resolve-typescript.js +427 -0
- package/src/rollup.js +5 -0
- package/src/sbom.js +64 -92
- package/src/scan.js +234 -156
- package/src/vfs-bundle/entries.js +140 -0
- package/src/vfs-bundle/github.js +193 -0
- package/src/vfs-bundle/soldeer.js +125 -0
- package/src/vfs-bundle/tree.js +606 -0
- package/src/vfs-bundle.js +74 -0
- package/src/why.js +434 -0
- package/src/apis/npm/index.js +0 -36
- package/src/apis/npm/semver.cjs +0 -44
- package/src/cmd/extract.js +0 -193
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import Module, { isBuiltin } from 'node:module'
|
|
2
|
+
import { basename, dirname, isAbsolute, join, normalize, resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import { packageJSONStat, packageJSONText } from '@exodus/stasis-core/bundle-util'
|
|
6
|
+
|
|
7
|
+
// Node's CommonJS resolution (`createRequire(parent).resolve(spec, { conditions })`) over a
|
|
8
|
+
// `host` (@exodus/stasis-core/host), mirroring lib/internal/modules/cjs/loader.js and
|
|
9
|
+
// esm/resolve.js step for step, errors with Node's `code`s included. Global folders (NODE_PATH,
|
|
10
|
+
// ~/.node_modules) are not consulted: a virtual tree resolves hermetically.
|
|
11
|
+
|
|
12
|
+
const codedError = (code, message) => Object.assign(new Error(message), { code })
|
|
13
|
+
|
|
14
|
+
const REQUIRE_CONDITIONS = new Set(['require', 'node', 'node-addons', 'module-sync'])
|
|
15
|
+
|
|
16
|
+
// esm/resolve.js's deprecatedInvalidSegmentRegEx (an empty segment is only deprecated there, so no error here).
|
|
17
|
+
const deprecatedInvalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/iu
|
|
18
|
+
const encodedSepRegEx = /%2F|%5C/iu
|
|
19
|
+
// Module._findPath's bare-package matcher: `name` or `@scope/name`, optional `/subpath`.
|
|
20
|
+
const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/u
|
|
21
|
+
// cjs/loader.js's character tests: relative requests, directory requests (no file probes), and
|
|
22
|
+
// requests that skip the node_modules lookup.
|
|
23
|
+
const RELATIVE_REQUEST = /^\.\.?(?:\/|$)/u
|
|
24
|
+
const TRAILING_SLASH = /\/$|(?:^|\/)\.\.?$/u
|
|
25
|
+
const RELATIVE_LOOKUP = /^\.(?:$|[./])/u
|
|
26
|
+
|
|
27
|
+
const isArrayIndex = (key) => {
|
|
28
|
+
const n = Number(key)
|
|
29
|
+
return `${n}` === key && n >= 0 && n < 0xFF_FF_FF_FF
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function patternKeyCompare(a, b) {
|
|
33
|
+
const aIdx = a.indexOf('*')
|
|
34
|
+
const bIdx = b.indexOf('*')
|
|
35
|
+
const baseLenA = aIdx === -1 ? a.length : aIdx + 1
|
|
36
|
+
const baseLenB = bIdx === -1 ? b.length : bIdx + 1
|
|
37
|
+
if (baseLenA > baseLenB) return -1
|
|
38
|
+
if (baseLenB > baseLenA) return 1
|
|
39
|
+
if (aIdx === -1) return 1
|
|
40
|
+
if (bIdx === -1) return -1
|
|
41
|
+
if (a.length > b.length) return -1
|
|
42
|
+
if (b.length > a.length) return 1
|
|
43
|
+
return 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isConditionalExportsMainSugar(exports, pkgPath) {
|
|
47
|
+
if (typeof exports === 'string' || Array.isArray(exports)) return true
|
|
48
|
+
if (typeof exports !== 'object' || exports === null) return false
|
|
49
|
+
const keys = Object.keys(exports)
|
|
50
|
+
const isSugar = (key) => key === '' || key[0] !== '.'
|
|
51
|
+
const sugar = keys.length > 0 && isSugar(keys[0])
|
|
52
|
+
if (keys.some((key) => isSugar(key) !== sugar)) {
|
|
53
|
+
throw codedError('ERR_INVALID_PACKAGE_CONFIG', `Invalid package config ${pkgPath}. "exports" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`)
|
|
54
|
+
}
|
|
55
|
+
return sugar
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// esm/resolve.js's best `*` pattern key of `map` for `subpath`: -> [key, wildcard] or null.
|
|
59
|
+
function bestPatternMatch(map, subpath) {
|
|
60
|
+
let bestMatch = ''
|
|
61
|
+
let bestMatchSubpath
|
|
62
|
+
for (const key of Object.keys(map)) {
|
|
63
|
+
const patternIndex = key.indexOf('*')
|
|
64
|
+
if (patternIndex === -1 || !subpath.startsWith(key.slice(0, patternIndex))) continue
|
|
65
|
+
const patternTrailer = key.slice(patternIndex + 1)
|
|
66
|
+
if (subpath.length >= key.length && subpath.endsWith(patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && key.lastIndexOf('*') === patternIndex) {
|
|
67
|
+
bestMatch = key
|
|
68
|
+
bestMatchSubpath = subpath.slice(patternIndex, subpath.length - patternTrailer.length)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return bestMatch ? [bestMatch, bestMatchSubpath] : null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// esm/resolve.js's parsePackageName: -> { packageName, packageSubpath, isScoped }.
|
|
75
|
+
function parsePackageName(specifier, base) {
|
|
76
|
+
let separatorIndex = specifier.indexOf('/')
|
|
77
|
+
const isScoped = specifier[0] === '@'
|
|
78
|
+
let valid = true
|
|
79
|
+
if (isScoped) {
|
|
80
|
+
if (separatorIndex === -1) valid = false
|
|
81
|
+
else separatorIndex = specifier.indexOf('/', separatorIndex + 1)
|
|
82
|
+
}
|
|
83
|
+
const packageName = separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex)
|
|
84
|
+
if (!valid || /^\.|%|\\/u.test(packageName)) {
|
|
85
|
+
throw codedError('ERR_INVALID_MODULE_SPECIFIER', `Invalid module "${specifier}" is not a valid package name imported from ${fileURLToPath(base)}`)
|
|
86
|
+
}
|
|
87
|
+
return { packageName, packageSubpath: `.${separatorIndex === -1 ? '' : specifier.slice(separatorIndex)}`, isScoped }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function createNodeResolver(host) {
|
|
91
|
+
// package.json reads, memoized per path; a malformed manifest, or one there that can't be read,
|
|
92
|
+
// throws ERR_INVALID_PACKAGE_CONFIG on every access.
|
|
93
|
+
const parsePackage = (pjsonPath) => {
|
|
94
|
+
let stat
|
|
95
|
+
try {
|
|
96
|
+
stat = packageJSONStat(host, pjsonPath)
|
|
97
|
+
} catch (err) {
|
|
98
|
+
return err
|
|
99
|
+
}
|
|
100
|
+
if (!stat?.isFile()) return { exists: false }
|
|
101
|
+
let data
|
|
102
|
+
try {
|
|
103
|
+
data = JSON.parse(packageJSONText(host.readFile(pjsonPath)))
|
|
104
|
+
} catch (cause) {
|
|
105
|
+
return codedError('ERR_INVALID_PACKAGE_CONFIG', `Invalid package config ${pjsonPath}: ${cause.message}`)
|
|
106
|
+
}
|
|
107
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) return codedError('ERR_INVALID_PACKAGE_CONFIG', `Invalid package config ${pjsonPath}.`)
|
|
108
|
+
const string = (value) => (typeof value === 'string' ? value : undefined)
|
|
109
|
+
// Node keeps `exports` and `imports` only as a string, an array or an object.
|
|
110
|
+
const map = (value) => (typeof value === 'string' || (typeof value === 'object' && value !== null) ? value : undefined)
|
|
111
|
+
return { exists: true, path: pjsonPath, name: string(data.name), main: string(data.main), exports: map(data.exports), imports: map(data.imports) }
|
|
112
|
+
}
|
|
113
|
+
const pkgCache = new Map()
|
|
114
|
+
const readPackage = (pjsonPath) => {
|
|
115
|
+
let pkg = pkgCache.get(pjsonPath)
|
|
116
|
+
if (pkg === undefined) pkgCache.set(pjsonPath, pkg = parsePackage(pjsonPath))
|
|
117
|
+
if (pkg instanceof Error) throw pkg
|
|
118
|
+
return pkg
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Node's readPackageScope: the nearest package.json, never crossing out of a node_modules dir.
|
|
122
|
+
const readPackageScope = (checkPath) => {
|
|
123
|
+
for (let dir = dirname(checkPath); basename(dir) !== 'node_modules'; dir = dirname(dir)) {
|
|
124
|
+
const pkg = readPackage(join(dir, 'package.json'))
|
|
125
|
+
if (pkg.exists) return pkg
|
|
126
|
+
if (dirname(dir) === dir) break
|
|
127
|
+
}
|
|
128
|
+
return null
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// internalModuleStat: 0 file, 1 dir, -1 missing.
|
|
132
|
+
const stat = (p) => {
|
|
133
|
+
const st = host.stat(p)
|
|
134
|
+
return st === null ? -1 : st.isDirectory() ? 1 : 0
|
|
135
|
+
}
|
|
136
|
+
const tryFile = (p) => (stat(p) === 0 ? host.realpath(p) : false)
|
|
137
|
+
const tryExtensions = (base, exts) => {
|
|
138
|
+
for (const ext of exts) {
|
|
139
|
+
const hit = tryFile(base + ext)
|
|
140
|
+
if (hit) return hit
|
|
141
|
+
}
|
|
142
|
+
return false
|
|
143
|
+
}
|
|
144
|
+
const tryPackage = (requestPath, exts, originalPath) => {
|
|
145
|
+
const pkg = readPackage(join(requestPath, 'package.json'))
|
|
146
|
+
const index = () => tryExtensions(resolve(requestPath, 'index'), exts)
|
|
147
|
+
if (!pkg.exists || !pkg.main) return index()
|
|
148
|
+
const filename = resolve(requestPath, pkg.main)
|
|
149
|
+
const actual = tryFile(filename) || tryExtensions(filename, exts) || tryExtensions(resolve(filename, 'index'), exts) || index()
|
|
150
|
+
if (actual) return actual
|
|
151
|
+
throw Object.assign(
|
|
152
|
+
codedError('MODULE_NOT_FOUND', `Cannot find module '${filename}'. Please verify that the package.json has a valid "main" entry`),
|
|
153
|
+
{ path: join(requestPath, 'package.json'), requestPath: originalPath },
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// --- esm/resolve.js: exports / imports ---
|
|
158
|
+
|
|
159
|
+
const fileExists = (url) => stat(fileURLToPath(url)) === 0
|
|
160
|
+
|
|
161
|
+
const throwInvalidPackageTarget = (subpath, target, packageJSONUrl, internal) => {
|
|
162
|
+
const rel = fileURLToPath(new URL('.', packageJSONUrl))
|
|
163
|
+
const t = typeof target === 'string' ? target : JSON.stringify(target)
|
|
164
|
+
throw codedError('ERR_INVALID_PACKAGE_TARGET',
|
|
165
|
+
internal
|
|
166
|
+
? `Invalid "imports" target ${t} defined for '${subpath}' in the package config ${rel}package.json`
|
|
167
|
+
: `Invalid "exports" ${subpath === '.' ? 'main' : 'target'} ${t} defined for '${subpath}' in the package config ${rel}package.json`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const resolvePackageTargetString = (target, subpath, match, packageJSONUrl, pattern, internal, conditions) => {
|
|
171
|
+
if (subpath !== '' && !pattern && !target.endsWith('/')) throwInvalidPackageTarget(match, target, packageJSONUrl, internal)
|
|
172
|
+
if (!target.startsWith('./')) {
|
|
173
|
+
// A bare `imports` target (`"#x": "dep"`) is a package specifier, resolved the ESM way.
|
|
174
|
+
if (internal && !target.startsWith('../') && !target.startsWith('/') && !URL.canParse(target)) {
|
|
175
|
+
return packageResolve(pattern ? target.replaceAll('*', () => subpath) : target + subpath, packageJSONUrl, conditions)
|
|
176
|
+
}
|
|
177
|
+
throwInvalidPackageTarget(match, target, packageJSONUrl, internal)
|
|
178
|
+
}
|
|
179
|
+
if (deprecatedInvalidSegmentRegEx.test(target.slice(2))) throwInvalidPackageTarget(match, target, packageJSONUrl, internal)
|
|
180
|
+
const resolved = new URL(target, packageJSONUrl)
|
|
181
|
+
if (!resolved.pathname.startsWith(new URL('.', packageJSONUrl).pathname)) throwInvalidPackageTarget(match, target, packageJSONUrl, internal)
|
|
182
|
+
if (subpath === '') return resolved
|
|
183
|
+
if (deprecatedInvalidSegmentRegEx.test(subpath)) {
|
|
184
|
+
const request = pattern ? match.replace('*', subpath) : match + subpath
|
|
185
|
+
throw codedError('ERR_INVALID_MODULE_SPECIFIER', `Invalid module "${request}" request is not a valid match in pattern "${match}" for the "${internal ? 'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`)
|
|
186
|
+
}
|
|
187
|
+
if (pattern) return new URL(resolved.href.replaceAll('*', () => subpath))
|
|
188
|
+
return new URL(subpath, resolved)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const resolvePackageTarget = (packageJSONUrl, target, subpath, packageSubpath, pattern, internal, conditions) => {
|
|
192
|
+
if (typeof target === 'string') {
|
|
193
|
+
return resolvePackageTargetString(target, subpath, packageSubpath, packageJSONUrl, pattern, internal, conditions)
|
|
194
|
+
}
|
|
195
|
+
if (Array.isArray(target)) {
|
|
196
|
+
if (target.length === 0) return null
|
|
197
|
+
let lastException
|
|
198
|
+
for (const item of target) {
|
|
199
|
+
let resolved
|
|
200
|
+
try {
|
|
201
|
+
resolved = resolvePackageTarget(packageJSONUrl, item, subpath, packageSubpath, pattern, internal, conditions)
|
|
202
|
+
} catch (e) {
|
|
203
|
+
lastException = e
|
|
204
|
+
if (e.code === 'ERR_INVALID_PACKAGE_TARGET') continue
|
|
205
|
+
throw e
|
|
206
|
+
}
|
|
207
|
+
if (resolved === undefined) continue
|
|
208
|
+
if (resolved === null) {
|
|
209
|
+
lastException = null
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
return resolved
|
|
213
|
+
}
|
|
214
|
+
if (lastException == null) return lastException
|
|
215
|
+
throw lastException
|
|
216
|
+
}
|
|
217
|
+
if (typeof target === 'object' && target !== null) {
|
|
218
|
+
const keys = Object.keys(target)
|
|
219
|
+
if (keys.some(isArrayIndex)) {
|
|
220
|
+
throw codedError('ERR_INVALID_PACKAGE_CONFIG', `Invalid package config ${fileURLToPath(packageJSONUrl)}. "exports" cannot contain numeric property keys.`)
|
|
221
|
+
}
|
|
222
|
+
for (const key of keys) {
|
|
223
|
+
if (key !== 'default' && !conditions.has(key)) continue
|
|
224
|
+
const resolved = resolvePackageTarget(packageJSONUrl, target[key], subpath, packageSubpath, pattern, internal, conditions)
|
|
225
|
+
if (resolved !== undefined) return resolved
|
|
226
|
+
}
|
|
227
|
+
return undefined
|
|
228
|
+
}
|
|
229
|
+
if (target === null) return null
|
|
230
|
+
throwInvalidPackageTarget(packageSubpath, target, packageJSONUrl, internal)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const throwExportsNotFound = (subpath, packageJSONUrl) => {
|
|
234
|
+
const pkgPath = fileURLToPath(new URL('.', packageJSONUrl))
|
|
235
|
+
throw codedError('ERR_PACKAGE_PATH_NOT_EXPORTED',
|
|
236
|
+
subpath === '.'
|
|
237
|
+
? `No "exports" main defined in ${pkgPath}package.json`
|
|
238
|
+
: `Package subpath '${subpath}' is not defined by "exports" in ${pkgPath}package.json`)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const packageExportsResolve = (packageJSONUrl, packageSubpath, packageConfig, conditions) => {
|
|
242
|
+
let exports = packageConfig.exports
|
|
243
|
+
if (isConditionalExportsMainSugar(exports, fileURLToPath(packageJSONUrl))) exports = { '.': exports }
|
|
244
|
+
let resolved
|
|
245
|
+
if (Object.hasOwn(exports, packageSubpath) && !packageSubpath.includes('*') && !packageSubpath.endsWith('/')) {
|
|
246
|
+
resolved = resolvePackageTarget(packageJSONUrl, exports[packageSubpath], '', packageSubpath, false, false, conditions)
|
|
247
|
+
} else {
|
|
248
|
+
const match = bestPatternMatch(exports, packageSubpath)
|
|
249
|
+
if (match) resolved = resolvePackageTarget(packageJSONUrl, exports[match[0]], match[1], match[0], true, false, conditions)
|
|
250
|
+
}
|
|
251
|
+
if (resolved == null) throwExportsNotFound(packageSubpath, packageJSONUrl)
|
|
252
|
+
return resolved
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const packageImportsResolve = (name, base, conditions) => {
|
|
256
|
+
// (`#/x` is merely "not defined" in Node 24, so it is not screened here.)
|
|
257
|
+
if (name === '#' || name.endsWith('/')) {
|
|
258
|
+
throw codedError('ERR_INVALID_MODULE_SPECIFIER', `Invalid module "${name}" is not a valid internal imports specifier name imported from ${fileURLToPath(base)}`)
|
|
259
|
+
}
|
|
260
|
+
const packageConfig = readPackageScope(fileURLToPath(base))
|
|
261
|
+
const packageJSONUrl = packageConfig ? pathToFileURL(packageConfig.path) : undefined
|
|
262
|
+
const imports = packageConfig?.imports
|
|
263
|
+
if (imports) {
|
|
264
|
+
let resolved
|
|
265
|
+
if (Object.hasOwn(imports, name) && !name.includes('*')) {
|
|
266
|
+
resolved = resolvePackageTarget(packageJSONUrl, imports[name], '', name, false, true, conditions)
|
|
267
|
+
} else {
|
|
268
|
+
const match = bestPatternMatch(imports, name)
|
|
269
|
+
if (match) resolved = resolvePackageTarget(packageJSONUrl, imports[match[0]], match[1], match[0], true, true, conditions)
|
|
270
|
+
}
|
|
271
|
+
if (resolved != null) return resolved
|
|
272
|
+
}
|
|
273
|
+
throw codedError('ERR_PACKAGE_IMPORT_NOT_DEFINED',
|
|
274
|
+
`Package import specifier "${name}" is not defined${packageJSONUrl ? ` in package ${fileURLToPath(packageJSONUrl)}` : ''} imported from ${fileURLToPath(base)}`)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const legacyMainResolve = (packageJSONUrl, packageConfig, base) => {
|
|
278
|
+
let guess
|
|
279
|
+
if (packageConfig.main !== undefined) {
|
|
280
|
+
for (const suffix of ['', '.js', '.json', '.node', '/index.js', '/index.json', '/index.node']) {
|
|
281
|
+
if (fileExists(guess = new URL(`./${packageConfig.main}${suffix}`, packageJSONUrl))) return guess
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
for (const index of ['./index.js', './index.json', './index.node']) {
|
|
285
|
+
if (fileExists(guess = new URL(index, packageJSONUrl))) return guess
|
|
286
|
+
}
|
|
287
|
+
throw codedError('ERR_MODULE_NOT_FOUND', `Cannot find package '${fileURLToPath(new URL('.', packageJSONUrl))}' imported from ${fileURLToPath(base)}`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ESM-style bare resolution, reached only through a bare `imports` target (`"#x": "dep"`).
|
|
291
|
+
const packageResolve = (specifier, base, conditions) => {
|
|
292
|
+
if (isBuiltin(specifier)) return new URL(`node:${specifier}`)
|
|
293
|
+
const { packageName, packageSubpath, isScoped } = parsePackageName(specifier, base)
|
|
294
|
+
const scope = readPackageScope(fileURLToPath(base))
|
|
295
|
+
if (scope && scope.exports != null && scope.name === packageName) {
|
|
296
|
+
return packageExportsResolve(pathToFileURL(scope.path), packageSubpath, scope, conditions)
|
|
297
|
+
}
|
|
298
|
+
let packageJSONUrl = new URL(`./node_modules/${packageName}/package.json`, base)
|
|
299
|
+
let packageJSONPath = fileURLToPath(packageJSONUrl)
|
|
300
|
+
let lastPath
|
|
301
|
+
do {
|
|
302
|
+
if (stat(packageJSONPath.slice(0, -'/package.json'.length)) !== 1) {
|
|
303
|
+
lastPath = packageJSONPath
|
|
304
|
+
packageJSONUrl = new URL(`${isScoped ? '../../../../node_modules/' : '../../../node_modules/'}${packageName}/package.json`, packageJSONUrl)
|
|
305
|
+
packageJSONPath = fileURLToPath(packageJSONUrl)
|
|
306
|
+
continue
|
|
307
|
+
}
|
|
308
|
+
const packageConfig = readPackage(packageJSONPath)
|
|
309
|
+
if (packageConfig.exports != null) return packageExportsResolve(packageJSONUrl, packageSubpath, packageConfig, conditions)
|
|
310
|
+
if (packageSubpath === '.') return legacyMainResolve(packageJSONUrl, packageConfig, base)
|
|
311
|
+
return new URL(packageSubpath, packageJSONUrl)
|
|
312
|
+
} while (packageJSONPath.length !== lastPath.length)
|
|
313
|
+
throw codedError('ERR_MODULE_NOT_FOUND', `Cannot find package '${packageName}' imported from ${fileURLToPath(base)}`)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// --- cjs/loader.js glue ---
|
|
317
|
+
|
|
318
|
+
const createEsmNotFoundErr = (request, path) => Object.assign(codedError('MODULE_NOT_FOUND', `Cannot find module '${request}'`), path ? { path } : {})
|
|
319
|
+
|
|
320
|
+
// An esm/resolve.js answer under CJS rules (finalizeEsmResolution): it must be a file URL to a
|
|
321
|
+
// file that exists, and an ESM "not found" becomes MODULE_NOT_FOUND naming `request`.
|
|
322
|
+
const viaEsm = (resolveUrl, request, errPath, parentPath, pkgDir) => {
|
|
323
|
+
let resolved
|
|
324
|
+
try {
|
|
325
|
+
resolved = resolveUrl()
|
|
326
|
+
} catch (e) {
|
|
327
|
+
if (e.code === 'ERR_MODULE_NOT_FOUND') throw createEsmNotFoundErr(request, errPath)
|
|
328
|
+
throw e
|
|
329
|
+
}
|
|
330
|
+
if (resolved.protocol === 'node:') throw codedError('ERR_INVALID_URL_SCHEME', 'The URL must be of scheme file')
|
|
331
|
+
if (encodedSepRegEx.test(resolved.href)) {
|
|
332
|
+
throw codedError('ERR_INVALID_MODULE_SPECIFIER', `Invalid module "${resolved.href}" must not include encoded "/" or "\\" characters imported from ${parentPath}`)
|
|
333
|
+
}
|
|
334
|
+
const filename = fileURLToPath(resolved)
|
|
335
|
+
const actual = tryFile(filename)
|
|
336
|
+
if (actual) return actual
|
|
337
|
+
throw createEsmNotFoundErr(filename, resolve(pkgDir, 'package.json'))
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Self-reference: a request naming the enclosing package, through its `exports`.
|
|
341
|
+
const trySelf = (parentPath, request, conditions) => {
|
|
342
|
+
const pkg = readPackageScope(parentPath)
|
|
343
|
+
if (!pkg || pkg.exports == null || pkg.name === undefined) return false
|
|
344
|
+
let expansion
|
|
345
|
+
if (request === pkg.name) expansion = '.'
|
|
346
|
+
else if (request.startsWith(`${pkg.name}/`)) expansion = `.${request.slice(pkg.name.length)}`
|
|
347
|
+
else return false
|
|
348
|
+
return viaEsm(() => packageExportsResolve(pathToFileURL(pkg.path), expansion, pkg, conditions), request, pkg.path, parentPath, dirname(pkg.path))
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// A bare request into `nmPath` whose package has `exports`.
|
|
352
|
+
const resolveExports = (nmPath, request, conditions) => {
|
|
353
|
+
const m = EXPORTS_PATTERN.exec(request)
|
|
354
|
+
if (!m) return false
|
|
355
|
+
const [, name, expansion = ''] = m
|
|
356
|
+
const pkgPath = resolve(nmPath, name)
|
|
357
|
+
const pkg = readPackage(`${pkgPath}/package.json`)
|
|
358
|
+
if (!pkg.exists || pkg.exports == null) return false
|
|
359
|
+
return viaEsm(() => packageExportsResolve(pathToFileURL(pkg.path), `.${expansion}`, pkg, conditions), request, pkg.path, null, pkgPath)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Module._findPath over `paths`.
|
|
363
|
+
const findPath = (request, paths, conditions) => {
|
|
364
|
+
const absoluteRequest = isAbsolute(request)
|
|
365
|
+
if (absoluteRequest) paths = ['']
|
|
366
|
+
else if (!paths || paths.length === 0) return false
|
|
367
|
+
const trailingSlash = TRAILING_SLASH.test(request)
|
|
368
|
+
const insidePath = !(RELATIVE_REQUEST.test(request) && normalize(request).startsWith('..'))
|
|
369
|
+
const exts = Object.keys(Module._extensions)
|
|
370
|
+
for (const curPath of paths) {
|
|
371
|
+
if (insidePath && curPath && stat(curPath) < 1) continue
|
|
372
|
+
if (!absoluteRequest) {
|
|
373
|
+
const exportsResolved = resolveExports(curPath, request, conditions)
|
|
374
|
+
if (exportsResolved) return exportsResolved
|
|
375
|
+
}
|
|
376
|
+
const basePath = resolve(curPath, request)
|
|
377
|
+
const rc = stat(basePath)
|
|
378
|
+
let filename = false
|
|
379
|
+
if (!trailingSlash) filename = (rc === 0 && host.realpath(basePath)) || tryExtensions(basePath, exts)
|
|
380
|
+
if (!filename && rc === 1) filename = tryPackage(basePath, exts, request)
|
|
381
|
+
if (filename) return filename
|
|
382
|
+
}
|
|
383
|
+
return false
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const notFound = (request, parentFile) => Object.assign(codedError('MODULE_NOT_FOUND', `Cannot find module '${request}'\nRequire stack:\n- ${parentFile}`), { requireStack: [parentFile] })
|
|
387
|
+
|
|
388
|
+
// Module._resolveFilename: -> the file's real path, or a builtin's id.
|
|
389
|
+
const resolveFilename = (parentFile, request, conditions) => {
|
|
390
|
+
if (isBuiltin(request)) return request
|
|
391
|
+
if (request === '') throw notFound(request, parentFile)
|
|
392
|
+
if (request[0] === '#') {
|
|
393
|
+
const pkg = readPackageScope(parentFile)
|
|
394
|
+
if (pkg?.imports != null) return viaEsm(() => packageImportsResolve(request, pathToFileURL(parentFile), conditions), request, undefined, parentFile, dirname(pkg.path))
|
|
395
|
+
}
|
|
396
|
+
const paths = RELATIVE_LOOKUP.test(request) ? [dirname(parentFile)] : Module._nodeModulePaths(dirname(parentFile))
|
|
397
|
+
const hit = trySelf(parentFile, request, conditions) || findPath(request, paths, conditions)
|
|
398
|
+
if (hit) return hit
|
|
399
|
+
throw notFound(request, parentFile)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Node's Module._pathCache: the tree is immutable for the build.
|
|
403
|
+
const memo = new Map()
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
// `conditions`: `require.resolve`'s own by default. A builtin returns its id, as it does.
|
|
407
|
+
resolve(parentFile, request, conditions = REQUIRE_CONDITIONS) {
|
|
408
|
+
parentFile = resolve(parentFile)
|
|
409
|
+
if (!(conditions instanceof Set)) conditions = new Set(conditions)
|
|
410
|
+
const key = `${dirname(parentFile)}\0${request}\0${[...conditions].join(',')}`
|
|
411
|
+
let hit = memo.get(key)
|
|
412
|
+
if (hit === undefined) memo.set(key, hit = resolveFilename(parentFile, request, conditions))
|
|
413
|
+
return hit
|
|
414
|
+
},
|
|
415
|
+
}
|
|
416
|
+
}
|