Search code examples
javascripttypescriptcompiler-constructiontypescript-compiler-api

Read and update object with Typescript compiler API


The typescript compiler API is new for me and looks like I'm missing something. I'm looking the way to update specific object at ts file with compiler API

Existing file - some-constant.ts

export const someConstant = {
    name: 'Jhon',
    lastName: 'Doe',
    additionalData: {
        age: 44,
        height: 145,
        someProp: 'OLD_Value'
        /**
         * Some comments that describes what's going on here
         */
    }
};

After all, I want to get something like this:

export const someConstant = {
    name: 'Jhon',
    lastName: 'Doe',
    additionalData: {
        age: 999,
        height: 3333,
        someProp: 'NEW_Value'
        eyeColor: 'brown',
        email: 'someemail@gmail.com',
        otherProp: 'with some value'
    }
};

Solution

  • I started writing an answer on how to do this with the compiler API, but then I gave up because it was starting to get super long.

    This is easily possible with ts-morph by doing the following:

    import { Project, PropertyAssignment, QuoteKind, Node } from "ts-morph";
    
    // setup
    const project = new Project({
        useInMemoryFileSystem: true, // this example doesn't use the real file system
        manipulationSettings: {
            quoteKind: QuoteKind.Single,
        },
    });
    const sourceFile = project.createSourceFile("/file.ts", `export const someConstant = {
        name: 'Jhon',
        lastName: 'Doe',
        additionalData: {
            age: 44,
            height: 145,
            someProp: 'OLD_Value'
            /**
             * Some comments that describes what's going on here
             */
        }
    };`);
    
    // get the object literal
    const additionalDataProp = sourceFile
        .getVariableDeclarationOrThrow("someConstant")
        .getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
        .getPropertyOrThrow("additionalData") as PropertyAssignment;
    const additionalDataObjLit = additionalDataProp
        .getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
    
    // remove all the "comment nodes" if you want to... you may want to do something more specific
    additionalDataObjLit.getPropertiesWithComments()
        .filter(Node.isCommentNode)
        .forEach(c => c.remove());
    
    // add the new properties
    additionalDataObjLit.addPropertyAssignments([{
        name: "eyeColor",
        initializer: writer => writer.quote("brown"),
    }, {
        name: "email",
        initializer: writer => writer.quote("someemail@gmail.com"),
    }, {
        name: "otherProp",
        initializer: writer => writer.quote("with some value"),
    }]);
    
    // output the new text
    console.log(sourceFile.getFullText());