diff --git a/doc/api/packages.md b/doc/api/packages.md index 658e74af15551c..2055f54e387a1f 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -613,7 +613,8 @@ Then any module _in that package_ can reference an export in the package itself: import { something } from 'a-package'; // Imports "something" from ./main.mjs. ``` -Self-referencing is available only if `package.json` has [`"exports"`][], and +Self-referencing is available only if `package.json` has a [`"name"`][] that +does not contain the character `:`, and a [`"exports"`][] field, and will allow importing only what that [`"exports"`][] (in the `package.json`) allows. So the code below, given the previous package, will generate a runtime error: diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index e7298a2acd782e..250e88f544fcfe 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -54,6 +54,7 @@ const { StringPrototypeCharCodeAt, StringPrototypeEndsWith, StringPrototypeLastIndexOf, + StringPrototypeIncludes, StringPrototypeIndexOf, StringPrototypeMatch, StringPrototypeSlice, @@ -444,6 +445,11 @@ function trySelf(parentPath, request) { return false; } + if (StringPrototypeIncludes(pkg.name, ':')) { + throw new ERR_INVALID_MODULE_SPECIFIER( + request, 'is not a valid package name', parentPath); + } + try { return finalizeEsmResolution(packageExportsResolve( pathToFileURL(pkgPath + '/package.json'), expansion, pkg, diff --git a/test/fixtures/self_ref_module_with_colon/bin.js b/test/fixtures/self_ref_module_with_colon/bin.js new file mode 100644 index 00000000000000..80cbce6025ba3e --- /dev/null +++ b/test/fixtures/self_ref_module_with_colon/bin.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +'use strict'; + +try { + console.log(require('file:package')); +} catch (e) { + console.log(e); +} +import('file:package').then(console.log, console.log); +import('file%3Apackage').then(console.log, console.log); diff --git a/test/fixtures/self_ref_module_with_colon/index.js b/test/fixtures/self_ref_module_with_colon/index.js new file mode 100644 index 00000000000000..7faa73693b54aa --- /dev/null +++ b/test/fixtures/self_ref_module_with_colon/index.js @@ -0,0 +1,4 @@ +'use strict' + +module.exports = 'Self resolution working'; + diff --git a/test/fixtures/self_ref_module_with_colon/package.json b/test/fixtures/self_ref_module_with_colon/package.json new file mode 100644 index 00000000000000..09d6bb8b347d89 --- /dev/null +++ b/test/fixtures/self_ref_module_with_colon/package.json @@ -0,0 +1,4 @@ +{ + "name": "file:package", + "exports": "./index.js" +} diff --git a/test/message/test-self-referential-package.js b/test/message/test-self-referential-package.js new file mode 100644 index 00000000000000..8a730b19492b80 --- /dev/null +++ b/test/message/test-self-referential-package.js @@ -0,0 +1,11 @@ +'use strict'; + +require('../common'); +const { spawn } = require('child_process'); + +const fixtures = require('../common/fixtures'); +const selfRefModule = fixtures.path('self_ref_module_with_colon'); + +spawn(process.argv0, [`${selfRefModule}/bin.js`], { + stdio: 'inherit' +}); diff --git a/test/message/test-self-referential-package.out b/test/message/test-self-referential-package.out new file mode 100644 index 00000000000000..b8a9dde4eeb6b7 --- /dev/null +++ b/test/message/test-self-referential-package.out @@ -0,0 +1,39 @@ +TypeError [ERR_INVALID_MODULE_SPECIFIER]: Invalid module "file:package" is not a valid package name imported from * + at new NodeError (node:internal/errors:*) + at trySelf (node:internal/modules/cjs/loader:*) + at Function.Module._resolveFilename (node:internal/modules/cjs/loader:*) + at Function.Module._load (node:internal/modules/cjs/loader:*) + at Module.require (node:internal/modules/cjs/loader:*) + at require (node:internal/modules/cjs/helpers:*) + at Object. (*) + at Module._compile (node:internal/modules/cjs/loader:*) + at Object.Module._extensions..js (node:internal/modules/cjs/loader:*) + at Module.load (node:internal/modules/cjs/loader:*) { + code: 'ERR_INVALID_MODULE_SPECIFIER' +} +Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/package' imported from * + at new NodeError (node:internal/errors:*) + at finalizeResolution (node:internal/modules/esm/resolve:*) + at moduleResolve (node:internal/modules/esm/resolve:*) + at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:*) + at Loader.resolve (node:internal/modules/esm/loader:*) + at Loader.getModuleJob (node:internal/modules/esm/loader:*) + at Loader.import (node:internal/modules/esm/loader:*) + at importModuleDynamically (node:internal/modules/cjs/loader:*) + at importModuleDynamicallyWrapper (node:internal/vm/module:*) + at importModuleDynamically (node:vm:*) { + code: 'ERR_MODULE_NOT_FOUND' +} +TypeError [ERR_INVALID_MODULE_SPECIFIER]: Invalid module "file%%3Apackage" is not a valid package name imported from * + at new NodeError (node:internal/errors:*) + at parsePackageName (node:internal/modules/esm/resolve:*) + at packageResolve (node:internal/modules/esm/resolve:*) + at moduleResolve (node:internal/modules/esm/resolve:*) + at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:*) + at Loader.resolve (node:internal/modules/esm/loader:*) + at Loader.getModuleJob (node:internal/modules/esm/loader:*) + at Loader.import (node:internal/modules/esm/loader:*) + at importModuleDynamically (node:internal/modules/cjs/loader:*) + at importModuleDynamicallyWrapper (node:internal/vm/module:*) { + code: 'ERR_INVALID_MODULE_SPECIFIER' +}