| 80 | } |
| 81 | |
| 82 | func checkUnion(typeToCheck *markers.TypeInfo, root *loader.Package, packageTypes map[string]*markers.TypeInfo) { |
| 83 | if typeToCheck.Markers.Get(genutils.UnionMarker.Name) == nil { |
| 84 | return |
| 85 | } |
| 86 | |
| 87 | unionMembers := []string{} |
| 88 | var unionDiscriminatorField *markers.FieldInfo |
| 89 | for index, unionField := range typeToCheck.Fields { |
| 90 | if unionField.Markers.Get(genutils.UnionDiscriminatorMarker.Name) != nil { |
| 91 | if unionDiscriminatorField != nil { |
| 92 | root.AddError(loader.ErrFromNode(fmt.Errorf( |
| 93 | "union `%v` should have only 1 union discriminator, but has 2: `%v` and `%v`", |
| 94 | typeToCheck.Name, |
| 95 | unionDiscriminatorField.Name, |
| 96 | unionField.Name), unionField.RawField)) |
| 97 | } |
| 98 | unionDiscriminatorField = &(typeToCheck.Fields[index]) |
| 99 | } else { |
| 100 | unionMembers = append(unionMembers, unionField.Name) |
| 101 | } |
| 102 | } |
| 103 | if unionDiscriminatorField == nil { |
| 104 | root.AddError(loader.ErrFromNode(fmt.Errorf( |
| 105 | "union `%v` should have 1 union discriminator. See here for details: https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190325-unions.md#proposal", |
| 106 | typeToCheck.Name), typeToCheck.RawSpec)) |
| 107 | return |
| 108 | } |
| 109 | |
| 110 | if unionDiscriminatorField.Markers.Get("optional") == nil { |
| 111 | root.AddError(loader.ErrFromNode(fmt.Errorf( |
| 112 | "in union `%v` the union discriminator `%v` should have the `+optional` comment marker", |
| 113 | typeToCheck.Name, |
| 114 | unionDiscriminatorField.Name), unionDiscriminatorField.RawField)) |
| 115 | } |
| 116 | if !strings.Contains(unionDiscriminatorField.Tag.Get("json"), ",omitempty") { |
| 117 | root.AddError(loader.ErrFromNode(fmt.Errorf( |
| 118 | "in union `%v` the union discriminator `%v` should contain the `omitempty` option in its `json` tag, since it is expected to be an optional field", |
| 119 | typeToCheck.Name, |
| 120 | unionDiscriminatorField.Name), unionDiscriminatorField.RawField)) |
| 121 | } |
| 122 | |
| 123 | wrongTypeError := loader.ErrFromNode(fmt.Errorf( |
| 124 | "in union `%v` the union discriminator `%v` should have a `string` type, or a type (defined in the same package) whose underlying type is a string", |
| 125 | typeToCheck.Name, |
| 126 | unionDiscriminatorField.Name), unionDiscriminatorField.RawField) |
| 127 | |
| 128 | discriminatorTypeRef, typeFound := root.TypesInfo.Types[unionDiscriminatorField.RawField.Type] |
| 129 | if !typeFound { |
| 130 | root.AddError(wrongTypeError) |
| 131 | return |
| 132 | } |
| 133 | |
| 134 | underlyingType, underlyingTypeIsBasic := discriminatorTypeRef.Type.Underlying().(*types.Basic) |
| 135 | if !underlyingTypeIsBasic || underlyingType.Kind() != types.String { |
| 136 | root.AddError(wrongTypeError) |
| 137 | return |
| 138 | } |
| 139 | |