mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-19 07:46:51 +00:00
* Feat: Add NotEmpty and NegativePattern constraints to StringParam; implement Closed for MapParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add validation support for array and map parameters - Introduced validators for ArrayParam and MapParam, allowing for cross-field validation within structured parameters. - Added NonEmpty validation for ArrayParam to ensure arrays are not empty. - Implemented ConditionalStructOp for conditional struct generation based on specified conditions. - Created a new Validator type for defining validation rules with optional guard conditions. - Added tests for various validation scenarios, including mutual exclusion and conditional parameters. - Enhanced the CUE generation logic to incorporate new validation features and conditional struct handling. Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent API with new scoped field conditions and improve validation checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance ArrayParam with NotEmpty constraint and update ScopedField documentation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: rename ScopedField to LocalField for improved clarity in condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: refactor local field conditions to use RegexMatch and streamline condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: simplify condition handling by removing unused comparison types and refactoring NotCondition usage Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unused raw CUE block handling from baseDefinition and ComponentDefinition Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * test: update condition handling in parameter tests to use NotExpr and Cond methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove negative pattern handling from StringParam and related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add support for emitting raw header blocks in template generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove non-empty check from ArrayParam and update related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: convert parameter constraint tests to use Ginkgo and Gomega for improved readability and maintainability Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent APIs for OAM with new CUE generation tests and condition evaluations Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: clean up whitespace in component, cuegen, expr, param, and resource files Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation by adding support for new expression types and iterator references Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unnecessary whitespace in cuegen.go Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: rename LenOf to LenOfExpr for clarity in comparison methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation and validation for string arrays in ArrayParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * ci: retrigger checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Co-authored-by: Ayush Kumar <aykumar@guidewire.com>
807 lines
24 KiB
Go
807 lines
24 KiB
Go
/*
|
|
Copyright 2025 The KubeVela Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package defkit
|
|
|
|
// Literal represents a literal value in an expression.
|
|
type Literal struct {
|
|
val any
|
|
}
|
|
|
|
func (l *Literal) expr() {}
|
|
func (l *Literal) value() {}
|
|
|
|
// Val returns the underlying value.
|
|
func (l *Literal) Val() any { return l.val }
|
|
|
|
// Lit creates a literal value from any Go value.
|
|
func Lit(v any) *Literal {
|
|
return &Literal{val: v}
|
|
}
|
|
|
|
// CompOp represents a comparison operator.
|
|
type CompOp string
|
|
|
|
const (
|
|
// OpEq represents equality (==)
|
|
OpEq CompOp = "=="
|
|
// OpNe represents inequality (!=)
|
|
OpNe CompOp = "!="
|
|
// OpLt represents less than (<)
|
|
OpLt CompOp = "<"
|
|
// OpLe represents less than or equal (<=)
|
|
OpLe CompOp = "<="
|
|
// OpGt represents greater than (>)
|
|
OpGt CompOp = ">"
|
|
// OpGe represents greater than or equal (>=)
|
|
OpGe CompOp = ">="
|
|
)
|
|
|
|
// Comparison represents a comparison between two expressions.
|
|
type Comparison struct {
|
|
baseCondition
|
|
left Expr
|
|
op CompOp
|
|
right Expr
|
|
}
|
|
|
|
// Left returns the left-hand side expression.
|
|
func (c *Comparison) Left() Expr { return c.left }
|
|
|
|
// Op returns the comparison operator.
|
|
func (c *Comparison) Op() CompOp { return c.op }
|
|
|
|
// Right returns the right-hand side expression.
|
|
func (c *Comparison) Right() Expr { return c.right }
|
|
|
|
// Eq creates an equality comparison.
|
|
func Eq(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpEq, right: right}
|
|
}
|
|
|
|
// Ne creates an inequality comparison.
|
|
func Ne(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpNe, right: right}
|
|
}
|
|
|
|
// Lt creates a less-than comparison.
|
|
func Lt(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpLt, right: right}
|
|
}
|
|
|
|
// Le creates a less-than-or-equal comparison.
|
|
func Le(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpLe, right: right}
|
|
}
|
|
|
|
// Gt creates a greater-than comparison.
|
|
func Gt(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpGt, right: right}
|
|
}
|
|
|
|
// Ge creates a greater-than-or-equal comparison.
|
|
func Ge(left, right Expr) *Comparison {
|
|
return &Comparison{left: left, op: OpGe, right: right}
|
|
}
|
|
|
|
// LogicalOp represents a logical operator.
|
|
type LogicalOp string
|
|
|
|
const (
|
|
// OpAnd represents logical AND (&&)
|
|
OpAnd LogicalOp = "&&"
|
|
// OpOr represents logical OR (||)
|
|
OpOr LogicalOp = "||"
|
|
)
|
|
|
|
// LogicalExpr represents a logical combination of conditions.
|
|
type LogicalExpr struct {
|
|
baseCondition
|
|
op LogicalOp
|
|
conditions []Condition
|
|
}
|
|
|
|
// Op returns the logical operator.
|
|
func (l *LogicalExpr) Op() LogicalOp { return l.op }
|
|
|
|
// Conditions returns the list of combined conditions.
|
|
func (l *LogicalExpr) Conditions() []Condition { return l.conditions }
|
|
|
|
// And creates a logical AND of multiple conditions.
|
|
func And(conditions ...Condition) *LogicalExpr {
|
|
return &LogicalExpr{
|
|
op: OpAnd,
|
|
conditions: conditions,
|
|
}
|
|
}
|
|
|
|
// Or creates a logical OR of multiple conditions.
|
|
func Or(conditions ...Condition) *LogicalExpr {
|
|
return &LogicalExpr{
|
|
op: OpOr,
|
|
conditions: conditions,
|
|
}
|
|
}
|
|
|
|
// NotExpr represents a logical negation of a condition.
|
|
type NotExpr struct {
|
|
baseCondition
|
|
cond Condition
|
|
}
|
|
|
|
// Cond returns the negated condition.
|
|
func (n *NotExpr) Cond() Condition { return n.cond }
|
|
|
|
// Not creates a logical NOT of a condition.
|
|
func Not(cond Condition) *NotExpr {
|
|
return &NotExpr{cond: cond}
|
|
}
|
|
|
|
// IsSetCondition represents a check for whether a parameter is set.
|
|
type IsSetCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (i *IsSetCondition) ParamName() string { return i.paramName }
|
|
|
|
// TruthyCondition represents a truthy check on a boolean parameter.
|
|
// In CUE, this generates `if parameter.name` instead of `if parameter.name == true`.
|
|
type TruthyCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (t *TruthyCondition) ParamName() string { return t.paramName }
|
|
|
|
// AndCondition represents a binary logical AND of two conditions.
|
|
// This is an internal IR type used by cuegen to combine conditions during code generation.
|
|
// For the user-facing API, use And() which accepts variadic conditions via LogicalExpr.
|
|
type AndCondition struct {
|
|
baseCondition
|
|
left Condition
|
|
right Condition
|
|
}
|
|
|
|
// --- Parameter Runtime Condition Types ---
|
|
|
|
// FalsyCondition represents a falsy check on a boolean parameter.
|
|
// In CUE, this generates `if !parameter.name`.
|
|
type FalsyCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (f *FalsyCondition) ParamName() string { return f.paramName }
|
|
|
|
// InCondition represents a check if a parameter value is in a set of values.
|
|
// Generates: parameter.name == val1 || parameter.name == val2 || ...
|
|
type InCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
values []any
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *InCondition) ParamName() string { return c.paramName }
|
|
|
|
// Values returns the set of values to check against.
|
|
func (c *InCondition) Values() []any { return c.values }
|
|
|
|
// StringContainsCondition checks if a string parameter contains a substring.
|
|
// Generates: strings.Contains(parameter.name, "substr")
|
|
type StringContainsCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
substr string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *StringContainsCondition) ParamName() string { return c.paramName }
|
|
|
|
// Substr returns the substring to check for.
|
|
func (c *StringContainsCondition) Substr() string { return c.substr }
|
|
|
|
// RegexMatchCondition checks if any Value matches a regex pattern.
|
|
// Generates: <value> =~ "pattern"
|
|
// Used by both LocalFieldRef.Matches() and StringParam.Matches().
|
|
type RegexMatchCondition struct {
|
|
baseCondition
|
|
source Value
|
|
pattern string
|
|
}
|
|
|
|
// Source returns the value being matched.
|
|
func (c *RegexMatchCondition) Source() Value { return c.source }
|
|
|
|
// Pattern returns the regex pattern.
|
|
func (c *RegexMatchCondition) Pattern() string { return c.pattern }
|
|
|
|
// RegexMatch creates a condition that checks if a value matches a regex pattern.
|
|
func RegexMatch(source Value, pattern string) *RegexMatchCondition {
|
|
return &RegexMatchCondition{source: source, pattern: pattern}
|
|
}
|
|
|
|
// StringStartsWithCondition checks if a string parameter starts with a prefix.
|
|
// Generates: strings.HasPrefix(parameter.name, "prefix")
|
|
type StringStartsWithCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
prefix string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *StringStartsWithCondition) ParamName() string { return c.paramName }
|
|
|
|
// Prefix returns the prefix to check for.
|
|
func (c *StringStartsWithCondition) Prefix() string { return c.prefix }
|
|
|
|
// StringEndsWithCondition checks if a string parameter ends with a suffix.
|
|
// Generates: strings.HasSuffix(parameter.name, "suffix")
|
|
type StringEndsWithCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
suffix string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *StringEndsWithCondition) ParamName() string { return c.paramName }
|
|
|
|
// Suffix returns the suffix to check for.
|
|
func (c *StringEndsWithCondition) Suffix() string { return c.suffix }
|
|
|
|
// LenCondition checks the length of a parameter (string, array, or map).
|
|
// Generates: len(parameter.name) op n
|
|
type LenCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
op string // ==, !=, <, <=, >, >=
|
|
length int
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *LenCondition) ParamName() string { return c.paramName }
|
|
|
|
// Op returns the comparison operator.
|
|
func (c *LenCondition) Op() string { return c.op }
|
|
|
|
// Length returns the length to compare against.
|
|
func (c *LenCondition) Length() int { return c.length }
|
|
|
|
// ArrayContainsCondition checks if an array parameter contains a specific value.
|
|
// Generates: list.Contains(parameter.name, value)
|
|
type ArrayContainsCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
value any
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *ArrayContainsCondition) ParamName() string { return c.paramName }
|
|
|
|
// Value returns the value to check for.
|
|
func (c *ArrayContainsCondition) Value() any { return c.value }
|
|
|
|
// MapHasKeyCondition checks if a map parameter has a specific key.
|
|
// Generates: parameter.name.key != _|_
|
|
type MapHasKeyCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
key string
|
|
}
|
|
|
|
// ParamName returns the parameter name being checked.
|
|
func (c *MapHasKeyCondition) ParamName() string { return c.paramName }
|
|
|
|
// Key returns the key to check for.
|
|
func (c *MapHasKeyCondition) Key() string { return c.key }
|
|
|
|
// --- CUE Stdlib Function Wrappers ---
|
|
// These functions generate CUE expressions that call standard library functions.
|
|
|
|
// CUEFunc represents a call to a CUE standard library function.
|
|
type CUEFunc struct {
|
|
pkg string // e.g., "strconv", "strings", "list"
|
|
fn string // e.g., "FormatInt", "ToLower"
|
|
args []Value
|
|
}
|
|
|
|
func (c *CUEFunc) expr() {}
|
|
func (c *CUEFunc) value() {}
|
|
|
|
// RequiredImports returns the CUE imports required by this function call.
|
|
func (c *CUEFunc) RequiredImports() []string {
|
|
if c.pkg != "" {
|
|
return []string{c.pkg}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Package returns the CUE package name.
|
|
func (c *CUEFunc) Package() string { return c.pkg }
|
|
|
|
// Function returns the function name.
|
|
func (c *CUEFunc) Function() string { return c.fn }
|
|
|
|
// Args returns the function arguments.
|
|
func (c *CUEFunc) Args() []Value { return c.args }
|
|
|
|
// StrconvFormatInt creates a strconv.FormatInt(v, base) expression.
|
|
// In CUE: strconv.FormatInt(v, 10)
|
|
func StrconvFormatInt(v Value, base int) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "strconv",
|
|
fn: "FormatInt",
|
|
args: []Value{v, Lit(base)},
|
|
}
|
|
}
|
|
|
|
// StringsToLower creates a strings.ToLower(v) expression.
|
|
// In CUE: strings.ToLower(v)
|
|
func StringsToLower(v Value) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "strings",
|
|
fn: "ToLower",
|
|
args: []Value{v},
|
|
}
|
|
}
|
|
|
|
// StringsToUpper creates a strings.ToUpper(v) expression.
|
|
// In CUE: strings.ToUpper(v)
|
|
func StringsToUpper(v Value) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "strings",
|
|
fn: "ToUpper",
|
|
args: []Value{v},
|
|
}
|
|
}
|
|
|
|
// StringsHasPrefix creates a strings.HasPrefix(s, prefix) expression.
|
|
// In CUE: strings.HasPrefix(s, prefix)
|
|
func StringsHasPrefix(s Value, prefix string) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "strings",
|
|
fn: "HasPrefix",
|
|
args: []Value{s, Lit(prefix)},
|
|
}
|
|
}
|
|
|
|
// StringsHasSuffix creates a strings.HasSuffix(s, suffix) expression.
|
|
// In CUE: strings.HasSuffix(s, suffix)
|
|
func StringsHasSuffix(s Value, suffix string) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "strings",
|
|
fn: "HasSuffix",
|
|
args: []Value{s, Lit(suffix)},
|
|
}
|
|
}
|
|
|
|
// ListConcat creates a list.Concat(lists...) expression.
|
|
// In CUE: list.Concat([list1, list2, ...])
|
|
func ListConcat(lists ...Value) *CUEFunc {
|
|
return &CUEFunc{
|
|
pkg: "list",
|
|
fn: "Concat",
|
|
args: lists,
|
|
}
|
|
}
|
|
|
|
// --- Patch Key Annotation Support ---
|
|
|
|
// PatchKeyOp represents a patch operation with a // +patchKey=name annotation.
|
|
// This is used for array merging strategies in Kubernetes strategic merge patch.
|
|
type PatchKeyOp struct {
|
|
path string
|
|
key string // e.g., "name" for containers
|
|
elements []Value
|
|
}
|
|
|
|
func (p *PatchKeyOp) resourceOp() {}
|
|
|
|
// Path returns the path being patched.
|
|
func (p *PatchKeyOp) Path() string { return p.path }
|
|
|
|
// Key returns the patch key for array merging.
|
|
func (p *PatchKeyOp) Key() string { return p.key }
|
|
|
|
// Elements returns the array elements to patch.
|
|
func (p *PatchKeyOp) Elements() []Value { return p.elements }
|
|
|
|
// SpreadAllOp represents a patch operation that constrains all array elements.
|
|
// This generates: path: [...{element}]
|
|
// Used for applying the same patch to every element in an array (e.g., all containers).
|
|
type SpreadAllOp struct {
|
|
path string
|
|
elements []Value
|
|
}
|
|
|
|
func (s *SpreadAllOp) resourceOp() {}
|
|
|
|
// Path returns the path being patched.
|
|
func (s *SpreadAllOp) Path() string { return s.path }
|
|
|
|
// Elements returns the array elements to constrain.
|
|
func (s *SpreadAllOp) Elements() []Value { return s.elements }
|
|
|
|
// --- Context Path Exists Check ---
|
|
|
|
// PathExistsCondition checks if a path exists in CUE (path != _|_).
|
|
type PathExistsCondition struct {
|
|
baseCondition
|
|
path string
|
|
}
|
|
|
|
// Path returns the path being checked.
|
|
func (p *PathExistsCondition) Path() string { return p.path }
|
|
|
|
// PathExists creates a condition that checks if a path exists.
|
|
// In CUE: path != _|_
|
|
func PathExists(path string) *PathExistsCondition {
|
|
return &PathExistsCondition{path: path}
|
|
}
|
|
|
|
// --- Array Element Struct ---
|
|
|
|
// patchKeyField represents a field within an ArrayElement that has a patchKey annotation.
|
|
// This is used for nested patchKey annotations inside array elements,
|
|
// e.g., volumeMounts inside a containers element.
|
|
type patchKeyField struct {
|
|
field string // field name (e.g., "volumeMounts")
|
|
key string // patchKey value (e.g., "name")
|
|
value Value // the array value
|
|
}
|
|
|
|
// ArrayElement represents a single element in an array patch.
|
|
// Used for building array values with struct elements.
|
|
type ArrayElement struct {
|
|
fields map[string]Value
|
|
fieldOrder []string
|
|
ops []ResourceOp // nested operations for complex structs
|
|
patchKeyFields []patchKeyField // nested patchKey-annotated array fields
|
|
}
|
|
|
|
func (a *ArrayElement) expr() {}
|
|
func (a *ArrayElement) value() {}
|
|
|
|
// NewArrayElement creates a new array element builder.
|
|
func NewArrayElement() *ArrayElement {
|
|
return &ArrayElement{
|
|
fields: make(map[string]Value),
|
|
fieldOrder: make([]string, 0),
|
|
ops: make([]ResourceOp, 0),
|
|
}
|
|
}
|
|
|
|
// Set sets a field on the array element.
|
|
func (a *ArrayElement) Set(key string, value Value) *ArrayElement {
|
|
if _, exists := a.fields[key]; !exists {
|
|
a.fieldOrder = append(a.fieldOrder, key)
|
|
}
|
|
a.fields[key] = value
|
|
return a
|
|
}
|
|
|
|
// SetIf conditionally sets a field on the array element.
|
|
func (a *ArrayElement) SetIf(cond Condition, key string, value Value) *ArrayElement {
|
|
a.ops = append(a.ops, &SetIfOp{path: key, value: value, cond: cond})
|
|
return a
|
|
}
|
|
|
|
// PatchKeyField adds a patchKey-annotated array field to the array element.
|
|
// This generates within the element:
|
|
//
|
|
// // +patchKey=key
|
|
// field: value
|
|
//
|
|
// Used for nested patchKey annotations inside array elements, e.g.,
|
|
// volumeMounts with patchKey=name inside a containers element.
|
|
func (a *ArrayElement) PatchKeyField(field string, key string, value Value) *ArrayElement {
|
|
a.patchKeyFields = append(a.patchKeyFields, patchKeyField{field: field, key: key, value: value})
|
|
return a
|
|
}
|
|
|
|
// Fields returns all fields set on this element.
|
|
func (a *ArrayElement) Fields() map[string]Value { return a.fields }
|
|
|
|
// FieldOrder returns field names in insertion order.
|
|
func (a *ArrayElement) FieldOrder() []string { return a.fieldOrder }
|
|
|
|
// Ops returns any conditional operations.
|
|
func (a *ArrayElement) Ops() []ResourceOp { return a.ops }
|
|
|
|
// PatchKeyFields returns the patchKey-annotated fields.
|
|
func (a *ArrayElement) PatchKeyFields() []patchKeyField { return a.patchKeyFields }
|
|
|
|
// --- Reference Expressions ---
|
|
|
|
// Ref creates a raw reference expression.
|
|
// Use this for referencing CUE variables like "v.protocol" or "context.output".
|
|
type Ref struct {
|
|
path string
|
|
}
|
|
|
|
func (r *Ref) expr() {}
|
|
func (r *Ref) value() {}
|
|
|
|
// Path returns the reference path.
|
|
func (r *Ref) Path() string { return r.path }
|
|
|
|
// Reference creates a raw reference to a CUE path.
|
|
// Example: Reference("v.protocol") for use in comprehensions
|
|
func Reference(path string) *Ref {
|
|
return &Ref{path: path}
|
|
}
|
|
|
|
// --- Parameter Reference ---
|
|
|
|
// Parameter creates a reference to a parameter value.
|
|
// This generates "parameter" or "parameter.fieldName" in CUE.
|
|
func Parameter() *Ref {
|
|
return &Ref{path: "parameter"}
|
|
}
|
|
|
|
// ParameterField creates a reference to a field within parameter.
|
|
// Example: ParameterField("replicas") generates "parameter.replicas"
|
|
func ParameterField(field string) *Ref {
|
|
return &Ref{path: "parameter." + field}
|
|
}
|
|
|
|
// ParamRef creates a reference to a parameter field for use in expressions.
|
|
// This is more explicit than ParameterField and is intended for use with
|
|
// list comprehensions and other value expressions.
|
|
// Example: ParamRef("constraints") generates "parameter.constraints"
|
|
func ParamRef(field string) *Ref {
|
|
return ParameterField(field)
|
|
}
|
|
|
|
// --- ForEach Map Iteration ---
|
|
|
|
// ForEachMapOp represents a for comprehension over a map.
|
|
// Generates: for k, v in source { (k): v } or custom expressions
|
|
type ForEachMapOp struct {
|
|
source string // The source to iterate over (e.g., "parameter")
|
|
keyVar string // Variable name for key (e.g., "k")
|
|
valVar string // Variable name for value (e.g., "v")
|
|
keyExpr string // Expression for key output (empty means "(keyVar)")
|
|
valExpr string // Expression for value output (empty means valVar)
|
|
body []ResourceOp // Optional nested operations in the body
|
|
}
|
|
|
|
func (f *ForEachMapOp) resourceOp() {}
|
|
func (f *ForEachMapOp) expr() {}
|
|
func (f *ForEachMapOp) value() {}
|
|
|
|
// Source returns the iteration source.
|
|
func (f *ForEachMapOp) Source() string { return f.source }
|
|
|
|
// KeyVar returns the key variable name.
|
|
func (f *ForEachMapOp) KeyVar() string { return f.keyVar }
|
|
|
|
// ValVar returns the value variable name.
|
|
func (f *ForEachMapOp) ValVar() string { return f.valVar }
|
|
|
|
// KeyExpr returns the key expression.
|
|
func (f *ForEachMapOp) KeyExpr() string { return f.keyExpr }
|
|
|
|
// ValExpr returns the value expression.
|
|
func (f *ForEachMapOp) ValExpr() string { return f.valExpr }
|
|
|
|
// Body returns nested operations.
|
|
func (f *ForEachMapOp) Body() []ResourceOp { return f.body }
|
|
|
|
// ForEachMap creates a for comprehension over the parameter map.
|
|
// This generates: for k, v in parameter { (k): v }
|
|
func ForEachMap() *ForEachMapOp {
|
|
return &ForEachMapOp{
|
|
source: "parameter",
|
|
keyVar: "k",
|
|
valVar: "v",
|
|
}
|
|
}
|
|
|
|
// --- CUE String Interpolation ---
|
|
|
|
// InterpolatedString represents a CUE string interpolation expression.
|
|
// Literal string parts are inlined, Value parts are wrapped in \(...).
|
|
//
|
|
// Example:
|
|
//
|
|
// Interpolation(vela.Namespace(), Lit(":"), name)
|
|
// // Generates: "\(context.namespace):\(parameter.name)"
|
|
type InterpolatedString struct {
|
|
parts []Value
|
|
}
|
|
|
|
func (i *InterpolatedString) value() {}
|
|
func (i *InterpolatedString) expr() {}
|
|
|
|
// Parts returns the interpolation parts.
|
|
func (i *InterpolatedString) Parts() []Value { return i.parts }
|
|
|
|
// Interpolation creates a CUE string interpolation expression.
|
|
// Literal string values are inlined directly. All other values are
|
|
// wrapped in \(...) interpolation syntax.
|
|
func Interpolation(parts ...Value) *InterpolatedString {
|
|
return &InterpolatedString{parts: parts}
|
|
}
|
|
|
|
// --- LenValueCondition ---
|
|
|
|
// LenValueCondition checks the length of an arbitrary Value (not just a parameter).
|
|
// This extends LenCondition to work with let variables and other expressions.
|
|
// Generates: len(source) op n
|
|
type LenValueCondition struct {
|
|
baseCondition
|
|
source Value
|
|
op string // ==, !=, <, <=, >, >=
|
|
length int
|
|
}
|
|
|
|
// Source returns the source value being measured.
|
|
func (c *LenValueCondition) Source() Value { return c.source }
|
|
|
|
// Op returns the comparison operator.
|
|
func (c *LenValueCondition) Op() string { return c.op }
|
|
|
|
// Length returns the length to compare against.
|
|
func (c *LenValueCondition) Length() int { return c.length }
|
|
|
|
// LenGt creates a condition: len(source) > n.
|
|
func LenGt(source Value, n int) *LenValueCondition {
|
|
return &LenValueCondition{source: source, op: ">", length: n}
|
|
}
|
|
|
|
// LenGe creates a condition: len(source) >= n.
|
|
func LenGe(source Value, n int) *LenValueCondition {
|
|
return &LenValueCondition{source: source, op: ">=", length: n}
|
|
}
|
|
|
|
// LenEq creates a condition: len(source) == n.
|
|
func LenEq(source Value, n int) *LenValueCondition {
|
|
return &LenValueCondition{source: source, op: "==", length: n}
|
|
}
|
|
|
|
// Over specifies the source to iterate over.
|
|
func (f *ForEachMapOp) Over(source string) *ForEachMapOp {
|
|
f.source = source
|
|
return f
|
|
}
|
|
|
|
// WithVars specifies the key and value variable names.
|
|
func (f *ForEachMapOp) WithVars(keyVar, valVar string) *ForEachMapOp {
|
|
f.keyVar = keyVar
|
|
f.valVar = valVar
|
|
return f
|
|
}
|
|
|
|
// WithKeyExpr specifies a custom key expression.
|
|
func (f *ForEachMapOp) WithKeyExpr(expr string) *ForEachMapOp {
|
|
f.keyExpr = expr
|
|
return f
|
|
}
|
|
|
|
// WithValExpr specifies a custom value expression.
|
|
func (f *ForEachMapOp) WithValExpr(expr string) *ForEachMapOp {
|
|
f.valExpr = expr
|
|
return f
|
|
}
|
|
|
|
// WithBody adds nested operations to the for body.
|
|
func (f *ForEachMapOp) WithBody(ops ...ResourceOp) *ForEachMapOp {
|
|
f.body = append(f.body, ops...)
|
|
return f
|
|
}
|
|
|
|
// PlusExpr represents a + operator between multiple values.
|
|
// Generates CUE: a + b + c
|
|
// Works for string concatenation, array concatenation, etc.
|
|
type PlusExpr struct {
|
|
parts []Value
|
|
}
|
|
|
|
func (p *PlusExpr) value() {}
|
|
func (p *PlusExpr) expr() {}
|
|
|
|
// Parts returns the operands.
|
|
func (p *PlusExpr) Parts() []Value { return p.parts }
|
|
|
|
// Plus creates a + expression between values.
|
|
// Generates CUE: parts[0] + parts[1] + ...
|
|
func Plus(parts ...Value) *PlusExpr {
|
|
return &PlusExpr{parts: parts}
|
|
}
|
|
|
|
// IterFieldRef references a field on the iteration variable.
|
|
// Generates CUE: v.fieldName (where v is the iteration variable).
|
|
type IterFieldRef struct {
|
|
varName string
|
|
field string
|
|
}
|
|
|
|
func (r *IterFieldRef) value() {}
|
|
func (r *IterFieldRef) expr() {}
|
|
|
|
// VarName returns the iteration variable name.
|
|
func (r *IterFieldRef) VarName() string { return r.varName }
|
|
|
|
// FieldName returns the field name.
|
|
func (r *IterFieldRef) FieldName() string { return r.field }
|
|
|
|
// IterVarRef references the iteration variable itself (not a field on it).
|
|
// Generates CUE: v (where v is the iteration variable).
|
|
type IterVarRef struct {
|
|
varName string
|
|
}
|
|
|
|
func (r *IterVarRef) value() {}
|
|
func (r *IterVarRef) expr() {}
|
|
|
|
// VarName returns the iteration variable name.
|
|
func (r *IterVarRef) VarName() string { return r.varName }
|
|
|
|
// IterLetRef references a let binding defined inside an iteration body.
|
|
// Generates CUE: _name (a private CUE identifier).
|
|
type IterLetRef struct {
|
|
name string
|
|
}
|
|
|
|
func (r *IterLetRef) value() {}
|
|
func (r *IterLetRef) expr() {}
|
|
|
|
// RefName returns the binding name.
|
|
func (r *IterLetRef) RefName() string { return r.name }
|
|
|
|
// IterFieldExistsCondition checks if an iteration variable field exists.
|
|
// Generates CUE: v.field != _|_ (or v.field == _|_ when negated).
|
|
type IterFieldExistsCondition struct {
|
|
baseCondition
|
|
varName string
|
|
field string
|
|
negate bool
|
|
}
|
|
|
|
// VarName returns the iteration variable name.
|
|
func (c *IterFieldExistsCondition) VarName() string { return c.varName }
|
|
|
|
// FieldName returns the field name.
|
|
func (c *IterFieldExistsCondition) FieldName() string { return c.field }
|
|
|
|
// IsNegated returns true if this is a "not exists" check.
|
|
func (c *IterFieldExistsCondition) IsNegated() bool { return c.negate }
|
|
|
|
// InlineArrayValue represents an inline array literal containing struct elements.
|
|
// This generates CUE like: [{field1: value1, field2: value2}]
|
|
// Used for deprecated parameter fallbacks that create a single-element array.
|
|
type InlineArrayValue struct {
|
|
fields map[string]Value
|
|
}
|
|
|
|
func (a *InlineArrayValue) expr() {}
|
|
func (a *InlineArrayValue) value() {}
|
|
|
|
// Fields returns the field mappings.
|
|
func (a *InlineArrayValue) Fields() map[string]Value { return a.fields }
|
|
|
|
// InlineArray creates an inline array value with a single struct element.
|
|
// Example: InlineArray(map[string]Value{"containerPort": port})
|
|
// Generates: [{containerPort: parameter.port}]
|
|
func InlineArray(fields map[string]Value) *InlineArrayValue {
|
|
return &InlineArrayValue{fields: fields}
|
|
}
|