@atlisp/lint 0.2.7 → 0.2.9

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.
@@ -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
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "locale": "zh",
3
+ "source": {
4
+ "globs": ["**/*.lsp"],
5
+ "exclude": ["**/node_modules/**", "**/vendor/**", "**/.git/**"]
6
+ },
7
+ "checks": {
8
+ "parens": "error",
9
+ "encoding": "warn",
10
+ "cl_syntax": "warn",
11
+ "quit_exit": "error",
12
+ "command_shell": "error",
13
+ "startapp": "warn",
14
+ "vl_registry_write": "warn",
15
+ "vlax_without_loading": "off",
16
+ "token_in_url": "warn",
17
+ "open_without_close": "warn",
18
+ "bare_function_names": "off",
19
+ "line_length": "warn",
20
+ "function_complexity": "warn",
21
+ "parameter_naming": "warn",
22
+ "unused_variable": "warn",
23
+ "missing_doc": "warn",
24
+ "error_handling": "warn",
25
+ "global_naming": "warn",
26
+ "extra_parens": "warn",
27
+ "arg_count": "warn",
28
+ "strcat_usage": "warn",
29
+ "cond_simplify": "warn",
30
+ "redundant_progn": "warn",
31
+ "quote_style": "warn",
32
+ "eq_usage": "warn",
33
+ "lambda_syntax": "warn",
34
+ "comment_style": "warn",
35
+ "empty_catch": "warn",
36
+ "nth_usage": "warn",
37
+ "append_single": "warn",
38
+ "setq_multiple": "warn",
39
+ "function_order": "off",
40
+ "magic_number": "off",
41
+ "mixed_indent": "warn",
42
+ "long_function_call": "warn",
43
+ "no_return": "warn",
44
+ "shadow_builtin": "warn",
45
+ "dynamic_doc": "warn",
46
+ "loop_optimization": "off",
47
+ "type_check": "off",
48
+ "redundant_if": "warn",
49
+ "trailing_whitespace": "warn",
50
+ "module_registration": "off",
51
+ "namespace_header": "off"
52
+ },
53
+ "line_length": {
54
+ "max": 100,
55
+ "tab_width": 2
56
+ },
57
+ "function_complexity": {
58
+ "max_lines": 60,
59
+ "max_nesting": 6
60
+ },
61
+ "cl_syntax": {
62
+ "keywords": ["&key"]
63
+ },
64
+ "dangerous_calls": {
65
+ "quit": "error",
66
+ "exit": "error",
67
+ "command_shell": "error",
68
+ "startapp": "warn",
69
+ "vl_registry_write": "warn"
70
+ },
71
+ "module_registration": {
72
+ "severity": "off",
73
+ "patterns": [],
74
+ "dirs": ["modules"]
75
+ },
76
+ "namespace_header": {
77
+ "severity": "off",
78
+ "package": "",
79
+ "deps": [],
80
+ "search_lines": 15
81
+ },
82
+ "bare_function_names": {
83
+ "allowlist": ["T", "nil"],
84
+ "namespace_pattern": "^[a-z]+:"
85
+ },
86
+ "sbcl": {
87
+ "walk_exclude": [".vscode", "vendor", ".git"],
88
+ "defmacro_allow_files": ["compat-cl"]
89
+ }
90
+ }
@@ -0,0 +1,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkGlobalFunctionNaming(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=global-function-naming.d.ts.map
@@ -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,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkMissingPrinc(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=missing-princ.d.ts.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,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkRedundantEntmake(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=redundant-entmake.d.ts.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: 'off',
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,
@@ -1,2 +1,3 @@
1
1
  export declare function formatCode(content: string, indentSize?: number): string;
2
+ export declare function formatCodeStable(content: string, indentSize?: number): string;
2
3
  //# sourceMappingURL=formatter.d.ts.map
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 v1Format(content, indentSize) {
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 (const line of lines) {
10
- const trimmedLine = line.trimEnd();
11
- if (trimmedLine === '') {
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 stripped = (0, utils_1.stripLine)(trimmedLine);
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
- const indent = ' '.repeat(depth * indentSize);
19
- result.push(indent + trimmedLine.trimStart());
31
+ result.push(' '.repeat(depth * indentSize) + trimmed.trimStart());
20
32
  continue;
21
33
  }
22
- let openCount = 0;
23
- let closeCount = 0;
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
- openCount++;
27
- else if (ch === ')')
28
- closeCount++;
38
+ if (ch === ')')
39
+ leadingCloseCount++;
40
+ else
41
+ break;
29
42
  }
30
43
  let effectiveDepth = depth;
31
- if (trimmedStripped.startsWith(')')) {
32
- let leadingClose = 0;
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
- result.push(' '.repeat(effectiveDepth * indentSize) + trimmedLine.trimStart());
42
- depth += openCount - closeCount;
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
- return result;
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 formatCode(content, indentSize = 2) {
49
- return v1Format(content, indentSize).join('\n');
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;
@@ -0,0 +1,161 @@
1
+ ;; @lisp SBCL Lint — syntax validation via SBCL
2
+ ;; Usage: sbcl --script lint-sbcl.lisp <src-dir> <stub-packages.json> <walk-exclude-json> <defmacro-allow-files-json> <locale>
3
+
4
+ (require :uiop)
5
+
6
+ (defparameter *errors* 0)
7
+ (defparameter *warnings* 0)
8
+ (defparameter *checked* 0)
9
+ (defparameter *locale* "zh")
10
+
11
+ ;; ── i18n ──────────────────────────────────────────────────────────────
12
+ (defun i18n (key)
13
+ (cdr (assoc key
14
+ (if (string= *locale* "zh")
15
+ '((:not-found . "not found symbol")
16
+ (:syntax-error . "syntax error")
17
+ (:vec-syntax . "#( vector syntax")
18
+ (:char-syntax . "# backslash char literal")
19
+ (:eval-syntax . "#. read-time eval")
20
+ (:defmacro . "defmacro")
21
+ (:trailing-ws . "trailing whitespace")
22
+ (:ok . "OK")
23
+ (:fail . "FAIL")
24
+ (:header . " @lisp SBCL Lint")
25
+ (:source . " Source")
26
+ (:found . " Found ~d .lsp files")
27
+ (:scanned . " Scanned")
28
+ (:errors . " Errors")
29
+ (:warnings . " Warnings"))
30
+ '((:not-found . "not found symbol")
31
+ (:syntax-error . "syntax error")
32
+ (:vec-syntax . "#( vector syntax")
33
+ (:char-syntax . "# backslash char literal")
34
+ (:eval-syntax . "#. read-time eval")
35
+ (:defmacro . "defmacro")
36
+ (:trailing-ws . "trailing whitespace")
37
+ (:ok . "OK")
38
+ (:fail . "FAIL")
39
+ (:header . " @lisp SBCL Lint")
40
+ (:source . " Source")
41
+ (:found . " Found ~d .lsp files")
42
+ (:scanned . " Scanned")
43
+ (:errors . " Errors")
44
+ (:warnings . " Warnings"))))))
45
+
46
+ ;; ── Stub packages from external file ──────────────────────────────────
47
+ (defun load-stub-packages (file-path)
48
+ (flet ((ensure-pkg (name &optional use-list)
49
+ (unless (find-package name)
50
+ (make-package name :use (or use-list '())))))
51
+ (with-open-file (s file-path :direction :input)
52
+ (let ((packages (read s)))
53
+ (dolist (pkg packages)
54
+ (ensure-pkg (first pkg) (second pkg)))))))
55
+
56
+ ;; ── File walking ──────────────────────────────────────────────────────
57
+ (defun source-files (dir)
58
+ (sort
59
+ (remove-if-not
60
+ (lambda (p)
61
+ (let ((n (pathname-type p)))
62
+ (and n (string-equal n "lsp"))))
63
+ (uiop:directory-files dir))
64
+ 'string< :key #'namestring))
65
+
66
+ (defun walk-tree (dir exclude-dirs)
67
+ (let ((result (source-files dir)))
68
+ (dolist (sub (uiop:subdirectories dir))
69
+ (let ((name (car (last (pathname-directory sub)))))
70
+ (unless (find name exclude-dirs :test 'string=)
71
+ (setf result (append result (walk-tree sub exclude-dirs))))))
72
+ result))
73
+
74
+ ;; ── Per-file check ────────────────────────────────────────────────────
75
+ (defun check-file (path src-dir defmacro-allow-files)
76
+ (incf *checked*)
77
+ (let* ((rel (enough-namestring path src-dir))
78
+ (fullname (format nil "~a.~a" (pathname-name path) (pathname-type path))))
79
+ (format t " ~a ... " rel)
80
+ (force-output)
81
+ ;; Syntax check via READ
82
+ (handler-case
83
+ (with-open-file (s path :direction :input)
84
+ (loop for form = (read s nil :eof)
85
+ until (eq form :eof)))
86
+ (error (e)
87
+ (let ((msg (princ-to-string e)))
88
+ (cond
89
+ ((search "not found" msg)
90
+ (format t "~% [NOTE] ~a: ~a~%" rel (i18n :not-found))
91
+ (incf *warnings*))
92
+ (t
93
+ (format t "~a~% [ERROR] ~a: ~a~%" (i18n :fail) rel (i18n :syntax-error))
94
+ (incf *errors*)
95
+ (return-from check-file))))))
96
+ ;; Trailing whitespace
97
+ (with-open-file (s path :direction :input)
98
+ (loop for line = (read-line s nil nil)
99
+ for lineno from 1
100
+ while line
101
+ when (and (> (length line) 0)
102
+ (find (char line (1- (length line))) '(#\Space #\Tab)))
103
+ do (progn
104
+ (format t "~% [WARN] ~a line ~d: ~a~%" rel lineno (i18n :trailing-ws))
105
+ (incf *warnings*))))
106
+ ;; CL-ism checks: raw content scan
107
+ (with-open-file (s path :direction :input)
108
+ (let ((content (make-string (file-length s))))
109
+ (file-position s 0)
110
+ (read-sequence content s)
111
+ (when (search "#(" content)
112
+ (format t "~% [WARN] ~a: ~a~%" rel (i18n :vec-syntax))
113
+ (incf *warnings*))
114
+ (when (search "#\\" content)
115
+ (format t "~% [WARN] ~a: ~a~%" rel (i18n :char-syntax))
116
+ (incf *warnings*))
117
+ (when (search "#." content)
118
+ (format t "~% [WARN] ~a: ~a~%" rel (i18n :eval-syntax))
119
+ (incf *warnings*))
120
+ (when (and (search "defmacro" content)
121
+ (not (some (lambda (s) (search s fullname)) defmacro-allow-files)))
122
+ (format t "~% [WARN] ~a: ~a~%" rel (i18n :defmacro))
123
+ (incf *warnings*))))
124
+ (format t "~a~%" (i18n :ok))))
125
+
126
+ ;; ── Main ──────────────────────────────────────────────────────────────
127
+ (defun main ()
128
+ (let* ((args (uiop:command-line-arguments))
129
+ (src-dir (first args))
130
+ (stub-file (second args))
131
+ (walk-exclude (if (third args)
132
+ (read-from-string (third args))
133
+ '(".vscode" "test" "experiment" "tools" ".git")))
134
+ (defmacro-allow (if (fourth args)
135
+ (read-from-string (fourth args))
136
+ '("compat-cl")))
137
+ (locale (fifth args)))
138
+ (when locale (setf *locale* locale))
139
+ (load-stub-packages stub-file)
140
+
141
+ (format t "~%==================================================~%")
142
+ (format t "~a~%" (i18n :header))
143
+ (format t "~a: ~a~%" (i18n :source) (namestring (pathname src-dir)))
144
+ (format t "==================================================~%~%")
145
+ (setf *errors* 0 *warnings* 0 *checked* 0)
146
+
147
+ (let ((files (walk-tree src-dir walk-exclude)))
148
+ (format t "~a~%~%" (format nil (i18n :found) (length files)))
149
+ (dolist (f files)
150
+ (check-file f src-dir defmacro-allow)))
151
+
152
+ (format t "~%==================================================~%")
153
+ (format t "~a: ~d~%" (i18n :scanned) *checked*)
154
+ (format t "~a: ~d~%" (i18n :errors) *errors*)
155
+ (format t "~a: ~d~%" (i18n :warnings) *warnings*)
156
+ (format t "==================================================~%~%")
157
+ (if (> *errors* 0)
158
+ (uiop:quit 1)
159
+ (uiop:quit 0))))
160
+
161
+ (main)
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 检查文件是否已格式化(未格式化则退出码为 1)
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
@@ -6,4 +6,5 @@ export interface RuleDoc {
6
6
  }
7
7
  export declare const RULES: RuleDoc[];
8
8
  export declare function generateRulesMarkdown(): string;
9
+ export declare function generateSchemaHint(): string;
9
10
  //# sourceMappingURL=rules.d.ts.map
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',
@@ -0,0 +1,41 @@
1
+ ((AUTOLISP ())
2
+ (@ (COMMON-LISP AUTOLISP))
3
+ (C ())
4
+ (JSON ())
5
+ (SIDEBAR ())
6
+ (FUN ())
7
+ (DCL ())
8
+ (BASE ())
9
+ (STRING ())
10
+ (BLOCK ())
11
+ (ENTITY ())
12
+ (LAYER ())
13
+ (LAYOUT ())
14
+ (CURVE ())
15
+ (LIST ())
16
+ (M ())
17
+ (P ())
18
+ (UI ())
19
+ (SYS ())
20
+ (EXCEL ())
21
+ (WORD ())
22
+ (RE ())
23
+ (VECTRA ())
24
+ (DOS ())
25
+ (AT-PM ())
26
+ (QRENCODE ())
27
+ (NETWORK ())
28
+ (PKGMAN ())
29
+ (DATETIME ())
30
+ (DICT ())
31
+ (@NLP ())
32
+ (AT-SIDEBAR ())
33
+ (S ())
34
+ (VL ())
35
+ (VLR ())
36
+ (VLAX ())
37
+ (THEME ())
38
+ (AJAX ())
39
+ (ATLISP ())
40
+ (LOG ())
41
+ (ATLISP-CORE ()))
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.7",
3
+ "version": "0.2.9",
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
  }