@atlisp/lint 0.2.8 → 0.2.10
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/atlisp-lint.default.json +4 -1
- package/atlisp-lint.schema.json +200 -0
- package/dist/checks/builtin-arg-count.js +1 -1
- package/dist/checks/global-function-naming.d.ts +3 -0
- package/dist/checks/global-function-naming.js +68 -0
- package/dist/checks/missing-princ.d.ts +3 -0
- package/dist/checks/missing-princ.js +46 -0
- package/dist/checks/redundant-entmake.d.ts +3 -0
- package/dist/checks/redundant-entmake.js +23 -0
- package/dist/config.js +4 -1
- package/dist/formatter.d.ts +1 -0
- package/dist/formatter.js +40 -27
- package/dist/index.js +11 -0
- package/dist/locale.js +12 -4
- package/dist/presets.js +6 -0
- package/dist/rules.d.ts +1 -0
- package/dist/rules.js +25 -0
- package/dist/runner.js +6 -0
- package/dist/validate.js +3 -0
- package/package.json +6 -5
package/atlisp-lint.default.json
CHANGED
|
@@ -87,7 +87,10 @@
|
|
|
87
87
|
"entget_in_loop": "warn",
|
|
88
88
|
"promise_handler": "off",
|
|
89
89
|
"module_cycle": "warn",
|
|
90
|
-
"arg_count_project": "warn"
|
|
90
|
+
"arg_count_project": "warn",
|
|
91
|
+
"redundant_entmake": "warn",
|
|
92
|
+
"missing_princ": "warn",
|
|
93
|
+
"global_function_naming": "info"
|
|
91
94
|
},
|
|
92
95
|
"line_length": {
|
|
93
96
|
"max": 200,
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "@atlisp/lint configuration",
|
|
4
|
+
"description": "Configuration schema for @atlisp/lint — AutoLISP static analysis tool",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"$schema": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Path to this schema file"
|
|
10
|
+
},
|
|
11
|
+
"locale": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["zh", "en"],
|
|
14
|
+
"default": "zh",
|
|
15
|
+
"description": "Output language (zh=Chinese, en=English)"
|
|
16
|
+
},
|
|
17
|
+
"preset": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["recommended", "strict", "relaxed"],
|
|
20
|
+
"description": "Config preset to start from (applied before user overrides)"
|
|
21
|
+
},
|
|
22
|
+
"source": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"properties": {
|
|
25
|
+
"globs": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": { "type": "string" },
|
|
28
|
+
"default": ["**/*.lsp"],
|
|
29
|
+
"description": "Glob patterns to match AutoLISP source files"
|
|
30
|
+
},
|
|
31
|
+
"exclude": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": { "type": "string" },
|
|
34
|
+
"default": ["**/node_modules/**", "**/vendor/**", "**/.git/**"],
|
|
35
|
+
"description": "Glob patterns to exclude from linting"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"required": ["globs", "exclude"]
|
|
39
|
+
},
|
|
40
|
+
"checks": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"description": "Rule severity configuration",
|
|
43
|
+
"properties": {
|
|
44
|
+
"append_single": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
45
|
+
"arg_count": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
46
|
+
"arg_count_project": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
47
|
+
"assoc_without_cdr": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
48
|
+
"bare_function_names": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
49
|
+
"builtin_arg_count": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
50
|
+
"cl_syntax": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
51
|
+
"command_shell": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
52
|
+
"comment_style": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
53
|
+
"commented_code": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
54
|
+
"cond_duplicate": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
55
|
+
"cond_simplify": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
56
|
+
"constant_condition": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
57
|
+
"dangling_defun": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
58
|
+
"double_not": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
59
|
+
"duplicate_defun": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
60
|
+
"dynamic_doc": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
61
|
+
"empty_branch": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
62
|
+
"empty_catch": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
63
|
+
"empty_comment": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
64
|
+
"encoding": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
65
|
+
"entget_in_loop": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
66
|
+
"eq_usage": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
67
|
+
"error_handling": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
68
|
+
"extra_parens": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
69
|
+
"format_indent": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
70
|
+
"function_complexity": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
71
|
+
"function_order": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
72
|
+
"global_function_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
73
|
+
"global_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
74
|
+
"identical_branches": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
75
|
+
"if_without_else": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
76
|
+
"lambda_syntax": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
77
|
+
"line_length": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
78
|
+
"long_function_call": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
79
|
+
"loop_optimization": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
80
|
+
"magic_number": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
81
|
+
"misplaced_else": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
82
|
+
"missing_doc": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
83
|
+
"missing_export": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
84
|
+
"missing_princ": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
85
|
+
"mixed_indent": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
86
|
+
"module_cycle": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
87
|
+
"module_registration": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
88
|
+
"multiple_setq": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
89
|
+
"namespace_header": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
90
|
+
"no_return": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
91
|
+
"nth_usage": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
92
|
+
"open_without_close": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
93
|
+
"parameter_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
94
|
+
"parens": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
95
|
+
"promise_handler": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
96
|
+
"quit_exit": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
97
|
+
"quote_style": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
98
|
+
"quote_vs_function": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
99
|
+
"recursive_call": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
100
|
+
"redundant_entmake": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
101
|
+
"redundant_if": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
102
|
+
"redundant_let": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
103
|
+
"redundant_list": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
104
|
+
"redundant_nil_else": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
105
|
+
"redundant_progn": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
106
|
+
"redundant_quotes": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
107
|
+
"redundant_setq": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
108
|
+
"self_compare": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
109
|
+
"setq_multiple": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
110
|
+
"setq_single_arg": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
111
|
+
"shadow_builtin": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
112
|
+
"single_arg_and_or": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
113
|
+
"startapp": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
114
|
+
"strcat_usage": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
115
|
+
"string_concat_loop": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
116
|
+
"token_in_url": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
117
|
+
"trailing_paren": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
118
|
+
"trailing_whitespace": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
119
|
+
"undeclared_setq": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
120
|
+
"unused_catch_result": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
|
|
121
|
+
"unused_let_binding": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
122
|
+
"unused_local_fun": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
123
|
+
"unused_package_dep": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
124
|
+
"unused_parameter": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
125
|
+
"unused_variable": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
126
|
+
"variable_shadow": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
127
|
+
"vl_registry_write": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
128
|
+
"vlax_without_loading": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
129
|
+
"while_constant": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" }
|
|
130
|
+
},
|
|
131
|
+
"additionalProperties": false
|
|
132
|
+
},
|
|
133
|
+
"line_length": {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"properties": {
|
|
136
|
+
"max": { "type": "integer", "minimum": 1, "default": 200 },
|
|
137
|
+
"tab_width": { "type": "integer", "minimum": 1, "default": 2 }
|
|
138
|
+
},
|
|
139
|
+
"required": ["max", "tab_width"]
|
|
140
|
+
},
|
|
141
|
+
"function_complexity": {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"properties": {
|
|
144
|
+
"max_lines": { "type": "integer", "minimum": 1, "default": 300 },
|
|
145
|
+
"max_nesting": { "type": "integer", "minimum": 1, "default": 30 }
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"cl_syntax": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"properties": {
|
|
151
|
+
"keywords": {
|
|
152
|
+
"type": "array",
|
|
153
|
+
"items": { "type": "string" },
|
|
154
|
+
"default": ["&key"]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"dangerous_calls": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"quit": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
162
|
+
"exit": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
|
|
163
|
+
"command_shell": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
164
|
+
"startapp": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
|
|
165
|
+
"vl_registry_write": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" }
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"module_registration": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"properties": {
|
|
171
|
+
"severity": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
172
|
+
"patterns": { "type": "array", "items": { "type": "string" } },
|
|
173
|
+
"dirs": { "type": "array", "items": { "type": "string" }, "default": ["modules"] }
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"namespace_header": {
|
|
177
|
+
"type": "object",
|
|
178
|
+
"properties": {
|
|
179
|
+
"severity": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
|
|
180
|
+
"package": { "type": "string", "default": "" },
|
|
181
|
+
"deps": { "type": "array", "items": { "type": "string" } },
|
|
182
|
+
"search_lines": { "type": "integer", "minimum": 1, "default": 15 }
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"bare_function_names": {
|
|
186
|
+
"type": "object",
|
|
187
|
+
"properties": {
|
|
188
|
+
"allowlist": { "type": "array", "items": { "type": "string" }, "default": ["T", "nil"] },
|
|
189
|
+
"namespace_pattern": { "type": "string", "default": "^[a-z]+:" }
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"sbcl": {
|
|
193
|
+
"type": "object",
|
|
194
|
+
"properties": {
|
|
195
|
+
"walk_exclude": { "type": "array", "items": { "type": "string" }, "default": [".vscode", "vendor", ".git"] },
|
|
196
|
+
"defmacro_allow_files": { "type": "array", "items": { "type": "string" }, "default": ["compat-cl"] }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -172,7 +172,7 @@ const BUILTIN_ARITY = {
|
|
|
172
172
|
trans: { min: 3, max: 4 },
|
|
173
173
|
// === Table/dictionary ===
|
|
174
174
|
tblobjname: { min: 2, max: 2 },
|
|
175
|
-
tblnext: { min:
|
|
175
|
+
tblnext: { min: 1, max: 2 },
|
|
176
176
|
tblsearch: { min: 2, max: 3 },
|
|
177
177
|
acad_colordlg: { min: 1, max: 3 },
|
|
178
178
|
// === ActiveX ===
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkGlobalFunctionNaming = checkGlobalFunctionNaming;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const BUILTIN_FUNCTIONS = new Set([
|
|
7
|
+
'if', 'cond', 'when', 'unless', 'progn', 'setq', 'setq-e', 'while', 'repeat',
|
|
8
|
+
'foreach', 'lambda', 'function', 'quote', 'defun', 'defun-q', 'defmacro',
|
|
9
|
+
'let', 'let*', 'mapcar', 'apply', 'eval', 'load', 'require',
|
|
10
|
+
'car', 'cdr', 'cadr', 'cdar', 'caar', 'cddr', 'caddr', 'cadar',
|
|
11
|
+
'cons', 'list', 'append', 'reverse', 'nth', 'assoc', 'subst', 'member',
|
|
12
|
+
'length', 'numberp', 'stringp', 'listp', 'atom', 'null', 'not',
|
|
13
|
+
'eq', 'equal', '=', '/=', '<', '>', '<=', '>=',
|
|
14
|
+
'+', '-', '*', '/', '1+', '1-', 'abs', 'min', 'max',
|
|
15
|
+
'strcat', 'substr', 'strlen', 'strcase',
|
|
16
|
+
'itoa', 'atoi', 'rtos', 'atof', 'fix', 'float',
|
|
17
|
+
'princ', 'print', 'prin1', 'prompt', 'terpri',
|
|
18
|
+
'open', 'close', 'read-line', 'write-line', 'read-char', 'write-char',
|
|
19
|
+
'entmake', 'entmakex', 'entget', 'entmod', 'entdel', 'entlast', 'entnext',
|
|
20
|
+
'ssget', 'ssadd', 'ssdel', 'sslength', 'ssname', 'ssmemb',
|
|
21
|
+
'command', 'vl-cmdf', 'vlax-invoke', 'vlax-invoke-method',
|
|
22
|
+
'vlax-get', 'vlax-put', 'vlax-get-property', 'vlax-put-property',
|
|
23
|
+
'vlax-make-variant', 'vlax-variant-value',
|
|
24
|
+
'vlax-safearray', 'vlax-safearray-fill', 'vlax-safearray->list',
|
|
25
|
+
'vl-catch-all-apply', 'vl-catch-all-error-p', 'vl-catch-all-error-message',
|
|
26
|
+
'vl-load-com', 'vlax-dump-object', 'vlax-for',
|
|
27
|
+
'vl-registry-read', 'vl-registry-write', 'vl-registry-delete',
|
|
28
|
+
'vl-file-copy', 'vl-file-delete', 'vl-file-rename',
|
|
29
|
+
'vl-directory-files', 'vl-mkdir', 'vl-string->list', 'vl-list->string',
|
|
30
|
+
'vl-string-search', 'vl-string-subst',
|
|
31
|
+
'vl-string-position', 'vl-string-mismatch',
|
|
32
|
+
'vl-symbol-value', 'vl-symbol-name',
|
|
33
|
+
'vl-sort', 'vl-sort-i',
|
|
34
|
+
'vl-remove-if', 'vl-remove-if-not', 'vl-member-if', 'vl-some', 'vl-every',
|
|
35
|
+
'vl-position', 'vl-consp',
|
|
36
|
+
'startapp', 'quit', 'exit', '*error*',
|
|
37
|
+
'vla-get-', 'vla-put-', 'vlax-ename->vla-object', 'vlax-vla-object->ename',
|
|
38
|
+
'vlax-3d-point', 'vlax-tmatrix',
|
|
39
|
+
'vlax-curve-getarea', 'vlax-curve-getdistatparam', 'vlax-curve-getparamatdist',
|
|
40
|
+
'vlax-curve-getclosestpointto', 'vlax-curve-getstartpoint', 'vlax-curve-getendpoint',
|
|
41
|
+
'vlax-curve-getpointatdist', 'vlax-curve-getpointatparam',
|
|
42
|
+
]);
|
|
43
|
+
function checkGlobalFunctionNaming(content, file) {
|
|
44
|
+
const issues = [];
|
|
45
|
+
const lines = content.split('\n');
|
|
46
|
+
for (let i = 0; i < lines.length; i++) {
|
|
47
|
+
const stripped = (0, utils_1.stripLine)(lines[i]).trim();
|
|
48
|
+
const m = stripped.match(/^\s*\(\s*defun\s+([^\s(]+)/);
|
|
49
|
+
if (!m)
|
|
50
|
+
continue;
|
|
51
|
+
const fnName = m[1];
|
|
52
|
+
if (BUILTIN_FUNCTIONS.has(fnName))
|
|
53
|
+
continue;
|
|
54
|
+
if (fnName.startsWith('C:') || fnName.startsWith('c:'))
|
|
55
|
+
continue;
|
|
56
|
+
if (fnName.includes(':'))
|
|
57
|
+
continue;
|
|
58
|
+
issues.push({
|
|
59
|
+
file,
|
|
60
|
+
line: i + 1,
|
|
61
|
+
severity: 'info',
|
|
62
|
+
rule: 'global_function_naming',
|
|
63
|
+
message: (0, locale_1.t)('global_function_naming', fnName),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return issues;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=global-function-naming.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkMissingPrinc = checkMissingPrinc;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const parser_1 = require("@atlisp/parser");
|
|
6
|
+
function checkMissingPrinc(content, file) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
let ast;
|
|
9
|
+
try {
|
|
10
|
+
ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return issues;
|
|
14
|
+
}
|
|
15
|
+
const defunNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
|
|
16
|
+
for (const node of defunNodes) {
|
|
17
|
+
if (!node.children || node.children.length < 3)
|
|
18
|
+
continue;
|
|
19
|
+
const nameNode = node.children[1];
|
|
20
|
+
if (!(0, parser_1.astIsSymbol)(nameNode))
|
|
21
|
+
continue;
|
|
22
|
+
const name = nameNode.name || '';
|
|
23
|
+
if (!name.startsWith('C:') && !name.startsWith('c:'))
|
|
24
|
+
continue;
|
|
25
|
+
const body = node.children.slice(3);
|
|
26
|
+
if (body.length === 0)
|
|
27
|
+
continue;
|
|
28
|
+
const lastForm = body[body.length - 1];
|
|
29
|
+
const isPrincCall = (lastForm.type === 'list' &&
|
|
30
|
+
lastForm.children &&
|
|
31
|
+
lastForm.children.length > 0 &&
|
|
32
|
+
(0, parser_1.astIsSymbol)(lastForm.children[0]) &&
|
|
33
|
+
['princ', 'print', 'prin1'].includes(lastForm.children[0].name || ''));
|
|
34
|
+
if (!isPrincCall) {
|
|
35
|
+
issues.push({
|
|
36
|
+
file,
|
|
37
|
+
line: node.pos.line,
|
|
38
|
+
severity: 'warn',
|
|
39
|
+
rule: 'missing_princ',
|
|
40
|
+
message: (0, locale_1.t)('missing_princ', name),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return issues;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=missing-princ.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkRedundantEntmake = checkRedundantEntmake;
|
|
4
|
+
const locale_1 = require("../locale");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
function checkRedundantEntmake(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 (/\((?:entmake|entmakex)\s+\(list\s+/.test(stripped)) {
|
|
12
|
+
issues.push({
|
|
13
|
+
file,
|
|
14
|
+
line: i + 1,
|
|
15
|
+
severity: 'warn',
|
|
16
|
+
rule: 'redundant_entmake',
|
|
17
|
+
message: (0, locale_1.t)('redundant_entmake'),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return issues;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=redundant-entmake.js.map
|
package/dist/config.js
CHANGED
|
@@ -120,7 +120,7 @@ const DEFAULT_CONFIG = {
|
|
|
120
120
|
shadow_builtin: 'warn',
|
|
121
121
|
dynamic_doc: 'warn',
|
|
122
122
|
loop_optimization: 'info',
|
|
123
|
-
format_indent: '
|
|
123
|
+
format_indent: 'warn',
|
|
124
124
|
redundant_if: 'info',
|
|
125
125
|
unused_catch_result: 'info',
|
|
126
126
|
string_concat_loop: 'info',
|
|
@@ -130,6 +130,9 @@ const DEFAULT_CONFIG = {
|
|
|
130
130
|
promise_handler: 'off',
|
|
131
131
|
module_cycle: 'warn',
|
|
132
132
|
arg_count_project: 'warn',
|
|
133
|
+
redundant_entmake: 'warn',
|
|
134
|
+
missing_princ: 'warn',
|
|
135
|
+
global_function_naming: 'info',
|
|
133
136
|
},
|
|
134
137
|
line_length: {
|
|
135
138
|
max: 200,
|
package/dist/formatter.d.ts
CHANGED
package/dist/formatter.js
CHANGED
|
@@ -1,51 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatCode = formatCode;
|
|
4
|
+
exports.formatCodeStable = formatCodeStable;
|
|
4
5
|
const utils_1 = require("./utils");
|
|
5
|
-
function
|
|
6
|
+
function isCommentLine(line) {
|
|
7
|
+
const trimmed = line.trim();
|
|
8
|
+
return trimmed.startsWith(';') || trimmed.startsWith(';|');
|
|
9
|
+
}
|
|
10
|
+
function formatCode(content, indentSize = 2) {
|
|
11
|
+
if (content === '' || content === '\n')
|
|
12
|
+
return content;
|
|
6
13
|
const lines = content.split('\n');
|
|
7
14
|
const result = [];
|
|
8
15
|
let depth = 0;
|
|
9
|
-
for (
|
|
10
|
-
const
|
|
11
|
-
|
|
16
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
17
|
+
const rawLine = lines[lineIdx];
|
|
18
|
+
const trimmed = rawLine.trimEnd();
|
|
19
|
+
if (trimmed === '') {
|
|
12
20
|
result.push('');
|
|
13
21
|
continue;
|
|
14
22
|
}
|
|
15
|
-
const
|
|
23
|
+
const isComment = isCommentLine(trimmed);
|
|
24
|
+
const stripped = (0, utils_1.stripLine)(trimmed);
|
|
16
25
|
const trimmedStripped = stripped.trim();
|
|
26
|
+
if (trimmedStripped === '' && isComment) {
|
|
27
|
+
result.push(' '.repeat(depth * indentSize) + trimmed.trimStart());
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
17
30
|
if (trimmedStripped === '') {
|
|
18
|
-
|
|
19
|
-
result.push(indent + trimmedLine.trimStart());
|
|
31
|
+
result.push(' '.repeat(depth * indentSize) + trimmed.trimStart());
|
|
20
32
|
continue;
|
|
21
33
|
}
|
|
22
|
-
|
|
23
|
-
|
|
34
|
+
const opens = (trimmedStripped.match(/\(/g) || []).length;
|
|
35
|
+
const closes = (trimmedStripped.match(/\)/g) || []).length;
|
|
36
|
+
let leadingCloseCount = 0;
|
|
24
37
|
for (const ch of trimmedStripped) {
|
|
25
|
-
if (ch === '
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
|
|
38
|
+
if (ch === ')')
|
|
39
|
+
leadingCloseCount++;
|
|
40
|
+
else
|
|
41
|
+
break;
|
|
29
42
|
}
|
|
30
43
|
let effectiveDepth = depth;
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
for (const ch of trimmedStripped) {
|
|
34
|
-
if (ch === ')')
|
|
35
|
-
leadingClose++;
|
|
36
|
-
else
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
effectiveDepth = Math.max(0, depth - leadingClose);
|
|
44
|
+
if (leadingCloseCount > 0) {
|
|
45
|
+
effectiveDepth = Math.max(0, depth - leadingCloseCount);
|
|
40
46
|
}
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
const indent = ' '.repeat(effectiveDepth * indentSize);
|
|
48
|
+
result.push(indent + trimmed.trimStart());
|
|
49
|
+
depth += opens - closes;
|
|
43
50
|
if (depth < 0)
|
|
44
51
|
depth = 0;
|
|
45
52
|
}
|
|
46
|
-
|
|
53
|
+
let output = result.join('\n');
|
|
54
|
+
if (output.length > 0 && !output.endsWith('\n')) {
|
|
55
|
+
output += '\n';
|
|
56
|
+
}
|
|
57
|
+
return output;
|
|
47
58
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
59
|
+
function formatCodeStable(content, indentSize = 2) {
|
|
60
|
+
const first = formatCode(content, indentSize);
|
|
61
|
+
const second = formatCode(first, indentSize);
|
|
62
|
+
return second;
|
|
50
63
|
}
|
|
51
64
|
//# sourceMappingURL=formatter.js.map
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ const formatters_sarif_1 = require("./formatters-sarif");
|
|
|
46
46
|
const formatters_html_1 = require("./formatters-html");
|
|
47
47
|
const formatter_1 = require("./formatter");
|
|
48
48
|
const locale_1 = require("./locale");
|
|
49
|
+
const rules_1 = require("./rules");
|
|
49
50
|
const cache_1 = require("./cache");
|
|
50
51
|
const watch_1 = require("./watch");
|
|
51
52
|
function parseArgs() {
|
|
@@ -71,6 +72,7 @@ function parseArgs() {
|
|
|
71
72
|
formatCode: false,
|
|
72
73
|
formatCheck: false,
|
|
73
74
|
sbcl: false,
|
|
75
|
+
docs: false,
|
|
74
76
|
};
|
|
75
77
|
for (let i = 0; i < argv.length; i++) {
|
|
76
78
|
switch (argv[i]) {
|
|
@@ -137,6 +139,9 @@ function parseArgs() {
|
|
|
137
139
|
case '--sbcl':
|
|
138
140
|
opts.sbcl = true;
|
|
139
141
|
break;
|
|
142
|
+
case '--docs':
|
|
143
|
+
opts.docs = true;
|
|
144
|
+
break;
|
|
140
145
|
default:
|
|
141
146
|
break;
|
|
142
147
|
}
|
|
@@ -297,6 +302,12 @@ async function main() {
|
|
|
297
302
|
const configPath = opts.config || path.join(rootDir, 'atlisp-lint.json');
|
|
298
303
|
const config = (0, config_1.loadConfig)(fs.existsSync(configPath) ? configPath : undefined);
|
|
299
304
|
(0, locale_1.setLocale)(config.locale || 'zh');
|
|
305
|
+
if (opts.docs) {
|
|
306
|
+
console.log((0, rules_1.generateRulesMarkdown)());
|
|
307
|
+
console.log();
|
|
308
|
+
console.log((0, rules_1.generateSchemaHint)());
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
300
311
|
if (opts.help) {
|
|
301
312
|
printHelp();
|
|
302
313
|
return;
|
package/dist/locale.js
CHANGED
|
@@ -101,6 +101,9 @@ const messages = {
|
|
|
101
101
|
promise_handler: 'vlax-invoke/vlax-invoke-method without callback handler — results may be lost',
|
|
102
102
|
module_cycle: 'Module dependency cycle detected — may cause initialization issues',
|
|
103
103
|
arg_count_project: "Function '{0}' called with {1} arguments but defined with {2} (cross-file)",
|
|
104
|
+
redundant_entmake: '(entmake (list (cons ...))) should use quoted association list for performance',
|
|
105
|
+
missing_princ: "C: command '{0}' is missing trailing (princ) — may return nil to the command line",
|
|
106
|
+
global_function_naming: "Function '{0}' lacks a package prefix — consider using namespace: prefix",
|
|
104
107
|
'help.text': `@atlisp/lint - AutoLISP static analysis tool
|
|
105
108
|
|
|
106
109
|
Usage: atlisp-lint [options]
|
|
@@ -126,7 +129,8 @@ Options:
|
|
|
126
129
|
--format-code Auto-format code indentation
|
|
127
130
|
--format-check Check if files are formatted (exit 1 if not)
|
|
128
131
|
--diff Only check files changed since last commit
|
|
129
|
-
--changed <branch> Only check files changed against a branch (default: main)
|
|
132
|
+
--changed <branch> Only check files changed against a branch (default: main)
|
|
133
|
+
--docs Print rules documentation as markdown`,
|
|
130
134
|
},
|
|
131
135
|
zh: {
|
|
132
136
|
'parens.mismatch': "括号不匹配:{0} 个 '(' vs {1} 个 ')'({2})",
|
|
@@ -225,6 +229,9 @@ Options:
|
|
|
225
229
|
promise_handler: 'vlax-invoke/vlax-invoke-method 没有回调处理器——结果可能丢失',
|
|
226
230
|
module_cycle: '检测到模块循环依赖——可能导致初始化问题',
|
|
227
231
|
arg_count_project: "函数 '{0}' 调用时传入了 {1} 个参数,但定义为 {2} 个(跨文件)",
|
|
232
|
+
redundant_entmake: '(entmake (list (cons ...))) 应使用 quoted 关联表以提升性能',
|
|
233
|
+
missing_princ: "C: 命令 '{0}' 末尾缺少 (princ) — 可能在命令行返回 nil",
|
|
234
|
+
global_function_naming: "函数 '{0}' 缺少包名前缀 — 建议使用 namespace: 前缀",
|
|
228
235
|
'help.text': `@atlisp/lint - AutoLISP 静态分析工具
|
|
229
236
|
|
|
230
237
|
用法: atlisp-lint [选项]
|
|
@@ -248,9 +255,10 @@ Options:
|
|
|
248
255
|
--help 显示此帮助信息
|
|
249
256
|
--version 显示版本号
|
|
250
257
|
--format-code 自动格式化代码缩进
|
|
251
|
-
--format-check
|
|
252
|
-
--diff
|
|
253
|
-
--changed <分支> 仅检查相对于某分支有变更的文件(默认:main
|
|
258
|
+
--format-check 检查文件是否已格式化(未格式化则退出码为 1)
|
|
259
|
+
--diff 仅检查自上次提交后变更的文件
|
|
260
|
+
--changed <分支> 仅检查相对于某分支有变更的文件(默认:main)
|
|
261
|
+
--docs 打印规则文档(Markdown 格式)`,
|
|
254
262
|
},
|
|
255
263
|
};
|
|
256
264
|
let currentLocale = 'zh';
|
package/dist/presets.js
CHANGED
|
@@ -74,6 +74,9 @@ exports.PRESETS = {
|
|
|
74
74
|
promise_handler: 'off',
|
|
75
75
|
module_cycle: 'warn',
|
|
76
76
|
arg_count_project: 'warn',
|
|
77
|
+
redundant_entmake: 'warn',
|
|
78
|
+
missing_princ: 'warn',
|
|
79
|
+
global_function_naming: 'info',
|
|
77
80
|
},
|
|
78
81
|
},
|
|
79
82
|
strict: {
|
|
@@ -160,6 +163,9 @@ exports.PRESETS = {
|
|
|
160
163
|
promise_handler: 'off',
|
|
161
164
|
module_cycle: 'error',
|
|
162
165
|
arg_count_project: 'error',
|
|
166
|
+
redundant_entmake: 'error',
|
|
167
|
+
missing_princ: 'error',
|
|
168
|
+
global_function_naming: 'error',
|
|
163
169
|
},
|
|
164
170
|
},
|
|
165
171
|
relaxed: {
|
package/dist/rules.d.ts
CHANGED
package/dist/rules.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RULES = void 0;
|
|
4
4
|
exports.generateRulesMarkdown = generateRulesMarkdown;
|
|
5
|
+
exports.generateSchemaHint = generateSchemaHint;
|
|
5
6
|
exports.RULES = [
|
|
6
7
|
{
|
|
7
8
|
name: 'append_single',
|
|
@@ -256,6 +257,24 @@ exports.RULES = [
|
|
|
256
257
|
description: '检查 AutoLISP 内置函数调用参数个数是否匹配',
|
|
257
258
|
category: '正确性',
|
|
258
259
|
},
|
|
260
|
+
{
|
|
261
|
+
name: 'redundant_entmake',
|
|
262
|
+
defaultSeverity: 'warn',
|
|
263
|
+
description: '检测 (entmake (list (cons ...))) 应使用 quoted 关联表',
|
|
264
|
+
category: '风格',
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'missing_princ',
|
|
268
|
+
defaultSeverity: 'warn',
|
|
269
|
+
description: '检测 C: 命令定义末尾缺少 (princ)',
|
|
270
|
+
category: '最佳实践',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: 'global_function_naming',
|
|
274
|
+
defaultSeverity: 'info',
|
|
275
|
+
description: '检测 defun 函数名缺少包名前缀',
|
|
276
|
+
category: '风格',
|
|
277
|
+
},
|
|
259
278
|
];
|
|
260
279
|
function generateRulesMarkdown() {
|
|
261
280
|
const lines = [
|
|
@@ -269,4 +288,10 @@ function generateRulesMarkdown() {
|
|
|
269
288
|
}
|
|
270
289
|
return lines.join('\n');
|
|
271
290
|
}
|
|
291
|
+
function generateSchemaHint() {
|
|
292
|
+
return `You can use the JSON Schema for editor autocompletion by adding to your atlisp-lint.json:
|
|
293
|
+
"$schema": "node_modules/@atlisp/lint/atlisp-lint.schema.json"
|
|
294
|
+
|
|
295
|
+
Total rules: ${exports.RULES.length}`;
|
|
296
|
+
}
|
|
272
297
|
//# sourceMappingURL=rules.js.map
|
package/dist/runner.js
CHANGED
|
@@ -86,6 +86,9 @@ const empty_comments_1 = require("./checks/empty-comments");
|
|
|
86
86
|
const commented_code_1 = require("./checks/commented-code");
|
|
87
87
|
const unused_catch_result_1 = require("./checks/unused-catch-result");
|
|
88
88
|
const string_concat_loop_1 = require("./checks/string-concat-loop");
|
|
89
|
+
const redundant_entmake_1 = require("./checks/redundant-entmake");
|
|
90
|
+
const missing_princ_1 = require("./checks/missing-princ");
|
|
91
|
+
const global_function_naming_1 = require("./checks/global-function-naming");
|
|
89
92
|
const config_1 = require("./config");
|
|
90
93
|
const locale_1 = require("./locale");
|
|
91
94
|
const disable_1 = require("./disable");
|
|
@@ -162,6 +165,9 @@ function runChecks(content, file, config) {
|
|
|
162
165
|
// New checks
|
|
163
166
|
addIfEnabled('unused_catch_result', () => (0, unused_catch_result_1.checkUnusedCatchResult)(content, file));
|
|
164
167
|
addIfEnabled('string_concat_loop', () => (0, string_concat_loop_1.checkStringConcatInLoop)(content, file));
|
|
168
|
+
addIfEnabled('redundant_entmake', () => (0, redundant_entmake_1.checkRedundantEntmake)(content, file));
|
|
169
|
+
addIfEnabled('missing_princ', () => (0, missing_princ_1.checkMissingPrinc)(content, file));
|
|
170
|
+
addIfEnabled('global_function_naming', () => (0, global_function_naming_1.checkGlobalFunctionNaming)(content, file));
|
|
165
171
|
// AST-based checks via single-pass visitor
|
|
166
172
|
const astRules = new Set([
|
|
167
173
|
'quit_exit',
|
package/dist/validate.js
CHANGED
|
@@ -85,6 +85,9 @@ const VALID_RULES = [
|
|
|
85
85
|
'module_cycle',
|
|
86
86
|
'arg_count_project',
|
|
87
87
|
'builtin_arg_count',
|
|
88
|
+
'redundant_entmake',
|
|
89
|
+
'missing_princ',
|
|
90
|
+
'global_function_naming',
|
|
88
91
|
];
|
|
89
92
|
const VALID_SEVERITIES = ['off', 'info', 'warn', 'error'];
|
|
90
93
|
function validateConfig(config) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlisp/lint",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"description": "AutoLISP static analysis tool — parens, security, conventions, SBCL syntax validation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CAD",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"lib/",
|
|
22
22
|
"bin/",
|
|
23
23
|
"atlisp-lint.default.json",
|
|
24
|
+
"atlisp-lint.schema.json",
|
|
24
25
|
"stub-packages.json"
|
|
25
26
|
],
|
|
26
27
|
"scripts": {
|
|
@@ -36,9 +37,6 @@
|
|
|
36
37
|
"prepublishOnly": "npm run build",
|
|
37
38
|
"prepack": "npm run build"
|
|
38
39
|
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@atlisp/parser": "^0.1.5"
|
|
41
|
-
},
|
|
42
40
|
"devDependencies": {
|
|
43
41
|
"@types/jest": "^30",
|
|
44
42
|
"@types/node": "^26.1.0",
|
|
@@ -54,5 +52,8 @@
|
|
|
54
52
|
"engines": {
|
|
55
53
|
"node": ">=18"
|
|
56
54
|
},
|
|
57
|
-
"license": "MIT"
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@atlisp/parser": "^0.1.7"
|
|
58
|
+
}
|
|
58
59
|
}
|