@atlisp/lint 0.1.3 → 0.1.5
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/README.md +5 -2
- package/atlisp-lint.default.json +29 -29
- package/bin/atlisp-lint +1 -1
- package/dist/checks/bare-names.js +4 -1
- package/dist/checks/cl-syntax.js +4 -1
- package/dist/checks/commented-code.d.ts +3 -0
- package/dist/checks/commented-code.js +46 -0
- package/dist/checks/constant-condition.d.ts +5 -0
- package/dist/checks/constant-condition.js +88 -0
- package/dist/checks/dangerous-calls.d.ts +2 -0
- package/dist/checks/dangerous-calls.js +70 -29
- package/dist/checks/dangling-defun.d.ts +6 -0
- package/dist/checks/dangling-defun.js +85 -0
- package/dist/checks/double-not.d.ts +5 -0
- package/dist/checks/double-not.js +30 -0
- package/dist/checks/empty-branch.d.ts +5 -0
- package/dist/checks/empty-branch.js +34 -0
- package/dist/checks/empty-comments.d.ts +3 -0
- package/dist/checks/empty-comments.js +26 -0
- package/dist/checks/encoding.js +13 -4
- package/dist/checks/function-complexity.d.ts +2 -0
- package/dist/checks/function-complexity.js +89 -45
- package/dist/checks/line-length.js +4 -1
- package/dist/checks/misplaced-else.d.ts +5 -0
- package/dist/checks/misplaced-else.js +31 -0
- package/dist/checks/missing-doc.js +6 -3
- package/dist/checks/missing-export.d.ts +13 -0
- package/dist/checks/missing-export.js +94 -0
- package/dist/checks/module-reg.js +9 -4
- package/dist/checks/multiple-setq.d.ts +5 -0
- package/dist/checks/multiple-setq.js +51 -0
- package/dist/checks/namespace-header.js +16 -6
- package/dist/checks/open-close.d.ts +2 -0
- package/dist/checks/open-close.js +18 -13
- package/dist/checks/parameter-naming.d.ts +2 -0
- package/dist/checks/parameter-naming.js +26 -14
- package/dist/checks/parens.js +8 -3
- package/dist/checks/quote-vs-function.d.ts +5 -0
- package/dist/checks/quote-vs-function.js +50 -0
- package/dist/checks/recursive-call.d.ts +5 -0
- package/dist/checks/recursive-call.js +49 -0
- package/dist/checks/redundant-cond.d.ts +5 -0
- package/dist/checks/redundant-cond.js +50 -0
- package/dist/checks/redundant-let.d.ts +5 -0
- package/dist/checks/redundant-let.js +31 -0
- package/dist/checks/redundant-nil-else.d.ts +5 -0
- package/dist/checks/redundant-nil-else.js +32 -0
- package/dist/checks/redundant-progn.d.ts +2 -0
- package/dist/checks/redundant-progn.js +18 -9
- package/dist/checks/redundant-quotes.d.ts +5 -0
- package/dist/checks/redundant-quotes.js +33 -0
- package/dist/checks/redundant-setq.d.ts +5 -0
- package/dist/checks/redundant-setq.js +34 -0
- package/dist/checks/self-compare.d.ts +5 -0
- package/dist/checks/self-compare.js +37 -0
- package/dist/checks/single-arg-and-or.d.ts +5 -0
- package/dist/checks/single-arg-and-or.js +32 -0
- package/dist/checks/token-in-url.js +4 -1
- package/dist/checks/trailing-paren.d.ts +3 -0
- package/dist/checks/trailing-paren.js +44 -0
- package/dist/checks/trailing-ws.js +4 -1
- package/dist/checks/unused-let.d.ts +5 -0
- package/dist/checks/unused-let.js +57 -0
- package/dist/checks/unused-local-fun.d.ts +5 -0
- package/dist/checks/unused-local-fun.js +62 -0
- package/dist/checks/unused-package-dep.d.ts +3 -0
- package/dist/checks/unused-package-dep.js +93 -0
- package/dist/checks/unused-param.d.ts +5 -0
- package/dist/checks/unused-param.js +63 -0
- package/dist/checks/unused-variable.d.ts +2 -0
- package/dist/checks/unused-variable.js +70 -42
- package/dist/checks/variable-shadow.d.ts +5 -0
- package/dist/checks/variable-shadow.js +66 -0
- package/dist/checks/vlax.js +8 -3
- package/dist/config.d.ts +1 -2
- package/dist/config.js +3 -35
- package/dist/disable.js +4 -1
- package/dist/formatters.d.ts +1 -2
- package/dist/formatters.js +8 -61
- package/dist/index.js +131 -201
- package/dist/locale.js +83 -91
- package/dist/project.d.ts +3 -0
- package/dist/project.js +138 -0
- package/dist/runner.d.ts +5 -11
- package/dist/runner.js +260 -71
- package/dist/sbcl.js +16 -11
- package/dist/worker.js +10 -5
- package/lib/lint-sbcl.lisp +19 -54
- package/package.json +11 -4
- package/LICENSE +0 -21
- package/dist/atlisp-lint.default.json +0 -90
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js.map +0 -1
- package/dist/checks/append-single.d.ts +0 -3
- package/dist/checks/append-single.d.ts.map +0 -1
- package/dist/checks/append-single.js +0 -17
- package/dist/checks/append-single.js.map +0 -1
- package/dist/checks/arg-count.d.ts +0 -3
- package/dist/checks/arg-count.d.ts.map +0 -1
- package/dist/checks/arg-count.js +0 -120
- package/dist/checks/arg-count.js.map +0 -1
- package/dist/checks/bare-names.d.ts.map +0 -1
- package/dist/checks/bare-names.js.map +0 -1
- package/dist/checks/cl-syntax.d.ts.map +0 -1
- package/dist/checks/cl-syntax.js.map +0 -1
- package/dist/checks/comment-style.d.ts +0 -3
- package/dist/checks/comment-style.d.ts.map +0 -1
- package/dist/checks/comment-style.js +0 -21
- package/dist/checks/comment-style.js.map +0 -1
- package/dist/checks/cond-simplify.d.ts +0 -3
- package/dist/checks/cond-simplify.d.ts.map +0 -1
- package/dist/checks/cond-simplify.js +0 -42
- package/dist/checks/cond-simplify.js.map +0 -1
- package/dist/checks/dangerous-calls.d.ts.map +0 -1
- package/dist/checks/dangerous-calls.js.map +0 -1
- package/dist/checks/dynamic-doc.d.ts +0 -3
- package/dist/checks/dynamic-doc.d.ts.map +0 -1
- package/dist/checks/dynamic-doc.js +0 -21
- package/dist/checks/dynamic-doc.js.map +0 -1
- package/dist/checks/empty-catch.d.ts +0 -3
- package/dist/checks/empty-catch.d.ts.map +0 -1
- package/dist/checks/empty-catch.js +0 -31
- package/dist/checks/empty-catch.js.map +0 -1
- package/dist/checks/encoding.d.ts.map +0 -1
- package/dist/checks/encoding.js.map +0 -1
- package/dist/checks/eq-usage.d.ts +0 -3
- package/dist/checks/eq-usage.d.ts.map +0 -1
- package/dist/checks/eq-usage.js +0 -22
- package/dist/checks/eq-usage.js.map +0 -1
- package/dist/checks/error-handling.d.ts +0 -3
- package/dist/checks/error-handling.d.ts.map +0 -1
- package/dist/checks/error-handling.js +0 -53
- package/dist/checks/error-handling.js.map +0 -1
- package/dist/checks/extra-parens.d.ts +0 -3
- package/dist/checks/extra-parens.d.ts.map +0 -1
- package/dist/checks/extra-parens.js +0 -42
- package/dist/checks/extra-parens.js.map +0 -1
- package/dist/checks/function-complexity.d.ts.map +0 -1
- package/dist/checks/function-complexity.js.map +0 -1
- package/dist/checks/function-order.d.ts +0 -3
- package/dist/checks/function-order.d.ts.map +0 -1
- package/dist/checks/function-order.js +0 -33
- package/dist/checks/function-order.js.map +0 -1
- package/dist/checks/global-naming.d.ts +0 -3
- package/dist/checks/global-naming.d.ts.map +0 -1
- package/dist/checks/global-naming.js +0 -51
- package/dist/checks/global-naming.js.map +0 -1
- package/dist/checks/index.d.ts +0 -3
- package/dist/checks/index.d.ts.map +0 -1
- package/dist/checks/index.js +0 -108
- package/dist/checks/index.js.map +0 -1
- package/dist/checks/lambda-syntax.d.ts +0 -3
- package/dist/checks/lambda-syntax.d.ts.map +0 -1
- package/dist/checks/lambda-syntax.js +0 -22
- package/dist/checks/lambda-syntax.js.map +0 -1
- package/dist/checks/line-length.d.ts.map +0 -1
- package/dist/checks/line-length.js.map +0 -1
- package/dist/checks/long-function-call.d.ts +0 -3
- package/dist/checks/long-function-call.d.ts.map +0 -1
- package/dist/checks/long-function-call.js +0 -48
- package/dist/checks/long-function-call.js.map +0 -1
- package/dist/checks/loop-optimization.d.ts +0 -3
- package/dist/checks/loop-optimization.d.ts.map +0 -1
- package/dist/checks/loop-optimization.js +0 -17
- package/dist/checks/loop-optimization.js.map +0 -1
- package/dist/checks/magic-number.d.ts +0 -3
- package/dist/checks/magic-number.d.ts.map +0 -1
- package/dist/checks/magic-number.js +0 -21
- package/dist/checks/magic-number.js.map +0 -1
- package/dist/checks/missing-doc.d.ts.map +0 -1
- package/dist/checks/missing-doc.js.map +0 -1
- package/dist/checks/mixed-indent.d.ts +0 -3
- package/dist/checks/mixed-indent.d.ts.map +0 -1
- package/dist/checks/mixed-indent.js +0 -19
- package/dist/checks/mixed-indent.js.map +0 -1
- package/dist/checks/module-reg.d.ts.map +0 -1
- package/dist/checks/module-reg.js.map +0 -1
- package/dist/checks/namespace-header.d.ts.map +0 -1
- package/dist/checks/namespace-header.js.map +0 -1
- package/dist/checks/no-return.d.ts +0 -3
- package/dist/checks/no-return.d.ts.map +0 -1
- package/dist/checks/no-return.js +0 -45
- package/dist/checks/no-return.js.map +0 -1
- package/dist/checks/nth-usage.d.ts +0 -3
- package/dist/checks/nth-usage.d.ts.map +0 -1
- package/dist/checks/nth-usage.js +0 -17
- package/dist/checks/nth-usage.js.map +0 -1
- package/dist/checks/open-close.d.ts.map +0 -1
- package/dist/checks/open-close.js.map +0 -1
- package/dist/checks/parameter-naming.d.ts.map +0 -1
- package/dist/checks/parameter-naming.js.map +0 -1
- package/dist/checks/parens.d.ts.map +0 -1
- package/dist/checks/parens.js.map +0 -1
- package/dist/checks/quote-style.d.ts +0 -3
- package/dist/checks/quote-style.d.ts.map +0 -1
- package/dist/checks/quote-style.js +0 -22
- package/dist/checks/quote-style.js.map +0 -1
- package/dist/checks/redundant-if.d.ts +0 -3
- package/dist/checks/redundant-if.d.ts.map +0 -1
- package/dist/checks/redundant-if.js +0 -17
- package/dist/checks/redundant-if.js.map +0 -1
- package/dist/checks/redundant-progn.d.ts.map +0 -1
- package/dist/checks/redundant-progn.js.map +0 -1
- package/dist/checks/setq-multiple.d.ts +0 -3
- package/dist/checks/setq-multiple.d.ts.map +0 -1
- package/dist/checks/setq-multiple.js +0 -17
- package/dist/checks/setq-multiple.js.map +0 -1
- package/dist/checks/shadow-builtin.d.ts +0 -3
- package/dist/checks/shadow-builtin.d.ts.map +0 -1
- package/dist/checks/shadow-builtin.js +0 -29
- package/dist/checks/shadow-builtin.js.map +0 -1
- package/dist/checks/strcat-usage.d.ts +0 -3
- package/dist/checks/strcat-usage.d.ts.map +0 -1
- package/dist/checks/strcat-usage.js +0 -22
- package/dist/checks/strcat-usage.js.map +0 -1
- package/dist/checks/token-in-url.d.ts.map +0 -1
- package/dist/checks/token-in-url.js.map +0 -1
- package/dist/checks/trailing-ws.d.ts.map +0 -1
- package/dist/checks/trailing-ws.js.map +0 -1
- package/dist/checks/type-check.d.ts +0 -3
- package/dist/checks/type-check.d.ts.map +0 -1
- package/dist/checks/type-check.js +0 -26
- package/dist/checks/type-check.js.map +0 -1
- package/dist/checks/unused-variable.d.ts.map +0 -1
- package/dist/checks/unused-variable.js.map +0 -1
- package/dist/checks/vlax.d.ts.map +0 -1
- package/dist/checks/vlax.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/disable.d.ts.map +0 -1
- package/dist/disable.js.map +0 -1
- package/dist/formatters.d.ts.map +0 -1
- package/dist/formatters.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/lint-sbcl.lisp +0 -161
- package/dist/locale.d.ts.map +0 -1
- package/dist/locale.js.map +0 -1
- package/dist/rules.d.ts +0 -9
- package/dist/rules.d.ts.map +0 -1
- package/dist/rules.js +0 -58
- package/dist/rules.js.map +0 -1
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js.map +0 -1
- package/dist/sbcl.d.ts.map +0 -1
- package/dist/sbcl.js.map +0 -1
- package/dist/stub-packages.json +0 -41
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- package/dist/validate.d.ts +0 -8
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -59
- package/dist/validate.js.map +0 -1
- package/dist/watch.d.ts +0 -9
- package/dist/watch.d.ts.map +0 -1
- package/dist/watch.js +0 -109
- package/dist/watch.js.map +0 -1
- package/dist/worker.d.ts.map +0 -1
- package/dist/worker.js.map +0 -1
- package/pre-commit/hook.sh +0 -4
|
@@ -1,57 +1,101 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkFunctionComplexity = checkFunctionComplexity;
|
|
4
|
+
exports.checkFunctionComplexityAst = checkFunctionComplexityAst;
|
|
4
5
|
const locale_1 = require("../locale");
|
|
5
|
-
const
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
6
7
|
function checkFunctionComplexity(content, file, maxLines, maxNesting) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkFunctionComplexityAst(ast, file, maxLines, maxNesting);
|
|
10
|
+
}
|
|
11
|
+
function checkFunctionComplexityAst(ast, file, maxLines, maxNesting) {
|
|
7
12
|
const issues = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
13
|
+
// Check defun forms
|
|
14
|
+
const defuns = (0, parser_1.astFindListWithHead)(ast, 'defun');
|
|
15
|
+
for (const defun of defuns) {
|
|
16
|
+
if (!defun.children || !defun.end)
|
|
17
|
+
continue;
|
|
18
|
+
if (defun.children.length < 3)
|
|
19
|
+
continue;
|
|
20
|
+
const nameNode = defun.children[1];
|
|
21
|
+
const name = nameNode.type === 'symbol' && nameNode.name ? nameNode.name : '<unknown>';
|
|
22
|
+
const bodyLines = (defun.end ? defun.end.line : defun.pos.line) - defun.pos.line + 1;
|
|
23
|
+
const depth = computeNestingDepth(defun, 1);
|
|
24
|
+
if (bodyLines > maxLines) {
|
|
25
|
+
issues.push({
|
|
26
|
+
file,
|
|
27
|
+
line: defun.pos.line,
|
|
28
|
+
severity: 'warn',
|
|
29
|
+
rule: 'function_complexity',
|
|
30
|
+
message: (0, locale_1.t)('function_complexity.lines', name, bodyLines, maxLines),
|
|
31
|
+
});
|
|
27
32
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
33
|
+
if (depth > maxNesting) {
|
|
34
|
+
issues.push({
|
|
35
|
+
file,
|
|
36
|
+
line: defun.pos.line,
|
|
37
|
+
severity: 'warn',
|
|
38
|
+
rule: 'function_complexity',
|
|
39
|
+
message: (0, locale_1.t)('function_complexity.nesting', name, depth, maxNesting),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check lambda forms: (lambda (args) body...)
|
|
44
|
+
const lambdas = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'lambda'));
|
|
45
|
+
for (const lam of lambdas) {
|
|
46
|
+
if (!lam.children || !lam.end)
|
|
47
|
+
continue;
|
|
48
|
+
// Skip quoted lambdas: (quote (lambda ...)) — data, not code
|
|
49
|
+
if (isInsideQuote(lam))
|
|
50
|
+
continue;
|
|
51
|
+
const bodyLines = (lam.end ? lam.end.line : lam.pos.line) - lam.pos.line + 1;
|
|
52
|
+
const depth = computeNestingDepth(lam, 1);
|
|
53
|
+
if (bodyLines > maxLines) {
|
|
54
|
+
issues.push({
|
|
55
|
+
file,
|
|
56
|
+
line: lam.pos.line,
|
|
57
|
+
severity: 'warn',
|
|
58
|
+
rule: 'function_complexity',
|
|
59
|
+
message: (0, locale_1.t)('function_complexity.lines', '(lambda)', bodyLines, maxLines),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (depth > maxNesting) {
|
|
63
|
+
issues.push({
|
|
64
|
+
file,
|
|
65
|
+
line: lam.pos.line,
|
|
66
|
+
severity: 'warn',
|
|
67
|
+
rule: 'function_complexity',
|
|
68
|
+
message: (0, locale_1.t)('function_complexity.nesting', '(lambda)', depth, maxNesting),
|
|
69
|
+
});
|
|
53
70
|
}
|
|
54
71
|
}
|
|
55
72
|
return issues;
|
|
56
73
|
}
|
|
74
|
+
function isInsideQuote(node) {
|
|
75
|
+
let cur = node.parent;
|
|
76
|
+
while (cur) {
|
|
77
|
+
if (cur.type === 'list' &&
|
|
78
|
+
cur.children &&
|
|
79
|
+
cur.children.length > 0 &&
|
|
80
|
+
cur.children[0].type === 'symbol' &&
|
|
81
|
+
cur.children[0].name === 'quote') {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
cur = cur.parent;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
function computeNestingDepth(node, depth) {
|
|
89
|
+
if (node.type !== 'list' || !node.children)
|
|
90
|
+
return depth;
|
|
91
|
+
let max = depth;
|
|
92
|
+
for (const child of node.children) {
|
|
93
|
+
if (child.type === 'list' && child.children) {
|
|
94
|
+
const childDepth = computeNestingDepth(child, depth + 1);
|
|
95
|
+
if (childDepth > max)
|
|
96
|
+
max = childDepth;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return max;
|
|
100
|
+
}
|
|
57
101
|
//# sourceMappingURL=function-complexity.js.map
|
|
@@ -9,7 +9,10 @@ function checkLineLength(content, file, max, tabWidth) {
|
|
|
9
9
|
const displayLen = lines[i].replace(/\t/g, ' '.repeat(tabWidth)).length;
|
|
10
10
|
if (displayLen > max) {
|
|
11
11
|
issues.push({
|
|
12
|
-
file,
|
|
12
|
+
file,
|
|
13
|
+
line: i + 1,
|
|
14
|
+
severity: 'warn',
|
|
15
|
+
rule: 'line_length',
|
|
13
16
|
message: (0, locale_1.t)('line_length', displayLen, max),
|
|
14
17
|
});
|
|
15
18
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkMisplacedElse(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkMisplacedElseAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=misplaced-else.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkMisplacedElse = checkMisplacedElse;
|
|
4
|
+
exports.checkMisplacedElseAst = checkMisplacedElseAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkMisplacedElse(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkMisplacedElseAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkMisplacedElseAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
const ifNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'if'));
|
|
14
|
+
for (const node of ifNodes) {
|
|
15
|
+
if (!node.children || node.children.length !== 4)
|
|
16
|
+
continue;
|
|
17
|
+
const cond = node.children[1];
|
|
18
|
+
if (!(0, parser_1.astIsList)(cond, 'not'))
|
|
19
|
+
continue;
|
|
20
|
+
const innerName = cond.children && cond.children[1] && cond.children[1].name;
|
|
21
|
+
issues.push({
|
|
22
|
+
file,
|
|
23
|
+
line: node.pos.line,
|
|
24
|
+
severity: 'warn',
|
|
25
|
+
rule: 'misplaced_else',
|
|
26
|
+
message: (0, locale_1.t)('misplaced_else', innerName || ''),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return issues;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=misplaced-else.js.map
|
|
@@ -18,19 +18,22 @@ function checkMissingDoc(content, file) {
|
|
|
18
18
|
continue;
|
|
19
19
|
if (name === 'T' || name === 'nil')
|
|
20
20
|
continue;
|
|
21
|
-
// Check if previous non-empty line is a comment
|
|
21
|
+
// Check if previous non-empty line is a comment (use raw line, not stripped)
|
|
22
22
|
let hasDoc = false;
|
|
23
23
|
for (let j = i - 1; j >= 0; j--) {
|
|
24
24
|
const prev = lines[j].trim();
|
|
25
25
|
if (!prev)
|
|
26
26
|
continue;
|
|
27
|
-
if (prev.startsWith(';')
|
|
27
|
+
if (prev.startsWith(';'))
|
|
28
28
|
hasDoc = true;
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
31
31
|
if (!hasDoc) {
|
|
32
32
|
issues.push({
|
|
33
|
-
file,
|
|
33
|
+
file,
|
|
34
|
+
line: i + 1,
|
|
35
|
+
severity: 'warn',
|
|
36
|
+
rule: 'missing_doc',
|
|
34
37
|
message: (0, locale_1.t)('missing_doc', name),
|
|
35
38
|
});
|
|
36
39
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
export interface MissingExportResult {
|
|
3
|
+
issues: Issue[];
|
|
4
|
+
allDefuns: Map<string, {
|
|
5
|
+
file: string;
|
|
6
|
+
line: number;
|
|
7
|
+
}[]>;
|
|
8
|
+
}
|
|
9
|
+
export declare function checkMissingExport(file: string, pkgDir: string, _allDefuns: Map<string, {
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
}[]>): Issue[];
|
|
13
|
+
//# sourceMappingURL=missing-export.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.checkMissingExport = checkMissingExport;
|
|
37
|
+
const locale_1 = require("../locale");
|
|
38
|
+
const parser_1 = require("@atlisp/parser");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
function checkMissingExport(file, pkgDir, _allDefuns) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
const pkgLspPath = path.join(pkgDir, 'pkg.lsp');
|
|
44
|
+
if (!fs.existsSync(pkgLspPath))
|
|
45
|
+
return issues;
|
|
46
|
+
const pkgContent = fs.readFileSync(pkgLspPath, 'utf-8');
|
|
47
|
+
const pkgAst = (0, parser_1.parseAst)(pkgContent);
|
|
48
|
+
const modulesNode = (0, parser_1.astFindAll)(pkgAst, (n) => (0, parser_1.astIsList)(n, 'setq'));
|
|
49
|
+
const registered = new Set();
|
|
50
|
+
for (const node of modulesNode) {
|
|
51
|
+
if (!node.children)
|
|
52
|
+
continue;
|
|
53
|
+
for (let i = 1; i < node.children.length - 1; i += 2) {
|
|
54
|
+
const sym = node.children[i];
|
|
55
|
+
if ((0, parser_1.astIsSymbol)(sym) && sym.name === '@::*modules*') {
|
|
56
|
+
const val = node.children[i + 1];
|
|
57
|
+
if (val.type === 'list' && val.children) {
|
|
58
|
+
for (const item of val.children) {
|
|
59
|
+
if ((0, parser_1.astIsSymbol)(item)) {
|
|
60
|
+
registered.add(item.name);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if ((0, parser_1.astIsSymbol)(sym) && sym.name === '@::*modules*') {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const fileContent = fs.readFileSync(file, 'utf-8');
|
|
71
|
+
const ast = (0, parser_1.parseAst)(fileContent);
|
|
72
|
+
const defunNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
|
|
73
|
+
for (const node of defunNodes) {
|
|
74
|
+
if (!node.children || node.children.length < 2)
|
|
75
|
+
continue;
|
|
76
|
+
const nameNode = node.children[1];
|
|
77
|
+
if (!(0, parser_1.astIsSymbol)(nameNode))
|
|
78
|
+
continue;
|
|
79
|
+
const name = nameNode.name;
|
|
80
|
+
if (name.startsWith('c:') || name.includes(':'))
|
|
81
|
+
continue;
|
|
82
|
+
if (!registered.has(name)) {
|
|
83
|
+
issues.push({
|
|
84
|
+
file,
|
|
85
|
+
line: nameNode.pos.line,
|
|
86
|
+
severity: 'warn',
|
|
87
|
+
rule: 'missing_export',
|
|
88
|
+
message: (0, locale_1.t)('missing_export', name),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return issues;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=missing-export.js.map
|
|
@@ -12,13 +12,18 @@ function checkModuleRegistration(content, file, relPath, config) {
|
|
|
12
12
|
if (!config.dirs.includes(topDir))
|
|
13
13
|
return [];
|
|
14
14
|
const lines = content.split('\n');
|
|
15
|
-
const relevant = lines.filter(l => l.trim().length > 0);
|
|
15
|
+
const relevant = lines.filter((l) => l.trim().length > 0);
|
|
16
16
|
const tail = relevant.slice(-20).join('\n');
|
|
17
17
|
if (!tail.includes('*modules*')) {
|
|
18
|
-
return [
|
|
19
|
-
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
file,
|
|
21
|
+
line: 1,
|
|
22
|
+
severity: config.severity,
|
|
23
|
+
rule: 'module_registration',
|
|
20
24
|
message: (0, locale_1.t)('module_registration'),
|
|
21
|
-
}
|
|
25
|
+
},
|
|
26
|
+
];
|
|
22
27
|
}
|
|
23
28
|
return [];
|
|
24
29
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkMultipleSetq(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkMultipleSetqAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=multiple-setq.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkMultipleSetq = checkMultipleSetq;
|
|
4
|
+
exports.checkMultipleSetqAst = checkMultipleSetqAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkMultipleSetq(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkMultipleSetqAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkMultipleSetqAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
// Find all parent lists that contain at least one setq
|
|
14
|
+
const parents = new Set();
|
|
15
|
+
const setqNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'setq'));
|
|
16
|
+
for (const n of setqNodes) {
|
|
17
|
+
if (n.parent)
|
|
18
|
+
parents.add(n.parent);
|
|
19
|
+
}
|
|
20
|
+
for (const parent of parents) {
|
|
21
|
+
if (!parent.children)
|
|
22
|
+
continue;
|
|
23
|
+
let prevWasSetq = false;
|
|
24
|
+
let prevSetqNode = null;
|
|
25
|
+
for (const child of parent.children) {
|
|
26
|
+
const isSetq = (0, parser_1.astIsList)(child, 'setq');
|
|
27
|
+
if (isSetq && prevWasSetq && prevSetqNode) {
|
|
28
|
+
issues.push({
|
|
29
|
+
file,
|
|
30
|
+
line: prevSetqNode.pos.line,
|
|
31
|
+
severity: 'warn',
|
|
32
|
+
rule: 'multiple_setq',
|
|
33
|
+
message: (0, locale_1.t)('multiple_setq'),
|
|
34
|
+
});
|
|
35
|
+
// Reset to avoid double-reporting the same pair
|
|
36
|
+
prevWasSetq = false;
|
|
37
|
+
prevSetqNode = null;
|
|
38
|
+
}
|
|
39
|
+
else if (isSetq) {
|
|
40
|
+
prevWasSetq = true;
|
|
41
|
+
prevSetqNode = child;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
prevWasSetq = false;
|
|
45
|
+
prevSetqNode = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return issues;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=multiple-setq.js.map
|
|
@@ -14,15 +14,25 @@ function checkNamespaceHeader(content, file, config) {
|
|
|
14
14
|
if (stripped.startsWith('(in-package')) {
|
|
15
15
|
if (stripped.includes(config.package))
|
|
16
16
|
return [];
|
|
17
|
-
return [
|
|
18
|
-
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
file,
|
|
20
|
+
line: i + 1,
|
|
21
|
+
severity: config.severity,
|
|
22
|
+
rule: 'namespace_header',
|
|
19
23
|
message: (0, locale_1.t)('namespace_header.wrong', config.package),
|
|
20
|
-
}
|
|
24
|
+
},
|
|
25
|
+
];
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
|
-
return [
|
|
24
|
-
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
file,
|
|
31
|
+
line: 1,
|
|
32
|
+
severity: config.severity,
|
|
33
|
+
rule: 'namespace_header',
|
|
25
34
|
message: (0, locale_1.t)('namespace_header.missing', config.package),
|
|
26
|
-
}
|
|
35
|
+
},
|
|
36
|
+
];
|
|
27
37
|
}
|
|
28
38
|
//# sourceMappingURL=namespace-header.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
2
3
|
export declare function checkOpenWithoutClose(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkOpenWithoutCloseAst(ast: AstNode, file: string): Issue[];
|
|
3
5
|
//# sourceMappingURL=open-close.d.ts.map
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkOpenWithoutClose = checkOpenWithoutClose;
|
|
4
|
-
|
|
4
|
+
exports.checkOpenWithoutCloseAst = checkOpenWithoutCloseAst;
|
|
5
5
|
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
6
7
|
function checkOpenWithoutClose(content, file) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
file,
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkOpenWithoutCloseAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkOpenWithoutCloseAst(ast, file) {
|
|
12
|
+
const openCalls = (0, parser_1.astFindListWithHead)(ast, 'open');
|
|
13
|
+
const closeCalls = (0, parser_1.astFindListWithHead)(ast, 'close');
|
|
14
|
+
if (openCalls.length > closeCalls.length) {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
file,
|
|
18
|
+
line: openCalls[0].pos.line,
|
|
19
|
+
severity: 'warn',
|
|
20
|
+
rule: 'open_without_close',
|
|
21
|
+
message: (0, locale_1.t)('open_without_close', openCalls.length, closeCalls.length),
|
|
22
|
+
},
|
|
23
|
+
];
|
|
19
24
|
}
|
|
20
25
|
return [];
|
|
21
26
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
2
3
|
export declare function checkParameterNaming(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkParameterNamingAst(ast: AstNode, file: string): Issue[];
|
|
3
5
|
//# sourceMappingURL=parameter-naming.d.ts.map
|
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkParameterNaming = checkParameterNaming;
|
|
4
|
+
exports.checkParameterNamingAst = checkParameterNamingAst;
|
|
4
5
|
const locale_1 = require("../locale");
|
|
5
|
-
const
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
6
7
|
function checkParameterNaming(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkParameterNamingAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkParameterNamingAst(ast, file) {
|
|
7
12
|
const issues = [];
|
|
8
|
-
const
|
|
9
|
-
for (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const defuns = (0, parser_1.astFindListWithHead)(ast, 'defun');
|
|
14
|
+
for (const defun of defuns) {
|
|
15
|
+
if (!defun.children || defun.children.length < 3)
|
|
16
|
+
continue;
|
|
17
|
+
const nameNode = defun.children[1];
|
|
18
|
+
const name = nameNode.type === 'symbol' && nameNode.name ? nameNode.name : '<unknown>';
|
|
19
|
+
// Third child should be the parameter list
|
|
20
|
+
const paramList = defun.children[2];
|
|
21
|
+
if (paramList.type !== 'list' || !paramList.children)
|
|
13
22
|
continue;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (/^[A-Z]/.test(p)
|
|
23
|
+
for (const p of paramList.children) {
|
|
24
|
+
if (p.type !== 'symbol' || !p.name)
|
|
25
|
+
continue;
|
|
26
|
+
if (p.name === 'T' || p.name === 'nil')
|
|
27
|
+
continue;
|
|
28
|
+
if (/^[A-Z]/.test(p.name)) {
|
|
20
29
|
issues.push({
|
|
21
|
-
file,
|
|
22
|
-
|
|
30
|
+
file,
|
|
31
|
+
line: p.pos.line,
|
|
32
|
+
severity: 'warn',
|
|
33
|
+
rule: 'parameter_naming',
|
|
34
|
+
message: (0, locale_1.t)('parameter_naming', p.name, name),
|
|
23
35
|
});
|
|
24
36
|
}
|
|
25
37
|
}
|
package/dist/checks/parens.js
CHANGED
|
@@ -32,10 +32,15 @@ function checkParens(content, file) {
|
|
|
32
32
|
}
|
|
33
33
|
if (openP !== closeP) {
|
|
34
34
|
const diff = openP - closeP;
|
|
35
|
-
return [
|
|
36
|
-
|
|
35
|
+
return [
|
|
36
|
+
{
|
|
37
|
+
file,
|
|
38
|
+
line: 1,
|
|
39
|
+
severity: 'error',
|
|
40
|
+
rule: 'parens',
|
|
37
41
|
message: (0, locale_1.t)('parens.mismatch', openP, closeP, (diff > 0 ? '+' : '') + diff),
|
|
38
|
-
}
|
|
42
|
+
},
|
|
43
|
+
];
|
|
39
44
|
}
|
|
40
45
|
return [];
|
|
41
46
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkQuoteVsFunction(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkQuoteVsFunctionAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=quote-vs-function.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkQuoteVsFunction = checkQuoteVsFunction;
|
|
4
|
+
exports.checkQuoteVsFunctionAst = checkQuoteVsFunctionAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
const HIGHER_ORDER_FUNCS = new Set([
|
|
8
|
+
'mapcar',
|
|
9
|
+
'apply',
|
|
10
|
+
'lambda',
|
|
11
|
+
'vl-sort',
|
|
12
|
+
'vl-sort-i',
|
|
13
|
+
'vl-remove-if',
|
|
14
|
+
'vl-remove-if-not',
|
|
15
|
+
'vl-member-if',
|
|
16
|
+
'vl-some',
|
|
17
|
+
'vl-every',
|
|
18
|
+
]);
|
|
19
|
+
function checkQuoteVsFunction(content, file) {
|
|
20
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
21
|
+
return checkQuoteVsFunctionAst(ast, file);
|
|
22
|
+
}
|
|
23
|
+
function checkQuoteVsFunctionAst(ast, file) {
|
|
24
|
+
const issues = [];
|
|
25
|
+
const quotedLambdas = (0, parser_1.astFindAll)(ast, (n) => {
|
|
26
|
+
if (!(0, parser_1.astIsList)(n, 'quote'))
|
|
27
|
+
return false;
|
|
28
|
+
if (!n.children || n.children.length < 2)
|
|
29
|
+
return false;
|
|
30
|
+
return (0, parser_1.astIsList)(n.children[1], 'lambda');
|
|
31
|
+
});
|
|
32
|
+
for (const node of quotedLambdas) {
|
|
33
|
+
const parent = node.parent;
|
|
34
|
+
if (!parent || !parent.children)
|
|
35
|
+
continue;
|
|
36
|
+
const parentHead = parent.children[0];
|
|
37
|
+
const parentName = (parentHead.type === 'symbol' && parentHead.name) || '';
|
|
38
|
+
if (HIGHER_ORDER_FUNCS.has(parentName)) {
|
|
39
|
+
issues.push({
|
|
40
|
+
file,
|
|
41
|
+
line: node.pos.line,
|
|
42
|
+
severity: 'warn',
|
|
43
|
+
rule: 'quote_vs_function',
|
|
44
|
+
message: (0, locale_1.t)('quote_vs_function', parentName),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=quote-vs-function.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkRecursiveCall(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkRecursiveCallAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=recursive-call.d.ts.map
|