updated reformat rules

This commit is contained in:
Christopher Pickering 2021-07-26 12:22:26 -05:00
parent 46d7899978
commit 416c63ff38
No known key found for this signature in database
GPG key ID: E14DB3B0A0FACF84
5 changed files with 129 additions and 56 deletions

View file

@ -1,6 +1,6 @@
# djlint
Simple Django template linter and reformatter.
Simple Django template linter and reformatter. Ps, reformatting might work with Jinja and Handlebar templates as well! Test it out with the `--check` flag.
[![codecov](https://codecov.io/gh/Riverside-Healthcare/djlint/branch/master/graph/badge.svg?token=eNTG721BAA)](https://codecov.io/gh/Riverside-Healthcare/djlint)
[![test](https://github.com/Riverside-Healthcare/djlint/actions/workflows/test.yml/badge.svg)](https://github.com/Riverside-Healthcare/djlint/actions/workflows/test.yml)
@ -75,3 +75,7 @@ A good rule consists of
- Code - Codes beginning with "E" signify error, and "W" warning.
- Message - Message to display when error is found.
- Patterns - regex expressions that will find the error.
## Contributing - Please Help!
Checkout the issue list and help where you can!

View file

@ -69,6 +69,24 @@ def format_attributes(match):
)
def add_newlines(match):
"""Only add newlines of the match is not in our acceptable one line pattern."""
g_one = match.group(1)
g_two = match.group(2)
# print("one")
# print(g_one)
# print("two")
# print(g_two)
if not re.search(tag_pos_inline, g_one + g_two, flags=re.IGNORECASE | re.MULTILINE):
# print("not matched")
return g_one + "\n" + g_two
else:
return g_one + g_two
def remove_indentation(rawcode):
"""Remove indentation from raw code."""
rawcode_flat = ""
@ -79,11 +97,11 @@ def remove_indentation(rawcode):
# ignore raw code
if re.search(tag_raw_flat_closing, item, re.IGNORECASE):
tmp = clean_line(item)
# tmp = item #clean_line(item)
is_block_raw = False
elif re.search(tag_raw_flat_opening, item, re.IGNORECASE):
tmp = clean_line(item)
# tmp = item #clean_line(item)
is_block_raw = True
# find ignored blocks and retain indentation, otherwise strip white space
@ -92,7 +110,7 @@ def remove_indentation(rawcode):
is_block_ignored = False
elif re.search(ignored_tag_opening, item, re.IGNORECASE):
tmp = item
tmp = clean_line(item)
is_block_ignored = True
# not filtered so just output it
@ -104,7 +122,24 @@ def remove_indentation(rawcode):
tmp = item
else:
tmp = item.strip()
tmp = clean_line(item) # item.strip()
# if not an acceptable inline tag then add breaks
# add missing line breaks before tag
# print("before")
tmp = re.sub(
tag_newline_before,
add_newlines,
tmp,
flags=re.IGNORECASE | re.MULTILINE,
)
# print("after")
# add missing line breaks after tag
tmp = re.sub(
tag_newline_after, add_newlines, tmp, flags=re.IGNORECASE | re.MULTILINE
)
# print(tmp)
rawcode_flat = rawcode_flat + tmp + "\n"
@ -116,17 +151,12 @@ def remove_indentation(rawcode):
flags=re.IGNORECASE | re.DOTALL | re.MULTILINE,
)
# add missing line breaks before tag
# put empty tags on one line
rawcode_flat = re.sub(
tag_newline_before,
r"\1\n\2",
r"(<([\w]+)[^>]*>)\n(<\/\2>)",
r"\1\3",
rawcode_flat,
flags=re.IGNORECASE | re.DOTALL | re.MULTILINE,
)
# add missing line breaks after tag
rawcode_flat = re.sub(
tag_newline_after, r"\1\n\2", rawcode_flat, flags=re.IGNORECASE | re.MULTILINE
flags=re.IGNORECASE | re.MULTILINE,
)
return rawcode_flat
@ -142,77 +172,104 @@ def add_indentation(rawcode):
blank_counter = 0
for item in rawcode_flat_list:
# print(is_block_raw)
# print(item)
# if a raw tag then start ignoring
if (
tag_raw_flat_closing
and re.search(tag_raw_flat_closing, item, re.IGNORECASE)
) or re.search(ignored_tag_closing, item, re.IGNORECASE):
# print("tag raw flat closing")
is_block_raw = False
# if a one-line, inline tag, just process it
if re.search(tag_pos_inline, item, re.IGNORECASE):
if re.search(tag_pos_inline, item, re.IGNORECASE) and is_block_raw == False:
# print("tag pos inline")
tmp = (indent * indent_level) + item
blank_counter = 0
# if unindent, move left
elif re.search(tag_unindent, item, re.IGNORECASE):
elif re.search(tag_unindent, item, re.IGNORECASE) and is_block_raw == False:
# print("tag unindent")
indent_level = indent_level - 1
tmp = (indent * indent_level) + item
blank_counter = 0
elif re.search(tag_unindent_line, item, re.IGNORECASE):
elif (
re.search(tag_unindent_line, item, re.IGNORECASE) and is_block_raw == False
):
# print("tag unindent line")
tmp = (indent * (indent_level - 1)) + item
blank_counter = 0
# if indent, move right
elif re.search(tag_indent, item, re.IGNORECASE):
elif re.search(tag_indent, item, re.IGNORECASE) and is_block_raw == False:
# print("tag indent")
tmp = (indent * indent_level) + item
indent_level = indent_level + 1
blank_counter = 0
# if raw, flatten! no indenting!
elif tag_raw_flat_opening and re.search(
tag_raw_flat_opening, item, re.IGNORECASE
):
tmp = item
is_block_raw = True
blank_counter = 0
elif tag_raw_flat_closing and re.search(
tag_raw_flat_closing, item, re.IGNORECASE
):
tmp = item
is_block_raw = False
blank_counter = 0
elif is_block_raw is True:
# print("is raw")
tmp = item
# if just a blank line
elif item.strip() == "":
# print("is blank")
if blank_counter < int(reduce_extralines_gt) or blank_counter + 1:
tmp = item.strip()
# otherwise, just leave same level
else:
tmp = item # (indent * indent_level) + item
# print("else")
tmp = (indent * indent_level) + item
# if not raw, we can try to fix django tags
tmp = re.sub(r"({[{|%])(\w[^}].+?)([}|%]})", r"\1 \2\3", tmp)
tmp = re.sub(r"({[{|%])([^}].+?[^ ])([}|%]})", r"\1\2 \3", tmp)
# handlebars templates
tmp = re.sub(r"({{#(?:each|if).+?[^ ])(}})", r"\1 \2", tmp)
# if a opening raw tag then start ignoring.. only if there is no closing tag
# on the same line
if (
tag_raw_flat_closing
and re.search(tag_raw_flat_opening, item, re.IGNORECASE)
) or re.search(ignored_tag_opening, item, re.IGNORECASE):
# print("tag raw flat opening")
is_block_raw = True
# if a normal tag, we can try to expand attributes
elif (
format_long_attributes
and is_block_raw == False
and len(tmp) > max_line_length
):
# get leading space, and attributes
tmp = re.sub(r"(\s*?)(<\w+)(.+?)(/?>)", format_attributes, tmp)
# turn off raw block if we hit end - for one line raw blocks
if (
tag_raw_flat_closing
and re.search(tag_raw_flat_closing, item, re.IGNORECASE)
) or re.search(ignored_tag_closing, item, re.IGNORECASE):
is_block_raw = False
# print(tmp)
beautified_code = beautified_code + tmp + "\n"
if format_long_attributes:
# find lines longer than x
new_beautified = ""
for line in beautified_code.splitlines():
if len(line) > max_line_length:
# get leading space, and attributes
line = re.sub(r"(\s*?)(<\w+)(.+?)(/?>)", format_attributes, line)
new_beautified += "\n" + line
beautified_code = new_beautified
return beautified_code.strip() + "\n"
def reformat_file(check: bool, this_file: Path):
"""Reformat html file."""
rawcode = this_file.read_text(encoding="utf8")
# print(remove_indentation(rawcode))
beautified_code = add_indentation(remove_indentation(rawcode))
# print(beautified_code)
if check is not True:
# update the file
this_file.write_text(beautified_code)

View file

@ -83,3 +83,8 @@
message: Missging title tag in html.
patterns:
- <html[^>]*?>(?:(?!<title>).)*</html>
- rule:
name: W017
message: Tag should be self closing.
patterns:
- <(img|input|area|base|br|col|embed|hr|link|meta|param|source|track|wbr|command|keygen|menuitem)[^/]*?>

View file

@ -6,28 +6,28 @@
indent = " "
# indicates tags whose contents should not be formatted
ignored_tag_opening = r"<script|<style|<!--|{\*|<\?php|<pre"
ignored_tag_opening = r"<script|<style|<!--|{\*|<\?php|<pre|<svg"
# indicates when to stop ignoring
ignored_tag_closing = r"</script|</style|-->|\*}|\?>|</pre"
ignored_tag_closing = r"</script|</style|-->|\*}|\?>|</pre|</svg"
# the contents of these tag blocks will be start on a new line
tag_newline_before = r"([^\n])((?:\{% +?(?:if|end|for|block|endblock|else|spaceless|compress|load|include)|(?:<script)|(?:</?(html|head|body|div|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|optgroup|fieldset|legend|label|header|main|section|aside|footer|figure|video|span|p|g|svg|button|h\d))))"
tag_newline_before = r"([^\n]+?)((?:(?:\{\{[\/|\#])|\{% +?(?:if|end|for|block|endblock|else|spaceless|compress|load|include)|(?:<script)|(?:{% endverbatim %})|(?:{% verbatim %})|(?:</?(html|head|body|div|cache|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|optgroup|fieldset|legend|label|header|main|section|aside|footer|figure|video|span|p|g|svg|button|img|source)[^>]*?>.*?)))"
# these tags should be followed by a newline
tag_newline_after = r"((?:\{% +?(?:if|end|for|block|else|spaceless|compress|load|include)(?:.*?%}))|(?:<html|<head|</head|<body|</body|</script|<div|</div|<nav|</nav|<ul|</ul|<ol|</ol|<dl|</dl|<li|</li|<table|</table|<thead|</thead|<tbody|</tbody|<tr|</tr|<th|</th|<td|</td|<blockquote|</blockquote|<select|</select|<form|</form|<option|</option|<optgroup|</optgroup|<fieldset|</fieldset|<legend|</legend|<label|</label|<header|</header|<main|</main|<section|</section|<aside|</aside|<footer|</footer|<figure|</figure|<video|</video|</span|<p|</p|<g|</g|<svg|</svg|</h\d).*?\>)([^\n])"
tag_newline_after = r"((?:(?:\{\{[\/\#].*?\}\})|\{% +?(?:if|end|for|block|else|spaceless|compress|load|include)(?:.*?%}))|(?:{% endverbatim %})|(?:{% verbatim %})|(?:<html|<head|</head|<body|</body|</script|<div|</div|<cache|</cache|<nav|</nav|<ul|</ul|<ol|</ol|<dl|</dl|<li|</li|<table|</table|<thead|</thead|<tbody|</tbody|<tr|</tr|<th|</th|<td|</td|<blockquote|</blockquote|<select|</select|<form|</form|<option|</option|<optgroup|</optgroup|<fieldset|</fieldset|<legend|</legend|<label|</label|<header|</header|<main|</main|<section|</section|<aside|</aside|<footer|</footer|<figure|</figure|<video|</video|<source|</source|</span|<p|</p|<g|</g|<svg|</svg|</h\d|<img).*?\>)([^\n]+)"
# the contents of these tag blocks will be indented
tag_indent = r"\{% +?(if|for|block|else|spaceless|compress)|(?:<(?:html|head|body|div|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|optgroup|fieldset|legend|label|header|main|section|aside|footer|figure|video|span|p|g|svg|h\d|button))"
tag_indent = r"(?:\{\{\#)|\{% +?(if|for|block|else|spaceless|compress)|(?:{% verbatim %})|(?:<(?:html|head|body|div|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|cache|optgroup|fieldset|legend|label|header|main|section|aside|footer|figure|video|span|p|g|svg|h\d|button|img|script|style|source))"
# this signals when tags should be unindented (see tags above)
tag_unindent = r"\{% end|(?:</(?:html|head|body|div|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|optgroup|fieldset|legend|label|header|main|section|aside|footer|figure|video|span|p|g|svg|h\d|button))"
tag_unindent = r"(?:\{\{\/)|\{% end|(?:{% endverbatim %})|(?:</(?:html|head|body|div|a|nav|ul|ol|dl|li|table|thead|tbody|tr|th|td|blockquote|select|form|option|optgroup|fieldset|legend|label|header|cache|main|section|aside|footer|figure|video|span|p|g|svg|h\d|button|img|script|style|source))"
# these tags should be unindented and next line will be indented
tag_unindent_line = r"\{% el"
tag_unindent_line = r"(?:\{% el)|(?:\{\{ *?(?:else|\^) *?\}\})"
# these tags can sometimes be on one line
tag_pos_inline = r"\{% if.*endif %\}|\{% block.*endblock %\}|<link.*/>|<link.*\">|<link.*>|<meta.*/>|<script.*</script>|<div.*</div>|<a.*</a>|<li.*</li>|<dt.*</dt>|<dd.*</dd>|<th.*</th>|<td.*</td>|<legend.*</legend>|<label.*</label>|<option.*</option>|<input.*/>|<input.*\">|<span.*</span>|<p.*</p>|<path.*/>|<!--.*-->|<button.*</button>|<h\d.*</h\d>"
tag_pos_inline = r"(?:<link.*/>|<link.*\">|<link.*>|<meta.*/>|<script.*</script>|<div[^>]*>[^<]*</div>|<a[^>]*>[^<]*</a>|<li[^>]*>[^<]*</li>|<dt[^>]*>[^<]*</dt>|<dd[^>]*>[^<]*</dd>|<th[^>]*>[^<]*</th>|<td[^>]*>[^<]*</td>|<legend[^>]*>[^<]*</legend>|<label[^>]*>[^<]*</label>|<option[^>]*>[^<]*</option>|<input.*/>|<input.*\">|<span[^>]*>[^<]*</span>|<p[^>]*>[^<]*</p>|<path.*/>|<!--.*-->|<button[^>]*>[^<]*</button>|<h\d[^>]*>[^<]*</h\d>|<img.*?/>)"
# these tags use raw code and should flatten to column 1
# tabs will be removed inside these tags! use spaces for spacing if needed!
@ -45,7 +45,7 @@ max_line_length = 99
format_long_attributes = True
# pattern used to find attributes in a tag
attribute_pattern = r"([a-zA-Z-_]+=(?:\".*?\"|\'.*?\')|required|checked)\s*"
attribute_pattern = r"(.+?=(?:\".*?\"|\'.*?\')|required|checked)\s*"
tag_pattern = r"(<\w+?)((?:\n\s*?[^>]+?)+?)(/?\>)"
ignored_paths = r"(?:\.tox|\.venv|node_modules|_build)"

View file

@ -191,3 +191,10 @@ def test_W016(runner, tmp_file):
result = runner.invoke(djlint, [tmp_file.name])
assert result.exit_code == 0
assert "W016 1:" in result.output
def test_W017(runner, tmp_file):
write_to_file(tmp_file.name, b"<img this >")
result = runner.invoke(djlint, [tmp_file.name])
assert result.exit_code == 0
assert "W017 1:" in result.output