mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #28417 from Microsoft/relativeFilesThroughDynamicFile
Allow creation of relative path file infos only for open script infos and dynamic file
This commit is contained in:
@@ -835,9 +835,9 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
private forEachProject(cb: (project: Project) => void) {
|
||||
this.inferredProjects.forEach(cb);
|
||||
this.configuredProjects.forEach(cb);
|
||||
this.externalProjects.forEach(cb);
|
||||
this.configuredProjects.forEach(cb);
|
||||
this.inferredProjects.forEach(cb);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -1037,7 +1037,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private removeProject(project: Project) {
|
||||
this.logger.info(`remove project: ${project.getRootFiles().toString()}`);
|
||||
this.logger.info("`remove Project::");
|
||||
project.print();
|
||||
|
||||
project.close();
|
||||
if (Debug.shouldAssert(AssertionLevel.Normal)) {
|
||||
@@ -1477,19 +1478,9 @@ namespace ts.server {
|
||||
|
||||
const writeProjectFileNames = this.logger.hasLevel(LogLevel.verbose);
|
||||
this.logger.startGroup();
|
||||
let counter = 0;
|
||||
const printProjects = (projects: Project[], counter: number): number => {
|
||||
for (const project of projects) {
|
||||
this.logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
|
||||
this.logger.info(project.filesToString(writeProjectFileNames));
|
||||
this.logger.info("-----------------------------------------------");
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
};
|
||||
counter = printProjects(this.externalProjects, counter);
|
||||
counter = printProjects(arrayFrom(this.configuredProjects.values()), counter);
|
||||
printProjects(this.inferredProjects, counter);
|
||||
let counter = printProjectsWithCounter(this.externalProjects, 0);
|
||||
counter = printProjectsWithCounter(arrayFrom(this.configuredProjects.values()), counter);
|
||||
printProjectsWithCounter(this.inferredProjects, counter);
|
||||
|
||||
this.logger.info("Open files: ");
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
@@ -2118,7 +2109,20 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
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);
|
||||
if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) {
|
||||
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
|
||||
}
|
||||
|
||||
// This is non rooted path with different current directory than project service current directory
|
||||
// Only paths recognized are open relative file paths
|
||||
const info = this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName));
|
||||
if (info) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// This means triple slash references wont be resolved in dynamic and unsaved files
|
||||
// which is intentional since we dont know what it means to be relative to non disk files
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) {
|
||||
@@ -2135,7 +2139,7 @@ namespace ts.server {
|
||||
let info = this.getScriptInfoForPath(path);
|
||||
if (!info) {
|
||||
const isDynamic = isDynamicFileName(fileName);
|
||||
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info`);
|
||||
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
|
||||
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
|
||||
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always have current directory context since containing external project name will always match the script info name.`);
|
||||
// If the file is not opened by client and the file doesnot exist on the disk, return
|
||||
@@ -2148,7 +2152,7 @@ namespace ts.server {
|
||||
if (!openedByClient) {
|
||||
this.watchClosedScriptInfo(info);
|
||||
}
|
||||
else if (!isRootedDiskPath(fileName) && currentDirectory !== this.currentDirectory) {
|
||||
else if (!isRootedDiskPath(fileName) && !isDynamic) {
|
||||
// File that is opened by user but isn't rooted disk path
|
||||
this.openFilesWithNonRootedDiskPath.set(this.toCanonicalFileName(fileName), info);
|
||||
}
|
||||
@@ -2909,4 +2913,12 @@ namespace ts.server {
|
||||
export function isConfigFile(config: ScriptInfoOrConfig): config is TsConfigSourceFile {
|
||||
return (config as TsConfigSourceFile).kind !== undefined;
|
||||
}
|
||||
|
||||
function printProjectsWithCounter(projects: Project[], counter: number) {
|
||||
for (const project of projects) {
|
||||
project.print(counter);
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,6 +995,13 @@ namespace ts.server {
|
||||
return strBuilder;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
print(counter?: number) {
|
||||
this.writeLog(`Project '${this.projectName}' (${ProjectKind[this.projectKind]}) ${counter === undefined ? "" : counter}`);
|
||||
this.writeLog(this.filesToString(this.projectService.logger.hasLevel(LogLevel.verbose)));
|
||||
this.writeLog("-----------------------------------------------");
|
||||
}
|
||||
|
||||
setCompilerOptions(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions) {
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
|
||||
+60
-33
@@ -289,7 +289,6 @@ namespace ts.server {
|
||||
function combineProjectOutputWhileOpeningReferencedProjects<T>(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
projectService: ProjectService,
|
||||
action: (project: Project) => ReadonlyArray<T>,
|
||||
getLocation: (t: T) => sourcemaps.SourceMappableLocation,
|
||||
resultsEqual: (a: T, b: T) => boolean,
|
||||
@@ -299,7 +298,6 @@ namespace ts.server {
|
||||
projects,
|
||||
defaultProject,
|
||||
/*initialLocation*/ undefined,
|
||||
projectService,
|
||||
({ project }, tryAddToTodo) => {
|
||||
for (const output of action(project)) {
|
||||
if (!contains(outputs, output, resultsEqual) && !tryAddToTodo(project, getLocation(output))) {
|
||||
@@ -312,17 +310,27 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
function combineProjectOutputForRenameLocations(
|
||||
projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService, findInStrings: boolean, findInComments: boolean
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: sourcemaps.SourceMappableLocation,
|
||||
findInStrings: boolean,
|
||||
findInComments: boolean
|
||||
): ReadonlyArray<RenameLocation> {
|
||||
const outputs: RenameLocation[] = [];
|
||||
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, 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);
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => getDefinitionLocation(defaultProject, initialLocation));
|
||||
},
|
||||
() => getDefinitionLocation(defaultProject, initialLocation)
|
||||
);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
@@ -333,31 +341,41 @@ namespace ts.server {
|
||||
return info && { fileName: info.fileName, position: info.textSpan.start };
|
||||
}
|
||||
|
||||
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
|
||||
function combineProjectOutputForReferences(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: sourcemaps.SourceMappableLocation
|
||||
): ReadonlyArray<ReferencedSymbol> {
|
||||
const outputs: ReferencedSymbol[] = [];
|
||||
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
outputs.push(symbolToAddTo);
|
||||
}
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
outputs.push(symbolToAddTo);
|
||||
}
|
||||
|
||||
for (const ref of outputReferencedSymbol.references) {
|
||||
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
|
||||
symbolToAddTo.references.push(ref);
|
||||
for (const ref of outputReferencedSymbol.references) {
|
||||
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
|
||||
symbolToAddTo.references.push(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => getDefinitionLocation(defaultProject, initialLocation));
|
||||
},
|
||||
() => getDefinitionLocation(defaultProject, initialLocation)
|
||||
);
|
||||
|
||||
return outputs.filter(o => o.references.length !== 0);
|
||||
}
|
||||
@@ -389,10 +407,10 @@ namespace ts.server {
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: TLocation,
|
||||
projectService: ProjectService,
|
||||
cb: CombineProjectOutputCallback<TLocation>,
|
||||
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
|
||||
): void {
|
||||
const projectService = defaultProject.projectService;
|
||||
let toDo: ProjectAndLocation<TLocation>[] | undefined;
|
||||
const seenProjects = createMap<true>();
|
||||
forEachProjectInProjects(projects, initialLocation && initialLocation.fileName, (project, path) => {
|
||||
@@ -1208,7 +1226,13 @@ namespace ts.server {
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
const locations = combineProjectOutputForRenameLocations(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService, !!args.findInStrings, !!args.findInComments);
|
||||
const locations = combineProjectOutputForRenameLocations(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
{ fileName: args.file, position },
|
||||
!!args.findInStrings,
|
||||
!!args.findInComments
|
||||
);
|
||||
if (!simplifiedResult) return locations;
|
||||
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
@@ -1242,7 +1266,11 @@ namespace ts.server {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const projects = this.getProjects(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const references = combineProjectOutputForReferences(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService);
|
||||
const references = combineProjectOutputForReferences(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
{ fileName: args.file, position },
|
||||
);
|
||||
|
||||
if (simplifiedResult) {
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
@@ -1749,7 +1777,6 @@ namespace ts.server {
|
||||
return combineProjectOutputWhileOpeningReferencedProjects<NavigateToItem>(
|
||||
this.getProjects(args),
|
||||
this.getDefaultProject(args),
|
||||
this.projectService,
|
||||
project =>
|
||||
project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject()),
|
||||
documentSpanLocation,
|
||||
|
||||
@@ -3301,6 +3301,23 @@ namespace ts.projectSystem {
|
||||
});
|
||||
});
|
||||
|
||||
it("dynamic file with reference paths without external project", () => {
|
||||
const file: File = {
|
||||
path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js",
|
||||
content: `/// <reference path="../../../../../../typings/@epic/Core.d.ts" />
|
||||
/// <reference path="../../../../../../typings/@epic/Shell.d.ts" />
|
||||
var x = 10;`
|
||||
};
|
||||
const host = createServerHost([libFile]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file.path, file.content);
|
||||
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
const project = projectService.inferredProjects[0];
|
||||
checkProjectRootFiles(project, [file.path]);
|
||||
checkProjectActualFiles(project, [file.path, libFile.path]);
|
||||
});
|
||||
|
||||
it("files opened, closed affecting multiple projects", () => {
|
||||
const file: File = {
|
||||
path: "/a/b/projects/config/file.ts",
|
||||
@@ -3882,25 +3899,39 @@ namespace ts.projectSystem {
|
||||
|
||||
describe("when opening new file that doesnt exist on disk yet", () => {
|
||||
function verifyNonExistentFile(useProjectRoot: boolean) {
|
||||
const host = createServerHost([libFile]);
|
||||
const folderPath = "/user/someuser/projects/someFolder";
|
||||
const fileInRoot: File = {
|
||||
path: `/src/somefile.d.ts`,
|
||||
content: "class c { }"
|
||||
};
|
||||
const fileInProjectRoot: File = {
|
||||
path: `${folderPath}/src/somefile.d.ts`,
|
||||
content: "class c { }"
|
||||
};
|
||||
const host = createServerHost([libFile, fileInRoot, fileInProjectRoot]);
|
||||
const { hasError, errorLogger } = createErrorLogger();
|
||||
const session = createSession(host, { canUseEvents: true, logger: errorLogger, useInferredProjectPerProjectRoot: true });
|
||||
|
||||
const folderPath = "/user/someuser/projects/someFolder";
|
||||
const projectService = session.getProjectService();
|
||||
const untitledFile = "untitled:Untitled-1";
|
||||
const refPathNotFound1 = "../../../../../../typings/@epic/Core.d.ts";
|
||||
const refPathNotFound2 = "./src/somefile.d.ts";
|
||||
const fileContent = `/// <reference path="${refPathNotFound1}" />
|
||||
/// <reference path="${refPathNotFound2}" />`;
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: server.CommandNames.Open,
|
||||
arguments: {
|
||||
file: untitledFile,
|
||||
fileContent: "",
|
||||
scriptKindName: "JS",
|
||||
fileContent,
|
||||
scriptKindName: "TS",
|
||||
projectRootPath: useProjectRoot ? folderPath : undefined
|
||||
}
|
||||
});
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const infoForUntitledAtProjectRoot = projectService.getScriptInfoForPath(`${folderPath.toLowerCase()}/${untitledFile.toLowerCase()}` as Path);
|
||||
const infoForUnitiledAtRoot = projectService.getScriptInfoForPath(`/${untitledFile.toLowerCase()}` as Path);
|
||||
const infoForSomefileAtProjectRoot = projectService.getScriptInfoForPath(`/${folderPath.toLowerCase()}/src/somefile.d.ts` as Path);
|
||||
const infoForSomefileAtRoot = projectService.getScriptInfoForPath(`${fileInRoot.path.toLowerCase()}` as Path);
|
||||
if (useProjectRoot) {
|
||||
assert.isDefined(infoForUntitledAtProjectRoot);
|
||||
assert.isUndefined(infoForUnitiledAtRoot);
|
||||
@@ -3909,7 +3940,11 @@ namespace ts.projectSystem {
|
||||
assert.isDefined(infoForUnitiledAtRoot);
|
||||
assert.isUndefined(infoForUntitledAtProjectRoot);
|
||||
}
|
||||
host.checkTimeoutQueueLength(2);
|
||||
assert.isUndefined(infoForSomefileAtRoot);
|
||||
assert.isUndefined(infoForSomefileAtProjectRoot);
|
||||
|
||||
// Since this is not js project so no typings are queued
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
const newTimeoutId = host.getNextTimeoutId();
|
||||
const expectedSequenceId = session.getNextSeq();
|
||||
@@ -3920,19 +3955,26 @@ namespace ts.projectSystem {
|
||||
files: [untitledFile]
|
||||
}
|
||||
});
|
||||
host.checkTimeoutQueueLength(3);
|
||||
host.checkTimeoutQueueLength(1);
|
||||
|
||||
// Run the last one = get error request
|
||||
host.runQueuedTimeoutCallbacks(newTimeoutId);
|
||||
|
||||
assert.isFalse(hasError());
|
||||
host.checkTimeoutQueueLength(2);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkErrorMessage(session, "syntaxDiag", { file: untitledFile, diagnostics: [] });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks();
|
||||
assert.isFalse(hasError());
|
||||
checkErrorMessage(session, "semanticDiag", { file: untitledFile, diagnostics: [] });
|
||||
const errorOffset = fileContent.indexOf(refPathNotFound1) + 1;
|
||||
checkErrorMessage(session, "semanticDiag", {
|
||||
file: untitledFile,
|
||||
diagnostics: [
|
||||
createDiagnostic({ line: 1, offset: errorOffset }, { line: 1, offset: errorOffset + refPathNotFound1.length }, Diagnostics.File_0_not_found, [refPathNotFound1], "error"),
|
||||
createDiagnostic({ line: 2, offset: errorOffset }, { line: 2, offset: errorOffset + refPathNotFound2.length }, Diagnostics.File_0_not_found, [refPathNotFound2.substr(2)], "error")
|
||||
]
|
||||
});
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks(1);
|
||||
@@ -10772,16 +10814,16 @@ fn5();`
|
||||
const untitledFile = "untitled:^Untitled-1";
|
||||
executeSessionRequestNoResponse<protocol.OpenRequest>(session, protocol.CommandTypes.Open, {
|
||||
file: untitledFile,
|
||||
fileContent: "let foo = 1;\nfooo/**/",
|
||||
fileContent: `/// <reference path="../../../../../../typings/@epic/Core.d.ts" />\nlet foo = 1;\nfooo/**/`,
|
||||
scriptKindName: "TS",
|
||||
projectRootPath: "/proj",
|
||||
});
|
||||
|
||||
const response = executeSessionRequest<protocol.CodeFixRequest, protocol.CodeFixResponse>(session, protocol.CommandTypes.GetCodeFixes, {
|
||||
file: untitledFile,
|
||||
startLine: 2,
|
||||
startLine: 3,
|
||||
startOffset: 1,
|
||||
endLine: 2,
|
||||
endLine: 3,
|
||||
endOffset: 5,
|
||||
errorCodes: [Diagnostics.Cannot_find_name_0_Did_you_mean_1.code],
|
||||
});
|
||||
@@ -10794,8 +10836,8 @@ fn5();`
|
||||
changes: [{
|
||||
fileName: untitledFile,
|
||||
textChanges: [{
|
||||
start: { line: 2, offset: 1 },
|
||||
end: { line: 2, offset: 5 },
|
||||
start: { line: 3, offset: 1 },
|
||||
end: { line: 3, offset: 5 },
|
||||
newText: "foo",
|
||||
}],
|
||||
}],
|
||||
|
||||
Reference in New Issue
Block a user