v-code-diff 1.4.0 → 1.5.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/src/CodeDiff.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue-demi'
2
+ import { computed, ref, watch } from 'vue-demi'
3
3
  import { createSplitDiff, createUnifiedDiff } from './utils'
4
4
  import UnifiedViewer from './unified/UnifiedViewer.vue'
5
5
  import SplitViewer from './split/SplitViewer.vue'
@@ -42,11 +42,15 @@ const newString = computed(() => {
42
42
  return props.noDiffLineFeed ? value.replace(/(\r\n)/g, '\n') : value
43
43
  })
44
44
 
45
- const diffChange = computed(() =>
45
+ const raw = computed(() =>
46
46
  isUnifiedViewer.value
47
47
  ? createUnifiedDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context)
48
48
  : createSplitDiff(oldString.value, newString.value, props.language, props.diffStyle, props.context),
49
49
  )
50
+ const diffChange = ref(raw.value)
51
+ watch(() => props, () => {
52
+ diffChange.value = raw.value
53
+ }, { deep: true })
50
54
  </script>
51
55
 
52
56
  <template>
@@ -60,11 +64,9 @@ const diffChange = computed(() =>
60
64
  </span>
61
65
  </div>
62
66
  </div>
63
- <UnifiedViewer v-if="isUnifiedViewer" :diff-change="diffChange.changes" />
64
- <SplitViewer v-else :diff-change="diffChange.changes" />
67
+ <UnifiedViewer v-if="isUnifiedViewer" :diff-change="diffChange" />
68
+ <SplitViewer v-else :diff-change="diffChange" />
65
69
  </div>
66
70
  </template>
67
71
 
68
- <style lang="scss">
69
-
70
- </style>
72
+ <style lang="scss"></style>
@@ -5,6 +5,7 @@ import type { SplitLineChange } from '../types'
5
5
  const props = defineProps<{
6
6
  splitLine: SplitLineChange
7
7
  }>()
8
+ const emit = defineEmits(['expand'])
8
9
 
9
10
  const getCodeMarker = (type: DiffType) => {
10
11
  if (type === DiffType.DELETE)
@@ -16,15 +17,15 @@ const getCodeMarker = (type: DiffType) => {
16
17
  </script>
17
18
 
18
19
  <template>
19
- <tr v-if="splitLine.fold">
20
- <td class="blob-num blob-num-hunk" colspan="1">
20
+ <tr v-if="splitLine.hideIndex !== undefined && splitLine.hide">
21
+ <td class="blob-num blob-num-hunk" colspan="1" @click="emit('expand', splitLine)">
21
22
  >
22
23
  </td>
23
24
  <td class="blob-code blob-code-inner blob-code-hunk" colspan="3" align="left">
24
25
 
25
26
  </td>
26
27
  </tr>
27
- <tr v-else>
28
+ <tr v-else-if="!splitLine.hide">
28
29
  <template v-for="line in [splitLine.left, splitLine.right]">
29
30
  <!-- eslint-disable -->
30
31
  <template v-if="line.type === DiffType.EMPTY">
@@ -32,29 +33,24 @@ const getCodeMarker = (type: DiffType) => {
32
33
  <td class="blob-code blob-code-empty empty-cell" />
33
34
  </template>
34
35
  <template v-else>
35
- <td
36
- class="blob-num"
37
- :class="{
38
- 'blob-num-deletion': line.type === DiffType.DELETE,
39
- 'blob-num-addition': line.type === DiffType.ADD,
40
- 'blob-num-context': line.type === DiffType.EQUAL,
41
- }"
42
- >
36
+ <td class="blob-num" :class="{
37
+ 'blob-num-deletion': line.type === DiffType.DELETE,
38
+ 'blob-num-addition': line.type === DiffType.ADD,
39
+ 'blob-num-context': line.type === DiffType.EQUAL,
40
+ 'blob-num-hunk': splitLine.hide !== undefined,
41
+
42
+ }">
43
43
  {{ line.num }}
44
44
  </td>
45
- <td
46
- class="blob-code"
47
- :class="{
48
- 'blob-code-deletion': line.type === DiffType.DELETE,
49
- 'blob-code-addition': line.type === DiffType.ADD,
50
- 'blob-code-context': line.type === DiffType.EQUAL,
51
- }"
52
- >
53
- <span
54
- class="blob-code-inner blob-code-marker"
55
- :data-code-marker="getCodeMarker(line.type)"
56
- v-html="line.code"
57
- />
45
+ <td class="blob-code" :class="{
46
+ 'blob-code-deletion': line.type === DiffType.DELETE,
47
+ 'blob-code-addition': line.type === DiffType.ADD,
48
+ 'blob-code-context': line.type === DiffType.EQUAL,
49
+ 'blob-code-hunk': splitLine.hide !== undefined,
50
+
51
+ }">
52
+ <span class="blob-code-inner blob-code-marker" :data-code-marker="getCodeMarker(line.type)"
53
+ v-html="line.code" />
58
54
  </td>
59
55
  </template>
60
56
  <!-- eslint-enable -->
@@ -62,5 +58,4 @@ const getCodeMarker = (type: DiffType) => {
62
58
  </tr>
63
59
  </template>
64
60
 
65
- <style lang="scss">
66
- </style>
61
+ <style lang="scss"></style>
@@ -1,10 +1,19 @@
1
1
  <script setup lang="ts">
2
- import type { SplitViewerChange } from '../types'
2
+ import type { SplitLineChange, SplitViewerChange } from '../types'
3
3
  import SplitLine from './SplitLine.vue'
4
4
 
5
5
  const props = defineProps<{
6
6
  diffChange: SplitViewerChange
7
7
  }>()
8
+
9
+ function expandHandler({ hideIndex }: SplitLineChange) {
10
+ if (hideIndex === undefined)
11
+ return
12
+ props.diffChange.collector[hideIndex!].lines.forEach((line) => {
13
+ line.hide = false
14
+ line.fold = false
15
+ })
16
+ }
8
17
  </script>
9
18
 
10
19
  <template>
@@ -16,7 +25,7 @@ const props = defineProps<{
16
25
  <col>
17
26
  </colgroup>
18
27
  <tbody>
19
- <SplitLine v-for="(item, index) in diffChange" :key="index" :split-line="item" />
28
+ <SplitLine v-for="(item, index) in diffChange?.changes" :key="index" :split-line="item" @expand="expandHandler" />
20
29
  </tbody>
21
30
  </table>
22
31
  </template>
package/src/types.ts CHANGED
@@ -5,6 +5,16 @@ export const enum DiffType {
5
5
  EMPTY = 'empty',
6
6
  }
7
7
 
8
+ export interface UnifiedLineUnchanges {
9
+ lines: UnifiedLineChange[]
10
+ fold: boolean
11
+ }
12
+
13
+ export interface SplitLineUnchanges {
14
+ lines: SplitLineChange[]
15
+ fold: boolean
16
+ }
17
+
8
18
  export interface DiffLine {
9
19
  type: DiffType
10
20
  code?: string
@@ -15,6 +25,8 @@ export interface SplitLineChange {
15
25
  fold?: boolean
16
26
  left: DiffLine
17
27
  right: DiffLine
28
+ hide?: boolean
29
+ hideIndex?: number
18
30
  }
19
31
 
20
32
  export interface UnifiedLineChange {
@@ -23,18 +35,23 @@ export interface UnifiedLineChange {
23
35
  code: string
24
36
  delNum?: number
25
37
  addNum?: number
38
+ hide?: boolean
39
+ hideIndex?: number
26
40
  }
27
41
 
28
42
  export interface DiffStat {
29
43
  additionsNum: number
30
44
  deletionsNum: number
31
45
  }
46
+
32
47
  export interface SplitViewerChange {
33
48
  changes: SplitLineChange[]
49
+ collector: SplitLineUnchanges[]
34
50
  stat: DiffStat
35
51
  }
36
52
 
37
53
  export interface UnifiedViewerChange {
38
54
  changes: UnifiedLineChange[]
55
+ collector: UnifiedLineUnchanges[]
39
56
  stat: DiffStat
40
57
  }
@@ -5,6 +5,7 @@ import { DiffType } from '../types'
5
5
  const props = defineProps<{
6
6
  line: UnifiedLineChange
7
7
  }>()
8
+ const emit = defineEmits(['expand'])
8
9
 
9
10
  const getCodeMarker = (type: DiffType) => {
10
11
  if (type === DiffType.DELETE)
@@ -16,24 +17,22 @@ const getCodeMarker = (type: DiffType) => {
16
17
  </script>
17
18
 
18
19
  <template>
19
- <tr v-if="line.fold">
20
- <td class="blob-num blob-num-hunk">
21
- >
22
- </td>
23
- <td class="blob-num blob-num-hunk">
20
+ <tr v-if="line.hideIndex !== undefined && line.hide">
21
+ <td class="blob-num blob-num-hunk text-center" colspan="2" @click="emit('expand', line)">
24
22
  >
25
23
  </td>
26
24
  <td class="blob-code blob-code-hunk" align="left">
27
25
 
28
26
  </td>
29
27
  </tr>
30
- <tr v-else>
28
+ <tr v-else-if="!line.hide">
31
29
  <td
32
30
  class="blob-num"
33
31
  :class="{
34
32
  'blob-num-deletion': line.type === DiffType.DELETE,
35
33
  'blob-num-addition': line.type === DiffType.ADD,
36
34
  'blob-num-context': line.type === DiffType.EQUAL,
35
+ 'blob-num-hunk': line.hide !== undefined,
37
36
  }"
38
37
  >
39
38
  {{ line.delNum }}
@@ -44,6 +43,7 @@ const getCodeMarker = (type: DiffType) => {
44
43
  'blob-num-deletion': line.type === DiffType.DELETE,
45
44
  'blob-num-addition': line.type === DiffType.ADD,
46
45
  'blob-num-context': line.type === DiffType.EQUAL,
46
+ 'blob-num-hunk': line.hide !== undefined,
47
47
  }"
48
48
  >
49
49
  {{ line.addNum }}
@@ -54,6 +54,7 @@ const getCodeMarker = (type: DiffType) => {
54
54
  'blob-code-deletion': line.type === DiffType.DELETE,
55
55
  'blob-code-addition': line.type === DiffType.ADD,
56
56
  'blob-code-context': line.type === DiffType.EQUAL,
57
+ 'blob-code-hunk': line.hide !== undefined,
57
58
  }"
58
59
  >
59
60
  <span class="blob-code-inner blob-code-marker" :data-code-marker="getCodeMarker(line.type)" v-html="line.code" />
@@ -1,16 +1,25 @@
1
1
  <script setup lang="ts">
2
- import type { UnifiedLineChange } from '../types'
2
+ import type { UnifiedLineChange, UnifiedViewerChange } from '../types'
3
3
  import UnifiedLine from './UnifiedLine.vue'
4
4
 
5
5
  const props = defineProps<{
6
- diffChange: UnifiedLineChange[]
6
+ diffChange: UnifiedViewerChange
7
7
  }>()
8
+
9
+ function expandHandler({ hideIndex }: UnifiedLineChange) {
10
+ if (hideIndex === undefined)
11
+ return
12
+ props.diffChange.collector[hideIndex!].lines.forEach((line) => {
13
+ line.hide = false
14
+ line.fold = false
15
+ })
16
+ }
8
17
  </script>
9
18
 
10
19
  <template>
11
20
  <table class="diff-table">
12
21
  <tbody>
13
- <UnifiedLine v-for="(item, index) in diffChange" :key="index" :line="item" />
22
+ <UnifiedLine v-for="(item, index) in diffChange?.changes" :key="index" :line="item" @expand="expandHandler" />
14
23
  </tbody>
15
24
  </table>
16
25
  </template>
package/src/utils.ts CHANGED
@@ -3,7 +3,7 @@ import type { Change } from 'diff'
3
3
  import { DIFF_DELETE, DIFF_INSERT, diff_match_patch as DiffMatchPatch } from 'diff-match-patch'
4
4
  import hljs from './highlight'
5
5
  import { DiffType } from './types'
6
- import type { DiffLine, DiffStat, SplitLineChange, SplitViewerChange, UnifiedLineChange, UnifiedViewerChange } from './types'
6
+ import type { DiffLine, DiffStat, SplitLineChange, SplitLineUnchanges, SplitViewerChange, UnifiedLineChange, UnifiedLineUnchanges, UnifiedViewerChange } from './types'
7
7
 
8
8
  const MODIFIED_START_TAG = '<code-diff-modified>'
9
9
  const MODIFIED_CLOSE_TAG = '</code-diff-modified>'
@@ -168,6 +168,7 @@ export function createSplitDiff(
168
168
  const rawChanges: SplitLineChange[] = []
169
169
  const result: SplitViewerChange = {
170
170
  changes: rawChanges,
171
+ collector: [],
171
172
  stat: calcDiffStat(changes),
172
173
  }
173
174
 
@@ -208,7 +209,6 @@ export function createSplitDiff(
208
209
  left = newEmptySplitDiff()
209
210
  right = newSplitDiff(DiffType.ADD, addNum, highlightCode)
210
211
  }
211
-
212
212
  rawChanges.push({ left, right })
213
213
  }
214
214
  break
@@ -300,17 +300,35 @@ export function createSplitDiff(
300
300
  line.fold = true
301
301
  }
302
302
 
303
- const processedChanges = []
303
+ const processedChanges: SplitViewerChange['changes'] = []
304
+ let unchanges: SplitLineUnchanges['lines'] = [] // collector for unchanged lines.
305
+
304
306
  for (let i = 0; i < rawChanges.length; i++) {
305
307
  const line = rawChanges[i]
306
308
  if (line.fold === false) {
309
+ if (unchanges.length) {
310
+ unchanges[0].hideIndex = result.collector.length
311
+ result.collector.push({
312
+ lines: unchanges,
313
+ fold: true,
314
+ })
315
+ unchanges = []
316
+ }
307
317
  processedChanges.push(line)
308
318
  continue
309
319
  }
310
- if (line.fold === true) {
311
- if (processedChanges[processedChanges.length - 1]?.fold !== true)
312
- processedChanges.push(line)
313
- }
320
+
321
+ line.hide = true
322
+ unchanges.push(line)
323
+ processedChanges.push(line)
324
+ }
325
+ if (unchanges.length) {
326
+ unchanges[0].hideIndex = result.collector.length
327
+ result.collector.push({
328
+ lines: unchanges,
329
+ fold: true,
330
+ })
331
+ unchanges = []
314
332
  }
315
333
  result.changes = processedChanges
316
334
 
@@ -333,6 +351,7 @@ export function createUnifiedDiff(
333
351
  const rawChanges: UnifiedLineChange[] = []
334
352
  const result: UnifiedViewerChange = {
335
353
  changes: rawChanges,
354
+ collector: [],
336
355
  stat: calcDiffStat(changes),
337
356
  }
338
357
 
@@ -449,16 +468,37 @@ export function createUnifiedDiff(
449
468
  }
450
469
 
451
470
  const processedChanges = []
471
+ let unchanges: UnifiedLineUnchanges['lines'] = [] // collector for unchanged lines.
472
+
452
473
  for (let i = 0; i < rawChanges.length; i++) {
453
474
  const line = rawChanges[i]
454
475
  if (line.fold === false) {
476
+ if (unchanges.length) {
477
+ unchanges[0].hideIndex = result.collector.length
478
+ // Keeps "hideIndex" in first element of collector
479
+ // for delegating lines to expand.
480
+ result.collector.push({
481
+ lines: unchanges,
482
+ fold: true,
483
+ })
484
+ unchanges = []
485
+ }
455
486
  processedChanges.push(line)
456
487
  continue
457
488
  }
458
- if (line.fold === true) {
459
- if (i === 0 || processedChanges[processedChanges.length - 1]?.fold !== true)
460
- processedChanges.push(line)
489
+ if (line.type === 'equal') {
490
+ line.hide = true
491
+ unchanges.push(line)
461
492
  }
493
+ processedChanges.push(line)
494
+ }
495
+ if (unchanges.length) {
496
+ unchanges[0].hideIndex = result.collector.length
497
+ result.collector.push({
498
+ lines: unchanges,
499
+ fold: true,
500
+ })
501
+ unchanges = []
462
502
  }
463
503
  result.changes = processedChanges
464
504