Skip to content

Commit 13fa966

Browse files
guybedfordBridgeAR
authored andcommitted
module: error for CJS .js load within type: module
PR-URL: #29492 Reviewed-By: Jan Krems <[email protected]>
1 parent a5bd7e3 commit 13fa966

File tree

5 files changed

+87
-34
lines changed

5 files changed

+87
-34
lines changed

lib/internal/modules/cjs/loader.js

+42-33
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,17 @@ Module._debug = deprecate(debug, 'Module._debug is deprecated.', 'DEP0077');
213213
// -> a.<ext>
214214
// -> a/index.<ext>
215215

216-
// Check if the directory is a package.json dir.
217-
const packageMainCache = Object.create(null);
218-
// Explicit exports from package.json files
219-
const packageExportsCache = new SafeMap();
216+
const packageJsonCache = new SafeMap();
220217

221-
function readPackageRaw(requestPath) {
218+
function readPackage(requestPath) {
222219
const jsonPath = path.resolve(requestPath, 'package.json');
223-
const json = internalModuleReadJSON(path.toNamespacedPath(jsonPath));
224220

221+
const existing = packageJsonCache.get(jsonPath);
222+
if (existing !== undefined) return existing;
223+
224+
const json = internalModuleReadJSON(path.toNamespacedPath(jsonPath));
225225
if (json === undefined) {
226+
packageJsonCache.set(jsonPath, false);
226227
return false;
227228
}
228229

@@ -233,45 +234,47 @@ function readPackageRaw(requestPath) {
233234

234235
try {
235236
const parsed = JSON.parse(json);
236-
packageMainCache[requestPath] = parsed.main;
237-
if (experimentalExports) {
238-
packageExportsCache.set(requestPath, parsed.exports);
239-
}
240-
return parsed;
237+
const filtered = {
238+
main: parsed.main,
239+
exports: parsed.exports,
240+
type: parsed.type
241+
};
242+
packageJsonCache.set(jsonPath, filtered);
243+
return filtered;
241244
} catch (e) {
242245
e.path = jsonPath;
243246
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
244247
throw e;
245248
}
246249
}
247250

248-
function readPackage(requestPath) {
249-
const entry = packageMainCache[requestPath];
250-
if (entry)
251-
return entry;
252-
253-
const pkg = readPackageRaw(requestPath);
254-
if (pkg === false) return false;
255-
256-
return pkg.main;
257-
}
258-
259-
function readExports(requestPath) {
260-
if (packageExportsCache.has(requestPath)) {
261-
return packageExportsCache.get(requestPath);
251+
function readPackageScope(checkPath) {
252+
const rootSeparatorIndex = checkPath.indexOf(path.sep);
253+
let separatorIndex;
254+
while (
255+
(separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex
256+
) {
257+
checkPath = checkPath.slice(0, separatorIndex);
258+
if (checkPath.endsWith(path.sep + 'node_modules'))
259+
return false;
260+
const pjson = readPackage(checkPath);
261+
if (pjson) return pjson;
262262
}
263+
return false;
264+
}
263265

264-
const pkg = readPackageRaw(requestPath);
265-
if (!pkg) {
266-
packageExportsCache.set(requestPath, null);
267-
return null;
268-
}
266+
function readPackageMain(requestPath) {
267+
const pkg = readPackage(requestPath);
268+
return pkg ? pkg.main : undefined;
269+
}
269270

270-
return pkg.exports;
271+
function readPackageExports(requestPath) {
272+
const pkg = readPackage(requestPath);
273+
return pkg ? pkg.exports : undefined;
271274
}
272275

273276
function tryPackage(requestPath, exts, isMain, originalPath) {
274-
const pkg = readPackage(requestPath);
277+
const pkg = readPackageMain(requestPath);
275278

276279
if (!pkg) {
277280
return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
@@ -372,7 +375,7 @@ function resolveExports(nmPath, request, absoluteRequest) {
372375
}
373376

374377
const basePath = path.resolve(nmPath, name);
375-
const pkgExports = readExports(basePath);
378+
const pkgExports = readPackageExports(basePath);
376379
const mappingKey = `.${expansion}`;
377380

378381
if (typeof pkgExports === 'object' && pkgExports !== null) {
@@ -947,6 +950,12 @@ Module.prototype._compile = function(content, filename) {
947950

948951
// Native extension for .js
949952
Module._extensions['.js'] = function(module, filename) {
953+
if (filename.endsWith('.js')) {
954+
const pkg = readPackageScope(filename);
955+
if (pkg && pkg.type === 'module') {
956+
throw new ERR_REQUIRE_ESM(filename);
957+
}
958+
}
950959
const content = fs.readFileSync(filename, 'utf8');
951960
module._compile(stripBOM(content), filename);
952961
};

src/node_file.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,8 @@ static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
875875
const size_t size = offset - start;
876876
if (size == 0 || (
877877
size == SearchString(&chars[start], size, "\"main\"") &&
878-
size == SearchString(&chars[start], size, "\"exports\""))) {
878+
size == SearchString(&chars[start], size, "\"exports\"") &&
879+
size == SearchString(&chars[start], size, "\"type\""))) {
879880
return;
880881
} else {
881882
Local<String> chars_string =

test/es-module/test-esm-type-flag-errors.js

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ expect('', packageWithoutTypeMain, 'package-without-type');
2323
expect('--input-type=module', packageTypeModuleMain,
2424
'ERR_INPUT_TYPE_NOT_ALLOWED', true);
2525

26+
try {
27+
require('../fixtures/es-modules/package-type-module/index.js');
28+
assert.fail('Expected CJS to fail loading from type: module package.');
29+
} catch (e) {
30+
assert(e.toString().match(/Error \[ERR_REQUIRE_ESM\]: Must use import to load ES Module:/));
31+
}
32+
2633
function expect(opt = '', inputFile, want, wantsError = false) {
2734
// TODO: Remove when --experimental-modules is unflagged
2835
opt = `--experimental-modules ${opt}`;

test/parallel/test-policy-integrity.js

+28
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ test({
212212
shouldFail: false,
213213
entry: parentFilepath,
214214
resources: {
215+
[packageURL]: {
216+
body: packageBody,
217+
match: true,
218+
},
215219
[parentURL]: {
216220
body: parentBody,
217221
match: true,
@@ -227,6 +231,10 @@ test({
227231
preload: [depFilepath],
228232
entry: parentFilepath,
229233
resources: {
234+
[packageURL]: {
235+
body: packageBody,
236+
match: true,
237+
},
230238
[parentURL]: {
231239
body: parentBody,
232240
match: true,
@@ -279,6 +287,10 @@ test({
279287
shouldFail: false,
280288
entry: depFilepath,
281289
resources: {
290+
[packageURL]: {
291+
body: packageBody,
292+
match: true,
293+
},
282294
[depURL]: {
283295
body: depBody,
284296
match: true,
@@ -289,6 +301,10 @@ test({
289301
shouldFail: false,
290302
entry: depFilepath,
291303
resources: {
304+
[packageURL]: {
305+
body: packageBody,
306+
match: true,
307+
},
292308
[policyToDepRelativeURLString]: {
293309
body: depBody,
294310
match: true,
@@ -309,6 +325,10 @@ test({
309325
shouldFail: false,
310326
entry: depFilepath,
311327
resources: {
328+
[packageURL]: {
329+
body: packageBody,
330+
match: true,
331+
},
312332
[policyToDepRelativeURLString]: {
313333
body: depBody,
314334
match: true,
@@ -351,6 +371,10 @@ test({
351371
shouldFail: false,
352372
entry: workerSpawningFilepath,
353373
resources: {
374+
[packageURL]: {
375+
body: packageBody,
376+
match: true,
377+
},
354378
[workerSpawningURL]: {
355379
body: workerSpawningBody,
356380
match: true,
@@ -370,6 +394,10 @@ test({
370394
entry: workerSpawningFilepath,
371395
preload: [parentFilepath],
372396
resources: {
397+
[packageURL]: {
398+
body: packageBody,
399+
match: true,
400+
},
373401
[workerSpawningURL]: {
374402
body: workerSpawningBody,
375403
match: true,

test/parallel/test-policy-parse-integrity.js

+8
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,16 @@ if (!tmpdirURL.pathname.endsWith('/')) {
3636
tmpdirURL.pathname += '/';
3737
}
3838

39+
const packageFilepath = path.join(tmpdir.path, 'package.json');
40+
const packageURL = pathToFileURL(packageFilepath);
41+
const packageBody = '{"main": "dep.js"}';
42+
3943
function test({ shouldFail, integrity }) {
4044
const resources = {
45+
[packageURL]: {
46+
body: packageBody,
47+
integrity: `sha256-${hash('sha256', packageBody)}`
48+
},
4149
[depURL]: {
4250
body: depBody,
4351
integrity

0 commit comments

Comments
 (0)