navigateTo: Collect results from all referenced projects. (#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 (#24966)

* More @sheetalkamat code review

* Remove unnecessary test

* Update API (#24966)
This commit is contained in:
Andy
2018-07-05 15:39:03 -07:00
committed by GitHub
parent 5b92678285
commit 64555aa6a9
70 changed files with 1536 additions and 1088 deletions
+2 -1
View File
@@ -7655,7 +7655,8 @@ namespace ts {
}
}
function isDeclarationFileName(fileName: string): boolean {
/** @internal */
export function isDeclarationFileName(fileName: string): boolean {
return fileExtensionIs(fileName, Extension.Dts);
}
+7 -3
View File
@@ -2344,7 +2344,7 @@ namespace ts {
const refPath = resolveProjectReferencePath(host, ref);
// An absolute path pointing to the containing directory of the config file
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile;
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
if (sourceFile === undefined) {
return undefined;
}
@@ -2823,10 +2823,14 @@ namespace ts {
};
}
export interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
export function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName {
export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName {
if (!host.fileExists(ref.path)) {
return combinePaths(ref.path, "tsconfig.json") as ResolvedConfigFileName;
}
+11 -11
View File
@@ -215,17 +215,6 @@ namespace ts {
sourceMapDataList = undefined!;
}
interface SourceMapSection {
version: 3;
file: string;
sourceRoot?: string;
sources: string[];
names?: string[];
mappings: string;
sourcesContent?: (string | null)[];
sections?: undefined;
}
type SourceMapSectionDefinition =
| { offset: { line: number, column: number }, url: string } // Included for completeness
| { offset: { line: number, column: number }, map: SourceMap };
@@ -582,6 +571,17 @@ namespace ts {
}
}
export interface SourceMapSection {
version: 3;
file: string;
sourceRoot?: string;
sources: string[];
names?: string[];
mappings: string;
sourcesContent?: (string | null)[];
sections?: undefined;
}
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function base64FormatEncode(inValue: number) {
+12 -5
View File
@@ -73,7 +73,7 @@ namespace ts.server {
return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText };
}
private processRequest<T extends protocol.Request>(command: string, args?: T["arguments"]): T {
private processRequest<T extends protocol.Request>(command: string, args: T["arguments"]): T {
const request: protocol.Request = {
seq: this.sequence,
type: "request",
@@ -278,9 +278,10 @@ namespace ts.server {
const request = this.processRequest<protocol.DefinitionRequest>(CommandNames.DefinitionAndBoundSpan, args);
const response = this.processResponse<protocol.DefinitionInfoAndBoundSpanReponse>(request);
const body = Debug.assertDefined(response.body); // TODO: GH#18217
return {
definitions: response.body!.definitions.map(entry => ({ // TODO: GH#18217
definitions: body.definitions.map(entry => ({
containerKind: ScriptElementKind.unknown,
containerName: "",
fileName: entry.file,
@@ -288,7 +289,7 @@ namespace ts.server {
kind: ScriptElementKind.unknown,
name: ""
})),
textSpan: this.decodeSpan(response.body!.textSpan, request.arguments.file)
textSpan: this.decodeSpan(body.textSpan, request.arguments.file)
};
}
@@ -341,8 +342,10 @@ namespace ts.server {
}));
}
getEmitOutput(_fileName: string): EmitOutput {
return notImplemented();
getEmitOutput(file: string): EmitOutput {
const request = this.processRequest<protocol.EmitOutputRequest>(protocol.CommandTypes.EmitOutput, { file });
const response = this.processResponse<protocol.EmitOutputResponse>(request);
return response.body;
}
getSyntacticDiagnostics(file: string): DiagnosticWithLocation[] {
@@ -716,6 +719,10 @@ namespace ts.server {
throw new Error("cleanupSemanticCache is not available through the server layer.");
}
getSourceMapper(): never {
return notImplemented();
}
dispose(): void {
throw new Error("dispose is not available through the server layer.");
}
+39 -25
View File
@@ -1007,7 +1007,7 @@ namespace FourSlash {
// If any of the expected values are undefined, assume that users don't
// care about them.
if (replacementSpan && !TestState.textSpansEqual(replacementSpan, entry.replacementSpan)) {
if (replacementSpan && !ts.textSpansEqual(replacementSpan, entry.replacementSpan)) {
return false;
}
else if (expectedText && text !== expectedText) {
@@ -1644,7 +1644,7 @@ Actual: ${stringify(fullActual)}`);
});
}
public baselineGetEmitOutput(insertResultsIntoVfs?: boolean) {
private getEmitFiles(): ReadonlyArray<FourSlashFile> {
// Find file to be emitted
const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on
@@ -1661,12 +1661,29 @@ Actual: ${stringify(fullActual)}`);
this.raiseError("No emitThisFile is specified in the test file");
}
return emitFiles;
}
public verifyGetEmitOutput(expectedOutputFiles: ReadonlyArray<string>): void {
const outputFiles = ts.flatMap(this.getEmitFiles(), e => this.languageService.getEmitOutput(e.fileName).outputFiles);
assert.deepEqual(outputFiles.map(f => f.name), expectedOutputFiles);
for (const { name, text } of outputFiles) {
const fromTestFile = this.getFileContent(name);
if (fromTestFile !== text) {
this.raiseError("Emit output is not as expected: " + showTextDiff(fromTestFile, text));
}
}
}
public baselineGetEmitOutput(): void {
Harness.Baseline.runBaseline(
this.testData.globalOptions[MetadataOptionNames.baselineFile],
ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]),
() => {
let resultString = "";
// Loop through all the emittedFiles and emit them one by one
emitFiles.forEach(emitFile => {
for (const emitFile of this.getEmitFiles()) {
const emitOutput = this.languageService.getEmitOutput(emitFile.fileName);
// Print emitOutputStatus in readable format
resultString += "EmitSkipped: " + emitOutput.emitSkipped + Harness.IO.newLine();
@@ -1692,13 +1709,10 @@ Actual: ${stringify(fullActual)}`);
for (const outputFile of emitOutput.outputFiles) {
const fileName = "FileName : " + outputFile.name + Harness.IO.newLine();
resultString = resultString + fileName + outputFile.text;
if (insertResultsIntoVfs) {
this.languageServiceAdapterHost.addScript(ts.getNormalizedAbsolutePath(outputFile.name, "/"), outputFile.text, /*isRootFile*/ true);
}
resultString = resultString + Harness.IO.newLine() + fileName + outputFile.text;
}
resultString += Harness.IO.newLine();
});
}
return resultString;
});
@@ -2137,11 +2151,10 @@ Actual: ${stringify(fullActual)}`);
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0");
}
const duplicate = findDuplicatedElement(implementations, implementationsAreEqual);
const duplicate = findDuplicatedElement(implementations, ts.documentSpansEqual);
if (duplicate) {
const { textSpan, fileName } = duplicate;
const end = textSpan.start + textSpan.length;
this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${end}) in ${fileName}`);
this.raiseError(`Duplicate implementations returned for range (${textSpan.start}, ${ts.textSpanEnd(textSpan)}) in ${fileName}`);
}
const ranges = this.getRanges();
@@ -2208,10 +2221,6 @@ Actual: ${stringify(fullActual)}`);
this.raiseError(error);
}
function implementationsAreEqual(a: ImplementationLocationInformation, b: ImplementationLocationInformation) {
return a.fileName === b.fileName && TestState.textSpansEqual(a.textSpan, b.textSpan);
}
function displayPartIsEqualTo(a: ts.SymbolDisplayPart, b: ts.SymbolDisplayPart): boolean {
return a.kind === b.kind && a.text === b.text;
}
@@ -3260,7 +3269,7 @@ Actual: ${stringify(fullActual)}`);
if (spanIndex !== undefined) {
const span = this.getTextSpanForRangeAtIndex(spanIndex);
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + stringify(entryId)));
assert.isTrue(ts.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + stringify(entryId)));
}
eq(item.hasAction, hasAction, "hasAction");
@@ -3346,10 +3355,6 @@ Actual: ${stringify(fullActual)}`);
this.cancellationToken.resetCancelled();
}
private static textSpansEqual(a: ts.TextSpan | undefined, b: ts.TextSpan | undefined): boolean {
return !!a && !!b && a.start === b.start && a.length === b.length;
}
public getEditsForFileRename({ oldPath, newPath, newFileContents }: FourSlashInterface.GetEditsForFileRenameOptions): void {
const test = (fileContents: { readonly [fileName: string]: string }, description: string): void => {
const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, ts.emptyOptions);
@@ -3551,8 +3556,13 @@ ${code}
function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string | undefined {
for (const option in optionObject) {
if (option !== MetadataOptionNames.fileName) {
return option;
switch (option) {
case MetadataOptionNames.fileName:
case MetadataOptionNames.baselineFile:
case MetadataOptionNames.emitThisFile:
break;
default:
return option;
}
}
return undefined;
@@ -4270,8 +4280,12 @@ namespace FourSlashInterface {
this.state.baselineCurrentFileNameOrDottedNameSpans();
}
public baselineGetEmitOutput(insertResultsIntoVfs?: boolean) {
this.state.baselineGetEmitOutput(insertResultsIntoVfs);
public getEmitOutput(expectedOutputFiles: ReadonlyArray<string>): void {
this.state.verifyGetEmitOutput(expectedOutputFiles);
}
public baselineGetEmitOutput() {
this.state.baselineGetEmitOutput();
}
public baselineQuickInfo() {
+6 -1
View File
@@ -560,6 +560,9 @@ namespace Harness.LanguageService {
getSourceFile(): ts.SourceFile {
throw new Error("SourceFile can not be marshaled across the shim layer.");
}
getSourceMapper(): never {
return ts.notImplemented();
}
dispose(): void { this.shim.dispose({}); }
}
@@ -707,7 +710,9 @@ namespace Harness.LanguageService {
return ts.sys.getEnvironmentVariable(name);
}
readDirectory() { return ts.notImplemented(); }
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
return this.host.readDirectory(path, extensions, exclude, include, depth);
}
watchFile(): ts.FileWatcher {
return { close: ts.noop };
@@ -78,7 +78,9 @@ interface Array<T> {}`
}
export interface SymLink {
/** Location of the symlink. */
path: string;
/** Relative path to the real file. */
symLink: string;
}
+33 -18
View File
@@ -1171,7 +1171,7 @@ namespace ts.server {
*/
private stopWatchingConfigFilesForClosedScriptInfo(info: ScriptInfo) {
Debug.assert(!info.isScriptOpen());
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (configFileExistenceInfo) {
const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile.get(info.path);
@@ -1205,7 +1205,7 @@ namespace ts.server {
/* @internal */
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
Debug.assert(info.isScriptOpen());
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (!configFileExistenceInfo) {
// Create the cache
@@ -1233,7 +1233,7 @@ namespace ts.server {
*/
/* @internal */
stopWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (configFileExistenceInfo && configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
Debug.assert(info.isScriptOpen());
@@ -1256,18 +1256,18 @@ namespace ts.server {
* The server must start searching from the directory containing
* the newly opened file.
*/
private forEachConfigFileLocation(info: ScriptInfo, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
private forEachConfigFileLocation(info: ScriptInfo, infoShouldBeOpen: boolean, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
if (this.syntaxOnly) {
return undefined;
}
Debug.assert(this.openFiles.has(info.path));
Debug.assert(!infoShouldBeOpen || this.openFiles.has(info.path));
const projectRootPath = this.openFiles.get(info.path);
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
const isSearchPathInProjectRoot = () => containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames);
// If projectRootPath doesnt contain info.path, then do normal search for config file
// If projectRootPath doesn't contain info.path, then do normal search for config file
const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot();
do {
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
@@ -1301,13 +1301,11 @@ namespace ts.server {
* The server must start searching from the directory containing
* the newly opened file.
*/
private getConfigFileNameForFile(info: ScriptInfo) {
Debug.assert(info.isScriptOpen());
private getConfigFileNameForFile(info: ScriptInfo, infoShouldBeOpen: boolean) {
if (infoShouldBeOpen) Debug.assert(info.isScriptOpen());
this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`);
const configFileName = this.forEachConfigFileLocation(info,
(configFileName, canonicalConfigFilePath) =>
this.configFileExists(configFileName, canonicalConfigFilePath, info)
);
const configFileName = this.forEachConfigFileLocation(info, infoShouldBeOpen, (configFileName, canonicalConfigFilePath) =>
this.configFileExists(configFileName, canonicalConfigFilePath, info));
if (configFileName) {
this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`);
}
@@ -1840,13 +1838,11 @@ namespace ts.server {
}
}
/*@internal*/
getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) {
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) {
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
}
/*@internal*/
getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) {
private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) {
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
}
@@ -1989,7 +1985,7 @@ namespace ts.server {
// we first detect if there is already a configured project created for it: if so,
// we re- read the tsconfig file content and update the project only if we havent already done so
// otherwise we create a new one.
const configFileName = this.getConfigFileNameForFile(info);
const configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
if (configFileName) {
const project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
@@ -2077,6 +2073,24 @@ namespace ts.server {
return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined);
}
/** @internal */
getProjectForFileWithoutOpening(fileName: NormalizedPath): { readonly scriptInfo: ScriptInfo, readonly projects: ReadonlyArray<Project> } | undefined {
const scriptInfo = this.filenameToScriptInfo.get(fileName) ||
this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName, this.currentDirectory, /*fileContent*/ undefined, /*scriptKind*/ undefined, /*hasMixedContent*/ undefined);
if (!scriptInfo) return undefined;
if (scriptInfo.containingProjects.length) {
return { scriptInfo, projects: scriptInfo.containingProjects };
}
const configFileName = this.getConfigFileNameForFile(scriptInfo, /*infoShouldBeOpen*/ false);
const project = configFileName === undefined ? undefined : this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
return project && project.containsScriptInfo(scriptInfo) ? { scriptInfo, projects: [project] } : undefined;
}
/** @internal */
fileExists(fileName: NormalizedPath): boolean {
return this.filenameToScriptInfo.has(fileName) || this.host.fileExists(fileName);
}
private findExternalProjectContainingOpenScriptInfo(info: ScriptInfo): ExternalProject | undefined {
return find(this.externalProjects, proj => {
// Ensure project structure is up-to-date to check if info is present in external project
@@ -2090,10 +2104,11 @@ namespace ts.server {
let configFileErrors: ReadonlyArray<Diagnostic> | undefined;
const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent)!; // TODO: GH#18217
this.openFiles.set(info.path, projectRootPath);
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
configFileName = this.getConfigFileNameForFile(info);
configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
if (configFileName) {
project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
+9 -4
View File
@@ -271,8 +271,8 @@ namespace ts.server {
return this.projectStateVersion.toString();
}
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined {
return undefined;
getProjectReferences(): ReadonlyArray<ProjectReference> {
return emptyArray;
}
getScriptFileNames() {
@@ -461,6 +461,11 @@ namespace ts.server {
return this.languageService;
}
/** @internal */
getSourceMapper(): SourceMapper {
return this.getLanguageService().getSourceMapper();
}
private shouldEmitFile(scriptInfo: ScriptInfo) {
return scriptInfo && !scriptInfo.isDynamicOrHasMixedContent();
}
@@ -1351,8 +1356,8 @@ namespace ts.server {
return asNormalizedPath(this.getProjectName());
}
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined {
return this.projectReferences;
getProjectReferences(): ReadonlyArray<ProjectReference> {
return this.projectReferences || emptyArray;
}
updateReferences(refs: ReadonlyArray<ProjectReference> | undefined) {
+28
View File
@@ -34,6 +34,8 @@ namespace ts.server.protocol {
Implementation = "implementation",
/* @internal */
ImplementationFull = "implementation-full",
/* @internal */
EmitOutput = "emit-output",
Exit = "exit",
Format = "format",
Formatonkey = "formatonkey",
@@ -794,6 +796,21 @@ namespace ts.server.protocol {
command: CommandTypes.Definition;
}
export interface DefinitionAndBoundSpanRequest extends FileLocationRequest {
readonly command: CommandTypes.DefinitionAndBoundSpan;
}
export interface DefinitionAndBoundSpanResponse extends Response {
readonly body: DefinitionInfoAndBoundSpan;
}
/** @internal */
export interface EmitOutputRequest extends FileRequest {}
/** @internal */
export interface EmitOutputResponse extends Response {
readonly body: EmitOutput;
}
/**
* Go to type request; value of command field is
* "typeDefinition". Return response giving the file locations that
@@ -1056,6 +1073,17 @@ namespace ts.server.protocol {
arguments: RenameRequestArgs;
}
/* @internal */
export interface RenameFullRequest extends FileLocationRequest {
readonly command: CommandTypes.RenameLocationsFull;
readonly arguments: RenameRequestArgs;
}
/* @internal */
export interface RenameFullResponse extends Response {
readonly body: ReadonlyArray<RenameLocation>;
}
/**
* Information about the item to be renamed.
*/
+287 -273
View File
@@ -42,31 +42,6 @@ namespace ts.server {
return false;
}
interface FileStart {
file: string;
start: protocol.Location;
}
function compareNumber(a: number, b: number) {
return a - b;
}
function compareFileStart(a: FileStart, b: FileStart) {
if (a.file < b.file) {
return -1;
}
else if (a.file === b.file) {
const n = compareNumber(a.start.line, b.start.line);
if (n === 0) {
return compareNumber(a.start.offset, b.start.offset);
}
else return n;
}
else {
return 1;
}
}
function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic): protocol.Diagnostic {
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName)!; // TODO: GH#18217
return {
@@ -279,8 +254,8 @@ namespace ts.server {
}
type Projects = ReadonlyArray<Project> | {
projects: ReadonlyArray<Project>;
symLinkedProjects: MultiMap<Project>;
readonly projects: ReadonlyArray<Project>;
readonly symLinkedProjects: MultiMap<Project>;
};
function isProjectsArray(projects: Projects): projects is ReadonlyArray<Project> {
@@ -290,7 +265,14 @@ namespace ts.server {
/**
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
*/
function combineProjectOutput<T, U>(defaultValue: T, getValue: (path: Path) => T, projects: Projects, action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined, comparer?: (a: U, b: U) => number, areEqual?: (a: U, b: U) => boolean) {
function combineProjectOutput<T, U>(
defaultValue: T,
getValue: (path: Path) => T,
projects: Projects,
action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined,
comparer?: (a: U, b: U) => number,
areEqual?: (a: U, b: U) => boolean,
): U[] {
const outputs = flatMap(isProjectsArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
if (!isProjectsArray(projects) && projects.symLinkedProjects) {
projects.symLinkedProjects.forEach((projects, path) => {
@@ -304,6 +286,150 @@ namespace ts.server {
: deduplicate(outputs, areEqual);
}
function combineProjectOutputWhileOpeningReferencedProjects<T>(
projects: Projects,
projectService: ProjectService,
action: (project: Project) => ReadonlyArray<T>,
getLocation: (t: T) => sourcemaps.SourceMappableLocation,
resultsEqual: (a: T, b: T) => boolean,
): T[] {
const outputs: T[] = [];
combineProjectOutputWorker(projects, <sourcemaps.SourceMappableLocation><any>undefined, projectService, ({ project }, tryAddToTodo) => {
for (const output of action(project)) {
if (!contains(outputs, output, resultsEqual) && !tryAddToTodo(project, getLocation(output))) {
outputs.push(output);
}
}
});
return outputs;
}
function combineProjectOutputForRenameLocations(projects: Projects, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> {
const outputs: RenameLocation[] = [];
combineProjectOutputWorker(projects, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.position, findInStrings, findInComments) || emptyArray) {
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
outputs.push(output);
}
}
});
return outputs;
}
function combineProjectOutputForReferences(projects: Projects, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
const outputs: ReferencedSymbol[] = [];
combineProjectOutputWorker(projects, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, outputReferencedSymbol.definition));
if (!symbolToAddTo) {
symbolToAddTo = { definition: outputReferencedSymbol.definition, references: [] };
outputs.push(symbolToAddTo);
}
for (const ref of outputReferencedSymbol.references) {
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(ref))) {
symbolToAddTo.references.push(ref);
}
}
}
});
return outputs.filter(o => o.references.length !== 0);
}
interface ProjectAndLocation {
readonly project: Project;
readonly location: sourcemaps.SourceMappableLocation;
}
interface ToDoAndSeenProjects {
readonly toDo: ProjectAndLocation[];
readonly seenProjects: Map<true>;
}
function combineProjectOutputWorker(
projects: Projects,
initialLocation: sourcemaps.SourceMappableLocation,
projectService: ProjectService,
cb: (where: ProjectAndLocation, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
): void {
let toDoAndSeenProjects: ToDoAndSeenProjects | undefined;
for (const project of isProjectsArray(projects) ? projects : projects.projects) {
toDoAndSeenProjects = callbackProjectAndLocation(projects, { project, location: initialLocation }, projectService, toDoAndSeenProjects, cb);
}
if (!isArray(projects) && projects.symLinkedProjects) {
projects.symLinkedProjects.forEach((symlinkedProjects, path) => {
for (const project of symlinkedProjects) {
toDoAndSeenProjects = callbackProjectAndLocation(projects, { project, location: { fileName: path, position: initialLocation.position } }, projectService, toDoAndSeenProjects, cb);
}
});
}
while (toDoAndSeenProjects && toDoAndSeenProjects.toDo.length) {
toDoAndSeenProjects = callbackProjectAndLocation(projects, Debug.assertDefined(toDoAndSeenProjects.toDo.pop()), projectService, toDoAndSeenProjects, cb);
}
}
function callbackProjectAndLocation(
originalProjects: Projects, // For lazily populating seenProjects
projectAndLocation: ProjectAndLocation,
projectService: ProjectService,
toDoAndSeenProjects: ToDoAndSeenProjects | undefined,
cb: (where: ProjectAndLocation, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
): ToDoAndSeenProjects | undefined {
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
cb(projectAndLocation, (project, location) => {
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
if (!originalLocation) return false;
const originalProjectAndScriptInfo = projectService.getProjectForFileWithoutOpening(toNormalizedPath(originalLocation.fileName));
if (!originalProjectAndScriptInfo) return false;
if (originalProjectAndScriptInfo) {
if (toDoAndSeenProjects === undefined) {
toDoAndSeenProjects = { toDo: [], seenProjects: createMap<true>() };
for (const project of isProjectsArray(originalProjects) ? originalProjects : originalProjects.projects) {
toDoAndSeenProjects.seenProjects.set(project.projectName, true);
}
if (!isArray(originalProjects) && originalProjects.symLinkedProjects) {
originalProjects.symLinkedProjects.forEach(symlinkedProjects => {
for (const project of symlinkedProjects) {
toDoAndSeenProjects!.seenProjects.set(project.projectName, true);
}
});
}
}
for (const project of originalProjectAndScriptInfo.projects) {
addToTodo({ project, location: originalLocation }, toDoAndSeenProjects);
}
const symlinkedProjectsMap = projectService.getSymlinkedProjects(originalProjectAndScriptInfo.scriptInfo);
if (symlinkedProjectsMap) {
symlinkedProjectsMap.forEach((symlinkedProjects) => {
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation }, toDoAndSeenProjects!);
});
}
}
return true;
});
return toDoAndSeenProjects;
}
function addToTodo(projectAndLocation: ProjectAndLocation, { seenProjects, toDo }: ToDoAndSeenProjects): void {
if (addToSeen(seenProjects, projectAndLocation.project.projectName)) toDo.push(projectAndLocation);
}
function documentSpanLocation({ fileName, textSpan }: DocumentSpan): sourcemaps.SourceMappableLocation {
return { fileName, position: textSpan.start };
}
function getMappedLocation(location: sourcemaps.SourceMappableLocation, projectService: ProjectService, project: Project): sourcemaps.SourceMappableLocation | undefined {
const mapsTo = project.getSourceMapper().tryGetOriginalLocation(location);
return mapsTo && projectService.fileExists(toNormalizedPath(mapsTo.fileName)) ? mapsTo : undefined;
}
export interface SessionOptions {
host: ServerHost;
cancellationToken: ServerCancellationToken;
@@ -690,46 +816,64 @@ namespace ts.server {
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<DefinitionInfo> {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, project);
return simplifiedResult ? this.mapDefinitionInfo(definitions, project) : definitions.map(Session.mapToOriginalLocation);
}
const definitions = project.getLanguageService().getDefinitionAtPosition(file, position);
if (!definitions) {
return emptyArray;
}
if (simplifiedResult) {
return this.mapDefinitionInfo(definitions, project);
}
return definitions.map(Session.mapToOriginalLocation);
private mapDefinitionInfoLocations(definitions: ReadonlyArray<DefinitionInfo>, project: Project): ReadonlyArray<DefinitionInfo> {
return definitions.map((info): DefinitionInfo => {
const newLoc = getMappedLocation(documentSpanLocation(info), this.projectService, project);
return !newLoc ? info : {
containerKind: info.containerKind,
containerName: info.containerName,
fileName: newLoc.fileName,
kind: info.kind,
name: info.name,
textSpan: {
start: newLoc.position,
length: info.textSpan.length
},
originalFileName: info.fileName,
originalTextSpan: info.textSpan,
};
});
}
private getDefinitionAndBoundSpan(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
const scriptInfo = project.getScriptInfo(file)!;
const scriptInfo = Debug.assertDefined(project.getScriptInfo(file));
const definitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan(file, position);
const unmappedDefinitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan(file, position);
if (!definitionAndBoundSpan || !definitionAndBoundSpan.definitions) {
if (!unmappedDefinitionAndBoundSpan || !unmappedDefinitionAndBoundSpan.definitions) {
return {
definitions: emptyArray,
textSpan: undefined! // TODO: GH#18217
};
}
const definitions = this.mapDefinitionInfoLocations(unmappedDefinitionAndBoundSpan.definitions, project);
const { textSpan } = unmappedDefinitionAndBoundSpan;
if (simplifiedResult) {
return {
definitions: this.mapDefinitionInfo(definitionAndBoundSpan.definitions, project),
textSpan: this.toLocationTextSpan(definitionAndBoundSpan.textSpan, scriptInfo)
definitions: this.mapDefinitionInfo(definitions, project),
textSpan: this.toLocationTextSpan(textSpan, scriptInfo)
};
}
return {
...definitionAndBoundSpan,
definitions: definitionAndBoundSpan.definitions.map(Session.mapToOriginalLocation)
definitions: definitions.map(Session.mapToOriginalLocation),
textSpan,
};
}
private getEmitOutput(args: protocol.FileRequestArgs): EmitOutput {
const { file, project } = this.getFileAndProject(args);
return project.getLanguageService().getEmitOutput(file);
}
private mapDefinitionInfo(definitions: ReadonlyArray<DefinitionInfo>, project: Project): ReadonlyArray<protocol.FileSpan> {
return definitions.map(def => this.toFileSpan(def.fileName, def.textSpan, project));
}
@@ -771,21 +915,31 @@ namespace ts.server {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
const definitions = project.getLanguageService().getTypeDefinitionAtPosition(file, position);
if (!definitions) {
return emptyArray;
}
const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getTypeDefinitionAtPosition(file, position) || emptyArray, project);
return this.mapDefinitionInfo(definitions, project);
}
private mapImplementationLocations(implementations: ReadonlyArray<ImplementationLocation>, project: Project): ReadonlyArray<ImplementationLocation> {
return implementations.map((info): ImplementationLocation => {
const newLoc = getMappedLocation(documentSpanLocation(info), this.projectService, project);
return !newLoc ? info : {
fileName: newLoc.fileName,
kind: info.kind,
displayParts: info.displayParts,
textSpan: {
start: newLoc.position,
length: info.textSpan.length
},
originalFileName: info.fileName,
originalTextSpan: info.textSpan,
};
});
}
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<ImplementationLocation> {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
const implementations = project.getLanguageService().getImplementationAtPosition(file, position);
if (!implementations) {
return emptyArray;
}
const implementations = this.mapImplementationLocations(project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, project);
if (simplifiedResult) {
return implementations.map(({ fileName, textSpan }) => this.toFileSpan(fileName, textSpan, project));
}
@@ -948,179 +1102,59 @@ namespace ts.server {
return info.getDefaultProject();
}
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | ReadonlyArray<RenameLocation> | undefined {
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | ReadonlyArray<RenameLocation> {
const file = toNormalizedPath(args.file);
const position = this.getPositionInFile(args, file);
const projects = this.getProjects(args);
if (simplifiedResult) {
const defaultProject = this.getDefaultProject(args);
// The rename info should be the same for every project
const renameInfo = defaultProject.getLanguageService().getRenameInfo(file, position);
if (!renameInfo) {
return undefined;
}
const locations = combineProjectOutputForRenameLocations(projects, { fileName: args.file, position }, this.projectService, !!args.findInStrings, !!args.findInComments);
if (!simplifiedResult) return locations;
if (!renameInfo.canRename) {
return {
info: renameInfo,
locs: emptyArray
};
}
const defaultProject = this.getDefaultProject(args);
const renameInfo = Session.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position));
return { info: renameInfo, locs: this.toSpanGroups(locations) };
}
const fileSpans = combineProjectOutput(
file,
path => this.projectService.getScriptInfoForPath(path)!.fileName,
projects,
(project, file) => {
const renameLocations = project.getLanguageService().findRenameLocations(file, position, args.findInStrings!, args.findInComments!);
if (!renameLocations) {
return emptyArray;
}
// strips 'triggerSpan'
private static mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }: RenameInfo): protocol.RenameInfo {
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers };
}
return renameLocations.map(location => {
const locationScriptInfo = project.getScriptInfo(location.fileName)!;
return {
file: location.fileName,
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
end: locationScriptInfo.positionToLineOffset(textSpanEnd(location.textSpan)),
};
});
},
compareRenameLocation,
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
);
const locs: protocol.SpanGroup[] = [];
for (const cur of fileSpans) {
let curFileAccum: protocol.SpanGroup | undefined;
if (locs.length > 0) {
curFileAccum = locs[locs.length - 1];
if (curFileAccum.file !== cur.file) {
curFileAccum = undefined;
}
}
if (!curFileAccum) {
curFileAccum = { file: cur.file, locs: [] };
locs.push(curFileAccum);
}
curFileAccum.locs.push({ start: cur.start, end: cur.end });
}
return { info: renameInfo, locs };
}
else {
return combineProjectOutput(
file,
path => this.projectService.getScriptInfoForPath(path)!.fileName,
projects,
(p, file) => p.getLanguageService().findRenameLocations(file, position, args.findInStrings!, args.findInComments!),
/*comparer*/ undefined,
renameLocationIsEqualTo
);
}
function renameLocationIsEqualTo(a: RenameLocation, b: RenameLocation) {
if (a === b) {
return true;
}
if (!a || !b) {
return false;
}
return a.fileName === b.fileName &&
a.textSpan.start === b.textSpan.start &&
a.textSpan.length === b.textSpan.length;
}
function compareRenameLocation(a: protocol.FileSpan, b: protocol.FileSpan) {
if (a.file < b.file) {
return -1;
}
else if (a.file > b.file) {
return 1;
}
else {
// reverse sort assuming no overlap
if (a.start.line < b.start.line) {
return 1;
}
else if (a.start.line > b.start.line) {
return -1;
}
else {
return b.start.offset - a.start.offset;
}
}
private toSpanGroups(locations: ReadonlyArray<RenameLocation>): ReadonlyArray<protocol.SpanGroup> {
const map = createMap<protocol.SpanGroup>();
for (const { fileName, textSpan } of locations) {
let group = map.get(fileName);
if (!group) map.set(fileName, group = { file: fileName, locs: [] });
group.locs.push(this.toLocationTextSpan(textSpan, Debug.assertDefined(this.projectService.getScriptInfo(fileName))));
}
return arrayFrom(map.values());
}
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | undefined | ReadonlyArray<ReferencedSymbol> {
const file = toNormalizedPath(args.file);
const projects = this.getProjects(args);
const position = this.getPositionInFile(args, file);
const references = combineProjectOutputForReferences(projects, { fileName: args.file, position }, this.projectService);
const defaultProject = this.getDefaultProject(args);
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
const position = this.getPosition(args, scriptInfo);
if (simplifiedResult) {
const defaultProject = this.getDefaultProject(args);
const scriptInfo = defaultProject.getScriptInfoForNormalizedPath(file)!;
const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position);
const displayString = nameInfo ? displayPartsToString(nameInfo.displayParts) : "";
const symbolDisplayString = nameInfo ? displayPartsToString(nameInfo.displayParts) : "";
const nameSpan = nameInfo && nameInfo.textSpan;
const nameColStart = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
const nameText = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
const refs = combineProjectOutput<NormalizedPath, protocol.ReferencesResponseItem>(
file,
path => this.projectService.getScriptInfoForPath(path)!.fileName,
projects,
(project, file) => {
const references = project.getLanguageService().getReferencesAtPosition(file, position);
if (!references) {
return emptyArray;
}
return references.map(ref => {
const refScriptInfo = project.getScriptInfo(ref.fileName)!;
const start = refScriptInfo.positionToLineOffset(ref.textSpan.start);
const refLineSpan = refScriptInfo.lineToTextSpan(start.line - 1);
const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
return {
file: ref.fileName,
start,
lineText,
end: refScriptInfo.positionToLineOffset(textSpanEnd(ref.textSpan)),
isWriteAccess: ref.isWriteAccess,
isDefinition: ref.isDefinition
};
});
},
compareFileStart,
areReferencesResponseItemsForTheSameLocation
);
return {
refs,
symbolName: nameText,
symbolStartOffset: nameColStart,
symbolDisplayString: displayString
};
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
const refs: protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol =>
referencedSymbol.references.map(({ fileName, textSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
const lineText = scriptInfo.getSnapshot().getText(textSpan.start, textSpanEnd(textSpan));
return { ...toFileSpan(fileName, textSpan, scriptInfo), lineText, isWriteAccess, isDefinition };
}));
const result: protocol.ReferencesResponseBody = { refs, symbolName, symbolStartOffset, symbolDisplayString };
return result;
}
else {
return combineProjectOutput(
file,
path => this.projectService.getScriptInfoForPath(path)!.fileName,
projects,
(project, file) => project.getLanguageService().findReferences(file, position),
/*comparer*/ undefined,
equateValues
);
}
function areReferencesResponseItemsForTheSameLocation(a: protocol.ReferencesResponseItem, b: protocol.ReferencesResponseItem) {
if (a && b) {
return a.file === b.file &&
a.start === b.start &&
a.end === b.end;
}
return false;
return references;
}
}
@@ -1568,63 +1602,45 @@ namespace ts.server {
}
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.NavtoItem> | ReadonlyArray<NavigateToItem> {
const projects = this.getProjects(args);
const full = this.getFullNavigateToItems(args);
return !simplifiedResult ? full : full.map((navItem) => {
const { file, project } = this.getFileAndProject({ file: navItem.fileName });
const scriptInfo = project.getScriptInfo(file)!;
const bakedItem: protocol.NavtoItem = {
name: navItem.name,
kind: navItem.kind,
isCaseSensitive: navItem.isCaseSensitive,
matchKind: navItem.matchKind,
file: navItem.fileName,
start: scriptInfo.positionToLineOffset(navItem.textSpan.start),
end: scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan))
};
if (navItem.kindModifiers && (navItem.kindModifiers !== "")) {
bakedItem.kindModifiers = navItem.kindModifiers;
}
if (navItem.containerName && (navItem.containerName.length > 0)) {
bakedItem.containerName = navItem.containerName;
}
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
bakedItem.containerKind = navItem.containerKind;
}
return bakedItem;
});
}
const fileName = args.currentFileOnly ? args.file && normalizeSlashes(args.file) : undefined;
if (simplifiedResult) {
return combineProjectOutput(
fileName,
() => undefined,
projects,
(project, file) => {
if (fileName && !file) {
return undefined;
}
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject());
if (!navItems) {
return emptyArray;
}
return navItems.map((navItem) => {
const scriptInfo = project.getScriptInfo(navItem.fileName)!;
const bakedItem: protocol.NavtoItem = {
name: navItem.name,
kind: navItem.kind,
isCaseSensitive: navItem.isCaseSensitive,
matchKind: navItem.matchKind,
file: navItem.fileName,
start: scriptInfo.positionToLineOffset(navItem.textSpan.start),
end: scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan))
};
if (navItem.kindModifiers && (navItem.kindModifiers !== "")) {
bakedItem.kindModifiers = navItem.kindModifiers;
}
if (navItem.containerName && (navItem.containerName.length > 0)) {
bakedItem.containerName = navItem.containerName;
}
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
bakedItem.containerKind = navItem.containerKind;
}
return bakedItem;
});
},
/*comparer*/ undefined,
areNavToItemsForTheSameLocation
);
private getFullNavigateToItems(args: protocol.NavtoRequestArgs): ReadonlyArray<NavigateToItem> {
const { currentFileOnly, searchValue, maxResultCount } = args;
if (currentFileOnly) {
const { file, project } = this.getFileAndProject(args);
return project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file);
}
else {
return combineProjectOutput(
fileName,
() => undefined,
projects,
(project, file) => {
if (fileName && !file) {
return undefined;
}
return project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject());
},
/*comparer*/ undefined,
return combineProjectOutputWhileOpeningReferencedProjects<NavigateToItem>(
this.getProjects(args),
this.projectService,
project =>
project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject()),
documentSpanLocation,
navigateToItemIsEqualTo);
}
@@ -1646,15 +1662,6 @@ namespace ts.server {
a.textSpan.start === b.textSpan.start &&
a.textSpan.length === b.textSpan.length;
}
function areNavToItemsForTheSameLocation(a: protocol.NavtoItem, b: protocol.NavtoItem) {
if (a && b) {
return a.file === b.file &&
a.start === b.start &&
a.end === b.end;
}
return false;
}
}
private getSupportedCodeFixes(): string[] {
@@ -1976,6 +1983,9 @@ namespace ts.server {
[CommandNames.DefinitionAndBoundSpanFull]: (request: protocol.DefinitionRequest) => {
return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.EmitOutput]: (request: protocol.EmitOutputRequest) => {
return this.requiredResponse(this.getEmitOutput(request.arguments));
},
[CommandNames.TypeDefinition]: (request: protocol.FileLocationRequest) => {
return this.requiredResponse(this.getTypeDefinition(request.arguments));
},
@@ -1991,10 +2001,10 @@ namespace ts.server {
[CommandNames.ReferencesFull]: (request: protocol.FileLocationRequest) => {
return this.requiredResponse(this.getReferences(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.Rename]: (request: protocol.Request) => {
[CommandNames.Rename]: (request: protocol.RenameRequest) => {
return this.requiredResponse(this.getRenameLocations(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.RenameLocationsFull]: (request: protocol.RenameRequest) => {
[CommandNames.RenameLocationsFull]: (request: protocol.RenameFullRequest) => {
return this.requiredResponse(this.getRenameLocations(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.RenameInfoFull]: (request: protocol.FileLocationRequest) => {
@@ -2332,6 +2342,10 @@ namespace ts.server {
readonly project: Project;
}
function toFileSpan(fileName: string, textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.FileSpan {
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
}
function mapTextChangesToCodeEdits(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
Debug.assert(!!textChanges.isNewFile === !sourceFile);
if (sourceFile) {
+1 -1
View File
@@ -17,7 +17,7 @@ namespace ts.NavigateTo {
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
if (excludeDtsFiles && fileExtensionIs(sourceFile.fileName, Extension.Dts)) {
if (excludeDtsFiles && sourceFile.isDeclarationFile) {
continue;
}
+9 -166
View File
@@ -1129,8 +1129,6 @@ namespace ts {
localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages();
}
let sourcemappedFileCache: SourceFileLikeCache;
function log(message: string) {
if (host.log) {
host.log(message);
@@ -1140,6 +1138,8 @@ namespace ts {
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
const sourceMapper = getSourceMapper(getCanonicalFileName, currentDirectory, log, host, () => program);
function getValidSourceFile(fileName: string): SourceFile {
const sourceFile = program.getSourceFile(fileName);
if (!sourceFile) {
@@ -1251,7 +1251,7 @@ namespace ts {
// 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,
// Because it only functions until `hostCache` is cleared, while we'll potentially need the functionality to lazily read sourcemap files during
// the course of whatever called `synchronizeHostData`
sourcemappedFileCache = createSourceFileLikeCache(host);
sourceMapper.clearCache();
// Make sure all the nodes in the program are both bound, and have their parent
// pointers set property.
@@ -1502,183 +1502,27 @@ namespace ts {
return checker.getSymbolAtLocation(node);
}
function toLineColumnOffset(fileName: string, position: number) {
const path = toPath(fileName, currentDirectory, getCanonicalFileName);
const file = program.getSourceFile(path) || sourcemappedFileCache.get(path)!; // TODO: GH#18217
return file.getLineAndCharacterOfPosition(position);
}
// Sometimes tools can sometimes see the following line as a source mapping url comment, so we mangle it a bit (the [M])
const sourceMapCommentRegExp = /^\/\/[@#] source[M]appingURL=(.+)$/;
const whitespaceOrMapCommentRegExp = /^\s*(\/\/[@#] .*)?$/;
const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+\/=]+)$)?/;
function scanForSourcemapURL(fileName: string) {
const mappedFile = sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
if (!mappedFile) {
return;
}
const starts = getLineStarts(mappedFile);
for (let index = starts.length - 1; index >= 0; index--) {
const lineText = mappedFile.text.substring(starts[index], starts[index + 1]);
const comment = sourceMapCommentRegExp.exec(lineText);
if (comment) {
return comment[1];
}
// If we see a nonwhitespace/map comment-like line, break, to avoid scanning up the entire file
else if (!lineText.match(whitespaceOrMapCommentRegExp)) {
break;
}
}
}
function convertDocumentToSourceMapper(file: { sourceMapper?: sourcemaps.SourceMapper }, contents: string, mapFileName: string) {
let maps: sourcemaps.SourceMapData | undefined;
try {
maps = JSON.parse(contents);
}
catch {
// swallow error
}
if (!maps || !maps.sources || !maps.file || !maps.mappings) {
// obviously invalid map
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
return file.sourceMapper = sourcemaps.decode({
readFile: s => host.readFile!(s), // TODO: GH#18217
fileExists: s => host.fileExists!(s), // TODO: GH#18217
getCanonicalFileName,
log,
}, mapFileName, maps, program, sourcemappedFileCache);
}
function getSourceMapper(fileName: string, file: { sourceMapper?: sourcemaps.SourceMapper }) {
if (!host.readFile || !host.fileExists) {
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
if (file.sourceMapper) {
return file.sourceMapper;
}
let mapFileName = scanForSourcemapURL(fileName);
if (mapFileName) {
const match = base64UrlRegExp.exec(mapFileName);
if (match) {
if (match[1]) {
const base64Object = match[1];
return convertDocumentToSourceMapper(file, base64decode(sys, base64Object), fileName);
}
// Not a data URL we can parse, skip it
mapFileName = undefined;
}
}
const possibleMapLocations: string[] = [];
if (mapFileName) {
possibleMapLocations.push(mapFileName);
}
possibleMapLocations.push(fileName + ".map");
for (const location of possibleMapLocations) {
const mapPath = toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
if (host.fileExists(mapPath)) {
return convertDocumentToSourceMapper(file, host.readFile(mapPath)!, mapPath); // TODO: GH#18217
}
}
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
function makeGetTargetOfMappedPosition<TIn>(
extract: (original: TIn) => sourcemaps.SourceMappableLocation,
create: (result: sourcemaps.SourceMappableLocation, unmapped: TIn, original: TIn) => TIn
) {
return getTargetOfMappedPosition;
function getTargetOfMappedPosition(input: TIn, original = input): TIn {
const info = extract(input);
if (endsWith(info.fileName, Extension.Dts)) {
let file: SourceFileLike | undefined = program.getSourceFile(info.fileName);
if (!file) {
const path = toPath(info.fileName, currentDirectory, getCanonicalFileName);
file = sourcemappedFileCache.get(path);
}
if (!file) {
return input;
}
const mapper = getSourceMapper(info.fileName, file);
const newLoc = mapper.getOriginalPosition(info);
if (newLoc === info) return input;
return getTargetOfMappedPosition(create(newLoc, input, original), original);
}
return input;
}
}
const getTargetOfMappedDeclarationInfo = makeGetTargetOfMappedPosition(
(info: DefinitionInfo) => ({ fileName: info.fileName, position: info.textSpan.start }),
(newLoc, info, original) => ({
containerKind: info.containerKind,
containerName: info.containerName,
fileName: newLoc.fileName,
kind: info.kind,
name: info.name,
textSpan: {
start: newLoc.position,
length: info.textSpan.length
},
originalFileName: original.fileName,
originalTextSpan: original.textSpan
})
);
function getTargetOfMappedDeclarationFiles(infos: ReadonlyArray<DefinitionInfo> | undefined): DefinitionInfo[] | undefined {
return map(infos, d => getTargetOfMappedDeclarationInfo(d));
}
/// Goto definition
function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
synchronizeHostData();
return getTargetOfMappedDeclarationFiles(GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position));
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
}
function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined {
synchronizeHostData();
const result = GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position);
if (!result) return result;
const mappedDefs = getTargetOfMappedDeclarationFiles(result.definitions);
if (mappedDefs === result.definitions) {
return result;
}
return {
definitions: mappedDefs,
textSpan: result.textSpan
};
return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position);
}
function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
synchronizeHostData();
return getTargetOfMappedDeclarationFiles(GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position));
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
}
/// Goto implementation
const getTargetOfMappedImplementationLocation = makeGetTargetOfMappedPosition(
(info: ImplementationLocation) => ({ fileName: info.fileName, position: info.textSpan.start }),
(newLoc, info) => ({
fileName: newLoc.fileName,
kind: info.kind,
displayParts: info.displayParts,
textSpan: {
start: newLoc.position,
length: info.textSpan.length
},
originalFileName: info.fileName,
originalTextSpan: info.textSpan
})
);
function getTargetOfMappedImplementationLocations(infos: ReadonlyArray<ImplementationLocation> | undefined): ImplementationLocation[] | undefined {
return map(infos, d => getTargetOfMappedImplementationLocation(d));
}
function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] | undefined {
synchronizeHostData();
return getTargetOfMappedImplementationLocations(FindAllReferences.getImplementationsAtPosition(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position));
return FindAllReferences.getImplementationsAtPosition(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
}
/// References and Occurrences
@@ -1735,10 +1579,8 @@ namespace ts {
return FindAllReferences.findReferencedSymbols(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
}
/// NavigateTo
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] {
synchronizeHostData();
const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles();
return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles);
}
@@ -2289,7 +2131,8 @@ namespace ts {
getProgram,
getApplicableRefactors,
getEditsForRefactor,
toLineColumnOffset
toLineColumnOffset: sourceMapper.toLineColumnOffset,
getSourceMapper: () => sourceMapper,
};
}
+115
View File
@@ -0,0 +1,115 @@
/* @internal */
namespace ts {
// Sometimes tools can sometimes see the following line as a source mapping url comment, so we mangle it a bit (the [M])
const sourceMapCommentRegExp = /^\/\/[@#] source[M]appingURL=(.+)\s*$/;
const whitespaceOrMapCommentRegExp = /^\s*(\/\/[@#] .*)?$/;
const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+\/=]+)$)?/;
export interface SourceMapper {
toLineColumnOffset(fileName: string, position: number): LineAndCharacter;
tryGetOriginalLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined;
clearCache(): void;
}
export function getSourceMapper(
getCanonicalFileName: GetCanonicalFileName,
currentDirectory: string,
log: (message: string) => void,
host: LanguageServiceHost,
getProgram: () => Program,
): SourceMapper {
let sourcemappedFileCache: SourceFileLikeCache;
return { tryGetOriginalLocation, toLineColumnOffset, clearCache };
function scanForSourcemapURL(fileName: string) {
const mappedFile = sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
if (!mappedFile) {
return;
}
const starts = getLineStarts(mappedFile);
for (let index = starts.length - 1; index >= 0; index--) {
const lineText = mappedFile.text.substring(starts[index], starts[index + 1]);
const comment = sourceMapCommentRegExp.exec(lineText);
if (comment) {
return comment[1];
}
// If we see a non-whitespace/map comment-like line, break, to avoid scanning up the entire file
else if (!lineText.match(whitespaceOrMapCommentRegExp)) {
break;
}
}
}
function convertDocumentToSourceMapper(file: { sourceMapper?: sourcemaps.SourceMapper }, contents: string, mapFileName: string) {
let maps: sourcemaps.SourceMapData | undefined;
try {
maps = JSON.parse(contents);
}
catch {
// swallow error
}
if (!maps || !maps.sources || !maps.file || !maps.mappings) {
// obviously invalid map
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
return file.sourceMapper = sourcemaps.decode({
readFile: s => host.readFile!(s), // TODO: GH#18217
fileExists: s => host.fileExists!(s), // TODO: GH#18217
getCanonicalFileName,
log,
}, mapFileName, maps, getProgram(), sourcemappedFileCache);
}
function getSourceMapper(fileName: string, file: SourceFileLike): sourcemaps.SourceMapper {
if (!host.readFile || !host.fileExists) {
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
if (file.sourceMapper) {
return file.sourceMapper;
}
let mapFileName = scanForSourcemapURL(fileName);
if (mapFileName) {
const match = base64UrlRegExp.exec(mapFileName);
if (match) {
if (match[1]) {
const base64Object = match[1];
return convertDocumentToSourceMapper(file, base64decode(sys, base64Object), fileName);
}
// Not a data URL we can parse, skip it
mapFileName = undefined;
}
}
const possibleMapLocations: string[] = [];
if (mapFileName) {
possibleMapLocations.push(mapFileName);
}
possibleMapLocations.push(fileName + ".map");
for (const location of possibleMapLocations) {
const mapPath = toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
if (host.fileExists(mapPath)) {
return convertDocumentToSourceMapper(file, host.readFile(mapPath)!, mapPath); // TODO: GH#18217
}
}
return file.sourceMapper = sourcemaps.identitySourceMapper;
}
function tryGetOriginalLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
if (!isDeclarationFileName(info.fileName)) return undefined;
const file = getProgram().getSourceFile(info.fileName) || sourcemappedFileCache.get(toPath(info.fileName, currentDirectory, getCanonicalFileName));
if (!file) return undefined;
const newLoc = getSourceMapper(info.fileName, file).getOriginalPosition(info);
return newLoc === info ? undefined : tryGetOriginalLocation(newLoc) || newLoc;
}
function toLineColumnOffset(fileName: string, position: number): LineAndCharacter {
const path = toPath(fileName, currentDirectory, getCanonicalFileName);
const file = getProgram().getSourceFile(path) || sourcemappedFileCache.get(path)!; // TODO: GH#18217
return file.getLineAndCharacterOfPosition(position);
}
function clearCache(): void {
sourcemappedFileCache = createSourceFileLikeCache(host);
}
}
}
+1
View File
@@ -29,6 +29,7 @@
"preProcess.ts",
"rename.ts",
"signatureHelp.ts",
"sourcemaps.ts",
"suggestionDiagnostics.ts",
"symbolDisplay.ts",
"transpile.ts",
+2
View File
@@ -334,6 +334,8 @@ namespace ts {
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
/** @internal */
getSourceMapper(): SourceMapper;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
+7
View File
@@ -1417,6 +1417,13 @@ namespace ts {
changes.insertNodeAtTopOfFile(sourceFile, importDecl, /*blankLineBetween*/ true);
}
}
export function textSpansEqual(a: TextSpan | undefined, b: TextSpan | undefined): boolean {
return !!a && !!b && a.start === b.start && a.length === b.length;
}
export function documentSpansEqual(a: DocumentSpan, b: DocumentSpan): boolean {
return a.fileName === b.fileName && textSpansEqual(a.textSpan, b.textSpan);
}
}
// Display-part writer helpers
+349 -175
View File
@@ -415,7 +415,7 @@ namespace ts.projectSystem {
checkArray("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path)!.fileName), expectedFiles.map(file => file.path));
}
function protocolLocationFromSubstring(str: string, substring: string) {
function protocolLocationFromSubstring(str: string, substring: string): protocol.Location {
const start = str.indexOf(substring);
Debug.assert(start !== -1);
return protocolToLocation(str)(start);
@@ -427,21 +427,36 @@ namespace ts.projectSystem {
return { line: x.line + 1, offset: x.character + 1 };
};
}
function protocolTextSpanFromSubstring(str: string, substring: string): protocol.TextSpan {
const span = textSpanFromSubstring(str, substring);
function protocolTextSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): protocol.TextSpan {
const span = textSpanFromSubstring(str, substring, options);
const toLocation = protocolToLocation(str);
return { start: toLocation(span.start), end: toLocation(span.start + span.length) };
return { start: toLocation(span.start), end: toLocation(textSpanEnd(span)) };
}
function textSpanFromSubstring(str: string, substring: string): TextSpan {
const start = str.indexOf(substring);
function textSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): TextSpan {
const start = nthIndexOf(str, substring, options ? options.index : 0);
Debug.assert(start !== -1);
return createTextSpan(start, substring.length);
}
function protocolFileLocationFromSubstring(file: File, substring: string): protocol.FileLocationRequestArgs {
return { file: file.path, ...protocolLocationFromSubstring(file.content, substring) };
}
function protocolFileSpanFromSubstring(file: File, substring: string): protocol.FileSpan {
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, substring) };
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions) {
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, substring, options) };
}
function documentSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): DocumentSpan {
return { fileName: file.path, textSpan: textSpanFromSubstring(file.content, substring, options) };
}
interface SpanFromSubstringOptions {
readonly index: number;
}
function nthIndexOf(str: string, substr: string, n: number): number {
let index = -1;
for (; n >= 0; n--) {
index = str.indexOf(substr, index + 1);
if (index === -1) return -1;
}
return index;
}
/**
@@ -496,10 +511,14 @@ namespace ts.projectSystem {
};
}
export function openFilesForSession(files: ReadonlyArray<File>, session: server.Session): void {
export function executeSessionRequest<TRequest extends protocol.Request, TResponse extends protocol.Response>(session: server.Session, command: TRequest["command"], args: TRequest["arguments"]): TResponse["body"] {
return session.executeCommand(makeSessionRequest(command, args)).response as TResponse["body"];
}
export function openFilesForSession(files: ReadonlyArray<File | { readonly file: File | string, readonly projectRootPath: string }>, session: server.Session): void {
for (const file of files) {
const request = makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open, { file: file.path });
session.executeCommand(request);
session.executeCommand(makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open,
"projectRootPath" in file ? { file: typeof file.file === "string" ? file.file : file.file.path, projectRootPath: file.projectRootPath } : { file: file.path }));
}
}
@@ -3385,7 +3404,7 @@ namespace ts.projectSystem {
host.reloadFS(files.map(f => f === fileSubA ? fileA : f));
host.checkTimeoutQueueLength(2);
closeFile(fileSubA);
closeFilesForSession([fileSubA], session);
// This should cancel existing updates and schedule new ones
host.checkTimeoutQueueLength(2);
checkNumberOfProjects(services, { configuredProjects: 1 });
@@ -3405,7 +3424,7 @@ namespace ts.projectSystem {
// file is deleted but watches are not yet invoked
const originalFileExists = host.fileExists;
host.fileExists = s => s === fileA.path ? false : originalFileExists.call(host, s);
closeFile(fileA);
closeFilesForSession([fileA], session);
host.checkTimeoutQueueLength(2); // Update configured project and projects for open file
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
@@ -3453,23 +3472,7 @@ namespace ts.projectSystem {
assert.isFalse(hasErrorMsg());
function openFile(file: File) {
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: file.path,
fileContent: file.content,
projectRootPath
}
});
}
function closeFile(file: File) {
session.executeCommandSeq<protocol.CloseRequest>({
command: protocol.CommandTypes.Close,
arguments: {
file: file.path
}
});
openFilesForSession([{ file, projectRootPath }], session);
}
});
});
@@ -3686,40 +3689,17 @@ namespace ts.projectSystem {
const files = [libFile, app, serverUtilities, backendTest];
const host = createServerHost(files);
const session = createSession(host, { useInferredProjectPerProjectRoot: true, canUseEvents: true });
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: app.path,
projectRootPath: projectRoot
}
});
openFilesForSession([{ file: app, projectRootPath: projectRoot }], session);
const service = session.getProjectService();
checkNumberOfProjects(service, { inferredProjects: 1 });
const project = service.inferredProjects[0];
checkProjectActualFiles(project, [libFile.path, app.path]);
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: backendTest.path,
projectRootPath: projectRoot
}
});
openFilesForSession([{ file: backendTest, projectRootPath: projectRoot }], session);
checkNumberOfProjects(service, { inferredProjects: 1 });
checkProjectActualFiles(project, files.map(f => f.path));
checkErrors([backendTest.path, app.path]);
session.executeCommandSeq<protocol.CloseRequest>({
command: protocol.CommandTypes.Close,
arguments: {
file: backendTest.path
}
});
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: serverUtilities.path,
projectRootPath: projectRoot
}
});
closeFilesForSession([backendTest], session);
openFilesForSession([{ file: serverUtilities.path, projectRootPath: projectRoot }], session);
checkErrors([serverUtilities.path, app.path]);
function checkErrors(openFiles: [string, string]) {
@@ -7886,72 +7866,42 @@ namespace ts.projectSystem {
const host = createServerHost(files);
const session = createSession(host);
const projectService = session.getProjectService();
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: aFile.path,
projectRootPath: folderA
}
});
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: bFile.path,
projectRootPath: folderB
}
});
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: aFc,
projectRootPath: folderA
}
});
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: bFc,
projectRootPath: folderB
}
});
openFilesForSession(
[
{ file: aFile, projectRootPath: folderA },
{ file: bFile, projectRootPath: folderB },
{ file: aFc, projectRootPath: folderA },
{ file: bFc, projectRootPath: folderB },
],
session);
checkNumberOfProjects(projectService, { configuredProjects: 2 });
assert.isDefined(projectService.configuredProjects.get(aTsconfig.path));
assert.isDefined(projectService.configuredProjects.get(bTsconfig.path));
verifyRenameResponse(session.executeCommandSeq<protocol.RenameRequest>({
command: protocol.CommandTypes.Rename,
arguments: {
file: aFc,
line: 1,
offset: 14,
findInStrings: false,
findInComments: false
}
}).response as protocol.RenameResponseBody);
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") });
function verifyRenameResponse({ info, locs }: protocol.RenameResponseBody) {
assert.isTrue(info.canRename);
assert.equal(locs.length, 4);
verifyLocations(0, aFile.path, aFc);
verifyLocations(2, bFile.path, bFc);
function verifyLocations(locStartIndex: number, firstFile: string, secondFile: string) {
assert.deepEqual(locs[locStartIndex], {
file: firstFile,
locs: [
{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 40 } },
{ start: { line: 1, offset: 9 }, end: { line: 1, offset: 10 } }
]
});
assert.deepEqual(locs[locStartIndex + 1], {
file: secondFile,
locs: [
{ start: { line: 1, offset: 14 }, end: { line: 1, offset: 15 } }
]
});
}
}
assert.equal(aFile.content, bFile.content);
const abLocs: protocol.TextSpan[] = [
protocolTextSpanFromSubstring(aFile.content, "C"),
protocolTextSpanFromSubstring(aFile.content, "C", { index: 1 }),
];
const cLocs: protocol.TextSpan[] = [protocolTextSpanFromSubstring(cFile.content, "C")];
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
canRename: true,
displayName: "C",
fullDisplayName: '"/users/username/projects/a/c/fc".C',
kind: ScriptElementKind.constElement,
kindModifiers: ScriptElementKindModifier.exportedModifier,
localizedErrorMessage: undefined,
},
locs: [
{ file: aFc, locs: cLocs },
{ file: aFile.path, locs: abLocs },
{ file: bFc, locs: cLocs },
{ file: bFile.path, locs: abLocs },
],
});
});
describe("module resolution when symlinked folder contents change and resolve modules", () => {
@@ -8948,93 +8898,323 @@ export function Test2() {
function makeSampleProjects() {
const aTs: File = {
path: "/a/a.ts",
content: "export function fnA() {}",
content: "export function fnA() {}\nexport interface IfaceA {}\nexport const instanceA: IfaceA = {};",
};
const aTsconfig: File = {
path: "/a/tsconfig.json",
content: `{
"compilerOptions": {
"outDir": "bin",
"declaration": true,
"declarationMap": true,
"composite": true,
}
}`,
const compilerOptions: CompilerOptions = {
outDir: "bin",
declaration: true,
declarationMap: true,
composite: true,
};
const configContent = JSON.stringify({ compilerOptions });
const aTsconfig: File = { path: "/a/tsconfig.json", content: configContent };
const aDtsMapContent: SourceMapSection = {
version: 3,
file: "a.d.ts",
sourceRoot: "",
sources: ["../a.ts"],
names: [],
mappings: "AAAA,wBAAgB,GAAG,SAAK;AACxB,MAAM,WAAW,MAAM;CAAG;AAC1B,eAAO,MAAM,SAAS,EAAE,MAAW,CAAC"
};
const aDtsMap: File = {
path: "/a/bin/a.d.ts.map",
content: JSON.stringify(aDtsMapContent),
};
const aDts: File = {
path: "/a/bin/a.d.ts",
// Need to mangle the sourceMappingURL part or it breaks the build
content: `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`,
};
const bTs: File = {
path: "/b/b.ts",
content: 'import { fnA } from "../a/a";\nexport function fnB() { fnA(); }',
content: "export function fnB() {}",
};
const bTsconfig: File = {
path: "/b/tsconfig.json",
content: `{
"compilerOptions": {
"outDir": "bin",
},
"references": [
{ "path": "../a" }
]
}`,
const bTsconfig: File = { path: "/b/tsconfig.json", content: configContent };
const bDtsMapContent: SourceMapSection = {
version: 3,
file: "b.d.ts",
sourceRoot: "",
sources: ["../b.ts"],
names: [],
mappings: "AAAA,wBAAgB,GAAG,SAAK",
};
const bDtsMap: File = {
path: "/b/bin/b.d.ts.map",
content: JSON.stringify(bDtsMapContent),
};
const bDts: File = {
// Need to mangle the sourceMappingURL part or it breaks the build
path: "/b/bin/b.d.ts",
content: `export declare function fnB(): void;\n//# source${""}MappingURL=b.d.ts.map`,
};
const host = createServerHost([aTs, aTsconfig, bTs, bTsconfig]);
const userTs: File = {
path: "/user/user.ts",
content: 'import { fnA, instanceA } from "../a/bin/a";\nimport { fnB } from "../b/bin/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
};
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, userTs]);
const session = createSession(host);
writeDeclarationFiles(aTs, host, session, [
{ name: "/a/bin/a.d.ts.map", text: '{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["../a.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAK"}' },
// Need to mangle the sourceMappingURL part or it breaks the build
{ name: "/a/bin/a.d.ts", text: `export declare function fnA(): void;\n//# source${""}MappingURL=a.d.ts.map` },
]);
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
return { session, aTs, bTs };
// Testing what happens if we delete the original sources.
host.removeFile(bTs.path);
openFilesForSession([userTs], session);
return { session, aTs, bDts, userTs };
}
describe("tsserverProjectSystem project references", () => {
it("goToDefinition", () => {
const { session, aTs, bTs } = makeSampleProjects();
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
});
openFilesForSession([bTs], session);
it("getDefinitionAndBoundSpan", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, {
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
});
});
const definitionRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(CommandNames.Definition, protocolFileLocationFromSubstring(bTs, "fnA()"));
const definitionResponse = session.executeCommand(definitionRequest).response as protocol.DefinitionResponse["body"];
it("goToType", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.TypeDefinitionRequest, protocol.TypeDefinitionResponse>(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "IfaceA")]);
});
assert.deepEqual(definitionResponse, [protocolFileSpanFromSubstring(aTs, "fnA")]);
it("goToImplementation", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.ImplementationRequest, protocol.ImplementationResponse>(session, protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
});
it("goToDefinition -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()"));
// bTs does not exist, so stick with bDts
assert.deepEqual(response, [protocolFileSpanFromSubstring(bDts, "fnB")]);
});
it("navigateTo", () => {
const { session, bTs } = makeSampleProjects();
openFilesForSession([bTs], session);
const navtoRequest = makeSessionRequest<protocol.NavtoRequestArgs>(CommandNames.Navto, { file: bTs.path, searchValue: "fn" });
const navtoResponse = session.executeCommand(navtoRequest).response as protocol.NavtoResponse["body"];
assert.deepEqual<ReadonlyArray<protocol.NavtoItem> | undefined>(navtoResponse, [
// TODO: First result should be from a.ts, not a.d.ts
const { session, aTs, bDts, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.NavtoRequest, protocol.NavtoResponse>(session, CommandNames.Navto, { file: userTs.path, searchValue: "fn" });
assert.deepEqual<ReadonlyArray<protocol.NavtoItem> | undefined>(response, [
{
file: "/a/bin/a.d.ts",
start: { line: 1, offset: 1 },
end: { line: 1, offset: 37 },
name: "fnA",
...protocolFileSpanFromSubstring(bDts, "export declare function fnB(): void;"),
name: "fnB",
matchKind: "prefix",
isCaseSensitive: true,
kind: ScriptElementKind.functionElement,
kindModifiers: "export,declare",
},
{
...protocolFileSpanFromSubstring(bTs, "export function fnB() { fnA(); }"),
name: "fnB",
...protocolFileSpanFromSubstring(userTs, "export function fnUser() { fnA(); fnB(); instanceA; }"),
name: "fnUser",
matchKind: "prefix",
isCaseSensitive: true,
kind: ScriptElementKind.functionElement,
kindModifiers: "export",
},
{
...protocolFileSpanFromSubstring(aTs, "export function fnA() {}"),
name: "fnA",
matchKind: "prefix",
isCaseSensitive: true,
kind: ScriptElementKind.functionElement,
kindModifiers: "export",
},
]);
});
it("findAllReferences", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
refs: [
makeReferenceItem(userTs, /*isDefinition*/ true, "fnA"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnA", { index: 1 }),
makeReferenceItem(aTs, /*isDefinition*/ true, "fnA"),
],
symbolName: "fnA",
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnA()").offset,
symbolDisplayString: "(alias) fnA(): void\nimport fnA",
});
});
it("findAllReferencesFull", () => {
const { session, aTs, userTs } = makeSampleProjects();
interface ReferencesFullRequest extends protocol.FileLocationRequest { command: protocol.CommandTypes.ReferencesFull; }
interface ReferencesFullResponse extends protocol.Response { body: ReadonlyArray<ReferencedSymbol>; }
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
function fnAVoid(kind: SymbolDisplayPartKind): SymbolDisplayPart[] {
return [
keywordPart(SyntaxKind.FunctionKeyword),
spacePart(),
displayPart("fnA", kind),
punctuationPart(SyntaxKind.OpenParenToken),
punctuationPart(SyntaxKind.CloseParenToken),
punctuationPart(SyntaxKind.ColonToken),
spacePart(),
keywordPart(SyntaxKind.VoidKeyword),
];
}
assert.deepEqual<ReadonlyArray<ReferencedSymbol>>(responseFull, [
{
definition: {
...documentSpanFromSubstring(userTs, "fnA"),
kind: ScriptElementKind.alias,
name: "(alias) function fnA(): void\nimport fnA",
containerKind: ScriptElementKind.unknown,
containerName: "",
displayParts: [
punctuationPart(SyntaxKind.OpenParenToken),
textPart("alias"),
punctuationPart(SyntaxKind.CloseParenToken),
spacePart(),
...fnAVoid(SymbolDisplayPartKind.aliasName),
lineBreakPart(),
keywordPart(SyntaxKind.ImportKeyword),
spacePart(),
displayPart("fnA", SymbolDisplayPartKind.aliasName),
],
},
references: [
makeReferenceEntry(userTs, /*isDefinition*/ true, "fnA"),
makeReferenceEntry(userTs, /*isDefinition*/ false, "fnA", { index: 1 }),
],
},
{
definition: {
...documentSpanFromSubstring(aTs, "fnA"),
kind: ScriptElementKind.functionElement,
name: "function fnA(): void",
containerKind: ScriptElementKind.unknown,
containerName: "",
displayParts: fnAVoid(SymbolDisplayPartKind.functionName),
},
references: [
makeReferenceEntry(aTs, /*isDefinition*/ true, "fnA"),
],
}
]);
});
it("findAllReferences -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
refs: [
makeReferenceItem(userTs, /*isDefinition*/ true, "fnB"),
makeReferenceItem(userTs, /*isDefinition*/ false, "fnB", { index: 1 }),
makeReferenceItem(bDts, /*isDefinition*/ true, "fnB"),
],
symbolName: "fnB",
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnB()").offset,
symbolDisplayString: "(alias) fnB(): void\nimport fnB",
});
});
it("renameLocations", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
canRename: true,
displayName: "fnA",
fullDisplayName: "fnA",
kind: ScriptElementKind.alias,
kindModifiers: ScriptElementKindModifier.none,
localizedErrorMessage: undefined,
},
locs: [
{
file: userTs.path,
locs: [
protocolTextSpanFromSubstring(userTs.content, "fnA"),
protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
],
},
{
file: aTs.path,
locs: [protocolTextSpanFromSubstring(aTs.content, "fnA")],
}
],
});
});
it("renameLocationsFull", () => {
const { session, aTs, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameFullRequest, protocol.RenameFullResponse>(session, protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<ReadonlyArray<RenameLocation>>(response, [
documentSpanFromSubstring(userTs, "fnA"),
documentSpanFromSubstring(userTs, "fnA", { index: 1 }),
documentSpanFromSubstring(aTs, "fnA"),
]);
});
it("renameLocations -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
canRename: true,
displayName: "fnB",
fullDisplayName: "fnB",
kind: ScriptElementKind.alias,
kindModifiers: ScriptElementKindModifier.none,
localizedErrorMessage: undefined,
},
locs: [
{
file: userTs.path,
locs: [
protocolTextSpanFromSubstring(userTs.content, "fnB"),
protocolTextSpanFromSubstring(userTs.content, "fnB", { index: 1 }),
],
},
{
file: bDts.path,
locs: [protocolTextSpanFromSubstring(bDts.content, "fnB")],
}
],
});
});
});
function writeDeclarationFiles(file: File, host: TestServerHost, session: TestSession, expectedFiles: ReadonlyArray<{ readonly name: string, readonly text: string }>): void {
function makeReferenceItem(file: File, isDefinition: boolean, text: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
return {
...protocolFileSpanFromSubstring(file, text, options),
isDefinition,
isWriteAccess: isDefinition,
lineText: text,
};
}
function makeReferenceEntry(file: File, isDefinition: boolean, text: string, options?: SpanFromSubstringOptions): ReferenceEntry {
return {
...documentSpanFromSubstring(file, text, options),
isDefinition,
isWriteAccess: isDefinition,
isInString: undefined,
};
}
function checkDeclarationFiles(file: File, session: TestSession, expectedFiles: ReadonlyArray<File>): void {
openFilesForSession([file], session);
const project = Debug.assertDefined(session.getProjectService().getDefaultProjectForFile(file.path as server.NormalizedPath, /*ensureProject*/ false));
const program = project.getCurrentProgram();
@@ -9042,12 +9222,6 @@ export function Test2() {
closeFilesForSession([file], session);
Debug.assert(!output.emitSkipped);
assert.deepEqual(output.outputFiles, expectedFiles.map(e => ({ ...e, writeByteOrderMark: false })));
for (const { name, text } of output.outputFiles) {
const directory: Folder = { path: getDirectoryPath(name) };
host.ensureFileOrFolder(directory);
host.writeFile(name, text);
}
assert.deepEqual(output.outputFiles, expectedFiles.map((e): OutputFile => ({ name: e.path, text: e.content, writeByteOrderMark: false })));
}
}
+65 -6
View File
@@ -7434,6 +7434,8 @@ declare namespace ts {
jsDocTypeExpression: JSDocTypeExpression;
diagnostics: Diagnostic[];
} | undefined;
/** @internal */
function isDeclarationFileName(fileName: string): boolean;
interface PragmaContext {
languageVersion: ScriptTarget;
pragmas?: PragmaMap;
@@ -8806,6 +8808,16 @@ declare namespace ts {
extendedDiagnostics?: boolean;
}
function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter, compilerOptions?: SourceMapOptions): SourceMapWriter;
interface SourceMapSection {
version: 3;
file: string;
sourceRoot?: string;
sources: string[];
names?: string[];
mappings: string;
sourcesContent?: (string | null)[];
sections?: undefined;
}
}
declare namespace ts {
interface CommentWriter {
@@ -8969,10 +8981,14 @@ declare namespace ts {
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
function parseConfigHostFromCompilerHost(host: CompilerHost): ParseConfigFileHost;
interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
/**
* Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
* The DiagnosticMessage's parameters are the imported module name, and the filename it resolved to.
@@ -10028,6 +10044,8 @@ declare namespace ts {
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
/** @internal */
getSourceMapper(): SourceMapper;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
@@ -10898,6 +10916,8 @@ declare namespace ts {
function getParentNodeInSpan(node: Node | undefined, file: SourceFile, span: TextSpan): Node | undefined;
function findModifier(node: Node, kind: Modifier["kind"]): Modifier | undefined;
function insertImport(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDecl: Statement): void;
function textSpansEqual(a: TextSpan | undefined, b: TextSpan | undefined): boolean;
function documentSpansEqual(a: DocumentSpan, b: DocumentSpan): boolean;
}
declare namespace ts {
function isFirstDeclarationOfSymbolParameter(symbol: Symbol): boolean;
@@ -11306,6 +11326,14 @@ declare namespace ts.SignatureHelp {
}
function getArgumentInfoForCompletions(node: Node, position: number, sourceFile: SourceFile): ArgumentInfoForCompletions | undefined;
}
declare namespace ts {
interface SourceMapper {
toLineColumnOffset(fileName: string, position: number): LineAndCharacter;
tryGetOriginalLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined;
clearCache(): void;
}
function getSourceMapper(getCanonicalFileName: GetCanonicalFileName, currentDirectory: string, log: (message: string) => void, host: LanguageServiceHost, getProgram: () => Program): SourceMapper;
}
declare namespace ts {
function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[];
}
@@ -12308,6 +12336,7 @@ declare namespace ts.server.protocol {
DefinitionAndBoundSpanFull = "definitionAndBoundSpan-full",
Implementation = "implementation",
ImplementationFull = "implementation-full",
EmitOutput = "emit-output",
Exit = "exit",
Format = "format",
Formatonkey = "formatonkey",
@@ -12630,6 +12659,17 @@ declare namespace ts.server.protocol {
interface DefinitionRequest extends FileLocationRequest {
command: CommandTypes.Definition;
}
interface DefinitionAndBoundSpanRequest extends FileLocationRequest {
readonly command: CommandTypes.DefinitionAndBoundSpan;
}
interface DefinitionAndBoundSpanResponse extends Response {
readonly body: DefinitionInfoAndBoundSpan;
}
interface EmitOutputRequest extends FileRequest {
}
interface EmitOutputResponse extends Response {
readonly body: EmitOutput;
}
interface TypeDefinitionRequest extends FileLocationRequest {
command: CommandTypes.TypeDefinition;
}
@@ -12728,6 +12768,13 @@ declare namespace ts.server.protocol {
command: CommandTypes.Rename;
arguments: RenameRequestArgs;
}
interface RenameFullRequest extends FileLocationRequest {
readonly command: CommandTypes.RenameLocationsFull;
readonly arguments: RenameRequestArgs;
}
interface RenameFullResponse extends Response {
readonly body: ReadonlyArray<RenameLocation>;
}
interface RenameInfo {
canRename: boolean;
localizedErrorMessage?: string;
@@ -13618,7 +13665,7 @@ declare namespace ts.server {
getCompilerOptions(): CompilerOptions;
getNewLine(): string;
getProjectVersion(): string;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference>;
getScriptFileNames(): string[];
private getOrCreateScriptInfoAndAttachToProject;
getScriptKind(fileName: string): ScriptKind;
@@ -13650,6 +13697,7 @@ declare namespace ts.server {
getGlobalProjectErrors(): ReadonlyArray<Diagnostic>;
getAllProjectErrors(): ReadonlyArray<Diagnostic>;
getLanguageService(ensureSynchronized?: boolean): LanguageService;
getSourceMapper(): SourceMapper;
private shouldEmitFile;
getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[];
emitFile(scriptInfo: ScriptInfo, writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void): boolean;
@@ -13732,7 +13780,7 @@ declare namespace ts.server {
updateGraph(): boolean;
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost;
getConfigFilePath(): NormalizedPath;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference>;
updateReferences(refs: ReadonlyArray<ProjectReference> | undefined): void;
enablePlugins(): void;
getGlobalProjectErrors(): ReadonlyArray<Diagnostic>;
@@ -14008,8 +14056,8 @@ declare namespace ts.server {
getSymlinkedProjects(info: ScriptInfo): MultiMap<Project> | undefined;
private watchClosedScriptInfo;
private stopWatchingScriptInfo;
getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined): ScriptInfo | undefined;
getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined): ScriptInfo | undefined;
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath;
private getOrCreateScriptInfoOpenedByClientForNormalizedPath;
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: {
fileExists(path: string): boolean;
}): ScriptInfo | undefined;
@@ -14024,6 +14072,11 @@ declare namespace ts.server {
private removeRootOfInferredProjectIfNowPartOfOtherProject;
private ensureProjectForOpenFiles;
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult;
getProjectForFileWithoutOpening(fileName: NormalizedPath): {
readonly scriptInfo: ScriptInfo;
readonly projects: ReadonlyArray<Project>;
} | undefined;
fileExists(fileName: NormalizedPath): boolean;
private findExternalProjectContainingOpenScriptInfo;
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult;
private telemetryOnOpenFile;
@@ -14121,11 +14174,14 @@ declare namespace ts.server {
private convertToDiagnosticsWithLinePosition;
private getDiagnosticsWorker;
private getDefinition;
private mapDefinitionInfoLocations;
private getDefinitionAndBoundSpan;
private getEmitOutput;
private mapDefinitionInfo;
private static mapToOriginalLocation;
private toFileSpan;
private getTypeDefinition;
private mapImplementationLocations;
private getImplementation;
private getOccurrences;
private getSyntacticDiagnosticsSync;
@@ -14140,6 +14196,8 @@ declare namespace ts.server {
private getProjects;
private getDefaultProject;
private getRenameLocations;
private static mapRenameInfo;
private toSpanGroups;
private getReferences;
private openClientFile;
private getPosition;
@@ -14178,6 +14236,7 @@ declare namespace ts.server {
private toLocationTextSpan;
private getNavigationTree;
private getNavigateToItems;
private getFullNavigateToItems;
private getSupportedCodeFixes;
private isLocation;
private extractPositionAndRange;
+6 -2
View File
@@ -4139,10 +4139,14 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4,6 +4,7 @@ Diagnostics:
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
EmitSkipped: false
FileName : /tests/cases/fourslash/a.js
function foo2() { return 30; } // no error - should emit a.js
@@ -1,34 +0,0 @@
EmitSkipped: false
FileName : ./dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.methodName = function (propName) { };
Foo.prototype.otherMethod = function () {
if (Math.random() > 0.5) {
return { x: 42 };
}
return { y: "yes" };
};
return Foo;
}());
exports.Foo = Foo;
FileName : ./dist/index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../tests/cases/fourslash/index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}FileName : ./dist/index.d.ts
export declare class Foo {
member: string;
methodName(propName: SomeType): void;
otherMethod(): {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
}
export interface SomeType {
member: number;
}
//# sourceMappingURL=index.d.ts.map
@@ -1,35 +0,0 @@
EmitSkipped: false
FileName : ./dist/index.js.map
{"version":3,"file":"index.js","sourceRoot":"/tests/cases/fourslash/","sources":["index.ts"],"names":[],"mappings":";;AAAA;IAAA;IASA,CAAC;IAPG,wBAAU,GAAV,UAAW,QAAkB,IAAS,CAAC;IACvC,yBAAW,GAAX;QACI,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE;YACrB,OAAO,EAAC,CAAC,EAAE,EAAE,EAAC,CAAC;SAClB;QACD,OAAO,EAAC,CAAC,EAAE,KAAK,EAAC,CAAC;IACtB,CAAC;IACL,UAAC;AAAD,CAAC,AATD,IASC;AATY,kBAAG"}FileName : ./dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.methodName = function (propName) { };
Foo.prototype.otherMethod = function () {
if (Math.random() > 0.5) {
return { x: 42 };
}
return { y: "yes" };
};
return Foo;
}());
exports.Foo = Foo;
//# sourceMappingURL=index.js.mapFileName : ./dist/index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"/tests/cases/fourslash/","sources":["index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}FileName : ./dist/index.d.ts
export declare class Foo {
member: string;
methodName(propName: SomeType): void;
otherMethod(): {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
}
export interface SomeType {
member: number;
}
//# sourceMappingURL=index.d.ts.map
@@ -1,34 +0,0 @@
EmitSkipped: false
FileName : ./dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.methodName = function (propName) { };
Foo.prototype.otherMethod = function () {
if (Math.random() > 0.5) {
return { x: 42 };
}
return { y: "yes" };
};
return Foo;
}());
exports.Foo = Foo;
FileName : ./dist/index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"/tests/cases/fourslash/","sources":["index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}FileName : ./dist/index.d.ts
export declare class Foo {
member: string;
methodName(propName: SomeType): void;
otherMethod(): {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
}
export interface SomeType {
member: number;
}
//# sourceMappingURL=index.d.ts.map
@@ -1,34 +0,0 @@
EmitSkipped: false
FileName : ./dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.methodName = function (propName) { };
Foo.prototype.otherMethod = function () {
if (Math.random() > 0.5) {
return { x: 42 };
}
return { y: "yes" };
};
return Foo;
}());
exports.Foo = Foo;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90ZXN0cy9jYXNlcy9mb3Vyc2xhc2gvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQTtJQUFBO0lBU0EsQ0FBQztJQVBHLHdCQUFVLEdBQVYsVUFBVyxRQUFrQixJQUFTLENBQUM7SUFDdkMseUJBQVcsR0FBWDtRQUNJLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEdBQUcsRUFBRTtZQUNyQixPQUFPLEVBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBQyxDQUFDO1NBQ2xCO1FBQ0QsT0FBTyxFQUFDLENBQUMsRUFBRSxLQUFLLEVBQUMsQ0FBQztJQUN0QixDQUFDO0lBQ0wsVUFBQztBQUFELENBQUMsQUFURCxJQVNDO0FBVFksa0JBQUcifQ==FileName : ./dist/index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../tests/cases/fourslash/index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}FileName : ./dist/index.d.ts
export declare class Foo {
member: string;
methodName(propName: SomeType): void;
otherMethod(): {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
}
export interface SomeType {
member: number;
}
//# sourceMappingURL=index.d.ts.map
@@ -1,34 +0,0 @@
EmitSkipped: false
FileName : ./dist/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype.methodName = function (propName) { };
Foo.prototype.otherMethod = function () {
if (Math.random() > 0.5) {
return { x: 42 };
}
return { y: "yes" };
};
return Foo;
}());
exports.Foo = Foo;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90ZXN0cy9jYXNlcy9mb3Vyc2xhc2gvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQTtJQUFBO0lBU0EsQ0FBQztJQVBHLHdCQUFVLEdBQVYsVUFBVyxRQUFrQixJQUFTLENBQUM7SUFDdkMseUJBQVcsR0FBWDtRQUNJLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEdBQUcsRUFBRTtZQUNyQixPQUFPLEVBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBQyxDQUFDO1NBQ2xCO1FBQ0QsT0FBTyxFQUFDLENBQUMsRUFBRSxLQUFLLEVBQUMsQ0FBQztJQUN0QixDQUFDO0lBQ0wsVUFBQztBQUFELENBQUMsQUFURCxJQVNDO0FBVFksa0JBQUciLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY2xhc3MgRm9vIHtcbiAgICBtZW1iZXI6IHN0cmluZztcbiAgICBtZXRob2ROYW1lKHByb3BOYW1lOiBTb21lVHlwZSk6IHZvaWQge31cbiAgICBvdGhlck1ldGhvZCgpIHtcbiAgICAgICAgaWYgKE1hdGgucmFuZG9tKCkgPiAwLjUpIHtcbiAgICAgICAgICAgIHJldHVybiB7eDogNDJ9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7eTogXCJ5ZXNcIn07XG4gICAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNvbWVUeXBlIHtcbiAgICBtZW1iZXI6IG51bWJlcjtcbn0iXX0=FileName : ./dist/index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../tests/cases/fourslash/index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}FileName : ./dist/index.d.ts
export declare class Foo {
member: string;
methodName(propName: SomeType): void;
otherMethod(): {
x: number;
y?: undefined;
} | {
y: string;
x?: undefined;
};
}
export interface SomeType {
member: number;
}
//# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/shims-pp/inputFile1.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -6,6 +7,7 @@ var Bar = /** @class */ (function () {
}
return Bar;
}());
FileName : /tests/cases/fourslash/shims-pp/inputFile1.d.ts
declare var x: number;
declare class Bar {
@@ -14,6 +16,7 @@ declare class Bar {
}
EmitSkipped: false
FileName : /tests/cases/fourslash/shims-pp/inputFile2.js
var x1 = "hello world";
var Foo = /** @class */ (function () {
@@ -21,6 +24,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : /tests/cases/fourslash/shims-pp/inputFile2.d.ts
declare var x1: string;
declare class Foo {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/shims/inputFile1.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -6,6 +7,7 @@ var Bar = /** @class */ (function () {
}
return Bar;
}());
FileName : /tests/cases/fourslash/shims/inputFile1.d.ts
declare var x: number;
declare class Bar {
@@ -14,6 +16,7 @@ declare class Bar {
}
EmitSkipped: false
FileName : /tests/cases/fourslash/shims/inputFile2.js
var x1 = "hello world";
var Foo = /** @class */ (function () {
@@ -21,6 +24,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : /tests/cases/fourslash/shims/inputFile2.d.ts
declare var x1: string;
declare class Foo {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -6,6 +7,7 @@ var Bar = /** @class */ (function () {
}
return Bar;
}());
FileName : /tests/cases/fourslash/inputFile1.d.ts
declare var x: number;
declare class Bar {
@@ -14,6 +16,7 @@ declare class Bar {
}
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js
var x1 = "hello world";
var Foo = /** @class */ (function () {
@@ -21,6 +24,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : /tests/cases/fourslash/inputFile2.d.ts
declare var x1: string;
declare class Foo {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : declSingleFile.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -12,6 +13,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : declSingleFile.d.ts
declare var x: number;
declare class Bar {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : declSingleFile.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : declSingleFile.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : declSingleFile.js.map
{"version":3,"file":"declSingleFile.js","sourceRoot":"","sources":["../inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : declSingleFile.js
{"version":3,"file":"declSingleFile.js","sourceRoot":"","sources":["../inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : declSingleFile.js
var x = 109;
var foo = "hello world";
var M = /** @class */ (function () {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
var x;
var M = /** @class */ (function () {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js
var x;
var Foo = /** @class */ (function () {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : out.js
/// <reference path='my.d.ts' />
var foo;
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : outFile.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -12,6 +13,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : outFile.d.ts
declare var x: number;
declare class Bar {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : outputDir/singleFile.js
var x;
var Bar = /** @class */ (function () {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : declSingleFile.js
var x = 5;
var Bar = /** @class */ (function () {
@@ -12,6 +13,7 @@ var Foo = /** @class */ (function () {
}
return Foo;
}());
FileName : declSingleFile.d.ts
declare var x: number;
declare class Bar {
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js.map
{"version":3,"file":"inputFile.js","sourceRoot":"","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile.js
{"version":3,"file":"inputFile.js","sourceRoot":"","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile.js
var x = 109;
var foo = "hello world";
var M = /** @class */ (function () {
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : sample/outDir/inputFile1.js.map
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : sample/outDir/inputFile1.js
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : sample/outDir/inputFile1.js
var x = 109;
var foo = "hello world";
var M = /** @class */ (function () {
@@ -10,8 +12,10 @@ var M = /** @class */ (function () {
}());
//# sourceMappingURL=inputFile1.js.map
EmitSkipped: false
FileName : sample/outDir/inputFile2.js.map
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,KAAK,GAAG,aAAa,CAAC;AAC1B,IAAI,KAAK,KAAK,SAAS,EAAE;IACtB,IAAI,CAAC,GAAG,EAAE,CAAC;CACb"}FileName : sample/outDir/inputFile2.js
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,KAAK,GAAG,aAAa,CAAC;AAC1B,IAAI,KAAK,KAAK,SAAS,EAAE;IACtB,IAAI,CAAC,GAAG,EAAE,CAAC;CACb"}
FileName : sample/outDir/inputFile2.js
var intro = "hello world";
if (intro !== undefined) {
var k = 10;
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js.map
{"version":3,"file":"inputFile.js","sourceRoot":"sourceRootDir/","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile.js
{"version":3,"file":"inputFile.js","sourceRoot":"sourceRootDir/","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile.js
var x = 109;
var foo = "hello world";
var M = /** @class */ (function () {
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js.map
{"version":3,"file":"inputFile1.js","sourceRoot":"sourceRootDir/","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
{"version":3,"file":"inputFile1.js","sourceRoot":"sourceRootDir/","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile1.js
var x = 109;
var foo = "hello world";
var M = /** @class */ (function () {
@@ -10,8 +12,10 @@ var M = /** @class */ (function () {
}());
//# sourceMappingURL=inputFile1.js.map
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js.map
{"version":3,"file":"inputFile2.js","sourceRoot":"sourceRootDir/","sources":["inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAG,wBAAwB,CAAC;AACnC;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile2.js
{"version":3,"file":"inputFile2.js","sourceRoot":"sourceRootDir/","sources":["inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAG,wBAAwB,CAAC;AACnC;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile2.js
var bar = "hello world Typescript";
var C = /** @class */ (function () {
function C() {
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js.map
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile1.js
// regular ts file
var t = 5;
var Bar = /** @class */ (function () {
@@ -8,7 +10,8 @@ var Bar = /** @class */ (function () {
}
return Bar;
}());
//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts
//# sourceMappingURL=inputFile1.js.map
FileName : /tests/cases/fourslash/inputFile1.d.ts
declare var t: number;
declare class Bar {
x: string;
@@ -16,11 +19,14 @@ declare class Bar {
}
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.jsx.map
{"version":3,"file":"inputFile2.jsx","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}FileName : /tests/cases/fourslash/inputFile2.jsx
{"version":3,"file":"inputFile2.jsx","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}
FileName : /tests/cases/fourslash/inputFile2.jsx
var y = "my div";
var x = <div name={y}/>;
//# sourceMappingURL=inputFile2.jsx.mapFileName : /tests/cases/fourslash/inputFile2.d.ts
//# sourceMappingURL=inputFile2.jsx.map
FileName : /tests/cases/fourslash/inputFile2.d.ts
declare var y: string;
declare var x: any;
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js.map
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}
FileName : /tests/cases/fourslash/inputFile1.js
// regular ts file
var t = 5;
var Bar = /** @class */ (function () {
@@ -8,7 +10,8 @@ var Bar = /** @class */ (function () {
}
return Bar;
}());
//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts
//# sourceMappingURL=inputFile1.js.map
FileName : /tests/cases/fourslash/inputFile1.d.ts
declare var t: number;
declare class Bar {
x: string;
@@ -16,11 +19,14 @@ declare class Bar {
}
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js.map
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AACA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,6BAAK,IAAI,EAAG,CAAC,GAAI,CAAA"}FileName : /tests/cases/fourslash/inputFile2.js
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AACA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,6BAAK,IAAI,EAAG,CAAC,GAAI,CAAA"}
FileName : /tests/cases/fourslash/inputFile2.js
var y = "my div";
var x = React.createElement("div", { name: y });
//# sourceMappingURL=inputFile2.js.mapFileName : /tests/cases/fourslash/inputFile2.d.ts
//# sourceMappingURL=inputFile2.js.map
FileName : /tests/cases/fourslash/inputFile2.d.ts
declare var React: any;
declare var y: string;
declare var x: any;
@@ -1,6 +1,7 @@
EmitSkipped: false
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js
var x1 = "hello world";
var Foo = /** @class */ (function () {
@@ -1,6 +1,7 @@
EmitSkipped: false
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile2.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
@@ -12,6 +13,7 @@ var Foo = /** @class */ (function () {
exports.Foo = Foo;
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile3.js
var x = "hello";
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : declSingle.js
var x = "hello";
var x1 = 1000;
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js
// File contains early errors. All outputs should be skipped.
var uninitialized_const_error;
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
var M;
(function (M) {
@@ -9,6 +10,7 @@ var M;
}());
M.foo = new C();
})(M || (M = {}));
FileName : /tests/cases/fourslash/inputFile.d.ts
declare module M {
class C {
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
define(["require", "exports"], function (require, exports) {
"use strict";
@@ -13,6 +14,7 @@ define(["require", "exports"], function (require, exports) {
M.foo = new C();
})(M = exports.M || (exports.M = {}));
});
FileName : /tests/cases/fourslash/inputFile.d.ts
class C {
}
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
var x = "hello world";
@@ -1,6 +1,8 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
var x = "hello world";
FileName : /tests/cases/fourslash/inputFile.d.ts
declare var x: number;
@@ -1,8 +1,10 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js
// File to emit, does not contain semantic errors
// expected to be emitted correctelly regardless of the semantic errors in the other file
var noErrors = true;
FileName : /tests/cases/fourslash/inputFile1.d.ts
declare var noErrors: boolean;
@@ -1,10 +1,12 @@
EmitSkipped: false
FileName : out.js
// File to emit, does not contain semantic errors, but --out is passed
// expected to not generate declarations because of the semantic errors in the other file
var noErrors = true;
// File not emitted, and contains semantic errors
var semanticError = "string";
FileName : out.d.ts
declare var noErrors: boolean;
declare var semanticError: boolean;
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile1.js
// File to emit, does not contain syntactic errors
// expected to be emitted correctelly regardless of the syntactic errors in the other file
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : out.js
// File to emit, does not contain syntactic errors, but --out is passed
// expected to not generate outputs because of the syntactic errors in the other file.
@@ -1,4 +1,5 @@
EmitSkipped: false
FileName : /tests/cases/fourslash/inputFile.js
var x;
@@ -1,34 +0,0 @@
/// <reference path="fourslash.ts" />
// @BaselineFile: declarationMapsGeneratedMapsEnableMapping_NoInline.baseline
// @outDir: ./dist
// @inlineSourceMap: true
// @declaration: true
// @declarationMap: true
// @Filename: index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.baselineGetEmitOutput(/*insertResultIntoVfs*/ true);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -1,35 +0,0 @@
/// <reference path="fourslash.ts" />
// @BaselineFile: declarationMapsGeneratedMapsEnableMapping_NoInlineSources.baseline
// @outDir: ./dist
// @inlineSourceMap: true
// @inlineSources: true
// @declaration: true
// @declarationMap: true
// @Filename: index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.baselineGetEmitOutput(/*insertResultIntoVfs*/ true);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -1,33 +0,0 @@
/// <reference path="fourslash.ts" />
// @BaselineFile: declarationMapsGeneratedMapsEnableMapping.baseline
// @outDir: ./dist
// @declaration: true
// @declarationMap: true
// @Filename: index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.baselineGetEmitOutput(/*insertResultIntoVfs*/ true);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -1,35 +0,0 @@
/// <reference path="fourslash.ts" />
// @BaselineFile: declarationMapsGeneratedMapsEnableMapping2.baseline
// @outDir: ./dist
// @sourceMap: true
// @sourceRoot: /tests/cases/fourslash/
// @declaration: true
// @declarationMap: true
// @Filename: index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.baselineGetEmitOutput(/*insertResultIntoVfs*/ true);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -1,34 +0,0 @@
/// <reference path="fourslash.ts" />
// @BaselineFile: declarationMapsGeneratedMapsEnableMapping3.baseline
// @outDir: ./dist
// @sourceRoot: /tests/cases/fourslash/
// @declaration: true
// @declarationMap: true
// @Filename: index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.baselineGetEmitOutput(/*insertResultIntoVfs*/ true);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
+1
View File
@@ -271,6 +271,7 @@ declare namespace FourSlashInterface {
baselineCurrentFileBreakpointLocations(): void;
baselineCurrentFileNameOrDottedNameSpans(): void;
baselineGetEmitOutput(insertResultsIntoVfs?: boolean): void;
getEmitOutput(expectedOutputFiles: ReadonlyArray<string>): void;
baselineQuickInfo(): void;
nameOrDottedNameSpanTextIs(text: string): void;
outliningSpansInCurrentFile(spans: Range[]): void;
@@ -1,40 +1,40 @@
/// <reference path="fourslash.ts" />
// @Filename: index.ts
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: indexdef.d.ts.map
////{"version":3,"file":"indexdef.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;IACI,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: indexdef.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=indexdef.d.ts.map
// @Filename: mymodule.ts
////import * as mod from "./indexdef";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.goToDefinition("1", "2");
/// <reference path="../fourslash.ts" />
// @Filename: index.ts
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: indexdef.d.ts.map
////{"version":3,"file":"indexdef.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;IACI,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: indexdef.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=indexdef.d.ts.map
// @Filename: mymodule.ts
////import * as mod from "./indexdef";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
verify.goToDefinition("1", "2");
@@ -0,0 +1,83 @@
/// <reference path="../fourslash.ts" />
// @Filename: /tsconfig.json
////{
//// "compilerOptions": {
//// "outDir": "./dist",
//// "inlineSourceMap": true,
//// "declaration": true,
//// "declarationMap": true,
//// "newLine": "lf",
//// },
//// "files": ["/index.ts"],
////}
// @Filename: /index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: /mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
// @Filename: /dist/index.js
////"use strict";
////exports.__esModule = true;
////var Foo = /** @class */ (function () {
//// function Foo() {
//// }
//// Foo.prototype.methodName = function (propName) { };
//// Foo.prototype.otherMethod = function () {
//// if (Math.random() > 0.5) {
//// return { x: 42 };
//// }
//// return { y: "yes" };
//// };
//// return Foo;
////}());
////exports.Foo = Foo;
//////# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBO0lBQUE7SUFTQSxDQUFDO0lBUEcsd0JBQVUsR0FBVixVQUFXLFFBQWtCLElBQVMsQ0FBQztJQUN2Qyx5QkFBVyxHQUFYO1FBQ0ksSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFO1lBQ3JCLE9BQU8sRUFBQyxDQUFDLEVBQUUsRUFBRSxFQUFDLENBQUM7U0FDbEI7UUFDRCxPQUFPLEVBQUMsQ0FBQyxFQUFFLEtBQUssRUFBQyxDQUFDO0lBQ3RCLENBQUM7SUFDTCxVQUFDO0FBQUQsQ0FBQyxBQVRELElBU0M7QUFUWSxrQkFBRyJ9
// @Filename: /dist/index.d.ts.map
////{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: /dist/index.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=index.d.ts.map
goTo.file("/index.ts");
verify.getEmitOutput(["/dist/index.js", "/dist/index.d.ts.map", "/dist/index.d.ts"]);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -0,0 +1,84 @@
/// <reference path="../fourslash.ts" />
// @Filename: /tsconfig.json
////{
//// "compilerOptions": {
//// "outDir": "./dist",
//// "inlineSourceMap": true,
//// "inlineSources": true,
//// "declaration": true,
//// "declarationMap": true,
//// "newLine": "lf",
//// },
//// "files": ["/index.ts"],
////}
// @Filename: /index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: /mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
// @Filename: /dist/index.js
////"use strict";
////exports.__esModule = true;
////var Foo = /** @class */ (function () {
//// function Foo() {
//// }
//// Foo.prototype.methodName = function (propName) { };
//// Foo.prototype.otherMethod = function () {
//// if (Math.random() > 0.5) {
//// return { x: 42 };
//// }
//// return { y: "yes" };
//// };
//// return Foo;
////}());
////exports.Foo = Foo;
//////# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBO0lBQUE7SUFTQSxDQUFDO0lBUEcsd0JBQVUsR0FBVixVQUFXLFFBQWtCLElBQVMsQ0FBQztJQUN2Qyx5QkFBVyxHQUFYO1FBQ0ksSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsR0FBRyxFQUFFO1lBQ3JCLE9BQU8sRUFBQyxDQUFDLEVBQUUsRUFBRSxFQUFDLENBQUM7U0FDbEI7UUFDRCxPQUFPLEVBQUMsQ0FBQyxFQUFFLEtBQUssRUFBQyxDQUFDO0lBQ3RCLENBQUM7SUFDTCxVQUFDO0FBQUQsQ0FBQyxBQVRELElBU0M7QUFUWSxrQkFBRyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjbGFzcyBGb28ge1xuICAgIG1lbWJlcjogc3RyaW5nO1xuICAgIG1ldGhvZE5hbWUocHJvcE5hbWU6IFNvbWVUeXBlKTogdm9pZCB7fVxuICAgIG90aGVyTWV0aG9kKCkge1xuICAgICAgICBpZiAoTWF0aC5yYW5kb20oKSA+IDAuNSkge1xuICAgICAgICAgICAgcmV0dXJuIHt4OiA0Mn07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHt5OiBcInllc1wifTtcbiAgICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU29tZVR5cGUge1xuICAgIG1lbWJlcjogbnVtYmVyO1xufSJdfQ==
// @Filename: /dist/index.d.ts.map
////{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: /dist/index.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=index.d.ts.map
goTo.file("/index.ts");
verify.getEmitOutput(["/dist/index.js", "/dist/index.d.ts.map", "/dist/index.d.ts"]);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -0,0 +1,82 @@
/// <reference path="../fourslash.ts" />
// @Filename: /tsconfig.json
////{
//// "compilerOptions": {
//// "outDir": "./dist",
//// "declaration": true,
//// "declarationMap": true,
//// "newLine": "lf",
//// },
//// "files": ["/index.ts"],
////}
// @Filename: /index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: /mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
// @Filename: /dist/index.js
////"use strict";
////exports.__esModule = true;
////var Foo = /** @class */ (function () {
//// function Foo() {
//// }
//// Foo.prototype.methodName = function (propName) { };
//// Foo.prototype.otherMethod = function () {
//// if (Math.random() > 0.5) {
//// return { x: 42 };
//// }
//// return { y: "yes" };
//// };
//// return Foo;
////}());
////exports.Foo = Foo;
////
// @Filename: /dist/index.d.ts.map
////{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: /dist/index.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=index.d.ts.map
goTo.file("/index.ts");
verify.getEmitOutput(["/dist/index.js", "/dist/index.d.ts.map", "/dist/index.d.ts"]);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -0,0 +1,87 @@
/// <reference path="../fourslash.ts" />
// @Filename: /tsconfig.json
////{
//// "compilerOptions": {
//// "outDir": "./dist",
//// "sourceMap": true,
//// "sourceRoot": "/",
//// "declaration": true,
//// "declarationMap": true,
//// "newLine": "lf",
//// },
//// "files": ["/index.ts"],
////}
// @Filename: /index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: /mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
// @Filename: /dist/index.js.map
////{"version":3,"file":"index.js","sourceRoot":"/","sources":["index.ts"],"names":[],"mappings":";;AAAA;IAAA;IASA,CAAC;IAPG,wBAAU,GAAV,UAAW,QAAkB,IAAS,CAAC;IACvC,yBAAW,GAAX;QACI,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,EAAE;YACrB,OAAO,EAAC,CAAC,EAAE,EAAE,EAAC,CAAC;SAClB;QACD,OAAO,EAAC,CAAC,EAAE,KAAK,EAAC,CAAC;IACtB,CAAC;IACL,UAAC;AAAD,CAAC,AATD,IASC;AATY,kBAAG"}
// @Filename: /dist/index.js
////"use strict";
////exports.__esModule = true;
////var Foo = /** @class */ (function () {
//// function Foo() {
//// }
//// Foo.prototype.methodName = function (propName) { };
//// Foo.prototype.otherMethod = function () {
//// if (Math.random() > 0.5) {
//// return { x: 42 };
//// }
//// return { y: "yes" };
//// };
//// return Foo;
////}());
////exports.Foo = Foo;
//////# sourceMappingURL=index.js.map
// @Filename: /dist/index.d.ts.map
////{"version":3,"file":"index.d.ts","sourceRoot":"/","sources":["index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: /dist/index.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=index.d.ts.map
goTo.file("/index.ts");
verify.getEmitOutput(["/dist/index.js.map", "/dist/index.js", "/dist/index.d.ts.map", "/dist/index.d.ts"]);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");
@@ -0,0 +1,83 @@
/// <reference path="../fourslash.ts" />
// @Filename: /tsconfig.json
////{
//// "compilerOptions": {
//// "outDir": "./dist",
//// "sourceRoot": "/",
//// "declaration": true,
//// "declarationMap": true,
//// "newLine": "lf",
//// },
//// "files": ["/index.ts"],
////}
// @Filename: /index.ts
// @emitThisFile: true
////export class Foo {
//// member: string;
//// /*2*/methodName(propName: SomeType): void {}
//// otherMethod() {
//// if (Math.random() > 0.5) {
//// return {x: 42};
//// }
//// return {y: "yes"};
//// }
////}
////
////export interface SomeType {
//// member: number;
////}
// @Filename: /mymodule.ts
////import * as mod from "/dist/index";
////const instance = new mod.Foo();
////instance.[|/*1*/methodName|]({member: 12});
// @Filename: /dist/index.js
////"use strict";
////exports.__esModule = true;
////var Foo = /** @class */ (function () {
//// function Foo() {
//// }
//// Foo.prototype.methodName = function (propName) { };
//// Foo.prototype.otherMethod = function () {
//// if (Math.random() > 0.5) {
//// return { x: 42 };
//// }
//// return { y: "yes" };
//// };
//// return Foo;
////}());
////exports.Foo = Foo;
////
// @Filename: /dist/index.d.ts.map
////{"version":3,"file":"index.d.ts","sourceRoot":"/","sources":["index.ts"],"names":[],"mappings":"AAAA,qBAAa,GAAG;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IACpC,WAAW;;;;;;;CAMd;AAED,MAAM,WAAW,QAAQ;IACrB,MAAM,EAAE,MAAM,CAAC;CAClB"}
// @Filename: /dist/index.d.ts
////export declare class Foo {
//// member: string;
//// methodName(propName: SomeType): void;
//// otherMethod(): {
//// x: number;
//// y?: undefined;
//// } | {
//// y: string;
//// x?: undefined;
//// };
////}
////export interface SomeType {
//// member: number;
////}
//////# sourceMappingURL=index.d.ts.map
goTo.file("/index.ts");
verify.getEmitOutput(["/dist/index.js", "/dist/index.d.ts.map", "/dist/index.d.ts"]);
verify.goToDefinition("1", "2"); // getDefinitionAndBoundSpan
verify.goToType("1", "2"); // getTypeDefinitionAtPosition
goTo.marker("1");
verify.goToDefinitionIs("2"); // getDefinitionAtPosition
goTo.implementation(); // getImplementationAtPosition
verify.caretAtMarker("2");