| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1175,25 +1175,36 @@ The resolver can throw the following errors: | |||
| 1175 | 1175 | **PACKAGE_IMPORTS_EXPORTS_RESOLVE**(_matchKey_, _matchObj_, _packageURL_, | |
| 1176 | 1176 | _isImports_, _conditions_) | |
| 1177 | 1177 | ||
| 1178 | - > 1. If _matchKey_ is a key of _matchObj_, and does not end in _"*"_, then | ||
| 1178 | + > 1. If _matchKey_ is a key of _matchObj_ and does not end in _"/"_ or contain | ||
| 1179 | + > _"*"_, then | ||
| 1179 | 1180 | > 1. Let _target_ be the value of _matchObj_\[_matchKey_\]. | |
| 1180 | 1181 | > 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( | |
| 1181 | 1182 | > _packageURL_, _target_, _""_, **false**, _isImports_, _conditions_). | |
| 1182 | 1183 | > 1. Return the object _{ resolved, exact: **true** }_. | |
| 1183 | - > 1. Let _expansionKeys_ be the list of keys of _matchObj_ ending in _"/"_ | ||
| 1184 | - > or _"*"_, sorted by length descending. | ||
| 1184 | + > 1. Let _expansionKeys_ be the list of keys of _matchObj_ either ending in | ||
| 1185 | + > _"/"_ or containing only a single _"*"_, sorted by the sorting function | ||
| 1186 | + > **PATTERN_KEY_COMPARE** which orders in descending order of specificity. | ||
| 1185 | 1187 | > 1. For each key _expansionKey_ in _expansionKeys_, do | |
| 1186 | - > 1. If _expansionKey_ ends in _"*"_ and _matchKey_ starts with but is | ||
| 1187 | - > not equal to the substring of _expansionKey_ excluding the last _"*"_ | ||
| 1188 | - > character, then | ||
| 1189 | - > 1. Let _target_ be the value of _matchObj_\[_expansionKey_\]. | ||
| 1190 | - > 1. Let _subpath_ be the substring of _matchKey_ starting at the | ||
| 1191 | - > index of the length of _expansionKey_ minus one. | ||
| 1192 | - > 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( | ||
| 1193 | - > _packageURL_, _target_, _subpath_, **true**, _isImports_, | ||
| 1194 | - > _conditions_). | ||
| 1195 | - > 1. Return the object _{ resolved, exact: **true** }_. | ||
| 1196 | - > 1. If _matchKey_ starts with _expansionKey_, then | ||
| 1188 | + > 1. Let _patternBase_ be **null**. | ||
| 1189 | + > 1. If _expansionKey_ contains _"*"_, set _patternBase_ to the substring of | ||
| 1190 | + > _expansionKey_ up to but excluding the first _"*"_ character. | ||
| 1191 | + > 1. If _patternBase_ is not **null** and _matchKey_ starts with but is not | ||
| 1192 | + > equal to _patternBase_, then | ||
| 1193 | + > 1. Let _patternTrailer_ be the substring of _expansionKey_ from the | ||
| 1194 | + > index after the first _"*"_ character. | ||
| 1195 | + > 1. If _patternTrailer_ has zero length, or if _matchKey_ ends with | ||
| 1196 | + > _patternTrailer_ and the length of _matchKey_ is greater than or | ||
| 1197 | + > equal to the length of _expansionKey_, then | ||
| 1198 | + > 1. Let _target_ be the value of _matchObj_\[_expansionKey_\]. | ||
| 1199 | + > 1. Let _subpath_ be the substring of _matchKey_ starting at the | ||
| 1200 | + > index of the length of _patternBase_ up to the length of | ||
| 1201 | + > _matchKey_ minus the length of _patternTrailer_. | ||
| 1202 | + > 1. Let _resolved_ be the result of **PACKAGE_TARGET_RESOLVE**( | ||
| 1203 | + > _packageURL_, _target_, _subpath_, **true**, _isImports_, | ||
| 1204 | + > _conditions_). | ||
| 1205 | + > 1. Return the object _{ resolved, exact: **true** }_. | ||
| 1206 | + > 1. Otherwise if _patternBase_ is **null** and _matchKey_ starts with | ||
| 1207 | + > _expansionKey_, then | ||
| 1197 | 1208 | > 1. Let _target_ be the value of _matchObj_\[_expansionKey_\]. | |
| 1198 | 1209 | > 1. Let _subpath_ be the substring of _matchKey_ starting at the | |
| 1199 | 1210 | > index of the length of _expansionKey_. | |
@@ -1203,6 +1214,22 @@ _isImports_, _conditions_) | |||
| 1203 | 1214 | > 1. Return the object _{ resolved, exact: **false** }_. | |
| 1204 | 1215 | > 1. Return the object _{ resolved: **null**, exact: **true** }_. | |
| 1205 | 1216 | ||
| 1217 | + **PATTERN_KEY_COMPARE**(_keyA_, _keyB_) | ||
| 1218 | + | ||
| 1219 | + > 1. Assert: _keyA_ ends with _"/"_ or contains only a single _"*"_. | ||
| 1220 | + > 1. Assert: _keyB_ ends with _"/"_ or contains only a single _"*"_. | ||
| 1221 | + > 1. Let _baseLengthA_ be the index of _"*"_ in _keyA_ plus one, if _keyA_ | ||
| 1222 | + > contains _"*"_, or the length of _keyA_ otherwise. | ||
| 1223 | + > 1. Let _baseLengthB_ be the index of _"*"_ in _keyB_ plus one, if _keyB_ | ||
| 1224 | + > contains _"*"_, or the length of _keyB_ otherwise. | ||
| 1225 | + > 1. If _baseLengthA_ is greater than _baseLengthB_, return -1. | ||
| 1226 | + > 1. If _baseLengthB_ is greater than _baseLengthA_, return 1. | ||
| 1227 | + > 1. If _keyA_ does not contain _"*"_, return 1. | ||
| 1228 | + > 1. If _keyB_ does not contain _"*"_, return -1. | ||
| 1229 | + > 1. If the length of _keyA_ is greater than the length of _keyB_, return -1. | ||
| 1230 | + > 1. If the length of _keyB_ is greater than the length of _keyA_, return 1. | ||
| 1231 | + > 1. Return 0. | ||
| 1232 | + | ||
| 1206 | 1233 | **PACKAGE_TARGET_RESOLVE**(_packageURL_, _target_, _subpath_, _pattern_, | |
| 1207 | 1234 | _internal_, _conditions_) | |
| 1208 | 1235 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -376,9 +376,8 @@ For these use cases, subpath export patterns can be used instead: | |||
| 376 | 376 | **`*` maps expose nested subpaths as it is a string replacement syntax | |
| 377 | 377 | only.** | |
| 378 | 378 | ||
| 379 | - The left hand matching pattern must always end in `*`. All instances of `*` on | ||
| 380 | - the right hand side will then be replaced with this value, including if it | ||
| 381 | - contains any `/` separators. | ||
| 379 | + All instances of `*` on the right hand side will then be replaced with this | ||
| 380 | + value, including if it contains any `/` separators. | ||
| 382 | 381 | ||
| 383 | 382 | ```js | |
| 384 | 383 | import featureX from 'es-module-package/features/x'; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,7 +15,9 @@ const { | |||
| 15 | 15 | SafeSet, | |
| 16 | 16 | String, | |
| 17 | 17 | StringPrototypeEndsWith, | |
| 18 | + StringPrototypeIncludes, | ||
| 18 | 19 | StringPrototypeIndexOf, | |
| 20 | + StringPrototypeLastIndexOf, | ||
| 19 | 21 | StringPrototypeReplace, | |
| 20 | 22 | StringPrototypeSlice, | |
| 21 | 23 | StringPrototypeSplit, | |
@@ -114,7 +116,7 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) { | |||
| 114 | 116 | `Package ${pkgPath} has a "main" field set to ${JSONStringify(main)}, ` + | |
| 115 | 117 | `excluding the full filename and extension to the resolved file at "${ | |
| 116 | 118 | StringPrototypeSlice(path, pkgPath.length)}", imported from ${ | |
| 117 | - basePath}.\n Automatic extension resolution of the "main" field is` + | ||
| 119 | + basePath}.\n Automatic extension resolution of the "main" field is ` + | ||
| 118 | 120 | 'deprecated for ES modules.', | |
| 119 | 121 | 'DeprecationWarning', | |
| 120 | 122 | 'DEP0151' | |
@@ -607,7 +609,9 @@ function packageExportsResolve( | |||
| 607 | 609 | if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) | |
| 608 | 610 | exports = { '.': exports }; | |
| 609 | 611 | ||
| 610 | - if (ObjectPrototypeHasOwnProperty(exports, packageSubpath)) { | ||
| 612 | + if (ObjectPrototypeHasOwnProperty(exports, packageSubpath) && | ||
| 613 | + !StringPrototypeIncludes(packageSubpath, '*') && | ||
| 614 | + !StringPrototypeEndsWith(packageSubpath, '/')) { | ||
| 611 | 615 | const target = exports[packageSubpath]; | |
| 612 | 616 | const resolved = resolvePackageTarget( | |
| 613 | 617 | packageJSONUrl, target, '', packageSubpath, base, false, false, conditions | |
@@ -618,30 +622,38 @@ function packageExportsResolve( | |||
| 618 | 622 | } | |
| 619 | 623 | ||
| 620 | 624 | let bestMatch = ''; | |
| 625 | + let bestMatchSubpath; | ||
| 621 | 626 | const keys = ObjectGetOwnPropertyNames(exports); | |
| 622 | 627 | for (let i = 0; i < keys.length; i++) { | |
| 623 | 628 | const key = keys[i]; | |
| 624 | - if (key[key.length - 1] === '*' && | ||
| 629 | + const patternIndex = StringPrototypeIndexOf(key, '*'); | ||
| 630 | + if (patternIndex !== -1 && | ||
| 625 | 631 | StringPrototypeStartsWith(packageSubpath, | |
| 626 | - StringPrototypeSlice(key, 0, -1)) && | ||
| 627 | - packageSubpath.length >= key.length && | ||
| 628 | - key.length > bestMatch.length) { | ||
| 629 | - bestMatch = key; | ||
| 632 | + StringPrototypeSlice(key, 0, patternIndex))) { | ||
| 633 | + const patternTrailer = StringPrototypeSlice(key, patternIndex + 1); | ||
| 634 | + if (packageSubpath.length >= key.length && | ||
| 635 | + StringPrototypeEndsWith(packageSubpath, patternTrailer) && | ||
| 636 | + patternKeyCompare(bestMatch, key) === 1 && | ||
| 637 | + StringPrototypeLastIndexOf(key, '*') === patternIndex) { | ||
| 638 | + bestMatch = key; | ||
| 639 | + bestMatchSubpath = StringPrototypeSlice( | ||
| 640 | + packageSubpath, patternIndex, | ||
| 641 | + packageSubpath.length - patternTrailer.length); | ||
| 642 | + } | ||
| 630 | 643 | } else if (key[key.length - 1] === '/' && | |
| 631 | 644 | StringPrototypeStartsWith(packageSubpath, key) && | |
| 632 | - key.length > bestMatch.length) { | ||
| 645 | + patternKeyCompare(bestMatch, key) === 1) { | ||
| 633 | 646 | bestMatch = key; | |
| 647 | + bestMatchSubpath = StringPrototypeSlice(packageSubpath, key.length); | ||
| 634 | 648 | } | |
| 635 | 649 | } | |
| 636 | 650 | ||
| 637 | 651 | if (bestMatch) { | |
| 638 | 652 | const target = exports[bestMatch]; | |
| 639 | - const pattern = bestMatch[bestMatch.length - 1] === '*'; | ||
| 640 | - const subpath = StringPrototypeSubstr(packageSubpath, bestMatch.length - | ||
| 641 | - (pattern ? 1 : 0)); | ||
| 642 | - const resolved = resolvePackageTarget(packageJSONUrl, target, subpath, | ||
| 643 | - bestMatch, base, pattern, false, | ||
| 644 | - conditions); | ||
| 653 | + const pattern = StringPrototypeIncludes(bestMatch, '*'); | ||
| 654 | + const resolved = resolvePackageTarget(packageJSONUrl, target, | ||
| 655 | + bestMatchSubpath, bestMatch, base, | ||
| 656 | + pattern, false, conditions); | ||
| 645 | 657 | if (resolved === null || resolved === undefined) | |
| 646 | 658 | throwExportsNotFound(packageSubpath, packageJSONUrl, base); | |
| 647 | 659 | if (!pattern) | |
@@ -652,6 +664,20 @@ function packageExportsResolve( | |||
| 652 | 664 | throwExportsNotFound(packageSubpath, packageJSONUrl, base); | |
| 653 | 665 | } | |
| 654 | 666 | ||
| 667 | + function patternKeyCompare(a, b) { | ||
| 668 | + const aPatternIndex = StringPrototypeIndexOf(a, '*'); | ||
| 669 | + const bPatternIndex = StringPrototypeIndexOf(b, '*'); | ||
| 670 | + const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; | ||
| 671 | + const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; | ||
| 672 | + if (baseLenA > baseLenB) return -1; | ||
| 673 | + if (baseLenB > baseLenA) return 1; | ||
| 674 | + if (aPatternIndex === -1) return 1; | ||
| 675 | + if (bPatternIndex === -1) return -1; | ||
| 676 | + if (a.length > b.length) return -1; | ||
| 677 | + if (b.length > a.length) return 1; | ||
| 678 | + return 0; | ||
| 679 | + } | ||
| 680 | + | ||
| 655 | 681 | /** | |
| 656 | 682 | * @param {string} name | |
| 657 | 683 | * @param {string | URL | undefined} base | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,7 +35,12 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js'; | |||
| 35 | 35 | ['pkgexports-sugar', { default: 'main' }], | |
| 36 | 36 | // Path patterns | |
| 37 | 37 | ['pkgexports/subpath/sub-dir1', { default: 'main' }], | |
| 38 | + ['pkgexports/subpath/sub-dir1.js', { default: 'main' }], | ||
| 38 | 39 | ['pkgexports/features/dir1', { default: 'main' }], | |
| 40 | + ['pkgexports/dir1/dir1/trailer', { default: 'main' }], | ||
| 41 | + ['pkgexports/dir2/dir2/trailer', { default: 'index' }], | ||
| 42 | + ['pkgexports/a/dir1/dir1', { default: 'main' }], | ||
| 43 | + ['pkgexports/a/b/dir1/dir1', { default: 'main' }], | ||
| 39 | 44 | ]); | |
| 40 | 45 | ||
| 41 | 46 | if (isRequire) { | |
@@ -77,6 +82,8 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js'; | |||
| 77 | 82 | ['pkgexports/null/subpath', './null/subpath'], | |
| 78 | 83 | // Empty fallback | |
| 79 | 84 | ['pkgexports/nofallback1', './nofallback1'], | |
| 85 | + // Non pattern matches | ||
| 86 | + ['pkgexports/trailer', './trailer'], | ||
| 80 | 87 | ]); | |
| 81 | 88 | ||
| 82 | 89 | const invalidExports = new Map([ | |
@@ -147,6 +154,8 @@ import fromInside from '../fixtures/node_modules/pkgexports/lib/hole.js'; | |||
| 147 | 154 | ['pkgexports/sub/not-a-file.js', `pkgexports${sep}not-a-file.js`], | |
| 148 | 155 | // No extension lookups | |
| 149 | 156 | ['pkgexports/no-ext', `pkgexports${sep}asdf`], | |
| 157 | + // Pattern specificity | ||
| 158 | + ['pkgexports/dir2/trailer', `subpath${sep}dir2.js`], | ||
| 150 | 159 | ]); | |
| 151 | 160 | ||
| 152 | 161 | if (!isRequire) { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments