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.
- src/__init__.py +1 -0
- src/cli/__init__.py +27 -0
- src/cli/__main__.py +22 -0
- src/cli/config.py +478 -0
- src/cli/linters/__init__.py +58 -0
- src/cli/linters/code_patterns.py +372 -0
- src/cli/linters/code_smells.py +450 -0
- src/cli/linters/documentation.py +155 -0
- src/cli/linters/shared.py +89 -0
- src/cli/linters/structure.py +313 -0
- src/cli/linters/structure_quality.py +316 -0
- src/cli/main.py +120 -0
- src/cli/utils.py +395 -0
- src/cli_main.py +34 -0
- src/core/types.py +13 -0
- src/core/violation_utils.py +69 -0
- src/linter_config/ignore.py +32 -16
- src/linters/collection_pipeline/linter.py +2 -2
- src/linters/dry/block_filter.py +97 -1
- src/linters/dry/cache.py +94 -6
- src/linters/dry/config.py +47 -10
- src/linters/dry/constant.py +92 -0
- src/linters/dry/constant_matcher.py +214 -0
- src/linters/dry/constant_violation_builder.py +98 -0
- src/linters/dry/linter.py +89 -48
- src/linters/dry/python_analyzer.py +12 -415
- src/linters/dry/python_constant_extractor.py +101 -0
- src/linters/dry/single_statement_detector.py +415 -0
- src/linters/dry/token_hasher.py +5 -5
- src/linters/dry/typescript_analyzer.py +5 -354
- src/linters/dry/typescript_constant_extractor.py +134 -0
- src/linters/dry/typescript_statement_detector.py +255 -0
- src/linters/dry/typescript_value_extractor.py +66 -0
- src/linters/file_header/linter.py +2 -2
- src/linters/file_placement/linter.py +2 -2
- src/linters/file_placement/pattern_matcher.py +19 -5
- src/linters/magic_numbers/linter.py +8 -67
- src/linters/magic_numbers/typescript_ignore_checker.py +81 -0
- src/linters/nesting/linter.py +12 -9
- src/linters/print_statements/linter.py +7 -24
- src/linters/srp/class_analyzer.py +9 -9
- src/linters/srp/heuristics.py +2 -2
- src/linters/srp/linter.py +2 -2
- src/linters/stateless_class/linter.py +2 -2
- src/linters/stringly_typed/__init__.py +36 -0
- src/linters/stringly_typed/config.py +190 -0
- src/linters/stringly_typed/context_filter.py +451 -0
- src/linters/stringly_typed/function_call_violation_builder.py +137 -0
- src/linters/stringly_typed/ignore_checker.py +102 -0
- src/linters/stringly_typed/ignore_utils.py +51 -0
- src/linters/stringly_typed/linter.py +344 -0
- src/linters/stringly_typed/python/__init__.py +33 -0
- src/linters/stringly_typed/python/analyzer.py +344 -0
- src/linters/stringly_typed/python/call_tracker.py +172 -0
- src/linters/stringly_typed/python/comparison_tracker.py +252 -0
- src/linters/stringly_typed/python/condition_extractor.py +131 -0
- src/linters/stringly_typed/python/conditional_detector.py +176 -0
- src/linters/stringly_typed/python/constants.py +21 -0
- src/linters/stringly_typed/python/match_analyzer.py +88 -0
- src/linters/stringly_typed/python/validation_detector.py +186 -0
- src/linters/stringly_typed/python/variable_extractor.py +96 -0
- src/linters/stringly_typed/storage.py +630 -0
- src/linters/stringly_typed/storage_initializer.py +45 -0
- src/linters/stringly_typed/typescript/__init__.py +28 -0
- src/linters/stringly_typed/typescript/analyzer.py +157 -0
- src/linters/stringly_typed/typescript/call_tracker.py +329 -0
- src/linters/stringly_typed/typescript/comparison_tracker.py +372 -0
- src/linters/stringly_typed/violation_generator.py +376 -0
- src/orchestrator/core.py +241 -12
- {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/METADATA +9 -3
- {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/RECORD +74 -28
- thailint-0.12.0.dist-info/entry_points.txt +4 -0
- src/cli.py +0 -2141
- thailint-0.10.0.dist-info/entry_points.txt +0 -4
- {thailint-0.10.0.dist-info → thailint-0.12.0.dist-info}/WHEEL +0 -0
- {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.
|
|
14
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
203
|
-
|
|
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.
|
|
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
|
[](https://opensource.org/licenses/MIT)
|
|
39
39
|
[](https://www.python.org/downloads/)
|
|
40
|
-
[](tests/)
|
|
41
|
+
[](htmlcov/)
|
|
42
42
|
[](https://thai-lint.readthedocs.io/en/latest/?badge=latest)
|
|
43
43
|
[](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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
41
|
-
src/linters/dry/python_analyzer.py,sha256=
|
|
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=
|
|
44
|
-
src/linters/dry/typescript_analyzer.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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
|
|
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=
|
|
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=
|
|
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=
|
|
98
|
-
src/linters/srp/linter.py,sha256=
|
|
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=
|
|
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=
|
|
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.
|
|
115
|
-
thailint-0.
|
|
116
|
-
thailint-0.
|
|
117
|
-
thailint-0.
|
|
118
|
-
thailint-0.
|
|
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,,
|