Как заменить TypeParameter из TypeNode с помощью компилятора машинописного текста - PullRequest
0 голосов
/ 09 апреля 2020

Я обрабатываю членов класса и хотел бы заменить вхождения O на строку.

Ввод:

class Sample {
  sn<O extends string>(input:{ one: O, twO : {k : O} ,three:O[] }) {
  }
}

Пример обработки:

methods.map(m => {
        const n = m.name.getText();
        const params = m.parameters
        const pl = params.length;
        let payload = ""
        if (pl === 1) {
            payload = params[0].type!.getText() //{one: O, two : {k : O},three:O[] })
            if (m.typeParameters) { // if typeParams exist i want replace all occurence of TypeReference O with string
                const tp = m.typeParameters[0]
              payload = `{one: string, twO : {k : string},three:string[] })` // i want result like this
            }
        } 

1 Ответ

1 голос
/ 10 апреля 2020

В таких случаях полезно изучить структуру AST вашего кода и обращаться к ней при создании решения. Вы можете анализировать AST с помощью TypeScript AST Viewer.

Вот как выглядит ваш код

Здесь вы можете видеть, что ваш MethodDeclaration имеет свойство typeParameters, которое является массивом TypeParameter. Он также имеет parameters, который является массивом Parameter.

. Вам нужно заменить любой TypeReference, который встречается в любом потомке узлов в parameters, который указывает на O с соответствующим свойством TypeParameter O constraint.

Для этого есть несколько маршрутов. Самый простой и наиболее широко документированный подход - это использование трансформатора.

Пример кода

Следующий пример будет применяться ко всем методам. Он ищет TypeReference узлов в любом месте parameters NodeArray и проверяет, является ли это ссылкой на один из TypeParameter s метода. Если это так, он заменит эту ссылку своим ограничением.

Это немного шире, чем ваш вопрос, но я предположил, что ваше реальное приложение может быть ближе к этому. Если нет, то вы сможете легко изменить его, чтобы указать целевые c методы или имена параметров.

Надеемся, это поможет вам указать правильное направление

Попробуйте код в StackBlitz: https://stackblitz.com/edit/typescript-transformer-example?file=index.ts

import * as ts from 'typescript'
import { Node, SourceFile } from 'typescript'


/* ****************************************************************************************************************** *
 * Code to transform
 * ****************************************************************************************************************** */

const cls = `
class Sample {
  sn<O extends string>(input:{ one: O, twO : {k : O} ,three:O[] }) {
  }
}
`;


/* ****************************************************************************************************************** *
 * Transformer
 * ****************************************************************************************************************** */

const transformer = (ctx: ts.TransformationContext) => (sourceFile: SourceFile): SourceFile => {
    function paramVisitor(baseMethod: ts.MethodDeclaration) {
        return (node: Node): Node => {
            if (ts.isTypeReferenceNode(node)) {
                const typeParam = baseMethod.typeParameters.find(t => t.name.escapedText === (node.typeName as ts.Identifier).escapedText);
                if (typeParam) return typeParam.constraint;
            }

            return ts.visitEachChild(node, paramVisitor(baseMethod), ctx);
        };
    }

    const visit = (node: Node): Node => {
        if (ts.isMethodDeclaration(node))
            return ts.updateMethod(
                node,
                node.decorators,
                node.modifiers,
                node.asteriskToken,
                node.name,
                node.questionToken,
                node.typeParameters,
                ts.visitNodes(node.parameters, paramVisitor(node)),
                node.type,
                node.body
            );

        return ts.visitEachChild(node, visit, ctx);
    };

    return ts.visitNode(sourceFile, visit);
};


/* ****************************************************************************************************************** *
 * Demonstration
 * ****************************************************************************************************************** */

const s = ts.createSourceFile('example.ts', cls, ts.ScriptTarget.ES5);
const { transformed } = ts.transform(s, [ transformer ]);

console.log(ts.createPrinter().printFile(transformed.find(f => f.fileName === 'example.ts')));

Рекомендуемое чтение:

Как написать преобразование TypeScript (плагин)

Создание TypeScript Transformer

Рекомендуемые инструменты:

ts-query - Для более хирургического подхода

ts-morph - может помочь упростить работу API компилятора.

ts-patch - если вам нужно применять преобразователи во время компиляции ts c

PS

В будущем добавьте тег typescript-compiler-api к своим сообщениям. На эти типы вопросов гораздо больше шансов получить ответ с помощью этого тега.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...