Skip to content

is there an example of how to transform AST of a file and emit it? #7580

Closed

Description

I would like to make a tool to replace imports of old style to imports of new style:

// before
import dsa = require('data/search/account');
// after
import * as dsa from 'data/search/account';

is it possible to do via public compiler api?
if so, can anyone outline the steps?

Activity

  1. zpdDG4gta8XKpMCd commented on Mar 18, 2016

    @zpdDG4gta8XKpMCd
    Author

    another example is enforcing curly braces on if statements and such:

    // before
    if (isThis())
       thenThat();
    // after
    if (isThis()) {
       thenThat();
    }
    
  2. DanielRosenwasser commented on Mar 18, 2016

    @DanielRosenwasser
    Member

    Ideally you could do this with #5595 (see also #3241), but until we have an API for that, you can use our language service API.

    Then:

    1. aggregate the nodes of interest
    2. generate the intended replacement text for each node
    3. and apply replacements in reverse

    Something like this might work:

    import * as ts from "typescript";
    import * as fs from "fs";
    
    interface Replacement {
        start: number;
        end: number;
        replacementText: string;
    }
    
    function transformProgram(program: ts.Program) {
        for (const file of program.getSourceFiles()) {
            const replacements = getReplacements(file);
            replacements.reverse();
    
            const newText = getNewText(file.getText(), replacements);
            fs.writeFileSync(file.fileName, newText);
        }
    }
    
    function getReplacements(sourceFile: ts.SourceFile) {
        const replacements: Replacement[] = [];
        for (const statement of sourceFile.statements) {
            if (statement.kind !== ts.SyntaxKind.ImportEqualsDeclaration) {
                continue;
            }
    
            const importEquals = statement as ts.ImportEqualsDeclaration;
            if (importEquals.moduleReference.kind !== ts.SyntaxKind.ExternalModuleReference) {
                continue;
            }
    
            const importString = (importEquals.moduleReference as ts.ExternalModuleReference).expression as ts.StringLiteral;
            if (!importString || importString.kind !== ts.SyntaxKind.StringLiteral) {
                continue;
            }
    
            replacements.push({
                start: statement.getStart(),
                end: statement.getEnd(),
                replacementText: `import ${ importEquals.name.getText() } from "${ importString.getText() }";`
            });
        }
        return replacements;
    }
    
    function getNewText(sourceText: string, replacementsInReverse: Replacement[]) {
        for (const { start, end, replacementText } of replacementsInReverse) {
            sourceText = sourceText.slice(0, start) + replacementText + sourceText.slice(end)
        }
    
        return sourceText;
    }

    Don't hold me to it though, I haven't tested it out yet.

  3. DanielRosenwasser commented on Mar 18, 2016

    @DanielRosenwasser
    Member
  4. wclr commented on Sep 4, 2016

    @wclr

    Is it possible now to make source transformation using alternations in AST not via text replacement as shown?

  5. kitsonk commented on Sep 4, 2016

    @kitsonk
    Contributor

    When #5595 lands, yes... it should be in master soon

  6. wclr commented on Sep 7, 2016

    @wclr

    So #5595 seem to land? Is there some docs/info about transforming AST?

  7. kitsonk commented on Sep 7, 2016

    @kitsonk
    Contributor

    No, not yet... the team have been burning the midnight oil to get it into master. If you don't feel comfortable spelunking in the source code for TypeScript, I think you are going to have to wait a while until there is any sort of decent documentation. Likely though, especially when it comes to using the services and other internals of TypeScript, it is really up to the wider community to start providing the "how to" instead of official documentation.

  8. wclr commented on Sep 7, 2016

    @wclr

    Kitson Kelly (@kitsonk) Ok, thanks for response) I'm quite comfortable with source/tests code. Here is what I want to do:

    1. I have a source TS file
    2. Need to load it and get AST (I assume it is done using ts.createSourceFile)
    3. Need a way to change AST (not sure how)
    4. Compile changed AST
    5. (as a bonus) Access resulting AST

    Are step 3-5 possible now? If yest could you direct to the source that should be investigated?

  9. rbuckton commented on Sep 8, 2016

    @rbuckton
    Contributor

    We do not currently expose the transformation API as part of the language service. This is something we are considering. Once we make it available as a public API we will provide documentation on its use.

  10. wclr commented on Sep 8, 2016

    @wclr

    Ron Buckton (@rbuckton) so it is not possible at all? ok can be hacked around?

  11. zpdDG4gta8XKpMCd commented on Sep 8, 2016

    @zpdDG4gta8XKpMCd
    Author

    i think he said that it is in private api that isnt exposed to public, can you use private API of TypeScript? sure, just take a full ownership of it meaning write your code right in it or modify it so that it is public

  12. wclr commented on Sep 8, 2016

    @wclr

    Ok, I get it, now I ask where to look for this private API in particular?

  13. zpdDG4gta8XKpMCd commented on Sep 8, 2016

    @zpdDG4gta8XKpMCd
    Author

    here is a list of all code cjanges related to AST transformations, at this point i'd say there is no better way to learn it other than by looking at what was done

  14. cape-dev commented on Oct 13, 2016

    @cape-dev

    We do not currently expose the transformation API as part of the language service. This is something we are considering. Once we make it available as a public API we will provide documentation on its use.

    Ron Buckton (@rbuckton) Is there an entry on the roadmap for making the AST transformation API public? Or can you estimate when this will happen?

    Renamed in favour of (@whitecolor) Did you find a way to achieve your goals?

  15. wclr commented on Oct 19, 2016

    @wclr

    @kamekazemaster no i didn't look close yet

  16. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Domain: APIRelates to the public API for TypeScriptQuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions