Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I get module locals? #561

Closed
granmoe opened this issue Mar 3, 2019 · 8 comments
Closed

How do I get module locals? #561

granmoe opened this issue Mar 3, 2019 · 8 comments

Comments

@granmoe
Copy link

granmoe commented Mar 3, 2019

In ts-ast-viewer.com, the SourceFile node has a property called "locals" that contains all symbols in module scope:

screen shot 2019-03-03 at 12 35 47 pm

Is there a way to get this using ts-morph? Or perhaps it is exposed somehow in the normal typescript compiler API?

I'm sorry if there is an obvious place to find the answer. I've searched the typescript docs and ts-morph docs and some of the source code and can't find anything.

Thank you for this incredible library!

@dsherret
Copy link
Owner

dsherret commented Mar 3, 2019

Hey @granmoe, always feel free to ask questions... there's a lot that's not really obvious and still a lot not implemented.

The locals property is on any node and internal to the compiler api. See here. Having access to that symbol table would be incredibly useful though. Currently there's this issue open on typescript's issue tracker for exposing this.

Right now, you could access this with the following code, but it's not so great:

import { ts } from "ts-morph";

// ...etc...

project.getProgram().compilerObject; // hack to force binding to happen

const locals = (sourceFile.compilerNode as any)["locals"] as ts.SymbolTable | undefined;

// work with locals here... note that it's compiler api symbols

I'm wondering how risky it is to expose this internal property... I'll look into it more later.

Sidenote: I have a pending issue in ts-ast-viewer for toggling on an off internal properties (dsherret/ts-ast-viewer#31).

@granmoe
Copy link
Author

granmoe commented Mar 6, 2019

Thank you for the excellent answer! The links were very helpful.

I simply (heh) need to find all symbols available in module-scope, and I've tried many, many different approaches, but all seem to break down in some way or another. It seems that I'd either have to handle each possible type of statement in module scope with all of its inherent complexity, or, hopefully, find something like locals (but hopefully something officially supported and exposed) that has already done the work for me.

This is all in the effort of pursuing my dream project. This is an idea I would devote many years to happily, but I keep having to start over with these crucial, first few steps 😕I am going to keep trying!

@granmoe
Copy link
Author

granmoe commented Mar 7, 2019

I tried getting locals using the solution above, but it's always undefined. Here's what I'm trying:

import { Project } from 'ts-morph'

test('Find all identifiers in module-scope (ts-morph, ts compiler locals hack', () => {
  const project = new Project()
  const sourceFile = project.addExistingSourceFile('sample.ts')

  project.getProgram().compilerObject
  const locals = (sourceFile.compilerNode as any)['locals']

  console.log({ locals })
})

I also tried some different ways of adding a file to the project with no luck:

import { Project } from 'ts-morph'

test('Find all identifiers in module-scope (ts-morph, ts compiler locals hack', () => {
  const project = new Project()
  const fileText = 'enum MyEnum {\n}\n'
  const sourceFile = project.createSourceFile('path/to/myNewFile.ts', fileText)

  project.getProgram().compilerObject
  const locals = (sourceFile.compilerNode as any)['locals']

  console.log({ locals })
})

Any ideas?

@dsherret
Copy link
Owner

dsherret commented Mar 7, 2019

@granmoe sorry, I didn't test out what I said last time. This seems to work:

import { Project, ts } from "ts-morph";
const project = new Project();
const fileText = 'enum MyEnum {\n}\n';
const sourceFile = project.createSourceFile('path/to/myNewFile.ts', fileText);

sourceFile.getSymbol(); // force binding
const locals = (sourceFile.compilerNode as any)['locals'] as ts.SymbolTable | undefined;

console.log({ locals });

@granmoe
Copy link
Author

granmoe commented Mar 11, 2019

Awesome! Thank you again 🙂

@dsherret
Copy link
Owner

I'm going to reopen this because I'd like to expose it in the library (even though it's internal to the compiler).

@dsherret dsherret reopened this Mar 24, 2019
@dsherret dsherret added this to the 2.1.0 milestone Apr 8, 2019
dsherret added a commit that referenced this issue May 18, 2019
…calByNameOrThrow`

These are using internal api in the compiler api, so they should be used with that in mind.
@dsherret
Copy link
Owner

Added Node#getLocals(), Node#getLocalByName(name: string), and Node#getLocalByNameOrThrow(name: string) in version 3.0.0 (unreleased).

Obviously this relies on a symbol table that's internal in the compiler so use these methods at your own risk knowing they could break more easily than the other methods (added a warning to the jsdoc).

@dsherret
Copy link
Owner

This is now released in 3.0.0. Sorry about the delay! I should have done smaller and faster releases.

Please review breaking-changes.md when upgrading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants