mirror of
https://github.com/Hopiu/djLint.git
synced 2026-03-16 21:40:24 +00:00
feat(linter): added --statistics flag to print summary of linter findings
closes #389
This commit is contained in:
parent
756c760e44
commit
489decb2e1
8 changed files with 89 additions and 16 deletions
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue