Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: transform internal implementation #15

Merged
merged 4 commits into from
Sep 9, 2023
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
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