fix(workflows): preserve commas inside quoted list-literal elements (#3134)

* fix(workflows): preserve commas inside quoted list-literal elements

The simple-expression evaluator parsed a list literal with a naive
`inner.split(",")`, which splits on commas inside quoted strings (and
nested brackets). So `{{ ["a, b", "c"] }}` evaluated to three items
(`["a", "b", "c"]`) instead of two, silently corrupting `fan-out` `items:`
and any list expression that contains a comma inside a quoted element.

Split list-literal elements on top-level commas only, ignoring commas
inside quotes or nested brackets, via a small `_split_top_level_commas`
helper. Plain and empty lists are unchanged.

Add tests covering quoted commas, nested lists, and the existing
plain/empty cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(workflows): cover single-quoted and nested list literals

Address review: extend the list-literal regression test to assert single-quoted elements with commas and nested lists parse correctly, alongside the existing double-quoted cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali jawwad
2026-06-25 01:10:02 +05:00
committed by GitHub
parent e5df517ddc
commit fdaaf18371
2 changed files with 56 additions and 1 deletions

View File

@@ -268,6 +268,24 @@ class TestExpressions:
ctx = StepContext(inputs={"a": False, "b": True})
assert evaluate_expression("{{ inputs.a or inputs.b }}", ctx) is True
def test_list_literal_preserves_quoted_commas(self):
from specify_cli.workflows.expressions import evaluate_expression
from specify_cli.workflows.base import StepContext
ctx = StepContext()
# commas inside a double-quoted element must not split it
assert evaluate_expression('{{ ["a, b", "c"] }}', ctx) == ["a, b", "c"]
assert evaluate_expression('{{ ["x, y, z"] }}', ctx) == ["x, y, z"]
# single-quoted elements are handled the same way
assert evaluate_expression("{{ ['a, b', 'c'] }}", ctx) == ["a, b", "c"]
assert evaluate_expression("{{ ['p, q, r'] }}", ctx) == ["p, q, r"]
# plain and empty lists still parse correctly
assert evaluate_expression("{{ [1, 2, 3] }}", ctx) == [1, 2, 3]
assert evaluate_expression("{{ [] }}", ctx) == []
# nested lists (commas inside the inner brackets) stay intact
assert evaluate_expression('{{ [["a", "b"], "c"] }}', ctx) == [["a", "b"], "c"]
assert evaluate_expression("{{ [[1, 2], [3, 4]] }}", ctx) == [[1, 2], [3, 4]]
def test_filter_default(self):
from specify_cli.workflows.expressions import evaluate_expression
from specify_cli.workflows.base import StepContext