@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.
- package/atlisp-lint.schema.json +32 -2
- package/dist/cache.js +19 -9
- package/dist/checks/builtin-arg-count.d.ts +1 -0
- package/dist/checks/builtin-arg-count.js +5 -0
- package/dist/checks/dangerous-calls.js +1 -0
- package/dist/checks/dangling-defun.d.ts +7 -0
- package/dist/checks/dangling-defun.js +19 -0
- package/dist/checks/global-function-naming.js +159 -35
- package/dist/checks/missing-princ.js +2 -2
- package/dist/checks/nth-usage.d.ts +1 -0
- package/dist/checks/nth-usage.js +16 -1
- package/dist/checks/unused-package-dep.d.ts +1 -0
- package/dist/checks/unused-package-dep.js +53 -0
- package/dist/cli/collector.d.ts +7 -0
- package/dist/cli/collector.js +154 -0
- package/dist/cli/parser.d.ts +30 -0
- package/dist/cli/parser.js +119 -0
- package/dist/config.js +32 -6
- package/dist/disable.js +12 -0
- package/dist/fixes/index.d.ts +8 -0
- package/dist/fixes/index.js +200 -0
- package/dist/index.js +56 -236
- package/dist/locale.js +30 -2
- package/dist/presets.js +24 -0
- package/dist/project.js +182 -134
- package/dist/rules.d.ts +1 -0
- package/dist/rules.js +85 -0
- package/dist/runner.d.ts +2 -3
- package/dist/runner.js +46 -371
- package/dist/types.d.ts +6 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +43 -0
- package/dist/validate.js +12 -0
- package/dist/visitor-runner.d.ts +28 -0
- package/dist/visitor-runner.js +115 -1
- package/dist/visitors/equal-nil.d.ts +8 -0
- package/dist/visitors/equal-nil.js +26 -0
- package/dist/visitors/index.d.ts +5 -0
- package/dist/visitors/index.js +14 -0
- package/dist/visitors/progn-in-cond.d.ts +8 -0
- package/dist/visitors/progn-in-cond.js +33 -0
- package/dist/visitors/redundant-and-or.d.ts +8 -0
- package/dist/visitors/redundant-and-or.js +27 -0
- package/dist/visitors/redundant-car-cdr.d.ts +8 -0
- package/dist/visitors/redundant-car-cdr.js +35 -0
- package/dist/visitors/types.d.ts +13 -0
- package/dist/visitors/types.js +72 -0
- package/package.json +1 -1
package/dist/runner.js
CHANGED
|
@@ -33,11 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.FIXABLE_RULES = void 0;
|
|
36
|
+
exports.FIXABLE_RULES = exports.applyFixes = void 0;
|
|
37
37
|
exports.runChecks = runChecks;
|
|
38
38
|
exports.lintFiles = lintFiles;
|
|
39
39
|
exports.lintFilesParallel = lintFilesParallel;
|
|
40
|
-
exports.applyFixes = applyFixes;
|
|
41
40
|
exports.parseIgnoreFile = parseIgnoreFile;
|
|
42
41
|
exports.fixFile = fixFile;
|
|
43
42
|
const fs = __importStar(require("fs"));
|
|
@@ -110,8 +109,8 @@ function runChecks(content, file, config) {
|
|
|
110
109
|
}
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
|
-
catch {
|
|
114
|
-
|
|
112
|
+
catch (e) {
|
|
113
|
+
console.warn(`[lint] check "${rule}" failed for ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
function addIssues(ruleIssues) {
|
|
@@ -198,6 +197,17 @@ function runChecks(content, file, config) {
|
|
|
198
197
|
'identical_branches',
|
|
199
198
|
'while_constant',
|
|
200
199
|
'cond_duplicate',
|
|
200
|
+
'command_s',
|
|
201
|
+
'zerop_usage',
|
|
202
|
+
'progn_in_body',
|
|
203
|
+
'if_progn_both',
|
|
204
|
+
'redundant_cond',
|
|
205
|
+
'selection_set_leak',
|
|
206
|
+
'empty_branch_cond',
|
|
207
|
+
'progn_in_cond',
|
|
208
|
+
'redundant_car_cdr',
|
|
209
|
+
'equal_nil',
|
|
210
|
+
'redundant_and_or',
|
|
201
211
|
]);
|
|
202
212
|
const needsAst = Array.from(astRules).some(r => checks[r] !== 'off');
|
|
203
213
|
if (needsAst) {
|
|
@@ -206,35 +216,49 @@ function runChecks(content, file, config) {
|
|
|
206
216
|
const visitorIssues = (0, visitor_runner_1.runChecksWithVisitor)(ast, file, config, disableMap);
|
|
207
217
|
addIssues(visitorIssues);
|
|
208
218
|
}
|
|
209
|
-
catch {
|
|
210
|
-
|
|
219
|
+
catch (e) {
|
|
220
|
+
console.warn(`[lint] AST parse/visitor failed for ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
211
221
|
}
|
|
212
222
|
}
|
|
213
223
|
return issues;
|
|
214
224
|
}
|
|
215
|
-
function lintFiles(files, config, rootDir) {
|
|
225
|
+
function lintFiles(files, config, rootDir, contentCache) {
|
|
216
226
|
(0, locale_1.setLocale)(config.locale || 'zh');
|
|
217
227
|
const allIssues = [];
|
|
218
|
-
|
|
228
|
+
const total = files.length;
|
|
229
|
+
const showProgress = process.stderr.isTTY && total > 5;
|
|
230
|
+
for (let fi = 0; fi < total; fi++) {
|
|
231
|
+
const filepath = files[fi];
|
|
219
232
|
const relPath = path.relative(rootDir, filepath);
|
|
233
|
+
if (showProgress) {
|
|
234
|
+
process.stderr.write(`\r[${fi + 1}/${total}] ${relPath} `);
|
|
235
|
+
}
|
|
220
236
|
let content;
|
|
221
|
-
|
|
222
|
-
content =
|
|
237
|
+
if (contentCache && contentCache.has(filepath)) {
|
|
238
|
+
content = contentCache.get(filepath);
|
|
223
239
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
240
|
+
else {
|
|
241
|
+
try {
|
|
242
|
+
content = fs.readFileSync(filepath, 'utf-8');
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
allIssues.push({
|
|
246
|
+
file: relPath,
|
|
247
|
+
line: 1,
|
|
248
|
+
severity: 'error',
|
|
249
|
+
rule: 'read',
|
|
250
|
+
message: (0, locale_1.t)('runner.read_error'),
|
|
251
|
+
});
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
233
254
|
}
|
|
234
255
|
const override = (0, config_1.findOverrides)(filepath);
|
|
235
256
|
const effectiveConfig = override ? (0, config_1.mergeOverrides)(config, override) : config;
|
|
236
257
|
allIssues.push(...runChecks(content, relPath, effectiveConfig));
|
|
237
258
|
}
|
|
259
|
+
if (showProgress) {
|
|
260
|
+
process.stderr.write('\r' + ' '.repeat(60) + '\r');
|
|
261
|
+
}
|
|
238
262
|
return allIssues;
|
|
239
263
|
}
|
|
240
264
|
function lintFilesParallel(files, config, rootDir) {
|
|
@@ -302,358 +326,9 @@ function lintFilesParallel(files, config, rootDir) {
|
|
|
302
326
|
resolve([]);
|
|
303
327
|
});
|
|
304
328
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
let depth = 0;
|
|
309
|
-
for (let i = start; i < s.length; i++) {
|
|
310
|
-
if (s[i] === '"') {
|
|
311
|
-
i++;
|
|
312
|
-
while (i < s.length && s[i] !== '"') {
|
|
313
|
-
if (s[i] === '\\')
|
|
314
|
-
i++;
|
|
315
|
-
i++;
|
|
316
|
-
}
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
if (s[i] === '(')
|
|
320
|
-
depth++;
|
|
321
|
-
else if (s[i] === ')') {
|
|
322
|
-
depth--;
|
|
323
|
-
if (depth === 0)
|
|
324
|
-
return i;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return s.length - 1;
|
|
328
|
-
}
|
|
329
|
-
function extractForm(s, start) {
|
|
330
|
-
let i = start;
|
|
331
|
-
while (i < s.length && s[i] === ' ')
|
|
332
|
-
i++;
|
|
333
|
-
if (i >= s.length)
|
|
334
|
-
return ['', i];
|
|
335
|
-
if (s[i] !== '(') {
|
|
336
|
-
const m = s.slice(i).match(/^\S+/);
|
|
337
|
-
if (m)
|
|
338
|
-
return [m[0], i + m[0].length];
|
|
339
|
-
return ['', i];
|
|
340
|
-
}
|
|
341
|
-
const end = findMatchingParen(s, i);
|
|
342
|
-
return [s.slice(i, end + 1), end + 1];
|
|
343
|
-
}
|
|
344
|
-
// ===== FIX APPLICATION =====
|
|
345
|
-
exports.FIXABLE_RULES = new Set([
|
|
346
|
-
'redundant_quotes',
|
|
347
|
-
'double_not',
|
|
348
|
-
'redundant_nil_else',
|
|
349
|
-
'single_arg_and_or',
|
|
350
|
-
'redundant_setq',
|
|
351
|
-
'redundant_progn',
|
|
352
|
-
'redundant_let',
|
|
353
|
-
'quote_style',
|
|
354
|
-
'redundant_if',
|
|
355
|
-
'misplaced_else',
|
|
356
|
-
'setq_multiple',
|
|
357
|
-
'append_single',
|
|
358
|
-
'nth_usage',
|
|
359
|
-
'setq_single_arg',
|
|
360
|
-
'extra_parens',
|
|
361
|
-
'empty_branch',
|
|
362
|
-
'comment_style',
|
|
363
|
-
'eq_usage',
|
|
364
|
-
'cond_simplify',
|
|
365
|
-
'self_compare',
|
|
366
|
-
'while_constant',
|
|
367
|
-
'redundant_list',
|
|
368
|
-
]);
|
|
369
|
-
function applyFixes(issues, content, filepath) {
|
|
370
|
-
const lines = content.split('\n');
|
|
371
|
-
const fixedLines = new Set();
|
|
372
|
-
const fixesByRule = new Map();
|
|
373
|
-
for (const iss of issues) {
|
|
374
|
-
if (iss.file !== filepath)
|
|
375
|
-
continue;
|
|
376
|
-
const set = fixesByRule.get(iss.rule) || new Set();
|
|
377
|
-
set.add(iss.line);
|
|
378
|
-
fixesByRule.set(iss.rule, set);
|
|
379
|
-
}
|
|
380
|
-
const fixableRules = exports.FIXABLE_RULES;
|
|
381
|
-
for (const [rule, lineSet] of fixesByRule) {
|
|
382
|
-
if (!fixableRules.has(rule))
|
|
383
|
-
continue;
|
|
384
|
-
const sortedLines = Array.from(lineSet).sort((a, b) => b - a);
|
|
385
|
-
for (const line of sortedLines) {
|
|
386
|
-
const idx = line - 1;
|
|
387
|
-
if (idx < 0 || idx >= lines.length)
|
|
388
|
-
continue;
|
|
389
|
-
const lineContent = lines[idx];
|
|
390
|
-
switch (rule) {
|
|
391
|
-
case 'redundant_quotes': {
|
|
392
|
-
const fixed = lineContent.replace(/''(\S)/g, "'$1");
|
|
393
|
-
if (fixed !== lineContent) {
|
|
394
|
-
lines[idx] = fixed;
|
|
395
|
-
fixedLines.add(idx);
|
|
396
|
-
}
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
case 'double_not': {
|
|
400
|
-
const fixed = lineContent.replace(/\(not\s+\(not\s+/g, '(not ');
|
|
401
|
-
if (fixed !== lineContent) {
|
|
402
|
-
lines[idx] = fixed;
|
|
403
|
-
fixedLines.add(idx);
|
|
404
|
-
}
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
case 'redundant_nil_else': {
|
|
408
|
-
const fixed = lineContent.replace(/\s+nil\s*\)$/, ')');
|
|
409
|
-
if (fixed !== lineContent) {
|
|
410
|
-
lines[idx] = fixed;
|
|
411
|
-
fixedLines.add(idx);
|
|
412
|
-
}
|
|
413
|
-
break;
|
|
414
|
-
}
|
|
415
|
-
case 'single_arg_and_or': {
|
|
416
|
-
const m = lineContent.match(/\((and|or)\s+([^)\s]+)\s*\)/);
|
|
417
|
-
if (m) {
|
|
418
|
-
lines[idx] = m[2];
|
|
419
|
-
fixedLines.add(idx);
|
|
420
|
-
}
|
|
421
|
-
break;
|
|
422
|
-
}
|
|
423
|
-
case 'redundant_progn': {
|
|
424
|
-
const proIdx = lineContent.indexOf('(progn ');
|
|
425
|
-
if (proIdx !== -1) {
|
|
426
|
-
const beforePro = lineContent.slice(0, proIdx);
|
|
427
|
-
const close = findMatchingParen(lineContent, proIdx);
|
|
428
|
-
if (close > proIdx) {
|
|
429
|
-
const inner = lineContent.slice(proIdx + 7, close);
|
|
430
|
-
const rest = lineContent.slice(close + 1);
|
|
431
|
-
const fixed = beforePro + inner + rest;
|
|
432
|
-
if (fixed !== lineContent) {
|
|
433
|
-
lines[idx] = fixed;
|
|
434
|
-
fixedLines.add(idx);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
case 'redundant_let': {
|
|
441
|
-
const fixed = lineContent.replace(/\(let\s+\(\)\s*/, '(progn ');
|
|
442
|
-
if (fixed !== lineContent) {
|
|
443
|
-
lines[idx] = fixed;
|
|
444
|
-
fixedLines.add(idx);
|
|
445
|
-
}
|
|
446
|
-
break;
|
|
447
|
-
}
|
|
448
|
-
case 'quote_style': {
|
|
449
|
-
const qIdx = lineContent.indexOf('(quote ');
|
|
450
|
-
if (qIdx !== -1) {
|
|
451
|
-
const beforeQ = lineContent.slice(0, qIdx);
|
|
452
|
-
const close = findMatchingParen(lineContent, qIdx);
|
|
453
|
-
if (close > qIdx) {
|
|
454
|
-
const quoted = lineContent.slice(qIdx + 7, close);
|
|
455
|
-
const rest = lineContent.slice(close + 1);
|
|
456
|
-
const fixed = beforeQ + "'" + quoted + rest;
|
|
457
|
-
if (fixed !== lineContent) {
|
|
458
|
-
lines[idx] = fixed;
|
|
459
|
-
fixedLines.add(idx);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
break;
|
|
464
|
-
}
|
|
465
|
-
case 'redundant_if': {
|
|
466
|
-
const pIdx = lineContent.indexOf('(progn ');
|
|
467
|
-
if (pIdx !== -1) {
|
|
468
|
-
const beforeP = lineContent.slice(0, pIdx);
|
|
469
|
-
const close = findMatchingParen(lineContent, pIdx);
|
|
470
|
-
if (close > pIdx) {
|
|
471
|
-
const inner = lineContent.slice(pIdx + 7, close);
|
|
472
|
-
const rest = lineContent.slice(close + 1);
|
|
473
|
-
const fixed = beforeP + inner + rest;
|
|
474
|
-
if (fixed !== lineContent) {
|
|
475
|
-
lines[idx] = fixed;
|
|
476
|
-
fixedLines.add(idx);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
break;
|
|
481
|
-
}
|
|
482
|
-
case 'misplaced_else': {
|
|
483
|
-
const ifStart = lineContent.indexOf('(if (not ');
|
|
484
|
-
if (ifStart !== -1) {
|
|
485
|
-
const notIdx = lineContent.indexOf('(not ', ifStart);
|
|
486
|
-
if (notIdx === -1)
|
|
487
|
-
break;
|
|
488
|
-
const notClose = findMatchingParen(lineContent, notIdx);
|
|
489
|
-
if (notClose <= notIdx)
|
|
490
|
-
break;
|
|
491
|
-
const ifClose = findMatchingParen(lineContent, ifStart);
|
|
492
|
-
if (ifClose <= ifStart)
|
|
493
|
-
break;
|
|
494
|
-
const indent = lineContent.slice(0, ifStart);
|
|
495
|
-
const condVar = lineContent.slice(notIdx + 5, notClose);
|
|
496
|
-
const branchContent = lineContent.slice(notClose + 1, ifClose).trim();
|
|
497
|
-
const [thenForm, thenEnd] = extractForm(branchContent, 0);
|
|
498
|
-
const elseForm = branchContent.slice(thenEnd).trim();
|
|
499
|
-
if (thenForm && elseForm) {
|
|
500
|
-
const rest = lineContent.slice(ifClose + 1);
|
|
501
|
-
const fixed = indent + '(if ' + condVar + ' ' + elseForm + ' ' + thenForm + ')' + rest;
|
|
502
|
-
if (fixed !== lineContent) {
|
|
503
|
-
lines[idx] = fixed;
|
|
504
|
-
fixedLines.add(idx);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
case 'redundant_setq': {
|
|
511
|
-
const trimmed = lines[idx].trim();
|
|
512
|
-
if (/^\(setq\s+(\S+)\s+\1\s*\)$/.test(trimmed)) {
|
|
513
|
-
lines.splice(idx, 1);
|
|
514
|
-
}
|
|
515
|
-
break;
|
|
516
|
-
}
|
|
517
|
-
case 'setq_multiple': {
|
|
518
|
-
const fixed = lineContent.replace(/\)\(setq\s+/g, ' ');
|
|
519
|
-
if (fixed !== lineContent) {
|
|
520
|
-
const merged = lineContent.replace(/^\(\s*setq\s+/, '(setq ');
|
|
521
|
-
if (merged.includes('setq') && !merged.match(/\)\(/)) {
|
|
522
|
-
lines[idx] = merged;
|
|
523
|
-
fixedLines.add(idx);
|
|
524
|
-
}
|
|
525
|
-
else {
|
|
526
|
-
const simplified = lineContent.replace(/\)\(setq\s+/g, '\n');
|
|
527
|
-
if (simplified !== lineContent) {
|
|
528
|
-
lines[idx] = simplified;
|
|
529
|
-
fixedLines.add(idx);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
case 'append_single': {
|
|
536
|
-
const aIdx = lineContent.indexOf('(append ');
|
|
537
|
-
if (aIdx !== -1) {
|
|
538
|
-
const close = findMatchingParen(lineContent, aIdx);
|
|
539
|
-
if (close > aIdx) {
|
|
540
|
-
const inner = lineContent.slice(aIdx + 8, close);
|
|
541
|
-
const listMatch = inner.match(/^\(list\s+(.*)\)\s*$/);
|
|
542
|
-
if (listMatch) {
|
|
543
|
-
const fixed = lineContent.slice(0, aIdx) + '(cons ' + listMatch[1] + ')' + lineContent.slice(close + 1);
|
|
544
|
-
if (fixed !== lineContent) {
|
|
545
|
-
lines[idx] = fixed;
|
|
546
|
-
fixedLines.add(idx);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
case 'nth_usage': {
|
|
554
|
-
const fixed = lineContent.replace(/\(nth\s+0\s+/g, '(car ');
|
|
555
|
-
if (fixed !== lineContent) {
|
|
556
|
-
lines[idx] = fixed;
|
|
557
|
-
fixedLines.add(idx);
|
|
558
|
-
}
|
|
559
|
-
break;
|
|
560
|
-
}
|
|
561
|
-
case 'setq_single_arg': {
|
|
562
|
-
if (/^\s*\(setq\s+\S+\s*\)\s*$/.test(lines[idx])) {
|
|
563
|
-
lines.splice(idx, 1);
|
|
564
|
-
}
|
|
565
|
-
break;
|
|
566
|
-
}
|
|
567
|
-
case 'extra_parens': {
|
|
568
|
-
const fixed = lineContent.replace(/\){2,}/g, ')');
|
|
569
|
-
if (fixed !== lineContent) {
|
|
570
|
-
lines[idx] = fixed;
|
|
571
|
-
fixedLines.add(idx);
|
|
572
|
-
}
|
|
573
|
-
break;
|
|
574
|
-
}
|
|
575
|
-
case 'empty_branch': {
|
|
576
|
-
const fixed = lineContent.replace(/\(if\s+\S+\s*\)/g, m => m.slice(0, -1) + ' nil)');
|
|
577
|
-
if (fixed !== lineContent) {
|
|
578
|
-
lines[idx] = fixed;
|
|
579
|
-
fixedLines.add(idx);
|
|
580
|
-
}
|
|
581
|
-
break;
|
|
582
|
-
}
|
|
583
|
-
case 'comment_style': {
|
|
584
|
-
const fixed = lineContent.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
|
|
585
|
-
if (fixed !== lineContent) {
|
|
586
|
-
lines[idx] = fixed;
|
|
587
|
-
fixedLines.add(idx);
|
|
588
|
-
}
|
|
589
|
-
break;
|
|
590
|
-
}
|
|
591
|
-
case 'eq_usage': {
|
|
592
|
-
const fixed = lineContent.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
|
|
593
|
-
if (fixed !== lineContent) {
|
|
594
|
-
lines[idx] = fixed;
|
|
595
|
-
fixedLines.add(idx);
|
|
596
|
-
}
|
|
597
|
-
break;
|
|
598
|
-
}
|
|
599
|
-
case 'cond_simplify': {
|
|
600
|
-
const condIdx = lineContent.indexOf('(cond ');
|
|
601
|
-
if (condIdx !== -1) {
|
|
602
|
-
const condEnd = findMatchingParen(lineContent, condIdx);
|
|
603
|
-
if (condEnd > condIdx) {
|
|
604
|
-
const inner = lineContent.slice(condIdx + 6, condEnd).trim();
|
|
605
|
-
const branchOpen = inner.indexOf('(');
|
|
606
|
-
if (branchOpen !== -1) {
|
|
607
|
-
const branchEnd = findMatchingParen(inner, branchOpen);
|
|
608
|
-
if (branchEnd > branchOpen) {
|
|
609
|
-
const indent = lineContent.slice(0, condIdx);
|
|
610
|
-
const branchContent = inner.slice(branchOpen + 1, branchEnd).trim();
|
|
611
|
-
const space = branchContent.search(/\s+/);
|
|
612
|
-
if (space !== -1) {
|
|
613
|
-
const testExpr = branchContent.slice(0, space);
|
|
614
|
-
const bodyExpr = branchContent.slice(space).trim();
|
|
615
|
-
const rest = lineContent.slice(condEnd + 1);
|
|
616
|
-
const fixed = indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
|
|
617
|
-
if (fixed !== lineContent) {
|
|
618
|
-
lines[idx] = fixed;
|
|
619
|
-
fixedLines.add(idx);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
break;
|
|
627
|
-
}
|
|
628
|
-
case 'self_compare': {
|
|
629
|
-
const fixed = lineContent.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
|
|
630
|
-
if (fixed !== lineContent) {
|
|
631
|
-
lines[idx] = fixed;
|
|
632
|
-
fixedLines.add(idx);
|
|
633
|
-
}
|
|
634
|
-
break;
|
|
635
|
-
}
|
|
636
|
-
case 'while_constant': {
|
|
637
|
-
const trimmed = lines[idx].trim();
|
|
638
|
-
const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
|
|
639
|
-
if (nilMatch) {
|
|
640
|
-
lines[idx] = lines[idx].replace(trimmed, 'nil');
|
|
641
|
-
}
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
644
|
-
case 'redundant_list': {
|
|
645
|
-
const fixed = lineContent.replace(/\(\s*list\s*\)/g, 'nil');
|
|
646
|
-
if (fixed !== lineContent) {
|
|
647
|
-
lines[idx] = fixed;
|
|
648
|
-
fixedLines.add(idx);
|
|
649
|
-
}
|
|
650
|
-
break;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return lines.join('\n');
|
|
656
|
-
}
|
|
329
|
+
var index_1 = require("./fixes/index");
|
|
330
|
+
Object.defineProperty(exports, "applyFixes", { enumerable: true, get: function () { return index_1.applyFixesFromProviders; } });
|
|
331
|
+
Object.defineProperty(exports, "FIXABLE_RULES", { enumerable: true, get: function () { return index_1.FIXABLE_RULES; } });
|
|
657
332
|
function parseIgnoreFile(rootDir) {
|
|
658
333
|
const ignoreFile = path.join(rootDir, '.atlisp-lint-ignore');
|
|
659
334
|
if (!fs.existsSync(ignoreFile))
|
package/dist/types.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface DangerousCallsConfig {
|
|
|
24
24
|
command_shell: Severity;
|
|
25
25
|
startapp: Severity;
|
|
26
26
|
vl_registry_write: Severity;
|
|
27
|
+
eval: Severity;
|
|
27
28
|
}
|
|
28
29
|
export interface ModuleRegistrationConfig extends CheckConfig {
|
|
29
30
|
patterns: string[];
|
|
@@ -42,6 +43,10 @@ export interface SbclConfig {
|
|
|
42
43
|
walk_exclude: string[];
|
|
43
44
|
defmacro_allow_files: string[];
|
|
44
45
|
}
|
|
46
|
+
export interface ProjectAnalysisConfig {
|
|
47
|
+
maxFiles: number;
|
|
48
|
+
batchSize: number;
|
|
49
|
+
}
|
|
45
50
|
export interface SourceConfig {
|
|
46
51
|
globs: string[];
|
|
47
52
|
exclude: string[];
|
|
@@ -66,6 +71,7 @@ export interface LintConfig {
|
|
|
66
71
|
namespace_header: NamespaceHeaderConfig;
|
|
67
72
|
bare_function_names: BareFunctionNamesConfig;
|
|
68
73
|
sbcl: SbclConfig;
|
|
74
|
+
project_analysis: ProjectAnalysisConfig;
|
|
69
75
|
preset?: string;
|
|
70
76
|
}
|
|
71
77
|
export interface FormattedResult {
|
package/dist/utils.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ export declare function codeLines(content: string): Generator<{
|
|
|
7
7
|
text: string;
|
|
8
8
|
stripped: string;
|
|
9
9
|
}>;
|
|
10
|
+
/** Find matching closing paren (string/comment aware) */
|
|
11
|
+
export declare function findMatchingParen(s: string, start: number): number;
|
|
12
|
+
/** Extract the next s-expression form starting at position */
|
|
13
|
+
export declare function extractForm(s: string, start: number): [string, number];
|
|
10
14
|
/** Extract string literals from a line */
|
|
11
15
|
export declare function extractStrings(line: string): string[];
|
|
12
16
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.stripLine = stripLine;
|
|
4
4
|
exports.stripLineRaw = stripLineRaw;
|
|
5
5
|
exports.codeLines = codeLines;
|
|
6
|
+
exports.findMatchingParen = findMatchingParen;
|
|
7
|
+
exports.extractForm = extractForm;
|
|
6
8
|
exports.extractStrings = extractStrings;
|
|
7
9
|
/** Strip string contents and comments from a line of AutoLISP code */
|
|
8
10
|
function stripLine(line) {
|
|
@@ -67,6 +69,47 @@ function* codeLines(content) {
|
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
}
|
|
72
|
+
/** Find matching closing paren (string/comment aware) */
|
|
73
|
+
function findMatchingParen(s, start) {
|
|
74
|
+
if (s[start] !== '(')
|
|
75
|
+
return start;
|
|
76
|
+
let depth = 0;
|
|
77
|
+
for (let i = start; i < s.length; i++) {
|
|
78
|
+
if (s[i] === '"') {
|
|
79
|
+
i++;
|
|
80
|
+
while (i < s.length && s[i] !== '"') {
|
|
81
|
+
if (s[i] === '\\')
|
|
82
|
+
i++;
|
|
83
|
+
i++;
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (s[i] === '(')
|
|
88
|
+
depth++;
|
|
89
|
+
else if (s[i] === ')') {
|
|
90
|
+
depth--;
|
|
91
|
+
if (depth === 0)
|
|
92
|
+
return i;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return s.length - 1;
|
|
96
|
+
}
|
|
97
|
+
/** Extract the next s-expression form starting at position */
|
|
98
|
+
function extractForm(s, start) {
|
|
99
|
+
let i = start;
|
|
100
|
+
while (i < s.length && s[i] === ' ')
|
|
101
|
+
i++;
|
|
102
|
+
if (i >= s.length)
|
|
103
|
+
return ['', i];
|
|
104
|
+
if (s[i] !== '(') {
|
|
105
|
+
const m = s.slice(i).match(/^\S+/);
|
|
106
|
+
if (m)
|
|
107
|
+
return [m[0], i + m[0].length];
|
|
108
|
+
return ['', i];
|
|
109
|
+
}
|
|
110
|
+
const end = findMatchingParen(s, i);
|
|
111
|
+
return [s.slice(i, end + 1), end + 1];
|
|
112
|
+
}
|
|
70
113
|
/** Extract string literals from a line */
|
|
71
114
|
function extractStrings(line) {
|
|
72
115
|
const strings = [];
|
package/dist/validate.js
CHANGED
|
@@ -89,6 +89,18 @@ const VALID_RULES = [
|
|
|
89
89
|
'redundant_entmake',
|
|
90
90
|
'missing_princ',
|
|
91
91
|
'global_function_naming',
|
|
92
|
+
'command_s',
|
|
93
|
+
'zerop_usage',
|
|
94
|
+
'progn_in_body',
|
|
95
|
+
'if_progn_both',
|
|
96
|
+
'redundant_cond',
|
|
97
|
+
'selection_set_leak',
|
|
98
|
+
'empty_branch_cond',
|
|
99
|
+
'function_reference',
|
|
100
|
+
'progn_in_cond',
|
|
101
|
+
'redundant_car_cdr',
|
|
102
|
+
'equal_nil',
|
|
103
|
+
'redundant_and_or',
|
|
92
104
|
];
|
|
93
105
|
const VALID_SEVERITIES = ['off', 'info', 'warn', 'error'];
|
|
94
106
|
function validateConfig(config) {
|
package/dist/visitor-runner.d.ts
CHANGED
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
import { Issue, LintConfig } from './types';
|
|
2
2
|
import { AstNode } from '@atlisp/parser';
|
|
3
|
+
export interface CollectState {
|
|
4
|
+
openCount: number;
|
|
5
|
+
closeCount: number;
|
|
6
|
+
setqDefs: Map<string, {
|
|
7
|
+
line: number;
|
|
8
|
+
file: string;
|
|
9
|
+
}>;
|
|
10
|
+
symbolRefs: Map<string, number>;
|
|
11
|
+
condKeys: Map<number, Set<string>>;
|
|
12
|
+
defunScopes: Array<{
|
|
13
|
+
name: string;
|
|
14
|
+
params: string[];
|
|
15
|
+
body: AstNode[];
|
|
16
|
+
line: number;
|
|
17
|
+
file: string;
|
|
18
|
+
}>;
|
|
19
|
+
letScopes: Array<{
|
|
20
|
+
bindings: string[];
|
|
21
|
+
body: AstNode[];
|
|
22
|
+
line: number;
|
|
23
|
+
}>;
|
|
24
|
+
dangerousCalls: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
node: AstNode;
|
|
27
|
+
}>;
|
|
28
|
+
ssgetCount: number;
|
|
29
|
+
sssetCount: number;
|
|
30
|
+
}
|
|
3
31
|
export declare function runChecksWithVisitor(ast: AstNode, file: string, config: LintConfig, disableMap: Map<string, Set<number>>): Issue[];
|
|
4
32
|
//# sourceMappingURL=visitor-runner.d.ts.map
|