diff --git a/example/src/routeInfo.tsx b/example/src/routeInfo.tsx index 2b27679..127a7e8 100644 --- a/example/src/routeInfo.tsx +++ b/example/src/routeInfo.tsx @@ -7,10 +7,22 @@ export default () => ( + , + + + , + + , + {/* + , + */} - Swap expression + log-identifiers + return-multiple-node + swap-expression + {/* rename-symbol */} diff --git a/example/src/transforms/index.ts b/example/src/transforms/index.ts index 8004532..9e382f0 100644 --- a/example/src/transforms/index.ts +++ b/example/src/transforms/index.ts @@ -1,8 +1,18 @@ +import LogIdentifiers from "./log-identifiers"; +import ReturnMultipleNode from "./return-multiple-node"; import SwapExpression from "./swap-expression"; +// import RenameSymbol from "./rename-symbol"; import { TransformModuleExport } from "src/types"; -export type ModuleNames = "swap-expression"; +export type ModuleNames = + | "swap-expression" + | "return-multiple-node" + | "log-identifiers"; + // | "rename-symbol" export const moduleMap: { [key in ModuleNames]: TransformModuleExport } = { - "swap-expression": SwapExpression + "swap-expression": SwapExpression, + "return-multiple-node": ReturnMultipleNode, + "log-identifiers": LogIdentifiers, + // "rename-symbol": RenameSymbol }; diff --git a/example/src/transforms/log-identifiers.ts b/example/src/transforms/log-identifiers.ts new file mode 100644 index 0000000..2ac77f3 --- /dev/null +++ b/example/src/transforms/log-identifiers.ts @@ -0,0 +1,32 @@ +import * as ts from "typescript"; +import { TransformModuleExport } from "../types"; + +const sourceCodeString = `\ +let foo = 1, bar = 2; +foo = bar; +{ + bar++; + "bar" + function() {console.log(bar)} +} +`; + +const transformer: ts.TransformerFactory = context => { + return sourceFile => { + const visitor = (node: ts.Node): ts.Node => { + if (ts.isIdentifier(node)) { + console.log(node.text); + } + return ts.visitEachChild(node, visitor, context); + }; + + return ts.visitNode(sourceFile, visitor); + }; +}; + +const toExport: TransformModuleExport = { + sourceCodeString, + transformer, +}; + +export default toExport; diff --git a/example/src/transforms/rename-symbol.ts b/example/src/transforms/rename-symbol.ts new file mode 100644 index 0000000..ba071c9 --- /dev/null +++ b/example/src/transforms/rename-symbol.ts @@ -0,0 +1,96 @@ +import * as ts from "typescript"; +import { TransformModuleExport } from "../types"; + +const sourceCodeString = `\ +let foo = 1; +foo = 2; +{ + const foo = "abcd"; +} +foo = 3; +`; + +// Renames all references to the first identifier with the text "foo" +const identifierText = "foo"; +const identifierMatchIndex = 1; +const newIdentifierText = "bar"; + +const transformerProgram = (program: ts.Program) => { + const typeChecker = program.getTypeChecker(); + + const transformerFactory: ts.TransformerFactory = context => { + return sourceFile => { + // 1. Find the symbol, if any + let identifierCurrentIndex = -1; + const findSymbolVisitor = (node: ts.Node): ts.Symbol | undefined => { + if (ts.isIdentifier(node)) { + const relatedSymbol = typeChecker.getSymbolAtLocation(node); + + if (relatedSymbol === undefined) { + return; + } + console.log(relatedSymbol.escapedName); + if (relatedSymbol.escapedName === identifierText) { + identifierCurrentIndex += 1; + if (identifierCurrentIndex === identifierMatchIndex) { + console.log("found"); + return relatedSymbol; + } + } + } + + return ts.forEachChild(node, findSymbolVisitor); + }; + + // 2. Mark the identifiers, if any + const foundIdentifiers = new Array(); + const findIdentifiersVisitor = (node: ts.Node): true | undefined => { + if (ts.isIdentifier(node)) { + const relatedSymbol = typeChecker.getSymbolAtLocation(node); + + if (relatedSymbol === foundSymbol) { + foundIdentifiers.push(node); + // Stop finding + return true; + } + } + + ts.forEachChild(node, findIdentifiersVisitor); + return undefined; + }; + + // 3. Modify the identifiers + const modifyIdentifiersVisitor = (node: ts.Node): ts.Node => { + if (ts.isIdentifier(node) && foundIdentifiers.includes(node)) { + return ts.updateIdentifier(ts.createIdentifier(newIdentifierText)); + } + + return ts.visitEachChild(node, modifyIdentifiersVisitor, context); + }; + + // Execute step 1 + const foundSymbol = ts.forEachChild(sourceFile, findSymbolVisitor); + + // Execute step 2, if step 1 passed + if (foundSymbol) { + ts.forEachChild(sourceFile, findIdentifiersVisitor); + } + + // Execute step 3, if step 2 passed + if (foundIdentifiers.length > 0) { + return ts.visitNode(sourceFile, modifyIdentifiersVisitor); + } + + return sourceFile; + }; + }; + + return transformerFactory; +}; + +const toExport: TransformModuleExport = { + sourceCodeString, + transformer: transformerProgram +}; + +export default toExport; diff --git a/example/src/transforms/return-multiple-node.ts b/example/src/transforms/return-multiple-node.ts new file mode 100644 index 0000000..f618552 --- /dev/null +++ b/example/src/transforms/return-multiple-node.ts @@ -0,0 +1,32 @@ +import * as ts from "typescript"; +import { TransformModuleExport } from "../types"; + +const sourceCodeString = `\ +let a = 1; +a = 2; +a++; +`; + +const transformer: ts.TransformerFactory = context => { + return sourceFile => { + const visitor = (node: ts.Node): ts.VisitResult => { + // If it is a expression statement, + if (ts.isExpressionStatement(node)) { + // Return it twice. + // Effectively duplicating the statement + return [node, node]; + } + + return ts.visitEachChild(node, visitor, context); + }; + + return ts.visitNode(sourceFile, visitor); + }; +}; + +const toExport: TransformModuleExport = { + sourceCodeString, + transformer, +}; + +export default toExport; diff --git a/example/src/transforms/swap-expression.ts b/example/src/transforms/swap-expression.ts index d00a2e3..e6163da 100644 --- a/example/src/transforms/swap-expression.ts +++ b/example/src/transforms/swap-expression.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import { TransformModuleExport } from "../types"; -const sourceCodeString = `x = y; a = b + c`; +const sourceCodeString = `x = y; a = b + c;`; const transformer: ts.TransformerFactory = context => { return sourceFile => {