mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-20 08:13:23 +00:00
* feat(defkit): introduce Mandatory() API and three-state CUE field markers Add a new .Mandatory() fluent method to all defkit param types and StructField, giving callers explicit control over all three CUE field presence semantics: field?: type — optional, emitted by default (no method call) field: type — non-optional; must have a value, defaults/merging can satisfy (.Mandatory()) field!: type — required in input; user must explicitly provide it (.Required()) Previously, Required() emitted no marker (identical to a mandatory field), making it impossible to generate the CUE ! marker at all. Now Required() emits ! and Mandatory() emits no marker, matching their intuitive meanings. - Add `mandatory bool` field to baseParam and StructField - Add IsMandatory() accessor to baseParam, StructField, and Param interface - Add .Mandatory() builder method to all 10 concrete param types and StructField - Replace the `optional string` variable in cuegen.go with a typed `marker` variable backed by named constants (fieldMarkerOptional, fieldMarkerNone, fieldMarkerRequired) - Update IsOptional() to return !required && !mandatory - Update Optional() to clear mandatory instead of required - Update all tests to use .Mandatory() for non-optional fields Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> * fix(defkit): correct doc comments after Required/Mandatory semantic swap Fix misleading comments that still described the pre-swap behaviour. Mandatory() comments incorrectly referenced the "!" marker, and Required()/IsRequired() accessors had stale descriptions. Aligned all doc comments and field annotations with the actual semantics: Required → "!" marker, Mandatory → non-optional (no ? marker). Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> * feat(defkit): add BeMandatory matcher and fix BeOptional for three-state semantics BeOptional incorrectly returned true for mandatory params by checking !IsRequired(). Now uses IsOptional() which correctly excludes both required and mandatory params. Adds BeMandatory() matcher and updates paramAccessor interface with IsOptional/IsMandatory methods. Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> * fix(defkit): clear required flag in Optional() for all param types The previous commit only fixed StringParam.Optional(). Apply the same fix to Int, Bool, Float, Array, Map, Struct, StructField, Enum, OneOf, and StringKeyMap so that Optional() consistently resets both mandatory and required flags across all parameter types. Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> * fix(defkit): make Required() and Mandatory() mutually exclusive and fix missing optional markers in CUE generation Required() and Mandatory() only set their own flag without clearing the other, allowing both to be true simultaneously via chaining. Each method now clears the opposite flag so the last call wins, matching the reset semantics that Optional() already followed. Also fix CUE generation for int, bool, float, and enum params where the optional marker was dropped from format strings when a default value was present, causing those fields to always render without the field marker regardless of their optional/mandatory/required state. Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> * Empty commit to re-trigger e2e Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com> --------- Signed-off-by: Jerrin Francis <jerrinfrancis7@gmail.com>
1691 lines
52 KiB
Go
1691 lines
52 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
|
|
|
|
// baseParam provides common parameter functionality.
|
|
type baseParam struct {
|
|
name string
|
|
paramType ParamType
|
|
required bool // when true, emits "!" marker — user must explicitly provide this field in input
|
|
mandatory bool // when true, field is non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it
|
|
defaultValue any
|
|
description string
|
|
forceOptional bool // when true, field stays optional even with a default value
|
|
short string // short flag alias (e.g. "i" → // +short=i)
|
|
ignore bool // when true, emits // +ignore directive
|
|
}
|
|
|
|
func (p *baseParam) expr() {}
|
|
func (p *baseParam) value() {}
|
|
func (p *baseParam) condition() {}
|
|
|
|
func (p *baseParam) Name() string { return p.name }
|
|
func (p *baseParam) IsRequired() bool { return p.required }
|
|
func (p *baseParam) IsOptional() bool { return !p.required && !p.mandatory }
|
|
func (p *baseParam) IsMandatory() bool { return p.mandatory }
|
|
func (p *baseParam) HasDefault() bool { return p.defaultValue != nil }
|
|
func (p *baseParam) GetDefault() any { return p.defaultValue }
|
|
func (p *baseParam) GetDescription() string { return p.description }
|
|
func (p *baseParam) IsForceOptional() bool { return p.forceOptional }
|
|
func (p *baseParam) GetShort() string { return p.short }
|
|
func (p *baseParam) IsIgnore() bool { return p.ignore }
|
|
|
|
// IsSet returns a condition that checks if the parameter has a value.
|
|
// This is used with SetIf for conditional field assignment.
|
|
func (p *baseParam) IsSet() Condition {
|
|
return &IsSetCondition{paramName: p.name}
|
|
}
|
|
|
|
// NotSet returns a condition that checks if the parameter is not set.
|
|
// This generates `if parameter["name"] == _|_` in CUE.
|
|
func (p *baseParam) NotSet() Condition {
|
|
return &NotCondition{inner: &IsSetCondition{paramName: p.name}}
|
|
}
|
|
|
|
// Eq creates a condition that compares this parameter to a literal value.
|
|
// Example: replicas.Eq(3) generates: parameter.replicas == 3
|
|
func (p *baseParam) Eq(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: "==", value: val}
|
|
}
|
|
|
|
// Ne creates a condition that checks if this parameter is not equal to a value.
|
|
// Example: status.Ne("error") generates: parameter.status != "error"
|
|
func (p *baseParam) Ne(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: "!=", value: val}
|
|
}
|
|
|
|
// Gt creates a condition that checks if this parameter is greater than a value.
|
|
// Example: replicas.Gt(1) generates: parameter.replicas > 1
|
|
func (p *baseParam) Gt(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: ">", value: val}
|
|
}
|
|
|
|
// Gte creates a condition that checks if this parameter is greater than or equal to a value.
|
|
// Example: replicas.Gte(1) generates: parameter.replicas >= 1
|
|
func (p *baseParam) Gte(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: ">=", value: val}
|
|
}
|
|
|
|
// Lt creates a condition that checks if this parameter is less than a value.
|
|
// Example: replicas.Lt(10) generates: parameter.replicas < 10
|
|
func (p *baseParam) Lt(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: "<", value: val}
|
|
}
|
|
|
|
// Lte creates a condition that checks if this parameter is less than or equal to a value.
|
|
// Example: replicas.Lte(10) generates: parameter.replicas <= 10
|
|
func (p *baseParam) Lte(val any) Condition {
|
|
return &ParamCompareCondition{paramName: p.name, op: "<=", value: val}
|
|
}
|
|
|
|
// ParamCompareCondition represents a comparison between a parameter and a value.
|
|
type ParamCompareCondition struct {
|
|
baseCondition
|
|
paramName string
|
|
op string
|
|
value any
|
|
}
|
|
|
|
// ParamName returns the parameter name being compared.
|
|
func (c *ParamCompareCondition) ParamName() string { return c.paramName }
|
|
|
|
// Op returns the comparison operator.
|
|
func (c *ParamCompareCondition) Op() string { return c.op }
|
|
|
|
// CompareValue returns the comparison value.
|
|
func (c *ParamCompareCondition) CompareValue() any { return c.value }
|
|
|
|
// StringParam represents a string parameter.
|
|
type StringParam struct {
|
|
baseParam
|
|
enumValues []string // allowed enum values
|
|
openEnum bool // when true, appends | string to enum disjunction (open enum)
|
|
pattern string // regex pattern constraint
|
|
minLen *int // minimum length constraint
|
|
maxLen *int // maximum length constraint
|
|
}
|
|
|
|
// String creates a new string parameter with the given name.
|
|
func String(name string) *StringParam {
|
|
return &StringParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeString,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
// The user must explicitly provide this field — even if a default value exists.
|
|
func (p *StringParam) Required() *StringParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker).
|
|
// The field must have a value, but defaults or CUE merging can satisfy it
|
|
// without the user explicitly providing it.
|
|
func (p *StringParam) Mandatory() *StringParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *StringParam) Optional() *StringParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// ForceOptional makes the field optional even when it has a default value.
|
|
// Normally, fields with defaults are treated as always-present (no ? in CUE).
|
|
// This generates field?: *default | type instead of field: *default | type.
|
|
func (p *StringParam) ForceOptional() *StringParam {
|
|
p.forceOptional = true
|
|
return p
|
|
}
|
|
|
|
// Short sets a short flag alias for the parameter.
|
|
// This generates a // +short=X directive in the CUE output.
|
|
func (p *StringParam) Short(s string) *StringParam {
|
|
p.short = s
|
|
return p
|
|
}
|
|
|
|
// Ignore marks the parameter as ignored by the UI.
|
|
// This generates a // +ignore directive in the CUE output.
|
|
func (p *StringParam) Ignore() *StringParam {
|
|
p.ignore = true
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *StringParam) Default(value string) *StringParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *StringParam) Description(desc string) *StringParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// Values restricts the parameter to specific allowed values.
|
|
func (p *StringParam) Values(values ...string) *StringParam {
|
|
p.enumValues = values
|
|
return p
|
|
}
|
|
|
|
// GetEnumValues returns the allowed enum values.
|
|
func (p *StringParam) GetEnumValues() []string {
|
|
return p.enumValues
|
|
}
|
|
|
|
// OpenEnum marks the enum as open, allowing any string in addition to the
|
|
// enumerated values. This generates CUE like: "value1" | "value2" | string
|
|
func (p *StringParam) OpenEnum() *StringParam {
|
|
p.openEnum = true
|
|
return p
|
|
}
|
|
|
|
// IsOpenEnum returns whether the enum allows arbitrary strings beyond the listed values.
|
|
func (p *StringParam) IsOpenEnum() bool {
|
|
return p.openEnum
|
|
}
|
|
|
|
// Pattern sets a regex pattern constraint for the parameter.
|
|
// This generates CUE like: string & =~"pattern"
|
|
func (p *StringParam) Pattern(regex string) *StringParam {
|
|
p.pattern = regex
|
|
return p
|
|
}
|
|
|
|
// GetPattern returns the regex pattern constraint.
|
|
func (p *StringParam) GetPattern() string {
|
|
return p.pattern
|
|
}
|
|
|
|
// MinLen sets the minimum length constraint for the parameter.
|
|
// This generates CUE like: strings.MinRunes(n)
|
|
func (p *StringParam) MinLen(n int) *StringParam {
|
|
p.minLen = &n
|
|
return p
|
|
}
|
|
|
|
// GetMinLen returns the minimum length constraint, or nil if not set.
|
|
func (p *StringParam) GetMinLen() *int {
|
|
return p.minLen
|
|
}
|
|
|
|
// MaxLen sets the maximum length constraint for the parameter.
|
|
// This generates CUE like: strings.MaxRunes(n)
|
|
func (p *StringParam) MaxLen(n int) *StringParam {
|
|
p.maxLen = &n
|
|
return p
|
|
}
|
|
|
|
// GetMaxLen returns the maximum length constraint, or nil if not set.
|
|
func (p *StringParam) GetMaxLen() *int {
|
|
return p.maxLen
|
|
}
|
|
|
|
// Concat creates a string concatenation expression.
|
|
// Example: name.Concat("-suffix") generates: parameter.name + "-suffix"
|
|
func (p *StringParam) Concat(suffix string) Value {
|
|
return &ParamConcatExpr{paramName: p.name, suffix: suffix}
|
|
}
|
|
|
|
// Prepend creates a string concatenation expression with a prefix.
|
|
// Example: name.Prepend("prefix-") generates: "prefix-" + parameter.name
|
|
func (p *StringParam) Prepend(prefix string) Value {
|
|
return &ParamConcatExpr{paramName: p.name, prefix: prefix}
|
|
}
|
|
|
|
// --- StringParam Runtime Condition Methods ---
|
|
|
|
// Contains creates a condition that checks if this string parameter contains a substring.
|
|
// Example: name.Contains("prod") generates: strings.Contains(parameter.name, "prod")
|
|
func (p *StringParam) Contains(substr string) Condition {
|
|
return &StringContainsCondition{paramName: p.name, substr: substr}
|
|
}
|
|
|
|
// Matches creates a condition that checks if this string parameter matches a regex pattern.
|
|
// Example: name.Matches("^prod-") generates: parameter.name =~ "^prod-"
|
|
func (p *StringParam) Matches(pattern string) Condition {
|
|
return &StringMatchesCondition{paramName: p.name, pattern: pattern}
|
|
}
|
|
|
|
// StartsWith creates a condition that checks if this string parameter starts with a prefix.
|
|
// Example: name.StartsWith("prod-") generates: strings.HasPrefix(parameter.name, "prod-")
|
|
func (p *StringParam) StartsWith(prefix string) Condition {
|
|
return &StringStartsWithCondition{paramName: p.name, prefix: prefix}
|
|
}
|
|
|
|
// EndsWith creates a condition that checks if this string parameter ends with a suffix.
|
|
// Example: name.EndsWith("-prod") generates: strings.HasSuffix(parameter.name, "-prod")
|
|
func (p *StringParam) EndsWith(suffix string) Condition {
|
|
return &StringEndsWithCondition{paramName: p.name, suffix: suffix}
|
|
}
|
|
|
|
// LenEq creates a condition that checks if this string parameter has exactly n characters.
|
|
// Example: name.LenEq(5) generates: len(parameter.name) == 5
|
|
func (p *StringParam) LenEq(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "==", length: n}
|
|
}
|
|
|
|
// LenGt creates a condition that checks if this string parameter has more than n characters.
|
|
// Example: name.LenGt(5) generates: len(parameter.name) > 5
|
|
func (p *StringParam) LenGt(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: ">", length: n}
|
|
}
|
|
|
|
// LenGte creates a condition that checks if this string parameter has n or more characters.
|
|
// Example: name.LenGte(5) generates: len(parameter.name) >= 5
|
|
func (p *StringParam) LenGte(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: ">=", length: n}
|
|
}
|
|
|
|
// LenLt creates a condition that checks if this string parameter has fewer than n characters.
|
|
// Example: name.LenLt(5) generates: len(parameter.name) < 5
|
|
func (p *StringParam) LenLt(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "<", length: n}
|
|
}
|
|
|
|
// LenLte creates a condition that checks if this string parameter has n or fewer characters.
|
|
// Example: name.LenLte(5) generates: len(parameter.name) <= 5
|
|
func (p *StringParam) LenLte(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "<=", length: n}
|
|
}
|
|
|
|
// In creates a condition that checks if this string parameter is one of the given values.
|
|
// Example: name.In("api", "web", "worker") generates: parameter.name == "api" || parameter.name == "web" || parameter.name == "worker"
|
|
func (p *StringParam) In(values ...string) Condition {
|
|
anyVals := make([]any, len(values))
|
|
for i, v := range values {
|
|
anyVals[i] = v
|
|
}
|
|
return &InCondition{paramName: p.name, values: anyVals}
|
|
}
|
|
|
|
// IntParam represents an integer parameter.
|
|
type IntParam struct {
|
|
baseParam
|
|
minVal *int // minimum value constraint
|
|
maxVal *int // maximum value constraint
|
|
}
|
|
|
|
// Int creates a new integer parameter with the given name.
|
|
func Int(name string) *IntParam {
|
|
return &IntParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeInt,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *IntParam) Required() *IntParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *IntParam) Mandatory() *IntParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *IntParam) Optional() *IntParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
func (p *IntParam) ForceOptional() *IntParam {
|
|
p.forceOptional = true
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *IntParam) Default(value int) *IntParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *IntParam) Description(desc string) *IntParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// Short sets a short flag alias for the parameter.
|
|
// This generates a // +short=X directive in the CUE output.
|
|
func (p *IntParam) Short(s string) *IntParam {
|
|
p.short = s
|
|
return p
|
|
}
|
|
|
|
// Ignore marks the parameter as ignored by the UI.
|
|
// This generates a // +ignore directive in the CUE output.
|
|
func (p *IntParam) Ignore() *IntParam {
|
|
p.ignore = true
|
|
return p
|
|
}
|
|
|
|
// Min sets the minimum value constraint for the parameter.
|
|
// This generates CUE like: int & >=n
|
|
func (p *IntParam) Min(n int) *IntParam {
|
|
p.minVal = &n
|
|
return p
|
|
}
|
|
|
|
// GetMin returns the minimum value constraint, or nil if not set.
|
|
func (p *IntParam) GetMin() *int {
|
|
return p.minVal
|
|
}
|
|
|
|
// Max sets the maximum value constraint for the parameter.
|
|
// This generates CUE like: int & <=n
|
|
func (p *IntParam) Max(n int) *IntParam {
|
|
p.maxVal = &n
|
|
return p
|
|
}
|
|
|
|
// GetMax returns the maximum value constraint, or nil if not set.
|
|
func (p *IntParam) GetMax() *int {
|
|
return p.maxVal
|
|
}
|
|
|
|
// In creates a condition that checks if this int parameter is one of the given values.
|
|
// Example: port.In(80, 443, 8080) generates: parameter.port == 80 || parameter.port == 443 || parameter.port == 8080
|
|
func (p *IntParam) In(values ...int) Condition {
|
|
anyVals := make([]any, len(values))
|
|
for i, v := range values {
|
|
anyVals[i] = v
|
|
}
|
|
return &InCondition{paramName: p.name, values: anyVals}
|
|
}
|
|
|
|
// Add creates an arithmetic expression that adds a value to this parameter.
|
|
// Example: replicas.Add(1) generates: parameter.replicas + 1
|
|
func (p *IntParam) Add(val int) Value {
|
|
return &ParamArithExpr{paramName: p.name, op: "+", arithVal: val}
|
|
}
|
|
|
|
// Sub creates an arithmetic expression that subtracts a value from this parameter.
|
|
// Example: replicas.Sub(1) generates: parameter.replicas - 1
|
|
func (p *IntParam) Sub(val int) Value {
|
|
return &ParamArithExpr{paramName: p.name, op: "-", arithVal: val}
|
|
}
|
|
|
|
// Mul creates an arithmetic expression that multiplies this parameter by a value.
|
|
// Example: replicas.Mul(2) generates: parameter.replicas * 2
|
|
func (p *IntParam) Mul(val int) Value {
|
|
return &ParamArithExpr{paramName: p.name, op: "*", arithVal: val}
|
|
}
|
|
|
|
// Div creates an arithmetic expression that divides this parameter by a value.
|
|
// Example: replicas.Div(2) generates: parameter.replicas / 2
|
|
func (p *IntParam) Div(val int) Value {
|
|
return &ParamArithExpr{paramName: p.name, op: "/", arithVal: val}
|
|
}
|
|
|
|
// BoolParam represents a boolean parameter.
|
|
type BoolParam struct {
|
|
baseParam
|
|
}
|
|
|
|
// Bool creates a new boolean parameter with the given name.
|
|
func Bool(name string) *BoolParam {
|
|
return &BoolParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeBool,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *BoolParam) Required() *BoolParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *BoolParam) Mandatory() *BoolParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *BoolParam) Optional() *BoolParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// ForceOptional makes the field optional even when it has a default value.
|
|
// Normally, fields with defaults are treated as always-present (no ? in CUE).
|
|
// This generates field?: *default | type instead of field: *default | type.
|
|
func (p *BoolParam) ForceOptional() *BoolParam {
|
|
p.forceOptional = true
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *BoolParam) Default(value bool) *BoolParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *BoolParam) Description(desc string) *BoolParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// Short sets a short flag alias for the parameter.
|
|
// This generates a // +short=X directive in the CUE output.
|
|
func (p *BoolParam) Short(s string) *BoolParam {
|
|
p.short = s
|
|
return p
|
|
}
|
|
|
|
// Ignore marks the parameter as ignored by the UI.
|
|
// This generates a // +ignore directive in the CUE output.
|
|
func (p *BoolParam) Ignore() *BoolParam {
|
|
p.ignore = true
|
|
return p
|
|
}
|
|
|
|
// IsTrue returns a condition that checks if the bool parameter is truthy.
|
|
// In CUE, this generates `if parameter.name` instead of `if parameter.name == true`.
|
|
func (p *BoolParam) IsTrue() Condition {
|
|
return &TruthyCondition{paramName: p.name}
|
|
}
|
|
|
|
// IsFalse returns a condition that checks if the bool parameter is falsy.
|
|
// In CUE, this generates `if !parameter.name` instead of `if parameter.name == false`.
|
|
func (p *BoolParam) IsFalse() Condition {
|
|
return &FalsyCondition{paramName: p.name}
|
|
}
|
|
|
|
// FloatParam represents a floating-point number parameter.
|
|
type FloatParam struct {
|
|
baseParam
|
|
minVal *float64 // minimum value constraint
|
|
maxVal *float64 // maximum value constraint
|
|
}
|
|
|
|
// Float creates a new float parameter with the given name.
|
|
func Float(name string) *FloatParam {
|
|
return &FloatParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeFloat,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *FloatParam) Required() *FloatParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *FloatParam) Mandatory() *FloatParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *FloatParam) Optional() *FloatParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
func (p *FloatParam) ForceOptional() *FloatParam {
|
|
p.forceOptional = true
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *FloatParam) Default(value float64) *FloatParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *FloatParam) Description(desc string) *FloatParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// Short sets a short flag alias for the parameter.
|
|
// This generates a // +short=X directive in the CUE output.
|
|
func (p *FloatParam) Short(s string) *FloatParam {
|
|
p.short = s
|
|
return p
|
|
}
|
|
|
|
// Ignore marks the parameter as ignored by the UI.
|
|
// This generates a // +ignore directive in the CUE output.
|
|
func (p *FloatParam) Ignore() *FloatParam {
|
|
p.ignore = true
|
|
return p
|
|
}
|
|
|
|
// Min sets the minimum value constraint for the parameter.
|
|
// This generates CUE like: number & >=n
|
|
func (p *FloatParam) Min(n float64) *FloatParam {
|
|
p.minVal = &n
|
|
return p
|
|
}
|
|
|
|
// GetMin returns the minimum value constraint, or nil if not set.
|
|
func (p *FloatParam) GetMin() *float64 {
|
|
return p.minVal
|
|
}
|
|
|
|
// Max sets the maximum value constraint for the parameter.
|
|
// This generates CUE like: number & <=n
|
|
func (p *FloatParam) Max(n float64) *FloatParam {
|
|
p.maxVal = &n
|
|
return p
|
|
}
|
|
|
|
// GetMax returns the maximum value constraint, or nil if not set.
|
|
func (p *FloatParam) GetMax() *float64 {
|
|
return p.maxVal
|
|
}
|
|
|
|
// In creates a condition that checks if this float parameter is one of the given values.
|
|
// Example: ratio.In(0.5, 1.0, 2.0) generates: parameter.ratio == 0.5 || parameter.ratio == 1.0 || parameter.ratio == 2.0
|
|
func (p *FloatParam) In(values ...float64) Condition {
|
|
anyVals := make([]any, len(values))
|
|
for i, v := range values {
|
|
anyVals[i] = v
|
|
}
|
|
return &InCondition{paramName: p.name, values: anyVals}
|
|
}
|
|
|
|
// ArrayParam represents an array/list parameter.
|
|
type ArrayParam struct {
|
|
baseParam
|
|
elementType ParamType
|
|
fields []Param // fields for structured array elements
|
|
schema string // raw CUE schema for the array elements
|
|
schemaRef string // reference to a helper definition (e.g., "HealthProbe")
|
|
minItems *int // minimum number of items
|
|
maxItems *int // maximum number of items
|
|
}
|
|
|
|
// Array creates a new array parameter with the given name.
|
|
func Array(name string) *ArrayParam {
|
|
return &ArrayParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeArray,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Of specifies the element type for the array.
|
|
func (p *ArrayParam) Of(elemType ParamType) *ArrayParam {
|
|
p.elementType = elemType
|
|
return p
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *ArrayParam) Required() *ArrayParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *ArrayParam) Mandatory() *ArrayParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *ArrayParam) Optional() *ArrayParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *ArrayParam) Default(value []any) *ArrayParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *ArrayParam) Description(desc string) *ArrayParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// ElementType returns the array element type.
|
|
func (p *ArrayParam) ElementType() ParamType {
|
|
return p.elementType
|
|
}
|
|
|
|
// WithFields adds field definitions for structured array elements.
|
|
// This allows defining the schema for objects within the array.
|
|
func (p *ArrayParam) WithFields(fields ...Param) *ArrayParam {
|
|
p.fields = append(p.fields, fields...)
|
|
return p
|
|
}
|
|
|
|
// GetFields returns the field definitions for array elements.
|
|
func (p *ArrayParam) GetFields() []Param {
|
|
return p.fields
|
|
}
|
|
|
|
// WithSchema sets a raw CUE schema for the array elements.
|
|
// This takes precedence over WithFields for schema generation.
|
|
func (p *ArrayParam) WithSchema(schema string) *ArrayParam {
|
|
p.schema = schema
|
|
return p
|
|
}
|
|
|
|
// GetSchema returns the raw CUE schema for array elements.
|
|
func (p *ArrayParam) GetSchema() string {
|
|
return p.schema
|
|
}
|
|
|
|
// WithSchemaRef sets a reference to a helper type definition (e.g., "#HealthProbe").
|
|
// This is used when the schema is defined elsewhere as a helper definition.
|
|
func (p *ArrayParam) WithSchemaRef(ref string) *ArrayParam {
|
|
p.schemaRef = ref
|
|
return p
|
|
}
|
|
|
|
// GetSchemaRef returns the schema reference for this parameter.
|
|
func (p *ArrayParam) GetSchemaRef() string {
|
|
return p.schemaRef
|
|
}
|
|
|
|
// MinItems sets the minimum number of items constraint for the array.
|
|
// This generates CUE like: list.MinItems(n)
|
|
func (p *ArrayParam) MinItems(n int) *ArrayParam {
|
|
p.minItems = &n
|
|
return p
|
|
}
|
|
|
|
// GetMinItems returns the minimum items constraint, or nil if not set.
|
|
func (p *ArrayParam) GetMinItems() *int {
|
|
return p.minItems
|
|
}
|
|
|
|
// MaxItems sets the maximum number of items constraint for the array.
|
|
// This generates CUE like: list.MaxItems(n)
|
|
func (p *ArrayParam) MaxItems(n int) *ArrayParam {
|
|
p.maxItems = &n
|
|
return p
|
|
}
|
|
|
|
// GetMaxItems returns the maximum items constraint, or nil if not set.
|
|
func (p *ArrayParam) GetMaxItems() *int {
|
|
return p.maxItems
|
|
}
|
|
|
|
// --- ArrayParam Runtime Condition Methods ---
|
|
|
|
// LenEq creates a condition that checks if this array has exactly n elements.
|
|
// Example: tags.LenEq(5) generates: len(parameter.tags) == 5
|
|
func (p *ArrayParam) LenEq(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "==", length: n}
|
|
}
|
|
|
|
// LenGt creates a condition that checks if this array has more than n elements.
|
|
// Example: tags.LenGt(0) generates: len(parameter.tags) > 0
|
|
func (p *ArrayParam) LenGt(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: ">", length: n}
|
|
}
|
|
|
|
// LenGte creates a condition that checks if this array has n or more elements.
|
|
// Example: tags.LenGte(1) generates: len(parameter.tags) >= 1
|
|
func (p *ArrayParam) LenGte(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: ">=", length: n}
|
|
}
|
|
|
|
// LenLt creates a condition that checks if this array has fewer than n elements.
|
|
// Example: tags.LenLt(10) generates: len(parameter.tags) < 10
|
|
func (p *ArrayParam) LenLt(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "<", length: n}
|
|
}
|
|
|
|
// LenLte creates a condition that checks if this array has n or fewer elements.
|
|
// Example: tags.LenLte(10) generates: len(parameter.tags) <= 10
|
|
func (p *ArrayParam) LenLte(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "<=", length: n}
|
|
}
|
|
|
|
// Contains creates a condition that checks if this array contains a specific value.
|
|
// Example: tags.Contains("gpu") generates: list.Contains(parameter.tags, "gpu")
|
|
func (p *ArrayParam) Contains(val any) Condition {
|
|
return &ArrayContainsCondition{paramName: p.name, value: val}
|
|
}
|
|
|
|
// IsEmpty creates a condition that checks if this array is empty.
|
|
// Example: tags.IsEmpty() generates: len(parameter.tags) == 0
|
|
func (p *ArrayParam) IsEmpty() Condition {
|
|
return &LenCondition{paramName: p.name, op: "==", length: 0}
|
|
}
|
|
|
|
// IsNotEmpty creates a condition that checks if this array is not empty.
|
|
// Example: tags.IsNotEmpty() generates: len(parameter.tags) > 0
|
|
func (p *ArrayParam) IsNotEmpty() Condition {
|
|
return &LenCondition{paramName: p.name, op: ">", length: 0}
|
|
}
|
|
|
|
// MapParam represents a map/dictionary parameter.
|
|
type MapParam struct {
|
|
baseParam
|
|
keyType ParamType
|
|
valueType ParamType
|
|
fields []Param // fields for structured map values
|
|
schema string // raw CUE schema for the map structure
|
|
schemaRef string // reference to a helper definition (e.g., "HealthProbe")
|
|
}
|
|
|
|
// Map creates a new map parameter with the given name.
|
|
func Map(name string) *MapParam {
|
|
return &MapParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeMap,
|
|
},
|
|
keyType: ParamTypeString, // default key type
|
|
}
|
|
}
|
|
|
|
// Of specifies the value type for the map.
|
|
func (p *MapParam) Of(valueType ParamType) *MapParam {
|
|
p.valueType = valueType
|
|
return p
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *MapParam) Required() *MapParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *MapParam) Mandatory() *MapParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *MapParam) Optional() *MapParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *MapParam) Default(value map[string]any) *MapParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *MapParam) Description(desc string) *MapParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// ValueType returns the map value type.
|
|
func (p *MapParam) ValueType() ParamType {
|
|
return p.valueType
|
|
}
|
|
|
|
// WithFields adds field definitions for structured map values.
|
|
// This allows defining the schema for objects within the map.
|
|
func (p *MapParam) WithFields(fields ...Param) *MapParam {
|
|
p.fields = append(p.fields, fields...)
|
|
return p
|
|
}
|
|
|
|
// GetFields returns the field definitions for map values.
|
|
func (p *MapParam) GetFields() []Param {
|
|
return p.fields
|
|
}
|
|
|
|
// WithSchema sets a raw CUE schema for the map structure.
|
|
// This takes precedence over WithFields for schema generation.
|
|
func (p *MapParam) WithSchema(schema string) *MapParam {
|
|
p.schema = schema
|
|
return p
|
|
}
|
|
|
|
// GetSchema returns the raw CUE schema for the map.
|
|
func (p *MapParam) GetSchema() string {
|
|
return p.schema
|
|
}
|
|
|
|
// WithSchemaRef sets a reference to a helper type definition (e.g., "#HealthProbe").
|
|
// This is used when the schema is defined elsewhere as a helper definition.
|
|
func (p *MapParam) WithSchemaRef(ref string) *MapParam {
|
|
p.schemaRef = ref
|
|
return p
|
|
}
|
|
|
|
// GetSchemaRef returns the schema reference for this parameter.
|
|
func (p *MapParam) GetSchemaRef() string {
|
|
return p.schemaRef
|
|
}
|
|
|
|
// Field returns a reference to a nested field within this map parameter.
|
|
// This allows map parameters to be used as variables with field access.
|
|
// Example: requests := Map("requests").WithSchema(...); requests.Field("cpu") => parameter.requests.cpu
|
|
func (p *MapParam) Field(fieldPath string) *ParamFieldRef {
|
|
return &ParamFieldRef{paramName: p.name, fieldPath: fieldPath}
|
|
}
|
|
|
|
// --- MapParam Runtime Condition Methods ---
|
|
|
|
// HasKey creates a condition that checks if this map has a specific key.
|
|
// Example: config.HasKey("debug") generates: parameter.config.debug != _|_
|
|
func (p *MapParam) HasKey(key string) Condition {
|
|
return &MapHasKeyCondition{paramName: p.name, key: key}
|
|
}
|
|
|
|
// LenEq creates a condition that checks if this map has exactly n entries.
|
|
// Example: config.LenEq(5) generates: len(parameter.config) == 5
|
|
func (p *MapParam) LenEq(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: "==", length: n}
|
|
}
|
|
|
|
// LenGt creates a condition that checks if this map has more than n entries.
|
|
// Example: config.LenGt(0) generates: len(parameter.config) > 0
|
|
func (p *MapParam) LenGt(n int) Condition {
|
|
return &LenCondition{paramName: p.name, op: ">", length: n}
|
|
}
|
|
|
|
// IsEmpty creates a condition that checks if this map is empty.
|
|
// Example: config.IsEmpty() generates: len(parameter.config) == 0
|
|
func (p *MapParam) IsEmpty() Condition {
|
|
return &LenCondition{paramName: p.name, op: "==", length: 0}
|
|
}
|
|
|
|
// IsNotEmpty creates a condition that checks if this map is not empty.
|
|
// Example: config.IsNotEmpty() generates: len(parameter.config) > 0
|
|
func (p *MapParam) IsNotEmpty() Condition {
|
|
return &LenCondition{paramName: p.name, op: ">", length: 0}
|
|
}
|
|
|
|
// StructField represents a field within a struct parameter.
|
|
type StructField struct {
|
|
name string
|
|
fieldType ParamType
|
|
required bool // when true, emits "!" marker — user must explicitly provide this field in input
|
|
mandatory bool // when true, field is non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it
|
|
defaultValue any
|
|
description string
|
|
nested *StructParam // for nested structs
|
|
schemaRef string // reference to a helper definition (e.g., "HealthProbe")
|
|
enumValues []string // allowed enum values for string fields
|
|
elementType ParamType // for array fields: element type (e.g., ParamTypeString for [...string])
|
|
}
|
|
|
|
// Field creates a new struct field definition.
|
|
func Field(name string, fieldType ParamType) *StructField {
|
|
return &StructField{
|
|
name: name,
|
|
fieldType: fieldType,
|
|
}
|
|
}
|
|
|
|
// Required marks the field as required in input, emitting the "!" CUE marker.
|
|
// The user must explicitly provide this field — even if a default value exists.
|
|
func (f *StructField) Required() *StructField {
|
|
f.required = true
|
|
return f
|
|
}
|
|
|
|
// Mandatory marks the field as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (f *StructField) Mandatory() *StructField {
|
|
f.mandatory = true
|
|
return f
|
|
}
|
|
|
|
// Optional marks the field as optional (default behavior).
|
|
func (f *StructField) Optional() *StructField {
|
|
f.mandatory = false
|
|
f.required = false
|
|
return f
|
|
}
|
|
|
|
// Default sets a default value for the field.
|
|
func (f *StructField) Default(value any) *StructField {
|
|
f.defaultValue = value
|
|
return f
|
|
}
|
|
|
|
// Description sets the field description.
|
|
func (f *StructField) Description(desc string) *StructField {
|
|
f.description = desc
|
|
return f
|
|
}
|
|
|
|
// Nested sets a nested struct definition for this field.
|
|
// For ParamTypeStruct fields, this defines the struct's shape.
|
|
// For ParamTypeArray fields, this defines the array element struct shape (generates [...{fields}]).
|
|
func (f *StructField) Nested(s *StructParam) *StructField {
|
|
f.nested = s
|
|
if f.fieldType == ParamTypeArray {
|
|
// Preserve array type; this indicates an array of nested structs.
|
|
if f.elementType == "" {
|
|
f.elementType = ParamTypeStruct
|
|
}
|
|
} else {
|
|
f.fieldType = ParamTypeStruct
|
|
}
|
|
return f
|
|
}
|
|
|
|
// Name returns the field name.
|
|
func (f *StructField) Name() string { return f.name }
|
|
|
|
// FieldType returns the field type.
|
|
func (f *StructField) FieldType() ParamType { return f.fieldType }
|
|
|
|
// IsRequired returns true if the field emits the "!" CUE marker — user must explicitly provide it.
|
|
func (f *StructField) IsRequired() bool { return f.required }
|
|
|
|
// IsMandatory returns true if the field is non-optional (no ? marker) but defaults or CUE merging can satisfy it.
|
|
func (f *StructField) IsMandatory() bool { return f.mandatory }
|
|
|
|
// HasDefault returns true if the field has a default value.
|
|
func (f *StructField) HasDefault() bool { return f.defaultValue != nil }
|
|
|
|
// GetDefault returns the default value.
|
|
func (f *StructField) GetDefault() any { return f.defaultValue }
|
|
|
|
// GetDescription returns the field description.
|
|
func (f *StructField) GetDescription() string { return f.description }
|
|
|
|
// GetNested returns the nested struct definition, if any.
|
|
func (f *StructField) GetNested() *StructParam { return f.nested }
|
|
|
|
// WithSchemaRef sets a reference to a helper type definition (e.g., "#RuleSelector").
|
|
// This is used when the field type is defined elsewhere as a helper definition.
|
|
func (f *StructField) WithSchemaRef(ref string) *StructField {
|
|
f.schemaRef = ref
|
|
return f
|
|
}
|
|
|
|
// GetSchemaRef returns the schema reference for this field.
|
|
func (f *StructField) GetSchemaRef() string { return f.schemaRef }
|
|
|
|
// Values restricts the field to specific allowed values.
|
|
// This is only meaningful for string fields.
|
|
func (f *StructField) Values(values ...string) *StructField {
|
|
f.enumValues = values
|
|
return f
|
|
}
|
|
|
|
// GetEnumValues returns the allowed enum values.
|
|
func (f *StructField) GetEnumValues() []string { return f.enumValues }
|
|
|
|
// Of sets the element type for array fields (e.g., ParamTypeString for [...string]).
|
|
func (f *StructField) Of(elemType ParamType) *StructField {
|
|
f.elementType = elemType
|
|
return f
|
|
}
|
|
|
|
// GetElementType returns the element type for array fields.
|
|
func (f *StructField) GetElementType() ParamType { return f.elementType }
|
|
|
|
// StructParam represents a structured parameter with named fields.
|
|
type StructParam struct {
|
|
baseParam
|
|
fields []*StructField
|
|
schemaRef string // reference to a helper definition (e.g., "HealthProbe")
|
|
}
|
|
|
|
// Struct creates a new struct parameter with the given name.
|
|
func Struct(name string) *StructParam {
|
|
return &StructParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeStruct,
|
|
},
|
|
fields: make([]*StructField, 0),
|
|
}
|
|
}
|
|
|
|
// WithFields adds field definitions to the struct.
|
|
func (p *StructParam) WithFields(fields ...*StructField) *StructParam {
|
|
p.fields = append(p.fields, fields...)
|
|
return p
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *StructParam) Required() *StructParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *StructParam) Mandatory() *StructParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *StructParam) Optional() *StructParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *StructParam) Description(desc string) *StructParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// GetFields returns all field definitions.
|
|
func (p *StructParam) GetFields() []*StructField {
|
|
return p.fields
|
|
}
|
|
|
|
// GetField returns a field by name, or nil if not found.
|
|
func (p *StructParam) GetField(name string) *StructField {
|
|
for _, f := range p.fields {
|
|
if f.name == name {
|
|
return f
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WithSchemaRef sets a reference to a helper type definition (e.g., "#RuleSelector").
|
|
// This is used when the struct type is defined elsewhere as a helper definition.
|
|
func (p *StructParam) WithSchemaRef(ref string) *StructParam {
|
|
p.schemaRef = ref
|
|
return p
|
|
}
|
|
|
|
// GetSchemaRef returns the schema reference for this struct.
|
|
func (p *StructParam) GetSchemaRef() string { return p.schemaRef }
|
|
|
|
// Field returns a reference to a nested field within this struct parameter.
|
|
// This allows struct parameters to be used as variables with field access.
|
|
// Example: config := Struct("config").WithFields(...); config.Field("port") => parameter.config.port
|
|
func (p *StructParam) Field(fieldPath string) *ParamFieldRef {
|
|
return &ParamFieldRef{paramName: p.name, fieldPath: fieldPath}
|
|
}
|
|
|
|
// EnumParam represents an enumeration parameter with allowed values.
|
|
type EnumParam struct {
|
|
baseParam
|
|
values []string
|
|
}
|
|
|
|
// Enum creates a new enum parameter with the given name.
|
|
func Enum(name string) *EnumParam {
|
|
return &EnumParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeEnum,
|
|
},
|
|
values: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
// Values sets the allowed enum values.
|
|
func (p *EnumParam) Values(values ...string) *EnumParam {
|
|
p.values = values
|
|
return p
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *EnumParam) Required() *EnumParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *EnumParam) Mandatory() *EnumParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *EnumParam) Optional() *EnumParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
func (p *EnumParam) ForceOptional() *EnumParam {
|
|
p.forceOptional = true
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *EnumParam) Default(value string) *EnumParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *EnumParam) Description(desc string) *EnumParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// Short sets a short flag alias for the parameter.
|
|
// This generates a // +short=X directive in the CUE output.
|
|
func (p *EnumParam) Short(s string) *EnumParam {
|
|
p.short = s
|
|
return p
|
|
}
|
|
|
|
// Ignore marks the parameter as ignored by the UI.
|
|
// This generates a // +ignore directive in the CUE output.
|
|
func (p *EnumParam) Ignore() *EnumParam {
|
|
p.ignore = true
|
|
return p
|
|
}
|
|
|
|
// GetValues returns the allowed enum values.
|
|
func (p *EnumParam) GetValues() []string {
|
|
return p.values
|
|
}
|
|
|
|
// OneOfVariant represents a variant in a discriminated union.
|
|
type OneOfVariant struct {
|
|
name string
|
|
fields []*StructField
|
|
}
|
|
|
|
// Variant creates a new variant for a OneOf parameter.
|
|
func Variant(name string) *OneOfVariant {
|
|
return &OneOfVariant{
|
|
name: name,
|
|
fields: make([]*StructField, 0),
|
|
}
|
|
}
|
|
|
|
// WithFields adds field definitions to the variant.
|
|
func (v *OneOfVariant) WithFields(fields ...*StructField) *OneOfVariant {
|
|
v.fields = append(v.fields, fields...)
|
|
return v
|
|
}
|
|
|
|
// Name returns the variant name.
|
|
func (v *OneOfVariant) Name() string { return v.name }
|
|
|
|
// GetFields returns the variant's field definitions.
|
|
func (v *OneOfVariant) GetFields() []*StructField { return v.fields }
|
|
|
|
// OneOfParam represents a discriminated union parameter.
|
|
type OneOfParam struct {
|
|
baseParam
|
|
discriminator string
|
|
variants []*OneOfVariant
|
|
}
|
|
|
|
// OneOf creates a new discriminated union parameter with the given name.
|
|
func OneOf(name string) *OneOfParam {
|
|
return &OneOfParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeOneOf,
|
|
},
|
|
discriminator: "type", // default discriminator field
|
|
variants: make([]*OneOfVariant, 0),
|
|
}
|
|
}
|
|
|
|
// Discriminator sets the field name used to distinguish variants.
|
|
func (p *OneOfParam) Discriminator(field string) *OneOfParam {
|
|
p.discriminator = field
|
|
return p
|
|
}
|
|
|
|
// Variants adds variant definitions to the union.
|
|
func (p *OneOfParam) Variants(variants ...*OneOfVariant) *OneOfParam {
|
|
p.variants = append(p.variants, variants...)
|
|
return p
|
|
}
|
|
|
|
// Default sets the default variant name for the discriminator.
|
|
func (p *OneOfParam) Default(value string) *OneOfParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *OneOfParam) Required() *OneOfParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *OneOfParam) Mandatory() *OneOfParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *OneOfParam) Optional() *OneOfParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *OneOfParam) Description(desc string) *OneOfParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// GetDiscriminator returns the discriminator field name.
|
|
func (p *OneOfParam) GetDiscriminator() string {
|
|
return p.discriminator
|
|
}
|
|
|
|
// GetVariants returns all variant definitions.
|
|
func (p *OneOfParam) GetVariants() []*OneOfVariant {
|
|
return p.variants
|
|
}
|
|
|
|
// GetVariant returns a variant by name, or nil if not found.
|
|
func (p *OneOfParam) GetVariant(name string) *OneOfVariant {
|
|
for _, v := range p.variants {
|
|
if v.name == name {
|
|
return v
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Convenience functions for common parameter patterns
|
|
|
|
// StringList creates a string array parameter.
|
|
func StringList(name string) *ArrayParam {
|
|
return Array(name).Of(ParamTypeString)
|
|
}
|
|
|
|
// IntList creates an integer array parameter.
|
|
func IntList(name string) *ArrayParam {
|
|
return Array(name).Of(ParamTypeInt)
|
|
}
|
|
|
|
// List creates a generic list parameter (array of any).
|
|
func List(name string) *ArrayParam {
|
|
return Array(name)
|
|
}
|
|
|
|
// Object creates a generic object/struct parameter.
|
|
// This is useful when the structure is complex or dynamic.
|
|
func Object(name string) *MapParam {
|
|
return Map(name)
|
|
}
|
|
|
|
// StringKeyMapParam represents a map with string keys and string values.
|
|
// In CUE: [string]: string
|
|
type StringKeyMapParam struct {
|
|
baseParam
|
|
}
|
|
|
|
// StringKeyMap creates a new string-to-string map parameter.
|
|
// Generates CUE like: labels?: [string]: string
|
|
func StringKeyMap(name string) *StringKeyMapParam {
|
|
return &StringKeyMapParam{
|
|
baseParam: baseParam{
|
|
name: name,
|
|
paramType: ParamTypeMap,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Required marks the parameter as required in input, emitting the "!" CUE marker.
|
|
func (p *StringKeyMapParam) Required() *StringKeyMapParam {
|
|
p.required = true
|
|
p.mandatory = false
|
|
return p
|
|
}
|
|
|
|
// Mandatory marks the parameter as non-optional (no ? marker); must have a value but defaults or CUE merging can satisfy it.
|
|
func (p *StringKeyMapParam) Mandatory() *StringKeyMapParam {
|
|
p.mandatory = true
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Optional marks the parameter as optional (default behavior).
|
|
func (p *StringKeyMapParam) Optional() *StringKeyMapParam {
|
|
p.mandatory = false
|
|
p.required = false
|
|
return p
|
|
}
|
|
|
|
// Default sets a default value for the parameter.
|
|
func (p *StringKeyMapParam) Default(value map[string]string) *StringKeyMapParam {
|
|
p.defaultValue = value
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *StringKeyMapParam) Description(desc string) *StringKeyMapParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// GetType returns the parameter type.
|
|
func (p *StringKeyMapParam) GetType() ParamType { return p.paramType }
|
|
|
|
// DynamicMapParam represents a parameter where the parameter itself is a dynamic map.
|
|
// In CUE: parameter: [string]: T (where T is the value type)
|
|
// This is used for traits like labels where all user values become map keys.
|
|
type DynamicMapParam struct {
|
|
baseParam
|
|
valueType ParamType // type of values in the map
|
|
valueTypeUnion string // for union types like "string | null"
|
|
}
|
|
|
|
// DynamicMap creates a new dynamic map parameter.
|
|
// This is used when the entire parameter schema is a map with dynamic keys.
|
|
// Generates CUE like: parameter: [string]: string | null
|
|
//
|
|
// Example usage:
|
|
//
|
|
// defkit.DynamicMap().ValueType(defkit.ParamTypeString) // parameter: [string]: string
|
|
// defkit.DynamicMap().ValueTypeUnion("string | null") // parameter: [string]: string | null
|
|
func DynamicMap() *DynamicMapParam {
|
|
return &DynamicMapParam{
|
|
baseParam: baseParam{
|
|
name: "", // Dynamic maps don't have a field name
|
|
paramType: ParamTypeMap,
|
|
},
|
|
valueType: ParamTypeString, // default to string values
|
|
}
|
|
}
|
|
|
|
// ValueType sets the value type for the dynamic map.
|
|
func (p *DynamicMapParam) ValueType(t ParamType) *DynamicMapParam {
|
|
p.valueType = t
|
|
return p
|
|
}
|
|
|
|
// ValueTypeUnion sets a union type for the values (e.g., "string | null").
|
|
func (p *DynamicMapParam) ValueTypeUnion(union string) *DynamicMapParam {
|
|
p.valueTypeUnion = union
|
|
return p
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *DynamicMapParam) Description(desc string) *DynamicMapParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// GetValueType returns the value type for this dynamic map.
|
|
func (p *DynamicMapParam) GetValueType() ParamType {
|
|
return p.valueType
|
|
}
|
|
|
|
// GetValueTypeUnion returns the union type string if set.
|
|
func (p *DynamicMapParam) GetValueTypeUnion() string {
|
|
return p.valueTypeUnion
|
|
}
|
|
|
|
// IsDynamicMap returns true (used for type detection).
|
|
func (p *DynamicMapParam) IsDynamicMap() bool {
|
|
return true
|
|
}
|
|
|
|
// --- Parameter Path Reference ---
|
|
|
|
// ParamPathRef represents a reference to a nested parameter path.
|
|
// This is used to reference nested parameter values like "podAffinity.required".
|
|
// It generates CUE like `parameter.podAffinity.required`.
|
|
type ParamPathRef struct {
|
|
path string // e.g., "podAffinity.required"
|
|
}
|
|
|
|
func (p *ParamPathRef) expr() {}
|
|
func (p *ParamPathRef) value() {}
|
|
|
|
// Path returns the parameter path.
|
|
func (p *ParamPathRef) Path() string { return p.path }
|
|
|
|
// IsSet returns a condition that checks if this parameter path has a value.
|
|
// This is used with SetIf for conditional field assignment.
|
|
// Generates: if parameter.path != _|_
|
|
func (p *ParamPathRef) IsSet() Condition {
|
|
return &ParamPathIsSetCondition{path: p.path}
|
|
}
|
|
|
|
// ParamPath creates a reference to a nested parameter path.
|
|
// This is used for accessing nested parameters in conditions and expressions.
|
|
//
|
|
// Usage:
|
|
//
|
|
// defkit.ParamPath("podAffinity.required").IsSet() // generates: if parameter.podAffinity.required != _|_
|
|
// defkit.From(defkit.ParamPath("podAffinity.required")).Map(...) // generates: [for v in parameter.podAffinity.required {...}]
|
|
func ParamPath(path string) *ParamPathRef {
|
|
return &ParamPathRef{path: path}
|
|
}
|
|
|
|
// ParamPathIsSetCondition checks if a parameter path has a value.
|
|
type ParamPathIsSetCondition struct {
|
|
baseCondition
|
|
path string
|
|
}
|
|
|
|
// Path returns the parameter path being checked.
|
|
func (c *ParamPathIsSetCondition) Path() string { return c.path }
|
|
|
|
// --- Open Struct Parameter ---
|
|
|
|
// OpenStructParam represents an open struct parameter that accepts any fields.
|
|
// This generates CUE like: parameter: {...}
|
|
// Used for json-patch and json-merge-patch traits where the entire parameter
|
|
// is passed through as the patch content.
|
|
type OpenStructParam struct {
|
|
baseParam
|
|
isOpen bool // always true for this type
|
|
}
|
|
|
|
// OpenStruct creates a new open struct parameter.
|
|
// This is used when the parameter schema should accept any fields.
|
|
// Generates CUE like: parameter: {...}
|
|
//
|
|
// Example usage:
|
|
//
|
|
// defkit.OpenStruct() // generates: parameter: {...}
|
|
func OpenStruct() *OpenStructParam {
|
|
return &OpenStructParam{
|
|
isOpen: true,
|
|
}
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *OpenStructParam) Description(desc string) *OpenStructParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// IsOpen returns true (used for type detection).
|
|
func (p *OpenStructParam) IsOpen() bool {
|
|
return true
|
|
}
|
|
|
|
// GetName returns an empty string (open structs don't have names).
|
|
func (p *OpenStructParam) GetName() string { return "" }
|
|
|
|
// GetDescription returns the parameter description.
|
|
func (p *OpenStructParam) GetDescription() string { return p.description }
|
|
|
|
// GetType returns the parameter type.
|
|
func (p *OpenStructParam) GetType() ParamType { return ParamTypeStruct }
|
|
|
|
// IsRequired returns false (open structs are inherently optional).
|
|
func (p *OpenStructParam) IsRequired() bool { return false }
|
|
|
|
// GetDefault returns nil (open structs don't have defaults).
|
|
func (p *OpenStructParam) GetDefault() any { return nil }
|
|
|
|
// --- Open Array Parameter ---
|
|
|
|
// OpenArrayParam represents an open array parameter that accepts any elements.
|
|
// This generates CUE like: operations: [...{...}]
|
|
// Used for json-patch trait where operations array accepts any operations.
|
|
type OpenArrayParam struct {
|
|
baseParam
|
|
}
|
|
|
|
// OpenArray creates a new open array parameter.
|
|
// This is used when the parameter schema should accept any array elements.
|
|
// Generates CUE like: name: [...{...}]
|
|
//
|
|
// Example usage:
|
|
//
|
|
// defkit.OpenArray("operations") // generates: operations: [...{...}]
|
|
func OpenArray(name string) *OpenArrayParam {
|
|
return &OpenArrayParam{
|
|
baseParam: baseParam{name: name},
|
|
}
|
|
}
|
|
|
|
// Description sets the parameter description.
|
|
func (p *OpenArrayParam) Description(desc string) *OpenArrayParam {
|
|
p.description = desc
|
|
return p
|
|
}
|
|
|
|
// GetDescription returns the parameter description.
|
|
func (p *OpenArrayParam) GetDescription() string { return p.description }
|
|
|
|
// GetType returns the parameter type.
|
|
func (p *OpenArrayParam) GetType() ParamType { return ParamTypeArray }
|
|
|
|
// IsRequired returns false (open arrays are inherently optional).
|
|
func (p *OpenArrayParam) IsRequired() bool { return false }
|
|
|
|
// GetDefault returns nil (open arrays don't have defaults).
|
|
func (p *OpenArrayParam) GetDefault() any { return nil }
|
|
|
|
// --- Parameter Expression Types ---
|
|
|
|
// ParamArithExpr represents an arithmetic expression on a parameter.
|
|
// Example: parameter.replicas + 1
|
|
type ParamArithExpr struct {
|
|
paramName string
|
|
op string
|
|
arithVal any
|
|
}
|
|
|
|
func (e *ParamArithExpr) expr() {}
|
|
func (e *ParamArithExpr) value() {}
|
|
|
|
// ParamName returns the parameter name.
|
|
func (e *ParamArithExpr) ParamName() string { return e.paramName }
|
|
|
|
// Op returns the arithmetic operator.
|
|
func (e *ParamArithExpr) Op() string { return e.op }
|
|
|
|
// ArithValue returns the value for the arithmetic operation.
|
|
func (e *ParamArithExpr) ArithValue() any { return e.arithVal }
|
|
|
|
// ParamConcatExpr represents a string concatenation expression on a parameter.
|
|
// Example: parameter.name + "-suffix"
|
|
type ParamConcatExpr struct {
|
|
paramName string
|
|
suffix string
|
|
prefix string
|
|
}
|
|
|
|
func (e *ParamConcatExpr) expr() {}
|
|
func (e *ParamConcatExpr) value() {}
|
|
|
|
// ParamName returns the parameter name.
|
|
func (e *ParamConcatExpr) ParamName() string { return e.paramName }
|
|
|
|
// Suffix returns the suffix to append.
|
|
func (e *ParamConcatExpr) Suffix() string { return e.suffix }
|
|
|
|
// Prefix returns the prefix to prepend.
|
|
func (e *ParamConcatExpr) Prefix() string { return e.prefix }
|
|
|
|
// ParamFieldRef represents a reference to a field within a struct parameter.
|
|
// Example: parameter.config.name
|
|
type ParamFieldRef struct {
|
|
paramName string
|
|
fieldPath string
|
|
}
|
|
|
|
func (r *ParamFieldRef) expr() {}
|
|
func (r *ParamFieldRef) value() {}
|
|
func (r *ParamFieldRef) condition() {}
|
|
|
|
// ParamName returns the parameter name.
|
|
func (r *ParamFieldRef) ParamName() string { return r.paramName }
|
|
|
|
// FieldPath returns the field path within the struct.
|
|
func (r *ParamFieldRef) FieldPath() string { return r.fieldPath }
|
|
|
|
// IsSet returns a condition that checks if this field is set.
|
|
func (r *ParamFieldRef) IsSet() Condition {
|
|
return &ParamPathIsSetCondition{path: r.paramName + "." + r.fieldPath}
|
|
}
|
|
|
|
// Eq creates a condition that compares this field to a value.
|
|
func (r *ParamFieldRef) Eq(val any) Condition {
|
|
return &ParamCompareCondition{paramName: r.paramName + "." + r.fieldPath, op: "==", value: val}
|
|
}
|
|
|
|
// Ne creates a condition that checks inequality.
|
|
func (r *ParamFieldRef) Ne(val any) Condition {
|
|
return &ParamCompareCondition{paramName: r.paramName + "." + r.fieldPath, op: "!=", value: val}
|
|
}
|