Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions src/services/pasteEdits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import {
codefix,
Debug,
fileShouldUseJavaScriptRequire,
findAncestor,
findIndex,
forEachChild,
formatting,
getNewLineOrDefaultFromHost,
getQuotePreference,
getTokenAtPosition,
isIdentifier,
Program,
rangeContainsPosition,
rangeContainsRange,
SourceFile,
Statement,
SymbolFlags,
Expand Down Expand Up @@ -56,17 +61,16 @@ function pasteEdits(
cancellationToken: CancellationToken,
changes: textChanges.ChangeTracker,
) {
let actualPastedText: string[] | undefined;
let actualPastedText: string | undefined;
if (pastedText.length !== pasteLocations.length) {
actualPastedText = pastedText.length === 1 ? pastedText : [pastedText.join("\n")];
actualPastedText = pastedText.length === 1 ? pastedText[0] : pastedText.join(getNewLineOrDefaultFromHost(formatContext.host, formatContext.options));
}

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);
newText = actualPastedText ? newText.slice(0, pos) + actualPastedText + newText.slice(end) : newText.slice(0, pos) + pastedText[i] + newText.slice(end);
}

let importAdder: codefix.ImportAdder;
Expand Down Expand Up @@ -104,12 +108,46 @@ function pasteEdits(
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);

// `updatedRanges` represent the new ranges that account for the offset changes caused by pasting new text and
// `offset` represents by how much the starting position of `pasteLocations` needs to be changed.
//
// We iterate over each updated range to get the node that wholly encloses the updated range.
// For each child of that node, we checked for unresolved identifiers
// within the updated range and try importing it.
let offset = 0;
pasteLocations.forEach((location, i) => {
const oldTextLength = location.end - location.pos;
const textToBePasted = actualPastedText ?? pastedText[i];
const startPos = location.pos + offset;
const endPos = startPos + textToBePasted.length;
const range: TextRange = { pos: startPos, end: endPos };
offset += textToBePasted.length - oldTextLength;

const enclosingNode = findAncestor(
getTokenAtPosition(context.sourceFile, range.pos),
ancestorNode => rangeContainsRange(ancestorNode, range),
);
if (!enclosingNode) return;

forEachChild(enclosingNode, function importUnresolvedIdentifiers(node) {
const isImportCandidate = isIdentifier(node) &&
rangeContainsPosition(range, node.getStart(updatedFile)) &&
!updatedProgram?.getTypeChecker().resolveName(
node.text,
node,
SymbolFlags.All,
/*excludeGlobals*/ false,
);
if (isImportCandidate) {
return importAdder.addImportForUnresolvedIdentifier(
context,
node,
/*useAutoImportProvider*/ true,
);
}
node.forEachChild(importUnresolvedIdentifiers);
});
});
}
importAdder.writeFixes(changes, getQuotePreference(copiedFrom ? copiedFrom.file : targetFile, preferences));
Expand All @@ -125,8 +163,7 @@ function pasteEdits(
changes.replaceRangeWithText(
targetFile,
{ pos: paste.pos, end: paste.end },
actualPastedText ?
actualPastedText[0] : pastedText[i],
actualPastedText ?? pastedText[i],
);
});
}
Loading
Loading