@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
package/dist/project.js CHANGED
@@ -41,10 +41,11 @@ const dangling_defun_1 = require("./checks/dangling-defun");
41
41
  const missing_export_1 = require("./checks/missing-export");
42
42
  const unused_package_dep_1 = require("./checks/unused-package-dep");
43
43
  const duplicate_defun_1 = require("./checks/duplicate-defun");
44
+ const builtin_arg_count_1 = require("./checks/builtin-arg-count");
45
+ const config_1 = require("./config");
44
46
  const locale_1 = require("./locale");
45
- function collectDefuns(file) {
46
- const content = fs.readFileSync(file, 'utf-8');
47
- const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
47
+ const locale_2 = require("./locale");
48
+ function collectDefunsFromAst(ast) {
48
49
  const results = [];
49
50
  const defunNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
50
51
  for (const node of defunNodes) {
@@ -54,9 +55,7 @@ function collectDefuns(file) {
54
55
  }
55
56
  return results;
56
57
  }
57
- function collectReferences(file) {
58
- const content = fs.readFileSync(file, 'utf-8');
59
- const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
58
+ function collectReferencesFromAst(ast) {
60
59
  const results = [];
61
60
  const allCalls = (0, parser_1.astFindAll)(ast, n => {
62
61
  if (n.type !== 'list' || !n.children || n.children.length === 0)
@@ -71,9 +70,7 @@ function collectReferences(file) {
71
70
  }
72
71
  return results;
73
72
  }
74
- function countFunctionArgs(file) {
75
- const content = fs.readFileSync(file, 'utf-8');
76
- const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
73
+ function countFunctionArgsFromAst(ast) {
77
74
  const result = new Map();
78
75
  const defunNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'defun') || (0, parser_1.astIsList)(n, 'defun-q'));
79
76
  for (const node of defunNodes) {
@@ -100,9 +97,7 @@ function countFunctionArgs(file) {
100
97
  }
101
98
  return result;
102
99
  }
103
- function countCallArgs(file) {
104
- const content = fs.readFileSync(file, 'utf-8');
105
- const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
100
+ function countCallArgsFromAst(ast) {
106
101
  const result = new Map();
107
102
  const allCalls = (0, parser_1.astFindAll)(ast, n => {
108
103
  if (n.type !== 'list' || !n.children || n.children.length === 0)
@@ -120,9 +115,7 @@ function countCallArgs(file) {
120
115
  }
121
116
  return result;
122
117
  }
123
- function findModuleDeps(filepath) {
124
- const content = fs.readFileSync(filepath, 'utf-8');
125
- const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
118
+ function findModuleDepsFromAst(ast) {
126
119
  const imports = [];
127
120
  const exports = [];
128
121
  const inPackageNodes = (0, parser_1.astFindAll)(ast, n => (0, parser_1.astIsList)(n, 'in-package'));
@@ -154,56 +147,167 @@ function findModuleDeps(filepath) {
154
147
  }
155
148
  return { imports, exports };
156
149
  }
157
- function collectAllModuleDeps(files) {
158
- const deps = new Map();
159
- for (const f of files) {
160
- deps.set(f, findModuleDeps(f));
150
+ function checkArgCountProject(filepath, defunArgs, callArgCounts, symbols, relPath) {
151
+ const issues = [];
152
+ const fileArgs = defunArgs.get(filepath);
153
+ if (!fileArgs)
154
+ return issues;
155
+ const callArgs = callArgCounts.get(filepath);
156
+ if (!callArgs)
157
+ return issues;
158
+ for (const [fnName, calls] of callArgs) {
159
+ const defs = symbols.defuns.get(fnName);
160
+ if (!defs)
161
+ continue;
162
+ const defArgCount = fileArgs.get(fnName);
163
+ if (defArgCount === undefined)
164
+ continue;
165
+ let allMatch = true;
166
+ for (const def of defs) {
167
+ const otherFileArgs = defunArgs.get(def.file);
168
+ if (otherFileArgs && otherFileArgs.get(fnName) !== defArgCount) {
169
+ allMatch = false;
170
+ break;
171
+ }
172
+ }
173
+ if (!allMatch)
174
+ continue;
175
+ for (const call of calls) {
176
+ if (call.count !== defArgCount) {
177
+ issues.push({
178
+ file: relPath,
179
+ line: call.line,
180
+ severity: 'warn',
181
+ rule: 'arg_count_project',
182
+ message: (0, locale_2.t)('arg_count_project', fnName, String(call.count), String(defArgCount)),
183
+ });
184
+ }
185
+ }
186
+ }
187
+ return issues;
188
+ }
189
+ function checkModuleCycle(moduleDeps, rootDir, allIssues) {
190
+ const visited = new Set();
191
+ const stack = new Set();
192
+ const cyclePath = [];
193
+ const exportIndex = new Map();
194
+ for (const [f, deps] of moduleDeps) {
195
+ for (const exp of deps.exports) {
196
+ const list = exportIndex.get(exp) || [];
197
+ list.push(f);
198
+ exportIndex.set(exp, list);
199
+ }
200
+ }
201
+ const dfs = (current) => {
202
+ if (stack.has(current)) {
203
+ const idx = cyclePath.indexOf(current);
204
+ const cycle = cyclePath.slice(idx).concat(current);
205
+ for (const f of cycle) {
206
+ const override = (0, config_1.findOverrides)(f);
207
+ const checks = override?.checks || {};
208
+ if (checks['module_cycle'] === 'off')
209
+ return false;
210
+ }
211
+ const displayCycle = cycle.map(c => path.relative(rootDir, c)).join(' → ');
212
+ allIssues.push({
213
+ file: path.relative(rootDir, current),
214
+ line: 1,
215
+ severity: 'warn',
216
+ rule: 'module_cycle',
217
+ message: `Module dependency cycle detected: ${displayCycle}`,
218
+ });
219
+ return true;
220
+ }
221
+ if (visited.has(current))
222
+ return false;
223
+ visited.add(current);
224
+ stack.add(current);
225
+ cyclePath.push(current);
226
+ try {
227
+ const deps = moduleDeps.get(current);
228
+ if (deps) {
229
+ for (const imp of deps.imports) {
230
+ const providerFiles = exportIndex.get(imp);
231
+ if (providerFiles) {
232
+ for (const otherFile of providerFiles) {
233
+ if (dfs(otherFile))
234
+ return true;
235
+ }
236
+ }
237
+ }
238
+ }
239
+ return false;
240
+ }
241
+ finally {
242
+ cyclePath.pop();
243
+ stack.delete(current);
244
+ }
245
+ };
246
+ for (const f of moduleDeps.keys()) {
247
+ if (!visited.has(f)) {
248
+ dfs(f);
249
+ }
161
250
  }
162
- return deps;
163
251
  }
164
252
  function lintProject(files, config, rootDir) {
165
253
  (0, locale_1.setLocale)(config.locale || 'zh');
166
254
  const allIssues = [];
167
255
  const symbols = { defuns: new Map(), references: new Map() };
256
+ const maxFiles = config.project_analysis?.maxFiles ?? 500;
257
+ if (files.length > maxFiles) {
258
+ const msg = `${files.length} files exceeds project_analysis.maxFiles (${maxFiles}). Skipping cross-file analysis. To increase, set project_analysis.maxFiles in config.`;
259
+ console.warn(`[atlisp-lint] ${msg}`);
260
+ return [];
261
+ }
168
262
  const fileContents = new Map();
263
+ const defunArgs = new Map();
264
+ const callArgCounts = new Map();
265
+ const moduleDeps = new Map();
266
+ // Phase A: Streaming collection — one file at a time, keep only metadata
169
267
  for (const filepath of files) {
268
+ let content;
170
269
  try {
171
- const content = fs.readFileSync(filepath, 'utf-8');
172
- fileContents.set(filepath, content);
270
+ content = fs.readFileSync(filepath, 'utf-8');
173
271
  }
174
272
  catch {
175
273
  continue;
176
274
  }
177
- }
178
- // Build project symbol table
179
- for (const [filepath] of fileContents) {
180
- const defunList = collectDefuns(filepath);
275
+ const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
276
+ // Extract all metadata from a single AST parse
277
+ const defunList = collectDefunsFromAst(ast);
181
278
  for (const d of defunList) {
182
279
  const list = symbols.defuns.get(d.name) || [];
183
280
  list.push({ file: filepath, line: d.line });
184
281
  symbols.defuns.set(d.name, list);
185
282
  }
186
- const refList = collectReferences(filepath);
283
+ const refList = collectReferencesFromAst(ast);
187
284
  for (const r of refList) {
188
285
  const list = symbols.references.get(r.name) || [];
189
286
  list.push({ file: filepath, line: r.line });
190
287
  symbols.references.set(r.name, list);
191
288
  }
289
+ defunArgs.set(filepath, countFunctionArgsFromAst(ast));
290
+ callArgCounts.set(filepath, countCallArgsFromAst(ast));
291
+ moduleDeps.set(filepath, findModuleDepsFromAst(ast));
292
+ // Cache file content for checks that still need it
293
+ fileContents.set(filepath, content);
294
+ // AST goes out of scope here → GC reclaims it
192
295
  }
193
- // New: build module dependency graph
194
- const moduleDeps = collectAllModuleDeps(Array.from(fileContents.keys()));
195
- // New: collect function arg counts per file
196
- const defunArgs = new Map();
197
- for (const [filepath] of fileContents) {
198
- defunArgs.set(filepath, countFunctionArgs(filepath));
199
- }
296
+ // Phase B: Cross-file checks using only symbol tables
200
297
  for (const [filepath] of fileContents) {
201
298
  const relPath = path.relative(rootDir, filepath);
202
- const override = findProjectOverride(filepath);
299
+ const override = (0, config_1.findOverrides)(filepath);
203
300
  const checks = override?.checks || config.checks;
204
- // Existing checks
205
301
  if (checks['dangling_defun'] !== 'off') {
206
- const danglingIssues = (0, dangling_defun_1.checkDanglingDefun)(filepath, symbols.defuns, symbols.references);
302
+ const defunList = [];
303
+ for (const [name, locations] of symbols.defuns) {
304
+ for (const loc of locations) {
305
+ if (loc.file === filepath) {
306
+ defunList.push({ name, line: loc.line });
307
+ }
308
+ }
309
+ }
310
+ const danglingIssues = (0, dangling_defun_1.checkDanglingDefunFromDefs)(defunList, symbols.references, filepath);
207
311
  for (const iss of danglingIssues) {
208
312
  iss.file = relPath;
209
313
  allIssues.push(iss);
@@ -220,10 +324,13 @@ function lintProject(files, config, rootDir) {
220
324
  }
221
325
  }
222
326
  if (checks['unused_package_dep'] !== 'off') {
223
- const depIssues = (0, unused_package_dep_1.checkUnusedPackageDep)(filepath);
224
- for (const iss of depIssues) {
225
- iss.file = relPath;
226
- allIssues.push(iss);
327
+ const content = fileContents.get(filepath);
328
+ if (content) {
329
+ const depIssues = (0, unused_package_dep_1.checkUnusedPackageDepFromContent)(filepath, content);
330
+ for (const iss of depIssues) {
331
+ iss.file = relPath;
332
+ allIssues.push(iss);
333
+ }
227
334
  }
228
335
  }
229
336
  if (checks['duplicate_defun'] !== 'off') {
@@ -233,108 +340,49 @@ function lintProject(files, config, rootDir) {
233
340
  allIssues.push(iss);
234
341
  }
235
342
  }
236
- // New: module cycle detection
237
- if (checks['module_cycle'] !== 'off') {
238
- const visited = new Set();
239
- const stack = new Set();
240
- const cyclePath = [];
241
- const dfs = (current) => {
242
- if (stack.has(current)) {
243
- const idx = cyclePath.indexOf(current);
244
- const cycle = cyclePath.slice(idx).concat(current);
245
- const displayCycle = cycle.map(c => path.relative(rootDir, c)).join(' → ');
246
- allIssues.push({
247
- file: relPath,
248
- line: 1,
249
- severity: 'warn',
250
- rule: 'module_cycle',
251
- message: `Module dependency cycle detected: ${displayCycle}`,
252
- });
253
- return true;
254
- }
255
- if (visited.has(current))
256
- return false;
257
- visited.add(current);
258
- stack.add(current);
259
- cyclePath.push(current);
260
- const deps = moduleDeps.get(current);
261
- if (deps) {
262
- for (const imp of deps.imports) {
263
- for (const [otherFile, otherDeps] of moduleDeps) {
264
- if (otherDeps.exports.includes(imp)) {
265
- if (dfs(otherFile))
266
- return true;
267
- }
268
- }
269
- }
270
- }
271
- cyclePath.pop();
272
- stack.delete(current);
273
- return false;
274
- };
275
- for (const f of moduleDeps.keys()) {
276
- if (!visited.has(f)) {
277
- dfs(f);
343
+ if (checks['arg_count_project'] !== 'off') {
344
+ const argIssues = checkArgCountProject(filepath, defunArgs, callArgCounts, symbols, relPath);
345
+ allIssues.push(...argIssues);
346
+ }
347
+ if (checks['function_reference'] !== 'off') {
348
+ const definedHere = new Set();
349
+ for (const [name, locations] of symbols.defuns) {
350
+ for (const loc of locations) {
351
+ if (loc.file === filepath)
352
+ definedHere.add(name);
278
353
  }
279
354
  }
280
- }
281
- // New: signature mismatch check
282
- if (checks['arg_count_project'] !== 'off') {
283
- const fileArgs = defunArgs.get(filepath);
284
- if (fileArgs) {
285
- const callArgs = countCallArgs(filepath);
286
- for (const [fnName, calls] of callArgs) {
287
- const defs = symbols.defuns.get(fnName);
288
- if (!defs)
289
- continue;
290
- const defArgCount = fileArgs.get(fnName);
291
- if (defArgCount === undefined)
292
- continue;
293
- // Only check if all definitions agree
294
- let allMatch = true;
295
- for (const def of defs) {
296
- const otherFileArgs = defunArgs.get(def.file);
297
- if (otherFileArgs && otherFileArgs.get(fnName) !== defArgCount) {
298
- allMatch = false;
299
- break;
300
- }
301
- }
302
- if (!allMatch)
303
- continue;
304
- for (const call of calls) {
305
- if (call.count !== defArgCount) {
306
- allIssues.push({
307
- file: relPath,
308
- line: call.line,
309
- severity: 'warn',
310
- rule: 'arg_count_project',
311
- message: `Function '${fnName}' called with ${call.count} arguments but defined with ${defArgCount}`,
312
- });
313
- }
355
+ for (const [name, refs] of symbols.references) {
356
+ if (builtin_arg_count_1.BUILTIN_FUNCTIONS.has(name))
357
+ continue;
358
+ if (definedHere.has(name))
359
+ continue;
360
+ if (symbols.defuns.has(name))
361
+ continue;
362
+ for (const ref of refs) {
363
+ if (ref.file === filepath) {
364
+ allIssues.push({
365
+ file: relPath,
366
+ line: ref.line,
367
+ severity: 'warn',
368
+ rule: 'function_reference',
369
+ message: (0, locale_2.t)('function_reference', name),
370
+ });
314
371
  }
315
372
  }
316
373
  }
317
374
  }
318
375
  }
319
- return allIssues;
320
- }
321
- function findProjectOverride(filepath) {
322
- let dir = path.dirname(filepath);
323
- for (;;) {
324
- const cfgPath = path.join(dir, '.atlisp-lint.json');
325
- if (fs.existsSync(cfgPath)) {
326
- try {
327
- return JSON.parse(fs.readFileSync(cfgPath, 'utf-8'));
328
- }
329
- catch {
330
- return null;
331
- }
376
+ // Module cycle check: run DFS once (not per file)
377
+ const cycleCheckFile = fileContents.keys().next().value;
378
+ if (cycleCheckFile) {
379
+ const override = (0, config_1.findOverrides)(cycleCheckFile);
380
+ const checks = override?.checks || config.checks;
381
+ if (checks['module_cycle'] !== 'off') {
382
+ checkModuleCycle(moduleDeps, rootDir, allIssues);
332
383
  }
333
- const parent = path.dirname(dir);
334
- if (parent === dir)
335
- return null;
336
- dir = parent;
337
384
  }
385
+ return allIssues;
338
386
  }
339
387
  function findPackageDir(filepath) {
340
388
  let dir = path.dirname(filepath);
package/dist/rules.d.ts CHANGED
@@ -7,4 +7,5 @@ export interface RuleDoc {
7
7
  export declare const RULES: RuleDoc[];
8
8
  export declare function generateRulesMarkdown(): string;
9
9
  export declare function generateSchemaHint(): string;
10
+ export declare function generateRuleDetail(ruleName: string): string;
10
11
  //# sourceMappingURL=rules.d.ts.map
package/dist/rules.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RULES = void 0;
4
4
  exports.generateRulesMarkdown = generateRulesMarkdown;
5
5
  exports.generateSchemaHint = generateSchemaHint;
6
+ exports.generateRuleDetail = generateRuleDetail;
6
7
  exports.RULES = [
7
8
  {
8
9
  name: 'append_single',
@@ -281,6 +282,78 @@ exports.RULES = [
281
282
  description: '检测 defun 函数名缺少包名前缀',
282
283
  category: '风格',
283
284
  },
285
+ {
286
+ name: 'command_s',
287
+ defaultSeverity: 'warn',
288
+ description: '检测 (command ...) 调用,推荐 (command-s ...)',
289
+ category: '最佳实践',
290
+ },
291
+ {
292
+ name: 'zerop_usage',
293
+ defaultSeverity: 'info',
294
+ description: '检测 (= x 0),推荐 (zerop x)',
295
+ category: '风格',
296
+ },
297
+ {
298
+ name: 'progn_in_body',
299
+ defaultSeverity: 'info',
300
+ description: '检测 while/repeat/foreach 体中冗余 progn',
301
+ category: '风格',
302
+ },
303
+ {
304
+ name: 'if_progn_both',
305
+ defaultSeverity: 'info',
306
+ description: '检测 if 两个分支都使用 progn,推荐 cond',
307
+ category: '风格',
308
+ },
309
+ {
310
+ name: 'redundant_cond',
311
+ defaultSeverity: 'info',
312
+ description: '检测单子句 cond,推荐 if',
313
+ category: '风格',
314
+ },
315
+ {
316
+ name: 'selection_set_leak',
317
+ defaultSeverity: 'warn',
318
+ description: '检测 ssget/ssset 次数不匹配',
319
+ category: '正确性',
320
+ },
321
+ {
322
+ name: 'empty_branch_cond',
323
+ defaultSeverity: 'warn',
324
+ description: '检测 cond 子句没有表达式',
325
+ category: '正确性',
326
+ },
327
+ {
328
+ name: 'function_reference',
329
+ defaultSeverity: 'warn',
330
+ description: '检测函数被引用但从未定义(跨文件)',
331
+ category: '正确性',
332
+ },
333
+ {
334
+ name: 'progn_in_cond',
335
+ defaultSeverity: 'info',
336
+ description: '检测 cond 子句中冗余 progn',
337
+ category: '风格',
338
+ },
339
+ {
340
+ name: 'redundant_car_cdr',
341
+ defaultSeverity: 'info',
342
+ description: '检测 (car (car x)) 等可简化为 (caar x)',
343
+ category: '风格',
344
+ },
345
+ {
346
+ name: 'equal_nil',
347
+ defaultSeverity: 'info',
348
+ description: '检测 (equal x nil) 建议使用 (null x)',
349
+ category: '风格',
350
+ },
351
+ {
352
+ name: 'redundant_and_or',
353
+ defaultSeverity: 'info',
354
+ description: '检测无参数的 (and) 或 (or)——可能是残留代码',
355
+ category: '风格',
356
+ },
284
357
  ];
285
358
  function generateRulesMarkdown() {
286
359
  const lines = [
@@ -300,4 +373,16 @@ function generateSchemaHint() {
300
373
 
301
374
  Total rules: ${exports.RULES.length}`;
302
375
  }
376
+ function generateRuleDetail(ruleName) {
377
+ const rule = exports.RULES.find(r => r.name === ruleName);
378
+ if (!rule)
379
+ return `Unknown rule: ${ruleName}. Use --list-rules to see all rules.`;
380
+ const lines = [
381
+ `Rule: ${rule.name}`,
382
+ `Severity: ${rule.defaultSeverity}`,
383
+ `Category: ${rule.category}`,
384
+ `Description: ${rule.description}`,
385
+ ];
386
+ return lines.join('\n');
387
+ }
303
388
  //# sourceMappingURL=rules.js.map
package/dist/runner.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import { Issue, LintConfig } from './types';
2
2
  export declare function runChecks(content: string, file: string, config: LintConfig): Issue[];
3
- export declare function lintFiles(files: string[], config: LintConfig, rootDir: string): Issue[];
3
+ export declare function lintFiles(files: string[], config: LintConfig, rootDir: string, contentCache?: Map<string, string>): Issue[];
4
4
  export declare function lintFilesParallel(files: string[], config: LintConfig, rootDir: string): Promise<Issue[]>;
5
- export declare const FIXABLE_RULES: Set<string>;
6
- export declare function applyFixes(issues: Issue[], content: string, filepath: string): string;
5
+ export { applyFixesFromProviders as applyFixes, FIXABLE_RULES } from './fixes/index';
7
6
  export declare function parseIgnoreFile(rootDir: string): string[];
8
7
  export declare function fixFile(filepath: string): string[];
9
8
  //# sourceMappingURL=runner.d.ts.map