@atlisp/lint 0.1.3 → 0.1.5

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 (262) hide show
  1. package/README.md +5 -2
  2. package/atlisp-lint.default.json +29 -29
  3. package/bin/atlisp-lint +1 -1
  4. package/dist/checks/bare-names.js +4 -1
  5. package/dist/checks/cl-syntax.js +4 -1
  6. package/dist/checks/commented-code.d.ts +3 -0
  7. package/dist/checks/commented-code.js +46 -0
  8. package/dist/checks/constant-condition.d.ts +5 -0
  9. package/dist/checks/constant-condition.js +88 -0
  10. package/dist/checks/dangerous-calls.d.ts +2 -0
  11. package/dist/checks/dangerous-calls.js +70 -29
  12. package/dist/checks/dangling-defun.d.ts +6 -0
  13. package/dist/checks/dangling-defun.js +85 -0
  14. package/dist/checks/double-not.d.ts +5 -0
  15. package/dist/checks/double-not.js +30 -0
  16. package/dist/checks/empty-branch.d.ts +5 -0
  17. package/dist/checks/empty-branch.js +34 -0
  18. package/dist/checks/empty-comments.d.ts +3 -0
  19. package/dist/checks/empty-comments.js +26 -0
  20. package/dist/checks/encoding.js +13 -4
  21. package/dist/checks/function-complexity.d.ts +2 -0
  22. package/dist/checks/function-complexity.js +89 -45
  23. package/dist/checks/line-length.js +4 -1
  24. package/dist/checks/misplaced-else.d.ts +5 -0
  25. package/dist/checks/misplaced-else.js +31 -0
  26. package/dist/checks/missing-doc.js +6 -3
  27. package/dist/checks/missing-export.d.ts +13 -0
  28. package/dist/checks/missing-export.js +94 -0
  29. package/dist/checks/module-reg.js +9 -4
  30. package/dist/checks/multiple-setq.d.ts +5 -0
  31. package/dist/checks/multiple-setq.js +51 -0
  32. package/dist/checks/namespace-header.js +16 -6
  33. package/dist/checks/open-close.d.ts +2 -0
  34. package/dist/checks/open-close.js +18 -13
  35. package/dist/checks/parameter-naming.d.ts +2 -0
  36. package/dist/checks/parameter-naming.js +26 -14
  37. package/dist/checks/parens.js +8 -3
  38. package/dist/checks/quote-vs-function.d.ts +5 -0
  39. package/dist/checks/quote-vs-function.js +50 -0
  40. package/dist/checks/recursive-call.d.ts +5 -0
  41. package/dist/checks/recursive-call.js +49 -0
  42. package/dist/checks/redundant-cond.d.ts +5 -0
  43. package/dist/checks/redundant-cond.js +50 -0
  44. package/dist/checks/redundant-let.d.ts +5 -0
  45. package/dist/checks/redundant-let.js +31 -0
  46. package/dist/checks/redundant-nil-else.d.ts +5 -0
  47. package/dist/checks/redundant-nil-else.js +32 -0
  48. package/dist/checks/redundant-progn.d.ts +2 -0
  49. package/dist/checks/redundant-progn.js +18 -9
  50. package/dist/checks/redundant-quotes.d.ts +5 -0
  51. package/dist/checks/redundant-quotes.js +33 -0
  52. package/dist/checks/redundant-setq.d.ts +5 -0
  53. package/dist/checks/redundant-setq.js +34 -0
  54. package/dist/checks/self-compare.d.ts +5 -0
  55. package/dist/checks/self-compare.js +37 -0
  56. package/dist/checks/single-arg-and-or.d.ts +5 -0
  57. package/dist/checks/single-arg-and-or.js +32 -0
  58. package/dist/checks/token-in-url.js +4 -1
  59. package/dist/checks/trailing-paren.d.ts +3 -0
  60. package/dist/checks/trailing-paren.js +44 -0
  61. package/dist/checks/trailing-ws.js +4 -1
  62. package/dist/checks/unused-let.d.ts +5 -0
  63. package/dist/checks/unused-let.js +57 -0
  64. package/dist/checks/unused-local-fun.d.ts +5 -0
  65. package/dist/checks/unused-local-fun.js +62 -0
  66. package/dist/checks/unused-package-dep.d.ts +3 -0
  67. package/dist/checks/unused-package-dep.js +93 -0
  68. package/dist/checks/unused-param.d.ts +5 -0
  69. package/dist/checks/unused-param.js +63 -0
  70. package/dist/checks/unused-variable.d.ts +2 -0
  71. package/dist/checks/unused-variable.js +70 -42
  72. package/dist/checks/variable-shadow.d.ts +5 -0
  73. package/dist/checks/variable-shadow.js +66 -0
  74. package/dist/checks/vlax.js +8 -3
  75. package/dist/config.d.ts +1 -2
  76. package/dist/config.js +3 -35
  77. package/dist/disable.js +4 -1
  78. package/dist/formatters.d.ts +1 -2
  79. package/dist/formatters.js +8 -61
  80. package/dist/index.js +131 -201
  81. package/dist/locale.js +83 -91
  82. package/dist/project.d.ts +3 -0
  83. package/dist/project.js +138 -0
  84. package/dist/runner.d.ts +5 -11
  85. package/dist/runner.js +260 -71
  86. package/dist/sbcl.js +16 -11
  87. package/dist/worker.js +10 -5
  88. package/lib/lint-sbcl.lisp +19 -54
  89. package/package.json +11 -4
  90. package/LICENSE +0 -21
  91. package/dist/atlisp-lint.default.json +0 -90
  92. package/dist/cache.d.ts.map +0 -1
  93. package/dist/cache.js.map +0 -1
  94. package/dist/checks/append-single.d.ts +0 -3
  95. package/dist/checks/append-single.d.ts.map +0 -1
  96. package/dist/checks/append-single.js +0 -17
  97. package/dist/checks/append-single.js.map +0 -1
  98. package/dist/checks/arg-count.d.ts +0 -3
  99. package/dist/checks/arg-count.d.ts.map +0 -1
  100. package/dist/checks/arg-count.js +0 -120
  101. package/dist/checks/arg-count.js.map +0 -1
  102. package/dist/checks/bare-names.d.ts.map +0 -1
  103. package/dist/checks/bare-names.js.map +0 -1
  104. package/dist/checks/cl-syntax.d.ts.map +0 -1
  105. package/dist/checks/cl-syntax.js.map +0 -1
  106. package/dist/checks/comment-style.d.ts +0 -3
  107. package/dist/checks/comment-style.d.ts.map +0 -1
  108. package/dist/checks/comment-style.js +0 -21
  109. package/dist/checks/comment-style.js.map +0 -1
  110. package/dist/checks/cond-simplify.d.ts +0 -3
  111. package/dist/checks/cond-simplify.d.ts.map +0 -1
  112. package/dist/checks/cond-simplify.js +0 -42
  113. package/dist/checks/cond-simplify.js.map +0 -1
  114. package/dist/checks/dangerous-calls.d.ts.map +0 -1
  115. package/dist/checks/dangerous-calls.js.map +0 -1
  116. package/dist/checks/dynamic-doc.d.ts +0 -3
  117. package/dist/checks/dynamic-doc.d.ts.map +0 -1
  118. package/dist/checks/dynamic-doc.js +0 -21
  119. package/dist/checks/dynamic-doc.js.map +0 -1
  120. package/dist/checks/empty-catch.d.ts +0 -3
  121. package/dist/checks/empty-catch.d.ts.map +0 -1
  122. package/dist/checks/empty-catch.js +0 -31
  123. package/dist/checks/empty-catch.js.map +0 -1
  124. package/dist/checks/encoding.d.ts.map +0 -1
  125. package/dist/checks/encoding.js.map +0 -1
  126. package/dist/checks/eq-usage.d.ts +0 -3
  127. package/dist/checks/eq-usage.d.ts.map +0 -1
  128. package/dist/checks/eq-usage.js +0 -22
  129. package/dist/checks/eq-usage.js.map +0 -1
  130. package/dist/checks/error-handling.d.ts +0 -3
  131. package/dist/checks/error-handling.d.ts.map +0 -1
  132. package/dist/checks/error-handling.js +0 -53
  133. package/dist/checks/error-handling.js.map +0 -1
  134. package/dist/checks/extra-parens.d.ts +0 -3
  135. package/dist/checks/extra-parens.d.ts.map +0 -1
  136. package/dist/checks/extra-parens.js +0 -42
  137. package/dist/checks/extra-parens.js.map +0 -1
  138. package/dist/checks/function-complexity.d.ts.map +0 -1
  139. package/dist/checks/function-complexity.js.map +0 -1
  140. package/dist/checks/function-order.d.ts +0 -3
  141. package/dist/checks/function-order.d.ts.map +0 -1
  142. package/dist/checks/function-order.js +0 -33
  143. package/dist/checks/function-order.js.map +0 -1
  144. package/dist/checks/global-naming.d.ts +0 -3
  145. package/dist/checks/global-naming.d.ts.map +0 -1
  146. package/dist/checks/global-naming.js +0 -51
  147. package/dist/checks/global-naming.js.map +0 -1
  148. package/dist/checks/index.d.ts +0 -3
  149. package/dist/checks/index.d.ts.map +0 -1
  150. package/dist/checks/index.js +0 -108
  151. package/dist/checks/index.js.map +0 -1
  152. package/dist/checks/lambda-syntax.d.ts +0 -3
  153. package/dist/checks/lambda-syntax.d.ts.map +0 -1
  154. package/dist/checks/lambda-syntax.js +0 -22
  155. package/dist/checks/lambda-syntax.js.map +0 -1
  156. package/dist/checks/line-length.d.ts.map +0 -1
  157. package/dist/checks/line-length.js.map +0 -1
  158. package/dist/checks/long-function-call.d.ts +0 -3
  159. package/dist/checks/long-function-call.d.ts.map +0 -1
  160. package/dist/checks/long-function-call.js +0 -48
  161. package/dist/checks/long-function-call.js.map +0 -1
  162. package/dist/checks/loop-optimization.d.ts +0 -3
  163. package/dist/checks/loop-optimization.d.ts.map +0 -1
  164. package/dist/checks/loop-optimization.js +0 -17
  165. package/dist/checks/loop-optimization.js.map +0 -1
  166. package/dist/checks/magic-number.d.ts +0 -3
  167. package/dist/checks/magic-number.d.ts.map +0 -1
  168. package/dist/checks/magic-number.js +0 -21
  169. package/dist/checks/magic-number.js.map +0 -1
  170. package/dist/checks/missing-doc.d.ts.map +0 -1
  171. package/dist/checks/missing-doc.js.map +0 -1
  172. package/dist/checks/mixed-indent.d.ts +0 -3
  173. package/dist/checks/mixed-indent.d.ts.map +0 -1
  174. package/dist/checks/mixed-indent.js +0 -19
  175. package/dist/checks/mixed-indent.js.map +0 -1
  176. package/dist/checks/module-reg.d.ts.map +0 -1
  177. package/dist/checks/module-reg.js.map +0 -1
  178. package/dist/checks/namespace-header.d.ts.map +0 -1
  179. package/dist/checks/namespace-header.js.map +0 -1
  180. package/dist/checks/no-return.d.ts +0 -3
  181. package/dist/checks/no-return.d.ts.map +0 -1
  182. package/dist/checks/no-return.js +0 -45
  183. package/dist/checks/no-return.js.map +0 -1
  184. package/dist/checks/nth-usage.d.ts +0 -3
  185. package/dist/checks/nth-usage.d.ts.map +0 -1
  186. package/dist/checks/nth-usage.js +0 -17
  187. package/dist/checks/nth-usage.js.map +0 -1
  188. package/dist/checks/open-close.d.ts.map +0 -1
  189. package/dist/checks/open-close.js.map +0 -1
  190. package/dist/checks/parameter-naming.d.ts.map +0 -1
  191. package/dist/checks/parameter-naming.js.map +0 -1
  192. package/dist/checks/parens.d.ts.map +0 -1
  193. package/dist/checks/parens.js.map +0 -1
  194. package/dist/checks/quote-style.d.ts +0 -3
  195. package/dist/checks/quote-style.d.ts.map +0 -1
  196. package/dist/checks/quote-style.js +0 -22
  197. package/dist/checks/quote-style.js.map +0 -1
  198. package/dist/checks/redundant-if.d.ts +0 -3
  199. package/dist/checks/redundant-if.d.ts.map +0 -1
  200. package/dist/checks/redundant-if.js +0 -17
  201. package/dist/checks/redundant-if.js.map +0 -1
  202. package/dist/checks/redundant-progn.d.ts.map +0 -1
  203. package/dist/checks/redundant-progn.js.map +0 -1
  204. package/dist/checks/setq-multiple.d.ts +0 -3
  205. package/dist/checks/setq-multiple.d.ts.map +0 -1
  206. package/dist/checks/setq-multiple.js +0 -17
  207. package/dist/checks/setq-multiple.js.map +0 -1
  208. package/dist/checks/shadow-builtin.d.ts +0 -3
  209. package/dist/checks/shadow-builtin.d.ts.map +0 -1
  210. package/dist/checks/shadow-builtin.js +0 -29
  211. package/dist/checks/shadow-builtin.js.map +0 -1
  212. package/dist/checks/strcat-usage.d.ts +0 -3
  213. package/dist/checks/strcat-usage.d.ts.map +0 -1
  214. package/dist/checks/strcat-usage.js +0 -22
  215. package/dist/checks/strcat-usage.js.map +0 -1
  216. package/dist/checks/token-in-url.d.ts.map +0 -1
  217. package/dist/checks/token-in-url.js.map +0 -1
  218. package/dist/checks/trailing-ws.d.ts.map +0 -1
  219. package/dist/checks/trailing-ws.js.map +0 -1
  220. package/dist/checks/type-check.d.ts +0 -3
  221. package/dist/checks/type-check.d.ts.map +0 -1
  222. package/dist/checks/type-check.js +0 -26
  223. package/dist/checks/type-check.js.map +0 -1
  224. package/dist/checks/unused-variable.d.ts.map +0 -1
  225. package/dist/checks/unused-variable.js.map +0 -1
  226. package/dist/checks/vlax.d.ts.map +0 -1
  227. package/dist/checks/vlax.js.map +0 -1
  228. package/dist/config.d.ts.map +0 -1
  229. package/dist/config.js.map +0 -1
  230. package/dist/disable.d.ts.map +0 -1
  231. package/dist/disable.js.map +0 -1
  232. package/dist/formatters.d.ts.map +0 -1
  233. package/dist/formatters.js.map +0 -1
  234. package/dist/index.d.ts.map +0 -1
  235. package/dist/index.js.map +0 -1
  236. package/dist/lib/lint-sbcl.lisp +0 -161
  237. package/dist/locale.d.ts.map +0 -1
  238. package/dist/locale.js.map +0 -1
  239. package/dist/rules.d.ts +0 -9
  240. package/dist/rules.d.ts.map +0 -1
  241. package/dist/rules.js +0 -58
  242. package/dist/rules.js.map +0 -1
  243. package/dist/runner.d.ts.map +0 -1
  244. package/dist/runner.js.map +0 -1
  245. package/dist/sbcl.d.ts.map +0 -1
  246. package/dist/sbcl.js.map +0 -1
  247. package/dist/stub-packages.json +0 -41
  248. package/dist/types.d.ts.map +0 -1
  249. package/dist/types.js.map +0 -1
  250. package/dist/utils.d.ts.map +0 -1
  251. package/dist/utils.js.map +0 -1
  252. package/dist/validate.d.ts +0 -8
  253. package/dist/validate.d.ts.map +0 -1
  254. package/dist/validate.js +0 -59
  255. package/dist/validate.js.map +0 -1
  256. package/dist/watch.d.ts +0 -9
  257. package/dist/watch.d.ts.map +0 -1
  258. package/dist/watch.js +0 -109
  259. package/dist/watch.js.map +0 -1
  260. package/dist/worker.d.ts.map +0 -1
  261. package/dist/worker.js.map +0 -1
  262. package/pre-commit/hook.sh +0 -4
package/README.md CHANGED
@@ -34,9 +34,12 @@ npx @atlisp/lint --fix
34
34
  --config <path> 指定配置文件路径
35
35
  --staged 仅检查 git 暂存区中的 .lsp 文件
36
36
  --format <format> 输出格式:default(默认)| json
37
- --init 在当前目录生成 .atlisp-lint.json
37
+ --init 在当前目录生成 atlisp-lint.json
38
38
  --install-hook 安装 git pre-commit hook
39
39
  --fix 自动修复尾部空格、UTF-8 BOM 等问题
40
+ --cache 启用文件哈希缓存,跳过未变更的文件
41
+ --clear-cache 清除缓存目录
42
+ --parallel 开启多线程并行检查(使用 Worker Threads)
40
43
  --hook-args <args> 自定义 pre-commit hook 参数(配合 --install-hook)
41
44
  ```
42
45
 
@@ -85,7 +88,7 @@ npx @atlisp/lint --fix
85
88
 
86
89
  ## 配置文件
87
90
 
88
- `.atlisp-lint.json`:
91
+ `atlisp-lint.json`:
89
92
 
90
93
  ```json
91
94
  {
@@ -6,49 +6,49 @@
6
6
  },
7
7
  "checks": {
8
8
  "parens": "error",
9
- "encoding": "warn",
9
+ "encoding": "error",
10
10
  "cl_syntax": "warn",
11
11
  "quit_exit": "error",
12
12
  "command_shell": "error",
13
13
  "startapp": "warn",
14
14
  "vl_registry_write": "warn",
15
- "vlax_without_loading": "off",
15
+ "vlax_without_loading": "warn",
16
16
  "token_in_url": "warn",
17
17
  "open_without_close": "warn",
18
- "bare_function_names": "off",
18
+ "bare_function_names": "warn",
19
19
  "line_length": "warn",
20
20
  "function_complexity": "warn",
21
21
  "parameter_naming": "warn",
22
22
  "unused_variable": "warn",
23
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
24
  "trailing_whitespace": "warn",
50
25
  "module_registration": "off",
51
- "namespace_header": "off"
26
+ "namespace_header": "off",
27
+ "unused_parameter": "warn",
28
+ "constant_condition": "warn",
29
+ "redundant_progn": "warn",
30
+ "empty_branch": "warn",
31
+ "unused_let_binding": "warn",
32
+ "recursive_call": "warn",
33
+ "variable_shadow": "warn",
34
+ "redundant_cond": "warn",
35
+ "unused_local_fun": "warn",
36
+ "multiple_setq": "warn",
37
+ "redundant_quotes": "warn",
38
+ "trailing_paren": "warn",
39
+ "empty_comment": "warn",
40
+ "redundant_setq": "warn",
41
+ "redundant_nil_else": "warn",
42
+ "single_arg_and_or": "warn",
43
+ "redundant_let": "warn",
44
+ "self_compare": "warn",
45
+ "misplaced_else": "warn",
46
+ "quote_vs_function": "warn",
47
+ "commented_code": "warn",
48
+ "double_not": "warn",
49
+ "dangling_defun": "warn",
50
+ "missing_export": "warn",
51
+ "unused_package_dep": "warn"
52
52
  },
53
53
  "line_length": {
54
54
  "max": 100,
package/bin/atlisp-lint CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- require('../dist/index.js').main().catch(e => { console.error(e); process.exit(1); });
2
+ require('../dist/index.js').main();
@@ -18,7 +18,10 @@ function checkBareFunctionNames(content, file, allowlist, namespacePattern) {
18
18
  continue; // local: defun foo/bar
19
19
  if (!nsRegex.test(name) && !name.includes(':')) {
20
20
  issues.push({
21
- file, line: lineno, severity: 'warn', rule: 'bare_function_names',
21
+ file,
22
+ line: lineno,
23
+ severity: 'warn',
24
+ rule: 'bare_function_names',
22
25
  message: (0, locale_1.t)('bare_function_names', name),
23
26
  });
24
27
  }
@@ -13,7 +13,10 @@ function checkClSyntax(content, file, keywords) {
13
13
  const idx = s.indexOf(kw);
14
14
  if (idx >= 0 && (idx === 0 || !/[a-zA-Z]/.test(s[idx - 1]))) {
15
15
  issues.push({
16
- file, line: lineno, severity: 'warn', rule: 'cl_syntax',
16
+ file,
17
+ line: lineno,
18
+ severity: 'warn',
19
+ rule: 'cl_syntax',
17
20
  message: (0, locale_1.t)('cl_syntax', kw),
18
21
  });
19
22
  }
@@ -0,0 +1,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkCommentedCode(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=commented-code.d.ts.map
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkCommentedCode = checkCommentedCode;
4
+ const locale_1 = require("../locale");
5
+ const CODE_PATTERNS = [
6
+ /^\s*\(defun\s/i,
7
+ /^\s*\(setq\s/i,
8
+ /^\s*\(if\s/i,
9
+ /^\s*\(cond\s/i,
10
+ /^\s*\(while\s/i,
11
+ /^\s*\(foreach\s/i,
12
+ /^\s*\(let\s/i,
13
+ /^\s*\(lambda\s/i,
14
+ /^\s*\(repeat\s/i,
15
+ /^\s*\(progn\s/i,
16
+ /^\s*\(princ?\s/i,
17
+ /^\s*\(command\s/i,
18
+ /^\s*\(defun-q\s/i,
19
+ /^\s*\(vl-\S/,
20
+ /^\s*\(vla-\S/,
21
+ ];
22
+ function checkCommentedCode(content, file) {
23
+ const issues = [];
24
+ const lines = content.split('\n');
25
+ for (let i = 0; i < lines.length; i++) {
26
+ const line = lines[i];
27
+ const match = line.match(/^\s*;+([^;].*)$/);
28
+ if (!match)
29
+ continue;
30
+ const afterSemicolon = match[1];
31
+ for (const pat of CODE_PATTERNS) {
32
+ if (pat.test(afterSemicolon)) {
33
+ issues.push({
34
+ file,
35
+ line: i + 1,
36
+ severity: 'warn',
37
+ rule: 'commented_code',
38
+ message: (0, locale_1.t)('commented_code'),
39
+ });
40
+ break;
41
+ }
42
+ }
43
+ }
44
+ return issues;
45
+ }
46
+ //# sourceMappingURL=commented-code.js.map
@@ -0,0 +1,5 @@
1
+ import { Issue } from '../types';
2
+ import { AstNode } from '@atlisp/parser';
3
+ export declare function checkConstantCondition(content: string, file: string): Issue[];
4
+ export declare function checkConstantConditionAst(ast: AstNode, file: string): Issue[];
5
+ //# sourceMappingURL=constant-condition.d.ts.map
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkConstantCondition = checkConstantCondition;
4
+ exports.checkConstantConditionAst = checkConstantConditionAst;
5
+ const locale_1 = require("../locale");
6
+ const parser_1 = require("@atlisp/parser");
7
+ const CONDITION_FORMS = new Set(['if', 'while']);
8
+ const CONSTANTS = new Set(['T', 'nil']);
9
+ function checkConstantCondition(content, file) {
10
+ const ast = (0, parser_1.parseAst)(content);
11
+ return checkConstantConditionAst(ast, file);
12
+ }
13
+ function checkConstantConditionAst(ast, file) {
14
+ const issues = [];
15
+ // Check if / while with constant condition
16
+ for (const form of CONDITION_FORMS) {
17
+ const nodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, form));
18
+ for (const node of nodes) {
19
+ if (!node.children || node.children.length < 2)
20
+ continue;
21
+ const cond = node.children[1];
22
+ if (cond.type === 'symbol' && cond.name && CONSTANTS.has(cond.name)) {
23
+ issues.push({
24
+ file,
25
+ line: cond.pos.line,
26
+ severity: 'warn',
27
+ rule: 'constant_condition',
28
+ message: (0, locale_1.t)('constant_condition', cond.name, `(${form} ...)`),
29
+ });
30
+ }
31
+ }
32
+ }
33
+ // Check (cond (T ...))
34
+ const condNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'cond'));
35
+ for (const condNode of condNodes) {
36
+ if (!condNode.children)
37
+ continue;
38
+ for (let i = 1; i < condNode.children.length; i++) {
39
+ const clause = condNode.children[i];
40
+ if (clause.type !== 'list' || !clause.children || clause.children.length === 0)
41
+ continue;
42
+ const condTest = clause.children[0];
43
+ if (condTest.type === 'symbol' && condTest.name && CONSTANTS.has(condTest.name)) {
44
+ issues.push({
45
+ file,
46
+ line: condTest.pos.line,
47
+ severity: 'warn',
48
+ rule: 'constant_condition',
49
+ message: (0, locale_1.t)('constant_condition', condTest.name, '(cond ...)'),
50
+ });
51
+ }
52
+ }
53
+ }
54
+ // Check (or T ...) — first arg is T, always short-circuits to T
55
+ const orNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'or'));
56
+ for (const node of orNodes) {
57
+ if (!node.children || node.children.length < 2)
58
+ continue;
59
+ const first = node.children[1];
60
+ if (first.type === 'symbol' && first.name === 'T') {
61
+ issues.push({
62
+ file,
63
+ line: first.pos.line,
64
+ severity: 'warn',
65
+ rule: 'constant_condition',
66
+ message: (0, locale_1.t)('constant_condition', 'T', '(or ...)'),
67
+ });
68
+ }
69
+ }
70
+ // Check (and nil ...) — first arg is nil, always short-circuits to nil
71
+ const andNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'and'));
72
+ for (const node of andNodes) {
73
+ if (!node.children || node.children.length < 2)
74
+ continue;
75
+ const first = node.children[1];
76
+ if (first.type === 'symbol' && first.name === 'nil') {
77
+ issues.push({
78
+ file,
79
+ line: first.pos.line,
80
+ severity: 'warn',
81
+ rule: 'constant_condition',
82
+ message: (0, locale_1.t)('constant_condition', 'nil', '(and ...)'),
83
+ });
84
+ }
85
+ }
86
+ return issues;
87
+ }
88
+ //# sourceMappingURL=constant-condition.js.map
@@ -1,3 +1,5 @@
1
1
  import { Issue, DangerousCallsConfig } from '../types';
2
+ import { AstNode } from '@atlisp/parser';
2
3
  export declare function checkDangerousCalls(content: string, file: string, config: DangerousCallsConfig): Issue[];
4
+ export declare function checkDangerousCallsAst(ast: AstNode, file: string, config: DangerousCallsConfig): Issue[];
3
5
  //# sourceMappingURL=dangerous-calls.d.ts.map
@@ -1,41 +1,82 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkDangerousCalls = checkDangerousCalls;
4
- const utils_1 = require("../utils");
4
+ exports.checkDangerousCallsAst = checkDangerousCallsAst;
5
5
  const locale_1 = require("../locale");
6
+ const parser_1 = require("@atlisp/parser");
6
7
  const PATTERNS = [
7
- { rule: 'quit', check: l => /\bquit\b/.test(l), key: 'quit', useStripped: true },
8
- { rule: 'exit', check: l => /\bexit\b/.test(l), key: 'exit', useStripped: true },
9
- { rule: 'command_shell', check: l => /\(command\s+"shell"\s/.test(l), key: 'command_shell' },
10
- { rule: 'startapp', check: l => /\bstartapp\b/.test(l), key: 'startapp' },
11
- { rule: 'vl_registry_write', check: l => /\bvl-registry-write\b/.test(l), key: 'vl_registry_write' },
8
+ { rule: 'quit', key: 'quit', messageKey: 'dangerous.quit', functionCall: true },
9
+ { rule: 'exit', key: 'exit', messageKey: 'dangerous.exit', functionCall: true },
10
+ { rule: 'startapp', key: 'startapp', messageKey: 'dangerous.startapp', functionCall: true },
11
+ {
12
+ rule: 'vl_registry_write',
13
+ key: 'vl_registry_write',
14
+ messageKey: 'dangerous.vl_registry_write',
15
+ functionCall: true,
16
+ },
17
+ { rule: 'command_shell', key: 'command_shell', messageKey: 'dangerous.command_shell', commandShell: true },
12
18
  ];
13
- const MESSAGE_KEYS = {
14
- quit: 'dangerous.quit',
15
- exit: 'dangerous.exit',
16
- command_shell: 'dangerous.command_shell',
17
- startapp: 'dangerous.startapp',
18
- vl_registry_write: 'dangerous.vl_registry_write',
19
- };
19
+ function isInQuote(node) {
20
+ let cur = node.parent;
21
+ while (cur) {
22
+ if (cur.type === 'list' &&
23
+ cur.children &&
24
+ cur.children.length > 0 &&
25
+ cur.children[0].type === 'symbol' &&
26
+ cur.children[0].name === 'quote') {
27
+ return true;
28
+ }
29
+ cur = cur.parent;
30
+ }
31
+ return false;
32
+ }
33
+ function isFunctionCall(list, name) {
34
+ if (list.type !== 'list' || !list.children || list.children.length === 0)
35
+ return false;
36
+ return list.children[0].type === 'symbol' && list.children[0].name === name;
37
+ }
20
38
  function checkDangerousCalls(content, file, config) {
39
+ const ast = (0, parser_1.parseAst)(content);
40
+ return checkDangerousCallsAst(ast, file, config);
41
+ }
42
+ function checkDangerousCallsAst(ast, file, config) {
21
43
  const issues = [];
22
- const lines = content.split('\n');
23
- for (let lineno = 1; lineno <= lines.length; lineno++) {
24
- const line = lines[lineno - 1];
25
- // Two versions: without strings (for bare word checks) and with strings (for quoted arg checks)
26
- const strippedCode = (0, utils_1.stripLine)(line).trim(); // strings removed
27
- const strippedRaw = (0, utils_1.stripLineRaw)(line).trim(); // strings preserved
28
- for (const p of PATTERNS) {
29
- const configuredSeverity = config[p.key];
30
- if (configuredSeverity === 'off')
31
- continue;
32
- const testStr = p.useStripped ? strippedCode : strippedRaw;
33
- if (!testStr)
34
- continue;
35
- if (p.check(testStr)) {
44
+ for (const pattern of PATTERNS) {
45
+ const severity = config[pattern.key];
46
+ if (severity === 'off')
47
+ continue;
48
+ if (pattern.commandShell) {
49
+ // Find (command "shell" ...) calls
50
+ const commandCalls = (0, parser_1.astFindAll)(ast, (n) => isFunctionCall(n, 'command'));
51
+ for (const call of commandCalls) {
52
+ if (isInQuote(call))
53
+ continue;
54
+ if (!call.children || call.children.length < 2)
55
+ continue;
56
+ const firstArg = call.children[1];
57
+ if (firstArg.type === 'string' && firstArg.value === 'shell') {
58
+ issues.push({
59
+ file,
60
+ line: call.pos.line,
61
+ severity,
62
+ rule: pattern.rule,
63
+ message: (0, locale_1.t)(pattern.messageKey),
64
+ });
65
+ }
66
+ }
67
+ }
68
+ else if (pattern.functionCall) {
69
+ // Find actual function calls
70
+ const calls = (0, parser_1.astFindAll)(ast, (n) => isFunctionCall(n, pattern.rule));
71
+ for (const call of calls) {
72
+ if (isInQuote(call))
73
+ continue;
36
74
  issues.push({
37
- file, line: lineno, severity: configuredSeverity, rule: p.rule,
38
- message: (0, locale_1.t)(MESSAGE_KEYS[p.rule]),
75
+ file,
76
+ line: call.pos.line,
77
+ severity,
78
+ rule: pattern.rule,
79
+ message: (0, locale_1.t)(pattern.messageKey),
39
80
  });
40
81
  }
41
82
  }
@@ -0,0 +1,6 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkDanglingDefun(file: string, allDefuns: Map<string, {
3
+ file: string;
4
+ line: number;
5
+ }[]>): Issue[];
6
+ //# sourceMappingURL=dangling-defun.d.ts.map
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.checkDanglingDefun = checkDanglingDefun;
37
+ const locale_1 = require("../locale");
38
+ const parser_1 = require("@atlisp/parser");
39
+ const fs = __importStar(require("fs"));
40
+ function checkDanglingDefun(file, allDefuns) {
41
+ const issues = [];
42
+ const content = fs.readFileSync(file, 'utf-8');
43
+ const ast = (0, parser_1.parseAst)(content);
44
+ const localDefuns = [];
45
+ const defunNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
46
+ for (const node of defunNodes) {
47
+ if (node.children && node.children.length >= 2 && (0, parser_1.astIsSymbol)(node.children[1])) {
48
+ localDefuns.push(node.children[1].name);
49
+ }
50
+ }
51
+ const calledSymbols = new Set();
52
+ const allCalls = (0, parser_1.astFindAll)(ast, (n) => {
53
+ if (n.type !== 'list' || !n.children || n.children.length === 0)
54
+ return false;
55
+ return (0, parser_1.astIsSymbol)(n.children[0]);
56
+ });
57
+ for (const call of allCalls) {
58
+ const name = call.children[0].name;
59
+ if (name !== 'defun' && name !== 'defun-q' && !name.startsWith('c:') && !name.includes(':')) {
60
+ calledSymbols.add(name);
61
+ }
62
+ }
63
+ for (const defunName of localDefuns) {
64
+ let isCalled = calledSymbols.has(defunName);
65
+ if (!isCalled) {
66
+ for (const [, defs] of allDefuns) {
67
+ if (defs.some((d) => d.file !== file)) {
68
+ isCalled = true;
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ if (!isCalled) {
74
+ issues.push({
75
+ file,
76
+ line: defunNodes.find((n) => n.children && n.children.length >= 2 && (0, parser_1.astIsSymbol)(n.children[1]) && n.children[1].name === defunName).pos.line,
77
+ severity: 'warn',
78
+ rule: 'dangling_defun',
79
+ message: (0, locale_1.t)('dangling_defun', defunName),
80
+ });
81
+ }
82
+ }
83
+ return issues;
84
+ }
85
+ //# sourceMappingURL=dangling-defun.js.map
@@ -0,0 +1,5 @@
1
+ import { Issue } from '../types';
2
+ import { AstNode } from '@atlisp/parser';
3
+ export declare function checkDoubleNot(content: string, file: string): Issue[];
4
+ export declare function checkDoubleNotAst(ast: AstNode, file: string): Issue[];
5
+ //# sourceMappingURL=double-not.d.ts.map
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkDoubleNot = checkDoubleNot;
4
+ exports.checkDoubleNotAst = checkDoubleNotAst;
5
+ const locale_1 = require("../locale");
6
+ const parser_1 = require("@atlisp/parser");
7
+ function checkDoubleNot(content, file) {
8
+ const ast = (0, parser_1.parseAst)(content);
9
+ return checkDoubleNotAst(ast, file);
10
+ }
11
+ function checkDoubleNotAst(ast, file) {
12
+ const issues = [];
13
+ const notNodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, 'not'));
14
+ for (const node of notNodes) {
15
+ if (!node.children || node.children.length < 2)
16
+ continue;
17
+ const arg = node.children[1];
18
+ if (!(0, parser_1.astIsList)(arg, 'not'))
19
+ continue;
20
+ issues.push({
21
+ file,
22
+ line: node.pos.line,
23
+ severity: 'warn',
24
+ rule: 'double_not',
25
+ message: (0, locale_1.t)('double_not'),
26
+ });
27
+ }
28
+ return issues;
29
+ }
30
+ //# sourceMappingURL=double-not.js.map
@@ -0,0 +1,5 @@
1
+ import { Issue } from '../types';
2
+ import { AstNode } from '@atlisp/parser';
3
+ export declare function checkEmptyBranch(content: string, file: string): Issue[];
4
+ export declare function checkEmptyBranchAst(ast: AstNode, file: string): Issue[];
5
+ //# sourceMappingURL=empty-branch.d.ts.map
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkEmptyBranch = checkEmptyBranch;
4
+ exports.checkEmptyBranchAst = checkEmptyBranchAst;
5
+ const locale_1 = require("../locale");
6
+ const parser_1 = require("@atlisp/parser");
7
+ // AutoLISP only has `if` for conditional branching; `while` with no body is valid (no-op loop)
8
+ const BRANCH_FORMS = new Set(['if']);
9
+ function checkEmptyBranch(content, file) {
10
+ const ast = (0, parser_1.parseAst)(content);
11
+ return checkEmptyBranchAst(ast, file);
12
+ }
13
+ function checkEmptyBranchAst(ast, file) {
14
+ const issues = [];
15
+ for (const form of BRANCH_FORMS) {
16
+ const nodes = (0, parser_1.astFindAll)(ast, (n) => (0, parser_1.astIsList)(n, form));
17
+ for (const node of nodes) {
18
+ if (!node.children)
19
+ continue;
20
+ // (if cond) — no then or else, only 2 items (form + cond)
21
+ if (node.children.length < 3) {
22
+ issues.push({
23
+ file,
24
+ line: node.pos.line,
25
+ severity: 'warn',
26
+ rule: 'empty_branch',
27
+ message: (0, locale_1.t)('empty_branch', `(${form} ...)`),
28
+ });
29
+ }
30
+ }
31
+ }
32
+ return issues;
33
+ }
34
+ //# sourceMappingURL=empty-branch.js.map
@@ -0,0 +1,3 @@
1
+ import { Issue } from '../types';
2
+ export declare function checkEmptyComments(content: string, file: string): Issue[];
3
+ //# sourceMappingURL=empty-comments.d.ts.map
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkEmptyComments = checkEmptyComments;
4
+ const locale_1 = require("../locale");
5
+ function checkEmptyComments(content, file) {
6
+ const issues = [];
7
+ const lines = content.split('\n');
8
+ for (let i = 0; i < lines.length; i++) {
9
+ const line = lines[i].trim();
10
+ // Check: line is a comment with only whitespace after the ;
11
+ if (line.startsWith(';')) {
12
+ const afterSemicolon = line.slice(1);
13
+ if (afterSemicolon.trim() === '') {
14
+ issues.push({
15
+ file,
16
+ line: i + 1,
17
+ severity: 'warn',
18
+ rule: 'empty_comment',
19
+ message: (0, locale_1.t)('empty_comment'),
20
+ });
21
+ }
22
+ }
23
+ }
24
+ return issues;
25
+ }
26
+ //# sourceMappingURL=empty-comments.js.map
@@ -6,9 +6,12 @@ function checkEncoding(content, file) {
6
6
  const issues = [];
7
7
  const raw = Buffer.from(content, 'utf-8');
8
8
  // BOM detection
9
- if (raw.length >= 3 && raw[0] === 0xEF && raw[1] === 0xBB && raw[2] === 0xBF) {
9
+ if (raw.length >= 3 && raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) {
10
10
  issues.push({
11
- file, line: 1, severity: 'warn', rule: 'encoding',
11
+ file,
12
+ line: 1,
13
+ severity: 'warn',
14
+ rule: 'encoding',
12
15
  message: (0, locale_1.t)('encoding.bom'),
13
16
  });
14
17
  }
@@ -17,14 +20,20 @@ function checkEncoding(content, file) {
17
20
  const roundtrip = Buffer.from(content, 'utf-8').toString('utf-8');
18
21
  if (roundtrip !== content) {
19
22
  issues.push({
20
- file, line: 1, severity: 'error', rule: 'encoding',
23
+ file,
24
+ line: 1,
25
+ severity: 'error',
26
+ rule: 'encoding',
21
27
  message: (0, locale_1.t)('encoding.non_utf8_cad'),
22
28
  });
23
29
  }
24
30
  }
25
31
  catch {
26
32
  issues.push({
27
- file, line: 1, severity: 'error', rule: 'encoding',
33
+ file,
34
+ line: 1,
35
+ severity: 'error',
36
+ rule: 'encoding',
28
37
  message: (0, locale_1.t)('encoding.non_utf8'),
29
38
  });
30
39
  }
@@ -1,3 +1,5 @@
1
1
  import { Issue } from '../types';
2
+ import { AstNode } from '@atlisp/parser';
2
3
  export declare function checkFunctionComplexity(content: string, file: string, maxLines: number, maxNesting: number): Issue[];
4
+ export declare function checkFunctionComplexityAst(ast: AstNode, file: string, maxLines: number, maxNesting: number): Issue[];
3
5
  //# sourceMappingURL=function-complexity.d.ts.map