Я хотел бы выполнить следующие преобразования для одного конкретного класса c с помощью специального преобразователя машинописного текста. Функция helper.isTargetClass(node)
может, например, быть служебным методом для преобразования правильного класса. Но этот logi c на самом деле не является частью вопроса.
if (ts.isClassDeclaration(node) && helper.isTargetClass(node) {
/**
* 1)
* I would like to add a child to the class declaration.
* Specifically I would like to add a static property.
* E.g. public static instances = [];
*/
/**
* 2)
* I would like to add a constructor if there is none defined
*/
/**
* 3)
* I would like to insert the following line in the constructor block.
* this.instances.push(this);
*/
/**
* 4)
* I would like to to something for each method declaration.
* Specifically on ts.isMethodDeclaration(node)
* The use case does not matter.
* But e.g. changing...
*
* public greet(): string {
* return "Hello";
* }
*
* ... to public greet = jasmine.createSpy();
*/
/**
* 5)
* I would like to do something on property declaration.
* Specifically on ts.isPropertyDeclaration(node)
* The use case does not matter.
* But e.g. changing public myNumber = 7; to public myNumber = "7";
*/
}
Я написал небольшую вспомогательную функцию для обхода дочерних узлов узла объявления класса.
export function doForEachChild(node: ts.Node, context: ts.TransformationContext, callback: (node: ts.Node) => ts.VisitResult<ts.Node>): ts.VisitResult<ts.Node> {
const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
return callback(node);
};
return ts.visitEachChild(node, visitor, context);
}
Это могло можно использовать следующим образом:
return doForEachChild(node, context, (childNode) => {
if (ts.isConstructorDeclaration(node)) {}
if (ts.isMethodDeclaration(node)) {}
if (ts.isPropertyDeclaration(node)) {}
});
Я представил этот маленький помощник, чтобы иметь возможность использовать шаблон посетителя и изменять указанные c дочерние узлы.
Я знаю, что, возможно, смогу добавьте что-нибудь в объявление класса, например:
const extendedMembers = ts.createNodeArray([createInstancesProperty(symbol.name), ...node.members]);
return ts.createClassDeclaration(node.decorators, node.modifiers, node.name, node.typeParameters, node.heritageClauses, extendedMembers);
Но я не знаю, как скомбинировать представленный материал.
Поэтому я хотел спросить, есть ли у кого-нибудь идеи или опыт работы с этим ? Есть ли хороший подход для достижения всех желаемых задач? Можно ли использовать шаблон посетителя, если я хочу вставить дочерний узел? Имеет ли смысл мой маленький помощник или есть лучший способ подойти к этому?
Эта проблема (https://github.com/madou/typescript-transformer-handbook/issues/12) решает в основном тот же вопрос. Может быть, это поможет, если мой вопрос все еще неясен.
В этом вопросе кто-то предлагает следующее:
В общем, вы в основном хотите делать это методом исключения, пока не дойдете до узел, который вы на самом деле хотите изменить, поэтому у меня может быть что-то в выражении if, которое я хочу изменить
В моем случае я действительно не хочу что-то менять; Я хотел бы кое-что вставить. Итак, да; верно, что узел, который будет изменен, будет объявлением класса. Я уже включил фрагмент кода, как это можно сделать. Но я не знаю, как я могу изменить другие вещи / выполнить другие задачи. Это немного сложно объяснить; но так или иначе; простое изменение узла (без шаблона посетителя и возвращение VisitorResult) не поможет. По крайней мере, то, что я испытал до сих пор.
Итак, основная проблема заключается в сочетании вставки дочернего узла в объявление класса и изменения других определенных c дочерних узлов.
Буду признателен за любые предложения. Заранее спасибо.