| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e08c008 commit df86793
12 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -196,6 +196,14 @@ added: v11.8.0 | |||
| 196 | 196 | ||
| 197 | 197 | Enable experimental diagnostic report feature. | |
| 198 | 198 | ||
| 199 | + ### `--experimental-resolve-self` | ||
| 200 | + <!-- YAML | ||
| 201 | + added: REPLACEME | ||
| 202 | + --> | ||
| 203 | + | ||
| 204 | + Enable experimental support for a package using `require` or `import` to load | ||
| 205 | + itself. | ||
| 206 | + | ||
| 199 | 207 | ### `--experimental-vm-modules` | |
| 200 | 208 | <!-- YAML | |
| 201 | 209 | added: v9.6.0 | |
@@ -1053,6 +1061,7 @@ Node.js options that are allowed are: | |||
| 1053 | 1061 | * `--experimental-policy` | |
| 1054 | 1062 | * `--experimental-repl-await` | |
| 1055 | 1063 | * `--experimental-report` | |
| 1064 | + * `--experimental-resolve-self` | ||
| 1056 | 1065 | * `--experimental-vm-modules` | |
| 1057 | 1066 | * `--experimental-wasm-modules` | |
| 1058 | 1067 | * `--force-context-aware` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -838,9 +838,6 @@ _isMain_ is **true** when resolving the Node.js application entry point. | |||
| 838 | 838 | > 1. Let _packageSubpath_ be *undefined*. | |
| 839 | 839 | > 1. If _packageSpecifier_ is an empty string, then | |
| 840 | 840 | > 1. Throw an _Invalid Specifier_ error. | |
| 841 | - > 1. If _packageSpecifier_ does not start with _"@"_, then | ||
| 842 | - > 1. Set _packageName_ to the substring of _packageSpecifier_ until the | ||
| 843 | - > first _"/"_ separator or the end of the string. | ||
| 844 | 841 | > 1. Otherwise, | |
| 845 | 842 | > 1. If _packageSpecifier_ does not contain a _"/"_ separator, then | |
| 846 | 843 | > 1. Throw an _Invalid Specifier_ error. | |
@@ -854,7 +851,7 @@ _isMain_ is **true** when resolving the Node.js application entry point. | |||
| 854 | 851 | > 1. Set _packageSubpath_ to _"."_ concatenated with the substring of | |
| 855 | 852 | > _packageSpecifier_ from the position at the length of _packageName_. | |
| 856 | 853 | > 1. If _packageSubpath_ contains any _"."_ or _".."_ segments or percent | |
| 857 | - > encoded strings for _"/"_ or _"\\"_ then, | ||
| 854 | + > encoded strings for _"/"_ or _"\\"_, then | ||
| 858 | 855 | > 1. Throw an _Invalid Specifier_ error. | |
| 859 | 856 | > 1. If _packageSubpath_ is _undefined_ and _packageName_ is a Node.js builtin | |
| 860 | 857 | > module, then | |
@@ -877,8 +874,31 @@ _isMain_ is **true** when resolving the Node.js application entry point. | |||
| 877 | 874 | > 1. Return **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, | |
| 878 | 875 | > _packageSubpath_, _pjson.exports_). | |
| 879 | 876 | > 1. Return the URL resolution of _packageSubpath_ in _packageURL_. | |
| 877 | + > 1. Set _selfUrl_ to the result of | ||
| 878 | + > **SELF_REFERENCE_RESOLE**(_packageSpecifier_, _parentURL_). | ||
| 879 | + > 1. If _selfUrl_ isn't empty, return _selfUrl_. | ||
| 880 | 880 | > 1. Throw a _Module Not Found_ error. | |
| 881 | 881 | ||
| 882 | + **SELF_REFERENCE_RESOLVE**(_specifier_, _parentURL_) | ||
| 883 | + | ||
| 884 | + > 1. Let _packageURL_ be the result of **READ_PACKAGE_SCOPE**(_parentURL_). | ||
| 885 | + > 1. If _packageURL_ is **null**, then | ||
| 886 | + > 1. Return an empty result. | ||
| 887 | + > 1. Let _pjson_ be the result of **READ_PACKAGE_JSON**(_packageURL_). | ||
| 888 | + > 1. Set _name_ to _pjson.name_. | ||
| 889 | + > 1. If _name_ is empty, then return an empty result. | ||
| 890 | + > 1. If _name_ is equal to _specifier_, then | ||
| 891 | + > 1. Return the result of **PACKAGE_MAIN_RESOLVE**(_packageURL_, _pjson_). | ||
| 892 | + > 1. If _specifier_ starts with _name_ followed by "/", then | ||
| 893 | + > 1. Set _subpath_ to everything after the "/". | ||
| 894 | + > 1. If _pjson_ is not **null** and _pjson_ has an _"exports"_ key, then | ||
| 895 | + > 1. Let _exports_ be _pjson.exports_. | ||
| 896 | + > 1. If _exports_ is not **null** or **undefined**, then | ||
| 897 | + > 1. Return **PACKAGE_EXPORTS_RESOLVE**(_packageURL_, _subpath_, | ||
| 898 | + > _pjson.exports_). | ||
| 899 | + > 1. Return the URL resolution of _subpath_ in _packageURL_. | ||
| 900 | + > 1. Otherwise return an empty result. | ||
| 901 | + | ||
| 882 | 902 | **PACKAGE_MAIN_RESOLVE**(_packageURL_, _pjson_) | |
| 883 | 903 | ||
| 884 | 904 | > 1. If _pjson_ is **null**, then | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -160,8 +160,9 @@ require(X) from module at path Y | |||
| 160 | 160 | a. LOAD_AS_FILE(Y + X) | |
| 161 | 161 | b. LOAD_AS_DIRECTORY(Y + X) | |
| 162 | 162 | c. THROW "not found" | |
| 163 | - 4. LOAD_NODE_MODULES(X, dirname(Y)) | ||
| 164 | - 5. THROW "not found" | ||
| 163 | + 5. LOAD_NODE_MODULES(X, dirname(Y)) | ||
| 164 | + 4. LOAD_SELF_REFERENCE(X, dirname(Y)) | ||
| 165 | + 6. THROW "not found" | ||
| 165 | 166 | ||
| 166 | 167 | LOAD_AS_FILE(X) | |
| 167 | 168 | 1. If X is a file, load X as JavaScript text. STOP | |
@@ -201,6 +202,13 @@ NODE_MODULES_PATHS(START) | |||
| 201 | 202 | c. DIRS = DIRS + DIR | |
| 202 | 203 | d. let I = I - 1 | |
| 203 | 204 | 5. return DIRS | |
| 205 | + | ||
| 206 | + LOAD_SELF_REFERENCE(X, START) | ||
| 207 | + 1. Find the closest package scope to START. | ||
| 208 | + 2. If no scope was found, throw "not found". | ||
| 209 | + 3. If the name in `package.json` isn't a prefix of X, throw "not found". | ||
| 210 | + 4. Otherwise, resolve the remainder of X relative to this package as if it | ||
| 211 | + was loaded via `LOAD_NODE_MODULES` with a name in `package.json`. | ||
| 204 | 212 | ``` | |
| 205 | 213 | ||
| 206 | 214 | Node.js allows packages loaded via | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -59,6 +59,7 @@ const enableSourceMaps = getOptionValue('--enable-source-maps'); | |||
| 59 | 59 | const preserveSymlinks = getOptionValue('--preserve-symlinks'); | |
| 60 | 60 | const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main'); | |
| 61 | 61 | const experimentalModules = getOptionValue('--experimental-modules'); | |
| 62 | + const experimentalSelf = getOptionValue('--experimental-resolve-self'); | ||
| 62 | 63 | const manifest = getOptionValue('--experimental-policy') ? | |
| 63 | 64 | require('internal/process/policy').manifest : | |
| 64 | 65 | null; | |
@@ -237,6 +238,7 @@ function readPackage(requestPath) { | |||
| 237 | 238 | try { | |
| 238 | 239 | const parsed = JSON.parse(json); | |
| 239 | 240 | const filtered = { | |
| 241 | + name: parsed.name, | ||
| 240 | 242 | main: parsed.main, | |
| 241 | 243 | exports: parsed.exports, | |
| 242 | 244 | type: parsed.type | |
@@ -366,6 +368,125 @@ function findLongestRegisteredExtension(filename) { | |||
| 366 | 368 | return '.js'; | |
| 367 | 369 | } | |
| 368 | 370 | ||
| 371 | + function resolveBasePath(basePath, exts, isMain, trailingSlash, request) { | ||
| 372 | + let filename; | ||
| 373 | + | ||
| 374 | + const rc = stat(basePath); | ||
| 375 | + if (!trailingSlash) { | ||
| 376 | + if (rc === 0) { // File. | ||
| 377 | + if (!isMain) { | ||
| 378 | + if (preserveSymlinks) { | ||
| 379 | + filename = path.resolve(basePath); | ||
| 380 | + } else { | ||
| 381 | + filename = toRealPath(basePath); | ||
| 382 | + } | ||
| 383 | + } else if (preserveSymlinksMain) { | ||
| 384 | + // For the main module, we use the preserveSymlinksMain flag instead | ||
| 385 | + // mainly for backward compatibility, as the preserveSymlinks flag | ||
| 386 | + // historically has not applied to the main module. Most likely this | ||
| 387 | + // was intended to keep .bin/ binaries working, as following those | ||
| 388 | + // symlinks is usually required for the imports in the corresponding | ||
| 389 | + // files to resolve; that said, in some use cases following symlinks | ||
| 390 | + // causes bigger problems which is why the preserveSymlinksMain option | ||
| 391 | + // is needed. | ||
| 392 | + filename = path.resolve(basePath); | ||
| 393 | + } else { | ||
| 394 | + filename = toRealPath(basePath); | ||
| 395 | + } | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + if (!filename) { | ||
| 399 | + // Try it with each of the extensions | ||
| 400 | + if (exts === undefined) | ||
| 401 | + exts = Object.keys(Module._extensions); | ||
| 402 | + filename = tryExtensions(basePath, exts, isMain); | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + if (!filename && rc === 1) { // Directory. | ||
| 407 | + // try it with each of the extensions at "index" | ||
| 408 | + if (exts === undefined) | ||
| 409 | + exts = Object.keys(Module._extensions); | ||
| 410 | + filename = tryPackage(basePath, exts, isMain, request); | ||
| 411 | + } | ||
| 412 | + | ||
| 413 | + return filename; | ||
| 414 | + } | ||
| 415 | + | ||
| 416 | + function trySelf(paths, exts, isMain, trailingSlash, request) { | ||
| 417 | + if (!experimentalSelf) { | ||
| 418 | + return false; | ||
| 419 | + } | ||
| 420 | + | ||
| 421 | + const { data: pkg, path: basePath } = readPackageScope(paths[0]); | ||
| 422 | + if (!pkg) return false; | ||
| 423 | + if (typeof pkg.name !== 'string') return false; | ||
| 424 | + | ||
| 425 | + let expansion; | ||
| 426 | + if (request === pkg.name) { | ||
| 427 | + expansion = ''; | ||
| 428 | + } else if (StringPrototype.startsWith(request, `${pkg.name}/`)) { | ||
| 429 | + expansion = StringPrototype.slice(request, pkg.name.length); | ||
| 430 | + } else { | ||
| 431 | + return false; | ||
| 432 | + } | ||
| 433 | + | ||
| 434 | + if (exts === undefined) | ||
| 435 | + exts = Object.keys(Module._extensions); | ||
| 436 | + | ||
| 437 | + if (expansion) { | ||
| 438 | + // Use exports | ||
| 439 | + const fromExports = applyExports(basePath, expansion); | ||
| 440 | + if (!fromExports) return false; | ||
| 441 | + return resolveBasePath(fromExports, exts, isMain, trailingSlash, request); | ||
| 442 | + } else { | ||
| 443 | + // Use main field | ||
| 444 | + return tryPackage(basePath, exts, isMain, request); | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + function applyExports(basePath, expansion) { | ||
| 449 | + const pkgExports = readPackageExports(basePath); | ||
| 450 | + const mappingKey = `.${expansion}`; | ||
| 451 | + | ||
| 452 | + if (typeof pkgExports === 'object' && pkgExports !== null) { | ||
| 453 | + if (ObjectPrototype.hasOwnProperty(pkgExports, mappingKey)) { | ||
| 454 | + const mapping = pkgExports[mappingKey]; | ||
| 455 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '', | ||
| 456 | + basePath, mappingKey); | ||
| 457 | + } | ||
| 458 | + | ||
| 459 | + let dirMatch = ''; | ||
| 460 | + for (const candidateKey of Object.keys(pkgExports)) { | ||
| 461 | + if (candidateKey[candidateKey.length - 1] !== '/') continue; | ||
| 462 | + if (candidateKey.length > dirMatch.length && | ||
| 463 | + StringPrototype.startsWith(mappingKey, candidateKey)) { | ||
| 464 | + dirMatch = candidateKey; | ||
| 465 | + } | ||
| 466 | + } | ||
| 467 | + | ||
| 468 | + if (dirMatch !== '') { | ||
| 469 | + const mapping = pkgExports[dirMatch]; | ||
| 470 | + const subpath = StringPrototype.slice(mappingKey, dirMatch.length); | ||
| 471 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, | ||
| 472 | + subpath, basePath, mappingKey); | ||
| 473 | + } | ||
| 474 | + } | ||
| 475 | + if (mappingKey === '.' && typeof pkgExports === 'string') { | ||
| 476 | + return resolveExportsTarget(pathToFileURL(basePath + '/'), pkgExports, | ||
| 477 | + '', basePath, mappingKey); | ||
| 478 | + } | ||
| 479 | + if (pkgExports != null) { | ||
| 480 | + // eslint-disable-next-line no-restricted-syntax | ||
| 481 | + const e = new Error(`Package exports for '${basePath}' do not define ` + | ||
| 482 | + `a '${mappingKey}' subpath`); | ||
| 483 | + e.code = 'MODULE_NOT_FOUND'; | ||
| 484 | + throw e; | ||
| 485 | + } | ||
| 486 | + | ||
| 487 | + return path.resolve(basePath, mappingKey); | ||
| 488 | + } | ||
| 489 | + | ||
| 369 | 490 | // This only applies to requests of a specific form: | |
| 370 | 491 | // 1. name/.* | |
| 371 | 492 | // 2. @scope/name/.* | |
@@ -380,43 +501,7 @@ function resolveExports(nmPath, request, absoluteRequest) { | |||
| 380 | 501 | } | |
| 381 | 502 | ||
| 382 | 503 | const basePath = path.resolve(nmPath, name); | |
| 383 | - const pkgExports = readPackageExports(basePath); | ||
| 384 | - const mappingKey = `.${expansion}`; | ||
| 385 | - | ||
| 386 | - if (typeof pkgExports === 'object' && pkgExports !== null) { | ||
| 387 | - if (ObjectPrototype.hasOwnProperty(pkgExports, mappingKey)) { | ||
| 388 | - const mapping = pkgExports[mappingKey]; | ||
| 389 | - return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, '', | ||
| 390 | - basePath, mappingKey); | ||
| 391 | - } | ||
| 392 | - | ||
| 393 | - let dirMatch = ''; | ||
| 394 | - for (const candidateKey of Object.keys(pkgExports)) { | ||
| 395 | - if (candidateKey[candidateKey.length - 1] !== '/') continue; | ||
| 396 | - if (candidateKey.length > dirMatch.length && | ||
| 397 | - StringPrototype.startsWith(mappingKey, candidateKey)) { | ||
| 398 | - dirMatch = candidateKey; | ||
| 399 | - } | ||
| 400 | - } | ||
| 401 | - | ||
| 402 | - if (dirMatch !== '') { | ||
| 403 | - const mapping = pkgExports[dirMatch]; | ||
| 404 | - const subpath = StringPrototype.slice(mappingKey, dirMatch.length); | ||
| 405 | - return resolveExportsTarget(pathToFileURL(basePath + '/'), mapping, | ||
| 406 | - subpath, basePath, mappingKey); | ||
| 407 | - } | ||
| 408 | - } | ||
| 409 | - if (mappingKey === '.' && typeof pkgExports === 'string') { | ||
| 410 | - return resolveExportsTarget(pathToFileURL(basePath + '/'), pkgExports, | ||
| 411 | - '', basePath, mappingKey); | ||
| 412 | - } | ||
| 413 | - if (pkgExports != null) { | ||
| 414 | - // eslint-disable-next-line no-restricted-syntax | ||
| 415 | - const e = new Error(`Package exports for '${basePath}' do not define ` + | ||
| 416 | - `a '${mappingKey}' subpath`); | ||
| 417 | - e.code = 'MODULE_NOT_FOUND'; | ||
| 418 | - throw e; | ||
| 419 | - } | ||
| 504 | + return applyExports(basePath, expansion); | ||
| 420 | 505 | } | |
| 421 | 506 | ||
| 422 | 507 | return path.resolve(nmPath, request); | |
@@ -532,6 +617,13 @@ Module._findPath = function(request, paths, isMain) { | |||
| 532 | 617 | return filename; | |
| 533 | 618 | } | |
| 534 | 619 | } | |
| 620 | + | ||
| 621 | + const selfFilename = trySelf(paths, exts, isMain, trailingSlash, request); | ||
| 622 | + if (selfFilename) { | ||
| 623 | + Module._pathCache[cacheKey] = selfFilename; | ||
| 624 | + return selfFilename; | ||
| 625 | + } | ||
| 626 | + | ||
| 535 | 627 | return false; | |
| 536 | 628 | }; | |
| 537 | 629 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -93,12 +93,15 @@ struct PackageConfig { | |||
| 93 | 93 | enum class Exists { Yes, No }; | |
| 94 | 94 | enum class IsValid { Yes, No }; | |
| 95 | 95 | enum class HasMain { Yes, No }; | |
| 96 | + enum class HasName { Yes, No }; | ||
| 96 | 97 | enum PackageType : uint32_t { None = 0, CommonJS, Module }; | |
| 97 | 98 | ||
| 98 | 99 | const Exists exists; | |
| 99 | 100 | const IsValid is_valid; | |
| 100 | 101 | const HasMain has_main; | |
| 101 | 102 | const std::string main; | |
| 103 | + const HasName has_name; | ||
| 104 | + const std::string name; | ||
| 102 | 105 | const PackageType type; | |
| 103 | 106 | ||
| 104 | 107 | v8::Global<v8::Value> exports; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments