mgechev / ngast

Parser for Angular projects.

Home Page:https://mgechev.github.io/ngast/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`projectSymbols.getModules()` throws error

Cammisuli opened this issue · comments

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 😄!

Thanks for sharing the issue and the solution! Maybe require('path').normalize..?

I see. Does have you had a chance to test this on Mac or Linux?

I actually tried it with the Linux (Ubuntu) Sub System on Windows, and without any fixes of replacing the slashes, it works fine.

image

I looked more into the problem and discovered that when trying to get the tsProgram here:

const defaultDir = this.program.getTsProgram().getCurrentDirectory();

It goes into the Angular compiler-cli here:
https://github.com/angular/angular/blob/0b1f5d21270063b2019b11a9494397916d3977d6/packages/compiler-cli/src/transformers/program.ts#L489

Which calls this._createProgramWithBasicStubs() and then calls ts.createProgram here:
https://github.com/angular/angular/blob/0b1f5d21270063b2019b11a9494397916d3977d6/packages/compiler-cli/src/transformers/program.ts#L554

And then TypeScript calls processRootFile here:
https://github.com/Microsoft/TypeScript/blob/868a9ee117173a60167626131a78eec00f19b716/src/compiler/program.ts#L586

And then finally calls normalizePath here:
https://github.com/Microsoft/TypeScript/blob/868a9ee117173a60167626131a78eec00f19b716/src/compiler/core.ts#L1986
Which effectively does: path.replace(/\\/g, "/"), and reverses what the @angular/compiler-cli does with path.normalize here.

It's a long ride, but there it is.

So, getting the rootNames to match what TypeScript is doing, would be best.

And because this library should be a friendly wrapper for the Angular compiler, I think it's good to put the replace(/\\/g, '/')).

Thanks!

@Cammisuli sounds good. Would you open a PR for the proposed fix? I'll after that update the dependencies of ngrev.