thailint 0.10.0__py3-none-any.whl → 0.12.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 (76) hide show
  1. src/__init__.py +1 -0
  2. src/cli/__init__.py +27 -0
  3. src/cli/__main__.py +22 -0
  4. src/cli/config.py +478 -0
  5. src/cli/linters/__init__.py +58 -0
  6. src/cli/linters/code_patterns.py +372 -0
  7. src/cli/linters/code_smells.py +450 -0
  8. src/cli/linters/documentation.py +155 -0
  9. src/cli/linters/shared.py +89 -0
  10. src/cli/linters/structure.py +313 -0
  11. src/cli/linters/structure_quality.py +316 -0
  12. src/cli/main.py +120 -0
  13. src/cli/utils.py +395 -0
  14. src/cli_main.py +34 -0
  15. src/core/types.py +13 -0
  16. src/core/violation_utils.py +69 -0
  17. src/linter_config/ignore.py +32 -16
  18. src/linters/collection_pipeline/linter.py +2 -2
  19. src/linters/dry/block_filter.py +97 -1
  20. src/linters/dry/cache.py +94 -6
  21. src/linters/dry/config.py +47 -10
  22. src/linters/dry/constant.py +92 -0
  23. src/linters/dry/constant_matcher.py +214 -0
  24. src/linters/dry/constant_violation_builder.py +98 -0
  25. src/linters/dry/linter.py +89 -48
  26. src/linters/dry/python_analyzer.py +12 -415
  27. src/linters/dry/python_constant_extractor.py +101 -0
  28. src/linters/dry/single_statement_detector.py +415 -0
  29. src/linters/dry/token_hasher.py +5 -5
  30. src/linters/dry/typescript_analyzer.py +5 -354
  31. src/linters/dry/typescript_constant_extractor.py +134 -0
  32. src/linters/dry/typescript_statement_detector.py +255 -0
  33. src/linters/dry/typescript_value_extractor.py +66 -0
  34. src/linters/file_header/linter.py +2 -2
  35. src/linters/file_placement/linter.py +2 -2
  36. src/linters/file_placement/pattern_matcher.py +19 -5
  37. src/linters/magic_numbers/linter.py +8 -67
  38. src/linters/magic_numbers/typescript_ignore_checker.py +81 -0
  39. src/linters/nesting/linter.py +12 -9
  40. src/linters/print_statements/linter.py +7 -24
  41. src/linters/srp/class_analyzer.py +9 -9
  42. src/linters/srp/heuristics.py +2 -2
  43. src/linters/srp/linter.py +2 -2
  44. src/linters/stateless_class/linter.py +2 -2
  45. src/linters/stringly_typed/__init__.py +36 -0
  46. src/linters/stringly_typed/config.py +190 -0
  47. src/linters/stringly_typed/context_filter.py +451 -0
  48. src/linters/stringly_typed/function_call_violation_builder.py +137 -0
  49. src/linters/stringly_typed/ignore_checker.py +102 -0
  50. src/linters/stringly_typed/ignore_utils.py +51 -0
  51. src/linters/stringly_typed/linter.py +344 -0
  52. src/linters/stringly_typed/python/__init__.py +33 -0
  53. src/linters/stringly_typed/python/analyzer.py +344 -0
  54. src/linters/stringly_typed/python/call_tracker.py +172 -0
  55. src/linters/stringly_typed/python/comparison_tracker.py +252 -0
  56. src/linters/stringly_typed/python/condition_extractor.py +131 -0
  57. src/linters/stringly_typed/python/conditional_detector.py +176 -0
  58. src/linters/stringly_typed/python/constants.py +21 -0
  59. src/linters/stringly_typed/python/match_analyzer.py +88 -0
  60. src/linters/stringly_typed/python/validation_detector.py +186 -0
  61. src/linters/stringly_typed/python/variable_extractor.py +96 -0
  62. src/linters/stringly_typed/storage.py +630 -0
  63. src/linters/stringly_typed/storage_initializer.py +45 -0
  64. src/linters/stringly_typed/typescript/__init__.py +28 -0
  65. src/linters/stringly_typed/typescript/analyzer.py +157 -0
  66. src/linters/stringly_typed/typescript/call_tracker.py +329 -0
  67. src/linters/stringly_typed/typescript/comparison_tracker.py +372 -0
  68. src/linters/stringly_typed/violation_generator.py +376 -0
  69. src/orchestrator/core.py +241 -12
  70. {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/METADATA +9 -3
  71. {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/RECORD +74 -28
  72. thailint-0.12.0.dist-info/entry_points.txt +4 -0
  73. src/cli.py +0 -2141
  74. thailint-0.10.0.dist-info/entry_points.txt +0 -4
  75. {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/WHEEL +0 -0
  76. {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/licenses/LICENSE +0 -0
src/orchestrator/core.py CHANGED
@@ -10,34 +10,162 @@ Overview: Provides the main entry point for linting operations by coordinating e
10
10
  appropriate file information and language metadata, executes applicable rules against contexts,
11
11
  and collects violations across all processed files. Supports recursive and non-recursive
12
12
  directory traversal, respects .thailintignore patterns at repository level, and provides
13
- configurable linting through .thailint.yaml configuration files. Serves as the primary
14
- interface between the linter framework and user-facing CLI/library APIs.
13
+ configurable linting through .thailint.yaml configuration files. Includes parallel processing
14
+ support for improved performance on multi-core systems. Serves as the primary interface between
15
+ the linter framework and user-facing CLI/library APIs.
15
16
 
16
17
  Dependencies: pathlib for file operations, BaseLintRule and BaseLintContext from core.base,
17
18
  Violation from core.types, RuleRegistry from core.registry, LinterConfigLoader from
18
19
  linter_config.loader, IgnoreDirectiveParser from linter_config.ignore, detect_language
19
- from language_detector
20
+ from language_detector, concurrent.futures for parallel processing
20
21
 
21
22
  Exports: Orchestrator class, FileLintContext implementation class
22
23
 
23
24
  Interfaces: Orchestrator(project_root: Path | None), lint_file(file_path: Path) -> list[Violation],
24
- lint_directory(dir_path: Path, recursive: bool) -> list[Violation]
25
+ lint_directory(dir_path: Path, recursive: bool) -> list[Violation],
26
+ lint_files_parallel(file_paths, max_workers) -> list[Violation]
25
27
 
26
28
  Implementation: Directory glob pattern matching for traversal (** for recursive, * for shallow),
27
29
  ignore pattern checking before file processing, dynamic context creation per file,
28
- rule filtering by applicability, violation collection and aggregation across files
30
+ rule filtering by applicability, violation collection and aggregation across files,
31
+ ProcessPoolExecutor for parallel file processing
29
32
  """
30
33
 
34
+ from __future__ import annotations
35
+
36
+ import multiprocessing
37
+ import os
38
+ from concurrent.futures import Future, ProcessPoolExecutor, as_completed
31
39
  from pathlib import Path
32
40
 
33
41
  from src.core.base import BaseLintContext, BaseLintRule
34
42
  from src.core.registry import RuleRegistry
35
43
  from src.core.types import Violation
36
- from src.linter_config.ignore import IgnoreDirectiveParser
44
+ from src.linter_config.ignore import get_ignore_parser
37
45
  from src.linter_config.loader import LinterConfigLoader
38
46
 
39
47
  from .language_detector import detect_language
40
48
 
49
+ # Default max workers for parallel processing (capped to avoid resource contention)
50
+ DEFAULT_MAX_WORKERS = 8
51
+
52
+ # Hardcoded exclusions for files/directories that should never be linted
53
+ # These are always skipped regardless of configuration to improve performance
54
+ _HARDCODED_EXCLUDE_EXTENSIONS: frozenset[str] = frozenset(
55
+ {
56
+ ".pyc",
57
+ ".pyo",
58
+ ".pyd", # Python bytecode
59
+ ".so",
60
+ ".dll",
61
+ ".dylib", # Compiled libraries
62
+ ".class", # Java bytecode
63
+ ".o",
64
+ ".obj", # Object files
65
+ }
66
+ )
67
+ _HARDCODED_EXCLUDE_DIRS: frozenset[str] = frozenset(
68
+ {
69
+ "__pycache__",
70
+ "node_modules",
71
+ ".git",
72
+ ".svn",
73
+ ".hg",
74
+ ".venv",
75
+ "venv",
76
+ ".tox",
77
+ ".eggs",
78
+ "*.egg-info",
79
+ ".pytest_cache",
80
+ ".mypy_cache",
81
+ ".ruff_cache",
82
+ "dist",
83
+ "build",
84
+ "htmlcov",
85
+ }
86
+ )
87
+
88
+
89
+ def _is_hardcoded_excluded(file_path: Path) -> bool:
90
+ """Check if file should be excluded based on hardcoded patterns.
91
+
92
+ Args:
93
+ file_path: Path to check
94
+
95
+ Returns:
96
+ True if file should be skipped (compiled file, cache directory, etc.)
97
+ """
98
+ # Check file extension
99
+ if file_path.suffix in _HARDCODED_EXCLUDE_EXTENSIONS:
100
+ return True
101
+
102
+ # Check if any parent directory is in the exclude list
103
+ for part in file_path.parts:
104
+ if part in _HARDCODED_EXCLUDE_DIRS:
105
+ return True
106
+ # Handle wildcard patterns like *.egg-info
107
+ if part.endswith(".egg-info"):
108
+ return True
109
+
110
+ return False
111
+
112
+
113
+ def _should_include_dir(dirname: str) -> bool:
114
+ """Check if directory should be traversed (not excluded)."""
115
+ return dirname not in _HARDCODED_EXCLUDE_DIRS and not dirname.endswith(".egg-info")
116
+
117
+
118
+ def _collect_files_from_walk(root: str, filenames: list[str]) -> list[Path]:
119
+ """Collect non-excluded files from a single directory."""
120
+ root_path = Path(root)
121
+ return [root_path / f for f in filenames if Path(f).suffix not in _HARDCODED_EXCLUDE_EXTENSIONS]
122
+
123
+
124
+ def _collect_files_fast(dir_path: Path, recursive: bool = True) -> list[Path]:
125
+ """Collect files, skipping excluded directories entirely.
126
+
127
+ Uses os.walk() instead of glob to avoid traversing into excluded
128
+ directories like .venv, node_modules, __pycache__, etc.
129
+
130
+ Args:
131
+ dir_path: Directory to collect files from.
132
+ recursive: Whether to traverse subdirectories.
133
+
134
+ Returns:
135
+ List of file paths, excluding hardcoded exclusions.
136
+ """
137
+ files: list[Path] = []
138
+ for root, dirs, filenames in os.walk(dir_path):
139
+ dirs[:] = [d for d in dirs if _should_include_dir(d)]
140
+ files.extend(_collect_files_from_walk(root, filenames))
141
+ if not recursive:
142
+ break
143
+ return files
144
+
145
+
146
+ def _lint_file_worker(args: tuple[Path, Path, dict]) -> list[dict]:
147
+ """Worker function for parallel file linting.
148
+
149
+ This function runs in a separate process and creates its own Orchestrator
150
+ instance to lint a single file. Results are returned as dicts to avoid
151
+ pickling issues with Violation dataclass.
152
+
153
+ Args:
154
+ args: Tuple of (file_path, project_root, config)
155
+
156
+ Returns:
157
+ List of violation dicts (serializable for cross-process transfer)
158
+ """
159
+ file_path, project_root, config = args
160
+ try:
161
+ # Create isolated orchestrator for this worker process
162
+ orchestrator = Orchestrator(project_root=project_root, config=config)
163
+ violations = orchestrator.lint_file(file_path)
164
+ # Convert to dicts for pickling
165
+ return [v.to_dict() for v in violations]
166
+ except Exception: # nosec B112 - defensive; don't crash on worker errors
167
+ return []
168
+
41
169
 
42
170
  class FileLintContext(BaseLintContext):
43
171
  """Concrete implementation of lint context for file analysis."""
@@ -56,6 +184,7 @@ class FileLintContext(BaseLintContext):
56
184
  self._path = path
57
185
  self._language = lang
58
186
  self._content = content
187
+ self._lines: list[str] | None = None # Cached line split
59
188
  self.metadata = metadata or {}
60
189
 
61
190
  @property
@@ -81,12 +210,31 @@ class FileLintContext(BaseLintContext):
81
210
  """Get programming language of file."""
82
211
  return self._language
83
212
 
213
+ @property
214
+ def file_lines(self) -> list[str]:
215
+ """Get file content as list of lines (cached).
216
+
217
+ Returns:
218
+ List of lines from file content, empty list if no content.
219
+ """
220
+ if self._lines is None:
221
+ content = self.file_content
222
+ self._lines = content.split("\n") if content else []
223
+ return self._lines
224
+
84
225
 
85
- class Orchestrator:
226
+ class Orchestrator: # thailint: ignore[srp]
86
227
  """Main linter orchestrator coordinating rule execution.
87
228
 
88
229
  Integrates rule registry, configuration loading, ignore patterns, and language
89
230
  detection to provide comprehensive linting of files and directories.
231
+
232
+ SRP Exception: Method count (12) exceeds guideline (8) because this is the
233
+ central orchestration point. Methods are organized into logical groups:
234
+ - Core linting: lint_file, lint_files, lint_directory
235
+ - Parallel linting: lint_files_parallel, lint_directory_parallel
236
+ - Helper methods: _execute_rules, _safe_check_rule, _ensure_rules_discovered, etc.
237
+ All methods support the single responsibility of coordinating lint operations.
90
238
  """
91
239
 
92
240
  def __init__(self, project_root: Path | None = None, config: dict | None = None):
@@ -99,7 +247,7 @@ class Orchestrator:
99
247
  self.project_root = project_root or Path.cwd()
100
248
  self.registry = RuleRegistry()
101
249
  self.config_loader = LinterConfigLoader()
102
- self.ignore_parser = IgnoreDirectiveParser(self.project_root)
250
+ self.ignore_parser = get_ignore_parser(self.project_root)
103
251
 
104
252
  # Performance optimization: Defer rule discovery until first file is linted
105
253
  # This eliminates ~0.077s overhead for commands that don't need rules (--help, config, etc.)
@@ -125,6 +273,10 @@ class Orchestrator:
125
273
  Returns:
126
274
  List of violations found in the file.
127
275
  """
276
+ # Fast path: skip compiled files and common excluded directories
277
+ if _is_hardcoded_excluded(file_path):
278
+ return []
279
+
128
280
  if self.ignore_parser.is_ignored(file_path):
129
281
  return []
130
282
 
@@ -197,11 +349,11 @@ class Orchestrator:
197
349
  List of all violations found across all files.
198
350
  """
199
351
  violations = []
200
- pattern = "**/*" if recursive else "*"
352
+ # Use fast file collection that skips excluded directories entirely
353
+ file_paths = _collect_files_fast(dir_path, recursive)
201
354
 
202
- for file_path in dir_path.glob(pattern):
203
- if file_path.is_file():
204
- violations.extend(self.lint_file(file_path))
355
+ for file_path in file_paths:
356
+ violations.extend(self.lint_file(file_path))
205
357
 
206
358
  # Call finalize() on all rules after processing all files
207
359
  for rule in self.registry.list_all():
@@ -209,6 +361,83 @@ class Orchestrator:
209
361
 
210
362
  return violations
211
363
 
364
+ def lint_files_parallel(
365
+ self, file_paths: list[Path], max_workers: int | None = None
366
+ ) -> list[Violation]:
367
+ """Lint multiple files in parallel using process pool.
368
+
369
+ Uses ProcessPoolExecutor to distribute file linting across multiple
370
+ CPU cores. Each worker process creates its own Orchestrator instance.
371
+
372
+ Args:
373
+ file_paths: List of file paths to lint.
374
+ max_workers: Maximum worker processes. Defaults to min(DEFAULT_MAX_WORKERS, cpu_count).
375
+
376
+ Returns:
377
+ List of violations found across all files.
378
+ """
379
+ if not file_paths:
380
+ return []
381
+
382
+ effective_workers = max_workers or min(DEFAULT_MAX_WORKERS, multiprocessing.cpu_count())
383
+
384
+ # For small file counts, sequential is faster due to process overhead
385
+ if len(file_paths) < effective_workers * 2:
386
+ return self.lint_files(file_paths)
387
+
388
+ violations = self._execute_parallel_linting(file_paths, effective_workers)
389
+ violations.extend(self._finalize_rules())
390
+ return violations
391
+
392
+ def _execute_parallel_linting(
393
+ self, file_paths: list[Path], max_workers: int
394
+ ) -> list[Violation]:
395
+ """Execute parallel linting using process pool."""
396
+ work_items = [(fp, self.project_root, self.config) for fp in file_paths]
397
+
398
+ with ProcessPoolExecutor(max_workers=max_workers) as executor:
399
+ futures = [executor.submit(_lint_file_worker, item) for item in work_items]
400
+ return self._collect_parallel_results(futures)
401
+
402
+ def _collect_parallel_results(self, futures: list[Future[list[dict]]]) -> list[Violation]:
403
+ """Collect results from parallel futures."""
404
+ violations: list[Violation] = []
405
+ for future in as_completed(futures):
406
+ violations.extend(self._extract_violations_from_future(future))
407
+ return violations
408
+
409
+ def _extract_violations_from_future(self, future: Future[list[dict]]) -> list[Violation]:
410
+ """Extract violations from a completed future, handling errors."""
411
+ try:
412
+ return [Violation.from_dict(d) for d in future.result()]
413
+ except Exception: # nosec B112 - continue on worker errors
414
+ return []
415
+
416
+ def _finalize_rules(self) -> list[Violation]:
417
+ """Call finalize() on all rules for cross-file analysis."""
418
+ self._ensure_rules_discovered()
419
+ violations: list[Violation] = []
420
+ for rule in self.registry.list_all():
421
+ violations.extend(rule.finalize())
422
+ return violations
423
+
424
+ def lint_directory_parallel(
425
+ self, dir_path: Path, recursive: bool = True, max_workers: int | None = None
426
+ ) -> list[Violation]:
427
+ """Lint all files in a directory using parallel processing.
428
+
429
+ Args:
430
+ dir_path: Path to directory to lint.
431
+ recursive: Whether to traverse subdirectories recursively.
432
+ max_workers: Maximum worker processes. Defaults to min(DEFAULT_MAX_WORKERS, cpu_count).
433
+
434
+ Returns:
435
+ List of all violations found across all files.
436
+ """
437
+ # Use fast file collection that skips excluded directories entirely
438
+ file_paths = _collect_files_fast(dir_path, recursive)
439
+ return self.lint_files_parallel(file_paths, max_workers=max_workers)
440
+
212
441
  def _ensure_rules_discovered(self) -> None:
213
442
  """Ensure rules have been discovered and registered (lazy initialization)."""
214
443
  if not self._rules_discovered:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thailint
3
- Version: 0.10.0
3
+ Version: 0.12.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,8 +37,8 @@ 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-795%2F795%20passing-brightgreen.svg)](tests/)
41
- [![Coverage](https://img.shields.io/badge/coverage-88%25-brightgreen.svg)](htmlcov/)
40
+ [![Tests](https://img.shields.io/badge/tests-1076%2F1076%20passing-brightgreen.svg)](tests/)
41
+ [![Coverage](https://img.shields.io/badge/coverage-89%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
43
  [![SARIF 2.1.0](https://img.shields.io/badge/SARIF-2.1.0-orange.svg)](docs/sarif-output.md)
44
44
 
@@ -116,6 +116,12 @@ thailint complements your existing linting stack by catching the patterns AI too
116
116
  - No instance state (self.attr) detection
117
117
  - Excludes ABC, Protocol, and decorated classes
118
118
  - Helpful refactoring suggestions
119
+ - **Stringly-Typed Linting** - Detect string patterns that should use enums
120
+ - Python and TypeScript support
121
+ - Cross-file detection with SQLite storage
122
+ - Detects membership validation, equality chains, function call patterns
123
+ - False positive filtering (200+ exclusion patterns)
124
+ - Inline ignore directive support
119
125
  - **Pluggable Architecture** - Easy to extend with custom linters
120
126
  - **Multi-Language Support** - Python, TypeScript, JavaScript, and more
121
127
  - **Flexible Configuration** - YAML/JSON configs with pattern matching
@@ -1,8 +1,20 @@
1
- src/__init__.py,sha256=f601zncODr2twrUHqTLS5wyOdZqZi9tMjAe2INhRKqU,2175
1
+ src/__init__.py,sha256=0IT3HnAnSBEfos4G_27cflJiaoWWfeSEfHxsUr53OsM,2192
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=NoCEg1jLDkS7My4XhUfrssQmBGX-EaC2ULMwQs23Rt0,67580
5
+ src/cli/__init__.py,sha256=R0cTBbMsGIAn4r1-YgKFvCMxrDbsmj9JCoPdsMSf9Jc,1193
6
+ src/cli/__main__.py,sha256=xIKI57yqB1NOw9eXnGXfU8rC2UwcAJYjDxlZbt9eP0w,671
7
+ src/cli/config.py,sha256=a_kMr3DRQ8t_HzVXmgemKnKMSS0tPAxTA33tQswpRkc,14328
8
+ src/cli/linters/__init__.py,sha256=zpPCtFyKIkq0t3wqfUsd5_VJepPyT3LvAg4JZ_ToEeA,2056
9
+ src/cli/linters/code_patterns.py,sha256=Cyu26_Y-dTBudSgLDcwH3-djjXCN83xqzgMkZV9oZ-U,12434
10
+ src/cli/linters/code_smells.py,sha256=xf9fSS5qwRGOMw4FvhJo0QsU5Et0gFcObriZk-BUIg8,14858
11
+ src/cli/linters/documentation.py,sha256=UaD2MMltgfSVlQAo8MCXepmQWGLiz-5Llg6uowrwvIA,5170
12
+ src/cli/linters/shared.py,sha256=tHOsLF_L-xwf1KE4kVR7oES4IMOj-1ADWRnDhW36QzM,3010
13
+ src/cli/linters/structure.py,sha256=xPhb-SqtPM9QMhB5un8pi74l9SYKN1LHQL9Eb0ZLVqI,10538
14
+ src/cli/linters/structure_quality.py,sha256=qjZn1zKAp_rnmg1vVwUJ-Ob057AoYV3uZtZqiW2qFsU,10585
15
+ src/cli/main.py,sha256=mRyRN_IQI2WyqDCxI8vuzdhbkCkVrK6INfJPjU8ayIU,3844
16
+ src/cli/utils.py,sha256=L1q2i6NBkWoQZLYnkeNNdfzHYRhaUobbzqSr2w8JUFY,12595
17
+ src/cli_main.py,sha256=-3XVwLztHt9clehSxr0nrXh9mhAiZOt0gP73TgijPEI,1499
6
18
  src/config.py,sha256=gQ2DoBSZra4Dw3zUVd-t0lyD_pOY4iufx7sL_sXGBGU,12482
7
19
  src/core/__init__.py,sha256=5FtsDvhMt4SNRx3pbcGURrxn135XRbeRrjSUxiXwkNc,381
8
20
  src/core/base.py,sha256=7bb_CAEohgEFXDgIK6Qc_zt6Cz4U9K6uhLhunbMX8f0,7966
@@ -11,37 +23,46 @@ src/core/config_parser.py,sha256=zAY4bDptNlVID0a4JDXN0YlUKXLM92cFqTAwhp_8uGc,418
11
23
  src/core/linter_utils.py,sha256=4jmC2YfpPvGhS_XHlHXa5SBIJh9CQlNj5zuW_GpdPKc,5273
12
24
  src/core/registry.py,sha256=yRA8mQLiZwjmgxl1wSTgdj1cuo_QXuRdrXt3NpCBUgE,3285
13
25
  src/core/rule_discovery.py,sha256=GL6X-38qiqmPHpk96iOCrFOLjENIze-QamO0WwugZEg,5365
14
- src/core/types.py,sha256=dIYLaCDNtCAzVaplx5S5yxywkLIuX0BN9No_l2zCfV0,2887
26
+ src/core/types.py,sha256=SElFzf_VSrAMsoiE0aU8ZYXuvKqdfwfM5umUHx4eT8w,3342
15
27
  src/core/violation_builder.py,sha256=le9YCMcJt0hFji41-cCplpowys-jT44kGe-59_Du1ZM,6592
28
+ src/core/violation_utils.py,sha256=hSTSfQaaB7038G2Au4vqBLYTnkoaSN3k70IxWacjbl8,1993
16
29
  src/formatters/__init__.py,sha256=yE1yIL8lplTMEjsmQm7F-kOMaYq7OjmbFuiwwK0D-gM,815
17
30
  src/formatters/sarif.py,sha256=gGOwb_v7j4mx4bpvV1NNDd-JyHH8i8XX89iQ6uRSvG4,7050
18
31
  src/linter_config/__init__.py,sha256=_I2VVlZlfKyT-tKukuUA5-aVcHLOe3m6C2cev43AiEc,298
19
- src/linter_config/ignore.py,sha256=S2Ub0CCOOC-wpU5Y_EodMprciw18fgWcnp4z_h1MYNk,19638
32
+ src/linter_config/ignore.py,sha256=4vX_WyRKsJeJtGc0b5O7FVkrHU9V-pVFkE3lv6-a61E,20550
20
33
  src/linter_config/loader.py,sha256=K6mKRkP2jgwar-pwBoJGWgwynLVjqdez-l3Nd6bUCMk,3363
21
34
  src/linters/__init__.py,sha256=-nnNsL8E5-2p9qlLKp_TaShHAjPH-NacOEU1sXmAR9k,77
22
35
  src/linters/collection_pipeline/__init__.py,sha256=BcnbY3wgJB1XLfZ9J9qfUJQ1_yCo_THjGDTppxJEMZY,3231
23
36
  src/linters/collection_pipeline/config.py,sha256=Z3V84X2rlj27x1eZfFBJwOMzoqFzOiwdjk-ze5sDop0,2240
24
37
  src/linters/collection_pipeline/continue_analyzer.py,sha256=51DBvR92no01rlMOjukGhsLX8jtuLbrEU--fbehUW6A,2812
25
38
  src/linters/collection_pipeline/detector.py,sha256=67M0LZwBHqZHNy5E6OS1CnBFVqis1LzkO0YP615BFr4,4291
26
- src/linters/collection_pipeline/linter.py,sha256=jvLqKsBAFj_QRrQVBTTMdLzDOjn2H2YlD9cSrdfbJbk,13947
39
+ src/linters/collection_pipeline/linter.py,sha256=ZWGXj1NpH2Qumf1UqybGrNcF3jyk3nihXl-RPPKzfHI,13939
27
40
  src/linters/collection_pipeline/suggestion_builder.py,sha256=xwMWFCTm8UWvn_6XAJerH68XayJJGWiPFmpe-NztUlc,2103
28
41
  src/linters/dry/__init__.py,sha256=p58tN3z_VbulfTkRm1kLZJ43Bemt66T2sro1teirUY8,826
29
42
  src/linters/dry/base_token_analyzer.py,sha256=SgnsX4a4kUzOsA9hTkLkg4yB8I77ewAyiUp6cAybUrg,2684
30
- src/linters/dry/block_filter.py,sha256=sSCaut6U8sZQUhpFKey4qxgdB0E43_8X2K_lkhIWIXE,8297
43
+ src/linters/dry/block_filter.py,sha256=7MRDLOV8GOav8UK2nqID1Wb885WcXBnOGY5ZG0VkSe0,11347
31
44
  src/linters/dry/block_grouper.py,sha256=NP66BlofaY7HVXcWwmK5lyiNXbaTlU1V3IbcZubIq_I,1937
32
- src/linters/dry/cache.py,sha256=dedkGU5SolTjmTTsmj-dwPEnxyhWZ2aBiHGkQy1JwXo,5881
45
+ src/linters/dry/cache.py,sha256=3XCgF0dHgNyaYzYzVJpNXrSEn38rNDGLXWGd0u1j_qQ,8748
33
46
  src/linters/dry/cache_query.py,sha256=qu_uHe360ZvKmFTBvfREjjPMGbJgLQsFTKPVIA2jQJ0,1949
34
- src/linters/dry/config.py,sha256=XaHX5SnbH8cEBHiNKMSuYQJwCbKL-Q9XgZVRcc9UBgQ,5439
47
+ src/linters/dry/config.py,sha256=TNUsxgLnlmuhTIEF2MQNYypo7R8EcCNP7VREKEpIyQc,7088
35
48
  src/linters/dry/config_loader.py,sha256=wikqnigOp6p1h9jaAATV_3bDXSiaIUFaf9xg1jQMDpo,1313
49
+ src/linters/dry/constant.py,sha256=n9cNwa-1GQPISGZ3dgGcpLv7tc-uy56ravHiFsIwoRk,3249
50
+ src/linters/dry/constant_matcher.py,sha256=W-EY6P79S8qkBVpPEReDOBA9PSrIgtc0bYMrekqrY88,7972
51
+ src/linters/dry/constant_violation_builder.py,sha256=F88aLlgscWmyUeIr_EgF4CeheXEc6Iv2pBG2eKJTmts,4048
36
52
  src/linters/dry/deduplicator.py,sha256=a1TRvldxCszf5QByo1ihXF3W98dpGuyaRT74jPfQftM,3988
37
53
  src/linters/dry/duplicate_storage.py,sha256=9pIALnwAuz5BJUYNXrPbObbP932CE9x0vgUkICryT_s,1970
38
54
  src/linters/dry/file_analyzer.py,sha256=ufSQ85ddsGTqGnBHZNTdV_5DGfTpUmJOB58sIdJNV0I,2928
39
55
  src/linters/dry/inline_ignore.py,sha256=ASfA-fp_1aPpkakN2e0T6qdTh8S7Jqj89ovxXJLmFlc,4439
40
- src/linters/dry/linter.py,sha256=XMLwCgGrFX0l0dVUJs1jpsXOfgxeKKDbxOtN5h5Emhk,5835
41
- src/linters/dry/python_analyzer.py,sha256=S0eEpBcMI0ufyMKfK0Lep-VgJ9-xt0M9525o_4hXDaQ,28025
56
+ src/linters/dry/linter.py,sha256=vWYS-UMKGG_NNGaqWgwcfm9LKpTRP66Nxfpo6WZi9Rc,8524
57
+ src/linters/dry/python_analyzer.py,sha256=ryie7hbmxdQV4pyckNm1PzXVXY-DqHlQfg7BauZzd48,10628
58
+ src/linters/dry/python_constant_extractor.py,sha256=_Mp1MniSXD2sWLTzZU8lAIKqCBrpkvPLWoDeQ5VbrZY,3877
59
+ src/linters/dry/single_statement_detector.py,sha256=_HKc3gQ1NKMY0NWugKuyqjBoU4v2HHSqlRMcUO187eY,17926
42
60
  src/linters/dry/storage_initializer.py,sha256=ykMALFs4uMUrN0_skEwySDl_t5Dm_LGHllF0OxDhiUI,1366
43
- src/linters/dry/token_hasher.py,sha256=VT7BkzYMIWadvGrnL8bFlH3lzRfgdZSj5lDU364tRNA,5589
44
- src/linters/dry/typescript_analyzer.py,sha256=ecAJZjNRtzw_XKyvXX9v53Ewyfuex_obVxmq5aBk0h4,22854
61
+ src/linters/dry/token_hasher.py,sha256=letAGxJi909iLeLX4aY7B5zOc5skGv2BClQzhEgM7l8,5657
62
+ src/linters/dry/typescript_analyzer.py,sha256=OrEqmdusYedbv8p6Qh1-zzDZbEfcPU5R9eCDQ3OHWgs,10651
63
+ src/linters/dry/typescript_constant_extractor.py,sha256=zpXse2G9r3D4xtPdfQesH9QxVroaYqjN_YDOfI0zPZU,4942
64
+ src/linters/dry/typescript_statement_detector.py,sha256=bASmWjBCb578sJk7j-jwVd3C5j8KP5YP_5NM2Hz13_0,10763
65
+ src/linters/dry/typescript_value_extractor.py,sha256=SUFqXEj6fug6KBYdfVHli_LNb4uWuA3sDX8kRA_LxxQ,2396
45
66
  src/linters/dry/violation_builder.py,sha256=WkCibSNytoqMHGC-3GrVff4PD7-SOnVzzZgkMeqmzco,2952
46
67
  src/linters/dry/violation_filter.py,sha256=RJVZZ3RWqJhIdkRQ8YcXXG9XGhiQmaiZ4_IzHWpbCG8,3265
47
68
  src/linters/dry/violation_generator.py,sha256=hbMs8Fo2hS8JCXicZcZni6NEkv4fJRsyrsjzrqN6qVw,6122
@@ -52,7 +73,7 @@ src/linters/file_header/bash_parser.py,sha256=y74YLSQ6FKXnkl9RCu31N3llDxeAH9wRgm
52
73
  src/linters/file_header/config.py,sha256=Ewrln4W4QDnInTgWr8WgSlQEjAuDyMbUuh9GHAa9a4c,4030
53
74
  src/linters/file_header/css_parser.py,sha256=ijpGMixg2ZqNWWdiZjSNtMXCOhm6XDfSY7OU68B9fS8,2332
54
75
  src/linters/file_header/field_validator.py,sha256=uASqHj7ID4JJZzgc6X3SmRRLWV35NnX2iZElCt3HW1o,2830
55
- src/linters/file_header/linter.py,sha256=ffh-gMF9IW7syqE3EXuZUxo94RMP6Dfd97hGsS3Rabg,12153
76
+ src/linters/file_header/linter.py,sha256=MV4bHiC_q-ZAxIninNZaVQIyT4H-8nym-YFC4soeyJs,12145
56
77
  src/linters/file_header/markdown_parser.py,sha256=dmrB8JCxKTHyw-qMU6S-UjKaFbqJ6ZQY1f23tND5_Jo,4964
57
78
  src/linters/file_header/python_parser.py,sha256=RTOeEt1b3tCvFWbZIt89awQA37CUOSBIGagEYnayn-M,1432
58
79
  src/linters/file_header/typescript_parser.py,sha256=R11Vkr6dUVaU8t90m8rrkMzODtBYk7u-TYFsMDRwzX8,2532
@@ -60,18 +81,19 @@ src/linters/file_header/violation_builder.py,sha256=HPYTmrcCmcO6Dx5dhmj85zZgEBM5
60
81
  src/linters/file_placement/__init__.py,sha256=vJ43GZujcbAk-K3DwfsQZ0J3yP_5G35CKssatLyntXk,862
61
82
  src/linters/file_placement/config_loader.py,sha256=Of5sTG2S-04efn3KOlXrSxpMcC1ipBpSvCjtJOMmWno,2640
62
83
  src/linters/file_placement/directory_matcher.py,sha256=1rxJtCEzqDYDQnscVX6pzk7gxCMD11pVIGaWcli-tHY,2742
63
- src/linters/file_placement/linter.py,sha256=VCqQN4aeYhAEPmzSzJGcAEVRPyoVVT9w3o1n3368oPo,14789
84
+ src/linters/file_placement/linter.py,sha256=eymYjCuzu4ZkKMHK1N1TsdiGM6FlQES7uecZeBS81tM,14781
64
85
  src/linters/file_placement/path_resolver.py,sha256=S6g7xOYsoSc0O_RDJh8j4Z2klcwzp16rSUfEAErGOTI,1972
65
- src/linters/file_placement/pattern_matcher.py,sha256=0TWozhKGqQk66oJpP66ewlmOI3bI8GpDf37PyImZcUA,2030
86
+ src/linters/file_placement/pattern_matcher.py,sha256=z0SlhRKf2SqWQmL9x2QyjLqWSSdvXHdJOFqLjMnC9Xg,2520
66
87
  src/linters/file_placement/pattern_validator.py,sha256=KW2Wv4owIGiLxxC3hhyVsKkIuzC95pGv3wQD3m4_eYo,3853
67
88
  src/linters/file_placement/rule_checker.py,sha256=JONXcaYxZ8CM_7Zg6Th01p5cve1rJ8YkReAUJ44nfUg,7795
68
89
  src/linters/file_placement/violation_factory.py,sha256=NkQmBcgpa3g3W2ZdFZNQ5djLVP4x9OKs65d7F1rCKvM,6040
69
90
  src/linters/magic_numbers/__init__.py,sha256=17dkCUf0uiYLvpOZF01VDojj92NzxXZMtRhrSBUzsdc,1689
70
91
  src/linters/magic_numbers/config.py,sha256=3zV6ZNezouBWUYy4kMw5PUlPNvIWXVwOxTz1moZfRoI,3270
71
92
  src/linters/magic_numbers/context_analyzer.py,sha256=bWv5EK3CDO0_iSd-SvDgOJeX4PGKSxG6F_cLjZnt9S8,8582
72
- src/linters/magic_numbers/linter.py,sha256=maj4NgrDapv0RurKvaVgOI1BUujixZv4E7UeYy4eGT4,18394
93
+ src/linters/magic_numbers/linter.py,sha256=pRprO22bXb9wzjCaKa5TbckvzlnuZNyXKyw0zEvXT5Y,16525
73
94
  src/linters/magic_numbers/python_analyzer.py,sha256=0u1cFaaFCqOW5yeW-YbmPoZuVIeN_KtmkFyyxup6aR0,2803
74
95
  src/linters/magic_numbers/typescript_analyzer.py,sha256=2Ra9SsXTLkZP5t-s-38ErIk4kY6EqzPfLz0I61EyIGg,7773
96
+ src/linters/magic_numbers/typescript_ignore_checker.py,sha256=9JWqtXd8KU_GCc_66KSZT2X7uQhNGpxE2ikOyjcLyao,2847
75
97
  src/linters/magic_numbers/violation_builder.py,sha256=SqIQv3N9lpP2GRC1TC5InrvaEdrAq24V7Ec2Xj5olb0,3308
76
98
  src/linters/method_property/__init__.py,sha256=t0C6zD5WLm-McgmvVajQJg4HQfOi7_4YzNLhKNA484w,1415
77
99
  src/linters/method_property/config.py,sha256=lcKfeCIeWBcD91j0AchccWhGvc68epiQeKbgL6DCEA8,5359
@@ -80,22 +102,22 @@ src/linters/method_property/python_analyzer.py,sha256=QQTpKrdCJzFqu7gdQfAqno9_wb
80
102
  src/linters/method_property/violation_builder.py,sha256=GKZC8TS9vZq_lKK5ffOVUHUlMpZN3_-Mv3inRE-v2pE,4141
81
103
  src/linters/nesting/__init__.py,sha256=tszmyCEQMpEwB5H84WcAUfRYDQl7jpsn04es5DtAHsM,3200
82
104
  src/linters/nesting/config.py,sha256=PfPA2wJn3i6HHXeM0qu6Qx-v1KJdRwlRkFOdpf7NhS8,2405
83
- src/linters/nesting/linter.py,sha256=-klbXIbg145beICop81CNQ5J1OInQaeycDT8u3Ff2Ww,6236
105
+ src/linters/nesting/linter.py,sha256=3uO9lbLQbTvjLaKRjYWi9GaNlmQmHcbwD3YmXH8DfXE,6431
84
106
  src/linters/nesting/python_analyzer.py,sha256=__fs_NE9xA4NM1MDOHBGdrI0zICkTcgbVZtfT03cxF0,3230
85
107
  src/linters/nesting/typescript_analyzer.py,sha256=wO6p6QNnyW1uaieTCZjaqR56C68AjifAv23tYaSuR2c,3860
86
108
  src/linters/nesting/typescript_function_extractor.py,sha256=5CRyP04jWP5b6NkkOGoScee6sJFZ1V-mkA0hxLkTUt8,4710
87
109
  src/linters/nesting/violation_builder.py,sha256=sMHS45F2lrA1WYrG3Uug8HfeRPljnXcyJPHSe2F76Bs,4828
88
110
  src/linters/print_statements/__init__.py,sha256=yhvdTFSqBB4UDreeadTHKFzhayxeT6JkF3yxUHMgn1g,1893
89
111
  src/linters/print_statements/config.py,sha256=rth3XmzqZGzXkRXDIVZswdtNOXIe1vIRaF46tVLKnyQ,3041
90
- src/linters/print_statements/linter.py,sha256=J23gtU6FQ2uH2Sj38PPRiV4k2HU0uto2Bqf2D28pKrI,14630
112
+ src/linters/print_statements/linter.py,sha256=HX7YjztFHXKeVasYf954taxivSrZtAoRuPU1dmXKTec,14122
91
113
  src/linters/print_statements/python_analyzer.py,sha256=SyCkh8HkYAfcSM7LCwDE1ahhxwPgrlnSVLs1iRemyaw,5461
92
114
  src/linters/print_statements/typescript_analyzer.py,sha256=4nCC2nNoQF8xtTou2XDA6jlWEuzNRsxdro50ZoVZZzE,5377
93
115
  src/linters/print_statements/violation_builder.py,sha256=Vs5m3AnWjrQqQHf6JJDaPP5B1V3YNl5pepG_oiTJnx4,3333
94
116
  src/linters/srp/__init__.py,sha256=GbhaSB2_AYY-mWgG_ThbyAcDXoVZuB5eLzguoShf38w,3367
95
- src/linters/srp/class_analyzer.py,sha256=vSBKLDBc734Iy-p9Ux7ygnNYaUtkT3ivUUJS54tyKs0,3912
117
+ src/linters/srp/class_analyzer.py,sha256=tZ6xAT0Y7LkzeVlGHckQRhFdnssuetUYxTQdUHwBoCo,4045
96
118
  src/linters/srp/config.py,sha256=hTxrM21HIOmg0sM6eJ_h3hRnuxqRZEgs13Ie97-PDr4,3397
97
- src/linters/srp/heuristics.py,sha256=0JxKitWXJo0BxubLGLPoKhr39h4bxkfos2633ypOXcs,3203
98
- src/linters/srp/linter.py,sha256=Sqh4QPz6G14A9osLHFO4xegnZSYaCWucKZPNjXzvUYA,7627
119
+ src/linters/srp/heuristics.py,sha256=M4vCFW43cmPGkPZVpAuBNsCq4kXH_nvzOLCnpU7a71Y,3242
120
+ src/linters/srp/linter.py,sha256=xp8myHJo5mVLpKmiuZjl6zgAL6WeikkoMDQbI_wZsuI,7619
99
121
  src/linters/srp/metrics_evaluator.py,sha256=Prk_dPacas_dX7spAzV0g734srmzT5u0t5d4mTG9g2o,1606
100
122
  src/linters/srp/python_analyzer.py,sha256=PH27l38BFPNmj22Z10QDBioLDCZ4xpJFzBfTh_4XMZ4,3585
101
123
  src/linters/srp/typescript_analyzer.py,sha256=Wi0P_G1v5AnZYtMN3sNm1iHva84-8Kep2LZ5RmAS4c4,2885
@@ -103,16 +125,40 @@ src/linters/srp/typescript_metrics_calculator.py,sha256=0RyHTWzBJbLUT3BqFuNc1wJV
103
125
  src/linters/srp/violation_builder.py,sha256=AMZIFNEAt-7sYVtV7x4VIuvTilxFMnU_IOH1j4wZZ_c,4072
104
126
  src/linters/stateless_class/__init__.py,sha256=8ePpinmCD27PCz7ukwUWcNwo-ZgyvhOquns-U51MyiQ,1063
105
127
  src/linters/stateless_class/config.py,sha256=u8Jt_xygIkuxZx2o0Uw_XFatOh11QhC9aN8lB_vfnLk,1993
106
- src/linters/stateless_class/linter.py,sha256=ECMDxL0ZIZDKFJ2APnpy6yzNs-gkklpmBdaSBEZQfHE,11129
128
+ src/linters/stateless_class/linter.py,sha256=mYGF7Qn-7RG8qCwbLMTFXcfbU5jDbi8qEZpx6TEk-Bs,11121
107
129
  src/linters/stateless_class/python_analyzer.py,sha256=Nv8mTM7HKjqDA8Kyu-bw3GOo9eq9XA4zD3GYsjQmV9E,7789
130
+ src/linters/stringly_typed/__init__.py,sha256=6r4IIykZ6mm551KQpRTSDp418EFqJQbuzjSfLHcwyBc,1511
131
+ src/linters/stringly_typed/config.py,sha256=-ckS5SG5DEo-G7ty9gB3BB09Xf24Pr4VHz3WylL4bAU,7738
132
+ src/linters/stringly_typed/context_filter.py,sha256=lpDQBC1Sh0nC_dnPBhHPXJ0oUH012_xs8loo8eYiXDU,13511
133
+ src/linters/stringly_typed/function_call_violation_builder.py,sha256=JpiPRvlarZcyX-v4jQeawLI2xN6r4OdEHTOCU8HEL8w,4694
134
+ src/linters/stringly_typed/ignore_checker.py,sha256=sFV9NzsIhUWZe59h2X9JJv8yE3PWQLWAbhOG7Sl1Cs8,3438
135
+ src/linters/stringly_typed/ignore_utils.py,sha256=hw0wfnGFJQkysr1qi_vmykZPr02SNBElwVHFu55tB6M,1531
136
+ src/linters/stringly_typed/linter.py,sha256=cqgQ_8SElEOzCtdi7I6sct281zheuQyo6gm1ZPyBHvU,12224
137
+ src/linters/stringly_typed/python/__init__.py,sha256=y1ELj3We0_VeA0ygXd1DxudSWrZE5OhLGtZNkKwuomA,1359
138
+ src/linters/stringly_typed/python/analyzer.py,sha256=j6ObrKexB6oQILZ_HhaULbBDiQg6MWjkpYUVMdWrIe4,12073
139
+ src/linters/stringly_typed/python/call_tracker.py,sha256=xSel_LVB6shZJsSCyK--pwH_5KQnw-S4hvAYWRdJHCk,5898
140
+ src/linters/stringly_typed/python/comparison_tracker.py,sha256=EGJRyC2e7Zj3_EvC2sHdTq2cgnvB1l7Im2ugBAOE69Y,8075
141
+ src/linters/stringly_typed/python/condition_extractor.py,sha256=R1-7TXu2_pBMSGf8RD8ygWh-BmKkXUlLA6ZbCZysbsA,4114
142
+ src/linters/stringly_typed/python/conditional_detector.py,sha256=umXVh-gWAybnnrqS2AHlcDy-Fdd3ty5KhJpbWTU_P_Q,5927
143
+ src/linters/stringly_typed/python/constants.py,sha256=IF3Y2W96hihHlr5HMenq5Q93uOo7KHzNazVVvhq3E58,671
144
+ src/linters/stringly_typed/python/match_analyzer.py,sha256=o7_XCIEggsS9NBPQ3aNBvu37cpQAEvWyXjfqNMMj2k8,2536
145
+ src/linters/stringly_typed/python/validation_detector.py,sha256=VKm3V5t2JhkyVJHF8C8iX7fcsk_5o5zGeZpSEnMJU8I,6190
146
+ src/linters/stringly_typed/python/variable_extractor.py,sha256=yYJQ5jTSMz94SD_0IMfCHMWcw1F57GmRuh9h51oiAEs,2769
147
+ src/linters/stringly_typed/storage.py,sha256=gbQwkmy7gXnE2ePqFJP0l4-tvZ8RRYOxb1-CXNLVSzc,22069
148
+ src/linters/stringly_typed/storage_initializer.py,sha256=3-4St1ieN8325Xkb0HTS27dVyjjluM_X-bkwOfJW1JM,1548
149
+ src/linters/stringly_typed/typescript/__init__.py,sha256=lOgclS9wxLNyszfwVGbVxKfCkbTLX1pvskHzcADi5Xg,1121
150
+ src/linters/stringly_typed/typescript/analyzer.py,sha256=iNEk6wQJJfmJoRTXx29GEeqTpKzQ5TcNIimSuQPb6UU,6376
151
+ src/linters/stringly_typed/typescript/call_tracker.py,sha256=W88M5FrTYlLTjavkY3Auqw4ynKweJRSd68MoV2H9lbI,10909
152
+ src/linters/stringly_typed/typescript/comparison_tracker.py,sha256=GTfAQAhDsHrUoiSy-L5AIOFLJCR_7PpVPi3yn19hVmw,12186
153
+ src/linters/stringly_typed/violation_generator.py,sha256=vBNT2ei9mOSbW-DuLNlgXLYHM-Vk5-7AevUwWyZ8w4Y,15637
108
154
  src/orchestrator/__init__.py,sha256=XXLDJq2oaB-TpP2Y97GRnde9EkITGuFCmuLrDfxI9nY,245
109
- src/orchestrator/core.py,sha256=z0YcwsK18uhlztIPi54ux3mOm8fHMREYJoudsJPhC0Q,8857
155
+ src/orchestrator/core.py,sha256=exdSuPm9ly7xy3QUB9vjAlk2LlSMhkTHNifLZ-fgsS8,17369
110
156
  src/orchestrator/language_detector.py,sha256=rHyVMApit80NTTNyDH1ObD1usKD8LjGmH3DwqNAWYGc,2736
111
157
  src/templates/thailint_config_template.yaml,sha256=vxyhRRi25_xOnHDRx0jzz69dgPqKU2IU5-YFGUoX5lM,4953
112
158
  src/utils/__init__.py,sha256=NiBtKeQ09Y3kuUzeN4O1JNfUIYPQDS2AP1l5ODq-Dec,125
113
159
  src/utils/project_root.py,sha256=b3YTEGTa9RPcOeHn1IByMMWyRiUabfVlpnlektL0A0o,6156
114
- thailint-0.10.0.dist-info/METADATA,sha256=ZeNW9Hi0Fvu5BB0Sr9Dro1fopDYG6C6hobA5nd3qTQs,48517
115
- thailint-0.10.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
116
- thailint-0.10.0.dist-info/entry_points.txt,sha256=l7DQJgU18sVLDpSaXOXY3lLhnQHQIRrSJZTQjG1cEAk,62
117
- thailint-0.10.0.dist-info/licenses/LICENSE,sha256=kxh1J0Sb62XvhNJ6MZsVNe8PqNVJ7LHRn_EWa-T3djw,1070
118
- thailint-0.10.0.dist-info/RECORD,,
160
+ thailint-0.12.0.dist-info/METADATA,sha256=bqVguJOc21dxwRlIOmu73KSW3ELtCB5uJGW7OXT4tvo,48840
161
+ thailint-0.12.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
162
+ thailint-0.12.0.dist-info/entry_points.txt,sha256=DNoGUlxpaMFqxQDgHp1yeGqohOjdFR-kH19uHYi3OUY,72
163
+ thailint-0.12.0.dist-info/licenses/LICENSE,sha256=kxh1J0Sb62XvhNJ6MZsVNe8PqNVJ7LHRn_EWa-T3djw,1070
164
+ thailint-0.12.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ thai-lint=src.cli_main:cli
3
+ thailint=src.cli_main:cli
4
+