Мне нужно изменить около 1000 файлов машинописных текстов определенным образом: мне нужно заменить все токены StringLiteral и JsxText на CallExpression для функции перевода для целей интернационализации моего приложения.
Я уже выполнил такую задачу с нашей кодовой базой C# с помощью Roslyn, поэтому теперь я пытаюсь выполнить аналогичную задачу с помощью API компилятора машинописного текста. Он очень похож на API Roslyn, но у них есть неприятная разница. В 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);Какие у меня есть варианты?
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};
Вы можете попросить DMS проанализировать файл, применить набор правил снизу вверх к вашему дереву, а затем распечатать результат.
Эти правила полностью осведомлены о синтаксисе, потому что они работают с AST, поэтому их не обманывает текст в комментариях или строковые литералы, или границы строк / пробелы / форматы / переплетенные комментарии, ...
Теперь вам нужно изменить 1000 файлов. Он достаточно велик, поэтому стоит попытаться определить TypeScript и применить DMS. (Если бы интерфейс TypeScript для DMS был готов, сделайте то же самое). Иногда это не так; YMMV в зависимости от того, чем вы действительно хотите заниматься. DMS лучше всего использовать на больших базах кода и действительно эффективен, если вам нужно выполнить сложные преобразования.
TypeScript фактически сохраняет понятие мелочей, я думаю, это просто не так четко представлено в API. Вы можете посмотреть: basarat.gitbook.io/typescript/overview/ast/…. Вот пример, в котором вы можете видеть, что AST сохраняет мелочи, но вам нужно вручную получить их: ts-ast-viewer.com/#code/…. Также может быть полезно взглянуть на использование
ts.createFormattingScanner().