summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/internal/modules/cjs/loader.js75
-rw-r--r--src/node_file.cc3
-rw-r--r--test/es-module/test-esm-type-flag-errors.js7
-rw-r--r--test/parallel/test-policy-integrity.js28
-rw-r--r--test/parallel/test-policy-parse-integrity.js8
5 files changed, 87 insertions, 34 deletions
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index 019215ff54..51adba6086 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -212,16 +212,17 @@ Module._debug = deprecate(debug, 'Module._debug is deprecated.', 'DEP0077');
// -> a.<ext>
// -> a/index.<ext>
-// Check if the directory is a package.json dir.
-const packageMainCache = Object.create(null);
-// Explicit exports from package.json files
-const packageExportsCache = new SafeMap();
+const packageJsonCache = new SafeMap();
-function readPackageRaw(requestPath) {
+function readPackage(requestPath) {
const jsonPath = path.resolve(requestPath, 'package.json');
- const json = internalModuleReadJSON(path.toNamespacedPath(jsonPath));
+ const existing = packageJsonCache.get(jsonPath);
+ if (existing !== undefined) return existing;
+
+ const json = internalModuleReadJSON(path.toNamespacedPath(jsonPath));
if (json === undefined) {
+ packageJsonCache.set(jsonPath, false);
return false;
}
@@ -232,11 +233,13 @@ function readPackageRaw(requestPath) {
try {
const parsed = JSON.parse(json);
- packageMainCache[requestPath] = parsed.main;
- if (experimentalExports) {
- packageExportsCache.set(requestPath, parsed.exports);
- }
- return parsed;
+ const filtered = {
+ main: parsed.main,
+ exports: parsed.exports,
+ type: parsed.type
+ };
+ packageJsonCache.set(jsonPath, filtered);
+ return filtered;
} catch (e) {
e.path = jsonPath;
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
@@ -244,33 +247,33 @@ function readPackageRaw(requestPath) {
}
}
-function readPackage(requestPath) {
- const entry = packageMainCache[requestPath];
- if (entry)
- return entry;
-
- const pkg = readPackageRaw(requestPath);
- if (pkg === false) return false;
-
- return pkg.main;
-}
-
-function readExports(requestPath) {
- if (packageExportsCache.has(requestPath)) {
- return packageExportsCache.get(requestPath);
+function readPackageScope(checkPath) {
+ const rootSeparatorIndex = checkPath.indexOf(path.sep);
+ let separatorIndex;
+ while (
+ (separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex
+ ) {
+ checkPath = checkPath.slice(0, separatorIndex);
+ if (checkPath.endsWith(path.sep + 'node_modules'))
+ return false;
+ const pjson = readPackage(checkPath);
+ if (pjson) return pjson;
}
+ return false;
+}
- const pkg = readPackageRaw(requestPath);
- if (!pkg) {
- packageExportsCache.set(requestPath, null);
- return null;
- }
+function readPackageMain(requestPath) {
+ const pkg = readPackage(requestPath);
+ return pkg ? pkg.main : undefined;
+}
- return pkg.exports;
+function readPackageExports(requestPath) {
+ const pkg = readPackage(requestPath);
+ return pkg ? pkg.exports : undefined;
}
function tryPackage(requestPath, exts, isMain, originalPath) {
- const pkg = readPackage(requestPath);
+ const pkg = readPackageMain(requestPath);
if (!pkg) {
return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
@@ -371,7 +374,7 @@ function resolveExports(nmPath, request, absoluteRequest) {
}
const basePath = path.resolve(nmPath, name);
- const pkgExports = readExports(basePath);
+ const pkgExports = readPackageExports(basePath);
const mappingKey = `.${expansion}`;
if (typeof pkgExports === 'object' && pkgExports !== null) {
@@ -947,6 +950,12 @@ Module.prototype._compile = function(content, filename) {
// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
+ if (filename.endsWith('.js')) {
+ const pkg = readPackageScope(filename);
+ if (pkg && pkg.type === 'module') {
+ throw new ERR_REQUIRE_ESM(filename);
+ }
+ }
const content = fs.readFileSync(filename, 'utf8');
module._compile(content, filename);
};
diff --git a/src/node_file.cc b/src/node_file.cc
index ae2aa0677f..195757f43f 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -875,7 +875,8 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
const size_t size = offset - start;
if (size == 0 || (
size == SearchString(&chars[start], size, "\"main\"") &&
- size == SearchString(&chars[start], size, "\"exports\""))) {
+ size == SearchString(&chars[start], size, "\"exports\"") &&
+ size == SearchString(&chars[start], size, "\"type\""))) {
return;
} else {
Local<String> chars_string =
diff --git a/test/es-module/test-esm-type-flag-errors.js b/test/es-module/test-esm-type-flag-errors.js
index 169118e018..a54a018ad9 100644
--- a/test/es-module/test-esm-type-flag-errors.js
+++ b/test/es-module/test-esm-type-flag-errors.js
@@ -23,6 +23,13 @@ expect('', packageWithoutTypeMain, 'package-without-type');
expect('--input-type=module', packageTypeModuleMain,
'ERR_INPUT_TYPE_NOT_ALLOWED', true);
+try {
+ require('../fixtures/es-modules/package-type-module/index.js');
+ assert.fail('Expected CJS to fail loading from type: module package.');
+} catch (e) {
+ assert(e.toString().match(/Error \[ERR_REQUIRE_ESM\]: Must use import to load ES Module:/));
+}
+
function expect(opt = '', inputFile, want, wantsError = false) {
// TODO: Remove when --experimental-modules is unflagged
opt = `--experimental-modules ${opt}`;
diff --git a/test/parallel/test-policy-integrity.js b/test/parallel/test-policy-integrity.js
index 722b45f633..2cc1f1280c 100644
--- a/test/parallel/test-policy-integrity.js
+++ b/test/parallel/test-policy-integrity.js
@@ -212,6 +212,10 @@ test({
shouldFail: false,
entry: parentFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[parentURL]: {
body: parentBody,
match: true,
@@ -227,6 +231,10 @@ test({
preload: [depFilepath],
entry: parentFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[parentURL]: {
body: parentBody,
match: true,
@@ -279,6 +287,10 @@ test({
shouldFail: false,
entry: depFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[depURL]: {
body: depBody,
match: true,
@@ -289,6 +301,10 @@ test({
shouldFail: false,
entry: depFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[policyToDepRelativeURLString]: {
body: depBody,
match: true,
@@ -309,6 +325,10 @@ test({
shouldFail: false,
entry: depFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[policyToDepRelativeURLString]: {
body: depBody,
match: true,
@@ -351,6 +371,10 @@ test({
shouldFail: false,
entry: workerSpawningFilepath,
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[workerSpawningURL]: {
body: workerSpawningBody,
match: true,
@@ -370,6 +394,10 @@ test({
entry: workerSpawningFilepath,
preload: [parentFilepath],
resources: {
+ [packageURL]: {
+ body: packageBody,
+ match: true,
+ },
[workerSpawningURL]: {
body: workerSpawningBody,
match: true,
diff --git a/test/parallel/test-policy-parse-integrity.js b/test/parallel/test-policy-parse-integrity.js
index 7779f767fb..6fa9541639 100644
--- a/test/parallel/test-policy-parse-integrity.js
+++ b/test/parallel/test-policy-parse-integrity.js
@@ -36,8 +36,16 @@ if (!tmpdirURL.pathname.endsWith('/')) {
tmpdirURL.pathname += '/';
}
+const packageFilepath = path.join(tmpdir.path, 'package.json');
+const packageURL = pathToFileURL(packageFilepath);
+const packageBody = '{"main": "dep.js"}';
+
function test({ shouldFail, integrity }) {
const resources = {
+ [packageURL]: {
+ body: packageBody,
+ integrity: `sha256-${hash('sha256', packageBody)}`
+ },
[depURL]: {
body: depBody,
integrity