@sun-asterisk/sunlint 1.3.0 → 1.3.1

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 (73) hide show
  1. package/CHANGELOG.md +68 -1
  2. package/CONTRIBUTING.md +1179 -54
  3. package/README.md +3 -4
  4. package/config/ci-cd.json +54 -0
  5. package/config/development.json +56 -0
  6. package/config/large-project.json +143 -0
  7. package/config/presets/all.json +0 -1
  8. package/config/release.json +70 -0
  9. package/config/rule-analysis-strategies.js +23 -4
  10. package/config/rules/S027-categories.json +122 -0
  11. package/config/rules/enhanced-rules-registry.json +136 -75
  12. package/config/rules/rules-registry-generated.json +2 -2
  13. package/config/rules/rules-registry.json +13 -1
  14. package/core/cli-action-handler.js +24 -30
  15. package/core/cli-program.js +11 -3
  16. package/core/config-merger.js +29 -2
  17. package/core/enhanced-rules-registry.js +3 -3
  18. package/core/semantic-engine.js +117 -19
  19. package/core/unified-rule-registry.js +1 -1
  20. package/docs/COMMAND-EXAMPLES.md +134 -0
  21. package/docs/LARGE-PROJECT-GUIDE.md +324 -0
  22. package/engines/heuristic-engine.js +71 -13
  23. package/integrations/eslint/plugin/index.js +0 -2
  24. package/origin-rules/common-en.md +8 -8
  25. package/package.json +1 -1
  26. package/rules/common/C017_constructor_logic/analyzer.js +254 -17
  27. package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
  28. package/rules/common/C033_separate_service_repository/README.md +78 -0
  29. package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
  30. package/rules/common/C033_separate_service_repository/config.json +50 -0
  31. package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
  32. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
  33. package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
  34. package/rules/common/C035_error_logging_context/analyzer.js +230 -0
  35. package/rules/common/C035_error_logging_context/config.json +54 -0
  36. package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
  37. package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
  38. package/rules/common/C040_centralized_validation/analyzer.js +165 -0
  39. package/rules/common/C040_centralized_validation/config.json +46 -0
  40. package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
  41. package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
  42. package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
  43. package/rules/common/C076_explicit_function_types/README.md +30 -0
  44. package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
  45. package/rules/common/C076_explicit_function_types/config.json +15 -0
  46. package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
  47. package/rules/index.js +1 -0
  48. package/rules/parser/rule-parser.js +13 -2
  49. package/rules/security/S005_no_origin_auth/README.md +226 -0
  50. package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
  51. package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
  52. package/rules/security/S005_no_origin_auth/config.json +85 -0
  53. package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
  54. package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
  55. package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
  56. package/rules/security/S007_no_plaintext_otp/README.md +198 -0
  57. package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
  58. package/rules/security/S007_no_plaintext_otp/config.json +79 -0
  59. package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
  60. package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
  61. package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
  62. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
  63. package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
  64. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
  65. package/scripts/prepare-release.sh +1 -1
  66. package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
  67. package/docs/FUTURE_PACKAGES.md +0 -83
  68. package/docs/HEURISTIC_VS_AI.md +0 -113
  69. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
  70. package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
  71. package/docs/RELEASE_GUIDE.md +0 -230
  72. package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
  73. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
@@ -332,6 +332,34 @@
332
332
  ]
333
333
  }
334
334
  },
335
+ "C035": {
336
+ "name": "Log all relevant context when handling errors",
337
+ "description": "When handling errors, must log full information related - structured logging with context",
338
+ "category": "error-handling",
339
+ "severity": "warning",
340
+ "languages": [
341
+ "typescript",
342
+ "javascript",
343
+ "dart",
344
+ "kotlin"
345
+ ],
346
+ "analyzer": "./rules/common/C035_error_logging_context/analyzer.js",
347
+ "config": "./rules/common/C035_error_logging_context/config.json",
348
+ "version": "1.0.0",
349
+ "status": "stable",
350
+ "tags": [
351
+ "logging",
352
+ "error-handling",
353
+ "observability",
354
+ "debugging"
355
+ ],
356
+ "engineMappings": {
357
+ "eslint": [
358
+ "no-empty-catch",
359
+ "@typescript-eslint/no-unused-vars"
360
+ ]
361
+ }
362
+ },
335
363
  "C037": {
336
364
  "name": "Standard Response Objects",
337
365
  "description": "API handlers should return standard response objects (not raw strings)",
@@ -445,25 +473,6 @@
445
473
  }
446
474
  }
447
475
  },
448
- "C076": {
449
- "name": "One Assert Per Test",
450
- "description": "Each test should assert only one behavior (Single Assert Rule)",
451
- "category": "testing",
452
- "severity": "warning",
453
- "languages": [
454
- "typescript",
455
- "javascript"
456
- ],
457
- "analyzer": "eslint",
458
- "eslintRule": "custom/c076",
459
- "version": "1.0.0",
460
- "status": "stable",
461
- "tags": [
462
- "testing",
463
- "unit-test",
464
- "assertion"
465
- ]
466
- },
467
476
  "S001": {
468
477
  "name": "Fail Securely",
469
478
  "description": "Verify that if there is an error in access control, the system fails securely",
@@ -541,34 +550,56 @@
541
550
  "typescript",
542
551
  "javascript"
543
552
  ],
544
- "analyzer": "eslint",
545
- "eslintRule": "custom/typescript_s005",
553
+ "analyzer": "./rules/security/S005_no_origin_auth/analyzer.js",
546
554
  "version": "1.0.0",
547
555
  "status": "stable",
548
556
  "tags": [
549
557
  "security",
550
558
  "authentication",
551
559
  "headers"
552
- ]
560
+ ],
561
+ "strategy": {
562
+ "preferred": "ast",
563
+ "fallbacks": [
564
+ "ast",
565
+ "regex"
566
+ ],
567
+ "accuracy": {
568
+ "ast": 95,
569
+ "regex": 85
570
+ }
571
+ },
572
+ "engineMappings": {
573
+ "eslint": [
574
+ "custom/typescript_s005"
575
+ ]
576
+ }
553
577
  },
554
578
  "S006": {
555
- "name": "Activation Recovery Secret Not Plaintext",
556
- "description": "Activation recovery secret must not be in plaintext",
579
+ "name": "No Plaintext Recovery/Activation Codes",
580
+ "description": "Do not send recovery or activation codes in plaintext",
557
581
  "category": "security",
558
582
  "severity": "error",
559
583
  "languages": [
560
- "typescript",
561
- "javascript"
584
+ "All languages"
562
585
  ],
563
- "analyzer": "eslint",
564
- "eslintRule": "custom/typescript_s006",
586
+ "analyzer": "./rules/security/S006_no_plaintext_recovery_codes/analyzer.js",
587
+ "config": "./rules/security/S006_no_plaintext_recovery_codes/config.json",
565
588
  "version": "1.0.0",
566
589
  "status": "stable",
567
590
  "tags": [
568
591
  "security",
569
- "secrets",
570
- "encryption"
571
- ]
592
+ "owasp",
593
+ "cryptographic-failures",
594
+ "authentication"
595
+ ],
596
+ "strategy": {
597
+ "preferred": "regex",
598
+ "fallback": "heuristic"
599
+ },
600
+ "engineMappings": {
601
+ "heuristic": "S006_no_plaintext_recovery_codes"
602
+ }
572
603
  },
573
604
  "S007": {
574
605
  "name": "No Plaintext OTP",
@@ -577,17 +608,40 @@
577
608
  "severity": "error",
578
609
  "languages": [
579
610
  "typescript",
580
- "javascript"
611
+ "javascript",
612
+ "dart",
613
+ "kotlin",
614
+ "java",
615
+ "python",
616
+ "go",
617
+ "swift"
581
618
  ],
582
- "analyzer": "eslint",
583
- "eslintRule": "custom/typescript_s007",
619
+ "analyzer": "./rules/security/S007_no_plaintext_otp/analyzer.js",
620
+ "config": "./rules/security/S007_no_plaintext_otp/config.json",
584
621
  "version": "1.0.0",
585
622
  "status": "stable",
586
623
  "tags": [
587
624
  "security",
588
625
  "otp",
589
- "encryption"
590
- ]
626
+ "encryption",
627
+ "owasp",
628
+ "cryptographic-failures",
629
+ "authentication"
630
+ ],
631
+ "strategy": {
632
+ "preferred": "heuristic",
633
+ "fallbacks": [
634
+ "heuristic",
635
+ "regex"
636
+ ],
637
+ "accuracy": {
638
+ "heuristic": 90,
639
+ "regex": 75
640
+ }
641
+ },
642
+ "engineMappings": {
643
+ "heuristic": "S007_no_plaintext_otp"
644
+ }
591
645
  },
592
646
  "S008": {
593
647
  "name": "Crypto Agility",
@@ -1525,13 +1579,15 @@
1525
1579
  ]
1526
1580
  },
1527
1581
  "strategy": {
1528
- "preferred": "ast",
1582
+ "preferred": "semantic",
1529
1583
  "fallbacks": [
1530
- "ast",
1584
+ "semantic",
1585
+ "ast",
1531
1586
  "regex"
1532
1587
  ],
1533
1588
  "accuracy": {
1534
- "ast": 90,
1589
+ "semantic": 95,
1590
+ "ast": 85,
1535
1591
  "regex": 70
1536
1592
  }
1537
1593
  }
@@ -1620,35 +1676,6 @@
1620
1676
  "accuracy": {}
1621
1677
  }
1622
1678
  },
1623
- "C035": {
1624
- "id": "C035",
1625
- "name": "Rule C035",
1626
- "description": "Auto-migrated rule C035 from ESLint mapping",
1627
- "category": "general",
1628
- "severity": "warning",
1629
- "languages": [
1630
- "typescript",
1631
- "javascript"
1632
- ],
1633
- "version": "1.0.0",
1634
- "status": "migrated",
1635
- "tags": [
1636
- "migrated"
1637
- ],
1638
- "engineMappings": {
1639
- "eslint": [
1640
- "no-empty-catch",
1641
- "@typescript-eslint/no-unused-vars"
1642
- ]
1643
- },
1644
- "strategy": {
1645
- "preferred": "regex",
1646
- "fallbacks": [
1647
- "regex"
1648
- ],
1649
- "accuracy": {}
1650
- }
1651
- },
1652
1679
  "C041": {
1653
1680
  "id": "C041",
1654
1681
  "name": "Rule C041",
@@ -1735,22 +1762,27 @@
1735
1762
  },
1736
1763
  "C072": {
1737
1764
  "id": "C072",
1738
- "name": "Rule C072",
1739
- "description": "Auto-migrated rule C072 from ESLint mapping",
1740
- "category": "general",
1765
+ "name": "Single Test Behavior",
1766
+ "description": "Each test should assert only one behavior",
1767
+ "category": "testing",
1741
1768
  "severity": "warning",
1742
1769
  "languages": [
1743
1770
  "typescript",
1744
1771
  "javascript"
1745
1772
  ],
1746
1773
  "version": "1.0.0",
1747
- "status": "migrated",
1774
+ "status": "stable",
1748
1775
  "tags": [
1749
- "migrated"
1776
+ "testing",
1777
+ "unit-test",
1778
+ "single-behavior"
1750
1779
  ],
1751
1780
  "engineMappings": {
1752
1781
  "eslint": [
1753
- "custom/one-assert-per-test"
1782
+ "custom/c072-one-assert-per-test"
1783
+ ],
1784
+ "heuristic": [
1785
+ "rules/common/C072_single_test_behavior/analyzer.js"
1754
1786
  ]
1755
1787
  },
1756
1788
  "strategy": {
@@ -1789,6 +1821,36 @@
1789
1821
  "accuracy": {}
1790
1822
  }
1791
1823
  },
1824
+ "C076": {
1825
+ "id": "C076",
1826
+ "name": "Explicit Function Argument Types",
1827
+ "description": "All public functions must declare explicit types for arguments",
1828
+ "category": "type-safety",
1829
+ "severity": "error",
1830
+ "languages": [
1831
+ "typescript",
1832
+ "javascript"
1833
+ ],
1834
+ "version": "1.0.0",
1835
+ "status": "stable",
1836
+ "tags": [
1837
+ "type-safety",
1838
+ "public-api",
1839
+ "explicit-types"
1840
+ ],
1841
+ "engineMappings": {
1842
+ "heuristic": [
1843
+ "rules/common/C076_explicit_function_types/semantic-analyzer.js"
1844
+ ]
1845
+ },
1846
+ "strategy": {
1847
+ "preferred": "symbol",
1848
+ "fallbacks": [
1849
+ "symbol"
1850
+ ],
1851
+ "accuracy": {}
1852
+ }
1853
+ },
1792
1854
  "T002": {
1793
1855
  "id": "T002",
1794
1856
  "name": "Rule T002",
@@ -2300,7 +2362,6 @@
2300
2362
  "C047",
2301
2363
  "C072",
2302
2364
  "C075",
2303
- "C076",
2304
2365
  "T002",
2305
2366
  "T003",
2306
2367
  "T004",
@@ -914,7 +914,7 @@
914
914
  },
915
915
  "C039": {
916
916
  "name": "Do not store temporary data in global or static mutable fields",
917
- "description": "No description available",
917
+ "description": "Prevent issues related to shared state and race conditions in concurrent environments. Ensure thread-safety and testability. Using global or static mutable fields can introduce hard-to-detect and hard-to-fix bugs.",
918
918
  "category": "Common",
919
919
  "severity": "major",
920
920
  "languages": [
@@ -937,7 +937,7 @@
937
937
  },
938
938
  "C040": {
939
939
  "name": "Do not spread validation logic across multiple classes",
940
- "description": "No description available",
940
+ "description": "Centralize validation logic to simplify maintenance, increase reusability, and ensure consistency. Centralized validation helps reduce bugs and simplifies updating validation rules.",
941
941
  "category": "Common",
942
942
  "severity": "major",
943
943
  "languages": [
@@ -59,6 +59,18 @@
59
59
  "status": "experimental",
60
60
  "tags": ["validation", "separation", "architecture"]
61
61
  },
62
+ "C035": {
63
+ "name": "Error Logging Context",
64
+ "description": "Khi xử lý lỗi, phải ghi log đầy đủ thông tin liên quan - structured logging with context",
65
+ "category": "logging",
66
+ "severity": "warning",
67
+ "languages": ["typescript", "javascript"],
68
+ "analyzer": "./rules/common/C035_error_logging_context/analyzer.js",
69
+ "config": "./rules/common/C035_error_logging_context/config.json",
70
+ "version": "1.0.0",
71
+ "status": "experimental",
72
+ "tags": ["logging", "error-handling", "context", "structured-logging"]
73
+ },
62
74
  "C043": {
63
75
  "name": "No Console Or Print",
64
76
  "description": "Do not use console.log or print in production code",
@@ -651,7 +663,7 @@
651
663
  "quality": {
652
664
  "name": "Code Quality",
653
665
  "description": "Rules for code quality improvement",
654
- "rules": ["C002", "C003", "C006", "C010", "C013", "C014", "C017", "C018", "C023", "C029", "C030", "C035", "C041", "C042", "C043", "C047", "C072", "C075", "C076", "T002", "T003", "T004", "T007", "T010", "T019", "T020", "T021", "R001", "R002", "R003", "R004", "R005", "R006"],
666
+ "rules": ["C002", "C003", "C006", "C010", "C013", "C014", "C017", "C018", "C023", "C029", "C030", "C035", "C041", "C042", "C043", "C047", "C072", "C075", "T002", "T003", "T004", "T007", "T010", "T019", "T020", "T021", "R001", "R002", "R003", "R004", "R005", "R006"],
655
667
  "severity": "warning"
656
668
  },
657
669
  "security": {
@@ -109,21 +109,29 @@ class CliActionHandler {
109
109
  }
110
110
 
111
111
  /**
112
- * Run analysis with modern orchestrator
113
- * Following Rule C006: Verb-noun naming
114
- * Following Rule C012: Command Query Separation - analysis is a command
112
+ * Run analysis using modern orchestrator
115
113
  */
116
114
  async runModernAnalysis(rulesToRun, files, config) {
117
115
  if (this.isModernMode) {
118
116
  console.log(chalk.blue('🚀 Using modern engine architecture'));
119
117
 
120
- // Initialize orchestrator with configuration
118
+ // Initialize orchestrator with configuration including targetFiles for optimization
121
119
  await this.orchestrator.initialize({
122
120
  enabledEngines: this.determineEnabledEngines(config),
123
121
  aiConfig: config.ai || {},
124
122
  eslintConfig: config.eslint || {},
125
- heuristicConfig: config.heuristic || {}
123
+ heuristicConfig: {
124
+ ...config.heuristic || {},
125
+ targetFiles: this.options.targetFiles, // Pass filtered files for semantic optimization
126
+ maxSemanticFiles: this.options.maxSemanticFiles !== undefined ? parseInt(this.options.maxSemanticFiles) : 1000, // Configurable semantic file limit
127
+ verbose: this.options.verbose // Pass verbose for debugging
128
+ }
126
129
  });
130
+
131
+ if (this.options.verbose) {
132
+ console.log(`🔧 Debug: maxSemanticFiles option = ${this.options.maxSemanticFiles}`);
133
+ console.log(`🔧 Debug: parsed maxSemanticFiles = ${this.options.maxSemanticFiles !== undefined ? parseInt(this.options.maxSemanticFiles) : 1000}`);
134
+ }
127
135
 
128
136
  // Run analysis with new orchestrator
129
137
  const results = await this.orchestrator.analyze(files, rulesToRun, {
@@ -136,21 +144,7 @@ class CliActionHandler {
136
144
  requestedEngine: this.options.engine
137
145
  }
138
146
  });
139
-
140
147
  return results;
141
- } else {
142
- console.log(chalk.yellow('🔄 Using legacy orchestrator'));
143
-
144
- // Ensure verbose/quiet flags are in config
145
- const analysisConfig = {
146
- ...config,
147
- verbose: this.options.verbose,
148
- quiet: this.options.quiet,
149
- // Pass requested engine to enable strict engine mode (no fallback)
150
- requestedEngine: this.options.engine
151
- };
152
-
153
- return await this.orchestrator.runAnalysis(rulesToRun, this.options, analysisConfig);
154
148
  }
155
149
  }
156
150
 
@@ -268,6 +262,17 @@ class CliActionHandler {
268
262
  * Following Rule C031: Separate validation logic
269
263
  */
270
264
  validateInput(config) {
265
+ // Validate engine option if specified (check this first, always)
266
+ if (this.options.engine) {
267
+ const validEngines = ['eslint', 'heuristic', 'openai'];
268
+ if (!validEngines.includes(this.options.engine)) {
269
+ throw new Error(
270
+ chalk.red(`❌ Invalid engine: ${this.options.engine}\n`) +
271
+ chalk.gray(`Valid engines: ${validEngines.join(', ')}`)
272
+ );
273
+ }
274
+ }
275
+
271
276
  // Priority 1: CLI --input parameter (highest priority)
272
277
  if (this.options.input) {
273
278
  // Validate CLI input path exists
@@ -302,17 +307,6 @@ class CliActionHandler {
302
307
  }
303
308
  return;
304
309
  }
305
-
306
- // Validate engine option if specified
307
- if (this.options.engine) {
308
- const validEngines = ['eslint', 'sunlint', 'heuristic'];
309
- if (!validEngines.includes(this.options.engine)) {
310
- throw new Error(
311
- chalk.red(`❌ Invalid engine: ${this.options.engine}\n`) +
312
- chalk.gray(`Valid engines: ${validEngines.join(', ')}`)
313
- );
314
- }
315
- }
316
310
  }
317
311
 
318
312
  /**
@@ -26,7 +26,7 @@ function createCliProgram() {
26
26
  // TypeScript specific options (Phase 1 focus)
27
27
  program
28
28
  .option('--typescript', 'Enable TypeScript-specific analysis')
29
- .option('--typescript-engine <engine>', 'TypeScript analysis engine (eslint,sunlint,hybrid)', 'sunlint')
29
+ .option('--typescript-engine <engine>', 'TypeScript analysis engine (eslint,heuristic,hybrid)', 'heuristic')
30
30
  .option('--ensure-deps', 'Ensure ESLint dependencies are installed');
31
31
 
32
32
  // Input/Output options (v1.x: explicit --input required)
@@ -58,7 +58,7 @@ function createCliProgram() {
58
58
 
59
59
  // Advanced options
60
60
  program
61
- .option('--engine <engine>', 'Force specific analysis engine (eslint,sunlint)', '')
61
+ .option('--engine <engine>', 'Force specific analysis engine (eslint,heuristic)', '')
62
62
  .option('--dry-run', 'Show what would be analyzed without running')
63
63
  .option('--verbose', 'Enable verbose logging')
64
64
  .option('--quiet', 'Suppress non-error output')
@@ -67,6 +67,7 @@ function createCliProgram() {
67
67
  .option('--no-ai', 'Force disable AI analysis (use heuristic only)')
68
68
  .option('--legacy', 'Use legacy analysis architecture')
69
69
  .option('--modern', 'Use modern plugin-based architecture (default)')
70
+ .option('--max-semantic-files <number>', 'Control semantic analysis scope: 0=disable, -1=unlimited, >0=limit (default: 1000)', '1000')
70
71
  .option('--list-engines', 'List available analysis engines');
71
72
 
72
73
  // ESLint Integration options
@@ -107,7 +108,7 @@ Version Strategy:
107
108
  Engine Configuration:
108
109
  $ sunlint --all --input=src # Use config engine setting
109
110
  $ sunlint --all --input=src --engine=eslint # Force ESLint engine
110
- $ sunlint --all --input=src --engine=sunlint # Force SunLint engine
111
+ $ sunlint --all --input=src --engine=heuristic # Force Heuristic engine
111
112
 
112
113
  CI/CD Integration:
113
114
  $ sunlint --all --changed-files --format=summary --no-ai
@@ -127,6 +128,13 @@ Advanced File Targeting:
127
128
  $ sunlint --languages=typescript,dart --include="src/**,packages/**" --input=.
128
129
  $ sunlint --all --only-source --exclude-tests --languages=typescript --input=.
129
130
 
131
+ Large Project Optimization:
132
+ $ sunlint --all --input=. --max-semantic-files=500 # Conservative analysis
133
+ $ sunlint --all --input=. --max-semantic-files=2000 # Comprehensive analysis
134
+ $ sunlint --all --input=. --max-semantic-files=-1 # Unlimited (all files)
135
+ $ sunlint --all --input=. --max-semantic-files=0 # Disable semantic analysis
136
+ $ sunlint --all --changed-files --max-semantic-files=300 # Fast CI analysis
137
+
130
138
  Sun* Engineering - Coding Standards Made Simple ☀️
131
139
  `);
132
140
 
@@ -209,8 +209,35 @@ class ConfigMerger {
209
209
  // Add flexible patterns for input paths
210
210
  const expandedInclude = [...currentInclude];
211
211
  for (const inputPath of inputPaths) {
212
- expandedInclude.push(inputPath + '/**');
213
- expandedInclude.push('**/' + inputPath + '/**');
212
+ // Check if inputPath is a file or directory
213
+ const fs = require('fs');
214
+ const path = require('path');
215
+
216
+ try {
217
+ const resolvedPath = path.resolve(inputPath);
218
+ if (fs.existsSync(resolvedPath)) {
219
+ const stat = fs.statSync(resolvedPath);
220
+ if (stat.isFile()) {
221
+ // For files, add the exact path
222
+ expandedInclude.push(inputPath);
223
+ expandedInclude.push('**/' + inputPath);
224
+ } else if (stat.isDirectory()) {
225
+ // For directories, add recursive patterns
226
+ expandedInclude.push(inputPath + '/**');
227
+ expandedInclude.push('**/' + inputPath + '/**');
228
+ }
229
+ } else {
230
+ // If path doesn't exist, assume it's a pattern and add both file and directory variants
231
+ expandedInclude.push(inputPath);
232
+ expandedInclude.push(inputPath + '/**');
233
+ expandedInclude.push('**/' + inputPath);
234
+ expandedInclude.push('**/' + inputPath + '/**');
235
+ }
236
+ } catch (error) {
237
+ // Fallback to original logic if file system check fails
238
+ expandedInclude.push(inputPath + '/**');
239
+ expandedInclude.push('**/' + inputPath + '/**');
240
+ }
214
241
  }
215
242
  result.include = expandedInclude;
216
243
 
@@ -100,7 +100,8 @@ class EnhancedRulesRegistry {
100
100
  'C006': ['eslint', 'heuristic', 'openai'],
101
101
  'C007': ['eslint', 'heuristic', 'openai'],
102
102
  'C014': ['eslint', 'heuristic', 'openai'],
103
- 'C033': ['eslint', 'heuristic'],
103
+ 'C033': ['heuristic', 'eslint'],
104
+ 'C035': ['heuristic', 'eslint'],
104
105
  'C040': ['eslint', 'heuristic'],
105
106
 
106
107
  // AI-enhanced rules (complex logic analysis)
@@ -109,7 +110,6 @@ class EnhancedRulesRegistry {
109
110
  'C015': ['openai', 'heuristic'],
110
111
  'C032': ['openai', 'heuristic'],
111
112
  'C034': ['openai', 'heuristic'],
112
- 'C035': ['openai', 'heuristic'],
113
113
  'C037': ['openai', 'heuristic', 'eslint'],
114
114
  'C038': ['openai', 'heuristic']
115
115
  };
@@ -328,4 +328,4 @@ class EnhancedRulesRegistry {
328
328
  }
329
329
  }
330
330
 
331
- module.exports = EnhancedRulesRegistry;
331
+ module.exports = EnhancedRulesRegistry;