@atlisp/lint 0.1.16 → 0.1.19

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.
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatSarif = formatSarif;
4
+ function formatSarif(issues, errorCount, warningCount) {
5
+ const results = issues.map(iss => {
6
+ const level = iss.severity === 'error' ? 'error' : 'warning';
7
+ return {
8
+ level,
9
+ message: {
10
+ text: iss.message,
11
+ },
12
+ locations: [
13
+ {
14
+ physicalLocation: {
15
+ artifactLocation: {
16
+ uri: iss.file,
17
+ },
18
+ region: {
19
+ startLine: iss.line || 1,
20
+ },
21
+ },
22
+ },
23
+ ],
24
+ ruleId: iss.rule,
25
+ };
26
+ });
27
+ const sarif = {
28
+ $schema: 'https://json.schemastore.org/sarif-2.1.0.json',
29
+ version: '2.1.0',
30
+ runs: [
31
+ {
32
+ tool: {
33
+ driver: {
34
+ name: '@atlisp/lint',
35
+ version: '0.1.18',
36
+ informationUri: 'https://github.com/atlisp/lint',
37
+ rules: issues.map(iss => ({
38
+ id: iss.rule,
39
+ name: iss.rule,
40
+ shortDescription: { text: iss.message },
41
+ properties: { severity: iss.severity },
42
+ })),
43
+ },
44
+ },
45
+ results,
46
+ summary: {
47
+ errorCount,
48
+ warningCount,
49
+ },
50
+ },
51
+ ],
52
+ };
53
+ return JSON.stringify(sarif, null, 2);
54
+ }
55
+ //# sourceMappingURL=formatters-sarif.js.map
package/dist/index.js CHANGED
@@ -42,6 +42,8 @@ const runner_1 = require("./runner");
42
42
  const project_1 = require("./project");
43
43
  const sbcl_1 = require("./sbcl");
44
44
  const formatters_1 = require("./formatters");
45
+ const formatters_sarif_1 = require("./formatters-sarif");
46
+ const formatters_html_1 = require("./formatters-html");
45
47
  const formatter_1 = require("./formatter");
46
48
  const locale_1 = require("./locale");
47
49
  const cache_1 = require("./cache");
@@ -52,6 +54,8 @@ function parseArgs() {
52
54
  src: [],
53
55
  test: [],
54
56
  staged: false,
57
+ diff: false,
58
+ changed: '',
55
59
  format: 'default',
56
60
  init: false,
57
61
  installHook: false,
@@ -82,6 +86,12 @@ function parseArgs() {
82
86
  case '--staged':
83
87
  opts.staged = true;
84
88
  break;
89
+ case '--diff':
90
+ opts.diff = true;
91
+ break;
92
+ case '--changed':
93
+ opts.changed = argv[++i] || 'main';
94
+ break;
85
95
  case '--format':
86
96
  opts.format = argv[++i];
87
97
  break;
@@ -163,6 +173,23 @@ function* walkFiles(dir, rootDir, regex) {
163
173
  }
164
174
  }
165
175
  }
176
+ function collectChangedFiles(rootDir, baseBranch) {
177
+ try {
178
+ const output = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=ACM ${baseBranch}`, {
179
+ cwd: rootDir,
180
+ encoding: 'utf-8',
181
+ });
182
+ return output
183
+ .split('\n')
184
+ .map(l => l.trim())
185
+ .filter(l => l.endsWith('.lsp'))
186
+ .map(l => path.resolve(rootDir, l))
187
+ .filter(f => fs.existsSync(f));
188
+ }
189
+ catch {
190
+ return [];
191
+ }
192
+ }
166
193
  // Placeholder regex (dynamically constructed to avoid no-control-regex)
167
194
  const GLOB_PLACEHOLDER = '\x00GLOB\x00';
168
195
  const GLOB_RE = new RegExp(GLOB_PLACEHOLDER, 'g');
@@ -294,7 +321,13 @@ async function main() {
294
321
  return;
295
322
  }
296
323
  // Collect files
297
- const files = opts.staged ? collectStagedFiles(rootDir) : collectFiles(rootDir, opts, config);
324
+ const files = opts.staged
325
+ ? collectStagedFiles(rootDir)
326
+ : opts.diff
327
+ ? collectChangedFiles(rootDir, 'HEAD')
328
+ : opts.changed
329
+ ? collectChangedFiles(rootDir, opts.changed)
330
+ : collectFiles(rootDir, opts, config);
298
331
  if (files.length === 0) {
299
332
  console.log((0, locale_1.t)('index.no_files'));
300
333
  return;
@@ -330,7 +363,7 @@ async function main() {
330
363
  }
331
364
  // --watch mode
332
365
  if (opts.watch) {
333
- (0, watch_1.watchFiles)(files, { rootDir, format: opts.format, config });
366
+ (0, watch_1.watchFiles)(files, { rootDir, format: (opts.format === 'sarif' || opts.format === 'html' ? 'default' : opts.format), config });
334
367
  return;
335
368
  }
336
369
  // --fix mode: auto-fix before linting
@@ -478,6 +511,12 @@ async function main() {
478
511
  if (opts.format === 'json') {
479
512
  console.log((0, formatters_1.formatJson)(issues, errorCount, warningCount));
480
513
  }
514
+ else if (opts.format === 'sarif') {
515
+ console.log((0, formatters_sarif_1.formatSarif)(issues, errorCount, warningCount));
516
+ }
517
+ else if (opts.format === 'html') {
518
+ console.log((0, formatters_html_1.formatHtml)(issues, errorCount, warningCount));
519
+ }
481
520
  else {
482
521
  console.log((0, formatters_1.formatDefault)(issues, fileContents));
483
522
  }
package/dist/locale.js CHANGED
@@ -38,8 +38,6 @@ const messages = {
38
38
  unused_let_binding: "Let binding '{0}' is never used",
39
39
  recursive_call: "Function '{0}' calls itself — possible infinite recursion",
40
40
  variable_shadow: "Variable '{0}' is set with setq inside a let that binds the same name",
41
- 'redundant_cond.single': 'Single-clause {0} — simplify to (if ...)',
42
- 'redundant_cond.t_last': '{0} with T as last clause condition — use (if ...) else branch instead',
43
41
  unused_local_fun: "Local function/variable '{0}' is defined in defun with / but never used",
44
42
  multiple_setq: 'Consecutive (setq ...) forms — consider merging into a single (setq ...)',
45
43
  redundant_quotes: "Redundant double quote — ''x can be simplified to 'x",
@@ -91,6 +89,14 @@ const messages = {
91
89
  'index.watch_hint': 'Press Ctrl+C to stop',
92
90
  'index.watch_status': '{0} files checked: {1} error(s), {2} warning(s)',
93
91
  'index.format_unstable': 'Formatting is not idempotent — re-running formatCode produces different output',
92
+ unused_catch_result: 'vl-catch-all-apply result used as boolean — use vl-catch-all-error-p to check',
93
+ string_concat_loop: 'String concatenation inside {0} — move strcat outside the loop for performance',
94
+ if_without_else: 'if has no else branch and the return value is used — add nil else for clarity',
95
+ redundant_list: '(list) evaluates to nil — use nil directly',
96
+ entget_in_loop: 'entget inside loop — cache entget result before the loop for performance',
97
+ promise_handler: 'vlax-invoke/vlax-invoke-method without callback handler — results may be lost',
98
+ module_cycle: 'Module dependency cycle detected — may cause initialization issues',
99
+ arg_count_project: "Function '{0}' called with {1} arguments but defined with {2} (cross-file)",
94
100
  'help.text': `@atlisp/lint - AutoLISP static analysis tool
95
101
 
96
102
  Usage: atlisp-lint [options]
@@ -113,8 +119,10 @@ Options:
113
119
  --hook-args <args> Custom pre-commit hook arguments (with --install-hook)
114
120
  --help Show this help message
115
121
  --version Show version number
116
- --format-code Auto-format code indentation
117
- --format-check Check if files are formatted (exit 1 if not)`,
122
+ --format-code Auto-format code indentation
123
+ --format-check Check if files are formatted (exit 1 if not)
124
+ --diff Only check files changed since last commit
125
+ --changed <branch> Only check files changed against a branch (default: main)`,
118
126
  },
119
127
  zh: {
120
128
  'parens.mismatch': "括号不匹配:{0} 个 '(' vs {1} 个 ')'({2})",
@@ -150,8 +158,6 @@ Options:
150
158
  unused_let_binding: "let 绑定 '{0}' 从未被使用",
151
159
  recursive_call: "函数 '{0}' 调用了自身——可能存在无限递归",
152
160
  variable_shadow: "变量 '{0}' 在 let 绑定了相同名称后被 setq 赋值",
153
- 'redundant_cond.single': '单子句 {0} ——建议简化为 (if ...)',
154
- 'redundant_cond.t_last': '{0} 的最后一条子句条件为 T ——建议改用 (if ...) else 分支',
155
161
  unused_local_fun: "局部函数/变量 '{0}' 在 defun 的 / 后定义但从未使用",
156
162
  multiple_setq: '连续多个 (setq ...) ——建议合并为一个 (setq ...)',
157
163
  redundant_quotes: "冗余双引号 —— ''x 可以简化为 'x",
@@ -203,6 +209,14 @@ Options:
203
209
  'index.watch_hint': '按 Ctrl+C 停止',
204
210
  'index.watch_status': '已检查 {0} 个文件: {1} 个错误, {2} 个警告',
205
211
  'index.format_unstable': '格式化结果不稳定——再次格式化后输出不同',
212
+ unused_catch_result: 'vl-catch-all-apply 的结果被当作布尔值使用——应用 vl-catch-all-error-p 检查',
213
+ string_concat_loop: '循环 {0} 内使用了字符串拼接——为提升性能请将 strcat 移到循环外',
214
+ if_without_else: 'if 没有 else 分支且返回值被使用——建议添加 nil else 分支',
215
+ redundant_list: '(list) 等于 nil——请直接使用 nil',
216
+ entget_in_loop: '循环内使用了 entget——请在循环外缓存 entget 结果',
217
+ promise_handler: 'vlax-invoke/vlax-invoke-method 没有回调处理器——结果可能丢失',
218
+ module_cycle: '检测到模块循环依赖——可能导致初始化问题',
219
+ arg_count_project: "函数 '{0}' 调用时传入了 {1} 个参数,但定义为 {2} 个(跨文件)",
206
220
  'help.text': `@atlisp/lint - AutoLISP 静态分析工具
207
221
 
208
222
  用法: atlisp-lint [选项]
@@ -226,7 +240,9 @@ Options:
226
240
  --help 显示此帮助信息
227
241
  --version 显示版本号
228
242
  --format-code 自动格式化代码缩进
229
- --format-check 检查文件是否已格式化(未格式化则退出码为 1)`,
243
+ --format-check 检查文件是否已格式化(未格式化则退出码为 1
244
+ --diff 仅检查自上次提交后变更的文件
245
+ --changed <分支> 仅检查相对于某分支有变更的文件(默认:main)`,
230
246
  },
231
247
  };
232
248
  let currentLocale = 'zh';
package/dist/presets.js CHANGED
@@ -26,7 +26,6 @@ exports.PRESETS = {
26
26
  unused_let_binding: 'warn',
27
27
  recursive_call: 'warn',
28
28
  variable_shadow: 'warn',
29
- redundant_cond: 'warn',
30
29
  unused_local_fun: 'warn',
31
30
  multiple_setq: 'warn',
32
31
  redundant_quotes: 'warn',
@@ -66,6 +65,14 @@ exports.PRESETS = {
66
65
  shadow_builtin: 'warn',
67
66
  dynamic_doc: 'warn',
68
67
  redundant_if: 'warn',
68
+ unused_catch_result: 'warn',
69
+ string_concat_loop: 'warn',
70
+ if_without_else: 'warn',
71
+ redundant_list: 'warn',
72
+ entget_in_loop: 'warn',
73
+ promise_handler: 'warn',
74
+ module_cycle: 'warn',
75
+ arg_count_project: 'warn',
69
76
  },
70
77
  },
71
78
  strict: {
@@ -94,7 +101,6 @@ exports.PRESETS = {
94
101
  unused_let_binding: 'error',
95
102
  recursive_call: 'error',
96
103
  variable_shadow: 'error',
97
- redundant_cond: 'error',
98
104
  unused_local_fun: 'error',
99
105
  multiple_setq: 'warn',
100
106
  redundant_quotes: 'error',
@@ -145,6 +151,14 @@ exports.PRESETS = {
145
151
  redundant_if: 'error',
146
152
  module_registration: 'error',
147
153
  namespace_header: 'error',
154
+ unused_catch_result: 'error',
155
+ string_concat_loop: 'warn',
156
+ if_without_else: 'error',
157
+ redundant_list: 'error',
158
+ entget_in_loop: 'warn',
159
+ promise_handler: 'error',
160
+ module_cycle: 'error',
161
+ arg_count_project: 'error',
148
162
  },
149
163
  },
150
164
  relaxed: {
package/dist/project.js CHANGED
@@ -54,7 +54,7 @@ function collectDefuns(file) {
54
54
  }
55
55
  return results;
56
56
  }
57
- function collectReferences(file, _filepath) {
57
+ function collectReferences(file) {
58
58
  const content = fs.readFileSync(file, 'utf-8');
59
59
  const ast = (0, parser_1.parseAst)(content);
60
60
  const results = [];
@@ -71,6 +71,93 @@ function collectReferences(file, _filepath) {
71
71
  }
72
72
  return results;
73
73
  }
74
+ function countFunctionArgs(file) {
75
+ const content = fs.readFileSync(file, 'utf-8');
76
+ const ast = (0, parser_1.parseAst)(content);
77
+ const result = new Map();
78
+ const defunNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
79
+ for (const node of defunNodes) {
80
+ if (!node.children || node.children.length < 3)
81
+ continue;
82
+ const name = (0, parser_1.astIsSymbol)(node.children[1]) ? node.children[1].name : '';
83
+ if (!name)
84
+ continue;
85
+ const paramList = node.children[2];
86
+ if (paramList.type !== 'list' || !paramList.children) {
87
+ result.set(name, 0);
88
+ continue;
89
+ }
90
+ let count = 0;
91
+ for (const child of paramList.children) {
92
+ if (child.type === 'symbol' && child.name && child.name !== '/') {
93
+ count++;
94
+ }
95
+ else if (child.type === 'symbol' && child.name === '/') {
96
+ break;
97
+ }
98
+ }
99
+ result.set(name, count);
100
+ }
101
+ return result;
102
+ }
103
+ function countCallArgs(file) {
104
+ const content = fs.readFileSync(file, 'utf-8');
105
+ const ast = (0, parser_1.parseAst)(content);
106
+ const result = new Map();
107
+ const allCalls = (0, parser_1.astFindAll)(ast, n => {
108
+ if (n.type !== 'list' || !n.children || n.children.length === 0)
109
+ return false;
110
+ return (0, parser_1.astIsSymbol)(n.children[0]);
111
+ });
112
+ for (const call of allCalls) {
113
+ const name = call.children[0].name;
114
+ if (name === 'defun' || name === 'defun-q' || name.startsWith('c:') || name.includes(':'))
115
+ continue;
116
+ if (!result.has(name))
117
+ result.set(name, []);
118
+ const argCount = call.children ? call.children.length - 1 : 0;
119
+ result.get(name).push({ line: call.pos.line, count: argCount });
120
+ }
121
+ return result;
122
+ }
123
+ function findModuleDeps(filepath) {
124
+ const content = fs.readFileSync(filepath, 'utf-8');
125
+ const ast = (0, parser_1.parseAst)(content);
126
+ const imports = [];
127
+ const exports = [];
128
+ const inPackageNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'in-package'));
129
+ for (const node of inPackageNodes) {
130
+ if (node.children && node.children.length >= 3 && node.children[1].type === 'symbol') {
131
+ const useList = node.children[2];
132
+ if (useList.type === 'list' && useList.children) {
133
+ for (const use of useList.children) {
134
+ if (use.type === 'symbol' && use.name)
135
+ imports.push(use.name);
136
+ }
137
+ }
138
+ }
139
+ }
140
+ const setqNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'setq'));
141
+ for (const node of setqNodes) {
142
+ if (node.children && node.children.length >= 3 &&
143
+ node.children[1].type === 'symbol' && node.children[1].name === '@::*modules*' &&
144
+ node.children[2].type === 'list' && node.children[2].children) {
145
+ for (const exp of node.children[2].children) {
146
+ if (exp.type === 'string' && typeof exp.value === 'string') {
147
+ exports.push(exp.value);
148
+ }
149
+ }
150
+ }
151
+ }
152
+ return { imports, exports };
153
+ }
154
+ function collectAllModuleDeps(files) {
155
+ const deps = new Map();
156
+ for (const f of files) {
157
+ deps.set(f, findModuleDeps(f));
158
+ }
159
+ return deps;
160
+ }
74
161
  function lintProject(files, config, rootDir) {
75
162
  (0, locale_1.setLocale)(config.locale || 'zh');
76
163
  const allIssues = [];
@@ -85,6 +172,7 @@ function lintProject(files, config, rootDir) {
85
172
  continue;
86
173
  }
87
174
  }
175
+ // Build project symbol table
88
176
  for (const [filepath] of fileContents) {
89
177
  const defunList = collectDefuns(filepath);
90
178
  for (const d of defunList) {
@@ -92,17 +180,25 @@ function lintProject(files, config, rootDir) {
92
180
  list.push({ file: filepath, line: d.line });
93
181
  symbols.defuns.set(d.name, list);
94
182
  }
95
- const refList = collectReferences(filepath, filepath);
183
+ const refList = collectReferences(filepath);
96
184
  for (const r of refList) {
97
185
  const list = symbols.references.get(r.name) || [];
98
186
  list.push({ file: filepath, line: r.line });
99
187
  symbols.references.set(r.name, list);
100
188
  }
101
189
  }
190
+ // New: build module dependency graph
191
+ const moduleDeps = collectAllModuleDeps(Array.from(fileContents.keys()));
192
+ // New: collect function arg counts per file
193
+ const defunArgs = new Map();
194
+ for (const [filepath] of fileContents) {
195
+ defunArgs.set(filepath, countFunctionArgs(filepath));
196
+ }
102
197
  for (const [filepath] of fileContents) {
103
198
  const relPath = path.relative(rootDir, filepath);
104
199
  const override = findProjectOverride(filepath);
105
200
  const checks = override?.checks || config.checks;
201
+ // Existing checks
106
202
  if (checks['dangling_defun'] !== 'off') {
107
203
  const danglingIssues = (0, dangling_defun_1.checkDanglingDefun)(filepath, symbols.defuns, symbols.references);
108
204
  for (const iss of danglingIssues) {
@@ -134,6 +230,88 @@ function lintProject(files, config, rootDir) {
134
230
  allIssues.push(iss);
135
231
  }
136
232
  }
233
+ // New: module cycle detection
234
+ if (checks['module_cycle'] !== 'off') {
235
+ const visited = new Set();
236
+ const stack = new Set();
237
+ const cyclePath = [];
238
+ function dfs(current) {
239
+ if (stack.has(current)) {
240
+ const idx = cyclePath.indexOf(current);
241
+ const cycle = cyclePath.slice(idx).concat(current);
242
+ const displayCycle = cycle.map(c => path.relative(rootDir, c)).join(' → ');
243
+ allIssues.push({
244
+ file: relPath,
245
+ line: 1,
246
+ severity: 'warn',
247
+ rule: 'module_cycle',
248
+ message: `Module dependency cycle detected: ${displayCycle}`,
249
+ });
250
+ return true;
251
+ }
252
+ if (visited.has(current))
253
+ return false;
254
+ visited.add(current);
255
+ stack.add(current);
256
+ cyclePath.push(current);
257
+ const deps = moduleDeps.get(current);
258
+ if (deps) {
259
+ for (const imp of deps.imports) {
260
+ for (const [otherFile, otherDeps] of moduleDeps) {
261
+ if (otherDeps.exports.includes(imp)) {
262
+ if (dfs(otherFile))
263
+ return true;
264
+ }
265
+ }
266
+ }
267
+ }
268
+ cyclePath.pop();
269
+ stack.delete(current);
270
+ return false;
271
+ }
272
+ for (const f of moduleDeps.keys()) {
273
+ if (!visited.has(f)) {
274
+ dfs(f);
275
+ }
276
+ }
277
+ }
278
+ // New: signature mismatch check
279
+ if (checks['arg_count_project'] !== 'off') {
280
+ const fileArgs = defunArgs.get(filepath);
281
+ if (fileArgs) {
282
+ const callArgs = countCallArgs(filepath);
283
+ for (const [fnName, calls] of callArgs) {
284
+ const defs = symbols.defuns.get(fnName);
285
+ if (!defs)
286
+ continue;
287
+ const defArgCount = fileArgs.get(fnName);
288
+ if (defArgCount === undefined)
289
+ continue;
290
+ // Only check if all definitions agree
291
+ let allMatch = true;
292
+ for (const def of defs) {
293
+ const otherFileArgs = defunArgs.get(def.file);
294
+ if (otherFileArgs && otherFileArgs.get(fnName) !== defArgCount) {
295
+ allMatch = false;
296
+ break;
297
+ }
298
+ }
299
+ if (!allMatch)
300
+ continue;
301
+ for (const call of calls) {
302
+ if (call.count !== defArgCount) {
303
+ allIssues.push({
304
+ file: relPath,
305
+ line: call.line,
306
+ severity: 'warn',
307
+ rule: 'arg_count_project',
308
+ message: `Function '${fnName}' called with ${call.count} arguments but defined with ${defArgCount}`,
309
+ });
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
137
315
  }
138
316
  return allIssues;
139
317
  }
package/dist/rules.js CHANGED
@@ -156,7 +156,6 @@ exports.RULES = [
156
156
  description: '检测函数调用自身(可能无限递归)',
157
157
  category: '正确性',
158
158
  },
159
- { name: 'redundant_cond', defaultSeverity: 'warn', description: '检测单子句 cond 或末尾 T 子句', category: '风格' },
160
159
  { name: 'redundant_if', defaultSeverity: 'warn', description: '检测 if/when 分支中冗余 progn', category: '风格' },
161
160
  { name: 'redundant_let', defaultSeverity: 'warn', description: '检测无绑定的 let 建议改用 progn', category: '风格' },
162
161
  { name: 'redundant_nil_else', defaultSeverity: 'warn', description: '检测 if 中冗余的 nil 分支', category: '风格' },
@@ -229,6 +228,14 @@ exports.RULES = [
229
228
  description: '检测 vlax-* 使用前未调用 vl-load-com',
230
229
  category: '最佳实践',
231
230
  },
231
+ { name: 'unused_catch_result', defaultSeverity: 'warn', description: '检测 vl-catch-all-apply 结果被当布尔值用', category: '正确性' },
232
+ { name: 'string_concat_loop', defaultSeverity: 'warn', description: '检测循环内字符串拼接', category: '性能' },
233
+ { name: 'if_without_else', defaultSeverity: 'warn', description: '检测 if 无 else 分支且返回值被使用', category: '正确性' },
234
+ { name: 'redundant_list', defaultSeverity: 'warn', description: '检测 (list) 等价于 nil', category: '风格' },
235
+ { name: 'entget_in_loop', defaultSeverity: 'warn', description: '检测循环内 entget', category: '性能' },
236
+ { name: 'promise_handler', defaultSeverity: 'warn', description: '检测 vlax-invoke 缺少回调处理器', category: '最佳实践' },
237
+ { name: 'module_cycle', defaultSeverity: 'warn', description: '检测模块循环依赖', category: '架构' },
238
+ { name: 'arg_count_project', defaultSeverity: 'warn', description: '跨文件检查函数参数数量', category: '正确性' },
232
239
  ];
233
240
  function generateRulesMarkdown() {
234
241
  const lines = [
package/dist/runner.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Issue, LintConfig } from './types';
2
2
  export declare function runChecks(content: string, file: string, config: LintConfig): Issue[];
3
- /** Single-pass visitor-based runChecks using AstVisitor */
4
- export declare function runChecksWithVisitor(content: string, file: string, config: LintConfig): Issue[];
3
+ export declare function runChecksWithVisitorWrapper(content: string, file: string, config: LintConfig): Issue[];
5
4
  export declare function lintFiles(files: string[], config: LintConfig, rootDir: string): Issue[];
6
5
  export declare function lintFilesParallel(files: string[], config: LintConfig, rootDir: string): Promise<Issue[]>;
7
6
  export declare function applyFixes(issues: Issue[], content: string, filepath: string): string;