@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.
- package/CHANGELOG.md +68 -1
- package/CONTRIBUTING.md +1179 -54
- package/README.md +3 -4
- package/config/ci-cd.json +54 -0
- package/config/development.json +56 -0
- package/config/large-project.json +143 -0
- package/config/presets/all.json +0 -1
- package/config/release.json +70 -0
- package/config/rule-analysis-strategies.js +23 -4
- package/config/rules/S027-categories.json +122 -0
- package/config/rules/enhanced-rules-registry.json +136 -75
- package/config/rules/rules-registry-generated.json +2 -2
- package/config/rules/rules-registry.json +13 -1
- package/core/cli-action-handler.js +24 -30
- package/core/cli-program.js +11 -3
- package/core/config-merger.js +29 -2
- package/core/enhanced-rules-registry.js +3 -3
- package/core/semantic-engine.js +117 -19
- package/core/unified-rule-registry.js +1 -1
- package/docs/COMMAND-EXAMPLES.md +134 -0
- package/docs/LARGE-PROJECT-GUIDE.md +324 -0
- package/engines/heuristic-engine.js +71 -13
- package/integrations/eslint/plugin/index.js +0 -2
- package/origin-rules/common-en.md +8 -8
- package/package.json +1 -1
- package/rules/common/C017_constructor_logic/analyzer.js +254 -17
- package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
- package/rules/common/C033_separate_service_repository/README.md +78 -0
- package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
- package/rules/common/C033_separate_service_repository/config.json +50 -0
- package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
- package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
- package/rules/common/C035_error_logging_context/analyzer.js +230 -0
- package/rules/common/C035_error_logging_context/config.json +54 -0
- package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
- package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
- package/rules/common/C040_centralized_validation/analyzer.js +165 -0
- package/rules/common/C040_centralized_validation/config.json +46 -0
- package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
- package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
- package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
- package/rules/common/C076_explicit_function_types/README.md +30 -0
- package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
- package/rules/common/C076_explicit_function_types/config.json +15 -0
- package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
- package/rules/index.js +1 -0
- package/rules/parser/rule-parser.js +13 -2
- package/rules/security/S005_no_origin_auth/README.md +226 -0
- package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
- package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
- package/rules/security/S005_no_origin_auth/config.json +85 -0
- package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
- package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
- package/rules/security/S007_no_plaintext_otp/README.md +198 -0
- package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
- package/rules/security/S007_no_plaintext_otp/config.json +79 -0
- package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
- package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
- package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
- package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
- package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
- package/scripts/prepare-release.sh +1 -1
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
- package/docs/FUTURE_PACKAGES.md +0 -83
- package/docs/HEURISTIC_VS_AI.md +0 -113
- package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
- package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
- package/docs/RELEASE_GUIDE.md +0 -230
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
- 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": "
|
|
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": "
|
|
556
|
-
"description": "
|
|
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
|
-
"
|
|
561
|
-
"javascript"
|
|
584
|
+
"All languages"
|
|
562
585
|
],
|
|
563
|
-
"analyzer": "
|
|
564
|
-
"
|
|
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
|
-
"
|
|
570
|
-
"
|
|
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": "
|
|
583
|
-
"
|
|
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": "
|
|
1582
|
+
"preferred": "semantic",
|
|
1529
1583
|
"fallbacks": [
|
|
1530
|
-
"
|
|
1584
|
+
"semantic",
|
|
1585
|
+
"ast",
|
|
1531
1586
|
"regex"
|
|
1532
1587
|
],
|
|
1533
1588
|
"accuracy": {
|
|
1534
|
-
"
|
|
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": "
|
|
1739
|
-
"description": "
|
|
1740
|
-
"category": "
|
|
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": "
|
|
1774
|
+
"status": "stable",
|
|
1748
1775
|
"tags": [
|
|
1749
|
-
"
|
|
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": "
|
|
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": "
|
|
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", "
|
|
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
|
|
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:
|
|
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
|
/**
|
package/core/cli-program.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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=
|
|
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
|
|
package/core/config-merger.js
CHANGED
|
@@ -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
|
-
|
|
213
|
-
|
|
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': ['
|
|
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;
|