mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
Refactor FunctionGen - no interface needed
This commit is contained in:
parent
f9e92a1aa7
commit
0b29555323
@ -1093,14 +1093,14 @@ func (g *genValidations) emitCallToOtherTypeFunc(c *generator.Context, node *typ
|
|||||||
// Emitted code assumes that the value in question is always a pair of nilable
|
// Emitted code assumes that the value in question is always a pair of nilable
|
||||||
// variables named "obj" and "oldObj", and the field path to this value is
|
// variables named "obj" and "oldObj", and the field path to this value is
|
||||||
// named "fldPath".
|
// named "fldPath".
|
||||||
func emitCallsToValidators(c *generator.Context, validations []validators.FunctionGen, sw *generator.SnippetWriter) {
|
func emitCallsToValidators(c *generator.Context, validations []*validators.FunctionGen, sw *generator.SnippetWriter) {
|
||||||
// Helper func
|
// Helper func
|
||||||
sort := func(in []validators.FunctionGen) []validators.FunctionGen {
|
sort := func(in []*validators.FunctionGen) []*validators.FunctionGen {
|
||||||
sooner := make([]validators.FunctionGen, 0, len(in))
|
sooner := make([]*validators.FunctionGen, 0, len(in))
|
||||||
later := make([]validators.FunctionGen, 0, len(in))
|
later := make([]*validators.FunctionGen, 0, len(in))
|
||||||
|
|
||||||
for _, fg := range in {
|
for _, fg := range in {
|
||||||
isShortCircuit := (fg.Flags().IsSet(validators.ShortCircuit))
|
isShortCircuit := (fg.Flags.IsSet(validators.ShortCircuit))
|
||||||
|
|
||||||
if isShortCircuit {
|
if isShortCircuit {
|
||||||
sooner = append(sooner, fg)
|
sooner = append(sooner, fg)
|
||||||
@ -1116,19 +1116,17 @@ func emitCallsToValidators(c *generator.Context, validations []validators.Functi
|
|||||||
validations = sort(validations)
|
validations = sort(validations)
|
||||||
|
|
||||||
for _, v := range validations {
|
for _, v := range validations {
|
||||||
isShortCircuit := v.Flags().IsSet(validators.ShortCircuit)
|
isShortCircuit := v.Flags.IsSet(validators.ShortCircuit)
|
||||||
isNonError := v.Flags().IsSet(validators.NonError)
|
isNonError := v.Flags.IsSet(validators.NonError)
|
||||||
|
|
||||||
fn, extraArgs := v.SignatureAndArgs()
|
|
||||||
targs := generator.Args{
|
targs := generator.Args{
|
||||||
"funcName": c.Universe.Type(fn),
|
"funcName": c.Universe.Type(v.Function),
|
||||||
"field": mkSymbolArgs(c, fieldPkgSymbols),
|
"field": mkSymbolArgs(c, fieldPkgSymbols),
|
||||||
}
|
}
|
||||||
|
|
||||||
emitCall := func() {
|
emitCall := func() {
|
||||||
sw.Do("$.funcName|raw$", targs)
|
sw.Do("$.funcName|raw$", targs)
|
||||||
typeArgs := v.TypeArgs()
|
if typeArgs := v.TypeArgs; len(typeArgs) > 0 {
|
||||||
if len(typeArgs) > 0 {
|
|
||||||
sw.Do("[", nil)
|
sw.Do("[", nil)
|
||||||
for i, typeArg := range typeArgs {
|
for i, typeArg := range typeArgs {
|
||||||
sw.Do("$.|raw$", c.Universe.Type(typeArg))
|
sw.Do("$.|raw$", c.Universe.Type(typeArg))
|
||||||
@ -1139,7 +1137,7 @@ func emitCallsToValidators(c *generator.Context, validations []validators.Functi
|
|||||||
sw.Do("]", nil)
|
sw.Do("]", nil)
|
||||||
}
|
}
|
||||||
sw.Do("(ctx, op, fldPath, obj, oldObj", targs)
|
sw.Do("(ctx, op, fldPath, obj, oldObj", targs)
|
||||||
for _, arg := range extraArgs {
|
for _, arg := range v.Args {
|
||||||
sw.Do(", ", nil)
|
sw.Do(", ", nil)
|
||||||
toGolangSourceDataLiteral(sw, c, arg)
|
toGolangSourceDataLiteral(sw, c, arg)
|
||||||
}
|
}
|
||||||
@ -1147,21 +1145,21 @@ func emitCallsToValidators(c *generator.Context, validations []validators.Functi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If validation is conditional, wrap the validation function with a conditions check.
|
// If validation is conditional, wrap the validation function with a conditions check.
|
||||||
if !v.Conditions().Empty() {
|
if !v.Conditions.Empty() {
|
||||||
emitBaseFunction := emitCall
|
emitBaseFunction := emitCall
|
||||||
emitCall = func() {
|
emitCall = func() {
|
||||||
sw.Do("func() $.field.ErrorList|raw$ {\n", targs)
|
sw.Do("func() $.field.ErrorList|raw$ {\n", targs)
|
||||||
sw.Do(" if ", nil)
|
sw.Do(" if ", nil)
|
||||||
firstCondition := true
|
firstCondition := true
|
||||||
if len(v.Conditions().OptionEnabled) > 0 {
|
if len(v.Conditions.OptionEnabled) > 0 {
|
||||||
sw.Do("op.Options.Has($.$)", strconv.Quote(v.Conditions().OptionEnabled))
|
sw.Do("op.Options.Has($.$)", strconv.Quote(v.Conditions.OptionEnabled))
|
||||||
firstCondition = false
|
firstCondition = false
|
||||||
}
|
}
|
||||||
if len(v.Conditions().OptionDisabled) > 0 {
|
if len(v.Conditions.OptionDisabled) > 0 {
|
||||||
if !firstCondition {
|
if !firstCondition {
|
||||||
sw.Do(" && ", nil)
|
sw.Do(" && ", nil)
|
||||||
}
|
}
|
||||||
sw.Do("!op.Options.Has($.$)", strconv.Quote(v.Conditions().OptionDisabled))
|
sw.Do("!op.Options.Has($.$)", strconv.Quote(v.Conditions.OptionDisabled))
|
||||||
}
|
}
|
||||||
sw.Do(" {\n", nil)
|
sw.Do(" {\n", nil)
|
||||||
sw.Do(" return ", nil)
|
sw.Do(" return ", nil)
|
||||||
@ -1174,7 +1172,7 @@ func emitCallsToValidators(c *generator.Context, validations []validators.Functi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, comment := range v.Comments() {
|
for _, comment := range v.Comments {
|
||||||
sw.Do("// $.$\n", comment)
|
sw.Do("// $.$\n", comment)
|
||||||
}
|
}
|
||||||
if isShortCircuit {
|
if isShortCircuit {
|
||||||
@ -1218,16 +1216,15 @@ func (g *genValidations) emitValidationVariables(c *generator.Context, t *types.
|
|||||||
})
|
})
|
||||||
for _, variable := range variables {
|
for _, variable := range variables {
|
||||||
fn := variable.Init()
|
fn := variable.Init()
|
||||||
supportInitFn, supportInitArgs := fn.SignatureAndArgs()
|
|
||||||
targs := generator.Args{
|
targs := generator.Args{
|
||||||
"varName": c.Universe.Type(types.Name(variable.Var())),
|
"varName": c.Universe.Type(types.Name(variable.Var())),
|
||||||
"initFn": c.Universe.Type(supportInitFn),
|
"initFn": c.Universe.Type(fn.Function),
|
||||||
}
|
}
|
||||||
for _, comment := range fn.Comments() {
|
for _, comment := range fn.Comments {
|
||||||
sw.Do("// $.$\n", comment)
|
sw.Do("// $.$\n", comment)
|
||||||
}
|
}
|
||||||
sw.Do("var $.varName|private$ = $.initFn|raw$", targs)
|
sw.Do("var $.varName|private$ = $.initFn|raw$", targs)
|
||||||
typeArgs := variable.Init().TypeArgs()
|
typeArgs := variable.Init().TypeArgs
|
||||||
if len(typeArgs) > 0 {
|
if len(typeArgs) > 0 {
|
||||||
sw.Do("[", nil)
|
sw.Do("[", nil)
|
||||||
for i, typeArg := range typeArgs {
|
for i, typeArg := range typeArgs {
|
||||||
@ -1239,11 +1236,11 @@ func (g *genValidations) emitValidationVariables(c *generator.Context, t *types.
|
|||||||
sw.Do("]", nil)
|
sw.Do("]", nil)
|
||||||
}
|
}
|
||||||
sw.Do("(", targs)
|
sw.Do("(", targs)
|
||||||
for i, arg := range supportInitArgs {
|
for i, arg := range fn.Args {
|
||||||
toGolangSourceDataLiteral(sw, c, arg)
|
if i != 0 {
|
||||||
if i < len(supportInitArgs)-1 {
|
|
||||||
sw.Do(", ", nil)
|
sw.Do(", ", nil)
|
||||||
}
|
}
|
||||||
|
toGolangSourceDataLiteral(sw, c, arg)
|
||||||
}
|
}
|
||||||
sw.Do(")\n", nil)
|
sw.Do(")\n", nil)
|
||||||
|
|
||||||
@ -1277,14 +1274,13 @@ func toGolangSourceDataLiteral(sw *generator.SnippetWriter, c *generator.Context
|
|||||||
case *validators.PrivateVar:
|
case *validators.PrivateVar:
|
||||||
sw.Do("$.|private$", c.Universe.Type(types.Name(*v)))
|
sw.Do("$.|private$", c.Universe.Type(types.Name(*v)))
|
||||||
case validators.WrapperFunction:
|
case validators.WrapperFunction:
|
||||||
fn, extraArgs := v.Function.SignatureAndArgs()
|
if extraArgs := v.Function.Args; len(extraArgs) == 0 {
|
||||||
if len(extraArgs) == 0 {
|
|
||||||
// If the function to be wrapped has no additional arguments, we can
|
// If the function to be wrapped has no additional arguments, we can
|
||||||
// just use it directly.
|
// just use it directly.
|
||||||
targs := generator.Args{
|
targs := generator.Args{
|
||||||
"funcName": c.Universe.Type(fn),
|
"funcName": c.Universe.Type(v.Function.Function),
|
||||||
}
|
}
|
||||||
for _, comment := range v.Function.Comments() {
|
for _, comment := range v.Function.Comments {
|
||||||
sw.Do("// $.$\n", comment)
|
sw.Do("// $.$\n", comment)
|
||||||
}
|
}
|
||||||
sw.Do("$.funcName|raw$", targs)
|
sw.Do("$.funcName|raw$", targs)
|
||||||
@ -1292,7 +1288,7 @@ func toGolangSourceDataLiteral(sw *generator.SnippetWriter, c *generator.Context
|
|||||||
// If the function to be wrapped has additional arguments, we need
|
// If the function to be wrapped has additional arguments, we need
|
||||||
// a "standard signature" validation function to wrap it.
|
// a "standard signature" validation function to wrap it.
|
||||||
targs := generator.Args{
|
targs := generator.Args{
|
||||||
"funcName": c.Universe.Type(fn),
|
"funcName": c.Universe.Type(v.Function.Function),
|
||||||
"field": mkSymbolArgs(c, fieldPkgSymbols),
|
"field": mkSymbolArgs(c, fieldPkgSymbols),
|
||||||
"operation": mkSymbolArgs(c, operationPkgSymbols),
|
"operation": mkSymbolArgs(c, operationPkgSymbols),
|
||||||
"context": mkSymbolArgs(c, contextPkgSymbols),
|
"context": mkSymbolArgs(c, contextPkgSymbols),
|
||||||
@ -1305,7 +1301,7 @@ func toGolangSourceDataLiteral(sw *generator.SnippetWriter, c *generator.Context
|
|||||||
|
|
||||||
emitCall := func() {
|
emitCall := func() {
|
||||||
sw.Do("return $.funcName|raw$", targs)
|
sw.Do("return $.funcName|raw$", targs)
|
||||||
typeArgs := v.Function.TypeArgs()
|
typeArgs := v.Function.TypeArgs
|
||||||
if len(typeArgs) > 0 {
|
if len(typeArgs) > 0 {
|
||||||
sw.Do("[", nil)
|
sw.Do("[", nil)
|
||||||
for i, typeArg := range typeArgs {
|
for i, typeArg := range typeArgs {
|
||||||
|
@ -250,8 +250,8 @@ func (evtv eachValTagValidator) getValidations(fldPath *field.Path, t *types.Typ
|
|||||||
|
|
||||||
// ForEachVal returns a validation that applies a function to each element of
|
// ForEachVal returns a validation that applies a function to each element of
|
||||||
// a list or map.
|
// a list or map.
|
||||||
func ForEachVal(fldPath *field.Path, t *types.Type, fn FunctionGen) (Validations, error) {
|
func ForEachVal(fldPath *field.Path, t *types.Type, fn *FunctionGen) (Validations, error) {
|
||||||
return globalEachVal.getValidations(fldPath, t, Validations{Functions: []FunctionGen{fn}})
|
return globalEachVal.getValidations(fldPath, t, Validations{Functions: []*FunctionGen{fn}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (evtv eachValTagValidator) getListValidations(fldPath *field.Path, t *types.Type, validations Validations) (Validations, error) {
|
func (evtv eachValTagValidator) getListValidations(fldPath *field.Path, t *types.Type, validations Validations) (Validations, error) {
|
||||||
@ -286,7 +286,7 @@ func (evtv eachValTagValidator) getListValidations(fldPath *field.Path, t *types
|
|||||||
cmpFn.Body = buf.String()
|
cmpFn.Body = buf.String()
|
||||||
cmpArg = cmpFn
|
cmpArg = cmpFn
|
||||||
}
|
}
|
||||||
f := Function(eachValTagName, vfn.Flags(), validateEachSliceVal, cmpArg, WrapperFunction{vfn, t.Elem})
|
f := Function(eachValTagName, vfn.Flags, validateEachSliceVal, cmpArg, WrapperFunction{vfn, t.Elem})
|
||||||
result.Functions = append(result.Functions, f)
|
result.Functions = append(result.Functions, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ func (evtv eachValTagValidator) getMapValidations(t *types.Type, validations Val
|
|||||||
result.OpaqueValType = validations.OpaqueType
|
result.OpaqueValType = validations.OpaqueType
|
||||||
|
|
||||||
for _, vfn := range validations.Functions {
|
for _, vfn := range validations.Functions {
|
||||||
f := Function(eachValTagName, vfn.Flags(), validateEachMapVal, WrapperFunction{vfn, t.Elem})
|
f := Function(eachValTagName, vfn.Flags, validateEachMapVal, WrapperFunction{vfn, t.Elem})
|
||||||
result.Functions = append(result.Functions, f)
|
result.Functions = append(result.Functions, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +369,7 @@ func (ektv eachKeyTagValidator) getValidations(t *types.Type, validations Valida
|
|||||||
result := Validations{}
|
result := Validations{}
|
||||||
result.OpaqueKeyType = validations.OpaqueType
|
result.OpaqueKeyType = validations.OpaqueType
|
||||||
for _, vfn := range validations.Functions {
|
for _, vfn := range validations.Functions {
|
||||||
f := Function(eachKeyTagName, vfn.Flags(), validateEachMapKey, WrapperFunction{vfn, t.Key})
|
f := Function(eachKeyTagName, vfn.Flags, validateEachMapKey, WrapperFunction{vfn, t.Key})
|
||||||
result.Functions = append(result.Functions, f)
|
result.Functions = append(result.Functions, f)
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
@ -377,8 +377,8 @@ func (ektv eachKeyTagValidator) getValidations(t *types.Type, validations Valida
|
|||||||
|
|
||||||
// ForEachKey returns a validation that applies a function to each key of
|
// ForEachKey returns a validation that applies a function to each key of
|
||||||
// a map.
|
// a map.
|
||||||
func ForEachKey(_ *field.Path, t *types.Type, fn FunctionGen) (Validations, error) {
|
func ForEachKey(_ *field.Path, t *types.Type, fn *FunctionGen) (Validations, error) {
|
||||||
return globalEachKey.getValidations(t, Validations{Functions: []FunctionGen{fn}})
|
return globalEachKey.getValidations(t, Validations{Functions: []*FunctionGen{fn}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ektv eachKeyTagValidator) Docs() TagDoc {
|
func (ektv eachKeyTagValidator) Docs() TagDoc {
|
||||||
|
@ -165,7 +165,7 @@ func (reg *registry) sortTagsIntoPhases(tags map[string][]gengo.Tag) [][]string
|
|||||||
// Tag extraction will retain the relative order between 111 and 222, but
|
// Tag extraction will retain the relative order between 111 and 222, but
|
||||||
// 333 is extracted as tag "k8s:ifOptionEnabled". Those are all in a map,
|
// 333 is extracted as tag "k8s:ifOptionEnabled". Those are all in a map,
|
||||||
// which we iterate (in a random order). When it reaches the emit stage,
|
// which we iterate (in a random order). When it reaches the emit stage,
|
||||||
// the "ifOptionEnabled" part is gone, and we will have 3 functionGen
|
// the "ifOptionEnabled" part is gone, and we will have 3 FunctionGen
|
||||||
// objects, all with tag "k8s:validateFalse", in a non-deterministic order
|
// objects, all with tag "k8s:validateFalse", in a non-deterministic order
|
||||||
// because of the map iteration. If we sort them at that point, we won't
|
// because of the map iteration. If we sort them at that point, we won't
|
||||||
// have enough information to do something smart, unless we look at the
|
// have enough information to do something smart, unless we look at the
|
||||||
|
@ -96,11 +96,11 @@ func (rtv requirednessTagValidator) doRequired(context Context) (Validations, er
|
|||||||
// do manual dispatch here.
|
// do manual dispatch here.
|
||||||
switch context.Type.Kind {
|
switch context.Type.Kind {
|
||||||
case types.Slice:
|
case types.Slice:
|
||||||
return Validations{Functions: []FunctionGen{Function(requiredTagName, ShortCircuit, requiredSliceValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(requiredTagName, ShortCircuit, requiredSliceValidator)}}, nil
|
||||||
case types.Map:
|
case types.Map:
|
||||||
return Validations{Functions: []FunctionGen{Function(requiredTagName, ShortCircuit, requiredMapValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(requiredTagName, ShortCircuit, requiredMapValidator)}}, nil
|
||||||
case types.Pointer:
|
case types.Pointer:
|
||||||
return Validations{Functions: []FunctionGen{Function(requiredTagName, ShortCircuit, requiredPointerValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(requiredTagName, ShortCircuit, requiredPointerValidator)}}, nil
|
||||||
case types.Struct:
|
case types.Struct:
|
||||||
// The +k8s:required tag on a non-pointer struct is not supported.
|
// The +k8s:required tag on a non-pointer struct is not supported.
|
||||||
// If you encounter this error and believe you have a valid use case
|
// If you encounter this error and believe you have a valid use case
|
||||||
@ -109,7 +109,7 @@ func (rtv requirednessTagValidator) doRequired(context Context) (Validations, er
|
|||||||
// this behavior or provide alternative validation mechanisms.
|
// this behavior or provide alternative validation mechanisms.
|
||||||
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", requiredTagName)
|
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", requiredTagName)
|
||||||
}
|
}
|
||||||
return Validations{Functions: []FunctionGen{Function(requiredTagName, ShortCircuit, requiredValueValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(requiredTagName, ShortCircuit, requiredValueValidator)}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -167,11 +167,11 @@ func (rtv requirednessTagValidator) doOptional(context Context) (Validations, er
|
|||||||
// do manual dispatch here.
|
// do manual dispatch here.
|
||||||
switch context.Type.Kind {
|
switch context.Type.Kind {
|
||||||
case types.Slice:
|
case types.Slice:
|
||||||
return Validations{Functions: []FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalSliceValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalSliceValidator)}}, nil
|
||||||
case types.Map:
|
case types.Map:
|
||||||
return Validations{Functions: []FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalMapValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalMapValidator)}}, nil
|
||||||
case types.Pointer:
|
case types.Pointer:
|
||||||
return Validations{Functions: []FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalPointerValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalPointerValidator)}}, nil
|
||||||
case types.Struct:
|
case types.Struct:
|
||||||
// The +k8s:optional tag on a non-pointer struct is not supported.
|
// The +k8s:optional tag on a non-pointer struct is not supported.
|
||||||
// If you encounter this error and believe you have a valid use case
|
// If you encounter this error and believe you have a valid use case
|
||||||
@ -180,7 +180,7 @@ func (rtv requirednessTagValidator) doOptional(context Context) (Validations, er
|
|||||||
// this behavior or provide alternative validation mechanisms.
|
// this behavior or provide alternative validation mechanisms.
|
||||||
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", optionalTagName)
|
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", optionalTagName)
|
||||||
}
|
}
|
||||||
return Validations{Functions: []FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalValueValidator)}}, nil
|
return Validations{Functions: []*FunctionGen{Function(optionalTagName, ShortCircuit|NonError, optionalValueValidator)}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasZeroDefault returns whether the field has a default value and whether
|
// hasZeroDefault returns whether the field has a default value and whether
|
||||||
@ -268,21 +268,21 @@ func (requirednessTagValidator) doForbidden(context Context) (Validations, error
|
|||||||
switch context.Type.Kind {
|
switch context.Type.Kind {
|
||||||
case types.Slice:
|
case types.Slice:
|
||||||
return Validations{
|
return Validations{
|
||||||
Functions: []FunctionGen{
|
Functions: []*FunctionGen{
|
||||||
Function(forbiddenTagName, ShortCircuit, forbiddenSliceValidator),
|
Function(forbiddenTagName, ShortCircuit, forbiddenSliceValidator),
|
||||||
Function(forbiddenTagName, ShortCircuit|NonError, optionalSliceValidator),
|
Function(forbiddenTagName, ShortCircuit|NonError, optionalSliceValidator),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case types.Map:
|
case types.Map:
|
||||||
return Validations{
|
return Validations{
|
||||||
Functions: []FunctionGen{
|
Functions: []*FunctionGen{
|
||||||
Function(forbiddenTagName, ShortCircuit, forbiddenMapValidator),
|
Function(forbiddenTagName, ShortCircuit, forbiddenMapValidator),
|
||||||
Function(forbiddenTagName, ShortCircuit|NonError, optionalMapValidator),
|
Function(forbiddenTagName, ShortCircuit|NonError, optionalMapValidator),
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case types.Pointer:
|
case types.Pointer:
|
||||||
return Validations{
|
return Validations{
|
||||||
Functions: []FunctionGen{
|
Functions: []*FunctionGen{
|
||||||
Function(forbiddenTagName, ShortCircuit, forbiddenPointerValidator),
|
Function(forbiddenTagName, ShortCircuit, forbiddenPointerValidator),
|
||||||
Function(forbiddenTagName, ShortCircuit|NonError, optionalPointerValidator),
|
Function(forbiddenTagName, ShortCircuit|NonError, optionalPointerValidator),
|
||||||
},
|
},
|
||||||
@ -296,7 +296,7 @@ func (requirednessTagValidator) doForbidden(context Context) (Validations, error
|
|||||||
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", forbiddenTagName)
|
return Validations{}, fmt.Errorf("non-pointer structs cannot use the %q tag", forbiddenTagName)
|
||||||
}
|
}
|
||||||
return Validations{
|
return Validations{
|
||||||
Functions: []FunctionGen{
|
Functions: []*FunctionGen{
|
||||||
Function(forbiddenTagName, ShortCircuit, forbiddenValueValidator),
|
Function(forbiddenTagName, ShortCircuit, forbiddenValueValidator),
|
||||||
Function(forbiddenTagName, ShortCircuit|NonError, optionalValueValidator),
|
Function(forbiddenTagName, ShortCircuit|NonError, optionalValueValidator),
|
||||||
},
|
},
|
||||||
|
@ -100,7 +100,7 @@ func (stv subfieldTagValidator) GetValidations(context Context, args []string, p
|
|||||||
Results: []ParamResult{{"", nilableFieldType}},
|
Results: []ParamResult{{"", nilableFieldType}},
|
||||||
}
|
}
|
||||||
getFn.Body = fmt.Sprintf("return %so.%s", fieldExprPrefix, submemb.Name)
|
getFn.Body = fmt.Sprintf("return %so.%s", fieldExprPrefix, submemb.Name)
|
||||||
f := Function(subfieldTagName, vfn.Flags(), validateSubfield, subname, getFn, WrapperFunction{vfn, submemb.Type})
|
f := Function(subfieldTagName, vfn.Flags, validateSubfield, subname, getFn, WrapperFunction{vfn, submemb.Type})
|
||||||
result.Functions = append(result.Functions, f)
|
result.Functions = append(result.Functions, f)
|
||||||
result.Variables = append(result.Variables, validations.Variables...)
|
result.Variables = append(result.Variables, validations.Variables...)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func (frtv fixedResultTagValidator) GetValidations(context Context, _ []string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return result, fmt.Errorf("can't decode tag payload: %w", err)
|
return result, fmt.Errorf("can't decode tag payload: %w", err)
|
||||||
}
|
}
|
||||||
result.AddFunction(GenericFunction(frtv.TagName(), tag.flags, fixedResultValidator, tag.typeArgs, frtv.result, tag.msg))
|
result.AddFunction(Function(frtv.TagName(), tag.flags, fixedResultValidator, frtv.result, tag.msg).WithTypeArgs(tag.typeArgs...))
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -207,13 +207,47 @@ type TagPayloadSchema struct {
|
|||||||
Default string
|
Default string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validations defines the function calls and variables to generate to perform validation.
|
// Validations defines the function calls and variables to generate to perform
|
||||||
|
// validation.
|
||||||
type Validations struct {
|
type Validations struct {
|
||||||
Functions []FunctionGen
|
// Functions holds the function calls that should be generated to perform
|
||||||
|
// validation. These functions may not be called in order - they may be
|
||||||
|
// sorted based on their flags and other criteria.
|
||||||
|
//
|
||||||
|
// Each function's signature must be of the form:
|
||||||
|
// func(
|
||||||
|
// // standard arguments
|
||||||
|
// ctx context.Context
|
||||||
|
// op operation.Operation,
|
||||||
|
// fldPath field.Path,
|
||||||
|
// value, oldValue <ValueType>, // always nilable
|
||||||
|
// // additional arguments (optional)
|
||||||
|
// Args[0] <Args[0]Type>,
|
||||||
|
// Args[1] <Args[1]Type>,
|
||||||
|
// ...
|
||||||
|
// Args[N] <Args[N]Type>)
|
||||||
|
//
|
||||||
|
// The standard arguments are not included in the FunctionGen.Args list.
|
||||||
|
Functions []*FunctionGen
|
||||||
|
|
||||||
|
// Variables holds any variables which must be generated to perform
|
||||||
|
// validation. Variables are not permitted in every context.
|
||||||
Variables []VariableGen
|
Variables []VariableGen
|
||||||
|
|
||||||
|
// Comments holds comments to emit (without the leanding "//").
|
||||||
Comments []string
|
Comments []string
|
||||||
|
|
||||||
|
// OpaqueType indicates that the type being validated is opaque, and that
|
||||||
|
// any validations defined on it should not be emitted.
|
||||||
OpaqueType bool
|
OpaqueType bool
|
||||||
|
|
||||||
|
// OpaqueKeyType indicates that the key type of a map being validated is
|
||||||
|
// opaque, and that any validations defined on it should not be emitted.
|
||||||
OpaqueKeyType bool
|
OpaqueKeyType bool
|
||||||
|
|
||||||
|
// OpaqueValType indicates that the key type of a map or slice being
|
||||||
|
// validated is opaque, and that any validations defined on it should not
|
||||||
|
// be emitted.
|
||||||
OpaqueValType bool
|
OpaqueValType bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +259,7 @@ func (v *Validations) Len() int {
|
|||||||
return len(v.Functions) + len(v.Variables) + len(v.Comments)
|
return len(v.Functions) + len(v.Variables) + len(v.Comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validations) AddFunction(f FunctionGen) {
|
func (v *Validations) AddFunction(f *FunctionGen) {
|
||||||
v.Functions = append(v.Functions, f)
|
v.Functions = append(v.Functions, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,46 +303,6 @@ const (
|
|||||||
NonError
|
NonError
|
||||||
)
|
)
|
||||||
|
|
||||||
// FunctionGen provides validation-gen with the information needed to generate a
|
|
||||||
// validation function invocation.
|
|
||||||
type FunctionGen interface {
|
|
||||||
// TagName returns the tag which triggers this validator.
|
|
||||||
TagName() string
|
|
||||||
|
|
||||||
// SignatureAndArgs returns the function name and all extraArg value literals that are passed when the function
|
|
||||||
// invocation is generated.
|
|
||||||
//
|
|
||||||
// The function signature must be of the form:
|
|
||||||
// func(op operation.Operation,
|
|
||||||
// fldPath field.Path,
|
|
||||||
// value, oldValue <ValueType>, // always nilable
|
|
||||||
// extraArgs[0] <extraArgs[0]Type>, // optional
|
|
||||||
// ...,
|
|
||||||
// extraArgs[N] <extraArgs[N]Type>)
|
|
||||||
//
|
|
||||||
// extraArgs may contain:
|
|
||||||
// - data literals comprised of maps, slices, strings, ints, floats and bools
|
|
||||||
// - references, represented by types.Type (to reference any type in the universe), and types.Member (to reference members of the current value)
|
|
||||||
//
|
|
||||||
// If validation function to be called does not have a signature of this form, please introduce
|
|
||||||
// a function that does and use that function to call the validation function.
|
|
||||||
SignatureAndArgs() (function types.Name, extraArgs []any)
|
|
||||||
|
|
||||||
// TypeArgs assigns types to the type parameters of the function, for invocation.
|
|
||||||
TypeArgs() []types.Name
|
|
||||||
|
|
||||||
// Flags returns the options for this validator function.
|
|
||||||
Flags() FunctionFlags
|
|
||||||
|
|
||||||
// Conditions returns the conditions that must true for a resource to be
|
|
||||||
// validated by this function.
|
|
||||||
Conditions() Conditions
|
|
||||||
|
|
||||||
// Comments returns optional comments that should be added to the generated
|
|
||||||
// code (without the leading "//").
|
|
||||||
Comments() []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conditions defines what conditions must be true for a resource to be validated.
|
// Conditions defines what conditions must be true for a resource to be validated.
|
||||||
// If any of the conditions are not true, the resource is not validated.
|
// If any of the conditions are not true, the resource is not validated.
|
||||||
type Conditions struct {
|
type Conditions struct {
|
||||||
@ -342,83 +336,76 @@ type VariableGen interface {
|
|||||||
Var() PrivateVar
|
Var() PrivateVar
|
||||||
|
|
||||||
// Init generates the function call that the variable is assigned to.
|
// Init generates the function call that the variable is assigned to.
|
||||||
Init() FunctionGen
|
Init() *FunctionGen
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function creates a FunctionGen for a given function name and extraArgs.
|
// Function creates a FunctionGen for a given function name and extraArgs.
|
||||||
func Function(tagName string, flags FunctionFlags, function types.Name, extraArgs ...any) FunctionGen {
|
func Function(tagName string, flags FunctionFlags, function types.Name, extraArgs ...any) *FunctionGen {
|
||||||
return GenericFunction(tagName, flags, function, nil, extraArgs...)
|
return &FunctionGen{
|
||||||
}
|
TagName: tagName,
|
||||||
|
Flags: flags,
|
||||||
func GenericFunction(tagName string, flags FunctionFlags, function types.Name, typeArgs []types.Name, extraArgs ...any) FunctionGen {
|
Function: function,
|
||||||
// Callers of Signature don't care if the args are all of a known type, it just
|
Args: extraArgs,
|
||||||
// makes it easier to declare validators.
|
|
||||||
var anyArgs []any
|
|
||||||
if len(extraArgs) > 0 {
|
|
||||||
anyArgs = make([]any, len(extraArgs))
|
|
||||||
copy(anyArgs, extraArgs)
|
|
||||||
}
|
|
||||||
return &functionGen{tagName: tagName, flags: flags, function: function, extraArgs: anyArgs, typeArgs: typeArgs}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithCondition adds a condition to a FunctionGen.
|
|
||||||
func WithCondition(fn FunctionGen, conditions Conditions) FunctionGen {
|
|
||||||
name, args := fn.SignatureAndArgs()
|
|
||||||
return &functionGen{
|
|
||||||
tagName: fn.TagName(),
|
|
||||||
flags: fn.Flags(),
|
|
||||||
function: name,
|
|
||||||
extraArgs: args,
|
|
||||||
typeArgs: fn.TypeArgs(),
|
|
||||||
comments: fn.Comments(),
|
|
||||||
conditions: conditions,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithComment adds a comment to a FunctionGen.
|
// FunctionGen describes a function call that should be generated.
|
||||||
func WithComment(fn FunctionGen, comment string) FunctionGen {
|
type FunctionGen struct {
|
||||||
name, args := fn.SignatureAndArgs()
|
// TagName is the tag which triggered this function.
|
||||||
return &functionGen{
|
TagName string
|
||||||
tagName: fn.TagName(),
|
|
||||||
flags: fn.Flags(),
|
// Flags holds the options for this validator function.
|
||||||
function: name,
|
Flags FunctionFlags
|
||||||
extraArgs: args,
|
|
||||||
typeArgs: fn.TypeArgs(),
|
// Function is the name of the function to call.
|
||||||
comments: append(fn.Comments(), comment),
|
Function types.Name
|
||||||
conditions: fn.Conditions(),
|
|
||||||
}
|
// Args holds arguments to pass to the function, and may conatin:
|
||||||
|
// - data literals comprised of maps, slices, strings, ints, floats, and bools
|
||||||
|
// - types.Type (to reference any type in the universe)
|
||||||
|
// - types.Member (to reference members of the current value)
|
||||||
|
// - types.Identifier (to reference any identifier in the universe)
|
||||||
|
// - validators.WrapperFunction (to call another validation function)
|
||||||
|
// - validators.Literal (to pass a literal value)
|
||||||
|
// - validators.FunctionLiteral (to pass a function literal)
|
||||||
|
// - validators.PrivateVar (to reference a variable)
|
||||||
|
//
|
||||||
|
// See toGolangSourceDataLiteral for details.
|
||||||
|
Args []any
|
||||||
|
|
||||||
|
// TypeArgs assigns types to the type parameters of the function, for
|
||||||
|
// generic function calls which require explicit type arguments.
|
||||||
|
TypeArgs []types.Name
|
||||||
|
|
||||||
|
// Conditions holds any conditions that must true for a field to be
|
||||||
|
// validated by this function.
|
||||||
|
Conditions Conditions
|
||||||
|
|
||||||
|
// Comments holds optional comments that should be added to the generated
|
||||||
|
// code (without the leading "//").
|
||||||
|
Comments []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type functionGen struct {
|
// WithTypeArgs sets the type arguments for a FunctionGen.
|
||||||
tagName string
|
func (fg *FunctionGen) WithTypeArgs(typeArgs ...types.Name) *FunctionGen {
|
||||||
function types.Name
|
fg.TypeArgs = typeArgs
|
||||||
extraArgs []any
|
return fg
|
||||||
typeArgs []types.Name
|
|
||||||
flags FunctionFlags
|
|
||||||
conditions Conditions
|
|
||||||
comments []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *functionGen) TagName() string {
|
// WithConditions sets the conditions for a FunctionGen.
|
||||||
return v.tagName
|
func (fg *FunctionGen) WithConditions(conditions Conditions) *FunctionGen {
|
||||||
|
fg.Conditions = conditions
|
||||||
|
return fg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *functionGen) SignatureAndArgs() (function types.Name, args []any) {
|
// AddComment adds a comment to a FunctionGen.
|
||||||
return v.function, v.extraArgs
|
func (fg *FunctionGen) AddComment(comment string) *FunctionGen {
|
||||||
|
fg.Comments = append(fg.Comments, comment)
|
||||||
|
return fg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *functionGen) TypeArgs() []types.Name { return v.typeArgs }
|
|
||||||
|
|
||||||
func (v *functionGen) Flags() FunctionFlags {
|
|
||||||
return v.flags
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *functionGen) Conditions() Conditions { return v.conditions }
|
|
||||||
|
|
||||||
func (v *functionGen) Comments() []string { return v.comments }
|
|
||||||
|
|
||||||
// Variable creates a VariableGen for a given function name and extraArgs.
|
// Variable creates a VariableGen for a given function name and extraArgs.
|
||||||
func Variable(variable PrivateVar, init FunctionGen) VariableGen {
|
func Variable(variable PrivateVar, init *FunctionGen) VariableGen {
|
||||||
return &variableGen{
|
return &variableGen{
|
||||||
variable: variable,
|
variable: variable,
|
||||||
init: init,
|
init: init,
|
||||||
@ -427,18 +414,18 @@ func Variable(variable PrivateVar, init FunctionGen) VariableGen {
|
|||||||
|
|
||||||
type variableGen struct {
|
type variableGen struct {
|
||||||
variable PrivateVar
|
variable PrivateVar
|
||||||
init FunctionGen
|
init *FunctionGen
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v variableGen) TagName() string {
|
func (v variableGen) TagName() string {
|
||||||
return v.init.TagName()
|
return v.init.TagName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v variableGen) Var() PrivateVar {
|
func (v variableGen) Var() PrivateVar {
|
||||||
return v.variable
|
return v.variable
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v variableGen) Init() FunctionGen {
|
func (v variableGen) Init() *FunctionGen {
|
||||||
return v.init
|
return v.init
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +433,7 @@ func (v variableGen) Init() FunctionGen {
|
|||||||
// regular validation function (op, fldPath, obj, oldObj) and calls another
|
// regular validation function (op, fldPath, obj, oldObj) and calls another
|
||||||
// validation function with the same signature, plus extra args if needed.
|
// validation function with the same signature, plus extra args if needed.
|
||||||
type WrapperFunction struct {
|
type WrapperFunction struct {
|
||||||
Function FunctionGen
|
Function *FunctionGen
|
||||||
ObjType *types.Type
|
ObjType *types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user