diff --git a/modules/ts-plugins/src/ts-transform-append-extension/index.ts b/modules/ts-plugins/src/ts-transform-append-extension/index.ts index 21c93a8..886bf05 100644 --- a/modules/ts-plugins/src/ts-transform-append-extension/index.ts +++ b/modules/ts-plugins/src/ts-transform-append-extension/index.ts @@ -39,18 +39,14 @@ export default function ( extMappings.set(base, addition); } - function shouldMutateModuleSpecifier(node: Node): string | false { - if (!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) return false; - if (node.moduleSpecifier === undefined) return false; - // only when module specifier is valid - if (!ts.isStringLiteral(node.moduleSpecifier)) return false; + function shouldMutateImportSource(node: Node | undefined): string | false { + if (!node || !ts.isStringLiteral(node)) return false; // only when path is relative - if (!node.moduleSpecifier.text.startsWith('./') && !node.moduleSpecifier.text.startsWith('../')) - return false; + if (!node.text.startsWith('./') && !node.text.startsWith('../')) return false; // only when module specifier has accepted extension - const ext = path.extname(node.moduleSpecifier.text); + const ext = path.extname(node.text); if (!extMappings.has(ext)) return false; - return node.moduleSpecifier.text + extMappings.get(ext); + return node.text + extMappings.get(ext); } return (ctx: TransformationContext) => { @@ -58,9 +54,9 @@ export default function ( return (sourceFile: SourceFile) => { function visit(node: Node): Node { - const newImportSource = shouldMutateModuleSpecifier(node); - if (newImportSource) { - if (ts.isImportDeclaration(node)) { + if (ts.isImportDeclaration(node)) { + const newImportSource = shouldMutateImportSource(node.moduleSpecifier); + if (newImportSource) { const newModuleSpecifier = factory.createStringLiteral(newImportSource); node = factory.updateImportDeclaration( node, @@ -69,7 +65,10 @@ export default function ( newModuleSpecifier, node.assertClause ); - } else if (ts.isExportDeclaration(node)) { + } + } else if (ts.isExportDeclaration(node)) { + const newImportSource = shouldMutateImportSource(node.moduleSpecifier); + if (newImportSource) { const newModuleSpecifier = factory.createStringLiteral(newImportSource); node = factory.updateExportDeclaration( node, @@ -80,6 +79,16 @@ export default function ( node.assertClause ); } + } else if ( + ts.isCallExpression(node) && + node.expression.kind === ts.SyntaxKind.ImportKeyword + ) { + const newImportSource = shouldMutateImportSource(node.arguments[0]); + if (newImportSource) { + const newArgs = node.arguments.slice(); + newArgs[0] = factory.createStringLiteral(newImportSource); + node = factory.updateCallExpression(node, node.expression, node.typeArguments, newArgs); + } } return ts.visitEachChild(node, visit, ctx); diff --git a/modules/ts-plugins/test/test-transformer.ts b/modules/ts-plugins/test/test-transformer.ts index 747626f..7744954 100644 --- a/modules/ts-plugins/test/test-transformer.ts +++ b/modules/ts-plugins/test/test-transformer.ts @@ -68,7 +68,7 @@ export function assertSourceEqual( */ ignoreEmptyLines?: boolean; } = {} -): true | Error { +): true | string { const {ignoreIndent = true, ignoreEmptyLines = true} = options; const actualLines = actual.split('\n'); const expectedLines = expected.split('\n'); @@ -90,10 +90,9 @@ export function assertSourceEqual( } else if (ignoreEmptyLines && !t2) { i2++; } else { - return new Error(`Mismatch at line ${i1} + return `Mismatch at line ${i1} Actual: ${t1} - Expected: ${t2} - `); + Expected: ${t2}`; } } return true; diff --git a/modules/ts-plugins/test/ts-transform-append-extension.spec.ts b/modules/ts-plugins/test/ts-transform-append-extension.spec.ts index 78bd34a..068bd6f 100644 --- a/modules/ts-plugins/test/ts-transform-append-extension.spec.ts +++ b/modules/ts-plugins/test/ts-transform-append-extension.spec.ts @@ -3,17 +3,23 @@ import {transpile, assertSourceEqual} from './test-transformer.js'; // @ts-expect-error Aliased import, remapped to valid path in esm-loader import appendExtension from '@vis.gl/ts-plugins/ts-transform-append-extension'; -const input = `\ +const input1 = `\ export type { TypedArray } from "./types"; export { add } from "./math/add"; import vs from "../shaders/vs.glsl"; import { Shader } from "@luma.gl/core"; export { vs, Shader };`; +const input2 = `\ +const throttle = await import("lodash.throttle"); +const Matrix4 = import("./math/matrix4"); +import("./shaders").then((modules) => { });`; + const testCases = [ { title: 'add default extension to js imports', config: {after: true}, + input: input1, output: `\ export { add } from "./math/add.js"; import vs from "../shaders/vs.glsl"; @@ -23,6 +29,7 @@ export { vs, Shader };` { title: 'add default extension to d.ts imports', config: {afterDeclarations: true}, + input: input1, output: `\ export type { TypedArray } from "./types.js"; export { add } from "./math/add.js"; @@ -33,18 +40,28 @@ export { vs, Shader };` { title: 'add custom extension to js imports', config: {after: true, extensions: ['.mjs', '.glsl.mjs']}, + input: input1, output: `\ export { add } from "./math/add.mjs"; import vs from "../shaders/vs.glsl.mjs"; import { Shader } from "@luma.gl/core"; export { vs, Shader };` + }, + { + title: 'dynamic imports', + config: {after: true}, + input: input2, + output: `\ +const throttle = await import("lodash.throttle"); +const Matrix4 = import("./math/matrix4.js"); +import("./shaders.js").then((modules) => { });` } ]; test('ts-transform-append-extension', (t) => { for (const testCase of testCases) { const result = transpile({ - source: input, + source: testCase.input, transformer: appendExtension, config: testCase.config, outputType: testCase.config.afterDeclarations ? 'd.ts' : 'js'