Giter Club home page Giter Club logo

ngast's Introduction

Build Status

ngast

This library provides user friendly API for parsing Angular projects.

Getting started

$ npm i @angular/core @angular/compiler @angular/compiler-cli ngast --save

ngast is built on top of Ivy (ngtsc), make sure to compile your project with ngcc (run ng serve, ng build or npx ngcc).

Workspace

First you need connect the WorkspaceSymbols to the tsconfig.json root :

import { join } from 'path';
import { WorkspaceSymbols } from 'ngast';

const config = join(process.cwd(), 'tsconfig.json');
const workspace = new WorkspaceSymbols(config);

From there you can find all the decorated classes in your project :

const modules = workspace.getAllModules();
const components = workspace.getAllComponents();
const directives = workspace.getAllDirectives();
const injectables = workspace.getAllInjectable();
const pipes = workspace.getAllPipes();

The first time one of the method above is called, ngast will run the analysis of the workspace.

The analysis is currently quite long: >10sec for a small project can go beyond 2min for a very large project.

Working without Ivy

Version 0.4.0 is built on top of the ViewEngine, you can take a look at the documentation here.

Example

Projects using ngast:

License

MIT

ngast's People

Contributors

alexrashed avatar basvermeulen avatar cammisuli avatar chrisguttandin avatar dependabot[bot] avatar dherges avatar dmitryefimenko avatar grandschtroumpf avatar irustm avatar mgechev avatar vik-13 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

ngast's Issues

`ModuleWithProviders` not reflected in Angular AST

(I may use a lot of wrong terms, please correct me. I try to be precise)

If understanding right, ngast reflects the structure (composition and dependencies) of an Angular application from a run-time view. For example, let's say an AppModule imported the BrowserModule:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now, in the ngast, the ModuleSymbol representing AppModule returns an empty .getProviders() (sounds obvious because providers: [] is an empty array in the above).

The ProjectSymbols.getProvider() includes "imported"(?) providers from BrowserModule like (partial extract): "ɵDomRendererFactory2"


Now, let's import more module in AppModule

@Injectable()
class MyFeatureService {
  constructor (private http: HttpClient) {}
}

@NgModule({})
class MyFeatureModule {
  public static forRoot(): ModuleWithProviders {
    return { ngModule: MyFeatureModule, providers: [ MyFeatureService ]};
  }
}


@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    MyFeatureModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Still, ModuleSymbol.getProviders() is an empty array (the one repsenting AppModule - ok).

ModuleSymbol.getProviders() is an empty array (also for the one representing MyFeatureModule - ok).

ProjectSymbols.getProviders() now includes also providers from HttpClientModule (like the JsonPClientBackend, HTTP_INTERCEPTORS, and so on) and also the useClass provider for MyFeatureService.


So far, so good. Now let's exclude the AppModule from the ts.Program and only analyze the MyFeatureModule:

Now, in the ProjectSymbols.getProviders() there are still providers for JsonPClientBackend, HTTP_INTERCEPTORS, and so on. But the provider for MyFeatureService is missing. I think probably because MyFeatureModule.forRoot() was nowhere imported but still the dependency metadata for the MyFeatureService was generated because of the @Injectable() annotation.

And also still, ModuleSymbol.getProviders() returns an empty array because of the "empty" module annotation @NgModule({}) class MyFeatureModule.


First question: why are .forRoot() providers on ProjectSymbols.getProviders()?

Seeing this, it looks like ngast reflects an Angular application from a run-time perspective. It looks like ProjectSymbols.getProviders() reflects the "root injector scope". Is that right?

Second question: why is ModuleWithProviders not reflected in ngast?

Even with the ProjectSymbols.getProviders() it's no longer possible to find out which module declared the provider, because ModuleSymbol.getProviders() (the one representing MyFeatureModule) returns an empty provider array. However, the ModuleSymbol.getProviders() representing CoreModule returns a set of providers declared by CoreModule (like "ɵe", "IterableDiffers", "KeyValueDiffers", "LOCALE_ID", and so on).

Also the StaticSymbol.members (of the MyFeatureModule) is an empty array so it's not possible to inflect something about static methods returning a ModuleWithProviders.

Why is the ModuleWithProviders not reflected in ngast?

No exported member 'ErroredTrait'.

node_modules/ngast/lib/ngtsc/symbol.d.ts:26:306 - error TS2694: Namespace '"@angular/compiler-cli/src/ngtsc/transform"' has no exported member 'ErroredTrait'.

26 export declare const isAnalysed: <A, B, C>(trait?: import("@angular/compiler-cli/src/ngtsc/transform").PendingTrait<A, B, C> | import("@angular/compiler-cli/src/ngtsc/transform").SkippedTrait<A, B, C> | AnalyzedTrait<A, B, C> | ResolvedTrait<A, B, C> | import("@angular/compiler-cli/src/ngtsc/transform").ErroredTrait<A, B, C> | undefined) => trait is AnalyzedTrait<A, B, C> | ResolvedTrait<A, B, C>;

I noticed that remove the concept of an errored trait was undertaken here
angular/angular#39923

ErroredTrait is no longer in the code
https://github.com/ng-ast/ngast/blob/master/lib/ngtsc/symbol.ts

but it seems that the npm package still has the outdated code
"[email protected]"

Would this be the case?

Modules are not detected when using tsconfig#files with main.ts

With Angular 9 the default method of including files in the tsconfig.json is to define the entrypoints using the files section (angular/angular-cli#15030).
Therefore angular-cli now creates a main.ts and references it in tsconfig#files.
The main.ts does not directly declare the AppModule but only references it.

ngast however expects the module to be in the Typescript program's root filenames:

this.program.getRootFileNames() as string[],

It should use the Typescript program's source files, as it's used in the Angular project itself:
https://github.com/angular/angular/blob/e9de28111dbdede31181547c8686683203030ca0/packages/language-service/src/typescript_host.ts#L163

Therefore ngast does not detect any modules anymore for a project created with angular-cli.

[ngtsc] use angular.json

Currently ngast uses the root typescript configuration to scan the project.
By using the angular.json file as a reference instead we could :

  • Provide more information concerning the workspace structure.
  • Lazily analyze each project instead of analyzing the whole workspace.
  • Being able to provide different APIs depending on the projectType.
  • Support stylePreprocessorOptions for the css parser.

How to do that :

  1. Parse angular.json file
  • Either use a simple JSON.parse(fs.readFileSync('angular.json')) (no more dependency but no typing).
  • Or use the method readWorkspace of @angular-devkit/core (strongly typed but another dependency).
  1. Per project look for the tsConfig field name under 'projects/:projectName/architect/build/options/tsconfig'.
  2. Only instantiate the compiler once for all project.

Support for older angular compiler versions

I'm trying to analyse an angular 7 project and I'm getting some errors because this library is trying to compile it with the angular 11 compiler, is there a way to overcome this problem?
Thank you

`projectSymbols.getModules()` throws error

Hey!

Recently I was asked to find a way to analyze our Angular project, and I came across this project that wraps all the fun stuff that the @angular/compiler-cli does.

So, I started, and when i tried to use projectSymbols.getModules() I always got an error like so:

Error: Type DeviceActionsBarControl in 
C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.ctrl.ts 
is part of the declarations of 2 modules: 
DeviceActionsBarModule in C:\Development\WWW\portals\console\app\controls\device-action-bar\device-actions-bar.module.ts and 
DeviceActionsBarModule in C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.module.ts! 
Please consider moving DeviceActionsBarControl in C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.ctrl.ts 
to a higher module that imports DeviceActionsBarModule in C:\Development\WWW\portals\console\app\controls\device-action-bar\device-actions-bar.module.ts 
and DeviceActionsBarModule in C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.module.ts. 

You can also create a new NgModule that exports and includes DeviceActionsBarControl in 
C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.ctrl.ts then
 import that NgModule in DeviceActionsBarModule in
C:\Development\WWW\portals\console\app\controls\device-action-bar\device-actions-bar.module.ts and 
DeviceActionsBarModule in
C:/Development/WWW/portals/console/app/controls/device-action-bar/device-actions-bar.module.ts.

This was the first time seeing this error being thrown, and I have never seen it while starting the actual project in JIT, or building in prod with AOT.

So I dug in. First thing I noticed is that the error is complaining that a component is in the same module. Which was just whacky. Then I noticed that the slashes were different. And me being on a Windows machine, slashes are always a pain in the butt.

I tried changing the baseUrl in all the tsconfigs I could find, and still the same error occurred.

I then went down into the @angular/compiler-cli and noticed this little guy:
https://github.com/angular/angular/blob/d9ae70c699c4e2969f2d3539c50e719ba47bb6a1/packages/compiler-cli/src/perform_compile.ts#L150

path.normalize took my properly slashed paths (C:/etc/etc) and made them Windowsy (C:\etc\etc)

So when Angular tries to traverse some modules, the returned path was C:/etc/etc, but the rootNames
always were C:\etc\etc.

Now, I'm not sure if there's some property I need to set in Node, Typescript or Angular to keep those paths with forward slashes. But, I found that by replacing

this.program = createProgram({ rootNames: config.rootNames, options: config.options, host: this.compilerHost });

with :

this.program = createProgram({
      rootNames: config.rootNames.map((rootName) => rootName.replace(/\\/g, '/')),
      options: config.options,
      host: this.compilerHost
});

Solved my issue and I managed to get all my modules.

I'm just wondering, would this be the best solution. And if so, I'm more than happy to create a pull request with it. If not, any direction would be great.

Thanks 😄!

Angular 13.1 support

Hi,

Do you plan to support Angular 13.1? With latest ngast version there is "Unknown import type" error

node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/transform/src/compilation.js:440
                finally { if (e_7) throw e_7.error; }
                                   ^

Error: Unknown import type?
    at Object.reflectTypeEntityToDeclaration (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/reflection/src/typescript.js:448:23)
    at node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/metadata/src/util.js:37:35
    at Array.map (<anonymous>)
    at Object.extractReferencesFromType (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/metadata/src/util.js:32:14)
    at DtsMetadataReader.getNgModuleMetadata (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/metadata/src/dts.js:61:38)
    at MetadataDtsModuleScopeResolver.resolve (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/scope/src/dependency.js:61:43)
    at MetadataDtsModuleScopeResolver.resolve (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/scope/src/dependency.js:100:46)
    at LocalModuleScopeRegistry.getExportedScope (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/scope/src/local.js:529:51)
    at LocalModuleScopeRegistry.getScopeOfModuleReference (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/scope/src/local.js:271:44)
    at LocalModuleScopeRegistry.getScopeOfModule (node_modules/ngast/node_modules/@angular/compiler-cli/src/ngtsc/scope/src/local.js:148:22)

[ngtsc] Link dependencies injected with @Inject decorator with the provider

The problem

With this example :

const TOKEN = new InjectionToken();
@Component({
  ...
  providers: [{ provide: TOKEN, useValue: true }]
})
export class MainComponent {
  constructor(@Inject(TOKEN) isTrue) {}
}

@NgModule({
  declarations: [MainComponent],
  providers: [{ provide: TOKEN, useValue: false }]
})

When running :

const [component] = workspace.getAllComponents();
const [token] = component.getDependencies();

The value token should reference the provider inside the component (with the value true).
Current behavior: returns undefined.


How to solve :

  1. Do more research on the compiler to found out if this information is hold somewhere
  2. If not create a ProviderRegistry that keeps track of all the provider per class declaration or at the root if providedIn: 'root'
  3. For components & directives we can use the scope to look for the closest implementation of the provider.
  4. For injectables & Pipes there is no scope available, we should scan every modules & root field of the ProviderRegistry.

Hopefully there is a built-in solution in the angular compiler so we can stop at step 1 🤞

Support lazy routes in ProjectSymbols?

{ path: routesNames.heroes.basePath, loadChildren: () => import('./modules/heroes/heroes.module').then(m => m.HeroesModule) },
const projectSymbols = new ProjectSymbols(
    projectPath,
    resourceResolver,
    e => (parseError = e)
);

I get that error

Error during template compile of 'AppRoutingModule'
Reference to a local (non-exported) symbols are not supported in decorators but 'routes' was referenced
Consider exporting 'routes'.

Do you have any plans to do lazy routes support?

If not, I'd like to do it.

Question- Is there a way to not follow aot in ngast(v0.4.0)?

Lazy loaded modules gives error (The AOT collector does not support the arrow function)

@Component({
  ...
  providers: [{provide: server, useFactory: () => new Server()}]
})

ERROR - Function expressions are not supported in decorators

Is there a way to not follow aot in ngast(v0.4.0)?

[ngtsc] publish with next or canary tag

I'm building a vscode extension, and I would like to take advantage of the new version of ngast with the ngtsc compiler support.
Would it be possible to publish it with the tag next or canary depending how mature you consider the current state of the library.
Thanks.

Optimization proposal, getResolvedMetadata

Hi!

Can it be better to read from a file on demand?

templateMetadata.template = this.resourceResolver.getSync(templateMetadata.templateUrl);

Only when it is necessary to execute getTemplateAst?

For example, in this place?

const dirMetadata = this.getResolvedMetadata();
if (dirMetadata) {
const source = dirMetadata.template;

I don't need to get all the styles, just the template.
And if a method of obtaining is called somewhere, then take from the cache.

[Feature request] Get the selector scope of a module

Hello,
I would like to get the selector scope of a specifc module. I'm not sure how to perform that based on a ModuleSymbol, and I think it can be a great feature to add. any idea how I could do that ?
I would be glad to do a PR if you think it would be usefull too.
Thanks.

Question - Could not resolve dependency with @angular/[email protected]

I tried install latest version, but I have current error:

npm ERR! Could not resolve dependency:
npm ERR! peer @angular/compiler@"^10.0.0" from [email protected]
npm ERR! node_modules/ngast
npm ERR!   ngast@"*" from the root project
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps

Maybe do you have any ideas? Without force installing, offcourse

My current version of @angular/compiler is 11

ContextSymbol.getModules() returns duplicated modules

Since NgAnalyzedModules.ngModuleByPipeOrDirective returns a map, and getModules uses only the values. There are multiple references/clones of the same module metadata (like CommonModule) returned by getModules().

Looks like we need to de-dupe by type.reference.

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.