Coder Social home page Coder Social logo

dsherret / ts-morph Goto Github PK

View Code? Open in Web Editor NEW
4.9K 4.9K 194.0 28.62 MB

TypeScript Compiler API wrapper for static analysis and programmatic code changes.

Home Page: https://ts-morph.com

License: MIT License

TypeScript 99.97% JavaScript 0.03%
ast code-generation javascript static-analysis typescript

ts-morph's People

Contributors

ajvincent avatar basarat avatar cancerberosgx avatar dicarlo2 avatar dsherret avatar franklinwhale avatar geremih avatar gerrit0 avatar giuseppelt avatar holdyourwaffle avatar jakebailey avatar kronodeus avatar lazarljubenovic avatar lo1tuma avatar mitchlloyd avatar mmorearty avatar mohamedlamineallal avatar nicdard avatar pineapples avatar rhys-vdw avatar rwoverdijk avatar schiller-manuel avatar sguillia avatar shaharkazaz avatar sisisin avatar tobyhede avatar tw3 avatar validark avatar vogloblinsky avatar wojpawlik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ts-morph's Issues

Assumptions - Automated tests for the code structure of the TypeScript compiler

This library is based on a lot of assumptions about the TypeScript library.

Take the following example property:

prop: string;

In certain parts of this library, no compile error would be thrown if the above type were changed to:

prop: string | number;

It would be good to have automated tests to make sure certain parts of the TypeScript compiler haven't changed. This could be done using this library and it would be very easy to do.

add/insert new const/var

Is there a function like addEnum for variables and constants?
If not, I want investigate and make it, but asking before

Add a source file by structure

This would be easy to implement:

ast.addSourceFileFromStructure("fileName.ts", {
    classes: [{
        name: "MyClass",
        // etc...
    }],
    // etc...
});

Create specific insert and removal functions

I've noticed a lot of problems with the current implementation for manipulation. It would be better to create specific functions for inserting and removing parts of the code. These could then be easily fine-tuned for performance.

Some ideas:

  • insertIntoSyntaxList - Specify the index being inserted at.
  • insertCreatingSyntaxList
  • removeFromSyntaxList - Would know to remove the syntax list if necessary
  • More?

This would make manipulation much more reliable because then certain assumptions could be made about what is being inserted and removed. That would help a lot with performance and reduce the chance of error.

Intelligent class/interface member add

It would be better if there was some intelligence behind adding a method/property to a class (ex. private properties get inserted with other private properties). Currently, it just inserts to the end index.

Edit: Also, set accessors should be added after get accessors.

Throw error when using removed node

It would be useful to throw an error when someone tries to use a node that was removed from a source file. It would help catch some potential bugs.

If someone wants information about this node before it's removed, then they should create an object that stores the data they need before they remove it from a source file.

Manipulation

I'm going to need to fix the current code in order to do this. What I'm thinking is this...

When building an object like an enum:

  1. Start with the base object (ex. enum MyEnum {})
  2. Work incrementally from there (ex. const enum MyEnum {})
  3. Only offset the next nodes once done.

I need to try to preserve the existing nodes whenever making changes so I can't just parse the file each time. Something similar to the IncrementalParser inside the compiler would be nice.


Throwing an idea out there. I might have to do this:

  1. Copy the text with the new changes from the source file into a new file (this causes the parser to create an AST).
  2. Fill in the original source file with the parts that changed in the new source file.

That feel like that would be extremely reliable, but probably kind of slow. I guess get it working for now then do optimizations later.

QUESTION : resolve imports

Hi,

First, let' say ๐Ÿ‘ about this library, very wonderful work !!

I am the maintainer of compodoc, a documentation tool for Angular applications. https://github.com/compodoc/compodoc

I need for some use-case to support dynamic imports of different things.

// module-a.ts
export const VERSION = 5;
// module-b.ts
import { VERSION } from './module-a';
let toto = VERSION;
console.log(toto);

Would be nice if during AST parsing with TypeScript, if i could edit the AST node of toto variable to inject VERSION instead of just having a reference.

Did you know how can i achieve this with your lib or just with TypeScript compiler APIs ?
This blog http://blog.scottlogic.com/2017/05/02/typescript-compiler-api-revisited.html, chapter "TRANSFORMING THE AST" helps a little

Thanks

Changing the Value of an Initializer

I have a line in a class in a file I'm processing like this:

public static readonly Version: string = "1.0"; 

I get via:

ClassDeclaration.getStaticProperties

and I want to change it to

public static readonly Version: string = "2.0"; 

The call I make is

setInitializer("\"2.0\"");

But it blows up with:

Code:
        public static readonly Version: string; = "2.0"   // version to pass to EDAProperties
    at BaseError (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/errors/BaseError.js:5:9)
    at InvalidOperationError (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/errors/InvalidOperationError.js:6:9)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:28:19)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)
    at handleNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/manipulation/insertStraight.js:37:13)

setInitializer first removes the existing initializer bringing the semi-colon all the way over, then adds the new initializer which ends-up being after the semi-colon.

Manipulation options

There's some constants that are lazily stored in the language service class (like newline char and string char). It would be good to move these outside the language service into its own class and then expose this to users so they can set the options for manipulation.

This is also a refactoring task. The factory knows too much right now.

Add ts-lint rule: Check for function calls not supplying a source file

Passing around source files helps improve the performance of the application because when a source file is required, it won't have to go up the parents of the tree to find the root. Providing a source file is optional though.

It would be good to create a tslint rule for this project that requires function calls provide a source file if the parameter expects one.

Change Child Ordering

I'm not sure that's the right issue name.

I have a class with two static class members and I want to be able to swap their order in the source file. I've poked around a bit and can't find a way to do so (I can identify when they're out of order, but can't change the fact).

Improve using and manipulating function overloads

Would be good to add some helper functions and improve manipulation for this.

Add navigation methods:

  • getOverloads() - returns the overload declarations
  • getImplementation() - returns implementation declaration from
  • isImplementation() -- does .hasBody() basically

Add manipulation methods (these probably have to be specific to the implementation):

  • func.addOverload({})
  • func.addOverloads([{}, {}])
  • func.insertOverload(0, {})
  • func.insertOverloads(0, [{}, {}])
  • method.addOverload({})
  • method.addOverloads([{}, {}])
  • method.insertOverload(0, {})
  • method.insertOverloads(0, [{}, {}])
  • ctor.addOverload({})
  • ctor.addOverloads([{}, {}])
  • ctor.insertOverload(0, {})
  • ctor.insertOverloads(0, [{}, {}])

Save files that have unsaved modifications

This will be useful because then people can do something like a rename refactor, get all the changed files, then save them to the disk.

Add:

  • TsSimpleAst.getUnsavedSourceFiles() - not needed because the save methods should be sufficient
  • TsSimpleAst.saveUnsavedSourceFiles()
  • TsSimpleAst.saveUnsavedSourceFilesSync()

Types

Before continuing, it would be good to figure out how to implement types. Should be easy... post some notes in here if necessary.

Improve find references

It should mirror the typescript compiler a bit more.

Also:

  • Add a findReferences() function to Identifier.
  • Make it easy to get the node for the reference (getChildAtPos & getDescendantAtPos)

Ability to set node from structure

Edit (2018/09/16): This was changed from .fill to .set for version 15.

Basically, this would allow you to set multiple properties at once:

functionDeclaration.set({
    isAsync: true,
    hasExportKeyword: true
});

It would be useful with #45 too:

functionDeclaration2.set(functionDeclaration1.getStructure());

Edit: Mostly all done... still todo:

  • GetAccessorDeclaration
  • SetAccessorDeclaration
  • DecoratorDeclaration
  • ExportDeclaration
  • ImportDeclaration
  • TypeParameterDeclaration
  • VariableDeclaration
  • VariableDeclarationList
  • VariableStatement
  • ExportSpecifier
  • ImportSpecifier
  • ExportAssignment
  • JsxAttribute
  • JsxElement
  • JsxSpreadAttribute
  • PropertyAssignment
  • ShorthandPropertyAssignment

Documentation

I've been documenting the code using JSDocs, but I also make heavy use of mixins... I'm not sure if any JSDoc generators will be able to understand what I'm doing with the mixins.

Get if namespace is namespace or module

Probably just add a hasModuleKeyword() and hasNamespaceKeyword() method. This isn't as useful as it used to be and I don't think it's worth it to introduce a NamespaceDeclarationType enum.

Low priority manipulation tasks

I'm going to use this issue to collect together some low priority manipulation tasks. I'll come back to implement these at the end.

ClassDeclaration

  • Class methods in an ambient context Moved to #125.
  • Get & set accessors

Decorator

  • Renaming - Edit: Won't do. Users can get the appropriate identifier and rename that.
  • Setting as a factory or not
  • Adding/inserting arguments

JSDoc

  • Setting description

Function/Methods/Constructors

  • Setting body text

VariableDeclarationList

  • Setting declaration type.

VariableStatement

  • Adding variable declarations

More to come...

Calling .getType() does not work after manipulation

I have a ClassDeclaration, classDec, for the following class:

        class MyClass {
            public x: number = 0;
        }

If I do something like:

        classDec.getInstanceMembers()
            .filter(m => m.hasModifier(ts.SyntaxKind.PublicKeyword))
            .forEach(member => {
                if (member instanceof ParameterDeclaration || member instanceof PropertyDeclaration) {
                    let mType = member.getType();
                    ...
                }
            });

It blows-up because if something to do with an undefined symbol.

Here's the stack trace:

TypeError: Cannot read property 'flags' of undefined
    at getCheckFlags (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/node_modules/typescript/lib/typescript.js:26031:26)
    at getTypeOfSymbol (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/node_modules/typescript/lib/typescript.js:29477:17)
    at getTypeOfNode (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/node_modules/typescript/lib/typescript.js:45506:24)
    at Object.getTypeAtLocation (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/node_modules/typescript/lib/typescript.js:25507:31)
    at TypeChecker.getTypeAtLocation (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/compiler/tools/TypeChecker.js:51:62)
    at PropertyDeclaration.getType (/Users/mhaan/AppDev/tscompile/node_modules/ts-simple-ast/dist/compiler/base/TypedNode.js:8:50)
    at ast.getSourceFiles.forEach.processNS.forEach.classDec.getInstanceMembers.filter.forEach.member (/Users/mhaan/AppDev/tscompile/lib/app2.js:46:36)
    at Array.forEach (native)

Note that if I exclude PropertyDeclarations (by removing "|| member instanceof PropertyDeclaration") then that member is not found at all.

Cannot find name Constructor

I'm getting about 90 of these errors, all originating from this library in node_modules. I don't know why they're being generated (tsc shouldn't be tying to compile anything in node_modules) but I do note that I can't seem to find a "Constructor" defined anywhere in the library - so I don't know what's going on.

Ability to get structure from node

The base for this already exists in createGetStructureFunctions; however, that should be changed to remove scenario specific logic. The user should be able to do the following:

const functionStructure = functionDeclaration.getStructure();

// EDIT: Won't be doing this below. People can modify the returned object when
// they're done themselves.

// or... (return type would be a partial of FunctionDeclarationStructure)
const functionStructure = functionDeclaration.getStructure({
    include: [nameof(AsyncableNode), nameof(GeneratorableNode)]
});

// or... (return type would be a partial of FunctionDeclarationStructure)
const functionStructure = functionDeclaration.getStructure({
    exclude: [nameof(AsyncableNode), nameof(GeneratorableNode)]
});

This seems pretty tedious to implement and susceptible to bugs, but these problems can basically be eliminated with code generation.

Left to do (does not include already completed tasks or all tasks):

  • DocumentationableNode
  • ParameteredNode
  • TypeParameteredNode
  • Specific getStructureFunctions
  • Code generate the functions to do this (clean up the old code)

Memoize?

Should some heavy method call's result be memoized and then the caches wiped away after manipulation has occurred?

Removing nodes

Currently, removing nodes is not very well supported in this library. Will add a list of everything that needs to be implemented soon.

While working on this I'm going to:

  1. Separate out replacing trees with a new tree into a single function.
  2. Separate out formatting for nodes into a single area. That means that formatting rules used for inserts can also be used for removing.
  3. Separate out code for manipulating the text based on the formatting rules.
  4. Try to eliminate a lot of the existing manipulation functions... there's some overlap currently.

Create utility Node type guard checks class

This should be done using code generation. It's easy to forget to add methods for these.

  1. Code generate a mixin that contains all the isX() methods.
  2. Apply the mixin to Node.
  3. Write a script that ensures all the mixins return true for these methods.

Edit: I'm having second thoughts about this because it would spam the auto-complete. I'm thinking it might be better to put this on a utils class.


import Ast, {TypeGuards} from "ts-simple-ast";

// ...

if (TypeGuards.isEnumDeclaration(node)) {
    // node is EnumDeclaration in here
}

if (TypeGuards.isBodiedNode(node)) {
    // node is Node & BodiedNode in here
}

This class should be completely code generated so that no unit tests are required (code generation is low risk for mistakes) and so that it doesn't need to be maintained (because maintaining it would be a pain!)

Add test to ensure no memory leaks while manipulating

Right now the code for replacing one underlying source file could possibly have a memory leak if a mistake were made. It would be good to add some tests for some of the manipulation (especially ones that create temporary nodes in the process) to ensure that they don't remain in the cache.

Probably a simple test is sufficient... it could do a few different kinds of manipulations and then manipulate back to the original code. Once done it could ensure that the size of the cache is the same as it was when it started.

Issue with constructor defined members/properties

To be clear, it's an overloaded constructor:

        constructor();
        constructor(Email: string, FirstName: string, LastName: string, SecurityToken: string);
        constructor(public Email: string = "", public FirstName?: string, public LastName?: string, public SecurityToken?: string) {
            super();
        }

Neither getInstanceMembers nor getInstanceProperties returns any of those.

Symbols

Before continuing, it would be good to figure out how to implement symbols. Post some notes in here if necessary.

Map ts.SyntaxKind to corresponding wrapped node

Trying to use this lib in a TypeScript project of my own and having difficulty taking advantage of the typings. For example, the following code works (it's just something i'm hacking at right now):

import Ast from "ts-simple-ast";
// import { NamespaceDeclaration } from "ts-simple-ast";
import * as ts from "typescript";
// import * as _ from "lodash";

const ast = new Ast({
    tsConfigFilePath: "tsconfig.json"
});

ast.addSourceFiles("msgs/**/*{.d.ts,.ts}");

ast.getSourceFiles().forEach((sf, idx) => {
    if (idx === 0) {
        console.log(sf.getFilePath());
        sf.getNamespaces().forEach(ns => processNS([], ns));
        console.log("=================");
    }
});

function processNS(nsParents, ns) {
    let currNSStr = nsParents.length === 0 ? ns.node.name.text : nsParents.map(ns => ns.node.name.text).join(".");
    ns.getClasses().forEach(c => {
        console.log(`${currNSStr}.${c.node.name.text}`);
    });

    let currNS = nsParents.concat(ns);
    ns.getChildrenOfKind(ts.SyntaxKind.ModuleDeclaration).forEach(childNS => {
        processNS(currNS, childNS);
    });
}

The problem is I'd like, for example, for the function to be written as follows:

function processNS(nsParents, ns: NamespaceDeclaration) {
    let currNSStr = nsParents.length === 0 ? ns.node.name.text : nsParents.map(ns => ns.node.name.text).join(".");
    ns.getClasses().forEach(c => {
        console.log(`${currNSStr}.${c.node.name.text}`);
    });

    let currNS = nsParents.concat(ns);
    ns.getChildrenOfKind(ts.SyntaxKind.ModuleDeclaration).forEach(childNS => {
        processNS(currNS, childNS);
    });
}

But then vscode complains about the "node" portion of "ns.node.name.text" and "c.node.name.text" (and it also complains about "childNS" which it says is of type Node<ts.Node>).

If I change it instead to:

function processNS(nsParents, ns: ts.NamespaceDeclaration) {
    let currNSStr = nsParents.length === 0 ? ns.node.name.text : nsParents.map(ns => ns.node.name.text).join(".");
    ns.getClasses().forEach(c => {
        console.log(`${currNSStr}.${c.node.name.text}`);
    });

    let currNS = nsParents.concat(ns);
    ns.getChildrenOfKind(ts.SyntaxKind.ModuleDeclaration).forEach(childNS => {
        processNS(currNS, childNS);
    });
}

Then it also complains about the "node" in "ns.node.name.text" but also "getClasses" of "ns.getClasses()" and "getChildrenOfKind" of "ns.getChildrenOfKind().

So, the question is - how should I be setting that type such that I can take advantage of the typing system?

Issue With Namespaces?

SourceFile.getClasses() does not return classes which are inside a namespace. Do I need to do something to access the namespaces? I can get them with getNamespaces, but then I don't seem to be able to access the classes within that namespace...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.