forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpasteEdits.ts
More file actions
115 lines (110 loc) · 4.85 KB
/
pasteEdits.ts
File metadata and controls
115 lines (110 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { addRange } from "../compiler/core.js";
import {
CancellationToken,
Program,
SourceFile,
Statement,
SymbolFlags,
TextRange,
UserPreferences,
} from "../compiler/types.js";
import { getLineOfLocalPosition } from "../compiler/utilities.js";
import {
codefix,
Debug,
fileShouldUseJavaScriptRequire,
forEachChild,
formatting,
getQuotePreference,
isIdentifier,
textChanges,
} from "./_namespaces/ts.js";
import { addTargetFileImports } from "./refactors/helpers.js";
import {
addExportsInOldFile,
getExistingLocals,
getUsageInfo,
} from "./refactors/moveToFile.js";
import {
CodeFixContextBase,
FileTextChanges,
LanguageServiceHost,
PasteEdits,
} from "./types.js";
const fixId = "providePostPasteEdits";
/** @internal */
export function pasteEditsProvider(
targetFile: SourceFile,
pastedText: string[],
pasteLocations: TextRange[],
copiedFrom: { file: SourceFile; range: TextRange[]; } | undefined,
host: LanguageServiceHost,
preferences: UserPreferences,
formatContext: formatting.FormatContext,
cancellationToken: CancellationToken,
): PasteEdits {
const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => pasteEdits(targetFile, pastedText, pasteLocations, copiedFrom, host, preferences, formatContext, cancellationToken, changeTracker));
return { edits: changes, fixId };
}
function pasteEdits(
targetFile: SourceFile,
pastedText: string[],
pasteLocations: TextRange[],
copiedFrom: { file: SourceFile; range: TextRange[]; } | undefined,
host: LanguageServiceHost,
preferences: UserPreferences,
formatContext: formatting.FormatContext,
cancellationToken: CancellationToken,
changes: textChanges.ChangeTracker,
) {
let actualPastedText: string[] | undefined;
if (pastedText.length !== pasteLocations.length) {
actualPastedText = pastedText.length === 1 ? pastedText : [pastedText.join("\n")];
}
const statements: Statement[] = [];
let newText = targetFile.text;
for (let i = pasteLocations.length - 1; i >= 0; i--) {
const { pos, end } = pasteLocations[i];
newText = actualPastedText ? newText.slice(0, pos) + actualPastedText[0] + newText.slice(end) : newText.slice(0, pos) + pastedText[i] + newText.slice(end);
}
Debug.checkDefined(host.runWithTemporaryFileUpdate).call(host, targetFile.fileName, newText, (updatedProgram: Program, originalProgram: Program | undefined, updatedFile: SourceFile) => {
const importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host);
if (copiedFrom?.range) {
Debug.assert(copiedFrom.range.length === pastedText.length);
copiedFrom.range.forEach(copy => {
addRange(statements, copiedFrom.file.statements, getLineOfLocalPosition(copiedFrom.file, copy.pos), getLineOfLocalPosition(copiedFrom.file, copy.end) + 1);
});
const usage = getUsageInfo(copiedFrom.file, statements, originalProgram!.getTypeChecker(), getExistingLocals(updatedFile, statements, originalProgram!.getTypeChecker()));
Debug.assertIsDefined(originalProgram);
const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, originalProgram, host, !!copiedFrom.file.commonJsModuleIndicator);
addExportsInOldFile(copiedFrom.file, usage.targetFileImportsFromOldFile, changes, useEsModuleSyntax);
addTargetFileImports(copiedFrom.file, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, originalProgram.getTypeChecker(), updatedProgram, importAdder);
}
else {
const context: CodeFixContextBase = {
sourceFile: updatedFile,
program: originalProgram!,
cancellationToken,
host,
preferences,
formatContext,
};
forEachChild(updatedFile, function cb(node) {
if (isIdentifier(node) && !originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) {
// generate imports
importAdder.addImportForUnresolvedIdentifier(context, node, /*useAutoImportProvider*/ true);
}
node.forEachChild(cb);
});
}
importAdder.writeFixes(changes, getQuotePreference(copiedFrom ? copiedFrom.file : targetFile, preferences));
});
pasteLocations.forEach((paste, i) => {
changes.replaceRangeWithText(
targetFile,
{ pos: paste.pos, end: paste.end },
actualPastedText ?
actualPastedText[0] : pastedText[i],
);
});
}