@atlisp/lint 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,39 +2,98 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkStringConcatInLoop = checkStringConcatInLoop;
|
|
4
4
|
const locale_1 = require("../locale");
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function maskLine(line) {
|
|
6
|
+
let out = '';
|
|
7
|
+
let inString = false;
|
|
8
|
+
for (let k = 0; k < line.length; k++) {
|
|
9
|
+
const ch = line[k];
|
|
10
|
+
if (inString) {
|
|
11
|
+
if (ch === '\\') {
|
|
12
|
+
out += ' ';
|
|
13
|
+
k++;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
if (ch === '"')
|
|
17
|
+
inString = false;
|
|
18
|
+
out += ' ';
|
|
19
|
+
}
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (ch === '"') {
|
|
23
|
+
inString = true;
|
|
24
|
+
out += ' ';
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (ch === ';')
|
|
28
|
+
break;
|
|
29
|
+
out += ch;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
function findLoops(lines) {
|
|
34
|
+
const loops = [];
|
|
8
35
|
const re = /\((while|repeat|foreach)\s/g;
|
|
9
36
|
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const masked = maskLine(lines[i]);
|
|
10
38
|
let match;
|
|
11
|
-
while ((match = re.exec(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
39
|
+
while ((match = re.exec(masked)) !== null) {
|
|
40
|
+
loops.push({ name: match[1], line: i, col: match.index });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return loops;
|
|
44
|
+
}
|
|
45
|
+
// Find the line index where the form opening at (startLine, startCol) closes.
|
|
46
|
+
// Returns -1 if the form is never closed (unbalanced input).
|
|
47
|
+
function findFormEnd(lines, startLine, startCol) {
|
|
48
|
+
let depth = 0;
|
|
49
|
+
let inString = false;
|
|
50
|
+
for (let j = startLine; j < lines.length; j++) {
|
|
51
|
+
const line = lines[j];
|
|
52
|
+
const begin = j === startLine ? startCol : 0;
|
|
53
|
+
for (let k = begin; k < line.length; k++) {
|
|
54
|
+
const ch = line[k];
|
|
55
|
+
if (inString) {
|
|
56
|
+
if (ch === '\\') {
|
|
57
|
+
k++;
|
|
58
|
+
}
|
|
59
|
+
else if (ch === '"') {
|
|
60
|
+
inString = false;
|
|
22
61
|
}
|
|
23
|
-
|
|
24
|
-
started = true;
|
|
25
|
-
if (depth === 0 && started)
|
|
26
|
-
break;
|
|
62
|
+
continue;
|
|
27
63
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
file,
|
|
32
|
-
line: i + 1,
|
|
33
|
-
severity: 'info',
|
|
34
|
-
rule: 'string_concat_loop',
|
|
35
|
-
message: (0, locale_1.t)('string_concat_loop', name),
|
|
36
|
-
});
|
|
64
|
+
if (ch === '"') {
|
|
65
|
+
inString = true;
|
|
66
|
+
continue;
|
|
37
67
|
}
|
|
68
|
+
if (ch === ';')
|
|
69
|
+
break;
|
|
70
|
+
if (ch === '(')
|
|
71
|
+
depth++;
|
|
72
|
+
else if (ch === ')') {
|
|
73
|
+
depth--;
|
|
74
|
+
if (depth === 0)
|
|
75
|
+
return j;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return -1;
|
|
80
|
+
}
|
|
81
|
+
function checkStringConcatInLoop(content, file) {
|
|
82
|
+
const issues = [];
|
|
83
|
+
const lines = content.split('\n');
|
|
84
|
+
for (const loop of findLoops(lines)) {
|
|
85
|
+
const end = findFormEnd(lines, loop.line, loop.col);
|
|
86
|
+
if (end < 0)
|
|
87
|
+
continue;
|
|
88
|
+
const loopBody = lines.slice(loop.line, end + 1).join('\n');
|
|
89
|
+
if (loopBody.includes('(strcat')) {
|
|
90
|
+
issues.push({
|
|
91
|
+
file,
|
|
92
|
+
line: loop.line + 1,
|
|
93
|
+
severity: 'info',
|
|
94
|
+
rule: 'string_concat_loop',
|
|
95
|
+
message: (0, locale_1.t)('string_concat_loop', loop.name),
|
|
96
|
+
});
|
|
38
97
|
}
|
|
39
98
|
}
|
|
40
99
|
return issues;
|