@atlisp/lint 0.1.3 → 0.1.4

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/dist/index.js CHANGED
@@ -39,48 +39,26 @@ const path = __importStar(require("path"));
39
39
  const child_process_1 = require("child_process");
40
40
  const config_1 = require("./config");
41
41
  const runner_1 = require("./runner");
42
+ const project_1 = require("./project");
42
43
  const sbcl_1 = require("./sbcl");
43
44
  const formatters_1 = require("./formatters");
44
- const watch_1 = require("./watch");
45
- const validate_1 = require("./validate");
46
- const rules_1 = require("./rules");
47
45
  const locale_1 = require("./locale");
48
- const VERSION = require('../package.json').version;
49
- const HELP_TEXT = `
50
- @atlisp/lint v${VERSION} — AutoLISP static analysis tool
51
-
52
- USAGE
53
- atlisp-lint [options]
54
-
55
- OPTIONS
56
- --src <dir> Source directory (repeatable)
57
- --test <dir> Test directory (repeatable)
58
- --config <path> Path to config file
59
- --staged Lint only git-staged files
60
- --format <fmt> Output: default, json, html
61
- --output <path> Write output to file
62
- --fix Auto-fix trailing whitespace / BOM / comment style
63
- --init Generate .atlisp-lint.json
64
- --install-hook Install git pre-commit hook
65
- --hook-args <args> Extra args for pre-commit hook
66
- --watch Watch mode
67
- --parallel Use parallel workers
68
- --cache Enable result caching
69
- --clear-cache Clear cache and exit
70
- --max-warnings <n> Fail if warnings exceed n
71
- --validate-config Validate config and exit
72
- --docs Print rules documentation
73
- --quiet Only output errors
74
- --help Show this help
75
- --version Show version
76
- `.trim();
46
+ const cache_1 = require("./cache");
77
47
  function parseArgs() {
78
48
  const argv = process.argv.slice(2);
79
49
  const opts = {
80
- src: [], test: [], staged: false, format: 'default', init: false,
81
- installHook: false, fix: false, hookArgs: '', watch: false,
82
- parallel: false, cache: false, clearCache: false,
83
- validateConfig: false, docs: false, quiet: false, help: false, version: false,
50
+ src: [],
51
+ test: [],
52
+ staged: false,
53
+ format: 'default',
54
+ init: false,
55
+ installHook: false,
56
+ fix: false,
57
+ hookArgs: '',
58
+ cache: false,
59
+ clearCache: false,
60
+ parallel: false,
61
+ project: false,
84
62
  };
85
63
  for (let i = 0; i < argv.length; i++) {
86
64
  switch (argv[i]) {
@@ -111,44 +89,25 @@ function parseArgs() {
111
89
  case '--hook-args':
112
90
  opts.hookArgs = argv[++i];
113
91
  break;
114
- case '--watch':
115
- opts.watch = true;
116
- break;
117
- case '--parallel':
118
- opts.parallel = true;
119
- break;
120
92
  case '--cache':
121
93
  opts.cache = true;
122
94
  break;
123
95
  case '--clear-cache':
124
96
  opts.clearCache = true;
125
97
  break;
126
- case '--max-warnings':
127
- opts.maxWarnings = parseInt(argv[++i], 10);
128
- break;
129
- case '--validate-config':
130
- opts.validateConfig = true;
131
- break;
132
- case '--docs':
133
- opts.docs = true;
134
- break;
135
- case '--quiet':
136
- opts.quiet = true;
137
- break;
138
- case '--help':
139
- opts.help = true;
98
+ case '--parallel':
99
+ opts.parallel = true;
140
100
  break;
141
- case '--version':
142
- opts.version = true;
101
+ case '--project':
102
+ opts.project = true;
143
103
  break;
144
- case '--output':
145
- opts.output = argv[++i];
104
+ default:
146
105
  break;
147
- default: break;
148
106
  }
149
107
  }
150
108
  return opts;
151
109
  }
110
+ // Zero-dependency glob: **/*.lsp → recursive walk + regex match
152
111
  function* walkFiles(dir, rootDir, regex) {
153
112
  let entries;
154
113
  try {
@@ -189,6 +148,7 @@ function globFiles(pattern, rootDir) {
189
148
  function collectFiles(rootDir, opts, config) {
190
149
  const files = new Set();
191
150
  if (opts.src.length > 0 || opts.test.length > 0) {
151
+ // Walk specific directories
192
152
  for (const d of opts.src) {
193
153
  for (const f of globFiles('**/*.lsp', path.resolve(rootDir, d))) {
194
154
  files.add(f);
@@ -201,38 +161,43 @@ function collectFiles(rootDir, opts, config) {
201
161
  }
202
162
  }
203
163
  else {
164
+ // Use config globs relative to rootDir
204
165
  for (const pattern of config.source.globs) {
205
166
  for (const f of globFiles(pattern, rootDir)) {
206
167
  files.add(f);
207
168
  }
208
169
  }
209
170
  }
210
- const excludePatterns = config.source.exclude.map(e => {
171
+ const excludePatterns = config.source.exclude.map((e) => {
211
172
  const str = e.replace(/\./g, '\\.').replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*');
212
173
  return new RegExp(`^${str}$`);
213
174
  });
214
- return Array.from(files).filter(f => {
175
+ return Array.from(files)
176
+ .filter((f) => {
215
177
  const rel = path.relative(rootDir, f).replace(/\\/g, '/');
216
178
  for (const re of excludePatterns) {
217
179
  if (re.test(rel))
218
180
  return false;
219
181
  }
220
182
  return true;
221
- }).sort();
183
+ })
184
+ .sort();
222
185
  }
223
186
  function collectStagedFiles(rootDir) {
224
187
  const output = (0, child_process_1.execSync)('git diff --cached --name-only --diff-filter=ACM', {
225
- cwd: rootDir, encoding: 'utf-8',
188
+ cwd: rootDir,
189
+ encoding: 'utf-8',
226
190
  });
227
- return output.split('\n')
228
- .map(l => l.trim())
229
- .filter(l => l.endsWith('.lsp'))
230
- .map(l => path.resolve(rootDir, l))
231
- .filter(f => fs.existsSync(f));
191
+ return output
192
+ .split('\n')
193
+ .map((l) => l.trim())
194
+ .filter((l) => l.endsWith('.lsp'))
195
+ .map((l) => path.resolve(rootDir, l))
196
+ .filter((f) => fs.existsSync(f));
232
197
  }
233
198
  function initConfig(rootDir) {
234
199
  const defaultPath = path.join(__dirname, '..', 'atlisp-lint.default.json');
235
- const targetPath = path.join(rootDir, '.atlisp-lint.json');
200
+ const targetPath = path.join(rootDir, 'atlisp-lint.json');
236
201
  if (fs.existsSync(targetPath)) {
237
202
  console.log((0, locale_1.t)('index.config_exists'));
238
203
  return;
@@ -258,152 +223,117 @@ npx @atlisp/lint ${args} || exit 1
258
223
  console.log((0, locale_1.t)('index.hook_installed', hookPath));
259
224
  }
260
225
  async function main() {
261
- const opts = parseArgs();
262
- const rootDir = process.cwd();
263
- if (opts.help) {
264
- console.log(HELP_TEXT);
265
- return;
266
- }
267
- if (opts.version) {
268
- console.log(VERSION);
269
- return;
270
- }
271
- // --clear-cache
272
- if (opts.clearCache) {
273
- (0, runner_1.clearCache)(rootDir);
274
- console.log((0, locale_1.t)('index.cache_cleared'));
275
- return;
276
- }
277
- if (opts.docs) {
278
- const docs = (0, rules_1.generateRulesMarkdown)();
279
- if (opts.output) {
280
- fs.writeFileSync(opts.output, docs, 'utf-8');
281
- console.log(`${(0, locale_1.t)('index.config_created', opts.output)}`);
226
+ try {
227
+ const opts = parseArgs();
228
+ const rootDir = process.cwd();
229
+ if (opts.init) {
230
+ initConfig(rootDir);
231
+ return;
282
232
  }
283
- else {
284
- console.log(docs);
233
+ if (opts.installHook) {
234
+ installPreCommitHook(rootDir, opts.hookArgs);
235
+ return;
285
236
  }
286
- return;
287
- }
288
- if (opts.init) {
289
- initConfig(rootDir);
290
- return;
291
- }
292
- if (opts.installHook) {
293
- installPreCommitHook(rootDir, opts.hookArgs);
294
- return;
295
- }
296
- const configPath = opts.config || path.join(rootDir, '.atlisp-lint.json');
297
- const config = (0, config_1.loadConfig)(fs.existsSync(configPath) ? configPath : undefined);
298
- (0, locale_1.setLocale)(config.locale || 'zh');
299
- if (opts.validateConfig) {
300
- const errors = (0, validate_1.validateConfig)(config);
301
- if (errors.length === 0) {
302
- console.log((0, locale_1.t)('index.config_valid'));
237
+ if (opts.clearCache) {
238
+ (0, cache_1.clearCache)(rootDir);
239
+ console.log((0, locale_1.t)('index.cache_cleared'));
240
+ return;
303
241
  }
304
- else {
305
- for (const e of errors) {
306
- console.error(`${(0, locale_1.t)('summary.tag_fail')}: ${e.path} ${e.message}`);
242
+ // Load config
243
+ const configPath = opts.config || path.join(rootDir, 'atlisp-lint.json');
244
+ const config = (0, config_1.loadConfig)(fs.existsSync(configPath) ? configPath : undefined);
245
+ (0, locale_1.setLocale)(config.locale || 'zh');
246
+ // Collect files
247
+ const files = opts.staged ? collectStagedFiles(rootDir) : collectFiles(rootDir, opts, config);
248
+ if (files.length === 0) {
249
+ console.log((0, locale_1.t)('index.no_files'));
250
+ return;
251
+ }
252
+ // --fix mode: auto-fix before linting
253
+ if (opts.fix) {
254
+ for (const f of files) {
255
+ const fixes = (0, runner_1.fixFile)(f);
256
+ for (const rule of fixes) {
257
+ console.log(`${(0, locale_1.t)('summary.tag_fail')}: ${path.relative(rootDir, f)} — ${(0, locale_1.t)('index.fixed', rule)}`);
258
+ }
307
259
  }
308
- process.exit(1);
260
+ if (!opts.staged)
261
+ return;
309
262
  }
310
- return;
311
- }
312
- const files = opts.staged ? collectStagedFiles(rootDir) : collectFiles(rootDir, opts, config);
313
- if (files.length === 0) {
314
- console.log((0, locale_1.t)('index.no_files'));
315
- return;
316
- }
317
- if (opts.watch) {
318
- (0, watch_1.watchFiles)(files, { rootDir, format: opts.format === 'html' ? 'default' : opts.format, config });
319
- return;
320
- }
321
- // Load ignore patterns
322
- const ignorePatterns = (0, runner_1.parseIgnoreFile)(rootDir);
323
- // Progress callback
324
- let lastProgress = 0;
325
- const onProgress = (done, total) => {
326
- if (opts.quiet)
263
+ // Filter cached files
264
+ const filesToLint = opts.cache
265
+ ? files.filter((f) => {
266
+ const cached = (0, cache_1.isCached)(f, rootDir);
267
+ if (cached) {
268
+ console.log(`${(0, locale_1.t)('summary.tag_warn')}: ${path.relative(rootDir, f)} — ${(0, locale_1.t)('index.cached')}`);
269
+ }
270
+ return !cached;
271
+ })
272
+ : files;
273
+ if (filesToLint.length === 0) {
274
+ console.log((0, locale_1.t)('index.all_cached'));
327
275
  return;
328
- const pct = Math.round((done / total) * 100);
329
- if (pct > lastProgress) {
330
- lastProgress = pct;
331
- process.stdout.write(`\r${(0, locale_1.t)('index.progress', done, total, pct)}`);
332
- if (done >= total)
333
- process.stdout.write('\n');
334
276
  }
335
- };
336
- // --fix mode
337
- if (opts.fix) {
338
- for (const f of files) {
339
- const relForward = path.relative(rootDir, f).replace(/\\/g, '/');
340
- if (ignorePatterns.some(re => re.test(relForward)))
341
- continue;
342
- const fixes = (0, runner_1.fixFile)(f);
343
- for (const rule of fixes) {
344
- console.log(`${(0, locale_1.t)('summary.tag_fail')}: ${path.relative(rootDir, f)} — ${(0, locale_1.t)('index.fixed', rule)}`);
277
+ // Phase 1: Static checks (parallel or sequential)
278
+ const issues = opts.parallel
279
+ ? await (0, runner_1.lintFilesParallel)(filesToLint, config, rootDir)
280
+ : (0, runner_1.lintFiles)(filesToLint, config, rootDir);
281
+ // Phase 1b: Project-level cross-file checks
282
+ if (opts.project) {
283
+ const projectIssues = (0, project_1.lintProject)(filesToLint, config, rootDir);
284
+ issues.push(...projectIssues);
285
+ }
286
+ // Mark as cached
287
+ if (opts.cache) {
288
+ for (const f of filesToLint) {
289
+ (0, cache_1.markCached)(f, rootDir);
345
290
  }
346
291
  }
347
- if (!opts.staged)
348
- return;
349
- }
350
- // Phase 1: Static checks
351
- let issues;
352
- if (opts.parallel) {
353
- issues = await (0, runner_1.lintFilesParallel)(files, config, rootDir, { ignorePatterns, onProgress });
354
- }
355
- else {
356
- issues = (0, runner_1.lintFiles)(files, config, rootDir, { useCache: opts.cache, ignorePatterns, onProgress });
357
- }
358
- // Phase 2: SBCL syntax validation
359
- const stubPkgPath = path.join(__dirname, '..', 'stub-packages.json');
360
- try {
361
- const sbclIssues = (0, sbcl_1.runSbclLint)(rootDir, config.sbcl, stubPkgPath);
362
- issues.push(...sbclIssues);
363
- }
364
- catch (err) {
365
- const msg = err instanceof Error ? err.message : String(err);
366
- issues.push({
367
- file: 'sbcl', line: 1, severity: 'error', rule: 'sbcl',
368
- message: msg,
369
- });
370
- }
371
- // Build file content map for code line display
372
- const fileContents = new Map();
373
- for (const iss of issues) {
374
- if (!fileContents.has(iss.file)) {
375
- const fp = path.resolve(rootDir, iss.file);
376
- try {
377
- fileContents.set(iss.file, fs.readFileSync(fp, 'utf-8'));
292
+ // Phase 2: SBCL syntax validation
293
+ const stubPkgPath = path.join(__dirname, '..', 'stub-packages.json');
294
+ try {
295
+ const sbclIssues = (0, sbcl_1.runSbclLint)(rootDir, config.sbcl, stubPkgPath);
296
+ issues.push(...sbclIssues);
297
+ }
298
+ catch (err) {
299
+ const msg = err instanceof Error ? err.message : String(err);
300
+ issues.push({
301
+ file: 'sbcl',
302
+ line: 1,
303
+ severity: 'error',
304
+ rule: 'sbcl',
305
+ message: msg,
306
+ });
307
+ }
308
+ // Build file content map for code line display
309
+ const fileContents = new Map();
310
+ for (const iss of issues) {
311
+ if (!fileContents.has(iss.file)) {
312
+ const fp = path.resolve(rootDir, iss.file);
313
+ try {
314
+ fileContents.set(iss.file, fs.readFileSync(fp, 'utf-8'));
315
+ }
316
+ catch {
317
+ /* ignore */
318
+ }
378
319
  }
379
- catch { /* ignore */ }
380
320
  }
381
- }
382
- const outputIssues = opts.quiet ? issues.filter(i => i.severity === 'error') : issues;
383
- const errorCount = outputIssues.filter(i => i.severity === 'error').length;
384
- const warningCount = outputIssues.filter(i => i.severity === 'warn').length;
385
- // --max-warnings
386
- if (opts.maxWarnings !== undefined && warningCount > opts.maxWarnings) {
387
- console.log(`${(0, locale_1.t)('index.max_warnings')}: ${warningCount} > ${opts.maxWarnings}`);
388
- process.exit(1);
389
- }
390
- if (opts.format === 'html') {
391
- const html = (0, formatters_1.formatHtml)(outputIssues, errorCount, warningCount);
392
- if (opts.output) {
393
- fs.writeFileSync(opts.output, html, 'utf-8');
394
- console.log(`${(0, locale_1.t)('index.config_created', opts.output)}`);
321
+ // Format & output
322
+ const errorCount = issues.filter((i) => i.severity === 'error').length;
323
+ const warningCount = issues.filter((i) => i.severity === 'warn').length;
324
+ if (opts.format === 'json') {
325
+ console.log((0, formatters_1.formatJson)(issues, errorCount, warningCount));
395
326
  }
396
327
  else {
397
- console.log(html);
328
+ console.log((0, formatters_1.formatDefault)(issues, fileContents));
398
329
  }
330
+ process.exit(errorCount > 0 ? 1 : 0);
399
331
  }
400
- else if (opts.format === 'json') {
401
- console.log((0, formatters_1.formatJson)(outputIssues));
402
- }
403
- else {
404
- console.log((0, formatters_1.formatDefault)(outputIssues, fileContents));
332
+ catch (err) {
333
+ const msg = err instanceof Error ? err.message : String(err);
334
+ console.error(`Error: ${msg}`);
335
+ process.exit(1);
405
336
  }
406
- process.exit(errorCount > 0 ? 1 : 0);
407
337
  }
408
338
  if (require.main === module) {
409
339
  main();