From dd055c811dce54165c384e8b22c50071fb410673 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 27 Sep 2024 02:25:39 -0500 Subject: [PATCH] Fix `experimentalDts` for `Node16`/`NodeNext` module resolution --- src/exports.ts | 8 +- src/utils.ts | 29 +++++++ test/__snapshots__/dts.test.ts.snap | 120 ++++++++++++++-------------- test/dts.test.ts | 81 +++++++++++++++++-- 4 files changed, 166 insertions(+), 72 deletions(-) diff --git a/src/exports.ts b/src/exports.ts index cb803b4c..4d8c0696 100644 --- a/src/exports.ts +++ b/src/exports.ts @@ -1,5 +1,5 @@ import path from 'node:path' -import { slash, trimDtsExtension, truthy } from './utils' +import { replaceDtsWithJsExtensions, slash, truthy } from './utils' export type ExportDeclaration = ModuleExport | NamedExport @@ -41,14 +41,14 @@ function formatAggregationExport( declaration: ExportDeclaration, declarationDirPath: string, ): string { - const dest = trimDtsExtension( + const dest = replaceDtsWithJsExtensions( `./${path.posix.normalize( slash(path.relative(declarationDirPath, declaration.destFileName)), )}`, ) if (declaration.kind === 'module') { - // No implemeted + // No implemented return '' } else if (declaration.kind === 'named') { return [ @@ -72,7 +72,7 @@ export function formatDistributionExports( fromFilePath: string, toFilePath: string, ) { - let importPath = trimDtsExtension( + let importPath = replaceDtsWithJsExtensions( path.posix.relative( path.posix.dirname(path.posix.normalize(slash(fromFilePath))), path.posix.normalize(slash(toFilePath)), diff --git a/src/utils.ts b/src/utils.ts index 3e6294a2..fb7eabb9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -242,3 +242,32 @@ export function writeFileSync(filePath: string, content: string) { fs.mkdirSync(path.dirname(filePath), { recursive: true }) fs.writeFileSync(filePath, content) } + +/** + * Replaces TypeScript declaration file + * extensions (`.d.ts`, `.d.mts`, `.d.cts`) + * with their corresponding JavaScript variants (`.js`, `.mjs`, `.cjs`). + * + * @param dtsFilePath - The file path to be transformed. + * @returns The updated file path with the JavaScript extension. + * + * @internal + */ +export function replaceDtsWithJsExtensions(dtsFilePath: string) { + return dtsFilePath.replace( + /\.d\.(ts|mts|cts)$/, + (_, fileExtension: string) => { + switch (fileExtension) { + case 'ts': + case 'tsx': + return '.js' + case 'mts': + return '.mjs' + case 'cts': + return '.cjs' + default: + return '' + } + }, + ) +} diff --git a/test/__snapshots__/dts.test.ts.snap b/test/__snapshots__/dts.test.ts.snap index af7f717a..2de72a3a 100644 --- a/test/__snapshots__/dts.test.ts.snap +++ b/test/__snapshots__/dts.test.ts.snap @@ -234,95 +234,95 @@ export { } // dist/index.d.mts ////////////////////////////////////////////////////////////////////// -export { VERSION } from './_tsup-dts-rollup'; -export { render_alias_1 as render } from './_tsup-dts-rollup'; -export { ClientRenderOptions_alias_1 as ClientRenderOptions } from './_tsup-dts-rollup'; -export { sharedFunction_alias_1 as sharedFunction } from './_tsup-dts-rollup'; -export { sharedType_alias_1 as sharedType } from './_tsup-dts-rollup'; +export { VERSION } from './_tsup-dts-rollup.mjs'; +export { render_alias_1 as render } from './_tsup-dts-rollup.mjs'; +export { ClientRenderOptions_alias_1 as ClientRenderOptions } from './_tsup-dts-rollup.mjs'; +export { sharedFunction_alias_1 as sharedFunction } from './_tsup-dts-rollup.mjs'; +export { sharedType_alias_1 as sharedType } from './_tsup-dts-rollup.mjs'; ////////////////////////////////////////////////////////////////////// // dist/index.d.ts ////////////////////////////////////////////////////////////////////// -export { VERSION } from './_tsup-dts-rollup'; -export { render_alias_1 as render } from './_tsup-dts-rollup'; -export { ClientRenderOptions_alias_1 as ClientRenderOptions } from './_tsup-dts-rollup'; -export { sharedFunction_alias_1 as sharedFunction } from './_tsup-dts-rollup'; -export { sharedType_alias_1 as sharedType } from './_tsup-dts-rollup'; +export { VERSION } from './_tsup-dts-rollup.js'; +export { render_alias_1 as render } from './_tsup-dts-rollup.js'; +export { ClientRenderOptions_alias_1 as ClientRenderOptions } from './_tsup-dts-rollup.js'; +export { sharedFunction_alias_1 as sharedFunction } from './_tsup-dts-rollup.js'; +export { sharedType_alias_1 as sharedType } from './_tsup-dts-rollup.js'; ////////////////////////////////////////////////////////////////////// // dist/my-lib-client.d.mts ////////////////////////////////////////////////////////////////////// -export { render } from './_tsup-dts-rollup'; -export { ClientRenderOptions } from './_tsup-dts-rollup'; -export { sharedFunction } from './_tsup-dts-rollup'; -export { sharedType } from './_tsup-dts-rollup'; +export { render } from './_tsup-dts-rollup.mjs'; +export { ClientRenderOptions } from './_tsup-dts-rollup.mjs'; +export { sharedFunction } from './_tsup-dts-rollup.mjs'; +export { sharedType } from './_tsup-dts-rollup.mjs'; ////////////////////////////////////////////////////////////////////// // dist/my-lib-client.d.ts ////////////////////////////////////////////////////////////////////// -export { render } from './_tsup-dts-rollup'; -export { ClientRenderOptions } from './_tsup-dts-rollup'; -export { sharedFunction } from './_tsup-dts-rollup'; -export { sharedType } from './_tsup-dts-rollup'; +export { render } from './_tsup-dts-rollup.js'; +export { ClientRenderOptions } from './_tsup-dts-rollup.js'; +export { sharedFunction } from './_tsup-dts-rollup.js'; +export { sharedType } from './_tsup-dts-rollup.js'; ////////////////////////////////////////////////////////////////////// // dist/server/index.d.mts ////////////////////////////////////////////////////////////////////// -export { render_alias_2 as render } from '../_tsup-dts-rollup'; -export { default_alias as default } from '../_tsup-dts-rollup'; -export { ServerRenderOptions } from '../_tsup-dts-rollup'; -export { serverConstant } from '../_tsup-dts-rollup'; -export { serverConstantAlias } from '../_tsup-dts-rollup'; -export { ServerClass } from '../_tsup-dts-rollup'; -export { ServerThirdPartyNamespace } from '../_tsup-dts-rollup'; -export { sharedFunction_alias_2 as sharedFunction } from '../_tsup-dts-rollup'; -export { sharedType_alias_2 as sharedType } from '../_tsup-dts-rollup'; -export { renderToPipeableStream } from '../_tsup-dts-rollup'; -export { renderToString } from '../_tsup-dts-rollup'; -export { renderToNodeStream } from '../_tsup-dts-rollup'; -export { renderToStaticMarkup } from '../_tsup-dts-rollup'; -export { renderToStaticNodeStream } from '../_tsup-dts-rollup'; -export { renderToReadableStream } from '../_tsup-dts-rollup'; -export { RenderToPipeableStreamOptions } from '../_tsup-dts-rollup'; -export { PipeableStream } from '../_tsup-dts-rollup'; -export { ServerOptions } from '../_tsup-dts-rollup'; -export { RenderToReadableStreamOptions } from '../_tsup-dts-rollup'; -export { ReactDOMServerReadableStream } from '../_tsup-dts-rollup'; -export { version } from '../_tsup-dts-rollup'; +export { render_alias_2 as render } from '../_tsup-dts-rollup.mjs'; +export { default_alias as default } from '../_tsup-dts-rollup.mjs'; +export { ServerRenderOptions } from '../_tsup-dts-rollup.mjs'; +export { serverConstant } from '../_tsup-dts-rollup.mjs'; +export { serverConstantAlias } from '../_tsup-dts-rollup.mjs'; +export { ServerClass } from '../_tsup-dts-rollup.mjs'; +export { ServerThirdPartyNamespace } from '../_tsup-dts-rollup.mjs'; +export { sharedFunction_alias_2 as sharedFunction } from '../_tsup-dts-rollup.mjs'; +export { sharedType_alias_2 as sharedType } from '../_tsup-dts-rollup.mjs'; +export { renderToPipeableStream } from '../_tsup-dts-rollup.mjs'; +export { renderToString } from '../_tsup-dts-rollup.mjs'; +export { renderToNodeStream } from '../_tsup-dts-rollup.mjs'; +export { renderToStaticMarkup } from '../_tsup-dts-rollup.mjs'; +export { renderToStaticNodeStream } from '../_tsup-dts-rollup.mjs'; +export { renderToReadableStream } from '../_tsup-dts-rollup.mjs'; +export { RenderToPipeableStreamOptions } from '../_tsup-dts-rollup.mjs'; +export { PipeableStream } from '../_tsup-dts-rollup.mjs'; +export { ServerOptions } from '../_tsup-dts-rollup.mjs'; +export { RenderToReadableStreamOptions } from '../_tsup-dts-rollup.mjs'; +export { ReactDOMServerReadableStream } from '../_tsup-dts-rollup.mjs'; +export { version } from '../_tsup-dts-rollup.mjs'; ////////////////////////////////////////////////////////////////////// // dist/server/index.d.ts ////////////////////////////////////////////////////////////////////// -export { render_alias_2 as render } from '../_tsup-dts-rollup'; -export { default_alias as default } from '../_tsup-dts-rollup'; -export { ServerRenderOptions } from '../_tsup-dts-rollup'; -export { serverConstant } from '../_tsup-dts-rollup'; -export { serverConstantAlias } from '../_tsup-dts-rollup'; -export { ServerClass } from '../_tsup-dts-rollup'; -export { ServerThirdPartyNamespace } from '../_tsup-dts-rollup'; -export { sharedFunction_alias_2 as sharedFunction } from '../_tsup-dts-rollup'; -export { sharedType_alias_2 as sharedType } from '../_tsup-dts-rollup'; -export { renderToPipeableStream } from '../_tsup-dts-rollup'; -export { renderToString } from '../_tsup-dts-rollup'; -export { renderToNodeStream } from '../_tsup-dts-rollup'; -export { renderToStaticMarkup } from '../_tsup-dts-rollup'; -export { renderToStaticNodeStream } from '../_tsup-dts-rollup'; -export { renderToReadableStream } from '../_tsup-dts-rollup'; -export { RenderToPipeableStreamOptions } from '../_tsup-dts-rollup'; -export { PipeableStream } from '../_tsup-dts-rollup'; -export { ServerOptions } from '../_tsup-dts-rollup'; -export { RenderToReadableStreamOptions } from '../_tsup-dts-rollup'; -export { ReactDOMServerReadableStream } from '../_tsup-dts-rollup'; -export { version } from '../_tsup-dts-rollup'; +export { render_alias_2 as render } from '../_tsup-dts-rollup.js'; +export { default_alias as default } from '../_tsup-dts-rollup.js'; +export { ServerRenderOptions } from '../_tsup-dts-rollup.js'; +export { serverConstant } from '../_tsup-dts-rollup.js'; +export { serverConstantAlias } from '../_tsup-dts-rollup.js'; +export { ServerClass } from '../_tsup-dts-rollup.js'; +export { ServerThirdPartyNamespace } from '../_tsup-dts-rollup.js'; +export { sharedFunction_alias_2 as sharedFunction } from '../_tsup-dts-rollup.js'; +export { sharedType_alias_2 as sharedType } from '../_tsup-dts-rollup.js'; +export { renderToPipeableStream } from '../_tsup-dts-rollup.js'; +export { renderToString } from '../_tsup-dts-rollup.js'; +export { renderToNodeStream } from '../_tsup-dts-rollup.js'; +export { renderToStaticMarkup } from '../_tsup-dts-rollup.js'; +export { renderToStaticNodeStream } from '../_tsup-dts-rollup.js'; +export { renderToReadableStream } from '../_tsup-dts-rollup.js'; +export { RenderToPipeableStreamOptions } from '../_tsup-dts-rollup.js'; +export { PipeableStream } from '../_tsup-dts-rollup.js'; +export { ServerOptions } from '../_tsup-dts-rollup.js'; +export { RenderToReadableStreamOptions } from '../_tsup-dts-rollup.js'; +export { ReactDOMServerReadableStream } from '../_tsup-dts-rollup.js'; +export { version } from '../_tsup-dts-rollup.js'; " `; diff --git a/test/dts.test.ts b/test/dts.test.ts index 174a4438..eefdf7d6 100644 --- a/test/dts.test.ts +++ b/test/dts.test.ts @@ -258,29 +258,29 @@ test('should emit declaration files with experimentalDts', async () => { export function sharedFunction(value: T): T | null { return value || null } - + type sharedType = { shared: boolean } - + export type { sharedType } `, 'src/server.ts': ` export * from './shared' /** - * Comment for server render function + * Comment for server render function */ export function render(options: ServerRenderOptions): string { return JSON.stringify(options) } - + export interface ServerRenderOptions { /** * Comment for ServerRenderOptions.stream - * + * * @public - * + * * @my_custom_tag */ stream: boolean @@ -298,7 +298,7 @@ test('should emit declaration files with experimentalDts', async () => { import * as ServerThirdPartyNamespace from 'react-dom'; export { ServerThirdPartyNamespace } - // Export a third party module + // Export a third party module export * from 'react-dom/server'; `, @@ -308,7 +308,7 @@ test('should emit declaration files with experimentalDts', async () => { export function render(options: ClientRenderOptions): string { return JSON.stringify(options) } - + export interface ClientRenderOptions { document: boolean } @@ -473,3 +473,68 @@ test('declaration files with multiple entrypoints #316', async () => { 'dist/bar/index.d.ts', ).toMatchSnapshot() }) + +test.for([ + { moduleResolution: 'NodeNext', module: 'NodeNext' }, + { moduleResolution: 'Node16', module: 'Node16' }, + { moduleResolution: 'Bundler', module: 'ESNext' }, + { moduleResolution: 'Node10', module: 'ESNext' }, +])( + "experimentalDts works with TypeScript's $moduleResolution module resolution and module set to $module", + async ({ moduleResolution, module }, { expect }) => { + const { getFileContent, outFiles } = await run( + getTestName(), + { + 'src/index.ts': `export const foo = [1, 2, 3]`, + 'tsup.config.ts': `export default { + entry: { index: 'src/index.ts' }, + format: ['esm', 'cjs'], + experimentalDts: true, + }`, + 'package.json': JSON.stringify({ + name: 'testing-experimental-dts', + type: 'module', + }), + 'tsconfig.json': JSON.stringify({ + compilerOptions: { + module, + moduleResolution, + outDir: './dist', + rootDir: './src', + skipLibCheck: true, + strict: true, + }, + include: ['src'], + }), + }, + { + entry: [], + }, + ) + + expect(outFiles).toStrictEqual([ + '_tsup-dts-rollup.d.cts', + '_tsup-dts-rollup.d.ts', + 'index.cjs', + 'index.d.cts', + 'index.d.ts', + 'index.js', + ]) + + expect(await getFileContent('dist/index.d.ts')).toStrictEqual( + `export { foo } from './_tsup-dts-rollup.js';\n`, + ) + + expect(await getFileContent('dist/index.d.cts')).toStrictEqual( + `export { foo } from './_tsup-dts-rollup.cjs';\n`, + ) + + expect(await getFileContent('dist/_tsup-dts-rollup.d.cts')).toStrictEqual( + `export declare const foo: number[];\r\n\r\nexport { }\r\n`, + ) + + expect(await getFileContent('dist/_tsup-dts-rollup.d.ts')).toStrictEqual( + `export declare const foo: number[];\r\n\r\nexport { }\r\n`, + ) + }, +)