SILENT
SILENT

Reputation: 4258

Typescript Transformer - QuestionToken missing

I made a simple transformer.

import ts from "typescript";
import path from "path";

export function Transformer(
    checker: ts.TypeChecker,
): ts.TransformerFactory<ts.SourceFile> {
    return (context) => {
        const v: ts.Visitor = (node: ts.Node) => {
            console.log(node.kind);
            return ts.visitEachChild(node, v, context);
        };
        return (node) => ts.visitNode(node, v);
    };
}

async function MainAsync() {
    const dir = path.resolve("./");
    const filePathIn = path.resolve(dir, "./src/test.ts");
    console.log({ filePathIn });
    const program = ts.createProgram([filePathIn], {});
    const checker = program.getTypeChecker();
    const source = program.getSourceFile(filePathIn);
    console.log("checking source");
    if (!source) return;
    console.log("run through transformer");
    await ts.transform(source, [Transformer(checker)]);
    // console.log({ result });
}

MainAsync();

Testing against a simple test.ts file

export class TestMe {
    id0?: {
        test0: string;
    };
    id: number;
}

Codesandbox link

The console output is

297 - SourceFile
252 - ClassDeclaration
92 - ExportKeyword
78 - Identifier
163 - PropertyDeclaration
78 - Identifier
>>> MISSING 57 - QuestionToken
177 - TypeLiteral
162 - PropertySignature
78 - Identifier
147 - StringKeyword
163 - PropertyDeclaration
78 - Identifier
144 - NumberKeyword

Note that its missing 57 - QuestionToken. I also confirmed the expected test.ts output via TypeScript AST Viewer.

Typescript still checks if its an optional type if I try to use it via VSCode. Whats going on? How do I force the QuestionToken to appear?

Github reference

Upvotes: 0

Views: 244

Answers (1)

Ryan Cavanaugh
Ryan Cavanaugh

Reputation: 220884

You need to provide a tokenVisitor to visitEachChild:

import ts = require("typescript");
import path = require("path");

export function Transformer(
    checker: ts.TypeChecker,
): ts.TransformerFactory<ts.SourceFile> {
    return (context) => {
        const v: ts.Visitor = (node: ts.Node) => {
            console.log(node.kind + ' - ' + ts.SyntaxKind[node.kind]);
            return ts.visitEachChild(node, v, context, undefined, visitToken);
        };
        return (node) => ts.visitNode(node, v);
    };

    function visitToken(t: ts.Node) {
        console.log(ts.SyntaxKind[t.kind]);
        return t;
    }
}

async function MainAsync() {
    const dir = path.resolve("./");
    const filePathIn = path.resolve(dir, "test.ts");
    console.log({ filePathIn });
    const program = ts.createProgram([filePathIn], {});
    const checker = program.getTypeChecker();
    const source = program.getSourceFile(filePathIn);
    console.log("checking source");
    if (!source) return;
    console.log("run through transformer");
    await ts.transform(source, [Transformer(checker)]);
}

MainAsync().then(() => { });

Upvotes: 2

Related Questions