# 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