-
Notifications
You must be signed in to change notification settings - Fork 78
/
lint.js
116 lines (97 loc) · 3.17 KB
/
lint.js
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
#!/usr/bin/env node
'use strict'
const loader = require('./lib/loader.js');
const linter = require('./lib/linter.js');
const validator = require('./lib/validator.js');
const colors = process.env.NODE_DISABLE_COLORS ? {} : {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
reset: '\x1b[0m'
};
const formatSchemaError = (err, context) => {
const pointer = context.pop();
let output = `
${colors.yellow + pointer}
`;
if (err.name === 'AssertionError') {
output += colors.reset + truncateLongMessages(err.message);
}
else if (err instanceof validator.JSONSchemaError) {
output += colors.reset + readableJsonSchemaMessages(err).join('\n');
}
else {
output += colors.red + err.stack;
}
return output;
}
function readableJsonSchemaMessages(err) {
return err.errors.map(error => {
const { data, dataPath, params, message } = error;
if (params.missingProperty) {
return `${dataPath} is missing property: ${params.missingProperty}`;
}
if (params.additionalProperty) {
return `${dataPath} has an unexpected additional property: ${params.additionalProperty}`;
}
if (params.format) {
return `${dataPath} has an unexpected format. It should match ${params.format}. Value is: ${data}`;
}
return `${dataPath} ${message}`;
});
}
const truncateLongMessages = message => {
let lines = message.split('\n');
if (lines.length > 6) {
lines = lines.slice(0, 5).concat(
[' ... snip ...'],
lines.slice(-1)
);
}
return lines.join('\n');
}
const formatLintResults = lintResults => {
let output = '';
lintResults.forEach(result => {
const { rule, error, pointer } = result;
output += `
${colors.yellow + pointer} ${colors.cyan} R: ${rule.name} ${colors.white} D: ${rule.description}
${colors.reset + truncateLongMessages(error.message)}
`;
});
return output;
}
const command = async (file, cmd) => {
const verbose = cmd.quiet ? 1 : cmd.verbose;
linter.initialize();
await loader.loadRuleFiles(cmd.rules, { verbose });
const spec = await loader.readOrError(file, {
jsonSchema: cmd.jsonSchema === true,
resolve: true,
verbose,
});
validator.validate(spec, { verbose, skip: cmd.skip }, (err, _options) => {
const { context, lintResults } = _options;
if (err) {
console.error(colors.red + 'Specification schema is invalid.' + colors.reset);
const output = formatSchemaError(err, context);
console.error(output);
process.exit(1);
}
if (lintResults.length) {
console.error(colors.red + 'Specification contains lint errors: ' + lintResults.length + colors.reset);
const output = formatLintResults(lintResults);
console.warn(output)
process.exit(1);
}
if (!cmd.quiet) {
console.log(colors.green + 'Specification is valid, with 0 lint errors' + colors.reset)
}
process.exit(0);
});
};
module.exports = { command }