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

`getExportedDeclarations` not working with yarn PnP

Open AlCalzone opened this issue 4 years ago • 5 comments
trafficstars

Describe the bug

Version: 11.0.0

I'm in the process of migrating a project to Yarn v3, including the Plug'n'Play functionality.

My project is structured as a TypeScript monorepo. The documentation is generated using ts-morph. Since the switch, that is failing, because getExportedDeclarations() is returning an empty array for re-exported types from another package of the monorepo. Many other types have become any.

I suspect this is because ts-morph is not compatible with Yarn PnP out of the box, but I'm not sure how to make it work to be honest.

To Reproduce

This is somewhat tricky to reproduce, but you can use my repo to do so.

  1. clone https://github.com/zwave-js/node-zwave-js
  2. check out commit eb20fcb
  3. run yarn add --dev ts-morph (so yarn PnP doesn't barf at you)
  4. create a file repro.ts with the following content in the root:
import { Project } from "ts-morph";

import { tsConfigFilePath } from "./packages/maintenance/src/tsAPITools";

const program = new Project({ tsConfigFilePath });

const file = program.getSourceFile("packages/zwave-js/src/index.ts");
const identifier = "ValueID";
const decl = file?.getExportedDeclarations().get(identifier);
debugger;
  1. run this in a debugging console: yarn node -r ts-node/register repro.ts

Expected behavior

decl should be an array with length 1, including the original symbol for ValueID.

AlCalzone avatar Jun 27 '21 21:06 AlCalzone

I was able to work around this for now by using yarn's patch protocol to require typescript from within ts-morph with the PnP API enabled: 5085a05 (#2913)

AlCalzone avatar Jun 28 '21 15:06 AlCalzone

I have this problem too after upgrading Yarn to the latest version and switching to the default PnP mode. @dsherret Is there an official solution on the horizon?

sschultze avatar Nov 15 '21 19:11 sschultze

It looks like this popular package can help. https://www.npmjs.com/package/ts-pnp

I wasn't able to figure out yet how to set ts-morphs Project.resolutionHost property to make use of this.

sschultze avatar Nov 15 '21 19:11 sschultze

It seems like the way ts-morph imports typescript cannot be effected by yarn PnP api. From this comment ts-morph decided to include typescript bundle as hard-copy. Because yarn enables PnP by patching typescript, including typescript like this way (not by using package json - dependencies) ts-morph cannot be compatible with yarn pnp.

So patching @ts-morph/common is one of the fast workarounds. Just fix import statement(this is similar to what @AlCalzone did, details can be changed). You can use yarn patch, patch-package, or anything else.

// in ts-morph-common.js
const ts = require('./typescript') // this one point out hard-copied typescript
// change to
const ts = require('typescript') //

I'm not sure if ts-morph should change this behavior, to support yarn pnp. Anyway this kind of bundle process (hard copy typescript dist file) is not regular way as I know, so we should think about it (although the comment said there was a hell when ts-morph serves typescript as dependency)...? @dsherret

jwoo0122 avatar Jul 04 '22 02:07 jwoo0122

Yeah like @jwoo0122 and @AlCalzone said, yarn patch protocol + redirecting the import works.
  1. Run yarn patch @ts-morph/common
  2. In <directory>/dist/ts-morph-common.js change
- var ts = require('./typescript');
+ var ts = require('typescript');
  1. Run yarn patch-commit -s <directory>
  2. In .yarnrc.yml add
packageExtensions:
+  "@ts-morph/common@*":
+    peerDependencies:
+      typescript: "*"
+  "ts-morph@*":
+    peerDependencies:
+      typescript: "*"
  1. Run yarn

You could change a few things, like patching the package.json directly in @ts-morph/common, but you get the idea.

SagnikPradhan avatar Jul 07 '22 15:07 SagnikPradhan