1 | _ = require 'underscore'
|
2 | _.str = require 'underscore.string'
|
3 |
|
4 |
|
5 |
|
6 | module.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 |
|
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 |
|
98 | parseFile = (s) ->
|
99 | s = _.str.ltrim s, '-'
|
100 | s = _.str.ltrim s, '+'
|
101 | s = s.trim()
|
102 |
|
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 |
|
106 | if s.match (/^(a|b)\//) then s.substr(2) else s
|