@atlisp/lint 0.2.12 → 0.2.13
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.
- package/atlisp-lint.schema.json +27 -4
- package/dist/cache.js +19 -9
- package/dist/checks/builtin-arg-count.d.ts +1 -0
- package/dist/checks/builtin-arg-count.js +5 -0
- package/dist/checks/dangerous-calls.js +1 -0
- package/dist/checks/global-function-naming.js +159 -35
- package/dist/checks/missing-princ.js +2 -2
- package/dist/checks/nth-usage.d.ts +1 -0
- package/dist/checks/nth-usage.js +16 -1
- package/dist/cli/collector.d.ts +7 -0
- package/dist/cli/collector.js +154 -0
- package/dist/cli/parser.d.ts +30 -0
- package/dist/cli/parser.js +119 -0
- package/dist/config.js +28 -6
- package/dist/disable.js +12 -0
- package/dist/fixes/index.d.ts +8 -0
- package/dist/fixes/index.js +200 -0
- package/dist/index.js +56 -236
- package/dist/locale.js +30 -2
- package/dist/presets.js +24 -0
- package/dist/project.js +64 -34
- package/dist/rules.d.ts +1 -0
- package/dist/rules.js +85 -0
- package/dist/runner.d.ts +2 -3
- package/dist/runner.js +46 -371
- package/dist/types.d.ts +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +43 -0
- package/dist/validate.js +12 -0
- package/dist/visitor-runner.d.ts +28 -0
- package/dist/visitor-runner.js +115 -1
- package/dist/visitors/equal-nil.d.ts +8 -0
- package/dist/visitors/equal-nil.js +26 -0
- package/dist/visitors/index.d.ts +5 -0
- package/dist/visitors/index.js +14 -0
- package/dist/visitors/progn-in-cond.d.ts +8 -0
- package/dist/visitors/progn-in-cond.js +33 -0
- package/dist/visitors/redundant-and-or.d.ts +8 -0
- package/dist/visitors/redundant-and-or.js +27 -0
- package/dist/visitors/redundant-car-cdr.d.ts +8 -0
- package/dist/visitors/redundant-car-cdr.js +35 -0
- package/dist/visitors/types.d.ts +13 -0
- package/dist/visitors/types.js +72 -0
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArgs = parseArgs;
|
|
4
|
+
function parseArgs() {
|
|
5
|
+
const argv = process.argv.slice(2);
|
|
6
|
+
const opts = {
|
|
7
|
+
src: [],
|
|
8
|
+
test: [],
|
|
9
|
+
staged: false,
|
|
10
|
+
diff: false,
|
|
11
|
+
changed: '',
|
|
12
|
+
format: 'default',
|
|
13
|
+
init: false,
|
|
14
|
+
installHook: false,
|
|
15
|
+
fix: false,
|
|
16
|
+
hookArgs: '',
|
|
17
|
+
cache: false,
|
|
18
|
+
clearCache: false,
|
|
19
|
+
parallel: false,
|
|
20
|
+
project: false,
|
|
21
|
+
watch: false,
|
|
22
|
+
help: false,
|
|
23
|
+
version: false,
|
|
24
|
+
formatCode: false,
|
|
25
|
+
formatCheck: false,
|
|
26
|
+
sbcl: false,
|
|
27
|
+
docs: false,
|
|
28
|
+
listRules: false,
|
|
29
|
+
explain: '',
|
|
30
|
+
dryRun: false,
|
|
31
|
+
maxWarnings: -1,
|
|
32
|
+
};
|
|
33
|
+
for (let i = 0; i < argv.length; i++) {
|
|
34
|
+
switch (argv[i]) {
|
|
35
|
+
case '--src':
|
|
36
|
+
opts.src.push(argv[++i]);
|
|
37
|
+
break;
|
|
38
|
+
case '--test':
|
|
39
|
+
opts.test.push(argv[++i]);
|
|
40
|
+
break;
|
|
41
|
+
case '--config':
|
|
42
|
+
opts.config = argv[++i];
|
|
43
|
+
break;
|
|
44
|
+
case '--staged':
|
|
45
|
+
opts.staged = true;
|
|
46
|
+
break;
|
|
47
|
+
case '--diff':
|
|
48
|
+
opts.diff = true;
|
|
49
|
+
break;
|
|
50
|
+
case '--changed':
|
|
51
|
+
opts.changed = argv[++i] || 'main';
|
|
52
|
+
break;
|
|
53
|
+
case '--format':
|
|
54
|
+
opts.format = argv[++i];
|
|
55
|
+
break;
|
|
56
|
+
case '--init':
|
|
57
|
+
opts.init = true;
|
|
58
|
+
break;
|
|
59
|
+
case '--install-hook':
|
|
60
|
+
opts.installHook = true;
|
|
61
|
+
break;
|
|
62
|
+
case '--fix':
|
|
63
|
+
opts.fix = true;
|
|
64
|
+
break;
|
|
65
|
+
case '--hook-args':
|
|
66
|
+
opts.hookArgs = argv[++i];
|
|
67
|
+
break;
|
|
68
|
+
case '--cache':
|
|
69
|
+
opts.cache = true;
|
|
70
|
+
break;
|
|
71
|
+
case '--clear-cache':
|
|
72
|
+
opts.clearCache = true;
|
|
73
|
+
break;
|
|
74
|
+
case '--parallel':
|
|
75
|
+
opts.parallel = true;
|
|
76
|
+
break;
|
|
77
|
+
case '--project':
|
|
78
|
+
opts.project = true;
|
|
79
|
+
break;
|
|
80
|
+
case '--watch':
|
|
81
|
+
opts.watch = true;
|
|
82
|
+
break;
|
|
83
|
+
case '--help':
|
|
84
|
+
opts.help = true;
|
|
85
|
+
break;
|
|
86
|
+
case '--version':
|
|
87
|
+
opts.version = true;
|
|
88
|
+
break;
|
|
89
|
+
case '--format-code':
|
|
90
|
+
opts.formatCode = true;
|
|
91
|
+
break;
|
|
92
|
+
case '--format-check':
|
|
93
|
+
opts.formatCheck = true;
|
|
94
|
+
break;
|
|
95
|
+
case '--sbcl':
|
|
96
|
+
opts.sbcl = true;
|
|
97
|
+
break;
|
|
98
|
+
case '--docs':
|
|
99
|
+
opts.docs = true;
|
|
100
|
+
break;
|
|
101
|
+
case '--list-rules':
|
|
102
|
+
opts.listRules = true;
|
|
103
|
+
break;
|
|
104
|
+
case '--explain':
|
|
105
|
+
opts.explain = argv[++i];
|
|
106
|
+
break;
|
|
107
|
+
case '--dry-run':
|
|
108
|
+
opts.dryRun = true;
|
|
109
|
+
break;
|
|
110
|
+
case '--max-warnings':
|
|
111
|
+
opts.maxWarnings = parseInt(argv[++i], 10);
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return opts;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=parser.js.map
|
package/dist/config.js
CHANGED
|
@@ -65,6 +65,18 @@ const DEFAULT_CONFIG = {
|
|
|
65
65
|
missing_doc: 'info',
|
|
66
66
|
trailing_whitespace: 'info',
|
|
67
67
|
undeclared_setq: 'warn',
|
|
68
|
+
command_s: 'warn',
|
|
69
|
+
zerop_usage: 'info',
|
|
70
|
+
progn_in_body: 'info',
|
|
71
|
+
if_progn_both: 'info',
|
|
72
|
+
redundant_cond: 'info',
|
|
73
|
+
selection_set_leak: 'warn',
|
|
74
|
+
empty_branch_cond: 'warn',
|
|
75
|
+
function_reference: 'warn',
|
|
76
|
+
progn_in_cond: 'info',
|
|
77
|
+
redundant_car_cdr: 'info',
|
|
78
|
+
equal_nil: 'info',
|
|
79
|
+
redundant_and_or: 'info',
|
|
68
80
|
module_registration: 'off',
|
|
69
81
|
namespace_header: 'off',
|
|
70
82
|
unused_parameter: 'warn',
|
|
@@ -152,6 +164,7 @@ const DEFAULT_CONFIG = {
|
|
|
152
164
|
command_shell: 'warn',
|
|
153
165
|
startapp: 'warn',
|
|
154
166
|
vl_registry_write: 'warn',
|
|
167
|
+
eval: 'warn',
|
|
155
168
|
},
|
|
156
169
|
module_registration: {
|
|
157
170
|
severity: 'off',
|
|
@@ -219,13 +232,22 @@ function getCheckSeverity(config, rule) {
|
|
|
219
232
|
return config.checks[rule] || 'off';
|
|
220
233
|
}
|
|
221
234
|
function findOverrides(filepath) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
235
|
+
let dir = path.dirname(filepath);
|
|
236
|
+
for (;;) {
|
|
237
|
+
const configPath = path.join(dir, '.atlisp-lint.json');
|
|
238
|
+
if (fs.existsSync(configPath)) {
|
|
239
|
+
try {
|
|
240
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const parent = path.dirname(dir);
|
|
247
|
+
if (parent === dir)
|
|
248
|
+
return null;
|
|
249
|
+
dir = parent;
|
|
227
250
|
}
|
|
228
|
-
return null;
|
|
229
251
|
}
|
|
230
252
|
function mergeOverrides(base, overrides) {
|
|
231
253
|
const merged = JSON.parse(JSON.stringify(base));
|
package/dist/disable.js
CHANGED
|
@@ -7,6 +7,18 @@ function parseDisableComments(content, fileLine) {
|
|
|
7
7
|
const lines = content.split('\n');
|
|
8
8
|
for (let i = 0; i < lines.length; i++) {
|
|
9
9
|
const line = lines[i];
|
|
10
|
+
const disableFileM = line.match(/;\s*atlisp-lint:\s*disable-file=(.+)/i);
|
|
11
|
+
if (disableFileM) {
|
|
12
|
+
const rules = disableFileM[1]
|
|
13
|
+
.split(',')
|
|
14
|
+
.map(r => r.trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
for (const rule of rules) {
|
|
17
|
+
if (!map.has(rule))
|
|
18
|
+
map.set(rule, new Set());
|
|
19
|
+
map.get(rule).add(0);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
10
22
|
const m = line.match(/;\s*atlisp-lint:\s*disable=(.+)/i);
|
|
11
23
|
if (!m)
|
|
12
24
|
continue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
export type FixResult = string | null;
|
|
3
|
+
export interface FixProvider {
|
|
4
|
+
(line: string): string;
|
|
5
|
+
}
|
|
6
|
+
export declare const FIXABLE_RULES: Set<string>;
|
|
7
|
+
export declare function applyFixesFromProviders(issues: Issue[], content: string, filepath: string): string;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FIXABLE_RULES = void 0;
|
|
4
|
+
exports.applyFixesFromProviders = applyFixesFromProviders;
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const nth_usage_1 = require("../checks/nth-usage");
|
|
7
|
+
const FIX_PROVIDERS = {
|
|
8
|
+
redundant_quotes(line) {
|
|
9
|
+
return line.replace(/''(\S)/g, "'$1");
|
|
10
|
+
},
|
|
11
|
+
double_not(line) {
|
|
12
|
+
return line.replace(/\(not\s+\(not\s+/g, '(not ');
|
|
13
|
+
},
|
|
14
|
+
redundant_nil_else(line) {
|
|
15
|
+
return line.replace(/\s+nil\s*\)$/, ')');
|
|
16
|
+
},
|
|
17
|
+
single_arg_and_or(line) {
|
|
18
|
+
const m = line.match(/\((and|or)\s+([^)\s]+)\s*\)/);
|
|
19
|
+
return m ? m[2] : line;
|
|
20
|
+
},
|
|
21
|
+
redundant_progn(line) {
|
|
22
|
+
const proIdx = line.indexOf('(progn ');
|
|
23
|
+
if (proIdx === -1)
|
|
24
|
+
return line;
|
|
25
|
+
const beforePro = line.slice(0, proIdx);
|
|
26
|
+
const close = (0, utils_1.findMatchingParen)(line, proIdx);
|
|
27
|
+
if (close <= proIdx)
|
|
28
|
+
return line;
|
|
29
|
+
const inner = line.slice(proIdx + 7, close);
|
|
30
|
+
const rest = line.slice(close + 1);
|
|
31
|
+
return beforePro + inner + rest;
|
|
32
|
+
},
|
|
33
|
+
redundant_let(line) {
|
|
34
|
+
return line.replace(/\(let\s+\(\)\s*/, '(progn ');
|
|
35
|
+
},
|
|
36
|
+
quote_style(line) {
|
|
37
|
+
const qIdx = line.indexOf('(quote ');
|
|
38
|
+
if (qIdx === -1)
|
|
39
|
+
return line;
|
|
40
|
+
const beforeQ = line.slice(0, qIdx);
|
|
41
|
+
const close = (0, utils_1.findMatchingParen)(line, qIdx);
|
|
42
|
+
if (close <= qIdx)
|
|
43
|
+
return line;
|
|
44
|
+
const quoted = line.slice(qIdx + 7, close);
|
|
45
|
+
const rest = line.slice(close + 1);
|
|
46
|
+
return beforeQ + "'" + quoted + rest;
|
|
47
|
+
},
|
|
48
|
+
redundant_if(line) {
|
|
49
|
+
const pIdx = line.indexOf('(progn ');
|
|
50
|
+
if (pIdx === -1)
|
|
51
|
+
return line;
|
|
52
|
+
const beforeP = line.slice(0, pIdx);
|
|
53
|
+
const close = (0, utils_1.findMatchingParen)(line, pIdx);
|
|
54
|
+
if (close <= pIdx)
|
|
55
|
+
return line;
|
|
56
|
+
const inner = line.slice(pIdx + 7, close);
|
|
57
|
+
const rest = line.slice(close + 1);
|
|
58
|
+
return beforeP + inner + rest;
|
|
59
|
+
},
|
|
60
|
+
misplaced_else(line) {
|
|
61
|
+
const ifStart = line.indexOf('(if (not ');
|
|
62
|
+
if (ifStart === -1)
|
|
63
|
+
return line;
|
|
64
|
+
const notIdx = line.indexOf('(not ', ifStart);
|
|
65
|
+
if (notIdx === -1)
|
|
66
|
+
return line;
|
|
67
|
+
const notClose = (0, utils_1.findMatchingParen)(line, notIdx);
|
|
68
|
+
if (notClose <= notIdx)
|
|
69
|
+
return line;
|
|
70
|
+
const ifClose = (0, utils_1.findMatchingParen)(line, ifStart);
|
|
71
|
+
if (ifClose <= ifStart)
|
|
72
|
+
return line;
|
|
73
|
+
const indent = line.slice(0, ifStart);
|
|
74
|
+
const condVar = line.slice(notIdx + 5, notClose);
|
|
75
|
+
const branchContent = line.slice(notClose + 1, ifClose).trim();
|
|
76
|
+
const [thenForm, thenEnd] = (0, utils_1.extractForm)(branchContent, 0);
|
|
77
|
+
const elseForm = branchContent.slice(thenEnd).trim();
|
|
78
|
+
if (!thenForm || !elseForm)
|
|
79
|
+
return line;
|
|
80
|
+
const rest = line.slice(ifClose + 1);
|
|
81
|
+
return indent + '(if ' + condVar + ' ' + elseForm + ' ' + thenForm + ')' + rest;
|
|
82
|
+
},
|
|
83
|
+
setq_multiple(line) {
|
|
84
|
+
const fixed = line.replace(/\)\(setq\s+/g, ' ');
|
|
85
|
+
if (fixed === line)
|
|
86
|
+
return line;
|
|
87
|
+
const merged = line.replace(/^\(\s*setq\s+/, '(setq ');
|
|
88
|
+
if (merged.includes('setq') && !merged.match(/\)\(/))
|
|
89
|
+
return merged;
|
|
90
|
+
return line.replace(/\)\(setq\s+/g, '\n');
|
|
91
|
+
},
|
|
92
|
+
append_single(line) {
|
|
93
|
+
const aIdx = line.indexOf('(append ');
|
|
94
|
+
if (aIdx === -1)
|
|
95
|
+
return line;
|
|
96
|
+
const close = (0, utils_1.findMatchingParen)(line, aIdx);
|
|
97
|
+
if (close <= aIdx)
|
|
98
|
+
return line;
|
|
99
|
+
const inner = line.slice(aIdx + 8, close);
|
|
100
|
+
const listMatch = inner.match(/^\(list\s+(.*)\)\s*$/);
|
|
101
|
+
if (!listMatch)
|
|
102
|
+
return line;
|
|
103
|
+
return line.slice(0, aIdx) + '(cons ' + listMatch[1] + ')' + line.slice(close + 1);
|
|
104
|
+
},
|
|
105
|
+
nth_usage(line) {
|
|
106
|
+
return (0, nth_usage_1.replaceNthUsage)(line) || line;
|
|
107
|
+
},
|
|
108
|
+
setq_single_arg(line) {
|
|
109
|
+
return line;
|
|
110
|
+
},
|
|
111
|
+
extra_parens(line) {
|
|
112
|
+
return line.replace(/\){2,}/g, ')');
|
|
113
|
+
},
|
|
114
|
+
empty_branch(line) {
|
|
115
|
+
return line.replace(/\(if\s+\S+\s*\)/g, m => m.slice(0, -1) + ' nil)');
|
|
116
|
+
},
|
|
117
|
+
comment_style(line) {
|
|
118
|
+
return line.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
|
|
119
|
+
},
|
|
120
|
+
eq_usage(line) {
|
|
121
|
+
return line.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
|
|
122
|
+
},
|
|
123
|
+
cond_simplify(line) {
|
|
124
|
+
const condIdx = line.indexOf('(cond ');
|
|
125
|
+
if (condIdx === -1)
|
|
126
|
+
return line;
|
|
127
|
+
const condEnd = (0, utils_1.findMatchingParen)(line, condIdx);
|
|
128
|
+
if (condEnd <= condIdx)
|
|
129
|
+
return line;
|
|
130
|
+
const inner = line.slice(condIdx + 6, condEnd).trim();
|
|
131
|
+
const branchOpen = inner.indexOf('(');
|
|
132
|
+
if (branchOpen === -1)
|
|
133
|
+
return line;
|
|
134
|
+
const branchEnd = (0, utils_1.findMatchingParen)(inner, branchOpen);
|
|
135
|
+
if (branchEnd <= branchOpen)
|
|
136
|
+
return line;
|
|
137
|
+
const indent = line.slice(0, condIdx);
|
|
138
|
+
const branchContent = inner.slice(branchOpen + 1, branchEnd).trim();
|
|
139
|
+
const space = branchContent.search(/\s+/);
|
|
140
|
+
if (space === -1)
|
|
141
|
+
return line;
|
|
142
|
+
const testExpr = branchContent.slice(0, space);
|
|
143
|
+
const bodyExpr = branchContent.slice(space).trim();
|
|
144
|
+
const rest = line.slice(condEnd + 1);
|
|
145
|
+
return indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
|
|
146
|
+
},
|
|
147
|
+
self_compare(line) {
|
|
148
|
+
return line.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
|
|
149
|
+
},
|
|
150
|
+
while_constant(line) {
|
|
151
|
+
const trimmed = line.trim();
|
|
152
|
+
const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
|
|
153
|
+
if (!nilMatch)
|
|
154
|
+
return line;
|
|
155
|
+
return line.replace(trimmed, 'nil');
|
|
156
|
+
},
|
|
157
|
+
redundant_list(line) {
|
|
158
|
+
return line.replace(/\(\s*list\s*\)/g, 'nil');
|
|
159
|
+
},
|
|
160
|
+
zerop_usage(line) {
|
|
161
|
+
return line.replace(/\(=\s+(\S+)\s+0\s*\)/g, '(zerop $1)').replace(/\(=\s+0\s+(\S+)\s*\)/g, '(zerop $1)');
|
|
162
|
+
},
|
|
163
|
+
redundant_cond(line) {
|
|
164
|
+
const m = line.match(/^(\s*)\(cond\s+\(\(([^)]+)\)\s+\(([^)]*)\)\s*\)\s*\)$/);
|
|
165
|
+
if (!m)
|
|
166
|
+
return line;
|
|
167
|
+
return `${m[1]}(if (${m[2]}) (${m[3]}))`;
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
exports.FIXABLE_RULES = new Set(Object.keys(FIX_PROVIDERS));
|
|
171
|
+
function applyFixesFromProviders(issues, content, filepath) {
|
|
172
|
+
const lines = content.split('\n');
|
|
173
|
+
const fixedLines = new Set();
|
|
174
|
+
const fixesByRule = new Map();
|
|
175
|
+
for (const iss of issues) {
|
|
176
|
+
if (iss.file !== filepath)
|
|
177
|
+
continue;
|
|
178
|
+
const set = fixesByRule.get(iss.rule) || new Set();
|
|
179
|
+
set.add(iss.line);
|
|
180
|
+
fixesByRule.set(iss.rule, set);
|
|
181
|
+
}
|
|
182
|
+
for (const [rule, lineSet] of fixesByRule) {
|
|
183
|
+
const provider = FIX_PROVIDERS[rule];
|
|
184
|
+
if (!provider)
|
|
185
|
+
continue;
|
|
186
|
+
const sortedLines = Array.from(lineSet).sort((a, b) => b - a);
|
|
187
|
+
for (const line of sortedLines) {
|
|
188
|
+
const idx = line - 1;
|
|
189
|
+
if (idx < 0 || idx >= lines.length)
|
|
190
|
+
continue;
|
|
191
|
+
const fixed = provider(lines[idx]);
|
|
192
|
+
if (fixed !== lines[idx]) {
|
|
193
|
+
lines[idx] = fixed;
|
|
194
|
+
fixedLines.add(idx);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return lines.join('\n');
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=index.js.map
|