UNPKG

2.24 kBtext/coffeescriptView Raw
1_ = require 'underscore'
2_.str = require 'underscore.string'
3
4# parses unified diff
5# http://www.gnu.org/software/diffutils/manual/diffutils.html#Unified-Format
6module.exports = (input) ->
7 return [] if not input
8 return [] if input.match /^\s+$/
9
10 lines = input.split '\n'
11 return [] if lines.length == 0
12
13 files = []
14 file = null
15 ln_del = 0
16 ln_add = 0
17
18 start = ->
19 file =
20 lines: []
21 deletions: 0
22 additions: 0
23 files.push file
24
25 restart = ->
26 start() if not file || file.lines.length
27
28 new_file = ->
29 restart()
30 file.new = true
31
32 deleted_file = ->
33 restart()
34 file.deleted = true
35
36 index = (line) ->
37 restart()
38 file.index = line.split(' ').slice(1)
39
40 from_file = (line) ->
41 restart()
42 file.from = parseFile line
43
44 to_file = (line) ->
45 restart()
46 file.to = parseFile line
47
48 chunk = (line, match) ->
49 ln_del = +match[1]
50 ln_add = +match[3]
51 file.lines.push {type:'chunk', chunk:true, content:line}
52
53 del = (line) ->
54 file.lines.push {type:'del', del:true, ln:ln_del++, content:line}
55 file.deletions++
56
57 add = (line) ->
58 file.lines.push {type:'add', add:true, ln:ln_add++, content:line}
59 file.additions++
60
61 noeol = '\\ No newline at end of file'
62 normal = (line) ->
63 return if not file
64 file.lines.push {
65 type: 'normal'
66 normal: true
67 ln1: ln_del++ unless line is noeol
68 ln2: ln_add++ unless line is noeol
69 content: line
70 }
71
72 schema = [
73 # todo beter regexp to avoid detect normal line starting with diff
74 [/^diff\s/, start],
75 [/^new file mode \d+$/, new_file],
76 [/^deleted file mode \d+$/, deleted_file],
77 [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index],
78 [/^---\s/, from_file]
79 [/^\+\+\+\s/, to_file]
80 [/^@@\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s@@/, chunk],
81 [/^-/, del],
82 [/^\+/, add]
83 ]
84
85 parse = (line) ->
86 for p in schema
87 m = line.match p[0]
88 if m
89 p[1](line, m)
90 return true
91 return false
92
93 for line in lines
94 normal(line) unless parse line
95
96 return files
97
98parseFile = (s) ->
99 s = _.str.ltrim s, '-'
100 s = _.str.ltrim s, '+'
101 s = s.trim()
102 # ignore possible time stamp
103 t = (/\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/).exec(s)
104 s = s.substring(0, t.index).trim() if t
105 # ignore git prefixes a/ or b/
106 if s.match (/^(a|b)\//) then s.substr(2) else s