diff --git a/muppet/puppet/ast.py b/muppet/puppet/ast.py index f30acaaf0c750eb65593146ca933bbe0ed2997b4..a8baa1a6b92f574086149d26710c7237dd370a26 100644 --- a/muppet/puppet/ast.py +++ b/muppet/puppet/ast.py @@ -179,6 +179,7 @@ class PuppetCollect(Puppet): type: Puppet query: Puppet + ops: list[PuppetInstanciationParameter] = field(default_factory=list) @dataclass @@ -625,6 +626,11 @@ def build_ast(form: Any) -> Puppet: case ['concat', *parts]: return PuppetConcat([build_ast(p) for p in parts]) + case ['collect', {'type': t, 'query': q, 'ops': ops}]: + return PuppetCollect(build_ast(t), + build_ast(q), + [parse_puppet_instanciation_param(x) for x in ops]) + case ['collect', {'type': t, 'query': q}]: return PuppetCollect(build_ast(t), build_ast(q)) diff --git a/muppet/puppet/format/parser.py b/muppet/puppet/format/parser.py index b5406a931c0ce49c1a1c879f4fc0ea8079e30687..ccb59f2711324f243e4648214717d41a65d29819 100644 --- a/muppet/puppet/format/parser.py +++ b/muppet/puppet/format/parser.py @@ -372,7 +372,15 @@ class ParserFormatter(Serializer[ParseDirective]): @override def _puppet_collect(self, it: PuppetCollect) -> ParseDirective: - return ws & self.s(it.type) & ws & self.s(it.query) + parser = ws & self.s(it.type) & ws & self.s(it.query) + + sub = ws & "{" + for param in it.ops: + sub &= self.instanciation_parameter(param) + sub &= ws & '}' + + parser &= optional(sub) + return parser @override def _puppet_concat(self, it: PuppetConcat) -> ParseDirective: diff --git a/tests/test_parse_elsif.py b/tests/test_parse_elsif.py index 8afa037e431a770845e7e6cd7bd9c5424cce2ef0..1bcf43dca815537a74fd74fc3a66fab71cd5fa13 100644 --- a/tests/test_parse_elsif.py +++ b/tests/test_parse_elsif.py @@ -179,3 +179,21 @@ def test_string_interpolation_deep_access(): parse_string(""" "${x['y']['z']}" """) + + +def test_collect(): + parse_string(""" + Exec <| title=='apt_update' |> { + refreshonly => false, + } + """) + + +def test_collect_nested(): + parse_string(""" + if $_update['frequency'] == 'always' { + Exec <| title=='apt_update' |> { + refreshonly => false, + } + } + """)