@atlisp/lint 0.1.21 → 0.1.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.
- package/dist/checks/empty-catch.js +17 -6
- package/dist/checks/unused-catch-result.js +39 -18
- package/dist/runner.d.ts +1 -0
- package/dist/runner.js +73 -7
- package/dist/visitor-runner.js +5 -9
- package/package.json +1 -1
|
@@ -61,19 +61,30 @@ function getSetqVarName(node) {
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
function hasErrorCheckInSiblings(node, varName) {
|
|
64
|
-
|
|
64
|
+
let parent = node.parent;
|
|
65
65
|
if (!parent || !parent.children)
|
|
66
66
|
return false;
|
|
67
67
|
const idx = parent.children.indexOf(node);
|
|
68
68
|
for (let i = idx + 1; i < parent.children.length; i++) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
if (containsErrorCheck(parent.children[i], varName))
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if ((0, parser_1.astIsList)(parent, 'setq')) {
|
|
73
|
+
const grandparent = parent.parent;
|
|
74
|
+
if (grandparent && grandparent.children) {
|
|
75
|
+
const parentIdx = grandparent.children.indexOf(parent);
|
|
76
|
+
for (let i = parentIdx + 1; i < grandparent.children.length; i++) {
|
|
77
|
+
if (containsErrorCheck(grandparent.children[i], varName))
|
|
78
|
+
return true;
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
return false;
|
|
78
83
|
}
|
|
84
|
+
function containsErrorCheck(node, varName) {
|
|
85
|
+
const matches = (0, parser_1.astFindAll)(node, n => (0, parser_1.astIsList)(n, 'vl-catch-all-error-p') &&
|
|
86
|
+
n.children && n.children.length >= 2 &&
|
|
87
|
+
(0, parser_1.astIsSymbol)(n.children[1], varName));
|
|
88
|
+
return matches.length > 0;
|
|
89
|
+
}
|
|
79
90
|
//# sourceMappingURL=empty-catch.js.map
|
|
@@ -2,27 +2,48 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkUnusedCatchResult = checkUnusedCatchResult;
|
|
4
4
|
const locale_1 = require("../locale");
|
|
5
|
+
const parser_1 = require("@atlisp/parser");
|
|
5
6
|
function checkUnusedCatchResult(content, file) {
|
|
6
7
|
const issues = [];
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
for (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
}
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
const catchNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'vl-catch-all-apply'));
|
|
10
|
+
for (const node of catchNodes) {
|
|
11
|
+
if (isInQuote(node))
|
|
12
|
+
continue;
|
|
13
|
+
if (isWrappedByCatchError(node))
|
|
14
|
+
continue;
|
|
15
|
+
if (isSetqStored(node))
|
|
16
|
+
continue;
|
|
17
|
+
issues.push({
|
|
18
|
+
file,
|
|
19
|
+
line: node.pos.line,
|
|
20
|
+
severity: 'warn',
|
|
21
|
+
rule: 'unused_catch_result',
|
|
22
|
+
message: (0, locale_1.t)('unused_catch_result'),
|
|
23
|
+
});
|
|
25
24
|
}
|
|
26
25
|
return issues;
|
|
27
26
|
}
|
|
27
|
+
function isInQuote(node) {
|
|
28
|
+
let p = node.parent;
|
|
29
|
+
while (p) {
|
|
30
|
+
if ((0, parser_1.astIsList)(p, 'quote'))
|
|
31
|
+
return true;
|
|
32
|
+
p = p.parent;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
function isWrappedByCatchError(node) {
|
|
37
|
+
const parent = node.parent;
|
|
38
|
+
return !!(parent && (0, parser_1.astIsList)(parent, 'vl-catch-all-error-p'));
|
|
39
|
+
}
|
|
40
|
+
function isSetqStored(node) {
|
|
41
|
+
const parent = node.parent;
|
|
42
|
+
if (!parent || !(0, parser_1.astIsList)(parent, 'setq'))
|
|
43
|
+
return false;
|
|
44
|
+
if (!parent.children || parent.children.length < 3)
|
|
45
|
+
return false;
|
|
46
|
+
const idx = parent.children.indexOf(node);
|
|
47
|
+
return idx >= 2 && idx % 2 === 0;
|
|
48
|
+
}
|
|
28
49
|
//# sourceMappingURL=unused-catch-result.js.map
|
package/dist/runner.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare function runChecks(content: string, file: string, config: LintCon
|
|
|
3
3
|
export declare function runChecksWithVisitorWrapper(content: string, file: string, config: LintConfig): Issue[];
|
|
4
4
|
export declare function lintFiles(files: string[], config: LintConfig, rootDir: string): Issue[];
|
|
5
5
|
export declare function lintFilesParallel(files: string[], config: LintConfig, rootDir: string): Promise<Issue[]>;
|
|
6
|
+
export declare const FIXABLE_RULES: Set<string>;
|
|
6
7
|
export declare function applyFixes(issues: Issue[], content: string, filepath: string): string;
|
|
7
8
|
export declare function parseIgnoreFile(rootDir: string): string[];
|
|
8
9
|
export declare function fixFile(filepath: string): string[];
|
package/dist/runner.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FIXABLE_RULES = void 0;
|
|
36
37
|
exports.runChecks = runChecks;
|
|
37
38
|
exports.runChecksWithVisitorWrapper = runChecksWithVisitorWrapper;
|
|
38
39
|
exports.lintFiles = lintFiles;
|
|
@@ -308,6 +309,16 @@ function extractForm(s, start) {
|
|
|
308
309
|
const end = findMatchingParen(s, i);
|
|
309
310
|
return [s.slice(i, end + 1), end + 1];
|
|
310
311
|
}
|
|
312
|
+
// ===== FIX APPLICATION =====
|
|
313
|
+
exports.FIXABLE_RULES = new Set([
|
|
314
|
+
'redundant_quotes', 'double_not', 'redundant_nil_else',
|
|
315
|
+
'single_arg_and_or', 'redundant_setq', 'redundant_progn',
|
|
316
|
+
'redundant_let', 'quote_style', 'redundant_if', 'misplaced_else',
|
|
317
|
+
'setq_multiple', 'append_single', 'nth_usage', 'setq_single_arg',
|
|
318
|
+
'extra_parens', 'empty_branch',
|
|
319
|
+
'comment_style', 'eq_usage', 'cond_simplify', 'self_compare',
|
|
320
|
+
'while_constant', 'redundant_list',
|
|
321
|
+
]);
|
|
311
322
|
function applyFixes(issues, content, filepath) {
|
|
312
323
|
const lines = content.split('\n');
|
|
313
324
|
const fixesByRule = new Map();
|
|
@@ -318,13 +329,7 @@ function applyFixes(issues, content, filepath) {
|
|
|
318
329
|
set.add(iss.line);
|
|
319
330
|
fixesByRule.set(iss.rule, set);
|
|
320
331
|
}
|
|
321
|
-
const fixableRules =
|
|
322
|
-
'redundant_quotes', 'double_not', 'redundant_nil_else',
|
|
323
|
-
'single_arg_and_or', 'redundant_setq', 'redundant_progn',
|
|
324
|
-
'redundant_let', 'quote_style', 'redundant_if', 'misplaced_else',
|
|
325
|
-
'setq_multiple', 'append_single', 'nth_usage', 'setq_single_arg',
|
|
326
|
-
'extra_parens', 'empty_branch',
|
|
327
|
-
]);
|
|
332
|
+
const fixableRules = exports.FIXABLE_RULES;
|
|
328
333
|
let result = content;
|
|
329
334
|
for (const [rule, lineSet] of fixesByRule) {
|
|
330
335
|
if (!fixableRules.has(rule))
|
|
@@ -503,6 +508,67 @@ function applyFixes(issues, content, filepath) {
|
|
|
503
508
|
result = replaceLine(result, idx, fixed);
|
|
504
509
|
break;
|
|
505
510
|
}
|
|
511
|
+
case 'comment_style': {
|
|
512
|
+
const fixed = lineContent.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
|
|
513
|
+
if (fixed !== lineContent)
|
|
514
|
+
result = replaceLine(result, idx, fixed);
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
case 'eq_usage': {
|
|
518
|
+
const fixed = lineContent.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
|
|
519
|
+
if (fixed !== lineContent)
|
|
520
|
+
result = replaceLine(result, idx, fixed);
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case 'cond_simplify': {
|
|
524
|
+
const condIdx = lineContent.indexOf('(cond ');
|
|
525
|
+
if (condIdx !== -1) {
|
|
526
|
+
const condEnd = findMatchingParen(lineContent, condIdx);
|
|
527
|
+
if (condEnd > condIdx) {
|
|
528
|
+
const inner = lineContent.slice(condIdx + 6, condEnd).trim();
|
|
529
|
+
const branchOpen = inner.indexOf('(');
|
|
530
|
+
if (branchOpen !== -1) {
|
|
531
|
+
const branchEnd = findMatchingParen(inner, branchOpen);
|
|
532
|
+
if (branchEnd > branchOpen) {
|
|
533
|
+
const indent = lineContent.slice(0, condIdx);
|
|
534
|
+
const branchContent = inner.slice(branchOpen + 1, branchEnd).trim();
|
|
535
|
+
const space = branchContent.search(/\s+/);
|
|
536
|
+
if (space !== -1) {
|
|
537
|
+
const testExpr = branchContent.slice(0, space);
|
|
538
|
+
const bodyExpr = branchContent.slice(space).trim();
|
|
539
|
+
const rest = lineContent.slice(condEnd + 1);
|
|
540
|
+
const fixed = indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
|
|
541
|
+
if (fixed !== lineContent)
|
|
542
|
+
result = replaceLine(result, idx, fixed);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case 'self_compare': {
|
|
551
|
+
const fixed = lineContent.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
|
|
552
|
+
if (fixed !== lineContent)
|
|
553
|
+
result = replaceLine(result, idx, fixed);
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case 'while_constant': {
|
|
557
|
+
const allLines = result.split('\n');
|
|
558
|
+
const trimmed = allLines[idx].trim();
|
|
559
|
+
const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
|
|
560
|
+
if (nilMatch) {
|
|
561
|
+
allLines[idx] = allLines[idx].replace(trimmed, 'nil');
|
|
562
|
+
result = allLines.join('\n');
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
case 'redundant_list': {
|
|
567
|
+
const fixed = lineContent.replace(/\(\s*list\s*\)/g, 'nil');
|
|
568
|
+
if (fixed !== lineContent)
|
|
569
|
+
result = replaceLine(result, idx, fixed);
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
506
572
|
}
|
|
507
573
|
}
|
|
508
574
|
}
|
package/dist/visitor-runner.js
CHANGED
|
@@ -17,7 +17,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
|
|
|
17
17
|
openCount: 0,
|
|
18
18
|
closeCount: 0,
|
|
19
19
|
setqDefs: new Map(),
|
|
20
|
-
symbolRefs: new
|
|
20
|
+
symbolRefs: new Map(),
|
|
21
21
|
condKeys: new Map(),
|
|
22
22
|
defunScopes: [],
|
|
23
23
|
letScopes: [],
|
|
@@ -379,9 +379,9 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
|
|
|
379
379
|
const seen = new Set();
|
|
380
380
|
for (let i = 1; i < node.children.length; i++) {
|
|
381
381
|
const clause = node.children[i];
|
|
382
|
-
if (clause.type !== 'list' || !clause.children || clause.children.length <
|
|
382
|
+
if (clause.type !== 'list' || !clause.children || clause.children.length < 1)
|
|
383
383
|
continue;
|
|
384
|
-
const condTest = clause.children[
|
|
384
|
+
const condTest = clause.children[0];
|
|
385
385
|
const key = getCondKey(condTest);
|
|
386
386
|
if (seen.has(key)) {
|
|
387
387
|
addIssue('cond_duplicate', clause.pos.line, (0, locale_1.t)('cond_duplicate'));
|
|
@@ -574,7 +574,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
|
|
|
574
574
|
if (checks['unused_variable'] !== 'off') {
|
|
575
575
|
visitor.on('*', node => {
|
|
576
576
|
if (node.type === 'symbol' && node.name) {
|
|
577
|
-
state.symbolRefs.
|
|
577
|
+
state.symbolRefs.set(node.name, (state.symbolRefs.get(node.name) || 0) + 1);
|
|
578
578
|
}
|
|
579
579
|
});
|
|
580
580
|
}
|
|
@@ -672,11 +672,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
|
|
|
672
672
|
if (checks['unused_variable'] !== 'off') {
|
|
673
673
|
for (const [name, def] of state.setqDefs) {
|
|
674
674
|
if (state.setqDefs.size > 1) {
|
|
675
|
-
|
|
676
|
-
for (const ref of state.symbolRefs) {
|
|
677
|
-
if (ref === name)
|
|
678
|
-
refCount++;
|
|
679
|
-
}
|
|
675
|
+
const refCount = state.symbolRefs.get(name) || 0;
|
|
680
676
|
if (refCount <= 1) {
|
|
681
677
|
addIssue('unused_variable', def.line, (0, locale_1.t)('unused_variable', name));
|
|
682
678
|
}
|