@atlisp/lint 0.2.11 → 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 (48) hide show
  1. package/atlisp-lint.schema.json +32 -2
  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/dangling-defun.d.ts +7 -0
  7. package/dist/checks/dangling-defun.js +19 -0
  8. package/dist/checks/global-function-naming.js +159 -35
  9. package/dist/checks/missing-princ.js +2 -2
  10. package/dist/checks/nth-usage.d.ts +1 -0
  11. package/dist/checks/nth-usage.js +16 -1
  12. package/dist/checks/unused-package-dep.d.ts +1 -0
  13. package/dist/checks/unused-package-dep.js +53 -0
  14. package/dist/cli/collector.d.ts +7 -0
  15. package/dist/cli/collector.js +154 -0
  16. package/dist/cli/parser.d.ts +30 -0
  17. package/dist/cli/parser.js +119 -0
  18. package/dist/config.js +32 -6
  19. package/dist/disable.js +12 -0
  20. package/dist/fixes/index.d.ts +8 -0
  21. package/dist/fixes/index.js +200 -0
  22. package/dist/index.js +56 -236
  23. package/dist/locale.js +30 -2
  24. package/dist/presets.js +24 -0
  25. package/dist/project.js +182 -134
  26. package/dist/rules.d.ts +1 -0
  27. package/dist/rules.js +85 -0
  28. package/dist/runner.d.ts +2 -3
  29. package/dist/runner.js +46 -371
  30. package/dist/types.d.ts +6 -0
  31. package/dist/utils.d.ts +4 -0
  32. package/dist/utils.js +43 -0
  33. package/dist/validate.js +12 -0
  34. package/dist/visitor-runner.d.ts +28 -0
  35. package/dist/visitor-runner.js +115 -1
  36. package/dist/visitors/equal-nil.d.ts +8 -0
  37. package/dist/visitors/equal-nil.js +26 -0
  38. package/dist/visitors/index.d.ts +5 -0
  39. package/dist/visitors/index.js +14 -0
  40. package/dist/visitors/progn-in-cond.d.ts +8 -0
  41. package/dist/visitors/progn-in-cond.js +33 -0
  42. package/dist/visitors/redundant-and-or.d.ts +8 -0
  43. package/dist/visitors/redundant-and-or.js +27 -0
  44. package/dist/visitors/redundant-car-cdr.d.ts +8 -0
  45. package/dist/visitors/redundant-car-cdr.js +35 -0
  46. package/dist/visitors/types.d.ts +13 -0
  47. package/dist/visitors/types.js +72 -0
  48. 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": {
@@ -196,6 +209,23 @@
196
209
  "walk_exclude": { "type": "array", "items": { "type": "string" }, "default": [".vscode", "vendor", ".git"] },
197
210
  "defmacro_allow_files": { "type": "array", "items": { "type": "string" }, "default": ["compat-cl"] }
198
211
  }
212
+ },
213
+ "project_analysis": {
214
+ "type": "object",
215
+ "properties": {
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
+ }
228
+ }
199
229
  }
200
230
  }
201
231
  }
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;
@@ -6,4 +6,11 @@ export declare function checkDanglingDefun(file: string, allDefuns: Map<string,
6
6
  file: string;
7
7
  line: number;
8
8
  }[]>): Issue[];
9
+ export declare function checkDanglingDefunFromDefs(localDefuns: {
10
+ name: string;
11
+ line: number;
12
+ }[], allReferences: Map<string, {
13
+ file: string;
14
+ line: number;
15
+ }[]>, file: string): Issue[];
9
16
  //# sourceMappingURL=dangling-defun.d.ts.map
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.checkDanglingDefun = checkDanglingDefun;
37
+ exports.checkDanglingDefunFromDefs = checkDanglingDefunFromDefs;
37
38
  const locale_1 = require("../locale");
38
39
  const parser_1 = require("@atlisp/parser");
39
40
  const fs = __importStar(require("fs"));
@@ -64,4 +65,22 @@ function checkDanglingDefun(file, allDefuns, allReferences) {
64
65
  }
65
66
  return issues;
66
67
  }
68
+ function checkDanglingDefunFromDefs(localDefuns, allReferences, file) {
69
+ const issues = [];
70
+ for (const defun of localDefuns) {
71
+ const refs = allReferences.get(defun.name) || [];
72
+ const calledElsewhere = refs.some(r => r.file !== file);
73
+ const calledLocally = refs.some(r => r.file === file);
74
+ if (!calledLocally && !calledElsewhere) {
75
+ issues.push({
76
+ file,
77
+ line: defun.line,
78
+ severity: 'warn',
79
+ rule: 'dangling_defun',
80
+ message: (0, locale_1.t)('dangling_defun', defun.name),
81
+ });
82
+ }
83
+ }
84
+ return issues;
85
+ }
67
86
  //# sourceMappingURL=dangling-defun.js.map
@@ -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
@@ -1,3 +1,4 @@
1
1
  import { Issue } from '../types';
2
2
  export declare function checkUnusedPackageDep(file: string): Issue[];
3
+ export declare function checkUnusedPackageDepFromContent(file: string, content: string): Issue[];
3
4
  //# sourceMappingURL=unused-package-dep.d.ts.map
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.checkUnusedPackageDep = checkUnusedPackageDep;
37
+ exports.checkUnusedPackageDepFromContent = checkUnusedPackageDepFromContent;
37
38
  const locale_1 = require("../locale");
38
39
  const parser_1 = require("@atlisp/parser");
39
40
  const fs = __importStar(require("fs"));
@@ -90,4 +91,56 @@ function checkUnusedPackageDep(file) {
90
91
  }
91
92
  return issues;
92
93
  }
94
+ function checkUnusedPackageDepFromContent(file, content) {
95
+ const issues = [];
96
+ const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
97
+ const inPackageNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'in-package'));
98
+ if (inPackageNodes.length === 0)
99
+ return issues;
100
+ const allPackages = new Set();
101
+ for (const node of inPackageNodes) {
102
+ if (node.children && node.children.length >= 2 && (0, parser_1.astIsSymbol)(node.children[1])) {
103
+ allPackages.add(node.children[1].name);
104
+ }
105
+ }
106
+ const usedSymbols = new Set();
107
+ const allLists = (0, parser_1.astFindAll)(ast, n => n.type === 'list');
108
+ for (const node of allLists) {
109
+ if (!node.children || node.children.length === 0)
110
+ continue;
111
+ const car = node.children[0];
112
+ if (car.type === 'symbol' && car.name) {
113
+ const parts = car.name.split(':');
114
+ if (parts.length === 2 && parts[0] && parts[1]) {
115
+ usedSymbols.add(parts[0]);
116
+ }
117
+ }
118
+ for (let i = 1; i < node.children.length; i++) {
119
+ const child = node.children[i];
120
+ if (child.type === 'symbol' && child.name) {
121
+ const parts = child.name.split(':');
122
+ if (parts.length === 2 && parts[0] && parts[1]) {
123
+ usedSymbols.add(parts[0]);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ const mainPackage = inPackageNodes.length > 0 && inPackageNodes[0].children && inPackageNodes[0].children[1]
129
+ ? inPackageNodes[0].children[1].name || ''
130
+ : '';
131
+ allPackages.delete(mainPackage);
132
+ for (const pkg of allPackages) {
133
+ if (!usedSymbols.has(pkg)) {
134
+ const node = inPackageNodes.find(n => n.children && n.children.length >= 2 && (0, parser_1.astIsSymbol)(n.children[1]) && n.children[1].name === pkg);
135
+ issues.push({
136
+ file,
137
+ line: node ? node.pos.line : 1,
138
+ severity: 'warn',
139
+ rule: 'unused_package_dep',
140
+ message: (0, locale_1.t)('unused_package_dep', pkg),
141
+ });
142
+ }
143
+ }
144
+ return issues;
145
+ }
93
146
  //# sourceMappingURL=unused-package-dep.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