# atlisp-lint
**Repository Path**: atlisp/atlisp-lint
## Basic Information
- **Project Name**: atlisp-lint
- **Description**: AutoLISP 静态分析工具 — 括号匹配、安全检查、编码检测、命名规范、语法校验。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-07-01
- **Last Updated**: 2026-07-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# @atlisp/lint
AutoLISP 静态分析工具 — 括号匹配、安全检查、编码检测、命名规范、函数复杂度、跨文件分析、SBCL 语法校验。
## 安装
```bash
npm install -g @atlisp/lint
```
需要 Node.js >= 18。SBCL 语法校验为可选功能,如需启用请安装 [SBCL](https://www.sbcl.org)。
## 快速开始
```bash
# 在项目目录下初始化配置文件
npx @atlisp/lint --init
# 运行检查
npx @atlisp/lint
# 输出 JSON 格式
npx @atlisp/lint --format json
# 自动修复可修复问题
npx @atlisp/lint --fix
# 监听文件变化自动重检
npx @atlisp/lint --watch
# 自动格式化代码缩进
npx @atlisp/lint --format-code
# 检查代码格式(不修改文件)
npx @atlisp/lint --format-check
```
## CLI 选项
```
--src
指定源码目录(可多次使用)
--test 指定测试目录(可多次使用)
--config 指定配置文件路径
--staged 仅检查 git 暂存区中的 .lsp 文件
--format 输出格式:default(默认)| json
--init 在当前目录生成 atlisp-lint.json
--install-hook 安装 git pre-commit hook
--fix 自动修复尾部空格、BOM、多余括号、冗余 progn/let、引号风格等问题
--cache 启用文件哈希缓存,跳过未变更的文件
--clear-cache 清除缓存目录
--parallel 开启多线程并行检查(使用 Worker Threads)
--project 启用跨文件分析(Phase 1b)
--sbcl 启用 SBCL 语法校验(Phase 2,需安装 SBCL)
--watch 监听模式,文件变动自动重新检查
--hook-args 自定义 pre-commit hook 参数(配合 --install-hook)
--diff 仅检查自上次提交后变更的文件
--changed 仅检查相对于某分支有变更的文件(默认:main)
--help 显示帮助信息
--version 显示版本号
--format-code 自动格式化代码缩进(基于括号深度 + AST 对齐)
--format-check 只检查代码缩进格式(不修改文件,不符合则退出码 1)
```
## 架构:三相检测
### Phase 1a — 单文件静态检查(84 条规则)
所有 84 条规则在单文件范围内运行,支持 `--parallel` 多线程并行。
| 规则 | 默认 | 类别 | 说明 |
|------|------|------|------|
| `parens` | error | 语法 | 括号不匹配 |
| `trailing_paren` | warn | 语法 | 多余闭合括号 |
| `extra_parens` | warn | 语法 | 可疑的连续右括号 |
| `encoding` | error | 编码 | UTF-8 BOM 检查 / 非 UTF-8 编码 |
| `quit_exit` | error | 安全 | quit/exit 调用(会终止 CAD 进程) |
| `command_shell` | error | 安全 | command shell(命令注入风险) |
| `startapp` | warn | 安全 | startapp(启动外部程序) |
| `vl_registry_write` | warn | 安全 | vl-registry-write(修改注册表) |
| `token_in_url` | warn | 安全 | URL 中含 token=(凭据泄露) |
| `vlax_without_loading` | warn | 安全 | vlax-* 未调用 vl-load-com |
| `cl_syntax` | warn | 语法 | Common Lisp 特有语法(如 &key) |
| `line_length` | warn | 风格 | 行长度超过限制 |
| `function_complexity` | warn | 复杂度 | 函数行数或嵌套深度超限 |
| `trailing_whitespace` | warn | 风格 | 行尾多余空格 |
| `empty_comment` | warn | 风格 | 空注释行(只有 ; 没有内容) |
| `parameter_naming` | warn | 最佳实践 | 参数首字母大写 |
| `unused_variable` | warn | 最佳实践 | 变量赋值但未使用 |
| `unused_parameter` | warn | 最佳实践 | 参数从未使用 |
| `unused_let_binding` | warn | 最佳实践 | let 绑定从未使用 |
| `unused_local_fun` | warn | 最佳实践 | defun / 局部函数未使用 |
| `missing_doc` | warn | 风格 | 函数缺少注释说明 |
| `error_handling` | warn | 最佳实践 | 使用 command 但缺少 \*error\* 处理 |
| `global_naming` | warn | 风格 | 全局变量未用 \*...\* 命名 |
| `constant_condition` | warn | 风格 | if/while/cond 中常量条件 |
| `redundant_progn` | warn | 风格 | 分支中多余 progn |
| `empty_branch` | warn | 风格 | if/cond 中空分支 |
| `redundant_if` | warn | 风格 | if/when 中冗余 progn |
| `redundant_let` | warn | 风格 | 无绑定 let 建议改用 progn |
| `redundant_quotes` | warn | 风格 | 冗余双引号 ''x |
| `redundant_setq` | warn | 风格 | setq 赋值自身 |
| `redundant_nil_else` | warn | 风格 | if 中冗余 nil 分支 |
| `single_arg_and_or` | warn | 风格 | 单参数 and/or 可简化 |
| `double_not` | warn | 风格 | 双重 (not (not ...)) |
| `multiple_setq` | warn | 风格 | 连续 setq 可合并 |
| `setq_multiple` | warn | 风格 | 连续 setq 可合并 |
| `setq_single_arg` | warn | 正确性 | setq 缺少值 |
| `assoc_without_cdr` | warn | 正确性 | assoc 结果未用 cdr 提取 |
| `identical_branches` | warn | 正确性 | if 的 then/else 分支完全相同 |
| `while_constant` | warn | 正确性 | while 使用常量条件 |
| `cond_duplicate` | warn | 正确性 | cond 中存在重复条件 |
| `recursive_call` | warn | 正确性 | 函数自调用(可能无限递归) |
| `self_compare` | warn | 正确性 | 自比较表达式 |
| `variable_shadow` | warn | 最佳实践 | setq 覆盖 let 绑定的同名变量 |
| `misplaced_else` | warn | 风格 | (if (not ...) ...) 交换分支 |
| `quote_vs_function` | warn | 风格 | mapcar/apply 中用引用 lambda |
| `commented_code` | warn | 风格 | 被注释掉的代码 |
| `quote_style` | warn | 风格 | (quote ...) 建议缩写 |
| `eq_usage` | warn | 最佳实践 | eq 与数字比较 |
| `lambda_syntax` | warn | 风格 | (function (lambda ...)) 建议缩写 |
| `comment_style` | warn | 风格 | ; 后缺少空格 |
| `empty_catch` | warn | 最佳实践 | vl-catch-all-apply 未检查结果 |
| `nth_usage` | warn | 风格 | (nth 0 ...) 建议 car |
| `append_single` | warn | 风格 | (append (list ...)) 建议 cons |
| `mixed_indent` | warn | 风格 | 缩进混用 tab 和空格 |
| `long_function_call` | off | 风格 | 单行参数过多 |
| `no_return` | warn | 最佳实践 | 函数无返回值 |
| `shadow_builtin` | warn | 最佳实践 | defun 覆盖内置函数 |
| `dynamic_doc` | warn | 最佳实践 | C: 命令缺少 (princ) |
| `open_without_close` | warn | 最佳实践 | open/close 数量不匹配 |
| `strcat_usage` | warn | 最佳实践 | + 拼接而非 strcat |
| `cond_simplify` | warn | 风格 | 单分支 cond 可简化为 if |
| `arg_count` | warn | 最佳实践 | 参数数量不匹配 |
| `bare_function_names` | off | 风格 | defun 缺少命名空间前缀 |
| `format_indent` | off | 风格 | 代码缩进不符合格式化规范 |
| `function_order` | off | 最佳实践 | 定义在使用之后 |
| `magic_number` | off | 风格 | 硬编码魔法数字 |
| `module_registration` | off | 架构 | 模块文件未注册到 \*modules\* |
| `namespace_header` | off | 架构 | 缺少 (in-package ...) 头 |
| `loop_optimization` | off | 最佳实践 | 优化 while/assoc 循环 |
| `builtin_arg_count` | error | 正确性 | 内置函数调用参数个数不匹配 |
| `unused_catch_result` | info | 正确性 | vl-catch-all-apply 结果被当布尔值用 |
| `string_concat_loop` | info | 性能 | 循环内字符串拼接 |
| `if_without_else` | info | 风格 | if 无 else 分支 |
| `redundant_list` | info | 风格 | (list) 等价于 nil |
| `entget_in_loop` | warn | 性能 | 循环内 entget |
| `promise_handler` | info | 最佳实践 | vlax-invoke 缺少回调处理器 |
### Phase 1b — 跨文件分析(--project)
通过 `--project` 启用,构建项目符号表后进行以下检查:
| 规则 | 默认 | 说明 |
|------|------|------|
| `dangling_defun` | warn | 函数定义但从未被任何文件调用 |
| `missing_export` | warn | 函数未注册到 @::\*modules\* |
| `unused_package_dep` | warn | 导入的包从未被引用 |
| `module_cycle` | warn | 模块循环依赖 |
| `arg_count_project` | warn | 跨文件检查函数参数数量 |
同时检测 `duplicate_defun`(函数名在多个文件中重复定义)。
### Phase 2 — SBCL 语法校验(可选)
调用 SBCL 对每个 `.lsp` 文件做 Common Lisp reader 级别深度解析:
- 语法错误 — reader 无法解析的内容
- 符号未找到 — 未注册到 stub packages 中的符号
- CL-ism — `#(`、`#\`、`#.` 等 AutoLISP 无效语法
- defmacro — 默认不允许,除非文件在允许列表中
## --format-code 代码格式化
基于括号深度自动调整代码缩进,规则:
- 每层嵌套增加 2 空格缩进
- `)` 单独一行时自动回到对应层级的缩进
- 注释行按当前嵌套深度缩进
- 字符串中的括号不影响缩进计算
- 自动删除行尾多余空格
- 空行保持不变
- 格式化后进行幂等性检查,若再次格式化结果不一致则输出警告
```bash
# 格式化所有 .lsp 文件
npx @atlisp/lint --format-code
# 仅检查格式(不修改文件),不符合则退出码 1
npx @atlisp/lint --format-check
```
## --fix 自动修复
### 预扫描修复(fixFile)
| 规则 | 修复方式 |
|------|----------|
| `trailing_whitespace` | 删除行尾空格 |
| `encoding (BOM)` | 删除 UTF-8 BOM |
| `trailing_paren` | 删除多余闭合括号 |
| `empty_comment` | 删除空注释行 |
### 规则级修复(applyFixes)
| 规则 | 修复方式 |
|------|----------|
| `redundant_quotes` | ''x → 'x |
| `double_not` | (not (not ...)) → (not ...) |
| `redundant_nil_else` | (if cond x nil) → (if cond x) |
| `single_arg_and_or` | (and x) → x |
| `redundant_setq` | 删除 (setq x x) 行 |
| `redundant_progn` | 移除分支中多余的 (progn ...) 包装 |
| `redundant_let` | (let () ...) → (progn ...) |
| `quote_style` | (quote x) → 'x |
| `redundant_if` | 移除 if/when 分支中冗余 progn |
| `misplaced_else` | (if (not x) a b) → (if x b a) |
| `format_indent` | 对整个文件应用 `formatCode()` 修复缩进 |
## 行内忽略
在代码行尾添加注释可以忽略特定规则的检查:
```lisp
(setq secret "token=abc123") ; atlisp-lint: disable=token_in_url
```
## 配置文件
`atlisp-lint.json`:
```json
{
"locale": "zh",
"source": {
"globs": ["**/*.lsp"],
"exclude": ["**/node_modules/**", "**/vendor/**", "**/.git/**"]
},
"checks": {
"parens": "error",
"encoding": "error",
"trailing_whitespace": "warn"
},
"preset": "recommended",
"line_length": {
"max": 200,
"tab_width": 2
},
"function_complexity": {
"max_lines": 300,
"max_nesting": 30
},
"cl_syntax": {
"keywords": ["&key"]
},
"dangerous_calls": {
"quit": "error",
"exit": "error",
"command_shell": "error",
"startapp": "warn",
"vl_registry_write": "warn"
},
"bare_function_names": {
"allowlist": ["T", "nil"],
"namespace_pattern": "^[a-z]+:"
},
"sbcl": {
"walk_exclude": [".vscode", "vendor", ".git"],
"defmacro_allow_files": ["compat-cl"]
}
}
```
### 配置预设
通过 `preset` 字段选择预设,预设应用后再叠加用户配置(用户设置优先级最高):
| 预设 | 说明 |
|------|------|
| `recommended` | 推荐(默认值) |
| `strict` | 严格模式(大部分规则升为 error) |
| `relaxed` | 宽松模式(仅保留 4 条 error 规则) |
预设会覆盖 `checks` 中对应规则的默认值,用户可以在同一个文件中继续覆盖预设值。
### 目录级覆盖
在某个目录下放置 `.atlisp-lint.json`,该目录及其子目录中的文件会自动合并该覆盖配置。
```json
{
"checks": {
"line_length": "off"
}
}
```
## 多语言
支持中文和英文,通过配置文件 `locale` 字段切换:
```json
{ "locale": "zh" } // 中文(默认)
{ "locale": "en" } // English
```
## Git 集成
```bash
# 安装 pre-commit hook,每次提交前自动检查暂存文件
npx @atlisp/lint --install-hook
# 带自定义参数的 hook
npx @atlisp/lint --install-hook --hook-args "--config ci-config.json"
# 手动检查暂存文件
npx @atlisp/lint --staged
```
## 缓存
```bash
# 启用缓存
npx @atlisp/lint --cache
# 清除缓存
npx @atlisp/lint --clear-cache
```
基于文件内容 MD5 哈希缓存,跳过内容未变更的文件。
## 忽略文件
在项目根目录创建 `.atlisp-lint-ignore`,使用 gitignore 风格模式排除文件:
```
**/test/**
**/vendor/**
```
## 开发
```bash
# 安装依赖
npm install
# 编译
npm run build
# 测试
npm test
# 运行所有检查
npm run format:check && npm run lint && npm run typecheck && npm test
```
## 许可
MIT