closes #67, closes #59

This commit is contained in:
Christopher Pickering 2021-10-06 14:20:47 +02:00
parent b8dec2ebfb
commit 569f9112ac
No known key found for this signature in database
GPG key ID: E14DB3B0A0FACF84
9 changed files with 248 additions and 228 deletions

View file

@ -4,12 +4,16 @@ Changelog
Next Release
------------
- Added rule H020 to find empty tag pairs
- Added rule H021 to find inline styles
- Added rule H022 to find http links
- Added rule H023 to find entity references
- Added rule H024 to find type on scripts and styles
- Improved attribute formatting
- Updated ``blank_line_after_tag`` option to add newline regardless of location
- Fixed django ``trans`` tag formatting
- Added linter rule H021 to check for inline styles
- Added formatting for inline styles
- Added formatting for template conditions inside attributes
- Added srcset as possible url location in linter rules
0.5.3
-----

View file

@ -53,6 +53,12 @@ Codes
+--------+-------------------------------------------------------------------------+
| H021 | Inline styles should be avoided. |
+--------+-------------------------------------------------------------------------+
| H022 | Use HTTPS for external links. |
+--------+-------------------------------------------------------------------------+
| H023 | Do not use entity references. |
+--------+-------------------------------------------------------------------------+
| H024 | Omit type on scripts and styles. |
+--------+-------------------------------------------------------------------------+
Adding Rules
------------

View file

@ -39,6 +39,12 @@ def format_template_tags(config: Config, attributes: str) -> str:
)
)[-1]
else:
# if we don't know where we are, then return what we started with.
if not re.findall(
re.compile(r"^<\w+[^=\"']\s*", re.M), attributes[: match.start()]
):
return match.group()
attr_name = list(
re.finditer(
re.compile(r"^<\w+[^=\"']\s*", re.M), attributes[: match.start()]

View file

@ -24,7 +24,7 @@ def indent_html(rawcode: str, config: Config) -> str:
is_raw_first_line = False
is_block_raw = False
slt_html = config.break_html_tags
slt_html = config.indent_html_tags
# here using all tags cause we allow empty tags on one line
always_slt_html = config.always_single_line_html_tags

View file

@ -37,14 +37,14 @@
flags: re.DOTALL
# this should be using the static path from django settings
patterns:
- <(?:link|img|script)\s[^\>]*?(?:href|src)=[\"\']/?static/?
- <(?:link|img|script|source)\s[^\>]*?(?:href|src|srcset)=[\"\']/?static/?
- rule:
name: J004
message: (Jinja) Static urls should follow {{ url_for('static'..) }} pattern.
flags: re.DOTALL
# this should be using the static path from django settings
patterns:
- <(?:link|img|script)\s[^\>]*?(?:href|src)=[\"\']/?static/?
- <(?:link|img|script|source)\s[^\>]*?(?:href|src|srcset)=[\"\']/?static/?
- rule:
name: H005
message: Html tag should have lang attribute.
@ -69,7 +69,7 @@
message: Attributes should be double quoted.
flags: re.DOTALL|re.I
patterns:
- (?:class|id|src|width|height|alt|style|lang|title)=\'[^\']*'
- (?:class|id|src|width|height|alt|style|lang|title|srcset|media)=\'[^\']*'
- rule:
name: H009
message: Tag names should be lowercase.
@ -81,7 +81,7 @@
message: Attribute names should be lowercase.
flags: re.DOTALL
patterns:
- <\w+[^\>]+?(?:CLASS|ID|SRC|WIDTH|HEIGHT|ALT|STYLE|LANG|TITLE)=
- <\w+[^\>]+?(?:CLASS|ID|SRC|WIDTH|HEIGHT|ALT|STYLE|LANG|TITLE|MEDIA|SRCSET)=
- rule:
name: H011
message: Attribute values should be quoted.
@ -208,7 +208,7 @@
| ul
| var
| video
| wbr)\s+?[^>]*?(?:class|id|src|width|height|alt|style|lang|title|href|action|method|checked|required)=[a-zA-Z_-]+
| wbr)\s+?[^>]*?(?:class|id|src|width|height|alt|style|lang|title|href|action|method|checked|required|srcset)=[a-zA-Z_-]+
- <(?:meta)\s+?[^>]*?(?:class|id|src|alt|style|lang|title|href|action|method|name)=[a-zA-Z_-]+
- rule:
name: H012
@ -281,3 +281,21 @@
flags: re.I
patterns:
- <\w+\s[^>]*style(?=[^>]*>)
- rule:
name: H022
message: Use HTTPS for external links.
flags: re.I
patterns:
- <\w+\s[^>]*?(?:href|data-url|action|src|url|srcset)=[\"|']http://[^>]*?>
- rule:
name: H023
message: Do not use entity references.
flags: re.I
patterns:
- '&.{5};'
- rule:
name: H024
message: Omit type on scripts and styles.
flags: re.I
patterns:
- <(?:script|style)[^>]*?type=["|'][^>]*?>

View file

@ -232,6 +232,132 @@ class Config:
| {%[ ]djlint:on[ ]%}
"""
# all html tags possible
self.indent_html_tags: str = r"""
a
| abbr
| acronym
| address
| applet
| area
| article
| aside
| audio
| b
| base
| basefont
| bdi
| bdo
| big
| blockquote
| body
| br
| button
| canvas
| caption
| center
| cite
| code
| col
| colgroup
| data
| datalist
| dd
| del
| details
| dfn
| dialog
| dir
| div
| dl
| dt
| em
| embed
| fieldset
| figcaption
| figure
| font
| footer
| form
| frame
| frameset
| h1
| h2
| h3
| h4
| h5
| h6
| head
| header
| hr
| html
| i
| iframe
| icon
| img
| input
| ins
| kbd
| label
| legend
| li
| link
| main
| map
| mark
| meta
| meter
| nav
| noframes
| noscript
| object
| ol
| optgroup
| option
| output
| p
| path
| param
| picture
| progress
| q
| rp
| rt
| ruby
| s
| samp
| script
| section
| select
| small
| source
| span
| strike
| strong
| style
| sub
| summary
| sup
| svg
| table
| tbody
| td
| template
| tfoot
| th
| thead
| time
| title
| tr
| track
| tt
| u
| ul
| var
| video
| wbr
"""
# the contents of these tag blocks will be indented, then unindented
self.tag_indent: str = (
r"""
@ -258,117 +384,29 @@ class Config:
)
| (?:<
(?:
html
| head
| body
| div
| a
| nav
| ul
| ol
| dl
| dd
| dt
| li
| table
| thead
| tbody
| tr
| th
| td
| blockquote
| select
| i
| form
| option
| cache
| optgroup
| fieldset
| legend
| label
| header
| main
| section
| aside
| footer
| figure
| figcaption
| video
| span
| p
| g
| svg
| h\d
| button
| img
| path
| script
| style
| details
| summary
"""
+ self.indent_html_tags
+ """
)
)
"""
)
self.tag_unindent: str = r"""^
self.tag_unindent: str = (
r"""^
(?:
(?:\{\{\/)
| (?:\{%-?[ ]*?end)
)
| (?:</
(?:
html
| head
| body
| div
| a
| nav
| ul
| ol
| dl
| dd
| dt
| li
| table
| thead
| tbody
| tr
| th
| td
| blockquote
| select
| form
| i
| option
| optgroup
| fieldset
| legend
| label
| header
| cache
| main
| section
| aside
| footer
| figure
| figcaption
| video
| span
| p
| g
| svg
| h\d
| button
| img
| path
| script
| style
| details
| summary
"""
+ self.indent_html_tags
+ """
)
)
"""
)
# these tags should be unindented and next line will be indented
self.tag_unindent_line: str = r"""
@ -540,126 +578,52 @@ class Config:
"""
self.break_html_tags: str = r"""
a
# | abbr
| acronym
| address
| applet
| area
| article
| aside
| audio
| b
| base
| basefont
| bdi
| bdo
| big
| blockquote
| body
| br
| button
| canvas
| caption
| center
| cite
| code
| col
| colgroup
| data
| datalist
| dd
| del
| details
| dfn
| dialog
| dir
| div
| dl
| dt
# | em
| embed
| fieldset
| figcaption
| figure
| font
| footer
| form
| frame
| frameset
| h1
| h2
| h3
| h4
| h5
| h6
html
| head
| header
| hr
| html
# | i
| iframe
# | icon
| img
| input
| ins
| kbd
| label
| legend
| li
| link
| main
| map
| mark
| meta
| meter
| body
| div
| a
| nav
| noframes
| noscript
| object
| ol
| optgroup
| option
| output
| p
| path
| param
| picture
| progress
| q
| rp
| rt
| ruby
| s
| samp
| script
| section
| select
# | small
| source
# | span
| strike
# | strong
| style
| sub
| summary
| sup
| svg
| table
| tbody
| td
| template
| tfoot
| th
| thead
| time
| title
| tr
| track
| tt
| u
| ul
| var
| ol
| dl
| dd
| dt
| li
| table
| thead
| tbody
| tr
| th
| td
| blockquote
| select
| form
| option
| optgroup
| fieldset
| legend
| label
| header
| cache
| main
| section
| aside
| footer
| figure
| figcaption
| video
| wbr
| span
| p
| g
| svg
| h\d
| button
| img
| path
| picture
| script
| style
| details
| summary
"""

View file

@ -7,7 +7,7 @@ run::
for a single test, run::
pytest tests/test_config.py::test_blank_lines_after_tag --cov=src/djlint \
pytest tests/test_config.py::test_indent --cov=src/djlint \
--cov-branch --cov-report xml:coverage.xml --cov-report term-missing
"""

View file

@ -285,6 +285,27 @@ def test_H021(runner: CliRunner, tmp_file: TextIO) -> None:
assert "H021 1:" in result.output
def test_H022(runner: CliRunner, tmp_file: TextIO) -> None:
write_to_file(tmp_file.name, b'<a href="http://">')
result = runner.invoke(djlint, [tmp_file.name])
assert result.exit_code == 1
assert "H022 1:" in result.output
def test_H023(runner: CliRunner, tmp_file: TextIO) -> None:
write_to_file(tmp_file.name, b"&mdash;")
result = runner.invoke(djlint, [tmp_file.name])
assert result.exit_code == 1
assert "H023 1:" in result.output
def test_H024(runner: CliRunner, tmp_file: TextIO) -> None:
write_to_file(tmp_file.name, b'<script type="hare">')
result = runner.invoke(djlint, [tmp_file.name])
assert result.exit_code == 1
assert "H024 1:" in result.output
def test_rules_not_matched_in_ignored_block(
runner: CliRunner, tmp_file: TextIO
) -> None:

View file

@ -5,6 +5,9 @@ run::
pytest tests/test_nunjucks.py --cov=src/djlint --cov-branch \
--cov-report xml:coverage.xml --cov-report term-missing
pytest tests/test_nunjucks.py::test_spaceless --cov=src/djlint --cov-branch \
--cov-report xml:coverage.xml --cov-report term-missing
"""
# pylint: disable=C0116
from pathlib import Path
@ -45,12 +48,10 @@ def test_spaceless(runner: CliRunner, tmp_file: TextIO) -> None:
runner,
b"""{%- if entry.children.length -%}<strong>{%- endif -%}""",
)
assert output["exit_code"] == 1
print(output["text"])
assert output["exit_code"] == 0
assert (
output["text"]
== r"""{%- if entry.children.length -%}
<strong>
{%- endif -%}
== r"""{%- if entry.children.length -%}<strong>{%- endif -%}
"""
)