Skip to content

Commit

Permalink
Merge pull request #15 from Hajime-san/fix-transform
Browse files Browse the repository at this point in the history
fix: transform internal implementation
  • Loading branch information
Hajime-san authored Sep 9, 2023
2 parents 021f249 + 3e0d95f commit 15d9ddf
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 142 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ Please install [Deno](https://deno.land/[email protected]/getting_started/installat
## command
### remote
- dry run
- `deno run --allow-env --allow-read --allow-write https://deno.land/x/[email protected].18/bin.ts -b=./src -c=./tsconfig.json -d`
- `deno run --allow-env --allow-read --allow-write https://deno.land/x/[email protected].19/bin.ts -b=./src -c=./tsconfig.json -d`
- transform
- `deno run --allow-env --allow-read --allow-write https://deno.land/x/[email protected].18/bin.ts -b=./src -c=./tsconfig.json -r`
- `deno run --allow-env --allow-read --allow-write https://deno.land/x/[email protected].19/bin.ts -b=./src -c=./tsconfig.json -r`
### local
- `deno task run-dry`
- `deno task run`
Expand Down
1 change: 1 addition & 0 deletions src/bin_internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const main = async (args: {
targetFileAbsPath,
fileContent,
ts.ScriptTarget.ESNext,
true,
);

const result = restoreNewLine(
Expand Down
61 changes: 8 additions & 53 deletions src/resolve_util.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import { path, ts } from './deps.ts';
import { relativeFilePath } from './path.ts';

type NodeLike = ts.Node | ts.Expression;

type HasModuleSpecifierNode = ts.ImportDeclaration | ts.ExportDeclaration;

type TokenObject = NodeLike & {
text: string;
};

export const isTokenObject = (node: NodeLike): node is TokenObject => {
// deno-lint-ignore no-prototype-builtins
return (node as unknown as Record<string, unknown>).hasOwnProperty('text');
};

export const resolveModuleName = (args: {
fileName: string;
targetFileAbsPath: string;
Expand Down Expand Up @@ -62,47 +49,15 @@ export const hasShouldResolveImportedFiles = (args: {
return true;
};

type ModuleSpecifierReturnType<T extends HasModuleSpecifierNode> = T extends
ts.ImportDeclaration ? string : string | undefined;

export const getModuleSpecifier = <T extends HasModuleSpecifierNode>(args: {
node: T;
export const getResolvedStringLiteral = (args: {
originalText: string;
imports: ReturnType<typeof resolvedModules>;
}): {
moduleSpecifier: ModuleSpecifierReturnType<T>;
} => {
const { node, imports } = args;
let moduleSpecifier: ModuleSpecifierReturnType<T>;
if (node.moduleSpecifier && isTokenObject(node.moduleSpecifier)) {
const _moduleSpecifier = node.moduleSpecifier;
moduleSpecifier = imports.find((v) =>
v.original === _moduleSpecifier.text
)?.resolved ??
_moduleSpecifier.text;
}
return {
// @ts-ignore Variable 'X' is used before being assigned. deno-ts(2454)
moduleSpecifier,
};
};

export const getExpressionArguments = (args: {
node: ts.CallExpression;
imports: ReturnType<typeof resolvedModules>;
}): {
expressionArguments: Array<string>;
} => {
const { node, imports } = args;
const expressionArguments = node.arguments.map((argument) => {
if (isTokenObject(argument)) {
return imports.find((v) => v.original === argument.text)?.resolved ??
argument.text;
}
}).filter((v) => typeof v !== 'undefined') as Array<string>;

return {
expressionArguments,
};
}): string => {
const { originalText, imports } = args;
// trim quotes
const formattedText = originalText.slice(1, -1);
return imports.find((v) => v.original === formattedText)?.resolved ??
formattedText;
};

export type ResolvedModuleImport = {
Expand Down
52 changes: 9 additions & 43 deletions src/resolve_util_test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
import { asserts } from './dev_deps.ts';
import { path } from './deps.ts';
import {
getExpressionArguments,
getModuleSpecifier,
getResolvedStringLiteral,
hasShouldResolveImportedFiles,
isTokenObject,
resolvedModules,
resolveModuleName,
} from './resolve_util.ts';
import {
externalLibImportDeclaration,
localCallExpression,
localSourceImportDeclaration,
tsConfigMockObject,
} from './tests/fixture/mod.ts';
import { tsConfigMockObject } from './tests/fixture/mod.ts';
const { assertEquals } = asserts;
const __dirname = path.dirname(path.fromFileUrl(import.meta.url));

Deno.test('isTokenObject', () => {
assertEquals(
isTokenObject(localSourceImportDeclaration.moduleSpecifier),
true,
);
});

Deno.test('resolveModuleName', async (t) => {
await t.step('local module', () => {
assertEquals(
Expand Down Expand Up @@ -130,46 +116,26 @@ Deno.test('hasShouldResolveImportedFiles', async (t) => {
});
});

Deno.test('getModuleSpecifier', async (t) => {
Deno.test('getResolvedStringLiteral', async (t) => {
await t.step('local module', () => {
assertEquals(
getModuleSpecifier({
node: localSourceImportDeclaration,
getResolvedStringLiteral({
originalText: '"./ComponentA"',
imports: [
{ original: './ComponentA', resolved: './ComponentA.tsx' },
],
}),
{
moduleSpecifier: './ComponentA.tsx',
},
'./ComponentA.tsx',
);
});

await t.step('node_module', () => {
assertEquals(
getModuleSpecifier({
node: externalLibImportDeclaration,
getResolvedStringLiteral({
originalText: '\'react\'',
imports: [],
}),
{
moduleSpecifier: 'react',
},
);
});
});

Deno.test('getExpressionArguments', async (t) => {
await t.step('local module', () => {
assertEquals(
getExpressionArguments({
node: localCallExpression,
imports: [
{ original: './ComponentE', resolved: './ComponentE.tsx' },
],
}),
{
expressionArguments: ['./ComponentE.tsx'],
},
'react',
);
});
});
67 changes: 24 additions & 43 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ts } from './deps.ts';
import {
getExpressionArguments,
getModuleSpecifier,
getResolvedStringLiteral,
ResolvedModuleImport,
} from './resolve_util.ts';
import { hasUnicodeStr, unescapeUnicodeStr } from './str.ts';
Expand Down Expand Up @@ -42,62 +41,44 @@ const transformModuleSpecifier = (
// to
// const foo = import('./foo.(ts|tsx)');
if (
ts.isCallExpression(newNode) &&
newNode.expression.kind === ts.SyntaxKind.ImportKeyword
ts.isStringLiteral(newNode) &&
ts.isCallExpression(newNode.parent) &&
newNode.parent.expression.kind === ts.SyntaxKind.ImportKeyword
) {
const { expressionArguments } = getExpressionArguments({
node: newNode,
const resolvedStringLiteral = getResolvedStringLiteral({
originalText: newNode.getText(sourceFile),
imports,
});
return context.factory.updateCallExpression(
newNode,
newNode.expression,
newNode.typeArguments,
expressionArguments.map((argument) =>
context.factory.createStringLiteral(argument)
),
);
return context.factory.createStringLiteral(resolvedStringLiteral);
}

// Transform "aggregating modules"
if (ts.isExportDeclaration(newNode)) {
const { moduleSpecifier } = getModuleSpecifier({
node: newNode,
// export { foo } from "./foo"
// to
// export { foo } from "./foo.(ts|tsx|d.ts)"
if (
ts.isStringLiteral(newNode) && ts.isExportDeclaration(newNode.parent)
) {
const resolvedStringLiteral = getResolvedStringLiteral({
originalText: newNode.getText(sourceFile),
imports,
});
// export { foo } from "./foo"
// to
// export { foo } from "./foo.(ts|tsx|d.ts)"
if (moduleSpecifier) {
return context.factory.updateExportDeclaration(
newNode,
newNode.modifiers,
newNode.isTypeOnly,
newNode.exportClause,
context.factory.createStringLiteral(moduleSpecifier),
newNode.assertClause,
);
}
//
// export { foo }
return newNode;
return context.factory.createStringLiteral(resolvedStringLiteral);
}

// Transform "static import"
//
// import { bar } from "./bar"
// to
// import { bar } from "./bar.(ts|tsx|d.ts)"
if (ts.isImportDeclaration(newNode)) {
const { moduleSpecifier } = getModuleSpecifier({
node: newNode,
if (
ts.isStringLiteral(newNode) && ts.isImportDeclaration(newNode.parent)
) {
const resolvedStringLiteral = getResolvedStringLiteral({
originalText: newNode.getText(sourceFile),
imports,
});
return context.factory.updateImportDeclaration(
newNode,
newNode.modifiers,
newNode.importClause,
context.factory.createStringLiteral(moduleSpecifier),
newNode.assertClause,
);
return context.factory.createStringLiteral(resolvedStringLiteral);
}
return newNode;
};
Expand Down
3 changes: 2 additions & 1 deletion src/transform_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Deno.test('transform', async (t) => {
`const bigIntLiterals = 0o777777777777n;\n` +
`const numericSeparators = 100_000;\n`,
ts.ScriptTarget.ESNext,
true,
),
imports: [
{ original: './ComponentA', resolved: './ComponentA.tsx' },
Expand All @@ -23,7 +24,7 @@ Deno.test('transform', async (t) => {
printer: ts.createPrinter(),
}),
`import { ComponentA } from "./ComponentA.tsx";\n` +
`const str = "😎";\n` +
`const str = '😎';\n` +
`const bigIntLiterals = 0o777777777777n;\n` +
`const numericSeparators = 100_000;\n`,
);
Expand Down

0 comments on commit 15d9ddf

Please sign in to comment.