@atlisp/lint 0.2.16 → 0.2.18
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 +1 -1
- package/atlisp-lint.default.json +1 -1
- package/dist/checks/arg-count.d.ts +2 -1
- package/dist/checks/arg-count.js +37 -19
- package/dist/checks/builtin-arg-count.d.ts +2 -1
- package/dist/checks/builtin-arg-count.js +3 -2
- package/dist/checks/cond-duplicate.js +5 -6
- package/dist/checks/constant-condition.js +9 -9
- package/dist/checks/dangerous-calls.js +1 -1
- package/dist/checks/dangling-defun.d.ts +0 -7
- package/dist/checks/dangling-defun.js +0 -63
- package/dist/checks/double-not.js +1 -1
- package/dist/checks/empty-branch.js +1 -1
- package/dist/checks/empty-catch.d.ts +2 -1
- package/dist/checks/empty-catch.js +8 -7
- package/dist/checks/function-complexity.js +5 -18
- package/dist/checks/global-naming.js +1 -1
- package/dist/checks/identical-branches.js +3 -3
- package/dist/checks/if-without-else.js +1 -1
- package/dist/checks/misplaced-else.js +2 -2
- package/dist/checks/missing-export.js +3 -3
- package/dist/checks/missing-princ.js +1 -1
- package/dist/checks/multiple-setq.js +1 -1
- package/dist/checks/no-return.d.ts +2 -1
- package/dist/checks/no-return.js +4 -3
- package/dist/checks/nth-usage.js +1 -1
- package/dist/checks/parameter-naming.js +2 -2
- package/dist/checks/quote-vs-function.js +1 -1
- package/dist/checks/recursive-call.js +1 -1
- 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-setq.js +1 -1
- package/dist/checks/self-compare.js +1 -1
- package/dist/checks/setq-single-arg.js +3 -2
- package/dist/checks/single-arg-and-or.js +1 -1
- package/dist/checks/undeclared-setq.d.ts +2 -1
- package/dist/checks/undeclared-setq.js +6 -5
- package/dist/checks/unused-let.js +3 -3
- package/dist/checks/unused-local-fun.js +2 -2
- package/dist/checks/unused-package-dep.d.ts +0 -1
- package/dist/checks/unused-package-dep.js +6 -93
- package/dist/checks/unused-param.js +2 -2
- package/dist/checks/unused-variable.js +2 -2
- package/dist/checks/variable-shadow.js +3 -3
- package/dist/checks/while-constant.js +1 -1
- package/dist/cli/collector.js +26 -19
- package/dist/config.d.ts +1 -1
- package/dist/config.js +18 -9
- package/dist/fixes/index.d.ts +4 -0
- package/dist/fixes/index.js +843 -140
- package/dist/formatter.d.ts +0 -1
- package/dist/formatter.js +141 -31
- package/dist/index.js +59 -51
- package/dist/project.d.ts +1 -1
- package/dist/project.js +98 -112
- package/dist/runner.d.ts +1 -1
- package/dist/runner.js +17 -8
- package/dist/utils.js +21 -30
- package/dist/validate.js +3 -3
- package/dist/visitor-runner.d.ts +0 -28
- package/dist/visitor-runner.js +3 -809
- package/dist/visitors/equal-nil.d.ts +2 -2
- package/dist/visitors/equal-nil.js +5 -4
- package/dist/visitors/index.d.ts +1 -1
- package/dist/visitors/progn-in-cond.d.ts +2 -2
- package/dist/visitors/progn-in-cond.js +5 -4
- package/dist/visitors/redundant-and-or.d.ts +2 -2
- package/dist/visitors/redundant-and-or.js +3 -3
- package/dist/visitors/redundant-car-cdr.d.ts +2 -2
- package/dist/visitors/redundant-car-cdr.js +3 -3
- package/dist/visitors/register.d.ts +6 -0
- package/dist/visitors/register.js +625 -0
- package/dist/visitors/shared.d.ts +40 -0
- package/dist/visitors/shared.js +129 -0
- package/dist/visitors/types.d.ts +2 -7
- package/dist/visitors/types.js +0 -69
- package/dist/watch.js +33 -12
- package/dist/worker.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.higherOrderFuncs = void 0;
|
|
4
|
+
exports.isInQuote = isInQuote;
|
|
5
|
+
exports.isLiteral = isLiteral;
|
|
6
|
+
exports.astEqual = astEqual;
|
|
7
|
+
exports.getCondKey = getCondKey;
|
|
8
|
+
exports.hasConditionalForm = hasConditionalForm;
|
|
9
|
+
exports.hasSelfCall = hasSelfCall;
|
|
10
|
+
exports.defunParams = defunParams;
|
|
11
|
+
exports.defunLocals = defunLocals;
|
|
12
|
+
exports.collectSymbolRefs = collectSymbolRefs;
|
|
13
|
+
const parser_1 = require("@atlisp/parser");
|
|
14
|
+
function isInQuote(node, checkFunction = true) {
|
|
15
|
+
for (const p of (0, parser_1.astAncestors)(node)) {
|
|
16
|
+
if ((0, parser_1.astIsList)(p, 'quote') || (checkFunction && (0, parser_1.astIsList)(p, 'function'))) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function isLiteral(node) {
|
|
23
|
+
if ((0, parser_1.astIsSymbol)(node, 'T') || (0, parser_1.astIsSymbol)(node, 't') || (0, parser_1.astIsSymbol)(node, 'nil'))
|
|
24
|
+
return true;
|
|
25
|
+
if ((0, parser_1.astIsNumber)(node))
|
|
26
|
+
return true;
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function astEqual(a, b) {
|
|
30
|
+
if ((0, parser_1.astIsSymbol)(a) && (0, parser_1.astIsSymbol)(b))
|
|
31
|
+
return a.name === b.name;
|
|
32
|
+
if ((0, parser_1.astIsString)(a) && (0, parser_1.astIsString)(b))
|
|
33
|
+
return a.value === b.value;
|
|
34
|
+
if ((0, parser_1.astIsNumber)(a) && (0, parser_1.astIsNumber)(b))
|
|
35
|
+
return a.value === b.value;
|
|
36
|
+
if ((0, parser_1.astIsList)(a) && (0, parser_1.astIsList)(b)) {
|
|
37
|
+
if (a.children.length !== b.children.length)
|
|
38
|
+
return false;
|
|
39
|
+
for (let i = 0; i < a.children.length; i++) {
|
|
40
|
+
if (!astEqual(a.children[i], b.children[i]))
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function getCondKey(node) {
|
|
48
|
+
if ((0, parser_1.astIsSymbol)(node) || (0, parser_1.astIsKeyword)(node))
|
|
49
|
+
return node.name || '';
|
|
50
|
+
if ((0, parser_1.astIsString)(node) || (0, parser_1.astIsNumber)(node))
|
|
51
|
+
return String(node.value);
|
|
52
|
+
if ((0, parser_1.astIsList)(node)) {
|
|
53
|
+
return '(' + node.children.map(c => getCondKey(c)).join(' ') + ')';
|
|
54
|
+
}
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
function hasConditionalForm(body) {
|
|
58
|
+
for (const form of body) {
|
|
59
|
+
if ((0, parser_1.astIsList)(form) && form.children.length > 0 && (0, parser_1.astIsSymbol)(form.children[0])) {
|
|
60
|
+
const name = form.children[0].name;
|
|
61
|
+
if (name === 'if' || name === 'cond' || name === 'when' || name === 'unless') {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function hasSelfCall(body, fnName) {
|
|
69
|
+
for (const form of body) {
|
|
70
|
+
if ((0, parser_1.astIsList)(form, fnName)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
function defunParams(defunNode) {
|
|
77
|
+
const children = (0, parser_1.astChildren)(defunNode);
|
|
78
|
+
if (children.length < 3)
|
|
79
|
+
return [];
|
|
80
|
+
const paramList = children[2];
|
|
81
|
+
const params = [];
|
|
82
|
+
for (const child of (0, parser_1.astChildren)(paramList)) {
|
|
83
|
+
if ((0, parser_1.astIsSymbol)(child) && child.name !== '/') {
|
|
84
|
+
params.push(child.name);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return params;
|
|
88
|
+
}
|
|
89
|
+
function defunLocals(defunNode) {
|
|
90
|
+
const children = (0, parser_1.astChildren)(defunNode);
|
|
91
|
+
if (children.length < 3)
|
|
92
|
+
return [];
|
|
93
|
+
const paramList = children[2];
|
|
94
|
+
const locals = [];
|
|
95
|
+
let afterSlash = false;
|
|
96
|
+
for (const child of (0, parser_1.astChildren)(paramList)) {
|
|
97
|
+
if (!(0, parser_1.astIsSymbol)(child))
|
|
98
|
+
continue;
|
|
99
|
+
if (child.name === '/') {
|
|
100
|
+
afterSlash = true;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (afterSlash && child.name) {
|
|
104
|
+
locals.push(child.name);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return locals;
|
|
108
|
+
}
|
|
109
|
+
function collectSymbolRefs(node, result) {
|
|
110
|
+
if ((0, parser_1.astIsSymbol)(node) && node.name) {
|
|
111
|
+
result.add(node.name);
|
|
112
|
+
}
|
|
113
|
+
for (const c of (0, parser_1.astChildren)(node)) {
|
|
114
|
+
collectSymbolRefs(c, result);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.higherOrderFuncs = new Set([
|
|
118
|
+
'mapcar',
|
|
119
|
+
'apply',
|
|
120
|
+
'lambda',
|
|
121
|
+
'vl-sort',
|
|
122
|
+
'vl-sort-i',
|
|
123
|
+
'vl-remove-if',
|
|
124
|
+
'vl-remove-if-not',
|
|
125
|
+
'vl-member-if',
|
|
126
|
+
'vl-some',
|
|
127
|
+
'vl-every',
|
|
128
|
+
]);
|
|
129
|
+
//# sourceMappingURL=shared.js.map
|
package/dist/visitors/types.d.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CollectState } from '
|
|
1
|
+
import { AstVisitor } from '@atlisp/parser';
|
|
2
|
+
import { CollectState } from './shared';
|
|
3
3
|
export type AddIssueFn = (rule: string, line: number, message: string) => void;
|
|
4
4
|
export interface VisitorModule {
|
|
5
5
|
name: string;
|
|
6
6
|
register: (visitor: AstVisitor, state: CollectState, checks: Record<string, string>, addIssue: AddIssueFn) => void;
|
|
7
7
|
}
|
|
8
|
-
export declare function isInQuote(node: AstNode): boolean;
|
|
9
|
-
export declare function isLiteral(node: AstNode): boolean;
|
|
10
|
-
export declare function astEqual(a: AstNode, b: AstNode): boolean;
|
|
11
|
-
export declare function getCondKey(node: AstNode): string;
|
|
12
|
-
export declare function hasConditionalForm(body: AstNode[]): boolean;
|
|
13
8
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/visitors/types.js
CHANGED
|
@@ -1,72 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isInQuote = isInQuote;
|
|
4
|
-
exports.isLiteral = isLiteral;
|
|
5
|
-
exports.astEqual = astEqual;
|
|
6
|
-
exports.getCondKey = getCondKey;
|
|
7
|
-
exports.hasConditionalForm = hasConditionalForm;
|
|
8
|
-
function isInQuote(node) {
|
|
9
|
-
let p = node.parent;
|
|
10
|
-
while (p) {
|
|
11
|
-
if (p.type === 'list' &&
|
|
12
|
-
p.children &&
|
|
13
|
-
p.children.length > 0 &&
|
|
14
|
-
p.children[0].type === 'symbol' &&
|
|
15
|
-
(p.children[0].name === 'quote' || p.children[0].name === 'function')) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
p = p.parent;
|
|
19
|
-
}
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
function isLiteral(node) {
|
|
23
|
-
if (node.type === 'symbol' && (node.name === 'T' || node.name === 't' || node.name === 'nil'))
|
|
24
|
-
return true;
|
|
25
|
-
if (node.type === 'number')
|
|
26
|
-
return true;
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
function astEqual(a, b) {
|
|
30
|
-
if (a.type !== b.type)
|
|
31
|
-
return false;
|
|
32
|
-
if (a.type === 'symbol')
|
|
33
|
-
return a.name === b.name;
|
|
34
|
-
if (a.type === 'string')
|
|
35
|
-
return a.value === b.value;
|
|
36
|
-
if (a.type === 'number')
|
|
37
|
-
return a.value === b.value;
|
|
38
|
-
if (a.type === 'list') {
|
|
39
|
-
const ac = a.children || [];
|
|
40
|
-
const bc = b.children || [];
|
|
41
|
-
if (ac.length !== bc.length)
|
|
42
|
-
return false;
|
|
43
|
-
for (let i = 0; i < ac.length; i++) {
|
|
44
|
-
if (!astEqual(ac[i], bc[i]))
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
function getCondKey(node) {
|
|
52
|
-
if (node.type === 'symbol' || node.type === 'keyword')
|
|
53
|
-
return node.name || '';
|
|
54
|
-
if (node.type === 'string' || node.type === 'number')
|
|
55
|
-
return String(node.value);
|
|
56
|
-
if (node.type === 'list' && node.children) {
|
|
57
|
-
return '(' + node.children.map(c => getCondKey(c)).join(' ') + ')';
|
|
58
|
-
}
|
|
59
|
-
return '';
|
|
60
|
-
}
|
|
61
|
-
function hasConditionalForm(body) {
|
|
62
|
-
for (const form of body) {
|
|
63
|
-
if (form.type === 'list' && form.children && form.children.length > 0 && form.children[0].type === 'symbol') {
|
|
64
|
-
const name = form.children[0].name;
|
|
65
|
-
if (name === 'if' || name === 'cond' || name === 'when' || name === 'unless') {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
3
|
//# sourceMappingURL=types.js.map
|
package/dist/watch.js
CHANGED
|
@@ -39,11 +39,31 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const runner_1 = require("./runner");
|
|
40
40
|
const formatters_1 = require("./formatters");
|
|
41
41
|
const locale_1 = require("./locale");
|
|
42
|
+
let previousIssues = [];
|
|
43
|
+
let debounceTimer;
|
|
44
|
+
let pendingFiles = new Set();
|
|
45
|
+
function scheduleLint(files, rootDir, format, config, changedFile) {
|
|
46
|
+
pendingFiles.add(changedFile);
|
|
47
|
+
if (debounceTimer)
|
|
48
|
+
clearTimeout(debounceTimer);
|
|
49
|
+
debounceTimer = setTimeout(() => {
|
|
50
|
+
const toLint = Array.from(pendingFiles);
|
|
51
|
+
pendingFiles.clear();
|
|
52
|
+
debounceTimer = undefined;
|
|
53
|
+
// Only lint the changed files, merge with previous results
|
|
54
|
+
const newIssues = (0, runner_1.lintFiles)(toLint, config, rootDir);
|
|
55
|
+
const changedSet = new Set(toLint.map(f => path.relative(rootDir, f)));
|
|
56
|
+
const merged = previousIssues.filter(i => !changedSet.has(i.file)).concat(newIssues);
|
|
57
|
+
previousIssues = merged;
|
|
58
|
+
displayResults(merged, rootDir, format, files.length);
|
|
59
|
+
}, 200);
|
|
60
|
+
}
|
|
42
61
|
function watchFiles(files, options) {
|
|
43
62
|
const { rootDir, format, config } = options;
|
|
44
63
|
(0, locale_1.setLocale)(config.locale || 'zh');
|
|
45
64
|
// Initial lint
|
|
46
|
-
|
|
65
|
+
previousIssues = (0, runner_1.lintFiles)(files, config, rootDir);
|
|
66
|
+
displayResults(previousIssues, rootDir, format, files.length);
|
|
47
67
|
// Watch all files for changes
|
|
48
68
|
const watchers = [];
|
|
49
69
|
const watchedDirs = new Set();
|
|
@@ -52,15 +72,12 @@ function watchFiles(files, options) {
|
|
|
52
72
|
if (!watchedDirs.has(dir)) {
|
|
53
73
|
watchedDirs.add(dir);
|
|
54
74
|
try {
|
|
55
|
-
const watcher = fs.watch(dir, (
|
|
75
|
+
const watcher = fs.watch(dir, (_eventType, filename) => {
|
|
56
76
|
if (!filename)
|
|
57
77
|
return;
|
|
58
78
|
const fullPath = path.join(dir, filename);
|
|
59
79
|
if (files.includes(fullPath)) {
|
|
60
|
-
|
|
61
|
-
setTimeout(() => {
|
|
62
|
-
runLint(files, rootDir, format, config);
|
|
63
|
-
}, 200);
|
|
80
|
+
scheduleLint(files, rootDir, format, config, fullPath);
|
|
64
81
|
}
|
|
65
82
|
});
|
|
66
83
|
watchers.push(watcher);
|
|
@@ -84,10 +101,8 @@ function watchFiles(files, options) {
|
|
|
84
101
|
process.exit(0);
|
|
85
102
|
});
|
|
86
103
|
}
|
|
87
|
-
function
|
|
88
|
-
// Clear console
|
|
104
|
+
function displayResults(issues, rootDir, format, totalFiles) {
|
|
89
105
|
process.stdout.write('\x1Bc');
|
|
90
|
-
const issues = (0, runner_1.lintFiles)(files, config, rootDir);
|
|
91
106
|
const fileContents = new Map();
|
|
92
107
|
for (const iss of issues) {
|
|
93
108
|
if (!fileContents.has(iss.file)) {
|
|
@@ -106,8 +121,14 @@ function runLint(files, rootDir, format, config) {
|
|
|
106
121
|
else {
|
|
107
122
|
console.log((0, formatters_1.formatDefault)(issues, fileContents));
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
124
|
+
let errorCount = 0;
|
|
125
|
+
let warningCount = 0;
|
|
126
|
+
for (const iss of issues) {
|
|
127
|
+
if (iss.severity === 'error')
|
|
128
|
+
errorCount++;
|
|
129
|
+
else if (iss.severity === 'warn')
|
|
130
|
+
warningCount++;
|
|
131
|
+
}
|
|
132
|
+
console.log(`\n[${new Date().toLocaleTimeString()}] ${(0, locale_1.t)('index.watch_status', totalFiles, errorCount, warningCount)}`);
|
|
112
133
|
}
|
|
113
134
|
//# sourceMappingURL=watch.js.map
|
package/dist/worker.js
CHANGED
|
@@ -18,7 +18,7 @@ if (worker_threads_1.parentPort && worker_threads_1.workerData) {
|
|
|
18
18
|
const input = worker_threads_1.workerData;
|
|
19
19
|
(0, locale_1.setLocale)(input.config.locale || 'zh');
|
|
20
20
|
try {
|
|
21
|
-
const content = (0, fs_1.readFileSync)(input.filepath, 'utf-8');
|
|
21
|
+
const content = input.content ?? (0, fs_1.readFileSync)(input.filepath, 'utf-8');
|
|
22
22
|
const issues = (0, runner_1.runChecks)(content, input.relPath, input.config);
|
|
23
23
|
sendMessage({ filepath: input.filepath, issues });
|
|
24
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlisp/lint",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
4
4
|
"description": "AutoLISP static analysis tool — parens, security, conventions, SBCL syntax validation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CAD",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
},
|
|
55
55
|
"license": "MIT",
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@atlisp/parser": "^0.1.
|
|
57
|
+
"@atlisp/parser": "^0.1.9"
|
|
58
58
|
}
|
|
59
59
|
}
|