Tim*_*sky 6 compiler-construction abstract-syntax-tree automated-refactoring typescript
我必须以特定的方式修改大约1000个打字稿文件:为了我的应用程序的国际化,我需要将全部StringLiteral和JsxText令牌替换CallExpression为翻译功能。
我已经使用Roslyn在我们的C#代码库中完成了这样的任务,因此现在我正在尝试使用Typescript编译器API完成类似的任务。它与Roslyn API十分相似,但是它们之间有一个讨厌的区别。在Roslyn中,您有Trivia令牌的概念:这种令牌不会发出任何有趣的东西,但对于可读性而言是必不可少的。这些是空格,制表符,注释等。在Roslyn语法树中,您具有源文件中的所有琐事。当您以某种方式更改C#语法树并从该语法树发出源代码时,您将拥有所有相同的格式,注释,空格以及所有这些东西。
不幸的是,打字稿AST中没有任何琐事标记,因此当我使用这样的代码时,所有格式都会消失。
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);Run Code Online (Sandbox Code Playgroud)
我有什么选择?
ts.Printer和的情况下进行转换ts.Transformation。我可以让所有文字在检测阶段进行处理,按照它们在文件中的降序排列,并使用substring或类似的方法替换它们。这是一件非常棘手的事情,我真的不想这样做,但是我对第一种选择的弊端不满意。所以我该怎么做?我还有其他选择吗?
您可以使用捕获格式和注释的工具,并在转换过程完成后重新生成它们,正如您注意到 Roslyn 所做的那样。然而,Roslyn 和 TypeScript“编译器”是特定于其目标语言的。
一般来说,你想要的是一个“程序转换系统”。这些工具接受语法,自动构建捕获所有格式化数据的 AST,允许您使用源代码级模式定义转换,并通过匹配/修补 AST 来执行这些转换,并且它们漂亮地打印保留格式化数据的修改后的树。
我们的DMS 软件重组工具包可以做到这一点。
必须为其定义目标语言语法;我们已经对包括 JavaScript 在内的许多语言进行了开发,但尚未对 TypeScript 进行过开发。但是,您可以通过构建其他定义来构建语言方言。或者,您可以从头开始编写 TypeScript;如果你有明确的语法,这并不难,我认为 TypeScript 也存在这种语法。该定义的一部分告诉解析器如何识别注释,以便保存它们;DMS 知道如何保存所有格式和布局数据。
这样,为了解决您的特定任务,您可以使用 DMS 重写规则编写实际上非常简单的转换:
source domain ECMAScript~TypeScript; -- assuming TypeScript is built as a dialect
target domain ECMAScript~TypeScript; -- we're defining rules that map TypeScript to itself
-- you could write rules map TypeScript to C++ if you insist
rule InternationalizeStringLiteral(s:STRINGLITERAL): primary-> primary
= "\s"-> "Translate(\s)";
rule InternationalizeJsText(jst:JSTText): primary -> primary
= " \jst " -> "Translate(\jst)";
ruleset Internationalize = { InternationalizeStringLiteral, InternationalizeJsText};
Run Code Online (Sandbox Code Playgroud)
您可以要求 DMS 解析文件,将规则集自下而上应用到您的树,然后漂亮地打印结果。
这些规则是完全语法感知的,因为它们在 AST 上运行,因此它们不会被注释或字符串文字中的文本或行边界/空白/格式/交织注释所愚弄,...
现在,您有 1000 个文件需要更改。这已经足够大了,因此定义 TypeScript 和应用 DMS 可能是值得的。(如果 DMS 的 TypeScript 前端已经准备好,那么就完成上述操作)。有时并非如此;YMMV 取决于你真正想做的事情。DMS 最适合在大型代码库上使用,如果您需要进行复杂的转换,DMS 确实会大放异彩。