@@ -33,6 +33,7 @@ const {
3333 Stats,
3434} = require('fs');
3535const { getOptionValue } = require('internal/options');
36+ const pendingDeprecation = getOptionValue('--pending-deprecation');
3637// Do not eagerly grab .manifest, it may be in TDZ
3738const policy = getOptionValue('--experimental-policy') ?
3839 require('internal/process/policy') :
@@ -98,6 +99,23 @@ function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
9899 );
99100}
100101
102+ const doubleSlashRegEx = /[/\\][/\\]/;
103+
104+ function emitInvalidSegmentDeprecation(target, request, match, pjsonUrl, base) {
105+ if (!pendingDeprecation) { return; }
106+ const pjsonPath = fileURLToPath(pjsonUrl);
107+ const double = RegExpPrototypeExec(doubleSlashRegEx, target) !== null;
108+ process.emitWarning(
109+ `Use of deprecated ${double ? 'double slash' :
110+ 'leading or trailing slash matching'} resolving "${target}" for module ` +
111+ `request "${request}" ${request !== match ? `matched to "${match}" ` : ''
112+ }in the "exports" field module resolution of the package at ${pjsonPath}${
113+ base ? ` imported from ${fileURLToPath(base)}` : ''}.`,
114+ 'DeprecationWarning',
115+ 'DEP0166'
116+ );
117+ }
118+
101119/**
102120 * @param {URL} url
103121 * @param {URL} packageJSONUrl
@@ -344,15 +362,17 @@ function throwExportsNotFound(subpath, packageJSONUrl, base) {
344362
345363/**
346364 *
347- * @param {string | URL} subpath
365+ * @param {string} request
366+ * @param {string} match
348367 * @param {URL} packageJSONUrl
349368 * @param {boolean} internal
350369 * @param {string | URL | undefined} base
351370 */
352- function throwInvalidSubpath(subpath, packageJSONUrl, internal, base) {
353- const reason = `request is not a valid subpath for the "${internal ?
354- 'imports' : 'exports'}" resolution of ${fileURLToPath(packageJSONUrl)}`;
355- throw new ERR_INVALID_MODULE_SPECIFIER(subpath, reason,
371+ function throwInvalidSubpath(request, match, packageJSONUrl, internal, base) {
372+ const reason = `request is not a valid match in pattern "${match}" for the "${
373+ internal ? 'imports' : 'exports'}" resolution of ${
374+ fileURLToPath(packageJSONUrl)}`;
375+ throw new ERR_INVALID_MODULE_SPECIFIER(request, reason,
356376 base && fileURLToPath(base));
357377}
358378
@@ -368,12 +388,22 @@ function throwInvalidPackageTarget(
368388 internal, base && fileURLToPath(base));
369389}
370390
371- const invalidSegmentRegEx = /(^|\\|\/)((\.|%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))(\\|\/|$)/i;
391+ const invalidSegmentRegEx = /(^|\\|\/)((\.|%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))?(\\|\/|$)/i;
392+ 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))(\\|\/|$)/i;
372393const invalidPackageNameRegEx = /^\.|%|\\/;
373394const patternRegEx = /\*/g;
374395
375396function resolvePackageTargetString(
376- target, subpath, match, packageJSONUrl, base, pattern, internal, conditions) {
397+ target,
398+ subpath,
399+ match,
400+ packageJSONUrl,
401+ base,
402+ pattern,
403+ internal,
404+ isPathMap,
405+ conditions,
406+ ) {
377407
378408 if (subpath !== '' && !pattern && target[target.length - 1] !== '/')
379409 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
@@ -399,8 +429,21 @@ function resolvePackageTargetString(
399429 throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
400430 }
401431
402- if (RegExpPrototypeExec(invalidSegmentRegEx, StringPrototypeSlice(target, 2)) !== null)
403- throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
432+ if (RegExpPrototypeExec(invalidSegmentRegEx, StringPrototypeSlice(target, 2)) !== null) {
433+ if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, StringPrototypeSlice(target, 2)) === null) {
434+ if (!isPathMap) {
435+ const request = pattern ?
436+ StringPrototypeReplace(match, '*', () => subpath) :
437+ match + subpath;
438+ const resolvedTarget = pattern ?
439+ RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) :
440+ target;
441+ emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, base);
442+ }
443+ } else {
444+ throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base);
445+ }
446+ }
404447
405448 const resolved = new URL(target, packageJSONUrl);
406449 const resolvedPath = resolved.pathname;
@@ -412,18 +455,22 @@ function resolvePackageTargetString(
412455 if (subpath === '') return resolved;
413456
414457 if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) {
415- const request = pattern ?
416- StringPrototypeReplace(match, '*', () => subpath) : match + subpath;
417- throwInvalidSubpath(request, packageJSONUrl, internal, base);
458+ const request = pattern ? StringPrototypeReplace(match, '*', () => subpath) : match + subpath;
459+ if (RegExpPrototypeExec(deprecatedInvalidSegmentRegEx, subpath) === null) {
460+ if (!isPathMap) {
461+ const resolvedTarget = pattern ?
462+ RegExpPrototypeSymbolReplace(patternRegEx, target, () => subpath) :
463+ target;
464+ emitInvalidSegmentDeprecation(resolvedTarget, request, match, packageJSONUrl, base);
465+ }
466+ } else {
467+ throwInvalidSubpath(request, match, packageJSONUrl, internal, base);
468+ }
418469 }
419470
420471 if (pattern) {
421472 return new URL(
422- RegExpPrototypeSymbolReplace(
423- patternRegEx,
424- resolved.href,
425- () => subpath
426- )
473+ RegExpPrototypeSymbolReplace(patternRegEx, resolved.href, () => subpath)
427474 );
428475 }
429476
@@ -441,11 +488,11 @@ function isArrayIndex(key) {
441488}
442489
443490function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
444- base, pattern, internal, conditions) {
491+ base, pattern, internal, isPathMap, conditions) {
445492 if (typeof target === 'string') {
446493 return resolvePackageTargetString(
447494 target, subpath, packageSubpath, packageJSONUrl, base, pattern, internal,
448- conditions);
495+ isPathMap, conditions);
449496 } else if (ArrayIsArray(target)) {
450497 if (target.length === 0) {
451498 return null;
@@ -458,7 +505,7 @@ function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
458505 try {
459506 resolveResult = resolvePackageTarget(
460507 packageJSONUrl, targetItem, subpath, packageSubpath, base, pattern,
461- internal, conditions);
508+ internal, isPathMap, conditions);
462509 } catch (e) {
463510 lastException = e;
464511 if (e.code === 'ERR_INVALID_PACKAGE_TARGET') {
@@ -494,7 +541,7 @@ function resolvePackageTarget(packageJSONUrl, target, subpath, packageSubpath,
494541 const conditionalTarget = target[key];
495542 const resolveResult = resolvePackageTarget(
496543 packageJSONUrl, conditionalTarget, subpath, packageSubpath, base,
497- pattern, internal, conditions);
544+ pattern, internal, isPathMap, conditions);
498545 if (resolveResult === undefined)
499546 continue;
500547 return resolveResult;
@@ -557,7 +604,8 @@ function packageExportsResolve(
557604 !StringPrototypeEndsWith(packageSubpath, '/')) {
558605 const target = exports[packageSubpath];
559606 const resolveResult = resolvePackageTarget(
560- packageJSONUrl, target, '', packageSubpath, base, false, false, conditions
607+ packageJSONUrl, target, '', packageSubpath, base, false, false, false,
608+ conditions
561609 );
562610
563611 if (resolveResult == null) {
@@ -608,6 +656,7 @@ function packageExportsResolve(
608656 base,
609657 true,
610658 false,
659+ StringPrototypeEndsWith(packageSubpath, '/'),
611660 conditions);
612661
613662 if (resolveResult == null) {
@@ -654,7 +703,8 @@ function packageImportsResolve(name, base, conditions) {
654703 if (ObjectPrototypeHasOwnProperty(imports, name) &&
655704 !StringPrototypeIncludes(name, '*')) {
656705 const resolveResult = resolvePackageTarget(
657- packageJSONUrl, imports[name], '', name, base, false, true, conditions
706+ packageJSONUrl, imports[name], '', name, base, false, true, false,
707+ conditions
658708 );
659709 if (resolveResult != null) {
660710 return resolveResult;
@@ -687,7 +737,7 @@ function packageImportsResolve(name, base, conditions) {
687737 const resolveResult = resolvePackageTarget(packageJSONUrl, target,
688738 bestMatchSubpath,
689739 bestMatch, base, true,
690- true, conditions);
740+ true, false, conditions);
691741 if (resolveResult != null) {
692742 return resolveResult;
693743 }
0 commit comments