thailint 0.4.1__tar.gz → 0.15.0__tar.gz

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 (214) hide show
  1. {thailint-0.4.1 → thailint-0.15.0}/CHANGELOG.md +116 -0
  2. thailint-0.15.0/PKG-INFO +185 -0
  3. thailint-0.15.0/README.md +149 -0
  4. {thailint-0.4.1 → thailint-0.15.0}/pyproject.toml +8 -5
  5. {thailint-0.4.1 → thailint-0.15.0}/src/__init__.py +1 -0
  6. {thailint-0.4.1 → thailint-0.15.0}/src/analyzers/__init__.py +4 -3
  7. thailint-0.15.0/src/analyzers/ast_utils.py +54 -0
  8. {thailint-0.4.1 → thailint-0.15.0}/src/analyzers/typescript_base.py +4 -0
  9. thailint-0.15.0/src/cli/__init__.py +30 -0
  10. thailint-0.15.0/src/cli/__main__.py +22 -0
  11. thailint-0.15.0/src/cli/config.py +478 -0
  12. thailint-0.15.0/src/cli/config_merge.py +241 -0
  13. thailint-0.15.0/src/cli/linters/__init__.py +67 -0
  14. thailint-0.15.0/src/cli/linters/code_patterns.py +222 -0
  15. thailint-0.15.0/src/cli/linters/code_smells.py +333 -0
  16. thailint-0.15.0/src/cli/linters/documentation.py +81 -0
  17. thailint-0.15.0/src/cli/linters/performance.py +274 -0
  18. thailint-0.15.0/src/cli/linters/shared.py +315 -0
  19. thailint-0.15.0/src/cli/linters/structure.py +318 -0
  20. thailint-0.15.0/src/cli/linters/structure_quality.py +323 -0
  21. thailint-0.15.0/src/cli/main.py +120 -0
  22. thailint-0.15.0/src/cli/utils.py +395 -0
  23. thailint-0.15.0/src/cli_main.py +37 -0
  24. {thailint-0.4.1 → thailint-0.15.0}/src/config.py +4 -4
  25. {thailint-0.4.1 → thailint-0.15.0}/src/core/base.py +7 -2
  26. {thailint-0.4.1 → thailint-0.15.0}/src/core/cli_utils.py +19 -2
  27. {thailint-0.4.1 → thailint-0.15.0}/src/core/config_parser.py +36 -6
  28. thailint-0.15.0/src/core/constants.py +54 -0
  29. {thailint-0.4.1 → thailint-0.15.0}/src/core/linter_utils.py +95 -6
  30. {thailint-0.4.1 → thailint-0.15.0}/src/core/registry.py +1 -1
  31. thailint-0.15.0/src/core/rule_discovery.py +195 -0
  32. {thailint-0.4.1 → thailint-0.15.0}/src/core/types.py +13 -0
  33. {thailint-0.4.1 → thailint-0.15.0}/src/core/violation_builder.py +78 -15
  34. thailint-0.15.0/src/core/violation_utils.py +69 -0
  35. thailint-0.15.0/src/formatters/__init__.py +22 -0
  36. thailint-0.15.0/src/formatters/sarif.py +202 -0
  37. thailint-0.15.0/src/linter_config/directive_markers.py +109 -0
  38. thailint-0.15.0/src/linter_config/ignore.py +333 -0
  39. {thailint-0.4.1 → thailint-0.15.0}/src/linter_config/loader.py +45 -12
  40. thailint-0.15.0/src/linter_config/pattern_utils.py +65 -0
  41. thailint-0.15.0/src/linter_config/rule_matcher.py +89 -0
  42. thailint-0.15.0/src/linters/collection_pipeline/__init__.py +90 -0
  43. thailint-0.15.0/src/linters/collection_pipeline/any_all_analyzer.py +281 -0
  44. thailint-0.15.0/src/linters/collection_pipeline/ast_utils.py +40 -0
  45. thailint-0.15.0/src/linters/collection_pipeline/config.py +75 -0
  46. thailint-0.15.0/src/linters/collection_pipeline/continue_analyzer.py +94 -0
  47. thailint-0.15.0/src/linters/collection_pipeline/detector.py +360 -0
  48. thailint-0.15.0/src/linters/collection_pipeline/filter_map_analyzer.py +402 -0
  49. thailint-0.15.0/src/linters/collection_pipeline/linter.py +420 -0
  50. thailint-0.15.0/src/linters/collection_pipeline/suggestion_builder.py +130 -0
  51. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/base_token_analyzer.py +16 -9
  52. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/block_filter.py +120 -20
  53. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/block_grouper.py +4 -0
  54. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/cache.py +104 -10
  55. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/cache_query.py +4 -0
  56. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/config.py +54 -11
  57. thailint-0.15.0/src/linters/dry/constant.py +92 -0
  58. thailint-0.15.0/src/linters/dry/constant_matcher.py +223 -0
  59. thailint-0.15.0/src/linters/dry/constant_violation_builder.py +98 -0
  60. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/duplicate_storage.py +5 -4
  61. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/file_analyzer.py +4 -2
  62. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/inline_ignore.py +7 -16
  63. thailint-0.15.0/src/linters/dry/linter.py +227 -0
  64. thailint-0.15.0/src/linters/dry/python_analyzer.py +289 -0
  65. thailint-0.15.0/src/linters/dry/python_constant_extractor.py +100 -0
  66. thailint-0.15.0/src/linters/dry/single_statement_detector.py +417 -0
  67. thailint-0.15.0/src/linters/dry/token_hasher.py +173 -0
  68. thailint-0.15.0/src/linters/dry/typescript_analyzer.py +278 -0
  69. thailint-0.15.0/src/linters/dry/typescript_constant_extractor.py +138 -0
  70. thailint-0.15.0/src/linters/dry/typescript_statement_detector.py +255 -0
  71. thailint-0.15.0/src/linters/dry/typescript_value_extractor.py +69 -0
  72. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/violation_builder.py +4 -0
  73. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/violation_filter.py +5 -4
  74. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/violation_generator.py +2 -5
  75. thailint-0.15.0/src/linters/file_header/__init__.py +24 -0
  76. thailint-0.15.0/src/linters/file_header/atemporal_detector.py +105 -0
  77. thailint-0.15.0/src/linters/file_header/base_parser.py +93 -0
  78. thailint-0.15.0/src/linters/file_header/bash_parser.py +66 -0
  79. thailint-0.15.0/src/linters/file_header/config.py +140 -0
  80. thailint-0.15.0/src/linters/file_header/css_parser.py +70 -0
  81. thailint-0.15.0/src/linters/file_header/field_validator.py +72 -0
  82. thailint-0.15.0/src/linters/file_header/linter.py +308 -0
  83. thailint-0.15.0/src/linters/file_header/markdown_parser.py +130 -0
  84. thailint-0.15.0/src/linters/file_header/python_parser.py +42 -0
  85. thailint-0.15.0/src/linters/file_header/typescript_parser.py +73 -0
  86. thailint-0.15.0/src/linters/file_header/violation_builder.py +79 -0
  87. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/config_loader.py +3 -1
  88. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/directory_matcher.py +4 -0
  89. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/linter.py +70 -27
  90. thailint-0.15.0/src/linters/file_placement/pattern_matcher.py +90 -0
  91. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/pattern_validator.py +25 -7
  92. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/rule_checker.py +2 -2
  93. thailint-0.15.0/src/linters/lazy_ignores/__init__.py +43 -0
  94. thailint-0.15.0/src/linters/lazy_ignores/config.py +66 -0
  95. thailint-0.15.0/src/linters/lazy_ignores/directive_utils.py +121 -0
  96. thailint-0.15.0/src/linters/lazy_ignores/header_parser.py +177 -0
  97. thailint-0.15.0/src/linters/lazy_ignores/linter.py +158 -0
  98. thailint-0.15.0/src/linters/lazy_ignores/matcher.py +135 -0
  99. thailint-0.15.0/src/linters/lazy_ignores/python_analyzer.py +205 -0
  100. thailint-0.15.0/src/linters/lazy_ignores/rule_id_utils.py +180 -0
  101. thailint-0.15.0/src/linters/lazy_ignores/skip_detector.py +298 -0
  102. thailint-0.15.0/src/linters/lazy_ignores/types.py +69 -0
  103. thailint-0.15.0/src/linters/lazy_ignores/typescript_analyzer.py +146 -0
  104. thailint-0.15.0/src/linters/lazy_ignores/violation_builder.py +131 -0
  105. thailint-0.15.0/src/linters/lbyl/__init__.py +29 -0
  106. thailint-0.15.0/src/linters/lbyl/config.py +63 -0
  107. thailint-0.15.0/src/linters/lbyl/pattern_detectors/__init__.py +25 -0
  108. thailint-0.15.0/src/linters/lbyl/pattern_detectors/base.py +46 -0
  109. thailint-0.15.0/src/linters/magic_numbers/context_analyzer.py +249 -0
  110. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/linter.py +44 -83
  111. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/python_analyzer.py +4 -16
  112. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/typescript_analyzer.py +9 -11
  113. thailint-0.15.0/src/linters/magic_numbers/typescript_ignore_checker.py +81 -0
  114. thailint-0.15.0/src/linters/method_property/__init__.py +49 -0
  115. thailint-0.15.0/src/linters/method_property/config.py +138 -0
  116. thailint-0.15.0/src/linters/method_property/linter.py +414 -0
  117. thailint-0.15.0/src/linters/method_property/python_analyzer.py +473 -0
  118. thailint-0.15.0/src/linters/method_property/violation_builder.py +119 -0
  119. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/linter.py +24 -16
  120. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/python_analyzer.py +4 -0
  121. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/typescript_analyzer.py +6 -11
  122. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/violation_builder.py +1 -0
  123. thailint-0.15.0/src/linters/performance/__init__.py +91 -0
  124. thailint-0.15.0/src/linters/performance/config.py +43 -0
  125. thailint-0.15.0/src/linters/performance/constants.py +49 -0
  126. thailint-0.15.0/src/linters/performance/linter.py +149 -0
  127. thailint-0.15.0/src/linters/performance/python_analyzer.py +365 -0
  128. thailint-0.15.0/src/linters/performance/regex_analyzer.py +312 -0
  129. thailint-0.15.0/src/linters/performance/regex_linter.py +139 -0
  130. thailint-0.15.0/src/linters/performance/typescript_analyzer.py +236 -0
  131. thailint-0.15.0/src/linters/performance/violation_builder.py +160 -0
  132. thailint-0.15.0/src/linters/print_statements/__init__.py +53 -0
  133. thailint-0.15.0/src/linters/print_statements/config.py +78 -0
  134. thailint-0.15.0/src/linters/print_statements/linter.py +413 -0
  135. thailint-0.15.0/src/linters/print_statements/python_analyzer.py +153 -0
  136. thailint-0.15.0/src/linters/print_statements/typescript_analyzer.py +125 -0
  137. thailint-0.15.0/src/linters/print_statements/violation_builder.py +96 -0
  138. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/class_analyzer.py +11 -7
  139. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/heuristics.py +10 -9
  140. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/linter.py +15 -16
  141. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/python_analyzer.py +55 -20
  142. thailint-0.15.0/src/linters/srp/typescript_metrics_calculator.py +126 -0
  143. thailint-0.15.0/src/linters/stateless_class/__init__.py +25 -0
  144. thailint-0.15.0/src/linters/stateless_class/config.py +58 -0
  145. thailint-0.15.0/src/linters/stateless_class/linter.py +349 -0
  146. thailint-0.15.0/src/linters/stateless_class/python_analyzer.py +290 -0
  147. thailint-0.15.0/src/linters/stringly_typed/__init__.py +36 -0
  148. thailint-0.15.0/src/linters/stringly_typed/config.py +189 -0
  149. thailint-0.15.0/src/linters/stringly_typed/context_filter.py +451 -0
  150. thailint-0.15.0/src/linters/stringly_typed/function_call_violation_builder.py +135 -0
  151. thailint-0.15.0/src/linters/stringly_typed/ignore_checker.py +102 -0
  152. thailint-0.15.0/src/linters/stringly_typed/ignore_utils.py +51 -0
  153. thailint-0.15.0/src/linters/stringly_typed/linter.py +376 -0
  154. thailint-0.15.0/src/linters/stringly_typed/python/__init__.py +33 -0
  155. thailint-0.15.0/src/linters/stringly_typed/python/analyzer.py +348 -0
  156. thailint-0.15.0/src/linters/stringly_typed/python/call_tracker.py +175 -0
  157. thailint-0.15.0/src/linters/stringly_typed/python/comparison_tracker.py +257 -0
  158. thailint-0.15.0/src/linters/stringly_typed/python/condition_extractor.py +134 -0
  159. thailint-0.15.0/src/linters/stringly_typed/python/conditional_detector.py +179 -0
  160. thailint-0.15.0/src/linters/stringly_typed/python/constants.py +21 -0
  161. thailint-0.15.0/src/linters/stringly_typed/python/match_analyzer.py +94 -0
  162. thailint-0.15.0/src/linters/stringly_typed/python/validation_detector.py +189 -0
  163. thailint-0.15.0/src/linters/stringly_typed/python/variable_extractor.py +96 -0
  164. thailint-0.15.0/src/linters/stringly_typed/storage.py +630 -0
  165. thailint-0.15.0/src/linters/stringly_typed/storage_initializer.py +45 -0
  166. thailint-0.15.0/src/linters/stringly_typed/typescript/__init__.py +28 -0
  167. thailint-0.15.0/src/linters/stringly_typed/typescript/analyzer.py +157 -0
  168. thailint-0.15.0/src/linters/stringly_typed/typescript/call_tracker.py +335 -0
  169. thailint-0.15.0/src/linters/stringly_typed/typescript/comparison_tracker.py +378 -0
  170. thailint-0.15.0/src/linters/stringly_typed/violation_generator.py +405 -0
  171. thailint-0.15.0/src/orchestrator/core.py +471 -0
  172. thailint-0.15.0/src/templates/thailint_config_template.yaml +354 -0
  173. thailint-0.15.0/src/utils/project_root.py +206 -0
  174. thailint-0.4.1/PKG-INFO +0 -1205
  175. thailint-0.4.1/README.md +0 -1171
  176. thailint-0.4.1/src/cli.py +0 -1317
  177. thailint-0.4.1/src/core/rule_discovery.py +0 -132
  178. thailint-0.4.1/src/linter_config/ignore.py +0 -475
  179. thailint-0.4.1/src/linters/dry/linter.py +0 -163
  180. thailint-0.4.1/src/linters/dry/python_analyzer.py +0 -528
  181. thailint-0.4.1/src/linters/dry/token_hasher.py +0 -115
  182. thailint-0.4.1/src/linters/dry/typescript_analyzer.py +0 -590
  183. thailint-0.4.1/src/linters/file_placement/pattern_matcher.py +0 -55
  184. thailint-0.4.1/src/linters/magic_numbers/context_analyzer.py +0 -247
  185. thailint-0.4.1/src/linters/srp/typescript_metrics_calculator.py +0 -90
  186. thailint-0.4.1/src/orchestrator/core.py +0 -223
  187. thailint-0.4.1/src/templates/thailint_config_template.yaml +0 -132
  188. thailint-0.4.1/src/utils/project_root.py +0 -84
  189. {thailint-0.4.1 → thailint-0.15.0}/LICENSE +0 -0
  190. {thailint-0.4.1 → thailint-0.15.0}/src/api.py +0 -0
  191. {thailint-0.4.1 → thailint-0.15.0}/src/core/__init__.py +0 -0
  192. {thailint-0.4.1 → thailint-0.15.0}/src/linter_config/__init__.py +0 -0
  193. {thailint-0.4.1 → thailint-0.15.0}/src/linters/__init__.py +0 -0
  194. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/__init__.py +0 -0
  195. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/config_loader.py +0 -0
  196. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/deduplicator.py +0 -0
  197. {thailint-0.4.1 → thailint-0.15.0}/src/linters/dry/storage_initializer.py +0 -0
  198. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/__init__.py +0 -0
  199. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/path_resolver.py +0 -0
  200. {thailint-0.4.1 → thailint-0.15.0}/src/linters/file_placement/violation_factory.py +0 -0
  201. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/__init__.py +0 -0
  202. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/config.py +0 -0
  203. {thailint-0.4.1 → thailint-0.15.0}/src/linters/magic_numbers/violation_builder.py +0 -0
  204. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/__init__.py +0 -0
  205. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/config.py +0 -0
  206. {thailint-0.4.1 → thailint-0.15.0}/src/linters/nesting/typescript_function_extractor.py +0 -0
  207. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/__init__.py +0 -0
  208. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/config.py +0 -0
  209. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/metrics_evaluator.py +0 -0
  210. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/typescript_analyzer.py +0 -0
  211. {thailint-0.4.1 → thailint-0.15.0}/src/linters/srp/violation_builder.py +0 -0
  212. {thailint-0.4.1 → thailint-0.15.0}/src/orchestrator/__init__.py +0 -0
  213. {thailint-0.4.1 → thailint-0.15.0}/src/orchestrator/language_detector.py +0 -0
  214. {thailint-0.4.1 → thailint-0.15.0}/src/utils/__init__.py +0 -0
@@ -24,6 +24,122 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24
24
 
25
25
  ## [Unreleased]
26
26
 
27
+ ### Added
28
+
29
+ - **Stateless Class Linter** - Detect Python classes without state that should be module-level functions
30
+ - AST-based detection of classes without `__init__`/`__new__` constructors
31
+ - Detects classes without instance state (`self.attr` assignments)
32
+ - Excludes ABC, Protocol, and decorated classes (legitimate patterns)
33
+ - Excludes classes with class-level attributes
34
+ - Minimum 2 methods required to flag (avoids false positives on simple wrappers)
35
+ - CLI command: `thailint stateless-class src/`
36
+ - JSON and SARIF output formats
37
+ - Configuration via `.thailint.yaml` with `min_methods` and `ignore` options
38
+ - Self-dogfooded: 23 violations in thai-lint codebase were fixed
39
+ - 28 tests (15 detector + 13 CLI) with 100% pass rate
40
+ - Documentation: `docs/stateless-class-linter.md`
41
+
42
+ - **Project Root Detection System** - Three-level precedence system for accurate configuration and ignore pattern resolution
43
+ - `--project-root` CLI option for explicit project root specification (highest priority)
44
+ - Automatic project root inference from `--config` path (config's parent directory becomes project root)
45
+ - Auto-detection fallback that walks up from file location to find markers (`.git`, `.thailint.yaml`, `pyproject.toml`)
46
+ - Priority order: `--project-root` > config inference > auto-detection
47
+ - Click path validation (exists, is directory) with helpful error messages
48
+ - All paths resolved to absolute paths immediately for consistency
49
+
50
+ - **Docker Sibling Directory Support** - Solves critical Docker use case where config and code are in separate directories
51
+ - Explicit project root specification: `docker run -v $(pwd):/workspace thailint --project-root /workspace/root magic-numbers /workspace/backend/`
52
+ - Automatic config path inference: `docker run -v $(pwd):/workspace thailint --config /workspace/root/.thailint.yaml magic-numbers /workspace/backend/`
53
+ - Monorepo support with shared configuration across multiple projects
54
+ - CI/CD-friendly with explicit paths preventing auto-detection issues
55
+
56
+ - **Enhanced Configuration System**
57
+ - Config loading now respects project root context
58
+ - Ignore patterns resolve relative to project root (not file location)
59
+ - Config search paths: explicit `--config` > project-root/.thailint.yaml > auto-detected locations
60
+ - Pyprojroot fallback for test environment compatibility
61
+
62
+ - **Test Suite**
63
+ - 42 tests for project root detection (29 new + 13 updated, 100% passing)
64
+ - `tests/unit/test_cli_project_root.py` - Explicit `--project-root` tests (15 tests)
65
+ - `tests/unit/test_cli_config_inference.py` - Config path inference tests (14 tests)
66
+ - Priority order tests verifying explicit > inferred > auto-detection
67
+ - Error handling tests for invalid paths (doesn't exist, is file not directory)
68
+ - Integration tests with real directory structures
69
+
70
+ ### Changed
71
+
72
+ - **CLI Commands** - All linter commands now accept `--project-root` option
73
+ - `thailint magic-numbers --project-root PATH [TARGET]`
74
+ - `thailint nesting --project-root PATH [TARGET]`
75
+ - `thailint srp --project-root PATH [TARGET]`
76
+ - `thailint file-placement --project-root PATH [TARGET]`
77
+ - All commands support combined usage: `--project-root` with `--config`
78
+
79
+ - **Orchestrator Initialization** - Now accepts explicit project root parameter
80
+ - `Orchestrator(project_root=Path, config_path=Path)` signature
81
+ - Project root passed from CLI to orchestrator for all linting operations
82
+ - Config loading uses project root context for path resolution
83
+
84
+ - **Path Resolution** - All ignore patterns resolve relative to project root
85
+ - Previous behavior: patterns resolved relative to file being linted
86
+ - New behavior: patterns resolved relative to project root directory
87
+ - More predictable and consistent ignore pattern matching
88
+ - Better Docker compatibility with volume mounts
89
+
90
+ ### Documentation
91
+
92
+ - **README.md** - Added comprehensive Docker sibling directory examples
93
+ - "Docker with Sibling Directories" section (lines 171-207)
94
+ - "Docker with Sibling Directories (Advanced)" section (lines 1071-1107)
95
+ - Directory structure examples and use cases
96
+ - Priority order explanation with multiple solution approaches
97
+
98
+ - **CLI Reference** (docs/cli-reference.md)
99
+ - Complete `--project-root` option documentation (lines 120-170)
100
+ - Enhanced `--config` section explaining automatic project root inference (lines 92-118)
101
+ - Use case examples: Docker, monorepos, CI/CD, ignore patterns
102
+ - Error handling examples and exit codes
103
+ - Priority order documentation
104
+
105
+ - **Troubleshooting Guide** (docs/troubleshooting.md)
106
+ - New "Docker sibling directory structure not working" section (lines 754-856)
107
+ - Problem symptoms and root cause explanation
108
+ - Three solution approaches ranked by recommendation
109
+ - Debugging steps with test commands
110
+ - Cross-references to related documentation
111
+
112
+ - **Technical Architecture** (.ai/docs/python-cli-architecture.md)
113
+ - New "Project Root Detection" component documentation (section 2)
114
+ - Architecture diagram updated with project root detection layer
115
+ - Design decisions and implementation patterns
116
+ - Testing strategy and related components
117
+ - Docker use case examples and configuration integration
118
+
119
+ ### Fixed
120
+
121
+ - **Docker Sibling Directory Issue** - Config and code can now be in separate, non-nested directories
122
+ - Previous: Only worked when code was nested under config directory
123
+ - Fixed: Works with any directory structure using `--project-root` or config inference
124
+ - Ignore patterns now resolve correctly in Docker volume mount scenarios
125
+
126
+ - **Ignore Pattern Resolution** - Patterns now resolve consistently relative to project root
127
+ - Previous: Resolved relative to file being linted (inconsistent behavior)
128
+ - Fixed: Resolved relative to project root (predictable, consistent)
129
+ - Especially important for Docker and monorepo scenarios
130
+
131
+ - **Test Environment Compatibility** - Added pyprojroot fallback for pytest environments
132
+ - Tests can run in isolated temporary directories
133
+ - Auto-detection gracefully handles test scenarios without project markers
134
+ - No impact on production code behavior
135
+
136
+ ### Infrastructure
137
+
138
+ - Test suite execution time: All tests pass in <120ms (optimized for fast feedback)
139
+ - TDD approach: RED tests → GREEN implementation → Documentation
140
+ - Pre-commit hooks validated for all changes
141
+ - Zero regressions in existing functionality (13 existing tests updated, all passing)
142
+
27
143
  ## [0.2.1] - 2025-10-09
28
144
 
29
145
  **Docker Path Validation Fix** - Fixes critical Docker image bug where file-specific linting failed due to premature path validation.
@@ -0,0 +1,185 @@
1
+ Metadata-Version: 2.4
2
+ Name: thailint
3
+ Version: 0.15.0
4
+ Summary: The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: linter,ai,code-quality,static-analysis,file-placement,governance,multi-language,cli,docker,python,performance,typescript
8
+ Author: Steve Jackson
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Classifier: Topic :: Utilities
25
+ Classifier: Typing :: Typed
26
+ Requires-Dist: click (>=8.1.0,<9.0.0)
27
+ Requires-Dist: pyprojroot (>=0.3.0,<0.4.0)
28
+ Requires-Dist: pyyaml (>=6.0,<7.0)
29
+ Requires-Dist: tree-sitter (>=0.25.2,<0.26.0)
30
+ Requires-Dist: tree-sitter-typescript (>=0.23.2,<0.24.0)
31
+ Project-URL: Documentation, https://thai-lint.readthedocs.io/
32
+ Project-URL: Homepage, https://github.com/be-wise-be-kind/thai-lint
33
+ Project-URL: Repository, https://github.com/be-wise-be-kind/thai-lint
34
+ Description-Content-Type: text/markdown
35
+
36
+ # thai-lint
37
+
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
39
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
40
+ [![PyPI](https://img.shields.io/pypi/v/thai-lint)](https://pypi.org/project/thai-lint/)
41
+ [![Documentation](https://readthedocs.org/projects/thai-lint/badge/?version=latest)](https://thai-lint.readthedocs.io/)
42
+
43
+ **The AI Linter** - Catch the mistakes AI coding assistants keep making.
44
+
45
+ thailint detects anti-patterns that AI tools frequently introduce: duplicate code, excessive nesting, magic numbers, SRP violations, and more. It works across Python, TypeScript, and JavaScript with unified rules - filling gaps that existing linters miss.
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install thai-lint
51
+ ```
52
+
53
+ Or with Docker:
54
+ ```bash
55
+ docker run --rm -v $(pwd):/data washad/thailint:latest --help
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ```bash
61
+ # Generate a config file (optional)
62
+ thailint init-config
63
+
64
+ # Run any linter
65
+ thailint dry src/
66
+ ```
67
+
68
+ That's it. See violations, fix them, ship better code.
69
+
70
+ ## Available Linters
71
+
72
+ | Linter | What It Catches | Command | Docs |
73
+ |--------|-----------------|---------|------|
74
+ | **DRY** | Duplicate code across files | `thailint dry src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/dry-linter/) |
75
+ | **Nesting** | Deeply nested if/for/while blocks | `thailint nesting src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/nesting-linter/) |
76
+ | **Magic Numbers** | Unnamed numeric literals | `thailint magic-numbers src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/magic-numbers-linter/) |
77
+ | **Performance** | O(n²) patterns: string += in loops, regex in loops | `thailint perf src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/performance-linter/) |
78
+ | **SRP** | Classes doing too much | `thailint srp src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/srp-linter/) |
79
+ | **File Header** | Missing documentation headers | `thailint file-header src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-header-linter/) |
80
+ | **Stateless Class** | Classes that should be functions | `thailint stateless-class src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stateless-class-linter/) |
81
+ | **Collection Pipeline** | Loops with embedded filtering | `thailint pipeline src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/collection-pipeline-linter/) |
82
+ | **Method Property** | Methods that should be @property | `thailint method-property src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/method-property-linter/) |
83
+ | **File Placement** | Files in wrong directories | `thailint file-placement src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-placement-linter/) |
84
+ | **Lazy Ignores** | Unjustified linting suppressions | `thailint lazy-ignores src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lazy-ignores-linter/) |
85
+ | **Print Statements** | Debug prints left in code | `thailint print-statements src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/print-statements-linter/) |
86
+ | **Stringly Typed** | Strings that should be enums | `thailint stringly-typed src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stringly-typed-linter/) |
87
+
88
+ ## Configuration
89
+
90
+ Create `.thailint.yaml` in your project root:
91
+
92
+ ```yaml
93
+ dry:
94
+ enabled: true
95
+ min_duplicate_lines: 4
96
+
97
+ nesting:
98
+ enabled: true
99
+ max_nesting_depth: 3
100
+
101
+ magic-numbers:
102
+ enabled: true
103
+ allowed_numbers: [-1, 0, 1, 2, 10, 100]
104
+ ```
105
+
106
+ Or generate one automatically:
107
+ ```bash
108
+ thailint init-config --preset lenient # or: strict, standard
109
+ ```
110
+
111
+ See [Configuration Reference](https://thai-lint.readthedocs.io/en/latest/configuration/) for all options.
112
+
113
+ ## Output Formats
114
+
115
+ ```bash
116
+ # Human-readable (default)
117
+ thailint dry src/
118
+
119
+ # JSON for CI/CD
120
+ thailint dry --format json src/
121
+
122
+ # SARIF for GitHub Code Scanning
123
+ thailint dry --format sarif src/ > results.sarif
124
+ ```
125
+
126
+ ## Ignoring Violations
127
+
128
+ ```python
129
+ # Line-level
130
+ timeout = 3600 # thailint: ignore[magic-numbers]
131
+
132
+ # File-level
133
+ # thailint: ignore-file[dry]
134
+ ```
135
+
136
+ Or in config:
137
+ ```yaml
138
+ dry:
139
+ ignore:
140
+ - "tests/"
141
+ - "**/generated/**"
142
+ ```
143
+
144
+ See [How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to-ignore-violations/) for all 5 ignore levels.
145
+
146
+ ## CI/CD Integration
147
+
148
+ ```yaml
149
+ # GitHub Actions
150
+ - name: Run thailint
151
+ run: |
152
+ pip install thai-lint
153
+ thailint dry src/
154
+ thailint nesting src/
155
+ ```
156
+
157
+ Exit codes: `0` = success, `1` = violations found, `2` = error.
158
+
159
+ ## Documentation
160
+
161
+ - **[Quick Start Guide](https://thai-lint.readthedocs.io/en/latest/quick-start/)** - Get running in 5 minutes
162
+ - **[Configuration Reference](https://thai-lint.readthedocs.io/en/latest/configuration/)** - All config options
163
+ - **[Troubleshooting](https://thai-lint.readthedocs.io/en/latest/troubleshooting/)** - Common issues
164
+ - **[Full Documentation](https://thai-lint.readthedocs.io/)** - Everything else
165
+
166
+ ## Contributing
167
+
168
+ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
169
+
170
+ ```bash
171
+ git clone https://github.com/be-wise-be-kind/thai-lint.git
172
+ cd thai-lint
173
+ poetry install
174
+ just test
175
+ ```
176
+
177
+ ## License
178
+
179
+ MIT License - see [LICENSE](LICENSE) for details.
180
+
181
+ ## Support
182
+
183
+ - **Issues**: [github.com/be-wise-be-kind/thai-lint/issues](https://github.com/be-wise-be-kind/thai-lint/issues)
184
+ - **Docs**: [thai-lint.readthedocs.io](https://thai-lint.readthedocs.io/)
185
+
@@ -0,0 +1,149 @@
1
+ # thai-lint
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
5
+ [![PyPI](https://img.shields.io/pypi/v/thai-lint)](https://pypi.org/project/thai-lint/)
6
+ [![Documentation](https://readthedocs.org/projects/thai-lint/badge/?version=latest)](https://thai-lint.readthedocs.io/)
7
+
8
+ **The AI Linter** - Catch the mistakes AI coding assistants keep making.
9
+
10
+ thailint detects anti-patterns that AI tools frequently introduce: duplicate code, excessive nesting, magic numbers, SRP violations, and more. It works across Python, TypeScript, and JavaScript with unified rules - filling gaps that existing linters miss.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install thai-lint
16
+ ```
17
+
18
+ Or with Docker:
19
+ ```bash
20
+ docker run --rm -v $(pwd):/data washad/thailint:latest --help
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```bash
26
+ # Generate a config file (optional)
27
+ thailint init-config
28
+
29
+ # Run any linter
30
+ thailint dry src/
31
+ ```
32
+
33
+ That's it. See violations, fix them, ship better code.
34
+
35
+ ## Available Linters
36
+
37
+ | Linter | What It Catches | Command | Docs |
38
+ |--------|-----------------|---------|------|
39
+ | **DRY** | Duplicate code across files | `thailint dry src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/dry-linter/) |
40
+ | **Nesting** | Deeply nested if/for/while blocks | `thailint nesting src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/nesting-linter/) |
41
+ | **Magic Numbers** | Unnamed numeric literals | `thailint magic-numbers src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/magic-numbers-linter/) |
42
+ | **Performance** | O(n²) patterns: string += in loops, regex in loops | `thailint perf src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/performance-linter/) |
43
+ | **SRP** | Classes doing too much | `thailint srp src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/srp-linter/) |
44
+ | **File Header** | Missing documentation headers | `thailint file-header src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-header-linter/) |
45
+ | **Stateless Class** | Classes that should be functions | `thailint stateless-class src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stateless-class-linter/) |
46
+ | **Collection Pipeline** | Loops with embedded filtering | `thailint pipeline src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/collection-pipeline-linter/) |
47
+ | **Method Property** | Methods that should be @property | `thailint method-property src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/method-property-linter/) |
48
+ | **File Placement** | Files in wrong directories | `thailint file-placement src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-placement-linter/) |
49
+ | **Lazy Ignores** | Unjustified linting suppressions | `thailint lazy-ignores src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lazy-ignores-linter/) |
50
+ | **Print Statements** | Debug prints left in code | `thailint print-statements src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/print-statements-linter/) |
51
+ | **Stringly Typed** | Strings that should be enums | `thailint stringly-typed src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stringly-typed-linter/) |
52
+
53
+ ## Configuration
54
+
55
+ Create `.thailint.yaml` in your project root:
56
+
57
+ ```yaml
58
+ dry:
59
+ enabled: true
60
+ min_duplicate_lines: 4
61
+
62
+ nesting:
63
+ enabled: true
64
+ max_nesting_depth: 3
65
+
66
+ magic-numbers:
67
+ enabled: true
68
+ allowed_numbers: [-1, 0, 1, 2, 10, 100]
69
+ ```
70
+
71
+ Or generate one automatically:
72
+ ```bash
73
+ thailint init-config --preset lenient # or: strict, standard
74
+ ```
75
+
76
+ See [Configuration Reference](https://thai-lint.readthedocs.io/en/latest/configuration/) for all options.
77
+
78
+ ## Output Formats
79
+
80
+ ```bash
81
+ # Human-readable (default)
82
+ thailint dry src/
83
+
84
+ # JSON for CI/CD
85
+ thailint dry --format json src/
86
+
87
+ # SARIF for GitHub Code Scanning
88
+ thailint dry --format sarif src/ > results.sarif
89
+ ```
90
+
91
+ ## Ignoring Violations
92
+
93
+ ```python
94
+ # Line-level
95
+ timeout = 3600 # thailint: ignore[magic-numbers]
96
+
97
+ # File-level
98
+ # thailint: ignore-file[dry]
99
+ ```
100
+
101
+ Or in config:
102
+ ```yaml
103
+ dry:
104
+ ignore:
105
+ - "tests/"
106
+ - "**/generated/**"
107
+ ```
108
+
109
+ See [How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to-ignore-violations/) for all 5 ignore levels.
110
+
111
+ ## CI/CD Integration
112
+
113
+ ```yaml
114
+ # GitHub Actions
115
+ - name: Run thailint
116
+ run: |
117
+ pip install thai-lint
118
+ thailint dry src/
119
+ thailint nesting src/
120
+ ```
121
+
122
+ Exit codes: `0` = success, `1` = violations found, `2` = error.
123
+
124
+ ## Documentation
125
+
126
+ - **[Quick Start Guide](https://thai-lint.readthedocs.io/en/latest/quick-start/)** - Get running in 5 minutes
127
+ - **[Configuration Reference](https://thai-lint.readthedocs.io/en/latest/configuration/)** - All config options
128
+ - **[Troubleshooting](https://thai-lint.readthedocs.io/en/latest/troubleshooting/)** - Common issues
129
+ - **[Full Documentation](https://thai-lint.readthedocs.io/)** - Everything else
130
+
131
+ ## Contributing
132
+
133
+ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
134
+
135
+ ```bash
136
+ git clone https://github.com/be-wise-be-kind/thai-lint.git
137
+ cd thai-lint
138
+ poetry install
139
+ just test
140
+ ```
141
+
142
+ ## License
143
+
144
+ MIT License - see [LICENSE](LICENSE) for details.
145
+
146
+ ## Support
147
+
148
+ - **Issues**: [github.com/be-wise-be-kind/thai-lint/issues](https://github.com/be-wise-be-kind/thai-lint/issues)
149
+ - **Docs**: [thai-lint.readthedocs.io](https://thai-lint.readthedocs.io/)
@@ -17,14 +17,14 @@ build-backend = "poetry.core.masonry.api"
17
17
 
18
18
  [tool.poetry]
19
19
  name = "thailint"
20
- version = "0.4.1"
20
+ version = "0.15.0"
21
21
  description = "The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages"
22
22
  authors = ["Steve Jackson"]
23
23
  license = "MIT"
24
24
  readme = "README.md"
25
25
  homepage = "https://github.com/be-wise-be-kind/thai-lint"
26
26
  repository = "https://github.com/be-wise-be-kind/thai-lint"
27
- documentation = "https://github.com/be-wise-be-kind/thai-lint#readme"
27
+ documentation = "https://thai-lint.readthedocs.io/"
28
28
  keywords = [
29
29
  "linter",
30
30
  "ai",
@@ -36,9 +36,11 @@ keywords = [
36
36
  "cli",
37
37
  "docker",
38
38
  "python",
39
+ "performance",
40
+ "typescript",
39
41
  ]
40
42
  classifiers = [
41
- "Development Status :: 3 - Alpha",
43
+ "Development Status :: 4 - Beta",
42
44
  "Intended Audience :: Developers",
43
45
  "License :: OSI Approved :: MIT License",
44
46
  "Programming Language :: Python :: 3",
@@ -104,8 +106,8 @@ loguru = "^0.7.3"
104
106
  pytest-xdist = "^3.8.0"
105
107
 
106
108
  [tool.poetry.scripts]
107
- thailint = "src.cli:cli"
108
- thai-lint = "src.cli:cli"
109
+ thailint = "src.cli_main:cli"
110
+ thai-lint = "src.cli_main:cli"
109
111
 
110
112
  # Ruff configuration
111
113
  [tool.ruff]
@@ -228,6 +230,7 @@ disable = [
228
230
 
229
231
  [tool.pylint.format]
230
232
  max-line-length = 120
233
+ max-module-lines = 500
231
234
 
232
235
  # Flake8 configuration (in .flake8 file, not pyproject.toml)
233
236
  # Note: Flake8 doesn't support pyproject.toml natively
@@ -19,6 +19,7 @@ Exports: __version__, Linter (high-level API), cli (CLI entry point), load_confi
19
19
  Interfaces: Package version string, Linter class API, CLI command group, configuration functions
20
20
  """
21
21
 
22
+ __version__: str
22
23
  try:
23
24
  from importlib.metadata import version
24
25
 
@@ -9,15 +9,16 @@ Overview: Package containing base analyzer classes for different programming lan
9
9
  (TypeScriptBaseAnalyzer, etc.) that linter-specific analyzers extend. Centralizes
10
10
  language parsing infrastructure to improve maintainability and consistency.
11
11
 
12
- Dependencies: tree-sitter, language-specific tree-sitter bindings
12
+ Dependencies: tree-sitter, language-specific tree-sitter bindings, ast module
13
13
 
14
- Exports: TypeScriptBaseAnalyzer
14
+ Exports: TypeScriptBaseAnalyzer, build_parent_map
15
15
 
16
16
  Interfaces: Base analyzer classes with parse(), walk_tree(), and extract() methods
17
17
 
18
18
  Implementation: Composition-based design for linter analyzers to use base utilities
19
19
  """
20
20
 
21
+ from .ast_utils import build_parent_map
21
22
  from .typescript_base import TypeScriptBaseAnalyzer
22
23
 
23
- __all__ = ["TypeScriptBaseAnalyzer"]
24
+ __all__ = ["TypeScriptBaseAnalyzer", "build_parent_map"]
@@ -0,0 +1,54 @@
1
+ """
2
+ Purpose: Common Python AST utilities for linter analyzers
3
+
4
+ Scope: Shared AST traversal utilities for Python code analysis
5
+
6
+ Overview: Provides common AST utility functions used across multiple Python linters.
7
+ Centralizes shared patterns like parent map building to eliminate code duplication.
8
+ The build_parent_map function creates a dictionary mapping AST nodes to their parents,
9
+ enabling upward tree traversal for context detection.
10
+
11
+ Dependencies: ast module for AST node types
12
+
13
+ Exports: build_parent_map
14
+
15
+ Interfaces: build_parent_map(tree: ast.AST) -> dict[ast.AST, ast.AST]
16
+
17
+ Implementation: Recursive AST traversal with parent tracking
18
+ """
19
+
20
+ import ast
21
+
22
+
23
+ def build_parent_map(tree: ast.AST) -> dict[ast.AST, ast.AST]:
24
+ """Build a map of AST nodes to their parent nodes.
25
+
26
+ Enables upward tree traversal for context detection (e.g., finding if a node
27
+ is inside a particular block type).
28
+
29
+ Args:
30
+ tree: Root AST node to build map from
31
+
32
+ Returns:
33
+ Dictionary mapping each node to its parent node
34
+ """
35
+ parent_map: dict[ast.AST, ast.AST] = {}
36
+ _build_parent_map_recursive(tree, None, parent_map)
37
+ return parent_map
38
+
39
+
40
+ def _build_parent_map_recursive(
41
+ node: ast.AST, parent: ast.AST | None, parent_map: dict[ast.AST, ast.AST]
42
+ ) -> None:
43
+ """Recursively build parent map.
44
+
45
+ Args:
46
+ node: Current AST node
47
+ parent: Parent of current node
48
+ parent_map: Dictionary to populate
49
+ """
50
+ if parent is not None:
51
+ parent_map[node] = parent
52
+
53
+ for child in ast.iter_child_nodes(node):
54
+ _build_parent_map_recursive(child, node, parent_map)
@@ -18,6 +18,10 @@ Exports: TypeScriptBaseAnalyzer class with parsing and traversal utilities
18
18
  Interfaces: parse_typescript(code), walk_tree(node, node_type), extract_node_text(node)
19
19
 
20
20
  Implementation: Tree-sitter parser singleton, recursive AST traversal, composition pattern
21
+
22
+ Suppressions:
23
+ - type:ignore[assignment]: Tree-sitter TS_PARSER fallback when import fails
24
+ - type:ignore[assignment,misc]: Tree-sitter Node type alias (optional dependency fallback)
21
25
  """
22
26
 
23
27
  from typing import Any
@@ -0,0 +1,30 @@
1
+ """
2
+ Purpose: CLI package entry point and public API for thai-lint command-line interface
3
+
4
+ Scope: Re-export fully configured CLI with all commands registered
5
+
6
+ Overview: Provides the public API for the modular CLI package by re-exporting the CLI group from
7
+ src.cli.main and triggering command registration by importing submodules. Importing from this
8
+ module (src.cli) gives access to the complete CLI with all commands. Maintains backward
9
+ compatibility with code that imports from src.cli while enabling modular organization.
10
+
11
+ Dependencies: src.cli.main for CLI group, src.cli.config for config commands, src.cli.linters
12
+ for linter commands
13
+
14
+ Exports: cli (main Click command group with all commands registered)
15
+
16
+ Interfaces: Single import point for CLI access via 'from src.cli import cli'
17
+
18
+ Implementation: Imports submodules to trigger command registration via Click decorators
19
+
20
+ Suppressions:
21
+ - F401: Module re-exports required for public API interface
22
+ """
23
+
24
+ # Import the CLI group from main module
25
+ # Import config and linters to register their commands with the CLI group
26
+ from src.cli import config as _config_module # noqa: F401
27
+ from src.cli import linters as _linters_module # noqa: F401
28
+ from src.cli.main import cli # noqa: F401
29
+
30
+ __all__ = ["cli"]
@@ -0,0 +1,22 @@
1
+ """
2
+ Purpose: Entry point for running thai-lint CLI as a module (python -m src.cli)
3
+
4
+ Scope: Module execution support for direct CLI invocation
5
+
6
+ Overview: Enables running the CLI via 'python -m src.cli' by invoking the main cli group.
7
+ This file is executed when the package is run as a module, providing an alternative
8
+ entry point to the installed 'thailint' command.
9
+
10
+ Dependencies: src.cli for fully configured CLI
11
+
12
+ Exports: None (execution entry point only)
13
+
14
+ Interfaces: Command-line invocation via 'python -m src.cli [command] [args]'
15
+
16
+ Implementation: Imports and invokes cli() from the package
17
+ """
18
+
19
+ from src.cli import cli
20
+
21
+ if __name__ == "__main__":
22
+ cli()