How to add/remove modifier to/from a statement?

1k views Asked by At

I am using the TypeScript compiler API to transform TypeScript code, but one thing I haven't quite figured out is adding/removing modifiers in a generic way. The closest I've gotten is this

function removeDeclareModifier(s) {
    let modifiers;
    // Remove declare modifiers
    if (s.modifiers) {
        modifiers = s.modifiers.filter(m => m.kind !== ts.SyntaxKind.DeclareKeyword);
    } else {
        return s;
    }

    if (ts.isVariableStatement(s)) {
        return ts.updateVariableStatement(s, modifiers, s.declarationList);
    } else if (ts.isTypeAliasDeclaration(s)) {
        return ts.updateTypeAliasDeclaration(s, s.decorators, modifiers, s.name, s.typeParameters, s.type);
    } else if (ts.isInterfaceDeclaration(s)) {
        return ts.updateInterfaceDeclaration(s, s.decorators, modifiers, s.name, s.typeParameters, s.heritageClauses, s.members);
    } else if (ts.isEnumDeclaration(s)) {
        return ts.updateEnumDeclaration(s, s.decorators, modifiers, s.name, s.members);
    } else if (ts.isClassDeclaration(s)) {
        return ts.updateClassDeclaration(s, s.decorators, modifiers, s.name, s.typeParameters, s.heritageClauses, s.members);
    } else if (ts.isFunctionDeclaration(s)) {
        return ts.updateFunctionDeclaration(s, s.decorators, modifiers, s.asteriskToken, s.name, s.typeParameters, s.parameters, s.type, s.body);
    }
    return s;
}

but this seems really verbose, is probably missing a ton of cases and is very prone to breaking when one of the signatures change. I've found another answer where it was suggested to replace the modifiers array, but s.modifiers is readonly, so TypeScript won't let me do that.

Is there no better way to just update the modifiers without recreating the entire AST node?

1

There are 1 answers

0
closh On

You can use ts.transform

https://github.com/madou/typescript-transformer-handbook#writing-your-first-transformer

  const result = ts.transform<ts.SourceFile>(sourceFiles, [transformer]);

  function transformer<T extends ts.Node>(context: ts.TransformationContext) {
    return (rootNode: T) => {
        function visit(sourceFile: ts.Node): ts.Node {

            return ts.visitEachChild(sourceFile, (node) => converNode(node), context);
        }

        function converNode(node: ts.Node) {

            return ts.visitEachChild(node, visitChilds, context);

            function visitChilds(child: ts.Node): ts.Node | undefined {
                if (child.kind == ts.SyntaxKind.ExportKeyword) return undefined;
                if (child.kind == ts.SyntaxKind.AsyncKeyword) return undefined;

                return ts.visitEachChild(child, visitChilds, context);
            }

         
        }

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