feat: add negation support for step conditions (!{{var}})
Adds "!{{var}}" syntax for negated truthy checks in Step.Condition.
Useful for "skip this step if feature is enabled" patterns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
ee34a74e90
commit
6893eb6080
@@ -5,6 +5,7 @@
|
|||||||
//
|
//
|
||||||
// Supported formats:
|
// Supported formats:
|
||||||
// - "{{var}}" - truthy check (non-empty, non-"false", non-"0")
|
// - "{{var}}" - truthy check (non-empty, non-"false", non-"0")
|
||||||
|
// - "!{{var}}" - negated truthy check (include if var is falsy)
|
||||||
// - "{{var}} == value" - equality check
|
// - "{{var}} == value" - equality check
|
||||||
// - "{{var}} != value" - inequality check
|
// - "{{var}} != value" - inequality check
|
||||||
package formula
|
package formula
|
||||||
@@ -20,6 +21,9 @@ var (
|
|||||||
// {{var}} - simple variable reference for truthy check
|
// {{var}} - simple variable reference for truthy check
|
||||||
stepCondVarPattern = regexp.MustCompile(`^\{\{(\w+)\}\}$`)
|
stepCondVarPattern = regexp.MustCompile(`^\{\{(\w+)\}\}$`)
|
||||||
|
|
||||||
|
// !{{var}} - negated truthy check
|
||||||
|
stepCondNegatedVarPattern = regexp.MustCompile(`^!\{\{(\w+)\}\}$`)
|
||||||
|
|
||||||
// {{var}} == value or {{var}} != value
|
// {{var}} == value or {{var}} != value
|
||||||
stepCondComparePattern = regexp.MustCompile(`^\{\{(\w+)\}\}\s*(==|!=)\s*(.+)$`)
|
stepCondComparePattern = regexp.MustCompile(`^\{\{(\w+)\}\}\s*(==|!=)\s*(.+)$`)
|
||||||
)
|
)
|
||||||
@@ -30,6 +34,7 @@ var (
|
|||||||
// Condition formats:
|
// Condition formats:
|
||||||
// - "" (empty) - always include
|
// - "" (empty) - always include
|
||||||
// - "{{var}}" - include if var is truthy (non-empty, non-"false", non-"0")
|
// - "{{var}}" - include if var is truthy (non-empty, non-"false", non-"0")
|
||||||
|
// - "!{{var}}" - include if var is NOT truthy (negated)
|
||||||
// - "{{var}} == value" - include if var equals value
|
// - "{{var}} == value" - include if var equals value
|
||||||
// - "{{var}} != value" - include if var does not equal value
|
// - "{{var}} != value" - include if var does not equal value
|
||||||
func EvaluateStepCondition(condition string, vars map[string]string) (bool, error) {
|
func EvaluateStepCondition(condition string, vars map[string]string) (bool, error) {
|
||||||
@@ -47,6 +52,13 @@ func EvaluateStepCondition(condition string, vars map[string]string) (bool, erro
|
|||||||
return isTruthy(value), nil
|
return isTruthy(value), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try negated truthy pattern: !{{var}}
|
||||||
|
if m := stepCondNegatedVarPattern.FindStringSubmatch(condition); m != nil {
|
||||||
|
varName := m[1]
|
||||||
|
value := vars[varName]
|
||||||
|
return !isTruthy(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Try comparison pattern: {{var}} == value or {{var}} != value
|
// Try comparison pattern: {{var}} == value or {{var}} != value
|
||||||
if m := stepCondComparePattern.FindStringSubmatch(condition); m != nil {
|
if m := stepCondComparePattern.FindStringSubmatch(condition); m != nil {
|
||||||
varName := m[1]
|
varName := m[1]
|
||||||
|
|||||||
@@ -84,6 +84,35 @@ func TestEvaluateStepCondition(t *testing.T) {
|
|||||||
want: true,
|
want: true,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
// Negated truthy checks: !{{var}}
|
||||||
|
{
|
||||||
|
name: "negated - truthy value becomes false",
|
||||||
|
condition: "!{{enabled}}",
|
||||||
|
vars: map[string]string{"enabled": "true"},
|
||||||
|
want: false,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negated - falsy value becomes true",
|
||||||
|
condition: "!{{enabled}}",
|
||||||
|
vars: map[string]string{"enabled": "false"},
|
||||||
|
want: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negated - empty value becomes true",
|
||||||
|
condition: "!{{enabled}}",
|
||||||
|
vars: map[string]string{"enabled": ""},
|
||||||
|
want: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negated - missing variable becomes true",
|
||||||
|
condition: "!{{enabled}}",
|
||||||
|
vars: map[string]string{},
|
||||||
|
want: true,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
// Equality checks: {{var}} == value
|
// Equality checks: {{var}} == value
|
||||||
{
|
{
|
||||||
name: "equality - match",
|
name: "equality - match",
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ type Step struct {
|
|||||||
ExpandVars map[string]string `json:"expand_vars,omitempty"`
|
ExpandVars map[string]string `json:"expand_vars,omitempty"`
|
||||||
|
|
||||||
// Condition makes this step optional based on a variable.
|
// Condition makes this step optional based on a variable.
|
||||||
// Format: "{{var}}" (truthy) or "{{var}} == value" or "{{var}} != value".
|
// Format: "{{var}}" (truthy), "!{{var}}" (negated), "{{var}} == value", "{{var}} != value".
|
||||||
// Evaluated at cook/pour time via FilterStepsByCondition.
|
// Evaluated at cook/pour time via FilterStepsByCondition.
|
||||||
Condition string `json:"condition,omitempty"`
|
Condition string `json:"condition,omitempty"`
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user