Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions modules/ts-plugins/src/ts-transform-append-extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,24 @@ 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) => {
const {factory} = ctx;

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,
Expand All @@ -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,
Expand All @@ -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);
Expand Down
7 changes: 3 additions & 4 deletions modules/ts-plugins/test/test-transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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;
Expand Down
21 changes: 19 additions & 2 deletions modules/ts-plugins/test/ts-transform-append-extension.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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";
Expand All @@ -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'
Expand Down
Loading