-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[Bug] @yarnpkg/core definitions uses ../../yarnpkg-fslib/sources #1278
Comments
I'll take a look - I made a release yesterday, and I think something broke in the build pipeline. |
Everything's fine for the build - seems like TS always built bogus TS .d.ts files, we will need to investigate more in depth 🙁 |
@arcanis thank you for looking into this :) |
I experience the same issue as well at snyk/nodejs-lockfile-parser#57 @arcanis please let me know if it is something you think I can fix and I will get on it. |
Yep it's a really annoying one 🙁 I'm not exactly sure what happens, but I suspect it's because TypeScript doesn't seen I was wondering if it could be solved by adding a |
Sure I will give it a shot later today |
Trying to play with paths in tsconfig doesn't work... |
According to microsoft/TypeScript#36097 (comment) the inline imports is an intended behavior to avoid name conflicts and it makes sense. This makes me think we might need to patch typescript in order to resolve this. @arcanis what do you think? I will try to see if I can find where this goes wrong in the typescript code |
Inline imports make sense, but why would it use a relative path? That's the part I don't quite understand, since the autofix suggestions for undefined symbols are able to properly suggest the right import strings. It seems like TS has a bug that prevents it from using the package name 🤔 |
@arcanis I will need to verify if that issue happens in yarn1 with workspaces. If it does, then it is a ts bug, otherwise it means that the issue is caused by pnpify and we need to patch it manually to resolve it |
This is indeed a bug in typescript. I created the following repo to reproduce the bug - https://github.com/regevbr/typescript-workspaces-bug-reproduction- @arcanis would you mind opening an issue in typescript? I know you have your reputation there and they will take it more seriously under consideration. In any case the "workaround" is to explicitly state the return value of functions. I say it is a "workaround" because I think it is best practice to state the return value, rendering any change to the return value to throw a type error, causing the coder to think twice if the change of behavior is safe and compatible to any users of the function - changing a function's return value is like breaking an api... |
Actually I didn't notice that I used old typescript (I used another repo as the base to the repo) ... Using the latest typescript doesn't reproduce the issue... Sorry for the mess. I do believe now that the issue comes from yarn2 pnpify due to the usage of the :workspace protocol and the lack of node_modules like @arcanis suggested to begin with. In yarn1, workspaces creates a symlink in node modules for all the packages and ts properly uses them for the generated d.ts files. So back to the drawing boards to investigate the patched typescript cods in yarn2 :-( |
Ok I found the solution! function getPnpWorkspaceModuleName(moduleFileName) {
if (!isPnpAvailable()) {
return undefined;
}
var pnpApi = require("pnpapi");
var ownerPackage = pnpApi.findPackageLocator(moduleFileName);
if (!ownerPackage || ownerPackage.reference.indexOf('workspace:') !== 0) {
return undefined;
}
return ownerPackage.name;
}
function tryGetModuleNameAsNodeModule(moduleFileName, _a, host, options, packageNameOnly) {
var getCanonicalFileName = _a.getCanonicalFileName, sourceDirectory = _a.sourceDirectory;
if (!host.fileExists || !host.readFile) {
return undefined;
}
var parts = getNodeModulePathParts(moduleFileName);
if (!parts) {
var pnpModuleName = getPnpWorkspaceModuleName(moduleFileName);
return pnpModuleName || undefined;
}
.... The bug is reproducible at https://github.com/regevbr/typescript-workspaces-bug-reproduction- I'm sure it is not an airtight solution due to future plugins that can cause the same issue, so maybe you know a better way to realize that a file is part of the workspace or not? |
I realized the solution I provided will not work in case the import is nested, i.e function mockPnpWorkspaceNodeModule(moduleFileName) {
if (!isPnpAvailable()) {
return moduleFileName;
}
var pnpApi = require("pnpapi");
var ownerPackage = pnpApi.findPackageLocator(moduleFileName);
if (!ownerPackage || ownerPackage.reference.indexOf('workspace:') !== 0) {
return moduleFileName;
}
var pkgDirectory = ownerPackage.reference.replace('workspace:','');
return moduleFileName.replace('/' + pkgDirectory,ts.nodeModulesPathPart + ownerPackage.name);
}
function tryGetModuleNameAsNodeModule(moduleFileName, _a, host, options, packageNameOnly) {
var getCanonicalFileName = _a.getCanonicalFileName, sourceDirectory = _a.sourceDirectory;
if (!host.fileExists || !host.readFile) {
return undefined;
}
moduleFileName = mockPnpWorkspaceNodeModule(moduleFileName)
var parts = getNodeModulePathParts(moduleFileName);
if (!parts) {
return undefined;
} So I basically manipulate the path of the package to include export declare const add: (a: number, b: number) => import("@ts-test-bug/pkg1/dist").Test;
export declare const addNested: (a: number, b: number) => import("@ts-test-bug/pkg1/dist/add3").Test3; For the first line there is no need to add the I have updated the reproduction repo accordingly... |
So to fix the issue in my previous comment, I came up with this solution, which is more complicated :-( var workspaceProtocol = 'workspace:';
function mockPnpWorkspaceNodeModule(moduleFileName) {
if (!isPnpAvailable()) {
return undefined;
}
var pnpApi = require("pnpapi");
var ownerPackage = pnpApi.findPackageLocator(moduleFileName);
if (!ownerPackage || ownerPackage.reference.indexOf(workspaceProtocol) !== 0) {
return undefined;
}
var pkgDirectory = ownerPackage.reference.replace(workspaceProtocol,'');
var replacePartFrom = ts.directorySeparator + pkgDirectory;
var replacePartTo = ts.nodeModulesPathPart + ownerPackage.name;
var mockedFileName = moduleFileName.replace(replacePartFrom, replacePartTo);
var parts = getNodeModulePathParts(mockedFileName);
if (!parts) {
return undefined;
}
var buffer = replacePartFrom.length - replacePartTo.length;
parts.topLevelPackageNameIndex -= ts.nodeModulesPathPart.length - 1;
parts.packageRootIndex += buffer;
parts.fileNameIndex += buffer;
var pnpPkgNameReplacer = function (path) {
return path.replace(pkgDirectory, ownerPackage.name);
}
return {
pnpPkgNameReplacer: pnpPkgNameReplacer,
parts: parts,
}
}
function tryGetModuleNameAsNodeModule(moduleFileName, _a, host, options, packageNameOnly) {
var getCanonicalFileName = _a.getCanonicalFileName, sourceDirectory = _a.sourceDirectory;
if (!host.fileExists || !host.readFile) {
return undefined;
}
var pnpPkgNameReplacer;
var parts = getNodeModulePathParts(moduleFileName);
if (!parts) {
var mockedParts = mockPnpWorkspaceNodeModule(moduleFileName);
if (!mockedParts) {
return undefined;
}
parts = mockedParts.parts;
pnpPkgNameReplacer = mockedParts.pnpPkgNameReplacer;
}
var moduleSpecifier = moduleFileName;
if (!packageNameOnly) {
var packageRootIndex = parts.packageRootIndex;
var moduleFileNameForExtensionless = void 0;
while (true) {
var _b = tryDirectoryWithPackageJson(packageRootIndex), moduleFileToTry = _b.moduleFileToTry, packageRootPath = _b.packageRootPath;
if (packageRootPath) {
moduleSpecifier = packageRootPath;
break;
}
if (!moduleFileNameForExtensionless)
moduleFileNameForExtensionless = moduleFileToTry;
packageRootIndex = moduleFileName.indexOf(ts.directorySeparator, packageRootIndex + 1);
if (packageRootIndex === -1) {
moduleSpecifier = getExtensionlessFileName(moduleFileNameForExtensionless);
break;
}
}
}
var globalTypingsCacheLocation = host.getGlobalTypingsCacheLocation && host.getGlobalTypingsCacheLocation();
var pathToTopLevelNodeModules = getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex));
if (!isPnpAvailable() && !(ts.startsWith(sourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && ts.startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) {
return undefined;
}
var nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
if (pnpPkgNameReplacer) {
nodeModulesDirectoryName = pnpPkgNameReplacer(nodeModulesDirectoryName);
}
var packageName = ts.getPackageNameFromTypesPackageName(nodeModulesDirectoryName);
...
} The introduced |
@arcanis can you please check out my solution? I think the issue might affect a lot of projects... |
Hi @regevbr! Thanks a lot for investigating - I was AFK this week-end and only saw the mail notifications; I'll take a closer look at it tomorrow and report back. If I understand correctly:
Is that correct? If so, I wonder if perhaps it's not just a matter of obtaining the locator (same as you currently do), then find the workspace location (using |
The most recent post offers a complete solution to both cases! I created various scenarios in https://github.com/regevbr/typescript-workspaces-bug-reproduction- which reproduces the issues and my fix, solves all of them. I'm not sure what your suggestion means but I'm sure that you will be able to find a more clean and robust solution based on what I found, as I'm not familiar with the pnpify api. To sum up the bug - To sum up the solution - Please let me know if I wasn't clear enough :) and thanks for looking into it! |
Hi @arcanis is there anything else I can do to help? |
I'm actually looking at it right now! 😃 |
haha, if you want to DM with me about it, let me know, I'm working on a PR for another project so I'm free to help during |
I've a small patch that gets the following result: import { Fetcher, FetchOptions, MinimalFetchOptions } from './Fetcher';
import { Locator } from './types';
export declare class MultiFetcher implements Fetcher {
private readonly fetchers;
constructor(fetchers: Array<Fetcher>);
supports(locator: Locator, opts: MinimalFetchOptions): boolean;
getLocalPath(locator: Locator, opts: FetchOptions): import("@yarnpkg/fslib/sources/path.ts").PortablePath | null;
fetch(locator: Locator, opts: FetchOptions): Promise<import("@yarnpkg/core/sources/Fetcher.ts").FetchResult>;
private tryFetcher;
private getFetcher;
} However, the output references the |
Let me check real quick on my reproduction repo |
Nope for me it works great, you can see it in action in my repo https://github.com/regevbr/typescript-workspaces-bug-reproduction- |
Oh I know what you are tyring to do here... It will not work, you must let the rest of the method to run as there are some calculations there. That was the idea of my first try to solve |
thanks @arcanis!!! when can we expect a new version so we can test in other repos? |
The fix has been released: https://cdn.jsdelivr.net/npm/@yarnpkg/[email protected]/lib/MultiFetcher.d.ts |
Describe the bug
I'm trying to implement yarn 2 in renovate: renovatebot/renovate#6045
Importing @yarnpkg/core throws these errors:
##[error]node_modules/@yarnpkg/core/lib/MultiFetcher.d.ts(7,64): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/VirtualFetcher.d.ts(6,64): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/VirtualFetcher.d.ts(8,35): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/VirtualFetcher.d.ts(10,28): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/VirtualFetcher.d.ts(11,28): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/VirtualFetcher.d.ts(15,50): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
##[error]node_modules/@yarnpkg/core/lib/structUtils.d.ts(91,66): error TS2307: Cannot find module '../../yarnpkg-fslib/sources'.
You can also see the build here: https://github.com/renovatebot/renovate/pull/6045/checks?check_run_id=636048215
To Reproduce
The minimal information needed to reproduce your issue (ideally a package.json with a single dep). Note that bugs without minimal reproductions might be closed.
IMPORTANT: We strongly prefer reproductions that use Sherlock. Please check our documentation for more information: https://yarnpkg.com/advanced/sherlock
No reproduction, sorry
The text was updated successfully, but these errors were encountered: