mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-17 21:09:09 -05:00
Have the ChangeTracker filter out edits that are no-ops (#38123)
* Filter out edits that are no-ops in 'organize imports'. * Updated tests for 'organize imports'. * Always remove no-op changes from the change tracker. * Add a new `stringContainsAt` helper function to avoid traversing the entire file contents. * Combine `map`/`filter` sequence into `mapDefined`. * Fix up documentation.
This commit is contained in:
committed by
GitHub
parent
9569e8aaa4
commit
d7e437a409
@@ -887,7 +887,7 @@ namespace ts.textChanges {
|
||||
|
||||
namespace changesToText {
|
||||
export function getTextChangesFromChanges(changes: readonly Change[], newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] {
|
||||
return group(changes, c => c.sourceFile.path).map(changesInFile => {
|
||||
return mapDefined(group(changes, c => c.sourceFile.path), changesInFile => {
|
||||
const sourceFile = changesInFile[0].sourceFile;
|
||||
// order changes by start position
|
||||
// If the start position is the same, put the shorter range first, since an empty range (x, x) may precede (x, y) but not vice-versa.
|
||||
@@ -897,9 +897,20 @@ namespace ts.textChanges {
|
||||
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () =>
|
||||
`${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`);
|
||||
}
|
||||
const textChanges = normalized.map(c =>
|
||||
createTextChange(createTextSpanFromRange(c.range), computeNewText(c, sourceFile, newLineCharacter, formatContext, validate)));
|
||||
return { fileName: sourceFile.fileName, textChanges };
|
||||
|
||||
const textChanges = mapDefined(normalized, c => {
|
||||
const span = createTextSpanFromRange(c.range);
|
||||
const newText = computeNewText(c, sourceFile, newLineCharacter, formatContext, validate);
|
||||
|
||||
// Filter out redundant changes.
|
||||
if (span.length === newText.length && stringContainsAt(sourceFile.text, newText, span.start)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return createTextChange(span, newText);
|
||||
});
|
||||
|
||||
return textChanges.length > 0 ? { fileName: sourceFile.fileName, textChanges } : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2827,6 +2827,35 @@ namespace ts {
|
||||
return symbol.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful to check whether a string contains another string at a specific index
|
||||
* without allocating another string or traversing the entire contents of the outer string.
|
||||
*
|
||||
* This function is useful in place of either of the following:
|
||||
*
|
||||
* ```ts
|
||||
* // Allocates
|
||||
* haystack.substr(startIndex, needle.length) === needle
|
||||
*
|
||||
* // Full traversal
|
||||
* haystack.indexOf(needle, startIndex) === startIndex
|
||||
* ```
|
||||
*
|
||||
* @param haystack The string that potentially contains `needle`.
|
||||
* @param needle The string whose content might sit within `haystack`.
|
||||
* @param startIndex The index within `haystack` to start searching for `needle`.
|
||||
*/
|
||||
export function stringContainsAt(haystack: string, needle: string, startIndex: number) {
|
||||
const needleLength = needle.length;
|
||||
if (needleLength + startIndex > haystack.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < needleLength; i++) {
|
||||
if (needle.charCodeAt(i) !== haystack.charCodeAt(i + startIndex)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function startsWithUnderscore(name: string): boolean {
|
||||
return name.charCodeAt(0) === CharacterCodes._;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user