Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add comment before function using TypeScript Compiler API

I have a TypeScript file which I want transpiled to JavaScript. As part of this translation, I want to add a comment before every function and I was hoping to do this using the TypeScript Compiler API.

I tried two different approaches. One of them was to grab the SourceFile and change its statements, like this:

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,
    );
}));

which gives me the following error:

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)

I tried printing the statement right before the ts.addSyntheticLeadingComment and the statement is a FunctionDeclaration, as expected, albeit missing the emitNode field, which I would expect to be created by the getOrCreateEmitNode function.

The second approach I tried is similar, but it runs into the same issue; rather than overwriting the original srcFile.statement, I'm working with a printer, as follows:

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));

which gives the same error as the previous code.

The TypeScript file I am trying to change is very simple:

function myFunc(a: number, b: number): number {
    return a + b;
}
like image 536
Radu Szasz Avatar asked Mar 07 '23 08:03

Radu Szasz


1 Answers

Substituting the node is not necessary. Remember that comments aren't part of the AST, so don't add them to the array of statements in the place of the existing function declaration. Instead, just call addSyntheticLeadingComment on the node without using the return value.

For example, the following code works fine:

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));

Outputs:

/*My long desired comment*/
function myFunc(a: number, b: number): number {
    return a + b;
}
like image 78
David Sherret Avatar answered Mar 23 '23 03:03

David Sherret