v-code-diff 1.7.2 → 1.9.0
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/README.md +59 -44
- package/dist/v2/index.cjs.js +16 -14
- package/dist/v2/index.es.js +1065 -966
- package/dist/v2/index.umd.js +16 -14
- package/dist/v2.7/index.cjs.js +18 -16
- package/dist/v2.7/index.es.js +1295 -1233
- package/dist/v2.7/index.umd.js +18 -16
- package/dist/v3/index.cjs.js +18 -16
- package/dist/v3/index.es.js +1664 -1577
- package/dist/v3/index.umd.js +18 -16
- package/package.json +17 -14
- package/scripts/{postinstall.js → postinstall.cjs} +1 -2
- package/scripts/{utils.js → utils.cjs} +0 -2
- package/src/CodeDiff.vue +41 -16
- package/src/style.scss +15 -4
- package/src/types.ts +2 -0
- package/src/utils.ts +44 -13
- package/src/var.scss +541 -73
- package/types/index.d.ts +5 -4
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "v-code-diff",
|
|
3
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.9.0",
|
|
4
5
|
"description": "template component for vue-demi, can dev and build",
|
|
6
|
+
"license": "MIT",
|
|
5
7
|
"exports": {
|
|
6
8
|
".": {
|
|
7
9
|
"types": "./types/index.d.ts",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
+
"import": "./dist/index.es.js",
|
|
11
|
+
"require": "./dist/index.cjs.js"
|
|
10
12
|
}
|
|
11
13
|
},
|
|
12
14
|
"main": "dist/index.cjs",
|
|
13
15
|
"module": "dist/index.es.js",
|
|
14
16
|
"types": "./types/index.d.ts",
|
|
15
17
|
"files": [
|
|
16
|
-
"scripts",
|
|
17
18
|
"dist",
|
|
19
|
+
"scripts",
|
|
18
20
|
"src",
|
|
19
21
|
"types"
|
|
20
22
|
],
|
|
@@ -34,8 +36,7 @@
|
|
|
34
36
|
"dev:demo": "vue-demi-switch 3 vue3 && pnpm --filter demo dev",
|
|
35
37
|
"lint": "eslint .",
|
|
36
38
|
"lint:fix": "eslint . --ext .vue,.js,.jsx,.ts,.tsx,json --fix --ignore-path .gitignore",
|
|
37
|
-
"postinstall": "node scripts/postinstall.
|
|
38
|
-
"prepublishOnly": "npm run build",
|
|
39
|
+
"postinstall": "node scripts/postinstall.cjs",
|
|
39
40
|
"release": "bumpp --commit --no-push --tag && npm publish"
|
|
40
41
|
},
|
|
41
42
|
"peerDependencies": {
|
|
@@ -48,25 +49,27 @@
|
|
|
48
49
|
}
|
|
49
50
|
},
|
|
50
51
|
"dependencies": {
|
|
51
|
-
"diff": "^5.
|
|
52
|
+
"diff": "^5.1.0",
|
|
52
53
|
"diff-match-patch": "^1.0.5",
|
|
53
|
-
"highlight.js": "^11.
|
|
54
|
-
"vue-demi": "^0.
|
|
54
|
+
"highlight.js": "^11.9.0",
|
|
55
|
+
"vue-demi": "^0.14.6"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
|
-
"@antfu/eslint-config": "^
|
|
58
|
+
"@antfu/eslint-config": "^2.4.5",
|
|
58
59
|
"@types/diff": "^5.0.0",
|
|
59
60
|
"@types/diff-match-patch": "^1.0.32",
|
|
60
61
|
"@types/node": "^18.11.18",
|
|
62
|
+
"@unocss/eslint-plugin": "^0.58.0",
|
|
63
|
+
"@vueuse/core": "^10.7.0",
|
|
61
64
|
"bumpp": "^8.2.1",
|
|
62
|
-
"eslint": "^8.
|
|
65
|
+
"eslint": "^8.55.0",
|
|
63
66
|
"npm-run-all": "^4.1.5",
|
|
64
67
|
"rimraf": "^3.0.2",
|
|
65
|
-
"sass": "^1.
|
|
68
|
+
"sass": "^1.69.5",
|
|
66
69
|
"typescript": "~4.7.4",
|
|
67
|
-
"vite": "^4.
|
|
70
|
+
"vite": "^4.5.1",
|
|
68
71
|
"vite-plugin-css-injected-by-js": "^2.4.0",
|
|
69
|
-
"vue": "^3.3.
|
|
72
|
+
"vue": "^3.3.11",
|
|
70
73
|
"vue-tsc": "^0.40.13",
|
|
71
74
|
"vue2": "npm:vue@2",
|
|
72
75
|
"vue3": "npm:vue@3"
|
package/src/CodeDiff.vue
CHANGED
|
@@ -5,7 +5,6 @@ import UnifiedViewer from './unified/UnifiedViewer.vue'
|
|
|
5
5
|
import SplitViewer from './split/SplitViewer.vue'
|
|
6
6
|
|
|
7
7
|
import './style.scss'
|
|
8
|
-
import 'highlight.js/scss/vs.scss'
|
|
9
8
|
|
|
10
9
|
interface Props {
|
|
11
10
|
newString: string
|
|
@@ -18,16 +17,12 @@ interface Props {
|
|
|
18
17
|
noDiffLineFeed?: boolean
|
|
19
18
|
maxHeight?: string
|
|
20
19
|
filename?: string
|
|
20
|
+
newFilename?: string
|
|
21
21
|
hideHeader?: boolean
|
|
22
22
|
hideStat?: boolean
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
stat: {
|
|
27
|
-
isChanged: boolean
|
|
28
|
-
addNum: number
|
|
29
|
-
delNum: number
|
|
30
|
-
}
|
|
23
|
+
theme?: 'light' | 'dark'
|
|
24
|
+
// Give a pattern to ignore matching lines eg: '(time|token)'
|
|
25
|
+
ignoreMatchingLines?: string
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -39,14 +34,25 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
39
34
|
noDiffLineFeed: false,
|
|
40
35
|
maxHeight: undefined,
|
|
41
36
|
filename: undefined,
|
|
37
|
+
newFilename: undefined,
|
|
42
38
|
hideHeader: false,
|
|
43
39
|
hideStat: false,
|
|
40
|
+
theme: 'light',
|
|
41
|
+
ignoreMatchingLines: undefined,
|
|
44
42
|
})
|
|
45
43
|
|
|
46
44
|
const emits = defineEmits<{
|
|
47
45
|
(e: 'diff', diffResult: DiffResult): void
|
|
48
46
|
}>()
|
|
49
47
|
|
|
48
|
+
interface DiffResult {
|
|
49
|
+
stat: {
|
|
50
|
+
isChanged: boolean
|
|
51
|
+
addNum: number
|
|
52
|
+
delNum: number
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
const isUnifiedViewer = computed(() => props.outputFormat === 'line-by-line')
|
|
51
57
|
|
|
52
58
|
const oldString = computed(() => {
|
|
@@ -64,8 +70,8 @@ const newString = computed(() => {
|
|
|
64
70
|
|
|
65
71
|
const raw = computed(() =>
|
|
66
72
|
isUnifiedViewer.value
|
|
67
|
-
? createUnifiedDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context)
|
|
68
|
-
: createSplitDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context),
|
|
73
|
+
? createUnifiedDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context, props.ignoreMatchingLines)
|
|
74
|
+
: createSplitDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context, props.ignoreMatchingLines),
|
|
69
75
|
)
|
|
70
76
|
const diffChange = ref(raw.value)
|
|
71
77
|
const isNotChanged = computed(() => diffChange.value.stat.additionsNum === 0 && diffChange.value.stat.deletionsNum === 0)
|
|
@@ -83,13 +89,32 @@ watch(() => props, () => {
|
|
|
83
89
|
</script>
|
|
84
90
|
|
|
85
91
|
<template>
|
|
86
|
-
<div class="code-diff-view" :style="{ maxHeight }">
|
|
92
|
+
<div class="code-diff-view" :theme="theme" :style="{ maxHeight }">
|
|
87
93
|
<div v-if="!hideHeader" class="file-header">
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
<!-- line by line -->
|
|
95
|
+
<div v-if="isUnifiedViewer" class="file-info">
|
|
96
|
+
<span>
|
|
97
|
+
<div class="info-left">{{ filename }}</div>
|
|
98
|
+
<div class="info-left">{{ newFilename }}</div>
|
|
99
|
+
</span>
|
|
90
100
|
<span v-if="!hideStat" class="diff-stat">
|
|
91
|
-
<
|
|
92
|
-
|
|
101
|
+
<slot name="stat" :stat="diffChange.stat">
|
|
102
|
+
<span class="diff-stat-added">+{{ diffChange.stat.additionsNum }} additions</span>
|
|
103
|
+
<span class="diff-stat-deleted">-{{ diffChange.stat.deletionsNum }} deletions</span>
|
|
104
|
+
</slot>
|
|
105
|
+
</span>
|
|
106
|
+
</div>
|
|
107
|
+
<!-- side by side -->
|
|
108
|
+
<div v-else class="file-info">
|
|
109
|
+
<span class="info-left">{{ filename }}</span>
|
|
110
|
+
<span class="info-right">
|
|
111
|
+
<span style="margin-left: 20px;">{{ newFilename }}</span>
|
|
112
|
+
<span v-if="!hideStat" class="diff-stat">
|
|
113
|
+
<slot name="stat" :stat="diffChange.stat">
|
|
114
|
+
<span class="diff-stat-added">+{{ diffChange.stat.additionsNum }} additions</span>
|
|
115
|
+
<span class="diff-stat-deleted">-{{ diffChange.stat.deletionsNum }} deletions</span>
|
|
116
|
+
</slot>
|
|
117
|
+
</span>
|
|
93
118
|
</span>
|
|
94
119
|
</div>
|
|
95
120
|
</div>
|
package/src/style.scss
CHANGED
|
@@ -28,16 +28,27 @@
|
|
|
28
28
|
margin-left: 8px;
|
|
29
29
|
height: 24px;
|
|
30
30
|
|
|
31
|
-
.
|
|
32
|
-
font-size: 13px;
|
|
31
|
+
.info-left {
|
|
33
32
|
color: var(--color-fg-default);
|
|
34
33
|
}
|
|
34
|
+
.info-right {
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
align-items: center;
|
|
38
|
+
width: 50%;
|
|
39
|
+
}
|
|
35
40
|
.diff-stat {
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 8px;
|
|
36
44
|
.diff-stat-added {
|
|
37
|
-
color: var(--color-diffstat-addition-bg)
|
|
45
|
+
color: var(--color-diffstat-addition-bg);
|
|
38
46
|
}
|
|
39
47
|
.diff-stat-deleted {
|
|
40
|
-
color: var(--color-danger-emphasis)
|
|
48
|
+
color: var(--color-danger-emphasis);
|
|
49
|
+
}
|
|
50
|
+
.diff-stat-ignored {
|
|
51
|
+
color: var(--color-fg-subtle);
|
|
41
52
|
}
|
|
42
53
|
}
|
|
43
54
|
}
|
package/src/types.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -135,19 +135,34 @@ function getHighlightCode(language: string, code: string) {
|
|
|
135
135
|
.replace(new RegExp(closeEntity, 'g'), '</span>')
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
function calcDiffStat(changes: Change[]): DiffStat {
|
|
138
|
+
function calcDiffStat(changes: Change[], ignoreRegex?: RegExp): DiffStat {
|
|
139
139
|
const count = (s: string, c: string) => (s.match(new RegExp(c, 'g')) || []).length
|
|
140
|
+
const ignoreCount = (lines: string[]) => lines.filter(line => ignoreRegex?.test(line)).length
|
|
140
141
|
|
|
141
142
|
let additionsNum = 0
|
|
142
143
|
let deletionsNum = 0
|
|
144
|
+
let ignoreAdditionsNum = 0
|
|
145
|
+
let ignoreDeletionsNum = 0
|
|
143
146
|
for (const change of changes) {
|
|
144
|
-
if (change.added)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
if (change.added) {
|
|
148
|
+
const ignoreNum = ignoreCount(change.value.trim().split('\n'))
|
|
149
|
+
additionsNum += count(change.value.trim(), '\n') + 1 - ignoreNum
|
|
150
|
+
ignoreAdditionsNum += ignoreNum
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
if (change.removed) {
|
|
154
|
+
const ignoreNum = ignoreCount(change.value.trim().split('\n'))
|
|
155
|
+
deletionsNum += count(change.value.trim(), '\n') + 1 - ignoreNum
|
|
156
|
+
ignoreDeletionsNum += ignoreNum
|
|
157
|
+
continue
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
additionsNum,
|
|
162
|
+
deletionsNum,
|
|
163
|
+
ignoreAdditionsNum,
|
|
164
|
+
ignoreDeletionsNum,
|
|
149
165
|
}
|
|
150
|
-
return { additionsNum, deletionsNum }
|
|
151
166
|
}
|
|
152
167
|
|
|
153
168
|
export function createSplitDiff(
|
|
@@ -156,10 +171,12 @@ export function createSplitDiff(
|
|
|
156
171
|
language = 'plaintext',
|
|
157
172
|
diffStyle = 'word',
|
|
158
173
|
context = 10,
|
|
174
|
+
ignoreMatchingLines?: string,
|
|
159
175
|
): SplitViewerChange {
|
|
160
176
|
const newEmptySplitDiff = (): DiffLine => ({ type: DiffType.EMPTY })
|
|
161
177
|
const newSplitDiff = (type: DiffType, num: number, code: string): DiffLine => ({ type, num, code })
|
|
162
178
|
const changes = diffLines(oldString, newString)
|
|
179
|
+
const ignoreRegex = ignoreMatchingLines ? new RegExp(ignoreMatchingLines) : undefined
|
|
163
180
|
|
|
164
181
|
let delNum = 0
|
|
165
182
|
let addNum = 0
|
|
@@ -169,7 +186,7 @@ export function createSplitDiff(
|
|
|
169
186
|
const result: SplitViewerChange = {
|
|
170
187
|
changes: rawChanges,
|
|
171
188
|
collector: [],
|
|
172
|
-
stat: calcDiffStat(changes),
|
|
189
|
+
stat: calcDiffStat(changes, ignoreRegex),
|
|
173
190
|
}
|
|
174
191
|
|
|
175
192
|
for (let i = 0; i < changes.length; i++) {
|
|
@@ -257,13 +274,17 @@ export function createSplitDiff(
|
|
|
257
274
|
const leftLine = curLines.length === nextLines.length ? renderWords(nextLine, curLine, diffStyle) : curLine
|
|
258
275
|
const rightLine = curLines.length === nextLines.length ? renderWords(curLine, nextLine, diffStyle) : nextLine
|
|
259
276
|
|
|
277
|
+
// 忽略匹配的行等价于相等
|
|
278
|
+
const leftDiffType = ignoreRegex?.test(curLine) ? DiffType.EQUAL : DiffType.DELETE
|
|
279
|
+
const rightDiffType = ignoreRegex?.test(nextLine) ? DiffType.EQUAL : DiffType.ADD
|
|
280
|
+
|
|
260
281
|
const left
|
|
261
282
|
= j < cur.count!
|
|
262
|
-
? newSplitDiff(
|
|
283
|
+
? newSplitDiff(leftDiffType, delNum, getHighlightCode(language, leftLine))
|
|
263
284
|
: newEmptySplitDiff()
|
|
264
285
|
const right
|
|
265
286
|
= j < next.count!
|
|
266
|
-
? newSplitDiff(
|
|
287
|
+
? newSplitDiff(rightDiffType, addNum, getHighlightCode(language, rightLine))
|
|
267
288
|
: newEmptySplitDiff()
|
|
268
289
|
|
|
269
290
|
rawChanges.push({ left, right })
|
|
@@ -341,8 +362,10 @@ export function createUnifiedDiff(
|
|
|
341
362
|
language = 'plaintext',
|
|
342
363
|
diffStyle = 'word',
|
|
343
364
|
context = 10,
|
|
365
|
+
ignoreMatchingLines?: string,
|
|
344
366
|
): UnifiedViewerChange {
|
|
345
367
|
const changes = diffLines(oldString, newString)
|
|
368
|
+
const ignoreRegex = ignoreMatchingLines ? new RegExp(ignoreMatchingLines) : undefined
|
|
346
369
|
|
|
347
370
|
let delNum = 0
|
|
348
371
|
let addNum = 0
|
|
@@ -352,7 +375,7 @@ export function createUnifiedDiff(
|
|
|
352
375
|
const result: UnifiedViewerChange = {
|
|
353
376
|
changes: rawChanges,
|
|
354
377
|
collector: [],
|
|
355
|
-
stat: calcDiffStat(changes),
|
|
378
|
+
stat: calcDiffStat(changes, ignoreRegex),
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
for (let i = 0; i < changes.length; i++) {
|
|
@@ -414,7 +437,11 @@ export function createUnifiedDiff(
|
|
|
414
437
|
delNum++
|
|
415
438
|
|
|
416
439
|
const code = getHighlightCode(language, renderWords(nextLine, curLine, diffStyle))
|
|
417
|
-
rawChanges.push({
|
|
440
|
+
rawChanges.push({
|
|
441
|
+
type: ignoreRegex?.test(curLine) ? DiffType.EQUAL : DiffType.DELETE,
|
|
442
|
+
code,
|
|
443
|
+
delNum,
|
|
444
|
+
})
|
|
418
445
|
}
|
|
419
446
|
|
|
420
447
|
for (let j = 0; j < nextLines.length; j++) {
|
|
@@ -423,7 +450,11 @@ export function createUnifiedDiff(
|
|
|
423
450
|
addNum++
|
|
424
451
|
|
|
425
452
|
const code = getHighlightCode(language, renderWords(curLine, nextLine, diffStyle))
|
|
426
|
-
rawChanges.push({
|
|
453
|
+
rawChanges.push({
|
|
454
|
+
type: ignoreRegex?.test(nextLine) ? DiffType.EQUAL : DiffType.ADD,
|
|
455
|
+
code,
|
|
456
|
+
addNum,
|
|
457
|
+
})
|
|
427
458
|
}
|
|
428
459
|
|
|
429
460
|
skip = true
|