thailint 0.4.6__py3-none-any.whl → 0.7.0__py3-none-any.whl

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 (31) hide show
  1. src/cli.py +228 -1
  2. src/core/cli_utils.py +16 -1
  3. src/core/registry.py +1 -1
  4. src/formatters/__init__.py +22 -0
  5. src/formatters/sarif.py +202 -0
  6. src/linters/file_header/atemporal_detector.py +11 -11
  7. src/linters/file_header/base_parser.py +89 -0
  8. src/linters/file_header/bash_parser.py +58 -0
  9. src/linters/file_header/config.py +76 -16
  10. src/linters/file_header/css_parser.py +70 -0
  11. src/linters/file_header/field_validator.py +35 -29
  12. src/linters/file_header/linter.py +113 -121
  13. src/linters/file_header/markdown_parser.py +124 -0
  14. src/linters/file_header/python_parser.py +14 -58
  15. src/linters/file_header/typescript_parser.py +73 -0
  16. src/linters/file_header/violation_builder.py +13 -12
  17. src/linters/file_placement/linter.py +9 -11
  18. src/linters/magic_numbers/typescript_analyzer.py +1 -0
  19. src/linters/nesting/typescript_analyzer.py +1 -0
  20. src/linters/print_statements/__init__.py +53 -0
  21. src/linters/print_statements/config.py +78 -0
  22. src/linters/print_statements/linter.py +428 -0
  23. src/linters/print_statements/python_analyzer.py +149 -0
  24. src/linters/print_statements/typescript_analyzer.py +130 -0
  25. src/linters/print_statements/violation_builder.py +96 -0
  26. src/templates/thailint_config_template.yaml +26 -0
  27. {thailint-0.4.6.dist-info → thailint-0.7.0.dist-info}/METADATA +149 -3
  28. {thailint-0.4.6.dist-info → thailint-0.7.0.dist-info}/RECORD +31 -18
  29. {thailint-0.4.6.dist-info → thailint-0.7.0.dist-info}/WHEEL +0 -0
  30. {thailint-0.4.6.dist-info → thailint-0.7.0.dist-info}/entry_points.txt +0 -0
  31. {thailint-0.4.6.dist-info → thailint-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,130 @@
1
+ """
2
+ Purpose: TypeScript/JavaScript console.* call detection using Tree-sitter AST analysis
3
+
4
+ Scope: TypeScript and JavaScript console statement detection
5
+
6
+ Overview: Analyzes TypeScript and JavaScript code to detect console.* method calls that should
7
+ be replaced with proper logging. Uses Tree-sitter parser to traverse TypeScript/JavaScript
8
+ AST and identify call expressions where the callee is console.log, console.warn, console.error,
9
+ console.debug, or console.info (configurable). Returns structured data with the node, method
10
+ name, and line number for each detected console call. Supports both TypeScript and JavaScript
11
+ files with shared detection logic. Handles member expression pattern matching to identify
12
+ console object method calls.
13
+
14
+ Dependencies: TypeScriptBaseAnalyzer for tree-sitter parsing infrastructure, tree-sitter Node type, logging module
15
+
16
+ Exports: TypeScriptPrintStatementAnalyzer class
17
+
18
+ Interfaces: find_console_calls(root_node, methods) -> list[tuple[Node, str, int]]
19
+
20
+ Implementation: Tree-sitter node traversal with call_expression and member_expression pattern matching
21
+ """
22
+
23
+ import logging
24
+ from typing import Any
25
+
26
+ from src.analyzers.typescript_base import TypeScriptBaseAnalyzer
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # dry: ignore-block - tree-sitter import pattern (common across TypeScript analyzers)
31
+ try:
32
+ from tree_sitter import Node
33
+
34
+ TREE_SITTER_AVAILABLE = True
35
+ except ImportError:
36
+ TREE_SITTER_AVAILABLE = False
37
+ Node = Any # type: ignore
38
+
39
+
40
+ class TypeScriptPrintStatementAnalyzer(TypeScriptBaseAnalyzer):
41
+ """Analyzes TypeScript/JavaScript code for console.* calls using Tree-sitter."""
42
+
43
+ def find_console_calls(self, root_node: Node, methods: set[str]) -> list[tuple[Node, str, int]]:
44
+ """Find all console.* calls matching the specified methods.
45
+
46
+ Args:
47
+ root_node: Root tree-sitter node to search from
48
+ methods: Set of console method names to detect (e.g., {"log", "warn"})
49
+
50
+ Returns:
51
+ List of (node, method_name, line_number) tuples for each console call
52
+ """
53
+ logger.debug(
54
+ "find_console_calls: TREE_SITTER_AVAILABLE=%s, root_node=%s",
55
+ TREE_SITTER_AVAILABLE,
56
+ root_node is not None,
57
+ )
58
+ if not TREE_SITTER_AVAILABLE or root_node is None:
59
+ logger.debug("Early return: tree-sitter not available or root_node is None")
60
+ return []
61
+
62
+ calls: list[tuple[Node, str, int]] = []
63
+ self._collect_console_calls(root_node, methods, calls)
64
+ logger.debug("find_console_calls: found %d calls", len(calls))
65
+ return calls
66
+
67
+ def _collect_console_calls(
68
+ self, node: Node, methods: set[str], calls: list[tuple[Node, str, int]]
69
+ ) -> None:
70
+ """Recursively collect console.* calls from AST.
71
+
72
+ Args:
73
+ node: Current tree-sitter node
74
+ methods: Set of console method names to detect
75
+ calls: List to accumulate found calls
76
+ """
77
+ if node.type == "call_expression":
78
+ method_name = self._extract_console_method(node, methods)
79
+ if method_name is not None:
80
+ line_number = node.start_point[0] + 1
81
+ calls.append((node, method_name, line_number))
82
+
83
+ for child in node.children:
84
+ self._collect_console_calls(child, methods, calls)
85
+
86
+ def _extract_console_method(self, node: Node, methods: set[str]) -> str | None:
87
+ """Extract console method name if this is a console.* call.
88
+
89
+ Args:
90
+ node: Tree-sitter call_expression node
91
+ methods: Set of console method names to detect
92
+
93
+ Returns:
94
+ Method name if this is a matching console call, None otherwise
95
+ """
96
+ func_node = self.find_child_by_type(node, "member_expression")
97
+ if func_node is None:
98
+ return None
99
+ if not self._is_console_object(func_node):
100
+ return None
101
+ return self._get_matching_method(func_node, methods)
102
+
103
+ def _is_console_object(self, func_node: Node) -> bool:
104
+ """Check if the member expression is on 'console' object."""
105
+ object_node = self._find_object_node(func_node)
106
+ if object_node is None:
107
+ return False
108
+ return self.extract_node_text(object_node) == "console"
109
+
110
+ def _get_matching_method(self, func_node: Node, methods: set[str]) -> str | None:
111
+ """Get method name if it matches the configured methods."""
112
+ method_node = self.find_child_by_type(func_node, "property_identifier")
113
+ if method_node is None:
114
+ return None
115
+ method_name = self.extract_node_text(method_node)
116
+ return method_name if method_name in methods else None
117
+
118
+ def _find_object_node(self, member_expr: Node) -> Node | None:
119
+ """Find the object node in a member expression.
120
+
121
+ Args:
122
+ member_expr: Tree-sitter member_expression node
123
+
124
+ Returns:
125
+ Object node (identifier) or None
126
+ """
127
+ for child in member_expr.children:
128
+ if child.type == "identifier":
129
+ return child
130
+ return None
@@ -0,0 +1,96 @@
1
+ """
2
+ Purpose: Builds Violation objects for print statement detection
3
+
4
+ Scope: Violation creation for print and console statement detections
5
+
6
+ Overview: Provides ViolationBuilder class that creates Violation objects for print statement
7
+ detections. Generates descriptive messages suggesting the use of proper logging instead of
8
+ print/console statements. Constructs complete Violation instances with rule_id, file_path,
9
+ line number, column, message, and suggestions. Provides separate methods for Python print()
10
+ violations and TypeScript/JavaScript console.* violations with language-appropriate messages
11
+ and helpful remediation guidance.
12
+
13
+ Dependencies: ast module for Python AST nodes, pathlib.Path for file paths,
14
+ src.core.types.Violation for violation structure
15
+
16
+ Exports: ViolationBuilder class
17
+
18
+ Interfaces: create_python_violation(node, line, file_path) -> Violation,
19
+ create_typescript_violation(method, line, file_path) -> Violation
20
+
21
+ Implementation: Builder pattern with message templates suggesting logging as alternative
22
+ to print/console statements
23
+ """
24
+
25
+ import ast
26
+ from pathlib import Path
27
+
28
+ from src.core.types import Violation
29
+
30
+
31
+ class ViolationBuilder:
32
+ """Builds violations for print statement detections."""
33
+
34
+ def __init__(self, rule_id: str) -> None:
35
+ """Initialize the violation builder.
36
+
37
+ Args:
38
+ rule_id: The rule ID to use in violations
39
+ """
40
+ self.rule_id = rule_id
41
+
42
+ def create_python_violation(
43
+ self,
44
+ node: ast.Call,
45
+ line: int,
46
+ file_path: Path | None,
47
+ ) -> Violation:
48
+ """Create a violation for a Python print() call.
49
+
50
+ Args:
51
+ node: The AST Call node containing the print statement
52
+ line: Line number where the violation occurs
53
+ file_path: Path to the file
54
+
55
+ Returns:
56
+ Violation object with details about the print statement
57
+ """
58
+ message = "print() statement should be replaced with proper logging"
59
+ suggestion = "Use logging.info(), logging.debug(), or similar instead of print()"
60
+
61
+ return Violation(
62
+ rule_id=self.rule_id,
63
+ file_path=str(file_path) if file_path else "",
64
+ line=line,
65
+ column=node.col_offset if hasattr(node, "col_offset") else 0,
66
+ message=message,
67
+ suggestion=suggestion,
68
+ )
69
+
70
+ def create_typescript_violation(
71
+ self,
72
+ method: str,
73
+ line: int,
74
+ file_path: Path | None,
75
+ ) -> Violation:
76
+ """Create a violation for a TypeScript/JavaScript console.* call.
77
+
78
+ Args:
79
+ method: The console method name (log, warn, error, etc.)
80
+ line: Line number where the violation occurs
81
+ file_path: Path to the file
82
+
83
+ Returns:
84
+ Violation object with details about the console statement
85
+ """
86
+ message = f"console.{method}() should be replaced with proper logging"
87
+ suggestion = f"Use a logging library instead of console.{method}()"
88
+
89
+ return Violation(
90
+ rule_id=self.rule_id,
91
+ file_path=str(file_path) if file_path else "",
92
+ line=line,
93
+ column=0, # Tree-sitter nodes don't provide easy column access
94
+ message=message,
95
+ suggestion=suggestion,
96
+ )
@@ -106,6 +106,32 @@ file-placement:
106
106
  required_dir: ["config/", "./"]
107
107
  message: "Config files should be in config/ or project root"
108
108
 
109
+ # ============================================================================
110
+ # PRINT STATEMENTS LINTER
111
+ # ============================================================================
112
+ # Detects print()/console.* statements that should use proper logging
113
+ #
114
+ print-statements:
115
+ enabled: true
116
+
117
+ # Allow print() in if __name__ == "__main__": blocks (Python only)
118
+ # Default: true
119
+ allow_in_scripts: true
120
+
121
+ # Console methods to detect in TypeScript/JavaScript
122
+ # Default: [log, warn, error, debug, info]
123
+ console_methods:
124
+ - log
125
+ - warn
126
+ - error
127
+ - debug
128
+ - info
129
+
130
+ # File patterns to ignore (glob syntax)
131
+ # ignore:
132
+ # - "scripts/**"
133
+ # - "**/debug.py"
134
+
109
135
  # ============================================================================
110
136
  # GLOBAL SETTINGS
111
137
  # ============================================================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thailint
3
- Version: 0.4.6
3
+ Version: 0.7.0
4
4
  Summary: The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -37,9 +37,10 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
39
39
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
40
- [![Tests](https://img.shields.io/badge/tests-356%2F356%20passing-brightgreen.svg)](tests/)
40
+ [![Tests](https://img.shields.io/badge/tests-571%2F571%20passing-brightgreen.svg)](tests/)
41
41
  [![Coverage](https://img.shields.io/badge/coverage-87%25-brightgreen.svg)](htmlcov/)
42
42
  [![Documentation Status](https://readthedocs.org/projects/thai-lint/badge/?version=latest)](https://thai-lint.readthedocs.io/en/latest/?badge=latest)
43
+ [![SARIF 2.1.0](https://img.shields.io/badge/SARIF-2.1.0-orange.svg)](docs/sarif-output.md)
43
44
 
44
45
  The AI Linter - Enterprise-ready linting and governance for AI-generated code across multiple languages.
45
46
 
@@ -73,6 +74,11 @@ thailint complements your existing linting stack by catching the patterns AI too
73
74
 
74
75
  ### Core Capabilities
75
76
  - **File Placement Linting** - Enforce project structure and organization
77
+ - **File Header Linting** - Validate documentation headers in source files
78
+ - Python, TypeScript, JavaScript, Bash, Markdown, CSS support
79
+ - Mandatory field validation (Purpose, Scope, Overview)
80
+ - Atemporal language detection (no dates, "currently", "now")
81
+ - Language-specific header format parsing
76
82
  - **Magic Numbers Linting** - Detect unnamed numeric literals that should be constants
77
83
  - Python and TypeScript support with AST analysis
78
84
  - Context-aware detection (ignores constants, test files, range() usage)
@@ -122,7 +128,7 @@ cd thai-lint
122
128
  pip install -e ".[dev]"
123
129
  ```
124
130
 
125
- ### From PyPI (once published)
131
+ ### From PyPI
126
132
 
127
133
  ```bash
128
134
  pip install thai-lint
@@ -158,11 +164,17 @@ thailint dry .
158
164
  # Check for magic numbers
159
165
  thailint magic-numbers src/
160
166
 
167
+ # Check file headers
168
+ thailint file-header src/
169
+
161
170
  # With config file
162
171
  thailint dry --config .thailint.yaml src/
163
172
 
164
173
  # JSON output for CI/CD
165
174
  thailint dry --format json src/
175
+
176
+ # SARIF output for GitHub Code Scanning
177
+ thailint nesting --format sarif src/ > results.sarif
166
178
  ```
167
179
 
168
180
  **New to thailint?** See the **[Quick Start Guide](https://thai-lint.readthedocs.io/en/latest/quick-start/)** for a complete walkthrough including config generation, understanding output, and next steps.
@@ -869,6 +881,136 @@ def get_ports(): # thailint: ignore[magic-numbers] - Standard ports
869
881
 
870
882
  See **[How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to-ignore-violations/)** and **[Magic Numbers Linter Guide](https://thai-lint.readthedocs.io/en/latest/magic-numbers-linter/)** for complete documentation.
871
883
 
884
+ ## File Header Linter
885
+
886
+ ### Overview
887
+
888
+ The file header linter validates that source files have proper documentation headers containing required fields (Purpose, Scope, Overview) and don't use temporal language (dates, "currently", "now"). It enforces consistent documentation patterns across entire codebases.
889
+
890
+ ### Why File Headers?
891
+
892
+ File headers serve as **self-documentation** that helps developers (and AI assistants) quickly understand:
893
+
894
+ - **Purpose**: What does this file do?
895
+ - **Scope**: What area of the system does it cover?
896
+ - **Dependencies**: What does it rely on?
897
+ - **Exports**: What does it provide to other modules?
898
+
899
+ ### Quick Start
900
+
901
+ ```bash
902
+ # Check file headers in current directory
903
+ thailint file-header .
904
+
905
+ # Check specific directory
906
+ thailint file-header src/
907
+
908
+ # Get JSON output
909
+ thailint file-header --format json src/
910
+
911
+ # Get SARIF output for CI/CD
912
+ thailint file-header --format sarif src/ > results.sarif
913
+ ```
914
+
915
+ ### Configuration
916
+
917
+ Add to `.thailint.yaml`:
918
+
919
+ ```yaml
920
+ file-header:
921
+ enabled: true
922
+ mandatory_fields:
923
+ - Purpose
924
+ - Scope
925
+ - Overview
926
+ ignore:
927
+ - "**/__init__.py"
928
+ - "**/migrations/**"
929
+ ```
930
+
931
+ ### Example Violation
932
+
933
+ **Code without proper header:**
934
+ ```python
935
+ import os
936
+
937
+ def process_data():
938
+ pass
939
+ ```
940
+
941
+ **Violation messages:**
942
+ ```
943
+ src/utils.py:1 - Missing mandatory field: Purpose
944
+ src/utils.py:1 - Missing mandatory field: Scope
945
+ src/utils.py:1 - Missing mandatory field: Overview
946
+ ```
947
+
948
+ **Refactored with header:**
949
+ ```python
950
+ """
951
+ Purpose: Data processing utilities for ETL pipeline
952
+
953
+ Scope: Data transformation layer, used by batch processing jobs
954
+
955
+ Overview: Provides data transformation functions for the ETL pipeline.
956
+ Handles parsing, validation, and normalization of incoming data.
957
+
958
+ Dependencies: os, json
959
+
960
+ Exports: process_data(), validate_input(), transform_record()
961
+ """
962
+ import os
963
+
964
+ def process_data():
965
+ pass
966
+ ```
967
+
968
+ ### Atemporal Language Detection
969
+
970
+ The linter detects temporal language that becomes stale:
971
+
972
+ **Temporal (flagged):**
973
+ ```python
974
+ """
975
+ Purpose: Authentication module
976
+
977
+ Overview: Currently handles OAuth. This was recently updated.
978
+ Created: 2024-01-15. Will be extended in the future.
979
+ """
980
+ ```
981
+
982
+ **Atemporal (correct):**
983
+ ```python
984
+ """
985
+ Purpose: Authentication module
986
+
987
+ Overview: Handles OAuth authentication with Google and GitHub.
988
+ Implements authorization code flow with PKCE for security.
989
+ """
990
+ ```
991
+
992
+ ### Language Support
993
+
994
+ - **Python**: Module docstrings (`"""..."""`)
995
+ - **TypeScript/JavaScript**: JSDoc comments (`/** ... */`)
996
+ - **Bash**: Hash comments after shebang (`# ...`)
997
+ - **Markdown**: YAML frontmatter (`---...---`)
998
+ - **CSS/SCSS**: Block comments (`/* ... */`)
999
+
1000
+ ### Ignoring Violations
1001
+
1002
+ ```python
1003
+ # File-level ignore
1004
+ # thailint: ignore-file[file-header]
1005
+
1006
+ # Line-level ignore for atemporal violation
1007
+ """
1008
+ Overview: Created 2024-01-15. # thailint: ignore[file-header]
1009
+ """
1010
+ ```
1011
+
1012
+ See **[How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to-ignore-violations/)** and **[File Header Linter Guide](https://thai-lint.readthedocs.io/en/latest/file-header-linter/)** for complete documentation.
1013
+
872
1014
  ## Pre-commit Hooks
873
1015
 
874
1016
  Automate code quality checks before every commit and push with pre-commit hooks.
@@ -1153,11 +1295,13 @@ docker run --rm -v /path/to/workspace:/workspace \
1153
1295
  - **[CLI Reference](https://thai-lint.readthedocs.io/en/latest/cli-reference/)** - All CLI commands and options
1154
1296
  - **[Deployment Modes](https://thai-lint.readthedocs.io/en/latest/deployment-modes/)** - CLI, Library, and Docker usage
1155
1297
  - **[File Placement Linter](https://thai-lint.readthedocs.io/en/latest/file-placement-linter/)** - Detailed linter guide
1298
+ - **[File Header Linter](https://thai-lint.readthedocs.io/en/latest/file-header-linter/)** - File header validation guide
1156
1299
  - **[Magic Numbers Linter](https://thai-lint.readthedocs.io/en/latest/magic-numbers-linter/)** - Magic numbers detection guide
1157
1300
  - **[Nesting Depth Linter](https://thai-lint.readthedocs.io/en/latest/nesting-linter/)** - Nesting depth analysis guide
1158
1301
  - **[SRP Linter](https://thai-lint.readthedocs.io/en/latest/srp-linter/)** - Single Responsibility Principle guide
1159
1302
  - **[DRY Linter](https://thai-lint.readthedocs.io/en/latest/dry-linter/)** - Duplicate code detection guide
1160
1303
  - **[Pre-commit Hooks](https://thai-lint.readthedocs.io/en/latest/pre-commit-hooks/)** - Automated quality checks
1304
+ - **[SARIF Output Guide](docs/sarif-output.md)** - SARIF format for GitHub Code Scanning and CI/CD
1161
1305
  - **[Publishing Guide](https://thai-lint.readthedocs.io/en/latest/releasing/)** - Release and publishing workflow
1162
1306
  - **[Publishing Checklist](https://thai-lint.readthedocs.io/en/latest/publishing-checklist/)** - Post-publication validation
1163
1307
 
@@ -1168,6 +1312,8 @@ See [`examples/`](examples/) directory for working code:
1168
1312
  - **[basic_usage.py](examples/basic_usage.py)** - Simple library API usage
1169
1313
  - **[advanced_usage.py](examples/advanced_usage.py)** - Advanced patterns and workflows
1170
1314
  - **[ci_integration.py](examples/ci_integration.py)** - CI/CD integration example
1315
+ - **[sarif_usage.py](examples/sarif_usage.py)** - SARIF output format examples
1316
+ - **[file_header_usage.py](examples/file_header_usage.py)** - File header validation examples
1171
1317
 
1172
1318
  ## Project Structure
1173
1319
 
@@ -2,17 +2,19 @@ src/__init__.py,sha256=f601zncODr2twrUHqTLS5wyOdZqZi9tMjAe2INhRKqU,2175
2
2
  src/analyzers/__init__.py,sha256=fFloZtjkBGwYbAhKTxS3Qy3yDr2_3i3WSfKTw1mAioo,972
3
3
  src/analyzers/typescript_base.py,sha256=4I7fAcMOAY9vY1AXh52QpohgFmguBECwOkvBRP4zCS4,5054
4
4
  src/api.py,sha256=pJ5l3qxccKBEY-BkANwzTgLAl1ZFq7OP6hx6LSxbhDw,4664
5
- src/cli.py,sha256=VvMTaltsFKtCE4DNu6HqnSgKyZYulq3qALO8uteafI8,48092
5
+ src/cli.py,sha256=H8DAOCRIu4pK2fbTqryJ0arwKmJ9w3kkeRdtC-FVdAY,55579
6
6
  src/config.py,sha256=2ebAjIpAhw4bHbOxViEA5nCjfBlDEIrMR59DBrzcYzM,12460
7
7
  src/core/__init__.py,sha256=5FtsDvhMt4SNRx3pbcGURrxn135XRbeRrjSUxiXwkNc,381
8
8
  src/core/base.py,sha256=Eklcagi2ktfY4Kytl_ObXov2U49N9OGDpw4cu4PUzGY,7824
9
- src/core/cli_utils.py,sha256=rYOJz4mnr8RLP-nJdHOy-GJyxGNqkWtK3_rvKriHXj4,6083
9
+ src/core/cli_utils.py,sha256=vKw0jF1rZv_N7gbzvV5TeO9rV5VPfd89fneKrglQ2Hs,6502
10
10
  src/core/config_parser.py,sha256=zAY4bDptNlVID0a4JDXN0YlUKXLM92cFqTAwhp_8uGc,4183
11
11
  src/core/linter_utils.py,sha256=4jmC2YfpPvGhS_XHlHXa5SBIJh9CQlNj5zuW_GpdPKc,5273
12
- src/core/registry.py,sha256=IMkic1ukmo8HCX1TY5YoKjwKT_IT-ZmVx6sdntC5X2M,3289
12
+ src/core/registry.py,sha256=yRA8mQLiZwjmgxl1wSTgdj1cuo_QXuRdrXt3NpCBUgE,3285
13
13
  src/core/rule_discovery.py,sha256=smxJ9PEyMqEAIicsWaHOaSHD1PHUAOeFZT_a3DNRwgE,4163
14
14
  src/core/types.py,sha256=dIYLaCDNtCAzVaplx5S5yxywkLIuX0BN9No_l2zCfV0,2887
15
15
  src/core/violation_builder.py,sha256=7AQODqxwc3qp_4m1MPzknkeNGlht1LsDjPsTPpWAGJY,4678
16
+ src/formatters/__init__.py,sha256=yE1yIL8lplTMEjsmQm7F-kOMaYq7OjmbFuiwwK0D-gM,815
17
+ src/formatters/sarif.py,sha256=gGOwb_v7j4mx4bpvV1NNDd-JyHH8i8XX89iQ6uRSvG4,7050
16
18
  src/linter_config/__init__.py,sha256=_I2VVlZlfKyT-tKukuUA5-aVcHLOe3m6C2cev43AiEc,298
17
19
  src/linter_config/ignore.py,sha256=S2Ub0CCOOC-wpU5Y_EodMprciw18fgWcnp4z_h1MYNk,19638
18
20
  src/linter_config/loader.py,sha256=HB09W-uVsEcgCbvUwUHS5Jm2n0bqBXA3744vMc4GAqk,2542
@@ -38,16 +40,21 @@ src/linters/dry/violation_builder.py,sha256=EUiEQIOZjzAoHEqZiIR8WZP8m4dgqJjcveR5
38
40
  src/linters/dry/violation_filter.py,sha256=aTOMz8kXG2sZlSVcf3cAxgxHs7f2kBXInfr1V_04fUQ,3125
39
41
  src/linters/dry/violation_generator.py,sha256=cc6aKvTxtHSZm0F7Y-gL1bmD3JUphRmAvcbqk9aUzGg,6128
40
42
  src/linters/file_header/__init__.py,sha256=S3a2xrOlxnNWD02To5K2ZwILsNEvSj1IvUAH8RjgOV4,791
41
- src/linters/file_header/atemporal_detector.py,sha256=Rbjs2GHsgO-1r2kUHUuDRsX3XAX0INFZWVrKoUh5v-8,3104
42
- src/linters/file_header/config.py,sha256=1pjfa0hIUEiE0riMLTH9FQiETXfEkhAFuv1HBx0SGgI,2073
43
- src/linters/file_header/field_validator.py,sha256=bR0xZ5DhPHBE8lopbcaNwJr0auZlNDkCwml3Q8_7XOY,2380
44
- src/linters/file_header/linter.py,sha256=ISNnt-YMgkKQl4psVLefp5P7qTQ6wIGidq4dTkTNbaI,11228
45
- src/linters/file_header/python_parser.py,sha256=TcnA8OCbHK3YtixmFwSP7OCvxjjGLZBioez9wVukz28,2951
46
- src/linters/file_header/violation_builder.py,sha256=yDNqsZ-hDnURpph9oZNj2lCkJgd_7hprjk3Fr0iPphs,2653
43
+ src/linters/file_header/atemporal_detector.py,sha256=bgQJPDuJj1J5gHKIIOz1TYbBwu8GHrcMafWFVqZ_zZE,3192
44
+ src/linters/file_header/base_parser.py,sha256=HbuJpXQ4V3zTDTP_D0iFqoT7kab6gk8A1lZdlqCb6tc,3202
45
+ src/linters/file_header/bash_parser.py,sha256=ZnPleRD4c16ibYMBc682N9W-Qgtz9lKtLSqSmbo7oqg,2147
46
+ src/linters/file_header/config.py,sha256=Ewrln4W4QDnInTgWr8WgSlQEjAuDyMbUuh9GHAa9a4c,4030
47
+ src/linters/file_header/css_parser.py,sha256=ijpGMixg2ZqNWWdiZjSNtMXCOhm6XDfSY7OU68B9fS8,2332
48
+ src/linters/file_header/field_validator.py,sha256=uASqHj7ID4JJZzgc6X3SmRRLWV35NnX2iZElCt3HW1o,2830
49
+ src/linters/file_header/linter.py,sha256=rbfpHBCCn0cRKUyadc2luZSQay_gJfVC79JcqkwUMb4,12192
50
+ src/linters/file_header/markdown_parser.py,sha256=dmrB8JCxKTHyw-qMU6S-UjKaFbqJ6ZQY1f23tND5_Jo,4964
51
+ src/linters/file_header/python_parser.py,sha256=RTOeEt1b3tCvFWbZIt89awQA37CUOSBIGagEYnayn-M,1432
52
+ src/linters/file_header/typescript_parser.py,sha256=R11Vkr6dUVaU8t90m8rrkMzODtBYk7u-TYFsMDRwzX8,2532
53
+ src/linters/file_header/violation_builder.py,sha256=HPYTmrcCmcO6Dx5dhmj85zZgEBM5EZqTgql-0CA0A0k,2745
47
54
  src/linters/file_placement/__init__.py,sha256=vJ43GZujcbAk-K3DwfsQZ0J3yP_5G35CKssatLyntXk,862
48
55
  src/linters/file_placement/config_loader.py,sha256=Of5sTG2S-04efn3KOlXrSxpMcC1ipBpSvCjtJOMmWno,2640
49
56
  src/linters/file_placement/directory_matcher.py,sha256=YaBeLGiT4bgqN_v4FmEmSASOBxkMC1lyEYpL17wLIDY,2607
50
- src/linters/file_placement/linter.py,sha256=HtQf08UmKCe5YAHoPvVgWmxdUFu6ZeP2qicg-q7BgzM,14438
57
+ src/linters/file_placement/linter.py,sha256=A4mndpyIyxEzq64rLw2ILNA7APx_QmwzUfnhB0PyuCs,14190
51
58
  src/linters/file_placement/path_resolver.py,sha256=S6g7xOYsoSc0O_RDJh8j4Z2klcwzp16rSUfEAErGOTI,1972
52
59
  src/linters/file_placement/pattern_matcher.py,sha256=3HZWYgQKXz_y13z3lO1YHn51khCaiGOrneGxKXGWGw0,1898
53
60
  src/linters/file_placement/pattern_validator.py,sha256=eMt5GB5lgJMhhQACOlfDXQFfSfNrOY-wJN1JanGka6Q,3717
@@ -58,15 +65,21 @@ src/linters/magic_numbers/config.py,sha256=3zV6ZNezouBWUYy4kMw5PUlPNvIWXVwOxTz1m
58
65
  src/linters/magic_numbers/context_analyzer.py,sha256=cGXozlKll10Zao56c2E8ThIyH2mSQaPaUau_g7ngRLw,8446
59
66
  src/linters/magic_numbers/linter.py,sha256=maj4NgrDapv0RurKvaVgOI1BUujixZv4E7UeYy4eGT4,18394
60
67
  src/linters/magic_numbers/python_analyzer.py,sha256=0u1cFaaFCqOW5yeW-YbmPoZuVIeN_KtmkFyyxup6aR0,2803
61
- src/linters/magic_numbers/typescript_analyzer.py,sha256=DCYRdxjgMd6PkhJWKnc1W-S1T0sa-F9AHCLV2JwcR8g,7468
68
+ src/linters/magic_numbers/typescript_analyzer.py,sha256=NTU1XY-Hudse5oxOtEiG6nA0Rs5Icn9HXELnyPj8OZU,7554
62
69
  src/linters/magic_numbers/violation_builder.py,sha256=SqIQv3N9lpP2GRC1TC5InrvaEdrAq24V7Ec2Xj5olb0,3308
63
70
  src/linters/nesting/__init__.py,sha256=tszmyCEQMpEwB5H84WcAUfRYDQl7jpsn04es5DtAHsM,3200
64
71
  src/linters/nesting/config.py,sha256=PfPA2wJn3i6HHXeM0qu6Qx-v1KJdRwlRkFOdpf7NhS8,2405
65
72
  src/linters/nesting/linter.py,sha256=-klbXIbg145beICop81CNQ5J1OInQaeycDT8u3Ff2Ww,6236
66
73
  src/linters/nesting/python_analyzer.py,sha256=DF2lVnxYstakOpP_Zizox583Ypkb4eUpgQYEpu6x8gk,3078
67
- src/linters/nesting/typescript_analyzer.py,sha256=up1Cf6W-NYCMZSX9YOvS2Uxm7-XrLtAi94lvL9UDemo,3774
74
+ src/linters/nesting/typescript_analyzer.py,sha256=wO6p6QNnyW1uaieTCZjaqR56C68AjifAv23tYaSuR2c,3860
68
75
  src/linters/nesting/typescript_function_extractor.py,sha256=dDB1otJnFMCo-Pj4mTr4gekKe7V4ArOAtX6gV0dBDc4,4494
69
76
  src/linters/nesting/violation_builder.py,sha256=sMHS45F2lrA1WYrG3Uug8HfeRPljnXcyJPHSe2F76Bs,4828
77
+ src/linters/print_statements/__init__.py,sha256=yhvdTFSqBB4UDreeadTHKFzhayxeT6JkF3yxUHMgn1g,1893
78
+ src/linters/print_statements/config.py,sha256=rth3XmzqZGzXkRXDIVZswdtNOXIe1vIRaF46tVLKnyQ,3041
79
+ src/linters/print_statements/linter.py,sha256=J23gtU6FQ2uH2Sj38PPRiV4k2HU0uto2Bqf2D28pKrI,14630
80
+ src/linters/print_statements/python_analyzer.py,sha256=SyCkh8HkYAfcSM7LCwDE1ahhxwPgrlnSVLs1iRemyaw,5461
81
+ src/linters/print_statements/typescript_analyzer.py,sha256=v2R6ZG80eTQq92oE3Y3E4ZwUfBmXwB9G5QKftqbRbD8,5155
82
+ src/linters/print_statements/violation_builder.py,sha256=Vs5m3AnWjrQqQHf6JJDaPP5B1V3YNl5pepG_oiTJnx4,3333
70
83
  src/linters/srp/__init__.py,sha256=GbhaSB2_AYY-mWgG_ThbyAcDXoVZuB5eLzguoShf38w,3367
71
84
  src/linters/srp/class_analyzer.py,sha256=wuwviwhN1F_VVPaQ3pZvffmY3e9ToxPNJhv6BjhsgZc,3761
72
85
  src/linters/srp/config.py,sha256=hTxrM21HIOmg0sM6eJ_h3hRnuxqRZEgs13Ie97-PDr4,3397
@@ -80,11 +93,11 @@ src/linters/srp/violation_builder.py,sha256=jaIjVtRYWUTs1SVJVwd0FxCojo0DxhPzfhyf
80
93
  src/orchestrator/__init__.py,sha256=XXLDJq2oaB-TpP2Y97GRnde9EkITGuFCmuLrDfxI9nY,245
81
94
  src/orchestrator/core.py,sha256=z0YcwsK18uhlztIPi54ux3mOm8fHMREYJoudsJPhC0Q,8857
82
95
  src/orchestrator/language_detector.py,sha256=rHyVMApit80NTTNyDH1ObD1usKD8LjGmH3DwqNAWYGc,2736
83
- src/templates/thailint_config_template.yaml,sha256=u8WFv2coE4uqfgf_slw7xjo4kGYIowDm1RIgxsKQzrE,4275
96
+ src/templates/thailint_config_template.yaml,sha256=vxyhRRi25_xOnHDRx0jzz69dgPqKU2IU5-YFGUoX5lM,4953
84
97
  src/utils/__init__.py,sha256=NiBtKeQ09Y3kuUzeN4O1JNfUIYPQDS2AP1l5ODq-Dec,125
85
98
  src/utils/project_root.py,sha256=b3YTEGTa9RPcOeHn1IByMMWyRiUabfVlpnlektL0A0o,6156
86
- thailint-0.4.6.dist-info/METADATA,sha256=3iBTAjUgiuhAv4-_oU4Bjn96LP1Xyl8tFdV8YH2NitI,37855
87
- thailint-0.4.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
88
- thailint-0.4.6.dist-info/entry_points.txt,sha256=l7DQJgU18sVLDpSaXOXY3lLhnQHQIRrSJZTQjG1cEAk,62
89
- thailint-0.4.6.dist-info/licenses/LICENSE,sha256=kxh1J0Sb62XvhNJ6MZsVNe8PqNVJ7LHRn_EWa-T3djw,1070
90
- thailint-0.4.6.dist-info/RECORD,,
99
+ thailint-0.7.0.dist-info/METADATA,sha256=DiyHLUK6NNz3o2MtQsJPJX-3PWdUX0vyMt2SsSI3ot0,41840
100
+ thailint-0.7.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
101
+ thailint-0.7.0.dist-info/entry_points.txt,sha256=l7DQJgU18sVLDpSaXOXY3lLhnQHQIRrSJZTQjG1cEAk,62
102
+ thailint-0.7.0.dist-info/licenses/LICENSE,sha256=kxh1J0Sb62XvhNJ6MZsVNe8PqNVJ7LHRn_EWa-T3djw,1070
103
+ thailint-0.7.0.dist-info/RECORD,,