When installing unrelated package inside scoped packages dont invalidate resolutions from everything in the scoped package (#53873)

This commit is contained in:
Sheetal Nandi
2023-04-17 12:37:32 -07:00
committed by GitHub
parent 020ce0c08c
commit 53d378720a
4 changed files with 548 additions and 6 deletions

View File

@@ -1889,7 +1889,7 @@ export function pathContainsNodeModules(path: string): boolean {
*
* @internal
*/
export function parseNodeModuleFromPath(resolved: string): string | undefined {
export function parseNodeModuleFromPath(resolved: string, isFolder?: boolean): string | undefined {
const path = normalizePath(resolved);
const idx = path.lastIndexOf(nodeModulesPathPart);
if (idx === -1) {
@@ -1897,16 +1897,16 @@ export function parseNodeModuleFromPath(resolved: string): string | undefined {
}
const indexAfterNodeModules = idx + nodeModulesPathPart.length;
let indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterNodeModules);
let indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterNodeModules, isFolder);
if (path.charCodeAt(indexAfterNodeModules) === CharacterCodes.at) {
indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName);
indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName, isFolder);
}
return path.slice(0, indexAfterPackageName);
}
function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number): number {
function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number, isFolder: boolean | undefined): number {
const nextSeparatorIndex = path.indexOf(directorySeparator, prevSeparatorIndex + 1);
return nextSeparatorIndex === -1 ? prevSeparatorIndex : nextSeparatorIndex;
return nextSeparatorIndex === -1 ? isFolder ? path.length : prevSeparatorIndex : nextSeparatorIndex;
}
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {

View File

@@ -1152,7 +1152,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
// If the invalidated file is from a node_modules package, invalidate everything else
// in the package since we might not get notifications for other files in the package.
// This hardens our logic against unreliable file watchers.
const packagePath = parseNodeModuleFromPath(fileOrDirectoryPath);
const packagePath = parseNodeModuleFromPath(fileOrDirectoryPath, /*isFolder*/ true);
if (packagePath) (startsWithPathChecks ||= new Set()).add(packagePath as Path);
}
}

View File

@@ -1,5 +1,6 @@
import * as ts from "../../_namespaces/ts";
import * as Utils from "../../_namespaces/Utils";
import { libContent } from "../tsc/helpers";
import {
createWatchedSystem,
File,
@@ -621,4 +622,64 @@ declare namespace NodeJS {
},
]
});
verifyTscWatch({
scenario,
subScenario: "scoped package installation",
commandLineArgs: ["--w", "-p", `.`, "--traceResolution", "--extendedDiagnostics"],
sys: () => createWatchedSystem({
"/user/username/projects/myproject/lib/app.ts": Utils.dedent`
import { myapp } from "@myapp/ts-types";
const x: 10 = myapp;
`,
"/user/username/projects/myproject/tsconfig.json": "{}",
[libFile.path]: libContent,
}, { currentDirectory: "/user/username/projects/myproject" }),
edits: [
{
caption: "npm install unrelated non scoped",
edit: sys => sys.ensureFileOrFolder({
path: `/user/username/projects/myproject/node_modules/unrelated/index.d.ts`,
content: `export const unrelated = 10;`
}),
timeouts: sys => {
sys.runQueuedTimeoutCallbacks();
sys.runQueuedTimeoutCallbacks();
},
},
{
caption: "npm install unrelated scoped in myapp",
edit: sys => sys.ensureFileOrFolder({
path: `/user/username/projects/myproject/node_modules/@myapp/unrelated/index.d.ts`,
content: `export const myappUnrelated = 10;`
}),
timeouts: sys => {
sys.runQueuedTimeoutCallbacks();
sys.runQueuedTimeoutCallbacks();
},
},
{
caption: "npm install unrelated2 scoped in myapp",
edit: sys => sys.ensureFileOrFolder({
path: `/user/username/projects/myproject/node_modules/@myapp/unrelated2/index.d.ts`,
content: `export const myappUnrelated2 = 10;`
}),
timeouts: sys => {
sys.runQueuedTimeoutCallbacks();
sys.runQueuedTimeoutCallbacks();
},
},
{
caption: "npm install ts-types",
edit: sys => sys.ensureFileOrFolder({
path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/index.d.ts`,
content: `export const myapp = 10;`
}),
timeouts: sys => {
sys.runQueuedTimeoutCallbacks();
sys.runQueuedTimeoutCallbacks();
},
},
]
});
});