Skip to content

Commit

Permalink
Merge pull request #244 from Klavionik/adjustable-whitelines
Browse files Browse the repository at this point in the history
Adjustable whitelines feature
  • Loading branch information
lyz-code authored May 26, 2023
2 parents 229f9e6 + cb7969f commit 29e113c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 30 deletions.
17 changes: 17 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ export YAMLFIX_COMMENTS_REQUIRE_STARTING_SPACE="true"

This option enforces a space between the comment indicator (`#`) and the first character in the comment. It implements the enforcement of the yamllint rule `rules.comments.require-starting-space` - see: https://yamllint.readthedocs.io/en/stable/rules.html#module-yamllint.rules.comments

### Whitelines Adjusting

Default: `whitelines: int = 0`<br>
Environment variable override:
```bash
export YAMLFIX_WHITELINES="0"
```

This option allows to keep a speficied number of whitelines between lines.

It's useful if, for one, you like to separate GitHub Actions job steps or Docker-Compose
service definitions with a blank line.

Bear in mind that, like **Comments Whitelines**, it won't insert whitelines if there's no
whitelines in the first place. It will only fix 1 or more whitelines to the desired
amount (or remove them completely by default).

### Comments Whitelines

Default: `comments_whitelines: int = 1`<br>
Expand Down
46 changes: 19 additions & 27 deletions src/yamlfix/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,9 @@ def fix(self, source_code: str) -> str:
self._restore_jinja_variables,
self._restore_double_exclamations,
self._fix_comments,
self._fix_flow_style_lists,
self._fix_whitelines,
self._fix_top_level_lists,
self._fix_flow_style_lists,
self._add_newline_at_end_of_file,
]

Expand Down Expand Up @@ -478,7 +478,7 @@ def _fix_flow_style_lists(source_code: str) -> str:
```
This function moves the closing bracket to the end of the flow-style
list definition.
list definition and positions the newlines after the closing bracket.
Args:
source_code: Source code to be corrected.
Expand All @@ -487,26 +487,9 @@ def _fix_flow_style_lists(source_code: str) -> str:
Corrected source code.
"""
log.debug("Fixing flow-style lists...")
source_lines = source_code.splitlines()
reversed_fixed_source_lines: List[str] = []

should_append_square_brackets: bool = False
for line in reversed(source_lines):
if line == "]":
should_append_square_brackets = True
continue

if line == "":
reversed_fixed_source_lines.append(line)
continue

if should_append_square_brackets:
should_append_square_brackets = False
reversed_fixed_source_lines.append(line + "]")
else:
reversed_fixed_source_lines.append(line)

return "\n".join(reversed(reversed_fixed_source_lines))
pattern = r"\[(?P<items>.*)(?P<newlines>\n+)]"
replacement = r"[\g<items>]\g<newlines>"
return re.sub(pattern, repl=replacement, string=source_code)

@staticmethod
def _fix_truthy_strings(source_code: str) -> str:
Expand Down Expand Up @@ -616,8 +599,8 @@ def _fix_whitelines(self, source_code: str) -> str:
- 0 whiteline is allowed
- Exactly `self.config.comments_whitelines` whitelines are allowed
This method removes extraneous whitelines that are not immediately followed by
a comment.
This method also adjusts amount of whitelines that are not immediately followed
by a comment.
Args:
self: Source code to be corrected.
Expand All @@ -626,20 +609,21 @@ def _fix_whitelines(self, source_code: str) -> str:
Source code with appropriate whitelines standards.
"""
config = self.config
n_whitelines = config.whitelines
n_whitelines_from_content = config.comments_whitelines

re_whitelines_with_comments = "\n\n+[\t ]{0,}[#]"
re_whitelines_with_no_comments = "\n\n+[\t ]{0,}[^#\n\t ]"

remove_whitelines = partial(self._replace_whitelines, n_whitelines=0)
adjust_whitelines = partial(self._replace_whitelines, n_whitelines=n_whitelines)
replace_by_n_whitelines = partial(
self._replace_whitelines,
n_whitelines=n_whitelines_from_content,
)

source_code = re.sub(
pattern=re_whitelines_with_no_comments,
repl=remove_whitelines,
repl=adjust_whitelines,
string=source_code,
)
source_code = self._fix_section_whitelines(source_code)
Expand Down Expand Up @@ -722,7 +706,15 @@ def _restore_double_exclamations(source_code: str) -> str:

@staticmethod
def _add_newline_at_end_of_file(source_code: str) -> str:
return source_code + "\n"
"""Ensures that the file ends with exactly one newline.
Args:
source_code: Source code to be corrected.
Returns:
Corrected source code.
"""
return source_code.rstrip() + "\n"

@staticmethod
def _fix_jinja_variables(source_code: str) -> str:
Expand Down
1 change: 1 addition & 0 deletions src/yamlfix/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class YamlfixConfig(ConfigSchema):
comments_min_spaces_from_content: int = 2
comments_require_starting_space: bool = True
comments_whitelines: int = 1
whitelines: int = 0
section_whitelines: int = 0
config_path: Optional[str] = None
explicit_start: bool = True
Expand Down
109 changes: 109 additions & 0 deletions tests/unit/test_adapter_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,3 +830,112 @@ def test_section_whitelines_begin_no_explicit_start(self) -> None:
result = fix_code(source, config)

assert result == fixed_source

def test_whitelines_collapsed(self) -> None:
"""Checks that whitelines are collapsed by default."""
source = dedent(
"""\
key: value
dict:
key: value
nested_dict:
- key: value
key2: value2
- key: value
"""
)
fixed_source = dedent(
"""\
---
key: value
dict:
key: value
nested_dict:
- key: value
key2: value2
- key: value
"""
)
config = YamlfixConfig()

result = fix_code(source, config)

assert result == fixed_source

def test_whitelines_adjusted_to_value(self) -> None:
"""Checks that amount of whitelines are in line with the config value."""
source = dedent(
"""\
key: value
dict:
key: value
nested_list:
- key: value
key2: value2
- key: value
"""
)
fixed_source = dedent(
"""\
---
key: value
dict:
key: value
nested_list:
- key: value
key2: value2
- key: value
"""
)
config = YamlfixConfig()
config.whitelines = 1

result = fix_code(source, config)

assert result == fixed_source

def test_enforcing_flow_style_together_with_adjustable_newlines(self) -> None:
"""Checks that transforming block style sequences to flow style together with
newlines adjusting produces correct result.
"""
source = dedent(
"""\
---
dict:
nested_dict:
key: value
key2:
- list_item
nested_dict2:
key: value
"""
)
fixed_source = dedent(
"""\
---
dict:
nested_dict:
key: value
key2: [list_item]
nested_dict2:
key: value
"""
)
config = YamlfixConfig()
config.whitelines = 1
config.sequence_style = YamlNodeStyle.FLOW_STYLE

result = fix_code(source, config)

assert result == fixed_source
6 changes: 3 additions & 3 deletions tests/unit/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def test_fix_code_functions_emit_debug_logs(

fix_code("") # act

expected_logs = [
expected_logs = {
"Setting up ruamel yaml 'quote simple values' configuration...",
"Setting up ruamel yaml 'sequence flow style' configuration...",
"Running ruamel yaml base configuration...",
Expand All @@ -483,8 +483,8 @@ def test_fix_code_functions_emit_debug_logs(
"Fixing comments...",
"Fixing top level lists...",
"Fixing flow-style lists...",
]
assert caplog.messages == expected_logs
}
assert set(caplog.messages) == expected_logs
for record in caplog.records:
assert record.levelname == "DEBUG"

Expand Down

0 comments on commit 29e113c

Please sign in to comment.