Created
May 29, 2022 13:26
-
-
Save hi-ogawa/cb338b4765d25321b120b2a47819abcc to your computer and use it in GitHub Desktop.
typescript-transformer-api
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* eslint-disable no-console */ | |
| import * as fs from "fs"; | |
| import * as process from "process"; | |
| import * as ts from "typescript"; | |
| // | |
| // analyze statements of the following forms: | |
| // | |
| // const someVariable = someFunction(someObjectLiteral) | |
| // | |
| // | |
| // | |
| // transformer | |
| // | |
| const FUNCTION_NAME = "someFunction"; | |
| interface Call { | |
| name: string; | |
| data: Record<string, Record<string, string>>; | |
| } | |
| function analyzeCall(node: ts.ObjectLiteralExpression): Call["data"] { | |
| const result: Record<string, Record<string, string>> = {}; | |
| for (const prop1 of node.properties) { | |
| if ( | |
| prop1.name && | |
| (ts.isIdentifier(prop1.name) || ts.isStringLiteral(prop1.name)) && | |
| ts.isPropertyAssignment(prop1) && | |
| ts.isObjectLiteralExpression(prop1.initializer) | |
| ) { | |
| result[prop1.name.text] = {}; | |
| for (const prop2 of prop1.initializer.properties) { | |
| if (prop2.name && ts.isPropertyAssignment(prop2)) { | |
| // this includes computed property names | |
| result[prop1.name.text][prop2.name.getText()] = prop2.initializer.getText(); | |
| } else { | |
| // object spreads come here | |
| console.error("ERROR: unexpected prop2", prop1.getText()); | |
| } | |
| } | |
| } else { | |
| console.error("ERROR: unexpected prop1", prop1.getText()); | |
| } | |
| } | |
| return result; | |
| } | |
| class Extractor { | |
| public calls: Call[] = []; | |
| createTransformer(): ts.TransformerFactory<ts.SourceFile> { | |
| const extractor = this; | |
| function createVisitor(ctx: ts.TransformationContext): ts.Visitor { | |
| return function visitor(node: ts.Node): ts.Node { | |
| if (ts.isVariableDeclaration(node)) { | |
| if (node.initializer && ts.isCallExpression(node.initializer)) { | |
| const { expression, arguments: args } = node.initializer; | |
| if (ts.isIdentifier(expression) && expression.text === FUNCTION_NAME) { | |
| if ( | |
| ts.isIdentifier(node.name) && | |
| args.length === 1 && | |
| ts.isObjectLiteralExpression(args[0]) | |
| ) { | |
| extractor.calls.push({ | |
| name: node.name.text, | |
| data: analyzeCall(args[0]) | |
| }); | |
| } else { | |
| console.error("ERROR: unexpected call", node); | |
| } | |
| } | |
| } | |
| } | |
| return ts.visitEachChild(node, visitor, ctx); | |
| }; | |
| } | |
| return (ctx: ts.TransformationContext) => { | |
| return (sourceFile: ts.SourceFile) => { | |
| return ts.visitNode(sourceFile, createVisitor(ctx)); | |
| }; | |
| }; | |
| } | |
| } | |
| // | |
| // driver (cf. https://github.com/formatjs/formatjs/blob/3e1aa52c32f93bc50efd46827f3c99e2bfac6d7b/packages/ts-transformer/tests/index.test.ts#L96) | |
| // | |
| async function extractCalls(filename: string): Promise<Call[]> { | |
| const content = await fs.promises.readFile(filename, "utf-8"); | |
| const extractor = new Extractor(); | |
| ts.transpileModule(content, { | |
| compilerOptions: { | |
| target: ts.ScriptTarget.ESNext, | |
| allowJs: true | |
| }, | |
| fileName: filename, | |
| reportDiagnostics: true, | |
| transformers: { | |
| before: [extractor.createTransformer()] | |
| } | |
| }); | |
| return extractor.calls; | |
| } | |
| async function main() { | |
| const filenames = process.argv.slice(2); | |
| const result: Record<string, Call[]> = {}; | |
| for (const filename of filenames) { | |
| console.error(`:: processing "${filename}" ...`); | |
| result[filename] = await extractCalls(filename); | |
| } | |
| console.log(JSON.stringify(result, null, 2)); | |
| } | |
| if (require.main === module) { | |
| main(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment