diff --git a/.yarn/versions/32961798.yml b/.yarn/versions/32961798.yml new file mode 100644 index 000000000000..1ef7ecb1c936 --- /dev/null +++ b/.yarn/versions/32961798.yml @@ -0,0 +1,28 @@ +releases: + "@yarnpkg/cli": patch + "@yarnpkg/plugin-pnp": patch + "@yarnpkg/pnp": patch + +declined: + - "@yarnpkg/esbuild-plugin-pnp" + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm-cli" + - "@yarnpkg/plugin-pack" + - "@yarnpkg/plugin-patch" + - "@yarnpkg/plugin-pnpm" + - "@yarnpkg/plugin-stage" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/plugin-version" + - "@yarnpkg/plugin-workspace-tools" + - "@yarnpkg/builder" + - "@yarnpkg/core" + - "@yarnpkg/doctor" + - "@yarnpkg/nm" + - "@yarnpkg/pnpify" + - "@yarnpkg/sdks" diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/pnp-esm.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/pnp-esm.test.ts index fd1a2893cb0e..acc863f58ea8 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/pnp-esm.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/pnp-esm.test.ts @@ -194,7 +194,25 @@ describe(`Plug'n'Play - ESM`, () => { ); test( - `it should not allow unknown extensions`, + `it should load commonjs with an unknown extension`, + makeTemporaryEnv( + { + }, + async ({path, run, source}) => { + await xfs.writeFilePromise(ppath.join(path, `index.ts` as Filename), `console.log(typeof require === 'undefined')`); + + await expect(run(`install`)).resolves.toMatchObject({code: 0}); + + await expect(run(`node`, `./index.ts`)).resolves.toMatchObject({ + code: 0, + stdout: `false\n`, + }); + }, + ), + ); + + test( + `it should not allow unknown extensions with {type: "module"}`, makeTemporaryEnv( { type: `module`, @@ -214,7 +232,7 @@ describe(`Plug'n'Play - ESM`, () => { // Tests https://github.com/nodejs/node/issues/33226 test( - `it should not load extensionless commonjs files as ESM`, + `it should load extensionless commonjs files as an entrypoint`, makeTemporaryEnv( { }, { @@ -233,6 +251,49 @@ describe(`Plug'n'Play - ESM`, () => { ), ); + test( + `it should not allow extensionless commonjs imports`, + makeTemporaryEnv( + { }, + { + pnpEnableEsmLoader: true, + }, + async ({path, run, source}) => { + await xfs.writeFilePromise(ppath.join(path, `index.mjs` as Filename), `import bin from './cjs-bin';\nconsole.log(bin)`); + await xfs.writeFilePromise(ppath.join(path, `cjs-bin` as Filename), `module.exports = {foo: 'bar'}`); + + await expect(run(`install`)).resolves.toMatchObject({code: 0}); + + await expect(run(`node`, `./index.mjs`)).rejects.toMatchObject({ + code: 1, + stderr: expect.stringContaining(`Unknown file extension`), + }); + }, + ), + ); + + test( + `it should not allow extensionless files with {"type": "module"}`, + makeTemporaryEnv( + { + type: `module`, + }, + { + pnpEnableEsmLoader: true, + }, + async ({path, run, source}) => { + await xfs.writeFilePromise(ppath.join(path, `index` as Filename), ``); + + await expect(run(`install`)).resolves.toMatchObject({code: 0}); + + await expect(run(`node`, `./index`)).rejects.toMatchObject({ + code: 1, + stderr: expect.stringContaining(`Unknown file extension`), + }); + }, + ), + ); + test( `it should support ESM binaries`, makeTemporaryEnv( diff --git a/packages/yarnpkg-pnp/sources/esm-loader/built-loader.js b/packages/yarnpkg-pnp/sources/esm-loader/built-loader.js index 24cc134d6bc0..d1423d9f663c 100644 --- a/packages/yarnpkg-pnp/sources/esm-loader/built-loader.js +++ b/packages/yarnpkg-pnp/sources/esm-loader/built-loader.js @@ -2,7 +2,7 @@ let hook; module.exports = () => { if (typeof hook === `undefined`) - hook = require('zlib').brotliDecompressSync(Buffer.from('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', 'base64')).toString(); + hook = require('zlib').brotliDecompressSync(Buffer.from('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', 'base64')).toString(); return hook; }; diff --git a/packages/yarnpkg-pnp/sources/esm-loader/loaderUtils.ts b/packages/yarnpkg-pnp/sources/esm-loader/loaderUtils.ts index f409bd939aee..77bc42917e94 100644 --- a/packages/yarnpkg-pnp/sources/esm-loader/loaderUtils.ts +++ b/packages/yarnpkg-pnp/sources/esm-loader/loaderUtils.ts @@ -48,16 +48,27 @@ export function getFileFormat(filepath: string): string | null { `Unknown file extension ".json" for ${filepath}`, ); } - // Matching files without extensions deviates from Node's default - // behaviour but is a fix for https://github.com/nodejs/node/issues/33226 - case ``: case `.js`: { const pkg = nodeUtils.readPackageScope(filepath); - if (pkg) { - return pkg.data.type ?? `commonjs`; - } + // assume CJS for files outside of a package boundary + if (!pkg) + return `commonjs`; + return pkg.data.type ?? `commonjs`; + } + // Matching files beyond those handled above deviates from Node's default + // --experimental-loader behavior but is required to work around + // https://github.com/nodejs/node/issues/33226 + default: { + const isMain = process.argv[1] === filepath; + if (!isMain) + return null; + const pkg = nodeUtils.readPackageScope(filepath); + if (!pkg) + return `commonjs`; + // prevent extensions beyond .mjs or .js from loading as ESM + if (pkg.data.type === `module`) + return null; + return pkg.data.type ?? `commonjs`; } } - - return null; }