@atlisp/lint 0.1.23 → 0.1.25
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.default.json +2 -1
- package/dist/atlisp-lint.default.json +90 -0
- package/dist/checks/arg-count.js +1 -1
- package/dist/checks/assoc-without-cdr.js +1 -1
- package/dist/checks/builtin-arg-count.d.ts +3 -0
- package/dist/checks/builtin-arg-count.js +282 -0
- package/dist/checks/cond-duplicate.js +1 -1
- package/dist/checks/constant-condition.js +3 -3
- package/dist/checks/dangerous-calls.js +1 -1
- package/dist/checks/dangling-defun.js +1 -1
- package/dist/checks/double-not.js +1 -1
- package/dist/checks/empty-branch.js +1 -1
- package/dist/checks/empty-catch.js +1 -1
- package/dist/checks/function-complexity.js +1 -1
- package/dist/checks/global-naming.js +1 -1
- package/dist/checks/identical-branches.js +1 -1
- package/dist/checks/misplaced-else.js +1 -1
- package/dist/checks/multiple-setq.js +1 -1
- package/dist/checks/no-return.js +1 -1
- package/dist/checks/open-close.js +1 -1
- package/dist/checks/parameter-naming.js +1 -1
- package/dist/checks/quote-vs-function.js +1 -1
- package/dist/checks/recursive-call.js +1 -1
- package/dist/checks/redundant-let.js +1 -1
- package/dist/checks/redundant-nil-else.js +1 -1
- package/dist/checks/redundant-progn.js +1 -1
- package/dist/checks/redundant-quotes.js +1 -1
- package/dist/checks/redundant-setq.js +1 -1
- package/dist/checks/self-compare.js +1 -1
- package/dist/checks/setq-single-arg.js +1 -1
- package/dist/checks/single-arg-and-or.js +1 -1
- package/dist/checks/undeclared-setq.js +1 -1
- package/dist/checks/unused-catch-result.js +1 -1
- package/dist/checks/unused-let.js +1 -1
- package/dist/checks/unused-local-fun.js +1 -1
- package/dist/checks/unused-package-dep.js +1 -1
- package/dist/checks/unused-param.js +1 -1
- package/dist/checks/unused-variable.js +1 -1
- package/dist/checks/variable-shadow.js +1 -1
- package/dist/checks/while-constant.js +1 -1
- package/dist/formatters.d.ts +0 -1
- package/dist/formatters.js +0 -16
- package/dist/lib/lint-sbcl.lisp +161 -0
- package/dist/locale.js +2 -0
- package/dist/project.js +5 -5
- package/dist/rules.js +2 -1
- package/dist/runner.d.ts +0 -1
- package/dist/runner.js +150 -100
- package/dist/stub-packages.json +41 -0
- package/package.json +2 -2
package/dist/runner.js
CHANGED
|
@@ -35,7 +35,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.FIXABLE_RULES = void 0;
|
|
37
37
|
exports.runChecks = runChecks;
|
|
38
|
-
exports.runChecksWithVisitorWrapper = runChecksWithVisitorWrapper;
|
|
39
38
|
exports.lintFiles = lintFiles;
|
|
40
39
|
exports.lintFilesParallel = lintFilesParallel;
|
|
41
40
|
exports.applyFixes = applyFixes;
|
|
@@ -60,6 +59,7 @@ const error_handling_1 = require("./checks/error-handling");
|
|
|
60
59
|
const global_naming_1 = require("./checks/global-naming");
|
|
61
60
|
const extra_parens_1 = require("./checks/extra-parens");
|
|
62
61
|
const arg_count_1 = require("./checks/arg-count");
|
|
62
|
+
const builtin_arg_count_1 = require("./checks/builtin-arg-count");
|
|
63
63
|
const strcat_usage_1 = require("./checks/strcat-usage");
|
|
64
64
|
const cond_simplify_1 = require("./checks/cond-simplify");
|
|
65
65
|
const quote_style_1 = require("./checks/quote-style");
|
|
@@ -100,12 +100,17 @@ function runChecks(content, file, config) {
|
|
|
100
100
|
const severity = checks[rule];
|
|
101
101
|
if (!severity || severity === 'off')
|
|
102
102
|
return;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
try {
|
|
104
|
+
const results = fn();
|
|
105
|
+
for (const r of results) {
|
|
106
|
+
if (!(0, disable_1.isDisabled)(r.rule, r.line, disableMap)) {
|
|
107
|
+
issues.push(r);
|
|
108
|
+
}
|
|
107
109
|
}
|
|
108
110
|
}
|
|
111
|
+
catch {
|
|
112
|
+
// Check failed, continue with remaining checks
|
|
113
|
+
}
|
|
109
114
|
}
|
|
110
115
|
function addIssues(ruleIssues) {
|
|
111
116
|
for (const r of ruleIssues) {
|
|
@@ -133,6 +138,7 @@ function runChecks(content, file, config) {
|
|
|
133
138
|
addIfEnabled('global_naming', () => (0, global_naming_1.checkGlobalNaming)(content, file));
|
|
134
139
|
addIfEnabled('extra_parens', () => (0, extra_parens_1.checkExtraParens)(content, file));
|
|
135
140
|
addIfEnabled('arg_count', () => (0, arg_count_1.checkArgCount)(content, file));
|
|
141
|
+
addIfEnabled('builtin_arg_count', () => (0, builtin_arg_count_1.checkBuiltinArgCount)(content, file));
|
|
136
142
|
addIfEnabled('strcat_usage', () => (0, strcat_usage_1.checkStrcatUsage)(content, file));
|
|
137
143
|
addIfEnabled('cond_simplify', () => (0, cond_simplify_1.checkCondSimplify)(content, file));
|
|
138
144
|
addIfEnabled('quote_style', () => (0, quote_style_1.checkQuoteStyle)(content, file));
|
|
@@ -173,17 +179,17 @@ function runChecks(content, file, config) {
|
|
|
173
179
|
]);
|
|
174
180
|
const needsAst = Array.from(astRules).some(r => checks[r] !== 'off');
|
|
175
181
|
if (needsAst) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
182
|
+
try {
|
|
183
|
+
const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
|
|
184
|
+
const visitorIssues = (0, visitor_runner_1.runChecksWithVisitor)(ast, file, config, disableMap);
|
|
185
|
+
addIssues(visitorIssues);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// AST-based checks are skipped, text-based checks above still report issues
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
return issues;
|
|
181
192
|
}
|
|
182
|
-
function runChecksWithVisitorWrapper(content, file, config) {
|
|
183
|
-
const disableMap = (0, disable_1.parseDisableComments)(content);
|
|
184
|
-
const ast = (0, parser_1.parseAst)(content);
|
|
185
|
-
return (0, visitor_runner_1.runChecksWithVisitor)(ast, file, config, disableMap);
|
|
186
|
-
}
|
|
187
193
|
function lintFiles(files, config, rootDir) {
|
|
188
194
|
(0, locale_1.setLocale)(config.locale || 'zh');
|
|
189
195
|
const allIssues = [];
|
|
@@ -321,6 +327,7 @@ exports.FIXABLE_RULES = new Set([
|
|
|
321
327
|
]);
|
|
322
328
|
function applyFixes(issues, content, filepath) {
|
|
323
329
|
const lines = content.split('\n');
|
|
330
|
+
const fixedLines = new Set();
|
|
324
331
|
const fixesByRule = new Map();
|
|
325
332
|
for (const iss of issues) {
|
|
326
333
|
if (iss.file !== filepath)
|
|
@@ -330,7 +337,6 @@ function applyFixes(issues, content, filepath) {
|
|
|
330
337
|
fixesByRule.set(iss.rule, set);
|
|
331
338
|
}
|
|
332
339
|
const fixableRules = exports.FIXABLE_RULES;
|
|
333
|
-
let result = content;
|
|
334
340
|
for (const [rule, lineSet] of fixesByRule) {
|
|
335
341
|
if (!fixableRules.has(rule))
|
|
336
342
|
continue;
|
|
@@ -339,30 +345,38 @@ function applyFixes(issues, content, filepath) {
|
|
|
339
345
|
const idx = line - 1;
|
|
340
346
|
if (idx < 0 || idx >= lines.length)
|
|
341
347
|
continue;
|
|
342
|
-
const lineContent =
|
|
348
|
+
const lineContent = lines[idx];
|
|
343
349
|
switch (rule) {
|
|
344
350
|
case 'redundant_quotes': {
|
|
345
351
|
const fixed = lineContent.replace(/''(\S)/g, "'$1");
|
|
346
|
-
if (fixed !== lineContent)
|
|
347
|
-
|
|
352
|
+
if (fixed !== lineContent) {
|
|
353
|
+
lines[idx] = fixed;
|
|
354
|
+
fixedLines.add(idx);
|
|
355
|
+
}
|
|
348
356
|
break;
|
|
349
357
|
}
|
|
350
358
|
case 'double_not': {
|
|
351
359
|
const fixed = lineContent.replace(/\(not\s+\(not\s+/g, '(not ');
|
|
352
|
-
if (fixed !== lineContent)
|
|
353
|
-
|
|
360
|
+
if (fixed !== lineContent) {
|
|
361
|
+
lines[idx] = fixed;
|
|
362
|
+
fixedLines.add(idx);
|
|
363
|
+
}
|
|
354
364
|
break;
|
|
355
365
|
}
|
|
356
366
|
case 'redundant_nil_else': {
|
|
357
367
|
const fixed = lineContent.replace(/\s+nil\s*\)$/, ')');
|
|
358
|
-
if (fixed !== lineContent)
|
|
359
|
-
|
|
368
|
+
if (fixed !== lineContent) {
|
|
369
|
+
lines[idx] = fixed;
|
|
370
|
+
fixedLines.add(idx);
|
|
371
|
+
}
|
|
360
372
|
break;
|
|
361
373
|
}
|
|
362
374
|
case 'single_arg_and_or': {
|
|
363
375
|
const m = lineContent.match(/\((and|or)\s+([^)\s]+)\s*\)/);
|
|
364
|
-
if (m)
|
|
365
|
-
|
|
376
|
+
if (m) {
|
|
377
|
+
lines[idx] = m[2];
|
|
378
|
+
fixedLines.add(idx);
|
|
379
|
+
}
|
|
366
380
|
break;
|
|
367
381
|
}
|
|
368
382
|
case 'redundant_progn': {
|
|
@@ -374,16 +388,20 @@ function applyFixes(issues, content, filepath) {
|
|
|
374
388
|
const inner = lineContent.slice(proIdx + 7, close);
|
|
375
389
|
const rest = lineContent.slice(close + 1);
|
|
376
390
|
const fixed = beforePro + inner + rest;
|
|
377
|
-
if (fixed !== lineContent)
|
|
378
|
-
|
|
391
|
+
if (fixed !== lineContent) {
|
|
392
|
+
lines[idx] = fixed;
|
|
393
|
+
fixedLines.add(idx);
|
|
394
|
+
}
|
|
379
395
|
}
|
|
380
396
|
}
|
|
381
397
|
break;
|
|
382
398
|
}
|
|
383
399
|
case 'redundant_let': {
|
|
384
400
|
const fixed = lineContent.replace(/\(let\s+\(\)\s*/, '(progn ');
|
|
385
|
-
if (fixed !== lineContent)
|
|
386
|
-
|
|
401
|
+
if (fixed !== lineContent) {
|
|
402
|
+
lines[idx] = fixed;
|
|
403
|
+
fixedLines.add(idx);
|
|
404
|
+
}
|
|
387
405
|
break;
|
|
388
406
|
}
|
|
389
407
|
case 'quote_style': {
|
|
@@ -395,8 +413,10 @@ function applyFixes(issues, content, filepath) {
|
|
|
395
413
|
const quoted = lineContent.slice(qIdx + 7, close);
|
|
396
414
|
const rest = lineContent.slice(close + 1);
|
|
397
415
|
const fixed = beforeQ + "'" + quoted + rest;
|
|
398
|
-
if (fixed !== lineContent)
|
|
399
|
-
|
|
416
|
+
if (fixed !== lineContent) {
|
|
417
|
+
lines[idx] = fixed;
|
|
418
|
+
fixedLines.add(idx);
|
|
419
|
+
}
|
|
400
420
|
}
|
|
401
421
|
}
|
|
402
422
|
break;
|
|
@@ -410,8 +430,10 @@ function applyFixes(issues, content, filepath) {
|
|
|
410
430
|
const inner = lineContent.slice(pIdx + 7, close);
|
|
411
431
|
const rest = lineContent.slice(close + 1);
|
|
412
432
|
const fixed = beforeP + inner + rest;
|
|
413
|
-
if (fixed !== lineContent)
|
|
414
|
-
|
|
433
|
+
if (fixed !== lineContent) {
|
|
434
|
+
lines[idx] = fixed;
|
|
435
|
+
fixedLines.add(idx);
|
|
436
|
+
}
|
|
415
437
|
}
|
|
416
438
|
}
|
|
417
439
|
break;
|
|
@@ -436,18 +458,18 @@ function applyFixes(issues, content, filepath) {
|
|
|
436
458
|
if (thenForm && elseForm) {
|
|
437
459
|
const rest = lineContent.slice(ifClose + 1);
|
|
438
460
|
const fixed = indent + '(if ' + condVar + ' ' + elseForm + ' ' + thenForm + ')' + rest;
|
|
439
|
-
if (fixed !== lineContent)
|
|
440
|
-
|
|
461
|
+
if (fixed !== lineContent) {
|
|
462
|
+
lines[idx] = fixed;
|
|
463
|
+
fixedLines.add(idx);
|
|
464
|
+
}
|
|
441
465
|
}
|
|
442
466
|
}
|
|
443
467
|
break;
|
|
444
468
|
}
|
|
445
469
|
case 'redundant_setq': {
|
|
446
|
-
const
|
|
447
|
-
const trimmed = allLines[idx].trim();
|
|
470
|
+
const trimmed = lines[idx].trim();
|
|
448
471
|
if (/^\(setq\s+(\S+)\s+\1\s*\)$/.test(trimmed)) {
|
|
449
|
-
|
|
450
|
-
result = allLines.join('\n');
|
|
472
|
+
lines.splice(idx, 1);
|
|
451
473
|
}
|
|
452
474
|
break;
|
|
453
475
|
}
|
|
@@ -456,12 +478,15 @@ function applyFixes(issues, content, filepath) {
|
|
|
456
478
|
if (fixed !== lineContent) {
|
|
457
479
|
const merged = lineContent.replace(/^\(\s*setq\s+/, '(setq ');
|
|
458
480
|
if (merged.includes('setq') && !merged.match(/\)\(/)) {
|
|
459
|
-
|
|
481
|
+
lines[idx] = merged;
|
|
482
|
+
fixedLines.add(idx);
|
|
460
483
|
}
|
|
461
484
|
else {
|
|
462
485
|
const simplified = lineContent.replace(/\)\(setq\s+/g, '\n');
|
|
463
|
-
if (simplified !== lineContent)
|
|
464
|
-
|
|
486
|
+
if (simplified !== lineContent) {
|
|
487
|
+
lines[idx] = simplified;
|
|
488
|
+
fixedLines.add(idx);
|
|
489
|
+
}
|
|
465
490
|
}
|
|
466
491
|
}
|
|
467
492
|
break;
|
|
@@ -475,8 +500,10 @@ function applyFixes(issues, content, filepath) {
|
|
|
475
500
|
const listMatch = inner.match(/^\(list\s+(.*)\)\s*$/);
|
|
476
501
|
if (listMatch) {
|
|
477
502
|
const fixed = lineContent.slice(0, aIdx) + '(cons ' + listMatch[1] + ')' + lineContent.slice(close + 1);
|
|
478
|
-
if (fixed !== lineContent)
|
|
479
|
-
|
|
503
|
+
if (fixed !== lineContent) {
|
|
504
|
+
lines[idx] = fixed;
|
|
505
|
+
fixedLines.add(idx);
|
|
506
|
+
}
|
|
480
507
|
}
|
|
481
508
|
}
|
|
482
509
|
}
|
|
@@ -484,40 +511,48 @@ function applyFixes(issues, content, filepath) {
|
|
|
484
511
|
}
|
|
485
512
|
case 'nth_usage': {
|
|
486
513
|
const fixed = lineContent.replace(/\(nth\s+0\s+/g, '(car ');
|
|
487
|
-
if (fixed !== lineContent)
|
|
488
|
-
|
|
514
|
+
if (fixed !== lineContent) {
|
|
515
|
+
lines[idx] = fixed;
|
|
516
|
+
fixedLines.add(idx);
|
|
517
|
+
}
|
|
489
518
|
break;
|
|
490
519
|
}
|
|
491
520
|
case 'setq_single_arg': {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
allLines.splice(idx, 1);
|
|
495
|
-
result = allLines.join('\n');
|
|
521
|
+
if (/^\s*\(setq\s+\S+\s*\)\s*$/.test(lines[idx])) {
|
|
522
|
+
lines.splice(idx, 1);
|
|
496
523
|
}
|
|
497
524
|
break;
|
|
498
525
|
}
|
|
499
526
|
case 'extra_parens': {
|
|
500
527
|
const fixed = lineContent.replace(/\){2,}/g, ')');
|
|
501
|
-
if (fixed !== lineContent)
|
|
502
|
-
|
|
528
|
+
if (fixed !== lineContent) {
|
|
529
|
+
lines[idx] = fixed;
|
|
530
|
+
fixedLines.add(idx);
|
|
531
|
+
}
|
|
503
532
|
break;
|
|
504
533
|
}
|
|
505
534
|
case 'empty_branch': {
|
|
506
535
|
const fixed = lineContent.replace(/\(if\s+\S+\s*\)/g, m => m.slice(0, -1) + ' nil)');
|
|
507
|
-
if (fixed !== lineContent)
|
|
508
|
-
|
|
536
|
+
if (fixed !== lineContent) {
|
|
537
|
+
lines[idx] = fixed;
|
|
538
|
+
fixedLines.add(idx);
|
|
539
|
+
}
|
|
509
540
|
break;
|
|
510
541
|
}
|
|
511
542
|
case 'comment_style': {
|
|
512
543
|
const fixed = lineContent.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
|
|
513
|
-
if (fixed !== lineContent)
|
|
514
|
-
|
|
544
|
+
if (fixed !== lineContent) {
|
|
545
|
+
lines[idx] = fixed;
|
|
546
|
+
fixedLines.add(idx);
|
|
547
|
+
}
|
|
515
548
|
break;
|
|
516
549
|
}
|
|
517
550
|
case 'eq_usage': {
|
|
518
551
|
const fixed = lineContent.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
|
|
519
|
-
if (fixed !== lineContent)
|
|
520
|
-
|
|
552
|
+
if (fixed !== lineContent) {
|
|
553
|
+
lines[idx] = fixed;
|
|
554
|
+
fixedLines.add(idx);
|
|
555
|
+
}
|
|
521
556
|
break;
|
|
522
557
|
}
|
|
523
558
|
case 'cond_simplify': {
|
|
@@ -538,8 +573,10 @@ function applyFixes(issues, content, filepath) {
|
|
|
538
573
|
const bodyExpr = branchContent.slice(space).trim();
|
|
539
574
|
const rest = lineContent.slice(condEnd + 1);
|
|
540
575
|
const fixed = indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
|
|
541
|
-
if (fixed !== lineContent)
|
|
542
|
-
|
|
576
|
+
if (fixed !== lineContent) {
|
|
577
|
+
lines[idx] = fixed;
|
|
578
|
+
fixedLines.add(idx);
|
|
579
|
+
}
|
|
543
580
|
}
|
|
544
581
|
}
|
|
545
582
|
}
|
|
@@ -549,34 +586,31 @@ function applyFixes(issues, content, filepath) {
|
|
|
549
586
|
}
|
|
550
587
|
case 'self_compare': {
|
|
551
588
|
const fixed = lineContent.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
|
|
552
|
-
if (fixed !== lineContent)
|
|
553
|
-
|
|
589
|
+
if (fixed !== lineContent) {
|
|
590
|
+
lines[idx] = fixed;
|
|
591
|
+
fixedLines.add(idx);
|
|
592
|
+
}
|
|
554
593
|
break;
|
|
555
594
|
}
|
|
556
595
|
case 'while_constant': {
|
|
557
|
-
const
|
|
558
|
-
const trimmed = allLines[idx].trim();
|
|
596
|
+
const trimmed = lines[idx].trim();
|
|
559
597
|
const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
|
|
560
598
|
if (nilMatch) {
|
|
561
|
-
|
|
562
|
-
result = allLines.join('\n');
|
|
599
|
+
lines[idx] = lines[idx].replace(trimmed, 'nil');
|
|
563
600
|
}
|
|
564
601
|
break;
|
|
565
602
|
}
|
|
566
603
|
case 'redundant_list': {
|
|
567
604
|
const fixed = lineContent.replace(/\(\s*list\s*\)/g, 'nil');
|
|
568
|
-
if (fixed !== lineContent)
|
|
569
|
-
|
|
605
|
+
if (fixed !== lineContent) {
|
|
606
|
+
lines[idx] = fixed;
|
|
607
|
+
fixedLines.add(idx);
|
|
608
|
+
}
|
|
570
609
|
break;
|
|
571
610
|
}
|
|
572
611
|
}
|
|
573
612
|
}
|
|
574
613
|
}
|
|
575
|
-
return result;
|
|
576
|
-
}
|
|
577
|
-
function replaceLine(content, lineIdx, newLine) {
|
|
578
|
-
const lines = content.split('\n');
|
|
579
|
-
lines[lineIdx] = newLine;
|
|
580
614
|
return lines.join('\n');
|
|
581
615
|
}
|
|
582
616
|
function parseIgnoreFile(rootDir) {
|
|
@@ -593,23 +627,51 @@ const UTF8_BOM = 0xfeff;
|
|
|
593
627
|
function fixFile(filepath) {
|
|
594
628
|
const fixes = [];
|
|
595
629
|
let content = fs.readFileSync(filepath, 'utf-8');
|
|
596
|
-
|
|
597
|
-
.split('\n')
|
|
598
|
-
.map(l => l.replace(/[ \t]+$/, ''))
|
|
599
|
-
.join('\n');
|
|
600
|
-
if (wsFixed !== content) {
|
|
601
|
-
content = wsFixed;
|
|
602
|
-
fixes.push('trailing_whitespace');
|
|
603
|
-
}
|
|
630
|
+
// 1. Remove BOM
|
|
604
631
|
if (content.charCodeAt(0) === UTF8_BOM) {
|
|
605
632
|
content = content.slice(1);
|
|
606
633
|
fixes.push('encoding (BOM)');
|
|
607
634
|
}
|
|
635
|
+
// 2. Single line pass: trailing whitespace + empty comment lines
|
|
636
|
+
const origLines = content.split('\n');
|
|
637
|
+
let wsChanged = false;
|
|
638
|
+
let ecChanged = false;
|
|
639
|
+
const processed = origLines.map(l => {
|
|
640
|
+
const stripped = l.replace(/[ \t]+$/, '');
|
|
641
|
+
if (stripped !== l)
|
|
642
|
+
wsChanged = true;
|
|
643
|
+
if (/^\s*;\s*$/.test(stripped)) {
|
|
644
|
+
ecChanged = true;
|
|
645
|
+
return '';
|
|
646
|
+
}
|
|
647
|
+
return stripped;
|
|
648
|
+
});
|
|
649
|
+
if (wsChanged)
|
|
650
|
+
fixes.push('trailing_whitespace');
|
|
651
|
+
if (ecChanged)
|
|
652
|
+
fixes.push('empty_comment');
|
|
653
|
+
if (wsChanged || ecChanged)
|
|
654
|
+
content = processed.join('\n');
|
|
655
|
+
// 3. Count parens (string/comment aware), fix trailing excess
|
|
608
656
|
let openCount = 0;
|
|
609
657
|
let closeCount = 0;
|
|
610
|
-
let
|
|
611
|
-
for (let i = 0; i <
|
|
612
|
-
const ch =
|
|
658
|
+
let inStr = false;
|
|
659
|
+
for (let i = 0; i < content.length; i++) {
|
|
660
|
+
const ch = content[i];
|
|
661
|
+
if (ch === '"') {
|
|
662
|
+
inStr = !inStr;
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
if (inStr) {
|
|
666
|
+
if (ch === '\\')
|
|
667
|
+
i++;
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (ch === ';') {
|
|
671
|
+
const nl = content.indexOf('\n', i);
|
|
672
|
+
i = nl !== -1 ? nl : content.length;
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
613
675
|
if (ch === '(')
|
|
614
676
|
openCount++;
|
|
615
677
|
else if (ch === ')')
|
|
@@ -617,29 +679,17 @@ function fixFile(filepath) {
|
|
|
617
679
|
}
|
|
618
680
|
if (closeCount > openCount) {
|
|
619
681
|
let excess = closeCount - openCount;
|
|
620
|
-
|
|
621
|
-
|
|
682
|
+
let fixed = content;
|
|
683
|
+
while (excess > 0 && fixed.endsWith(')')) {
|
|
684
|
+
fixed = fixed.slice(0, -1);
|
|
622
685
|
excess--;
|
|
623
686
|
}
|
|
624
|
-
|
|
625
|
-
if (
|
|
626
|
-
content =
|
|
687
|
+
fixed = fixed.replace(/\n[ \t]*$/, '');
|
|
688
|
+
if (fixed !== content) {
|
|
689
|
+
content = fixed;
|
|
627
690
|
fixes.push('trailing_paren');
|
|
628
691
|
}
|
|
629
692
|
}
|
|
630
|
-
const lines = content.split('\n');
|
|
631
|
-
let changed = false;
|
|
632
|
-
const fixedLines = lines.map(l => {
|
|
633
|
-
if (/^\s*;\s*$/.test(l)) {
|
|
634
|
-
changed = true;
|
|
635
|
-
return '';
|
|
636
|
-
}
|
|
637
|
-
return l;
|
|
638
|
-
});
|
|
639
|
-
if (changed) {
|
|
640
|
-
content = fixedLines.join('\n');
|
|
641
|
-
fixes.push('empty_comment');
|
|
642
|
-
}
|
|
643
693
|
if (fixes.length > 0) {
|
|
644
694
|
fs.writeFileSync(filepath, content, 'utf-8');
|
|
645
695
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
((AUTOLISP ())
|
|
2
|
+
(@ (COMMON-LISP AUTOLISP))
|
|
3
|
+
(C ())
|
|
4
|
+
(JSON ())
|
|
5
|
+
(SIDEBAR ())
|
|
6
|
+
(FUN ())
|
|
7
|
+
(DCL ())
|
|
8
|
+
(BASE ())
|
|
9
|
+
(STRING ())
|
|
10
|
+
(BLOCK ())
|
|
11
|
+
(ENTITY ())
|
|
12
|
+
(LAYER ())
|
|
13
|
+
(LAYOUT ())
|
|
14
|
+
(CURVE ())
|
|
15
|
+
(LIST ())
|
|
16
|
+
(M ())
|
|
17
|
+
(P ())
|
|
18
|
+
(UI ())
|
|
19
|
+
(SYS ())
|
|
20
|
+
(EXCEL ())
|
|
21
|
+
(WORD ())
|
|
22
|
+
(RE ())
|
|
23
|
+
(VECTRA ())
|
|
24
|
+
(DOS ())
|
|
25
|
+
(AT-PM ())
|
|
26
|
+
(QRENCODE ())
|
|
27
|
+
(NETWORK ())
|
|
28
|
+
(PKGMAN ())
|
|
29
|
+
(DATETIME ())
|
|
30
|
+
(DICT ())
|
|
31
|
+
(@NLP ())
|
|
32
|
+
(AT-SIDEBAR ())
|
|
33
|
+
(S ())
|
|
34
|
+
(VL ())
|
|
35
|
+
(VLR ())
|
|
36
|
+
(VLAX ())
|
|
37
|
+
(THEME ())
|
|
38
|
+
(AJAX ())
|
|
39
|
+
(ATLISP ())
|
|
40
|
+
(LOG ())
|
|
41
|
+
(ATLISP-CORE ()))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlisp/lint",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "AutoLISP static analysis tool — parens, security, conventions, SBCL syntax validation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CAD",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"prepack": "npm run build"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@atlisp/parser": "^0.1.
|
|
40
|
+
"@atlisp/parser": "^0.1.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/jest": "^29",
|