Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
format-diff.js119 linesDownload Raw Back to lib
1const jsDiff = require('diff')
2
3const shouldPrintPatch = require('./should-print-patch.js')
4
5const colors = {
6  // red
7  removed: { open: '\x1B[31m', close: '\x1B[39m' },
8  // green
9  added: { open: '\x1B[32m', close: '\x1B[39m' },
10  // blue
11  header: { open: '\x1B[34m', close: '\x1B[39m' },
12  // cyan
13  section: { open: '\x1B[36m', close: '\x1B[39m' },
14}
15
16const color = (colorStr, colorId) => {
17  const { open, close } = colors[colorId]
18  // avoid highlighting the "\n" (would highlight till the end of the line)
19  return colorStr.replace(/[^\n\r]+/g, open + '$&' + close)
20}
21
22const formatDiff = async ({ files, opts = {}, refs, versions }) => {
23  let res = ''
24  const srcPrefix = opts.diffNoPrefix ? '' : opts.diffSrcPrefix || 'a/'
25  const dstPrefix = opts.diffNoPrefix ? '' : opts.diffDstPrefix || 'b/'
26
27  for (const filename of files.values()) {
28    const names = {
29      a: `${srcPrefix}${filename}`,
30      b: `${dstPrefix}${filename}`,
31    }
32
33    let fileMode = ''
34    const filenames = {
35      a: refs.get(`a/${filename}`),
36      b: refs.get(`b/${filename}`),
37    }
38    const contents = {
39      a: filenames.a && filenames.a.content,
40      b: filenames.b && filenames.b.content,
41    }
42    const modes = {
43      a: filenames.a && filenames.a.mode,
44      b: filenames.b && filenames.b.mode,
45    }
46
47    if (contents.a === contents.b && modes.a === modes.b) {
48      continue
49    }
50
51    if (opts.diffNameOnly) {
52      res += `${filename}\n`
53      continue
54    }
55
56    let patch = ''
57    let headerLength = 0
58    const header = str => {
59      headerLength++
60      patch += `${str}\n`
61    }
62
63    // manually build a git diff-compatible header
64    header(`diff --git ${names.a} ${names.b}`)
65    if (modes.a === modes.b) {
66      fileMode = filenames.a.mode
67    } else {
68      if (modes.a && !modes.b) {
69        header(`deleted file mode ${modes.a}`)
70      } else if (!modes.a && modes.b) {
71        header(`new file mode ${modes.b}`)
72      } else {
73        header(`old mode ${modes.a}`)
74        header(`new mode ${modes.b}`)
75      }
76    }
77    /* eslint-disable-next-line max-len */
78    header(`index ${opts.tagVersionPrefix || 'v'}${versions.a}..${opts.tagVersionPrefix || 'v'}${versions.b} ${fileMode}`)
79
80    if (await shouldPrintPatch(filename)) {
81      patch += jsDiff.createTwoFilesPatch(
82        names.a,
83        names.b,
84        contents.a || '',
85        contents.b || '',
86        '',
87        '',
88        {
89          context: opts.diffUnified === 0 ? 0 : opts.diffUnified || 3,
90          ignoreWhitespace: opts.diffIgnoreAllSpace,
91        }
92      ).replace(
93        '===================================================================\n',
94        ''
95      ).replace(/\t\n/g, '\n') // strip trailing tabs
96      headerLength += 2
97    } else {
98      header(`--- ${names.a}`)
99      header(`+++ ${names.b}`)
100    }
101
102    if (opts.color) {
103      // this RegExp will include all the `\n` chars into the lines, easier to join
104      const lines = patch.split(/^/m)
105      res += color(lines.slice(0, headerLength).join(''), 'header')
106      res += lines.slice(headerLength).join('')
107        .replace(/^-.*/gm, color('$&', 'removed'))
108        .replace(/^\+.*/gm, color('$&', 'added'))
109        .replace(/^@@.+@@/gm, color('$&', 'section'))
110    } else {
111      res += patch
112    }
113  }
114
115  return res.trim()
116}
117
118module.exports = formatDiff
119 
codekingpro/portable-devtools · Team Ai