dddlint 0.1.2__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 (36) hide show
  1. dddlint-0.1.2/.coverage +0 -0
  2. dddlint-0.1.2/.github/actions/smallsteps/action.yaml +20 -0
  3. dddlint-0.1.2/.github/workflows/workflow.yaml +123 -0
  4. dddlint-0.1.2/.gitignore +10 -0
  5. dddlint-0.1.2/.pre-commit-config.yaml +94 -0
  6. dddlint-0.1.2/.python-version +1 -0
  7. dddlint-0.1.2/.skills/dddlint/SKILL.md +46 -0
  8. dddlint-0.1.2/PKG-INFO +184 -0
  9. dddlint-0.1.2/README.md +167 -0
  10. dddlint-0.1.2/coverage.json +1 -0
  11. dddlint-0.1.2/dddlint.yaml +21 -0
  12. dddlint-0.1.2/examples/billing/invoice_service.py +14 -0
  13. dddlint-0.1.2/examples/core/customer_repo.py +13 -0
  14. dddlint-0.1.2/examples/core/order_service.py +17 -0
  15. dddlint-0.1.2/examples/dddlint.yaml +23 -0
  16. dddlint-0.1.2/llms.txt +20 -0
  17. dddlint-0.1.2/pyproject.toml +137 -0
  18. dddlint-0.1.2/smallsteps.toml +9 -0
  19. dddlint-0.1.2/src/dddlint/__init__.py +1 -0
  20. dddlint-0.1.2/src/dddlint/check.py +135 -0
  21. dddlint-0.1.2/src/dddlint/cli.py +146 -0
  22. dddlint-0.1.2/src/dddlint/config.py +31 -0
  23. dddlint-0.1.2/src/dddlint/config_check.py +89 -0
  24. dddlint-0.1.2/src/dddlint/extract.py +82 -0
  25. dddlint-0.1.2/src/dddlint/mcp_server.py +76 -0
  26. dddlint-0.1.2/src/dddlint/server.py +159 -0
  27. dddlint-0.1.2/src/dddlint/view.py +364 -0
  28. dddlint-0.1.2/tests/test_check.py +59 -0
  29. dddlint-0.1.2/tests/test_cli.py +54 -0
  30. dddlint-0.1.2/tests/test_config.py +23 -0
  31. dddlint-0.1.2/tests/test_config_check.py +88 -0
  32. dddlint-0.1.2/tests/test_extract.py +44 -0
  33. dddlint-0.1.2/tests/test_server.py +126 -0
  34. dddlint-0.1.2/tests/test_view.py +63 -0
  35. dddlint-0.1.2/uv.lock +2832 -0
  36. dddlint-0.1.2/zensical.toml +12 -0
Binary file
@@ -0,0 +1,20 @@
1
+ name: 'Smallsteps Ratchet Evaluation'
2
+ description: 'Evaluates your quality goals'
3
+ inputs:
4
+ SMALLSTEPS_PYTEST_COVERAGE:
5
+ description: "Current live performance value for 'Pytest Coverage'"
6
+ required: true
7
+
8
+ runs:
9
+ using: 'composite'
10
+ steps:
11
+ - name: Install uv
12
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
13
+ with:
14
+ enable-cache: true
15
+
16
+ - name: Run Smallsteps Guardrail Validation
17
+ shell: bash
18
+ run: uvx smallsteps check
19
+ env:
20
+ SMALLSTEPS_PYTEST_COVERAGE: ${{ inputs.SMALLSTEPS_PYTEST_COVERAGE }}
@@ -0,0 +1,123 @@
1
+ name: CI and Publish
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v5
17
+
18
+ - name: Set up Python
19
+ run: uv python install 3.12
20
+
21
+ - name: Install dependencies
22
+ run: uv sync --all-extras --frozen
23
+
24
+ - name: Lint with ruff
25
+ run: uv run ruff check .
26
+
27
+ - name: Format check with ruff
28
+ run: uv run ruff format --check .
29
+
30
+ - name: Type check with basedpyright
31
+ run: uv run basedpyright
32
+
33
+ - name: Run unit tests (parallel)
34
+ run: uv run pytest -m unit -n auto --cov=dddlint --cov-report=term-missing --cov-report=json
35
+
36
+ - name: Compute coverage
37
+ id: cov
38
+ run: echo "value=$(uv run python -c 'import json; print(json.load(open("coverage.json"))["totals"]["percent_covered"])')" >> "$GITHUB_OUTPUT"
39
+
40
+ - name: Enforce coverage ratchet
41
+ uses: ./.github/actions/smallsteps
42
+ with:
43
+ SMALLSTEPS_PYTEST_COVERAGE: ${{ steps.cov.outputs.value }}
44
+
45
+ publish:
46
+ needs: test
47
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
48
+ runs-on: ubuntu-latest
49
+ environment:
50
+ name: pypi
51
+ url: https://pypi.org/p/dddlint
52
+ permissions:
53
+ id-token: write
54
+ contents: write
55
+
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ with:
59
+ fetch-depth: 0
60
+ token: ${{ secrets.GITHUB_TOKEN }}
61
+ - name: Install uv
62
+ uses: astral-sh/setup-uv@v5
63
+
64
+ - name: Set up Python
65
+ run: uv python install 3.12
66
+
67
+ - name: Install dependencies
68
+ run: uv sync --all-extras --frozen
69
+
70
+ - name: Configure git
71
+ run: |
72
+ git config user.name "github-actions[bot]"
73
+ git config user.email "github-actions[bot]@users.noreply.github.com"
74
+
75
+ - name: Bump version
76
+ run: uv run bump-my-version bump patch
77
+
78
+ - name: Push version bump
79
+ run: git push --follow-tags
80
+
81
+ - name: Build package
82
+ run: uv build
83
+
84
+ - name: Publish to PyPI
85
+ uses: pypa/gh-action-pypi-publish@release/v1
86
+
87
+ docs:
88
+ needs: test
89
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
90
+ runs-on: ubuntu-latest
91
+ permissions:
92
+ contents: read
93
+ pages: write
94
+ id-token: write
95
+ environment:
96
+ name: github-pages
97
+ url: ${{ steps.deployment.outputs.page_url }}
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+
101
+ - name: Install uv
102
+ uses: astral-sh/setup-uv@v5
103
+
104
+ - name: Set up Python
105
+ run: uv python install 3.12
106
+
107
+ - name: Install dependencies
108
+ run: uv sync --all-extras --frozen
109
+
110
+ - name: Build docs
111
+ run: uv run zensical build
112
+
113
+ - name: Setup Pages
114
+ uses: actions/configure-pages@v5
115
+
116
+ - name: Upload artifact
117
+ uses: actions/upload-pages-artifact@v3
118
+ with:
119
+ path: site
120
+
121
+ - name: Deploy to GitHub Pages
122
+ id: deployment
123
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,10 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
@@ -0,0 +1,94 @@
1
+ default_language_version:
2
+ python: python3
3
+ default_stages: [pre-commit]
4
+ repos:
5
+ - repo: https://github.com/pre-commit/pre-commit-hooks
6
+ rev: v6.0.0
7
+ hooks:
8
+ - id: trailing-whitespace
9
+ args: [--markdown-linebreak-ext=md]
10
+ - id: end-of-file-fixer
11
+ - id: mixed-line-ending
12
+ args: [--fix=lf]
13
+ - id: check-yaml
14
+ args: [--unsafe]
15
+ - id: check-json
16
+ - id: check-toml
17
+ - id: check-merge-conflict
18
+ - id: check-case-conflict
19
+ - id: check-ast
20
+ - id: check-docstring-first
21
+ - id: debug-statements
22
+ - id: name-tests-test
23
+ args: [--pytest-test-first]
24
+ - id: detect-private-key
25
+ - id: check-added-large-files
26
+ args: [--maxkb=1000]
27
+
28
+ - repo: https://github.com/igorshubovych/markdownlint-cli
29
+ rev: v0.47.0
30
+ hooks:
31
+ - id: markdownlint
32
+ args: [--fix, --disable, MD013, MD024, MD033, MD036, MD040, MD041, MD060, --]
33
+
34
+ - repo: https://github.com/commitizen-tools/commitizen
35
+ rev: v4.12.1
36
+ hooks:
37
+ - id: commitizen
38
+ stages: [commit-msg]
39
+
40
+ - repo: https://github.com/benomahony/nasa-lsp
41
+ rev: v0.1.7
42
+ hooks:
43
+ - id: nasa-lsp
44
+ exclude: ^(tests|examples)/
45
+
46
+ - repo: local
47
+ hooks:
48
+ - id: ruff-format
49
+ name: ruff-format
50
+ entry: uv run ruff format
51
+ language: system
52
+ types_or: [python, pyi]
53
+ require_serial: true
54
+ - id: ruff
55
+ name: ruff
56
+ entry: uv run ruff check --fix --exit-non-zero-on-fix
57
+ language: system
58
+ types_or: [python, pyi]
59
+ require_serial: true
60
+ - id: basedpyright
61
+ name: basedpyright
62
+ entry: uv run basedpyright
63
+ language: system
64
+ types: [python]
65
+ pass_filenames: true
66
+ require_serial: true
67
+ - id: vulture
68
+ name: vulture
69
+ entry: uv run vulture src/dddlint/ --min-confidence 80
70
+ language: system
71
+ types: [python]
72
+ files: ^src/dddlint/
73
+ pass_filenames: false
74
+ require_serial: true
75
+ - id: bandit
76
+ name: bandit
77
+ entry: uv run bandit -c pyproject.toml -r src/dddlint/
78
+ language: system
79
+ files: ^src/dddlint/
80
+ exclude: ^tests/
81
+ pass_filenames: false
82
+ - id: cliqa
83
+ name: cliqa
84
+ entry: uv run cliqa analyze dddlint
85
+ language: system
86
+ files: ^(pyproject\.toml|src/.*\.py)$
87
+ pass_filenames: false
88
+ require_serial: true
89
+ - id: deptry
90
+ name: deptry
91
+ entry: uv run deptry . --extend-exclude "\.venv|tests"
92
+ language: system
93
+ pass_filenames: false
94
+ require_serial: true
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: dddlint
3
+ description: Help users work with dddlint. Use when the user asks about dddlint features, usage, or wants to implement functionality using this project.
4
+ ---
5
+
6
+ # dddlint Skill
7
+
8
+ This skill helps you work with dddlint.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use this skill when:
13
+
14
+ - User asks about dddlint features or capabilities
15
+ - User wants to use dddlint in their code
16
+ - User needs help with dddlint API or CLI
17
+ - User wants examples of dddlint usage
18
+
19
+ ## Project Information
20
+
21
+ - **Description**: Polyglot ubiquitous language linter for codebases and coding agents
22
+ - **Author**: benomahony
23
+ - **Documentation**: See docs/index.md for full documentation
24
+ - **Source**: src/dddlint/
25
+
26
+ ## Quick Reference
27
+
28
+ ### CLI Usage
29
+
30
+ ```bash
31
+ dddlint --help
32
+ ```
33
+
34
+ ### Library Usage
35
+
36
+ ```python
37
+ from dddlint.core import example_function
38
+
39
+ result = example_function("World")
40
+ ```
41
+
42
+ ## Resources
43
+
44
+ - Check docs/index.md for comprehensive documentation
45
+ - Check llms.txt for LLM-friendly documentation summary
46
+ - Check src/dddlint/ for implementation details
dddlint-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: dddlint
3
+ Version: 0.1.2
4
+ Summary: Polyglot ubiquitous language linter for codebases and coding agents
5
+ Project-URL: Repository, https://github.com/benomahony/dddlint
6
+ Author: benomahony
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: lsprotocol>=2025.0.0
9
+ Requires-Dist: mcp>=1.28.1
10
+ Requires-Dist: pydantic>=2.13.4
11
+ Requires-Dist: pygls>=2.1.1
12
+ Requires-Dist: pyyaml>=6.0.3
13
+ Requires-Dist: rich>=15.0.0
14
+ Requires-Dist: tree-sitter-language-pack>=1.8.1
15
+ Requires-Dist: typer>=0.26.2
16
+ Description-Content-Type: text/markdown
17
+
18
+ # dddlint
19
+
20
+ Polyglot ubiquitous language linter. Reads class, function, method, and type names across **306 languages** and enforces them against a domain vocabulary — banned terms, non-canonical synonyms, and one concept spelled multiple ways.
21
+
22
+ Works with any language tree-sitter recognises, without per-language queries. Slots into pre-commit hooks, CI pipelines, and coding agent loops via a non-zero exit code on findings. Ships with an LSP server for inline editor diagnostics and rename code actions.
23
+
24
+ ## Install
25
+
26
+ ```sh
27
+ uv add dddlint
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```sh
33
+ # lint current directory (looks for dddlint.yaml)
34
+ dddlint lint
35
+
36
+ # lint a specific path
37
+ dddlint lint src/
38
+
39
+ # open an interactive language graph in the browser
40
+ dddlint html
41
+
42
+ # start the LSP server (stdio)
43
+ dddlint lsp
44
+ ```
45
+
46
+ ## Config
47
+
48
+ Place `dddlint.yaml` at the project root. When a path is passed to `lint` or `html`, the config is looked up in that directory first, then falls back to the current working directory.
49
+
50
+ ```yaml
51
+ similarity_threshold: 0.85 # Jaccard threshold for drift detection
52
+ enforce_canonical: true # flag alias terms in addition to forbidden ones
53
+
54
+ # terms that must never appear in a definition name
55
+ forbidden:
56
+ - util
57
+ - helper
58
+ - manager
59
+
60
+ # canonical terms and their aliases
61
+ synonyms:
62
+ - canonical: customer
63
+ aliases: [client, user, accountholder]
64
+ - canonical: order
65
+ aliases: [purchase, transaction]
66
+
67
+ # high-level business domains
68
+ domains:
69
+ - name: commerce
70
+ include: ["**/commerce/**"]
71
+ synonyms:
72
+ - canonical: order
73
+ aliases: [purchase]
74
+
75
+ # bounded contexts — same structure as domains, applied after (context wins on conflict)
76
+ contexts:
77
+ - name: billing
78
+ include: ["**/billing/**"]
79
+ forbidden: [discount]
80
+ synonyms:
81
+ - canonical: invoice
82
+ aliases: [bill, statement]
83
+
84
+ # register file extensions for languages not auto-detected
85
+ languages:
86
+ svelte:
87
+ extensions: [".svelte"]
88
+ ```
89
+
90
+ Global rules apply everywhere. Domain rules apply to matching paths. Context rules apply after domains, so a context can override a domain synonym.
91
+
92
+ ## Rules
93
+
94
+ | Rule | Severity | Description |
95
+ |---|---|---|
96
+ | `forbidden` | error | A definition name contains a banned term |
97
+ | `alias` | warning | A definition uses a non-canonical synonym — includes a rename suggestion |
98
+ | `drift` | info | The same concept is spelled multiple ways across the codebase |
99
+ | `config:forbidden-canonical-clash` | error | A term is both forbidden and a canonical synonym |
100
+ | `config:alias-conflict` | warning | The same alias maps to different canonicals in different scopes |
101
+ | `config:duplicate-name` | info | Two domains or contexts have suspiciously similar names |
102
+
103
+ Config rules are checked against `dddlint.yaml` itself on every run.
104
+
105
+ ## LSP
106
+
107
+ The LSP server publishes diagnostics on file open and save, scanning the entire workspace each time so cross-file drift is always caught. Alias findings include a code action to rename the identifier to the canonical term with case preserved (`ClientRepo` → `CustomerRepo`, `get_client` → `get_customer`).
108
+
109
+ **Neovim** — add to `init.lua`:
110
+
111
+ ```lua
112
+ vim.api.nvim_create_autocmd("BufReadPost", {
113
+ callback = function(args)
114
+ local root = vim.fs.root(args.buf, { "dddlint.yaml" })
115
+ if root then
116
+ vim.lsp.start({
117
+ name = "dddlint",
118
+ cmd = { "dddlint", "lsp" },
119
+ root_dir = root,
120
+ }, { bufnr = args.buf })
121
+ end
122
+ end,
123
+ })
124
+ ```
125
+
126
+ The autocmd fires on every buffer, attaches only when `dddlint.yaml` is found, and is language-agnostic — no filetype list required.
127
+
128
+ **VS Code** — via a generic LSP client extension:
129
+
130
+ ```json
131
+ {
132
+ "lsp.servers": {
133
+ "dddlint": {
134
+ "command": ["uvx", "dddlint", "lsp"],
135
+ "filetypes": ["*"]
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ **Helix** — `.helix/languages.toml`:
142
+
143
+ ```toml
144
+ [language-server.dddlint]
145
+ command = "dddlint"
146
+ args = ["lsp"]
147
+ ```
148
+
149
+ ## Language support
150
+
151
+ Extraction is powered by [`tree-sitter-language-pack`](https://github.com/Goldziher/tree-sitter-language-pack), which covers 306 languages including:
152
+
153
+ Ada · Agda · Arduino · Bash · C · C++ · C# · Clojure · COBOL · Crystal · CSS · D · Dart · Dockerfile · Elixir · Elm · Erlang · F# · Fortran · GDScript · GLSL · Go · GraphQL · Groovy · Hack · Haskell · HCL · HTML · Java · JavaScript · Julia · Kotlin · Lean · Lua · MATLAB · Mojo · Nix · OCaml · Odin · Pascal · Perl · PHP · PowerShell · Prolog · Python · R · Racket · Ruby · Rust · Scala · Scheme · Solidity · SQL · Svelte · Swift · Terraform · TLA+ · TOML · TypeScript · V · VHDL · Vim · Vue · WebAssembly · XML · YAML · Zig — and [243 more](https://github.com/Goldziher/tree-sitter-language-pack).
154
+
155
+ ## CI
156
+
157
+ ```yaml
158
+ # .github/workflows/dddlint.yml
159
+ - run: uvx dddlint lint
160
+ ```
161
+
162
+ Exit code is `0` when clean, `1` when findings exist.
163
+
164
+ ## Pre-commit
165
+
166
+ ```yaml
167
+ # .pre-commit-config.yaml
168
+ repos:
169
+ - repo: local
170
+ hooks:
171
+ - id: dddlint
172
+ name: dddlint
173
+ entry: dddlint lint
174
+ language: python
175
+ pass_filenames: false
176
+ ```
177
+
178
+ ## Offline use
179
+
180
+ The language pack downloads parsers on first use. For CI or air-gapped runs, warm the cache in the image:
181
+
182
+ ```sh
183
+ python -c "import tree_sitter_language_pack as t; t.download_all()"
184
+ ```
@@ -0,0 +1,167 @@
1
+ # dddlint
2
+
3
+ Polyglot ubiquitous language linter. Reads class, function, method, and type names across **306 languages** and enforces them against a domain vocabulary — banned terms, non-canonical synonyms, and one concept spelled multiple ways.
4
+
5
+ Works with any language tree-sitter recognises, without per-language queries. Slots into pre-commit hooks, CI pipelines, and coding agent loops via a non-zero exit code on findings. Ships with an LSP server for inline editor diagnostics and rename code actions.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ uv add dddlint
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```sh
16
+ # lint current directory (looks for dddlint.yaml)
17
+ dddlint lint
18
+
19
+ # lint a specific path
20
+ dddlint lint src/
21
+
22
+ # open an interactive language graph in the browser
23
+ dddlint html
24
+
25
+ # start the LSP server (stdio)
26
+ dddlint lsp
27
+ ```
28
+
29
+ ## Config
30
+
31
+ Place `dddlint.yaml` at the project root. When a path is passed to `lint` or `html`, the config is looked up in that directory first, then falls back to the current working directory.
32
+
33
+ ```yaml
34
+ similarity_threshold: 0.85 # Jaccard threshold for drift detection
35
+ enforce_canonical: true # flag alias terms in addition to forbidden ones
36
+
37
+ # terms that must never appear in a definition name
38
+ forbidden:
39
+ - util
40
+ - helper
41
+ - manager
42
+
43
+ # canonical terms and their aliases
44
+ synonyms:
45
+ - canonical: customer
46
+ aliases: [client, user, accountholder]
47
+ - canonical: order
48
+ aliases: [purchase, transaction]
49
+
50
+ # high-level business domains
51
+ domains:
52
+ - name: commerce
53
+ include: ["**/commerce/**"]
54
+ synonyms:
55
+ - canonical: order
56
+ aliases: [purchase]
57
+
58
+ # bounded contexts — same structure as domains, applied after (context wins on conflict)
59
+ contexts:
60
+ - name: billing
61
+ include: ["**/billing/**"]
62
+ forbidden: [discount]
63
+ synonyms:
64
+ - canonical: invoice
65
+ aliases: [bill, statement]
66
+
67
+ # register file extensions for languages not auto-detected
68
+ languages:
69
+ svelte:
70
+ extensions: [".svelte"]
71
+ ```
72
+
73
+ Global rules apply everywhere. Domain rules apply to matching paths. Context rules apply after domains, so a context can override a domain synonym.
74
+
75
+ ## Rules
76
+
77
+ | Rule | Severity | Description |
78
+ |---|---|---|
79
+ | `forbidden` | error | A definition name contains a banned term |
80
+ | `alias` | warning | A definition uses a non-canonical synonym — includes a rename suggestion |
81
+ | `drift` | info | The same concept is spelled multiple ways across the codebase |
82
+ | `config:forbidden-canonical-clash` | error | A term is both forbidden and a canonical synonym |
83
+ | `config:alias-conflict` | warning | The same alias maps to different canonicals in different scopes |
84
+ | `config:duplicate-name` | info | Two domains or contexts have suspiciously similar names |
85
+
86
+ Config rules are checked against `dddlint.yaml` itself on every run.
87
+
88
+ ## LSP
89
+
90
+ The LSP server publishes diagnostics on file open and save, scanning the entire workspace each time so cross-file drift is always caught. Alias findings include a code action to rename the identifier to the canonical term with case preserved (`ClientRepo` → `CustomerRepo`, `get_client` → `get_customer`).
91
+
92
+ **Neovim** — add to `init.lua`:
93
+
94
+ ```lua
95
+ vim.api.nvim_create_autocmd("BufReadPost", {
96
+ callback = function(args)
97
+ local root = vim.fs.root(args.buf, { "dddlint.yaml" })
98
+ if root then
99
+ vim.lsp.start({
100
+ name = "dddlint",
101
+ cmd = { "dddlint", "lsp" },
102
+ root_dir = root,
103
+ }, { bufnr = args.buf })
104
+ end
105
+ end,
106
+ })
107
+ ```
108
+
109
+ The autocmd fires on every buffer, attaches only when `dddlint.yaml` is found, and is language-agnostic — no filetype list required.
110
+
111
+ **VS Code** — via a generic LSP client extension:
112
+
113
+ ```json
114
+ {
115
+ "lsp.servers": {
116
+ "dddlint": {
117
+ "command": ["uvx", "dddlint", "lsp"],
118
+ "filetypes": ["*"]
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ **Helix** — `.helix/languages.toml`:
125
+
126
+ ```toml
127
+ [language-server.dddlint]
128
+ command = "dddlint"
129
+ args = ["lsp"]
130
+ ```
131
+
132
+ ## Language support
133
+
134
+ Extraction is powered by [`tree-sitter-language-pack`](https://github.com/Goldziher/tree-sitter-language-pack), which covers 306 languages including:
135
+
136
+ Ada · Agda · Arduino · Bash · C · C++ · C# · Clojure · COBOL · Crystal · CSS · D · Dart · Dockerfile · Elixir · Elm · Erlang · F# · Fortran · GDScript · GLSL · Go · GraphQL · Groovy · Hack · Haskell · HCL · HTML · Java · JavaScript · Julia · Kotlin · Lean · Lua · MATLAB · Mojo · Nix · OCaml · Odin · Pascal · Perl · PHP · PowerShell · Prolog · Python · R · Racket · Ruby · Rust · Scala · Scheme · Solidity · SQL · Svelte · Swift · Terraform · TLA+ · TOML · TypeScript · V · VHDL · Vim · Vue · WebAssembly · XML · YAML · Zig — and [243 more](https://github.com/Goldziher/tree-sitter-language-pack).
137
+
138
+ ## CI
139
+
140
+ ```yaml
141
+ # .github/workflows/dddlint.yml
142
+ - run: uvx dddlint lint
143
+ ```
144
+
145
+ Exit code is `0` when clean, `1` when findings exist.
146
+
147
+ ## Pre-commit
148
+
149
+ ```yaml
150
+ # .pre-commit-config.yaml
151
+ repos:
152
+ - repo: local
153
+ hooks:
154
+ - id: dddlint
155
+ name: dddlint
156
+ entry: dddlint lint
157
+ language: python
158
+ pass_filenames: false
159
+ ```
160
+
161
+ ## Offline use
162
+
163
+ The language pack downloads parsers on first use. For CI or air-gapped runs, warm the cache in the image:
164
+
165
+ ```sh
166
+ python -c "import tree_sitter_language_pack as t; t.download_all()"
167
+ ```