Skip to content

Commit d169f5a

Browse files
committed
Compatible with SwiftData
support optional wiseInit: @codable(wiseInit: false) support variable FunctionCallExpr type: `var subModel = SubModel(subName: "", subAge: 0)` fix @model @codable mixed usage may cause crashes
1 parent 1856b3c commit d169f5a

5 files changed

Lines changed: 28 additions & 16 deletions

File tree

Sources/CodableWrapper/CodableWrapperMacros.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@attached(member, names: named(init(from:)), named(encode(to:)), arbitrary)
22
@attached(extension, conformances: Codable)
3-
public macro Codable() = #externalMacro(module: "CodableWrapperMacros", type: "Codable")
3+
public macro Codable(wiseInit: Bool = true) = #externalMacro(module: "CodableWrapperMacros", type: "Codable")
44

55
@attached(member, names: named(init(from:)), named(encode(to:)), arbitrary)
66
public macro CodableSubclass() = #externalMacro(module: "CodableWrapperMacros", type: "CodableSubclass")

Sources/CodableWrapper/Decoder.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ public extension KeyedDecodingContainer where K == AnyCodingKey {
2424
}
2525

2626
private extension KeyedDecodingContainer where K == AnyCodingKey {
27-
func tryNormalKeyDecode<Value>(type: Value.Type, key: String) -> Value? {
27+
func tryNormalKeyDecode<Value: Decodable>(type: Value.Type, key: String) -> Value? {
2828
func _decode(key: String) -> Value? {
2929
guard let key = Key(stringValue: key) else {
3030
return nil
3131
}
32+
if let value = try? decodeIfPresent(type, forKey: key) {
33+
return value
34+
}
3235
let value = try? decodeIfPresent(AnyDecodable.self, forKey: key)?.value
3336
if let value = value {
3437
if let converted = value as? Value {
@@ -37,10 +40,8 @@ private extension KeyedDecodingContainer where K == AnyCodingKey {
3740
if let _bridged = (Value.self as? _BuiltInBridgeType.Type)?._transform(from: value), let __bridged = _bridged as? Value {
3841
return __bridged
3942
}
40-
if let valueType = Value.self as? Decodable.Type {
41-
if let value = try? valueType.decode(from: self, forKey: key) as? Value {
42-
return value
43-
}
43+
if let value = try? Value.decode(from: self, forKey: key) {
44+
return value
4445
}
4546
}
4647
return nil
@@ -54,7 +55,7 @@ private extension KeyedDecodingContainer where K == AnyCodingKey {
5455
return nil
5556
}
5657

57-
private func tryNestedKeyDecode<Value>(type: Value.Type, key: String) -> Value? {
58+
private func tryNestedKeyDecode<Value: Decodable>(type: Value.Type, key: String) -> Value? {
5859
var keyComps = key.components(separatedBy: ".")
5960
guard let rootKey = AnyCodingKey(stringValue: keyComps.removeFirst()) else {
6061
return nil

Sources/CodableWrapperMacros/Codable.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import SwiftSyntaxMacros
44
public struct Codable: ExtensionMacro, MemberMacro {
55
public static func expansion(of node: AttributeSyntax,
66
attachedTo declaration: some DeclGroupSyntax,
7-
providingExtensionsOf type: some TypeSyntaxProtocol,
7+
providingExtensionsOf type: some TypeSyntaxProtocol,
88
conformingTo protocols: [TypeSyntax], in context: some MacroExpansionContext) throws -> [ExtensionDeclSyntax] {
99
var inheritedTypes: InheritedTypeListSyntax?
1010
if let declaration = declaration.as(StructDeclSyntax.self) {
@@ -15,8 +15,7 @@ public struct Codable: ExtensionMacro, MemberMacro {
1515
throw ASTError("use @Codable in `struct` or `class`")
1616
}
1717
if let inheritedTypes = inheritedTypes,
18-
inheritedTypes.contains(where: { inherited in inherited.type.trimmedDescription == "Codable" })
19-
{
18+
inheritedTypes.contains(where: { inherited in inherited.type.trimmedDescription == "Codable" }) {
2019
return []
2120
}
2221

@@ -30,14 +29,23 @@ public struct Codable: ExtensionMacro, MemberMacro {
3029

3130
public static func expansion(of node: SwiftSyntax.AttributeSyntax,
3231
providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax,
33-
in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax]
34-
{
32+
in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] {
3533
// TODO: diagnostic do not implement `init(from:)` or `encode(to:))`
3634

3735
let propertyContainer = try ModelMemberPropertyContainer(decl: declaration, context: context)
3836
let decoder = try propertyContainer.genDecoderInitializer(config: .init(isOverride: false))
3937
let encoder = try propertyContainer.genEncodeFunction(config: .init(isOverride: false))
40-
let memberwiseInit = try propertyContainer.genMemberwiseInit(config: .init(isOverride: false))
41-
return [decoder, encoder, memberwiseInit]
38+
39+
var hasWiseInit = true
40+
if case let .argumentList(list) = node.arguments, list.first?.expression.description == "false" {
41+
hasWiseInit = false
42+
}
43+
44+
if !hasWiseInit {
45+
return [decoder, encoder]
46+
} else {
47+
let memberwiseInit = try propertyContainer.genMemberwiseInit(config: .init(isOverride: false))
48+
return [decoder, encoder, memberwiseInit]
49+
}
4250
}
4351
}

Sources/CodableWrapperMacros/ModelMemberPropertyContainer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ struct ModelMemberPropertyContainer {
9090

9191
return text
9292
} else {
93-
let body = "container.decode(type: Swift.type(of: self.\(member.name)), keys: [\(member.codingKeys.joined(separator: ", "))], nestedKeys: [\(member.nestedKeys.joined(separator: ", "))])"
93+
let body = "container.decode(type: \(member.type).self, keys: [\(member.codingKeys.joined(separator: ", "))], nestedKeys: [\(member.nestedKeys.joined(separator: ", "))])"
9494

9595
if let initializerExpr = member.initializerExpr {
9696
return "self.\(member.name) = (try? \(body)) ?? (\(initializerExpr))"

Sources/CodableWrapperMacros/VariableDeclSyntaxExtension.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension VariableDeclSyntax {
3434
}
3535

3636
var inferType: String? {
37-
var type = bindings.compactMap(\.typeAnnotation).first?.type.description
37+
var type: String? = bindings.compactMap(\.typeAnnotation).first?.type.trimmedDescription
3838
// try infer type
3939
if type == nil, let initExpr = bindings.compactMap(\.initializer).first?.value {
4040
if initExpr.is(StringLiteralExprSyntax.self) {
@@ -45,6 +45,9 @@ extension VariableDeclSyntax {
4545
type = "Double"
4646
} else if initExpr.is(BooleanLiteralExprSyntax.self) {
4747
type = "Bool"
48+
} else if let funcDecl = initExpr.as(FunctionCallExprSyntax.self),
49+
let declRef = funcDecl.calledExpression.as(DeclReferenceExprSyntax.self) {
50+
type = declRef.trimmedDescription
4851
}
4952
}
5053
return type

0 commit comments

Comments
 (0)