@atlisp/lint 0.1.5 → 0.1.6
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/LICENSE +21 -0
- package/README.md +182 -58
- package/atlisp-lint.default.json +31 -1
- package/dist/atlisp-lint.default.json +90 -0
- package/dist/cache.d.ts +2 -2
- package/dist/cache.js +6 -6
- package/dist/checks/append-single.d.ts +3 -0
- package/dist/checks/append-single.js +17 -0
- package/dist/checks/arg-count.d.ts +3 -0
- package/dist/checks/arg-count.js +123 -0
- package/dist/checks/assoc-without-cdr.d.ts +5 -0
- package/dist/checks/assoc-without-cdr.js +32 -0
- package/dist/checks/comment-style.d.ts +3 -0
- package/dist/checks/comment-style.js +24 -0
- package/dist/checks/cond-duplicate.d.ts +5 -0
- package/dist/checks/cond-duplicate.js +52 -0
- package/dist/checks/cond-simplify.d.ts +3 -0
- package/dist/checks/cond-simplify.js +45 -0
- package/dist/checks/constant-condition.js +4 -4
- package/dist/checks/dangerous-calls.js +2 -2
- package/dist/checks/dangling-defun.d.ts +3 -0
- package/dist/checks/dangling-defun.js +10 -28
- package/dist/checks/double-not.js +1 -1
- package/dist/checks/duplicate-defun.d.ts +6 -0
- package/dist/checks/duplicate-defun.js +50 -0
- package/dist/checks/dynamic-doc.d.ts +3 -0
- package/dist/checks/dynamic-doc.js +21 -0
- package/dist/checks/empty-branch.js +1 -1
- package/dist/checks/empty-catch.d.ts +3 -0
- package/dist/checks/empty-catch.js +34 -0
- package/dist/checks/eq-usage.d.ts +3 -0
- package/dist/checks/eq-usage.js +25 -0
- package/dist/checks/error-handling.d.ts +3 -0
- package/dist/checks/error-handling.js +56 -0
- package/dist/checks/extra-parens.d.ts +3 -0
- package/dist/checks/extra-parens.js +45 -0
- package/dist/checks/function-complexity.js +1 -1
- package/dist/checks/function-order.d.ts +3 -0
- package/dist/checks/function-order.js +33 -0
- package/dist/checks/global-naming.d.ts +3 -0
- package/dist/checks/global-naming.js +62 -0
- package/dist/checks/identical-branches.d.ts +5 -0
- package/dist/checks/identical-branches.js +54 -0
- package/dist/checks/index.d.ts +3 -0
- package/dist/checks/index.js +117 -0
- package/dist/checks/lambda-syntax.d.ts +3 -0
- package/dist/checks/lambda-syntax.js +25 -0
- package/dist/checks/long-function-call.d.ts +3 -0
- package/dist/checks/long-function-call.js +54 -0
- package/dist/checks/loop-optimization.d.ts +3 -0
- package/dist/checks/loop-optimization.js +17 -0
- package/dist/checks/magic-number.d.ts +3 -0
- package/dist/checks/magic-number.js +21 -0
- package/dist/checks/misplaced-else.js +1 -1
- package/dist/checks/missing-export.js +2 -2
- package/dist/checks/mixed-indent.d.ts +3 -0
- package/dist/checks/mixed-indent.js +19 -0
- package/dist/checks/module-reg.js +1 -1
- package/dist/checks/multiple-setq.js +1 -1
- package/dist/checks/no-return.d.ts +3 -0
- package/dist/checks/no-return.js +51 -0
- package/dist/checks/nth-usage.d.ts +3 -0
- package/dist/checks/nth-usage.js +17 -0
- package/dist/checks/quote-style.d.ts +3 -0
- package/dist/checks/quote-style.js +25 -0
- package/dist/checks/quote-vs-function.js +1 -1
- package/dist/checks/recursive-call.js +1 -1
- package/dist/checks/redundant-if.d.ts +3 -0
- package/dist/checks/redundant-if.js +17 -0
- package/dist/checks/redundant-let.js +1 -1
- package/dist/checks/redundant-nil-else.js +1 -1
- package/dist/checks/redundant-progn.js +1 -1
- package/dist/checks/redundant-quotes.js +1 -1
- package/dist/checks/redundant-setq.js +1 -1
- package/dist/checks/self-compare.js +1 -1
- package/dist/checks/setq-multiple.d.ts +3 -0
- package/dist/checks/setq-multiple.js +17 -0
- package/dist/checks/setq-single-arg.d.ts +5 -0
- package/dist/checks/setq-single-arg.js +30 -0
- package/dist/checks/shadow-builtin.d.ts +3 -0
- package/dist/checks/shadow-builtin.js +77 -0
- package/dist/checks/single-arg-and-or.js +1 -1
- package/dist/checks/strcat-usage.d.ts +3 -0
- package/dist/checks/strcat-usage.js +25 -0
- package/dist/checks/type-check.d.ts +3 -0
- package/dist/checks/type-check.js +26 -0
- package/dist/checks/unused-let.js +1 -1
- package/dist/checks/unused-package-dep.js +3 -3
- package/dist/checks/variable-shadow.js +1 -1
- package/dist/checks/while-constant.d.ts +5 -0
- package/dist/checks/while-constant.js +40 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +70 -2
- package/dist/disable.js +1 -1
- package/dist/formatters.d.ts +1 -0
- package/dist/formatters.js +18 -2
- package/dist/index.js +53 -13
- package/dist/lib/lint-sbcl.lisp +161 -0
- package/dist/locale.js +24 -0
- package/dist/presets.d.ts +4 -0
- package/dist/presets.js +158 -0
- package/dist/project.js +37 -6
- package/dist/rules.d.ts +9 -0
- package/dist/rules.js +238 -0
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +198 -11
- package/dist/sbcl.js +1 -1
- package/dist/stub-packages.json +41 -0
- package/dist/types.d.ts +6 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.js +125 -0
- package/dist/watch.d.ts +9 -0
- package/dist/watch.js +113 -0
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ function checkRedundantQuotes(content, file) {
|
|
|
11
11
|
function checkRedundantQuotesAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
13
|
// ''x → (quote (quote x)) — nested quote
|
|
14
|
-
const doubleQuotes = (0, parser_1.astFindAll)(ast,
|
|
14
|
+
const doubleQuotes = (0, parser_1.astFindAll)(ast, n => {
|
|
15
15
|
if (!(0, parser_1.astIsList)(n, 'quote'))
|
|
16
16
|
return false;
|
|
17
17
|
if (!n.children || n.children.length < 2)
|
|
@@ -10,7 +10,7 @@ function checkRedundantSetq(content, file) {
|
|
|
10
10
|
}
|
|
11
11
|
function checkRedundantSetqAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
|
-
const setqNodes = (0, parser_1.astFindAll)(ast,
|
|
13
|
+
const setqNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'setq'));
|
|
14
14
|
for (const node of setqNodes) {
|
|
15
15
|
if (!node.children)
|
|
16
16
|
continue;
|
|
@@ -12,7 +12,7 @@ function checkSelfCompare(content, file) {
|
|
|
12
12
|
function checkSelfCompareAst(ast, file) {
|
|
13
13
|
const issues = [];
|
|
14
14
|
for (const fn of COMPARE_FUNCTIONS) {
|
|
15
|
-
const nodes = (0, parser_1.astFindAll)(ast,
|
|
15
|
+
const nodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, fn));
|
|
16
16
|
for (const node of nodes) {
|
|
17
17
|
if (!node.children)
|
|
18
18
|
continue;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkSetqMultiple = checkSetqMultiple;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkSetqMultiple(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
for (let i = 0; i < lines.length; i++) {
|
|
10
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
11
|
+
if (/\(setq\s+\S+\s+[^\s)]+\)\s*\(setq\b/.test(stripped)) {
|
|
12
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'setq_multiple', message: (0, locale_1.t)('setq_multiple') });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return issues;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=setq-multiple.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkSetqSingleArg(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkSetqSingleArgAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=setq-single-arg.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkSetqSingleArg = checkSetqSingleArg;
|
|
4
|
+
exports.checkSetqSingleArgAst = checkSetqSingleArgAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkSetqSingleArg(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkSetqSingleArgAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkSetqSingleArgAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
const nodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'setq'));
|
|
14
|
+
for (const node of nodes) {
|
|
15
|
+
if (!node.children)
|
|
16
|
+
continue;
|
|
17
|
+
// (setq x) — 2 children: 'setq', x — missing value
|
|
18
|
+
if (node.children.length === 2) {
|
|
19
|
+
issues.push({
|
|
20
|
+
file,
|
|
21
|
+
line: node.pos.line,
|
|
22
|
+
severity: 'warn',
|
|
23
|
+
rule: 'setq_single_arg',
|
|
24
|
+
message: (0, locale_1.t)('setq_single_arg', node.children[1].name || ''),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return issues;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=setq-single-arg.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkShadowBuiltin = checkShadowBuiltin;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const BUILTINS = new Set([
|
|
7
|
+
'car',
|
|
8
|
+
'cdr',
|
|
9
|
+
'cons',
|
|
10
|
+
'list',
|
|
11
|
+
'append',
|
|
12
|
+
'length',
|
|
13
|
+
'member',
|
|
14
|
+
'assoc',
|
|
15
|
+
'subst',
|
|
16
|
+
'apply',
|
|
17
|
+
'mapcar',
|
|
18
|
+
'foreach',
|
|
19
|
+
'while',
|
|
20
|
+
'repeat',
|
|
21
|
+
'if',
|
|
22
|
+
'cond',
|
|
23
|
+
'progn',
|
|
24
|
+
'setq',
|
|
25
|
+
'set',
|
|
26
|
+
'quote',
|
|
27
|
+
'function',
|
|
28
|
+
'lambda',
|
|
29
|
+
'defun',
|
|
30
|
+
'princ',
|
|
31
|
+
'print',
|
|
32
|
+
'prompt',
|
|
33
|
+
'getint',
|
|
34
|
+
'getreal',
|
|
35
|
+
'getstring',
|
|
36
|
+
'getpoint',
|
|
37
|
+
'getvar',
|
|
38
|
+
'setvar',
|
|
39
|
+
'command',
|
|
40
|
+
'vlax-',
|
|
41
|
+
'vla-',
|
|
42
|
+
'vl-',
|
|
43
|
+
'ssget',
|
|
44
|
+
'ssname',
|
|
45
|
+
'sslength',
|
|
46
|
+
'entget',
|
|
47
|
+
'entmod',
|
|
48
|
+
'entmake',
|
|
49
|
+
'entdel',
|
|
50
|
+
'entlast',
|
|
51
|
+
'entsel',
|
|
52
|
+
'tblobjname',
|
|
53
|
+
'tblsearch',
|
|
54
|
+
'tblnext',
|
|
55
|
+
'regapp',
|
|
56
|
+
'startapp',
|
|
57
|
+
'vl-registry-write',
|
|
58
|
+
'vl-registry-read',
|
|
59
|
+
'vl-registry-delete',
|
|
60
|
+
'vl-catch-all-apply',
|
|
61
|
+
'vl-catch-all-error-p',
|
|
62
|
+
'vl-load-com',
|
|
63
|
+
'vlax-get-or-create-object',
|
|
64
|
+
]);
|
|
65
|
+
function checkShadowBuiltin(content, file) {
|
|
66
|
+
const issues = [];
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
for (let i = 0; i < lines.length; i++) {
|
|
69
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
70
|
+
const m = stripped.match(/\(defun\s+(\S+)\b/);
|
|
71
|
+
if (m && BUILTINS.has(m[1].toLowerCase())) {
|
|
72
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'shadow_builtin', message: (0, locale_1.t)('shadow_builtin', m[1]) });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return issues;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=shadow-builtin.js.map
|
|
@@ -11,7 +11,7 @@ function checkSingleArgAndOr(content, file) {
|
|
|
11
11
|
function checkSingleArgAndOrAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
13
|
for (const form of ['and', 'or']) {
|
|
14
|
-
const nodes = (0, parser_1.astFindAll)(ast,
|
|
14
|
+
const nodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, form));
|
|
15
15
|
for (const node of nodes) {
|
|
16
16
|
if (!node.children)
|
|
17
17
|
continue;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkStrcatUsage = checkStrcatUsage;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkStrcatUsage(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
for (let i = 0; i < lines.length; i++) {
|
|
10
|
+
const stripped = (0, utils_1.stripLineRaw)(lines[i]);
|
|
11
|
+
// Check for (+ "str" ...) pattern
|
|
12
|
+
const m = stripped.match(/\(\+\s+"[^"]*"/);
|
|
13
|
+
if (m) {
|
|
14
|
+
issues.push({
|
|
15
|
+
file,
|
|
16
|
+
line: i + 1,
|
|
17
|
+
severity: 'warn',
|
|
18
|
+
rule: 'strcat_usage',
|
|
19
|
+
message: (0, locale_1.t)('strcat_usage'),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return issues;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=strcat-usage.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkTypeCheck = checkTypeCheck;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkTypeCheck(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
for (let i = 0; i < lines.length; i++) {
|
|
10
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
11
|
+
const m = stripped.match(/\(setq\s+\S+\s+\(getvar\b/);
|
|
12
|
+
if (m) {
|
|
13
|
+
const varName = m[0].match(/\(setq\s+(\S+)/)?.[1] || '';
|
|
14
|
+
if (!varName)
|
|
15
|
+
continue;
|
|
16
|
+
const body = lines.slice(i, i + 5).join('\n');
|
|
17
|
+
const typeChk = '(type ' + varName;
|
|
18
|
+
const eqTypeChk = '(= (type ' + varName;
|
|
19
|
+
if (!body.includes(typeChk) && !body.includes(eqTypeChk)) {
|
|
20
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'type_check', message: (0, locale_1.t)('type_check', varName) });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return issues;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=type-check.js.map
|
|
@@ -10,7 +10,7 @@ function checkUnusedLetBinding(content, file) {
|
|
|
10
10
|
}
|
|
11
11
|
function checkUnusedLetBindingAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
|
-
const letNodes = (0, parser_1.astFindAll)(ast,
|
|
13
|
+
const letNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'let'));
|
|
14
14
|
for (const node of letNodes) {
|
|
15
15
|
if (!node.children || node.children.length < 2)
|
|
16
16
|
continue;
|
|
@@ -41,7 +41,7 @@ function checkUnusedPackageDep(file) {
|
|
|
41
41
|
const issues = [];
|
|
42
42
|
const content = fs.readFileSync(file, 'utf-8');
|
|
43
43
|
const ast = (0, parser_1.parseAst)(content);
|
|
44
|
-
const inPackageNodes = (0, parser_1.astFindAll)(ast,
|
|
44
|
+
const inPackageNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'in-package'));
|
|
45
45
|
if (inPackageNodes.length === 0)
|
|
46
46
|
return issues;
|
|
47
47
|
const allPackages = new Set();
|
|
@@ -51,7 +51,7 @@ function checkUnusedPackageDep(file) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
const usedSymbols = new Set();
|
|
54
|
-
const allLists = (0, parser_1.astFindAll)(ast,
|
|
54
|
+
const allLists = (0, parser_1.astFindAll)(ast, n => n.type === 'list');
|
|
55
55
|
for (const node of allLists) {
|
|
56
56
|
if (!node.children || node.children.length === 0)
|
|
57
57
|
continue;
|
|
@@ -78,7 +78,7 @@ function checkUnusedPackageDep(file) {
|
|
|
78
78
|
allPackages.delete(mainPackage);
|
|
79
79
|
for (const pkg of allPackages) {
|
|
80
80
|
if (!usedSymbols.has(pkg)) {
|
|
81
|
-
const node = inPackageNodes.find(
|
|
81
|
+
const node = inPackageNodes.find(n => n.children && n.children.length >= 2 && (0, parser_1.astIsSymbol)(n.children[1]) && n.children[1].name === pkg);
|
|
82
82
|
issues.push({
|
|
83
83
|
file,
|
|
84
84
|
line: node ? node.pos.line : 1,
|
|
@@ -10,7 +10,7 @@ function checkVariableShadow(content, file) {
|
|
|
10
10
|
}
|
|
11
11
|
function checkVariableShadowAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
|
-
const letNodes = (0, parser_1.astFindAll)(ast,
|
|
13
|
+
const letNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'let'));
|
|
14
14
|
for (const node of letNodes) {
|
|
15
15
|
if (!node.children || node.children.length < 2)
|
|
16
16
|
continue;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkWhileConstant(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkWhileConstantAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=while-constant.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkWhileConstant = checkWhileConstant;
|
|
4
|
+
exports.checkWhileConstantAst = checkWhileConstantAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkWhileConstant(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkWhileConstantAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkWhileConstantAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
const whileNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'while'));
|
|
14
|
+
for (const node of whileNodes) {
|
|
15
|
+
if (!node.children || node.children.length < 2)
|
|
16
|
+
continue;
|
|
17
|
+
const cond = node.children[1];
|
|
18
|
+
// Check for constant conditions: nil, T, 1, 0, etc.
|
|
19
|
+
if (cond.type === 'symbol' && (cond.name === 'nil' || cond.name === 'T')) {
|
|
20
|
+
issues.push({
|
|
21
|
+
file,
|
|
22
|
+
line: node.pos.line,
|
|
23
|
+
severity: 'warn',
|
|
24
|
+
rule: 'while_constant',
|
|
25
|
+
message: (0, locale_1.t)('while_constant', cond.name),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (cond.type === 'number') {
|
|
29
|
+
issues.push({
|
|
30
|
+
file,
|
|
31
|
+
line: node.pos.line,
|
|
32
|
+
severity: 'warn',
|
|
33
|
+
rule: 'while_constant',
|
|
34
|
+
message: (0, locale_1.t)('while_constant', String(cond.value)),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return issues;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=while-constant.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LintConfig } from './types';
|
|
2
2
|
export declare function loadConfig(configPath?: string): LintConfig;
|
|
3
|
+
export declare function getCheckSeverity(config: LintConfig, rule: string): string;
|
|
3
4
|
export declare function findOverrides(filepath: string): Partial<LintConfig> | null;
|
|
4
5
|
export declare function mergeOverrides(base: LintConfig, overrides: Partial<LintConfig>): LintConfig;
|
|
5
6
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -34,10 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.loadConfig = loadConfig;
|
|
37
|
+
exports.getCheckSeverity = getCheckSeverity;
|
|
37
38
|
exports.findOverrides = findOverrides;
|
|
38
39
|
exports.mergeOverrides = mergeOverrides;
|
|
39
40
|
const fs = __importStar(require("fs"));
|
|
40
41
|
const path = __importStar(require("path"));
|
|
42
|
+
const presets_1 = require("./presets");
|
|
41
43
|
const DEFAULT_CONFIG = {
|
|
42
44
|
locale: 'zh',
|
|
43
45
|
source: {
|
|
@@ -56,14 +58,69 @@ const DEFAULT_CONFIG = {
|
|
|
56
58
|
token_in_url: 'warn',
|
|
57
59
|
open_without_close: 'warn',
|
|
58
60
|
bare_function_names: 'warn',
|
|
59
|
-
trailing_whitespace: 'warn',
|
|
60
61
|
line_length: 'warn',
|
|
61
62
|
function_complexity: 'warn',
|
|
62
63
|
parameter_naming: 'warn',
|
|
63
64
|
unused_variable: 'warn',
|
|
64
65
|
missing_doc: 'warn',
|
|
66
|
+
trailing_whitespace: 'warn',
|
|
65
67
|
module_registration: 'off',
|
|
66
68
|
namespace_header: 'off',
|
|
69
|
+
unused_parameter: 'warn',
|
|
70
|
+
constant_condition: 'warn',
|
|
71
|
+
redundant_progn: 'warn',
|
|
72
|
+
empty_branch: 'warn',
|
|
73
|
+
unused_let_binding: 'warn',
|
|
74
|
+
recursive_call: 'warn',
|
|
75
|
+
variable_shadow: 'warn',
|
|
76
|
+
redundant_cond: 'warn',
|
|
77
|
+
unused_local_fun: 'warn',
|
|
78
|
+
multiple_setq: 'warn',
|
|
79
|
+
redundant_quotes: 'warn',
|
|
80
|
+
trailing_paren: 'warn',
|
|
81
|
+
empty_comment: 'warn',
|
|
82
|
+
redundant_setq: 'warn',
|
|
83
|
+
redundant_nil_else: 'warn',
|
|
84
|
+
single_arg_and_or: 'warn',
|
|
85
|
+
redundant_let: 'warn',
|
|
86
|
+
self_compare: 'warn',
|
|
87
|
+
misplaced_else: 'warn',
|
|
88
|
+
quote_vs_function: 'warn',
|
|
89
|
+
commented_code: 'warn',
|
|
90
|
+
double_not: 'warn',
|
|
91
|
+
setq_single_arg: 'warn',
|
|
92
|
+
assoc_without_cdr: 'warn',
|
|
93
|
+
identical_branches: 'warn',
|
|
94
|
+
while_constant: 'warn',
|
|
95
|
+
cond_duplicate: 'warn',
|
|
96
|
+
duplicate_defun: 'warn',
|
|
97
|
+
dangling_defun: 'warn',
|
|
98
|
+
missing_export: 'warn',
|
|
99
|
+
unused_package_dep: 'warn',
|
|
100
|
+
error_handling: 'warn',
|
|
101
|
+
global_naming: 'warn',
|
|
102
|
+
extra_parens: 'warn',
|
|
103
|
+
arg_count: 'warn',
|
|
104
|
+
strcat_usage: 'warn',
|
|
105
|
+
cond_simplify: 'warn',
|
|
106
|
+
quote_style: 'warn',
|
|
107
|
+
eq_usage: 'warn',
|
|
108
|
+
lambda_syntax: 'warn',
|
|
109
|
+
comment_style: 'warn',
|
|
110
|
+
empty_catch: 'warn',
|
|
111
|
+
nth_usage: 'warn',
|
|
112
|
+
append_single: 'warn',
|
|
113
|
+
setq_multiple: 'warn',
|
|
114
|
+
function_order: 'off',
|
|
115
|
+
magic_number: 'off',
|
|
116
|
+
mixed_indent: 'warn',
|
|
117
|
+
long_function_call: 'warn',
|
|
118
|
+
no_return: 'warn',
|
|
119
|
+
shadow_builtin: 'warn',
|
|
120
|
+
dynamic_doc: 'warn',
|
|
121
|
+
loop_optimization: 'off',
|
|
122
|
+
type_check: 'off',
|
|
123
|
+
redundant_if: 'warn',
|
|
67
124
|
},
|
|
68
125
|
line_length: {
|
|
69
126
|
max: 100,
|
|
@@ -111,9 +168,17 @@ function loadConfig(configPath) {
|
|
|
111
168
|
}
|
|
112
169
|
const raw = fs.readFileSync(absPath, 'utf-8');
|
|
113
170
|
const user = JSON.parse(raw);
|
|
114
|
-
//
|
|
171
|
+
// Start from default config
|
|
115
172
|
const merged = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
173
|
+
// Apply preset if specified (preset applies before user overrides)
|
|
174
|
+
const preset = user.preset;
|
|
175
|
+
if (preset && presets_1.PRESETS[preset]) {
|
|
176
|
+
deepMerge(merged, presets_1.PRESETS[preset]);
|
|
177
|
+
}
|
|
178
|
+
// Apply user overrides (user settings take precedence)
|
|
116
179
|
deepMerge(merged, user);
|
|
180
|
+
// Remove non-config keys
|
|
181
|
+
delete merged.preset;
|
|
117
182
|
return merged;
|
|
118
183
|
}
|
|
119
184
|
return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
@@ -133,6 +198,9 @@ function deepMerge(target, source) {
|
|
|
133
198
|
}
|
|
134
199
|
}
|
|
135
200
|
}
|
|
201
|
+
function getCheckSeverity(config, rule) {
|
|
202
|
+
return config.checks[rule] || 'off';
|
|
203
|
+
}
|
|
136
204
|
function findOverrides(filepath) {
|
|
137
205
|
const dir = path.dirname(filepath);
|
|
138
206
|
const configPath = path.join(dir, '.atlisp-lint.json');
|
package/dist/disable.js
CHANGED
package/dist/formatters.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Issue } from './types';
|
|
2
2
|
export declare function formatDefault(issues: Issue[], fileContents?: Map<string, string>): string;
|
|
3
|
+
export declare function formatHtml(issues: Issue[], errorCount: number, warningCount: number): string;
|
|
3
4
|
export declare function formatJson(issues: Issue[], errorCount?: number, warningCount?: number): string;
|
|
4
5
|
//# sourceMappingURL=formatters.d.ts.map
|
package/dist/formatters.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatDefault = formatDefault;
|
|
4
|
+
exports.formatHtml = formatHtml;
|
|
4
5
|
exports.formatJson = formatJson;
|
|
5
6
|
const locale_1 = require("./locale");
|
|
6
7
|
const colors = {
|
|
@@ -68,11 +69,26 @@ function formatDefault(issues, fileContents) {
|
|
|
68
69
|
}
|
|
69
70
|
return lines.join('\n');
|
|
70
71
|
}
|
|
72
|
+
function formatHtml(issues, errorCount, warningCount) {
|
|
73
|
+
let html = `<!DOCTYPE html>
|
|
74
|
+
<html lang="en">
|
|
75
|
+
<head><meta charset="UTF-8"><title>@atlisp/lint Report</title></head>
|
|
76
|
+
<body>
|
|
77
|
+
<h1>@atlisp/lint Report</h1>
|
|
78
|
+
<p>${errorCount} error(s), ${warningCount} warning(s)</p>
|
|
79
|
+
<ul>
|
|
80
|
+
`;
|
|
81
|
+
for (const iss of issues) {
|
|
82
|
+
html += ` <li>${iss.severity}: ${iss.file}:${iss.line} — ${iss.message}</li>\n`;
|
|
83
|
+
}
|
|
84
|
+
html += '</ul>\n</body>\n</html>';
|
|
85
|
+
return html;
|
|
86
|
+
}
|
|
71
87
|
function formatJson(issues, errorCount, warningCount) {
|
|
72
88
|
return JSON.stringify({
|
|
73
89
|
issues,
|
|
74
|
-
error_count: errorCount ?? issues.filter(
|
|
75
|
-
warning_count: warningCount ?? issues.filter(
|
|
90
|
+
error_count: errorCount ?? issues.filter(i => i.severity === 'error').length,
|
|
91
|
+
warning_count: warningCount ?? issues.filter(i => i.severity === 'warn').length,
|
|
76
92
|
}, null, 2);
|
|
77
93
|
}
|
|
78
94
|
//# sourceMappingURL=formatters.js.map
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const sbcl_1 = require("./sbcl");
|
|
|
44
44
|
const formatters_1 = require("./formatters");
|
|
45
45
|
const locale_1 = require("./locale");
|
|
46
46
|
const cache_1 = require("./cache");
|
|
47
|
+
const watch_1 = require("./watch");
|
|
47
48
|
function parseArgs() {
|
|
48
49
|
const argv = process.argv.slice(2);
|
|
49
50
|
const opts = {
|
|
@@ -59,6 +60,7 @@ function parseArgs() {
|
|
|
59
60
|
clearCache: false,
|
|
60
61
|
parallel: false,
|
|
61
62
|
project: false,
|
|
63
|
+
watch: false,
|
|
62
64
|
};
|
|
63
65
|
for (let i = 0; i < argv.length; i++) {
|
|
64
66
|
switch (argv[i]) {
|
|
@@ -101,6 +103,9 @@ function parseArgs() {
|
|
|
101
103
|
case '--project':
|
|
102
104
|
opts.project = true;
|
|
103
105
|
break;
|
|
106
|
+
case '--watch':
|
|
107
|
+
opts.watch = true;
|
|
108
|
+
break;
|
|
104
109
|
default:
|
|
105
110
|
break;
|
|
106
111
|
}
|
|
@@ -168,12 +173,12 @@ function collectFiles(rootDir, opts, config) {
|
|
|
168
173
|
}
|
|
169
174
|
}
|
|
170
175
|
}
|
|
171
|
-
const excludePatterns = config.source.exclude.map(
|
|
176
|
+
const excludePatterns = config.source.exclude.map(e => {
|
|
172
177
|
const str = e.replace(/\./g, '\\.').replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*');
|
|
173
178
|
return new RegExp(`^${str}$`);
|
|
174
179
|
});
|
|
175
180
|
return Array.from(files)
|
|
176
|
-
.filter(
|
|
181
|
+
.filter(f => {
|
|
177
182
|
const rel = path.relative(rootDir, f).replace(/\\/g, '/');
|
|
178
183
|
for (const re of excludePatterns) {
|
|
179
184
|
if (re.test(rel))
|
|
@@ -190,10 +195,10 @@ function collectStagedFiles(rootDir) {
|
|
|
190
195
|
});
|
|
191
196
|
return output
|
|
192
197
|
.split('\n')
|
|
193
|
-
.map(
|
|
194
|
-
.filter(
|
|
195
|
-
.map(
|
|
196
|
-
.filter(
|
|
198
|
+
.map(l => l.trim())
|
|
199
|
+
.filter(l => l.endsWith('.lsp'))
|
|
200
|
+
.map(l => path.resolve(rootDir, l))
|
|
201
|
+
.filter(f => fs.existsSync(f));
|
|
197
202
|
}
|
|
198
203
|
function initConfig(rootDir) {
|
|
199
204
|
const defaultPath = path.join(__dirname, '..', 'atlisp-lint.default.json');
|
|
@@ -249,6 +254,11 @@ async function main() {
|
|
|
249
254
|
console.log((0, locale_1.t)('index.no_files'));
|
|
250
255
|
return;
|
|
251
256
|
}
|
|
257
|
+
// --watch mode
|
|
258
|
+
if (opts.watch) {
|
|
259
|
+
(0, watch_1.watchFiles)(files, { rootDir, format: opts.format, config });
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
252
262
|
// --fix mode: auto-fix before linting
|
|
253
263
|
if (opts.fix) {
|
|
254
264
|
for (const f of files) {
|
|
@@ -260,10 +270,20 @@ async function main() {
|
|
|
260
270
|
if (!opts.staged)
|
|
261
271
|
return;
|
|
262
272
|
}
|
|
263
|
-
// Filter cached files
|
|
273
|
+
// Filter cached files (pre-read content to avoid double I/O)
|
|
274
|
+
const contentCache = new Map();
|
|
264
275
|
const filesToLint = opts.cache
|
|
265
|
-
? files.filter(
|
|
266
|
-
|
|
276
|
+
? files.filter(f => {
|
|
277
|
+
let content;
|
|
278
|
+
try {
|
|
279
|
+
content = fs.readFileSync(f, 'utf-8');
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
/* ignore */
|
|
283
|
+
}
|
|
284
|
+
if (content !== undefined)
|
|
285
|
+
contentCache.set(f, content);
|
|
286
|
+
const cached = (0, cache_1.isCached)(f, rootDir, content);
|
|
267
287
|
if (cached) {
|
|
268
288
|
console.log(`${(0, locale_1.t)('summary.tag_warn')}: ${path.relative(rootDir, f)} — ${(0, locale_1.t)('index.cached')}`);
|
|
269
289
|
}
|
|
@@ -283,10 +303,30 @@ async function main() {
|
|
|
283
303
|
const projectIssues = (0, project_1.lintProject)(filesToLint, config, rootDir);
|
|
284
304
|
issues.push(...projectIssues);
|
|
285
305
|
}
|
|
286
|
-
//
|
|
306
|
+
// Apply rule-based fixes (after lint, when --fix is set)
|
|
307
|
+
if (opts.fix) {
|
|
308
|
+
for (const f of filesToLint) {
|
|
309
|
+
const relPath = path.relative(rootDir, f);
|
|
310
|
+
const fileIssues = issues.filter(i => i.file === relPath);
|
|
311
|
+
if (fileIssues.length > 0) {
|
|
312
|
+
try {
|
|
313
|
+
const content = fs.readFileSync(f, 'utf-8');
|
|
314
|
+
const fixed = (0, runner_1.applyFixes)(fileIssues, content, relPath);
|
|
315
|
+
if (fixed !== content) {
|
|
316
|
+
fs.writeFileSync(f, fixed, 'utf-8');
|
|
317
|
+
console.log(`${(0, locale_1.t)('summary.tag_fail')}: ${relPath} — ${(0, locale_1.t)('index.fixed')}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
/* ignore */
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Mark as cached (reuse pre-read content if available)
|
|
287
327
|
if (opts.cache) {
|
|
288
328
|
for (const f of filesToLint) {
|
|
289
|
-
(0, cache_1.markCached)(f, rootDir);
|
|
329
|
+
(0, cache_1.markCached)(f, rootDir, contentCache.get(f));
|
|
290
330
|
}
|
|
291
331
|
}
|
|
292
332
|
// Phase 2: SBCL syntax validation
|
|
@@ -319,8 +359,8 @@ async function main() {
|
|
|
319
359
|
}
|
|
320
360
|
}
|
|
321
361
|
// Format & output
|
|
322
|
-
const errorCount = issues.filter(
|
|
323
|
-
const warningCount = issues.filter(
|
|
362
|
+
const errorCount = issues.filter(i => i.severity === 'error').length;
|
|
363
|
+
const warningCount = issues.filter(i => i.severity === 'warn').length;
|
|
324
364
|
if (opts.format === 'json') {
|
|
325
365
|
console.log((0, formatters_1.formatJson)(issues, errorCount, warningCount));
|
|
326
366
|
}
|