Fixes for newlines in yaml

This commit is contained in:
Miguel Jacq 2026-06-20 18:27:22 +10:00
parent bbbbe33e54
commit 00d0064362
Signed by: mig5
GPG key ID: 03906B4110AAD3B8
4 changed files with 25 additions and 7 deletions

View file

@ -157,7 +157,7 @@ class ErbTranslator:
return self.ruby_value(expr) return self.ruby_value(expr)
def statement_to_erb(self, stmt: str) -> str: def statement_to_erb(self, stmt: str) -> str:
if stmt.endswith("-"): if stmt.endswith(("-", "+")):
stmt = stmt[:-1].rstrip() stmt = stmt[:-1].rstrip()
if stmt.startswith("for "): if stmt.startswith("for "):

View file

@ -510,10 +510,10 @@ class YamlHandler(DictLikeHandler):
# into the rendered YAML and nesting the next top-level key. # into the rendered YAML and nesting the next top-level key.
lines.append(f"{j2.for_start(item_var, collection_var)}{item_lines[0]}") lines.append(f"{j2.for_start(item_var, collection_var)}{item_lines[0]}")
lines.extend(item_lines[1:]) lines.extend(item_lines[1:])
lines.append(j2.for_end()) lines.append(j2.for_end(keep_trailing_newline=True))
else: else:
lines.append(j2.for_start(item_var, collection_var)) lines.append(j2.for_start(item_var, collection_var))
lines.append(j2.for_end()) lines.append(j2.for_end(keep_trailing_newline=True))
return "\n".join(lines) return "\n".join(lines)

View file

@ -43,10 +43,19 @@ def to_json(
return filtered(value, f"to_json({', '.join(args)})") return filtered(value, f"to_json({', '.join(args)})")
def statement(value: str, *, trim_right: bool = False) -> str: def statement(
value: str,
*,
trim_right: bool = False,
keep_trailing_newline: bool = False,
) -> str:
"""Return a Jinja2 statement tag for an already-built statement body.""" """Return a Jinja2 statement tag for an already-built statement body."""
if trim_right and keep_trailing_newline:
raise ValueError("trim_right and keep_trailing_newline are mutually exclusive")
if trim_right: if trim_right:
return f"{{% {value} -%}}" return f"{{% {value} -%}}"
if keep_trailing_newline:
return f"{{% {value} +%}}"
return f"{{% {value} %}}" return f"{{% {value} %}}"
@ -66,8 +75,12 @@ def for_start(item_var: str, collection_var: str) -> str:
return statement(f"for {item_var} in {collection_var}") return statement(f"for {item_var} in {collection_var}")
def for_end(*, trim_right: bool = False) -> str: def for_end(*, trim_right: bool = False, keep_trailing_newline: bool = False) -> str:
return statement("endfor", trim_right=trim_right) return statement(
"endfor",
trim_right=trim_right,
keep_trailing_newline=keep_trailing_newline,
)
def yaml_scalar_expression(var_name: str, raw_value: str | None = None) -> str: def yaml_scalar_expression(var_name: str, raw_value: str | None = None) -> str:

View file

@ -217,7 +217,7 @@ def test_yaml_loop_preserves_blank_separator_after_list(tmp_path: Path):
def test_yaml_loop_preserves_following_top_level_comments(tmp_path: Path): def test_yaml_loop_preserves_following_top_level_comments(tmp_path: Path):
from jinja2 import Template from jinja2 import Environment, Template
from jinjaturtle.core import analyze_loops from jinjaturtle.core import analyze_loops
@ -248,10 +248,15 @@ def test_yaml_loop_preserves_following_top_level_comments(tmp_path: Path):
fmt, parsed, "role", original_text=text, loop_candidates=loop_candidates fmt, parsed, "role", original_text=text, loop_candidates=loop_candidates
) )
rendered = Template(template).render(**defaults) rendered = Template(template).render(**defaults)
ansible_rendered = (
Environment(trim_blocks=True).from_string(template).render(**defaults)
)
assert "# Offense count: 2" in rendered assert "# Offense count: 2" in rendered
assert "# This cop supports unsafe autocorrection" in rendered assert "# This cop supports unsafe autocorrection" in rendered
assert "spec.rb\n\n# Offense count: 2" in ansible_rendered
assert yaml.safe_load(rendered) == yaml.safe_load(text) assert yaml.safe_load(rendered) == yaml.safe_load(text)
assert yaml.safe_load(ansible_rendered) == yaml.safe_load(text)
def test_yaml_scalar_loop_preserves_quoted_list_items(tmp_path: Path): def test_yaml_scalar_loop_preserves_quoted_list_items(tmp_path: Path):