Skip to content

Commit 64555aa

Browse files
author
Andy
authored
navigateTo: Collect results from all referenced projects. (microsoft#25283)
* navigateTo: Collect results from all referenced projects. * Don't use project references, just source maps * Move more code to session * Test when implementation file is deleted * Use tsserver tests instead of fourslash tests to ensure session is used * Support find-all-references * Restore fourslash tests * Update emit baselines (added missing newline) * Support rename * @weswigham code review * Don't open/close files * Avoid growing `toDo` too eagerly * @sheetalkamat code review * Also get symlinked projects for originalLocation * Update API (microsoft#24966) * More @sheetalkamat code review * Remove unnecessary test * Update API (microsoft#24966)
1 parent 5b92678 commit 64555aa

File tree

70 files changed

+1537
-1089
lines changed

Some content is hidden

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

70 files changed

+1537
-1089
lines changed

src/compiler/parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7655,7 +7655,8 @@ namespace ts {
76557655
}
76567656
}
76577657

7658-
function isDeclarationFileName(fileName: string): boolean {
7658+
/** @internal */
7659+
export function isDeclarationFileName(fileName: string): boolean {
76597660
return fileExtensionIs(fileName, Extension.Dts);
76607661
}
76617662

src/compiler/program.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,7 +2344,7 @@ namespace ts {
23442344
const refPath = resolveProjectReferencePath(host, ref);
23452345
// An absolute path pointing to the containing directory of the config file
23462346
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
2347-
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile;
2347+
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
23482348
if (sourceFile === undefined) {
23492349
return undefined;
23502350
}
@@ -2823,10 +2823,14 @@ namespace ts {
28232823
};
28242824
}
28252825

2826+
export interface ResolveProjectReferencePathHost {
2827+
fileExists(fileName: string): boolean;
2828+
}
28262829
/**
2827-
* Returns the target config filename of a project reference
2830+
* Returns the target config filename of a project reference.
2831+
* Note: The file might not exist.
28282832
*/
2829-
export function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName {
2833+
export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName {
28302834
if (!host.fileExists(ref.path)) {
28312835
return combinePaths(ref.path, "tsconfig.json") as ResolvedConfigFileName;
28322836
}

src/compiler/sourcemap.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,6 @@ namespace ts {
215215
sourceMapDataList = undefined!;
216216
}
217217

218-
interface SourceMapSection {
219-
version: 3;
220-
file: string;
221-
sourceRoot?: string;
222-
sources: string[];
223-
names?: string[];
224-
mappings: string;
225-
sourcesContent?: (string | null)[];
226-
sections?: undefined;
227-
}
228-
229218
type SourceMapSectionDefinition =
230219
| { offset: { line: number, column: number }, url: string } // Included for completeness
231220
| { offset: { line: number, column: number }, map: SourceMap };
@@ -582,6 +571,17 @@ namespace ts {
582571
}
583572
}
584573

574+
export interface SourceMapSection {
575+
version: 3;
576+
file: string;
577+
sourceRoot?: string;
578+
sources: string[];
579+
names?: string[];
580+
mappings: string;
581+
sourcesContent?: (string | null)[];
582+
sections?: undefined;
583+
}
584+
585585
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
586586

587587
function base64FormatEncode(inValue: number) {

src/harness/client.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ namespace ts.server {
7373
return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText };
7474
}
7575

76-
private processRequest<T extends protocol.Request>(command: string, args?: T["arguments"]): T {
76+
private processRequest<T extends protocol.Request>(command: string, args: T["arguments"]): T {
7777
const request: protocol.Request = {
7878
seq: this.sequence,
7979
type: "request",
@@ -278,17 +278,18 @@ namespace ts.server {
278278

279279
const request = this.processRequest<protocol.DefinitionRequest>(CommandNames.DefinitionAndBoundSpan, args);
280280
const response = this.processResponse<protocol.DefinitionInfoAndBoundSpanReponse>(request);
281+
const body = Debug.assertDefined(response.body); // TODO: GH#18217
281282

282283
return {
283-
definitions: response.body!.definitions.map(entry => ({ // TODO: GH#18217
284+
definitions: body.definitions.map(entry => ({
284285
containerKind: ScriptElementKind.unknown,
285286
containerName: "",
286287
fileName: entry.file,
287288
textSpan: this.decodeSpan(entry),
288289
kind: ScriptElementKind.unknown,
289290
name: ""
290291
})),
291-
textSpan: this.decodeSpan(response.body!.textSpan, request.arguments.file)
292+
textSpan: this.decodeSpan(body.textSpan, request.arguments.file)
292293
};
293294
}
294295

@@ -341,8 +342,10 @@ namespace ts.server {
341342
}));
342343
}
343344

344-
getEmitOutput(_fileName: string): EmitOutput {
345-
return notImplemented();
345+
getEmitOutput(file: string): EmitOutput {
346+
const request = this.processRequest<protocol.EmitOutputRequest>(protocol.CommandTypes.EmitOutput, { file });
347+
const response = this.processResponse<protocol.EmitOutputResponse>(request);
348+
return response.body;
346349
}
347350

348351
getSyntacticDiagnostics(file: string): DiagnosticWithLocation[] {
@@ -716,6 +719,10 @@ namespace ts.server {
716719
throw new Error("cleanupSemanticCache is not available through the server layer.");
717720
}
718721

722+
getSourceMapper(): never {
723+
return notImplemented();
724+
}
725+
719726
dispose(): void {
720727
throw new Error("dispose is not available through the server layer.");
721728
}

src/harness/fourslash.ts

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ namespace FourSlash {
10071007

10081008
// If any of the expected values are undefined, assume that users don't
10091009
// care about them.
1010-
if (replacementSpan && !TestState.textSpansEqual(replacementSpan, entry.replacementSpan)) {
1010+
if (replacementSpan && !ts.textSpansEqual(replacementSpan, entry.replacementSpan)) {
10111011
return false;
10121012
}
10131013
else if (expectedText && text !== expectedText) {
@@ -1644,7 +1644,7 @@ Actual: ${stringify(fullActual)}`);
16441644
});
16451645
}
16461646

1647-
public baselineGetEmitOutput(insertResultsIntoVfs?: boolean) {
1647+
private getEmitFiles(): ReadonlyArray<FourSlashFile> {
16481648
// Find file to be emitted
16491649
const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on
16501650

@@ -1661,12 +1661,29 @@ Actual: ${stringify(fullActual)}`);
16611661
this.raiseError("No emitThisFile is specified in the test file");
16621662
}
16631663

1664+
return emitFiles;
1665+
}
1666+
1667+
public verifyGetEmitOutput(expectedOutputFiles: ReadonlyArray<string>): void {
1668+
const outputFiles = ts.flatMap(this.getEmitFiles(), e => this.languageService.getEmitOutput(e.fileName).outputFiles);
1669+
1670+
assert.deepEqual(outputFiles.map(f => f.name), expectedOutputFiles);
1671+
1672+
for (const { name, text } of outputFiles) {
1673+
const fromTestFile = this.getFileContent(name);
1674+
if (fromTestFile !== text) {
1675+
this.raiseError("Emit output is not as expected: " + showTextDiff(fromTestFile, text));
1676+
}
1677+
}
1678+
}
1679+
1680+
public baselineGetEmitOutput(): void {
16641681
Harness.Baseline.runBaseline(
1665-
this.testData.globalOptions[MetadataOptionNames.baselineFile],
1682+
ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]),
16661683
() => {
16671684
let resultString = "";
16681685
// Loop through all the emittedFiles and emit them one by one
1669-
emitFiles.forEach(emitFile => {
1686+
for (const emitFile of this.getEmitFiles()) {
16701687
const emitOutput = this.languageService.getEmitOutput(emitFile.fileName);
16711688
// Print emitOutputStatus in readable format
16721689
resultString += "EmitSkipped: " + emitOutput.emitSkipped + Harness.IO.newLine();
@@ -1692,13 +1709,10 @@ Actual: ${stringify(fullActual)}`);
16921709

16931710
for (const outputFile of emitOutput.outputFiles) {
16941711
const fileName = "FileName : " + outputFile.name + Harness.IO.newLine();
1695-
resultString = resultString + fileName + outputFile.text;
1696-
if (insertResultsIntoVfs) {
1697-
this.languageServiceAdapterHost.addScript(ts.getNormalizedAbsolutePath(outputFile.name, "/"), outputFile.text, /*isRootFile*/ true);
1698-
}
1712+
resultString = resultString + Harness.IO.newLine() + fileName + outputFile.text;
16991713
}
17001714
resultString += Harness.IO.newLine();
1701-
});
1715+
}
17021716

17031717
return resultString;
17041718
});
@@ -2137,11 +2151,10 @@ Actual: ${stringify(fullActual)}`);
21372151
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0");
21382152
}
21392153

2140-
const duplicate = findDuplicatedElement(implementations, implementationsAreEqual);
2154+
const duplicate = findDuplicatedElement(implementations, ts.documentSpansEqual);
21412155
if (duplicate) {
21422156
const { textSpan, fileName } = duplicate;
2143-
const end = textSpan.start + textSpan.length;
2144-
this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${end}) in ${fileName}`);
2157+
this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${ts.textSpanEnd(textSpan)}) in ${fileName}`);
21452158
}
21462159

21472160
const ranges = this.getRanges();
@@ -2208,10 +2221,6 @@ Actual: ${stringify(fullActual)}`);
22082221
this.raiseError(error);
22092222
}
22102223

2211-
function implementationsAreEqual(a: ImplementationLocationInformation, b: ImplementationLocationInformation) {
2212-
return a.fileName === b.fileName && TestState.textSpansEqual(a.textSpan, b.textSpan);
2213-
}
2214-
22152224
function displayPartIsEqualTo(a: ts.SymbolDisplayPart, b: ts.SymbolDisplayPart): boolean {
22162225
return a.kind === b.kind && a.text === b.text;
22172226
}
@@ -3260,7 +3269,7 @@ Actual: ${stringify(fullActual)}`);
32603269

32613270
if (spanIndex !== undefined) {
32623271
const span = this.getTextSpanForRangeAtIndex(spanIndex);
3263-
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + stringify(entryId)));
3272+
assert.isTrue(ts.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + stringify(entryId)));
32643273
}
32653274

32663275
eq(item.hasAction, hasAction, "hasAction");
@@ -3346,10 +3355,6 @@ Actual: ${stringify(fullActual)}`);
33463355
this.cancellationToken.resetCancelled();
33473356
}
33483357

3349-
private static textSpansEqual(a: ts.TextSpan | undefined, b: ts.TextSpan | undefined): boolean {
3350-
return !!a && !!b && a.start === b.start && a.length === b.length;
3351-
}
3352-
33533358
public getEditsForFileRename({ oldPath, newPath, newFileContents }: FourSlashInterface.GetEditsForFileRenameOptions): void {
33543359
const test = (fileContents: { readonly [fileName: string]: string }, description: string): void => {
33553360
const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, ts.emptyOptions);
@@ -3551,8 +3556,13 @@ ${code}
35513556

35523557
function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string | undefined {
35533558
for (const option in optionObject) {
3554-
if (option !== MetadataOptionNames.fileName) {
3555-
return option;
3559+
switch (option) {
3560+
case MetadataOptionNames.fileName:
3561+
case MetadataOptionNames.baselineFile:
3562+
case MetadataOptionNames.emitThisFile:
3563+
break;
3564+
default:
3565+
return option;
35563566
}
35573567
}
35583568
return undefined;
@@ -4270,8 +4280,12 @@ namespace FourSlashInterface {
42704280
this.state.baselineCurrentFileNameOrDottedNameSpans();
42714281
}
42724282

4273-
public baselineGetEmitOutput(insertResultsIntoVfs?: boolean) {
4274-
this.state.baselineGetEmitOutput(insertResultsIntoVfs);
4283+
public getEmitOutput(expectedOutputFiles: ReadonlyArray<string>): void {
4284+
this.state.verifyGetEmitOutput(expectedOutputFiles);
4285+
}
4286+
4287+
public baselineGetEmitOutput() {
4288+
this.state.baselineGetEmitOutput();
42754289
}
42764290

42774291
public baselineQuickInfo() {

src/harness/harnessLanguageService.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,9 @@ namespace Harness.LanguageService {
560560
getSourceFile(): ts.SourceFile {
561561
throw new Error("SourceFile can not be marshaled across the shim layer.");
562562
}
563+
getSourceMapper(): never {
564+
return ts.notImplemented();
565+
}
563566
dispose(): void { this.shim.dispose({}); }
564567
}
565568

@@ -707,7 +710,9 @@ namespace Harness.LanguageService {
707710
return ts.sys.getEnvironmentVariable(name);
708711
}
709712

710-
readDirectory() { return ts.notImplemented(); }
713+
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
714+
return this.host.readDirectory(path, extensions, exclude, include, depth);
715+
}
711716

712717
watchFile(): ts.FileWatcher {
713718
return { close: ts.noop };

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ interface Array<T> {}`
7878
}
7979

8080
export interface SymLink {
81+
/** Location of the symlink. */
8182
path: string;
83+
/** Relative path to the real file. */
8284
symLink: string;
8385
}
8486

0 commit comments

Comments
 (0)