diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d80350..c1f874a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,13 +9,11 @@ on: jobs: tests: name: Python ${{ matrix.python-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: - - 3.6 - - 3.7 - 3.8 - 3.9 - '3.10' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a4cd384..8b0fc01 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.1.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 diff --git a/README.md b/README.md index e6daacd..1e5f84c 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ ***A pure-Python Django/Jinja template indenter without dependencies.*** -DjHTML is a fully automatic template indenter that works with mixed -HTML/CSS/Javascript templates that contain +DjHTML indents mixed HTML/CSS/JavaScript templates that contain [Django](https://docs.djangoproject.com/en/stable/ref/templates/language/) or [Jinja](https://jinja.palletsprojects.com/templates/) template tags. It works similar to other code-formatting tools such as @@ -15,54 +14,77 @@ whitespace at the beginning of lines. It will not insert newlines or other characters. The goal is to correctly indent already well-structured templates, not to fix broken ones. -For example, consider the following incorrectly indented template: + +### New! Multi-line HTML elements + +As of version 3, DjHTML indents multi-line HTML elements and +multi-line attribute values like this: + +```jinja +
+ Don't you hate code that's not properly indented? +
+``` + + +### New! Multi-line CSS indentation + +Multi-line CSS values are now continued at the same indentation level: ```jinja - - - - {% block content %} - Hello, world! - {% endblock %} - - - + ``` -This is what it will look like after processing by DjHTML: + +### New! Improved JavaScript indentation + +Many new JavaScript indention rules have been added, such as the +indentation of method chaining: ```jinja - - - - {% block content %} - Hello, world! - {% endblock %} - - - + ``` +### New! Tabwidth guessing + +Without the `-t` / `--tabwidth` argument, DjHTML no longer defaults to +a tabwidth of 4 but instead guesses the correct tabwidth. + + ## Installation -DjHTML is compatible with all operating systems supported by Python. -Install DjHTML with the following command: +DjHTML requires Python 3.8 or higher and is compatible with all +operating systems supported by Python. Install DjHTML with the +following command: $ pip install djhtml -Note that [Windows still uses legacy code pages for the system -encoding](https://docs.python.org/3/using/windows.html#win-utf8-mode). -It is highly advised to set the environment variable `PYTHONUTF8` to -`1` to avoid issues with indenting UTF-8 files. You can do so with the +Note that +[Windows still uses legacy code pages](https://docs.python.org/3/using/windows.html#win-utf8-mode) +instead of UTF-8. It is highly advised to set the environment variable +`PYTHONUTF8` to `1` with the [setx](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setx) command: @@ -78,12 +100,14 @@ command: reindented template.html 1 template has been reindented. +You can also run `djhtml .` to indent all HTML files beneath the +current directory. + An exit status of 0 means that everything went well, regardless of whether any files were changed. When the option `-c` / `--check` is used, the exit status is 1 when one or more files would have changed, -but no changes are actually made. The exit status of 123 means that -there was an error while indenting one or more files. All available -options are given by `djthml -h` / `djthml --help`. +but no changes are actually made. All available options are given by +`djthml -h` / `djthml --help`. ## `fmt:off` and `fmt:on` @@ -92,13 +116,11 @@ You can exclude specific lines from being processed with the `{# fmt:off #}` and `{# fmt:on #}` operators: ```jinja -
+{# fmt:off #} + ,-._|\ + / .\ + \_,--._/ +{# fmt:on #} ``` Contents inside `
 ... 
`, ``, `/* ... */`, and @@ -124,7 +146,7 @@ The indenter operates in one of three different modes: ## pre-commit configuration -The best way to use DjHTML is as a [pre-commit](https://pre-commit.com/) +A great way to use DjHTML is as a [pre-commit](https://pre-commit.com/) hook, so all your HTML, CSS and JavaScript files will automatically be indented upon every commit. @@ -203,25 +225,36 @@ happy, please do the following: Your feedback for improving DjHTML is very welcome! + ## Development -Use your preferred system for setting up a virtualenv, docker environment, -or whatever else, then run the following: +First of all, clone this repository: -```sh -python -m pip install -e '.[dev]' -pre-commit install --install-hooks -``` + $ git clone https://github.com/rtts/djhtml + $ cd djhtml -Tests can then be run quickly in that environment: +Then, create a Python virtualenv and activate it: -```sh -python -m unittest discover -v -``` + $ python -m venv ~/.virtualenvs/djhtml + $ . ~/.virtualenvs/djhtml/bin/activate -Or testing in all available supported environments and linting can be run -with [`nox`](https://nox.thea.codes): +Then, install the package in [development +mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html) +including the `dev` dependencies, and install the pre-commit hooks: -```sh -nox -``` + $ python -m pip install -e '.[dev]' + $ pre-commit install --install-hooks + +You can run the unittests with: + + $ python -m unittest + +Or use [`nox`](https://nox.thea.codes) to test all supported Python +interpreters: + + $ nox + +Finally, to get a little insight into the tokenization step of the +indenting algorithm, you can run DjHTML with the `-d` / `--debug` +argument. You will see a Python representation of the tokens that are +created. diff --git a/djhtml/__main__.py b/djhtml/__main__.py index 5368a55..7e062e8 100644 --- a/djhtml/__main__.py +++ b/djhtml/__main__.py @@ -7,6 +7,12 @@ standard output. Example usage: $ djhtml - < input.html > output.html + +Passing a directory name will recurse into the directory and format +all files with typical extensions. For more fine-grained control of +which files get processed, use external tools like find, xargs or +pre-commit. + """ import sys @@ -51,12 +57,25 @@ def main(): _error(e) continue + # Guess tabwidth + if not options.tabwidth: + prev = 0 + probabilities = [0] * 9 + for line in source.splitlines(): + if line and not line.isspace(): + depth = _get_depth(line) + if abs(depth - prev) in [2, 4, 8]: + probabilities[abs(depth - prev)] += 1 + prev = depth + guess = probabilities.index(max(probabilities)) + # Indent input file try: - if options.debug: - print(Mode(source).debug()) - sys.exit() - result = Mode(source).indent(options.tabwidth) + result = Mode(source).indent(options.tabwidth or guess or 4) + except modes.MaxLineLengthExceeded: + problematic_files += 1 + _error(f"Maximum line length exceeded in {filename}") + continue except Exception: _error( f"Fatal error while processing {filename}\n\n" @@ -66,8 +85,7 @@ def main(): ) raise - changed = _verify_changed(source, result) - if changed: + if changed := _verify_changed(source, result): changed_files += 1 else: unchanged_files += 1 @@ -75,8 +93,7 @@ def main(): # Write output file if not options.check: if filename == "-": - if not options.quiet: - print(result, end="") + print(result, end="") elif changed: try: with open(filename, "w") as output_file: @@ -102,6 +119,9 @@ def main(): f"{problematic_files} template{s} could not be processed due to an error." ) + if options.debug: + print(Mode(source).debug(), file=sys.stderr) + # Exit with appropriate exit status if problematic_files: sys.exit(123) @@ -141,9 +161,20 @@ def _verify_changed(source, result): return changed +def _get_depth(line): + count = 0 + for char in line: + if char == " ": + count += 1 + elif char == "\t": + count += 4 + else: + break + return count + + def _info(msg): - if not options.quiet: - print(msg, file=sys.stderr) + print(msg, file=sys.stderr) def _error(msg): diff --git a/djhtml/lines.py b/djhtml/lines.py index 6314562..03f8153 100644 --- a/djhtml/lines.py +++ b/djhtml/lines.py @@ -2,57 +2,69 @@ class Line: """ A single output line not including the final newline. - The behavior regarding final newlines has changed between DjHTML - v1.4.14 and v1.5.0. It used to always append the final newline, - but now this will only happen when the source file already - contains a final newline. - - See https://github.com/rtts/djhtml/issues/56 for the discussion - that led to this change. - """ - def __init__(self, nr=1): - self.nr = nr - self.tokens = [] - self.level = 0 + def __init__(self, tokens=None, level=0, offset=0, ignore=False): + """ + Lines are currently never instantiated with arguments, but + that doesn't mean they can't. + + """ + self.tokens = tokens or [] + self.level = level + self.offset = offset + self.ignore = ignore def append(self, token): """ - Append tokens to the line. + Append token to line. """ - token.line_nr = self.nr self.tokens.append(token) @property def text(self): """ - The unindented text of this line without leading/trailing spaces. + The text of this line including the original + leading/trailing spaces. + + """ + return "".join([token.text for token in self.tokens]) + + @property + def indents(self): + """ + Whether this line has more opening than closing tokens. """ - return "".join([str(token) for token in self.tokens]).strip() + return len([token for token in self.tokens if token.indents]) > len( + [token for token in self.tokens if token.dedents] + ) def indent(self, tabwidth): """ - The final, indented text of this line. Make sure to set the level - and optionally offset before calling this method. + The final, indented text of this line. """ - if self.tokens: - if self.tokens[0].ignore: - return "".join([str(token) for token in self.tokens]) - elif self.text: - offset = self.tokens[0].offset * tabwidth - spaces = tabwidth * self.level + offset - return " " * spaces + self.text + if self.ignore: + return self.text + if text := self.text.strip(): + return " " * (tabwidth * self.level + self.offset) + text return "" - def __repr__(self): - return repr(self.tokens) + def __len__(self): + """ + The length of the line (so far), excluding the whitespace + at the beginning. Be careful calling len() because it might + result in trailing spaces being counted that will be removed + by indent(). - def __bool__(self): - return bool(self.tokens and self.text) + """ + return len(self.text.lstrip()) - def __next__(self): - return Line(nr=self.nr + 1) + def __repr__(self): + kwargs = "" + for attr in ["level", "offset", "ignore"]: + if value := getattr(self, attr): + kwargs += f", {attr}={value!r}" + return f"Line({self.tokens!r}{kwargs})" diff --git a/djhtml/modes.py b/djhtml/modes.py index d032a21..e2c8630 100644 --- a/djhtml/modes.py +++ b/djhtml/modes.py @@ -4,43 +4,30 @@ from .tokens import Token -class DjTXT: +class BaseMode: """ - Mode for indenting text files that contain Django/Jinja template tags. - Also serves as the base class for the other modes: - - - DjHTML - - DjCSS - - DjJS + Base class for the different modes. """ - RAW_TOKENS = [ - r"\n", - r"{%[-\+]?.*?[-\+]?%}", - r"{#.*?#}", - r"{#", - ] - OPENING_AND_CLOSING_TAGS = [ - "elif", - "else", - "empty", - "plural", - ] - AMBIGUOUS_BLOCK_TAGS = { - # token_name: (regex_if_block, regex_if_not_block) - "set": (None, " = "), - "video": (" as ", None), - } - FMT_ON = r"{# fmt:on #}" - FMT_OFF = r"{# fmt:off #}" - OPENING_TAG = r"{%[-\+]? *(\w+).*?[-\+]?%}" + MAX_LINE_LENGTH = 10_000 + + def __init__(self, source=None, return_mode=None): + """ + Instantiate with source text before calling indent(), or + with the return_mode when invoked from within another mode. + + """ + assert type(self) is not BaseMode + assert source is not None or return_mode - def __init__(self, source="", return_mode=None): self.source = source self.return_mode = return_mode or self self.token_re = compile_re(self.RAW_TOKENS) + # To keep track of the current offsets. + self.offsets = dict(relative=0, absolute=0) + def indent(self, tabwidth): """ Return the indented text as a single string. @@ -50,78 +37,18 @@ def indent(self, tabwidth): self.parse() return "\n".join([line.indent(tabwidth) for line in self.lines]) - def parse(self): - """ - You found the top-secret indenting algorithm! - - """ - stack = [] - for line in self.lines: - first_token = True - for token in line.tokens: - opening_token = None - - # When a dedenting token is found, match it with the - # token at the top of the stack. - if token.dedents: - try: - if ( - stack[-1].kind == token.kind - and stack[-1].is_hard == token.is_hard - ): - opening_token = stack.pop() - elif token.kind == "django": - opening_token = stack.pop() - while opening_token.kind != token.kind: - opening_token = stack.pop() - elif first_token: - # This closing token could not be matched. - # Instead of erroring out, set the line level - # to what it would have been with a - # regular text token. - - # If there is any OpenHard token in the - # set and current token is CloseHard then - # let's move back to OpenHard. - if token.is_hard and any( - t.is_hard and t.indents for t in stack - ): - s = stack.pop() - while not s.is_hard or not s.indents: - s = stack.pop() - - line.level = stack[-1].level + 1 - except IndexError: - line.level = 0 - - # If this dedenting token is the first in line, - # set the line level to the line level of the - # corresponding opening token. - if first_token and opening_token: - line.level = opening_token.level - - # If the first token is not a dedenting token, the - # line level will be one higher than that of the token - # at the top of the stack. - elif first_token: - line.level = stack[-1].level + 1 if stack else 0 - - # Push indenting tokens onto the stack. Note that some - # tokens can be both indenting and dedenting (e.g., - # ``{% else %}``), hence the if instead of elif. - if token.indents: - token.level = opening_token.level if opening_token else line.level - stack.append(token) - - # Subsequent tokens have no effect on the line level - # (but tokens with only spaces don't count). - if token.text.strip(): - first_token = False - def tokenize(self): """ Split the source text into tokens and place them on lines. + How text is split into raw tokens is defined by the regexes + of each mode. For each raw token, the create_token() method of + the mode is called. + + Some tokens, such a ", - r"[\{\(\)\}]", + r"[{()}]", r"/\*", + r'".+"', + r"'.+'", + r"[\w-]+: ", + r";", ] - def create_token(self, raw_token, src): - kind = "css" - self.next_mode = self + def create_token(self, raw_token, src, line): + mode = self if raw_token in "{(": - return Token.Open(raw_token, kind) - if raw_token in "})": - return Token.Close(raw_token, kind) - if raw_token == "/*": - self.next_mode = Comment(r"\*/", self, kind) - return Token.Open(raw_token, kind) - if raw_token == "": - self.next_mode = self.return_mode - return Token.Close(raw_token, "html") - - return super().create_token(raw_token, src) + token = Token.Open(raw_token, mode=DjCSS, **self.offsets) + if raw_token == "{": + self.offsets["absolute"] = 0 + elif raw_token in "})": + if raw_token == "}": + self.offsets["absolute"] = 0 + token = Token.Close(raw_token, mode=DjCSS, **self.offsets) + elif raw_token.endswith(": "): + token = Token.Text(raw_token, mode=DjCSS, **self.offsets) + self.offsets["absolute"] = len(line) + len(raw_token) + elif raw_token == ";": + self.offsets["absolute"] = 0 + token = Token.Text(raw_token, mode=DjCSS, **self.offsets) + elif raw_token == "/*": + token, mode = Token.Open(raw_token, mode=DjCSS, ignore=True), Comment( + r"\*/", mode=DjCSS, return_mode=self + ) + elif raw_token == "": + token, mode = ( + Token.Close(raw_token, mode=self.return_mode.__class__), + self.return_mode, + ) + else: + token, mode = super().create_token(raw_token, src, line) + + return token, mode class DjJS(DjTXT): @@ -321,61 +366,122 @@ class DjJS(DjTXT): """ RAW_TOKENS = DjTXT.RAW_TOKENS + [ - r"", - r'".*?"', - r"'.*?'", - r"`.*?`", - r"`", - r"[\{\[\(\)\]\}]", r"//.*", r"/\*", + r"[$\w-]+:", + r'"(?:\\.|[^\\"])*"', # "string" + r"'(?:\\.|[^\\'])*'", # 'string' + r"`(?:\\.|[^\\`])*`", # `string` + r"/(?:\\.|[^\\/\n])*/", # /string/ + r"[{[()\]}]", + r"var ", + r"let ", + r"const ", + r"if(?= *\()", + r"else(?= *\n)", + r"for(?= *\()", + r"while(?= *\()", + r"", ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.hard_indents = 0 - self.opened_brackets = 0 - - def create_token(self, raw_token, src): - kind = "javascript" - self.next_mode = self - - if raw_token.strip() == "switch": - self.hard_indents = self.hard_indents + 1 - - if self.hard_indents: - if raw_token == "{": - self.opened_brackets += 1 - if self.opened_brackets == self.hard_indents: - return Token.OpenHard(raw_token, kind) - elif raw_token == "}": - if self.opened_brackets == self.hard_indents: - self.opened_brackets -= 1 - self.hard_indents -= 1 - return Token.CloseHard(raw_token, kind) - self.opened_brackets -= 1 + self.previous_offsets = [] + self.haskell = False + self.haskell_re = re.compile(r"^ *, ([$\w-]+ *=|[$\w-]+;?)") + self.variable_re = re.compile(r"^ *([$\w-]+ *=|[$\w-]+;?)") + self.previous_line_ended_with_comma = False + def create_token(self, raw_token, src, line): + mode = self + persist_relative_offset = False + + # Reset absolute offset in almost all cases + if ( + not line + and not self.haskell_re.match(raw_token) + and not ( + self.variable_re.match(raw_token) + and self.previous_line_ended_with_comma + ) + ): + self.offsets["absolute"] = 0 + + # Opening and closing tokens if raw_token in "{[(": - return Token.Open(raw_token, kind) - if raw_token in ")]}": - return Token.Close(raw_token, kind) - if raw_token == "`": - self.next_mode = Comment("`", self, kind) - return Token.Open(raw_token, kind) - if raw_token == "/*": - self.next_mode = Comment(r"\*/", self, kind) - return Token.Open(raw_token, kind) - if raw_token.lstrip().startswith("."): - return Token.Text(raw_token, offset=1) - if raw_token.lstrip().startswith("case "): - return Token.OpenAndClose(raw_token, kind) - if raw_token.lstrip().startswith("default:"): - return Token.OpenAndClose(raw_token, kind) - if raw_token == "": - self.next_mode = self.return_mode - return Token.Close(raw_token, "html") - - return super().create_token(raw_token, src) + self.previous_offsets.append(self.offsets.copy()) + self.offsets = dict(relative=0, absolute=0) + token = Token.Open(raw_token, mode=DjJS) + elif raw_token in ")]}": + if self.previous_offsets: + self.offsets = self.previous_offsets.pop() + if raw_token == ")": + persist_relative_offset = True + token = Token.Close(raw_token, mode=DjJS) + elif raw_token == "/*": + token, mode = Token.Open(raw_token, mode=DjJS, ignore=True), Comment( + r"\*/", mode=DjJS, return_mode=self + ) + elif raw_token.startswith("//"): + token = Token.Text(raw_token, mode=DjJS, ignore=True) + + # "Double" tokens + elif not line and raw_token.lstrip().startswith("case "): + token = Token.OpenDouble(raw_token, mode=DjJS) + return token, mode + elif raw_token.rstrip().endswith("default:"): + token = Token.OpenDouble(raw_token, mode=DjJS) + return token, mode + + # Tokens that mess with relative offset + elif raw_token.lstrip().startswith("..."): + token = Token.Text(raw_token, mode=DjJS) + elif not line and raw_token.lstrip().startswith((".", ": ", "? ")): + token = Token.Text(raw_token, mode=DjJS, relative=1) + elif not line and raw_token in ["if", "else", "for", "while"]: + token = Token.Text(raw_token, mode=DjJS, **self.offsets) + self.offsets["relative"] += 1 + persist_relative_offset = True + elif raw_token.rstrip().endswith(("=", ":")): + token = Token.Text(raw_token, mode=DjJS, **self.offsets) + if not line.indents: + self.offsets["relative"] = 1 + persist_relative_offset = True + + # Tokens that mess with absolute offset + elif raw_token in ["var ", "let ", "const "]: + token = Token.Text(raw_token, mode=DjJS) + self.offsets["absolute"] = len(line) + len(raw_token) + elif ( + not line + and not self.haskell + and not self.previous_line_ended_with_comma + and self.haskell_re.match(raw_token) + ): + self.haskell = True + self.offsets["absolute"] -= 2 + token = Token.Text(raw_token, mode=DjJS, **self.offsets) + + # Get out of this mess! + elif raw_token == "": + token, mode = ( + Token.Close(raw_token, mode=self.return_mode.__class__), + self.return_mode, + ) + else: + token, mode = super().create_token(raw_token, src, line) + + # Reset relative offset in almost all cases + if not persist_relative_offset and raw_token.strip(): + self.offsets["relative"] = 0 + + # Remember whether the line ended with a comma + if raw_token.rstrip().endswith(","): + self.previous_line_ended_with_comma = True + else: + self.previous_line_ended_with_comma = False + + return token, mode # The following are "special" modes with different constructors. @@ -387,18 +493,16 @@ class Comment(DjTXT): """ - def __init__(self, endtag, return_mode, kind): + def __init__(self, endtag, *, mode, return_mode): self.endtag = endtag + self.mode = mode self.return_mode = return_mode - self.kind = kind self.token_re = compile_re([r"\n", endtag]) - def create_token(self, raw_token, src): - self.next_mode = self + def create_token(self, raw_token, src, line): if re.match(self.endtag, raw_token): - self.next_mode = self.return_mode - return Token.Close(raw_token, self.kind) - return Token.Ignore(raw_token) + return Token.Close(raw_token, mode=self.mode, ignore=True), self.return_mode + return Token.Text(raw_token, mode=Comment, ignore=True), self class InsideHTMLTag(DjTXT): @@ -407,43 +511,68 @@ class InsideHTMLTag(DjTXT): """ - RAW_TOKENS = DjTXT.RAW_TOKENS + [r"/?>", r'"'] + RAW_TOKENS = DjTXT.RAW_TOKENS + [r"/?>", r"[^ ='\">/]+=", r'"', r"'"] - def __init__(self, tagname, return_mode): + def __init__(self, tagname, line, return_mode): self.tagname = tagname self.return_mode = return_mode self.token_re = compile_re(self.RAW_TOKENS) self.inside_attr = False + self.offsets = dict( + relative=-1 if line.indents else 0, absolute=len(line) + len(tagname) + 2 + ) - def create_token(self, raw_token, src): - kind = "html" - self.next_mode = self + # Pff... + self.additional_offset = -len(tagname) - 1 - if raw_token == '"': + def create_token(self, raw_token, src, line): + mode = self + + if not line: + self.additional_offset = 0 + self.additional_offset += len(raw_token) + + if "text/template" in raw_token: + self.tagname = "" + + if raw_token in ['"', "'"]: if self.inside_attr: - self.inside_attr = False - return Token.Close(raw_token, kind) - self.inside_attr = True - return Token.Open(raw_token, kind) + token = Token.Text(raw_token, mode=InsideHTMLTag, **self.offsets) + if self.inside_attr == raw_token: + self.inside_attr = False + token.absolute = self.offsets["absolute"] - 1 + self.offsets["absolute"] = self.previous_offset + else: + self.inside_attr = raw_token + self.previous_offset = self.offsets["absolute"] + self.offsets["absolute"] += self.additional_offset + token = Token.Text(raw_token, mode=InsideHTMLTag, **self.offsets) elif not self.inside_attr and raw_token == "/>": - self.next_mode = self.return_mode - return Token.Close(raw_token, kind) + token, mode = Token.Text(raw_token, mode=DjHTML), self.return_mode elif not self.inside_attr and raw_token == ">": if self.tagname.lower() in DjHTML.IGNORE_TAGS: - self.next_mode = self.return_mode - return Token.Close(raw_token, kind) + token, mode = Token.Text(raw_token, mode=DjHTML), self.return_mode + elif self.tagname == "style": + token, mode = Token.Open(raw_token, mode=DjHTML), DjCSS( + return_mode=self.return_mode + ) + elif self.tagname == "script": + token, mode = Token.Open(raw_token, mode=DjHTML), DjJS( + return_mode=self.return_mode + ) else: - if self.tagname == "style": - self.next_mode = DjCSS(return_mode=self.return_mode) - elif self.tagname == "script": - self.next_mode = DjJS(return_mode=self.return_mode) - else: - self.next_mode = self.return_mode - return Token.OpenAndClose(raw_token, kind) - elif "text/template" in raw_token: - self.tagname = "" + token, mode = ( + Token.Open(raw_token, mode=DjHTML), + self.return_mode, + ) + else: + token, mode = super().create_token(raw_token, src, line) + + return token, mode + - return super().create_token(raw_token, src) +class MaxLineLengthExceeded(Exception): + pass def compile_re(raw_tokens): diff --git a/djhtml/options.py b/djhtml/options.py index 9fee2b1..3d05b85 100644 --- a/djhtml/options.py +++ b/djhtml/options.py @@ -3,19 +3,38 @@ import options print(f"Tabwidth is {options.tabwidth}") + """ import argparse import sys +from importlib.metadata import version parser = argparse.ArgumentParser( description=( - "DjHTML is a fully automatic template indenter that works with mixed" - " HTML/CSS/Javascript templates that contain Django or Jinja template" - " tags. It works similar to other code-formatting tools such as Black and" - " interoperates nicely with pre-commit. Full documentation can be found at" - " https://github.com/rtts/djhtml" + """ +DjHTML indents mixed HTML/CSS/JavaScript templates that +contain Django or Jinja template tags. It works similar to +other code-formatting tools such as Black and interoperates +nicely with pre-commit.""" ), + epilog="Full documentation at https://github.com/rtts/djhtml", + formatter_class=argparse.RawDescriptionHelpFormatter, + add_help=False, +) +parser.add_argument( + "-h", + "--help", + dest="show_help", + action="store_true", + help="show this help message and exit", +) +parser.add_argument( + "-v", + "--version", + dest="show_version", + action="store_true", + help="show version number and exit", ) parser.add_argument( "-c", @@ -23,20 +42,19 @@ action="store_true", help="check indentation without modifying files", ) -parser.add_argument("-q", "--quiet", action="store_true", help="be quiet") parser.add_argument( "-t", "--tabwidth", metavar="N", type=int, - default=4, - help="tabwidth (default is 4)", + default=0, + help="tabwidth (the default is to guess)", ) parser.add_argument( "input_filenames", - metavar="filename", - nargs="+", - help="input filenames (either paths or directories)", + metavar="SOURCE", + nargs="*", + help="file or directory name(s) to indent", ) parser.add_argument("-d", "--debug", action="store_true", help=argparse.SUPPRESS) parser.add_argument("-i", "--in-place", action="store_true", help=argparse.SUPPRESS) @@ -45,7 +63,13 @@ self = sys.modules[__name__] args = parser.parse_args(namespace=self) -if self.in_place: +if show_version: + print(version("djhtml")) + sys.exit() +elif show_help or not input_filenames: + parser.print_help() + sys.exit() +elif in_place: sys.exit( """ You have called DjHTML with the -i or --in-place argument which diff --git a/djhtml/tokens.py b/djhtml/tokens.py index 308ef49..831fe7a 100644 --- a/djhtml/tokens.py +++ b/djhtml/tokens.py @@ -8,37 +8,50 @@ class _Base: indents = False dedents = False ignore = False - is_hard = False - - def __init__(self, text, kind="", offset=0): + is_double = False + + def __init__( + self, text, *, mode, level=0, relative=0, absolute=0, ignore=False + ): + """ + Tokens must have a text and a mode class. The level + represents the line level of opening tokens and is set + afterwards by the parser. This violates the principle of + encapsulation, but makes sense because the line level can + only be determined after the tokenization is complete. + + """ self.text = text - self.kind = kind - self.offset = offset - - def __str__(self): - return self.text + self.mode = mode + self.level = level + self.relative = relative + self.absolute = absolute + self.ignore = ignore def __repr__(self): - return f"({self.__class__.__name__}:{repr(self.text)})" + kwargs = f", mode={self.mode.__name__}" + for attr in ["level", "relative", "absolute", "ignore"]: + if value := getattr(self, attr): + kwargs += f", {attr}={value!r}" + return f"{self.__class__.__name__}({self.text!r}{kwargs})" class Text(_Base): pass - class Ignore(_Base): - ignore = True - class Open(_Base): indents = True - class OpenHard(Open): - is_hard = True + class OpenDouble(_Base): + indents = True + is_double = True class Close(_Base): dedents = True - class CloseHard(Close): - is_hard = True + class CloseDouble(_Base): + dedents = True + is_double = True - class OpenAndClose(_Base): + class CloseAndOpen(_Base): indents = True dedents = True diff --git a/noxfile.py b/noxfile.py index 0ff90eb..13b1406 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,6 +1,6 @@ import nox -@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]) +@nox.session(python=["3.8", "3.9", "3.10", "3.11"]) def tests(session): - session.run("python", "-m", "unittest", "discover", "-v") + session.run("python", "-m", "unittest") diff --git a/setup.cfg b/setup.cfg index ca589da..fb2d9c2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = djhtml -version = 2.0.0 +version = 3.0.0 description = Django/Jinja template indenter long_description = file: README.md long_description_content_type = text/markdown @@ -11,15 +11,13 @@ license = GPLv3+ classifiers = Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Operating System :: OS Independent -python_requires = '>=3.6' +python_requires = '>=3.8' [options] packages = find: @@ -27,9 +25,6 @@ packages = find: [options.extras_require] dev = nox - isort - black - flake8 pre-commit [options.packages.find] @@ -45,6 +40,8 @@ console_scripts = [flake8] max-line-length = 88 extend-ignore = E203 +per-file-ignores = + djhtml/options.py: F821 [isort] profile = black diff --git a/tests/generate_tokens.py b/tests/generate_tokens.py new file mode 100755 index 0000000..5ffb11f --- /dev/null +++ b/tests/generate_tokens.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +""" +Generate *.tokens files from *.html files in the suite directory. + +""" + +from pathlib import Path + +from djhtml.modes import DjHTML + +DIR = Path(__file__).parent / "suite" + +for filename in DIR.iterdir(): + if filename.suffix == ".html": + with open(DIR / filename) as html: + with open(DIR / (filename.stem + ".tokens"), "w") as f: + f.write(DjHTML(html.read()).debug()) diff --git a/tests/suite/css.html b/tests/suite/css.html new file mode 100644 index 0000000..477eb95 --- /dev/null +++ b/tests/suite/css.html @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/suite/css.in b/tests/suite/css.in deleted file mode 100644 index 4ee1693..0000000 --- a/tests/suite/css.in +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - diff --git a/tests/suite/css.out b/tests/suite/css.out deleted file mode 100644 index 359adf0..0000000 --- a/tests/suite/css.out +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - diff --git a/tests/suite/css.tokens b/tests/suite/css.tokens new file mode 100644 index 0000000..12da6cb --- /dev/null +++ b/tests/suite/css.tokens @@ -0,0 +1,190 @@ +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' a ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('text-decoration: ', mode=DjCSS), Text('none', mode=DjCSS, absolute=17), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' a ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('text-decoration: ', mode=DjCSS), Text('none', mode=DjCSS, absolute=17), Text(';', mode=DjCSS)], level=2) +Line([Text(' &:hover ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('text-decoration: ', mode=DjCSS), Text('underline', mode=DjCSS, absolute=17), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjCSS), Open('/*', mode=DjCSS, level=1, ignore=True)], level=1, ignore=True) +Line([Text(' * Hi mom!', mode=Comment, ignore=True)], level=2, ignore=True) +Line([Text(' *', mode=Comment, ignore=True)], level=2, ignore=True) +Line([Text(' ', mode=Comment, ignore=True), Close('*/', mode=DjCSS, ignore=True)], level=1, ignore=True) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' #gradient ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('background: ', mode=DjCSS), Text('linear-gradient', mode=DjCSS, absolute=12), Open('(', mode=DjCSS, level=2, absolute=12)], level=2) +Line([Text(' to top left,', mode=DjCSS, absolute=12)], level=3, offset=12) +Line([Text(' rgba', mode=DjCSS, absolute=12), Open('(', mode=DjCSS, level=3, absolute=12), Text('204,0,0,1', mode=DjCSS, absolute=12), Close(')', mode=DjCSS, absolute=12), Text(',', mode=DjCSS, absolute=12)], level=3, offset=12) +Line([Text(' rgba', mode=DjCSS, absolute=12), Open('(', mode=DjCSS, level=3, absolute=12), Text('204,0,0,0', mode=DjCSS, absolute=12), Close(')', mode=DjCSS, absolute=12)], level=3, offset=12) +Line([Text(' ', mode=DjCSS, absolute=12), Close(')', mode=DjCSS, absolute=12), Text(';', mode=DjCSS)], level=2, offset=12) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' @font-face ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('font-family: ', mode=DjCSS), Text("'Open Sans'", mode=DjCSS, absolute=13), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('font-style: ', mode=DjCSS), Text('normal', mode=DjCSS, absolute=12), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('font-weight: ', mode=DjCSS), Text('normal', mode=DjCSS, absolute=13), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('src: ', mode=DjCSS), Text('url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Open_Sans.woff2') format('woff2'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=2) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Open_Sans.woff') format('woff'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=2, offset=5) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Open_Sans.eot?#iefix') format('embedded-opentype'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=2, offset=5) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Open_Sans.svg#OpenSans') format('svg'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=2, offset=5) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Open_Sans.ttf') format('truetype'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(';', mode=DjCSS)], level=2, offset=5) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' @font-face ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('font-family: ', mode=DjCSS), Text('Helvetica', mode=DjCSS, absolute=13), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('src: ', mode=DjCSS), Open('{% for format, filename in licensed_fonts %}', mode=DjTXT, level=2, absolute=5)], level=2) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=3, absolute=5), Text("'{% static filename %}') format('{{ format }}'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=3, offset=5) +Line([Text(' ', mode=DjCSS, absolute=5), Close('{% endfor %}', mode=DjTXT, absolute=5)], level=2, offset=5) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Arial.woff2') format('woff2'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(',', mode=DjCSS, absolute=5)], level=2, offset=5) +Line([Text(' url', mode=DjCSS, absolute=5), Open('(', mode=DjCSS, level=2, absolute=5), Text("'Arial.woff') format('woff'", mode=DjCSS, absolute=5), Close(')', mode=DjCSS, absolute=5), Text(';', mode=DjCSS)], level=2, offset=5) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' @media', mode=DjCSS), Open('(', mode=DjCSS, level=1), Text('max-width: ', mode=DjCSS), Text('800px', mode=DjCSS, absolute=18), Close(')', mode=DjCSS, absolute=18), Text(' ', mode=DjCSS, absolute=18), Open('{', mode=DjCSS, level=1, absolute=18)], level=1) +Line([Text(' body ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('margin-top: ', mode=DjCSS), Text('1em', mode=DjCSS, absolute=12), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Text('margin-bottom: ', mode=DjCSS), Text('1em', mode=DjCSS, absolute=15), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=1), Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left ', mode=DjCSS, absolute=11), Close('}', mode=DjCSS)], level=1) +Line([Text(' h1 ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('font-weight: ', mode=DjCSS), Text('bold', mode=DjCSS, absolute=13), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('font-size: ', mode=DjCSS), Text('huge', mode=DjCSS, absolute=11)], level=2) +Line([Text(' ', mode=DjCSS, absolute=11), Close('}', mode=DjCSS)], level=1) +Line([Text(' footnote ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('dontread: ', mode=DjCSS), Text('true !important', mode=DjCSS, absolute=10)], level=2) +Line([Text(' ', mode=DjCSS, absolute=10), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=2), Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=11), Text(';', mode=DjCSS), Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left ', mode=DjCSS, absolute=24), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=2), Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=11), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left ', mode=DjCSS, absolute=7), Close('}', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left ', mode=DjCSS, absolute=7), Close('}', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=2), Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=11), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left', mode=DjCSS, absolute=7)], level=3) +Line([Text(' ', mode=DjCSS, absolute=7), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left', mode=DjCSS, absolute=7)], level=3) +Line([Text(' ', mode=DjCSS, absolute=7), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' article ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' p', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('#999', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Text('align: ', mode=DjCSS), Text('left', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' blockquote:before ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('content: ', mode=DjCSS), Text('"text-align: right"', mode=DjCSS, absolute=9), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Text(' @media', mode=DjCSS), Open('(', mode=DjCSS, level=1), Text('text-align: ', mode=DjCSS), Text('right', mode=DjCSS, absolute=19), Close(')', mode=DjCSS, absolute=19), Text(' ', mode=DjCSS, absolute=19), Open('{', mode=DjCSS, level=1, absolute=19)], level=1) +Line([Text(' a:hover, a:active ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' text-decoration:none', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' p::first-line ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('red', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' a:hover, a:active ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('foo: ', mode=DjCSS), Text('bar,', mode=DjCSS, absolute=5)], level=2) +Line([Text(' baz', mode=DjCSS, absolute=5), Text(';', mode=DjCSS)], level=2, offset=5) +Line([]) +Line([Text(' a:hover, a:active ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('foo: ', mode=DjCSS), Text('bar', mode=DjCSS, absolute=5)], level=3) +Line([Text(' baz', mode=DjCSS, absolute=5)], level=3, offset=5) +Line([Text(' ', mode=DjCSS, absolute=5), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' body ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('font-family: ', mode=DjCSS), Text('Arial,', mode=DjCSS, absolute=13)], level=2) +Line([Text(' Helvetica', mode=DjCSS, absolute=13), Text(';', mode=DjCSS)], level=2, offset=13) +Line([Text(' a:link,', mode=DjCSS)], level=2) +Line([Text(' a:hover,', mode=DjCSS)], level=2) +Line([Text(' a:active ', mode=DjCSS), Open('{', mode=DjCSS, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('red', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([]) +Line([Text(' ', mode=DjCSS), Open('/*', mode=DjCSS, level=1, ignore=True), Text(' Since DjCSS expects a space between the property and the value,', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' the following is currently broken ', mode=Comment, ignore=True), Close('*/', mode=DjCSS, ignore=True)], level=2, ignore=True) +Line([Text(' body ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' font-family:Arial,', mode=DjCSS)], level=2) +Line([Text(' Helvetica', mode=DjCSS), Text(';', mode=DjCSS)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' body ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('green', mode=DjCSS, absolute=7), Text(';', mode=DjCSS), Text(' ', mode=DjCSS), Text('font-family: ', mode=DjCSS), Text('Arial,', mode=DjCSS, absolute=27)], level=2) +Line([Text(' Helvetica', mode=DjCSS, absolute=27), Text(';', mode=DjCSS)], level=2, offset=27) +Line([]) +Line([Text(' ', mode=DjCSS), Open('/*', mode=DjCSS, level=2, ignore=True), Text(' Spaces within lines are always preserved ', mode=Comment, ignore=True), Close('*/', mode=DjCSS, ignore=True)], level=2, ignore=True) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('red', mode=DjCSS, absolute=7), Text(';', mode=DjCSS), Text(' ', mode=DjCSS), Text('font-family: ', mode=DjCSS), Text('Arial,', mode=DjCSS, absolute=27)], level=2) +Line([Text(' Helvetica', mode=DjCSS, absolute=27), Text(';', mode=DjCSS)], level=2, offset=27) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) \ No newline at end of file diff --git a/tests/suite/django.out b/tests/suite/django.html similarity index 68% rename from tests/suite/django.out rename to tests/suite/django.html index faf9e9b..f31857f 100644 --- a/tests/suite/django.out +++ b/tests/suite/django.html @@ -1,3 +1,13 @@ + +
+ + {% load static %} {% block content %} @@ -110,3 +120,46 @@

Welcome, {{ request.user }}

{% endwith %} {% endslot %} {% endcomponent_block %} + + + +{{ '' if condition }} +some text +{{ '' if condition }} +more text + + + +{{ '' + if condition }} + some text + {{ ' +if condition }} +more text + + + +{% block main %} +
+
+
+ {% placeholder "placeholder1" %} +
+
+ {% placeholder "placeholder2" or %} + + {% endplaceholder %} +
+
+
+
+
+ {% placeholder "placeholder3" %} +
+
+
+
+ {% placeholder "placeholder4" %} +
+
+{% endblock %} diff --git a/tests/suite/django.in b/tests/suite/django.in deleted file mode 100644 index 65bd342..0000000 --- a/tests/suite/django.in +++ /dev/null @@ -1,112 +0,0 @@ - -{% load static %} -{% block content %} -{% if request.user.is_authenticated %} -

Welcome, {{ request.user }}

-{% else %} -Click here to login -{% endif %} -{% endblock %} - - - - - - - - - - - -{% comment %} - ,-._|\ - / .\ - \_,--._/ -{% endcomment %} - - - -{% verbatim %} - ,-._|\ - / .\ - \_,--._/ -{% endverbatim %} - - - -{% comment "Yo dawg" %} - I heard you like comments -{% endcomment %} - - - -{%comment %} - %} -{% endcomment%} -{%if%} -{%block content %} -Yuck! -{% endblock%} -{% endif %} - - - -{% block %} -1 -{% with %} -2 -{% endblock %} -1 -{% endwith %} - - - -{% blocktrans count count=queryset.count %} -There is 1 item. -{% plural %} -There are {{ count }} items. -{% endblocktrans %} - - - -{% if %} -{% elif %} -{% else %} -{% endif %} -{% for %} -{% empty %} -{% endfor %} - - - - -Click here! - - - - -{% video form.instance.video as my_video %} -{% video my_video '360 x 200' %} -{% endvideo %} - - - -{% component_block "instruction" border_top=True header="Login" %} -{% slot "body" %} -{% with "login --token="|add:token as content %} -{% component "copy_field" field_selector="token-field" content=content %} -{% endwith %} -{% endslot %} -{% endcomponent_block %} diff --git a/tests/suite/django.tokens b/tests/suite/django.tokens new file mode 100644 index 0000000..6a7cf0a --- /dev/null +++ b/tests/suite/django.tokens @@ -0,0 +1,166 @@ +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Open('{#', mode=DjTXT, ignore=True), Text(' fmt:off #}', mode=Comment, ignore=True)], ignore=True) +Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=Comment, ignore=True), Close('{# fmt:on #}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Text('/>', mode=DjHTML)], offset=11) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('{% load static %}', mode=DjTXT)]) +Line([Open('{% block content %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Open('{% if request.user.is_authenticated %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('h1', mode=InsideHTMLTag, absolute=4), Open('>', mode=DjHTML, level=2), Text('Welcome, ', mode=DjHTML), Text('{{ request.user }}', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), CloseAndOpen('{% else %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text("{% url 'login' %}", mode=DjTXT, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=2), Text('Click here to login', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Close('{% endblock %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('style', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML)]) +Line([Text(' a ', mode=DjCSS), Open('{', mode=DjCSS, level=1)], level=1) +Line([Text(' ', mode=DjCSS), Open('{% block color %}', mode=DjTXT, level=2)], level=2) +Line([Text(' ', mode=DjCSS), Text('color: ', mode=DjCSS), Text('red', mode=DjCSS, absolute=7), Text(';', mode=DjCSS)], level=3) +Line([Text(' ', mode=DjCSS), Close('{% endblock %}', mode=DjTXT)], level=2) +Line([Text(' ', mode=DjCSS), Close('}', mode=DjCSS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' $', mode=DjJS), Open('(', mode=DjJS, level=1), Text('function', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Open('{% if verbose %}', mode=DjTXT, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text('"Hi mom!"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('{% endif %}', mode=DjTXT)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% comment %}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('{% endcomment %}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% verbatim %}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('{% endverbatim %}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% comment "Yo dawg" %}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' I heard you like comments', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('{% endcomment %}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{%comment %}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' %}', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('{% endcomment%}', mode=DjTXT, ignore=True)], ignore=True) +Line([Open('{%if%}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Open('{%block content %}', mode=DjTXT, level=1)], level=1) +Line([Text(' Yuck!', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endblock%}', mode=DjTXT)], level=1) +Line([Close('{% endif %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% block %}', mode=DjTXT)]) +Line([Text(' 1', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Open('{% with %}', mode=DjTXT, level=1)], level=1) +Line([Text(' 2', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endblock %}', mode=DjTXT)], level=1) +Line([Text(' 1', mode=DjHTML)], level=1) +Line([Close('{% endwith %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% blocktrans count count=queryset.count %}', mode=DjTXT)]) +Line([Text(' There is 1 item.', mode=DjHTML)], level=1) +Line([CloseAndOpen('{% plural %}', mode=DjTXT)]) +Line([Text(' There are ', mode=DjHTML), Text('{{ count }}', mode=DjHTML), Text(' items.', mode=DjHTML)], level=1) +Line([Close('{% endblocktrans %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% if %}', mode=DjTXT)]) +Line([CloseAndOpen('{% elif %}', mode=DjTXT)]) +Line([CloseAndOpen('{% else %}', mode=DjTXT)]) +Line([Close('{% endif %}', mode=DjTXT)]) +Line([Open('{% for %}', mode=DjTXT)]) +Line([CloseAndOpen('{% empty %}', mode=DjTXT)]) +Line([Close('{% endfor %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('{% if %}', mode=DjTXT, absolute=3), Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=18), Text('"', mode=InsideHTMLTag, absolute=17), Close('{% endif %}', mode=DjTXT, absolute=3), Open('>', mode=DjHTML)]) +Line([Text(' Click here!', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% video form.instance.video as my_video %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text("{% video my_video '360 x 200' %}", mode=DjTXT)], level=1) +Line([Close('{% endvideo %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% component_block "instruction" border_top=True header="Login" %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Open('{% slot "body" %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Open('{% with "login --token="|add:token as content %}', mode=DjTXT, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('{% component "copy_field" field_selector="token-field" content=content %}', mode=DjTXT)], level=3) +Line([Text(' ', mode=DjHTML), Close('{% endwith %}', mode=DjTXT)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endslot %}', mode=DjTXT)], level=1) +Line([Close('{% endcomponent_block %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text("{{ '' if condition }}", mode=DjHTML)]) +Line([Text('some text', mode=DjHTML)]) +Line([Text("{{ '' if condition }}", mode=DjHTML)]) +Line([Text('more text', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text("{{ '", mode=DjHTML), Text('<', mode=DjHTML), Text('b', mode=InsideHTMLTag, absolute=7), Open('>', mode=DjHTML), Text("'", mode=DjHTML)]) +Line([Text(' if condition }}', mode=DjHTML)], level=1) +Line([Text(' some text', mode=DjHTML)], level=1) +Line([Text(" {{ '", mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Text('if condition }}', mode=DjHTML)]) +Line([Text('more text', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% block main %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('section', mode=InsideHTMLTag, absolute=9), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=3)], level=3) +Line([Text(' ', mode=DjHTML), Text('{% placeholder "placeholder1" %}', mode=DjTXT)], level=4) +Line([Text(' ', mode=DjHTML), Close('
', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=3)], level=3) +Line([Text(' ', mode=DjHTML), Open('{% placeholder "placeholder2" or %}', mode=DjTXT, level=4)], level=4) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('img ', mode=InsideHTMLTag, absolute=5), Text('src=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9), Text(' ', mode=InsideHTMLTag, absolute=5), Text('alt=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=17), Text('"', mode=InsideHTMLTag, absolute=16), Text(' ', mode=InsideHTMLTag, absolute=5), Text('/>', mode=DjHTML)], level=5) +Line([Text(' ', mode=DjHTML), Close('{% endplaceholder %}', mode=DjTXT)], level=4) +Line([Text(' ', mode=DjHTML), Close('
', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('section', mode=InsideHTMLTag, absolute=9), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('{% placeholder "placeholder3" %}', mode=DjTXT)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('section', mode=InsideHTMLTag, absolute=9), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('{% placeholder "placeholder4" %}', mode=DjTXT)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('{% endblock %}', mode=DjTXT)]) +Line([]) \ No newline at end of file diff --git a/tests/suite/html.html b/tests/suite/html.html new file mode 100644 index 0000000..9c355e0 --- /dev/null +++ b/tests/suite/html.html @@ -0,0 +1,354 @@ + + + + + Plain + + + + +

Title

+ + + + + +
+ text +
+ text +
+ + + +
+
+
+ text +
+ +
+ text +
+
+
+ + + text2 + text3 + + text3 + + + + + + + + text3 + + text1 + + + + +
+
+ text +
+ + + +
+ + + + + +
+ + + + + + + + + + + + + + + + +
+   
+
+
+
+ + + + +
+    
+ {# + #} + {##} + + + +
+
+
+
+
+
+ +
+
+
+ +
+
+
+ + + + + + + + + + + +
bar %}class="baz"{% endif %}> + quux +
+ + + +
+ text +
+ +
+ text +
+ + + + + + + + Click me! + + + + +
+ > +
+
+ < +
+ + + +
+ +
+ + + + + text + + + text + + + text + + + text + + + + + +
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+ text +
+ + +
', mode=DjHTML), Close('', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([]) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, relative=-1, absolute=10), Open('>', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, relative=-1, absolute=15), Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([Close('', mode=DjHTML)]) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('div0', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML), Text('<', mode=DjHTML), Text('div1', mode=InsideHTMLTag, relative=-1, absolute=12), Open('>', mode=DjHTML)]) +Line([Text(' text2', mode=DjHTML), Close('', mode=DjHTML), Text('<', mode=DjHTML), Text('div1', mode=InsideHTMLTag, absolute=18), Open('>', mode=DjHTML, level=1), Text('<', mode=DjHTML), Text('div2', mode=InsideHTMLTag, absolute=24), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' text3', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML), Text('<', mode=DjHTML), Text('div2', mode=InsideHTMLTag, absolute=13), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' text3', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('div0', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div1', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div2', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' text3', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML), Close('', mode=DjHTML), Close('', mode=DjHTML), Text('<', mode=DjHTML), Text('div0', mode=InsideHTMLTag, absolute=27), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' text1', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Text('/>', mode=DjHTML)], level=1) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('img', mode=InsideHTMLTag, absolute=5), Text('>', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('input', mode=InsideHTMLTag, absolute=7), Text('>', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('input ', mode=InsideHTMLTag, absolute=7), Text('/>', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('input', mode=InsideHTMLTag, absolute=7), Text('>', mode=DjHTML), Text('', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('!doctype>', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('
', mode=DjHTML, ignore=True)], ignore=True)
+Line([Text('   
', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text('
', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text('
', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('
', mode=DjHTML, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text(' ', mode=DjHTML), Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text(' ', mode=DjHTML), Open('
', mode=DjHTML, ignore=True)], ignore=True)
+Line([Text('    ', mode=Comment, ignore=True), Close('
', mode=DjHTML, ignore=True)], ignore=True) +Line([Text(' ', mode=DjHTML), Open('{#', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ', mode=Comment, ignore=True), Close('#}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ', mode=DjHTML), Open('{#', mode=DjTXT, ignore=True), Close('#}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('row', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('input-group date', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Text(' ', mode=InsideHTMLTag, absolute=5), Text('data-provide=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=44), Text('datepicker', mode=InsideHTMLTag, absolute=44), Text('"', mode=InsideHTMLTag, absolute=43), Text(' ', mode=InsideHTMLTag, absolute=5), Text('data-date-format=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=74), Text('yyyy/mm/dd', mode=InsideHTMLTag, absolute=74), Text('"', mode=InsideHTMLTag, absolute=73), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('btn', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Close('', mode=DjHTML), Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=11), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('custom-control custom-switch', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('input ', mode=InsideHTMLTag, absolute=7), Text('type=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=13), Text('checkbox', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12), Text(' ', mode=InsideHTMLTag, absolute=7), Text('name=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=29), Text('filter-changes', mode=InsideHTMLTag, absolute=29), Text('"', mode=InsideHTMLTag, absolute=28), Text(' ', mode=InsideHTMLTag, absolute=7), Text('id=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=49), Text('filter-changes', mode=InsideHTMLTag, absolute=49), Text('"', mode=InsideHTMLTag, absolute=48), Text(' ', mode=InsideHTMLTag, absolute=7), Text('class=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=72), Text('custom-control-input fs-nano', mode=InsideHTMLTag, absolute=72), Text('"', mode=InsideHTMLTag, absolute=71), Text(' ', mode=InsideHTMLTag, absolute=7), Text('value=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=109), Text('0', mode=InsideHTMLTag, absolute=109), Text('"', mode=InsideHTMLTag, absolute=108), Text(' ', mode=InsideHTMLTag, absolute=7), Open('{% if request.session.manage_filter_changes %}', mode=DjTXT, level=2, absolute=7), Open('{% if request.session.manage_filter_changes == True %}', mode=DjTXT, level=2, absolute=7), Text('checked', mode=InsideHTMLTag, absolute=7), Close('{% endif %}', mode=DjTXT, absolute=7), Close('{% endif %}', mode=DjTXT, absolute=7), Text('>', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('form ', mode=InsideHTMLTag, absolute=6), Text('class=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=13), Text('form-inline', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('custom-control custom-switch', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('input ', mode=InsideHTMLTag, absolute=7), Text('type=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=13), Text('checkbox', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12), Text(' ', mode=InsideHTMLTag, absolute=7), Text('name=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=29), Text('filter-status-new', mode=InsideHTMLTag, absolute=29), Text('"', mode=InsideHTMLTag, absolute=28), Text(' ', mode=InsideHTMLTag, absolute=7), Text('id=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=52), Text('filter-status-new', mode=InsideHTMLTag, absolute=52), Text('"', mode=InsideHTMLTag, absolute=51), Text(' ', mode=InsideHTMLTag, absolute=7), Text('class=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=78), Text('custom-control-input fs-nano', mode=InsideHTMLTag, absolute=78), Text('"', mode=InsideHTMLTag, absolute=77), Text(' ', mode=InsideHTMLTag, absolute=7), Text('value=', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=115), Text('0', mode=InsideHTMLTag, absolute=115), Text('"', mode=InsideHTMLTag, absolute=114), Text(' ', mode=InsideHTMLTag, absolute=7), Open('{% if request.session.manage_filter_status_new %}', mode=DjTXT, level=3, absolute=7), Open('{% if request.session.manage_filter_status_new == True %}', mode=DjTXT, level=3, absolute=7), Text('checked', mode=InsideHTMLTag, absolute=7), Close('{% endif %}', mode=DjTXT, absolute=7), Close('{% endif %}', mode=DjTXT, absolute=7), Text('>', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('svg ', mode=InsideHTMLTag, absolute=5), Text('width=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('325', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11), Text(' ', mode=InsideHTMLTag, absolute=5), Text('height=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=25), Text('325', mode=InsideHTMLTag, absolute=25), Text('"', mode=InsideHTMLTag, absolute=24), Text(' ', mode=InsideHTMLTag, absolute=5), Text('xmlns=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=37), Text('http://www.w3.org/2000/svg', mode=InsideHTMLTag, absolute=37), Text('"', mode=InsideHTMLTag, absolute=36), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('path', mode=InsideHTMLTag, absolute=6)], level=1) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('d=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=9), Text('M 80 80', mode=InsideHTMLTag, absolute=9)], level=1, offset=6) +Line([Text(' A 45 45, 0, 0, 0, 125 125', mode=InsideHTMLTag, absolute=9)], level=1, offset=9) +Line([Text(' L 125 80 Z', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=1, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('fill=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=12), Text('green', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11)], level=1, offset=6) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('/>', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('path', mode=InsideHTMLTag, absolute=6)], level=1) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('d=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=9)], level=1, offset=6) +Line([Text(' M 80 80', mode=InsideHTMLTag, absolute=9)], level=1, offset=9) +Line([Text(' A 45 45, 0, 0, 0, 125 125', mode=InsideHTMLTag, absolute=9)], level=1, offset=9) +Line([Text(' L 125 80 Z', mode=InsideHTMLTag, absolute=9)], level=1, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=1, offset=8) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('fill=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=12), Text('green', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11)], level=1, offset=6) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('/>', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('path ', mode=InsideHTMLTag, absolute=6), Text('d=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=9), Text('M 80 80', mode=InsideHTMLTag, absolute=9)], level=1) +Line([Text(' A 45 45, 0, 0, 0, 125 125', mode=InsideHTMLTag, absolute=9)], level=1, offset=9) +Line([Text(' L 125 80 Z', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=1, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('fill=', mode=InsideHTMLTag, absolute=6), Text('"', mode=InsideHTMLTag, absolute=12), Text('green', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11)], level=1, offset=6) +Line([Text(' ', mode=InsideHTMLTag, absolute=6), Text('/>', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Open('{% if foo > bar %}', mode=DjTXT, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=30), Text('baz', mode=InsideHTMLTag, absolute=30), Text('"', mode=InsideHTMLTag, absolute=29), Close('{% endif %}', mode=DjTXT, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' quux', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Open('{% block class %}', mode=DjTXT, absolute=5)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12), Text('foo', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11)], level=1, offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Close('{% endblock %}', mode=DjTXT, absolute=5)], offset=5) +Line([Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Open('{% block classes %}', mode=DjTXT, absolute=5)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=12)], level=1, offset=5) +Line([Text(' foo', mode=InsideHTMLTag, absolute=12)], level=1, offset=12) +Line([Text(' bar', mode=InsideHTMLTag, absolute=12)], level=1, offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=11)], level=1, offset=11) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Close('{% endblock %}', mode=DjTXT, absolute=5)], offset=5) +Line([Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9), Text('1', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Text(' ', mode=InsideHTMLTag, absolute=5), Text('class=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=19), Open('{% block classes %}', mode=DjTXT, absolute=19)]) +Line([Text(' foo', mode=InsideHTMLTag, absolute=19)], level=1, offset=19) +Line([Text(' bar', mode=InsideHTMLTag, absolute=19)], level=1, offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Open('{% if %}', mode=DjTXT, level=1, absolute=19)], level=1, offset=19) +Line([Text(' baz', mode=InsideHTMLTag, absolute=19)], level=2, offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), CloseAndOpen('{% elif %}', mode=DjTXT, level=1, absolute=19)], level=1, offset=19) +Line([Text(' quux', mode=InsideHTMLTag, absolute=19)], level=2, offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Close('{% endif %}', mode=DjTXT, absolute=19)], level=1, offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Close('{% endblock %}', mode=DjTXT, absolute=19)], offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Text('"', mode=InsideHTMLTag, absolute=18)], offset=18) +Line([Text(' hidden', mode=InsideHTMLTag, absolute=5)], offset=5) +Line([Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('{% url %}', mode=DjTXT, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10), Text('button', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9)], offset=3) +Line([Open('>', mode=DjHTML)]) +Line([Text(' Click me!', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' >', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('button ', mode=InsideHTMLTag, absolute=8), Text('action=', mode=InsideHTMLTag, absolute=8), Text('"', mode=InsideHTMLTag, absolute=16), Text('a-', mode=InsideHTMLTag, absolute=16), Text('>', mode=InsideHTMLTag, absolute=16), Text('b', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' hi', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('id=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=7), Text('1', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=6), Text(' ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10), Text('button', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9), Open('>', mode=DjHTML)], offset=3) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('id=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=7), Text('2', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=6), Text(' ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15)], offset=3) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10), Text('button', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9), Open('>', mode=DjHTML)], offset=3) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('id=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=7), Text('3', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=6), Text(' ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10), Text('button', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9)], offset=3) +Line([Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('id=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=7), Text('4', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=6), Text(' ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15)], offset=3) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10), Text('button', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9)], offset=3) +Line([Open('>', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('img ', mode=InsideHTMLTag, absolute=5), Text('src=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=10), Text('/some/long/path', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9), Text('1', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Text('>', mode=DjHTML)], offset=5) +Line([Text('<', mode=DjHTML), Text('blockquote ', mode=InsideHTMLTag, absolute=12), Text('class=', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=19), Text('dishy', mode=InsideHTMLTag, absolute=19), Text('"', mode=InsideHTMLTag, absolute=18)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('id=', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=16), Text('2', mode=InsideHTMLTag, absolute=16), Text('"', mode=InsideHTMLTag, absolute=15), Text(' ', mode=InsideHTMLTag, absolute=12), Text('/>', mode=DjHTML)], offset=12) +Line([Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('/some/long/path', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('id=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=7), Text('3', mode=InsideHTMLTag, absolute=7), Text('"', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML), Close('', mode=DjHTML)], offset=3) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9)]) +Line([Text(' 1', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)], offset=9) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9), Text('2', mode=InsideHTMLTag, absolute=9)], level=1) +Line([Text(' ', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=1)], level=1, offset=8) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9)], level=2) +Line([Text(' 3', mode=InsideHTMLTag, absolute=9)], level=2, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=2)], level=2, offset=8) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9)], level=3) +Line([Text(' 4', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=3, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=3)], level=3) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9), Text('5', mode=InsideHTMLTag, absolute=9)], level=4) +Line([Text(' ', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=4, offset=8) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=4)], level=4) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('id=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=9)], level=5) +Line([Text(' 6', mode=InsideHTMLTag, absolute=9)], level=5, offset=9) +Line([Text(' ', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)], level=5, offset=8) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML, level=5)], level=5) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=5) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=4) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=3) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div ', mode=InsideHTMLTag, absolute=5), Text('!click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('@click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('#click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('$click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('%click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('^click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('&click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('*click=', mode=InsideHTMLTag, absolute=5), Text('"', mode=InsideHTMLTag, absolute=13)], offset=5) +Line([Text(' ', mode=InsideHTMLTag, absolute=13), Text('"', mode=InsideHTMLTag, absolute=12)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=5), Text('', mode=DjHTML)]) +Line([Text(' text', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('my-component', mode=InsideHTMLTag, absolute=14)]) +Line([Text(' hidden', mode=InsideHTMLTag, absolute=14), Text('/>', mode=DjHTML)], offset=14) +Line([Text('<', mode=DjHTML), Text('my.component', mode=InsideHTMLTag, absolute=14)]) +Line([Text(' hidden', mode=InsideHTMLTag, absolute=14), Text('/>', mode=DjHTML)], offset=14) +Line([Text('<', mode=DjHTML), Text('my:component', mode=InsideHTMLTag, absolute=14)]) +Line([Text(' hidden', mode=InsideHTMLTag, absolute=14), Text('/>', mode=DjHTML)], offset=14) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML), Text('text', mode=DjHTML), Text('<', mode=DjHTML), Text('blockquote ', mode=InsideHTMLTag, relative=-1, absolute=21), Text('id=', mode=InsideHTMLTag, relative=-1, absolute=21), Text('"', mode=InsideHTMLTag, relative=-1, absolute=25), Text('1', mode=InsideHTMLTag, relative=-1, absolute=25), Text('"', mode=InsideHTMLTag, relative=-1, absolute=24), Text(' ', mode=InsideHTMLTag, relative=-1, absolute=21), Text('id=', mode=InsideHTMLTag, relative=-1, absolute=21), Text('"', mode=InsideHTMLTag, relative=-1, absolute=32), Text('2', mode=InsideHTMLTag, relative=-1, absolute=32), Text('"', mode=InsideHTMLTag, relative=-1, absolute=31)]) +Line([Text(' ', mode=InsideHTMLTag, relative=-1, absolute=21), Text('id=', mode=InsideHTMLTag, relative=-1, absolute=21), Text('"', mode=InsideHTMLTag, relative=-1, absolute=25), Text('3', mode=InsideHTMLTag, relative=-1, absolute=25), Text('"', mode=InsideHTMLTag, relative=-1, absolute=24), Text(' ', mode=InsideHTMLTag, relative=-1, absolute=21), Text('cite=', mode=InsideHTMLTag, relative=-1, absolute=21), Text('"', mode=InsideHTMLTag, relative=-1, absolute=34)], offset=21) +Line([Text(' Wikipedia', mode=InsideHTMLTag, relative=-1, absolute=34)], offset=34) +Line([Text(' ', mode=InsideHTMLTag, relative=-1, absolute=34), Text('"', mode=InsideHTMLTag, relative=-1, absolute=33)], offset=33) +Line([Text(' ', mode=InsideHTMLTag, relative=-1, absolute=21), Text('id=', mode=InsideHTMLTag, relative=-1, absolute=21), Text('"', mode=InsideHTMLTag, relative=-1, absolute=25), Text('4', mode=InsideHTMLTag, relative=-1, absolute=25), Text('"', mode=InsideHTMLTag, relative=-1, absolute=24), Text('/>', mode=DjHTML), Close('', mode=DjHTML)], offset=21) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('{% include "attrs.html" %}', mode=DjTXT, absolute=3)], offset=3) +Line([Text(' ', mode=InsideHTMLTag, absolute=3), Text('class=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=10)], offset=3) +Line([Text(' ', mode=InsideHTMLTag, absolute=10), Open('{% block classes %}', mode=DjTXT, absolute=10)], offset=10) +Line([Text(' foo', mode=InsideHTMLTag, absolute=10)], level=1, offset=10) +Line([Text(' bar', mode=InsideHTMLTag, absolute=10)], level=1, offset=10) +Line([Text(' ', mode=InsideHTMLTag, absolute=10), Close('{% endblock %}', mode=DjTXT, absolute=10)], offset=10) +Line([Text(' ', mode=InsideHTMLTag, absolute=10), Text('"', mode=InsideHTMLTag, absolute=9)], offset=9) +Line([Text('/>', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('blockquote ', mode=InsideHTMLTag, absolute=12), Text('cite=', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=18), Text('Guido Van Rossum', mode=InsideHTMLTag, absolute=18), Text('"', mode=InsideHTMLTag, absolute=17)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('style=', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=19), Text('font-style: italic;', mode=InsideHTMLTag, absolute=19)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Open('{% if dark_mode %}', mode=DjTXT, absolute=19)], offset=19) +Line([Text(' background: black;', mode=InsideHTMLTag, absolute=19)], level=1, offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Close('{% endif %}', mode=DjTXT, absolute=19)], offset=19) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Text('"', mode=InsideHTMLTag, absolute=18), Open('>', mode=DjHTML)], offset=18) +Line([Text(" Don't you hate code that's not properly indented?", mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('blockquote ', mode=InsideHTMLTag, absolute=12), Text('class=', mode=InsideHTMLTag, absolute=12), Text("'", mode=InsideHTMLTag, absolute=19), Text('foo', mode=InsideHTMLTag, absolute=19)]) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Text("'", mode=InsideHTMLTag, absolute=18)], offset=18) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('class=', mode=InsideHTMLTag, absolute=12), Text("'", mode=InsideHTMLTag, absolute=19), Text('bar', mode=InsideHTMLTag, absolute=19), Text('"', mode=InsideHTMLTag, absolute=19)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Text("'", mode=InsideHTMLTag, absolute=18)], offset=18) +Line([Text(' ', mode=InsideHTMLTag, absolute=12), Text('class=', mode=InsideHTMLTag, absolute=12), Text('"', mode=InsideHTMLTag, absolute=19), Text('baz', mode=InsideHTMLTag, absolute=19), Text("'", mode=InsideHTMLTag, absolute=19)], offset=12) +Line([Text(' ', mode=InsideHTMLTag, absolute=19), Text('"', mode=InsideHTMLTag, absolute=18)], offset=18) +Line([Text('/>', mode=DjHTML)]) +Line([]) \ No newline at end of file diff --git a/tests/suite/html_arrow_attr.in b/tests/suite/html_arrow_attr.in deleted file mode 100644 index 2b5d063..0000000 --- a/tests/suite/html_arrow_attr.in +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/tests/suite/html_arrow_attr.out b/tests/suite/html_arrow_attr.out deleted file mode 100644 index 3e9880a..0000000 --- a/tests/suite/html_arrow_attr.out +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/tests/suite/html_tag.in b/tests/suite/html_tag.in deleted file mode 100644 index c5734c6..0000000 --- a/tests/suite/html_tag.in +++ /dev/null @@ -1,21 +0,0 @@ - -
bar %}class="baz"{% endif %}> -quux -
- - -
-text -
- - -
-> -
-
-< -
diff --git a/tests/suite/html_tag.out b/tests/suite/html_tag.out deleted file mode 100644 index 9ba31a1..0000000 --- a/tests/suite/html_tag.out +++ /dev/null @@ -1,21 +0,0 @@ - -
bar %}class="baz"{% endif %}> - quux -
- - -
- text -
- - -
- > -
-
- < -
diff --git a/tests/suite/jinja.out b/tests/suite/jinja.html similarity index 84% rename from tests/suite/jinja.out rename to tests/suite/jinja.html index 7664412..b1ed319 100644 --- a/tests/suite/jinja.out +++ b/tests/suite/jinja.html @@ -45,3 +45,10 @@ {% endset %} Contents of block is block + + + +{% if ( condition1 and +condition2 ) %} +text +{% endif %} diff --git a/tests/suite/jinja.in b/tests/suite/jinja.in deleted file mode 100644 index 3cb03fb..0000000 --- a/tests/suite/jinja.in +++ /dev/null @@ -1,47 +0,0 @@ - -{# - ,-._|\ - / .\ - \_,--._/ -#} - - - -{% raw %} - ,-._|\ - / .\ - \_,--._/ -{% endraw %} - - - -
-{%+ if something %} -yay -{% endif %} -
- -
-{% if something +%} -yay -{% endif %} -
- -{% for item in seq -%} - {{ item }} -{%- endfor %} - -{%- macro render_currency(currency, amount) -%} -{{ amount }} -{%- endmacro -%} - - - -
-{% set "five" = 5 %} -Five is {{ five }} -{% set blockdata %} -Contents -{% endset %} -Contents of block is block -
diff --git a/tests/suite/jinja.tokens b/tests/suite/jinja.tokens new file mode 100644 index 0000000..744a4f2 --- /dev/null +++ b/tests/suite/jinja.tokens @@ -0,0 +1,55 @@ +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{#', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('#}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% raw %}', mode=DjTXT, ignore=True)], ignore=True) +Line([Text(' ,-._|\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' / .\\', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Text(' \\_,--._/', mode=Comment, ignore=True)], level=1, ignore=True) +Line([Close('{% endraw %}', mode=DjTXT, ignore=True)], ignore=True) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Open('{%+ if something %}', mode=DjTXT, level=1)], level=1) +Line([Text(' yay', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Open('{% if something +%}', mode=DjTXT, level=1)], level=1) +Line([Text(' yay', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Open('{% for item in seq -%}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('{{ item }}', mode=DjHTML)], level=1) +Line([Close('{%- endfor %}', mode=DjTXT)]) +Line([]) +Line([Open('{%- macro render_currency(currency, amount) -%}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('{{ amount }}', mode=DjHTML)], level=1) +Line([Close('{%- endmacro -%}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('{% set "five" = 5 %}', mode=DjTXT)], level=1) +Line([Text(' Five is ', mode=DjHTML), Text('{{ five }}', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Open('{% set blockdata %}', mode=DjTXT, level=1)], level=1) +Line([Text(' Contents', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endset %}', mode=DjTXT)], level=1) +Line([Text(' Contents of block is block', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('{% if ( condition1 and', mode=DjHTML)]) +Line([Text('condition2 ) %}', mode=DjHTML)]) +Line([Text('text', mode=DjHTML)]) +Line([Close('{% endif %}', mode=DjTXT)]) +Line([]) \ No newline at end of file diff --git a/tests/suite/js.out b/tests/suite/js.html similarity index 53% rename from tests/suite/js.out rename to tests/suite/js.html index eb4a5bf..12d2f4b 100644 --- a/tests/suite/js.out +++ b/tests/suite/js.html @@ -157,10 +157,11 @@ } case 'rejected': { console.log('Rejected'); - break; } + break; default: { console.log('Default'); + break; } } @@ -216,6 +217,15 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/suite/js.in b/tests/suite/js.in deleted file mode 100644 index d17d057..0000000 --- a/tests/suite/js.in +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/suite/js.tokens b/tests/suite/js.tokens new file mode 100644 index 0000000..d7a5f82 --- /dev/null +++ b/tests/suite/js.tokens @@ -0,0 +1,447 @@ +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' function f', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' return 42;', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' array = ', mode=DjJS), Open('[', mode=DjJS, level=1)], level=1) +Line([Text(' 1,', mode=DjJS)], level=2) +Line([Text(' 2,', mode=DjJS)], level=2) +Line([Text(' 3,', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close(']', mode=DjJS)], level=1) +Line([]) +Line([Text(' dictionary = ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Text('value1:', mode=DjJS), Text(' 1,', mode=DjJS, relative=1)], level=2) +Line([Text(' ', mode=DjJS), Text('value2:', mode=DjJS), Text(' 2,', mode=DjJS, relative=1)], level=2) +Line([Text(' ', mode=DjJS), Text('value3:', mode=DjJS), Text(' 3,', mode=DjJS, relative=1)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([]) +Line([Text(' function_call', mode=DjJS), Open('(', mode=DjJS, level=1)], level=1) +Line([Text(' arg1,', mode=DjJS)], level=2) +Line([Text(' arg2,', mode=DjJS)], level=2) +Line([Text(' arg3,', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' one', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS)], level=1) +Line([Text(' .two', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS)], level=2) +Line([Text(' .three', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' four', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' function f', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' return 42;', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' $', mode=DjJS), Open('(', mode=DjJS, level=1), Text('function', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' this.addEventListener', mode=DjJS), Open('(', mode=DjJS, level=2), Text("'change'", mode=DjJS), Text(', function ', mode=DjJS), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' doStuff', mode=DjJS), Open('(', mode=DjJS, level=3), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Open('/*', mode=DjJS, level=1, ignore=True)], level=1, ignore=True) +Line([Text(' * Hi mom!', mode=Comment, ignore=True)], level=2, ignore=True) +Line([Text(' *', mode=Comment, ignore=True)], level=2, ignore=True) +Line([Text(' ', mode=Comment, ignore=True), Close('*/', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text('"$(function() {"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text("'$(function() {'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text('`$(function() {`', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text('`\nfunction f() {\nreturn 42;\n}\n `', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('format_duration_value = ', mode=DjJS, absolute=6), Open('(', mode=DjJS, level=1), Text('a', mode=DjJS), Close(')', mode=DjJS), Text(' => ', mode=DjJS, relative=1, absolute=6), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Text('let ', mode=DjJS), Text('secs = a * 3600; ', mode=DjJS, absolute=4), Text('// get total amount of seconds from your input', mode=DjJS, ignore=True)], level=2) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('days = Math.floor', mode=DjJS, absolute=6), Open('(', mode=DjJS, level=2), Text('secs / ', mode=DjJS), Open('(', mode=DjJS, level=2), Text('3600 * 24', mode=DjJS), Close(')', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS, absolute=6)], level=2) +Line([Text(' return ', mode=DjJS), Open('(', mode=DjJS, level=2), Text('`\n
\n ${days.toString().padStart(2,\'0\')}\n m\n
\n `', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Text(';', mode=DjJS, absolute=6)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' $', mode=DjJS), Open('(', mode=DjJS, level=1), Text('function1', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS)], level=1) +Line([Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('foo = ', mode=DjJS, absolute=4), Open('(', mode=DjJS, level=3), Text('function2', mode=DjJS), Open('(', mode=DjJS, level=3), Close(')', mode=DjJS), Open('{', mode=DjJS, level=3)], level=3) +Line([Text(' doStuff', mode=DjJS), Open('(', mode=DjJS, level=4), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Open('(', mode=DjJS, level=3), Close(')', mode=DjJS), Text(';', mode=DjJS, relative=1, absolute=4)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text('// Jeez', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('let ', mode=DjJS), Text('time = 10;', mode=DjJS, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('time < 10', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=2), Text('"Good morning"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Text(' else ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('time < 20', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=2), Text('"Good day"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Text(' else ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=2), Text('"Good evening"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('mode = ', mode=DjJS, absolute=6), Text("'approved'", mode=DjJS, relative=1, absolute=6)], level=1) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('mode', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'approved'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Approved'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'rejected'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Rejected'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Default'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('mode', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'approved'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Approved'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Default'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'rejected'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Rejected'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('mode', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'approved'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'rejected'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'invalid'", mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Not default'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Default'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('mode', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'approved'", mode=DjJS), Text(': ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Approved'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text("'rejected'", mode=DjJS), Text(': ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Rejected'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=3), Text("'Default'", mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('year = 2016;', mode=DjJS, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('month = 2;', mode=DjJS, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('dayCount;', mode=DjJS, absolute=4)], level=1) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('month', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('1:', mode=DjJS)], level=2) +Line([Text(' function switchFoo ', mode=DjJS), Open('(', mode=DjJS, level=3), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=3)], level=3) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=4), Text('"Foo"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=3) +Line([Text(' switchFoo', mode=DjJS), Open('(', mode=DjJS, level=3), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('12:', mode=DjJS)], level=2) +Line([Text(' dayCount = 31;', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('4:', mode=DjJS)], level=2) +Line([Text(' switch', mode=DjJS), Open('(', mode=DjJS, level=3), Text('boo', mode=DjJS), Close(')', mode=DjJS), Open('{', mode=DjJS, level=3)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=4), Text('1:', mode=DjJS)], level=4) +Line([OpenDouble(' case ', mode=DjJS, level=4), Text('2:', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('11:', mode=DjJS)], level=2) +Line([Text(' dayCount = 30;', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('2:', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=3), Open('(', mode=DjJS, level=3), Open('(', mode=DjJS, level=3), Text('year % 4 == 0', mode=DjJS), Close(')', mode=DjJS), Text(' && !', mode=DjJS), Open('(', mode=DjJS, level=3), Text('year % 100 == 0', mode=DjJS), Close(')', mode=DjJS), Close(')', mode=DjJS), Text(' || ', mode=DjJS), Open('(', mode=DjJS, level=3), Text('year % 400 == 0', mode=DjJS), Close(')', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('{', mode=DjJS, level=3)], level=3) +Line([Text(' dayCount = 29;', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Text(' else ', mode=DjJS), Open('{', mode=DjJS, level=3)], level=3) +Line([Text(' dayCount = 28;', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=3) +Line([Text(' break;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2)], level=2) +Line([Text(' dayCount = -1; ', mode=DjJS), Text('// invalid month', mode=DjJS, ignore=True)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text('dayCount', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('a', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('b:', mode=DjJS)], level=2) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=3), Text('c', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=3)], level=3) +Line([OpenDouble(' case ', mode=DjJS, level=4), Text('d:', mode=DjJS)], level=4) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=5), Text('e', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=5)], level=5) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=6)], level=6) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=5) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('foo', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('bar:', mode=DjJS), Text(' break', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), OpenDouble('default:', mode=DjJS, level=2), Text(' return', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' function switchBoo ', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=2), Text('"Boo"', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Text(' switchBoo', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('let ', mode=DjJS), Text('arr = ', mode=DjJS, absolute=4), Open('[', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Text("'switch'", mode=DjJS), Text(',', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text("'default:'", mode=DjJS), Text(',', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text("'case '", mode=DjJS), Text(',', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close(']', mode=DjJS), Text(';', mode=DjJS, absolute=4)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('foo', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=1)], level=1) +Line([OpenDouble(' case ', mode=DjJS, level=2), Text('bar:', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=3), Text('baz', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('{', mode=DjJS, level=3)], level=3) +Line([Text(' switch ', mode=DjJS), Open('(', mode=DjJS, level=4), Text('foo', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=4)], level=4) +Line([OpenDouble(' case ', mode=DjJS, level=5), Text('bar:', mode=DjJS)], level=5) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=6), Text('baz', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('{', mode=DjJS, level=6)], level=6) +Line([Text(' xizzy', mode=DjJS), Open('(', mode=DjJS, level=7), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=7) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=6) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' window.fetch', mode=DjJS), Open('(', mode=DjJS, level=1), Text("'/test.html'", mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' .then', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Open('(', mode=DjJS, level=2), Text('html', mode=DjJS), Close(')', mode=DjJS), Text(' => ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' document.body.innerHTML = html;', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([]) +Line([Text(' foo', mode=DjJS)], level=1) +Line([Text(' .bar', mode=DjJS, relative=1)], level=2) +Line([Text(' .baz', mode=DjJS, relative=1)], level=2) +Line([Text(' .then', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' => ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' foo', mode=DjJS)], level=3) +Line([Text(' .bar', mode=DjJS, relative=1)], level=4) +Line([Text(' .baz', mode=DjJS, relative=1)], level=4) +Line([Text(' .then', mode=DjJS, relative=1), Open('(', mode=DjJS, level=4), Open('(', mode=DjJS, level=4), Close(')', mode=DjJS), Text(' => ', mode=DjJS), Open('{', mode=DjJS, level=4)], level=4) +Line([Text(' foo', mode=DjJS)], level=5) +Line([Text(' .bar', mode=DjJS, relative=1)], level=6) +Line([Text(' .baz', mode=DjJS, relative=1)], level=6) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=4) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=2) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('head', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' function foo', mode=DjJS), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' ', mode=DjJS), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('head', mode=InsideHTMLTag, absolute=6), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' function foo', mode=DjJS), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('', mode=DjHTML)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('// The following does not contain a comment', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' wsHost = ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('/^wss?:\\/\\//', mode=DjJS), Text('i.test', mode=DjJS), Open('(', mode=DjJS, level=1), Text('me._host', mode=DjJS), Close(')', mode=DjJS), Text(' ? ', mode=DjJS), Text("''", mode=DjJS), Text(' : me._protocol', mode=DjJS), Close(')', mode=DjJS), Text(' + me._host;', mode=DjJS, relative=1)], level=1) +Line([]) +Line([Text(' foo; ', mode=DjJS), Text('// This is a comment', mode=DjJS, ignore=True)], level=1) +Line([Text(' bar ', mode=DjJS), Text('//This too', mode=DjJS, ignore=True)], level=1) +Line([Text(' baz', mode=DjJS), Text('//Even this', mode=DjJS, ignore=True)], level=1) +Line([]) +Line([Text(' foo ', mode=DjJS), Text('// function() {', mode=DjJS, ignore=True)], level=1) +Line([Text(' bar ', mode=DjJS), Text('// var a = 1;', mode=DjJS, ignore=True)], level=1) +Line([Text(' baz ', mode=DjJS), Text('// }', mode=DjJS, ignore=True)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('a = 1,', mode=DjJS, absolute=4)], level=1) +Line([Text(' b = 2,', mode=DjJS, absolute=4)], level=1, offset=4) +Line([Text(' c;', mode=DjJS, absolute=4)], level=1, offset=4) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('foo = bar; ', mode=DjJS, absolute=4), Text('let ', mode=DjJS), Text('a = 1,', mode=DjJS, absolute=19)], level=1) +Line([Text(' b = 2,', mode=DjJS, absolute=19)], level=1, offset=19) +Line([Text(' c', mode=DjJS, absolute=19)], level=1, offset=19) +Line([]) +Line([Text(' ', mode=DjJS), Text('// Haskell-style indentation', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('a = 1', mode=DjJS, absolute=6)], level=1) +Line([Text(' , b = 2', mode=DjJS, absolute=4)], level=1, offset=4) +Line([Text(' , c', mode=DjJS, absolute=4)], level=1, offset=4) +Line([]) +Line([Text(' ', mode=DjJS), Text('// Notice the first line is the same', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('a = 1', mode=DjJS, absolute=6)], level=1) +Line([Text(' b = 2', mode=DjJS)], level=1) +Line([Text(' c = 3', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('// Yes, this makes sense', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('func1 = function', mode=DjJS, absolute=6), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS, absolute=6), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' return foo', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Text(',', mode=DjJS, absolute=6)], level=1) +Line([Text(' func2 = function', mode=DjJS, absolute=6), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS, absolute=6), Open('{', mode=DjJS, level=1), Text(' return 2 ', mode=DjJS), Close('}', mode=DjJS), Text(',', mode=DjJS, absolute=6)], level=1, offset=6) +Line([Text(' func3 = function', mode=DjJS, absolute=6), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(' ', mode=DjJS, absolute=6), Open('{', mode=DjJS, level=1), Text(' return 3 ', mode=DjJS), Close('}', mode=DjJS)], level=1, offset=6) +Line([]) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('foo = bar,', mode=DjJS, absolute=6)], level=1) +Line([Text(' baz = ', mode=DjJS, absolute=6), Open('{', mode=DjJS, level=1)], level=1, offset=6) +Line([Text(' ...', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('// We are not supporting madness like this', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('a = 1,', mode=DjJS, absolute=6)], level=1) +Line([Text(' ', mode=DjJS), Open('{% if %}', mode=DjTXT, level=1)], level=1) +Line([Text(' b = 2,', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Text(' c = 3;', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('case = ', mode=DjJS, absolute=4), Text('"foo"', mode=DjJS, relative=1, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('dict = ', mode=DjJS, absolute=4), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Text('case:', mode=DjJS), Text(' ', mode=DjJS, relative=1), Text('"bar"', mode=DjJS, relative=1), Text(',', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Text('"default:"', mode=DjJS), Text(': ', mode=DjJS), Text('"baz"', mode=DjJS, relative=1), Text(',', mode=DjJS)], level=2) +Line([Text(' ...params,', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' foo', mode=DjJS)], level=1) +Line([Text(' ? bar', mode=DjJS, relative=1)], level=2) +Line([Text(' : baz', mode=DjJS, relative=1)], level=2) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('foo = ', mode=DjJS, absolute=4), Text("'\\'{'", mode=DjJS, relative=1, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('bar = ', mode=DjJS, absolute=4), Text('"\\"{"', mode=DjJS, relative=1, absolute=4)], level=1) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('baz = ', mode=DjJS, absolute=4), Text('`\\`{`', mode=DjJS, relative=1, absolute=4)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('foo', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' bar', mode=DjJS, relative=1)], level=2) +Line([]) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('foo', mode=DjJS), Close(')', mode=DjJS), Text(' return', mode=DjJS, relative=1)], level=1) +Line([Text(' bar', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1)], level=1) +Line([Text(' foo &&', mode=DjJS)], level=2) +Line([Text(' bar', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' baz', mode=DjJS, relative=1)], level=2) +Line([Text(' ', mode=DjJS), Text('else', mode=DjJS)], level=1) +Line([Text(' return', mode=DjJS, relative=1)], level=2) +Line([]) +Line([Text(' ', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('foo', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' ', mode=DjJS, relative=1), Text('if', mode=DjJS, relative=1), Text(' ', mode=DjJS, relative=2), Open('(', mode=DjJS, level=2), Text('bar', mode=DjJS), Close(')', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS, relative=2), Text('if', mode=DjJS, relative=2), Text(' ', mode=DjJS, relative=3), Open('(', mode=DjJS, level=3), Text('baz', mode=DjJS), Close(')', mode=DjJS)], level=3) +Line([Text(' return', mode=DjJS, relative=3)], level=4) +Line([Text(' ', mode=DjJS), Text('else', mode=DjJS)], level=1) +Line([Text(' console.log', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Text('"Footgun detected!"', mode=DjJS), Close(')', mode=DjJS)], level=2) +Line([]) +Line([Text(' leitmot', mode=DjJS), Text('if', mode=DjJS), Text(' ', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS)], level=1) +Line([Text(' elsewhere ', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Text(' mean', mode=DjJS), Text('while', mode=DjJS), Text(' ', mode=DjJS), Open('(', mode=DjJS, level=1), Text('true', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('while', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('true', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' break', mode=DjJS, relative=1)], level=2) +Line([]) +Line([Text(' ', mode=DjJS), Text('for', mode=DjJS), Text(' ', mode=DjJS, relative=1), Open('(', mode=DjJS, level=1), Text('i=1, 1<10, i++', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' ', mode=DjJS, relative=1), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' break', mode=DjJS)], level=2) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Text('var ', mode=DjJS), Text('foo =', mode=DjJS, absolute=4)], level=1) +Line([Text(' bar', mode=DjJS, relative=1)], level=2) +Line([]) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('func =', mode=DjJS, absolute=6)], level=1) +Line([Text(' function', mode=DjJS, relative=1), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' return', mode=DjJS)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS)], level=2) +Line([]) +Line([Text(' ', mode=DjJS), Text('// Note that unquoted "default" is a reserved keyword', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('let ', mode=DjJS), Text('dict = ', mode=DjJS, absolute=4), Open('{', mode=DjJS, level=1)], level=1) +Line([Text(' ', mode=DjJS), Text('"default"', mode=DjJS), Text(':', mode=DjJS)], level=2) +Line([Text(' foo', mode=DjJS, relative=1)], level=3) +Line([Text(' ', mode=DjJS), Text('bar:', mode=DjJS)], level=2) +Line([Text(' baz', mode=DjJS, relative=1)], level=3) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' re = ', mode=DjJS), Text('/ab+c/', mode=DjJS, relative=1)], level=1) +Line([Text(' space_re = ', mode=DjJS), Text('/ foo /', mode=DjJS, relative=1)], level=1) +Line([Text(' single_re = ', mode=DjJS), Text('/foo\\/ + bar/', mode=DjJS, relative=1)], level=1) +Line([Text(' double_re = ', mode=DjJS), Text('/foo/', mode=DjJS, relative=1), Text(' + ', mode=DjJS), Text('/bar/', mode=DjJS)], level=1) +Line([Text(' look_like_comment = ', mode=DjJS), Text('/\\(/', mode=DjJS, relative=1), Text('/', mode=DjJS)], level=1) +Line([]) +Line([Text(' ', mode=DjJS), Text('// The following is known to be broken', mode=DjJS, ignore=True)], level=1, ignore=True) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('x = 42', mode=DjJS, absolute=6)], level=1) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('y = 7', mode=DjJS, absolute=6)], level=1) +Line([Text(' ', mode=DjJS), Text('const ', mode=DjJS), Text('six = x ', mode=DjJS, absolute=6), Text('/ (function() { /', mode=DjJS, absolute=6), Text('/ comment', mode=DjJS, absolute=6)], level=1) +Line([Text(' return y', mode=DjJS)], level=1) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Open('(', mode=DjJS, level=1), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) \ No newline at end of file diff --git a/tests/suite/paradoxes.out b/tests/suite/paradoxes.html similarity index 61% rename from tests/suite/paradoxes.out rename to tests/suite/paradoxes.html index da8628a..3c8eae0 100644 --- a/tests/suite/paradoxes.out +++ b/tests/suite/paradoxes.html @@ -1,13 +1,15 @@ -{% if %} - -{% else %} - -{% endif %} -. -{% if %} - -{% endif %} +
+ {% if some_condition %} + + {% elif some_other condition %} + + {% endif %} + . + {% if some_condition or some_other_condition %} + + {% endif %} +
@@ -33,25 +35,6 @@ {% endfor %} - - - {% if %} -
- {% else %} - {% if %} - {% block %} - - {% endblock %}{% endif %} - {% endif %} - . - {% if %} - - {% else %} -
- {% endif %} - - - - - - {# fmt:off #} - ,-._|\ - / .\ - \_,--._/ - {# fmt:on #} - + diff --git a/tests/suite/paradoxes.in b/tests/suite/paradoxes.in deleted file mode 100644 index 01cde80..0000000 --- a/tests/suite/paradoxes.in +++ /dev/null @@ -1,74 +0,0 @@ - -{% if %} - -{% else %} - -{% endif %} -. -{% if %} - -{% endif %} - - - -{% if some_condition %} - -{% elif some_other_condition %} - -{% endif %} - [a bunch of details go here] -{% if end_tag_needed %}{% endif %} - - - -{% block %} - - - - - -{% endblock %} -{% for x in [1,2,3,4,5] %} - -{% endfor %} - - - - -{% if %} -
-{% else %} -{% if %} -{% block %} - -{% endblock %}{% endif %} -{% endif %} -. -{% if %} - -{% else %} -
-{% endif %} - - - - - - - - - - {# fmt:off #} - ,-._|\ - / .\ - \_,--._/ - {# fmt:on #} - diff --git a/tests/suite/paradoxes.tokens b/tests/suite/paradoxes.tokens new file mode 100644 index 0000000..3fbcfab --- /dev/null +++ b/tests/suite/paradoxes.tokens @@ -0,0 +1,51 @@ +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('div', mode=InsideHTMLTag, absolute=5), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjHTML), Open('{% if some_condition %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('{% url a %}', mode=DjTXT, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), CloseAndOpen('{% elif some_other condition %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('{% url b %}', mode=DjTXT, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Text(' .', mode=DjHTML)], level=1) +Line([Text(' ', mode=DjHTML), Open('{% if some_condition or some_other_condition %}', mode=DjTXT, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=2) +Line([Text(' ', mode=DjHTML), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% if some_condition %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('{% url some_url', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=1)], level=1) +Line([CloseAndOpen('{% elif some_other_condition %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a ', mode=InsideHTMLTag, absolute=3), Text('href=', mode=InsideHTMLTag, absolute=3), Text('"', mode=InsideHTMLTag, absolute=9), Text('{% url some_other_url', mode=InsideHTMLTag, absolute=9), Text('"', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML, level=1)], level=1) +Line([Close('{% endif %}', mode=DjTXT)]) +Line([Text('[a bunch of details go here]', mode=DjHTML)]) +Line([Open('{% if end_tag_needed %}', mode=DjTXT), Close('', mode=DjHTML), Close('{% endif %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Open('{% block %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('>', mode=DjHTML, level=1)], level=1) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('>', mode=DjHTML, level=2)], level=2) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('>', mode=DjHTML, level=3)], level=3) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('>', mode=DjHTML, level=4)], level=4) +Line([Text(' ', mode=DjHTML), Text('<', mode=DjHTML), Text('a', mode=InsideHTMLTag, absolute=3), Open('>', mode=DjHTML, level=5)], level=5) +Line([Close('{% endblock %}', mode=DjTXT)]) +Line([Open('{% for x in [1,2,3,4,5] %}', mode=DjTXT)]) +Line([Text(' ', mode=DjHTML), Close('', mode=DjHTML)], level=1) +Line([Close('{% endfor %}', mode=DjTXT)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([Text('<', mode=DjHTML), Text('script', mode=InsideHTMLTag, absolute=8), Open('>', mode=DjHTML)]) +Line([Text(' ', mode=DjJS), Open('{% if jquery %}', mode=DjTXT, level=1)], level=1) +Line([Text(' $', mode=DjJS), Open('(', mode=DjJS, level=2), Text('function', mode=DjJS), Open('(', mode=DjJS, level=2), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' ', mode=DjJS), CloseAndOpen('{% else %}', mode=DjTXT, level=1)], level=1) +Line([Text(' document.addEventListener', mode=DjJS), Open('(', mode=DjJS, level=2), Text('"DOMContentLoaded"', mode=DjJS), Text(', function', mode=DjJS), Open('(', mode=DjJS, level=2), Text('event', mode=DjJS), Close(')', mode=DjJS), Text(' ', mode=DjJS), Open('{', mode=DjJS, level=2)], level=2) +Line([Text(' ', mode=DjJS), Close('{% endif %}', mode=DjTXT)], level=1) +Line([Text(' console.log', mode=DjJS), Open('(', mode=DjJS, level=1), Text('"Time to ditch jQuery!"', mode=DjJS), Close(')', mode=DjJS)], level=1) +Line([Text(' ', mode=DjJS), Close('}', mode=DjJS), Close(')', mode=DjJS), Text(';', mode=DjJS)], level=1) +Line([Close('', mode=DjHTML)]) +Line([]) +Line([]) +Line([Open('', mode=DjHTML, ignore=True)], ignore=True) +Line([]) \ No newline at end of file diff --git a/tests/test_suite.py b/tests/test_suite.py index 2dc5da0..e7a5c1e 100644 --- a/tests/test_suite.py +++ b/tests/test_suite.py @@ -1,49 +1,12 @@ -import os import unittest +from pathlib import Path from djhtml.modes import DjHTML class TestSuite(unittest.TestCase): maxDiff = None - DIR = os.path.join(os.path.dirname(__file__), "suite") - - def _test_file(self, basename): - with open(os.path.join(self.DIR, f"{basename}.in"), "r") as f: - actual_input = f.read() - - try: - with open(os.path.join(self.DIR, f"{basename}.out"), "r") as f: - expected_output = f.read() - except FileNotFoundError: - expected_output = None - - try: - with open(os.path.join(self.DIR, f"{basename}.err"), "r") as f: - expected_error = f.read().strip() - except FileNotFoundError: - expected_error = None - - if expected_output is None and expected_error is None: - self.fail(f"{basename} has no expected error or output.") - - if expected_output is not None and expected_error is not None: - self.fail(f"{basename} has both expected error and output.") - - try: - actual_output = DjHTML(actual_input).indent(4) - actual_error = None - except Exception as err: - actual_error = str(err).strip() - actual_output = None - - if actual_error is not None and expected_error is None: - self.fail(f"Unexpected error: {actual_error}") - if actual_error is None and expected_error is not None: - self.fail(f"Unexpected success, expected error: {expected_error}") - - self.assertEqual(actual_output, expected_output) - self.assertEqual(actual_error, expected_error) + DIR = Path(__file__).parent / "suite" def test_available_files(self): """ @@ -51,8 +14,26 @@ def test_available_files(self): expected output to the actual output. """ - for filename in os.listdir(self.DIR): - if filename.endswith(".in"): - basename, _ = os.path.splitext(filename) - with self.subTest(basename): - self._test_file(basename) + for filename in self.DIR.iterdir(): + if filename.suffix == ".html": + with self.subTest(filename): + self._test_file(filename.stem) + + def _test_file(self, basename): + with open(self.DIR / (basename + ".html")) as f: + expected_output = f.read() + + with open(self.DIR / (basename + ".tokens")) as f: + expected_tokens = f.read() + + # Indent the expected output to 0 (no indentation) + unindented = DjHTML(expected_output).indent(0) + self.assertNotEqual(unindented, expected_output) + + # Re-indent the unindented output to 4 + actual_output = DjHTML(unindented).indent(4) + self.assertEqual(expected_output, actual_output) + + # Compare the tokenization + actual_tokens = DjHTML(actual_output).debug() + self.assertEqual(expected_tokens, actual_tokens)