Skip to content

Commit cbb5826

Browse files
TypeScript Botsheetalkamatjakebailey
authored
🤖 Pick PR #54401 (Handle already released source file...) into release-5.1 (#54403)
Co-authored-by: Sheetal Nandi <[email protected]> Co-authored-by: Jake Bailey <[email protected]>
1 parent 7e48587 commit cbb5826

File tree

3 files changed

+249
-1
lines changed

3 files changed

+249
-1
lines changed

Diff for: ‎src/services/services.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1713,9 +1713,13 @@ export function createLanguageService(
17131713
// calculate this early so it's not undefined if downleveled to a var (or, if emitted
17141714
// as a const variable without downleveling, doesn't crash).
17151715
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
1716+
let releasedScriptKinds: Set<Path> | undefined = new Set();
17161717

17171718
// If the program is already up-to-date, we can reuse it
17181719
if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost!.fileExists(fileName), hasInvalidatedResolutions, hasInvalidatedLibResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) {
1720+
compilerHost = undefined;
1721+
parsedCommandLines = undefined;
1722+
releasedScriptKinds = undefined;
17191723
return;
17201724
}
17211725

@@ -1738,6 +1742,7 @@ export function createLanguageService(
17381742
// After this point, the cache needs to be cleared to allow all collected snapshots to be released
17391743
compilerHost = undefined;
17401744
parsedCommandLines = undefined;
1745+
releasedScriptKinds = undefined;
17411746

17421747
// We reset this cache on structure invalidation so we don't hold on to outdated files for long; however we can't use the `compilerHost` above,
17431748
// Because it only functions until `hostCache` is cleared, while we'll potentially need the functionality to lazily read sourcemap files during
@@ -1841,12 +1846,13 @@ export function createLanguageService(
18411846
// We do not support the scenario where a host can modify a registered
18421847
// file's script kind, i.e. in one project some file is treated as ".ts"
18431848
// and in another as ".js"
1844-
if (scriptKind === oldSourceFile.scriptKind) {
1849+
if (scriptKind === oldSourceFile.scriptKind || releasedScriptKinds!.has(oldSourceFile.resolvedPath)) {
18451850
return documentRegistry.updateDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind, languageVersionOrOptions);
18461851
}
18471852
else {
18481853
// Release old source file and fall through to aquire new file with new script kind
18491854
documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()), oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat);
1855+
releasedScriptKinds!.add(oldSourceFile.resolvedPath);
18501856
}
18511857
}
18521858

Diff for: ‎src/testRunner/unittests/tsserver/documentRegistry.ts

+39
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import * as ts from "../../_namespaces/ts";
22
import {
33
baselineTsserverLogs,
4+
closeFilesForSession,
45
createLoggerWithInMemoryLogs,
56
createProjectService,
7+
createSession,
8+
openFilesForSession,
69
TestProjectService,
710
} from "../helpers/tsserver";
811
import {
@@ -103,3 +106,39 @@ describe("unittests:: tsserver:: documentRegistry:: document registry in project
103106
baselineTsserverLogs("documentRegistry", "Caches the source file if script info is orphan, and orphan script info changes", service);
104107
});
105108
});
109+
110+
describe("unittests:: tsserver:: documentRegistry:: works when reusing orphan script info with different scriptKind", () => {
111+
it("works when reusing orphan script info with different scriptKind", () => {
112+
const host = createServerHost({});
113+
const session = createSession(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) });
114+
const newText = "exrpot const x = 10;";
115+
const content = `import x from 'react';\n${newText}`;
116+
openFilesForSession([
117+
{ file: "^/inmemory/model/6", content, scriptKindName: "TSX", projectRootPath: "/users/user/projects/san" },
118+
{ file: "^/inmemory/model/4", content, scriptKindName: "TSX", projectRootPath: "/users/user/projects/san" },
119+
], session);
120+
closeFilesForSession(["^/inmemory/model/4"], session);
121+
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
122+
command: ts.server.protocol.CommandTypes.UpdateOpen,
123+
arguments: {
124+
changedFiles: [{
125+
fileName: "^/inmemory/model/6",
126+
textChanges: [{
127+
newText,
128+
start: { line: 1, offset: 1 },
129+
end: { line: 2, offset: newText.length + 1 } // Remove the import so that structure is not reused
130+
}]
131+
}],
132+
openFiles: [
133+
{
134+
file: "^/inmemory/model/4",
135+
fileContent: newText,
136+
projectRootPath: "/users/user/projects/san", // Add same document with different script kind
137+
scriptKindName: "TS"
138+
},
139+
]
140+
}
141+
});
142+
baselineTsserverLogs("documentRegistry", "works when reusing orphan script info with different scriptKind", session);
143+
});
144+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
currentDirectory:: / useCaseSensitiveFileNames: false
2+
Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist
3+
Before request
4+
5+
Info seq [hh:mm:ss:mss] request:
6+
{
7+
"command": "open",
8+
"arguments": {
9+
"file": "^/inmemory/model/6",
10+
"projectRootPath": "/users/user/projects/san",
11+
"fileContent": "import x from 'react';\nexrpot const x = 10;",
12+
"scriptKindName": "TSX"
13+
},
14+
"seq": 1,
15+
"type": "request"
16+
}
17+
Info seq [hh:mm:ss:mss] Search path: ^/inmemory/model
18+
Info seq [hh:mm:ss:mss] For info: ^/inmemory/model/6 :: No config files found.
19+
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
20+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/^ 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
21+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/^ 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
22+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
23+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
24+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
25+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations
26+
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file
27+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots
28+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/san/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots
29+
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots
30+
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /users/user/projects/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots
31+
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
32+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
33+
Info seq [hh:mm:ss:mss] Files (1)
34+
^/inmemory/model/6 SVC-1-0 "import x from 'react';\nexrpot const x = 10;"
35+
36+
37+
^/inmemory/model/6
38+
Root file specified for compilation
39+
40+
Info seq [hh:mm:ss:mss] -----------------------------------------------
41+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
42+
Info seq [hh:mm:ss:mss] Files (1)
43+
44+
Info seq [hh:mm:ss:mss] -----------------------------------------------
45+
Info seq [hh:mm:ss:mss] Open files:
46+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/6 ProjectRootPath: /users/user/projects/san
47+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
48+
Info seq [hh:mm:ss:mss] response:
49+
{
50+
"responseRequired": false
51+
}
52+
After request
53+
54+
PolledWatches::
55+
/users/user/projects/san/^: *new*
56+
{"pollingInterval":500}
57+
/users/user/projects/san/node_modules: *new*
58+
{"pollingInterval":500}
59+
/users/user/projects/node_modules: *new*
60+
{"pollingInterval":500}
61+
/a/lib/lib.d.ts: *new*
62+
{"pollingInterval":500}
63+
/users/user/projects/san/node_modules/@types: *new*
64+
{"pollingInterval":500}
65+
/users/user/projects/node_modules/@types: *new*
66+
{"pollingInterval":500}
67+
68+
Before request
69+
70+
Info seq [hh:mm:ss:mss] request:
71+
{
72+
"command": "open",
73+
"arguments": {
74+
"file": "^/inmemory/model/4",
75+
"projectRootPath": "/users/user/projects/san",
76+
"fileContent": "import x from 'react';\nexrpot const x = 10;",
77+
"scriptKindName": "TSX"
78+
},
79+
"seq": 2,
80+
"type": "request"
81+
}
82+
Info seq [hh:mm:ss:mss] Search path: ^/inmemory/model
83+
Info seq [hh:mm:ss:mss] For info: ^/inmemory/model/4 :: No config files found.
84+
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
85+
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 2 structureChanged: true structureIsReused:: Not Elapsed:: *ms
86+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
87+
Info seq [hh:mm:ss:mss] Files (2)
88+
^/inmemory/model/6 SVC-1-0 "import x from 'react';\nexrpot const x = 10;"
89+
^/inmemory/model/4 SVC-1-0 "import x from 'react';\nexrpot const x = 10;"
90+
91+
92+
^/inmemory/model/6
93+
Root file specified for compilation
94+
^/inmemory/model/4
95+
Root file specified for compilation
96+
97+
Info seq [hh:mm:ss:mss] -----------------------------------------------
98+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
99+
Info seq [hh:mm:ss:mss] Files (2)
100+
101+
Info seq [hh:mm:ss:mss] -----------------------------------------------
102+
Info seq [hh:mm:ss:mss] Open files:
103+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/6 ProjectRootPath: /users/user/projects/san
104+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
105+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/4 ProjectRootPath: /users/user/projects/san
106+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
107+
Info seq [hh:mm:ss:mss] response:
108+
{
109+
"responseRequired": false
110+
}
111+
After request
112+
113+
Before request
114+
115+
Info seq [hh:mm:ss:mss] request:
116+
{
117+
"command": "close",
118+
"arguments": {
119+
"file": "^/inmemory/model/4"
120+
},
121+
"seq": 3,
122+
"type": "request"
123+
}
124+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
125+
Info seq [hh:mm:ss:mss] Files (2)
126+
127+
Info seq [hh:mm:ss:mss] -----------------------------------------------
128+
Info seq [hh:mm:ss:mss] Open files:
129+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/6 ProjectRootPath: /users/user/projects/san
130+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
131+
Info seq [hh:mm:ss:mss] response:
132+
{
133+
"responseRequired": false
134+
}
135+
After request
136+
137+
Before request
138+
139+
Info seq [hh:mm:ss:mss] request:
140+
{
141+
"command": "updateOpen",
142+
"arguments": {
143+
"changedFiles": [
144+
{
145+
"fileName": "^/inmemory/model/6",
146+
"textChanges": [
147+
{
148+
"newText": "exrpot const x = 10;",
149+
"start": {
150+
"line": 1,
151+
"offset": 1
152+
},
153+
"end": {
154+
"line": 2,
155+
"offset": 21
156+
}
157+
}
158+
]
159+
}
160+
],
161+
"openFiles": [
162+
{
163+
"file": "^/inmemory/model/4",
164+
"fileContent": "exrpot const x = 10;",
165+
"projectRootPath": "/users/user/projects/san",
166+
"scriptKindName": "TS"
167+
}
168+
]
169+
},
170+
"seq": 4,
171+
"type": "request"
172+
}
173+
Info seq [hh:mm:ss:mss] Search path: ^/inmemory/model
174+
Info seq [hh:mm:ss:mss] For info: ^/inmemory/model/4 :: No config files found.
175+
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
176+
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 3 structureChanged: true structureIsReused:: SafeModules Elapsed:: *ms
177+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
178+
Info seq [hh:mm:ss:mss] Files (2)
179+
^/inmemory/model/6 SVC-1-1 "exrpot const x = 10;"
180+
^/inmemory/model/4 SVC-2-0 "exrpot const x = 10;"
181+
182+
183+
^/inmemory/model/6
184+
Root file specified for compilation
185+
^/inmemory/model/4
186+
Root file specified for compilation
187+
188+
Info seq [hh:mm:ss:mss] -----------------------------------------------
189+
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
190+
Info seq [hh:mm:ss:mss] Files (2)
191+
192+
Info seq [hh:mm:ss:mss] -----------------------------------------------
193+
Info seq [hh:mm:ss:mss] Open files:
194+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/6 ProjectRootPath: /users/user/projects/san
195+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
196+
Info seq [hh:mm:ss:mss] FileName: ^/inmemory/model/4 ProjectRootPath: /users/user/projects/san
197+
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*
198+
Info seq [hh:mm:ss:mss] response:
199+
{
200+
"response": true,
201+
"responseRequired": true
202+
}
203+
After request

0 commit comments

Comments
 (0)