feat(linter): added --statistics flag to print summary of linter findings

closes #389
This commit is contained in:
Christopher Pickering 2022-09-19 09:41:54 +02:00
parent 756c760e44
commit 489decb2e1
No known key found for this signature in database
GPG key ID: E14DB3B0A0FACF84
8 changed files with 89 additions and 16 deletions

View file

@ -5,13 +5,13 @@ exclude: >
)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/myint/autoflake
rev: v1.4
rev: v1.6.0
hooks:
- id: autoflake
exclude: &fixtures tests/functional/|tests/input|tests/extensions/data|tests/regrtest_data/|tests/data/
@ -22,7 +22,7 @@ repos:
- --remove-duplicate-keys
- --remove-unused-variables
- repo: https://github.com/asottile/pyupgrade
rev: v2.31.0
rev: v2.38.0
hooks:
- id: pyupgrade
args: [--py36-plus]
@ -33,11 +33,11 @@ repos:
exclude: docs*
additional_dependencies: [toml]
- repo: https://github.com/psf/black
rev: 22.1.0
rev: 22.8.0
hooks:
- id: black
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.2.0
rev: v2.4.0
hooks:
- id: pretty-format-ini
args: [--autofix]

View file

@ -49,7 +49,9 @@ Options:
--preserve-blank-lines Attempt to preserve blank lines.
--format-css Also format contents of <style> tags.
--format-js Also format contents of <script> tags.
--configuration Path to global configuration file in .djlintrc format
--configuration PATH Path to global configuration file in .djlintrc format
--statistics Count the number of occurrences of each
error/warning code.
-h, --help Show this message and exit.
```

View file

@ -49,7 +49,9 @@ Options:
--preserve-blank-lines Attempt to preserve blank lines.
--format-css Also format contents of <style> tags.
--format-js Also format contents of <script> tags.
--configuration Path to global configuration file in .djlintrc format
--configuration PATH Path to global configuration file in .djlintrc format
--statistics Count the number of occurrences of each
error/warning code.
-h, --help Show this message and exit.
```

View file

@ -49,7 +49,9 @@ Options:
--preserve-blank-lines Attempt to preserve blank lines.
--format-css Also format contents of <style> tags.
--format-js Also format contents of <script> tags.
--configuration Path to global configuration file in .djlintrc format
--configuration PATH Path to global configuration file in .djlintrc format
--statistics Count the number of occurrences of each
error/warning code.
-h, --help Show this message and exit.
```

View file

@ -122,6 +122,11 @@ from .src import get_src
required=False,
help="Path to global configuration file in .djlintrc format",
)
@click.option(
"--statistics",
is_flag=True,
help="Count the number of occurrences of each error/warning code.",
)
@colorama_text(autoreset=True)
def main(
src: List[str],
@ -141,6 +146,7 @@ def main(
format_css: bool,
format_js: bool,
configuration: Optional[str],
statistics: bool,
) -> None:
"""djLint · HTML template linter and formatter."""
config = Config(
@ -161,6 +167,7 @@ def main(
format_css=format_css,
format_js=format_js,
configuration=configuration,
statistics=statistics,
)
temp_file = None

View file

@ -1,7 +1,8 @@
"""Build djLint console output."""
import shutil
from collections import Counter
from pathlib import Path
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional
import regex as re
from click import echo
@ -33,14 +34,22 @@ def print_output(
if config.stdin is False or config.lint:
echo()
for error in sorted(file_errors, key=lambda x: next(iter(list(x.values())[0]))):
if error.get("format_message") and config.stdin is False:
# reformat message
format_error_count += build_check_output(error["format_message"], config)
if config.statistics:
lint_error_count = build_stats_output(
[x.get("lint_message") for x in file_errors], config
)
if error.get("lint_message"):
# lint message
lint_error_count += build_output(error["lint_message"], config)
else:
for error in sorted(file_errors, key=lambda x: next(iter(list(x.values())[0]))):
if error.get("format_message") and config.stdin is False:
# reformat message
format_error_count += build_check_output(
error["format_message"], config
)
if error.get("lint_message"):
# lint message
lint_error_count += build_output(error["lint_message"], config)
tense_message = (
build_quantity(format_error_count) + " would be"
@ -180,3 +189,37 @@ def build_quantity_tense(size: int) -> str:
+ " "
+ ("were" if size > 1 or size == 0 else "was")
)
def build_stats_output(errors: List[Optional[Any]], config: Config) -> int:
"""Build output for linter statistics."""
if len(errors) == 0:
return 0
codes = []
for error in errors:
if error:
for code in list(error.values())[0]:
codes.append(code["code"])
messages = {
rule["rule"]["name"]: rule["rule"]["message"] for rule in config.linter_rules
}
if messages and codes:
longest_code = len(max(messages.keys(), key=len))
longest_count = len(
str(max(Counter(codes).values(), key=lambda x: len(str(x))))
)
for code in sorted(Counter(codes).items()):
code_space = (longest_code - len(str(code[0]))) * " "
count_space = (longest_count - len(str(code[1]))) * " "
echo(
f"{Fore.YELLOW}{code[0]}{Fore.BLUE} {code_space}{code[1]}{Style.RESET_ALL} {count_space}{messages[code[0]]}"
)
return sum(Counter(codes).values())

View file

@ -206,6 +206,7 @@ class Config:
format_css: bool = False,
format_js: bool = False,
configuration: Optional[str] = None,
statistics: bool = False,
):
self.reformat = reformat
@ -306,6 +307,8 @@ class Config:
)
)
self.statistics = statistics
# base options
default_indent = 4
if not indent:

View file

@ -954,3 +954,17 @@ def test_ignoring_rules(runner: CliRunner, tmp_file: TextIO) -> None:
)
result = runner.invoke(djlint, [tmp_file.name])
assert "H006" not in result.output
def test_statistics_empty(runner: CliRunner, tmp_file: TextIO) -> None:
write_to_file(tmp_file.name, b"")
result = runner.invoke(djlint, [tmp_file.name, "--statistics"])
assert result.exit_code == 0
def test_statistics_with_results(runner: CliRunner, tmp_file: TextIO) -> None:
write_to_file(tmp_file.name, b"<div>")
result = runner.invoke(djlint, [tmp_file.name, "--statistics"])
assert result.exit_code == 1