I have to modify around 1 000 of typescript files in a specific way: I need to replace all StringLiteral
and JsxText
tokens with a CallExpression
to a translation function for internationalization purposes of my application.
I've already done such a task with our C# codebase with Roslyn, so now I'm trying to accomplish similar task with typescript compiler API. It's quite similar to the Roslyn API, but they have a nasty difference. In Roslyn you have a notion of Trivia tokens: such that doesn't emit to anything interesting, but are essential for readability purposes. Those are whitespaces, tabs, comments, etc. In a Roslyn syntax tree you have all the trivia from your source file. When you change your C# syntax tree in a some way and emit source code back from that syntax tree, you have all the same formatting, comments, whitespaces and all that stuff.
Unfortunatedly there aren't any trivia tokens in a typescript AST, so when I use code like this all my formatting goes away.
const result: ts.TransformationResult<ts.SourceFile> = ts.transform(
sourceFile, [ transformerFactory(visitorFunction) ]
);
const transformedSourceFile: ts.SourceFile = result.transformed[0];
const printer: ts.Printer = ts.createPrinter();
const generated: string = printer.printNode( ts.EmitHint.SourceFile, transformedSourceFile, sourceFile);
What options do I have?
- I can stick with a described above approach, but it will lead to lots of useless editing, spoiled github history and gigantic pull request. Whith this approach I should definitedly use Prettier after my transformations and probably I should install it as a developer dependancy and in our CI so we don't have such problems in future.
- I can still use AST for detection of my tokens, but I can make transformation without
ts.Printer
andts.Transformation
. I can get all literals to process during the detection phase, order them by their position in file descending and replace them usingsubstring
or something like this. This is quite tricky thing and I don't really want to do that, but I'm not happy with downsides of the first option.
So what should I do? Do I have some other options?
ts.createFormattingScanner()
may also be useful. – Josh Bowden