v-code-diff 1.14.0 → 1.15.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 +50 -55
- package/dist/v2/index.cjs +20 -18
- package/dist/v2/index.es.js +736 -685
- package/dist/v2/index.umd.js +22 -20
- package/dist/v2.7/index.cjs +15 -13
- package/dist/v2.7/index.es.js +222 -190
- package/dist/v2.7/index.umd.js +15 -13
- package/dist/v3/index.cjs +27 -25
- package/dist/v3/index.es.js +1564 -1531
- package/dist/v3/index.umd.js +27 -25
- package/package.json +4 -2
- package/src/CodeDiff.vue +8 -4
- package/src/split/SplitLine.vue +20 -2
- package/src/split/SplitViewer.vue +12 -2
- package/src/types.ts +7 -0
- package/src/unified/UnifiedLine.vue +21 -4
- package/src/unified/UnifiedViewer.vue +12 -2
- package/src/utils.ts +5 -0
- package/types/index.d.ts +69 -12
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "v-code-diff",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.15.0",
|
|
5
5
|
"packageManager": "pnpm@11.2.2",
|
|
6
6
|
"description": "A code diff viewer for Vue 2.6, Vue 2.7, and Vue 3",
|
|
7
7
|
"license": "MIT",
|
|
@@ -56,7 +56,9 @@
|
|
|
56
56
|
"postinstall": "node scripts/postinstall.cjs",
|
|
57
57
|
"prepublishOnly": "npm run build",
|
|
58
58
|
"release": "bumpp --commit --no-push --tag && npm publish",
|
|
59
|
-
"test": "
|
|
59
|
+
"test": "run-s test:unit test:types",
|
|
60
|
+
"test:types": "tsc --noEmit --skipLibCheck --module ESNext --moduleResolution node --target ES2020 tests/types.test-d.ts",
|
|
61
|
+
"test:unit": "vitest run"
|
|
60
62
|
},
|
|
61
63
|
"peerDependencies": {
|
|
62
64
|
"@vue/composition-api": "^1.4.9",
|
package/src/CodeDiff.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, shallowRef, watch } from 'vue-demi'
|
|
3
|
+
import type { DiffChangeClickEvent } from './types'
|
|
3
4
|
import { createSplitDiff, createUnifiedDiff } from './utils'
|
|
4
5
|
import UnifiedViewer from './unified/UnifiedViewer.vue'
|
|
5
6
|
import SplitViewer from './split/SplitViewer.vue'
|
|
@@ -23,6 +24,7 @@ interface Props {
|
|
|
23
24
|
newFilename?: string
|
|
24
25
|
hideHeader?: boolean
|
|
25
26
|
hideStat?: boolean
|
|
27
|
+
hideNavigation?: boolean
|
|
26
28
|
theme?: 'light' | 'dark'
|
|
27
29
|
// Give a pattern to ignore matching lines eg: '(time|token)'
|
|
28
30
|
ignoreMatchingLines?: string
|
|
@@ -41,12 +43,14 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
41
43
|
newFilename: undefined,
|
|
42
44
|
hideHeader: false,
|
|
43
45
|
hideStat: false,
|
|
46
|
+
hideNavigation: false,
|
|
44
47
|
theme: 'light',
|
|
45
48
|
ignoreMatchingLines: undefined,
|
|
46
49
|
})
|
|
47
50
|
|
|
48
51
|
const emits = defineEmits<{
|
|
49
52
|
(e: 'diff', diffResult: DiffResult): void
|
|
53
|
+
(e: 'change-click', payload: DiffChangeClickEvent): void
|
|
50
54
|
}>()
|
|
51
55
|
|
|
52
56
|
interface DiffResult {
|
|
@@ -132,7 +136,7 @@ watch(() => props, () => {
|
|
|
132
136
|
<div class="info-left">{{ filename }}</div>
|
|
133
137
|
<div class="info-left">{{ newFilename }}</div>
|
|
134
138
|
</span>
|
|
135
|
-
<span class="diff-commandbar">
|
|
139
|
+
<span v-if="!hideNavigation" class="diff-commandbar">
|
|
136
140
|
<button class="command-item-button" title="Next Change" @click="goToNextDiff">
|
|
137
141
|
<DownArrowIcon />
|
|
138
142
|
</button>
|
|
@@ -152,7 +156,7 @@ watch(() => props, () => {
|
|
|
152
156
|
<span class="info-left">{{ filename }}</span>
|
|
153
157
|
<span class="info-right">
|
|
154
158
|
<span style="margin-left: 20px;">{{ newFilename }}</span>
|
|
155
|
-
<span class="diff-commandbar">
|
|
159
|
+
<span v-if="!hideNavigation" class="diff-commandbar">
|
|
156
160
|
<button class="command-item-button" title="Next Change" @click="goToNextDiff">
|
|
157
161
|
<DownArrowIcon />
|
|
158
162
|
</button>
|
|
@@ -169,8 +173,8 @@ watch(() => props, () => {
|
|
|
169
173
|
</span>
|
|
170
174
|
</div>
|
|
171
175
|
</div>
|
|
172
|
-
<UnifiedViewer v-if="isUnifiedViewer" :diff-change="diffChange" :language="language" />
|
|
173
|
-
<SplitViewer v-else :diff-change="diffChange" :language="language" />
|
|
176
|
+
<UnifiedViewer v-if="isUnifiedViewer" :diff-change="diffChange" :language="language" @change-click="emits('change-click', $event)" />
|
|
177
|
+
<SplitViewer v-else :diff-change="diffChange" :language="language" @change-click="emits('change-click', $event)" />
|
|
174
178
|
</div>
|
|
175
179
|
</template>
|
|
176
180
|
|
package/src/split/SplitLine.vue
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { DiffType } from '../types'
|
|
3
|
-
import type { SplitLineChange } from '../types'
|
|
3
|
+
import type { DiffChangeClickEvent, DiffLine, SplitLineChange } from '../types'
|
|
4
4
|
|
|
5
5
|
defineProps<{
|
|
6
6
|
splitLine: SplitLineChange
|
|
7
7
|
}>()
|
|
8
8
|
|
|
9
|
-
const emit = defineEmits
|
|
9
|
+
const emit = defineEmits<{
|
|
10
|
+
(e: 'expand', line: SplitLineChange): void
|
|
11
|
+
(e: 'change-click', payload: DiffChangeClickEvent): void
|
|
12
|
+
}>()
|
|
10
13
|
|
|
11
14
|
function getCodeMarker(type: DiffType) {
|
|
12
15
|
if (type === DiffType.DELETE)
|
|
@@ -27,6 +30,20 @@ function onSplitLineMousedown(event: MouseEvent, side: 'left' | 'right') {
|
|
|
27
30
|
for (const el of leftElements)
|
|
28
31
|
el.classList.toggle('no-select', side === 'right')
|
|
29
32
|
}
|
|
33
|
+
|
|
34
|
+
function onChangeClick(event: MouseEvent, line: DiffLine, side: 'old' | 'new') {
|
|
35
|
+
if (line.type !== DiffType.ADD && line.type !== DiffType.DELETE)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
// Vue 2 DOM templates require kebab-case event names.
|
|
39
|
+
// eslint-disable-next-line vue/custom-event-name-casing
|
|
40
|
+
emit('change-click', {
|
|
41
|
+
side,
|
|
42
|
+
type: line.type,
|
|
43
|
+
lineNumber: line.num!,
|
|
44
|
+
event,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
30
47
|
</script>
|
|
31
48
|
|
|
32
49
|
<template>
|
|
@@ -71,6 +88,7 @@ function onSplitLineMousedown(event: MouseEvent, side: 'left' | 'right') {
|
|
|
71
88
|
'split-side-right': index === 1,
|
|
72
89
|
}"
|
|
73
90
|
@mousedown="onSplitLineMousedown($event, index === 0 ? 'left' : 'right')"
|
|
91
|
+
@click="onChangeClick($event, line, index === 0 ? 'old' : 'new')"
|
|
74
92
|
>
|
|
75
93
|
<span
|
|
76
94
|
class="blob-code-inner blob-code-marker" :data-code-marker="getCodeMarker(line.type)"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, shallowRef, watch } from 'vue-demi'
|
|
3
|
-
import type { SplitLineChange, SplitViewerChange } from '../types'
|
|
3
|
+
import type { DiffChangeClickEvent, SplitLineChange, SplitViewerChange } from '../types'
|
|
4
4
|
import { RENDER_BATCH_SIZE, highlightSplitLine } from '../utils'
|
|
5
5
|
import SplitLine from './SplitLine.vue'
|
|
6
6
|
|
|
@@ -9,6 +9,10 @@ const props = defineProps<{
|
|
|
9
9
|
language: string
|
|
10
10
|
}>()
|
|
11
11
|
|
|
12
|
+
const emit = defineEmits<{
|
|
13
|
+
(e: 'change-click', payload: DiffChangeClickEvent): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
12
16
|
const renderLimit = ref(RENDER_BATCH_SIZE)
|
|
13
17
|
const visibleChanges = shallowRef(props.diffChange.changes.filter(line => !line.hide || line.hideIndex !== undefined))
|
|
14
18
|
const renderedChanges = computed(() => visibleChanges.value.slice(0, renderLimit.value))
|
|
@@ -50,7 +54,13 @@ function loadMore() {
|
|
|
50
54
|
<col>
|
|
51
55
|
</colgroup>
|
|
52
56
|
<tbody>
|
|
53
|
-
<SplitLine
|
|
57
|
+
<SplitLine
|
|
58
|
+
v-for="(item, index) in renderedChanges"
|
|
59
|
+
:key="index"
|
|
60
|
+
:split-line="item"
|
|
61
|
+
@expand="expandHandler"
|
|
62
|
+
@change-click="emit('change-click', $event)"
|
|
63
|
+
/>
|
|
54
64
|
<tr v-if="remainingLines">
|
|
55
65
|
<td class="blob-code blob-code-hunk load-more" colspan="4">
|
|
56
66
|
<button class="load-more-button" type="button" @click="loadMore">
|
package/src/types.ts
CHANGED
|
@@ -21,6 +21,13 @@ export interface DiffLine {
|
|
|
21
21
|
num?: number
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface DiffChangeClickEvent {
|
|
25
|
+
side: 'old' | 'new'
|
|
26
|
+
type: DiffType.ADD | DiffType.DELETE
|
|
27
|
+
lineNumber: number
|
|
28
|
+
event: MouseEvent
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
export interface SplitLineChange {
|
|
25
32
|
fold?: boolean
|
|
26
33
|
highlighted?: boolean
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import type { UnifiedLineChange } from '../types'
|
|
2
|
+
import type { DiffChangeClickEvent, UnifiedLineChange } from '../types'
|
|
3
3
|
import { DiffType } from '../types'
|
|
4
4
|
|
|
5
|
-
defineProps<{
|
|
5
|
+
const props = defineProps<{
|
|
6
6
|
line: UnifiedLineChange
|
|
7
7
|
}>()
|
|
8
|
-
const emit = defineEmits
|
|
8
|
+
const emit = defineEmits<{
|
|
9
|
+
(e: 'expand', line: UnifiedLineChange): void
|
|
10
|
+
(e: 'change-click', payload: DiffChangeClickEvent): void
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
function onChangeClick(event: MouseEvent) {
|
|
14
|
+
if (props.line.type !== DiffType.ADD && props.line.type !== DiffType.DELETE)
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
// Vue 2 DOM templates require kebab-case event names.
|
|
18
|
+
// eslint-disable-next-line vue/custom-event-name-casing
|
|
19
|
+
emit('change-click', {
|
|
20
|
+
side: props.line.type === DiffType.DELETE ? 'old' : 'new',
|
|
21
|
+
type: props.line.type,
|
|
22
|
+
lineNumber: props.line.type === DiffType.DELETE ? props.line.delNum! : props.line.addNum!,
|
|
23
|
+
event,
|
|
24
|
+
})
|
|
25
|
+
}
|
|
9
26
|
|
|
10
27
|
function getCodeMarker(type: DiffType) {
|
|
11
28
|
if (type === DiffType.DELETE)
|
|
@@ -25,7 +42,7 @@ function getCodeMarker(type: DiffType) {
|
|
|
25
42
|
⋯
|
|
26
43
|
</td>
|
|
27
44
|
</tr>
|
|
28
|
-
<tr v-else-if="!line.hide" :data-diff-change="line.type !== DiffType.EQUAL ? '' : undefined">
|
|
45
|
+
<tr v-else-if="!line.hide" :data-diff-change="line.type !== DiffType.EQUAL ? '' : undefined" @click="onChangeClick">
|
|
29
46
|
<td
|
|
30
47
|
class="blob-num"
|
|
31
48
|
:class="{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, shallowRef, watch } from 'vue-demi'
|
|
3
|
-
import type { UnifiedLineChange, UnifiedViewerChange } from '../types'
|
|
3
|
+
import type { DiffChangeClickEvent, UnifiedLineChange, UnifiedViewerChange } from '../types'
|
|
4
4
|
import { RENDER_BATCH_SIZE, highlightUnifiedLine } from '../utils'
|
|
5
5
|
import UnifiedLine from './UnifiedLine.vue'
|
|
6
6
|
|
|
@@ -9,6 +9,10 @@ const props = defineProps<{
|
|
|
9
9
|
language: string
|
|
10
10
|
}>()
|
|
11
11
|
|
|
12
|
+
const emit = defineEmits<{
|
|
13
|
+
(e: 'change-click', payload: DiffChangeClickEvent): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
12
16
|
const renderLimit = ref(RENDER_BATCH_SIZE)
|
|
13
17
|
const visibleChanges = shallowRef(props.diffChange.changes.filter(line => !line.hide || line.hideIndex !== undefined))
|
|
14
18
|
const renderedChanges = computed(() => visibleChanges.value.slice(0, renderLimit.value))
|
|
@@ -44,7 +48,13 @@ function loadMore() {
|
|
|
44
48
|
<template>
|
|
45
49
|
<table class="diff-table">
|
|
46
50
|
<tbody>
|
|
47
|
-
<UnifiedLine
|
|
51
|
+
<UnifiedLine
|
|
52
|
+
v-for="(item, index) in renderedChanges"
|
|
53
|
+
:key="index"
|
|
54
|
+
:line="item"
|
|
55
|
+
@expand="expandHandler"
|
|
56
|
+
@change-click="emit('change-click', $event)"
|
|
57
|
+
/>
|
|
48
58
|
<tr v-if="remainingLines">
|
|
49
59
|
<td class="blob-code blob-code-hunk load-more" colspan="3">
|
|
50
60
|
<button class="load-more-button" type="button" @click="loadMore">
|
package/src/utils.ts
CHANGED
|
@@ -74,6 +74,11 @@ function diffLines(prev: string, current: string) {
|
|
|
74
74
|
current = current.slice(0, -1)
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
if (prev)
|
|
78
|
+
prev += '\n'
|
|
79
|
+
if (current)
|
|
80
|
+
current += '\n'
|
|
81
|
+
|
|
77
82
|
let changes: Diff.Change[] | undefined
|
|
78
83
|
if (prev.length + current.length >= 100_000 && prev.includes('\n') && current.includes('\n')) {
|
|
79
84
|
const prevLines = prev ? prev.replace(/\n$/, '').split('\n') : []
|
package/types/index.d.ts
CHANGED
|
@@ -1,18 +1,75 @@
|
|
|
1
1
|
import type { HLJSApi } from 'highlight.js'
|
|
2
|
-
import type { DefineComponent } from 'vue-demi'
|
|
2
|
+
import type { DefineComponent, VNode } from 'vue-demi'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export interface CodeDiffProps {
|
|
5
|
+
newString: string
|
|
6
|
+
oldString: string
|
|
7
|
+
language?: string
|
|
8
|
+
context?: number
|
|
9
|
+
diffStyle?: 'word' | 'char'
|
|
10
|
+
forceInlineComparison?: boolean
|
|
11
|
+
outputFormat?: 'line-by-line' | 'side-by-side'
|
|
12
|
+
trim?: boolean
|
|
13
|
+
noDiffLineFeed?: boolean
|
|
14
|
+
maxHeight?: string
|
|
15
|
+
filename?: string
|
|
16
|
+
newFilename?: string
|
|
17
|
+
hideHeader?: boolean
|
|
18
|
+
hideStat?: boolean
|
|
19
|
+
hideNavigation?: boolean
|
|
20
|
+
theme?: 'light' | 'dark'
|
|
21
|
+
ignoreMatchingLines?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CodeReaderProps {
|
|
25
|
+
text: string
|
|
26
|
+
language?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DiffStat {
|
|
30
|
+
additionsNum: number
|
|
31
|
+
deletionsNum: number
|
|
32
|
+
ignoreAdditionsNum: number
|
|
33
|
+
ignoreDeletionsNum: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DiffResult {
|
|
37
|
+
stat: {
|
|
38
|
+
isChanged: boolean
|
|
39
|
+
addNum: number
|
|
40
|
+
delNum: number
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DiffChangeClickEvent {
|
|
45
|
+
side: 'old' | 'new'
|
|
46
|
+
type: 'added' | 'removed'
|
|
47
|
+
lineNumber: number
|
|
48
|
+
event: MouseEvent
|
|
7
49
|
}
|
|
8
50
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
51
|
+
export interface CodeDiffSlots {
|
|
52
|
+
stat: (props: { stat: DiffStat }) => VNode[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface CodeDiffEmits {
|
|
56
|
+
diff: (diffResult: DiffResult) => void
|
|
57
|
+
'change-click': (payload: DiffChangeClickEvent) => void
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type Empty = Record<string, never>
|
|
61
|
+
type CodeDiffComponent = DefineComponent<CodeDiffProps, Empty, Empty, Empty, Empty, Empty, Empty, CodeDiffEmits, 'diff' | 'change-click'>
|
|
62
|
+
|
|
63
|
+
export declare const CodeDiff: CodeDiffComponent & {
|
|
64
|
+
new (): InstanceType<CodeDiffComponent> & { $slots: CodeDiffSlots }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export declare const CodeReader: DefineComponent<CodeReaderProps>
|
|
68
|
+
export declare const hljs: HLJSApi
|
|
69
|
+
|
|
70
|
+
declare const plugin: {
|
|
71
|
+
install: (app: { component: (name: string, component: unknown) => unknown }) => void
|
|
72
|
+
hljs: HLJSApi
|
|
16
73
|
}
|
|
17
74
|
|
|
18
|
-
export default
|
|
75
|
+
export default plugin
|