@createiq/htmldiff 1.2.0-beta.1 → 1.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/HtmlDiff.cjs +38 -14
- package/dist/HtmlDiff.cjs.map +1 -1
- package/dist/HtmlDiff.d.cts +10 -0
- package/dist/HtmlDiff.d.mts +10 -0
- package/dist/HtmlDiff.mjs +38 -14
- package/dist/HtmlDiff.mjs.map +1 -1
- package/package.json +1 -1
- package/src/HtmlDiff.ts +57 -21
- package/src/ThreeWayTable.ts +15 -1
- package/test/HtmlDiff.spec.ts +15 -0
- package/test/HtmlDiff.threeWay.spec.ts +11 -0
- package/test/HtmlDiff.threeWay.tables.spec.ts +26 -0
package/dist/HtmlDiff.cjs
CHANGED
|
@@ -1580,7 +1580,7 @@ function preprocessByContent(genesis, cpLatest, meCurrent, gTables, cTables, mTa
|
|
|
1580
1580
|
placeholderToDiff
|
|
1581
1581
|
};
|
|
1582
1582
|
}
|
|
1583
|
-
const POSITIONAL_PAIR_SIMILARITY_THRESHOLD = .
|
|
1583
|
+
const POSITIONAL_PAIR_SIMILARITY_THRESHOLD = .15;
|
|
1584
1584
|
function positionallyAligned(genesis, cpLatest, meCurrent, gTables, cTables, mTables) {
|
|
1585
1585
|
if (gTables.length !== cTables.length || cTables.length !== mTables.length) return false;
|
|
1586
1586
|
for (let i = 0; i < gTables.length; i++) {
|
|
@@ -2044,6 +2044,16 @@ var HtmlDiff = class HtmlDiff {
|
|
|
2044
2044
|
newText;
|
|
2045
2045
|
oldText;
|
|
2046
2046
|
tablePreprocessDepth = 0;
|
|
2047
|
+
/**
|
|
2048
|
+
* Tracks currently-open formatting-tag wraps. Each entry pairs the
|
|
2049
|
+
* opening tag (so a later closing tag can find its match) with the
|
|
2050
|
+
* styling info needed to RE-OPEN the wrap if an overlapping
|
|
2051
|
+
* formatting-tag close forces it to split. Without the styling info,
|
|
2052
|
+
* an overlap like `<strong>X</strong>` ↔ `<u>X</u>` produces an
|
|
2053
|
+
* unclosable wrap (the closing tag for the outer wrap arrives while
|
|
2054
|
+
* an inner wrap is still on the stack); see `insertTag`'s closing
|
|
2055
|
+
* handler for the split logic.
|
|
2056
|
+
*/
|
|
2047
2057
|
specialTagDiffStack = [];
|
|
2048
2058
|
newWords = [];
|
|
2049
2059
|
oldWords = [];
|
|
@@ -2510,38 +2520,52 @@ var HtmlDiff = class HtmlDiff {
|
|
|
2510
2520
|
if (words.length === 0) break;
|
|
2511
2521
|
const indexOfFirstNonTag = words.findIndex((x) => !Utils_default.isTag(x));
|
|
2512
2522
|
const indexLastTagInFirstTagBlock = indexOfFirstNonTag === -1 ? words.length - 1 : indexOfFirstNonTag - 1;
|
|
2513
|
-
let
|
|
2514
|
-
let
|
|
2523
|
+
let preInject = "";
|
|
2524
|
+
let postInject = "";
|
|
2515
2525
|
if (HtmlDiff.SpecialCaseOpeningTagRegex.test(words[0])) {
|
|
2516
2526
|
const tagNames = /* @__PURE__ */ new Set();
|
|
2517
2527
|
for (const word of words) if (Utils_default.isTag(word)) tagNames.add(Utils_default.getTagName(word));
|
|
2518
2528
|
const styledTagNames = Array.from(tagNames).join(" ");
|
|
2519
|
-
|
|
2520
|
-
|
|
2529
|
+
const styledCssClass = `mod ${styledTagNames}`;
|
|
2530
|
+
this.specialTagDiffStack.push({
|
|
2531
|
+
tag: words[0],
|
|
2532
|
+
styledTagNames,
|
|
2533
|
+
cssClass: styledCssClass,
|
|
2534
|
+
metadata
|
|
2535
|
+
});
|
|
2536
|
+
postInject = `<ins${Utils_default.composeTagAttributes(styledCssClass, metadata ?? {})}>`;
|
|
2521
2537
|
if (tag === HtmlDiff.DelTag) {
|
|
2522
2538
|
words.shift();
|
|
2523
2539
|
while (words.length > 0 && HtmlDiff.SpecialCaseOpeningTagRegex.test(words[0])) words.shift();
|
|
2524
2540
|
}
|
|
2525
2541
|
} else if (HtmlDiff.SpecialCaseClosingTagsSet.has(words[0].toLowerCase())) {
|
|
2526
|
-
const openingTag = this.specialTagDiffStack.length === 0 ? null : this.specialTagDiffStack.pop();
|
|
2527
2542
|
let tagIndexToCompare = indexLastTagInFirstTagBlock;
|
|
2528
2543
|
if (tag === HtmlDiff.DelTag && indexOfFirstNonTag === -1) {
|
|
2529
2544
|
if (words.slice(0, indexLastTagInFirstTagBlock + 1).some((w) => !HtmlDiff.SpecialCaseClosingTagsSet.has(w.toLowerCase()))) tagIndexToCompare = 0;
|
|
2530
2545
|
}
|
|
2531
|
-
const
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2546
|
+
const closingTagName = Utils_default.getTagName(words[tagIndexToCompare]);
|
|
2547
|
+
let matchIdx = -1;
|
|
2548
|
+
for (let i = this.specialTagDiffStack.length - 1; i >= 0; i--) if (Utils_default.getTagName(this.specialTagDiffStack[i].tag) === closingTagName) {
|
|
2549
|
+
matchIdx = i;
|
|
2550
|
+
break;
|
|
2551
|
+
}
|
|
2552
|
+
if (matchIdx >= 0) {
|
|
2553
|
+
const aboveEntries = this.specialTagDiffStack.splice(matchIdx + 1);
|
|
2554
|
+
this.specialTagDiffStack.pop();
|
|
2555
|
+
preInject = "</ins>".repeat(aboveEntries.length + 1);
|
|
2556
|
+
for (const entry of aboveEntries) {
|
|
2557
|
+
postInject += `<ins${Utils_default.composeTagAttributes(entry.cssClass, entry.metadata ?? {})}>`;
|
|
2558
|
+
this.specialTagDiffStack.push(entry);
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2536
2561
|
if (tag === HtmlDiff.DelTag) {
|
|
2537
2562
|
words.shift();
|
|
2538
2563
|
while (words.length > 0 && HtmlDiff.SpecialCaseClosingTagsSet.has(words[0].toLowerCase())) words.shift();
|
|
2539
2564
|
}
|
|
2540
2565
|
}
|
|
2541
|
-
if (words.length === 0 &&
|
|
2566
|
+
if (words.length === 0 && preInject.length === 0 && postInject.length === 0) break;
|
|
2542
2567
|
const isTagForExtraction = tag === HtmlDiff.DelTag ? (x) => Utils_default.isTag(x) && !HtmlDiff.SpecialCaseOpeningTagRegex.test(x) && !HtmlDiff.SpecialCaseClosingTagsSet.has(x.toLowerCase()) : Utils_default.isTag;
|
|
2543
|
-
|
|
2544
|
-
else this.content.push(this.extractConsecutiveWords(words, isTagForExtraction).join("") + specialCaseTagInjection);
|
|
2568
|
+
this.content.push(preInject + this.extractConsecutiveWords(words, isTagForExtraction).join("") + postInject);
|
|
2545
2569
|
if (words.length === 0) continue;
|
|
2546
2570
|
this.insertTag(tag, cssClass, words, metadata);
|
|
2547
2571
|
break;
|