Skip to content

cfengine format: Refactored code, added type hints and docstrings, expanded tests, and fixed small issues#55

Merged
olehermanse merged 10 commits intocfengine:mainfrom
olehermanse:continuation
Apr 14, 2026
Merged

cfengine format: Refactored code, added type hints and docstrings, expanded tests, and fixed small issues#55
olehermanse merged 10 commits intocfengine:mainfrom
olehermanse:continuation

Conversation

@olehermanse
Copy link
Copy Markdown
Member

@olehermanse olehermanse commented Apr 9, 2026

No description provided.

@olehermanse olehermanse changed the title WIP WIP formatting improvements Apr 9, 2026
@olehermanse olehermanse force-pushed the continuation branch 4 times, most recently from 04f4df3 to 4f76e8b Compare April 13, 2026 12:58
@olehermanse olehermanse marked this pull request as ready for review April 13, 2026 13:00
@olehermanse olehermanse changed the title WIP formatting improvements cfengine format: Refactored code, added type hints and docstrings, and expanded tests Apr 13, 2026
@cf-bottom
Copy link
Copy Markdown

Thanks for submitting a pull request! Maybe @craigcomstock can review this?

@olehermanse olehermanse changed the title cfengine format: Refactored code, added type hints and docstrings, and expanded tests cfengine format: Refactored code, added type hints and docstrings, expanded tests, and fixed small issues Apr 13, 2026
@olehermanse olehermanse requested review from larsewi and victormlg and removed request for larsewi and victormlg April 13, 2026 13:23


def _has_trailing_comma(middle):
"""Check if list middle nodes end with a trailing comma."""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middle? I know this is just a function parameter name but seems like it should be more like just list_of_nodes or something like that.

Copy link
Copy Markdown
Member Author

@olehermanse olehermanse Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this tree-sitter code you often have to consider what the list of nodes looks like - it has commas and curly braces as separate elements.

The reason for the name is that you have a list of nodes like;

nodes = ["{", "a", ",", "b", "}"]

So nodes[1:-1] are referred to as middle (what's left after removing the ends on each side).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the kind of things that I would like to see in the doc string. I.e., the parameter middle contains tokens between the two curly braces of a list.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return True

# Multi-line with split stakeholder
if _has_stakeholder(children) and _stakeholder_needs_splitting(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the list of stakeholders be reformatted for trailing comma even if the stakeholder has no comments which is the condition included invisibly by _stakeholder_needs_splitting() as I read it.

My example I was trying was

bundle agent main
{
  reports: "hi" -> { "yoda", "boba", };
}

And was surprised to not see some of this code exercised.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug I can fix. Adding / removing commas is a bit more "tricky" than the other reformatting we do, since commas are nodes in the syntax tree, and since comment nodes can occur pretty much everywhere.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests: 63348d2

Fix: 88ff48d

"""Format the middle elements (between { and }) of a stakeholder list."""
if not any(n.type == "comment" for n in middle):
if _has_trailing_comma(middle):
return split_generic_list(middle, indent, line_length)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see these functions properly doing what they say: always add trailing comma in multi-line lists:

191         # Always add a trailing comma on multi-line lists
192         if elements and not elements[-1].endswith(","):
193             elements[-1] = elements[-1] + ","

An example:

bundle agent main
{
  reports:
    "hi" -> {
      "yoda", # this is yoda of course
      "boba" # and yet another star wars character
    };
}

Is formatted as:

bundle agent main
{
  reports:
    "hi" -> {
        "yoda",
        # this is yoda of course
        "boba"
        # and yet another star wars character
      };
}

And it would seem according to the comment in the code I mention above that "boba" should be followed by a comma.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests: 63348d2

Fix: 88ff48d

return False
prefix = promiser_line(children)
if not prefix:
line = _promiser_line_with_stakeholder(children)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have code coverage maybe? I am not sure when this case would be reached. Seems like most cases would pop out above at line 361:

if _has_stakeholder(children) and _stakeholder_needs_splitting(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add comments to make it as clear as possible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

olehermanse and others added 8 commits April 13, 2026 18:54
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
Other PRs were merged to master, and so there are test failures /
linting errors I had to fix now.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
JSON code was returning 1 (error) for case where file was reformatted.

Also ended up refactoring a bit to make this as clear as possible.

Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
…ilining

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
Signed-off-by: Ole Herman Schumacher Elgesem <ole@northern.tech>
Copy link
Copy Markdown
Contributor

@larsewi larsewi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all, a great improvement

Comment on lines +91 to +96
if root.type == node_type:
return root
for child in root.children:
found = _find_opt(child, node_type)
if found:
return found
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not sufficient to just call the _find_opt() and check the returned value?

raise ValueError(f"No node of type {node_type!r} found")


def _find_opt(root: Node, node_type: str):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there is a better name that can be used here? E.g., _find_or_none

def test_maybe_split_rval_too_long():
root = _parse('bundle agent x { vars: "v" slist => { "a", "b" }; }')
list_node = _find(root, "list")
result = maybe_split_rval(list_node, 6, 999, 80)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if you'd suffix the argument name, so that it is clear what these numbers are.

@larsewi
Copy link
Copy Markdown
Contributor

larsewi commented Apr 14, 2026

I would just merge and summit follow-up PRs if you want to change anything more now.

@olehermanse olehermanse merged commit 6e9a4f2 into cfengine:main Apr 14, 2026
5 checks passed
@olehermanse olehermanse deleted the continuation branch April 14, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants