@@ -14,9 +14,11 @@ const {
1414 Module,
1515 resolveForCJSWithHooks,
1616 clearCJSResolutionCaches,
17+ deleteCJSRelativeResolveCacheEntry,
1718} = require ( 'internal/modules/cjs/loader' ) ;
19+ const { getFilePathFromFileURL } = require ( 'internal/modules/helpers' ) ;
1820const { fileURLToPath, isURL, URLParse, pathToFileURL } = require ( 'internal/url' ) ;
19- const { emitExperimentalWarning, kEmptyObject , isWindows } = require ( 'internal/util' ) ;
21+ const { emitExperimentalWarning, isWindows } = require ( 'internal/util' ) ;
2022const { validateObject, validateOneOf, validateString } = require ( 'internal/validators' ) ;
2123const {
2224 codes : {
@@ -75,29 +77,18 @@ function createParentModuleForClearCache(parentPath) {
7577/**
7678 * Resolve a cache filename for CommonJS.
7779 * Always goes through resolveForCJSWithHooks so that registered hooks
78- * are respected. CJS operates on file paths and bare specifiers. file:
79- * URL objects or strings are converted to paths; non-file URLs are not
80- * supported and will return null .
80+ * are respected. The specifier is passed as-is: if hooks are registered,
81+ * they handle any URL interpretation; if not, it is treated as a plain
82+ * path/identifier (matching how require() interprets its argument) .
8183 * @param {string|URL } specifier
8284 * @param {string|undefined } parentPath
8385 * @returns {string|null }
8486 */
8587function resolveClearCacheFilename ( specifier , parentPath ) {
86- let request ;
87- if ( isURL ( specifier ) ) {
88- if ( specifier . protocol !== 'file:' ) {
89- return null ;
90- }
91- request = fileURLToPath ( specifier ) ;
92- } else if ( typeof specifier === 'string' && StringPrototypeStartsWith ( specifier , 'file:' ) ) {
93- const parsed = URLParse ( specifier ) ;
94- if ( ! parsed || parsed . protocol !== 'file:' ) {
95- return null ;
96- }
97- request = fileURLToPath ( parsed ) ;
98- } else {
99- request = specifier ;
100- }
88+ // Pass the specifier through as-is. When hooks are registered they
89+ // receive the raw value; without hooks CJS resolution treats it as
90+ // a plain path or bare name, consistent with how require() behaves.
91+ const request = isURL ( specifier ) ? specifier . href : specifier ;
10192
10293 if ( ! parentPath && isRelative ( request ) ) {
10394 return null ;
@@ -164,29 +155,6 @@ function deleteModuleFromParents(targetModule) {
164155 return deleted ;
165156}
166157
167- /**
168- * Resolve a file path for a file URL, stripping search/hash.
169- * @param {string } url
170- * @returns {string|null }
171- */
172- function getFilePathFromClearCacheURL ( url ) {
173- const parsedURL = URLParse ( url ) ;
174- if ( parsedURL ?. protocol !== 'file:' ) {
175- return null ;
176- }
177-
178- if ( parsedURL . search !== '' || parsedURL . hash !== '' ) {
179- parsedURL . search = '' ;
180- parsedURL . hash = '' ;
181- }
182-
183- try {
184- return fileURLToPath ( parsedURL ) ;
185- } catch {
186- return null ;
187- }
188- }
189-
190158/**
191159 * Remove load cache entries for a URL and its file-path variants.
192160 * @param {import('internal/modules/esm/module_map').LoadCache } loadCache
@@ -195,7 +163,7 @@ function getFilePathFromClearCacheURL(url) {
195163 */
196164function deleteLoadCacheEntries ( loadCache , url ) {
197165 let deleted = loadCache . deleteAll ( url ) ;
198- const filename = getFilePathFromClearCacheURL ( url ) ;
166+ const filename = getFilePathFromFileURL ( url ) ;
199167 if ( ! filename ) {
200168 return deleted ;
201169 }
@@ -210,7 +178,7 @@ function deleteLoadCacheEntries(loadCache, url) {
210178 if ( cachedURL === url ) {
211179 continue ;
212180 }
213- const cachedFilename = getFilePathFromClearCacheURL ( cachedURL ) ;
181+ const cachedFilename = getFilePathFromFileURL ( cachedURL ) ;
214182 if ( cachedFilename === filename ) {
215183 loadCache . deleteAll ( cachedURL ) ;
216184 deleted = true ;
@@ -240,7 +208,6 @@ function isRelative(pathToCheck) {
240208 * @param {string|URL } specifier What would've been passed into import() or require().
241209 * @param {{
242210 * parentURL: string|URL,
243- * importAttributes?: Record<string, string>,
244211 * resolver: 'import'|'require',
245212 * caches: 'resolution'|'module'|'all',
246213 * }} options
@@ -260,11 +227,6 @@ function clearCache(specifier, options) {
260227 validateOneOf ( resolver , 'options.resolver' , [ 'import' , 'require' ] ) ;
261228 validateOneOf ( caches , 'options.caches' , [ 'resolution' , 'module' , 'all' ] ) ;
262229
263- const importAttributes = options . importAttributes ?? kEmptyObject ;
264- if ( options . importAttributes !== undefined ) {
265- validateObject ( options . importAttributes , 'options.importAttributes' ) ;
266- }
267-
268230 const clearResolution = caches === 'resolution' || caches === 'all' ;
269231 const clearModule = caches === 'module' || caches === 'all' ;
270232
@@ -283,38 +245,40 @@ function clearCache(specifier, options) {
283245 } else {
284246 resolvedURL = resolveClearCacheURL ( specifier , parentURL ) ;
285247 if ( resolvedURL ) {
286- resolvedFilename = getFilePathFromClearCacheURL ( resolvedURL ) ;
248+ resolvedFilename = getFilePathFromFileURL ( resolvedURL ) ;
287249 }
288250 }
289251 }
290252
291253 // Clear resolution caches.
292254 if ( clearResolution ) {
293255 // ESM has a structured resolution cache keyed by (specifier, parentURL,
294- // importAttributes).
256+ // importAttributes). Clear all attribute variants for the given
257+ // (specifier, parentURL) pair since attributes don't affect resolution
258+ // per spec and it avoids partial-clear surprises.
295259 if ( resolver === 'import' ) {
296260 const specifierStr = isSpecifierURL ? specifier . href : specifier ;
297261 const cascadedLoader =
298262 require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ;
299- cascadedLoader . deleteResolveCacheEntry ( specifierStr , parentURL , importAttributes ) ;
263+ cascadedLoader . deleteAllResolveCacheEntries ( specifierStr , parentURL ) ;
300264 }
301265
302- // CJS has relativeResolveCache and Module._pathCache that map
303- // specifiers to filenames. Clear all entries pointing to the resolved
304- // file. Module._pathCache keys are not easily reconstructable so a
305- // value-scan is required.
306- if ( resolver === 'require' && resolvedFilename ) {
307- clearCJSResolutionCaches ( resolvedFilename ) ;
308- }
266+ // CJS resolution caches are only relevant when the resolver is 'require'.
267+ if ( resolver === 'require' && parentPath ) {
268+ // Delete the specific relativeResolveCache entry for this
269+ // (parent-dir, request) pair. More targeted than a full value-scan.
270+ const requestStr = isSpecifierURL ? specifier . href : specifier ;
271+ deleteCJSRelativeResolveCacheEntry ( path . dirname ( parentPath ) , requestStr ) ;
309272
310- if ( resolvedFilename ) {
311273 // Clear package.json caches for the resolved module's package so that
312274 // updated exports/imports conditions are picked up on re-resolution.
313- const { getNearestParentPackageJSON, clearPackageJSONCache } =
314- require ( 'internal/modules/package_json_reader' ) ;
315- const pkg = getNearestParentPackageJSON ( resolvedFilename ) ;
316- if ( pkg ?. path ) {
317- clearPackageJSONCache ( pkg . path ) ;
275+ if ( resolvedFilename ) {
276+ const { getNearestParentPackageJSON, clearPackageJSONCache } =
277+ require ( 'internal/modules/package_json_reader' ) ;
278+ const pkg = getNearestParentPackageJSON ( resolvedFilename ) ;
279+ if ( pkg ?. path ) {
280+ clearPackageJSONCache ( pkg . path ) ;
281+ }
318282 }
319283 }
320284 }
0 commit comments