Skip to content

Commit 2fc6e2e

Browse files
authored
Test document position mapper (#57426)
1 parent 78bc536 commit 2fc6e2e

File tree

173 files changed

+3382
-520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

173 files changed

+3382
-520
lines changed

src/harness/projectServiceStateLogger.ts

Lines changed: 130 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import {
22
arrayFrom,
33
compareStringsCaseSensitive,
44
Debug,
5+
DocumentPositionMapper,
6+
emptyArray,
57
identity,
8+
identitySourceMapConsumer,
69
isString,
710
noop,
11+
SourceMapper,
812
} from "./_namespaces/ts";
913
import {
1014
AutoImportProviderProject,
@@ -30,6 +34,7 @@ interface ProjectData {
3034
isClosed: ReturnType<Project["isClosed"]>;
3135
isOrphan: ReturnType<Project["isOrphan"]>;
3236
noOpenRef: boolean;
37+
documentPositionMappers: SourceMapper["documentPositionMappers"];
3338
autoImportProviderHost: Project["autoImportProviderHost"];
3439
noDtsResolutionProject: Project["noDtsResolutionProject"];
3540
originalConfiguredProjects: Project["originalConfiguredProjects"];
@@ -66,14 +71,21 @@ export function patchServiceForStateBaseline(service: ProjectService) {
6671

6772
const projects = new Map<Project, ProjectData>();
6873
const scriptInfos = new Map<ScriptInfo, ScriptInfoData>();
74+
const documentPositionMappers = new Map<DocumentPositionMapper, DocumentPositionMapper>();
75+
let nextDocumentPositionMapperId = 1;
76+
const mapperToId = new Map<DocumentPositionMapper, number>();
6977
const logger = service.logger as LoggerWithInMemoryLogs;
7078
service.baseline = title => {
71-
const projectLogs = baselineProjects();
72-
const infoLogs = baselineScriptInfos();
73-
if (projectLogs?.length || infoLogs?.length) {
79+
const currentMappers = new Set<DocumentPositionMapper>();
80+
const projectLogs = baselineProjects(currentMappers);
81+
const infoLogs = baselineScriptInfos(currentMappers);
82+
currentMappers.delete(identitySourceMapConsumer);
83+
const mapperLogs = baselineDocumentPositionMappers(currentMappers);
84+
if (projectLogs?.length || infoLogs?.length || mapperLogs?.length) {
7485
if (title) logger.log(title);
7586
sendLogsToLogger("Projects::", projectLogs);
7687
sendLogsToLogger("ScriptInfos::", infoLogs);
88+
sendLogsToLogger("DocumentPositionMappers::", mapperLogs);
7789
}
7890
};
7991

@@ -88,7 +100,7 @@ export function patchServiceForStateBaseline(service: ProjectService) {
88100
logger.log("");
89101
}
90102

91-
function baselineProjects() {
103+
function baselineProjects(currentMappers: Set<DocumentPositionMapper>) {
92104
const autoImportProviderProjects = [] as AutoImportProviderProject[];
93105
const auxiliaryProjects = [] as AuxiliaryProject[];
94106
return baselineState(
@@ -97,6 +109,8 @@ export function patchServiceForStateBaseline(service: ProjectService) {
97109
(logs, project, data) => {
98110
if (project.autoImportProviderHost) autoImportProviderProjects.push(project.autoImportProviderHost);
99111
if (project.noDtsResolutionProject) auxiliaryProjects.push(project.noDtsResolutionProject);
112+
const documentMappers = getSourceMapper(project)?.documentPositionMappers;
113+
if (documentMappers) documentMappers.forEach(mapper => currentMappers.add(mapper));
100114
let projectDiff = newOrDeleted(project, projects, data);
101115
const projectPropertyLogs = [] as string[];
102116
projectDiff = printProperty(PrintPropertyWhen.Always, data, "projectStateVersion", project.projectStateVersion, projectDiff, projectPropertyLogs);
@@ -105,6 +119,15 @@ export function patchServiceForStateBaseline(service: ProjectService) {
105119
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isClosed", project.isClosed(), projectDiff, projectPropertyLogs);
106120
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isOrphan", !isBackgroundProject(project) && project.isOrphan(), projectDiff, projectPropertyLogs);
107121
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "noOpenRef", isConfiguredProject(project) && !project.hasOpenRef(), projectDiff, projectPropertyLogs);
122+
projectDiff = printMapPropertyValue(
123+
PrintPropertyWhen.Changed,
124+
data?.documentPositionMappers,
125+
"documentPositionMappers",
126+
getSourceMapper(project)?.documentPositionMappers,
127+
projectDiff,
128+
projectPropertyLogs,
129+
toStringDocumentPostionMapper,
130+
);
108131
projectDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "autoImportProviderHost", project.autoImportProviderHost, projectDiff, projectPropertyLogs, project.autoImportProviderHost ? project.autoImportProviderHost.projectName : project.autoImportProviderHost);
109132
projectDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "noDtsResolutionProject", project.noDtsResolutionProject, projectDiff, projectPropertyLogs, project.noDtsResolutionProject ? project.noDtsResolutionProject.projectName : project.noDtsResolutionProject);
110133
return printSetPropertyAndCreateStatementLog(
@@ -129,15 +152,17 @@ export function patchServiceForStateBaseline(service: ProjectService) {
129152
autoImportProviderHost: project.autoImportProviderHost,
130153
noDtsResolutionProject: project.noDtsResolutionProject,
131154
originalConfiguredProjects: project.originalConfiguredProjects && new Set(project.originalConfiguredProjects),
155+
documentPositionMappers: new Map(getSourceMapper(project)?.documentPositionMappers),
132156
}),
133157
);
134158
}
135159

136-
function baselineScriptInfos() {
160+
function baselineScriptInfos(currentMappers: Set<DocumentPositionMapper>) {
137161
return baselineState(
138162
[service.filenameToScriptInfo],
139163
scriptInfos,
140164
(logs, info, data) => {
165+
if (info.documentPositionMapper) currentMappers.add(info.documentPositionMapper);
141166
let infoDiff = newOrDeleted(info, scriptInfos, data);
142167
const infoPropertyLogs = [] as string[];
143168
const isOpen = info.isScriptOpen();
@@ -147,7 +172,7 @@ export function patchServiceForStateBaseline(service: ProjectService) {
147172
infoDiff = printScriptInfoSourceMapFilePath(data, info, infoDiff, infoPropertyLogs);
148173
infoDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "declarationInfoPath", info.declarationInfoPath, infoDiff, infoPropertyLogs);
149174
infoDiff = printSetPropertyValueWorker(PrintPropertyWhen.DefinedOrChangedOrNew, data?.sourceInfos, "sourceInfos", info.sourceInfos, infoDiff, infoPropertyLogs, identity);
150-
infoDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "documentPositionMapper", info.documentPositionMapper, infoDiff, infoPropertyLogs, info.documentPositionMapper ? "DocumentPositionMapper" : undefined);
175+
infoDiff = printProperty(PrintPropertyWhen.DefinedOrChangedOrNew, data, "documentPositionMapper", info.documentPositionMapper, infoDiff, infoPropertyLogs, info.documentPositionMapper ? toStringDocumentPostionMapper(info.documentPositionMapper) : undefined);
151176
let defaultProject: Project | undefined;
152177
try {
153178
if (isOpen) defaultProject = info.getDefaultProject();
@@ -182,8 +207,28 @@ export function patchServiceForStateBaseline(service: ProjectService) {
182207
);
183208
}
184209

210+
function baselineDocumentPositionMappers(currentMappers: Set<DocumentPositionMapper>) {
211+
const result = baselineState(
212+
[currentMappers],
213+
documentPositionMappers,
214+
(logs, mapper, data) => {
215+
const mapperDiff = newOrDeleted(mapper, documentPositionMappers, data);
216+
logs.push([
217+
`${toStringDocumentPostionMapper(mapper)}${mapperDiff}`,
218+
emptyArray,
219+
]);
220+
return mapperDiff;
221+
},
222+
identity,
223+
);
224+
mapperToId.forEach((_id, mapper) => {
225+
if (!documentPositionMappers.has(mapper)) mapperToId.delete(mapper);
226+
});
227+
return result;
228+
}
229+
185230
function baselineState<T, Data>(
186-
currentCaches: (T[] | Map<any, T>)[],
231+
currentCaches: (T[] | Map<any, T> | Set<T>)[],
187232
dataMap: Map<T, Data>,
188233
printWorker: (logs: StateItemLog[], current: T, data: Data | undefined) => Diff,
189234
toData: (current: T) => Data,
@@ -235,8 +280,7 @@ export function patchServiceForStateBaseline(service: ProjectService) {
235280
return printPropertyWorker(
236281
printWhen,
237282
value,
238-
!!data && data[key] !== value,
239-
Diff.Change,
283+
!!data && data[key] !== value ? Diff.Change : Diff.None,
240284
dataDiff,
241285
propertyLogs,
242286
`${key}: ${stringValue === undefined ? value : stringValue}`,
@@ -252,48 +296,92 @@ export function patchServiceForStateBaseline(service: ProjectService) {
252296
propertyLogs: StatePropertyLog[],
253297
toStringPropertyValue: (v: T) => string,
254298
) {
255-
const setPropertyLogs = [] as string[];
256-
let setPropertyDiff = Diff.None;
257-
propertyValue?.forEach(p =>
258-
setPropertyDiff = printPropertyWorker(
299+
return printMapOrSetPropertyValueWorker(
300+
printWhen,
301+
dataValue,
302+
propertyName,
303+
propertyValue,
304+
dataDiff,
305+
propertyLogs,
306+
value => dataDiff !== Diff.New && !dataValue?.has(value) ? Diff.New : Diff.None,
307+
toStringPropertyValue,
308+
);
309+
}
310+
311+
function printMapPropertyValue<T>(
312+
printWhen: PrintPropertyWhen.Changed,
313+
dataValue: Map<string, T> | undefined,
314+
propertyName: string,
315+
propertyValue: Map<string, T> | undefined,
316+
dataDiff: Diff,
317+
propertyLogs: StatePropertyLog[],
318+
toStringPropertyValue: (v: T) => string,
319+
) {
320+
return printMapOrSetPropertyValueWorker(
321+
printWhen,
322+
dataValue,
323+
propertyName,
324+
propertyValue,
325+
dataDiff,
326+
propertyLogs,
327+
(value, key) =>
328+
dataDiff !== Diff.New && dataValue?.get(key) !== value ?
329+
!dataValue?.has(key) ? Diff.New : Diff.Change : Diff.None,
330+
(value, key) => `${key}: ${toStringPropertyValue(value)}`,
331+
);
332+
}
333+
334+
type MapOrSetPropertyKey<T> = T extends Map<infer U, any> ? U : T extends Set<infer U> ? U : never;
335+
type MapOrSetPropertyValue<T> = T extends Map<any, infer U> ? U : T extends Set<infer U> ? U : never;
336+
function printMapOrSetPropertyValueWorker<T extends Map<string, any> | Set<any>>(
337+
printWhen: PrintPropertyWhen.Always | PrintPropertyWhen.DefinedOrChangedOrNew | PrintPropertyWhen.Changed,
338+
dataValue: T | undefined,
339+
propertyName: string,
340+
propertyValue: T | undefined,
341+
dataDiff: Diff,
342+
propertyLogs: StatePropertyLog[],
343+
getPropertyDiff: (value: MapOrSetPropertyValue<T>, key: MapOrSetPropertyKey<T>) => Diff,
344+
toStringPropertyValue: (value: MapOrSetPropertyValue<T>, key: MapOrSetPropertyKey<T>) => string,
345+
) {
346+
// Print changes
347+
const mapPropertyLogs = [] as string[];
348+
let mapPropertyDiff = Diff.None;
349+
propertyValue?.forEach((p, key) =>
350+
mapPropertyDiff = printPropertyWorker(
259351
PrintPropertyWhen.Always,
260352
p,
261-
dataDiff !== Diff.New && !dataValue?.has(p),
262-
Diff.New,
263-
setPropertyDiff,
264-
setPropertyLogs,
265-
` ${toStringPropertyValue(p)}`,
353+
getPropertyDiff(p, key),
354+
mapPropertyDiff,
355+
mapPropertyLogs,
356+
` ${toStringPropertyValue(p, key)}`,
266357
)
267358
);
268-
dataValue?.forEach(p => {
269-
if (propertyValue?.has(p)) return;
270-
setPropertyDiff = Diff.Change;
271-
setPropertyLogs.push(` ${toStringPropertyValue(p)}${Diff.Deleted}`);
359+
dataValue?.forEach((p, key) => {
360+
if (propertyValue?.has(key)) return;
361+
mapPropertyDiff = Diff.Change;
362+
mapPropertyLogs.push(` ${toStringPropertyValue(p, key)}${Diff.Deleted}`);
272363
});
273364
dataDiff = printPropertyWorker(
274365
printWhen,
275366
propertyValue,
276-
!!setPropertyDiff,
277-
Diff.Change,
367+
!!mapPropertyDiff ? Diff.Change : Diff.None,
278368
dataDiff,
279369
propertyLogs,
280370
`${propertyName}: ${propertyValue?.size || 0}`,
281371
);
282-
propertyLogs.push(setPropertyLogs);
372+
if (printWhen !== PrintPropertyWhen.Changed || mapPropertyDiff) propertyLogs.push(mapPropertyLogs);
283373
return dataDiff;
284374
}
285375

286376
function printPropertyWorker(
287377
printWhen: PrintPropertyWhen,
288378
value: any,
289-
propertyChanged: boolean,
290-
propertyChangeDiff: Diff.Change | Diff.New,
379+
propertyDiff: Diff,
291380
dataDiff: Diff,
292381
propertyLogs: StatePropertyLog[],
293382
stringValue: string,
294383
) {
295-
const propertyDiff = propertyChanged ? propertyChangeDiff : Diff.None;
296-
const result = !dataDiff && propertyDiff ? propertyChangeDiff : dataDiff;
384+
const result = !dataDiff && propertyDiff ? Diff.Change : dataDiff;
297385
switch (printWhen) {
298386
case PrintPropertyWhen.Changed:
299387
if (!propertyDiff) return result;
@@ -365,4 +453,17 @@ export function patchServiceForStateBaseline(service: ProjectService) {
365453
identity,
366454
);
367455
}
456+
457+
function toStringDocumentPostionMapper(documentPositionMapper: DocumentPositionMapper) {
458+
if (documentPositionMapper === identitySourceMapConsumer) return "identitySourceMapConsumer";
459+
let id = mapperToId.get(documentPositionMapper);
460+
if (!id) mapperToId.set(documentPositionMapper, id = nextDocumentPositionMapperId++);
461+
return `DocumentPositionMapper${id}`;
462+
}
463+
464+
function getSourceMapper(project: Project) {
465+
return project.projectKind !== ProjectKind.AutoImportProvider ?
466+
project.getLanguageService(/*ensureSynchronized*/ false)?.getSourceMapper() :
467+
undefined;
468+
}
368469
}

src/services/sourcemaps.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface SourceMapper {
3636
tryGetSourcePosition(info: DocumentPosition): DocumentPosition | undefined;
3737
tryGetGeneratedPosition(info: DocumentPosition): DocumentPosition | undefined;
3838
clearCache(): void;
39+
documentPositionMappers: Map<string, DocumentPositionMapper>;
3940
}
4041

4142
/** @internal */
@@ -56,7 +57,13 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper {
5657
const currentDirectory = host.getCurrentDirectory();
5758
const sourceFileLike = new Map<string, SourceFileLike | false>();
5859
const documentPositionMappers = new Map<string, DocumentPositionMapper>();
59-
return { tryGetSourcePosition, tryGetGeneratedPosition, toLineColumnOffset, clearCache };
60+
return {
61+
tryGetSourcePosition,
62+
tryGetGeneratedPosition,
63+
toLineColumnOffset,
64+
clearCache,
65+
documentPositionMappers,
66+
};
6067

6168
function toPath(fileName: string) {
6269
return ts_toPath(fileName, currentDirectory, getCanonicalFileName);

tests/baselines/reference/tsserver/auxiliaryProject/does-not-remove-scrips-from-InferredProject.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ Projects::
146146
/dev/null/inferredProject1* (Inferred) *changed*
147147
projectStateVersion: 1
148148
projectProgramVersion: 1
149+
documentPositionMappers: 1 *changed*
150+
/b.d.ts: identitySourceMapConsumer *new*
149151
noDtsResolutionProject: /dev/null/auxiliaryProject1* *changed*
150152

151153
ScriptInfos::

tests/baselines/reference/tsserver/auxiliaryProject/file-is-added-later-through-finding-definition.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ Projects::
266266
/dev/null/inferredProject1* (Inferred) *changed*
267267
projectStateVersion: 1
268268
projectProgramVersion: 1
269+
documentPositionMappers: 1 *changed*
270+
/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts: identitySourceMapConsumer *new*
269271
noDtsResolutionProject: /dev/null/auxiliaryProject1* *changed*
270272

271273
ScriptInfos::
@@ -377,6 +379,18 @@ Info seq [hh:mm:ss:mss] response:
377379
}
378380
After request
379381

382+
Projects::
383+
/dev/null/auxiliaryProject1* (Auxiliary)
384+
projectStateVersion: 2
385+
projectProgramVersion: 2
386+
/dev/null/inferredProject1* (Inferred) *changed*
387+
projectStateVersion: 1
388+
projectProgramVersion: 1
389+
documentPositionMappers: 2 *changed*
390+
/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts: identitySourceMapConsumer
391+
/user/users/projects/myproject/node_modules/@types/yargs/index.d.ts: identitySourceMapConsumer *new*
392+
noDtsResolutionProject: /dev/null/auxiliaryProject1*
393+
380394
ScriptInfos::
381395
/a/lib/lib.d.ts
382396
version: Text-1

tests/baselines/reference/tsserver/auxiliaryProject/resolution-is-reused-from-different-folder.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ Projects::
305305
/dev/null/inferredProject1* (Inferred) *changed*
306306
projectStateVersion: 1
307307
projectProgramVersion: 1
308+
documentPositionMappers: 1 *changed*
309+
/user/users/projects/myproject/node_modules/@types/yargs/callback.d.ts: identitySourceMapConsumer *new*
308310
noDtsResolutionProject: /dev/null/auxiliaryProject1* *changed*
309311

310312
ScriptInfos::

0 commit comments

Comments
 (0)