| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -217,6 +217,88 @@ added: v22.8.0 | |||
| 217 | 217 | * Returns: {string|undefined} Path to the [module compile cache][] directory if it is enabled, | |
| 218 | 218 | or `undefined` otherwise. | |
| 219 | 219 | ||
| 220 | + ### `module.findPackageJSON(specifier[, base])` | ||
| 221 | + | ||
| 222 | + <!-- YAML | ||
| 223 | + added: REPLACEME | ||
| 224 | + --> | ||
| 225 | + | ||
| 226 | + > Stability: 1.1 - Active Development | ||
| 227 | + | ||
| 228 | + * `specifier` {string|URL} The specifier for the module whose `package.json` to | ||
| 229 | + retrieve. When passing a _bare specifier_, the `package.json` at the root of | ||
| 230 | + the package is returned. When passing a _relative specifier_ or an _absolute specifier_, | ||
| 231 | + the closest parent `package.json` is returned. | ||
| 232 | + * `base` {string|URL} The absolute location (`file:` URL string or FS path) of the | ||
| 233 | + containing module. For CJS, use `__filename` (not `__dirname`!); for ESM, use | ||
| 234 | + `import.meta.url`. You do not need to pass it if `specifier` is an `absolute specifier`. | ||
| 235 | + * Returns: {string|undefined} A path if the `package.json` is found. When `startLocation` | ||
| 236 | + is a package, the package's root `package.json`; when a relative or unresolved, the closest | ||
| 237 | + `package.json` to the `startLocation`. | ||
| 238 | + | ||
| 239 | + > **Caveat**: Do not use this to try to determine module format. There are many things effecting | ||
| 240 | + > that determination; the `type` field of package.json is the _least_ definitive (ex file extension | ||
| 241 | + > superceeds it, and a loader hook superceeds that). | ||
| 242 | + | ||
| 243 | + ```text | ||
| 244 | + /path/to/project | ||
| 245 | + ├ packages/ | ||
| 246 | + ├ bar/ | ||
| 247 | + ├ bar.js | ||
| 248 | + └ package.json // name = '@foo/bar' | ||
| 249 | + └ qux/ | ||
| 250 | + ├ node_modules/ | ||
| 251 | + └ some-package/ | ||
| 252 | + └ package.json // name = 'some-package' | ||
| 253 | + ├ qux.js | ||
| 254 | + └ package.json // name = '@foo/qux' | ||
| 255 | + ├ main.js | ||
| 256 | + └ package.json // name = '@foo' | ||
| 257 | + ``` | ||
| 258 | + | ||
| 259 | + ```mjs | ||
| 260 | + // /path/to/project/packages/bar/bar.js | ||
| 261 | + import { findPackageJSON } from 'node:module'; | ||
| 262 | + | ||
| 263 | + findPackageJSON('..', import.meta.url); | ||
| 264 | + // '/path/to/project/package.json' | ||
| 265 | + // Same result when passing an absolute specifier instead: | ||
| 266 | + findPackageJSON(new URL('../', import.meta.url)); | ||
| 267 | + findPackageJSON(import.meta.resolve('../')); | ||
| 268 | + | ||
| 269 | + findPackageJSON('some-package', import.meta.url); | ||
| 270 | + // '/path/to/project/packages/bar/node_modules/some-package/package.json' | ||
| 271 | + // When passing an absolute specifier, you might get a different result if the | ||
| 272 | + // resolved module is inside a subfolder that has nested `package.json`. | ||
| 273 | + findPackageJSON(import.meta.resolve('some-package')); | ||
| 274 | + // '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json' | ||
| 275 | + | ||
| 276 | + findPackageJSON('@foo/qux', import.meta.url); | ||
| 277 | + // '/path/to/project/packages/qux/package.json' | ||
| 278 | + ``` | ||
| 279 | + | ||
| 280 | + ```cjs | ||
| 281 | + // /path/to/project/packages/bar/bar.js | ||
| 282 | + const { findPackageJSON } = require('node:module'); | ||
| 283 | + const { pathToFileURL } = require('node:url'); | ||
| 284 | + const path = require('node:path'); | ||
| 285 | + | ||
| 286 | + findPackageJSON('..', __filename); | ||
| 287 | + // '/path/to/project/package.json' | ||
| 288 | + // Same result when passing an absolute specifier instead: | ||
| 289 | + findPackageJSON(pathToFileURL(path.join(__dirname, '..'))); | ||
| 290 | + | ||
| 291 | + findPackageJSON('some-package', __filename); | ||
| 292 | + // '/path/to/project/packages/bar/node_modules/some-package/package.json' | ||
| 293 | + // When passing an absolute specifier, you might get a different result if the | ||
| 294 | + // resolved module is inside a subfolder that has nested `package.json`. | ||
| 295 | + findPackageJSON(pathToFileURL(require.resolve('some-package'))); | ||
| 296 | + // '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json' | ||
| 297 | + | ||
| 298 | + findPackageJSON('@foo/qux', __filename); | ||
| 299 | + // '/path/to/project/packages/qux/package.json' | ||
| 300 | + ``` | ||
| 301 | + | ||
| 220 | 302 | ### `module.isBuiltin(moduleName)` | |
| 221 | 303 | ||
| 222 | 304 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -603,11 +603,11 @@ function trySelf(parentPath, request) { | |||
| 603 | 603 | try { | |
| 604 | 604 | const { packageExportsResolve } = require('internal/modules/esm/resolve'); | |
| 605 | 605 | return finalizeEsmResolution(packageExportsResolve( | |
| 606 | - pathToFileURL(pkg.path + '/package.json'), expansion, pkg.data, | ||
| 606 | + pathToFileURL(pkg.path), expansion, pkg.data, | ||
| 607 | 607 | pathToFileURL(parentPath), getCjsConditions()), parentPath, pkg.path); | |
| 608 | 608 | } catch (e) { | |
| 609 | 609 | if (e.code === 'ERR_MODULE_NOT_FOUND') { | |
| 610 | - throw createEsmNotFoundErr(request, pkg.path + '/package.json'); | ||
| 610 | + throw createEsmNotFoundErr(request, pkg.path); | ||
| 611 | 611 | } | |
| 612 | 612 | throw e; | |
| 613 | 613 | } | |
@@ -1184,14 +1184,15 @@ Module._resolveFilename = function(request, parent, isMain, options) { | |||
| 1184 | 1184 | ||
| 1185 | 1185 | if (request[0] === '#' && (parent?.filename || parent?.id === '<repl>')) { | |
| 1186 | 1186 | const parentPath = parent?.filename ?? process.cwd() + path.sep; | |
| 1187 | - const pkg = packageJsonReader.getNearestParentPackageJSON(parentPath) || { __proto__: null }; | ||
| 1188 | - if (pkg.data?.imports != null) { | ||
| 1187 | + const pkg = packageJsonReader.getNearestParentPackageJSON(parentPath); | ||
| 1188 | + if (pkg?.data.imports != null) { | ||
| 1189 | 1189 | try { | |
| 1190 | 1190 | const { packageImportsResolve } = require('internal/modules/esm/resolve'); | |
| 1191 | 1191 | return finalizeEsmResolution( | |
| 1192 | - packageImportsResolve(request, pathToFileURL(parentPath), | ||
| 1193 | - getCjsConditions()), parentPath, | ||
| 1194 | - pkg.path); | ||
| 1192 | + packageImportsResolve(request, pathToFileURL(parentPath), getCjsConditions()), | ||
| 1193 | + parentPath, | ||
| 1194 | + pkg.path, | ||
| 1195 | + ); | ||
| 1195 | 1196 | } catch (e) { | |
| 1196 | 1197 | if (e.code === 'ERR_MODULE_NOT_FOUND') { | |
| 1197 | 1198 | throw createEsmNotFoundErr(request); | |
@@ -1251,8 +1252,7 @@ function finalizeEsmResolution(resolved, parentPath, pkgPath) { | |||
| 1251 | 1252 | if (actual) { | |
| 1252 | 1253 | return actual; | |
| 1253 | 1254 | } | |
| 1254 | - const err = createEsmNotFoundErr(filename, | ||
| 1255 | - path.resolve(pkgPath, 'package.json')); | ||
| 1255 | + const err = createEsmNotFoundErr(filename, pkgPath); | ||
| 1256 | 1256 | throw err; | |
| 1257 | 1257 | } | |
| 1258 | 1258 | ||
@@ -1598,7 +1598,7 @@ function loadTS(module, filename) { | |||
| 1598 | 1598 | ||
| 1599 | 1599 | const parent = module[kModuleParent]; | |
| 1600 | 1600 | const parentPath = parent?.filename; | |
| 1601 | - const packageJsonPath = path.resolve(pkg.path, 'package.json'); | ||
| 1601 | + const packageJsonPath = pkg.path; | ||
| 1602 | 1602 | const usesEsm = containsModuleSyntax(content, filename); | |
| 1603 | 1603 | const err = new ERR_REQUIRE_ESM(filename, usesEsm, parentPath, | |
| 1604 | 1604 | packageJsonPath); | |
@@ -1657,7 +1657,7 @@ Module._extensions['.js'] = function(module, filename) { | |||
| 1657 | 1657 | // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed. | |
| 1658 | 1658 | const parent = module[kModuleParent]; | |
| 1659 | 1659 | const parentPath = parent?.filename; | |
| 1660 | - const packageJsonPath = path.resolve(pkg.path, 'package.json'); | ||
| 1660 | + const packageJsonPath = pkg.path; | ||
| 1661 | 1661 | const usesEsm = containsModuleSyntax(content, filename); | |
| 1662 | 1662 | const err = new ERR_REQUIRE_ESM(filename, usesEsm, parentPath, | |
| 1663 | 1663 | packageJsonPath); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -356,7 +356,6 @@ function invalidPackageTarget( | |||
| 356 | 356 | ||
| 357 | 357 | 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; | |
| 358 | 358 | 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; | |
| 359 | - const invalidPackageNameRegEx = /^\.|%|\\/; | ||
| 360 | 359 | const patternRegEx = /\*/g; | |
| 361 | 360 | ||
| 362 | 361 | /** | |
@@ -752,44 +751,6 @@ function packageImportsResolve(name, base, conditions) { | |||
| 752 | 751 | throw importNotDefined(name, packageJSONUrl, base); | |
| 753 | 752 | } | |
| 754 | 753 | ||
| 755 | - /** | ||
| 756 | - * Parse a package name from a specifier. | ||
| 757 | - * @param {string} specifier - The import specifier. | ||
| 758 | - * @param {string | URL | undefined} base - The parent URL. | ||
| 759 | - */ | ||
| 760 | - function parsePackageName(specifier, base) { | ||
| 761 | - let separatorIndex = StringPrototypeIndexOf(specifier, '/'); | ||
| 762 | - let validPackageName = true; | ||
| 763 | - let isScoped = false; | ||
| 764 | - if (specifier[0] === '@') { | ||
| 765 | - isScoped = true; | ||
| 766 | - if (separatorIndex === -1 || specifier.length === 0) { | ||
| 767 | - validPackageName = false; | ||
| 768 | - } else { | ||
| 769 | - separatorIndex = StringPrototypeIndexOf( | ||
| 770 | - specifier, '/', separatorIndex + 1); | ||
| 771 | - } | ||
| 772 | - } | ||
| 773 | - | ||
| 774 | - const packageName = separatorIndex === -1 ? | ||
| 775 | - specifier : StringPrototypeSlice(specifier, 0, separatorIndex); | ||
| 776 | - | ||
| 777 | - // Package name cannot have leading . and cannot have percent-encoding or | ||
| 778 | - // \\ separators. | ||
| 779 | - if (RegExpPrototypeExec(invalidPackageNameRegEx, packageName) !== null) { | ||
| 780 | - validPackageName = false; | ||
| 781 | - } | ||
| 782 | - | ||
| 783 | - if (!validPackageName) { | ||
| 784 | - throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| 785 | - specifier, 'is not a valid package name', fileURLToPath(base)); | ||
| 786 | - } | ||
| 787 | - | ||
| 788 | - const packageSubpath = '.' + (separatorIndex === -1 ? '' : | ||
| 789 | - StringPrototypeSlice(specifier, separatorIndex)); | ||
| 790 | - | ||
| 791 | - return { packageName, packageSubpath, isScoped }; | ||
| 792 | - } | ||
| 793 | 754 | ||
| 794 | 755 | /** | |
| 795 | 756 | * Resolves a package specifier to a URL. | |
@@ -804,57 +765,24 @@ function packageResolve(specifier, base, conditions) { | |||
| 804 | 765 | return new URL('node:' + specifier); | |
| 805 | 766 | } | |
| 806 | 767 | ||
| 807 | - const { packageName, packageSubpath, isScoped } = | ||
| 808 | - parsePackageName(specifier, base); | ||
| 768 | + const { packageJSONUrl, packageJSONPath, packageSubpath } = packageJsonReader.getPackageJSONURL(specifier, base); | ||
| 809 | 769 | ||
| 810 | - // ResolveSelf | ||
| 811 | - const packageConfig = packageJsonReader.getPackageScopeConfig(base); | ||
| 812 | - if (packageConfig.exists) { | ||
| 813 | - if (packageConfig.exports != null && packageConfig.name === packageName) { | ||
| 814 | - const packageJSONUrl = pathToFileURL(packageConfig.pjsonPath); | ||
| 815 | - return packageExportsResolve( | ||
| 816 | - packageJSONUrl, packageSubpath, packageConfig, base, conditions); | ||
| 817 | - } | ||
| 818 | - } | ||
| 770 | + const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true }); | ||
| 819 | 771 | ||
| 820 | - let packageJSONUrl = | ||
| 821 | - new URL('./node_modules/' + packageName + '/package.json', base); | ||
| 822 | - let packageJSONPath = fileURLToPath(packageJSONUrl); | ||
| 823 | - let lastPath; | ||
| 824 | - do { | ||
| 825 | - const stat = internalFsBinding.internalModuleStat( | ||
| 826 | - internalFsBinding, | ||
| 827 | - StringPrototypeSlice(packageJSONPath, 0, packageJSONPath.length - 13), | ||
| 772 | + // Package match. | ||
| 773 | + if (packageConfig.exports != null) { | ||
| 774 | + return packageExportsResolve( | ||
| 775 | + packageJSONUrl, packageSubpath, packageConfig, base, conditions); | ||
| 776 | + } | ||
| 777 | + if (packageSubpath === '.') { | ||
| 778 | + return legacyMainResolve( | ||
| 779 | + packageJSONUrl, | ||
| 780 | + packageConfig, | ||
| 781 | + base, | ||
| 828 | 782 | ); | |
| 829 | - // Check for !stat.isDirectory() | ||
| 830 | - if (stat !== 1) { | ||
| 831 | - lastPath = packageJSONPath; | ||
| 832 | - packageJSONUrl = new URL((isScoped ? | ||
| 833 | - '../../../../node_modules/' : '../../../node_modules/') + | ||
| 834 | - packageName + '/package.json', packageJSONUrl); | ||
| 835 | - packageJSONPath = fileURLToPath(packageJSONUrl); | ||
| 836 | - continue; | ||
| 837 | - } | ||
| 838 | - | ||
| 839 | - // Package match. | ||
| 840 | - const packageConfig = packageJsonReader.read(packageJSONPath, { __proto__: null, specifier, base, isESM: true }); | ||
| 841 | - if (packageConfig.exports != null) { | ||
| 842 | - return packageExportsResolve( | ||
| 843 | - packageJSONUrl, packageSubpath, packageConfig, base, conditions); | ||
| 844 | - } | ||
| 845 | - if (packageSubpath === '.') { | ||
| 846 | - return legacyMainResolve( | ||
| 847 | - packageJSONUrl, | ||
| 848 | - packageConfig, | ||
| 849 | - base, | ||
| 850 | - ); | ||
| 851 | - } | ||
| 852 | - | ||
| 853 | - return new URL(packageSubpath, packageJSONUrl); | ||
| 854 | - // Cross-platform root check. | ||
| 855 | - } while (packageJSONPath.length !== lastPath.length); | ||
| 783 | + } | ||
| 856 | 784 | ||
| 857 | - throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null); | ||
| 785 | + return new URL(packageSubpath, packageJSONUrl); | ||
| 858 | 786 | } | |
| 859 | 787 | ||
| 860 | 788 | /** | |
@@ -1105,10 +1033,11 @@ module.exports = { | |||
| 1105 | 1033 | decorateErrorWithCommonJSHints, | |
| 1106 | 1034 | defaultResolve, | |
| 1107 | 1035 | encodedSepRegEx, | |
| 1036 | + legacyMainResolve, | ||
| 1108 | 1037 | packageExportsResolve, | |
| 1109 | 1038 | packageImportsResolve, | |
| 1039 | + packageResolve, | ||
| 1110 | 1040 | throwIfInvalidParentURL, | |
| 1111 | - legacyMainResolve, | ||
| 1112 | 1041 | }; | |
| 1113 | 1042 | ||
| 1114 | 1043 | // cycle | |
| Back | FazBrowse Home | New Git URL |
0 commit comments