From 4dd6e3e88a335962d2b9262dc8ed886510a47d57 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sun, 28 Aug 2022 14:10:06 +1200 Subject: [PATCH 1/4] fix: support .mts and .cts out of the box --- packages/typescript/src/index.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index f3b263435..ee56d6eb3 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -17,6 +17,8 @@ import { preflight } from './preflight'; import createWatchProgram, { WatchProgramHelper } from './watchProgram'; import TSCache from './tscache'; +const defaultTsExtensionsGlob = '?(m|c)ts+(|x)'; + export default function typescript(options: RollupTypescriptOptions = {}): Plugin { const { cacheDir, @@ -36,9 +38,13 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi const watchProgramHelper = new WatchProgramHelper(); const parsedOptions = parseTypescriptConfig(ts, tsconfig, compilerOptions, noForceEmit); - const filter = createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude, { - resolve: filterRoot ?? parsedOptions.options.rootDir - }); + const filter = createFilter( + include || [`*.${defaultTsExtensionsGlob}`, `**/*.${defaultTsExtensionsGlob}`], + exclude, + { + resolve: filterRoot ?? parsedOptions.options.rootDir + } + ); parsedOptions.fileNames = parsedOptions.fileNames.filter(filter); const formatHost = createFormattingHost(ts, parsedOptions.options); @@ -110,7 +116,8 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi const resolved = resolveModule(importee, containingFile); if (resolved) { - if (resolved.extension === '.d.ts') return null; + if (resolved.extension.startsWith('.d.') && resolved.extension.match(/\./g)?.length === 2) + return null; return path.normalize(resolved.resolvedFileName); } From e12223436ba01ad6e8397db1b69a887649592d8f Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sun, 28 Aug 2022 14:30:28 +1200 Subject: [PATCH 2/4] test: support .mts and .cts out of the box --- .../typescript/test/fixtures/cts/main.mts | 3 ++ .../test/fixtures/cts/tsconfig.json | 6 +++ .../typescript/test/fixtures/dcts/main.cts | 5 ++ .../test/fixtures/dcts/tsconfig.json | 6 +++ .../typescript/test/fixtures/dmts/main.mts | 5 ++ .../test/fixtures/dmts/tsconfig.json | 6 +++ .../typescript/test/fixtures/mts/main.mts | 3 ++ .../test/fixtures/mts/tsconfig.json | 6 +++ packages/typescript/test/test.js | 48 ++++++++++++++++++- 9 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 packages/typescript/test/fixtures/cts/main.mts create mode 100644 packages/typescript/test/fixtures/cts/tsconfig.json create mode 100644 packages/typescript/test/fixtures/dcts/main.cts create mode 100644 packages/typescript/test/fixtures/dcts/tsconfig.json create mode 100644 packages/typescript/test/fixtures/dmts/main.mts create mode 100644 packages/typescript/test/fixtures/dmts/tsconfig.json create mode 100644 packages/typescript/test/fixtures/mts/main.mts create mode 100644 packages/typescript/test/fixtures/mts/tsconfig.json diff --git a/packages/typescript/test/fixtures/cts/main.mts b/packages/typescript/test/fixtures/cts/main.mts new file mode 100644 index 000000000..ccf559ebb --- /dev/null +++ b/packages/typescript/test/fixtures/cts/main.mts @@ -0,0 +1,3 @@ +const answer = 42; +// eslint-disable-next-line no-console +console.log(`the answer is ${answer}`); diff --git a/packages/typescript/test/fixtures/cts/tsconfig.json b/packages/typescript/test/fixtures/cts/tsconfig.json new file mode 100644 index 000000000..3fc681555 --- /dev/null +++ b/packages/typescript/test/fixtures/cts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16" + } +} diff --git a/packages/typescript/test/fixtures/dcts/main.cts b/packages/typescript/test/fixtures/dcts/main.cts new file mode 100644 index 000000000..e82d43df2 --- /dev/null +++ b/packages/typescript/test/fixtures/dcts/main.cts @@ -0,0 +1,5 @@ +/* eslint-disable */ +// @ts-ignore +import { foo } from 'an-import'; + +foo(); diff --git a/packages/typescript/test/fixtures/dcts/tsconfig.json b/packages/typescript/test/fixtures/dcts/tsconfig.json new file mode 100644 index 000000000..3fc681555 --- /dev/null +++ b/packages/typescript/test/fixtures/dcts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16" + } +} diff --git a/packages/typescript/test/fixtures/dmts/main.mts b/packages/typescript/test/fixtures/dmts/main.mts new file mode 100644 index 000000000..e82d43df2 --- /dev/null +++ b/packages/typescript/test/fixtures/dmts/main.mts @@ -0,0 +1,5 @@ +/* eslint-disable */ +// @ts-ignore +import { foo } from 'an-import'; + +foo(); diff --git a/packages/typescript/test/fixtures/dmts/tsconfig.json b/packages/typescript/test/fixtures/dmts/tsconfig.json new file mode 100644 index 000000000..3fc681555 --- /dev/null +++ b/packages/typescript/test/fixtures/dmts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16" + } +} diff --git a/packages/typescript/test/fixtures/mts/main.mts b/packages/typescript/test/fixtures/mts/main.mts new file mode 100644 index 000000000..ccf559ebb --- /dev/null +++ b/packages/typescript/test/fixtures/mts/main.mts @@ -0,0 +1,3 @@ +const answer = 42; +// eslint-disable-next-line no-console +console.log(`the answer is ${answer}`); diff --git a/packages/typescript/test/fixtures/mts/tsconfig.json b/packages/typescript/test/fixtures/mts/tsconfig.json new file mode 100644 index 000000000..3fc681555 --- /dev/null +++ b/packages/typescript/test/fixtures/mts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16" + } +} diff --git a/packages/typescript/test/test.js b/packages/typescript/test/test.js index d72fea497..506354b87 100644 --- a/packages/typescript/test/test.js +++ b/packages/typescript/test/test.js @@ -16,7 +16,7 @@ test.beforeEach(() => process.chdir(__dirname)); const outputOptions = { format: 'esm' }; -test.serial('runs code through typescript', async (t) => { +test.serial('runs ts code through typescript', async (t) => { const bundle = await rollup({ input: 'fixtures/basic/main.ts', plugins: [typescript({ tsconfig: 'fixtures/basic/tsconfig.json', target: 'es5' })], @@ -28,6 +28,30 @@ test.serial('runs code through typescript', async (t) => { t.false(code.includes('const'), code); }); +test.serial('runs mts code through typescript', async (t) => { + const bundle = await rollup({ + input: 'fixtures/mts/main.ts', + plugins: [typescript({ tsconfig: 'fixtures/mts/tsconfig.json', target: 'es5' })], + onwarn + }); + const code = await getCode(bundle, outputOptions); + + t.false(code.includes('number'), code); + t.false(code.includes('const'), code); +}); + +test.serial('runs cts code through typescript', async (t) => { + const bundle = await rollup({ + input: 'fixtures/cts/main.ts', + plugins: [typescript({ tsconfig: 'fixtures/cts/tsconfig.json', target: 'es5' })], + onwarn + }); + const code = await getCode(bundle, outputOptions); + + t.false(code.includes('number'), code); + t.false(code.includes('const'), code); +}); + test.serial('runs code through typescript with compilerOptions', async (t) => { const bundle = await rollup({ input: 'fixtures/basic/main.ts', @@ -375,6 +399,28 @@ test.serial('should not resolve .d.ts files', async (t) => { t.deepEqual(imports, ['an-import']); }); +test.serial('should not resolve .d.cts files', async (t) => { + const bundle = await rollup({ + input: 'fixtures/dts/main.cts', + plugins: [typescript({ tsconfig: 'fixtures/dcts/tsconfig.json' })], + onwarn, + external: ['an-import'] + }); + const imports = bundle.cache.modules[0].dependencies; + t.deepEqual(imports, ['an-import']); +}); + +test.serial('should not resolve .d.mts files', async (t) => { + const bundle = await rollup({ + input: 'fixtures/dts/main.mts', + plugins: [typescript({ tsconfig: 'fixtures/dmts/tsconfig.json' })], + onwarn, + external: ['an-import'] + }); + const imports = bundle.cache.modules[0].dependencies; + t.deepEqual(imports, ['an-import']); +}); + test.serial('should transpile JSX if enabled', async (t) => { process.chdir('fixtures/jsx'); From c52226ba9567ba064246ecc05e8e9bd24985ab01 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sun, 28 Aug 2022 18:53:49 +1200 Subject: [PATCH 3/4] docs: explain what the is used for --- packages/typescript/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index ee56d6eb3..11496c7df 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -17,6 +17,9 @@ import { preflight } from './preflight'; import createWatchProgram, { WatchProgramHelper } from './watchProgram'; import TSCache from './tscache'; +/** + * The glob pattern used to test if a given file extension corresponds to a TypeScript file. + */ const defaultTsExtensionsGlob = '?(m|c)ts+(|x)'; export default function typescript(options: RollupTypescriptOptions = {}): Plugin { From c7a3d65a28c424ed3e156a18cbf276a34513176e Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Sun, 28 Aug 2022 18:56:12 +1200 Subject: [PATCH 4/4] fix: improve detection of type declaration files --- packages/typescript/src/index.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index 11496c7df..dd027c46c 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import { createFilter } from '@rollup/pluginutils'; import { Plugin, RollupOptions, SourceDescription } from 'rollup'; -import type { Watch } from 'typescript'; +import type { ResolvedModuleFull, Watch } from 'typescript'; import { RollupTypescriptOptions } from '../types'; @@ -119,8 +119,7 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi const resolved = resolveModule(importee, containingFile); if (resolved) { - if (resolved.extension.startsWith('.d.') && resolved.extension.match(/\./g)?.length === 2) - return null; + if (isTypeDeclarationFile(resolved)) return null; return path.normalize(resolved.resolvedFileName); } @@ -183,3 +182,16 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi } }; } + +/** + * Check if the given resolved TypeScript module is a type declaration. + */ +function isTypeDeclarationFile(resolved: ResolvedModuleFull) { + const lastDotDDot = resolved.extension.lastIndexOf('.d.'); + if (lastDotDDot < 0) return false; + + const lastDot = resolved.extension.lastIndexOf('.'); + + // Ensure the dot is the second one in `.d.` + return lastDot === lastDotDDot + 2; +}