@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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -58
  3. package/atlisp-lint.default.json +32 -1
  4. package/dist/atlisp-lint.default.json +90 -0
  5. package/dist/cache.d.ts +2 -2
  6. package/dist/cache.js +6 -6
  7. package/dist/checks/append-single.d.ts +3 -0
  8. package/dist/checks/append-single.js +17 -0
  9. package/dist/checks/arg-count.d.ts +3 -0
  10. package/dist/checks/arg-count.js +123 -0
  11. package/dist/checks/assoc-without-cdr.d.ts +5 -0
  12. package/dist/checks/assoc-without-cdr.js +32 -0
  13. package/dist/checks/comment-style.d.ts +3 -0
  14. package/dist/checks/comment-style.js +24 -0
  15. package/dist/checks/cond-duplicate.d.ts +5 -0
  16. package/dist/checks/cond-duplicate.js +52 -0
  17. package/dist/checks/cond-simplify.d.ts +3 -0
  18. package/dist/checks/cond-simplify.js +45 -0
  19. package/dist/checks/constant-condition.js +4 -4
  20. package/dist/checks/dangerous-calls.js +2 -2
  21. package/dist/checks/dangling-defun.d.ts +3 -0
  22. package/dist/checks/dangling-defun.js +10 -28
  23. package/dist/checks/double-not.js +1 -1
  24. package/dist/checks/duplicate-defun.d.ts +6 -0
  25. package/dist/checks/duplicate-defun.js +50 -0
  26. package/dist/checks/dynamic-doc.d.ts +3 -0
  27. package/dist/checks/dynamic-doc.js +21 -0
  28. package/dist/checks/empty-branch.js +1 -1
  29. package/dist/checks/empty-catch.d.ts +3 -0
  30. package/dist/checks/empty-catch.js +34 -0
  31. package/dist/checks/eq-usage.d.ts +3 -0
  32. package/dist/checks/eq-usage.js +25 -0
  33. package/dist/checks/error-handling.d.ts +3 -0
  34. package/dist/checks/error-handling.js +56 -0
  35. package/dist/checks/extra-parens.d.ts +3 -0
  36. package/dist/checks/extra-parens.js +45 -0
  37. package/dist/checks/format-indent.d.ts +3 -0
  38. package/dist/checks/format-indent.js +29 -0
  39. package/dist/checks/function-complexity.js +1 -1
  40. package/dist/checks/function-order.d.ts +3 -0
  41. package/dist/checks/function-order.js +33 -0
  42. package/dist/checks/global-naming.d.ts +3 -0
  43. package/dist/checks/global-naming.js +62 -0
  44. package/dist/checks/identical-branches.d.ts +5 -0
  45. package/dist/checks/identical-branches.js +54 -0
  46. package/dist/checks/index.d.ts +3 -0
  47. package/dist/checks/index.js +117 -0
  48. package/dist/checks/lambda-syntax.d.ts +3 -0
  49. package/dist/checks/lambda-syntax.js +25 -0
  50. package/dist/checks/long-function-call.d.ts +3 -0
  51. package/dist/checks/long-function-call.js +54 -0
  52. package/dist/checks/loop-optimization.d.ts +3 -0
  53. package/dist/checks/loop-optimization.js +17 -0
  54. package/dist/checks/magic-number.d.ts +3 -0
  55. package/dist/checks/magic-number.js +21 -0
  56. package/dist/checks/misplaced-else.js +1 -1
  57. package/dist/checks/missing-export.js +2 -2
  58. package/dist/checks/mixed-indent.d.ts +3 -0
  59. package/dist/checks/mixed-indent.js +19 -0
  60. package/dist/checks/module-reg.js +1 -1
  61. package/dist/checks/multiple-setq.js +1 -1
  62. package/dist/checks/no-return.d.ts +3 -0
  63. package/dist/checks/no-return.js +51 -0
  64. package/dist/checks/nth-usage.d.ts +3 -0
  65. package/dist/checks/nth-usage.js +17 -0
  66. package/dist/checks/quote-style.d.ts +3 -0
  67. package/dist/checks/quote-style.js +25 -0
  68. package/dist/checks/quote-vs-function.js +1 -1
  69. package/dist/checks/recursive-call.js +1 -1
  70. package/dist/checks/redundant-if.d.ts +3 -0
  71. package/dist/checks/redundant-if.js +17 -0
  72. package/dist/checks/redundant-let.js +1 -1
  73. package/dist/checks/redundant-nil-else.js +1 -1
  74. package/dist/checks/redundant-progn.js +1 -1
  75. package/dist/checks/redundant-quotes.js +1 -1
  76. package/dist/checks/redundant-setq.js +1 -1
  77. package/dist/checks/self-compare.js +1 -1
  78. package/dist/checks/setq-multiple.d.ts +3 -0
  79. package/dist/checks/setq-multiple.js +17 -0
  80. package/dist/checks/setq-single-arg.d.ts +5 -0
  81. package/dist/checks/setq-single-arg.js +30 -0
  82. package/dist/checks/shadow-builtin.d.ts +3 -0
  83. package/dist/checks/shadow-builtin.js +77 -0
  84. package/dist/checks/single-arg-and-or.js +1 -1
  85. package/dist/checks/strcat-usage.d.ts +3 -0
  86. package/dist/checks/strcat-usage.js +25 -0
  87. package/dist/checks/type-check.d.ts +3 -0
  88. package/dist/checks/type-check.js +26 -0
  89. package/dist/checks/unused-let.js +1 -1
  90. package/dist/checks/unused-package-dep.js +3 -3
  91. package/dist/checks/variable-shadow.js +1 -1
  92. package/dist/checks/while-constant.d.ts +5 -0
  93. package/dist/checks/while-constant.js +40 -0
  94. package/dist/config.d.ts +1 -0
  95. package/dist/config.js +71 -2
  96. package/dist/disable.js +1 -1
  97. package/dist/formatter.d.ts +2 -0
  98. package/dist/formatter.js +51 -0
  99. package/dist/formatters.d.ts +1 -0
  100. package/dist/formatters.js +18 -2
  101. package/dist/index.js +172 -32
  102. package/dist/lib/lint-sbcl.lisp +161 -0
  103. package/dist/locale.js +76 -0
  104. package/dist/presets.d.ts +4 -0
  105. package/dist/presets.js +159 -0
  106. package/dist/project.js +37 -6
  107. package/dist/rules.d.ts +9 -0
  108. package/dist/rules.js +239 -0
  109. package/dist/runner.d.ts +2 -0
  110. package/dist/runner.js +329 -12
  111. package/dist/sbcl.js +1 -1
  112. package/dist/stub-packages.json +41 -0
  113. package/dist/types.d.ts +6 -0
  114. package/dist/validate.d.ts +8 -0
  115. package/dist/validate.js +126 -0
  116. package/dist/watch.d.ts +9 -0
  117. package/dist/watch.js +113 -0
  118. package/package.json +1 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 VitalGG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @atlisp/lint
2
2
 
3
- AutoLISP 静态分析工具 — 括号匹配、安全检查、编码检测、命名规范、函数复杂度、SBCL 语法校验。
3
+ AutoLISP 静态分析工具 — 括号匹配、安全检查、编码检测、命名规范、函数复杂度、跨文件分析、SBCL 语法校验。
4
4
 
5
5
  ## 安装
6
6
 
@@ -22,62 +22,190 @@ npx @atlisp/lint
22
22
  # 输出 JSON 格式
23
23
  npx @atlisp/lint --format json
24
24
 
25
- # 自动修复可修复问题(尾部空格、BOM)
25
+ # 自动修复可修复问题
26
26
  npx @atlisp/lint --fix
27
+
28
+ # 监听文件变化自动重检
29
+ npx @atlisp/lint --watch
30
+
31
+ # 自动格式化代码缩进
32
+ npx @atlisp/lint --format-code
33
+
34
+ # 检查代码格式(不修改文件)
35
+ npx @atlisp/lint --format-check
27
36
  ```
28
37
 
29
38
  ## CLI 选项
30
39
 
31
40
  ```
32
- --src <dir> 指定源码目录(可多次使用)
33
- --test <dir> 指定测试目录(可多次使用)
34
- --config <path> 指定配置文件路径
35
- --staged 仅检查 git 暂存区中的 .lsp 文件
36
- --format <format> 输出格式:default(默认)| json
37
- --init 在当前目录生成 atlisp-lint.json
38
- --install-hook 安装 git pre-commit hook
39
- --fix 自动修复尾部空格、UTF-8 BOM 等问题
40
- --cache 启用文件哈希缓存,跳过未变更的文件
41
- --clear-cache 清除缓存目录
42
- --parallel 开启多线程并行检查(使用 Worker Threads)
43
- --hook-args <args> 自定义 pre-commit hook 参数(配合 --install-hook
41
+ --src <dir> 指定源码目录(可多次使用)
42
+ --test <dir> 指定测试目录(可多次使用)
43
+ --config <path> 指定配置文件路径
44
+ --staged 仅检查 git 暂存区中的 .lsp 文件
45
+ --format <format> 输出格式:default(默认)| json
46
+ --init 在当前目录生成 atlisp-lint.json
47
+ --install-hook 安装 git pre-commit hook
48
+ --fix 自动修复尾部空格、BOM、多余括号、冗余 progn/let、引号风格等问题
49
+ --cache 启用文件哈希缓存,跳过未变更的文件
50
+ --clear-cache 清除缓存目录
51
+ --parallel 开启多线程并行检查(使用 Worker Threads)
52
+ --project 启用跨文件分析(Phase 1b
53
+ --watch 监听模式,文件变动自动重新检查
54
+ --hook-args <args> 自定义 pre-commit hook 参数(配合 --install-hook)
55
+ --help 显示帮助信息
56
+ --version 显示版本号
57
+ --format-code 自动格式化代码缩进(基于括号深度 + AST 对齐)
58
+ --format-check 只检查代码缩进格式(不修改文件,不符合则退出码 1)
44
59
  ```
45
60
 
46
- ## 检查规则
47
-
48
- ### 阶段 1:静态检查
61
+ ## 架构:三相检测
62
+
63
+ ### Phase 1a — 单文件静态检查(74 条规则)
64
+
65
+ 所有 74 条规则在单文件范围内运行,支持 `--parallel` 多线程并行。
66
+
67
+ | 规则 | 默认 | 类别 | 说明 |
68
+ |------|------|------|------|
69
+ | `parens` | error | 语法 | 括号不匹配 |
70
+ | `trailing_paren` | warn | 语法 | 多余闭合括号 |
71
+ | `extra_parens` | warn | 语法 | 可疑的连续右括号 |
72
+ | `encoding` | error | 编码 | UTF-8 BOM 检查 / 非 UTF-8 编码 |
73
+ | `quit_exit` | error | 安全 | quit/exit 调用(会终止 CAD 进程) |
74
+ | `command_shell` | error | 安全 | command shell(命令注入风险) |
75
+ | `startapp` | warn | 安全 | startapp(启动外部程序) |
76
+ | `vl_registry_write` | warn | 安全 | vl-registry-write(修改注册表) |
77
+ | `token_in_url` | warn | 安全 | URL 中含 token=(凭据泄露) |
78
+ | `vlax_without_loading` | warn | 安全 | vlax-* 未调用 vl-load-com |
79
+ | `cl_syntax` | warn | 语法 | Common Lisp 特有语法(如 &key) |
80
+ | `line_length` | warn | 风格 | 行长度超过限制 |
81
+ | `function_complexity` | warn | 复杂度 | 函数行数或嵌套深度超限 |
82
+ | `trailing_whitespace` | warn | 风格 | 行尾多余空格 |
83
+ | `empty_comment` | warn | 风格 | 空注释行(只有 ; 没有内容) |
84
+ | `parameter_naming` | warn | 最佳实践 | 参数首字母大写 |
85
+ | `unused_variable` | warn | 最佳实践 | 变量赋值但未使用 |
86
+ | `unused_parameter` | warn | 最佳实践 | 参数从未使用 |
87
+ | `unused_let_binding` | warn | 最佳实践 | let 绑定从未使用 |
88
+ | `unused_local_fun` | warn | 最佳实践 | defun / 局部函数未使用 |
89
+ | `missing_doc` | warn | 风格 | 函数缺少注释说明 |
90
+ | `error_handling` | warn | 最佳实践 | 使用 command 但缺少 \*error\* 处理 |
91
+ | `global_naming` | warn | 风格 | 全局变量未用 \*...\* 命名 |
92
+ | `constant_condition` | warn | 风格 | if/while/cond 中常量条件 |
93
+ | `redundant_progn` | warn | 风格 | 分支中多余 progn |
94
+ | `empty_branch` | warn | 风格 | if/cond 中空分支 |
95
+ | `redundant_cond` | warn | 风格 | 单子句 cond 或末尾 T 子句 |
96
+ | `redundant_if` | warn | 风格 | if/when 中冗余 progn |
97
+ | `redundant_let` | warn | 风格 | 无绑定 let 建议改用 progn |
98
+ | `redundant_quotes` | warn | 风格 | 冗余双引号 ''x |
99
+ | `redundant_setq` | warn | 风格 | setq 赋值自身 |
100
+ | `redundant_nil_else` | warn | 风格 | if 中冗余 nil 分支 |
101
+ | `single_arg_and_or` | warn | 风格 | 单参数 and/or 可简化 |
102
+ | `double_not` | warn | 风格 | 双重 (not (not ...)) |
103
+ | `multiple_setq` | warn | 风格 | 连续 setq 可合并 |
104
+ | `setq_multiple` | warn | 风格 | 连续 setq 可合并 |
105
+ | `setq_single_arg` | warn | 正确性 | setq 缺少值 |
106
+ | `assoc_without_cdr` | warn | 正确性 | assoc 结果未用 cdr 提取 |
107
+ | `identical_branches` | warn | 正确性 | if 的 then/else 分支完全相同 |
108
+ | `while_constant` | warn | 正确性 | while 使用常量条件 |
109
+ | `cond_duplicate` | warn | 正确性 | cond 中存在重复条件 |
110
+ | `recursive_call` | warn | 正确性 | 函数自调用(可能无限递归) |
111
+ | `self_compare` | warn | 正确性 | 自比较表达式 |
112
+ | `variable_shadow` | warn | 最佳实践 | setq 覆盖 let 绑定的同名变量 |
113
+ | `misplaced_else` | warn | 风格 | (if (not ...) ...) 交换分支 |
114
+ | `quote_vs_function` | warn | 风格 | mapcar/apply 中用引用 lambda |
115
+ | `commented_code` | warn | 风格 | 被注释掉的代码 |
116
+ | `quote_style` | warn | 风格 | (quote ...) 建议缩写 |
117
+ | `eq_usage` | warn | 最佳实践 | eq 与数字比较 |
118
+ | `lambda_syntax` | warn | 风格 | (function (lambda ...)) 建议缩写 |
119
+ | `comment_style` | warn | 风格 | ; 后缺少空格 |
120
+ | `empty_catch` | warn | 最佳实践 | vl-catch-all-apply 未检查结果 |
121
+ | `nth_usage` | warn | 风格 | (nth 0 ...) 建议 car |
122
+ | `append_single` | warn | 风格 | (append (list ...)) 建议 cons |
123
+ | `mixed_indent` | warn | 风格 | 缩进混用 tab 和空格 |
124
+ | `long_function_call` | warn | 风格 | 单行参数过多 |
125
+ | `no_return` | warn | 最佳实践 | 函数无返回值 |
126
+ | `shadow_builtin` | warn | 最佳实践 | defun 覆盖内置函数 |
127
+ | `dynamic_doc` | warn | 最佳实践 | C: 命令缺少 (princ) |
128
+ | `open_without_close` | warn | 最佳实践 | open/close 数量不匹配 |
129
+ | `strcat_usage` | warn | 最佳实践 | + 拼接而非 strcat |
130
+ | `cond_simplify` | warn | 风格 | 单分支 cond 可简化为 if |
131
+ | `arg_count` | warn | 最佳实践 | 参数数量不匹配 |
132
+ | `bare_function_names` | off | 风格 | defun 缺少命名空间前缀 |
133
+ | `format_indent` | off | 风格 | 代码缩进不符合格式化规范 |
134
+ | `function_order` | off | 最佳实践 | 定义在使用之后 |
135
+ | `magic_number` | off | 风格 | 硬编码魔法数字 |
136
+ | `module_registration` | off | 架构 | 模块文件未注册到 \*modules\* |
137
+ | `namespace_header` | off | 架构 | 缺少 (in-package ...) 头 |
138
+ | `loop_optimization` | off | 最佳实践 | 优化 while/assoc 循环 |
139
+ | `type_check` | off | 最佳实践 | getvar 结果未类型检查 |
140
+
141
+ ### Phase 1b — 跨文件分析(--project)
142
+
143
+ 通过 `--project` 启用,构建项目符号表后进行以下检查:
49
144
 
50
145
  | 规则 | 默认 | 说明 |
51
146
  |------|------|------|
52
- | `parens` | error | 括号不匹配 |
53
- | `encoding` | error | UTF-8 编码 |
54
- | `cl_syntax` | warn | Common Lisp 特有语法(如 `&key`) |
55
- | `quit_exit` | error | 调用 `quit` / `exit`(会终止 CAD) |
56
- | `command_shell` | error | 调用 `command` 执行 shell |
57
- | `startapp` | warn | 调用 `startapp` 启动外部程序 |
58
- | `vl_registry_write` | warn | 写注册表 |
59
- | `vlax_without_loading` | warn | 使用 `vlax-*` 前未调用 `vl-load-com` |
60
- | `token_in_url` | warn | URL 中包含 `token=`(凭据泄露) |
61
- | `open_without_close` | warn | open/close 数量不匹配(资源泄露) |
62
- | `bare_function_names` | warn | defun 缺少命名空间前缀 |
63
- | `line_length` | warn | 行长度超过限制 |
64
- | `function_complexity` | warn | 函数行数或嵌套深度超限 |
65
- | `parameter_naming` | warn | 参数首字母大写 |
66
- | `unused_variable` | warn | 变量被赋值但未使用 |
67
- | `missing_doc` | warn | 函数缺少注释说明 |
68
- | `trailing_whitespace` | warn | 行尾多余空格 |
69
- | `module_registration` | off | 模块文件未注册到 `*modules*` |
70
- | `namespace_header` | off | 缺少 `(in-package ...)` 头 |
71
-
72
- ### 阶段 2:SBCL 语法校验
73
-
74
- 调用 SBCL 对每个 `.lsp` 文件做 Common Lisp reader 级别的深度解析:
147
+ | `dangling_defun` | warn | 函数定义但从未被任何文件调用 |
148
+ | `missing_export` | warn | 函数未注册到 @::\*modules\* |
149
+ | `unused_package_dep` | warn | 导入的包从未被引用 |
150
+
151
+ 同时检测 `duplicate_defun`(函数名在多个文件中重复定义)。
152
+
153
+ ### Phase 2 SBCL 语法校验(可选)
154
+
155
+ 调用 SBCL 对每个 `.lsp` 文件做 Common Lisp reader 级别深度解析:
75
156
 
76
157
  - 语法错误 — reader 无法解析的内容
77
158
  - 符号未找到 — 未注册到 stub packages 中的符号
78
159
  - CL-ism — `#(`、`#\`、`#.` 等 AutoLISP 无效语法
79
160
  - defmacro — 默认不允许,除非文件在允许列表中
80
161
 
162
+ ## --format-code 代码格式化
163
+
164
+ 基于括号深度自动调整代码缩进,规则:
165
+
166
+ - 每层嵌套增加 2 空格缩进
167
+ - `)` 单独一行时自动回到对应层级的缩进
168
+ - 注释行按当前嵌套深度缩进
169
+ - 字符串中的括号不影响缩进计算
170
+ - 自动删除行尾多余空格
171
+ - 空行保持不变
172
+ - 格式化后进行幂等性检查,若再次格式化结果不一致则输出警告
173
+
174
+ ```bash
175
+ # 格式化所有 .lsp 文件
176
+ npx @atlisp/lint --format-code
177
+
178
+ # 仅检查格式(不修改文件),不符合则退出码 1
179
+ npx @atlisp/lint --format-check
180
+ ```
181
+
182
+ ## --fix 自动修复
183
+
184
+ ### 预扫描修复(fixFile)
185
+
186
+ | 规则 | 修复方式 |
187
+ |------|----------|
188
+ | `trailing_whitespace` | 删除行尾空格 |
189
+ | `encoding (BOM)` | 删除 UTF-8 BOM |
190
+ | `trailing_paren` | 删除多余闭合括号 |
191
+ | `empty_comment` | 删除空注释行 |
192
+
193
+ ### 规则级修复(applyFixes)
194
+
195
+ | 规则 | 修复方式 |
196
+ |------|----------|
197
+ | `redundant_quotes` | ''x → 'x |
198
+ | `double_not` | (not (not ...)) → (not ...) |
199
+ | `redundant_nil_else` | (if cond x nil) → (if cond x) |
200
+ | `single_arg_and_or` | (and x) → x |
201
+ | `redundant_setq` | 删除 (setq x x) 行 |
202
+ | `redundant_progn` | 移除分支中多余的 (progn ...) 包装 |
203
+ | `redundant_let` | (let () ...) → (progn ...) |
204
+ | `quote_style` | (quote x) → 'x |
205
+ | `redundant_if` | 移除 if/when 分支中冗余 progn |
206
+ | `misplaced_else` | (if (not x) a b) → (if x b a) |
207
+ | `format_indent` | 对整个文件应用 `formatCode()` 修复缩进 |
208
+
81
209
  ## 行内忽略
82
210
 
83
211
  在代码行尾添加注释可以忽略特定规则的检查:
@@ -100,24 +228,9 @@ npx @atlisp/lint --fix
100
228
  "checks": {
101
229
  "parens": "error",
102
230
  "encoding": "error",
103
- "cl_syntax": "warn",
104
- "quit_exit": "error",
105
- "command_shell": "error",
106
- "startapp": "warn",
107
- "vl_registry_write": "warn",
108
- "vlax_without_loading": "warn",
109
- "token_in_url": "warn",
110
- "open_without_close": "warn",
111
- "bare_function_names": "warn",
112
- "line_length": "warn",
113
- "function_complexity": "warn",
114
- "parameter_naming": "warn",
115
- "unused_variable": "warn",
116
- "missing_doc": "warn",
117
- "trailing_whitespace": "warn",
118
- "module_registration": "off",
119
- "namespace_header": "off"
231
+ "trailing_whitespace": "warn"
120
232
  },
233
+ "preset": "recommended",
121
234
  "line_length": {
122
235
  "max": 100,
123
236
  "tab_width": 2
@@ -147,9 +260,33 @@ npx @atlisp/lint --fix
147
260
  }
148
261
  ```
149
262
 
263
+ ### 配置预设
264
+
265
+ 通过 `preset` 字段选择预设,预设应用后再叠加用户配置(用户设置优先级最高):
266
+
267
+ | 预设 | 说明 |
268
+ |------|------|
269
+ | `recommended` | 推荐(默认值) |
270
+ | `strict` | 严格模式(大部分规则升为 error) |
271
+ | `relaxed` | 宽松模式(仅保留 4 条 error 规则) |
272
+
273
+ 预设会覆盖 `checks` 中对应规则的默认值,用户可以在同一个文件中继续覆盖预设值。
274
+
275
+ ### 目录级覆盖
276
+
277
+ 在某个目录下放置 `.atlisp-lint.json`,该目录及其子目录中的文件会自动合并该覆盖配置。
278
+
279
+ ```json
280
+ {
281
+ "checks": {
282
+ "line_length": "off"
283
+ }
284
+ }
285
+ ```
286
+
150
287
  ## 多语言
151
288
 
152
- 支持中文和英文,通过配置文件的 `locale` 字段切换:
289
+ 支持中文和英文,通过配置文件 `locale` 字段切换:
153
290
 
154
291
  ```json
155
292
  { "locale": "zh" } // 中文(默认)
@@ -169,6 +306,27 @@ npx @atlisp/lint --install-hook --hook-args "--config ci-config.json"
169
306
  npx @atlisp/lint --staged
170
307
  ```
171
308
 
309
+ ## 缓存
310
+
311
+ ```bash
312
+ # 启用缓存
313
+ npx @atlisp/lint --cache
314
+
315
+ # 清除缓存
316
+ npx @atlisp/lint --clear-cache
317
+ ```
318
+
319
+ 基于文件内容 MD5 哈希缓存,跳过内容未变更的文件。
320
+
321
+ ## 忽略文件
322
+
323
+ 在项目根目录创建 `.atlisp-lint-ignore`,使用 gitignore 风格模式排除文件:
324
+
325
+ ```
326
+ **/test/**
327
+ **/vendor/**
328
+ ```
329
+
172
330
  ## 开发
173
331
 
174
332
  ```bash
@@ -180,6 +338,9 @@ npm run build
180
338
 
181
339
  # 测试
182
340
  npm test
341
+
342
+ # 运行所有检查
343
+ npm run format:check && npm run lint && npm run typecheck && npm test
183
344
  ```
184
345
 
185
346
  ## 许可
@@ -46,9 +46,40 @@
46
46
  "quote_vs_function": "warn",
47
47
  "commented_code": "warn",
48
48
  "double_not": "warn",
49
+ "setq_single_arg": "warn",
50
+ "assoc_without_cdr": "warn",
51
+ "identical_branches": "warn",
52
+ "while_constant": "warn",
53
+ "cond_duplicate": "warn",
54
+ "duplicate_defun": "warn",
49
55
  "dangling_defun": "warn",
50
56
  "missing_export": "warn",
51
- "unused_package_dep": "warn"
57
+ "unused_package_dep": "warn",
58
+ "error_handling": "warn",
59
+ "global_naming": "warn",
60
+ "extra_parens": "warn",
61
+ "arg_count": "warn",
62
+ "strcat_usage": "warn",
63
+ "cond_simplify": "warn",
64
+ "quote_style": "warn",
65
+ "eq_usage": "warn",
66
+ "lambda_syntax": "warn",
67
+ "comment_style": "warn",
68
+ "empty_catch": "warn",
69
+ "nth_usage": "warn",
70
+ "append_single": "warn",
71
+ "setq_multiple": "warn",
72
+ "format_indent": "off",
73
+ "function_order": "off",
74
+ "magic_number": "off",
75
+ "mixed_indent": "warn",
76
+ "long_function_call": "warn",
77
+ "no_return": "warn",
78
+ "shadow_builtin": "warn",
79
+ "dynamic_doc": "warn",
80
+ "loop_optimization": "off",
81
+ "type_check": "off",
82
+ "redundant_if": "warn"
52
83
  },
53
84
  "line_length": {
54
85
  "max": 100,
@@ -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
+ }
package/dist/cache.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare function isCached(filepath: string, rootDir: string): boolean;
2
- export declare function markCached(filepath: string, rootDir: string): void;
1
+ export declare function isCached(filepath: string, rootDir: string, content?: string): boolean;
2
+ export declare function markCached(filepath: string, rootDir: string, content?: string): void;
3
3
  export declare function clearCache(rootDir: string): void;
4
4
  //# sourceMappingURL=cache.d.ts.map
package/dist/cache.js CHANGED
@@ -46,22 +46,22 @@ function getCacheDir(rootDir) {
46
46
  function fileHash(content) {
47
47
  return crypto.createHash('md5').update(content).digest('hex');
48
48
  }
49
- function isCached(filepath, rootDir) {
49
+ function isCached(filepath, rootDir, content) {
50
50
  const cacheDir = getCacheDir(rootDir);
51
51
  if (!fs.existsSync(cacheDir))
52
52
  return false;
53
- const content = fs.readFileSync(filepath, 'utf-8');
54
- const hash = fileHash(content);
53
+ const src = content !== undefined ? content : fs.readFileSync(filepath, 'utf-8');
54
+ const hash = fileHash(src);
55
55
  const cacheFile = path.join(cacheDir, hash);
56
56
  return fs.existsSync(cacheFile);
57
57
  }
58
- function markCached(filepath, rootDir) {
58
+ function markCached(filepath, rootDir, content) {
59
59
  const cacheDir = getCacheDir(rootDir);
60
60
  if (!fs.existsSync(cacheDir)) {
61
61
  fs.mkdirSync(cacheDir, { recursive: true });
62
62
  }
63
- const content = fs.readFileSync(filepath, 'utf-8');
64
- const hash = fileHash(content);
63
+ const src = content !== undefined ? content : fs.readFileSync(filepath, 'utf-8');
64
+ const hash = fileHash(src);
65
65
  const cacheFile = path.join(cacheDir, hash);
66
66
  fs.writeFileSync(cacheFile, '');
67
67
  }
@@ -0,0 +1,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkAppendSingle(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=append-single.d.ts.map
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkAppendSingle = checkAppendSingle;
4
+ const locale_1 = require("../locale");
5
+ const utils_1 = require("../utils");
6
+ function checkAppendSingle(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 (/\(append\s+\(list\b/.test(stripped)) {
12
+ issues.push({ file, line: i + 1, severity: 'warn', rule: 'append_single', message: (0, locale_1.t)('append_single') });
13
+ }
14
+ }
15
+ return issues;
16
+ }
17
+ //# sourceMappingURL=append-single.js.map
@@ -0,0 +1,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkArgCount(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=arg-count.d.ts.map