From 6df62788a1431646bdc427df0f316b508c4b88d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 30 Jun 2020 11:00:36 +0200 Subject: [PATCH] Handle overlapping replacements --- .../changesets/textSplitAndReplace.test.ts | 33 +++++++++++++++++++ .../changesets/textSplitAndReplace.ts | 13 +++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.test.ts b/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.test.ts index 641ff2cb9b..778236ee6d 100644 --- a/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.test.ts +++ b/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.test.ts @@ -98,4 +98,37 @@ describe("text split and replace", () => { expect(result[7]).toStrictEqual({ text: "We are going to die." }); expect(result[8]).toStrictEqual({ text: "“" }); }); + + it("should ignore conflicting replacements", () => { + const result = textSplitAndReplace( + "'So this is it,' said Arthur, 'We are going to die.'", + [ + { textToReplace: "said Arthur", replacement: { text: "to be replaced" } }, + { textToReplace: " said", replacement: { text: "to be ignored 1" }, replaceAll: true }, + { textToReplace: "d A", replacement: { text: "to be ignored 2" }, replaceAll: true }, + { textToReplace: "Arthur,", replacement: { text: "to be ignored 3" }, replaceAll: true } + ], + testWrapper + ); + expect(result).toHaveLength(3); + expect(result[0]).toStrictEqual({ text: "'So this is it,' " }); + expect(result[1]).toStrictEqual({ text: "to be replaced" }); + expect(result[2]).toStrictEqual({ text: ", 'We are going to die.'" }); + }); + + it("should replace adjacent texts", () => { + const result = textSplitAndReplace( + "'So this is it,' said Arthur, 'We are going to die.'", + [ + { textToReplace: "'So this is it,'", replacement: { text: "one" } }, + { textToReplace: " said Arthur, ", replacement: { text: "two" } }, + { textToReplace: "'We are going to die.'", replacement: { text: "three" } } + ], + testWrapper + ); + expect(result).toHaveLength(3); + expect(result[0]).toStrictEqual({ text: "one" }); + expect(result[1]).toStrictEqual({ text: "two" }); + expect(result[2]).toStrictEqual({ text: "three" }); + }); }); diff --git a/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.ts b/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.ts index 1f4bcf3fad..c94f85f34c 100644 --- a/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.ts +++ b/scm-ui/ui-webapp/src/repos/components/changesets/textSplitAndReplace.ts @@ -34,6 +34,14 @@ type PartToReplace = { replacement: T; }; +function hasConflict(alreadyFoundReplacements: PartToReplace[], newReplacement: PartToReplace) { + return !!alreadyFoundReplacements.find( + existing => + (existing.start <= newReplacement.start && existing.start + existing.length > newReplacement.start) || + (newReplacement.start <= existing.start && newReplacement.start + newReplacement.length > existing.start) + ); +} + export default function textSplitAndReplace( text: string, replacements: Replacement[], @@ -47,7 +55,10 @@ export default function textSplitAndReplace( const start = text.indexOf(replacement.textToReplace, lastIndex); if (start >= 0) { const length = replacement.textToReplace.length; - partsToReplace.push({ start, length, replacement: replacement.replacement }); + const newReplacement = { start, length, replacement: replacement.replacement }; + if (!hasConflict(partsToReplace, newReplacement)) { + partsToReplace.push(newReplacement); + } lastIndex = start + length; } else { lastIndex = -1;