thibaudcolas / curlylint Goto Github PK
View Code? Open in Web Editor NEWExperimental HTML templates linting for Jinja, Nunjucks, Django templates, Twig, Liquid
Home Page: https://www.curlylint.org/
License: MIT License
Experimental HTML templates linting for Jinja, Nunjucks, Django templates, Twig, Liquid
Home Page: https://www.curlylint.org/
License: MIT License
I have a block of code which is triggering #23.
<span data-{{ triggers-issue}}>Hello, world!</span>
Before that issue is being fixed, I'd like to be able to just exclude that block from linting using something like a "noqa" comment.
I'm not sure what would work; perhaps something like the following?
{# curlylintignore #}
<span data-{{ triggers-issue}}>Hello, world!</span>
{# endcurlylintignore #}
I can ignore the entire file, but I'd like to be able to lint the rest of the file.
When running curlylint on a basic html template I noticed that the "<!doctype html>" was causing false positive Bad indentation and parent inline element issues. Once I commented out the "<!doctype html>" all tests passed.
"<!doctype html>"
Notices other blogs were taking the same steps I did
Windows 2012R2
Curlylint ver => 0.13.0
Python ver 3.7.6
(Write your steps here:)
You should see different results based on the state of the <!doctype html> tag
Curlylint wants a space after {% endif %}
. But this seems valid scenario to me:
<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}"></form>
It raises:
Parse error: expected one of '>', '\\s+', '{#', '{%', '{{' at 45:70 parse_error
Curlylint is okay when 'shifting' the white:
<form{% if has_file_field %} enctype="multipart/form-data"{% endif %} action="{{ form_url }}"></form>
I used curlylint, version 0.12.0
Trying out curlylint, using it in pre-commit rev: "v0.13.1"
Im editing some jinja2 templating file. In it I have a block
...
{% for xyz in xyzs %}
<do>stuff</do>
{% endfor %}
curlylint now complains:
Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with' at 24:5 parse_error
jinja2 of course renders just fine.
for now I'll stop using it. Might drop in later again. In case you need more info let me know
An unmatched HTML tag inside a {% comment %}
block raises the error
Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with'
.
comment, parse error
#74 is similar but not identical.
curlylint 0.13.1, python 3.11.1, MacOS 11.7.3
Create a new folder containing a file test.html
:
{% comment %}
there is an <interesting> tag here
{% endcomment %}
Run curlylint --parse-only .
Linting should pass with no errors
Error reported:
test.html
2:3 Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with' at 2:3 parse_error
Oh no! π₯ π π₯
1 error reported
It would be great to have the ability to exclude some folders/files. For example, being able to run something like
python3 -m curlylint . --exclude some_folder
Add an option exclude
that will remove folders/files from the linter
(Write your answer here.)
(Write your answer here.)
Yes
The linting can fail on certain complex lines, like for example our (valid) usage of mail command for bareos backups in a template file:
"/usr/lib/bareos/bsmtp -h localhost -f \"\(Bareos\) \<%r\>\" -s \"Bareos: %t %e of %c %l\" %r"
Taken from: https://docs.bareos.org/Configuration/Messages.html#config-Dir_Messages_MailCommand
Im not sure how to format the line above (or even if it is possible) so that the linter accepts it..
but I do know that the template and command works..
So I would like the possibility to skip this linting.
Just skipping the/a line, not skipping it for the whole 200+ lines file as linting still is good here.
Either skipping curlylint completely or just this rule.
For example with a # noqa ...
line above the one you want to skip or something similar.
In Django at least, libraries can come with their own block-level tags. curlylint expects content in these tags to be indented to the same level as the tags themselves. I think we can agree that this behaviour is weird.
The better question is what else to expect. I could see both "enforce no indentation levels for unknown block tags" (because they may be whitespace-sensitive) and "enforce an additional indentation level" (as with tags such as {% block %}
.
test.html
:
{% blocktrans %}
sdf
{% endblocktrans %}
{% someblock %}
sdf
{% endsomeblock %}
If you run curlylint --rule "indent: 4" test.html
:
test.html
0:0 Bad text indentation, expected 0, got 4 indent
Oh no! π₯ π π₯
1 error reported
Despite the reported line number, this refers to the indentation in someblock
β if you remove someblock
, the error goes away, if you remove blocktrans
, the error remains unchanged.
Side note, because I keep opening issues: This is a great project and I am extremely happy to have found it. Thank you for providing and maintaining it!
Self closing tags which are valid HTML/XML are throwing off the linter.
self closing tag
(Write your steps here:)
my.xml
with the following content
<foo>
<bar />
</foo>
curlylint my.xml --rule 'indent: 2'
All done! β¨ π° β¨
my.xml
1:7 Parse error: expected one of '>', 'attribute', '{#', '{%', '{{' at 1:7 parse_error
To be noted, if you change the file content to:
<foo>
<bar></bar>
</foo>
the linter won't report any error (as expected).
Parsing fails for {% comment %}
including number within HTML tag.
OSX 12.6
Python 3.10.6
curlylint 0.13.1
<div
{% comment %}
1
{% endcomment %}
></div>
Should pass, similarly to this version, without a number (which passes as expected):
<div
{% comment %}
A
{% endcomment %}
></div>
Fails with:
$ curlylint --verbose /project/template.html
Identified project root as: /project
Analyzing file content from stdin
Files being analyzed:
/project/template.html
/project/template.html
2:8 Parse error: expected one of '>', 'attribute', '{#', '{%', '{{' at 2:8 parse_error
I've been hoping to find a templating equivalent of Black for quite a while. Could automatic formatting fit this project?
I get a parse error when I don't believe one should happen. I don't really know what it's having an issue with though so unfortunately I can't be more descriptive.
Tried searching for "comment", but switching the comment to an if
gave the same issue so I'm unsure the problem.
curlylint==0.12.2 parsy==1.1.0 pathspec==0.8.1
attrs==19.3.0 click==7.0 toml==0.10.0
Python 3.8.3 on Mac OS 10.13.6
I reduced my template to the smallest example that still exhibited the issue:
{% if page_type %}
{% comment %} some comment {% endcomment %}
<div>
{% endif %}
{% if page_type %}
</div>
{% endif %}
If I remove the {% comment %}
line than it passes as valid. If I change the comment to an if
block I still see the issue. Single line {# #}
also has the issue.
Should clear as valid
3:3 Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with' at 3:3 parse_error
I tried using curlylint on a project that uses Jinja's i18n extension. Without configuring or changing anything, I would get failures like this:
$ cat test.html
{% trans %}
project
{% pluralize %}
projects
{% endtrans %}
$ curlylint test.html
test.html
2:3 Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with' at 2:3 parse_error
Oh no! π₯ π π₯
1 error reported
I couldn't find any documentation about configuring support for custom elements.
In order to get this to work, I had to a) read the source code to determine if this was possible b) add the following to my pyproject.toml
:
[tool.curlylint]
jinja_custom_elements_names = [['trans', 'pluralize', 'endtrans']]
Ideally jinja_custom_elements_names
would be documented / officially supported. The format (a list of lists) should also be explained -- it seems that order is important.
I also discovered that with a sufficiently large directory of templates, naively adding a string instead of a list, e.g.:
[tool.curlylint]
jinja_custom_elements_names = ['trans']
would result in a significant (exponential?) increase in runtime, and should probably be guarded against.
Indentation rules are applied inside <pre>...</pre>
blocks
"pre"
Python 3.8
curlylint==0.12.0
If I run curlylint --rule 'indent: 2'
on a snippet like
<pre class="highlight"><code>SELECT
pid,
(CURRENT_TIMESTAMP - query_start) as query_time,
datname,
usename,
query
FROM pg_stat_activity
ORDER BY query_time DESC;
</code></pre>
curlylint wants me to change it to
<pre class="highlight">
<code>
SELECT
pid,
(CURRENT_TIMESTAMP - query_start) as query_time,
datname,
usename,
query
FROM pg_stat_activity
ORDER BY query_time DESC;
</code>
</pre>
to resolve the indent errors. Doing this changes the meaning/display of this snippet from
SELECT
pid,
(CURRENT_TIMESTAMP - query_start) as query_time,
datname,
usename,
query
FROM pg_stat_activity
ORDER BY query_time DESC;
to
SELECT
pid,
(CURRENT_TIMESTAMP - query_start) as query_time,
datname,
usename,
query
FROM pg_stat_activity
ORDER BY query_time DESC;
Don't enforce indentation rules inside <pre>...</pre>
blocks
0:5 '<code>SELECT\n pβ¦' should be on the next line indent
0:11 Bad text indentation, expected 4, got 2 indent
0:11 Bad text indentation, expected 4, got 0 indent
8:0 Bad indentation, expected 2, got 0 indent
8:7 '</pre>' should be on the next line indent
Cannot run curlylint
with the latest version of click
. This is similar to psf/black#2964. Workaround is to pin click<8.1.0
.
ImportError: cannot import name '_unicodefun' from 'click'
Python 3.8
Install from pip with python3 -m pip install curlylint
, observe failure.
james@gazelle ξ° /tmp/curlylint ξ° python3 -m virtualenv .
created virtual environment CPython3.8.10.final.0-64 in 270ms
creator CPython3Posix(dest=/tmp/curlylint, clear=False, no_vcs_ignore=False, global=False)
seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/james/.local/share/virtualenv)
added seed packages: pip==22.0.4, setuptools==60.9.3, wheel==0.37.1
activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator
james@gazelle ξ° /tmp/curlylint ξ° source bin/activate
james@gazelle ξ° 3.8.10 ξ° /tmp/curlylint ξ° python3 -m pip install curlylint
Collecting curlylint
Downloading curlylint-0.13.0-py3-none-any.whl (51 kB)
ββββββββββββββββββββββββββββββββββββββββ 51.9/51.9 KB 1.7 MB/s eta 0:00:00
Collecting toml>=0.9.4
Using cached toml-0.10.2-py2.py3-none-any.whl (16 kB)
Collecting attrs>=17.2.0
Using cached attrs-21.4.0-py2.py3-none-any.whl (60 kB)
Collecting click>=6.5
Using cached click-8.1.0-py3-none-any.whl (96 kB)
Collecting pathspec<1,>=0.6
Using cached pathspec-0.9.0-py2.py3-none-any.whl (31 kB)
Collecting parsy==1.1.0
Using cached parsy-1.1.0-py3-none-any.whl (6.9 kB)
Installing collected packages: parsy, toml, pathspec, click, attrs, curlylint
Successfully installed attrs-21.4.0 click-8.1.0 curlylint-0.13.0 parsy-1.1.0 pathspec-0.9.0 toml-0.10.2
james@gazelle ξ° 3.8.10 ξ° /tmp/curlylint ξ° touch blah.html
james@gazelle ξ° 3.8.10 ξ° /tmp/curlylint ξ° curlylint
Traceback (most recent call last):
File "/tmp/curlylint/bin/curlylint", line 8, in <module>
sys.exit(patched_main())
File "/tmp/curlylint/lib/python3.8/site-packages/curlylint/cli.py", line 301, in patched_main
patch_click()
File "/tmp/curlylint/lib/python3.8/site-packages/curlylint/cli.py", line 291, in patch_click
from click import _unicodefun # type: ignore
ImportError: cannot import name '_unicodefun' from 'click' (/tmp/curlylint/lib/python3.8/site-packages/click/__init__.py)
Curlylint runs successfully
ImportError: cannot import name '_unicodefun' from 'click' (/tmp/curlylint/lib/python3.8/site-packages/click/__init__.py)
parse.py
contains the following on line 565 at time of writing:
yield P.fail("expected `{% if " + content + " %}`")
Some HTML input can cause content
to be of type Parser
not str
, causing the error in the title.
I suspect there are two bugs here:
content
can change seems to indicate a deeper bug than I'm able to understand at the moment. I think pulling at that thread will help with the "proper" fix"concatenate"
I have two samples:
Write the below to example.html
and then curlylint example.html
with no other config
{% for area_url, area_name in areas %}
{% if forloop.first %}
<ul>
{% endif %}
<li><a href="{{ area_url }}">{{ area_name }}</a></li>
{% if forloop.last %}
</ul>
{% endif %}
{% empty %}
<p>
No areas found of type {{ area_type.name }}.
</p>
{% endfor %}
{% for area_url, area_name in areas %}
{% if forloop.first %}
<ul>
{% endif %}
{% endfor %}
In this example, the <ul>
is opened but not closed, however I don't think this should be a linting error...as you can see from the above example, it is closed later in the template.
(None of this is to say that the template is good, but I don't think it should raise this exception!)
For sample 1, I think it shouldn't blow up. I fixed this by adding str()
around content
, but like I say, I think we should understand why content
isn't a string already, like it's clearly expecting.
For sample 2: this might be more complex and could be punted to a different issue, but I don't think it should error.
To be clear in example 2, the error is "correct" in that I get
curlylint example.html
example.html
4:3 Parse error: expected one of 'autoescape', 'block', 'blocktrans', 'comment', 'filter', 'for', 'if', 'ifchanged', 'ifequal', 'ifnotequal', 'not an intermediate Jinja tag name', 'spaceless', 'verbatim', 'with' at 4:3 parse_error
Oh no! π₯ π π₯
1 error reported
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
actions/cache
, actions/checkout
, actions/setup-node
, actions/setup-python
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/workflows/ci.yml
actions/checkout v3
actions/setup-node v3
actions/cache v3
actions/checkout v3
actions/setup-python v3
actions/checkout v3
actions/setup-python v3
package.json
prettier 2.6.1
website/package.json
.nvmrc
node 15
website/.nvmrc
node 15
requirements.txt
black ==22.3.0
flake8 ==4.0.1
mypy ==0.812
pytest ==7.0.1
coverage ==6.3.2
memory-profiler ==0.58
setup.py
parsy ==1.1.0
attrs >=17.2.0
click >=6.5
toml >=0.9.4
pathspec >=0.6, <1
dataclasses >=0.6
I tried curlylint on our set of Django templates, and it stumbled over some things I cannot really explain. One example is this template:
curlyprint complains:
aleksis/core/templates/dynamic_preferences/sections.html
12:2 Parse error: expected 'li' at 12:2 parse_error
It shows similar errors for other templates, but this is a very simple one.
"parse", mainly.
I am not sure what Draft.js has to do with this, neither what relevance my browser has to do with it, as I run curlylint on the shell.
I use curlylint 0.12.0 from PyPI under Python 3.9 on Debian bullseye/sid.
pip3 install curlylint
wget https://edugit.org/AlekSIS/official/AlekSIS-Core/-/raw/d579eec21675787347c7e7d4c2862d9d75030b0a/aleksis/core/templates/dynamic_preferences/sections.html
curlylint sections.html
Template is lint-clean.
curlylint throws above parse error.
{% load i18n %}
<ul class="tabs">
<li class="tab ">
{% for section in registry.section_objects.values %}
<li class="tab">
<a class="{% if active_section == section.name %}active{% endif %}"
href="{% url registry_url section.name %}"
target="_self">
{{ section.verbose_name }}
</a>
</li>
{% endfor %}
</ul>
Running curlylint
on the following example Django template throws an exception. It appears that having an un-closed tag inside of the if
statement causes an issue for curlylint. While probably not a great practice (there are other ways to achieve the same result) it came as a surprise that it wouldn't even parse it.
{% for thing in things %}
{% if forloop.first %}
<ul>
{% endif %}
<li>{{ thing }}</li>
{% if forloop.last %}
</ul>
{% endif %}
{% endfor %}
I looked through all of the open and closed issues.
Python 3.6.6
curlylint 0.12.0
Parse and lint the template without throwing an exception.
Exception thrown:
File ".venv/lib/python3.6/site-packages/parsy/__init__.py", line 275, in seq_parser
result = parser(stream, index).aggregate(result)
File ".venv/lib/python3.6/site-packages/parsy/__init__.py", line 80, in __call__
return self.wrapped_fn(stream, index)
File ".venv/lib/python3.6/site-packages/parsy/__init__.py", line 338, in generated
next_parser = iterator.send(value)
File ".venv/lib/python3.6/site-packages/curlylint/parse.py", line 541, in opt_container_impl
yield P.fail("expected `{% if " + content + " %}`")
TypeError: must be str, not Parser
I can fork this repo and add a sample template to the tests directory if that is helpful. Or create a minimal repo demonstrating the issue. Let me know which might be the most useful!
To directly closing some svg tags (at least <circle .../>
) is not allowed:
<svg width="20" height="20">
<circle cx="10" cy="10" r="10" stroke-width="1" stroke="black" fill="{{ entry.getStatusColor() }}" opacity="0.5" />
</svg>
this error is reported:
tmp/xxx.html.twig:2:117 Parse error: expected one of '>', 'attribute', '{#', '{%', '{{' at 1:117
In case the standard forbids this, I am fine. But for me https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle looks like it is allowed.
So I suppose to not report this as failure.
--
--
All line numbers in the stylish
and json
report format are off by one, reporting line 0 when the actual issue is on line 1. In the compact
export format, both versions of the line number are reported.
Create a test.html
with this content:
<form></div>
For reference, I also tested this with indent errors by running against a file containing just <div></div>
. The same issue occurs, but doesn't illustrate the issue with mixed content in some error messages.
Run curlylint test.html
. The output reports line number 0:
test.html
0:8 Parse error: expected 'form' at 0:8 parse_error
Oh no! π₯ π π₯
1 error reported
Run curlylint --format json test.html
. The output reports line number 0:
[{"file_path": "test.html", "line": 0, "column": 8, "message": "Parse error: expected 'form' at 0:8", "code": "parse_error"}]
Oh no! π₯ π π₯
1 error reported
Run curlylint --format compact
. The output reports line number 1 and line number 0:
test.html:1:8: Parse error: expected 'form' at 0:8 (parse_error)
Oh no! π₯ π π₯
1 error reported
Consistent reporting of line numbers, preferably 1-indexed. π
Behaviour is buggy/mixed, primarily 0-indexed, as described above. Sorry, no screenshots, but I pasted the output.
As above. Your issue template indicates that I should link a project for this, which I can do, if the one-line test.html
is insufficient. Please let me know, in that case.
The compact
method casts its contents to str
(1), which comes down to the IssueLocation
class, which includes a +1
in its str() method. The other two formatters don't adjust the internal line number at all.
The issue of the mixed message in the compact
report seems to sit deeper, as it's due to the issue message, which is constructed in each rule.
When fetching the sdist from PyPI, the tests fail due to missing resources.
[ 38s] _________ ERROR collecting curlylint/rules/aria_role/aria_role_test.py _________
[ 38s] curlylint/rules/aria_role/aria_role_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/aria_role/aria_role_test.json'
[ 38s] _ ERROR collecting curlylint/rules/django_forms_rendering/django_forms_rendering_test.py _
[ 38s] curlylint/rules/django_forms_rendering/django_forms_rendering_test.py:8: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/django_forms_rendering/django_forms_rendering_test.json'
[ 38s] _____ ERROR collecting curlylint/rules/html_has_lang/html_has_lang_test.py _____
[ 38s] curlylint/rules/html_has_lang/html_has_lang_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/html_has_lang/html_has_lang_test.json'
[ 38s] _________ ERROR collecting curlylint/rules/image_alt/image_alt_test.py _________
[ 38s] curlylint/rules/image_alt/image_alt_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/image_alt/image_alt_test.json'
[ 38s] _____ ERROR collecting curlylint/rules/meta_viewport/meta_viewport_test.py _____
[ 38s] curlylint/rules/meta_viewport/meta_viewport_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/meta_viewport/meta_viewport_test.json'
[ 38s] ______ ERROR collecting curlylint/rules/no_autofocus/no_autofocus_test.py ______
[ 38s] curlylint/rules/no_autofocus/no_autofocus_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/no_autofocus/no_autofocus_test.json'
[ 38s] _ ERROR collecting curlylint/rules/tabindex_no_positive/tabindex_no_positive_test.py _
[ 38s] curlylint/rules/tabindex_no_positive/tabindex_no_positive_test.py:9: in <module>
[ 38s] class TestRule(unittest.TestCase, metaclass=RulesTestMeta):
[ 38s] curlylint/rules/rule_test_case.py:23: in __new__
[ 38s] fixtures = json.loads(open(tests["fixtures"], "r").read())
[ 38s] E FileNotFoundError: [Errno 2] No such file or directory: '/home/abuild/rpmbuild/BUILD/curlylint-0.12.0/curlylint/rules/tabindex_no_positive/tabindex_no_positive_test.json'
Thanks for the neat tool!
I've run into an issue with jinja2 when close a html tag inside of a jinja2 if statement. Something simple like this -
<!DOCTYPE HTML>
<div>
{% if a == 1 %}
</div>
<h1>a</h1>
<div>
{% endif %}
</div>
will produce this error:
test.html 3:9 Parse error: expected one of '[:a-zA-Z]', 'animate', 'animateMotion', 'animateTransform', 'area', 'base', 'br', 'circle', 'col', 'ellipse', 'embed', 'feBlend', 'feColorMatrix', 'feComposite', 'feConvolveMatrix', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpotLight', 'feTile', 'feTurbulence', 'hr', 'image', 'img', 'input', 'line', 'link', 'meta', 'mpath', 'param', 'path', 'polygon', 'polyline', 'rect', 'script', 'set', 'source', 'stop', 'style', 'track', 'use', 'wbr', '{#', '{%', '{{' at 3:9 parse_error
I'm on a Mac using python 3.9 w/ the latest version of curlylint.
curlylint test.html
The general syntax validation seems to work well up until this step. Possible could the template tags be stripped out for this particular test? Or allow close / open tags out of sequence inside an if statement?
Or ideas for a better way to write jinja are also welcome :)
Thanks!
I'd like to easily and automatically lint my Jinja2 templates
GitHub has recently introduced a Super Linter which is basically a collection of linters for common languages that are packaged in a Docker file that can be run from a GitHub Action to lint all your code quickly and easily without having to install packages.
It would be great if CurlyLint could be added to that. It would make it easier for people to use it and also greatly increase the visibility of this project.
Installing locally works but would prefer to do it via the GitHub Super Linter.
They give instructions on how to add linters here: https://github.com/github/super-linter/wiki/Adding-new-language-support. Could have a go at adding it myself (and will do if you don't have time and are happy to add this), but thought it might be better coming from the maintainer of this project in case they have any questions or want any changes to allow it to be added.
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
template:
<div {{ name }}="value"></div>
0:15 Parse error: expected one of '>', '\\s+', '{#', '{%', '{{' at 0:15 parse_error
This seems like a reasonable (albeit slightly unusual) template.
looked at all open and closed issues
(Write your answer here if relevant.)
$ curlylint --version
curlylint, version 0.12.0
When writing a Jinja2 template, using the expression if foo is None:
does not trigger a linter error, so we only find out about it during runtime, aka TemplateRuntimeError
Ref: https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.TemplateRuntimeError
Writing Python, it's common to use the if foo is None:
syntax, and sadly curlylint didn't catch this before I deployed to prd and learned the hard way.
is None
curlylint 0.13.1, running in either macOS or Linux.
I don't know if prior versions detected this, as it's new code we wrote and linted with the current version.
{% if foo is None: %}
foo is None!
{% endif %}
curlylint
against that fileI would have expected that the linter would fail, and hopefully suggest that I use the valid lowercase none
is the right way to use this comparison.
Passes with no errors:
$ curlylint broken.html
All done! β¨ π° β¨
See steps above for file content that demonstrates issue.
I found this while using None
, but the same would apply for True
and False
.
Some links:
Yes
I would like to indent inside template tags
setting curlylint --rule 'indent: 4'
Given this code:
{% extends 'home/base.html' %}
{% load cache%}
{% block body %}
{% cache 6000 home.home %}
{{ block.super }}
<p>Last request: {{ date }}</p>
{% endcache %}
{% endblock %}
I get these errors:
curlylint --rule 'indent: 4' apps/home/templates/home/home.html
apps/home/templates/home/home.html
6:8 Bad indentation, expected 4, got 8 indent
7:8 Bad indentation, expected 4, got 8 indent
Oh no! π₯ π π₯
2 errors reported
Which I can fix like this:
{% extends 'home/base.html' %}
{% load cache%}
{% block body %}
{% cache 6000 home.home %}
{{ block.super }}
<p>Last request: {{ date }}</p>
{% endcache %}
{% endblock %}
Result:
curlylint --rule 'indent: 4' apps/home/templates/home/home.html
All done! β¨ π° β¨
Can we add this feature?
{% ... %}
The base.html
of the Django admin has a textbook accessibility fail β disabling zooming for mobile users: https://github.com/django/django/blob/278b6187d2a6711afb0b35dc5c3c09fe5be9adb3/django/contrib/admin/templates/admin/base.html#L15
This is what the meta_viewport
rule is meant to pick up, unfortunately it doesnβt pick it up.
viewport, meta, user-scalable
$ curlylint --version
curlylint, version 0.12.0
macOS Catalina
$ curlylint --rule 'meta_viewport: true' admin/templates/admin/base.html
admin/templates/admin/base.html
14:1 Remove `user-scalable=no` from the viewport meta so users can zoom meta_viewport
Oh no! π₯ π π₯
1 error reported
$ curlylint --rule 'meta_viewport: true' admin/templates/admin/base.html
All done! β¨ π° β¨
The problem seems to be with the meta tag being inside of a block:
{% block responsive %}
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive.css" %}">
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive_rtl.css" %}">{% endif %}
{% endblock %}
Moving it out of the block, the issue is picked up correctly.
I have Django templates I would like to lint, but cannot because they incorporate Alpine.js events.
The linter is throwing a parse error, because it doesn't support attributes starting with @
, which Alpine.js uses for events like @click
. To support Alpine.js, html attributes starting with @ would have to be recognized as valid.
The image_alt
rule does not seem to work inside Django template blocks. This seems very similar to #28, but since it's a different rule I wanted to open a separate ticket.
Image_alt, image, alt tag, django
$ curlylint --version
curlylint, version 0.12.2
MacOS Catalina 10.15.7
template.html
:{% block content %}
<img src="/path/static/image.png">
{% endblock %}
image_alt
enabled:curlylint --rule 'image_alt: true' template.html
$ curlylint --rule 'image_alt: true' template.html
template.html
3:5 The `<img>` tag must have a `alt` attribute, either with meaningful text, or an empty string for decorative images image_alt
Oh no! π₯ π π₯
1 error reported
$ curlylint --rule 'image_alt: true' template.html
All done! β¨ π° β¨
The missing alt attribute is reported correctly when the img
tag is moved out of the block.
Scrollback in terminals is often inconvenient, so I'm in a habit to pipe tool output into a temporary file. Introducing curlylint in a larger project can produce thousands of annotations!
But curlylint output always includes console colours, so the file reads like this:
οΏ½[2m6:4οΏ½[0m Bad indentation, expected 8, got 4 indent
οΏ½[2m7:4οΏ½[0m Bad indentation, expected 8, got 4 indent
οΏ½[2m14:0οΏ½[0m Bad indentation, expected 4, got 0 indent
Many tools either detect that their output is piped somewhere (which is a bit meh, I think) or provide a flag to force unformatted output. Down the line, different reporting formats might be a thing in any case, so maybe a flag like --report=plain
, so later we could also have --report=json
?
When using the following template code in Django templates:
templates/test.html
<input type="{{ field.field.widget.input_type }}" {% for key, value in field.field.widget.attrs.items %}{{ key }}="{{ value }}" {% endfor %}>
or
<input type="{{ field.field.widget.input_type }}" {% for key, value in field.field.widget.attrs.items %} {{ key }}="{{ value }}" {% endfor %}>
It gives a parse error:
β― curlylint ~/templates/test.html
~/templates/test.html
0:114 Parse error: expected one of '/', '>', 'attribute', 'space(s) between attributes', '{#', '{%', '{{' at 0:114 parse_error
Oh no! π₯ π π₯
1 error reported
I searched for in the issue tracker for:
Django error
Django parse_error
But i couldn't find the same kind of issue.
β― curlylint --version
curlylint, version 0.13.0
Windows 10
And also:
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
(Write your steps here:)
<input type="{{ field.field.widget.input_type }}" {% for key, value in field.field.widget.attrs.items %} {{ key }}="{{ value }}" {% endfor %}>
curlylint test.html
It shouldn't complain about a parse_error because this is regular Django template language.
It gives a parse_error:
β― curlylint test.html
test.html
0:114 Parse error: expected one of '/', '>', 'attribute', 'space(s) between attributes', '{#', '{%', '{{' at 0:114 parse_error
Oh no! π₯ π π₯
1 error reported
Prettier sometimes splits lines like this:
Really long line<a href="example.com">Really long line</a>
Into this:
Really long line<a href="example.com">Really long line</a
>
This is valid HTML, even if it looks a little weird. It's done because white space in between elements can mean something whereas whitespace in elements is safe.
Curlylint does not recognise this as valid and complains.
prettier
Curlylint 0.12.0
test.html
file with the contents of the split line:Really long line<a href="example.com">Really long line</a
>
curylint test.html
File should pass linting
% curlylint test.html
test.html
0:57 Parse error: expected '>' at 0:57 parse_error
Oh no! π₯ π π₯
1 error reported
Removing the newline resolves the error and file lints correctly.
Given above
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.