Skip to content

Commit

Permalink
feat: don't erase comment-only yaml documents
Browse files Browse the repository at this point in the history
  • Loading branch information
marcules committed Dec 29, 2022
1 parent 0f880c4 commit c36d86e
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
42 changes: 42 additions & 0 deletions src/yamlfix/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ def patch_sequence_style(key_node: Node, value_node: Node) -> None:
if not sequence_node.value:
return

# if this key_node is the `yamlfix_document_fix_id` node,
# the sequence_node is the top-level list, which has to be forced
# into block-mode, so the key_node can be removed afterwards
force_block_style = force_block_style or self._seq_is_in_top_level_node(
key_node
)

# if this sequence contains non-scalar nodes (i.e. dicts, lists, etc.),
# force block-style
force_block_style = (
Expand Down Expand Up @@ -252,6 +259,9 @@ def patch_sequence_style(key_node: Node, value_node: Node) -> None:

self.patch_functions.append(patch_sequence_style)

def _seq_is_in_top_level_node(self, key_node: Node) -> bool:
return str(key_node.value) == f"yamlfix_{self.config.document_fix_id}"

@staticmethod
def _seq_contains_non_scalar_nodes(seq_node: Node) -> bool:
return any(not isinstance(node, ScalarNode) for node in seq_node.value)
Expand Down Expand Up @@ -342,9 +352,11 @@ def fix(self, source_code: str) -> str:
log.debug("Running source code fixers...")

fixers = [
self._fix_comment_only_files,
self._fix_truthy_strings,
self._fix_jinja_variables,
self._ruamel_yaml_fixer,
self._restore_comment_only_files,
self._restore_truthy_strings,
self._restore_jinja_variables,
self._restore_double_exclamations,
Expand Down Expand Up @@ -693,3 +705,33 @@ def _restore_jinja_variables(source_code: str) -> str:
fixed_source_lines.append(line)

return "\n".join(fixed_source_lines)

def _fix_comment_only_files(self, source_code: str) -> str:
"""Add a mapping key with an id to the start of the document\
to preserve comments."""
fixed_source_lines = []
yamlfix_document_id_line = f"yamlfix_{self.config.document_fix_id}:"

# Add the document id line after each document start
has_start_indicator = False
for line in source_code.splitlines():
fixed_source_lines.append(line)
if line.startswith("---"):
has_start_indicator = True
fixed_source_lines.append(yamlfix_document_id_line)

# if the document has no start indicator, the document id as the first line
if not has_start_indicator:
fixed_source_lines.insert(0, yamlfix_document_id_line)

return "\n".join(fixed_source_lines)

def _restore_comment_only_files(self, source_code: str) -> str:
"""Remove the document start id from the document again."""
fixed_source_lines = []

for line in source_code.splitlines():
if self.config.document_fix_id not in line:
fixed_source_lines.append(line)

return "\n".join(fixed_source_lines)
2 changes: 2 additions & 0 deletions src/yamlfix/model.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Define program entities like configuration value entities."""

import uuid
from typing import Optional

from maison.schema import ConfigSchema
Expand All @@ -12,6 +13,7 @@ class YamlfixConfig(ConfigSchema):
comments_min_spaces_from_content: int = 2
comments_require_starting_space: bool = True
config_path: Optional[str] = None
document_fix_id: str = uuid.uuid4().hex
explicit_start: bool = True
flow_style_sequence: Optional[bool] = True
indent_mapping: int = 2
Expand Down
34 changes: 33 additions & 1 deletion tests/unit/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,21 @@ def test_fix_code_preserves_comments(self) -> None:

assert result == source

def test_fix_code_preserves_comments_without_start_indication(self) -> None:
"""Don't delete comments without yaml explicit start indictor."""
source = dedent(
"""\
# Keep comments!
program: yamlfix
"""
)
config = YamlfixConfig()
config.explicit_start = False

result = fix_code(source, config)

assert result == source

def test_fix_code_preserves_comment_only_file(self) -> None:
"""Don't delete comments even if the file is only comments."""
source = dedent(
Expand All @@ -196,7 +211,24 @@ def test_fix_code_preserves_comment_only_file(self) -> None:
result = fix_code(source)

assert result == source


def test_fix_code_preserves_comment_only_files_without_start_indication(
self,
) -> None:
"""Don't delete comments even if the file is only comments, without\
start indication."""
source = dedent(
"""\
# Keep comments!
"""
)
config = YamlfixConfig()
config.explicit_start = False

result = fix_code(source, config)

assert result == source

def test_fix_code_respects_parent_lists_with_comments(self) -> None:
"""Do not indent lists at the first level even if there is a comment."""
source = dedent(
Expand Down

0 comments on commit c36d86e

Please sign in to comment.