Skip to content

Commit 02743c9

Browse files
authored
feat(OPTR-37950): add string/int decoding resilience (#17)
1 parent 017de16 commit 02743c9

File tree

2 files changed

+84
-7
lines changed

2 files changed

+84
-7
lines changed

tools/EVA.SDK.Generator.V2/Commands/Generate/Outputs/swift/Resources/Mocks.swift

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ extension Dictionary where Value == ProductDetailsWrapper {
8787
}
8888
}
8989

90-
9190
struct ProductDetails: Codable {}
9291

9392
public enum Maybe<Wrapped> {
@@ -105,4 +104,47 @@ extension Maybe: ExpressibleByNilLiteral {
105104
public init(nilLiteral: ()) {
106105
self = .null
107106
}
108-
}
107+
}
108+
109+
protocol Wrapper {
110+
associatedtype Unwrapped
111+
var unwrapped: Unwrapped { get }
112+
}
113+
114+
struct StringWrapper: Codable, Hashable, Wrapper {
115+
var unwrapped: String
116+
}
117+
118+
struct IntWrapper: Codable, Hashable, Wrapper {
119+
var unwrapped: Int
120+
}
121+
122+
extension Array: Wrapper where Element: Wrapper {
123+
var unwrapped: [Element.Unwrapped] {
124+
[]
125+
}
126+
}
127+
128+
extension Maybe: Wrapper where Wrapped: Wrapper {
129+
var unwrapped: Maybe<Wrapped.Unwrapped> {
130+
.null
131+
}
132+
}
133+
134+
extension Dictionary: Wrapper where Value: Wrapper {
135+
var unwrapped: [Key: Value.Unwrapped] {
136+
[:]
137+
}
138+
}
139+
140+
extension EVACorePageConfig: Wrapper where T: Wrapper {
141+
var unwrapped: EVACorePageConfig<T.Unwrapped> {
142+
.init(Filter: Filter?.unwrapped, Limit: Limit, SortDirection: SortDirection, SortProperty: SortProperty, Start: Start)
143+
}
144+
}
145+
146+
extension EVACorePageTokenConfig: Wrapper where T: Wrapper {
147+
var unwrapped: EVACorePageTokenConfig<T.Unwrapped> {
148+
.init(Filter: Filter?.unwrapped, Limit: Limit)
149+
}
150+
}

tools/EVA.SDK.Generator.V2/Commands/Generate/Outputs/swift/SwiftOutput.cs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using EVA.SDK.Generator.V2.Commands.Generate.Transforms;
33
using EVA.SDK.Generator.V2.Helpers;
44
using Microsoft.Extensions.Logging;
5+
using System.Text.RegularExpressions;
56

67
namespace EVA.SDK.Generator.V2.Commands.Generate.Outputs.swift;
78

@@ -457,15 +458,33 @@ private static void WriteDecodeInit(TypeSpecification type, IndentedStringBuilde
457458
{
458459
var typeName = GetPropTypeName(value, key, typeContext, ctx);
459460
var typeNameNotNullable = GetPropTypeName(value, key, typeContext, ctx, true);
460-
typeNameNotNullable = typeNameNotNullable.Replace("ProductDetails", "ProductDetailsWrapper");
461-
typeName = typeName.Replace("ProductDetails", "ProductDetailsWrapper");
462461

463-
var containsProductDetails = typeNameNotNullable.Contains("ProductDetails");
462+
var postfix = string.Empty;
463+
var containsProductDetails = false;
464+
var isOptional = value.Type.Nullable || value.Deprecated != null || value.Skippable;
465+
466+
foreach (var t in new string[] { "ProductDetails", "String", "Int" })
467+
{
468+
var before = typeNameNotNullable;
469+
typeNameNotNullable = Regex.Replace(typeNameNotNullable, $@"\b{t}\b",$"{t}Wrapper");
470+
typeName = Regex.Replace(typeName, $@"\b{t}\b",$"{t}Wrapper");
471+
typeNameNotNullable = Regex.Replace(typeNameNotNullable, $"{t}Wrapper:",$"{t}:");
472+
typeName = Regex.Replace(typeName, $"{t}Wrapper:",$"{t}:");
473+
474+
if (before != typeNameNotNullable)
475+
{
476+
if (t == "ProductDetails")
477+
{
478+
containsProductDetails = true;
479+
}
480+
var property = t == "ProductDetails" ? "productDetails" : "unwrapped";
481+
postfix = (isOptional ? "?" : "") + "." + property;
482+
}
483+
}
484+
464485
// Check if we have a conflicting property defined that will "claim" our typename
465486
// This is usually the case for props name Date or Data
466487
var typePrefix = (type.Properties.ContainsKey(typeNameNotNullable) && !containsProductDetails) ? "Foundation." : string.Empty;
467-
var isOptional = value.Type.Nullable || value.Deprecated != null || value.Skippable;
468-
var postfix = containsProductDetails ? ((isOptional ? "?" : "") + ".productDetails") : string.Empty;
469488

470489
if (isOptional)
471490
{
@@ -582,6 +601,8 @@ private static void WriteNonFlagsEnum(TypeSpecification type, string typename, I
582601
output.WriteLine("default: self = .undocumented(codingKey.intValue ?? -1, codingKey.stringValue)");
583602
}
584603
}
604+
605+
WriteIntRawValueInit(output);
585606
}
586607

587608
output.WriteLine("}");
@@ -608,11 +629,25 @@ private static void WriteFlagsEnum(TypeSpecification type, string typename, Inde
608629
if (value == 0) continue;
609630
output.WriteLine($"public static let {name} = {typename}(rawValue: {value})");
610631
}
632+
633+
WriteIntRawValueInit(output);
611634
}
612635

613636
output.WriteLine("}");
614637
}
615638

639+
private static void WriteIntRawValueInit(IndentedStringBuilder output)
640+
{
641+
output.WriteLine();
642+
output.WriteLine("public init(from decoder: any Decoder) throws");
643+
using (output.BracedIndentation)
644+
{
645+
output.WriteLine("let container = try decoder.singleValueContainer()");
646+
output.WriteLine("let rawValue = try container.decode(IntWrapper.self).unwrapped");
647+
output.WriteLine("self.init(rawValue: rawValue)");
648+
}
649+
}
650+
616651
private static string GetPropTypeName(PropertySpecification ps, string name, string? typeContext, OutputContext<SwiftOptions> ctx, bool forceNotNullable = false, bool forceNullable = false)
617652
{
618653
var n = OptionalSuffix(ps.Type, forceNotNullable, forceNullable, ps.Skippable);

0 commit comments

Comments
 (0)