|
|
@@ -24,6 +24,24 @@ public struct AutoCodableMacro: MemberMacro {
|
|
|
return []
|
|
|
}
|
|
|
|
|
|
+ // 解析类型遵循的协议列表
|
|
|
+ let inheritedProtocols = typeDecl.inheritanceClause?.inheritedTypes
|
|
|
+ .compactMap { $0.type.as(IdentifierTypeSyntax.self)?.name.text } ?? []
|
|
|
+
|
|
|
+ // 判断是否遵循 Codable/Decodable/Encodable
|
|
|
+ let conformsToCodable = inheritedProtocols.contains("Codable")
|
|
|
+ let conformsToDecodable = inheritedProtocols.contains("Decodable") || conformsToCodable
|
|
|
+ let conformsToEncodable = inheritedProtocols.contains("Encodable") || conformsToCodable
|
|
|
+
|
|
|
+ // 校验:至少遵循一个协议,否则报错
|
|
|
+ guard conformsToDecodable || conformsToEncodable else {
|
|
|
+ context.diagnose(Diagnostic(
|
|
|
+ node: node,
|
|
|
+ message: AutoCodableMacroError.protocolError
|
|
|
+ ))
|
|
|
+ return []
|
|
|
+ }
|
|
|
+
|
|
|
// 提取所有存储属性
|
|
|
let properties: [(name: String, type: String)] = typeDecl.memberBlock.members.compactMap { member -> (name: String, type: String)? in
|
|
|
// 1. 检查是否是变量声明
|
|
|
@@ -61,43 +79,47 @@ public struct AutoCodableMacro: MemberMacro {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+ var syntax: [DeclSyntax] = []
|
|
|
// 生成 CodingKeys 枚举
|
|
|
let codingKeys = try EnumDeclSyntax("enum CodingKeys: String, CodingKey") {
|
|
|
for property in properties {
|
|
|
DeclSyntax("case \(raw: property.name)")
|
|
|
}
|
|
|
}
|
|
|
+ syntax.append(DeclSyntax(codingKeys))
|
|
|
|
|
|
- // 生成 init(from:) 方法
|
|
|
- let bodyBuilder: SyntaxNodeString = declaration is ClassDeclSyntax ? "required init(from decoder: Decoder) throws" : "init(from decoder: Decoder) throws"
|
|
|
- let initFrom = try InitializerDeclSyntax(bodyBuilder) {
|
|
|
- CodeBlockItemListSyntax {
|
|
|
- "let container = try decoder.container(keyedBy: CodingKeys.self)"
|
|
|
- for property in properties {
|
|
|
+ if conformsToDecodable {
|
|
|
+ // 生成 init(from:) 方法
|
|
|
+ let bodyBuilder: SyntaxNodeString = declaration is ClassDeclSyntax ? "required init(from decoder: Decoder) throws" : "init(from decoder: Decoder) throws"
|
|
|
+ let initFrom = try InitializerDeclSyntax(bodyBuilder) {
|
|
|
+ CodeBlockItemListSyntax {
|
|
|
+ "let container = try decoder.container(keyedBy: CodingKeys.self)"
|
|
|
+ for property in properties {
|
|
|
"""
|
|
|
if let value = try? container.decode(\(raw: property.type).self, forKey: .\(raw: property.name)) {
|
|
|
self.\(raw: property.name) = value
|
|
|
}
|
|
|
"""
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ syntax.append(DeclSyntax(initFrom))
|
|
|
}
|
|
|
|
|
|
- // 生成 encode(to:) 方法
|
|
|
- let encodeTo = try FunctionDeclSyntax("func encode(to encoder: Encoder) throws") {
|
|
|
- CodeBlockItemListSyntax {
|
|
|
- "var container = encoder.container(keyedBy: CodingKeys.self)"
|
|
|
- for property in properties {
|
|
|
- "try container.encode(\(raw: property.name), forKey: .\(raw: property.name))"
|
|
|
+ if conformsToEncodable {
|
|
|
+ // 生成 encode(to:) 方法
|
|
|
+ let encodeTo = try FunctionDeclSyntax("func encode(to encoder: Encoder) throws") {
|
|
|
+ CodeBlockItemListSyntax {
|
|
|
+ "var container = encoder.container(keyedBy: CodingKeys.self)"
|
|
|
+ for property in properties {
|
|
|
+ "try container.encode(\(raw: property.name), forKey: .\(raw: property.name))"
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ syntax.append(DeclSyntax(encodeTo))
|
|
|
}
|
|
|
|
|
|
- return [
|
|
|
- DeclSyntax(codingKeys),
|
|
|
- DeclSyntax(initFrom),
|
|
|
- DeclSyntax(encodeTo)
|
|
|
- ]
|
|
|
+ return syntax
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -105,6 +127,7 @@ public struct AutoCodableMacro: MemberMacro {
|
|
|
enum AutoCodableMacroError: DiagnosticMessage {
|
|
|
case onlyClassesAndStructs
|
|
|
case noStoredProperties
|
|
|
+ case protocolError
|
|
|
|
|
|
var message: String {
|
|
|
switch self {
|
|
|
@@ -112,6 +135,8 @@ enum AutoCodableMacroError: DiagnosticMessage {
|
|
|
"AutoCodable can only be applied to classes and structs"
|
|
|
case .noStoredProperties:
|
|
|
"Type has no stored properties; Codable implementation will be empty"
|
|
|
+ case .protocolError:
|
|
|
+ "类型必须遵循 Codable、Decodable 或 Encodable"
|
|
|
}
|
|
|
}
|
|
|
|