diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bfc502ce2da1e..ccea229b25998 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7646,7 +7646,8 @@ namespace ts { } } - function isDeclarationFileName(fileName: string): boolean { + /** @internal */ + export function isDeclarationFileName(fileName: string): boolean { return fileExtensionIs(fileName, Extension.Dts); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 741514d2ef264..75cdcaea32885 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -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; } diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index 8dfe91a6cff67..87fadd504df62 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -216,17 +216,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 }; @@ -577,6 +566,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) { diff --git a/src/harness/client.ts b/src/harness/client.ts index 20748a9c54cf8..ebe97aea0705d 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -73,7 +73,7 @@ namespace ts.server { return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText }; } - private processRequest(command: string, args?: T["arguments"]): T { + private processRequest(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(CommandNames.DefinitionAndBoundSpan, args); const response = this.processResponse(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.CommandTypes.EmitOutput, { file }); + const response = this.processResponse(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."); } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 859eff93575b6..db282b07b2c6b 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -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 { // 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): 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): void { + this.state.verifyGetEmitOutput(expectedOutputFiles); + } + + public baselineGetEmitOutput() { + this.state.baselineGetEmitOutput(); } public baselineQuickInfo() { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index e5dda42ff8bde..43d0eb1572050 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -557,6 +557,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({}); } } @@ -704,7 +707,9 @@ namespace Harness.LanguageService { return ts.sys.getEnvironmentVariable(name); } - readDirectory() { return ts.notImplemented(); } + readDirectory(path: string, extensions?: ReadonlyArray, exclude?: ReadonlyArray, include?: ReadonlyArray, depth?: number): string[] { + return this.host.readDirectory(path, extensions, exclude, include, depth); + } watchFile(): ts.FileWatcher { return { close: ts.noop }; diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index d56bc37cc2157..8f3fbe1ad2d4c 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -78,7 +78,9 @@ interface Array {}` } export interface SymLink { + /** Location of the symlink. */ path: string; + /** Relative path to the real file. */ symLink: string; } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 9e86ef849a50a..4cfdb859cf2be 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -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 } | 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 | 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) { diff --git a/src/server/project.ts b/src/server/project.ts index 343c4a2e97dfd..08b08eae04c8b 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -271,8 +271,8 @@ namespace ts.server { return this.projectStateVersion.toString(); } - getProjectReferences(): ReadonlyArray | undefined { - return undefined; + getProjectReferences(): ReadonlyArray { + 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 | undefined { - return this.projectReferences; + getProjectReferences(): ReadonlyArray { + return this.projectReferences || emptyArray; } updateReferences(refs: ReadonlyArray | undefined) { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index b3238fd9f7fd6..0f534c22f23ce 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -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; + } + /** * Information about the item to be renamed. */ diff --git a/src/server/session.ts b/src/server/session.ts index ed46cdd39b418..1f22c7baa7152 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -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 | { - projects: ReadonlyArray; - symLinkedProjects: MultiMap; + readonly projects: ReadonlyArray; + readonly symLinkedProjects: MultiMap; }; function isProjectsArray(projects: Projects): projects is ReadonlyArray { @@ -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(defaultValue: T, getValue: (path: Path) => T, projects: Projects, action: (project: Project, value: T) => ReadonlyArray | U | undefined, comparer?: (a: U, b: U) => number, areEqual?: (a: U, b: U) => boolean) { + function combineProjectOutput( + defaultValue: T, + getValue: (path: Path) => T, + projects: Projects, + action: (project: Project, value: T) => ReadonlyArray | 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( + projects: Projects, + projectService: ProjectService, + action: (project: Project) => ReadonlyArray, + getLocation: (t: T) => sourcemaps.SourceMappableLocation, + resultsEqual: (a: T, b: T) => boolean, + ): T[] { + const outputs: T[] = []; + combineProjectOutputWorker(projects, 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 { + 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 { + 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; + } + + 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() }; + 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 | ReadonlyArray { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - - const definitions = project.getLanguageService().getDefinitionAtPosition(file, position); - if (!definitions) { - return emptyArray; - } - - if (simplifiedResult) { - return this.mapDefinitionInfo(definitions, project); - } - - return definitions.map(Session.mapToOriginalLocation); + const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, project); + return simplifiedResult ? this.mapDefinitionInfo(definitions, project) : definitions.map(Session.mapToOriginalLocation); + } + + private mapDefinitionInfoLocations(definitions: ReadonlyArray, project: Project): ReadonlyArray { + 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, project: Project): ReadonlyArray { 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, project: Project): ReadonlyArray { + 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 | ReadonlyArray { 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 | undefined { + private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | ReadonlyArray { 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; - } - - if (!renameInfo.canRename) { - return { - info: renameInfo, - locs: emptyArray - }; - } - - 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; - } - - 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 }); - } + const locations = combineProjectOutputForRenameLocations(projects, { fileName: args.file, position }, this.projectService, !!args.findInStrings, !!args.findInComments); + if (!simplifiedResult) return locations; - 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 - ); - } + const defaultProject = this.getDefaultProject(args); + const renameInfo = Session.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position)); + return { info: renameInfo, locs: this.toSpanGroups(locations) }; + } - 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; - } + // strips 'triggerSpan' + private static mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }: RenameInfo): protocol.RenameInfo { + return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }; + } - 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): ReadonlyArray { + const map = createMap(); + 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 { 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( - 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 | ReadonlyArray { - const projects = this.getProjects(args); - - 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; - } + 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; + }); + } - 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 { + 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( + 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) { diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 38ac57255f4d0..00a9a9d4f3b9d 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -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; } diff --git a/src/services/services.ts b/src/services/services.ts index 13dab6acd870a..81951be361608 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -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. @@ -1503,183 +1503,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( - 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 | 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 | 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 @@ -1736,10 +1580,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); } @@ -2290,7 +2132,8 @@ namespace ts { getProgram, getApplicableRefactors, getEditsForRefactor, - toLineColumnOffset + toLineColumnOffset: sourceMapper.toLineColumnOffset, + getSourceMapper: () => sourceMapper, }; } diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts new file mode 100644 index 0000000000000..f617d879893a2 --- /dev/null +++ b/src/services/sourcemaps.ts @@ -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); + } + } +} diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 6e1495d78a270..355a4d302c0e8 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -29,6 +29,7 @@ "preProcess.ts", "rename.ts", "signatureHelp.ts", + "sourcemaps.ts", "suggestionDiagnostics.ts", "symbolDisplay.ts", "transpile.ts", diff --git a/src/services/types.ts b/src/services/types.ts index 45eb637f0dc62..51c98724c0957 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -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, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray; getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 7a4712e15cd8d..b87ec2610d856 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -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 diff --git a/src/testRunner/unittests/tsserverProjectSystem.ts b/src/testRunner/unittests/tsserverProjectSystem.ts index 95d1686a1491e..e38d80667bc6a 100644 --- a/src/testRunner/unittests/tsserverProjectSystem.ts +++ b/src/testRunner/unittests/tsserverProjectSystem.ts @@ -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, session: server.Session): void { + export function executeSessionRequest(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, session: server.Session): void { for (const file of files) { - const request = makeSessionRequest(CommandNames.Open, { file: file.path }); - session.executeCommand(request); + session.executeCommand(makeSessionRequest(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({ - command: protocol.CommandTypes.Open, - arguments: { - file: file.path, - fileContent: file.content, - projectRootPath - } - }); - } - - function closeFile(file: File) { - session.executeCommandSeq({ - 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({ - 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({ - 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({ - command: protocol.CommandTypes.Close, - arguments: { - file: backendTest.path - } - }); - session.executeCommandSeq({ - 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({ - command: protocol.CommandTypes.Open, - arguments: { - file: aFile.path, - projectRootPath: folderA - } - }); - session.executeCommandSeq({ - command: protocol.CommandTypes.Open, - arguments: { - file: bFile.path, - projectRootPath: folderB - } - }); - - session.executeCommandSeq({ - command: protocol.CommandTypes.Open, - arguments: { - file: aFc, - projectRootPath: folderA - } - }); - session.executeCommandSeq({ - 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({ - command: protocol.CommandTypes.Rename, - arguments: { - file: aFc, - line: 1, - offset: 14, - findInStrings: false, - findInComments: false - } - }).response as protocol.RenameResponseBody); - - 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); + const response = executeSessionRequest(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") }); - 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(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 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, bTs, bTsconfig]); + 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]); + + // Testing what happens if we delete the original sources. + host.removeFile(bTs.path); - return { session, aTs, bTs }; + openFilesForSession([userTs], session); + + return { session, aTs, bDts, userTs }; } describe("tsserverProjectSystem project references", () => { it("goToDefinition", () => { - const { session, aTs, bTs } = makeSampleProjects(); - - openFilesForSession([bTs], session); - - const definitionRequest = makeSessionRequest(CommandNames.Definition, protocolFileLocationFromSubstring(bTs, "fnA()")); - const definitionResponse = session.executeCommand(definitionRequest).response as protocol.DefinitionResponse["body"]; + const { session, aTs, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]); + }); - assert.deepEqual(definitionResponse, [protocolFileSpanFromSubstring(aTs, "fnA")]); + it("getDefinitionAndBoundSpan", () => { + const { session, aTs, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(response, { + textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }), + definitions: [protocolFileSpanFromSubstring(aTs, "fnA")], + }); }); - it("navigateTo", () => { - const { session, bTs } = makeSampleProjects(); + it("goToType", () => { + const { session, aTs, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA")); + assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "IfaceA")]); + }); - openFilesForSession([bTs], session); + it("goToImplementation", () => { + const { session, aTs, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]); + }); - const navtoRequest = makeSessionRequest(CommandNames.Navto, { file: bTs.path, searchValue: "fn" }); - const navtoResponse = session.executeCommand(navtoRequest).response as protocol.NavtoResponse["body"]; + it("goToDefinition -- target does not exist", () => { + const { session, bDts, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()")); + // bTs does not exist, so stick with bDts + assert.deepEqual(response, [protocolFileSpanFromSubstring(bDts, "fnB")]); + }); - assert.deepEqual | undefined>(navtoResponse, [ - // TODO: First result should be from a.ts, not a.d.ts + it("navigateTo", () => { + const { session, aTs, bDts, userTs } = makeSampleProjects(); + const response = executeSessionRequest(session, CommandNames.Navto, { file: userTs.path, searchValue: "fn" }); + assert.deepEqual | 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(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(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; } + const responseFull = executeSessionRequest(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>(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(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()")); + assert.deepEqual(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(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual(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(session, protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()")); + assert.deepEqual>(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(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()")); + assert.deepEqual(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): 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 }))); } } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 28d019ed18ec8..5ab85919002b8 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7420,6 +7420,8 @@ declare namespace ts { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined; + /** @internal */ + function isDeclarationFileName(fileName: string): boolean; interface PragmaContext { languageVersion: ScriptTarget; pragmas?: PragmaMap; @@ -8800,6 +8802,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 { @@ -8963,10 +8975,14 @@ declare namespace ts { */ function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray): 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. @@ -10022,6 +10038,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, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray; getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions; applyCodeActionCommand(action: CodeActionCommand): Promise; @@ -10892,6 +10910,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; @@ -11300,6 +11320,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[]; } @@ -12301,6 +12329,7 @@ declare namespace ts.server.protocol { DefinitionAndBoundSpanFull = "definitionAndBoundSpan-full", Implementation = "implementation", ImplementationFull = "implementation-full", + EmitOutput = "emit-output", Exit = "exit", Format = "format", Formatonkey = "formatonkey", @@ -12623,6 +12652,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; } @@ -12721,6 +12761,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; + } interface RenameInfo { canRename: boolean; localizedErrorMessage?: string; @@ -13611,7 +13658,7 @@ declare namespace ts.server { getCompilerOptions(): CompilerOptions; getNewLine(): string; getProjectVersion(): string; - getProjectReferences(): ReadonlyArray | undefined; + getProjectReferences(): ReadonlyArray; getScriptFileNames(): string[]; private getOrCreateScriptInfoAndAttachToProject; getScriptKind(fileName: string): ScriptKind; @@ -13643,6 +13690,7 @@ declare namespace ts.server { getGlobalProjectErrors(): ReadonlyArray; getAllProjectErrors(): ReadonlyArray; getLanguageService(ensureSynchronized?: boolean): LanguageService; + getSourceMapper(): SourceMapper; private shouldEmitFile; getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[]; emitFile(scriptInfo: ScriptInfo, writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void): boolean; @@ -13725,7 +13773,7 @@ declare namespace ts.server { updateGraph(): boolean; getCachedDirectoryStructureHost(): CachedDirectoryStructureHost; getConfigFilePath(): NormalizedPath; - getProjectReferences(): ReadonlyArray | undefined; + getProjectReferences(): ReadonlyArray; updateReferences(refs: ReadonlyArray | undefined): void; enablePlugins(): void; getGlobalProjectErrors(): ReadonlyArray; @@ -14001,8 +14049,8 @@ declare namespace ts.server { getSymlinkedProjects(info: ScriptInfo): MultiMap | 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; @@ -14017,6 +14065,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; + } | undefined; + fileExists(fileName: NormalizedPath): boolean; private findExternalProjectContainingOpenScriptInfo; openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult; private telemetryOnOpenFile; @@ -14114,11 +14167,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; @@ -14133,6 +14189,8 @@ declare namespace ts.server { private getProjects; private getDefaultProject; private getRenameLocations; + private static mapRenameInfo; + private toSpanGroups; private getReferences; private openClientFile; private getPosition; @@ -14171,6 +14229,7 @@ declare namespace ts.server { private toLocationTextSpan; private getNavigationTree; private getNavigateToItems; + private getFullNavigateToItems; private getSupportedCodeFixes; private isLocation; private extractPositionAndRange; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index ec82ee914dd39..fc9e4410c9027 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4140,10 +4140,14 @@ declare namespace ts { * @returns A 'Program' object. */ function createProgram(rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray): 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 { diff --git a/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline b/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline index e01194874bf70..80a31656fd04b 100644 --- a/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline +++ b/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline @@ -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 diff --git a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping.baseline b/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping.baseline deleted file mode 100644 index 5fae8ec8c9914..0000000000000 --- a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping.baseline +++ /dev/null @@ -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 diff --git a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping2.baseline b/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping2.baseline deleted file mode 100644 index 151713a03bd45..0000000000000 --- a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping2.baseline +++ /dev/null @@ -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 diff --git a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping3.baseline b/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping3.baseline deleted file mode 100644 index f05cbbd4c351b..0000000000000 --- a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping3.baseline +++ /dev/null @@ -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 diff --git a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInline.baseline b/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInline.baseline deleted file mode 100644 index ad51be6ddc0f5..0000000000000 --- a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInline.baseline +++ /dev/null @@ -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 diff --git a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInlineSources.baseline b/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInlineSources.baseline deleted file mode 100644 index 8f6440b29dc78..0000000000000 --- a/tests/baselines/reference/declarationMapsGeneratedMapsEnableMapping_NoInlineSources.baseline +++ /dev/null @@ -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 diff --git a/tests/baselines/reference/getEmitOutput-pp.baseline b/tests/baselines/reference/getEmitOutput-pp.baseline index 82243870b2940..d3e9e977f58a7 100644 --- a/tests/baselines/reference/getEmitOutput-pp.baseline +++ b/tests/baselines/reference/getEmitOutput-pp.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutput.baseline b/tests/baselines/reference/getEmitOutput.baseline index 9fa32d4dfe89a..1b029eefd126d 100644 --- a/tests/baselines/reference/getEmitOutput.baseline +++ b/tests/baselines/reference/getEmitOutput.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline b/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline index ac2d4850bb426..9208d6fb4f915 100644 --- a/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline +++ b/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline b/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline index 18e8920ba72ee..0e19223306afe 100644 --- a/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline +++ b/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputExternalModule.baseline b/tests/baselines/reference/getEmitOutputExternalModule.baseline index bd4162854f870..c577fb5679233 100644 --- a/tests/baselines/reference/getEmitOutputExternalModule.baseline +++ b/tests/baselines/reference/getEmitOutputExternalModule.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : declSingleFile.js var x = 5; var Bar = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputExternalModule2.baseline b/tests/baselines/reference/getEmitOutputExternalModule2.baseline index 3aff8629acf4e..dfbe9bf061d71 100644 --- a/tests/baselines/reference/getEmitOutputExternalModule2.baseline +++ b/tests/baselines/reference/getEmitOutputExternalModule2.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : declSingleFile.js var x = 5; var Bar = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputMapRoots.baseline b/tests/baselines/reference/getEmitOutputMapRoots.baseline index 4b4a9b0395bd7..67a136a3456fd 100644 --- a/tests/baselines/reference/getEmitOutputMapRoots.baseline +++ b/tests/baselines/reference/getEmitOutputMapRoots.baseline @@ -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 () { diff --git a/tests/baselines/reference/getEmitOutputNoErrors.baseline b/tests/baselines/reference/getEmitOutputNoErrors.baseline index 8cf9b0f143d93..8dea3c96fe61d 100644 --- a/tests/baselines/reference/getEmitOutputNoErrors.baseline +++ b/tests/baselines/reference/getEmitOutputNoErrors.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : /tests/cases/fourslash/inputFile.js var x; var M = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline b/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline index b913e00e7984d..e37174aa2323c 100644 --- a/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline +++ b/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : /tests/cases/fourslash/inputFile2.js var x; var Foo = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputOut.baseline b/tests/baselines/reference/getEmitOutputOut.baseline index 9508b6d55708e..26bb4e1b69328 100644 --- a/tests/baselines/reference/getEmitOutputOut.baseline +++ b/tests/baselines/reference/getEmitOutputOut.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : out.js /// var foo; diff --git a/tests/baselines/reference/getEmitOutputOutFile.baseline b/tests/baselines/reference/getEmitOutputOutFile.baseline index c683d963f0e4d..ce3454c4ed404 100644 --- a/tests/baselines/reference/getEmitOutputOutFile.baseline +++ b/tests/baselines/reference/getEmitOutputOutFile.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputSingleFile.baseline b/tests/baselines/reference/getEmitOutputSingleFile.baseline index fd370667bc529..929cd9d7a7dfa 100644 --- a/tests/baselines/reference/getEmitOutputSingleFile.baseline +++ b/tests/baselines/reference/getEmitOutputSingleFile.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : outputDir/singleFile.js var x; var Bar = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputSingleFile2.baseline b/tests/baselines/reference/getEmitOutputSingleFile2.baseline index 18e8920ba72ee..0e19223306afe 100644 --- a/tests/baselines/reference/getEmitOutputSingleFile2.baseline +++ b/tests/baselines/reference/getEmitOutputSingleFile2.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputSourceMap.baseline b/tests/baselines/reference/getEmitOutputSourceMap.baseline index e1e65087e6d49..5ef3f843b236b 100644 --- a/tests/baselines/reference/getEmitOutputSourceMap.baseline +++ b/tests/baselines/reference/getEmitOutputSourceMap.baseline @@ -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 () { diff --git a/tests/baselines/reference/getEmitOutputSourceMap2.baseline b/tests/baselines/reference/getEmitOutputSourceMap2.baseline index ccd11b1fec01c..f9a3455ba774f 100644 --- a/tests/baselines/reference/getEmitOutputSourceMap2.baseline +++ b/tests/baselines/reference/getEmitOutputSourceMap2.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputSourceRoot.baseline b/tests/baselines/reference/getEmitOutputSourceRoot.baseline index ddd6568b70439..a5185984a6ff6 100644 --- a/tests/baselines/reference/getEmitOutputSourceRoot.baseline +++ b/tests/baselines/reference/getEmitOutputSourceRoot.baseline @@ -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 () { diff --git a/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline b/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline index f6d9cb184e64a..a8013f697ca90 100644 --- a/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline +++ b/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline @@ -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() { diff --git a/tests/baselines/reference/getEmitOutputTsxFile_Preserve.baseline b/tests/baselines/reference/getEmitOutputTsxFile_Preserve.baseline index 5a04550370805..0e15fe43aca59 100644 --- a/tests/baselines/reference/getEmitOutputTsxFile_Preserve.baseline +++ b/tests/baselines/reference/getEmitOutputTsxFile_Preserve.baseline @@ -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 =
; -//# 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; diff --git a/tests/baselines/reference/getEmitOutputTsxFile_React.baseline b/tests/baselines/reference/getEmitOutputTsxFile_React.baseline index 4f5b8f65d2257..071d18992ea30 100644 --- a/tests/baselines/reference/getEmitOutputTsxFile_React.baseline +++ b/tests/baselines/reference/getEmitOutputTsxFile_React.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputWithDeclarationFile.baseline b/tests/baselines/reference/getEmitOutputWithDeclarationFile.baseline index fa07a2af00ec0..0176f4b628ffb 100644 --- a/tests/baselines/reference/getEmitOutputWithDeclarationFile.baseline +++ b/tests/baselines/reference/getEmitOutputWithDeclarationFile.baseline @@ -1,6 +1,7 @@ EmitSkipped: false EmitSkipped: false + FileName : /tests/cases/fourslash/inputFile2.js var x1 = "hello world"; var Foo = /** @class */ (function () { diff --git a/tests/baselines/reference/getEmitOutputWithDeclarationFile2.baseline b/tests/baselines/reference/getEmitOutputWithDeclarationFile2.baseline index b22067dc31809..86a6519b4b0b7 100644 --- a/tests/baselines/reference/getEmitOutputWithDeclarationFile2.baseline +++ b/tests/baselines/reference/getEmitOutputWithDeclarationFile2.baseline @@ -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"; diff --git a/tests/baselines/reference/getEmitOutputWithDeclarationFile3.baseline b/tests/baselines/reference/getEmitOutputWithDeclarationFile3.baseline index 1ce3d9f33c3b1..cd1f2739e3326 100644 --- a/tests/baselines/reference/getEmitOutputWithDeclarationFile3.baseline +++ b/tests/baselines/reference/getEmitOutputWithDeclarationFile3.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : declSingle.js var x = "hello"; var x1 = 1000; diff --git a/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline b/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline index 6609554a299ae..b011e5885e3ab 100644 --- a/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline +++ b/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline index d2b26ca48c89b..7ad60f361bb01 100644 --- a/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline @@ -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 { diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline index 77131f89dd5ef..46ba9652cc7db 100644 --- a/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline @@ -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 { } diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline index 55a58ea041f34..7ada814a55e89 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : /tests/cases/fourslash/inputFile.js var x = "hello world"; diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline index b5848da34570e..739ef23319140 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline index 4c22a7e3f9386..2fb3cdd921059 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline index 6a58015c1b3bc..0d5ab3f674741 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline @@ -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; diff --git a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline index f51782cc75d5c..1ec89e66d5a55 100644 --- a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline +++ b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline @@ -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 diff --git a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline index 0f526b85b4f6e..f429d4e1295c2 100644 --- a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline +++ b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline @@ -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. diff --git a/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline b/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline index 8aa81ba60ce6a..f84b9e810c93c 100644 --- a/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline +++ b/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline @@ -1,4 +1,5 @@ EmitSkipped: false + FileName : /tests/cases/fourslash/inputFile.js var x; diff --git a/tests/cases/fourslash/declarationMapsEnableMapping_NoInline.ts b/tests/cases/fourslash/declarationMapsEnableMapping_NoInline.ts deleted file mode 100644 index a17f7afcdd884..0000000000000 --- a/tests/cases/fourslash/declarationMapsEnableMapping_NoInline.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// -// @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"); \ No newline at end of file diff --git a/tests/cases/fourslash/declarationMapsEnableMapping_NoInlineSources.ts b/tests/cases/fourslash/declarationMapsEnableMapping_NoInlineSources.ts deleted file mode 100644 index 4760bbc628d2d..0000000000000 --- a/tests/cases/fourslash/declarationMapsEnableMapping_NoInlineSources.ts +++ /dev/null @@ -1,35 +0,0 @@ -/// -// @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"); \ No newline at end of file diff --git a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping.ts b/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping.ts deleted file mode 100644 index 42e08f8a27f31..0000000000000 --- a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping.ts +++ /dev/null @@ -1,33 +0,0 @@ -/// -// @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"); diff --git a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping2.ts b/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping2.ts deleted file mode 100644 index 261122c1e8e7b..0000000000000 --- a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping2.ts +++ /dev/null @@ -1,35 +0,0 @@ -/// -// @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"); diff --git a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping3.ts b/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping3.ts deleted file mode 100644 index cd90793358e5c..0000000000000 --- a/tests/cases/fourslash/declarationMapsGeneratedMapsEnableMapping3.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// -// @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"); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 2c62f5161d619..00fc4b3ec8c10 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -271,6 +271,7 @@ declare namespace FourSlashInterface { baselineCurrentFileBreakpointLocations(): void; baselineCurrentFileNameOrDottedNameSpans(): void; baselineGetEmitOutput(insertResultsIntoVfs?: boolean): void; + getEmitOutput(expectedOutputFiles: ReadonlyArray): void; baselineQuickInfo(): void; nameOrDottedNameSpanTextIs(text: string): void; outliningSpansInCurrentFile(spans: Range[]): void; diff --git a/tests/cases/fourslash/declarationMapGoToDefinition.ts b/tests/cases/fourslash/server/declarationMapGoToDefinition.ts similarity index 93% rename from tests/cases/fourslash/declarationMapGoToDefinition.ts rename to tests/cases/fourslash/server/declarationMapGoToDefinition.ts index a83fd7e8396e3..15f49b1e1b913 100644 --- a/tests/cases/fourslash/declarationMapGoToDefinition.ts +++ b/tests/cases/fourslash/server/declarationMapGoToDefinition.ts @@ -1,40 +1,40 @@ -/// -// @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"); +/// +// @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"); diff --git a/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInline.ts b/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInline.ts new file mode 100644 index 0000000000000..f85993e708452 --- /dev/null +++ b/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInline.ts @@ -0,0 +1,83 @@ +/// + +// @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"); diff --git a/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInlineSources.ts b/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInlineSources.ts new file mode 100644 index 0000000000000..83ef95f2f4ac2 --- /dev/null +++ b/tests/cases/fourslash/server/declarationMapsEnableMapping_NoInlineSources.ts @@ -0,0 +1,84 @@ +/// + +// @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"); diff --git a/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping.ts b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping.ts new file mode 100644 index 0000000000000..c8ea0f74a4391 --- /dev/null +++ b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping.ts @@ -0,0 +1,82 @@ +/// + +// @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"); diff --git a/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping2.ts b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping2.ts new file mode 100644 index 0000000000000..7799d61e2aeb2 --- /dev/null +++ b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping2.ts @@ -0,0 +1,87 @@ +/// + +// @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"); diff --git a/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping3.ts b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping3.ts new file mode 100644 index 0000000000000..5785b595440d7 --- /dev/null +++ b/tests/cases/fourslash/server/declarationMapsGeneratedMapsEnableMapping3.ts @@ -0,0 +1,83 @@ +/// + +// @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");