mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 11:50:54 -06:00
Find references of a module by filename (#41805)
* Naive implementation enough to build and write a test * Add simple test * Add project references test * Add deduplication test, accept baselines * Add test for referencing a script (doesn’t do anything) * Update API baselines * Use refFileMap for non-module references * Fix find-all-refs on module specifier * Remove unused util * Don’t store text range on ts.RefFile * Ensure string literal could itself be a file reference * Remove unused utilities * Improve baseline format * Preserve old behavior of falling back to string literal references * Update baselines from master * Fix old RefFileMap code after merge * Add test for additional response info * Undo test change
This commit is contained in:
parent
1c1cd9b08d
commit
9dfbf07d8a
@ -362,6 +362,18 @@ namespace ts.server {
|
||||
}));
|
||||
}
|
||||
|
||||
getFileReferences(fileName: string): ReferenceEntry[] {
|
||||
const request = this.processRequest<protocol.FileReferencesRequest>(CommandNames.FileReferences, { file: fileName });
|
||||
const response = this.processResponse<protocol.FileReferencesResponse>(request);
|
||||
|
||||
return response.body!.refs.map(entry => ({ // TODO: GH#18217
|
||||
fileName: entry.file,
|
||||
textSpan: this.decodeSpan(entry),
|
||||
isWriteAccess: entry.isWriteAccess,
|
||||
isDefinition: entry.isDefinition,
|
||||
}));
|
||||
}
|
||||
|
||||
getEmitOutput(file: string): EmitOutput {
|
||||
const request = this.processRequest<protocol.EmitOutputRequest>(protocol.CommandTypes.EmitOutput, { file });
|
||||
const response = this.processResponse<protocol.EmitOutputResponse>(request);
|
||||
|
||||
@ -1114,38 +1114,77 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyBaselineFindAllReferences(markerName: string) {
|
||||
const marker = this.getMarkerByName(markerName);
|
||||
const references = this.languageService.findReferences(marker.fileName, marker.position);
|
||||
public verifyBaselineFindAllReferences(...markerNames: string[]) {
|
||||
const baseline = markerNames.map(markerName => {
|
||||
const marker = this.getMarkerByName(markerName);
|
||||
const references = this.languageService.findReferences(marker.fileName, marker.position);
|
||||
const refsByFile = references
|
||||
? ts.group(ts.sort(ts.flatMap(references, r => r.references), (a, b) => a.textSpan.start - b.textSpan.start), ref => ref.fileName)
|
||||
: ts.emptyArray;
|
||||
|
||||
// Write input files
|
||||
const baselineContent = this.getBaselineContentForGroupedReferences(refsByFile, markerName);
|
||||
|
||||
// Write response JSON
|
||||
return baselineContent + JSON.stringify(references, undefined, 2);
|
||||
}).join("\n\n");
|
||||
Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(".baseline.jsonc"), baseline);
|
||||
}
|
||||
|
||||
public verifyBaselineGetFileReferences(fileName: string) {
|
||||
const references = this.languageService.getFileReferences(fileName);
|
||||
const refsByFile = references
|
||||
? ts.group(ts.sort(ts.flatMap(references, r => r.references), (a, b) => a.textSpan.start - b.textSpan.start), ref => ref.fileName)
|
||||
? ts.group(ts.sort(references, (a, b) => a.textSpan.start - b.textSpan.start), ref => ref.fileName)
|
||||
: ts.emptyArray;
|
||||
|
||||
// Write input files
|
||||
let baselineContent = this.getBaselineContentForGroupedReferences(refsByFile);
|
||||
|
||||
// Write response JSON
|
||||
baselineContent += JSON.stringify(references, undefined, 2);
|
||||
Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(".baseline.jsonc"), baselineContent);
|
||||
}
|
||||
|
||||
private getBaselineContentForGroupedReferences(refsByFile: readonly (readonly ts.ReferenceEntry[])[], markerName?: string) {
|
||||
const marker = markerName !== undefined ? this.getMarkerByName(markerName) : undefined;
|
||||
let baselineContent = "";
|
||||
for (const group of refsByFile) {
|
||||
baselineContent += getBaselineContentForFile(group[0].fileName, this.getFileContent(group[0].fileName));
|
||||
baselineContent += "\n\n";
|
||||
}
|
||||
|
||||
// Write response JSON
|
||||
baselineContent += JSON.stringify(references, undefined, 2);
|
||||
Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(".baseline.jsonc"), baselineContent);
|
||||
return baselineContent;
|
||||
|
||||
function getBaselineContentForFile(fileName: string, content: string) {
|
||||
let newContent = `=== ${fileName} ===\n`;
|
||||
let pos = 0;
|
||||
for (const { textSpan } of refsByFile.find(refs => refs[0].fileName === fileName) ?? ts.emptyArray) {
|
||||
if (fileName === marker.fileName && ts.textSpanContainsPosition(textSpan, marker.position)) {
|
||||
newContent += "/*FIND ALL REFS*/";
|
||||
}
|
||||
const end = textSpan.start + textSpan.length;
|
||||
newContent += content.slice(pos, textSpan.start);
|
||||
newContent += "[|";
|
||||
newContent += content.slice(textSpan.start, end);
|
||||
pos = textSpan.start;
|
||||
// It's easier to read if the /*FIND ALL REFS*/ comment is outside the range markers, which makes
|
||||
// this code a bit more verbose than it would be if I were less picky about the baseline format.
|
||||
if (fileName === marker?.fileName && marker.position === textSpan.start) {
|
||||
newContent += "/*FIND ALL REFS*/";
|
||||
newContent += "[|";
|
||||
}
|
||||
else if (fileName === marker?.fileName && ts.textSpanContainsPosition(textSpan, marker.position)) {
|
||||
newContent += "[|";
|
||||
newContent += content.slice(pos, marker.position);
|
||||
newContent += "/*FIND ALL REFS*/";
|
||||
pos = marker.position;
|
||||
}
|
||||
else {
|
||||
newContent += "[|";
|
||||
}
|
||||
newContent += content.slice(pos, end);
|
||||
newContent += "|]";
|
||||
pos = end;
|
||||
}
|
||||
if (marker?.fileName === fileName && marker.position >= pos) {
|
||||
newContent += content.slice(pos, marker.position);
|
||||
newContent += "/*FIND ALL REFS*/";
|
||||
pos = marker.position;
|
||||
}
|
||||
newContent += content.slice(pos);
|
||||
return newContent.split(/\r?\n/).map(l => "// " + l).join("\n");
|
||||
}
|
||||
|
||||
@ -332,8 +332,12 @@ namespace FourSlashInterface {
|
||||
this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected);
|
||||
}
|
||||
|
||||
public baselineFindAllReferences(markerName: string) {
|
||||
this.state.verifyBaselineFindAllReferences(markerName);
|
||||
public baselineFindAllReferences(...markerNames: string[]) {
|
||||
this.state.verifyBaselineFindAllReferences(...markerNames);
|
||||
}
|
||||
|
||||
public baselineGetFileReferences(fileName: string) {
|
||||
this.state.verifyBaselineGetFileReferences(fileName);
|
||||
}
|
||||
|
||||
public referenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<FourSlash.Range>, parts: ReferenceGroup[]) {
|
||||
|
||||
@ -519,6 +519,9 @@ namespace Harness.LanguageService {
|
||||
findReferences(fileName: string, position: number): ts.ReferencedSymbol[] {
|
||||
return unwrapJSONCallResult(this.shim.findReferences(fileName, position));
|
||||
}
|
||||
getFileReferences(fileName: string): ts.ReferenceEntry[] {
|
||||
return unwrapJSONCallResult(this.shim.getFileReferences(fileName));
|
||||
}
|
||||
getOccurrencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] {
|
||||
return unwrapJSONCallResult(this.shim.getOccurrencesAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
@ -37,6 +37,9 @@ namespace ts.server.protocol {
|
||||
/* @internal */
|
||||
EmitOutput = "emit-output",
|
||||
Exit = "exit",
|
||||
FileReferences = "fileReferences",
|
||||
/* @internal */
|
||||
FileReferencesFull = "fileReferences-full",
|
||||
Format = "format",
|
||||
Formatonkey = "formatonkey",
|
||||
/* @internal */
|
||||
@ -1152,6 +1155,25 @@ namespace ts.server.protocol {
|
||||
body?: ReferencesResponseBody;
|
||||
}
|
||||
|
||||
export interface FileReferencesRequest extends FileRequest {
|
||||
command: CommandTypes.FileReferences;
|
||||
}
|
||||
|
||||
export interface FileReferencesResponseBody {
|
||||
/**
|
||||
* The file locations referencing the symbol.
|
||||
*/
|
||||
refs: readonly ReferencesResponseItem[];
|
||||
/**
|
||||
* The name of the symbol.
|
||||
*/
|
||||
symbolName: string;
|
||||
}
|
||||
|
||||
export interface FileReferencesResponse extends Response {
|
||||
body?: FileReferencesResponseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument for RenameRequest request.
|
||||
*/
|
||||
|
||||
@ -409,6 +409,29 @@ namespace ts.server {
|
||||
return outputs.filter(o => o.references.length !== 0);
|
||||
}
|
||||
|
||||
function combineProjectOutputForFileReferences(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
fileName: string
|
||||
): readonly ReferenceEntry[] {
|
||||
const outputs: ReferenceEntry[] = [];
|
||||
|
||||
combineProjectOutputWorker(
|
||||
projects,
|
||||
defaultProject,
|
||||
/*initialLocation*/ undefined,
|
||||
project => {
|
||||
for (const referenceEntry of project.getLanguageService().getFileReferences(fileName) || emptyArray) {
|
||||
if (!contains(outputs, referenceEntry, documentSpansEqual)) {
|
||||
outputs.push(referenceEntry);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
interface ProjectAndLocation<TLocation extends DocumentPosition | undefined> {
|
||||
readonly project: Project;
|
||||
readonly location: TLocation;
|
||||
@ -1509,7 +1532,7 @@ namespace ts.server {
|
||||
return arrayFrom(map.values());
|
||||
}
|
||||
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | undefined | readonly ReferencedSymbol[] {
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | readonly ReferencedSymbol[] {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const projects = this.getProjects(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
@ -1528,22 +1551,28 @@ namespace ts.server {
|
||||
const nameSpan = nameInfo && nameInfo.textSpan;
|
||||
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
|
||||
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
|
||||
const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol =>
|
||||
referencedSymbol.references.map(({ fileName, textSpan, contextSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
|
||||
const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(fileName));
|
||||
const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo);
|
||||
const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1);
|
||||
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: fileName,
|
||||
...span,
|
||||
lineText,
|
||||
isWriteAccess,
|
||||
isDefinition
|
||||
};
|
||||
}));
|
||||
const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol => {
|
||||
return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry));
|
||||
});
|
||||
return { refs, symbolName, symbolStartOffset, symbolDisplayString };
|
||||
}
|
||||
|
||||
private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] {
|
||||
const projects = this.getProjects(args);
|
||||
const references = combineProjectOutputForFileReferences(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
args.file,
|
||||
);
|
||||
|
||||
if (!simplifiedResult) return references;
|
||||
const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry));
|
||||
return {
|
||||
refs,
|
||||
symbolName: `"${args.file}"`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName is the name of the file to be opened
|
||||
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
|
||||
@ -2639,6 +2668,12 @@ namespace ts.server {
|
||||
[CommandNames.GetSpanOfEnclosingComment]: (request: protocol.SpanOfEnclosingCommentRequest) => {
|
||||
return this.requiredResponse(this.getSpanOfEnclosingComment(request.arguments));
|
||||
},
|
||||
[CommandNames.FileReferences]: (request: protocol.FileReferencesRequest) => {
|
||||
return this.requiredResponse(this.getFileReferences(request.arguments, /*simplifiedResult*/ true));
|
||||
},
|
||||
[CommandNames.FileReferencesFull]: (request: protocol.FileReferencesRequest) => {
|
||||
return this.requiredResponse(this.getFileReferences(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.Format]: (request: protocol.FormatRequest) => {
|
||||
return this.requiredResponse(this.getFormattingEditsForRange(request.arguments));
|
||||
},
|
||||
@ -3068,4 +3103,18 @@ namespace ts.server {
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferenceEntry): protocol.ReferencesResponseItem {
|
||||
const scriptInfo = Debug.checkDefined(projectService.getScriptInfo(fileName));
|
||||
const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo);
|
||||
const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1);
|
||||
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: fileName,
|
||||
...span,
|
||||
lineText,
|
||||
isWriteAccess,
|
||||
isDefinition
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,7 +622,21 @@ namespace ts.FindAllReferences {
|
||||
// Could not find a symbol e.g. unknown identifier
|
||||
if (!symbol) {
|
||||
// String literal might be a property (and thus have a symbol), so do this here rather than in getReferencedSymbolsSpecial.
|
||||
return !options.implementations && isStringLiteralLike(node) ? getReferencesForStringLiteral(node, sourceFiles, checker, cancellationToken) : undefined;
|
||||
if (!options.implementations && isStringLiteralLike(node)) {
|
||||
if (isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ true) || isExternalModuleReference(node.parent) || isImportDeclaration(node.parent) || isImportCall(node.parent)) {
|
||||
const fileIncludeReasons = program.getFileIncludeReasons();
|
||||
const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text)?.resolvedFileName;
|
||||
const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined;
|
||||
if (referencedFile) {
|
||||
return [{ definition: { type: DefinitionKind.String, node }, references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray }];
|
||||
}
|
||||
// Fall through to string literal references. This is not very likely to return
|
||||
// anything useful, but I guess it's better than nothing, and there's an existing
|
||||
// test that expects this to happen (fourslash/cases/untypedModuleImport.ts).
|
||||
}
|
||||
return getReferencesForStringLiteral(node, sourceFiles, checker, cancellationToken);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (symbol.escapedName === InternalSymbolName.ExportEquals) {
|
||||
@ -642,6 +656,35 @@ namespace ts.FindAllReferences {
|
||||
return mergeReferences(program, moduleReferences, references, moduleReferencesOfExportTarget);
|
||||
}
|
||||
|
||||
export function getReferencesForFileName(fileName: string, program: Program, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet<string> = new Set(sourceFiles.map(f => f.fileName))): readonly Entry[] {
|
||||
const moduleSymbol = program.getSourceFile(fileName)?.symbol;
|
||||
if (moduleSymbol) {
|
||||
return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet)[0]?.references || emptyArray;
|
||||
}
|
||||
const fileIncludeReasons = program.getFileIncludeReasons();
|
||||
const referencedFile = program.getSourceFile(fileName);
|
||||
return referencedFile && fileIncludeReasons && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray;
|
||||
}
|
||||
|
||||
function getReferencesForNonModule(referencedFile: SourceFile, refFileMap: MultiMap<Path, FileIncludeReason>, program: Program): readonly SpanEntry[] | undefined {
|
||||
let entries: SpanEntry[] | undefined;
|
||||
const references = refFileMap.get(referencedFile.path) || emptyArray;
|
||||
for (const ref of references) {
|
||||
if (isReferencedFile(ref)) {
|
||||
const referencingFile = program.getSourceFileByPath(ref.file)!;
|
||||
const location = getReferencedFileLocation(program.getSourceFileByPath, ref);
|
||||
if (isReferenceFileLocation(location)) {
|
||||
entries = append(entries, {
|
||||
kind: EntryKind.Span,
|
||||
fileName: referencingFile.fileName,
|
||||
textSpan: createTextSpanFromRange(location)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
function getMergedAliasedSymbolOfNamespaceExportDeclaration(node: Node, symbol: Symbol, checker: TypeChecker) {
|
||||
if (node.parent && isNamespaceExportDeclaration(node.parent)) {
|
||||
const aliasedSymbol = checker.getAliasedSymbol(symbol);
|
||||
|
||||
@ -1728,6 +1728,11 @@ namespace ts {
|
||||
return FindAllReferences.findReferencedSymbols(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
function getFileReferences(fileName: string): ReferenceEntry[] {
|
||||
synchronizeHostData();
|
||||
return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map(FindAllReferences.toReferenceEntry);
|
||||
}
|
||||
|
||||
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] {
|
||||
synchronizeHostData();
|
||||
const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles();
|
||||
@ -2526,6 +2531,7 @@ namespace ts {
|
||||
getTypeDefinitionAtPosition,
|
||||
getReferencesAtPosition,
|
||||
findReferences,
|
||||
getFileReferences,
|
||||
getOccurrencesAtPosition,
|
||||
getDocumentHighlights,
|
||||
getNameOrDottedNameSpan,
|
||||
|
||||
@ -208,6 +208,12 @@ namespace ts {
|
||||
*/
|
||||
findReferences(fileName: string, position: number): string;
|
||||
|
||||
/**
|
||||
* Returns a JSON-encoded value of the type:
|
||||
* { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean, isDefinition?: boolean }[]
|
||||
*/
|
||||
getFileReferences(fileName: string): string;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns a JSON-encoded value of the type:
|
||||
@ -916,6 +922,13 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
public getFileReferences(fileName: string) {
|
||||
return this.forwardJSONCall(
|
||||
`getFileReferences('${fileName})`,
|
||||
() => this.languageService.getFileReferences(fileName)
|
||||
);
|
||||
}
|
||||
|
||||
public getOccurrencesAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
`getOccurrencesAtPosition('${fileName}', ${position})`,
|
||||
|
||||
@ -468,6 +468,7 @@ namespace ts {
|
||||
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
|
||||
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
|
||||
getFileReferences(fileName: string): ReferenceEntry[];
|
||||
|
||||
/** @deprecated */
|
||||
getOccurrencesAtPosition(fileName: string, position: number): readonly ReferenceEntry[] | undefined;
|
||||
|
||||
@ -171,6 +171,7 @@
|
||||
"unittests/tsserver/getApplicableRefactors.ts",
|
||||
"unittests/tsserver/getEditsForFileRename.ts",
|
||||
"unittests/tsserver/getExportReferences.ts",
|
||||
"unittests/tsserver/getFileReferences.ts",
|
||||
"unittests/tsserver/importHelpers.ts",
|
||||
"unittests/tsserver/importSuggestionsCache.ts",
|
||||
"unittests/tsserver/inferredProjects.ts",
|
||||
|
||||
58
src/testRunner/unittests/tsserver/getFileReferences.ts
Normal file
58
src/testRunner/unittests/tsserver/getFileReferences.ts
Normal file
@ -0,0 +1,58 @@
|
||||
namespace ts.projectSystem {
|
||||
describe("unittests:: tsserver:: getFileReferences", () => {
|
||||
const importA = `import "./a";`;
|
||||
const importCurlyFromA = `import {} from "./a";`;
|
||||
const importAFromA = `import { a } from "/project/a";`;
|
||||
const typeofImportA = `type T = typeof import("./a").a;`;
|
||||
|
||||
const aTs: File = {
|
||||
path: "/project/a.ts",
|
||||
content: "export const a = {};",
|
||||
};
|
||||
const bTs: File = {
|
||||
path: "/project/b.ts",
|
||||
content: importA,
|
||||
};
|
||||
const cTs: File = {
|
||||
path: "/project/c.ts",
|
||||
content: importCurlyFromA
|
||||
};
|
||||
const dTs: File = {
|
||||
path: "/project/d.ts",
|
||||
content: [importAFromA, typeofImportA].join("\n")
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/project/tsconfig.json",
|
||||
content: "{}",
|
||||
};
|
||||
|
||||
function makeSampleSession() {
|
||||
const host = createServerHost([aTs, bTs, cTs, dTs, tsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs, bTs, cTs, dTs], session);
|
||||
return session;
|
||||
}
|
||||
|
||||
it("should get file references", () => {
|
||||
const session = makeSampleSession();
|
||||
|
||||
const response = executeSessionRequest<protocol.FileReferencesRequest, protocol.FileReferencesResponse>(
|
||||
session,
|
||||
protocol.CommandTypes.FileReferences,
|
||||
{ file: aTs.path },
|
||||
);
|
||||
|
||||
const expectResponse: protocol.FileReferencesResponseBody = {
|
||||
refs: [
|
||||
makeReferenceItem({ file: bTs, text: "./a", lineText: importA, contextText: importA, isDefinition: false, isWriteAccess: false }),
|
||||
makeReferenceItem({ file: cTs, text: "./a", lineText: importCurlyFromA, contextText: importCurlyFromA, isDefinition: false, isWriteAccess: false }),
|
||||
makeReferenceItem({ file: dTs, text: "/project/a", lineText: importAFromA, contextText: importAFromA, isDefinition: false, isWriteAccess: false }),
|
||||
makeReferenceItem({ file: dTs, text: "./a", lineText: typeofImportA, contextText: typeofImportA, isDefinition: false, isWriteAccess: false }),
|
||||
],
|
||||
symbolName: `"${aTs.path}"`,
|
||||
};
|
||||
|
||||
assert.deepEqual(response, expectResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -207,6 +207,8 @@ namespace ts.server {
|
||||
CommandNames.Implementation,
|
||||
CommandNames.ImplementationFull,
|
||||
CommandNames.Exit,
|
||||
CommandNames.FileReferences,
|
||||
CommandNames.FileReferencesFull,
|
||||
CommandNames.Format,
|
||||
CommandNames.Formatonkey,
|
||||
CommandNames.FormatFull,
|
||||
|
||||
@ -5531,6 +5531,7 @@ declare namespace ts {
|
||||
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
|
||||
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
|
||||
getFileReferences(fileName: string): ReferenceEntry[];
|
||||
/** @deprecated */
|
||||
getOccurrencesAtPosition(fileName: string, position: number): readonly ReferenceEntry[] | undefined;
|
||||
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
|
||||
@ -6536,6 +6537,7 @@ declare namespace ts.server.protocol {
|
||||
DefinitionAndBoundSpan = "definitionAndBoundSpan",
|
||||
Implementation = "implementation",
|
||||
Exit = "exit",
|
||||
FileReferences = "fileReferences",
|
||||
Format = "format",
|
||||
Formatonkey = "formatonkey",
|
||||
Geterr = "geterr",
|
||||
@ -7349,6 +7351,22 @@ declare namespace ts.server.protocol {
|
||||
interface ReferencesResponse extends Response {
|
||||
body?: ReferencesResponseBody;
|
||||
}
|
||||
interface FileReferencesRequest extends FileRequest {
|
||||
command: CommandTypes.FileReferences;
|
||||
}
|
||||
interface FileReferencesResponseBody {
|
||||
/**
|
||||
* The file locations referencing the symbol.
|
||||
*/
|
||||
refs: readonly ReferencesResponseItem[];
|
||||
/**
|
||||
* The name of the symbol.
|
||||
*/
|
||||
symbolName: string;
|
||||
}
|
||||
interface FileReferencesResponse extends Response {
|
||||
body?: FileReferencesResponseBody;
|
||||
}
|
||||
/**
|
||||
* Argument for RenameRequest request.
|
||||
*/
|
||||
@ -9980,6 +9998,7 @@ declare namespace ts.server {
|
||||
private mapRenameInfo;
|
||||
private toSpanGroups;
|
||||
private getReferences;
|
||||
private getFileReferences;
|
||||
/**
|
||||
* @param fileName is the name of the file to be opened
|
||||
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
|
||||
|
||||
@ -5531,6 +5531,7 @@ declare namespace ts {
|
||||
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
|
||||
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
|
||||
getFileReferences(fileName: string): ReferenceEntry[];
|
||||
/** @deprecated */
|
||||
getOccurrencesAtPosition(fileName: string, position: number): readonly ReferenceEntry[] | undefined;
|
||||
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// === /b.js ===
|
||||
// const { [|f|]/*FIND ALL REFS*/ } = require('./a')
|
||||
// [|f|]
|
||||
// const { [|f|] } = require('./a')
|
||||
// /*FIND ALL REFS*/[|f|]
|
||||
|
||||
// === /a.js ===
|
||||
// function [|f|]() { }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// === /b.js ===
|
||||
// const { [|f|]/*FIND ALL REFS*/ } = require('./a')
|
||||
// [|f|]
|
||||
// const { [|f|] } = require('./a')
|
||||
// /*FIND ALL REFS*/[|f|]
|
||||
|
||||
// === /a.js ===
|
||||
// function [|f|]() { }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// === /b.js ===
|
||||
// const { [|f|]/*FIND ALL REFS*/ } = require('./a')
|
||||
// [|f|]
|
||||
// const { [|f|] } = require('./a')
|
||||
// /*FIND ALL REFS*/[|f|]
|
||||
|
||||
// === /a.js ===
|
||||
// function [|f|]() { }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// === /app.ts ===
|
||||
// /*FIND ALL REFS*/export function [|hello|]() {};
|
||||
// export function [|he/*FIND ALL REFS*/llo|]() {};
|
||||
|
||||
// === /indirect-use.ts ===
|
||||
// import("./re-export").then(mod => mod.services.app.[|hello|]());
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// === /app.ts ===
|
||||
// /*FIND ALL REFS*/export function [|hello|]() {};
|
||||
// export function [|he/*FIND ALL REFS*/llo|]() {};
|
||||
|
||||
// === /indirect-use.ts ===
|
||||
// import type { app } from "./re-export";
|
||||
|
||||
186
tests/baselines/reference/findAllRefsNonModule.baseline.jsonc
Normal file
186
tests/baselines/reference/findAllRefsNonModule.baseline.jsonc
Normal file
@ -0,0 +1,186 @@
|
||||
// === /import.ts ===
|
||||
// import [|"./script/*FIND ALL REFS*/"|];
|
||||
|
||||
// === /require.js ===
|
||||
// require([|"./script"|]);
|
||||
// console.log("./script");
|
||||
|
||||
// === /tripleSlash.ts ===
|
||||
// /// <reference path="[|script.ts|]" />
|
||||
|
||||
[
|
||||
{
|
||||
"definition": {
|
||||
"containerKind": "",
|
||||
"containerName": "",
|
||||
"fileName": "/import.ts",
|
||||
"kind": "var",
|
||||
"name": "./script",
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 8
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "\"./script\"",
|
||||
"kind": "stringLiteral"
|
||||
}
|
||||
]
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 7,
|
||||
"length": 10
|
||||
},
|
||||
"fileName": "/import.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 10
|
||||
},
|
||||
"fileName": "/require.js",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 21,
|
||||
"length": 9
|
||||
},
|
||||
"fileName": "/tripleSlash.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// === /import.ts ===
|
||||
// import [|"./script"|];
|
||||
|
||||
// === /require.js ===
|
||||
// require([|"./script/*FIND ALL REFS*/"|]);
|
||||
// console.log("./script");
|
||||
|
||||
// === /tripleSlash.ts ===
|
||||
// /// <reference path="[|script.ts|]" />
|
||||
|
||||
[
|
||||
{
|
||||
"definition": {
|
||||
"containerKind": "",
|
||||
"containerName": "",
|
||||
"fileName": "/require.js",
|
||||
"kind": "var",
|
||||
"name": "./script",
|
||||
"textSpan": {
|
||||
"start": 9,
|
||||
"length": 8
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "\"./script\"",
|
||||
"kind": "stringLiteral"
|
||||
}
|
||||
]
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 7,
|
||||
"length": 10
|
||||
},
|
||||
"fileName": "/import.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 10
|
||||
},
|
||||
"fileName": "/require.js",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 21,
|
||||
"length": 9
|
||||
},
|
||||
"fileName": "/tripleSlash.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// === /require.js ===
|
||||
// require("[|./script|]");
|
||||
// console.log("[|./script|]/*FIND ALL REFS*/");
|
||||
|
||||
// === /stringLiteral.ts ===
|
||||
// console.log("[|./script|]");
|
||||
|
||||
[
|
||||
{
|
||||
"definition": {
|
||||
"containerKind": "",
|
||||
"containerName": "",
|
||||
"fileName": "/require.js",
|
||||
"kind": "var",
|
||||
"name": "./script",
|
||||
"textSpan": {
|
||||
"start": 34,
|
||||
"length": 8
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "\"./script\"",
|
||||
"kind": "stringLiteral"
|
||||
}
|
||||
]
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 9,
|
||||
"length": 8
|
||||
},
|
||||
"fileName": "/require.js",
|
||||
"contextSpan": {
|
||||
"start": 0,
|
||||
"length": 20
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false,
|
||||
"isInString": true
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 34,
|
||||
"length": 8
|
||||
},
|
||||
"fileName": "/require.js",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false,
|
||||
"isInString": true
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 13,
|
||||
"length": 8
|
||||
},
|
||||
"fileName": "/stringLiteral.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false,
|
||||
"isInString": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -5,7 +5,7 @@
|
||||
// const y = 0;
|
||||
|
||||
// === /a.js ===
|
||||
// /*FIND ALL REFS*/module.exports = class [|C|] {};
|
||||
// module.exports = class /*FIND ALL REFS*/[|C|] {};
|
||||
// module.exports.D = class D {};
|
||||
|
||||
[
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// === /a.js ===
|
||||
// /*FIND ALL REFS*/module.exports = class C {};
|
||||
// module.exports.[|D|] = class D {};
|
||||
// module.exports = class C {};
|
||||
// module.exports./*FIND ALL REFS*/[|D|] = class D {};
|
||||
|
||||
// === /b.js ===
|
||||
// /** @type {import("./a")} */
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// === /a.js ===
|
||||
// /*FIND ALL REFS*/module.exports = class C {};
|
||||
// module.exports.D = class [|D|] {};
|
||||
// module.exports = class C {};
|
||||
// module.exports.D = class /*FIND ALL REFS*/[|D|] {};
|
||||
|
||||
// === /b.js ===
|
||||
// /** @type {import("./a")} */
|
||||
|
||||
64
tests/baselines/reference/getFileReferences1.baseline.jsonc
Normal file
64
tests/baselines/reference/getFileReferences1.baseline.jsonc
Normal file
@ -0,0 +1,64 @@
|
||||
// === /project/b.ts ===
|
||||
// import "[|./a|]";
|
||||
|
||||
// === /project/c.ts ===
|
||||
// import {} from "[|./a|]";
|
||||
|
||||
// === /project/d.ts ===
|
||||
// import { a } from "[|/project/a|]";
|
||||
// type T = typeof import("[|./a|]").a;
|
||||
|
||||
[
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 3
|
||||
},
|
||||
"fileName": "/project/b.ts",
|
||||
"contextSpan": {
|
||||
"start": 0,
|
||||
"length": 13
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 16,
|
||||
"length": 3
|
||||
},
|
||||
"fileName": "/project/c.ts",
|
||||
"contextSpan": {
|
||||
"start": 0,
|
||||
"length": 21
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 19,
|
||||
"length": 10
|
||||
},
|
||||
"fileName": "/project/d.ts",
|
||||
"contextSpan": {
|
||||
"start": 0,
|
||||
"length": 31
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 56,
|
||||
"length": 3
|
||||
},
|
||||
"fileName": "/project/d.ts",
|
||||
"contextSpan": {
|
||||
"start": 32,
|
||||
"length": 32
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
14
tests/baselines/reference/getFileReferences2.baseline.jsonc
Normal file
14
tests/baselines/reference/getFileReferences2.baseline.jsonc
Normal file
@ -0,0 +1,14 @@
|
||||
// === /project/b.ts ===
|
||||
// import [|"./a"|];
|
||||
|
||||
[
|
||||
{
|
||||
"textSpan": {
|
||||
"start": 7,
|
||||
"length": 5
|
||||
},
|
||||
"fileName": "/project/b.ts",
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,26 @@
|
||||
// === /test.ts ===
|
||||
// import "[|./util|]";
|
||||
|
||||
// === /index.ts ===
|
||||
// export * from "[|./util|]";
|
||||
|
||||
[
|
||||
{
|
||||
"fileName": "/index.ts",
|
||||
"textSpan": {
|
||||
"start": 15,
|
||||
"length": 6
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/test.ts",
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 6
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,48 @@
|
||||
// === /project/b.ts ===
|
||||
// import "[|./a|]";
|
||||
|
||||
// === /project/c.ts ===
|
||||
// import {} from "[|./a|]";
|
||||
|
||||
// === /project/d.ts ===
|
||||
// import { a } from "[|/project/a|]";
|
||||
// type T = typeof import("[|./a|]").a;
|
||||
|
||||
[
|
||||
{
|
||||
"fileName": "/project/b.ts",
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 3
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/project/c.ts",
|
||||
"textSpan": {
|
||||
"start": 16,
|
||||
"length": 3
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/project/d.ts",
|
||||
"textSpan": {
|
||||
"start": 19,
|
||||
"length": 10
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/project/d.ts",
|
||||
"textSpan": {
|
||||
"start": 56,
|
||||
"length": 3
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,38 @@
|
||||
// === /packages/client/index.ts ===
|
||||
// import "[|@shared/referenced|]";
|
||||
|
||||
// === /packages/server/index.js ===
|
||||
// const mod = require("[|../shared/src/referenced|]");
|
||||
|
||||
// === /packages/server/router.js ===
|
||||
// const blah = require("[|../shared/dist/referenced|]");
|
||||
|
||||
[
|
||||
{
|
||||
"fileName": "/packages/server/index.js",
|
||||
"textSpan": {
|
||||
"start": 21,
|
||||
"length": 24
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/packages/server/router.js",
|
||||
"textSpan": {
|
||||
"start": 22,
|
||||
"length": 25
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
},
|
||||
{
|
||||
"fileName": "/packages/client/index.ts",
|
||||
"textSpan": {
|
||||
"start": 8,
|
||||
"length": 18
|
||||
},
|
||||
"isWriteAccess": false,
|
||||
"isDefinition": false
|
||||
}
|
||||
]
|
||||
21
tests/cases/fourslash/findAllRefsNonModule.ts
Normal file
21
tests/cases/fourslash/findAllRefsNonModule.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @checkJs: true
|
||||
|
||||
// @Filename: /script.ts
|
||||
//// console.log("I'm a script!");
|
||||
|
||||
// @Filename: /import.ts
|
||||
//// import "./script/*1*/";
|
||||
|
||||
// @Filename: /require.js
|
||||
//// require("./script/*2*/");
|
||||
//// console.log("./script/*3*/");
|
||||
|
||||
// @Filename: /tripleSlash.ts
|
||||
//// /// <reference path="script.ts" />
|
||||
|
||||
// @Filename: /stringLiteral.ts
|
||||
//// console.log("./script");
|
||||
|
||||
verify.baselineFindAllReferences("1", "2", "3");
|
||||
@ -289,7 +289,8 @@ declare namespace FourSlashInterface {
|
||||
goToType(startMarkerNames: ArrayOrSingle<string>, endMarkerNames: ArrayOrSingle<string>): void;
|
||||
verifyGetEmitOutputForCurrentFile(expected: string): void;
|
||||
verifyGetEmitOutputContentsForCurrentFile(expected: ts.OutputFile[]): void;
|
||||
baselineFindAllReferences(markerName: string): void;
|
||||
baselineFindAllReferences(...markerNames: string[]): void;
|
||||
baselineGetFileReferences(fileName: string): void;
|
||||
noReferences(markerNameOrRange?: string | Range): void;
|
||||
symbolAtLocation(startRange: Range, ...declarationRanges: Range[]): void;
|
||||
typeOfSymbolAtLocation(range: Range, symbol: any, expected: string): void;
|
||||
|
||||
16
tests/cases/fourslash/getFileReferences1.ts
Normal file
16
tests/cases/fourslash/getFileReferences1.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /project/a.ts
|
||||
//// export const a = 0;
|
||||
|
||||
// @Filename: /project/b.ts
|
||||
//// import "./a";
|
||||
|
||||
// @Filename: /project/c.ts
|
||||
//// import {} from "./a";
|
||||
|
||||
// @Filename: /project/d.ts
|
||||
//// import { a } from "/project/a";
|
||||
//// type T = typeof import("./a").a;
|
||||
|
||||
verify.baselineGetFileReferences("/project/a.ts");
|
||||
9
tests/cases/fourslash/getFileReferences2.ts
Normal file
9
tests/cases/fourslash/getFileReferences2.ts
Normal file
@ -0,0 +1,9 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /project/a.ts
|
||||
//// console.log("I'm a script!");
|
||||
|
||||
// @Filename: /project/b.ts
|
||||
//// import "./a";
|
||||
|
||||
verify.baselineGetFileReferences("/project/a.ts");
|
||||
@ -0,0 +1,23 @@
|
||||
/// <reference path="../fourslash.ts" />
|
||||
|
||||
// @Filename: /tsconfig.json
|
||||
//// { "files": [], "references": [{ "path": "tsconfig.build.json" }, { "path": "tsconfig.test.json" }] }
|
||||
|
||||
// @Filename: /tsconfig.build.json
|
||||
//// { "compilerOptions": { "rootDir": "src", "outDir": "dist/build", "composite": true }, "files": ["index.ts"] }
|
||||
|
||||
// @Filename: /index.ts
|
||||
//// export * from "./util";
|
||||
|
||||
// @Filename: /tsconfig.test.json
|
||||
//// { "compilerOptions": { "rootDir": "src", "outDir": "dist/test", "composite": true }, "files": ["test.ts", "index.ts"] }
|
||||
|
||||
// @Filename: /test.ts
|
||||
//// import "./util";
|
||||
|
||||
// @Filename: /util.ts
|
||||
//// export {}
|
||||
|
||||
// util.ts is referenced by index.ts, which is included in tsconfig.build.json and tsconfig.test.json.
|
||||
// That reference will be returned from both projects' language services. Test ensures it gets deduplicated.
|
||||
verify.baselineGetFileReferences("/util.ts");
|
||||
19
tests/cases/fourslash/server/getFileReferences_server1.ts
Normal file
19
tests/cases/fourslash/server/getFileReferences_server1.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/// <reference path="../fourslash.ts" />
|
||||
|
||||
// @Filename: /project/tsconfig.json
|
||||
//// {}
|
||||
|
||||
// @Filename: /project/a.ts
|
||||
//// export const a = 0;
|
||||
|
||||
// @Filename: /project/b.ts
|
||||
//// import "./a";
|
||||
|
||||
// @Filename: /project/c.ts
|
||||
//// import {} from "./a";
|
||||
|
||||
// @Filename: /project/d.ts
|
||||
//// import { a } from "/project/a";
|
||||
//// type T = typeof import("./a").a;
|
||||
|
||||
verify.baselineGetFileReferences("/project/a.ts");
|
||||
27
tests/cases/fourslash/server/getFileReferences_server2.ts
Normal file
27
tests/cases/fourslash/server/getFileReferences_server2.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/// <reference path="../fourslash.ts" />
|
||||
|
||||
// @Filename: /tsconfig.json
|
||||
//// { "files": [], "references": [{ "path": "packages/server" }, { "path": "packages/client" }] }
|
||||
|
||||
// @Filename: /packages/shared/tsconfig.json
|
||||
//// { "compilerOptions": { "rootDir": "src", "outDir": "dist", "composite": true } }
|
||||
|
||||
// @Filename: /packages/shared/src/referenced.ts
|
||||
//// export {};
|
||||
|
||||
// @Filename: /packages/server/tsconfig.json
|
||||
//// { "compilerOptions": { "checkJs": true }, "references": [{ "path": "../shared" }] }
|
||||
|
||||
// @Filename: /packages/server/index.js
|
||||
//// const mod = require("../shared/src/referenced");
|
||||
|
||||
// @Filename: /packages/server/router.js
|
||||
//// const blah = require("../shared/dist/referenced");
|
||||
|
||||
// @Filename: /packages/client/tsconfig.json
|
||||
//// { "compilerOptions": { "paths": { "@shared/*": ["../shared/src/*"] } }, "references": [{ "path": "../shared" }] }
|
||||
|
||||
// @Filename: /packages/client/index.ts
|
||||
//// import "@shared/referenced";
|
||||
|
||||
verify.baselineGetFileReferences("/packages/shared/src/referenced.ts");
|
||||
Loading…
x
Reference in New Issue
Block a user