Добавить комментарий перед функцией с помощью TypeScript Compiler API

У меня есть файл TypeScript, который я хочу перенести на JavaScript. В рамках этого перевода я хочу добавить комментарий перед каждой функцией, и я надеялся сделать это с помощью TypeScript Compiler API.

Я пробовал два разных подхода. Один из них заключался в том, чтобы взять SourceFile и изменить его statements, вот так:

const program = ts.createProgram([args.input], {});
const srcFile = find(program.getSourceFiles(), (sourceFile) => !sourceFile.isDeclarationFile);
srcFile.statements = ts.createNodeArray(srcFile.statements.map((statement) => {
    if (!ts.isFunctionDeclaration(statement)) {
        return statement;
    }
    return ts.addSyntheticLeadingComment(
        statement,
        ts.SyntaxKind.MultiLineCommentTrivia,
        "My long desired comment",
        true,
    );
}));

что дает мне следующую ошибку:

TypeError: Cannot read property 'emitNode' of undefined
at getOrCreateEmitNode (/Users/.../node_modules/typescript/lib/typescript.js:52792:19)
at getOrCreateEmitNode (/Users/.../node_modules/typescript/lib/typescript.js:52801:17)
at setSyntheticLeadingComments (/Users/.../node_modules/typescript/lib/typescript.js:52918:9)
at Object.addSyntheticLeadingComment (/Users/.../node_modules/typescript/lib/typescript.js:52923:16)
at /Users/.../dist/index.js:26:15
at Array.map (<anonymous>)
at Object.<anonymous> (/Users/.../dist/index.js:21:60)
at Module._compile (internal/modules/cjs/loader.js:654:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)
at Module.load (internal/modules/cjs/loader.js:566:32)

Я попытался распечатать statement прямо перед ts.addSyntheticLeadingComment, а statement - это FunctionDeclaration, как и ожидалось, хотя и пропустило поле emitNode, которое, как я ожидал, будет создано функцией getOrCreateEmitNode.

Второй подход, который я пробовал, похож на него, но он сталкивается с той же проблемой; вместо того, чтобы перезаписывать исходный srcFile.statement, я работаю с принтером следующим образом:

const printer = ts.createPrinter(undefined, {
    substituteNode: (hint, node) => {
        if (ts.isFunctionDeclaration(node)) {
            return ts.addSyntheticLeadingComment(
                node,
                ts.SyntaxKind.MultiLineCommentTrivia,
                "My long desired comment",
                true,
           );
        }
    },
});

console.log(printer.printFile(srcFile));

что дает ту же ошибку, что и предыдущий код.

Файл TypeScript, который я пытаюсь изменить, очень прост:

function myFunc(a: number, b: number): number {
    return a + b;
}

Я был бы очень признателен за помощь с этим.

С уважением, Раду


person Radu Szasz    schedule 24.04.2018    source источник


Ответы (2)


Подставлять узел не нужно. Помните, что комментарии не являются частью AST, поэтому не добавляйте их в массив операторов вместо существующего объявления функции. Вместо этого просто вызовите addSyntheticLeadingComment на узле без использования возвращаемого значения.

Например, следующий код работает нормально:

import * as ts from "typescript";

const file = ts.createSourceFile("test.ts", `function myFunc(a: number, b: number): number {
    return a + b;
}`, ts.ScriptTarget.Latest, true);
const functionDec = file.statements.find(ts.isFunctionDeclaration)!;

ts.addSyntheticLeadingComment(functionDec, ts.SyntaxKind.MultiLineCommentTrivia,
    "My long desired comment", true);

const printer = ts.createPrinter({ removeComments: false });
console.log(printer.printFile(file));

Выходы:

/*My long desired comment*/
function myFunc(a: number, b: number): number {
    return a + b;
}
person David Sherret    schedule 08.02.2019

Ответ Дэвида Шеррета правильный, но я продолжал сталкиваться с Cannot read property 'emitNode' of undefined at getOrCreateEmitNode ошибками, что бы я ни пробовал.

Как оказалось, мне не хватало четвертого параметра в ts.createSourceFile под названием setParentNodes. Установив для этого параметра значение true, я смог использовать addSyntheticLeadingComment.

Обычно этот параметр (setParentNodes) устанавливает свойство parent каждого Node.

getOrCreateEmitNode необходимо пройти вверх по дереву и не может этого сделать без родительских ссылок. Дополнительные сведения о setParentNodes см. В этом выпуске Github

person PMCS    schedule 02.06.2021