@atlisp/lint 0.1.2 → 0.1.4
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 +3 -0
- package/atlisp-lint.default.json +26 -7
- 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 +5 -2
- 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 +5 -0
- package/dist/checks/redundant-progn.js +31 -0
- 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 -30
- 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 +0 -13
- package/dist/disable.js +4 -1
- package/dist/formatters.d.ts +1 -2
- package/dist/formatters.js +8 -61
- package/dist/index.d.ts +1 -1
- package/dist/index.js +137 -117
- package/dist/locale.js +83 -47
- package/dist/project.d.ts +3 -0
- package/dist/project.js +138 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.js +215 -23
- package/dist/sbcl.js +16 -11
- package/dist/worker.js +10 -50
- package/lib/lint-sbcl.lisp +19 -54
- package/package.json +18 -4
- package/dist/atlisp-lint.default.json +0 -71
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.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/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/encoding.d.ts.map +0 -1
- package/dist/checks/encoding.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/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/line-length.d.ts.map +0 -1
- package/dist/checks/line-length.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/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/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/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/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 -39
- 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 -55
- 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
|
@@ -0,0 +1,93 @@
|
|
|
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.checkUnusedPackageDep = checkUnusedPackageDep;
|
|
37
|
+
const locale_1 = require("../locale");
|
|
38
|
+
const parser_1 = require("@atlisp/parser");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
function checkUnusedPackageDep(file) {
|
|
41
|
+
const issues = [];
|
|
42
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
43
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
44
|
+
const inPackageNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'in-package'));
|
|
45
|
+
if (inPackageNodes.length === 0)
|
|
46
|
+
return issues;
|
|
47
|
+
const allPackages = new Set();
|
|
48
|
+
for (const node of inPackageNodes) {
|
|
49
|
+
if (node.children && node.children.length >= 2 && (0, parser_1.astIsSymbol)(node.children[1])) {
|
|
50
|
+
allPackages.add(node.children[1].name);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const usedSymbols = new Set();
|
|
54
|
+
const allLists = (0, parser_1.astFindAll)(ast, (n) => n.type === 'list');
|
|
55
|
+
for (const node of allLists) {
|
|
56
|
+
if (!node.children || node.children.length === 0)
|
|
57
|
+
continue;
|
|
58
|
+
const car = node.children[0];
|
|
59
|
+
if (car.type === 'symbol' && car.name) {
|
|
60
|
+
const parts = car.name.split(':');
|
|
61
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
62
|
+
usedSymbols.add(parts[0]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (let i = 1; i < node.children.length; i++) {
|
|
66
|
+
const child = node.children[i];
|
|
67
|
+
if (child.type === 'symbol' && child.name) {
|
|
68
|
+
const parts = child.name.split(':');
|
|
69
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
70
|
+
usedSymbols.add(parts[0]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const mainPackage = inPackageNodes.length > 0 && inPackageNodes[0].children && inPackageNodes[0].children[1]
|
|
76
|
+
? inPackageNodes[0].children[1].name || ''
|
|
77
|
+
: '';
|
|
78
|
+
allPackages.delete(mainPackage);
|
|
79
|
+
for (const pkg of allPackages) {
|
|
80
|
+
if (!usedSymbols.has(pkg)) {
|
|
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
|
+
issues.push({
|
|
83
|
+
file,
|
|
84
|
+
line: node ? node.pos.line : 1,
|
|
85
|
+
severity: 'warn',
|
|
86
|
+
rule: 'unused_package_dep',
|
|
87
|
+
message: (0, locale_1.t)('unused_package_dep', pkg),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return issues;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=unused-package-dep.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkUnusedParameter(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkUnusedParameterAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=unused-param.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkUnusedParameter = checkUnusedParameter;
|
|
4
|
+
exports.checkUnusedParameterAst = checkUnusedParameterAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkUnusedParameter(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkUnusedParameterAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkUnusedParameterAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
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 funcName = nameNode.type === 'symbol' && nameNode.name ? nameNode.name : '<unknown>';
|
|
19
|
+
if (funcName.startsWith('c:') || funcName.startsWith('C:'))
|
|
20
|
+
continue;
|
|
21
|
+
const paramList = defun.children[2];
|
|
22
|
+
if (paramList.type !== 'list' || !paramList.children)
|
|
23
|
+
continue;
|
|
24
|
+
// Collect params before / (AutoLISP: (defun foo (a b / x y) ...) — a,b are params, x,y are locals)
|
|
25
|
+
const params = [];
|
|
26
|
+
for (const p of paramList.children) {
|
|
27
|
+
if (p.type === 'symbol' && p.name === '/')
|
|
28
|
+
break;
|
|
29
|
+
if (p.type !== 'symbol' || !p.name)
|
|
30
|
+
continue;
|
|
31
|
+
if (p.name === 'T' || p.name === 'nil')
|
|
32
|
+
continue;
|
|
33
|
+
params.push(p);
|
|
34
|
+
}
|
|
35
|
+
if (params.length === 0)
|
|
36
|
+
continue;
|
|
37
|
+
// Collect all symbol references in the body (excluding param list)
|
|
38
|
+
const used = new Set();
|
|
39
|
+
for (let i = 3; i < defun.children.length; i++) {
|
|
40
|
+
collectSymbolRefs(defun.children[i], used);
|
|
41
|
+
}
|
|
42
|
+
for (const p of params) {
|
|
43
|
+
if (!used.has(p.name)) {
|
|
44
|
+
issues.push({
|
|
45
|
+
file,
|
|
46
|
+
line: p.pos.line,
|
|
47
|
+
severity: 'warn',
|
|
48
|
+
rule: 'unused_parameter',
|
|
49
|
+
message: (0, locale_1.t)('unused_parameter', p.name, funcName),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
function collectSymbolRefs(node, refs) {
|
|
57
|
+
for (const n of (0, parser_1.astWalk)(node)) {
|
|
58
|
+
if (n.type === 'symbol' && n.name) {
|
|
59
|
+
refs.add(n.name);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=unused-param.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
2
3
|
export declare function checkUnusedVariable(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkUnusedVariableAst(ast: AstNode, file: string): Issue[];
|
|
3
5
|
//# sourceMappingURL=unused-variable.d.ts.map
|
|
@@ -1,50 +1,90 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkUnusedVariable = checkUnusedVariable;
|
|
4
|
+
exports.checkUnusedVariableAst = checkUnusedVariableAst;
|
|
4
5
|
const locale_1 = require("../locale");
|
|
5
|
-
const
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
6
7
|
function checkUnusedVariable(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkUnusedVariableAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkUnusedVariableAst(ast, file) {
|
|
7
12
|
const issues = [];
|
|
8
|
-
|
|
13
|
+
// Find all setq forms, collect variable definitions
|
|
14
|
+
const setqForms = (0, parser_1.astFindListWithHead)(ast, 'setq');
|
|
9
15
|
const setqVars = new Map();
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
for (const form of setqForms) {
|
|
17
|
+
if (!form.children)
|
|
18
|
+
continue;
|
|
19
|
+
for (let i = 1; i < form.children.length; i += 2) {
|
|
20
|
+
const v = form.children[i];
|
|
21
|
+
if (v.type !== 'symbol' || !v.name)
|
|
22
|
+
continue;
|
|
23
|
+
if (v.name === 'T' || v.name === 'nil')
|
|
24
|
+
continue;
|
|
25
|
+
if (v.name.startsWith('/'))
|
|
26
|
+
continue;
|
|
27
|
+
if (!setqVars.has(v.name)) {
|
|
28
|
+
setqVars.set(v.name, v.pos.line);
|
|
20
29
|
}
|
|
21
30
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Don't count the setq line itself
|
|
33
|
-
if (re.test(stripped) && !stripped.match(new RegExp('\\(setq\\s+' + v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b'))) {
|
|
34
|
-
usedVars.add(v);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
31
|
+
}
|
|
32
|
+
if (setqVars.size === 0)
|
|
33
|
+
return issues;
|
|
34
|
+
// Set of defined var nodes (to exclude from usage)
|
|
35
|
+
const defNodes = new Set();
|
|
36
|
+
for (const form of setqForms) {
|
|
37
|
+
if (!form.children)
|
|
38
|
+
continue;
|
|
39
|
+
for (let i = 1; i < form.children.length; i += 2) {
|
|
40
|
+
defNodes.add(form.children[i]);
|
|
38
41
|
}
|
|
39
42
|
}
|
|
43
|
+
// Walk entire AST, collect used variable references
|
|
44
|
+
// Skip references inside a (let ((x ...)) ...) when checking outer x
|
|
45
|
+
const usedVars = new Set();
|
|
46
|
+
for (const node of (0, parser_1.astWalk)(ast)) {
|
|
47
|
+
if (node.type !== 'symbol' || !node.name)
|
|
48
|
+
continue;
|
|
49
|
+
if (defNodes.has(node))
|
|
50
|
+
continue;
|
|
51
|
+
// Skip if this reference is inside a let that binds the same name
|
|
52
|
+
if (isInsideLetBinding(node, node.name))
|
|
53
|
+
continue;
|
|
54
|
+
usedVars.add(node.name);
|
|
55
|
+
}
|
|
40
56
|
for (const [v, line] of setqVars) {
|
|
41
|
-
if (!usedVars.has(v)
|
|
57
|
+
if (!usedVars.has(v)) {
|
|
42
58
|
issues.push({
|
|
43
|
-
file,
|
|
59
|
+
file,
|
|
60
|
+
line,
|
|
61
|
+
severity: 'warn',
|
|
62
|
+
rule: 'unused_variable',
|
|
44
63
|
message: (0, locale_1.t)('unused_variable', v),
|
|
45
64
|
});
|
|
46
65
|
}
|
|
47
66
|
}
|
|
48
67
|
return issues;
|
|
49
68
|
}
|
|
69
|
+
function isInsideLetBinding(node, varName) {
|
|
70
|
+
let cur = node.parent;
|
|
71
|
+
while (cur) {
|
|
72
|
+
if ((0, parser_1.astIsList)(cur, 'let') && cur.children && cur.children.length >= 2) {
|
|
73
|
+
const bindings = cur.children[1];
|
|
74
|
+
if (bindings.type === 'list' && bindings.children) {
|
|
75
|
+
for (const b of bindings.children) {
|
|
76
|
+
if (b.type === 'list' &&
|
|
77
|
+
b.children &&
|
|
78
|
+
b.children.length > 0 &&
|
|
79
|
+
b.children[0].type === 'symbol' &&
|
|
80
|
+
b.children[0].name === varName) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
cur = cur.parent;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
50
90
|
//# sourceMappingURL=unused-variable.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkVariableShadow(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkVariableShadowAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=variable-shadow.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkVariableShadow = checkVariableShadow;
|
|
4
|
+
exports.checkVariableShadowAst = checkVariableShadowAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function checkVariableShadow(content, file) {
|
|
8
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
9
|
+
return checkVariableShadowAst(ast, file);
|
|
10
|
+
}
|
|
11
|
+
function checkVariableShadowAst(ast, file) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
const letNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'let'));
|
|
14
|
+
for (const node of letNodes) {
|
|
15
|
+
if (!node.children || node.children.length < 2)
|
|
16
|
+
continue;
|
|
17
|
+
const bindingList = node.children[1];
|
|
18
|
+
if (bindingList.type !== 'list' || !bindingList.children)
|
|
19
|
+
continue;
|
|
20
|
+
// Collect let-bound variable names
|
|
21
|
+
const letVars = new Set();
|
|
22
|
+
for (const binding of bindingList.children) {
|
|
23
|
+
if (binding.type !== 'list' || !binding.children || binding.children.length === 0)
|
|
24
|
+
continue;
|
|
25
|
+
const varNode = binding.children[0];
|
|
26
|
+
if (varNode.type !== 'symbol' || !varNode.name)
|
|
27
|
+
continue;
|
|
28
|
+
letVars.add(varNode.name);
|
|
29
|
+
}
|
|
30
|
+
if (letVars.size === 0)
|
|
31
|
+
continue;
|
|
32
|
+
// Walk the body for (setq var ...) where var is a let-bound name
|
|
33
|
+
for (let i = 2; i < node.children.length; i++) {
|
|
34
|
+
collectSetqTargets(node.children[i], letVars, issues, file);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return issues;
|
|
38
|
+
}
|
|
39
|
+
function collectSetqTargets(node, letVars, issues, file) {
|
|
40
|
+
if (node.type !== 'list' || !node.children)
|
|
41
|
+
return;
|
|
42
|
+
const car = node.children[0];
|
|
43
|
+
if (car.type === 'symbol' && car.name === 'setq') {
|
|
44
|
+
for (let i = 1; i < node.children.length; i += 2) {
|
|
45
|
+
const target = node.children[i];
|
|
46
|
+
if (target.type === 'symbol' && target.name && letVars.has(target.name)) {
|
|
47
|
+
issues.push({
|
|
48
|
+
file,
|
|
49
|
+
line: target.pos.line,
|
|
50
|
+
severity: 'warn',
|
|
51
|
+
rule: 'variable_shadow',
|
|
52
|
+
message: (0, locale_1.t)('variable_shadow', target.name),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Recurse into sublists (but don't enter nested let forms — they create new scope)
|
|
58
|
+
if (car.type === 'symbol' && car.name === 'let')
|
|
59
|
+
return;
|
|
60
|
+
for (const child of node.children) {
|
|
61
|
+
if (child.type === 'list') {
|
|
62
|
+
collectSetqTargets(child, letVars, issues, file);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=variable-shadow.js.map
|
package/dist/checks/vlax.js
CHANGED
|
@@ -8,10 +8,15 @@ function checkVlaxWithoutLoading(content, file) {
|
|
|
8
8
|
return [];
|
|
9
9
|
for (const { lineno, stripped } of (0, utils_1.codeLines)(content)) {
|
|
10
10
|
if (/vlax-/i.test(stripped)) {
|
|
11
|
-
return [
|
|
12
|
-
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
file,
|
|
14
|
+
line: lineno,
|
|
15
|
+
severity: 'warn',
|
|
16
|
+
rule: 'vlax_without_loading',
|
|
13
17
|
message: (0, locale_1.t)('vlax_without_loading'),
|
|
14
|
-
}
|
|
18
|
+
},
|
|
19
|
+
];
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
return [];
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { LintConfig
|
|
1
|
+
import { LintConfig } from './types';
|
|
2
2
|
export declare function loadConfig(configPath?: string): LintConfig;
|
|
3
|
-
export declare function getCheckSeverity(config: LintConfig, checkName: string): Severity;
|
|
4
3
|
export declare function findOverrides(filepath: string): Partial<LintConfig> | null;
|
|
5
4
|
export declare function mergeOverrides(base: LintConfig, overrides: Partial<LintConfig>): LintConfig;
|
|
6
5
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -34,7 +34,6 @@ 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;
|
|
38
37
|
exports.findOverrides = findOverrides;
|
|
39
38
|
exports.mergeOverrides = mergeOverrides;
|
|
40
39
|
const fs = __importStar(require("fs"));
|
|
@@ -63,12 +62,6 @@ const DEFAULT_CONFIG = {
|
|
|
63
62
|
parameter_naming: 'warn',
|
|
64
63
|
unused_variable: 'warn',
|
|
65
64
|
missing_doc: 'warn',
|
|
66
|
-
error_handling: 'warn',
|
|
67
|
-
global_naming: 'warn',
|
|
68
|
-
extra_parens: 'warn',
|
|
69
|
-
arg_count: 'warn',
|
|
70
|
-
strcat_usage: 'warn',
|
|
71
|
-
cond_simplify: 'warn',
|
|
72
65
|
module_registration: 'off',
|
|
73
66
|
namespace_header: 'off',
|
|
74
67
|
},
|
|
@@ -140,12 +133,6 @@ function deepMerge(target, source) {
|
|
|
140
133
|
}
|
|
141
134
|
}
|
|
142
135
|
}
|
|
143
|
-
function getCheckSeverity(config, checkName) {
|
|
144
|
-
const sev = config.checks[checkName];
|
|
145
|
-
if (sev === 'error' || sev === 'warn')
|
|
146
|
-
return sev;
|
|
147
|
-
return 'off';
|
|
148
|
-
}
|
|
149
136
|
function findOverrides(filepath) {
|
|
150
137
|
const dir = path.dirname(filepath);
|
|
151
138
|
const configPath = path.join(dir, '.atlisp-lint.json');
|
package/dist/disable.js
CHANGED
|
@@ -10,7 +10,10 @@ function parseDisableComments(content, fileLine) {
|
|
|
10
10
|
const m = line.match(/;\s*atlisp-lint:\s*disable=(.+)/i);
|
|
11
11
|
if (!m)
|
|
12
12
|
continue;
|
|
13
|
-
const rules = m[1]
|
|
13
|
+
const rules = m[1]
|
|
14
|
+
.split(',')
|
|
15
|
+
.map((r) => r.trim())
|
|
16
|
+
.filter(Boolean);
|
|
14
17
|
let targetLine = i + 1;
|
|
15
18
|
if (fileLine !== undefined)
|
|
16
19
|
targetLine = fileLine;
|
package/dist/formatters.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Issue } from './types';
|
|
2
2
|
export declare function formatDefault(issues: Issue[], fileContents?: Map<string, string>): string;
|
|
3
|
-
export declare function formatJson(issues: Issue[]): string;
|
|
4
|
-
export declare function formatHtml(issues: Issue[], totalErrors: number, totalWarnings: number): string;
|
|
3
|
+
export declare function formatJson(issues: Issue[], errorCount?: number, warningCount?: number): string;
|
|
5
4
|
//# sourceMappingURL=formatters.d.ts.map
|
package/dist/formatters.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatDefault = formatDefault;
|
|
4
4
|
exports.formatJson = formatJson;
|
|
5
|
-
exports.formatHtml = formatHtml;
|
|
6
5
|
const locale_1 = require("./locale");
|
|
7
6
|
const colors = {
|
|
8
7
|
red: '\x1b[31m',
|
|
@@ -26,9 +25,7 @@ function formatDefault(issues, fileContents) {
|
|
|
26
25
|
const tagColor = iss.severity === 'error' ? colors.red : colors.yellow;
|
|
27
26
|
const tag = iss.severity === 'error' ? (0, locale_1.t)('summary.tag_fail') : (0, locale_1.t)('summary.tag_warn');
|
|
28
27
|
const loc = iss.line > 0 ? `${(0, locale_1.t)('summary.line')} ${iss.line}` : '';
|
|
29
|
-
const prefix = useColor
|
|
30
|
-
? `${tagColor}${tag}${colors.reset}`
|
|
31
|
-
: tag;
|
|
28
|
+
const prefix = useColor ? `${tagColor}${tag}${colors.reset}` : tag;
|
|
32
29
|
lines.push(`${prefix}: ${iss.file} — ${loc}${loc ? ': ' : ''}${iss.message}`.trim());
|
|
33
30
|
if (iss.line > 0 && fileContents) {
|
|
34
31
|
const content = fileContents.get(iss.file);
|
|
@@ -48,7 +45,7 @@ function formatDefault(issues, fileContents) {
|
|
|
48
45
|
}
|
|
49
46
|
if (lines.length > 0)
|
|
50
47
|
lines.push('');
|
|
51
|
-
const summaryColor = errors > 0 ? colors.red :
|
|
48
|
+
const summaryColor = errors > 0 ? colors.red : warnings > 0 ? colors.yellow : colors.cyan;
|
|
52
49
|
if (useColor) {
|
|
53
50
|
lines.push(`${colors.cyan}${(0, locale_1.t)('summary.header')}${colors.reset}`);
|
|
54
51
|
if (errors === 0 && warnings === 0) {
|
|
@@ -71,61 +68,11 @@ function formatDefault(issues, fileContents) {
|
|
|
71
68
|
}
|
|
72
69
|
return lines.join('\n');
|
|
73
70
|
}
|
|
74
|
-
function formatJson(issues) {
|
|
75
|
-
return JSON.stringify({
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const loc = iss.line > 0 ? `Line ${iss.line}` : '';
|
|
81
|
-
return `<tr class="${sevClass}">
|
|
82
|
-
<td><span class="badge badge-${sevClass}">${sevClass === 'error' ? 'FAIL' : 'WARN'}</span></td>
|
|
83
|
-
<td>${iss.file}</td>
|
|
84
|
-
<td>${loc}</td>
|
|
85
|
-
<td>${iss.rule}</td>
|
|
86
|
-
<td>${iss.message}</td>
|
|
87
|
-
</tr>`;
|
|
88
|
-
}).join('\n');
|
|
89
|
-
return `<!DOCTYPE html>
|
|
90
|
-
<html lang="zh">
|
|
91
|
-
<head>
|
|
92
|
-
<meta charset="UTF-8">
|
|
93
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
94
|
-
<title>@atlisp/lint Report</title>
|
|
95
|
-
<style>
|
|
96
|
-
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 20px; background: #f5f5f5; }
|
|
97
|
-
h1 { color: #333; }
|
|
98
|
-
.summary { display: flex; gap: 20px; margin: 20px 0; }
|
|
99
|
-
.stat { background: #fff; padding: 15px 25px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
|
100
|
-
.stat-errors { border-left: 4px solid #e74c3c; }
|
|
101
|
-
.stat-warnings { border-left: 4px solid #f39c12; }
|
|
102
|
-
.stat-ok { border-left: 4px solid #27ae60; }
|
|
103
|
-
.stat-value { font-size: 28px; font-weight: bold; }
|
|
104
|
-
.stat-label { color: #666; font-size: 12px; text-transform: uppercase; }
|
|
105
|
-
table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
|
106
|
-
th { background: #333; color: #fff; padding: 12px; text-align: left; }
|
|
107
|
-
td { padding: 10px 12px; border-bottom: 1px solid #eee; }
|
|
108
|
-
tr.error td { background: #fef0ef; }
|
|
109
|
-
tr.warn td { background: #fef9e7; }
|
|
110
|
-
.badge { padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; color: #fff; }
|
|
111
|
-
.badge-error { background: #e74c3c; }
|
|
112
|
-
.badge-warn { background: #f39c12; }
|
|
113
|
-
.footer { margin-top: 20px; color: #999; font-size: 12px; text-align: center; }
|
|
114
|
-
</style>
|
|
115
|
-
</head>
|
|
116
|
-
<body>
|
|
117
|
-
<h1>@atlisp/lint Report</h1>
|
|
118
|
-
<div class="summary">
|
|
119
|
-
<div class="stat stat-errors"><div class="stat-value">${totalErrors}</div><div class="stat-label">Errors</div></div>
|
|
120
|
-
<div class="stat stat-warnings"><div class="stat-value">${totalWarnings}</div><div class="stat-label">Warnings</div></div>
|
|
121
|
-
<div class="stat stat-ok"><div class="stat-value">${issues.length}</div><div class="stat-label">Total Issues</div></div>
|
|
122
|
-
</div>
|
|
123
|
-
<table>
|
|
124
|
-
<thead><tr><th>Severity</th><th>File</th><th>Line</th><th>Rule</th><th>Message</th></tr></thead>
|
|
125
|
-
<tbody>${rows.length ? rows : '<tr><td colspan="5" style="text-align:center;color:#999;">No issues found</td></tr>'}</tbody>
|
|
126
|
-
</table>
|
|
127
|
-
<div class="footer">Generated by @atlisp/lint</div>
|
|
128
|
-
</body>
|
|
129
|
-
</html>`;
|
|
71
|
+
function formatJson(issues, errorCount, warningCount) {
|
|
72
|
+
return JSON.stringify({
|
|
73
|
+
issues,
|
|
74
|
+
error_count: errorCount ?? issues.filter((i) => i.severity === 'error').length,
|
|
75
|
+
warning_count: warningCount ?? issues.filter((i) => i.severity === 'warn').length,
|
|
76
|
+
}, null, 2);
|
|
130
77
|
}
|
|
131
78
|
//# sourceMappingURL=formatters.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function main(): void
|
|
1
|
+
export declare function main(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|