thailint 0.4.1__tar.gz → 0.14.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.
- {thailint-0.4.1 → thailint-0.14.0}/CHANGELOG.md +116 -0
- thailint-0.14.0/PKG-INFO +185 -0
- thailint-0.14.0/README.md +149 -0
- {thailint-0.4.1 → thailint-0.14.0}/pyproject.toml +8 -5
- {thailint-0.4.1 → thailint-0.14.0}/src/__init__.py +1 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/analyzers/__init__.py +4 -3
- thailint-0.14.0/src/analyzers/ast_utils.py +54 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/analyzers/typescript_base.py +4 -0
- thailint-0.14.0/src/cli/__init__.py +30 -0
- thailint-0.14.0/src/cli/__main__.py +22 -0
- thailint-0.14.0/src/cli/config.py +478 -0
- thailint-0.14.0/src/cli/config_merge.py +241 -0
- thailint-0.14.0/src/cli/linters/__init__.py +67 -0
- thailint-0.14.0/src/cli/linters/code_patterns.py +222 -0
- thailint-0.14.0/src/cli/linters/code_smells.py +333 -0
- thailint-0.14.0/src/cli/linters/documentation.py +81 -0
- thailint-0.14.0/src/cli/linters/performance.py +274 -0
- thailint-0.14.0/src/cli/linters/shared.py +315 -0
- thailint-0.14.0/src/cli/linters/structure.py +318 -0
- thailint-0.14.0/src/cli/linters/structure_quality.py +323 -0
- thailint-0.14.0/src/cli/main.py +120 -0
- thailint-0.14.0/src/cli/utils.py +395 -0
- thailint-0.14.0/src/cli_main.py +37 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/config.py +4 -4
- {thailint-0.4.1 → thailint-0.14.0}/src/core/base.py +7 -2
- {thailint-0.4.1 → thailint-0.14.0}/src/core/cli_utils.py +19 -2
- {thailint-0.4.1 → thailint-0.14.0}/src/core/config_parser.py +36 -6
- thailint-0.14.0/src/core/constants.py +54 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/core/linter_utils.py +95 -6
- {thailint-0.4.1 → thailint-0.14.0}/src/core/registry.py +1 -1
- thailint-0.14.0/src/core/rule_discovery.py +195 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/core/types.py +13 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/core/violation_builder.py +78 -15
- thailint-0.14.0/src/core/violation_utils.py +69 -0
- thailint-0.14.0/src/formatters/__init__.py +22 -0
- thailint-0.14.0/src/formatters/sarif.py +202 -0
- thailint-0.14.0/src/linter_config/directive_markers.py +109 -0
- thailint-0.14.0/src/linter_config/ignore.py +333 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linter_config/loader.py +45 -12
- thailint-0.14.0/src/linter_config/pattern_utils.py +65 -0
- thailint-0.14.0/src/linter_config/rule_matcher.py +89 -0
- thailint-0.14.0/src/linters/collection_pipeline/__init__.py +90 -0
- thailint-0.14.0/src/linters/collection_pipeline/any_all_analyzer.py +281 -0
- thailint-0.14.0/src/linters/collection_pipeline/ast_utils.py +40 -0
- thailint-0.14.0/src/linters/collection_pipeline/config.py +75 -0
- thailint-0.14.0/src/linters/collection_pipeline/continue_analyzer.py +94 -0
- thailint-0.14.0/src/linters/collection_pipeline/detector.py +360 -0
- thailint-0.14.0/src/linters/collection_pipeline/filter_map_analyzer.py +402 -0
- thailint-0.14.0/src/linters/collection_pipeline/linter.py +420 -0
- thailint-0.14.0/src/linters/collection_pipeline/suggestion_builder.py +130 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/base_token_analyzer.py +16 -9
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/block_filter.py +120 -20
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/block_grouper.py +4 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/cache.py +104 -10
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/cache_query.py +4 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/config.py +54 -11
- thailint-0.14.0/src/linters/dry/constant.py +92 -0
- thailint-0.14.0/src/linters/dry/constant_matcher.py +223 -0
- thailint-0.14.0/src/linters/dry/constant_violation_builder.py +98 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/duplicate_storage.py +5 -4
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/file_analyzer.py +4 -2
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/inline_ignore.py +7 -16
- thailint-0.14.0/src/linters/dry/linter.py +227 -0
- thailint-0.14.0/src/linters/dry/python_analyzer.py +289 -0
- thailint-0.14.0/src/linters/dry/python_constant_extractor.py +100 -0
- thailint-0.14.0/src/linters/dry/single_statement_detector.py +417 -0
- thailint-0.14.0/src/linters/dry/token_hasher.py +173 -0
- thailint-0.14.0/src/linters/dry/typescript_analyzer.py +278 -0
- thailint-0.14.0/src/linters/dry/typescript_constant_extractor.py +138 -0
- thailint-0.14.0/src/linters/dry/typescript_statement_detector.py +255 -0
- thailint-0.14.0/src/linters/dry/typescript_value_extractor.py +69 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/violation_builder.py +4 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/violation_filter.py +5 -4
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/violation_generator.py +2 -5
- thailint-0.14.0/src/linters/file_header/__init__.py +24 -0
- thailint-0.14.0/src/linters/file_header/atemporal_detector.py +105 -0
- thailint-0.14.0/src/linters/file_header/base_parser.py +93 -0
- thailint-0.14.0/src/linters/file_header/bash_parser.py +66 -0
- thailint-0.14.0/src/linters/file_header/config.py +140 -0
- thailint-0.14.0/src/linters/file_header/css_parser.py +70 -0
- thailint-0.14.0/src/linters/file_header/field_validator.py +72 -0
- thailint-0.14.0/src/linters/file_header/linter.py +308 -0
- thailint-0.14.0/src/linters/file_header/markdown_parser.py +130 -0
- thailint-0.14.0/src/linters/file_header/python_parser.py +42 -0
- thailint-0.14.0/src/linters/file_header/typescript_parser.py +73 -0
- thailint-0.14.0/src/linters/file_header/violation_builder.py +79 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/config_loader.py +3 -1
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/directory_matcher.py +4 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/linter.py +70 -27
- thailint-0.14.0/src/linters/file_placement/pattern_matcher.py +90 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/pattern_validator.py +25 -7
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/rule_checker.py +2 -2
- thailint-0.14.0/src/linters/lazy_ignores/__init__.py +43 -0
- thailint-0.14.0/src/linters/lazy_ignores/config.py +66 -0
- thailint-0.14.0/src/linters/lazy_ignores/directive_utils.py +121 -0
- thailint-0.14.0/src/linters/lazy_ignores/header_parser.py +177 -0
- thailint-0.14.0/src/linters/lazy_ignores/linter.py +158 -0
- thailint-0.14.0/src/linters/lazy_ignores/matcher.py +135 -0
- thailint-0.14.0/src/linters/lazy_ignores/python_analyzer.py +205 -0
- thailint-0.14.0/src/linters/lazy_ignores/rule_id_utils.py +180 -0
- thailint-0.14.0/src/linters/lazy_ignores/skip_detector.py +298 -0
- thailint-0.14.0/src/linters/lazy_ignores/types.py +69 -0
- thailint-0.14.0/src/linters/lazy_ignores/typescript_analyzer.py +146 -0
- thailint-0.14.0/src/linters/lazy_ignores/violation_builder.py +131 -0
- thailint-0.14.0/src/linters/lbyl/__init__.py +29 -0
- thailint-0.14.0/src/linters/lbyl/config.py +63 -0
- thailint-0.14.0/src/linters/lbyl/pattern_detectors/__init__.py +25 -0
- thailint-0.14.0/src/linters/lbyl/pattern_detectors/base.py +46 -0
- thailint-0.14.0/src/linters/magic_numbers/context_analyzer.py +249 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/linter.py +44 -83
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/python_analyzer.py +4 -16
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/typescript_analyzer.py +9 -11
- thailint-0.14.0/src/linters/magic_numbers/typescript_ignore_checker.py +81 -0
- thailint-0.14.0/src/linters/method_property/__init__.py +49 -0
- thailint-0.14.0/src/linters/method_property/config.py +138 -0
- thailint-0.14.0/src/linters/method_property/linter.py +414 -0
- thailint-0.14.0/src/linters/method_property/python_analyzer.py +473 -0
- thailint-0.14.0/src/linters/method_property/violation_builder.py +119 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/linter.py +24 -16
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/python_analyzer.py +4 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/typescript_analyzer.py +6 -11
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/violation_builder.py +1 -0
- thailint-0.14.0/src/linters/performance/__init__.py +91 -0
- thailint-0.14.0/src/linters/performance/config.py +43 -0
- thailint-0.14.0/src/linters/performance/constants.py +49 -0
- thailint-0.14.0/src/linters/performance/linter.py +149 -0
- thailint-0.14.0/src/linters/performance/python_analyzer.py +365 -0
- thailint-0.14.0/src/linters/performance/regex_analyzer.py +312 -0
- thailint-0.14.0/src/linters/performance/regex_linter.py +139 -0
- thailint-0.14.0/src/linters/performance/typescript_analyzer.py +236 -0
- thailint-0.14.0/src/linters/performance/violation_builder.py +160 -0
- thailint-0.14.0/src/linters/print_statements/__init__.py +53 -0
- thailint-0.14.0/src/linters/print_statements/config.py +78 -0
- thailint-0.14.0/src/linters/print_statements/linter.py +413 -0
- thailint-0.14.0/src/linters/print_statements/python_analyzer.py +153 -0
- thailint-0.14.0/src/linters/print_statements/typescript_analyzer.py +125 -0
- thailint-0.14.0/src/linters/print_statements/violation_builder.py +96 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/class_analyzer.py +11 -7
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/heuristics.py +10 -9
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/linter.py +15 -16
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/python_analyzer.py +55 -20
- thailint-0.14.0/src/linters/srp/typescript_metrics_calculator.py +126 -0
- thailint-0.14.0/src/linters/stateless_class/__init__.py +25 -0
- thailint-0.14.0/src/linters/stateless_class/config.py +58 -0
- thailint-0.14.0/src/linters/stateless_class/linter.py +349 -0
- thailint-0.14.0/src/linters/stateless_class/python_analyzer.py +290 -0
- thailint-0.14.0/src/linters/stringly_typed/__init__.py +36 -0
- thailint-0.14.0/src/linters/stringly_typed/config.py +189 -0
- thailint-0.14.0/src/linters/stringly_typed/context_filter.py +451 -0
- thailint-0.14.0/src/linters/stringly_typed/function_call_violation_builder.py +135 -0
- thailint-0.14.0/src/linters/stringly_typed/ignore_checker.py +102 -0
- thailint-0.14.0/src/linters/stringly_typed/ignore_utils.py +51 -0
- thailint-0.14.0/src/linters/stringly_typed/linter.py +376 -0
- thailint-0.14.0/src/linters/stringly_typed/python/__init__.py +33 -0
- thailint-0.14.0/src/linters/stringly_typed/python/analyzer.py +348 -0
- thailint-0.14.0/src/linters/stringly_typed/python/call_tracker.py +175 -0
- thailint-0.14.0/src/linters/stringly_typed/python/comparison_tracker.py +257 -0
- thailint-0.14.0/src/linters/stringly_typed/python/condition_extractor.py +134 -0
- thailint-0.14.0/src/linters/stringly_typed/python/conditional_detector.py +179 -0
- thailint-0.14.0/src/linters/stringly_typed/python/constants.py +21 -0
- thailint-0.14.0/src/linters/stringly_typed/python/match_analyzer.py +94 -0
- thailint-0.14.0/src/linters/stringly_typed/python/validation_detector.py +189 -0
- thailint-0.14.0/src/linters/stringly_typed/python/variable_extractor.py +96 -0
- thailint-0.14.0/src/linters/stringly_typed/storage.py +630 -0
- thailint-0.14.0/src/linters/stringly_typed/storage_initializer.py +45 -0
- thailint-0.14.0/src/linters/stringly_typed/typescript/__init__.py +28 -0
- thailint-0.14.0/src/linters/stringly_typed/typescript/analyzer.py +157 -0
- thailint-0.14.0/src/linters/stringly_typed/typescript/call_tracker.py +335 -0
- thailint-0.14.0/src/linters/stringly_typed/typescript/comparison_tracker.py +378 -0
- thailint-0.14.0/src/linters/stringly_typed/violation_generator.py +405 -0
- thailint-0.14.0/src/orchestrator/core.py +471 -0
- thailint-0.14.0/src/templates/thailint_config_template.yaml +354 -0
- thailint-0.14.0/src/utils/project_root.py +206 -0
- thailint-0.4.1/PKG-INFO +0 -1205
- thailint-0.4.1/README.md +0 -1171
- thailint-0.4.1/src/cli.py +0 -1317
- thailint-0.4.1/src/core/rule_discovery.py +0 -132
- thailint-0.4.1/src/linter_config/ignore.py +0 -475
- thailint-0.4.1/src/linters/dry/linter.py +0 -163
- thailint-0.4.1/src/linters/dry/python_analyzer.py +0 -528
- thailint-0.4.1/src/linters/dry/token_hasher.py +0 -115
- thailint-0.4.1/src/linters/dry/typescript_analyzer.py +0 -590
- thailint-0.4.1/src/linters/file_placement/pattern_matcher.py +0 -55
- thailint-0.4.1/src/linters/magic_numbers/context_analyzer.py +0 -247
- thailint-0.4.1/src/linters/srp/typescript_metrics_calculator.py +0 -90
- thailint-0.4.1/src/orchestrator/core.py +0 -223
- thailint-0.4.1/src/templates/thailint_config_template.yaml +0 -132
- thailint-0.4.1/src/utils/project_root.py +0 -84
- {thailint-0.4.1 → thailint-0.14.0}/LICENSE +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/api.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/core/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linter_config/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/config_loader.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/deduplicator.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/dry/storage_initializer.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/path_resolver.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/file_placement/violation_factory.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/config.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/magic_numbers/violation_builder.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/config.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/nesting/typescript_function_extractor.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/config.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/metrics_evaluator.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/typescript_analyzer.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/linters/srp/violation_builder.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/orchestrator/__init__.py +0 -0
- {thailint-0.4.1 → thailint-0.14.0}/src/orchestrator/language_detector.py +0 -0
- {thailint-0.4.1 → thailint-0.14.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.
|
thailint-0.14.0/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: thailint
|
|
3
|
+
Version: 0.14.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
|
+
[](https://opensource.org/licenses/MIT)
|
|
39
|
+
[](https://www.python.org/downloads/)
|
|
40
|
+
[](https://pypi.org/project/thai-lint/)
|
|
41
|
+
[](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
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://pypi.org/project/thai-lint/)
|
|
6
|
+
[](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.
|
|
20
|
+
version = "0.14.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://
|
|
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 ::
|
|
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.
|
|
108
|
-
thai-lint = "src.
|
|
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()
|