@sun-asterisk/sunlint 1.0.7 → 1.1.4

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 (219) hide show
  1. package/.sunlint.json +35 -0
  2. package/CHANGELOG.md +30 -3
  3. package/CONTRIBUTING.md +235 -0
  4. package/PROJECT_STRUCTURE.md +60 -0
  5. package/README.md +146 -58
  6. package/cli.js +1 -0
  7. package/config/README.md +88 -0
  8. package/config/defaults/ai-rules-context.json +231 -0
  9. package/config/engines/engines.json +49 -0
  10. package/config/engines/eslint-rule-mapping.json +74 -0
  11. package/config/eslint-rule-mapping.json +126 -0
  12. package/config/integrations/eslint/base.config.js +125 -0
  13. package/config/integrations/eslint/simple.config.js +24 -0
  14. package/config/presets/strict.json +0 -1
  15. package/config/rule-analysis-strategies.js +74 -0
  16. package/config/{rules-registry.json → rules/rules-registry.json} +30 -7
  17. package/core/analysis-orchestrator.js +383 -591
  18. package/core/ast-modules/README.md +103 -0
  19. package/core/ast-modules/base-parser.js +90 -0
  20. package/core/ast-modules/index.js +97 -0
  21. package/core/ast-modules/package.json +37 -0
  22. package/core/ast-modules/parsers/eslint-js-parser.js +153 -0
  23. package/core/ast-modules/parsers/eslint-ts-parser.js +98 -0
  24. package/core/ast-modules/parsers/javascript-parser.js +187 -0
  25. package/core/ast-modules/parsers/typescript-parser.js +187 -0
  26. package/core/cli-action-handler.js +271 -255
  27. package/core/cli-program.js +18 -4
  28. package/core/config-manager.js +9 -3
  29. package/core/config-merger.js +40 -1
  30. package/core/config-validator.js +2 -2
  31. package/core/dependency-checker.js +125 -0
  32. package/core/enhanced-rules-registry.js +331 -0
  33. package/core/file-targeting-service.js +92 -23
  34. package/core/interfaces/analysis-engine.interface.js +100 -0
  35. package/core/multi-rule-runner.js +0 -221
  36. package/core/output-service.js +1 -1
  37. package/core/rule-mapping-service.js +1 -1
  38. package/core/rule-selection-service.js +10 -2
  39. package/core/smart-installer.js +164 -0
  40. package/docs/AI.md +163 -0
  41. package/docs/ARCHITECTURE.md +78 -0
  42. package/docs/CI-CD-GUIDE.md +315 -0
  43. package/docs/COMMAND-EXAMPLES.md +256 -0
  44. package/docs/CONFIGURATION.md +414 -0
  45. package/docs/DEBUG.md +86 -0
  46. package/docs/DEPENDENCIES.md +90 -0
  47. package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
  48. package/docs/DISTRIBUTION.md +153 -0
  49. package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
  50. package/docs/ESLINT_INTEGRATION.md +238 -0
  51. package/docs/FOLDER_STRUCTURE.md +59 -0
  52. package/docs/FUTURE_PACKAGES.md +83 -0
  53. package/docs/HEURISTIC_VS_AI.md +113 -0
  54. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +112 -0
  55. package/docs/PRODUCTION_SIZE_IMPACT.md +183 -0
  56. package/docs/README.md +32 -0
  57. package/docs/RELEASE_GUIDE.md +230 -0
  58. package/engines/eslint-engine.js +610 -0
  59. package/engines/heuristic-engine.js +864 -0
  60. package/engines/openai-engine.js +374 -0
  61. package/engines/tree-sitter-parser.js +0 -0
  62. package/engines/universal-ast-engine.js +0 -0
  63. package/integrations/eslint/README.md +99 -0
  64. package/integrations/eslint/configs/.eslintrc.js +98 -0
  65. package/integrations/eslint/configs/eslint.config.js +133 -0
  66. package/integrations/eslint/configs/eslint.config.simple.js +24 -0
  67. package/integrations/eslint/package.json +23 -0
  68. package/integrations/eslint/plugin/index.js +164 -0
  69. package/integrations/eslint/plugin/package.json +13 -0
  70. package/integrations/eslint/plugin/rules/common/c002-no-duplicate-code.js +204 -0
  71. package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +246 -0
  72. package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +216 -0
  73. package/integrations/eslint/plugin/rules/common/c010-limit-block-nesting.js +90 -0
  74. package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
  75. package/integrations/eslint/plugin/rules/common/c014-abstract-dependency-preferred.js +38 -0
  76. package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
  77. package/integrations/eslint/plugin/rules/common/c018-no-generic-throw.js +335 -0
  78. package/integrations/eslint/plugin/rules/common/c023-no-duplicate-variable-name-in-scope.js +142 -0
  79. package/integrations/eslint/plugin/rules/common/c029-catch-block-logging.js +115 -0
  80. package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +294 -0
  81. package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
  82. package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
  83. package/integrations/eslint/plugin/rules/common/c042-boolean-name-prefix.js +406 -0
  84. package/integrations/eslint/plugin/rules/common/c043-no-console-or-print.js +300 -0
  85. package/integrations/eslint/plugin/rules/common/c047-no-duplicate-retry-logic.js +239 -0
  86. package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
  87. package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
  88. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
  89. package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
  90. package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
  91. package/integrations/eslint/plugin/rules/security/s003-no-unvalidated-redirect.js +86 -0
  92. package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
  93. package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
  94. package/integrations/eslint/plugin/rules/security/s047-secure-random-passwords.js +108 -0
  95. package/integrations/eslint/plugin/rules/security/s055-verification-rest-check-the-incoming-content-type.js +143 -0
  96. package/integrations/eslint/plugin/rules/typescript/t002-interface-prefix-i.js +42 -0
  97. package/integrations/eslint/plugin/rules/typescript/t003-ts-ignore-reason.js +48 -0
  98. package/integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js +95 -0
  99. package/integrations/eslint/plugin/rules/typescript/t007-no-fn-in-constructor.js +52 -0
  100. package/integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js +48 -0
  101. package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
  102. package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
  103. package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
  104. package/integrations/eslint/tsconfig.json +27 -0
  105. package/package.json +61 -21
  106. package/rules/README.md +252 -0
  107. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  108. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  109. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  110. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  111. package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
  112. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  113. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  114. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  115. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  116. package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
  117. package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
  118. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  119. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  120. package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
  121. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
  122. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  123. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  124. package/rules/docs/C002_no_duplicate_code.md +57 -0
  125. package/rules/index.js +149 -0
  126. package/rules/migration/converter.js +385 -0
  127. package/rules/migration/mapping.json +164 -0
  128. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  129. package/rules/security/S026_json_schema_validation/config.json +27 -0
  130. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
  131. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  132. package/rules/security/S029_csrf_protection/analyzer.js +264 -0
  133. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  134. package/rules/universal/C010/generic.js +0 -0
  135. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  136. package/rules/utils/ast-utils.js +191 -0
  137. package/rules/utils/base-analyzer.js +98 -0
  138. package/rules/utils/pattern-matchers.js +239 -0
  139. package/rules/utils/rule-helpers.js +264 -0
  140. package/rules/utils/severity-constants.js +93 -0
  141. package/scripts/build-release.sh +117 -0
  142. package/scripts/ci-report.js +179 -0
  143. package/scripts/install.sh +196 -0
  144. package/scripts/manual-release.sh +338 -0
  145. package/scripts/merge-reports.js +424 -0
  146. package/scripts/pre-release-test.sh +175 -0
  147. package/scripts/prepare-release.sh +202 -0
  148. package/scripts/setup-github-registry.sh +42 -0
  149. package/scripts/test-scripts/README.md +22 -0
  150. package/scripts/test-scripts/test-c041-comparison.js +114 -0
  151. package/scripts/test-scripts/test-c041-eslint.js +67 -0
  152. package/scripts/test-scripts/test-eslint-rules.js +146 -0
  153. package/scripts/test-scripts/test-real-world.js +44 -0
  154. package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
  155. package/scripts/trigger-release.sh +285 -0
  156. package/scripts/validate-rule-structure.js +148 -0
  157. package/scripts/verify-install.sh +82 -0
  158. package/config/sunlint-schema.json +0 -159
  159. package/config/typescript/custom-rules.js +0 -9
  160. package/config/typescript/package-lock.json +0 -1585
  161. package/config/typescript/package.json +0 -13
  162. package/config/typescript/security-rules/index.js +0 -90
  163. package/config/typescript/tsconfig.json +0 -29
  164. package/core/ai-analyzer.js +0 -169
  165. package/core/eslint-engine-service.js +0 -312
  166. package/core/eslint-instance-manager.js +0 -104
  167. package/core/eslint-integration-service.js +0 -363
  168. package/core/sunlint-engine-service.js +0 -23
  169. package/core/typescript-analyzer.js +0 -262
  170. package/core/typescript-engine.js +0 -313
  171. /package/config/{default.json → defaults/default.json} +0 -0
  172. /package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +0 -0
  173. /package/config/{typescript/custom-rules-new.js → schemas/sunlint-schema.json} +0 -0
  174. /package/config/{typescript → testing}/test-s005-working.ts +0 -0
  175. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
  176. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
  177. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
  178. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
  179. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
  180. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
  181. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
  182. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
  183. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
  184. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
  185. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
  186. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
  187. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
  188. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
  189. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
  190. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
  191. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
  192. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
  193. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
  194. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
  195. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
  196. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
  197. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
  198. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
  199. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
  200. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
  201. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
  202. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
  203. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
  204. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
  205. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
  206. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
  207. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
  208. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
  209. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
  210. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
  211. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
  212. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
  213. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
  214. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
  215. /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
  216. /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
  217. /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
  218. /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
  219. /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
@@ -0,0 +1,133 @@
1
+ // ESLint Flat Configuration for SunLint (ESLint v9+)
2
+ // Following Rule C005: Single responsibility - ESLint configuration
3
+ const typescriptParser = require('@typescript-eslint/parser');
4
+ const typescriptPlugin = require('@typescript-eslint/eslint-plugin');
5
+ const customPlugin = require('../plugin');
6
+
7
+ module.exports = [
8
+ {
9
+ files: ['**/*.{js,ts,tsx,jsx}'],
10
+ languageOptions: {
11
+ parser: typescriptParser,
12
+ parserOptions: {
13
+ ecmaVersion: 2022,
14
+ sourceType: 'module',
15
+ project: './tsconfig.json'
16
+ },
17
+ globals: {
18
+ console: 'readonly',
19
+ process: 'readonly',
20
+ eval: 'readonly',
21
+ Buffer: 'readonly',
22
+ __dirname: 'readonly',
23
+ __filename: 'readonly',
24
+ exports: 'writable',
25
+ module: 'writable',
26
+ require: 'readonly',
27
+ global: 'readonly'
28
+ }
29
+ },
30
+ plugins: {
31
+ 'custom': customPlugin,
32
+ '@typescript-eslint': typescriptPlugin
33
+ },
34
+ rules: {
35
+ // Rule C019: No console.error for non-critical errors
36
+ 'no-console': ['warn', { allow: ['warn', 'log'] }],
37
+
38
+ // Code quality rules
39
+ 'no-unused-vars': 'warn',
40
+ 'prefer-const': 'warn',
41
+ 'no-var': 'error',
42
+ 'no-undef': 'warn',
43
+
44
+ // Rule C005: Single responsibility principle
45
+ 'max-lines-per-function': ['warn', { max: 50 }],
46
+ 'complexity': ['warn', { max: 10 }],
47
+
48
+ // Rule C014: Avoid direct new instantiation patterns
49
+ 'no-new': 'warn',
50
+
51
+ // Security and best practices
52
+ 'no-eval': 'error',
53
+ 'no-implied-eval': 'error',
54
+ 'no-new-func': 'error',
55
+ 'eqeqeq': 'error',
56
+ 'curly': 'error',
57
+
58
+ // Quality rules (dynamic loading based on category)
59
+ 'custom/c002': 'off',
60
+ 'custom/c003': 'off',
61
+ 'custom/c006': 'off',
62
+ 'custom/c010': 'off',
63
+ 'custom/c013': 'off',
64
+ 'custom/c014': 'off',
65
+ 'custom/c017': 'off',
66
+ 'custom/c018': 'off',
67
+ 'custom/c023': 'off',
68
+ 'custom/c029': 'off',
69
+ 'custom/c030': 'off',
70
+ 'custom/c035': 'off',
71
+ 'custom/c041': 'off',
72
+ 'custom/c042': 'off',
73
+ 'custom/c043': 'off',
74
+ 'custom/c047': 'off',
75
+ 'custom/c072': 'off',
76
+
77
+ // TypeScript rules (T-series)
78
+ 'custom/t002': 'warn',
79
+ 'custom/t003': 'warn',
80
+ 'custom/t004': 'warn',
81
+ 'custom/t007': 'warn',
82
+ 'custom/t010': 'warn',
83
+ 'custom/t019': 'warn',
84
+ 'custom/t020': 'warn',
85
+ 'custom/t021': 'warn',
86
+
87
+ // Security rules (dynamic loading based on category)
88
+ 'custom/typescript_s003': 'off',
89
+ 'custom/typescript_s005': 'off',
90
+ 'custom/typescript_s006': 'off',
91
+ 'custom/typescript_s008': 'off',
92
+ 'custom/typescript_s009': 'off',
93
+ 'custom/typescript_s010': 'off',
94
+ 'custom/typescript_s011': 'off',
95
+ 'custom/typescript_s012': 'off',
96
+ 'custom/typescript_s014': 'off',
97
+ 'custom/typescript_s015': 'off',
98
+ 'custom/typescript_s016': 'off',
99
+ 'custom/typescript_s017': 'off',
100
+ 'custom/typescript_s018': 'off',
101
+ 'custom/typescript_s019': 'off',
102
+ 'custom/typescript_s020': 'off',
103
+ 'custom/typescript_s022': 'off',
104
+ 'custom/typescript_s023': 'off',
105
+ 'custom/typescript_s025': 'off',
106
+ 'custom/typescript_s026': 'off',
107
+ 'custom/typescript_s027': 'off',
108
+ 'custom/typescript_s029': 'off',
109
+ 'custom/typescript_s030': 'off',
110
+ 'custom/typescript_s033': 'off',
111
+ 'custom/typescript_s034': 'off',
112
+ 'custom/typescript_s035': 'off',
113
+ 'custom/typescript_s036': 'off',
114
+ 'custom/typescript_s037': 'off',
115
+ 'custom/typescript_s038': 'off',
116
+ 'custom/typescript_s039': 'off',
117
+ 'custom/typescript_s041': 'off',
118
+ 'custom/typescript_s042': 'off',
119
+ 'custom/typescript_s043': 'off',
120
+ 'custom/typescript_s044': 'off',
121
+ 'custom/typescript_s045': 'off',
122
+ 'custom/typescript_s046': 'off',
123
+ 'custom/typescript_s047': 'off',
124
+ 'custom/typescript_s048': 'off',
125
+ 'custom/typescript_s050': 'off',
126
+ 'custom/typescript_s052': 'off',
127
+ 'custom/typescript_s054': 'off',
128
+ 'custom/typescript_s055': 'off',
129
+ 'custom/typescript_s057': 'off',
130
+ 'custom/typescript_s058': 'off'
131
+ }
132
+ }
133
+ ];
@@ -0,0 +1,24 @@
1
+ // Simple ESLint Flat Configuration for Testing
2
+ module.exports = [
3
+ {
4
+ files: ['**/*.{js,mjs,cjs}'],
5
+ languageOptions: {
6
+ ecmaVersion: 2022,
7
+ sourceType: 'module',
8
+ globals: {
9
+ console: 'readonly',
10
+ process: 'readonly',
11
+ eval: 'readonly'
12
+ }
13
+ },
14
+ rules: {
15
+ 'no-console': ['warn', { allow: ['warn', 'log'] }],
16
+ 'no-unused-vars': 'warn',
17
+ 'prefer-const': 'warn',
18
+ 'no-var': 'error',
19
+ 'no-undef': 'warn',
20
+ 'no-eval': 'error',
21
+ 'eqeqeq': 'error'
22
+ }
23
+ }
24
+ ];
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "typescript",
3
+ "private": true,
4
+ "devDependencies": {
5
+ "@types/bun": "latest",
6
+ "@typescript-eslint/eslint-plugin": "^8.34.1",
7
+ "@typescript-eslint/parser": "^8.34.1",
8
+ "@typescript-eslint/utils": "^8.34.1",
9
+ "eslint": "^9.29.0",
10
+ "@eslint/eslintrc": "^3.3.1",
11
+ "@eslint/js": "^9.28.0",
12
+ "eslint-plugin-sonarjs": "^3.0.2"
13
+ },
14
+ "peerDependencies": {
15
+ "typescript": "^5"
16
+ },
17
+ "scripts": {
18
+ "lint": "eslint .",
19
+ "lint:ts": "eslint src/ --ext .ts,.tsx"
20
+ },
21
+ "dependencies": {
22
+ }
23
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * SunLint ESLint Plugin - Organized Rules Index
3
+ * 🔹 22 Common Rules | 🔒 49 Security Rules | 📘 13 TypeScript Rules
4
+ */
5
+
6
+ // 🔹 Common Rules (C-series) - General coding standards
7
+ const c002 = require("./rules/common/c002-no-duplicate-code.js");
8
+ const c003 = require("./rules/common/c003-no-vague-abbreviations.js");
9
+ const c006 = require("./rules/common/c006-function-name-verb-noun.js");
10
+ const c010 = require("./rules/common/c010-limit-block-nesting.js");
11
+ const c013 = require("./rules/common/c013-no-dead-code.js");
12
+ const c014 = require("./rules/common/c014-abstract-dependency-preferred.js");
13
+ const c017 = require("./rules/common/c017-limit-constructor-logic.js");
14
+ const c018 = require("./rules/common/c018-no-generic-throw.js");
15
+ const c023 = require("./rules/common/c023-no-duplicate-variable-name-in-scope.js");
16
+ const c041 = require("./rules/common/c041-no-config-inline.js");
17
+ const c029 = require("./rules/common/c029-catch-block-logging.js");
18
+ const c030 = require("./rules/common/c030-use-custom-error-classes.js");
19
+ const c035 = require("./rules/common/c035-no-empty-catch.js");
20
+ const c042 = require("./rules/common/c042-boolean-name-prefix.js");
21
+ const c043 = require("./rules/common/c043-no-console-or-print.js");
22
+ const c047 = require("./rules/common/c047-no-duplicate-retry-logic.js");
23
+ const c072 = require("./rules/common/c072-one-assert-per-test.js");
24
+ const c075 = require("./rules/common/c075-explicit-function-return-types.js");
25
+ const c076 = require("./rules/common/c076-single-behavior-per-test.js");
26
+
27
+ // 📘 TypeScript Rules (T-series)
28
+ const t002 = require("./rules/typescript/t002-interface-prefix-i.js");
29
+ const t003 = require("./rules/typescript/t003-ts-ignore-reason.js");
30
+ const t004 = require("./rules/typescript/t004-no-empty-type.js");
31
+ const t007 = require("./rules/typescript/t007-no-fn-in-constructor.js");
32
+ const t010 = require("./rules/typescript/t010-no-nested-union-tuple.js");
33
+ const t019 = require("./rules/typescript/t019-no-this-assign.js");
34
+ const t020 = require("./rules/typescript/t020-no-default-multi-export.js");
35
+ const t021 = require("./rules/typescript/t021-limit-nested-generics.js");
36
+
37
+ // 🔒 Security Rules (S-series)
38
+ const s001 = require("./rules/security/s001-fail-securely.js");
39
+ const s002 = require("./rules/security/s002-idor-check.js");
40
+ const s003 = require("./rules/security/s003-no-unvalidated-redirect.js");
41
+ const s005 = require("./rules/security/s005-no-origin-auth.js");
42
+ const s006 = require("./rules/security/s006-activation-recovery-secret-not-plaintext.js");
43
+ const s007 = require("./rules/security/s007-no-plaintext-otp.js");
44
+ const s008 = require("./rules/security/s008-crypto-agility.js");
45
+ const s009 = require("./rules/security/s009-no-insecure-crypto.js");
46
+ const s010 = require("./rules/security/s010-no-insecure-random-in-sensitive-context.js");
47
+ const s011 = require("./rules/security/s011-no-insecure-uuid.js");
48
+ const s012 = require("./rules/security/s012-hardcode-secret.js");
49
+ const s013 = require("./rules/security/s013-verify-tls-connection.js");
50
+ const s014 = require("./rules/security/s014-insecure-tls-version.js");
51
+ const s015 = require("./rules/security/s015-insecure-tls-certificate.js");
52
+ const s016 = require("./rules/security/s016-sensitive-query-parameter.js");
53
+ const s017 = require("./rules/security/s017-no-sql-injection.js");
54
+ const s018 = require("./rules/security/s018-positive-input-validation.js");
55
+ const s019 = require("./rules/security/s019-no-raw-user-input-in-email.js");
56
+ const s020 = require("./rules/security/s020-no-eval-dynamic-execution.js");
57
+ const s022 = require("./rules/security/s022-output-encoding.js");
58
+ const s023 = require("./rules/security/s023-no-json-injection.js");
59
+ const s025 = require("./rules/security/s025-server-side-input-validation.js");
60
+ const s026 = require("./rules/security/s026-json-schema-validation.js");
61
+ const s027 = require("./rules/security/s027-no-hardcoded-secrets.js");
62
+ const s029 = require("./rules/security/s029-require-csrf-protection.js");
63
+ const s030 = require("./rules/security/s030-no-directory-browsing.js");
64
+ const s033 = require("./rules/security/s033-require-samesite-cookie.js");
65
+ const s034 = require("./rules/security/s034-require-host-cookie-prefix.js");
66
+ const s035 = require("./rules/security/s035-cookie-specific-path.js");
67
+ const s036 = require("./rules/security/s036-no-unsafe-file-include.js");
68
+ const s037 = require("./rules/security/s037-require-anti-cache-headers.js");
69
+ const s038 = require("./rules/security/s038-no-version-disclosure.js");
70
+ const s039 = require("./rules/security/s039-no-session-token-in-url.js");
71
+ const s041 = require("./rules/security/s041-require-session-invalidate-on-logout.js");
72
+ const s042 = require("./rules/security/s042-require-periodic-reauthentication.js");
73
+ const s043 = require("./rules/security/s043-terminate-sessions-on-password-change.js");
74
+ const s044 = require("./rules/security/s044-require-full-session-for-sensitive-operations.js");
75
+ const s045 = require("./rules/security/s045-anti-automation-controls.js");
76
+ const s046 = require("./rules/security/s046-secure-notification-on-auth-change.js");
77
+ const s047 = require("./rules/security/s047-secure-random-passwords.js");
78
+ const s048 = require("./rules/security/s048-password-credential-recovery.js");
79
+ const s050 = require("./rules/security/s050-session-token-weak-hash.js");
80
+ const s052 = require("./rules/security/s052-secure-random-authentication-code.js");
81
+ const s054 = require("./rules/security/s054-verification-default-account.js");
82
+ const s055 = require("./rules/security/s055-verification-rest-check-the-incoming-content-type.js");
83
+ const s057 = require("./rules/security/s057-utc-logging.js");
84
+ const s058 = require("./rules/security/s058-no-ssrf.js");
85
+
86
+ module.exports = {
87
+ rules: {
88
+ "c002": c002,
89
+ "c003": c003,
90
+ "c006": c006,
91
+ "c010": c010,
92
+ "c013": c013,
93
+ "c014": c014,
94
+ "c017": c017,
95
+ "c018": c018,
96
+ "c030": c030,
97
+ "c035": c035,
98
+ "c023": c023,
99
+ "c029": c029,
100
+ "c041": c041,
101
+ "c042": c042,
102
+ "c043": c043,
103
+ "c047": c047,
104
+ "c072": c072,
105
+ "c075": c075,
106
+ "c076": c076,
107
+ "t002": t002,
108
+ "t003": t003,
109
+ "t004": t004,
110
+ "t007": t007,
111
+ "t010": t010,
112
+ "t019": t019,
113
+ "t020": t020,
114
+ "t021": t021,
115
+ // Security rules
116
+ "typescript_s001": s001,
117
+ "typescript_s002": s002,
118
+ "typescript_s003": s003,
119
+ "typescript_s005": s005,
120
+ "typescript_s006": s006,
121
+ "typescript_s007": s007,
122
+ "typescript_s008": s008,
123
+ "typescript_s009": s009,
124
+ "typescript_s010": s010,
125
+ "typescript_s011": s011,
126
+ "typescript_s012": s012,
127
+ "typescript_s013": s013,
128
+ "typescript_s014": s014,
129
+ "typescript_s015": s015,
130
+ "typescript_s016": s016,
131
+ "typescript_s017": s017,
132
+ "typescript_s018": s018,
133
+ "typescript_s019": s019,
134
+ "typescript_s020": s020,
135
+ "typescript_s022": s022,
136
+ "typescript_s023": s023,
137
+ "typescript_s025": s025,
138
+ "typescript_s026": s026,
139
+ "typescript_s027": s027,
140
+ "typescript_s029": s029,
141
+ "typescript_s030": s030,
142
+ "typescript_s033": s033,
143
+ "typescript_s034": s034,
144
+ "typescript_s035": s035,
145
+ "typescript_s036": s036,
146
+ "typescript_s037": s037,
147
+ "typescript_s038": s038,
148
+ "typescript_s039": s039,
149
+ "typescript_s041": s041,
150
+ "typescript_s042": s042,
151
+ "typescript_s043": s043,
152
+ "typescript_s044": s044,
153
+ "typescript_s045": s045,
154
+ "typescript_s046": s046,
155
+ "typescript_s047": s047,
156
+ "typescript_s048": s048,
157
+ "typescript_s050": s050,
158
+ "typescript_s052": s052,
159
+ "typescript_s054": s054,
160
+ "typescript_s055": s055,
161
+ "typescript_s057": s057,
162
+ "typescript_s058": s058
163
+ }
164
+ };
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "eslint-plugin-custom",
3
+ "version": "1.0.0",
4
+ "description": "Custom ESLint rules for Sun Lint security and quality checks",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "engines": {
8
+ "node": ">=14.0.0"
9
+ },
10
+ "keywords": ["eslint", "security", "coding-standards"],
11
+ "author": "Sun* Engineering",
12
+ "license": "MIT"
13
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Custom ESLint rule for: C002 – Không để trùng lặp code > 10 dòng
3
+ * Rule ID: custom/c002
4
+ * Purpose: Detect duplicate code blocks longer than 10 lines to maintain DRY principle
5
+ */
6
+
7
+ module.exports = {
8
+ meta: {
9
+ type: "suggestion",
10
+ docs: {
11
+ description: "Detect duplicate code blocks longer than 10 lines",
12
+ recommended: false
13
+ },
14
+ schema: [
15
+ {
16
+ type: "object",
17
+ properties: {
18
+ minLines: {
19
+ type: "number",
20
+ minimum: 1,
21
+ default: 10
22
+ },
23
+ ignoreComments: {
24
+ type: "boolean",
25
+ default: true
26
+ },
27
+ ignoreWhitespace: {
28
+ type: "boolean",
29
+ default: true
30
+ }
31
+ },
32
+ additionalProperties: false
33
+ }
34
+ ],
35
+ messages: {
36
+ duplicateCode: "Duplicate code block found ({{lines}} lines). Consider extracting into a shared function or module."
37
+ }
38
+ },
39
+ create(context) {
40
+ const options = context.options[0] || {};
41
+ const minLines = options.minLines || 10;
42
+ const ignoreComments = options.ignoreComments !== false;
43
+ const ignoreWhitespace = options.ignoreWhitespace !== false;
44
+
45
+ const sourceCode = context.getSourceCode();
46
+ const codeBlocks = new Map();
47
+
48
+ function normalizeCode(text) {
49
+ let normalized = text;
50
+
51
+ if (ignoreWhitespace) {
52
+ // Remove extra whitespace and normalize spacing
53
+ normalized = normalized
54
+ .replace(/\s+/g, ' ')
55
+ .trim();
56
+ }
57
+
58
+ if (ignoreComments) {
59
+ // Remove single line comments
60
+ normalized = normalized.replace(/\/\/.*$/gm, '');
61
+ // Remove multi-line comments
62
+ normalized = normalized.replace(/\/\*[\s\S]*?\*\//g, '');
63
+ }
64
+
65
+ return normalized;
66
+ }
67
+
68
+ function getCodeLines(node) {
69
+ const startLine = node.loc.start.line;
70
+ const endLine = node.loc.end.line;
71
+ const lines = [];
72
+
73
+ for (let i = startLine; i <= endLine; i++) {
74
+ const line = sourceCode.lines[i - 1];
75
+ if (line !== undefined) {
76
+ lines.push(line);
77
+ }
78
+ }
79
+
80
+ return lines;
81
+ }
82
+
83
+ function analyzeNode(node) {
84
+ const lines = getCodeLines(node);
85
+
86
+ if (lines.length < minLines) {
87
+ return;
88
+ }
89
+
90
+ const codeText = lines.join('\n');
91
+ const normalizedCode = normalizeCode(codeText);
92
+
93
+ // Skip if normalized code is too short after cleaning
94
+ if (normalizedCode.length < 20) {
95
+ return;
96
+ }
97
+
98
+ const codeHash = normalizedCode;
99
+
100
+ if (codeBlocks.has(codeHash)) {
101
+ const existingNodes = codeBlocks.get(codeHash);
102
+
103
+ // Report duplicate for current node
104
+ context.report({
105
+ node,
106
+ messageId: "duplicateCode",
107
+ data: {
108
+ lines: lines.length
109
+ }
110
+ });
111
+
112
+ // Also report the first occurrence if not already reported
113
+ existingNodes.forEach(existingNode => {
114
+ if (!existingNode.reported) {
115
+ context.report({
116
+ node: existingNode.node,
117
+ messageId: "duplicateCode",
118
+ data: {
119
+ lines: existingNode.lines
120
+ }
121
+ });
122
+ existingNode.reported = true;
123
+ }
124
+ });
125
+
126
+ existingNodes.push({ node, lines: lines.length, reported: true });
127
+ } else {
128
+ codeBlocks.set(codeHash, [{ node, lines: lines.length, reported: false }]);
129
+ }
130
+ }
131
+
132
+ return {
133
+ // Check function declarations
134
+ FunctionDeclaration(node) {
135
+ if (node.body) {
136
+ analyzeNode(node.body);
137
+ }
138
+ },
139
+
140
+ // Check function expressions
141
+ FunctionExpression(node) {
142
+ if (node.body) {
143
+ analyzeNode(node.body);
144
+ }
145
+ },
146
+
147
+ // Check arrow functions
148
+ ArrowFunctionExpression(node) {
149
+ if (node.body && node.body.type === 'BlockStatement') {
150
+ analyzeNode(node.body);
151
+ }
152
+ },
153
+
154
+ // Check method definitions
155
+ MethodDefinition(node) {
156
+ if (node.value && node.value.body) {
157
+ analyzeNode(node.value.body);
158
+ }
159
+ },
160
+
161
+ // Check block statements (general code blocks)
162
+ BlockStatement(node) {
163
+ // Only analyze block statements that are not function bodies
164
+ const parent = node.parent;
165
+ if (parent &&
166
+ parent.type !== 'FunctionDeclaration' &&
167
+ parent.type !== 'FunctionExpression' &&
168
+ parent.type !== 'ArrowFunctionExpression' &&
169
+ parent.type !== 'MethodDefinition') {
170
+ analyzeNode(node);
171
+ }
172
+ },
173
+
174
+ // Check if/else statements
175
+ IfStatement(node) {
176
+ if (node.consequent && node.consequent.type === 'BlockStatement') {
177
+ analyzeNode(node.consequent);
178
+ }
179
+ if (node.alternate && node.alternate.type === 'BlockStatement') {
180
+ analyzeNode(node.alternate);
181
+ }
182
+ },
183
+
184
+ // Check loop bodies
185
+ ForStatement(node) {
186
+ if (node.body && node.body.type === 'BlockStatement') {
187
+ analyzeNode(node.body);
188
+ }
189
+ },
190
+
191
+ WhileStatement(node) {
192
+ if (node.body && node.body.type === 'BlockStatement') {
193
+ analyzeNode(node.body);
194
+ }
195
+ },
196
+
197
+ DoWhileStatement(node) {
198
+ if (node.body && node.body.type === 'BlockStatement') {
199
+ analyzeNode(node.body);
200
+ }
201
+ }
202
+ };
203
+ }
204
+ };