Surfaced by #55 / PR #60, which patched one instance of it without closing the hole.
The problem
just lint-templates reports 0 errors on templates that djlint --reformat immediately rewrites.
single_attribute_per_line is a reformat-only rule. djLint's check mode does not evaluate it, so the gate is structurally blind to the one formatting rule this repo actually cares about. Concretely: the 12 box/prose templates shipped in #54 passed just lint-templates and passed prek, and prek run --all-files on the very next branch restyled all 12 of them.
That means "the template lint passed" is not evidence a template is formatted, and every contributor's hook run dirties files they did not touch until someone happens to commit the formatter's output.
Why the current fix is a patch
PR #60 commits djlint's output for those 12 files. That resolves this instance and does nothing about the next new template. The repo's own rule — replace the mechanism, don't patch it — says the gate should be able to fail, and right now it cannot.
Options
- Check-mode equivalent. Run
djlint --reformat against a scratch copy of both trees and fail on any diff. This is what ruff format --check does for Python and it makes the existing just lint-templates honest. Cost: a second pass over 231 files, and the scratch-copy plumbing in the justfile.
- Make the prek hook fail on modification rather than silently reformatting and reporting
Passed. Cheapest, catches it at commit time, but only for files in that commit — a hook that reformats and passes is the proximate reason this went unnoticed.
- Drop
single_attribute_per_line if the layout it produces is not worth enforcing. Also a legitimate answer; it is a preference, not a correctness rule.
1 and 2 compose and are probably both wanted — 2 for the fast local signal, 1 so CI cannot be greener than a fresh --reformat.
The constraint any fix must respect
Whatever lands must not let djLint touch a class="…" value. single_attribute_per_line is layout inside the opening tag only; whitespace added inside a class value changes the rendered bytes and breaks the substring assertions the primitives parity tests depend on. That constraint is already documented in CLAUDE.md and is the reason this rule needs a guard rather than a blanket "just run the formatter."
Acceptance criteria
Surfaced by #55 / PR #60, which patched one instance of it without closing the hole.
The problem
just lint-templatesreports 0 errors on templates thatdjlint --reformatimmediately rewrites.single_attribute_per_lineis a reformat-only rule. djLint's check mode does not evaluate it, so the gate is structurally blind to the one formatting rule this repo actually cares about. Concretely: the 12box/prosetemplates shipped in #54 passedjust lint-templatesand passedprek, andprek run --all-fileson the very next branch restyled all 12 of them.That means "the template lint passed" is not evidence a template is formatted, and every contributor's hook run dirties files they did not touch until someone happens to commit the formatter's output.
Why the current fix is a patch
PR #60 commits djlint's output for those 12 files. That resolves this instance and does nothing about the next new template. The repo's own rule — replace the mechanism, don't patch it — says the gate should be able to fail, and right now it cannot.
Options
djlint --reformatagainst a scratch copy of both trees and fail on any diff. This is whatruff format --checkdoes for Python and it makes the existingjust lint-templateshonest. Cost: a second pass over 231 files, and the scratch-copy plumbing in thejustfile.Passed. Cheapest, catches it at commit time, but only for files in that commit — a hook that reformats and passes is the proximate reason this went unnoticed.single_attribute_per_lineif the layout it produces is not worth enforcing. Also a legitimate answer; it is a preference, not a correctness rule.1 and 2 compose and are probably both wanted — 2 for the fast local signal, 1 so CI cannot be greener than a fresh
--reformat.The constraint any fix must respect
Whatever lands must not let djLint touch a
class="…"value.single_attribute_per_lineis layout inside the opening tag only; whitespace added inside a class value changes the rendered bytes and breaks the substring assertions the primitives parity tests depend on. That constraint is already documented inCLAUDE.mdand is the reason this rule needs a guard rather than a blanket "just run the formatter."Acceptance criteria
djlint --reformatwould rewrite fails the gate —just lint-templates, CI, or both.cottonwith--profile=django,jinjawith--profile=jinja --extension=jinja) — the drift appeared in both.CLAUDE.md's djLint section updated to say that check mode does not see reformat-only rules, since that is the non-obvious fact behind the whole issue.