@atlisp/lint 0.1.22 → 0.1.23

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/dist/runner.d.ts CHANGED
@@ -3,6 +3,7 @@ export declare function runChecks(content: string, file: string, config: LintCon
3
3
  export declare function runChecksWithVisitorWrapper(content: string, file: string, config: LintConfig): Issue[];
4
4
  export declare function lintFiles(files: string[], config: LintConfig, rootDir: string): Issue[];
5
5
  export declare function lintFilesParallel(files: string[], config: LintConfig, rootDir: string): Promise<Issue[]>;
6
+ export declare const FIXABLE_RULES: Set<string>;
6
7
  export declare function applyFixes(issues: Issue[], content: string, filepath: string): string;
7
8
  export declare function parseIgnoreFile(rootDir: string): string[];
8
9
  export declare function fixFile(filepath: string): string[];
package/dist/runner.js CHANGED
@@ -33,6 +33,7 @@ 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
37
  exports.runChecks = runChecks;
37
38
  exports.runChecksWithVisitorWrapper = runChecksWithVisitorWrapper;
38
39
  exports.lintFiles = lintFiles;
@@ -308,6 +309,16 @@ function extractForm(s, start) {
308
309
  const end = findMatchingParen(s, i);
309
310
  return [s.slice(i, end + 1), end + 1];
310
311
  }
312
+ // ===== FIX APPLICATION =====
313
+ exports.FIXABLE_RULES = new Set([
314
+ 'redundant_quotes', 'double_not', 'redundant_nil_else',
315
+ 'single_arg_and_or', 'redundant_setq', 'redundant_progn',
316
+ 'redundant_let', 'quote_style', 'redundant_if', 'misplaced_else',
317
+ 'setq_multiple', 'append_single', 'nth_usage', 'setq_single_arg',
318
+ 'extra_parens', 'empty_branch',
319
+ 'comment_style', 'eq_usage', 'cond_simplify', 'self_compare',
320
+ 'while_constant', 'redundant_list',
321
+ ]);
311
322
  function applyFixes(issues, content, filepath) {
312
323
  const lines = content.split('\n');
313
324
  const fixesByRule = new Map();
@@ -318,13 +329,7 @@ function applyFixes(issues, content, filepath) {
318
329
  set.add(iss.line);
319
330
  fixesByRule.set(iss.rule, set);
320
331
  }
321
- const fixableRules = new Set([
322
- 'redundant_quotes', 'double_not', 'redundant_nil_else',
323
- 'single_arg_and_or', 'redundant_setq', 'redundant_progn',
324
- 'redundant_let', 'quote_style', 'redundant_if', 'misplaced_else',
325
- 'setq_multiple', 'append_single', 'nth_usage', 'setq_single_arg',
326
- 'extra_parens', 'empty_branch',
327
- ]);
332
+ const fixableRules = exports.FIXABLE_RULES;
328
333
  let result = content;
329
334
  for (const [rule, lineSet] of fixesByRule) {
330
335
  if (!fixableRules.has(rule))
@@ -503,6 +508,67 @@ function applyFixes(issues, content, filepath) {
503
508
  result = replaceLine(result, idx, fixed);
504
509
  break;
505
510
  }
511
+ case 'comment_style': {
512
+ const fixed = lineContent.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
513
+ if (fixed !== lineContent)
514
+ result = replaceLine(result, idx, fixed);
515
+ break;
516
+ }
517
+ case 'eq_usage': {
518
+ const fixed = lineContent.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
519
+ if (fixed !== lineContent)
520
+ result = replaceLine(result, idx, fixed);
521
+ break;
522
+ }
523
+ case 'cond_simplify': {
524
+ const condIdx = lineContent.indexOf('(cond ');
525
+ if (condIdx !== -1) {
526
+ const condEnd = findMatchingParen(lineContent, condIdx);
527
+ if (condEnd > condIdx) {
528
+ const inner = lineContent.slice(condIdx + 6, condEnd).trim();
529
+ const branchOpen = inner.indexOf('(');
530
+ if (branchOpen !== -1) {
531
+ const branchEnd = findMatchingParen(inner, branchOpen);
532
+ if (branchEnd > branchOpen) {
533
+ const indent = lineContent.slice(0, condIdx);
534
+ const branchContent = inner.slice(branchOpen + 1, branchEnd).trim();
535
+ const space = branchContent.search(/\s+/);
536
+ if (space !== -1) {
537
+ const testExpr = branchContent.slice(0, space);
538
+ const bodyExpr = branchContent.slice(space).trim();
539
+ const rest = lineContent.slice(condEnd + 1);
540
+ const fixed = indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
541
+ if (fixed !== lineContent)
542
+ result = replaceLine(result, idx, fixed);
543
+ }
544
+ }
545
+ }
546
+ }
547
+ }
548
+ break;
549
+ }
550
+ case 'self_compare': {
551
+ const fixed = lineContent.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
552
+ if (fixed !== lineContent)
553
+ result = replaceLine(result, idx, fixed);
554
+ break;
555
+ }
556
+ case 'while_constant': {
557
+ const allLines = result.split('\n');
558
+ const trimmed = allLines[idx].trim();
559
+ const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
560
+ if (nilMatch) {
561
+ allLines[idx] = allLines[idx].replace(trimmed, 'nil');
562
+ result = allLines.join('\n');
563
+ }
564
+ break;
565
+ }
566
+ case 'redundant_list': {
567
+ const fixed = lineContent.replace(/\(\s*list\s*\)/g, 'nil');
568
+ if (fixed !== lineContent)
569
+ result = replaceLine(result, idx, fixed);
570
+ break;
571
+ }
506
572
  }
507
573
  }
508
574
  }
@@ -17,7 +17,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
17
17
  openCount: 0,
18
18
  closeCount: 0,
19
19
  setqDefs: new Map(),
20
- symbolRefs: new Set(),
20
+ symbolRefs: new Map(),
21
21
  condKeys: new Map(),
22
22
  defunScopes: [],
23
23
  letScopes: [],
@@ -379,9 +379,9 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
379
379
  const seen = new Set();
380
380
  for (let i = 1; i < node.children.length; i++) {
381
381
  const clause = node.children[i];
382
- if (clause.type !== 'list' || !clause.children || clause.children.length < 2)
382
+ if (clause.type !== 'list' || !clause.children || clause.children.length < 1)
383
383
  continue;
384
- const condTest = clause.children[1];
384
+ const condTest = clause.children[0];
385
385
  const key = getCondKey(condTest);
386
386
  if (seen.has(key)) {
387
387
  addIssue('cond_duplicate', clause.pos.line, (0, locale_1.t)('cond_duplicate'));
@@ -574,7 +574,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
574
574
  if (checks['unused_variable'] !== 'off') {
575
575
  visitor.on('*', node => {
576
576
  if (node.type === 'symbol' && node.name) {
577
- state.symbolRefs.add(node.name);
577
+ state.symbolRefs.set(node.name, (state.symbolRefs.get(node.name) || 0) + 1);
578
578
  }
579
579
  });
580
580
  }
@@ -672,11 +672,7 @@ function runChecksWithVisitor(ast, file, config, disableMap) {
672
672
  if (checks['unused_variable'] !== 'off') {
673
673
  for (const [name, def] of state.setqDefs) {
674
674
  if (state.setqDefs.size > 1) {
675
- let refCount = 0;
676
- for (const ref of state.symbolRefs) {
677
- if (ref === name)
678
- refCount++;
679
- }
675
+ const refCount = state.symbolRefs.get(name) || 0;
680
676
  if (refCount <= 1) {
681
677
  addIssue('unused_variable', def.line, (0, locale_1.t)('unused_variable', name));
682
678
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlisp/lint",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "AutoLISP static analysis tool — parens, security, conventions, SBCL syntax validation",
5
5
  "keywords": [
6
6
  "CAD",