1 | "use strict";
|
2 |
|
3 | const fs = require("fs");
|
4 | const path = require("path");
|
5 | const jsonlint = require("jsonlint");
|
6 | const SEVERITY = require("./severity");
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | const merge = function (first, second) {
|
16 | if ("object" !== typeof first || "object" !== typeof second) {
|
17 | return second;
|
18 | }
|
19 | const third = {};
|
20 | for (const key of new Set([...Object.keys(first),
|
21 | ...Object.keys(second)])) {
|
22 |
|
23 | if (key in first && key in second) {
|
24 | third[key] = merge(first[key], second[key]);
|
25 |
|
26 | } else if (key in first) {
|
27 | third[key] = first[key];
|
28 |
|
29 | } else {
|
30 | third[key] = second[key];
|
31 | }
|
32 | }
|
33 | return third;
|
34 | };
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | const read = function (file) {
|
43 | const json = fs.readFileSync(file, "utf-8");
|
44 | try {
|
45 | return jsonlint.parse(json);
|
46 | } catch (err) {
|
47 | throw new Error(file + ": " + err.message);
|
48 | }
|
49 | };
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | const patterns = function (rotten, auto) {
|
60 | let standard;
|
61 | if (undefined === rotten) {
|
62 | standard = auto;
|
63 | } else if ("string" === typeof rotten) {
|
64 | standard = [rotten];
|
65 | } else if (Array.isArray(rotten)) {
|
66 | standard = rotten;
|
67 | } else {
|
68 | throw new Error("property 'patterns' is incorrect type (string and" +
|
69 | " array are accepted).");
|
70 | }
|
71 | return standard;
|
72 | };
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | const level = function (rotten, auto) {
|
82 | let standard;
|
83 | if (undefined === rotten) {
|
84 | standard = auto;
|
85 | } else if ("string" === typeof rotten) {
|
86 | if (rotten.toUpperCase() in SEVERITY) {
|
87 | standard = SEVERITY[rotten.toUpperCase()];
|
88 | if (standard > auto) {
|
89 | standard = auto;
|
90 | }
|
91 | } else {
|
92 | throw new Error("value of property 'level' is unknown (possibles" +
|
93 | " values : 'off', 'fatal', 'error', 'warn' and" +
|
94 | " 'info').");
|
95 | }
|
96 | } else {
|
97 | throw new Error("property 'level' is incorrect type (only string is" +
|
98 | " accepted).");
|
99 | }
|
100 | return standard;
|
101 | };
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | const name = function (rotten, auto, root) {
|
113 | let standard;
|
114 | if (undefined === rotten) {
|
115 | standard = require("./reporter/" + auto);
|
116 | } else if ("string" === typeof rotten) {
|
117 | if (-1 === ["checkstyle", "console", "csv",
|
118 | "json", "none", "unix"].indexOf(rotten.toLowerCase())) {
|
119 | const file = rotten.startsWith("/") ? rotten
|
120 | : path.join(root, rotten);
|
121 | standard = require(file);
|
122 | } else {
|
123 | standard = require("./reporter/" + rotten.toLowerCase());
|
124 | }
|
125 | } else {
|
126 | throw new Error("property 'name' is incorrect type (only string is" +
|
127 | " accepted).");
|
128 | }
|
129 | return standard;
|
130 | };
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 | const output = function (rotten, auto, root) {
|
142 | let standard;
|
143 | if (undefined === rotten || null === rotten) {
|
144 | standard = auto;
|
145 | } else if ("string" === typeof rotten) {
|
146 | const file = rotten.startsWith("/") ? rotten
|
147 | : path.join(root, rotten);
|
148 | try {
|
149 | standard = fs.createWriteStream(file, { "flags": "w" });
|
150 | } catch (_) {
|
151 | throw new Error("property 'output' is incorrect type (only string" +
|
152 | " is accepted).");
|
153 | }
|
154 | } else {
|
155 | throw new Error("'output' incorrect type.");
|
156 | }
|
157 | return standard;
|
158 | };
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 | const options = function (rotten, auto) {
|
168 | let standard;
|
169 | if (undefined === rotten) {
|
170 | standard = auto;
|
171 | } else if ("object" === typeof rotten) {
|
172 | standard = rotten;
|
173 | } else {
|
174 | throw new Error("property 'options' is incorrect type (only object is" +
|
175 | " accepted).");
|
176 | }
|
177 | return standard;
|
178 | };
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 | const reporters = function (rottens, auto, root) {
|
190 | let standards;
|
191 | if (undefined === rottens) {
|
192 | const Name = name(undefined, "console", root);
|
193 | standards = [
|
194 | new Name(level(undefined, auto.level),
|
195 | output(undefined, process.stdout, root),
|
196 | options(undefined, {}))
|
197 | ];
|
198 | } else if (Array.isArray(rottens)) {
|
199 | standards = rottens.map(function (rotten) {
|
200 | const Name = name(rotten.name, "console", root);
|
201 | return new Name(level(rotten.level, auto.level),
|
202 | output(rotten.output, process.stdout, root),
|
203 | options(rotten.options, {}));
|
204 | });
|
205 | } else if ("object" === typeof rottens) {
|
206 | const Name = name(rottens.name, "console", root);
|
207 | standards = [
|
208 | new Name(level(rottens.level, auto.level),
|
209 | output(rottens.output, process.stdout, root),
|
210 | options(rottens.options, {}))
|
211 | ];
|
212 | } else {
|
213 | throw new Error("'reporters' incorrect type.");
|
214 | }
|
215 | return standards;
|
216 | };
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | const linters = function (rottens, dir) {
|
228 | const standards = {};
|
229 | if (undefined === rottens) {
|
230 | throw new Error("'checkers[].linters' is undefined.");
|
231 | } else if (null === rottens) {
|
232 | throw new Error("'checkers[].linters' is null.");
|
233 |
|
234 | } else if ("string" === typeof rottens) {
|
235 | standards[rottens] = read(path.join(dir, rottens + ".json"));
|
236 |
|
237 | } else if (Array.isArray(rottens)) {
|
238 | for (const linter of rottens) {
|
239 | standards[linter] = read(path.join(dir, linter + ".json"));
|
240 | }
|
241 |
|
242 | } else if ("object" === typeof rottens) {
|
243 | for (const linter in rottens) {
|
244 |
|
245 | if ("string" === typeof rottens[linter]) {
|
246 | standards[linter] = read(path.join(dir, rottens[linter]));
|
247 |
|
248 | } else if (Array.isArray(rottens[linter])) {
|
249 | standards[linter] = {};
|
250 | for (const option of rottens[linter]) {
|
251 | if (null === option) {
|
252 | throw new Error("linter option is null.");
|
253 |
|
254 | } else if ("string" === typeof option) {
|
255 | standards[linter] = merge(standards[linter],
|
256 | read(path.join(dir, option)));
|
257 |
|
258 | } else if ("object" === typeof option) {
|
259 | standards[linter] = merge(standards[linter], option);
|
260 | } else {
|
261 | throw new Error("linter option incorrect type.");
|
262 | }
|
263 | }
|
264 |
|
265 |
|
266 | } else if ("object" === typeof rottens[linter]) {
|
267 | standards[linter] = rottens[linter];
|
268 | } else {
|
269 | throw new Error("linter incorrect type.");
|
270 | }
|
271 | }
|
272 | } else {
|
273 | throw new Error("'checkers[].linters' incorrect type.");
|
274 | }
|
275 |
|
276 | return standards;
|
277 | };
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 | const checkers = function (rottens, auto, dir) {
|
290 | let standards;
|
291 | if (Array.isArray(rottens)) {
|
292 | if (0 === rottens.length) {
|
293 | throw new Error("'checkers' is empty.");
|
294 | } else {
|
295 | standards = rottens.map(function (rotten) {
|
296 | return {
|
297 | "patterns": patterns(rotten.patterns, ["**"]),
|
298 | "level": level(rotten.level, auto.level),
|
299 | "linters": linters(rotten.linters, dir)
|
300 | };
|
301 | });
|
302 | }
|
303 | } else {
|
304 | throw new Error("'checkers' is not an array.");
|
305 | }
|
306 | return standards;
|
307 | };
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 | const normalize = function (rotten, root, dir) {
|
322 | const standard = {
|
323 | "patterns": patterns(rotten.patterns, ["**"]),
|
324 | "level": level(rotten.level, SEVERITY.INFO)
|
325 | };
|
326 | standard.reporters = reporters(rotten.reporters, standard, root);
|
327 | standard.checkers = checkers(rotten.checkers, standard, dir);
|
328 | return standard;
|
329 | };
|
330 |
|
331 | module.exports = normalize;
|