GithubHelp home page GithubHelp logo

thibaudcolas / curlylint Goto Github PK

View Code? Open in Web Editor NEW
226.0 4.0 25.0 1.84 MB

Experimental HTML templates linting for Jinja, Nunjucks, Django templates, Twig, Liquid

Home Page: https://www.curlylint.org/

License: MIT License

Python 8.78% Shell 0.22% JavaScript 3.20% Makefile 0.11% HTML 79.00% Liquid 5.00% CSS 1.65% Twig 1.60% Nunjucks 0.46%
jinja2 django django-templates twig nunjucks linter liquid html linting jinja

curlylint's People

Contributors

adamchainz avatar adrien-delhorme avatar asottile avatar imomaliev avatar jayvdb avatar jmsmkn avatar malikolivier avatar motet-a avatar renovate-bot avatar renovate[bot] avatar revelt avatar takkaria avatar thibaudcolas avatar tomdyson avatar yaegassy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

curlylint's Issues

Is it possible to exclude a block from linting?

Is your proposal related to a problem?

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.

Describe the solution you’d like

I'm not sure what would work; perhaps something like the following?

{# curlylintignore #}
  <span data-{{ triggers-issue}}>Hello, world!</span>
{# endcurlylintignore #}

Describe alternatives you’ve considered

I can ignore the entire file, but I'd like to be able to lint the rest of the file.

Handling <!doctype html>

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

"<!doctype html>"
Notices other blogs were taking the same steps I did

motet-a/jinjalint#16

Environment

Windows 2012R2
Curlylint ver => 0.13.0
Python ver 3.7.6

Steps to reproduce

(Write your steps here:)

  1. create a simple html doc with <!doctype html> tag
  2. add some html items
  3. test with tag in place then with out

Expected behavior

You should see different results based on the state of the <!doctype html> tag

Actual behavior

If statement wrapping attributes need white at the end

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

parse error expectation wrong

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

Parser fails on comment containing HTML tag

Describe the bug

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'.

Which terms did you search for in the documentation and issue tracker?

comment, parse error

#74 is similar but not identical.

Environment

curlylint 0.13.1, python 3.11.1, MacOS 11.7.3

Steps to reproduce

Create a new folder containing a file test.html:

{% comment %}
    there is an <interesting> tag here
{% endcomment %}

Run curlylint --parse-only .

Expected behavior

Linting should pass with no errors

Actual behavior

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

Exclude folders/files from linting

Is your proposal related to a problem?

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

Describe the solution you’d like

Add an option exclude that will remove folders/files from the linter

Describe alternatives you’ve considered

(Write your answer here.)

Additional context

(Write your answer here.)

Make it possible to skip/ignore rules/linting on specific lines

Is your proposal related to a problem?

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

Describe the solution you’d like

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.

Indentation in custom blocks

Describe the bug

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 %}.

Reproducible demo

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!

Support for self closing tags (HTML / XML)

Describe the bug

Self closing tags which are valid HTML/XML are throwing off the linter.

Which terms did you search for in the documentation and issue tracker?

self closing tag

Environment

  • curlylint, version 0.13.0
  • macOS Big Sur 11.4

Steps to reproduce

(Write your steps here:)

  1. First, create a file named my.xml with the following content
    <foo>
      <bar />
    </foo>
  2. Then, run the linter with the following command
    curlylint my.xml --rule 'indent: 2'
    

Expected behavior

All done! ✨ 🍰 ✨

Actual behavior

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

Describe the bug

Parsing fails for {% comment %} including number within HTML tag.

Environment

OSX 12.6

Python 3.10.6

curlylint 0.13.1

Steps to reproduce

  1. Create the template:
    <div
        {% comment %}
            1
        {% endcomment %}
    ></div> 
  2. Then, run curlylint on it

Expected behavior

Should pass, similarly to this version, without a number (which passes as expected):

<div
    {% comment %}
        A
    {% endcomment %}
></div> 

Actual behavior

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

invalid parse error

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

Tried searching for "comment", but switching the comment to an if gave the same issue so I'm unsure the problem.

Environment

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

Steps to reproduce

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.

Expected behavior

Should clear as valid

Actual behavior

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

Document jinja_custom_elements_names

Is your proposal related to a problem?

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']]

Describe the solution you’d like

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.

Additional context

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.

Don't enforce indentation rules inside <pre> tags

Describe the bug

Indentation rules are applied inside <pre>...</pre> blocks

Which terms did you search for in the documentation and issue tracker?

"pre"

Environment

Python 3.8
curlylint==0.12.0

Steps to reproduce

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;
  

Expected behavior

Don't enforce indentation rules inside <pre>...</pre> blocks

Actual behavior

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

`pip install curlylint` does not work due to incompatability with click 8.1.0

Describe the bug

Cannot run curlylint with the latest version of click. This is similar to psf/black#2964. Workaround is to pin click<8.1.0.

Which terms did you search for in the documentation and issue tracker?

ImportError: cannot import name '_unicodefun' from 'click'

Environment

Python 3.8

Steps to reproduce

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)

Expected behavior

Curlylint runs successfully

Actual behavior

ImportError: cannot import name '_unicodefun' from 'click' (/tmp/curlylint/lib/python3.8/site-packages/click/__init__.py)

TypeError: can only concatenate str (not "Parser") to str

Describe the bug

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:

  1. That the type of 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
  2. I'm not 100% sure the input file is wrong, so there might be a parser error that's causing this to be raised in the first place (see samples below).

Which terms did you search for in the documentation and issue tracker?

"concatenate"

Environment

  • curlylint 0.13.1
  • Python 3.10.7

Steps to reproduce

I have two samples:

To re-produce the actual bug

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 %}

Stripped down example that I don't think should be an error

{% 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!)

Expected behavior

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

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency mypy to v1
  • chore(deps): update dependency node to v20
  • chore(deps): update dependency parsy to v2
  • chore(deps): update dependency prettier to v3
  • chore(deps): update dependency pytest to v8
  • πŸ” Create all rate-limited PRs at once πŸ”

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.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
npm
package.json
  • prettier 2.6.1
website/package.json
nvm
.nvmrc
  • node 15
website/.nvmrc
  • node 15
pip_requirements
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
pip_setup
setup.py
  • parsy ==1.1.0
  • attrs >=17.2.0
  • click >=6.5
  • toml >=0.9.4
  • pathspec >=0.6, <1
  • dataclasses >=0.6

  • Check this box to trigger a request for Renovate to run again on this repository

Stumbles over… I don't know what ;)

Describe the bug

I tried curlylint on our set of Django templates, and it stumbled over some things I cannot really explain. One example is this template:

https://edugit.org/AlekSIS/official/AlekSIS-Core/-/blob/d579eec21675787347c7e7d4c2862d9d75030b0a/aleksis/core/templates/dynamic_preferences/sections.html

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.

Which terms did you search for in the documentation and issue tracker?

"parse", mainly.

Environment

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.

Steps to reproduce

  1. pip3 install curlylint
  2. wget https://edugit.org/AlekSIS/official/AlekSIS-Core/-/raw/d579eec21675787347c7e7d4c2862d9d75030b0a/aleksis/core/templates/dynamic_preferences/sections.html
  3. curlylint sections.html

Expected behavior

Template is lint-clean.

Actual behavior

curlylint throws above parse error.

Reproducible demo

{% 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>

Error parsing Django with unclosed tag inside if statement

Describe the bug

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 %}

Which terms did you search for in the documentation and issue tracker?

I looked through all of the open and closed issues.

Environment

Python 3.6.6
curlylint 0.12.0

Steps to reproduce

  1. First, create a template with the above example.
  2. Then, run curlylint pointing to the template created.

Expected behavior

Parse and lint the template without throwing an exception.

Actual behavior

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

Reproducible demo

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!

allow closing svg tag like <cirlcle ... />

Is your proposal related to a problem?

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

Describe the solution you’d like

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.

Describe alternatives you’ve considered

--

Additional context

--

Line numbers in stylish and json report are off by one

Describe the bug

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.

Steps to reproduce

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

Expected behavior

Consistent reporting of line numbers, preferably 1-indexed. πŸ˜‰

Actual behavior

Behaviour is buggy/mixed, primarily 0-indexed, as described above. Sorry, no screenshots, but I pasted the output.

Reproducible demo

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.

Bug source

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.

Tests from sdist fail

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'

Crash when closing HTML tags inside Jinja2 if statements

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!

Add Curlylint to GitHub Super Linter

Is your proposal related to a problem?

I'd like to easily and automatically lint my Jinja2 templates

Describe the solution you’d like

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.

Describe alternatives you’ve considered

Installing locally works but would prefer to do it via the GitHub Super Linter.

Additional context

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.

Action Required: Fix Renovate Configuration

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.

dynamic attributes cause parse error

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

looked at all open and closed issues

(Write your answer here if relevant.)

Environment

$ curlylint --version
curlylint, version 0.12.0

Invalid test usage in Jinja2 isn't caught by linter

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

is None

Environment

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.

Steps to reproduce

  1. First, create an HTML template with the following content:
{% if foo is None: %}
foo is None!
{% endif %}
  1. Then, run curlylint against that file

Expected behavior

I 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.

Actual behavior

Passes with no errors:

$ curlylint broken.html
All done! ✨ 🍰 ✨

Reproducible demo

See steps above for file content that demonstrates issue.

Other

I found this while using None, but the same would apply for True and False.

Some links:

Allow indentation inside template tags

Is your proposal related to a problem?

Yes

Describe the solution you’d like

I would like to indent inside template tags

Describe alternatives you’ve considered

setting curlylint --rule 'indent: 4'

Additional context

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?

Ability to do simple checks on template tag content

Is your proposal related to a problem?

  • there are some Django template conventions we would like to enforce with a linting rule
  • example: require using trimmed with blocktrans

Describe the solution you’d like

  • template tag requires - a configurable list of regex (might be simplest) that runs inside any template tag usages (in Django those with {% ... %}

Describe alternatives you’ve considered

  • add a custom tool that does a regex parse across all html files within a folder
  • monkey patch the Django template system (or add a custom template order that extends the Django one), when running in test or Dev mode any template tags that do not conform will throw an error

Additional context

meta_viewport rule fails to find viewport element inside block

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

viewport, meta, user-scalable

Environment

$ curlylint --version
curlylint, version 0.12.0

macOS Catalina

Steps to reproduce

  1. Save https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/base.html#L15 locally.
  2. curlylint --rule 'meta_viewport: true' admin/templates/admin/base.html

Expected behavior

$ 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

Actual behavior

$ 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.

Support Alpine.js syntax

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.

image_alt rule fails to find missing alt tag inside django block

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

Image_alt, image, alt tag, django

Environment

$ curlylint --version
curlylint, version 0.12.2

MacOS Catalina 10.15.7

Steps to reproduce

  1. Create the following template.html:
{% block content %}
    <img src="/path/static/image.png">
{% endblock %}
  1. Run curlylint with image_alt enabled:
curlylint --rule 'image_alt: true' template.html

Expected behavior

$ 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

Actual behavior

$ 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.

Provide an export format flag, or detect piping

Is your proposal related to a problem?

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

Describe the solution you’d like

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 curlylint linter in Django templates it generates a false positive parse error

Describe the bug

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

Which terms did you search for in the documentation and issue tracker?

I searched for in the issue tracker for:

Django error
Django parse_error

But i couldn't find the same kind of issue.

Environment

Version

❯ curlylint --version
curlylint, version 0.13.0

OS

Windows 10

And also:

Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.3 LTS
Release:	20.04
Codename:	focal

Steps to reproduce

(Write your steps here:)

  1. Create a test.html file with the following contents:
<input type="{{ field.field.widget.input_type }}" {% for key, value in field.field.widget.attrs.items %} {{ key }}="{{ value }}" {% endfor %}>
  1. Then run curlylint
curlylint test.html

Expected behavior

It shouldn't complain about a parse_error because this is regular Django template language.

Actual behavior

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

Curlylint complains about split anchor tags introduces by Prettier

Describe the bug

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.

Which terms did you search for in the documentation and issue tracker?

prettier

Environment

Curlylint 0.12.0

Steps to reproduce

  1. Create a test.html file with the contents of the split line:
Really long line<a href="example.com">Really long line</a
>
  1. Run curlylint on it
curylint test.html

Expected behavior

File should pass linting

Actual behavior

% 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.

Reproducible demo

Given above

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.