zshshellcheck 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. zshshellcheck-0.2.1/PKG-INFO +119 -0
  2. zshshellcheck-0.2.1/README.md +88 -0
  3. zshshellcheck-0.2.1/pyproject.toml +141 -0
  4. zshshellcheck-0.2.1/setup.cfg +4 -0
  5. zshshellcheck-0.2.1/src/zshcheck/__init__.py +3 -0
  6. zshshellcheck-0.2.1/src/zshcheck/analyzer.py +269 -0
  7. zshshellcheck-0.2.1/src/zshcheck/checks/__init__.py +1 -0
  8. zshshellcheck-0.2.1/src/zshcheck/checks/base.py +225 -0
  9. zshshellcheck-0.2.1/src/zshcheck/checks/commands.py +179 -0
  10. zshshellcheck-0.2.1/src/zshcheck/checks/quoting.py +165 -0
  11. zshshellcheck-0.2.1/src/zshcheck/checks/style.py +163 -0
  12. zshshellcheck-0.2.1/src/zshcheck/checks/variables.py +168 -0
  13. zshshellcheck-0.2.1/src/zshcheck/cli.py +321 -0
  14. zshshellcheck-0.2.1/src/zshcheck/diagnostics.py +177 -0
  15. zshshellcheck-0.2.1/src/zshcheck/parser.py +239 -0
  16. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/PKG-INFO +119 -0
  17. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/SOURCES.txt +25 -0
  18. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/dependency_links.txt +1 -0
  19. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/entry_points.txt +2 -0
  20. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/requires.txt +12 -0
  21. zshshellcheck-0.2.1/src/zshshellcheck.egg-info/top_level.txt +1 -0
  22. zshshellcheck-0.2.1/tests/test_analyzer.py +141 -0
  23. zshshellcheck-0.2.1/tests/test_checks.py +198 -0
  24. zshshellcheck-0.2.1/tests/test_cli.py +142 -0
  25. zshshellcheck-0.2.1/tests/test_diagnostics.py +200 -0
  26. zshshellcheck-0.2.1/tests/test_integration.py +114 -0
  27. zshshellcheck-0.2.1/tests/test_parser.py +155 -0
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: zshshellcheck
3
+ Version: 0.2.1
4
+ Summary: A static analysis tool for zsh shell scripts
5
+ Author-email: Rodrigo <rodregoc@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://rodrigo.is-a.dev/zshellcheck/
8
+ Project-URL: Repository, https://github.com/rodrigocnascimento/zshshellcheck
9
+ Project-URL: Issues, https://github.com/rodrigocnascimento/zshshellcheck/issues
10
+ Keywords: zsh,shell,lint,static-analysis,script
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Classifier: Topic :: Software Development :: Testing
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: tree-sitter>=0.20.0
21
+ Requires-Dist: tree-sitter-zsh>=0.60.0
22
+ Requires-Dist: click>=8.0.0
23
+ Requires-Dist: rich>=13.0.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
27
+ Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
28
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
29
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
30
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
31
+
32
+ <h1 align="center">ZshCheck</h1>
33
+
34
+ <p align="center">
35
+ <img src="https://raw.githubusercontent.com/rodrigocnascimento/zshellcheck/main/documentation/assets/header-image.png" alt="ZshCheck - Static Analysis for Zsh" width="600"/>
36
+ </p>
37
+
38
+ Uma ferramenta de análise estática para scripts zsh, construída com Python 3.12+.
39
+
40
+ ## Funcionalidades
41
+
42
+ - **Parser Tree-sitter**: Análise AST precisa usando gramática tree-sitter-zsh
43
+ - **Checks Plugin-based**: Sistema de verificação extensível com padrão registry
44
+ - **CLI Rico**: Saída formatada com tabela, JSON e formatos compactos
45
+ - **Múltiplos Formatos de Saída**: Table, JSON e compacto
46
+ - **Auto-Fix**: Corrige automaticamente problemas detectáveis (--fix flag)
47
+ - **Suporte a Unicode**: Aceita emojis e caracteres não-ASCII em comentários
48
+
49
+ ## Instalação
50
+
51
+ ```bash
52
+ pip install zshshellcheck
53
+ ```
54
+
55
+ ## Início Rápido
56
+
57
+ ```bash
58
+ # Analisar um script
59
+ zshcheck script.zsh
60
+
61
+ # Analisar múltiplos arquivos
62
+ zshcheck *.zsh
63
+
64
+ # Listar checks disponíveis
65
+ zshcheck --list-checks
66
+
67
+ # Filtrar por código de check
68
+ zshcheck --include ZC1001 --include ZC2001
69
+
70
+ # Saída em JSON
71
+ zshcheck --format json script.zsh
72
+
73
+ # Auto-fixar problemas (pergunta para cada fix)
74
+ zshcheck script.zsh --fix
75
+
76
+ # Ou usando a flag curta
77
+ zshcheck script.zsh -F
78
+ ```
79
+
80
+ ## Documentação
81
+
82
+ A documentação completa está disponível em: [https://developer.github.io/zshshellcheck/](https://developer.github.io/zshshellcheck/)
83
+
84
+ ## Limitações Conhecidas
85
+
86
+ ### Emojis e Unicode em scripts zsh
87
+
88
+ O parser `tree-sitter-zsh` pode apresentar problemas com caracteres unicode em identificadores (nomes de variáveis, funções). Esses caracteres agora são detectados como INFO (ZC9004) em vez de erro, para que você possa decidir se quer ajustar.
89
+
90
+ **Exemplo de warning**:
91
+ ```
92
+ INFO ZC9004 Non-ASCII characters detected (2 found). Found: 'ã' 'é'
93
+ ```
94
+
95
+ Isso aparece como INFO (não blockea a análise) e indica quais caracteres foram encontrados.
96
+
97
+ ### Sintaxe zsh avançada
98
+
99
+ Algumas sintaxes zsh avançadas (como parâmetros de glob qualifiers `${(k)functions}`) podem não ser suportadas pelo parser. Recomendamos usar a flag acima para scripts que contenham dessas expressões.
100
+
101
+ ## Desenvolvimento
102
+
103
+ ```bash
104
+ # Executar testes
105
+ pytest -v
106
+
107
+ # Executar linting
108
+ ruff check .
109
+
110
+ # Executar type checking
111
+ mypy .
112
+
113
+ # Verificação completa
114
+ ruff check . && mypy . && pytest
115
+ ```
116
+
117
+ ## Licença
118
+
119
+ MIT
@@ -0,0 +1,88 @@
1
+ <h1 align="center">ZshCheck</h1>
2
+
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/rodrigocnascimento/zshellcheck/main/documentation/assets/header-image.png" alt="ZshCheck - Static Analysis for Zsh" width="600"/>
5
+ </p>
6
+
7
+ Uma ferramenta de análise estática para scripts zsh, construída com Python 3.12+.
8
+
9
+ ## Funcionalidades
10
+
11
+ - **Parser Tree-sitter**: Análise AST precisa usando gramática tree-sitter-zsh
12
+ - **Checks Plugin-based**: Sistema de verificação extensível com padrão registry
13
+ - **CLI Rico**: Saída formatada com tabela, JSON e formatos compactos
14
+ - **Múltiplos Formatos de Saída**: Table, JSON e compacto
15
+ - **Auto-Fix**: Corrige automaticamente problemas detectáveis (--fix flag)
16
+ - **Suporte a Unicode**: Aceita emojis e caracteres não-ASCII em comentários
17
+
18
+ ## Instalação
19
+
20
+ ```bash
21
+ pip install zshshellcheck
22
+ ```
23
+
24
+ ## Início Rápido
25
+
26
+ ```bash
27
+ # Analisar um script
28
+ zshcheck script.zsh
29
+
30
+ # Analisar múltiplos arquivos
31
+ zshcheck *.zsh
32
+
33
+ # Listar checks disponíveis
34
+ zshcheck --list-checks
35
+
36
+ # Filtrar por código de check
37
+ zshcheck --include ZC1001 --include ZC2001
38
+
39
+ # Saída em JSON
40
+ zshcheck --format json script.zsh
41
+
42
+ # Auto-fixar problemas (pergunta para cada fix)
43
+ zshcheck script.zsh --fix
44
+
45
+ # Ou usando a flag curta
46
+ zshcheck script.zsh -F
47
+ ```
48
+
49
+ ## Documentação
50
+
51
+ A documentação completa está disponível em: [https://developer.github.io/zshshellcheck/](https://developer.github.io/zshshellcheck/)
52
+
53
+ ## Limitações Conhecidas
54
+
55
+ ### Emojis e Unicode em scripts zsh
56
+
57
+ O parser `tree-sitter-zsh` pode apresentar problemas com caracteres unicode em identificadores (nomes de variáveis, funções). Esses caracteres agora são detectados como INFO (ZC9004) em vez de erro, para que você possa decidir se quer ajustar.
58
+
59
+ **Exemplo de warning**:
60
+ ```
61
+ INFO ZC9004 Non-ASCII characters detected (2 found). Found: 'ã' 'é'
62
+ ```
63
+
64
+ Isso aparece como INFO (não blockea a análise) e indica quais caracteres foram encontrados.
65
+
66
+ ### Sintaxe zsh avançada
67
+
68
+ Algumas sintaxes zsh avançadas (como parâmetros de glob qualifiers `${(k)functions}`) podem não ser suportadas pelo parser. Recomendamos usar a flag acima para scripts que contenham dessas expressões.
69
+
70
+ ## Desenvolvimento
71
+
72
+ ```bash
73
+ # Executar testes
74
+ pytest -v
75
+
76
+ # Executar linting
77
+ ruff check .
78
+
79
+ # Executar type checking
80
+ mypy .
81
+
82
+ # Verificação completa
83
+ ruff check . && mypy . && pytest
84
+ ```
85
+
86
+ ## Licença
87
+
88
+ MIT
@@ -0,0 +1,141 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "zshshellcheck"
7
+ version = "0.2.1"
8
+ description = "A static analysis tool for zsh shell scripts"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "Rodrigo", email = "rodregoc@gmail.com"}
13
+ ]
14
+ requires-python = ">=3.12"
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Software Development :: Quality Assurance",
22
+ "Topic :: Software Development :: Testing",
23
+ ]
24
+ keywords = ["zsh", "shell", "lint", "static-analysis", "script"]
25
+ dependencies = [
26
+ "tree-sitter>=0.20.0",
27
+ "tree-sitter-zsh>=0.60.0",
28
+ "click>=8.0.0",
29
+ "rich>=13.0.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=7.0.0",
35
+ "pytest-cov>=4.0.0",
36
+ "pytest-xdist>=3.0.0",
37
+ "mypy>=1.0.0",
38
+ "ruff>=0.1.0",
39
+ "pre-commit>=3.0.0",
40
+ ]
41
+
42
+ [project.scripts]
43
+ zshcheck = "zshcheck.cli:main"
44
+
45
+ [project.urls]
46
+ Homepage = "https://rodrigo.is-a.dev/zshellcheck/"
47
+ Repository = "https://github.com/rodrigocnascimento/zshshellcheck"
48
+ Issues = "https://github.com/rodrigocnascimento/zshshellcheck/issues"
49
+
50
+ [tool.setuptools.packages.find]
51
+ where = ["src"]
52
+
53
+ # Ruff configuration
54
+ [tool.ruff]
55
+ target-version = "py312"
56
+ line-length = 100
57
+ select = [
58
+ "E", # pycodestyle errors
59
+ "W", # pycodestyle warnings
60
+ "F", # Pyflakes
61
+ "I", # isort
62
+ "N", # pep8-naming
63
+ "D", # pydocstyle
64
+ "UP", # pyupgrade
65
+ "B", # flake8-bugbear
66
+ "C4", # flake8-comprehensions
67
+ "SIM", # flake8-simplify
68
+ ]
69
+ ignore = [
70
+ "D100", # Missing docstring in public module
71
+ "D104", # Missing docstring in public package
72
+ "D107", # Missing docstring in __init__
73
+ ]
74
+
75
+ [tool.ruff.pydocstyle]
76
+ convention = "google"
77
+
78
+ [tool.ruff.per-file-ignores]
79
+ "tests/*" = ["D", "S"]
80
+
81
+ # Mypy configuration
82
+ [tool.mypy]
83
+ python_version = "3.12"
84
+ strict = true
85
+ warn_return_any = true
86
+ warn_unused_configs = true
87
+ warn_unused_ignores = true
88
+ warn_redundant_casts = true
89
+ warn_unreachable = true
90
+ disallow_untyped_defs = true
91
+ disallow_incomplete_defs = true
92
+ check_untyped_defs = true
93
+ disallow_untyped_decorators = true
94
+ no_implicit_optional = true
95
+ strict_optional = true
96
+ warn_no_return = true
97
+ show_error_codes = true
98
+ show_column_numbers = true
99
+
100
+ # Pytest configuration
101
+ [tool.pytest.ini_options]
102
+ testpaths = ["tests"]
103
+ python_files = ["test_*.py", "*_test.py"]
104
+ python_classes = ["Test*"]
105
+ python_functions = ["test_*"]
106
+ addopts = [
107
+ "-v",
108
+ "--strict-markers",
109
+ "--tb=short",
110
+ "--cov=zshcheck",
111
+ "--cov-report=term-missing",
112
+ "--cov-report=html:htmlcov",
113
+ "--cov-report=xml:coverage.xml",
114
+ "--cov-fail-under=70",
115
+ ]
116
+ markers = [
117
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
118
+ "integration: marks tests as integration tests",
119
+ ]
120
+
121
+ # Coverage configuration
122
+ [tool.coverage.run]
123
+ source = ["src/zshcheck"]
124
+ branch = true
125
+
126
+ [tool.coverage.report]
127
+ exclude_lines = [
128
+ "pragma: no cover",
129
+ "def __repr__",
130
+ "if self.debug:",
131
+ "if settings.DEBUG",
132
+ "raise AssertionError",
133
+ "raise NotImplementedError",
134
+ "if 0:",
135
+ "if __name__ == .__main__.:",
136
+ "class .*\\bProtocol\\):",
137
+ "@(abc\\.)?abstractmethod",
138
+ ]
139
+
140
+ [tool.coverage.html]
141
+ directory = "htmlcov"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """ZshCheck - A static analysis tool for zsh shell scripts."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,269 @@
1
+ """Analyzer module for zshcheck.
2
+
3
+ This module provides the main analysis engine that orchestrates parsing,
4
+ running checks, and collecting diagnostics.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+ from pathlib import Path
11
+
12
+ from tree_sitter import Node
13
+
14
+ from zshcheck.checks.base import AnalysisContext, CheckRegistry, get_registry
15
+ from zshcheck.diagnostics import Diagnostic, Position, Range, Severity
16
+ from zshcheck.parser import ZshParser
17
+
18
+ NON_ASCII_PATTERN = re.compile(r"[^\x00-\x7F]")
19
+
20
+
21
+ def _check_non_ascii(source: str) -> list[Diagnostic]:
22
+ """Check for non-ASCII characters (including emojis) that may cause parsing issues.
23
+
24
+ Args:
25
+ source: The source code to check.
26
+
27
+ Returns:
28
+ List of diagnostics for non-ASCII characters found.
29
+ """
30
+ diagnostics: list[Diagnostic] = []
31
+ matches = list(NON_ASCII_PATTERN.finditer(source))
32
+
33
+ if not matches:
34
+ return diagnostics
35
+
36
+ chars = [m.group() for m in matches[:5]]
37
+ chars_str = " ".join(f"'{c}'" for c in chars)
38
+
39
+ diagnostic = Diagnostic(
40
+ code="ZC9004",
41
+ severity=Severity.INFO,
42
+ message=(
43
+ f"Non-ASCII characters detected ({len(matches)} found). "
44
+ "tree-sitter-zsh grammar may not parse these correctly. "
45
+ f"Found: {chars_str}"
46
+ ),
47
+ range=Range(Position(1, 1), Position(1, 1)),
48
+ )
49
+ diagnostics.append(diagnostic)
50
+ return diagnostics
51
+
52
+
53
+ def apply_fixes(source: str, fixes: list[Diagnostic]) -> str:
54
+ """Apply fixes to source code.
55
+
56
+ Args:
57
+ source: Original source code.
58
+ fixes: List of diagnostics with fixes to apply.
59
+
60
+ Returns:
61
+ Source code with fixes applied.
62
+ """
63
+ if not fixes:
64
+ return source
65
+
66
+ result = source
67
+ ordered_fixes = sorted(
68
+ [f for f in fixes if f.fixable],
69
+ key=lambda d: (d.range.start.line, d.range.start.column),
70
+ reverse=True,
71
+ )
72
+
73
+ for diagnostic in ordered_fixes:
74
+ if diagnostic.fix is None:
75
+ continue
76
+ for replacement in diagnostic.fix.replacements:
77
+ start_line = replacement.range.start.line - 1
78
+ start_col = replacement.range.start.column - 1
79
+ end_line = replacement.range.end.line - 1
80
+ end_col = replacement.range.end.column
81
+
82
+ lines = result.splitlines(keepends=True)
83
+ if start_line < 0 or start_line >= len(lines):
84
+ continue
85
+ if end_line < 0 or end_line >= len(lines):
86
+ continue
87
+
88
+ if start_line == end_line:
89
+ line = lines[start_line]
90
+ lines[start_line] = line[:start_col] + replacement.text + line[end_col:]
91
+ else:
92
+ first_line = lines[start_line]
93
+ lines[start_line] = first_line[:start_col] + replacement.text + "\n"
94
+ del lines[start_line + 1 : end_line + 1]
95
+
96
+ result = "".join(lines)
97
+
98
+ return result
99
+
100
+
101
+ class Analyzer:
102
+ """Main analysis engine for zsh shell scripts."""
103
+
104
+ def __init__(self, registry: CheckRegistry | None = None) -> None:
105
+ """Initialize the analyzer.
106
+
107
+ Args:
108
+ registry: Check registry to use (creates default if None).
109
+ """
110
+ self._parser = ZshParser()
111
+ self._registry = registry or get_registry()
112
+
113
+ def analyze_string(
114
+ self,
115
+ source: str,
116
+ filename: str | None = None,
117
+ include: list[str] | None = None,
118
+ exclude: list[str] | None = None,
119
+ ) -> list[Diagnostic]:
120
+ """Analyze a zsh script from a string.
121
+
122
+ Args:
123
+ source: The zsh script source code.
124
+ filename: Optional filename for context.
125
+ include: Optional list of check codes to run.
126
+ exclude: Optional list of check codes to skip.
127
+
128
+ Returns:
129
+ List of diagnostics found.
130
+ """
131
+ parse_result = self._parser.parse(source)
132
+
133
+ # Collect parse errors first
134
+ all_diagnostics: list[Diagnostic] = list(parse_result.diagnostics)
135
+
136
+ # Check for non-ASCII characters
137
+ all_diagnostics.extend(_check_non_ascii(source))
138
+
139
+ if not parse_result.success or parse_result.root_node is None:
140
+ return all_diagnostics
141
+
142
+ # Create analysis context
143
+ context = AnalysisContext(
144
+ source=source,
145
+ filename=filename,
146
+ )
147
+
148
+ # Run all checks on the AST
149
+ check_diagnostics = self._run_checks(
150
+ parse_result.root_node,
151
+ context,
152
+ include=include,
153
+ exclude=exclude,
154
+ )
155
+
156
+ all_diagnostics.extend(check_diagnostics)
157
+
158
+ # Sort by line number, then column
159
+ all_diagnostics.sort()
160
+
161
+ return all_diagnostics
162
+
163
+ def analyze_file(
164
+ self,
165
+ path: str | Path,
166
+ include: list[str] | None = None,
167
+ exclude: list[str] | None = None,
168
+ ) -> list[Diagnostic]:
169
+ """Analyze a zsh script from a file.
170
+
171
+ Args:
172
+ path: Path to the zsh script file.
173
+ include: Optional list of check codes to run.
174
+ exclude: Optional list of check codes to skip.
175
+
176
+ Returns:
177
+ List of diagnostics found.
178
+ """
179
+ file_path = Path(path)
180
+ parse_result = self._parser.parse_file(file_path)
181
+
182
+ # Collect parse errors first
183
+ all_diagnostics: list[Diagnostic] = list(parse_result.diagnostics)
184
+
185
+ # Check for non-ASCII characters
186
+ all_diagnostics.extend(_check_non_ascii(parse_result.source))
187
+
188
+ if not parse_result.success or parse_result.root_node is None:
189
+ return all_diagnostics
190
+
191
+ # Create analysis context
192
+ context = AnalysisContext(
193
+ source=parse_result.source,
194
+ filename=str(file_path),
195
+ )
196
+
197
+ # Run all checks on the AST
198
+ check_diagnostics = self._run_checks(
199
+ parse_result.root_node,
200
+ context,
201
+ include=include,
202
+ exclude=exclude,
203
+ )
204
+
205
+ all_diagnostics.extend(check_diagnostics)
206
+
207
+ # Sort by line number, then column
208
+ all_diagnostics.sort()
209
+
210
+ return all_diagnostics
211
+
212
+ def _run_checks(
213
+ self,
214
+ root_node: Node,
215
+ context: AnalysisContext,
216
+ include: list[str] | None = None,
217
+ exclude: list[str] | None = None,
218
+ ) -> list[Diagnostic]:
219
+ """Run all checks against the AST.
220
+
221
+ Args:
222
+ root_node: Root node of the AST.
223
+ context: Analysis context.
224
+ include: Optional list of check codes to run.
225
+ exclude: Optional list of check codes to skip.
226
+
227
+ Returns:
228
+ List of diagnostics found.
229
+ """
230
+ diagnostics: list[Diagnostic] = []
231
+ exclude_set = set(exclude or [])
232
+
233
+ def visit_node(node: Node, depth: int) -> None:
234
+ # Run checks that are not excluded
235
+ for check in self._registry.checks:
236
+ if check.code in exclude_set:
237
+ continue
238
+ if include is not None and check.code not in include:
239
+ continue
240
+
241
+ if diagnostic := check.check(node, context):
242
+ diagnostics.append(diagnostic)
243
+
244
+ # Visit children
245
+ for child in node.children:
246
+ visit_node(child, depth + 1)
247
+
248
+ visit_node(root_node, 0)
249
+ return diagnostics
250
+
251
+
252
+ def create_default_analyzer() -> Analyzer:
253
+ """Create an analyzer with all default checks registered."""
254
+ from zshcheck.checks.commands import DeprecatedCommandCheck
255
+ from zshcheck.checks.quoting import UnquotedVariableCheck
256
+ from zshcheck.checks.style import DoubleBracketCheck
257
+ from zshcheck.checks.variables import UnusedVariableCheck
258
+
259
+ registry = CheckRegistry()
260
+ registry.register_all(
261
+ [
262
+ UnquotedVariableCheck(),
263
+ UnusedVariableCheck(),
264
+ DeprecatedCommandCheck(),
265
+ DoubleBracketCheck(),
266
+ ]
267
+ )
268
+
269
+ return Analyzer(registry)
@@ -0,0 +1 @@
1
+ """Checks package for zshcheck."""