diff --git a/Sources/ForkedModel/Macros.swift b/Sources/ForkedModel/Macros.swift index 38efa09..e4c3ef8 100644 --- a/Sources/ForkedModel/Macros.swift +++ b/Sources/ForkedModel/Macros.swift @@ -4,7 +4,7 @@ import ForkedMerge public typealias Mergeable = Forked.Mergeable -@attached(`extension`, names: arbitrary, conformances: Mergeable, VersionedModel) +@attached(`extension`, conformances: Mergeable, VersionedModel, names: arbitrary) @attached(member, names: arbitrary) public macro ForkedModel(version: Int? = nil) = #externalMacro(module: "ForkedModelMacros", type: "ForkedModelMacro") diff --git a/Sources/ForkedModelMacros/ForkedModelMacro.swift b/Sources/ForkedModelMacros/ForkedModelMacro.swift index bcb385c..9d143a9 100644 --- a/Sources/ForkedModelMacros/ForkedModelMacro.swift +++ b/Sources/ForkedModelMacros/ForkedModelMacro.swift @@ -46,19 +46,7 @@ public struct ForkedModelMacro: ExtensionMacro, MemberMacro { providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { - // Extract version if provided - var version: Int? = nil - if let argumentList = node.arguments?.as(LabeledExprListSyntax.self) { - for argument in argumentList { - if argument.label?.text == versionLabel, - let integerExpr = argument.expression.as(IntegerLiteralExprSyntax.self) { - version = Int(integerExpr.literal.text) - } - } - } - - // If version is provided, add modelVersion property and currentModelVersion - if let version { + if let version = extractVersion(from: node) { // Check if struct conforms to VersionedModel if let structDecl = declaration.as(StructDeclSyntax.self) { let conformsToVersionedModel = structDecl.inheritanceClause?.inheritedTypes.contains { @@ -143,7 +131,12 @@ public struct ForkedModelMacro: ExtensionMacro, MemberMacro { // If version is provided, also generate VersionedModel extension if let version = extractVersion(from: node) { - return [mergeableExtension] // VersionedModel conformance is handled by the member macro + let versionedModelExtension = try ExtensionDeclSyntax( + """ + extension \(type.trimmed): Forked.VersionedModel {} + """ + ) + return [mergeableExtension, versionedModelExtension] } return [mergeableExtension] @@ -256,21 +249,26 @@ public struct ForkedModelMacro: ExtensionMacro, MemberMacro { providingConformancesOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] { - // Extract version if provided - var version: Int? = nil - if let argumentList = node.arguments?.as(LabeledExprListSyntax.self) { - for argument in argumentList { - if argument.label?.text == versionLabel, - let integerExpr = argument.expression.as(IntegerLiteralExprSyntax.self) { - version = Int(integerExpr.literal.text) - } - } + if extractVersion(from: node) != nil { + // Create a proper TypeSyntax for VersionedModel + return [(TypeSyntax("Forked.VersionedModel"), nil)] + } + return [] + } + + private static func extractVersion(from node: AttributeSyntax) -> Int? { + guard let argumentList = node.arguments?.as(LabeledExprListSyntax.self) else { + return nil } - if version != nil { - return [("VersionedModel", nil)] + for argument in argumentList { + if argument.label?.text == versionLabel, + let integerExpr = argument.expression.as(IntegerLiteralExprSyntax.self) { + return Int(integerExpr.literal.text) + } } - return [] + + return nil } } diff --git a/Tests/ForkedTests/ForkedModelMacros.swift b/Tests/ForkedTests/ForkedModelMacros.swift index 2da19a8..d16b6f7 100644 --- a/Tests/ForkedTests/ForkedModelMacros.swift +++ b/Tests/ForkedTests/ForkedModelMacros.swift @@ -564,24 +564,25 @@ final class ForkedModelMacrosSuite: XCTestCase { expandedSource: """ struct User { + var name: String = "" + public static let currentModelVersion: Int = 1 public var modelVersion: Int? = Self.currentModelVersion - var name: String = "" } extension User: Forked.Mergeable { public func merged(withSubordinate other: Self, commonAncestor: Self) throws -> Self { var merged = self if self.name == commonAncestor.name { - merged.name = other.name + merged.name = other.name } else { - merged.name = self.name + merged.name = self.name } return merged } } - extension User: VersionedModel { + extension User: Forked.VersionedModel { } """, macros: Self.testMacros