ts-morph icon indicating copy to clipboard operation
ts-morph copied to clipboard

Expose flow nodes

Open dsherret opened this issue 3 years ago • 8 comments

https://stackoverflow.com/questions/72241016/how-to-access-flownode-in-typescript-ast-api

dsherret avatar May 14 '22 14:05 dsherret

You awesome thank you!

jon9090 avatar May 14 '22 14:05 jon9090

Hey @dsherret :) The solution you give me it's works on the question example.

But I try to apply this to my code and it's not work. I think I did wrong example.

I try to resolve from components property all the components. I need them in array of classes.

But why typescript can't resolve the classes from the exports?

https://codesandbox.io/s/eager-franklin-3w6d8j?file=/src/index.ts

This is how my code work exactly:

import { Project, SyntaxKind, PropertyAssignment } from "ts-morph";

console.clear();

const project = new Project({
  skipAddingFilesFromTsConfig: true
});

const fooComponentSourceFile = project.createSourceFile(
  "foo-component.ts",
  `export class FooComponent {}`
);

const barComponentSourceFile = project.createSourceFile(
  "bar-component.ts",
  `export class BarComponent {}`
);

const indexSourceFile = project.createSourceFile(
  "index.ts",
  `export * from './foo-component';
   export * from './bar-component';
  `
);

const appSourceFile = project.createSourceFile(
  "app.ts",
  `
import * as COMPONENTS from './index.ts';

const result = run({
  components: { ...COMPONENTS }
})
  `
);

const components = appSourceFile
  .getDescendantsOfKind(SyntaxKind.Identifier)
  .find((n) => n.getText() === "components");

// get the identifier
const nodesIdent = (components!.getParent() as PropertyAssignment).getNameNode();

// // hack to force the type checker to create the flow node
nodesIdent.getType();

// // get the flow node
const flowNode = (nodesIdent.compilerNode as any).flowNode as ts.FlowNode;

console.log({ n: flowNode }); // <-- getting object without node.

jon9090 avatar May 14 '22 15:05 jon9090

@jon9090 check project.getPreEmitDiagnostics() for any diagnostics after creating the source files.

At a glance, it looks like the code is using the import specifier "./index.ts", which should be "./index" to work with the ts compiler.

dsherret avatar May 14 '22 16:05 dsherret

@dsherret I add

project.getPreEmitDiagnostics();
project.resolveSourceFileDependencies();

And change to ./index;

https://codesandbox.io/s/eager-franklin-3w6d8j?file=/src/index.ts

The problem still exist. I don't get the variable flowNode.node to get the classes.

What else can I do?

jon9090 avatar May 14 '22 16:05 jon9090

@jon9090 check the output by doing something like console.log(project.getPreEmitDiagnostics())

dsherret avatar May 14 '22 17:05 dsherret

console.log(project.getPreEmitDiagnostics()) returns empty array. no compiler errors.

jon9090 avatar May 14 '22 17:05 jon9090

@jon9090 in the example you posted I get Cannot find name 'run'. since run is not defined.

That said, once I define a run function it still returns a flow node without any information. Maybe that's just expected in this scenario?

dsherret avatar May 14 '22 18:05 dsherret

@dsherret I update my code and add the run function: https://codesandbox.io/s/eager-franklin-3w6d8j?file=/src/index.ts

But what I try to get is the components classes value from appSourceFile. So I found the components within the object I pass to run function. the right side is the value. but i want to get instend the actual value which is the classes array:

thats what I can't do. why typescript can't be able to resolve in flow node the classes from the exports in index file?

If I do:

const COMPONENTS = {Foo, Bar};
const some = run({ components: { ...COMPONENTS } });

Then I got the Foo and Bar Identifiers from there I can go and resolve the class.

What I try to do is to get the exports from the flow node:

// // get the flow node
const flowNode = (nodesIdent.compilerNode as any).flowNode as ts.FlowNode;

console.log({ n: flowNode.node. initializer.elements[0].escapedText }); //<--- FooComponent

Because FooComponent is exports from index.ts and consume by appSourceFile:

import * as COMPONENTS from './index';  // <-- COMPONENTS === { FooComponent, BarComponent }
run({ components: { ...COMPONENTS } ) ...

jon9090 avatar May 14 '22 19:05 jon9090

Hey @dsherret I think I made a progress with this.

https://codesandbox.io/s/mystifying-faraday-2piybb?file=/src/index.ts:0-1044

I getting the members:

const members = Array.from((components!.getType().compilerType as any).members);
image

But how I getting the ClassDeclaration node?

image

I try to do:

members[0][1].getDeclarations()[0].kind // === 256 (ClassDeclaration)

But it's not acting like ClassDeclaration. for example it don't have getName function.

How I can get the real ClassDeclaration node?

jon9090 avatar May 16 '22 06:05 jon9090