@exodus/stasis 1.0.0-beta.3 → 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.
@@ -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
+ }