This repository has been archived by the owner on Oct 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcheck.js
156 lines (141 loc) · 4.1 KB
/
check.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
var lint = require("./jshint.js");
var identRegex = /[a-zA-Z\$_0-9]/;
function startRegex(arr) {
return RegExp("^(" + arr.join("|") + ")");
}
var disabledWarningsRe = startRegex([
"Bad for in variable '(.+)'.",
'Missing "use strict"']);
var errorsRe = startRegex([
"Unexpected",
"Expected ",
"Confusing (plus|minus)",
"\\{a\\} unterminated regular expression",
"Unclosed ",
"Unmatched ",
"Unbegun comment",
"Bad invocation",
"Missing space after",
"Missing operator at"]);
var infoRe = startRegex([
"Expected an assignment",
"Bad escapement of EOL",
"Unexpected comma",
"Unexpected space",
"Missing radix parameter.",
"A leading decimal point can",
"\\['{a}'\\] is better written in dot notation.",
"'{a}' used out of scope"]);
function isValidJS(str) {
try {
// evaluated code can only create variables in this function
eval("throw 0;" + str);
} catch (e) {
if (e === 0) return true;
}
return false;
}
function findIdentifierRange(line, startColumn) {
var pos = {
column: startColumn,
endColumn: undefined
};
if (!line) {
return pos;
}
// Look backwards
for (var i = startColumn; i >= 0; i--) {
var ch = line[i];
if (identRegex.exec(ch)) {
pos.column = i;
break;
}
}
for (var i = pos.column; i >= 0; i--) {
var ch = line[i];
if (!identRegex.exec(ch)) {
pos.column = i + 1;
break;
}
}
// And ahead
for (var i = pos.column; i <= line.length; i++) {
var ch = line[i];
if (!identRegex.exec(ch) || !ch) {
if (i !== pos.column) {
pos.endColumn = i;
}
break;
}
}
return pos;
}
/**
* Required inputs: text
*/
module.exports = function(info) {
var value = info.inputs.text;
value = value.replace(/^#!.*\n/, "\n");
if (!value) {
return [];
}
var lines = value.split("\n");
var errors = [];
// js hint reports many false errors
// report them as error only if code is actually invalid
var maxErrorLevel = isValidJS(value) ? "warning" : "error";
var globals;
if (info.options) {
globals = info.options.globals;
}
// var start = new Date();
lint(value, info.options, globals);
var results = lint.errors;
for (var i = 0; i < results.length; i++) {
var error = results[i];
if (!error) continue;
var raw = error.raw;
var type = "warning";
if (raw == "Missing semicolon.") {
var str = error.evidence.substr(error.character);
str = str.charAt(str.search(/\S/));
if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
error.reason = 'Missing ";" before statement';
type = "error";
} else {
type = "info";
}
} else if (disabledWarningsRe.test(raw)) {
continue;
} else if (infoRe.test(raw)) {
type = "info";
} else if (errorsRe.test(raw)) {
type = maxErrorLevel;
} else if (raw == "'{a}' is not defined.") {
type = "warning";
} else if (raw == "'{a}' is defined but never used.") {
type = "info";
}
var line = lines[error.line - 1];
if (line) {
// JSHint automatically converts tabs (\t) into 4 characters,
// whereas in the source file it's only one, so let's remove
// all "bonus" spaces (3 per tab) from the character position.
var match = line.match(/\t/g);
if (match) {
error.character -= match.length * 3;
}
}
var pos = findIdentifierRange(line, error.character - 1);
// console.log("Error", error, pos);
errors.push({
row: error.line - 1,
column: pos.column,
endColumn: pos.endColumn,
text: error.reason,
type: type,
raw: raw
});
}
return errors;
};