@atlisp/lint 0.1.5 → 0.1.8
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 +219 -58
- package/atlisp-lint.default.json +32 -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/format-indent.d.ts +3 -0
- package/dist/checks/format-indent.js +29 -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 +71 -2
- package/dist/disable.js +1 -1
- package/dist/formatter.d.ts +2 -0
- package/dist/formatter.js +51 -0
- package/dist/formatters.d.ts +1 -0
- package/dist/formatters.js +18 -2
- package/dist/index.js +172 -32
- package/dist/lib/lint-sbcl.lisp +161 -0
- package/dist/locale.js +76 -0
- package/dist/presets.d.ts +4 -0
- package/dist/presets.js +159 -0
- package/dist/project.js +37 -6
- package/dist/rules.d.ts +9 -0
- package/dist/rules.js +239 -0
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +329 -12
- 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 +126 -0
- package/dist/watch.d.ts +9 -0
- package/dist/watch.js +113 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkErrorHandling = checkErrorHandling;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkErrorHandling(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
let inDefun = false;
|
|
10
|
+
let defunName = '';
|
|
11
|
+
let defunStart = 0;
|
|
12
|
+
let defunText = '';
|
|
13
|
+
let hasErrorHandler = false;
|
|
14
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
16
|
+
if (!inDefun) {
|
|
17
|
+
const m = stripped.match(/\(defun\s+(\S+)/);
|
|
18
|
+
if (m) {
|
|
19
|
+
inDefun = true;
|
|
20
|
+
defunName = m[1];
|
|
21
|
+
defunStart = i + 1;
|
|
22
|
+
defunText = '';
|
|
23
|
+
hasErrorHandler = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (inDefun) {
|
|
27
|
+
defunText += stripped + '\n';
|
|
28
|
+
if (stripped.includes('*error*'))
|
|
29
|
+
hasErrorHandler = true;
|
|
30
|
+
// Check for depth returning to 0 (end of defun)
|
|
31
|
+
let depth = 0;
|
|
32
|
+
for (const ch of stripped) {
|
|
33
|
+
if (ch === '(')
|
|
34
|
+
depth++;
|
|
35
|
+
else if (ch === ')')
|
|
36
|
+
depth--;
|
|
37
|
+
}
|
|
38
|
+
if (depth === 0 && defunText.trim().length > 0 && defunName) {
|
|
39
|
+
// End of defun - check if it uses command but no *error*
|
|
40
|
+
if (/\(command\b/.test(defunText) && !hasErrorHandler && !defunName.startsWith('c:')) {
|
|
41
|
+
issues.push({
|
|
42
|
+
file,
|
|
43
|
+
line: defunStart,
|
|
44
|
+
severity: 'warn',
|
|
45
|
+
rule: 'error_handling',
|
|
46
|
+
message: (0, locale_1.t)('error_handling', defunName),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
inDefun = false;
|
|
50
|
+
defunName = '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=error-handling.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkExtraParens = checkExtraParens;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkExtraParens(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
let runningDepth = 0;
|
|
10
|
+
for (let i = 0; i < lines.length; i++) {
|
|
11
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
12
|
+
const closeOnly = stripped.trim();
|
|
13
|
+
// Empty line resets nothing; just continue tracking depth
|
|
14
|
+
if (!closeOnly)
|
|
15
|
+
continue;
|
|
16
|
+
// Count parens on this line
|
|
17
|
+
let lineOpen = 0, lineClose = 0;
|
|
18
|
+
for (const ch of stripped) {
|
|
19
|
+
if (ch === '(')
|
|
20
|
+
lineOpen++;
|
|
21
|
+
else if (ch === ')')
|
|
22
|
+
lineClose++;
|
|
23
|
+
}
|
|
24
|
+
// Check if this line is pure closing parens
|
|
25
|
+
if (/^\)+$/.test(closeOnly)) {
|
|
26
|
+
// Only flag if these closing parens exceed the running depth
|
|
27
|
+
// (i.e., they are unmatched / extra)
|
|
28
|
+
if (lineClose > runningDepth + lineOpen) {
|
|
29
|
+
const extra = lineClose - runningDepth - lineOpen;
|
|
30
|
+
issues.push({
|
|
31
|
+
file,
|
|
32
|
+
line: i + 1,
|
|
33
|
+
severity: 'warn',
|
|
34
|
+
rule: 'extra_parens',
|
|
35
|
+
message: (0, locale_1.t)('extra_parens', extra),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
runningDepth += lineOpen - lineClose;
|
|
40
|
+
if (runningDepth < 0)
|
|
41
|
+
runningDepth = 0;
|
|
42
|
+
}
|
|
43
|
+
return issues;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=extra-parens.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkFormatIndent = checkFormatIndent;
|
|
4
|
+
const formatter_1 = require("../formatter");
|
|
5
|
+
function checkFormatIndent(content, file) {
|
|
6
|
+
const formatted = (0, formatter_1.formatCode)(content);
|
|
7
|
+
if (content === formatted)
|
|
8
|
+
return [];
|
|
9
|
+
// Find first line that differs for better error location
|
|
10
|
+
const originalLines = content.split('\n');
|
|
11
|
+
const formattedLines = formatted.split('\n');
|
|
12
|
+
let firstDiffLine = 1;
|
|
13
|
+
for (let i = 0; i < Math.max(originalLines.length, formattedLines.length); i++) {
|
|
14
|
+
if (originalLines[i] !== formattedLines[i]) {
|
|
15
|
+
firstDiffLine = i + 1;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
file,
|
|
22
|
+
line: firstDiffLine,
|
|
23
|
+
severity: 'warn',
|
|
24
|
+
rule: 'format_indent',
|
|
25
|
+
message: 'Code indentation does not match expected format',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=format-indent.js.map
|
|
@@ -41,7 +41,7 @@ function checkFunctionComplexityAst(ast, file, maxLines, maxNesting) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
// Check lambda forms: (lambda (args) body...)
|
|
44
|
-
const lambdas = (0, parser_1.astFindAll)(ast,
|
|
44
|
+
const lambdas = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'lambda'));
|
|
45
45
|
for (const lam of lambdas) {
|
|
46
46
|
if (!lam.children || !lam.end)
|
|
47
47
|
continue;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkFunctionOrder = checkFunctionOrder;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkFunctionOrder(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
const defined = new Set();
|
|
10
|
+
for (let i = 0; i < lines.length; i++) {
|
|
11
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
12
|
+
const defunM = stripped.match(/\(defun\s+(\S+)/);
|
|
13
|
+
if (defunM) {
|
|
14
|
+
const name = defunM[1];
|
|
15
|
+
if (name.includes('/') || name.startsWith('c:'))
|
|
16
|
+
continue;
|
|
17
|
+
defined.add(name);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const callM = stripped.match(/\((\S+)\s+/);
|
|
21
|
+
if (callM) {
|
|
22
|
+
const name = callM[1];
|
|
23
|
+
if (name.startsWith('(') || name === 'defun' || name.startsWith('@') || /^[a-z]+:/.test(name))
|
|
24
|
+
continue;
|
|
25
|
+
if (!defined.has(name) && name.length > 1 && /^[a-z]/.test(name)) {
|
|
26
|
+
defined.add(name);
|
|
27
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'function_order', message: (0, locale_1.t)('function_order', name) });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return issues;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=function-order.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkGlobalNaming = checkGlobalNaming;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkGlobalNaming(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
let depth = 0;
|
|
10
|
+
let inDefun = false;
|
|
11
|
+
let defunLocals = new Set();
|
|
12
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13
|
+
const stripped = (0, utils_1.stripLine)(lines[i]);
|
|
14
|
+
// Track depth
|
|
15
|
+
for (const ch of stripped) {
|
|
16
|
+
if (ch === '(')
|
|
17
|
+
depth++;
|
|
18
|
+
else if (ch === ')')
|
|
19
|
+
depth--;
|
|
20
|
+
}
|
|
21
|
+
// Detect defun start and extract local variables
|
|
22
|
+
if (!inDefun) {
|
|
23
|
+
const defunMatch = stripped.match(/\(defun\s+\S+\s+\(([^)]*\/\s+[^)]*)\)/);
|
|
24
|
+
if (defunMatch) {
|
|
25
|
+
inDefun = true;
|
|
26
|
+
const all = defunMatch[1];
|
|
27
|
+
const slashIdx = all.indexOf('/');
|
|
28
|
+
defunLocals = new Set(all
|
|
29
|
+
.slice(slashIdx + 1)
|
|
30
|
+
.split(/\s+/)
|
|
31
|
+
.filter(Boolean));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (depth <= 0) {
|
|
35
|
+
inDefun = false;
|
|
36
|
+
defunLocals = new Set();
|
|
37
|
+
}
|
|
38
|
+
// setq at depth 0 or 1 (top-level or directly inside progn) is global
|
|
39
|
+
if (depth <= 1) {
|
|
40
|
+
const m = stripped.match(/\(setq\s+(\S+)/);
|
|
41
|
+
if (m) {
|
|
42
|
+
const v = m[1];
|
|
43
|
+
if (v !== 'T' &&
|
|
44
|
+
v !== 'nil' &&
|
|
45
|
+
!v.startsWith('*') &&
|
|
46
|
+
!v.endsWith('*') &&
|
|
47
|
+
!v.includes('/') &&
|
|
48
|
+
!defunLocals.has(v)) {
|
|
49
|
+
issues.push({
|
|
50
|
+
file,
|
|
51
|
+
line: i + 1,
|
|
52
|
+
severity: 'warn',
|
|
53
|
+
rule: 'global_naming',
|
|
54
|
+
message: (0, locale_1.t)('global_naming', v),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return issues;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=global-naming.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export declare function checkIdenticalBranches(content: string, file: string): Issue[];
|
|
4
|
+
export declare function checkIdenticalBranchesAst(ast: AstNode, file: string): Issue[];
|
|
5
|
+
//# sourceMappingURL=identical-branches.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkIdenticalBranches = checkIdenticalBranches;
|
|
4
|
+
exports.checkIdenticalBranchesAst = checkIdenticalBranchesAst;
|
|
5
|
+
const locale_1 = require("../locale");
|
|
6
|
+
const parser_1 = require("@atlisp/parser");
|
|
7
|
+
function astEqual(a, b) {
|
|
8
|
+
if (a.type !== b.type)
|
|
9
|
+
return false;
|
|
10
|
+
if (a.type === 'symbol')
|
|
11
|
+
return a.name === b.name;
|
|
12
|
+
if (a.type === 'number')
|
|
13
|
+
return a.value === b.value;
|
|
14
|
+
if (a.type === 'string')
|
|
15
|
+
return a.value === b.value;
|
|
16
|
+
if (a.type === 'list') {
|
|
17
|
+
const aChildren = a.children || [];
|
|
18
|
+
const bChildren = b.children || [];
|
|
19
|
+
if (aChildren.length !== bChildren.length)
|
|
20
|
+
return false;
|
|
21
|
+
for (let i = 0; i < aChildren.length; i++) {
|
|
22
|
+
if (!astEqual(aChildren[i], bChildren[i]))
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function checkIdenticalBranches(content, file) {
|
|
30
|
+
const ast = (0, parser_1.parseAst)(content);
|
|
31
|
+
return checkIdenticalBranchesAst(ast, file);
|
|
32
|
+
}
|
|
33
|
+
function checkIdenticalBranchesAst(ast, file) {
|
|
34
|
+
const issues = [];
|
|
35
|
+
// Check if statements: (if cond then-branch else-branch)
|
|
36
|
+
const ifNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'if'));
|
|
37
|
+
for (const node of ifNodes) {
|
|
38
|
+
if (!node.children || node.children.length < 4)
|
|
39
|
+
continue;
|
|
40
|
+
const thenBranch = node.children[2];
|
|
41
|
+
const elseBranch = node.children[3];
|
|
42
|
+
if (astEqual(thenBranch, elseBranch)) {
|
|
43
|
+
issues.push({
|
|
44
|
+
file,
|
|
45
|
+
line: node.pos.line,
|
|
46
|
+
severity: 'warn',
|
|
47
|
+
rule: 'identical_branches',
|
|
48
|
+
message: (0, locale_1.t)('identical_branches'),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return issues;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=identical-branches.js.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runChecks = runChecks;
|
|
4
|
+
const config_1 = require("../config");
|
|
5
|
+
const disable_1 = require("../disable");
|
|
6
|
+
const encoding_1 = require("./encoding");
|
|
7
|
+
const parens_1 = require("./parens");
|
|
8
|
+
const cl_syntax_1 = require("./cl-syntax");
|
|
9
|
+
const dangerous_calls_1 = require("./dangerous-calls");
|
|
10
|
+
const vlax_1 = require("./vlax");
|
|
11
|
+
const token_in_url_1 = require("./token-in-url");
|
|
12
|
+
const open_close_1 = require("./open-close");
|
|
13
|
+
const bare_names_1 = require("./bare-names");
|
|
14
|
+
const module_reg_1 = require("./module-reg");
|
|
15
|
+
const namespace_header_1 = require("./namespace-header");
|
|
16
|
+
const line_length_1 = require("./line-length");
|
|
17
|
+
const function_complexity_1 = require("./function-complexity");
|
|
18
|
+
const parameter_naming_1 = require("./parameter-naming");
|
|
19
|
+
const unused_variable_1 = require("./unused-variable");
|
|
20
|
+
const missing_doc_1 = require("./missing-doc");
|
|
21
|
+
const error_handling_1 = require("./error-handling");
|
|
22
|
+
const global_naming_1 = require("./global-naming");
|
|
23
|
+
const extra_parens_1 = require("./extra-parens");
|
|
24
|
+
const arg_count_1 = require("./arg-count");
|
|
25
|
+
const strcat_usage_1 = require("./strcat-usage");
|
|
26
|
+
const cond_simplify_1 = require("./cond-simplify");
|
|
27
|
+
const redundant_progn_1 = require("./redundant-progn");
|
|
28
|
+
const quote_style_1 = require("./quote-style");
|
|
29
|
+
const eq_usage_1 = require("./eq-usage");
|
|
30
|
+
const lambda_syntax_1 = require("./lambda-syntax");
|
|
31
|
+
const comment_style_1 = require("./comment-style");
|
|
32
|
+
const empty_catch_1 = require("./empty-catch");
|
|
33
|
+
const nth_usage_1 = require("./nth-usage");
|
|
34
|
+
const append_single_1 = require("./append-single");
|
|
35
|
+
const setq_multiple_1 = require("./setq-multiple");
|
|
36
|
+
const function_order_1 = require("./function-order");
|
|
37
|
+
const magic_number_1 = require("./magic-number");
|
|
38
|
+
const mixed_indent_1 = require("./mixed-indent");
|
|
39
|
+
const long_function_call_1 = require("./long-function-call");
|
|
40
|
+
const no_return_1 = require("./no-return");
|
|
41
|
+
const shadow_builtin_1 = require("./shadow-builtin");
|
|
42
|
+
const dynamic_doc_1 = require("./dynamic-doc");
|
|
43
|
+
const loop_optimization_1 = require("./loop-optimization");
|
|
44
|
+
const type_check_1 = require("./type-check");
|
|
45
|
+
const redundant_if_1 = require("./redundant-if");
|
|
46
|
+
const trailing_ws_1 = require("./trailing-ws");
|
|
47
|
+
function runChecks(content, file, config) {
|
|
48
|
+
const issues = [];
|
|
49
|
+
const disableMap = (0, disable_1.parseDisableComments)(content);
|
|
50
|
+
function addIfEnabled(rule, fn) {
|
|
51
|
+
if ((0, config_1.getCheckSeverity)(config, rule) === 'off')
|
|
52
|
+
return;
|
|
53
|
+
const results = fn();
|
|
54
|
+
for (const r of results) {
|
|
55
|
+
if (!(0, disable_1.isDisabled)(r.rule, r.line, disableMap)) {
|
|
56
|
+
issues.push(r);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const checks = [
|
|
61
|
+
{ rule: 'encoding', fn: () => (0, encoding_1.checkEncoding)(content, file) },
|
|
62
|
+
{ rule: 'parens', fn: () => (0, parens_1.checkParens)(content, file) },
|
|
63
|
+
{ rule: 'cl_syntax', fn: () => (0, cl_syntax_1.checkClSyntax)(content, file, config.cl_syntax.keywords) },
|
|
64
|
+
{ rule: 'quit_exit', fn: () => (0, dangerous_calls_1.checkDangerousCalls)(content, file, config.dangerous_calls) },
|
|
65
|
+
{ rule: 'vlax_without_loading', fn: () => (0, vlax_1.checkVlaxWithoutLoading)(content, file) },
|
|
66
|
+
{ rule: 'token_in_url', fn: () => (0, token_in_url_1.checkTokenInUrl)(content, file) },
|
|
67
|
+
{ rule: 'open_without_close', fn: () => (0, open_close_1.checkOpenWithoutClose)(content, file) },
|
|
68
|
+
{
|
|
69
|
+
rule: 'bare_function_names',
|
|
70
|
+
fn: () => (0, bare_names_1.checkBareFunctionNames)(content, file, config.bare_function_names.allowlist, config.bare_function_names.namespace_pattern),
|
|
71
|
+
},
|
|
72
|
+
{ rule: 'module_registration', fn: () => (0, module_reg_1.checkModuleRegistration)(content, file, file, config.module_registration) },
|
|
73
|
+
{ rule: 'namespace_header', fn: () => (0, namespace_header_1.checkNamespaceHeader)(content, file, config.namespace_header) },
|
|
74
|
+
{
|
|
75
|
+
rule: 'line_length',
|
|
76
|
+
fn: () => (0, line_length_1.checkLineLength)(content, file, config.line_length.max, config.line_length.tab_width),
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
rule: 'function_complexity',
|
|
80
|
+
fn: () => (0, function_complexity_1.checkFunctionComplexity)(content, file, config.function_complexity.max_lines, config.function_complexity.max_nesting),
|
|
81
|
+
},
|
|
82
|
+
{ rule: 'parameter_naming', fn: () => (0, parameter_naming_1.checkParameterNaming)(content, file) },
|
|
83
|
+
{ rule: 'unused_variable', fn: () => (0, unused_variable_1.checkUnusedVariable)(content, file) },
|
|
84
|
+
{ rule: 'missing_doc', fn: () => (0, missing_doc_1.checkMissingDoc)(content, file) },
|
|
85
|
+
{ rule: 'error_handling', fn: () => (0, error_handling_1.checkErrorHandling)(content, file) },
|
|
86
|
+
{ rule: 'global_naming', fn: () => (0, global_naming_1.checkGlobalNaming)(content, file) },
|
|
87
|
+
{ rule: 'extra_parens', fn: () => (0, extra_parens_1.checkExtraParens)(content, file) },
|
|
88
|
+
{ rule: 'arg_count', fn: () => (0, arg_count_1.checkArgCount)(content, file) },
|
|
89
|
+
{ rule: 'strcat_usage', fn: () => (0, strcat_usage_1.checkStrcatUsage)(content, file) },
|
|
90
|
+
{ rule: 'cond_simplify', fn: () => (0, cond_simplify_1.checkCondSimplify)(content, file) },
|
|
91
|
+
{ rule: 'redundant_progn', fn: () => (0, redundant_progn_1.checkRedundantProgn)(content, file) },
|
|
92
|
+
{ rule: 'quote_style', fn: () => (0, quote_style_1.checkQuoteStyle)(content, file) },
|
|
93
|
+
{ rule: 'eq_usage', fn: () => (0, eq_usage_1.checkEqUsage)(content, file) },
|
|
94
|
+
{ rule: 'lambda_syntax', fn: () => (0, lambda_syntax_1.checkLambdaSyntax)(content, file) },
|
|
95
|
+
{ rule: 'comment_style', fn: () => (0, comment_style_1.checkCommentStyle)(content, file) },
|
|
96
|
+
{ rule: 'empty_catch', fn: () => (0, empty_catch_1.checkEmptyCatch)(content, file) },
|
|
97
|
+
{ rule: 'nth_usage', fn: () => (0, nth_usage_1.checkNthUsage)(content, file) },
|
|
98
|
+
{ rule: 'append_single', fn: () => (0, append_single_1.checkAppendSingle)(content, file) },
|
|
99
|
+
{ rule: 'setq_multiple', fn: () => (0, setq_multiple_1.checkSetqMultiple)(content, file) },
|
|
100
|
+
{ rule: 'function_order', fn: () => (0, function_order_1.checkFunctionOrder)(content, file) },
|
|
101
|
+
{ rule: 'magic_number', fn: () => (0, magic_number_1.checkMagicNumber)(content, file) },
|
|
102
|
+
{ rule: 'mixed_indent', fn: () => (0, mixed_indent_1.checkMixedIndent)(content, file) },
|
|
103
|
+
{ rule: 'long_function_call', fn: () => (0, long_function_call_1.checkLongFunctionCall)(content, file, 6) },
|
|
104
|
+
{ rule: 'no_return', fn: () => (0, no_return_1.checkNoReturn)(content, file) },
|
|
105
|
+
{ rule: 'shadow_builtin', fn: () => (0, shadow_builtin_1.checkShadowBuiltin)(content, file) },
|
|
106
|
+
{ rule: 'dynamic_doc', fn: () => (0, dynamic_doc_1.checkDynamicDoc)(content, file) },
|
|
107
|
+
{ rule: 'loop_optimization', fn: () => (0, loop_optimization_1.checkLoopOptimization)(content, file) },
|
|
108
|
+
{ rule: 'type_check', fn: () => (0, type_check_1.checkTypeCheck)(content, file) },
|
|
109
|
+
{ rule: 'redundant_if', fn: () => (0, redundant_if_1.checkRedundantIf)(content, file) },
|
|
110
|
+
{ rule: 'trailing_whitespace', fn: () => (0, trailing_ws_1.checkTrailingWhitespace)(content, file) },
|
|
111
|
+
];
|
|
112
|
+
for (const c of checks) {
|
|
113
|
+
addIfEnabled(c.rule, c.fn);
|
|
114
|
+
}
|
|
115
|
+
return issues;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkLambdaSyntax = checkLambdaSyntax;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkLambdaSyntax(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
|
+
// Detect (function (lambda ...)) → can be #'
|
|
12
|
+
const m = stripped.match(/\(function\s+\(lambda\b/);
|
|
13
|
+
if (m) {
|
|
14
|
+
issues.push({
|
|
15
|
+
file,
|
|
16
|
+
line: i + 1,
|
|
17
|
+
severity: 'warn',
|
|
18
|
+
rule: 'lambda_syntax',
|
|
19
|
+
message: (0, locale_1.t)('lambda_syntax'),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return issues;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=lambda-syntax.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkLongFunctionCall = checkLongFunctionCall;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkLongFunctionCall(content, file, maxArgs) {
|
|
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(/\((\S+)\s+/);
|
|
12
|
+
if (!m)
|
|
13
|
+
continue;
|
|
14
|
+
const afterName = stripped.slice(m[0].length);
|
|
15
|
+
if (!afterName || afterName === ')')
|
|
16
|
+
continue;
|
|
17
|
+
let argCount = 0, depth = 0, inArg = false;
|
|
18
|
+
for (const ch of afterName) {
|
|
19
|
+
if (ch === '(') {
|
|
20
|
+
depth++;
|
|
21
|
+
if (!inArg)
|
|
22
|
+
inArg = true;
|
|
23
|
+
}
|
|
24
|
+
else if (ch === ')') {
|
|
25
|
+
depth--;
|
|
26
|
+
if (depth === 0 && inArg) {
|
|
27
|
+
argCount++;
|
|
28
|
+
inArg = false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (depth === 0 && (ch === ' ' || ch === '\t')) {
|
|
32
|
+
if (inArg) {
|
|
33
|
+
argCount++;
|
|
34
|
+
inArg = false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (!inArg)
|
|
38
|
+
inArg = true;
|
|
39
|
+
}
|
|
40
|
+
if (inArg)
|
|
41
|
+
argCount++;
|
|
42
|
+
if (argCount > maxArgs && !m[1].startsWith('(') && !m[1].startsWith('"') && m[1] !== 'if') {
|
|
43
|
+
issues.push({
|
|
44
|
+
file,
|
|
45
|
+
line: i + 1,
|
|
46
|
+
severity: 'warn',
|
|
47
|
+
rule: 'long_function_call',
|
|
48
|
+
message: (0, locale_1.t)('long_function_call', argCount),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return issues;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=long-function-call.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkLoopOptimization = checkLoopOptimization;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkLoopOptimization(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 (/(foreach|while)\s+\S+\s+\S+/.test(stripped) && stripped.includes('assoc')) {
|
|
12
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'loop_optimization', message: (0, locale_1.t)('loop_optimization') });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return issues;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=loop-optimization.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkMagicNumber = checkMagicNumber;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkMagicNumber(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(/\([a-z]+\s+.*?(\d{2,})\b/);
|
|
12
|
+
if (m) {
|
|
13
|
+
const num = m[1];
|
|
14
|
+
if (num !== '10' && num !== '20' && num !== '100' && num !== '1000') {
|
|
15
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'magic_number', message: (0, locale_1.t)('magic_number', num) });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return issues;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=magic-number.js.map
|
|
@@ -10,7 +10,7 @@ function checkMisplacedElse(content, file) {
|
|
|
10
10
|
}
|
|
11
11
|
function checkMisplacedElseAst(ast, file) {
|
|
12
12
|
const issues = [];
|
|
13
|
-
const ifNodes = (0, parser_1.astFindAll)(ast,
|
|
13
|
+
const ifNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'if'));
|
|
14
14
|
for (const node of ifNodes) {
|
|
15
15
|
if (!node.children || node.children.length !== 4)
|
|
16
16
|
continue;
|
|
@@ -45,7 +45,7 @@ function checkMissingExport(file, pkgDir, _allDefuns) {
|
|
|
45
45
|
return issues;
|
|
46
46
|
const pkgContent = fs.readFileSync(pkgLspPath, 'utf-8');
|
|
47
47
|
const pkgAst = (0, parser_1.parseAst)(pkgContent);
|
|
48
|
-
const modulesNode = (0, parser_1.astFindAll)(pkgAst,
|
|
48
|
+
const modulesNode = (0, parser_1.astFindAll)(pkgAst, n => (0, parser_1.astIsList)(n, 'setq'));
|
|
49
49
|
const registered = new Set();
|
|
50
50
|
for (const node of modulesNode) {
|
|
51
51
|
if (!node.children)
|
|
@@ -69,7 +69,7 @@ function checkMissingExport(file, pkgDir, _allDefuns) {
|
|
|
69
69
|
}
|
|
70
70
|
const fileContent = fs.readFileSync(file, 'utf-8');
|
|
71
71
|
const ast = (0, parser_1.parseAst)(fileContent);
|
|
72
|
-
const defunNodes = (0, parser_1.astFindAll)(ast,
|
|
72
|
+
const defunNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
|
|
73
73
|
for (const node of defunNodes) {
|
|
74
74
|
if (!node.children || node.children.length < 2)
|
|
75
75
|
continue;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkMixedIndent = checkMixedIndent;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
function checkMixedIndent(content, file) {
|
|
6
|
+
const issues = [];
|
|
7
|
+
const lines = content.split('\n');
|
|
8
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9
|
+
const line = lines[i];
|
|
10
|
+
if (!line.trim())
|
|
11
|
+
continue;
|
|
12
|
+
const indent = line.substring(0, line.length - line.trimStart().length);
|
|
13
|
+
if (indent.includes('\t') && indent.includes(' ')) {
|
|
14
|
+
issues.push({ file, line: i + 1, severity: 'warn', rule: 'mixed_indent', message: (0, locale_1.t)('mixed_indent') });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return issues;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=mixed-indent.js.map
|
|
@@ -12,7 +12,7 @@ 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(
|
|
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
18
|
return [
|