From da02a50635aa177ac3ebf2e06a6fcebd000c4c49 Mon Sep 17 00:00:00 2001 From: Ashkan Hosseini Date: Mon, 16 Dec 2024 12:13:29 +0100 Subject: [PATCH] fix(js): fix Rollup plugin to correctly handle .cjs.js and .mjs.js file extensions for type definitions. Updated the Rollup plugin's logic for generating type definition files to ensure compatibility with additional file extensions, including .cjs.js and .mjs.js. This change improves the handling of entry points and ensures that corresponding .d.ts files are correctly named and emitted in all supported scenarios. Added a comprehensive test case to validate the new behavior. closed #29308 --- e2e/rollup/src/rollup-legacy.test.ts | 12 ++-- .../plugins/rollup/type-definitions.spec.ts | 62 +++++++++++++++++++ .../js/src/plugins/rollup/type-definitions.ts | 8 ++- 3 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 packages/js/src/plugins/rollup/type-definitions.spec.ts diff --git a/e2e/rollup/src/rollup-legacy.test.ts b/e2e/rollup/src/rollup-legacy.test.ts index b5fcd121cec6b..fed8febe7a24b 100644 --- a/e2e/rollup/src/rollup-legacy.test.ts +++ b/e2e/rollup/src/rollup-legacy.test.ts @@ -40,13 +40,13 @@ describe('Rollup Plugin', () => { ); rmDist(); runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`); - checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`); + checkFilesExist(`dist/libs/${myPkg}/index.d.ts`); expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({ '.': { module: './index.esm.js', import: './index.cjs.mjs', default: './index.cjs.js', - types: './index.esm.d.ts', + types: './index.d.ts', }, './package.json': './package.json', }); @@ -105,7 +105,7 @@ describe('Rollup Plugin', () => { checkFilesExist(`dist/libs/${myPkg}/index.esm.js`); checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`); - checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`); + checkFilesExist(`dist/libs/${myPkg}/index.d.ts`); checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`); checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`); checkFilesExist(`dist/libs/${myPkg}/bar.esm.js`); @@ -116,19 +116,19 @@ describe('Rollup Plugin', () => { module: './index.esm.js', import: './index.cjs.mjs', default: './index.cjs.js', - types: './index.esm.d.ts', + types: './index.d.ts', }, './bar': { module: './bar.esm.js', import: './bar.cjs.mjs', default: './bar.cjs.js', - types: './bar.esm.d.ts', + types: './bar.d.ts', }, './foo': { module: './foo.esm.js', import: './foo.cjs.mjs', default: './foo.cjs.js', - types: './foo.esm.d.ts', + types: './foo.d.ts', }, }); }); diff --git a/packages/js/src/plugins/rollup/type-definitions.spec.ts b/packages/js/src/plugins/rollup/type-definitions.spec.ts new file mode 100644 index 0000000000000..0fcb6889b68d9 --- /dev/null +++ b/packages/js/src/plugins/rollup/type-definitions.spec.ts @@ -0,0 +1,62 @@ +import { typeDefinitions } from './type-definitions'; +describe('typeDefinitions', () => { + it('should emit correct .d.ts filenames for various file formats', () => { + const mockBundle = { + 'index.js': { + type: 'chunk', + isEntry: true, + fileName: 'index.js', + facadeModuleId: '/project/src/index.ts', + exports: ['default', 'namedExport1', 'namedExport2'], + }, + 'index1.js': { + type: 'chunk', + isEntry: true, + fileName: 'index.cjs', + facadeModuleId: '/project/src/index.ts', + exports: ['default', 'namedExport1', 'namedExport2'], + }, + 'index2.js': { + type: 'chunk', + isEntry: true, + fileName: 'index.mjs', + facadeModuleId: '/project/src/index.ts', + exports: ['default', 'namedExport1', 'namedExport2'], + }, + 'index3.js': { + type: 'chunk', + isEntry: true, + fileName: 'index.cjs.js', + facadeModuleId: '/project/src/index.ts', + exports: ['default', 'namedExport1', 'namedExport2'], + }, + 'index4.js': { + type: 'chunk', + isEntry: true, + fileName: 'index.mjs.js', + facadeModuleId: '/project/src/index.ts', + exports: ['default', 'namedExport1', 'namedExport2'], + }, + }; + + const mockOpts = {}; // Can be left empty for this scenario + + const mockEmitFile = jest.fn(); + + const plugin = typeDefinitions({ projectRoot: '/project' }); + + // Simulate the `this` context of a Rollup plugin + const mockContext = { + emitFile: mockEmitFile, + }; + + // Run the plugin's `generateBundle` function + (async function testPlugin() { + await plugin.generateBundle.call(mockContext, mockOpts, mockBundle); + + mockEmitFile.mock.calls.forEach(([{ fileName }]) => { + expect(fileName).toBe('index.d.ts'); + }); + })(); + }); +}); diff --git a/packages/js/src/plugins/rollup/type-definitions.ts b/packages/js/src/plugins/rollup/type-definitions.ts index f82ddf505bab5..33cf9811c7224 100644 --- a/packages/js/src/plugins/rollup/type-definitions.ts +++ b/packages/js/src/plugins/rollup/type-definitions.ts @@ -38,7 +38,13 @@ export function typeDefinitions(options: { projectRoot: string }) { /\.[cm]?[jt]sx?$/, '' ); - const dtsFileName = file.fileName.replace(/\.[cm]?js$/, '.d.ts'); + + // Replace various JavaScript file extensions (e.g., .js, .cjs, .mjs, .cjs.js, .mjs.js) with .d.ts for generating type definition file names. + const dtsFileName = file.fileName.replace( + /(\.cjs|\.mjs|\.js|\.cjs\.js|\.mjs\.js)$/, + '.d.ts' + ); + const relativeSourceDtsName = JSON.stringify('./' + entrySourceDtsName); const dtsFileSource = hasDefaultExport ? stripIndents`