1 | (function() {
|
2 | var _, parseFile;
|
3 |
|
4 | _ = require('underscore');
|
5 |
|
6 | _.str = require('underscore.string');
|
7 |
|
8 | module.exports = function(input) {
|
9 | var add, chunk, del, deleted_file, file, files, from_file, i, index, len, line, lines, ln_add, ln_del, new_file, noeol, normal, parse, restart, schema, start, to_file;
|
10 | if (!input) {
|
11 | return [];
|
12 | }
|
13 | if (input.match(/^\s+$/)) {
|
14 | return [];
|
15 | }
|
16 | lines = input.split('\n');
|
17 | if (lines.length === 0) {
|
18 | return [];
|
19 | }
|
20 | files = [];
|
21 | file = null;
|
22 | ln_del = 0;
|
23 | ln_add = 0;
|
24 | start = function() {
|
25 | file = {
|
26 | lines: [],
|
27 | deletions: 0,
|
28 | additions: 0
|
29 | };
|
30 | return files.push(file);
|
31 | };
|
32 | restart = function() {
|
33 | if (!file || file.lines.length) {
|
34 | return start();
|
35 | }
|
36 | };
|
37 | new_file = function() {
|
38 | restart();
|
39 | return file["new"] = true;
|
40 | };
|
41 | deleted_file = function() {
|
42 | restart();
|
43 | return file.deleted = true;
|
44 | };
|
45 | index = function(line) {
|
46 | restart();
|
47 | return file.index = line.split(' ').slice(1);
|
48 | };
|
49 | from_file = function(line) {
|
50 | restart();
|
51 | return file.from = parseFile(line);
|
52 | };
|
53 | to_file = function(line) {
|
54 | restart();
|
55 | return file.to = parseFile(line);
|
56 | };
|
57 | chunk = function(line, match) {
|
58 | ln_del = +match[1];
|
59 | ln_add = +match[3];
|
60 | return file.lines.push({
|
61 | type: 'chunk',
|
62 | chunk: true,
|
63 | content: line
|
64 | });
|
65 | };
|
66 | del = function(line) {
|
67 | file.lines.push({
|
68 | type: 'del',
|
69 | del: true,
|
70 | ln: ln_del++,
|
71 | content: line
|
72 | });
|
73 | return file.deletions++;
|
74 | };
|
75 | add = function(line) {
|
76 | file.lines.push({
|
77 | type: 'add',
|
78 | add: true,
|
79 | ln: ln_add++,
|
80 | content: line
|
81 | });
|
82 | return file.additions++;
|
83 | };
|
84 | noeol = '\\ No newline at end of file';
|
85 | normal = function(line) {
|
86 | if (!file) {
|
87 | return;
|
88 | }
|
89 | return file.lines.push({
|
90 | type: 'normal',
|
91 | normal: true,
|
92 | ln1: line !== noeol ? ln_del++ : void 0,
|
93 | ln2: line !== noeol ? ln_add++ : void 0,
|
94 | content: line
|
95 | });
|
96 | };
|
97 | schema = [[/^diff\s/, start], [/^new file mode \d+$/, new_file], [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s@@/, chunk], [/^-/, del], [/^\+/, add]];
|
98 | parse = function(line) {
|
99 | var i, len, m, p;
|
100 | for (i = 0, len = schema.length; i < len; i++) {
|
101 | p = schema[i];
|
102 | m = line.match(p[0]);
|
103 | if (m) {
|
104 | p[1](line, m);
|
105 | return true;
|
106 | }
|
107 | }
|
108 | return false;
|
109 | };
|
110 | for (i = 0, len = lines.length; i < len; i++) {
|
111 | line = lines[i];
|
112 | if (!parse(line)) {
|
113 | normal(line);
|
114 | }
|
115 | }
|
116 | return files;
|
117 | };
|
118 |
|
119 | parseFile = function(s) {
|
120 | var t;
|
121 | s = _.str.ltrim(s, '-');
|
122 | s = _.str.ltrim(s, '+');
|
123 | s = s.trim();
|
124 | t = /\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/.exec(s);
|
125 | if (t) {
|
126 | s = s.substring(0, t.index).trim();
|
127 | }
|
128 | if (s.match(/^(a|b)\//)) {
|
129 | return s.substr(2);
|
130 | } else {
|
131 | return s;
|
132 | }
|
133 | };
|
134 |
|
135 | }).call(this);
|