build(deps): update dependency djlint to v1.46.1 - #439
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
6 times, most recently
from
July 19, 2026 01:09
3372780 to
5018dca
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
2 times, most recently
from
July 19, 2026 08:58
4649e0e to
a742216
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
2 times, most recently
from
July 20, 2026 03:52
5baf94f to
972ee2e
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
from
July 20, 2026 19:04
972ee2e to
e5a4b60
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
from
July 21, 2026 04:14
e5a4b60 to
ffaa138
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
from
July 22, 2026 16:35
ffaa138 to
e128124
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
from
July 23, 2026 23:45
e128124 to
cd69e80
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
5 times, most recently
from
July 25, 2026 21:40
6fc7e0b to
f05ac79
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
2 times, most recently
from
August 5, 2026 01:52
eed944b to
a12fce5
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
from
August 7, 2026 01:12
a12fce5 to
5c695d5
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
4 times, most recently
from
August 8, 2026 16:59
331f179 to
34385be
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
6 times, most recently
from
August 15, 2026 18:33
fdfdb0a to
6defbb8
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
6 times, most recently
from
August 23, 2026 22:54
7ff093b to
68ba9b6
Compare
renovate
Bot
force-pushed
the
renovate/djlint-1.x-lockfile
branch
7 times, most recently
from
August 30, 2026 22:27
afaf1f8 to
077f085
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.40.5→1.46.1Release Notes
djlint/djLint (djlint)
v1.46.1Compare Source
Fix
{# #}comment on a line no longer swallows everything back to the first one, so a tag written between two comments is formatted and linted like any other. Before, it kept lines past--max-line-lengthand hid findings from the rules. A comment now ends at its first#}, which is where django, jinja and nunjucks end it.v1.46.0Compare Source
Feature
T041reports an{% extends %}that is not the first tag in the template, which django refuses to compile and which leaks whatever text comes before it into the page. A{# #}comment before it is left alone, as is anything inside a{% comment %},{% raw %}or{% verbatim %}block, named or not, a{# djlint:off #}region or yaml front matter. An html comment is reported, since it is written into the page ahead of the parent template's doctype, and so is a branch tag on the django profile, where{% if x %}{% extends "a.html" %}{% endif %}does not compile; jinja documents that form and keeps it.T042reports text or html written after{% extends %}and outside every{% block %}, which the engine silently discards. A template tag there still runs and is left alone, as are comments and the body of a{% macro %}.T043reports a block name used more than once in a template, which Django, Jinja and Nunjucks all refuse to parse, even where the two blocks sit in different branches of an{% if %}. A{% blocktrans %}, a named{% endblock %}, a block inside a template comment, a{% comment %}block or a{% raw %}or{% verbatim %}body, and the blocks an{% embed %}fills in another template are left alone; a block inside an html comment or a<script>counts, since the engine still parses it.T044reports a statement keyword inside an output tag, such as{{ if x }},{{ url 'home' }}or{{ endif }}, where a{% %}block tag was meant. A bare keyword such as{{ url }}is an ordinary variable and is left alone, as is an expression that merely starts with one of the names, such as{{ url ~ "/x" }},{{ url ? url : '#' }}or{{ block ('title') }}, and so is the body of a{% raw %}or{% verbatim %}block, named or not.T045reports a statement tag, such as{% include %}or{% if %}, written inside an html comment, where it still runs. A value printed into a comment, as in<!-- built {{ version }} -->, is left alone, and so is a bare Go keyword such as<!-- period {{ start }} to {{ end }} -->, which is an ordinary variable under every other profile, and a{%under handlebars and golang, which have no such syntax. A tag inside a template comment, a{% comment %}block or a raw block is left alone whether it is written with whitespace control, tabs or a named closing tag, as is one inside an Internet Explorer conditional comment, in any case and closed by its<![endif]-->; one left unclosed is the ordinary comment a browser reads it as and is reported.H053reports anidused more than once in the file, which breaksgetElementById,<label for>and fragment links. Two ids in exclusive branches of one{% if %}are never both rendered and are not reported, whichever language writes the branch, and neither are two ids in separate<template>fragments; a value written by a template tag is left alone.H054reports an interactive element nested inside another, such as a<button>inside an<a href>or a link inside a button. An<a>without anhrefis not interactive and is left alone, as is a hidden input or one whose type a template tag writes.H055reports alangon<html>that is not a language tag, such aslang="english",lang="en_US"or a value that is only whitespace, whichH005reads as present. An empty value is left toH005, and so is a value written by a template tag or by a php short echo, as inlang="<?= $lang ?>", while a value that merely starts with$or{, such aslang="$LANG", is read as written. A>written inside a template tag ahead of the attribute, as in{% if a > b %}, does not hide it.H056reports an emptysrcon an element that fetches what it names, such as<img src="">or<script src=""></script>, which a browser resolves to the page itself. Asrcwith no value at all counts too, while an unquoted value such assrc=/static/logo.png, a value written by a template tag, a value that is only whitespace, and the separatesrcsetanddata-srcattributes are left alone.H057reports a<video>with no captions track, which WCAG 1.2.2 requires for prerecorded video with sound. A<track>of kindcaptionsorsubtitlescounts, as does one with nokind, since subtitles is the default, while a commented out track and one written inside an attribute value do not; amutedvideo is left alone, as is one whose tracks or attributes a template tag may write, meaning a real{{,{%,{#or${rather than the brace of a css value or the$of a jQuery handler or a price.--sarifwrites the findings as a SARIF 2.1.0 document, which GitHub code scanning, Azure DevOps and most editors read, so a run can be uploaded and kept in the Security tab with history rather than shown only as annotations on one pull request. With--check, a file that would be reformatted is reported under aformattingrule.Fix
<% %>or<%! %>code block is left as written, since its body is python rather than markup. Formatting re-indented it, flattening areturn "unit"inside anifto the start of the line and leaving python that no longer parses, and a tag written in a python string was read as markup, soH025,H054andT001reported findings inside these blocks. A<%def>body is markup and is still formatted and linted.H037no longer reads an unquoted attribute value as an attribute name, so<img width=1 height=1>is not reported as a duplicate1. This started in 1.45.0, and a real duplicate whose values are unquoted and start with/,.or#, as inhref=/a href=/b, is now caught too.v1.45.2Compare Source
Fix
{%-or-%}marker strips. The break normally renders the space itself, so djLint drops the space as redundant, but a stripped break renders nothing:{%- if args -%}, {% endif %}followed by{%- for %}lost the space between a macro's arguments.v1.45.1Compare Source
Fix
H037no longer reads a quoted string inside a template tag as an attribute name, sohref="{{ url "/a/b" "/a/c" }}"is not reported as a duplicatea. This started in 1.45.0.) }}to the start of the line.{{ function([nested(...)]) }}is no longer dedented by one level.{%- endif %}:</b>, keeps its own level instead of being indented one further.data-x='{{ f({ ... }) }}'no longer loses a space from every line.--single-attribute-per-linereaches attributes guarded by a template tag, so{% if x %} a="1" b="2" {% endif %}inside a tag no longer keeps them on one line past--max-line-length.--max-line-lengthis spread over several lines, where before only--max-attribute-lengthdecided. A line long because of its text is left alone, since breaking text would change what renders.<{{ tag }}>, is read as a tag. It was not recognised at all, so a template block among its attributes was pulled out of the tag and re-indented to the start of the line, and its attributes went unformatted and unchecked.v1.45.0Compare Source
Feature
H043reports a<button>written without atype. A type written inside a template block, as in<button {% if a %}type="button"{% endif %}>, counts.H044reports a header row holding boththandtdcells. The emptytdthat opens a two-axis table's header row is allowed.H045reports an<iframe>with no accessible name.title,aria-labelandaria-labelledbyall count, as does a name written by a template tag.H046reports a positivetabindex.0and-1are left alone, as is a value written by a template tag.H047reportsaria-hidden="true"on an element that takes focus. Hiding a decorative icon is not reported, nor is adisabledcontrol or one withtabindex="-1".H048reports anaria-attribute that ARIA does not define, such as a misspelledaria-lable. Framework bindings like:aria-labelare left alone.H049reports a viewport that stops the page being zoomed, byuser-scalable=noor amaximum-scalebelow 2.H050reports an element html no longer defines, such as<center>,<font>,<marquee>or<strike>. Only the opening tag is reported, and a custom element whose name merely starts with one, such as<font-picker>, is left alone.H051reports aroleARIA does not define for markup, such asrole="buton". The roles DPUB-ARIA and GRAPHICS-ARIA add count, abstract ones such aslandmarkdo not, and a value written by a template tag or a framework binding such as:roleis left alone.H052reports a<meta http-equiv="refresh">that reloads or redirects on a timer, which fails WCAG 2.2.1. A delay of zero is an immediate redirect rather than a timer and is not reported.--quote-style/quote_stylesets the quotes djLint writes inside template tags,double(the default) orsingle, andT002follows it, so{% include 'a.html' %}is no longer reported in a project that writes single quotes. Html attributes stay withH008.--sort-attributes/sort_attributesorders a tag's attributes by name, withidfirst andclasssecond. A tag whose attributes are guarded by a template tag, as in<div {% if x %}a="1"{% endif %} b="2">, keeps the order it was written in.--name-endblocks/name_endblockswrites the block's name into the{% endblock %}that closes it, where the block spans several lines, makingT003fixable by running the formatter. A block opened and closed on one line is left alone.--no-indent-inner-html/no_indent_inner_htmlleaves<head>and<body>at the same indent as the<html>that holds them, matching the default VS Code html formatter.--keep-br-inline/keep_br_inlinekeeps<br>on the line of the text it breaks instead of giving it a line of its own.<hr>is unaffected, and the default is unchanged.--prefer-configurationlets the file named by--configurationoverride the project's ownpyproject.tomlor.djlintrc, which have always won where the two set the same thing. The default is unchanged.H008asks, so<div class='a'>becomes<div class="a">. Only the names the rule reports are touched, and a value holding a double quote of its own keeps its single quotes.H010reports are lowercased by the formatter, so<div CLASS="a">is fixed rather than only reported. A name the rule does not know, such as an svgviewBox, keeps its case, and--ignore-caseturns it off.©becomes©, which is whatH023asks for. Entities that carry syntax or template meaning are left as written, as are<pre>,<textarea>,<script>and<style>bodies, and--no-entity-formattingturns it off.typethat html5 already assumes is dropped, asH024asks, so<script type="text/javascript">becomes<script>, and the same for<style>and a stylesheet<link>. A type that means something, such astype="module", is kept.methodis lowercased, somethod="POST"becomesmethod="post", which is whatH029asks for. A tag written inside a template tag's string is left alone.Changed
H031is gone: the keywords meta tag it asked for no longer affects ranking, and bing treats it as a spam signal.H035is gone;H017already coversmeta.H036reports only two uses of<br>: a run of two or more, and a break against the inside edge of a block element. Breaks that are part of the content, such as in a postal address, are left alone, and the rule is on by default.T002is on by default, and--reformatnow writes the quotes it asks for, rewriting tag arguments and conditions such as{% if x == 'a' %}to the--quote-stylein force. A string already holding the quote it would be rewritten to is left alone.T028is off by default: the whitespace it strips can be whitespace that renders, soalt="{%- if brand -%}Acme{%- endif -%} logo"comes out asAcmelogo. It stays available with--include=T028.H014counts blank lines the way the formatter does, so--max-blank-lines 2and--preserve-blank-linesno longer produce files the linter then rejects. A line holding only whitespace counts as blank, and the report points at the first blank line rather than the content line above it.H020leaves alone an element whose empty form carries meaning, such as a blank<option>holding a select open.H023no longer reports an entity for an invisible character, such as‌, in named, decimal or hex form.--ignore-caseapplies to the linter as well as the formatter, soH009andH010stay quiet when it is set.--profile=allhonours every profile'sexcludelist, soT028no longer fires on django markup to recommend{%- if -%}, which django rejects.Fix
<p title="a<br>b">is not reported: affectsD004,J004,H006,H011,H013,H017,H018,H019,H020,H021,H022,H036andH043.D004,H019andH021see attributes written after a template tag containing a>, so the inline style in<div {% if n > 5 %}id="a"{% endif %} style="color:red">is checked.<script>,<style>,<pre>and<textarea>, which used to be skipped along with the body, soH024,D004,H008,H010,H011,H012andH037can see their attributes. Only the body is skipped now, and its contents are never read as markup.D018andJ018no longer report a link that already uses a url tag, such as<a href="{% url 'profile' %}" data-src="lazy">; a value now has to look like a path./static/and/media/assets are left to{% static %}rather than reported as routes.H005reports<html lang="">, and its message asks for a non-emptylang.H005andH007ignore custom elements whose name starts withhtml, such as<html-midi-player>.H007reports a missing doctype in a file that opens with something it does not recognise, such as an<?xml ... ?>declaration.H008leaves single quoted values holding a double quote alone, such astitle='{% translate "Delete" %}'. An attribute that merely ends in a known name, such asdata-title, is no longer treated as that attribute.H009reports exactly the elements the formatter lowercases, so--reformatalways clears it:<IMG>,<INPUT>and<NAV>are now reported, andG,PATH,NAMEandCACHEare not. An uppercase name inside an attribute value, as in<p title="x <DIV y">, is no longer read as a tag.H012sees attributes written after a{{ ... }}in the same tag, so the spaced=in<div {{ attrs }} class = "x">is reported.H013accepts a valuelessalt, so<img src="a.png" alt>passes as the decorative imagealt=""already did.H016recognises a<title>however it is written, so<title id='page-title'>no longer reads as a missing title and an svg<title>no longer counts as the document's. The report points at the<html>tag.H022no longer reads anhttp://inside another attribute's value as a link, and no longer reports loopback or private hosts:localhost,127.0.0.1,192.168.x,10.xand.localor.testnames.H024covers<link rel="stylesheet" type="text/css">.H025no longer calls a tag an orphan in a handlebars or go template: a wrapper opened in one branch of{{#if}}...{{else}}...{{/if}}and closed in the other is accepted, as in django and jinja.H029reads only the form's ownmethodattribute, so<form data-method="POST">is not reported.H030stays quiet for a base layout that fills its description in per page, so a head using{% block meta %}is no longer reported.H033sees a form whose earlier attribute holds a>, as in<form x-show="count > 0" action=" /x/">.H037counts an attribute written without a value, so<input required required>is reported as the duplicate it is.H042leaves a label alone in a partial that holds no form control. A control that is commented out still counts, so the label above it is checked.T001andT027no longer read a delimiter inside a string as the end of the tag, so{{ x|default('}}') }}is reported neither as needing padding nor as holding an unclosed string. A string that really does run past the tag is still reported.T032flags extra whitespace in tags that hold a|,(,),:,?or%, which were previously skipped. A run of spaces inside a string is still content and is left alone.T034no longer flags a}%written inside a string, so{% trans "Save 50}% today" %}is left alone.T039no longer reports a valid block tag holding a nested mapping such as{% set a = {"x": {"y": 1}} %}, a shape--reformatitself produces.T040allows an empty literal that only feeds a filter, as in{% extends ""|default:"base.html" %}.<script>,<style>or<textarea>is left alone;var s = "<DIV CLASS=x>"is no longer rewritten to"<div CLASS=x>".H011asks, soclass=onebecomesclass="one". A value carrying a quote of its own, such asa=b'c, is still left alone.{% set %}or a function call keep their own quotes when they hold the other kind, so{% set s = 'say "hi"' %}is left as written instead of escaped.{{ }}stay where they are; the first is no longer pulled up against the opening bracket.{{ _("test")|upper }}keeps its shape.{{#if}}are no longer taken for the start of a Jinja comment, which left everything up to the next#}unformatted.+whitespace control marker is read wherever-is, so{%+ if x %}counts as a block tag,T038no longer misreports these blocks and the formatter indents them.{%that opens nothing no longer hides the markup after it: a page quoting template syntax in prose, as in<code>{%-</code>, is formatted rather than skipped down to the next%}.{%written inside javascript is no longer read as a template tag; a<script>holding'{%'and'%}'in its code used to leave its whole line unformatted.{% language 'de' %}text{% endlanguage %}, are recognised as balanced on a line too.<input id="a" type="checkbox">used to flip between spread and joined on every run.<script>or<style>is followed by text. Text sitting directly against the element, as ina<script>x</script>b, is still left alone, since a line break there would render as a space.<script>,<style>or<pre>, so the children of<a class="x">text<style>now sit inside it, and a closing tag written after the block's end tag gives back the level it took.<pre>,<textarea>,<script>or<style>opened and closed on one line no longer cancels a block opened earlier:<pre>x</pre><script>left the script's body indented as markup, and took a second run to settle.<pre>and<textarea>that looks like a djLint marker, such as{# djlint:on #}shown as sample code, no longer ends the verbatim block and walks its contents a level further right on every run.--preserve-leading-spaceno longer moves a line further right on every run, as it did for a multi-line{# ... #}comment and every other line inside an indented block.--preserve-leading-spaceno longer keeps a blank line on one run and drops it on the next when a<pre>or<textarea>is written with leading indentation;--blank-line-after-taghad the same drift from the second tag in its list onwards.--preserve-leading-space, the contents of a{{ if }}or{{ range }}block no longer lose an indent level when an already formatted go template is formatted again.--blank-line-before-tagno longer splits a line to place its blank line, so a tag written after other content, such as the{% block %}inside a one line{% set %}...{% endset %}, stays where it is.--blank-line-before-tagno longer inserts a blank line into an attribute value, which grew the file on every run.--blank-line-after-tagalready left attributes alone.djlint:offblock placed between a tag's attributes no longer crashes the formatter when it contains a backslash, and its text comes back exactly as written.--format-cssand--format-jsno longer indent a<style>or<script>body by the wrong amount when several files are formatted at once.djlint - --reformat --lintno longer writes its report into the file: the lint findings, the--statisticsblock and the--github-outputannotations go to stderr when stdout is carrying the formatted code. A lint-only run is unchanged.--github-outputannotations no longer land in the file either: in CI, where the flag turns itself on from$GITHUB_ACTIONS,cat f.html | djlint - --reformat > f.htmlwrote::warninglines intof.html.--statisticsprints its summary alongside GitHub annotations. It was dropped whenever the GitHub output was on, which happens by itself in a workflow.djlint -: a CRLF buffer piped to--reformatcame back LF throughout. Input that--require-pragmaskips is handed back byte for byte.<script>string was rewritten as a newline and broke the script.\U0001f622rather than an emoji.djlint . | head -1, is no longer a failure: it printed a traceback and exited120.djlint . templates/, is checked once, so it is no longer reported and counted twice or written twice under--reformat.custom_blocks,ignore_blocks,custom_html,blank_line_after_tagorblank_line_before_tag, as inignore_blocks = "raw,", is ignored instead of turning off template indentation altogether or padding every template tag in the file..gitignoreis read only when--use-gitignoreoruse_gitignoreasks for it, so a line djLint cannot parse, such as one ending in a backslash, no longer aborts every run in the project with a traceback.--require-pragmaskips a file whose first line it cannot decode instead of aborting the whole run. A file that is checked and turns out undecodable is still reported as a failure.--indent-jsand--indent-cssoverride the indent alone, leaving other beautifier settings in the config file'sjsorcssblock, such aswrap_line_length, in place.--ignoreand--includeaccept a space after the comma, so--ignore "H011, H013"no longer reportsH013.Performance
Docs
H026page no longer claims an emptyclassoridcannot be targeted: an attribute presence selector such asdiv[class]does match one, so removing the attribute can change how a page is styled.--github-output/--no-github-outputoverride that.--allow-empty-inputappears in the command line reference, which had been missing it.H042is no longer documented as off by default, which it stopped being in 1.42.1.T002is on by default.v1.44.2Compare Source
Fix
H037no longer reports two attributes whose names differ only before a.as duplicates (data-a.checkedanddata-b.checked, or alpine'sx-on:click.preventandx-on:keyup.prevent).data-altanddata-x.altleftH013silent on an image with noalt,data-langandxml:langsilencedH005,data-heightanddata-widthsilencedH006,data-name="description"silencedH030anddata-name="keywords"silencedH031, anddata-x.idsatisfied a<label for>forH042.title="alt=x"leftH013silent,class="language-en"silencedH005, andtitle="the ID=5"was reported byH010as an uppercase attribute name.H005no longer reports a tag whose name only starts withhtml, such as<htmlx>, and points at the<html>tag itself rather than at everything up to the last>in the file.v1.44.1Compare Source
Fix
<span>a</span><span> b </span>rendered asab,a{% if x %} b {% endif %}casabc), a space that shows nothing was added (<span> </span>became<span> </span>), and moving a tag onto its own line could add one (x<img>y, or across a comment as ina{# c #}<img>). Whitespace is now kept where it renders and dropped where it does not.titletooltip no longer loses a line and adata-value read by script no longer comes back different. Line breaks inclass,style,srcsetandsizesmean nothing and are still joined.<pre>and<textarea>is left alone when the closing tag has something after it on its line (<pre> a\n b</pre> tail).</b><i>) indents its contents again, and a line that closes more tags than it opens unindents even when a whole tag ends it (</b><small></small>). Both left the lines after them at the wrong level.--line-break-after-multiline-tagnow applies only to tags actually written over several lines, as its help says. It was holding back the content of every element, splitting tags that fit on one line.classvalue is tidied wherever it was written:class=" a b "becomesclass="a b". A tag whose attribute value holds a line break is spread over lines, since it cannot fit on one.v1.44.0Compare Source
Feature
--allow-empty-inputoption, and the matchingallow_empty_inputconfig key, exits0instead of2when the given paths match no files.Fix
{% if %}...{% endif %}no longer dedents everything that follows it by one level, collapsing nested structures toward column 0 - a regression in 1.43.0. A close tag already at the content level of the template block it sits in is held there, but the level it was denied was then taken off the end of the line instead, so{% if r %}</strong>{% endif %}moved the rest of the block left. The matching open tag never took a level to give back, since{% endif %}had already returned it.exclude,extend_exclude,use_gitignoreorrequire_pragmanow exits0instead of1. Skipping them is the configuration doing its job, and it is what letsexcludework under pre-commit, which passes the names of every staged file. Paths that match no files at all now exit2rather than1, so exit1means only that djLint found something to report.2instead of1, so a crash is no longer indistinguishable from a lint error. The traceback is still printed.--profile, orprofilein a config file, is now a usage error. A typo used to lint with a silently different rule set and exit0, and raisedKeyErrorwith--require-pragma.build.html/) is no longer picked up as a template and opened as a file, crashing the run.No files to check!is written to stderr instead of stdout, where formatted code is written.djlint - --reformatthat--require-pragmaskips is handed back byte for byte instead of being replaced byNo files to check!.v1.43.2Compare Source
Fix
blank_line_before_tagno longer inserts a blank line when the previous line opens a block and increases the indentation, e.g. between<div>and{% block %}. Since 1.41.0blank_line_after_taghas left the closing edge of a block alone ({% endblock %}before</div>), while the opening edge kept its padding, so a template using both options came out lopsided.v1.43.1Compare Source
Fix
H025no longer reports the closing tag of a multi-line<script>or<style>as an orphan - a regression in 1.43.0. A genuinely unmatched</script>is still reported.v1.43.0Compare Source
Feature
--stdin-filenameoption gives content piped in on stdin (djlint -) its real path, soper-file-ignoresmatches against that name and linter messages report it. Per-file ignores were previously dead for piped input, since nothing matches the name-. Path separators are normalized as they are for files on disk.Fix
title="{% translate "You don't have permission" %}") no longer swallows the rest of the document, which madeH025report every enclosing element as an orphan. A template tag in a value is now skipped whole unless it holds a>, so a quoted literal likea="{{"is still left alone.</span>tail<textarea>y</textarea>) unindents again; everything after it stayed one level too deep.{% endif %} <td class="x">y</td>) indents as a block tag again, so{% endif %}unindents and{% else %}aligns with its{% if %}. A line only takes that shape once the tag fits on one line, so reformatting an already formatted file moved it.</pre> <span>x) is tracked again; its closing tag took a level from a tag opened before the block, dedenting that tag's siblings.<div>{% if x %}), and the choice is no longer applied to the wrong block. Blocks were paired with the source by position, which does not line up with the expanded html; they are now matched by tag and contents.style,srcset,data-srcsetorsizesvalue was written over several lines is no longer spread over multiple lines and pulled back together on the next run.max_attribute_lengthis now measured against what is written out, not against padding that the rewrite drops.<pre>or<textarea>opened on a line that also holds a self-contained comment (<pre>x<!--c-->) is recognized as opening a verbatim block again. Its contents were re-indented instead of left alone, and the closing</pre>gained an indent level on every run - unbounded whitespace growth inside preformatted text.text <b>bold/</b> tail). The loss accumulated, so a document repeating that shape drifted further left with each occurrence. A closing tag with nothing to pair against still dedents as before.<inside a one-line<script>,<style>,<textarea>or<title>no longer counts as a tag when indenting.<script>var a = '<span>'</script>left a phantom open<span>on the tag stack, leaving everything after it one level too deep.text <b>bold/more</b> tailinside a<p>) - a regression in 1.40.8. The wrong output was idempotent, so it survived later runs.{{/* ... */}}is no longer read as a block close tag. It starts with{{/, the handlebars block-close prefix, so it popped a block off the stack:H037reportedDuplicate attribute found.for mutually exclusive attributes such as<a {{if .A}}href="a"{{else}}{{/* c */}}href="b"{{end}}>, and the formatter unindented the rest of the block. A comment renders as nothing, soH037no longer treats one as a template-generated attribute name prefix either.{% if x %}{# comment #}- was skipped by the linter, most visibly makingT038reportEnd tag has no matching block tagfor a balanced{% if %}. Affects every rule that skips ignored blocks (H025,H037,H041,H042,T002,T003,T027,T038,T039) and every kind of ignored block.djlint:offpragma no longer ignores the tag written immediately before it.<img>{# djlint:off #}silently dropped every error on that<img>, while<img>{# djlint:off H013 #}correctly reported it - a pragma covers what follows it, not what precedes it.v1.42.3Compare Source
Fix
-,.,:,@and*no longer stop a tag from being wrapped over multiple lines. The attribute parser now accepts any character HTML allows in an attribute name, so Alpine key modifiers (@keydown.prevent.?), Angular bindings ((click),[disabled]) and Vue shorthands (#slot) are formatted like every other attribute instead of leaving the whole tag on one long line. Angular bindings also reach--format-attribute-js-jsonfor the first time, which already listed them.src={{ MEDIA_URL }}/logo.png,href={{ .Permalink }}#{{ .Anchor }}) is no longer split into a truncated value plus a bogus standalone attribute when attributes are wrapped; it stays one value, quoted when spread.v1.42.2Compare Source
Fix
${...}inside a quoted value (e.g. JS template literals like:name="`x[${i}]`") respectmax_attribute_lengthagain and are spread over multiple lines - a regression in 1.40.6. Unquoted Mako-style${...}expressions in tags are still left unformatted.<!--that is not a real HTML comment (for example inside a{# ... #}template comment or inside a<textarea>/<pre>) no longer swallows the rest of the document. This fixes falseH025orphan-tag reports and over-indentation of the tags that follow - a regression in 1.40.6.{{{ ... }}}and raw-block{{{{ ... }}}}expressions used as tag attributes are tokenized correctly again, fixing falseH025orphan-tag reports - a regression in 1.40.6.data-x="{{") no longer makes the tokenizer scan into later content looking for a matching}}, which could collapse<pre>/<textarea>whitespace - a regression in 1.40.6.}}of a handlebars{{#if}}/{{#each}}block-open tag is now idempotent; it no longer leaks a trailing space into the following{{...}}tag on later formatting passes.T038no longer reports block tags that appear only inside a handlebars comment ({{!-- ... --}},{{! ... }}) or inside a handlebars raw block ({{{{raw}}}} ... {{{{/raw}}}}).T039no longer reports handlebars raw-block delimiters ({{{{raw}}}}/{{{{/raw}}}}) as unclosed template tags.<or dangling=) are now left untouched instead of having the unparsable characters silently dropped when attributes are wrapped.<used as a less-than operator inside a template expression in text or<script>content (e.g.${a<b},{{a<b}}) is no longer mistaken for an HTML tag start, which could merge or drop following content and break idempotency - a regression in 1.40.6.:or/(e.g.href=https://example.com/page) are no longer split into a truncated value plus a bogus standalone attribute when attributes are wrapped - a regression in 1.40.6.="value"attribute is no longer rewritten with the literal attribute nameNone; malformed attributes are left untouched.<textarea>/<pre>is preserved instead of being collapsed by whitespace cleanup (it is verbatim content).Performance
{% comment %},{% blocktrans %},{% filter %},<pre>,<script>, etc.) is dramatically faster on templates with many{% ... %}tags. A lazy[ ]*?before the block keywords caused pathological backtracking; the equivalent greedy[ ]*removes it, cutting reformat time on large template-heavy files by roughly 5x.v1.42.1Compare Source
Fix
command,keygenandmenuitem- elements that were removed from the HTML standard.Changed
Linter rule defaults were reviewed against a simple bar: on by default means correctness, security, clear accessibility, or a consistency check the formatter also enforces - with near-zero false positives. Four rules moved to opt-in (
--include=...):{% endblock %}; the name demand is a style preference. The correctness checks T003 used to bundle - unclosed{% block %}, orphan{% endblock %}and mismatched endblock names, all hard template errors - moved into T038, which stays on by default, so nothing real is lost when T003 is off.aspect-ratio, preventing layout shift) but performance rather than correctness, and the dimensions are frequently unknowable in a template - user uploads, CMS urls, art-directed<picture>sources - so the rule demands data the author may not have.--include=H031.{{ ... }}output (form widgets),{% include %}/{% extends %}or unrecognized template tag silences the rule for that file, so where it does run, every report is a genuinely broken label association (a WCAG 1.3.1/4.1.2 failure the W3C validator also treats as an error).v1.42.0Compare Source
Feature
Template languages:
askamaprofile for Askama (jinja-style templates in Rust). Rust expressions are never reformatted: function and{% set %}/{% let %}formatting are disabled sosome_macro!("foo")?, char literals'a'and tuples keep their exact spelling, and string quotes are never rewritten. The Flask-specificurl_forrules (J004/J018) don't apply.teraprofile for Tera (Rust, used by Zola): jinja-style formatting plus Tera v2{% component %}/{% endcomponent %}blocks and single-tag{% set_global %}. The Flask-specificurl_forrules don't apply. MiniJinja needs no profile of its own - it is fully Jinja2-compatible, use--profile=jinja.liquidprofile for Liquid (Shopify themes, Jekyll, Eleventy, the Rustliquidcrate).{% case %}/{% when %},{% capture %},{% tablerow %},{% form %},{% paginate %},{% highlight %}and{% unless %}/{% elsif %}indent correctly,{%- -%}whitespace control is handled, and the bodies of Shopify section tags ({% schema %},{% style %},{% javascript %},{% stylesheet %}) are left untouched - they contain JSON, CSS or JS rather than html.golangprofile now indents template blocks:{{ if }},{{ range }},{{ with }},{{ block }}and{{ define }}indent their contents up to the matching{{ end }}, with{{ else }}/{{ else if }}as branches and the{{- -}}whitespace-control forms included. Blocks opened and closed on one line are left alone; single tags like{{ template }}and lookalike variables such as{{ .end }}are unaffected.New linter rules:
{% extends %}or{% include %}with a missing or empty template name - an error the engine only raises at render time, so the typo is easy to ship.{% block %}and closed in a different one. The pair looks balanced in the file, but a child template overriding either block renders unbalanced html.--include=H018): void tags closed with/>instead of>, e.g.<br/>- the trailing slash has no effect in HTML. The opposite convention of the optional H017 ("void tags should be self closing"); enable one or the other, not both.--include=H042): a<label for="...">whose value matches no elementidin the same file. Template-generated values are skipped; the rule is opt-in because inputs rendered by e.g.{{ form.email }}carry ids the linter cannot see.Configuration:
indentandmax_line_lengthnow fall back toindent_sizeandmax_line_lengthfrom a.editorconfigat the project root. The command line and djlint config files still take precedence, and only sections applying to html (or the configuredextension) are read.Documentation:
Fix
<cola>(matched by a brokencolgroupexclusion) and custom elements like<img-icon>are no longer reported.<meta>tags, missing from the rule's void tag list, are now reported.v1.41.0Compare Source
Feature
{% if %}without{% endif %}, handlebars{{#if}}without{{/if}}, end tags with no opening tag, and crossed blocks like{% if %}{% for %}{% endif %}. Tags fromcustom_blocksare checked too;{% block %}/{% endblock %}pairs stay covered by T003.{% url 'x" user.url }}(closed by}}instead of%}),{{ user.name }(missing a brace), or a tag cut off by the next tag or the end of the file. Complements T027 (unclosed string in a complete tag) and T034 (}%typo), which keep reporting their own cases.--rules FILECLI option: load a custom rules file in.djlint_rules.yamlformat from any path, instead of only next topyproject.toml.Changed
{% if abc == 101 %}becomes{% if abc == 101 %}. This fixes what rule T032 reports, so the linter and formatter no longer conflict. Whitespace inside string literals is preserved, including strings with backslash-escaped quotes; multiline tags, ignored blocks, the literal contents of{% verbatim %}/{% raw %}and the handlebars/golang profiles are untouched.excludelist is now tailored to djLint instead of copying ruff/black. Added directories that hold generated or third-party HTML:htmlcov(coverage.py reports),site-packages(installed packages' templates such as Django admin and DRF, matched in any virtualenv layout) and_site(Jekyll/Eleventy output). Removed Python tool caches and editor config that never contain HTML:.ipynb_checkpoints,.mypy_cache,.pytest_cache,.pytype,.ruff_cache,.pants.d,.vscodeandbuck-out.Fix
Formatter indentation:
<div>rendered by{% if %}...{% endif %}and closed by a later conditional) no longer shift the indentation of everything after it. When every branch of an{% if %}/{% elif %}/{% else %}shifts the depth equally, e.g. a<tr>opened in both branches, the shift is kept after{% endif %}.{% story ... with { ... } %},{% include ... with { ... } %}and non-JSON{{ func(...) }}calls are now indented by bracket depth.{% endtrans %}(Jinja/Twig block{% trans %}) no longer decreases the indentation level, which shifted the{% endtrans %}line and everything after it one level to the left.{% set %}objects nested inside HTML elements are no longer over-indented in proportion to their nesting depth.{% component "calendar" date="2015-06-19" / %}withcustom_blocks = "component") no longer indent the lines that follow them as if a block had been opened.Formatter line breaks and spacing:
{% set x %}...{% endset %}is no longer expanded onto multiple lines. The block captures its content verbatim, so the added whitespace changed the value of the variable. Authored multi-line set blocks are still indented as before.{{ ... }}function calls, a call passed as an argument no longer causes a stray space before the following comma, and the arguments after it keep the same indentation as the other arguments.blank_line_after_tagno longer inserts a blank line when the next line closes a block and decreases the indentation, e.g. between{% endblock %}and</div>.blank_line_before_tagnow inserts the blank line above a comment directly preceding the tag, keeping the comment attached to the tag it documents.Linter:
<slot></slot>: an empty slot element is the standard way to declare a default slot outlet.{% if %}/{% else %}and closed once outside it (and vice versa for close tags), since only one branch renders.<b>in<h1>blah <b>bold</h1>.{% endblock %}is on the same line as its{% block ... %}, e.g.{% block title %}{% endblock %}. The formatter keeps such blocks on one line, so the linter and formatter no longer conflict.{% verbatim %}...{% endverbatim %}blocks, matching the existing treatment of jinja{% raw %}blocks.Configuration:
ignore,include,custom_blocks,custom_html,exclude,extend_exclude,ignore_blocks,blank_line_after_tag,blank_line_before_tag) can now also be given as lists, e.g.ignore = ["H017", "H031"]inpyproject.toml; previously list values were silently ignored.--max-blank-linesgiven on the command line is no longer overridden by the config file, matching all other options.v1.40.10Compare Source
Fix
AttributeError: attribute 'reformat' of 'Config' objects is not writablewhen linting or formatting multiple files, andAttributeError: attribute 'start' of 'TagToken' objects is not writablewhen processing a file.v1.40.9Compare Source
Fix
{% cache %},{% timezone %},{% localtime %}and{% localize %}blocks instead of dedenting everything after them.<c-card>and<c-forms.input />as block HTML tags without requiringcustom_htmlconfiguration.<b>bold</b><span> </span><i>italic</i>keep rendering a space; non-collapsible whitespace such as U+2005 is kept verbatim._attribute values, where a newline separates commands and--comments run to the end of the line.classandstylevalues are spread over multiple lines withformat_attribute_template_tags.{% comment %}block content untouched when reformatting, e.g. bare URLs ending in/>.djlint:off RULEsuppression to any finding overlapping the region, so reformatted guards keep linting clean.{% if x %}data-{% endif %}srcset.v1.40.8Compare Source
Fix
idorclassis followed by a spaced equals sign.embedblocks.excludeandextend_excludefor explicitly provided files.Configuration
📅 Schedule: (in timezone Africa/Lusaka)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.