Skip to content

Commit 53d3787

Browse files
authored
When installing unrelated package inside scoped packages dont invalidate resolutions from everything in the scoped package (#53873)
1 parent 020ce0c commit 53d3787

File tree

4 files changed

+548
-6
lines changed

4 files changed

+548
-6
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,24 +1889,24 @@ export function pathContainsNodeModules(path: string): boolean {
18891889
*
18901890
* @internal
18911891
*/
1892-
export function parseNodeModuleFromPath(resolved: string): string | undefined {
1892+
export function parseNodeModuleFromPath(resolved: string, isFolder?: boolean): string | undefined {
18931893
const path = normalizePath(resolved);
18941894
const idx = path.lastIndexOf(nodeModulesPathPart);
18951895
if (idx === -1) {
18961896
return undefined;
18971897
}
18981898

18991899
const indexAfterNodeModules = idx + nodeModulesPathPart.length;
1900-
let indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterNodeModules);
1900+
let indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterNodeModules, isFolder);
19011901
if (path.charCodeAt(indexAfterNodeModules) === CharacterCodes.at) {
1902-
indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName);
1902+
indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName, isFolder);
19031903
}
19041904
return path.slice(0, indexAfterPackageName);
19051905
}
19061906

1907-
function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number): number {
1907+
function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number, isFolder: boolean | undefined): number {
19081908
const nextSeparatorIndex = path.indexOf(directorySeparator, prevSeparatorIndex + 1);
1909-
return nextSeparatorIndex === -1 ? prevSeparatorIndex : nextSeparatorIndex;
1909+
return nextSeparatorIndex === -1 ? isFolder ? path.length : prevSeparatorIndex : nextSeparatorIndex;
19101910
}
19111911

19121912
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {

src/compiler/resolutionCache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
11521152
// If the invalidated file is from a node_modules package, invalidate everything else
11531153
// in the package since we might not get notifications for other files in the package.
11541154
// This hardens our logic against unreliable file watchers.
1155-
const packagePath = parseNodeModuleFromPath(fileOrDirectoryPath);
1155+
const packagePath = parseNodeModuleFromPath(fileOrDirectoryPath, /*isFolder*/ true);
11561156
if (packagePath) (startsWithPathChecks ||= new Set()).add(packagePath as Path);
11571157
}
11581158
}

src/testRunner/unittests/tscWatch/resolutionCache.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as ts from "../../_namespaces/ts";
22
import * as Utils from "../../_namespaces/Utils";
3+
import { libContent } from "../tsc/helpers";
34
import {
45
createWatchedSystem,
56
File,
@@ -621,4 +622,64 @@ declare namespace NodeJS {
621622
},
622623
]
623624
});
625+
626+
verifyTscWatch({
627+
scenario,
628+
subScenario: "scoped package installation",
629+
commandLineArgs: ["--w", "-p", `.`, "--traceResolution", "--extendedDiagnostics"],
630+
sys: () => createWatchedSystem({
631+
"/user/username/projects/myproject/lib/app.ts": Utils.dedent`
632+
import { myapp } from "@myapp/ts-types";
633+
const x: 10 = myapp;
634+
`,
635+
"/user/username/projects/myproject/tsconfig.json": "{}",
636+
[libFile.path]: libContent,
637+
}, { currentDirectory: "/user/username/projects/myproject" }),
638+
edits: [
639+
{
640+
caption: "npm install unrelated non scoped",
641+
edit: sys => sys.ensureFileOrFolder({
642+
path: `/user/username/projects/myproject/node_modules/unrelated/index.d.ts`,
643+
content: `export const unrelated = 10;`
644+
}),
645+
timeouts: sys => {
646+
sys.runQueuedTimeoutCallbacks();
647+
sys.runQueuedTimeoutCallbacks();
648+
},
649+
},
650+
{
651+
caption: "npm install unrelated scoped in myapp",
652+
edit: sys => sys.ensureFileOrFolder({
653+
path: `/user/username/projects/myproject/node_modules/@myapp/unrelated/index.d.ts`,
654+
content: `export const myappUnrelated = 10;`
655+
}),
656+
timeouts: sys => {
657+
sys.runQueuedTimeoutCallbacks();
658+
sys.runQueuedTimeoutCallbacks();
659+
},
660+
},
661+
{
662+
caption: "npm install unrelated2 scoped in myapp",
663+
edit: sys => sys.ensureFileOrFolder({
664+
path: `/user/username/projects/myproject/node_modules/@myapp/unrelated2/index.d.ts`,
665+
content: `export const myappUnrelated2 = 10;`
666+
}),
667+
timeouts: sys => {
668+
sys.runQueuedTimeoutCallbacks();
669+
sys.runQueuedTimeoutCallbacks();
670+
},
671+
},
672+
{
673+
caption: "npm install ts-types",
674+
edit: sys => sys.ensureFileOrFolder({
675+
path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/index.d.ts`,
676+
content: `export const myapp = 10;`
677+
}),
678+
timeouts: sys => {
679+
sys.runQueuedTimeoutCallbacks();
680+
sys.runQueuedTimeoutCallbacks();
681+
},
682+
},
683+
]
684+
});
624685
});

0 commit comments

Comments
 (0)