@@ -23,6 +23,23 @@ enum RawEnumBackingType {
2323 case integer
2424}
2525
26+ /// The extracted enum value.
27+ private enum EnumValue : Hashable , CustomStringConvertible {
28+
29+ /// A string value.
30+ case string( String )
31+
32+ /// An integer value.
33+ case integer( Int )
34+
35+ var description : String {
36+ switch self {
37+ case . string( let value) : return " \" \( value) \" "
38+ case . integer( let value) : return String ( value)
39+ }
40+ }
41+ }
42+
2643extension FileTranslator {
2744
2845 /// Returns a declaration of the specified raw value-based enum schema.
@@ -42,32 +59,48 @@ extension FileTranslator {
4259 isNullable: Bool ,
4360 allowedValues: [ AnyCodable ]
4461 ) throws -> Declaration {
45- let cases : [ ( String , LiteralDescription ) ] = try allowedValues. map ( \. value)
46- . map { anyValue in
47- switch backingType {
48- case . string:
49- // In nullable enum schemas, empty strings are parsed as Void.
50- // This is unlikely to be fixed, so handling that case here.
51- // https://github.com/apple/swift-openapi-generator/issues/118
52- if isNullable && anyValue is Void { return ( context. asSwiftSafeName ( " " ) , . string( " " ) ) }
62+ var seen : Set < EnumValue > = [ ]
63+ var cases : [ ( String , LiteralDescription ) ] = [ ]
64+ func shouldAdd( _ value: EnumValue ) throws -> Bool {
65+ guard seen. insert ( value) . inserted else {
66+ try diagnostics. emit (
67+ . warning(
68+ message: " Duplicate enum value, skipping " ,
69+ context: [ " value " : " \( value) " , " foundIn " : typeName. description]
70+ )
71+ )
72+ return false
73+ }
74+ return true
75+ }
76+ for anyValue in allowedValues. map ( \. value) {
77+ switch backingType {
78+ case . string:
79+ // In nullable enum schemas, empty strings are parsed as Void.
80+ // This is unlikely to be fixed, so handling that case here.
81+ // https://github.com/apple/swift-openapi-generator/issues/118
82+ if isNullable && anyValue is Void {
83+ if try shouldAdd ( . string( " " ) ) { cases. append ( ( context. asSwiftSafeName ( " " ) , . string( " " ) ) ) }
84+ } else {
5385 guard let rawValue = anyValue as? String else {
5486 throw GenericError ( message: " Disallowed value for a string enum ' \( typeName) ': \( anyValue) " )
5587 }
5688 let caseName = context. asSwiftSafeName ( rawValue)
57- return ( caseName, . string( rawValue) )
58- case . integer:
59- let rawValue : Int
60- if let intRawValue = anyValue as? Int {
61- rawValue = intRawValue
62- } else if let stringRawValue = anyValue as? String , let intRawValue = Int ( stringRawValue) {
63- rawValue = intRawValue
64- } else {
65- throw GenericError ( message: " Disallowed value for an integer enum ' \( typeName) ': \( anyValue) " )
66- }
67- let caseName = rawValue < 0 ? " _n \( abs ( rawValue) ) " : " _ \( rawValue) "
68- return ( caseName, . int( rawValue) )
89+ if try shouldAdd ( . string( rawValue) ) { cases. append ( ( caseName, . string( rawValue) ) ) }
90+ }
91+ case . integer:
92+ let rawValue : Int
93+ if let intRawValue = anyValue as? Int {
94+ rawValue = intRawValue
95+ } else if let stringRawValue = anyValue as? String , let intRawValue = Int ( stringRawValue) {
96+ rawValue = intRawValue
97+ } else {
98+ throw GenericError ( message: " Disallowed value for an integer enum ' \( typeName) ': \( anyValue) " )
6999 }
100+ let caseName = rawValue < 0 ? " _n \( abs ( rawValue) ) " : " _ \( rawValue) "
101+ if try shouldAdd ( . integer( rawValue) ) { cases. append ( ( caseName, . int( rawValue) ) ) }
70102 }
103+ }
71104 let baseConformance : String
72105 switch backingType {
73106 case . string: baseConformance = Constants . RawEnum. baseConformanceString
0 commit comments