Files snapshot from new-commit-view

./src/helpers.ts

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
330625 Tucker McKnight
f72d85 Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
90eb8e Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
bfcbfe Tucker McKnight
bfcbfe Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
bfcbfe Tucker McKnight
bfcbfe Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
31332f Tucker McKnight
31332f Tucker McKnight
b8a3bb Tucker McKnight
f72d85 Tucker McKnight
f72d85 Tucker McKnight
bfcbfe Tucker McKnight
bfcbfe Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
f72d85 Tucker McKnight
bfcbfe Tucker McKnight
31332f Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
31332f Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
f72d85 Tucker McKnight
bfcbfe Tucker McKnight
31332f Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
383520 Tucker McKnight
31332f Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
268685 Tucker McKnight
b8a3bb Tucker McKnight
bfcbfe Tucker McKnight
bfcbfe Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
90eb8e Tucker McKnight
90eb8e Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
330625 Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
b8a3bb Tucker McKnight
330625 Tucker McKnight
b8a3bb Tucker McKnight
import childProcess from 'child_process'
import escape from 'escape-html'
import * as Diff from 'diff'
import {type Repository} from './dataTypes.ts'
import { type ReposConfigurationWithDefaultsApplied } from './configTypes.ts'

type Diffs = ReturnType<Repository['commits']['get']>['diffs']


const getGitDiffsFromPatchText = (patchText: string): Diffs => {
  const lines = patchText.split("\n")
  const hunks: Diffs = []
  let previousHunk = -1
  const filenameRegex = RegExp(/diff --git a\/(.*?) b\/(.*?)/)
  const lineNumberRegex = RegExp(/@@ -(.*?)[,| ].*/)
  let previousFilename = ''
  let currentFilename = ''
  let skipFourStartingAt = -1
  lines.forEach((line, index) => {
    if (line.startsWith("diff")) {
      previousFilename = currentFilename
      currentFilename = line.match(filenameRegex)[1]
      if (previousHunk !== -1) {
        skipFourStartingAt = index
      }
    }
    if (line.startsWith("@@") || index == lines.length - 1) {
      if (previousHunk === -1) {
        previousHunk = index
        return
      }

      let hunkEndIndex = index + 1
      if (skipFourStartingAt !== -1 && skipFourStartingAt < hunkEndIndex) {
        hunkEndIndex = skipFourStartingAt
        skipFourStartingAt = -1
      }
      const lastHunk = lines.slice(previousHunk, hunkEndIndex)

      let lastHunkBefore = lastHunk.filter((line) => {
        return line.startsWith("-") || line.startsWith(" ")
      }).map((str) => {
        if (str.startsWith('-')) { return str.replace("-", "") }
        if (str.startsWith(' ')) { return str.replace(" ", "") }
      }).join("\n")

      let lastHunkAfter = lastHunk.filter((line) => {
        return line.startsWith("+") || line.startsWith(" ")
      }).map((str) => {
        if (str.startsWith('+')) { return str.replace("+", "") }
        if (str.startsWith(' ')) { return str.replace(" ", "") }
      }).join("\n")

      // TODO: don't split on \n again here, do this earlier? More efficiently?
      const changeObject = (lastHunkBefore.split('\n').length > 1000 || lastHunkAfter.split('\n').length > 1000)
        ? []
        : Diff.diffWordsWithSpace(lastHunkBefore, lastHunkAfter)
      let beforeText = ""
      let afterText = ""
      let added = 0
      let removed = 0

      changeObject.forEach((obj) => {
        const numNewLines = obj.value.split('').filter(char => char === '\n').length

        if (!obj.added && !obj.removed) {
          beforeText = beforeText + escape(obj.value)
          afterText = afterText + escape(obj.value)
          added += obj.value.split('\n').length
          removed += obj.value.split('\n').length
        }
        if (obj.added) {
          afterText = afterText + "<mark>" + escape(obj.value) + "</mark>"
          added += obj.value.split('\n').length
          if (numNewLines > 0) {
            let insertAt = beforeText.lastIndexOf("\n")
            insertAt = insertAt === -1 ? 0 : insertAt

            beforeText = beforeText.slice(0, insertAt + 1) + (new Array(numNewLines).fill('\u{2063}\n', 0).join('')) + beforeText.slice(insertAt + 1)
          }
        }
        if (obj.removed) {
          beforeText = beforeText + "<mark>" + escape(obj.value) + "</mark>"
          removed += obj.value.split('\n').length
          if (numNewLines > 0) {
            let insertAt = afterText.lastIndexOf("\n")
            insertAt = insertAt === -1 ? 0 : insertAt

            afterText = afterText.slice(0, insertAt + 1) + (new Array(numNewLines).fill('\u{2063}\n', 0).join('')) + afterText.slice(insertAt + 1)
          }
        }
      })

      hunks.push({
        fileName: previousFilename !== '' ? previousFilename : currentFilename,
        lineNumber: parseInt(lines[previousHunk].match(lineNumberRegex)[1]),
        beforeText,
        afterText,
        added,
        removed,
      })
      previousFilename = ''
      previousHunk = index
    }
  })

  return hunks
}

const getLocation = (reposConfig: ReposConfigurationWithDefaultsApplied, outputDir: string, repoName: string, slugify: Function): string => {
  return outputDir + (reposConfig.path) + "/" + slugify(repoName) + ".git"
}

const readChunkedCommandOutput = async (executable, args): Promise<string> => {
  return new Promise((resolve) => {
    const cmd = childProcess.spawn(executable, args, {
      stdio: [0, "pipe", "inherit"],
    })
    let output = ""

    cmd.stdout.on('data', (data) => {
      output = output + data
    })

    cmd.on('close', () => {
      resolve(output)
    })
  })
}

export {
  getGitDiffsFromPatchText,
  getLocation,
  readChunkedCommandOutput,
}