Repository navigation
v2.2.0
Lean 4 support
codopsy now analyses Lean 4 (.lean) — 35 languages, 182 lint rules.
- Cyclomatic and cognitive complexity for
def/theorem/abbrev/example/instance, scored against Lean's own control flow:if then else,matcharms,induction,by_cases, and the∧/∨connectives.else ifchains stay flat instead of nesting. - 8 lint rules aimed at the two things that make a Lean file untrustworthy rather than merely ugly — proofs that are not finished, and declarations that widen what the kernel takes on faith:
| Rule | Default |
|---|---|
no-sorry |
error |
no-axiom |
warning |
no-native-decide |
warning |
no-unsafe |
warning |
no-unlimited-heartbeats |
warning |
no-partial-def |
info |
no-dbg-trace |
info |
no-debug-command |
info |
Lean is macro-extensible, so no tree-sitter grammar reads every file. Measured over lean4 and Mathlib core sources, the grammar codopsy uses leaves ~6% of bytes unparsed; hand-written Lean parses essentially in full. What it cannot read is now reported rather than silently skipped — see the next section.
New rule: syntax-error (all languages, info)
A file the parser could not read produced no functions, no issues, and therefore a perfect score. It now reports how many regions were unreadable and what share of the file they cover, so an unparsed file can no longer pass as a clean one. One issue per file; disable it with "syntax-error": false like any other rule.
Complexity fix: keyword tokens were counted twice
Several tree-sitter grammars name a keyword token exactly like the node it opens — Ruby's if token inside an if node, JavaScript's function inside a function_declaration. Both matched the classification tables, so every such branch was counted twice and phantom (anonymous) functions appeared in reports. Only named nodes are classified now.
This changes reported numbers for Ruby, Crystal, JavaScript and Lua: complexity and function counts go down. A baseline recorded with 2.0.x will register the difference as an improvement.
Other fixes
--hotspotssilently produced nothing unless the analysed directory was the repository root. Churn keys fromgit logare repo-root-relative; the comparison was built relative to the analysed directory, so the two never matched in a subdirectory.--helpstill described codopsy as being "for TypeScript, JavaScript & Rust".--max-complexity/--max-cognitive-complexityCLI defaults were hardcoded instead of reading the centraliseddefaults, so they could drift from the documented values.score_complexitynow honours the configuredmax-complexity/max-cognitive-complexitythresholds instead of the built-in ones (this landed after v2.0.1 and was never released).
Internal
The language registry is a single table per language, replacing three lists that had to stay in lockstep: a name array indexed by enum declaration order, a grammar match, and an extension map. Adding a language is now one row, and a new test asserts that all 35 grammars actually load and that every extension round-trips.
codopsy's own analysis of src is A (100/100), 0 issues.
Full Changelog: v2.0.1...v2.2.0