diff --git a/src/djlint/__init__.py b/src/djlint/__init__.py
index ad77789..67b57aa 100644
--- a/src/djlint/__init__.py
+++ b/src/djlint/__init__.py
@@ -21,6 +21,7 @@ import sys
from concurrent.futures import ProcessPoolExecutor, as_completed
from functools import partial
from pathlib import Path
+from typing import List
import click
from click import echo
@@ -29,22 +30,21 @@ from tqdm import tqdm
from .lint import lint_file
from .reformat import reformat_file
-from .settings import ignored_paths
+from .settings import Config
-def get_src(src: Path, extension=None):
+def get_src(src: Path, config: Config) -> List[Path]:
"""Get source files."""
if Path.is_file(src):
return [src]
# remove leading . from extension
+ extension = str(config.extension)
extension = extension[1:] if extension.startswith(".") else extension
paths = list(
filter(
- lambda x: not re.search(
- "|".join([re.escape(x) for x in ignored_paths]), str(x)
- ),
+ lambda x: not re.search(config.ignored_paths, str(x), re.VERBOSE),
list(src.glob(r"**/*.%s" % extension)),
)
)
@@ -56,7 +56,7 @@ def get_src(src: Path, extension=None):
return paths
-def build_output(error):
+def build_output(error: dict) -> int:
"""Build output for file errors."""
errors = sorted(list(error.values())[0], key=lambda x: int(x["line"].split(":")[0]))
width, _ = shutil.get_terminal_size()
@@ -75,10 +75,9 @@ def build_output(error):
)
for message in errors:
- error = bool(message["code"][:1] == "E")
echo(
"{} {} {} {} {}".format(
- (Fore.RED if error else Fore.YELLOW),
+ (Fore.RED if bool(message["code"][:1] == "E") else Fore.YELLOW),
message["code"] + Style.RESET_ALL,
Fore.BLUE + message["line"] + Style.RESET_ALL,
message["message"],
@@ -89,7 +88,7 @@ def build_output(error):
return len(errors)
-def build_check_output(errors, quiet):
+def build_check_output(errors: dict, quiet: bool) -> int:
"""Build output for reformat check."""
if len(errors) == 0:
return 0
@@ -128,12 +127,12 @@ def build_check_output(errors, quiet):
return len(list(filter(lambda x: len(x) > 0, errors.values())))
-def build_quantity(size: int):
+def build_quantity(size: int) -> str:
"""Count files in a list."""
return "%d file%s" % (size, ("s" if size > 1 or size == 0 else ""))
-def build_quantity_tense(size: int):
+def build_quantity_tense(size: int) -> str:
"""Count files in a list."""
return "%d file%s %s" % (
size,
@@ -155,7 +154,7 @@ def build_quantity_tense(size: int):
"-e",
"--extension",
type=str,
- default="html",
+ default="",
help="File extension to lint",
show_default=True,
)
@@ -184,9 +183,11 @@ def build_quantity_tense(size: int):
)
def main(
src: str, extension: str, ignore: str, reformat: bool, check: bool, quiet: bool
-):
+) -> None:
"""Djlint django template files."""
- file_list = get_src(Path(src), extension)
+ config = Config(src, extension=extension, ignore=ignore, quiet=quiet)
+
+ file_list = get_src(Path(src), config)
if len(file_list) == 0:
return
@@ -225,13 +226,13 @@ def main(
with ProcessPoolExecutor(max_workers=worker_count) as exe:
file_errors = []
if reformat is True or check is True:
- func = partial(reformat_file, check)
+ func = partial(reformat_file, config, check)
futures = {
exe.submit(func, this_file): this_file for this_file in file_list
}
else:
- func = partial(lint_file, ignore)
+ func = partial(lint_file, config)
futures = {
exe.submit(func, this_file): this_file for this_file in file_list
}
diff --git a/src/djlint/formatter/compress_html.py b/src/djlint/formatter/compress_html.py
index dceef14..55af006 100644
--- a/src/djlint/formatter/compress_html.py
+++ b/src/djlint/formatter/compress_html.py
@@ -1,21 +1,11 @@
"""djLint Attempt to logically shrink html."""
-import re as old_re
import regex as re
-from ..settings import (
- ignored_block_closing,
- ignored_block_opening,
- ignored_group_closing,
- ignored_group_opening,
- ignored_inline_blocks,
- single_line_html_tags,
- single_line_template_tags,
- start_template_tags,
-)
+from ..settings import Config
-def _clean_line(line):
+def _clean_line(line: str) -> str:
"""Clean up a line of html.
* remove duplicate spaces
@@ -25,7 +15,7 @@ def _clean_line(line):
return re.sub(r" {2,}", " ", line.strip())
-def _strip_html_whitespace(html):
+def _strip_html_whitespace(html: str, config: Config) -> str:
"""Remove unnecessary whitespace from text."""
rawcode_flat = ""
is_block_ignored = False
@@ -35,17 +25,19 @@ def _strip_html_whitespace(html):
# start of ignored block. If we are already in an ingored block, keep true.
is_group_ignored = is_group_ignored or bool(
- re.search("|".join(ignored_group_opening), item, re.IGNORECASE)
+ re.search(config.ignored_group_opening, item, re.IGNORECASE | re.VERBOSE)
)
# find ignored blocks and retain indentation, otherwise strip white space
if re.findall(
- r"(?:%s)" % "|".join(ignored_inline_blocks), item, flags=re.IGNORECASE
+ r"(?:%s)" % config.ignored_inline_blocks,
+ item,
+ flags=re.IGNORECASE | re.VERBOSE,
):
tmp = _clean_line(item)
elif (
- re.search("|".join(ignored_block_closing), item, re.IGNORECASE)
+ re.search(config.ignored_block_closing, item, re.IGNORECASE | re.VERBOSE)
and is_group_ignored is False
):
# do not format ignored lines
@@ -53,7 +45,7 @@ def _strip_html_whitespace(html):
is_block_ignored = False
elif (
- re.search("|".join(ignored_block_opening), item, re.IGNORECASE)
+ re.search(config.ignored_block_opening, item, re.IGNORECASE | re.VERBOSE)
and is_group_ignored is False
):
# do not format ignored lines
@@ -67,7 +59,9 @@ def _strip_html_whitespace(html):
tmp = _clean_line(item)
# end of ignore raw code
- if bool(re.search("|".join(ignored_group_closing), item, re.IGNORECASE)):
+ if bool(
+ re.search(config.ignored_group_closing, item, re.IGNORECASE | re.VERBOSE)
+ ):
is_group_ignored = False
rawcode_flat = rawcode_flat + tmp + "\n"
@@ -75,10 +69,10 @@ def _strip_html_whitespace(html):
return rawcode_flat
-def compress_html(html):
+def compress_html(html: str, config: Config) -> str:
"""Compress back tags that do not need to be expanded."""
# put empty tags on one line
- html = _strip_html_whitespace(html)
+ html = _strip_html_whitespace(html, config)
html = re.sub(
r"(<([\w]+)[^>]*>)\s+?(<\/\2>)",
@@ -89,22 +83,26 @@ def compress_html(html):
# put empty template tags on one line
html = re.sub(
- r"(" + start_template_tags + r")\s+?(\{\% end[^}]*?\%\})",
- r"\1\2",
+ r"({%[ ]*?("
+ + re.sub(r"\s", "", config.start_template_tags)
+ + r")[^}]+?%})\s+?(\{\% end[^}]*?\%\})",
+ r"\1\3",
html,
re.MULTILINE,
)
# put short single line tags on one line
- slt_html = "|".join(single_line_html_tags)
- html = old_re.sub(
+ # verbose doesn't seem to work with replace groups.
+ slt_html = re.sub(r"\s", "", config.single_line_html_tags)
+
+ html = re.sub(
r"(<(%s)>)\s*([^<\n]{,80})\s*?((\2)>)" % slt_html,
r"\1\3\4",
html,
re.IGNORECASE | re.MULTILINE | re.DOTALL,
)
- html = old_re.sub(
+ html = re.sub(
r"(<(%s)>)\s*?([^<\n]{,80})\s*?((\2)>)" % slt_html,
r"\1\3\4",
html,
@@ -112,17 +110,17 @@ def compress_html(html):
)
html = re.sub(
- r"(<(%s) [^\n]{,80}>)\s*([^<\n]{,80})\s*?((\2)>)" % slt_html,
+ r"(<(%s)[ ][^\n]{,80}>)\s*([^<\n]{,80})\s*?((\2)>)" % slt_html,
r"\1\3\4",
html,
re.IGNORECASE | re.MULTILINE | re.DOTALL,
)
- slt_template = "|".join(single_line_template_tags)
+ # cannot use verbose when replacing with var. 🤕
html = re.sub(
- r"({% +?("
- + slt_template
- + r") +?[^\n]{,30}%})\s*([^%\n]{,50})\s*?({% +?end(\2) +?%})",
+ r"({%[ ]*?("
+ + re.sub(r"\s", "", config.single_line_template_tags)
+ + r")[ ]+?[^\n]{,30}%})\s*([^%\n]{,50})\s*?({%[ ]+?end(\2)[ ]*?%})",
r"\1\3\4",
html,
re.IGNORECASE | re.MULTILINE,
diff --git a/src/djlint/formatter/expand_html.py b/src/djlint/formatter/expand_html.py
index 5b5dd39..49db712 100644
--- a/src/djlint/formatter/expand_html.py
+++ b/src/djlint/formatter/expand_html.py
@@ -4,73 +4,70 @@ from functools import partial
import regex as re
-from ..settings import (
- break_html_tags,
- break_template_tags,
- ignored_attributes,
- ignored_blocks,
- tag_pattern,
-)
+from ..settings import Config
-def _flatten_attributes(match):
+def _flatten_attributes(config: Config, match: re.Match) -> str:
"""Flatten multiline attributes back to one line.
Skip when attribute is ignored.
Attribute name can be in group one or group 2.
for now, skipping if they are anywhere
"""
- for attribute in ignored_attributes:
+ for attribute in config.ignored_attributes:
if attribute in match.group():
return match.group()
return "{} {}{}".format(
match.group(1),
- " ".join(match.group(2).strip().splitlines()),
+ " ".join(x.strip() for x in match.group(2).strip().splitlines()),
match.group(3),
)
-def _should_ignore(html, match):
+def _should_ignore(config: Config, html: str, match: re.Match) -> bool:
"""Do not add whitespace if the tag is in a non indent block."""
- for block in ignored_blocks:
+ for block in config.ignored_blocks:
return any(
ignored_match.start() < match.start(1)
and ignored_match.end() > match.end(1)
for ignored_match in re.finditer(
- block % re.escape(match.group(1)), html, re.DOTALL | re.IGNORECASE
+ block % re.escape(match.group(1)),
+ html,
+ re.DOTALL | re.IGNORECASE | re.VERBOSE,
)
)
return False
-def expand_html(html):
+def expand_html(html: str, config: Config) -> str:
"""Split single line html into many lines based on tags."""
- def add_html_line(out_format, match):
+ def add_html_line(out_format: str, match: re.Match) -> str:
"""Add whitespace.
Do not add whitespace if the tag is in a non indent block.
"""
- if _should_ignore(html, match):
+ if _should_ignore(config, html, match):
return match.group(1)
return out_format % match.group(1)
# put attributes on one line
+ func = partial(_flatten_attributes, config)
html = old_re.sub(
- tag_pattern,
- _flatten_attributes,
+ config.tag_pattern,
+ func,
html,
- flags=re.IGNORECASE | re.MULTILINE,
+ flags=re.IGNORECASE | re.MULTILINE | re.VERBOSE,
)
- html_tags = "|".join(break_html_tags)
+ html_tags = config.break_html_tags
# process opening tags ############
- # the tag either closes
+ # the tag either opens
# self closes
![]()
# has attributes
# or has attributes and self closes
![]()
@@ -78,7 +75,7 @@ def expand_html(html):
add_left = partial(add_html_line, "\n%s")
add_right = partial(add_html_line, "%s\n")
- break_char = r"(?)"
@@ -88,62 +85,71 @@ def expand_html(html):
),
add_left,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
#
html = re.sub(
- r"(<(?:%s)>)(?=[^\n])" % html_tags, add_right, html, flags=re.IGNORECASE
+ r"(<(?:%s)>)(?=[^\n])" % html_tags,
+ add_right,
+ html,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# \n and \n
html = re.sub(
- r"%s\K(<(?:%s) ?/>)"
+ r"%s\K(<(?:%s)[ ]?/>)"
% (
break_char,
html_tags,
),
add_left,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# and
html = re.sub(
- r"(<(?:%s) ?/>)(?=[^\n])" % html_tags, add_right, html, flags=re.IGNORECASE
+ r"(<(?:%s)[ ]?/>)(?=[^\n])" % html_tags,
+ add_right,
+ html,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# \n, \n, \n
html = re.sub(
- r"%s\K(<(?:%s) [^>]*?[^/]>)"
+ r"%s\K(<(?:%s)[ ][^>]*?[^/]>)"
% (
break_char,
html_tags,
),
add_left,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# , ,
html = re.sub(
- r"(<(?:%s) [^>]*?[^/]>)(?=[^\n])" % html_tags,
+ r"(<(?:%s)[ ][^>]*?[^/]>)(?=[^\n])" % html_tags,
add_right,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
html = re.sub(
- r"%s\K(<(?:%s) [^>]+?/>)"
+ r"%s\K(<(?:%s)[ ][^>]+?/>)"
% (
break_char,
html_tags,
),
add_left,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
html = re.sub(
- r"(<(?:%s) [^>]+?/>)(?=[^\n])" % html_tags, add_right, html, flags=re.IGNORECASE
+ r"(<(?:%s)[ ][^>]+?/>)(?=[^\n])" % html_tags,
+ add_right,
+ html,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# process closing (break_char, html_tags,)s ######
@@ -156,50 +162,57 @@ def expand_html(html):
),
add_left,
html,
- flags=re.IGNORECASE,
+ flags=re.IGNORECASE | re.VERBOSE,
)
html = re.sub(
- r"((?:%s)>)(?=[^\n])" % html_tags, add_right, html, flags=re.IGNORECASE
+ r"((?:%s)>)(?=[^\n])" % html_tags,
+ add_right,
+ html,
+ flags=re.IGNORECASE | re.VERBOSE,
)
# template tag breaks
- def should_i_move_template_tag(out_format, match):
+ def should_i_move_template_tag(out_format: str, match: re.Match) -> str:
# ensure template tag is not inside an html tag
- html_tags = "|".join(break_html_tags)
- if _should_ignore(html, match):
+ if _should_ignore(config, html, match):
return match.group(1)
if not re.findall(
- r"\<(?:" + html_tags + r") [^>]*?" + re.escape(match.group(1)) + "$",
+ r"\<(?:"
+ + str(config.break_html_tags)
+ + r")[ ][^>]*?"
+ + re.escape(match.group(1))
+ + "$",
html[: match.end()],
- re.MULTILINE,
+ re.MULTILINE | re.VERBOSE,
):
return out_format % match.group(1)
return match.group(1)
- for tag in break_template_tags:
- # find all matching tags
+ # template tags
+ # break before
+ html = re.sub(
+ break_char
+ + r"\K((?:{%|{{\#)[ ]*?(?:"
+ + re.sub(r"\s", "", config.break_template_tags)
+ + ")[^}]+?[%|}]})",
+ partial(should_i_move_template_tag, "\n%s"),
+ html,
+ re.IGNORECASE | re.MULTILINE,
+ )
- html = re.sub(
- r"%s\K(%s)"
- % (
- break_char,
- tag,
- ),
- partial(should_i_move_template_tag, "\n%s"),
- html,
- re.IGNORECASE | re.MULTILINE,
- )
-
- html = re.sub(
- r"(%s)(?=[^\n])" % tag,
- partial(should_i_move_template_tag, "%s\n"),
- html,
- re.IGNORECASE | re.MULTILINE,
- )
+ # break after
+ html = re.sub(
+ r"((?:{%|{{\#)[ ]*?(?:"
+ + re.sub(r"\s", "", config.break_template_tags)
+ + ")[^}]+?[%|}]})(?=[^\n])",
+ partial(should_i_move_template_tag, "%s\n"),
+ html,
+ re.IGNORECASE | re.MULTILINE,
+ )
return html
diff --git a/src/djlint/formatter/indent_html.py b/src/djlint/formatter/indent_html.py
index 8197cdb..58bfc58 100644
--- a/src/djlint/formatter/indent_html.py
+++ b/src/djlint/formatter/indent_html.py
@@ -1,27 +1,13 @@
"""djLint add indentation to html."""
+from functools import partial
+
import regex as re
-from ..settings import (
- always_single_line_html_tags,
- attribute_pattern,
- break_html_tags,
- format_long_attributes,
- ignored_block_closing,
- ignored_block_opening,
- ignored_group_closing,
- ignored_group_opening,
- ignored_inline_blocks,
- indent,
- max_line_length,
- single_line_template_tags,
- tag_indent,
- tag_unindent,
- tag_unindent_line,
-)
+from ..settings import Config
-def _format_attributes(match):
+def _format_attributes(config: Config, match: re.match) -> str:
"""Spread long attributes over multiple lines."""
leading_space = match.group(1)
@@ -29,7 +15,9 @@ def _format_attributes(match):
spacing = "\n" + leading_space + len(tag) * " "
- attributes = (spacing).join(re.findall(attribute_pattern, match.group(3).strip()))
+ attributes = (spacing).join(
+ re.findall(str(config.attribute_pattern), match.group(3).strip(), re.VERBOSE)
+ )
close = match.group(4)
@@ -41,70 +29,92 @@ def _format_attributes(match):
)
-def indent_html(rawcode):
+def indent_html(rawcode: str, config: Config) -> str:
"""Indent raw code."""
rawcode_flat_list = re.split("\n", rawcode)
+ indent = config.indent
+
beautified_code = ""
indent_level = 0
is_block_raw = False
- slt_html = "|".join(
- break_html_tags
- ) # here using all tags cause we allow empty tags on one line
+ slt_html = config.break_html_tags
- always_slt_html = "|".join(
- always_single_line_html_tags
- ) # here using all tags cause we allow empty tags on one line
+ # here using all tags cause we allow empty tags on one line
+ always_slt_html = config.always_single_line_html_tags
- slt_template = "|".join(single_line_template_tags)
+ # here using all tags cause we allow empty tags on one line
+ slt_template = config.single_line_template_tags
for item in rawcode_flat_list:
# if a raw tag then start ignoring
- if (
- re.search("|".join(ignored_group_opening), item, re.IGNORECASE)
- ) or re.search("|".join(ignored_group_opening), item, re.IGNORECASE):
+ if re.search(config.ignored_group_opening, item, re.IGNORECASE | re.VERBOSE):
is_block_raw = True
if re.findall(
- r"(?:%s)" % "|".join(ignored_inline_blocks), item, flags=re.IGNORECASE
+ config.ignored_inline_blocks, item, flags=re.IGNORECASE | re.VERBOSE
):
tmp = (indent * indent_level) + item + "\n"
# if a one-line, inline tag, just process it, only if line starts w/ it
elif (
- re.findall(r"(<(%s)>)(.*?)((\2)>)" % slt_html, item, re.IGNORECASE)
- or re.findall(r"(<(%s) .+?>)(.*?)((\2)>)" % slt_html, item, re.IGNORECASE)
- or re.findall(
- r"^({% +?(" + slt_template + r") +?.+?%})(.*?)({% +?end(\2) +?.*?%})",
- item,
- re.IGNORECASE | re.MULTILINE,
+ re.findall(
+ r"(<(%s)>)(.*?)((\2)>)" % slt_html, item, re.IGNORECASE | re.VERBOSE
)
- or re.findall(r"(<(%s) .*?/>)" % slt_html, item, flags=re.IGNORECASE)
or re.findall(
- r"(<(%s) .*?/?>)" % always_slt_html, item, flags=re.IGNORECASE
+ r"(<(%s)[ ].+?>)(.*?)((\2)>)" % slt_html,
+ item,
+ re.IGNORECASE | re.VERBOSE,
+ )
+ or re.findall(
+ r"^({%[ ]*?("
+ + str(slt_template)
+ + r")[ ]+?.+?%})(.*?)({%[ ]+?end(\2)[ ]+?.*?%})",
+ item,
+ re.IGNORECASE | re.MULTILINE | re.VERBOSE,
+ )
+ or re.findall(
+ r"(<(%s)[ ].*?/>)" % slt_html, item, flags=re.IGNORECASE | re.VERBOSE
+ )
+ or re.findall(
+ r"(<(%s)[ ].*?/?>)" % always_slt_html,
+ item,
+ flags=re.IGNORECASE | re.VERBOSE,
)
) and is_block_raw is False:
tmp = (indent * indent_level) + item + "\n"
# if unindent, move left
elif (
- re.search(r"^(?:" + tag_unindent + r")", item, re.IGNORECASE | re.MULTILINE)
+ re.search(
+ config.tag_unindent,
+ item,
+ re.IGNORECASE | re.MULTILINE | re.VERBOSE,
+ )
and is_block_raw is False
- or re.search("|".join(ignored_block_closing), item, re.IGNORECASE)
+ or re.search(config.ignored_block_closing, item, re.IGNORECASE | re.VERBOSE)
):
indent_level = max(indent_level - 1, 0)
tmp = (indent * indent_level) + item + "\n"
elif (
- re.search(r"^" + tag_unindent_line, item, re.IGNORECASE | re.MULTILINE)
+ re.search(
+ r"^" + str(config.tag_unindent_line),
+ item,
+ re.IGNORECASE | re.MULTILINE | re.VERBOSE,
+ )
and is_block_raw is False
):
tmp = (indent * (indent_level - 1)) + item + "\n"
# if indent, move right
elif (
- re.search(r"^(?:" + tag_indent + r")", item, re.IGNORECASE | re.MULTILINE)
+ re.search(
+ r"^(?:" + str(config.tag_indent) + r")",
+ item,
+ re.IGNORECASE | re.MULTILINE | re.VERBOSE,
+ )
and is_block_raw is False
):
tmp = (indent * indent_level) + item + "\n"
@@ -123,7 +133,7 @@ def indent_html(rawcode):
# we can try to fix template tags
tmp = re.sub(r"({[{|%]\-?)(\w[^}].+?)([}|%]})", r"\1 \2\3", tmp)
- tmp = re.sub(r"({[{|%])([^}].+?[^(?: |\-)])([}|%]})", r"\1\2 \3", tmp)
+ tmp = re.sub(r"({[{|%])([^}].+?[^(?:\ |\-)])([}|%]})", r"\1\2 \3", tmp)
tmp = re.sub(r"({[{|%])([^}].+?[^ ])(\-[}|%]})", r"\1\2 \3", tmp)
# handlebars templates
@@ -132,23 +142,29 @@ def indent_html(rawcode):
# if a opening raw tag then start ignoring.. only if there is no closing tag
# on the same line
if (
- re.search("|".join(ignored_group_opening), item, re.IGNORECASE)
- ) or re.search("|".join(ignored_block_opening), item, re.IGNORECASE):
+ re.search(config.ignored_group_opening, item, re.IGNORECASE | re.VERBOSE)
+ ) or re.search(config.ignored_block_opening, item, re.IGNORECASE | re.VERBOSE):
is_block_raw = True
# if a normal tag, we can try to expand attributes
elif (
- format_long_attributes
+ config.format_long_attributes
and is_block_raw is False
- and len(tmp) > max_line_length
+ and len(tmp) > int(config.max_line_length)
):
# get leading space, and attributes
- tmp = re.sub(r"(\s*?)(<\w+\s)([^>]+?)(/?>)", _format_attributes, tmp)
+ func = partial(_format_attributes, config)
+ tmp = re.sub(r"(\s*?)(<\w+\s)([^>]+?)(/?>)", func, tmp)
# turn off raw block if we hit end - for one line raw blocks
if (
- re.search("|".join(ignored_group_closing), item, re.IGNORECASE)
- ) or re.search("|".join(ignored_block_closing), item, re.IGNORECASE):
+ re.search(
+ re.sub(r"\s", "", config.ignored_group_closing), item, re.IGNORECASE
+ )
+ ) or re.search(
+ re.sub(r"\s", "", config.ignored_block_closing), item, re.IGNORECASE
+ ):
+
is_block_raw = False
beautified_code = beautified_code + tmp
diff --git a/src/djlint/lint.py b/src/djlint/lint.py
index c9818bf..b473602 100644
--- a/src/djlint/lint.py
+++ b/src/djlint/lint.py
@@ -1,9 +1,12 @@
"""Djlint html linter."""
from pathlib import Path
+from typing import Dict, List
import regex as re
import yaml
+from .settings import Config
+
rules = yaml.load(
(Path(__file__).parent / "rules.yaml").read_text(encoding="utf8"),
Loader=yaml.SafeLoader,
@@ -24,7 +27,7 @@ flags = {
}
-def build_flags(flag_list):
+def build_flags(flag_list: str) -> int:
"""Build list of regex flags."""
split_flags = flag_list.split("|")
@@ -34,14 +37,14 @@ def build_flags(flag_list):
return combined_flags
-def get_line(start, line_ends):
+def get_line(start: int, line_ends: List) -> str:
"""Get the line number and index of match."""
line = list(filter(lambda pair: pair["end"] > start, line_ends))[0]
return "%d:%d" % (line_ends.index(line) + 1, start - line["start"])
-def lint_file(ignore: str, this_file: Path):
+def lint_file(config: Config, this_file: Path) -> Dict:
"""Check file for formatting errors."""
file_name = str(this_file)
errors: dict = {file_name: []}
@@ -54,7 +57,7 @@ def lint_file(ignore: str, this_file: Path):
]
for rule in list(
- filter(lambda x: x["rule"]["name"] not in ignore.split(","), rules)
+ filter(lambda x: x["rule"]["name"] not in config.ignore.split(","), rules)
):
rule = rule["rule"]
diff --git a/src/djlint/reformat.py b/src/djlint/reformat.py
index b11dad0..96fa941 100644
--- a/src/djlint/reformat.py
+++ b/src/djlint/reformat.py
@@ -9,9 +9,10 @@ from pathlib import Path
from .formatter.compress_html import compress_html
from .formatter.expand_html import expand_html
from .formatter.indent_html import indent_html
+from .settings import Config
-def reformat_file(check: bool, this_file: Path):
+def reformat_file(config: Config, check: bool, this_file: Path) -> dict:
"""Reformat html file."""
rawcode = this_file.read_text(encoding="utf8")
@@ -21,9 +22,9 @@ def reformat_file(check: bool, this_file: Path):
while itteration < 10:
- expanded = expand_html(rawcode)
- compressed = compress_html(expanded)
- indented = indent_html(compressed)
+ expanded = expand_html(rawcode, config)
+ compressed = compress_html(expanded, config)
+ indented = indent_html(compressed, config)
if (
len(
diff --git a/src/djlint/rules.yaml b/src/djlint/rules.yaml
index 64e6869..c554789 100644
--- a/src/djlint/rules.yaml
+++ b/src/djlint/rules.yaml
@@ -116,6 +116,7 @@
flags: re.DOTALL|re.I
patterns:
- <(img|input|area|base|br|col|embed|hr|link|meta|param|source|track|wbr|command|keygen|menuitem|path)[^>]*?[^/]>
+ - <(img|input|area|base|br|col|embed|hr|link|meta|param|source|track|wbr|command|keygen|menuitem|path)>
- rule:
name: W018
message: Internal links should use the {% url ... %} pattern.
diff --git a/src/djlint/settings.py b/src/djlint/settings.py
index 67620ec..4b07f8d 100644
--- a/src/djlint/settings.py
+++ b/src/djlint/settings.py
@@ -2,234 +2,521 @@
# pylint: disable=C0301,C0103
# flake8: noqa
-# default indentation
-indent = " "
-# contents of tags will not be formatted, but tags will be formatted
-ignored_block_opening = [r"
+ |
+ | \#}
+ | ]*?)((?:\n[^>]+?)+?)(/?\>)
+ """
+
+ self.ignored_attributes: list = [r"""data-json"""]
+
+ self.start_template_tags: str = (
+ r"""
+ if
+ | for
+ | block
+ | spaceless
+ | compress
+ | load
+ | assets
+ | addto
+ | language
+ | with
+ | assets
+ | autoescape
+ | comment
+ | filter
+ | verbatim
+ | each
+ """
+ + self.custom_blocks
+ + r"""
+ """
+ )
+
+ self.break_template_tags: str = (
+ r"""
+ if
+ | end
+ | for
+ | block
+ | endblock
+ | else
+ | spaceless
+ | compress
+ | load
+ | include
+ | assets
+ | addto
+ | language
+ | with
+ | assets
+ | autoescape
+ | comment
+ | filter
+ | elif
+ | resetcycle
+ | verbatim
+ | each
+ """
+ + self.custom_blocks
+ + r"""
+ """
+ )
+
+ self.ignored_blocks: list = [
+ r"<(script|style|pre|textarea).*?(?:%s).*?(\1)>",
+ r"",
+ r"{\*.*?(?:%s).*?\*}",
+ r"{\#.*?(?:%s).*?#}",
+ r"<\?php.*?(?:%s).*?\?>",
+ ]
+
+ self.ignored_inline_blocks: str = r"""
+
+ | {\*.*?\*}
+ | {\#.*?\#}
+ | <\?php.*?\?>
+ """
+
+ self.single_line_html_tags: str = r"""
+ button
+ | a
+ | h1
+ | h2
+ | h3
+ | h4
+ | h5
+ | h6
+ | td
+ | th
+ | strong
+ | em
+ | icon
+ | span
+ | title
+ | link
+ | path
+ | label
+ | div
+ | li
+ """
+
+ self.always_single_line_html_tags: str = r"""
+ link
+ | img
+ | meta
+ """
+
+ self.single_line_template_tags: str = r"""
+ if
+ | for
+ | block
+ | with
+ | comment
+ """
+
+ 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
+ | 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
+ """