Skip to content

Commit 25f5a9a

Browse files
committed
refactor: end optimize
1 parent beecc36 commit 25f5a9a

File tree

3 files changed

+162
-9
lines changed

3 files changed

+162
-9
lines changed

packages/html-diff/src/index.ts

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,20 +290,72 @@ export default class HtmlDiff {
290290
)
291291
}
292292

293-
private getMatchedBlockList(
294-
oldStart = 0,
295-
oldEnd: number = this.oldWords.length,
296-
newStart = 0,
297-
newEnd: number = this.newWords.length,
293+
private getMatchedBlockList(): MatchedBlock[] {
294+
const n1 = this.oldWords.length
295+
const n2 = this.newWords.length
296+
297+
// 1. sync from start
298+
let start: MatchedBlock | null = null
299+
let i = 0
300+
while (i < n1 && i < n2 && this.oldWords[i] === this.newWords[i]) {
301+
i++
302+
}
303+
if (i >= this.config.minMatchedSize) {
304+
start = {
305+
oldStart: 0,
306+
oldEnd: i,
307+
newStart: 0,
308+
newEnd: i,
309+
size: i,
310+
}
311+
}
312+
313+
// 2. sync from end
314+
let end: MatchedBlock | null = null
315+
let e1 = n1 - 1
316+
let e2 = n2 - 1
317+
while (i <= e1 && i <= e2 && this.oldWords[e1] === this.newWords[e2]) {
318+
e1--
319+
e2--
320+
}
321+
const size = n1 - 1 - e1
322+
if (size >= this.config.minMatchedSize) {
323+
end = {
324+
oldStart: e1 + 1,
325+
oldEnd: n1,
326+
newStart: e2 + 1,
327+
newEnd: n2,
328+
size,
329+
}
330+
}
331+
332+
const ret = this.computeMatchedBlockList(
333+
start ? i : 0,
334+
end ? e1 + 1 : n1,
335+
start ? i : 0,
336+
end ? e2 + 1 : n2,
337+
)
338+
if (start) ret.unshift(start)
339+
if (end) ret.push(end)
340+
341+
return ret
342+
}
343+
344+
// todo difflib
345+
private computeMatchedBlockList(
346+
oldStart: number,
347+
oldEnd: number,
348+
newStart: number,
349+
newEnd: number,
298350
matchedBlockList: MatchedBlock[] = [],
299351
): MatchedBlock[] {
300-
const matchBlock = this.getBestMatchedBlock(oldStart, oldEnd, newStart, newEnd)
352+
const matchBlock = this.computeBestMatchedBlock(oldStart, oldEnd, newStart, newEnd)
301353
if (!matchBlock) {
302354
return []
303355
}
304356

305357
if (oldStart < matchBlock.oldStart && newStart < matchBlock.newStart) {
306-
this.getMatchedBlockList(
358+
this.computeMatchedBlockList(
307359
oldStart,
308360
matchBlock.oldStart,
309361
newStart,
@@ -313,7 +365,7 @@ export default class HtmlDiff {
313365
}
314366
matchedBlockList.push(matchBlock)
315367
if (oldEnd > matchBlock.oldEnd && newEnd > matchBlock.newEnd) {
316-
this.getMatchedBlockList(
368+
this.computeMatchedBlockList(
317369
matchBlock.oldEnd,
318370
oldEnd,
319371
matchBlock.newEnd,
@@ -326,7 +378,7 @@ export default class HtmlDiff {
326378

327379
// find the longest matched block between old and new words
328380
// 滑动窗口 O((N+M)×min(N,M))
329-
private getBestMatchedBlock(
381+
private computeBestMatchedBlock(
330382
oldStart: number,
331383
oldEnd: number,
332384
newStart: number,

packages/html-diff/tests/__snapshots__/index.spec.ts.snap

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,62 @@ exports[`HtmlDiff > should work with basic replace 2`] = `
9696
"<div><span class="html-diff-create-text-wrapper">world</span></div>",
9797
]
9898
`;
99+
100+
exports[`HtmlDiff > should work with equal 1`] = `
101+
"<h1>hello world</h1>
102+
<p>你若安好,便是晴天</p>"
103+
`;
104+
105+
exports[`HtmlDiff > should work with equal 2`] = `
106+
[
107+
"<h1>hello world</h1>
108+
<p>你若安好,便是晴天</p>",
109+
"<h1>hello world</h1>
110+
<p>你若安好,便是晴天</p>",
111+
]
112+
`;
113+
114+
exports[`HtmlDiff > should work with equal double 1`] = `
115+
"<p>hello world</p>
116+
<p><span class="html-diff-delete-text-wrapper">你若安好,便是晴天</span><span class="html-diff-create-text-wrapper">今天天气很不错</span></p>
117+
<p>你的微笑总是让我为你着迷</p>"
118+
`;
119+
120+
exports[`HtmlDiff > should work with equal double 2`] = `
121+
[
122+
"<p data-seq="1">hello world</p>
123+
<p data-seq="2"><span class="html-diff-delete-text-wrapper">你若安好,便是晴天</span></p>
124+
<p data-seq="3">你的微笑总是让我为你着迷</p>",
125+
"<p data-seq="1">hello world</p>
126+
<p data-seq="2"><span class="html-diff-create-text-wrapper">今天天气很不错</span></p>
127+
<p data-seq="3">你的微笑总是让我为你着迷</p>",
128+
]
129+
`;
130+
131+
exports[`HtmlDiff > should work with equal end 1`] = `
132+
"<p>你<span class="html-diff-delete-text-wrapper">有一双会说话的眼睛</span><span class="html-diff-create-text-wrapper">的微笑总是让我为你着迷</span></p>
133+
<p>你若安好,便是晴天</p>"
134+
`;
135+
136+
exports[`HtmlDiff > should work with equal end 2`] = `
137+
[
138+
"<p data-seq="1">你<span class="html-diff-delete-text-wrapper">有一双会说话的眼睛</span></p>
139+
<p data-seq="2">你若安好,便是晴天</p>",
140+
"<p data-seq="1">你<span class="html-diff-create-text-wrapper">的微笑总是让我为你着迷</span></p>
141+
<p data-seq="2">你若安好,便是晴天</p>",
142+
]
143+
`;
144+
145+
exports[`HtmlDiff > should work with equal start 1`] = `
146+
"<p>hello world</p>
147+
<p><span class="html-diff-delete-text-wrapper">你若安好,便是晴天</span><span class="html-diff-create-text-wrapper">今天天气很不错</span></p>"
148+
`;
149+
150+
exports[`HtmlDiff > should work with equal start 2`] = `
151+
[
152+
"<p data-seq="1">hello world</p>
153+
<p data-seq="2"><span class="html-diff-delete-text-wrapper">你若安好,便是晴天</span></p>",
154+
"<p data-seq="1">hello world</p>
155+
<p data-seq="2"><span class="html-diff-create-text-wrapper">今天天气很不错</span></p>",
156+
]
157+
`;

packages/html-diff/tests/index.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,48 @@ describe('HtmlDiff', () => {
2626
expect(diff.getSideBySideContents()).toMatchSnapshot()
2727
})
2828

29+
it('should work with equal', function () {
30+
const oldHtml = `<h1>hello world</h1>
31+
<p>你若安好,便是晴天</p>`
32+
const newHtml = `<h1>hello world</h1>
33+
<p>你若安好,便是晴天</p>`
34+
const diff = new HtmlDiff(oldHtml, newHtml)
35+
expect(diff.getUnifiedContent()).toMatchSnapshot()
36+
expect(diff.getSideBySideContents()).toMatchSnapshot()
37+
})
38+
39+
it('should work with equal start', function () {
40+
const oldHtml = `<p>hello world</p>
41+
<p>你若安好,便是晴天</p>`
42+
const newHtml = `<p>hello world</p>
43+
<p>今天天气很不错</p>`
44+
const diff = new HtmlDiff(oldHtml, newHtml)
45+
expect(diff.getUnifiedContent()).toMatchSnapshot()
46+
expect(diff.getSideBySideContents()).toMatchSnapshot()
47+
})
48+
49+
it('should work with equal end', function () {
50+
const oldHtml = `<p>你有一双会说话的眼睛</p>
51+
<p>你若安好,便是晴天</p>`
52+
const newHtml = `<p>你的微笑总是让我为你着迷</p>
53+
<p>你若安好,便是晴天</p>`
54+
const diff = new HtmlDiff(oldHtml, newHtml)
55+
expect(diff.getUnifiedContent()).toMatchSnapshot()
56+
expect(diff.getSideBySideContents()).toMatchSnapshot()
57+
})
58+
59+
it('should work with equal double', function () {
60+
const oldHtml = `<p>hello world</p>
61+
<p>你若安好,便是晴天</p>
62+
<p>你的微笑总是让我为你着迷</p>`
63+
const newHtml = `<p>hello world</p>
64+
<p>今天天气很不错</p>
65+
<p>你的微笑总是让我为你着迷</p>`
66+
const diff = new HtmlDiff(oldHtml, newHtml)
67+
expect(diff.getUnifiedContent()).toMatchSnapshot()
68+
expect(diff.getSideBySideContents()).toMatchSnapshot()
69+
})
70+
2971
it('should work sample 1', function () {
3072
const oldHtml = `<div>hello world</div>`
3173
const newHtml = `<h1>You got a dream. You gotta protect it.</h1>`

0 commit comments

Comments
 (0)