Skip to content

Commit 35b700b

Browse files
fix: preserve CJS JSON require in ESM hooks
closes #794
1 parent ef807db commit 35b700b

2 files changed

Lines changed: 41 additions & 5 deletions

File tree

src/esm/hook/load.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,10 @@ const prepareJsonAttributes = (
231231
};
232232

233233
const isCommonJsRequireContext = (
234-
context: Parameters<LoadHook>[1],
234+
{ conditions }: Parameters<LoadHook>[1],
235235
) => (
236-
context.conditions.includes('require')
237-
&& !context.conditions.includes('import')
236+
conditions?.includes('require') === true
237+
&& !conditions.includes('import')
238238
);
239239

240240
export const createLoad = (
@@ -361,6 +361,9 @@ export const createLoad = (
361361
}
362362

363363
const code = loaded.source.toString();
364+
// CJS JSON require still parses hook source as JSON after module hooks.
365+
// https://github.com/nodejs/node/blob/v24.15.0/lib/internal/modules/cjs/loader.js#L1969-L1978
366+
const shouldTransformJson = loadedFormat === 'json' && !isCommonJsRequireContext(context);
364367

365368
if (loadedFormat === 'commonjs-typescript') {
366369
const transformed = transformSync(
@@ -380,7 +383,7 @@ export const createLoad = (
380383

381384
if (
382385
// Support named imports in JSON modules
383-
loaded.format === 'json'
386+
shouldTransformJson
384387
|| isModuleTypeScriptFormat(loadedFormat)
385388
|| tsExtensionsPattern.test(url)
386389
) {
@@ -509,6 +512,9 @@ export const createLoadSync = (
509512
}
510513

511514
const code = loaded.source.toString();
515+
// CJS JSON require still parses hook source as JSON after module hooks.
516+
// https://github.com/nodejs/node/blob/v24.15.0/lib/internal/modules/cjs/loader.js#L1969-L1978
517+
const shouldTransformJson = loadedFormat === 'json' && !isCommonJsRequireContext(context);
512518

513519
if (loadedFormat === 'commonjs-typescript') {
514520
const transformed = transformSync(
@@ -529,7 +535,7 @@ export const createLoadSync = (
529535

530536
if (
531537
// Support named imports in JSON modules
532-
loaded.format === 'json'
538+
shouldTransformJson
533539
|| isModuleTypeScriptFormat(loadedFormat)
534540
|| tsExtensionsPattern.test(url)
535541
) {

tests/specs/version-sensitive.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,36 @@ export const versionSensitiveTests = (node: NodeApis) => describe('Version-sensi
136136
);
137137
});
138138

139+
test('sync ESM hook preserves CJS JSON require', async () => {
140+
await using fixture = await createFixture({
141+
'package.json': createPackageJson({ type: 'commonjs' }),
142+
'entry.cjs': 'require("fake-mocha/lib/mocha.js");',
143+
'node_modules/fake-mocha': {
144+
'package.json': createPackageJson({ type: 'commonjs' }),
145+
lib: {
146+
'mocha.js': `
147+
const mocharc = require("./mocharc.json");
148+
149+
console.log(JSON.stringify(mocharc));
150+
`,
151+
'mocharc.json': JSON.stringify({
152+
diff: true,
153+
extension: ['js', 'cjs', 'mjs'],
154+
}),
155+
},
156+
},
157+
});
158+
159+
const process = await node.hook(['entry.cjs'], fixture.path);
160+
161+
expect(process.exitCode).toBe(0);
162+
expect(process.stderr).toBe('');
163+
expect(JSON.parse(process.stdout)).toEqual({
164+
diff: true,
165+
extension: ['js', 'cjs', 'mjs'],
166+
});
167+
});
168+
139169
await test('watch reruns when imported TypeScript file changes', async () => {
140170
await using fixture = await createFixture({
141171
'package.json': createPackageJson({ type: 'commonjs' }),

0 commit comments

Comments
 (0)