@atlisp/lint 0.2.12 → 0.2.13

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 (44) hide show
  1. package/atlisp-lint.schema.json +27 -4
  2. package/dist/cache.js +19 -9
  3. package/dist/checks/builtin-arg-count.d.ts +1 -0
  4. package/dist/checks/builtin-arg-count.js +5 -0
  5. package/dist/checks/dangerous-calls.js +1 -0
  6. package/dist/checks/global-function-naming.js +159 -35
  7. package/dist/checks/missing-princ.js +2 -2
  8. package/dist/checks/nth-usage.d.ts +1 -0
  9. package/dist/checks/nth-usage.js +16 -1
  10. package/dist/cli/collector.d.ts +7 -0
  11. package/dist/cli/collector.js +154 -0
  12. package/dist/cli/parser.d.ts +30 -0
  13. package/dist/cli/parser.js +119 -0
  14. package/dist/config.js +28 -6
  15. package/dist/disable.js +12 -0
  16. package/dist/fixes/index.d.ts +8 -0
  17. package/dist/fixes/index.js +200 -0
  18. package/dist/index.js +56 -236
  19. package/dist/locale.js +30 -2
  20. package/dist/presets.js +24 -0
  21. package/dist/project.js +64 -34
  22. package/dist/rules.d.ts +1 -0
  23. package/dist/rules.js +85 -0
  24. package/dist/runner.d.ts +2 -3
  25. package/dist/runner.js +46 -371
  26. package/dist/types.d.ts +1 -0
  27. package/dist/utils.d.ts +4 -0
  28. package/dist/utils.js +43 -0
  29. package/dist/validate.js +12 -0
  30. package/dist/visitor-runner.d.ts +28 -0
  31. package/dist/visitor-runner.js +115 -1
  32. package/dist/visitors/equal-nil.d.ts +8 -0
  33. package/dist/visitors/equal-nil.js +26 -0
  34. package/dist/visitors/index.d.ts +5 -0
  35. package/dist/visitors/index.js +14 -0
  36. package/dist/visitors/progn-in-cond.d.ts +8 -0
  37. package/dist/visitors/progn-in-cond.js +33 -0
  38. package/dist/visitors/redundant-and-or.d.ts +8 -0
  39. package/dist/visitors/redundant-and-or.js +27 -0
  40. package/dist/visitors/redundant-car-cdr.d.ts +8 -0
  41. package/dist/visitors/redundant-car-cdr.js +35 -0
  42. package/dist/visitors/types.d.ts +13 -0
  43. package/dist/visitors/types.js +72 -0
  44. package/package.json +1 -1
@@ -51,6 +51,7 @@
51
51
  "command_shell": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
52
52
  "comment_style": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
53
53
  "commented_code": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
54
+ "command_s": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
54
55
  "cond_duplicate": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
55
56
  "cond_simplify": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
56
57
  "constant_condition": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
@@ -59,9 +60,11 @@
59
60
  "duplicate_defun": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
60
61
  "dynamic_doc": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
61
62
  "empty_branch": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
63
+ "empty_branch_cond": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
62
64
  "empty_catch": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
63
65
  "empty_comment": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
64
66
  "encoding": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
67
+ "equal_nil": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
65
68
  "entget_in_loop": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
66
69
  "eq_usage": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
67
70
  "error_handling": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
@@ -69,9 +72,11 @@
69
72
  "format_indent": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
70
73
  "function_complexity": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
71
74
  "function_order": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
75
+ "function_reference": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
72
76
  "global_function_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
73
77
  "global_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
74
78
  "identical_branches": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
79
+ "if_progn_both": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
75
80
  "if_without_else": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
76
81
  "lambda_syntax": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
77
82
  "line_length": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
@@ -92,11 +97,16 @@
92
97
  "open_without_close": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
93
98
  "parameter_naming": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
94
99
  "parens": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
100
+ "progn_in_body": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
101
+ "progn_in_cond": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
95
102
  "promise_handler": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
96
103
  "quit_exit": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
97
104
  "quote_style": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
98
105
  "quote_vs_function": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
99
106
  "recursive_call": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
107
+ "redundant_and_or": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
108
+ "redundant_car_cdr": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
109
+ "redundant_cond": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
100
110
  "redundant_entmake": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
101
111
  "redundant_if": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
102
112
  "redundant_let": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
@@ -105,6 +115,7 @@
105
115
  "redundant_progn": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
106
116
  "redundant_quotes": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" },
107
117
  "redundant_setq": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
118
+ "selection_set_leak": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
108
119
  "self_compare": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
109
120
  "setq_multiple": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
110
121
  "setq_single_arg": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
@@ -127,7 +138,8 @@
127
138
  "variable_shadow": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
128
139
  "vl_registry_write": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
129
140
  "vlax_without_loading": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "off" },
130
- "while_constant": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" }
141
+ "while_constant": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
142
+ "zerop_usage": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "info" }
131
143
  },
132
144
  "additionalProperties": false
133
145
  },
@@ -163,7 +175,8 @@
163
175
  "exit": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "error" },
164
176
  "command_shell": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
165
177
  "startapp": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
166
- "vl_registry_write": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" }
178
+ "vl_registry_write": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" },
179
+ "eval": { "type": "string", "enum": ["off", "info", "warn", "error"], "default": "warn" }
167
180
  }
168
181
  },
169
182
  "module_registration": {
@@ -200,8 +213,18 @@
200
213
  "project_analysis": {
201
214
  "type": "object",
202
215
  "properties": {
203
- "maxFiles": { "type": "integer", "minimum": 1, "default": 500, "description": "Maximum number of files for cross-file analysis. Exceeding this threshold skips project analysis." },
204
- "batchSize": { "type": "integer", "minimum": 1, "default": 50, "description": "Files processed per batch (reserved for future streaming)" }
216
+ "maxFiles": {
217
+ "type": "integer",
218
+ "minimum": 1,
219
+ "default": 500,
220
+ "description": "Maximum number of files for cross-file analysis. Exceeding this threshold skips project analysis."
221
+ },
222
+ "batchSize": {
223
+ "type": "integer",
224
+ "minimum": 1,
225
+ "default": 50,
226
+ "description": "Files processed per batch (reserved for future streaming)"
227
+ }
205
228
  }
206
229
  }
207
230
  }
package/dist/cache.js CHANGED
@@ -43,26 +43,36 @@ const CACHE_DIR = '.atlisp-lint-cache';
43
43
  function getCacheDir(rootDir) {
44
44
  return path.join(rootDir, CACHE_DIR);
45
45
  }
46
- function fileHash(content) {
47
- return crypto.createHash('md5').update(content).digest('hex');
46
+ function contentKey(content) {
47
+ return 'hash-' + crypto.createHash('md5').update(content).digest('hex');
48
+ }
49
+ function statKey(filepath) {
50
+ try {
51
+ const stat = fs.statSync(filepath);
52
+ return `mtime-${stat.mtimeMs}-${stat.size}`;
53
+ }
54
+ catch {
55
+ return null;
56
+ }
48
57
  }
49
58
  function isCached(filepath, rootDir, content) {
50
59
  const cacheDir = getCacheDir(rootDir);
51
60
  if (!fs.existsSync(cacheDir))
52
61
  return false;
53
- const src = content !== undefined ? content : fs.readFileSync(filepath, 'utf-8');
54
- const hash = fileHash(src);
55
- const cacheFile = path.join(cacheDir, hash);
56
- return fs.existsSync(cacheFile);
62
+ const key = content !== undefined ? contentKey(content) : statKey(filepath);
63
+ if (!key)
64
+ return false;
65
+ return fs.existsSync(path.join(cacheDir, key));
57
66
  }
58
67
  function markCached(filepath, rootDir, content) {
59
68
  const cacheDir = getCacheDir(rootDir);
60
69
  if (!fs.existsSync(cacheDir)) {
61
70
  fs.mkdirSync(cacheDir, { recursive: true });
62
71
  }
63
- const src = content !== undefined ? content : fs.readFileSync(filepath, 'utf-8');
64
- const hash = fileHash(src);
65
- const cacheFile = path.join(cacheDir, hash);
72
+ const key = content !== undefined ? contentKey(content) : statKey(filepath);
73
+ if (!key)
74
+ return;
75
+ const cacheFile = path.join(cacheDir, key);
66
76
  fs.writeFileSync(cacheFile, '');
67
77
  }
68
78
  function clearCache(rootDir) {
@@ -1,3 +1,4 @@
1
1
  import { Issue } from '../types';
2
+ export declare const BUILTIN_FUNCTIONS: Set<string>;
2
3
  export declare function checkBuiltinArgCount(content: string, file: string): Issue[];
3
4
  //# sourceMappingURL=builtin-arg-count.d.ts.map
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUILTIN_FUNCTIONS = void 0;
3
4
  exports.checkBuiltinArgCount = checkBuiltinArgCount;
4
5
  const locale_1 = require("../locale");
5
6
  const parser_1 = require("@atlisp/parser");
7
+ exports.BUILTIN_FUNCTIONS = new Set();
6
8
  const BUILTIN_ARITY = {
7
9
  // === Special forms & control flow ===
8
10
  if: { min: 2, max: 3 },
@@ -234,6 +236,9 @@ const BUILTIN_ARITY = {
234
236
  trace: { min: 1, max: 1 },
235
237
  untrace: { min: 1, max: 1 },
236
238
  };
239
+ for (const key of Object.keys(BUILTIN_ARITY)) {
240
+ exports.BUILTIN_FUNCTIONS.add(key);
241
+ }
237
242
  function checkBuiltinArgCount(content, file) {
238
243
  const issues = [];
239
244
  const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
@@ -15,6 +15,7 @@ const PATTERNS = [
15
15
  functionCall: true,
16
16
  },
17
17
  { rule: 'command_shell', key: 'command_shell', messageKey: 'dangerous.command_shell', commandShell: true },
18
+ { rule: 'eval', key: 'eval', messageKey: 'dangerous.eval', functionCall: true },
18
19
  ];
19
20
  function isInQuote(node) {
20
21
  let cur = node.parent;
@@ -4,41 +4,165 @@ exports.checkGlobalFunctionNaming = checkGlobalFunctionNaming;
4
4
  const locale_1 = require("../locale");
5
5
  const utils_1 = require("../utils");
6
6
  const BUILTIN_FUNCTIONS = new Set([
7
- 'if', 'cond', 'when', 'unless', 'progn', 'setq', 'setq-e', 'while', 'repeat',
8
- 'foreach', 'lambda', 'function', 'quote', 'defun', 'defun-q', 'defmacro',
9
- 'let', 'let*', 'mapcar', 'apply', 'eval', 'load', 'require',
10
- 'car', 'cdr', 'cadr', 'cdar', 'caar', 'cddr', 'caddr', 'cadar',
11
- 'cons', 'list', 'append', 'reverse', 'nth', 'assoc', 'subst', 'member',
12
- 'length', 'numberp', 'stringp', 'listp', 'atom', 'null', 'not',
13
- 'eq', 'equal', '=', '/=', '<', '>', '<=', '>=',
14
- '+', '-', '*', '/', '1+', '1-', 'abs', 'min', 'max',
15
- 'strcat', 'substr', 'strlen', 'strcase',
16
- 'itoa', 'atoi', 'rtos', 'atof', 'fix', 'float',
17
- 'princ', 'print', 'prin1', 'prompt', 'terpri',
18
- 'open', 'close', 'read-line', 'write-line', 'read-char', 'write-char',
19
- 'entmake', 'entmakex', 'entget', 'entmod', 'entdel', 'entlast', 'entnext',
20
- 'ssget', 'ssadd', 'ssdel', 'sslength', 'ssname', 'ssmemb',
21
- 'command', 'vl-cmdf', 'vlax-invoke', 'vlax-invoke-method',
22
- 'vlax-get', 'vlax-put', 'vlax-get-property', 'vlax-put-property',
23
- 'vlax-make-variant', 'vlax-variant-value',
24
- 'vlax-safearray', 'vlax-safearray-fill', 'vlax-safearray->list',
25
- 'vl-catch-all-apply', 'vl-catch-all-error-p', 'vl-catch-all-error-message',
26
- 'vl-load-com', 'vlax-dump-object', 'vlax-for',
27
- 'vl-registry-read', 'vl-registry-write', 'vl-registry-delete',
28
- 'vl-file-copy', 'vl-file-delete', 'vl-file-rename',
29
- 'vl-directory-files', 'vl-mkdir', 'vl-string->list', 'vl-list->string',
30
- 'vl-string-search', 'vl-string-subst',
31
- 'vl-string-position', 'vl-string-mismatch',
32
- 'vl-symbol-value', 'vl-symbol-name',
33
- 'vl-sort', 'vl-sort-i',
34
- 'vl-remove-if', 'vl-remove-if-not', 'vl-member-if', 'vl-some', 'vl-every',
35
- 'vl-position', 'vl-consp',
36
- 'startapp', 'quit', 'exit', '*error*',
37
- 'vla-get-', 'vla-put-', 'vlax-ename->vla-object', 'vlax-vla-object->ename',
38
- 'vlax-3d-point', 'vlax-tmatrix',
39
- 'vlax-curve-getarea', 'vlax-curve-getdistatparam', 'vlax-curve-getparamatdist',
40
- 'vlax-curve-getclosestpointto', 'vlax-curve-getstartpoint', 'vlax-curve-getendpoint',
41
- 'vlax-curve-getpointatdist', 'vlax-curve-getpointatparam',
7
+ 'if',
8
+ 'cond',
9
+ 'when',
10
+ 'unless',
11
+ 'progn',
12
+ 'setq',
13
+ 'setq-e',
14
+ 'while',
15
+ 'repeat',
16
+ 'foreach',
17
+ 'lambda',
18
+ 'function',
19
+ 'quote',
20
+ 'defun',
21
+ 'defun-q',
22
+ 'defmacro',
23
+ 'let',
24
+ 'let*',
25
+ 'mapcar',
26
+ 'apply',
27
+ 'eval',
28
+ 'load',
29
+ 'require',
30
+ 'car',
31
+ 'cdr',
32
+ 'cadr',
33
+ 'cdar',
34
+ 'caar',
35
+ 'cddr',
36
+ 'caddr',
37
+ 'cadar',
38
+ 'cons',
39
+ 'list',
40
+ 'append',
41
+ 'reverse',
42
+ 'nth',
43
+ 'assoc',
44
+ 'subst',
45
+ 'member',
46
+ 'length',
47
+ 'numberp',
48
+ 'stringp',
49
+ 'listp',
50
+ 'atom',
51
+ 'null',
52
+ 'not',
53
+ 'eq',
54
+ 'equal',
55
+ '=',
56
+ '/=',
57
+ '<',
58
+ '>',
59
+ '<=',
60
+ '>=',
61
+ '+',
62
+ '-',
63
+ '*',
64
+ '/',
65
+ '1+',
66
+ '1-',
67
+ 'abs',
68
+ 'min',
69
+ 'max',
70
+ 'strcat',
71
+ 'substr',
72
+ 'strlen',
73
+ 'strcase',
74
+ 'itoa',
75
+ 'atoi',
76
+ 'rtos',
77
+ 'atof',
78
+ 'fix',
79
+ 'float',
80
+ 'princ',
81
+ 'print',
82
+ 'prin1',
83
+ 'prompt',
84
+ 'terpri',
85
+ 'open',
86
+ 'close',
87
+ 'read-line',
88
+ 'write-line',
89
+ 'read-char',
90
+ 'write-char',
91
+ 'entmake',
92
+ 'entmakex',
93
+ 'entget',
94
+ 'entmod',
95
+ 'entdel',
96
+ 'entlast',
97
+ 'entnext',
98
+ 'ssget',
99
+ 'ssadd',
100
+ 'ssdel',
101
+ 'sslength',
102
+ 'ssname',
103
+ 'ssmemb',
104
+ 'command',
105
+ 'vl-cmdf',
106
+ 'vlax-invoke',
107
+ 'vlax-invoke-method',
108
+ 'vlax-get',
109
+ 'vlax-put',
110
+ 'vlax-get-property',
111
+ 'vlax-put-property',
112
+ 'vlax-make-variant',
113
+ 'vlax-variant-value',
114
+ 'vlax-safearray',
115
+ 'vlax-safearray-fill',
116
+ 'vlax-safearray->list',
117
+ 'vl-catch-all-apply',
118
+ 'vl-catch-all-error-p',
119
+ 'vl-catch-all-error-message',
120
+ 'vl-load-com',
121
+ 'vlax-dump-object',
122
+ 'vlax-for',
123
+ 'vl-registry-read',
124
+ 'vl-registry-write',
125
+ 'vl-registry-delete',
126
+ 'vl-file-copy',
127
+ 'vl-file-delete',
128
+ 'vl-file-rename',
129
+ 'vl-directory-files',
130
+ 'vl-mkdir',
131
+ 'vl-string->list',
132
+ 'vl-list->string',
133
+ 'vl-string-search',
134
+ 'vl-string-subst',
135
+ 'vl-string-position',
136
+ 'vl-string-mismatch',
137
+ 'vl-symbol-value',
138
+ 'vl-symbol-name',
139
+ 'vl-sort',
140
+ 'vl-sort-i',
141
+ 'vl-remove-if',
142
+ 'vl-remove-if-not',
143
+ 'vl-member-if',
144
+ 'vl-some',
145
+ 'vl-every',
146
+ 'vl-position',
147
+ 'vl-consp',
148
+ 'startapp',
149
+ 'quit',
150
+ 'exit',
151
+ '*error*',
152
+ 'vla-get-',
153
+ 'vla-put-',
154
+ 'vlax-ename->vla-object',
155
+ 'vlax-vla-object->ename',
156
+ 'vlax-3d-point',
157
+ 'vlax-tmatrix',
158
+ 'vlax-curve-getarea',
159
+ 'vlax-curve-getdistatparam',
160
+ 'vlax-curve-getparamatdist',
161
+ 'vlax-curve-getclosestpointto',
162
+ 'vlax-curve-getstartpoint',
163
+ 'vlax-curve-getendpoint',
164
+ 'vlax-curve-getpointatdist',
165
+ 'vlax-curve-getpointatparam',
42
166
  ]);
43
167
  function checkGlobalFunctionNaming(content, file) {
44
168
  const issues = [];
@@ -26,11 +26,11 @@ function checkMissingPrinc(content, file) {
26
26
  if (body.length === 0)
27
27
  continue;
28
28
  const lastForm = body[body.length - 1];
29
- const isPrincCall = (lastForm.type === 'list' &&
29
+ const isPrincCall = lastForm.type === 'list' &&
30
30
  lastForm.children &&
31
31
  lastForm.children.length > 0 &&
32
32
  (0, parser_1.astIsSymbol)(lastForm.children[0]) &&
33
- ['princ', 'print', 'prin1'].includes(lastForm.children[0].name || ''));
33
+ ['princ', 'print', 'prin1'].includes(lastForm.children[0].name || '');
34
34
  if (!isPrincCall) {
35
35
  issues.push({
36
36
  file,
@@ -1,3 +1,4 @@
1
1
  import { Issue } from '../types';
2
2
  export declare function checkNthUsage(content: string, file: string): Issue[];
3
+ export declare function replaceNthUsage(line: string): string | null;
3
4
  //# sourceMappingURL=nth-usage.d.ts.map
@@ -1,17 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkNthUsage = checkNthUsage;
4
+ exports.replaceNthUsage = replaceNthUsage;
4
5
  const locale_1 = require("../locale");
5
6
  const utils_1 = require("../utils");
7
+ const NTH_RE = /\(nth\s+(\d+)\b/;
8
+ const REPLACEMENTS = {
9
+ '0': 'car',
10
+ '1': 'cadr',
11
+ '2': 'caddr',
12
+ '3': 'cadddr',
13
+ };
6
14
  function checkNthUsage(content, file) {
7
15
  const issues = [];
8
16
  const lines = content.split('\n');
9
17
  for (let i = 0; i < lines.length; i++) {
10
18
  const stripped = (0, utils_1.stripLine)(lines[i]);
11
- if (/\(nth\s+0\b/.test(stripped)) {
19
+ const m = stripped.match(NTH_RE);
20
+ if (m && REPLACEMENTS[m[1]]) {
12
21
  issues.push({ file, line: i + 1, severity: 'warn', rule: 'nth_usage', message: (0, locale_1.t)('nth_usage') });
13
22
  }
14
23
  }
15
24
  return issues;
16
25
  }
26
+ function replaceNthUsage(line) {
27
+ return line.replace(NTH_RE, (_, idx) => {
28
+ const replacement = REPLACEMENTS[idx];
29
+ return replacement ? `(${replacement} ` : `(nth ${idx} `;
30
+ });
31
+ }
17
32
  //# sourceMappingURL=nth-usage.js.map
@@ -0,0 +1,7 @@
1
+ import { LintConfig } from '../types';
2
+ import { CliOptions } from './parser';
3
+ declare function collectChangedFiles(rootDir: string, baseBranch: string): string[];
4
+ export declare function collectFiles(rootDir: string, opts: CliOptions, config: LintConfig): string[];
5
+ export declare function collectStagedFiles(rootDir: string): string[];
6
+ export { collectChangedFiles };
7
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1,154 @@
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.collectFiles = collectFiles;
37
+ exports.collectStagedFiles = collectStagedFiles;
38
+ exports.collectChangedFiles = collectChangedFiles;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const child_process_1 = require("child_process");
42
+ const GLOB_PLACEHOLDER = '\x00GLOB\x00';
43
+ const GLOB_RE = new RegExp(GLOB_PLACEHOLDER, 'g');
44
+ function* walkFiles(dir, rootDir, regex) {
45
+ let entries;
46
+ try {
47
+ entries = fs.readdirSync(dir);
48
+ }
49
+ catch {
50
+ return;
51
+ }
52
+ for (const entry of entries) {
53
+ const fullPath = path.join(dir, entry);
54
+ let stat;
55
+ try {
56
+ stat = fs.statSync(fullPath);
57
+ }
58
+ catch {
59
+ continue;
60
+ }
61
+ const rel = path.relative(rootDir, fullPath).replace(/\\/g, '/');
62
+ if (rel.startsWith('..'))
63
+ continue;
64
+ if (stat.isDirectory()) {
65
+ yield* walkFiles(fullPath, rootDir, regex);
66
+ }
67
+ else if (stat.isFile()) {
68
+ if (regex.test(rel))
69
+ yield fullPath;
70
+ }
71
+ }
72
+ }
73
+ function collectChangedFiles(rootDir, baseBranch) {
74
+ try {
75
+ const output = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=ACM ${baseBranch}`, {
76
+ cwd: rootDir,
77
+ encoding: 'utf-8',
78
+ });
79
+ return output
80
+ .split('\n')
81
+ .map(l => l.trim())
82
+ .filter(l => l.endsWith('.lsp'))
83
+ .map(l => path.resolve(rootDir, l))
84
+ .filter(f => fs.existsSync(f));
85
+ }
86
+ catch {
87
+ return [];
88
+ }
89
+ }
90
+ function globFiles(pattern, rootDir) {
91
+ const regexStr = pattern
92
+ .replace(/\./g, '\\.')
93
+ .replace(/\*\*\//g, GLOB_PLACEHOLDER)
94
+ .replace(/\*\*/g, '.*')
95
+ .replace(/\*/g, '[^/]*')
96
+ .replace(/\?/g, '.')
97
+ .replace(GLOB_RE, '(.*/)?');
98
+ const regex = new RegExp(`^${regexStr}$`);
99
+ return Array.from(walkFiles(rootDir, rootDir, regex));
100
+ }
101
+ function collectFiles(rootDir, opts, config) {
102
+ const files = new Set();
103
+ if (opts.src.length > 0 || opts.test.length > 0) {
104
+ for (const d of opts.src) {
105
+ for (const f of globFiles('**/*.lsp', path.resolve(rootDir, d))) {
106
+ files.add(f);
107
+ }
108
+ }
109
+ for (const d of opts.test) {
110
+ for (const f of globFiles('**/*.lsp', path.resolve(rootDir, d))) {
111
+ files.add(f);
112
+ }
113
+ }
114
+ }
115
+ else {
116
+ for (const pattern of config.source.globs) {
117
+ for (const f of globFiles(pattern, rootDir)) {
118
+ files.add(f);
119
+ }
120
+ }
121
+ }
122
+ const excludePatterns = config.source.exclude.map(e => {
123
+ const str = e
124
+ .replace(/\./g, '\\.')
125
+ .replace(/\*\*\//g, GLOB_PLACEHOLDER)
126
+ .replace(/\*\*/g, '.*')
127
+ .replace(/\*/g, '[^/]*')
128
+ .replace(GLOB_RE, '(.*/)?');
129
+ return new RegExp(`^${str}$`);
130
+ });
131
+ return Array.from(files)
132
+ .filter(f => {
133
+ const rel = path.relative(rootDir, f).replace(/\\/g, '/');
134
+ for (const re of excludePatterns) {
135
+ if (re.test(rel))
136
+ return false;
137
+ }
138
+ return true;
139
+ })
140
+ .sort();
141
+ }
142
+ function collectStagedFiles(rootDir) {
143
+ const output = (0, child_process_1.execSync)('git diff --cached --name-only --diff-filter=ACM', {
144
+ cwd: rootDir,
145
+ encoding: 'utf-8',
146
+ });
147
+ return output
148
+ .split('\n')
149
+ .map(l => l.trim())
150
+ .filter(l => l.endsWith('.lsp'))
151
+ .map(l => path.resolve(rootDir, l))
152
+ .filter(f => fs.existsSync(f));
153
+ }
154
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1,30 @@
1
+ export interface CliOptions {
2
+ src: string[];
3
+ test: string[];
4
+ config?: string;
5
+ staged: boolean;
6
+ diff: boolean;
7
+ changed: string;
8
+ format: 'default' | 'json' | 'sarif' | 'html';
9
+ init: boolean;
10
+ installHook: boolean;
11
+ fix: boolean;
12
+ hookArgs: string;
13
+ cache: boolean;
14
+ clearCache: boolean;
15
+ parallel: boolean;
16
+ project: boolean;
17
+ watch: boolean;
18
+ help: boolean;
19
+ version: boolean;
20
+ formatCode: boolean;
21
+ formatCheck: boolean;
22
+ sbcl: boolean;
23
+ docs: boolean;
24
+ listRules: boolean;
25
+ explain: string;
26
+ dryRun: boolean;
27
+ maxWarnings: number;
28
+ }
29
+ export declare function parseArgs(): CliOptions;
30
+ //# sourceMappingURL=parser.d.ts.map