1
+ import SwiftSyntax
2
+ import SwiftSyntaxMacros
3
+
4
+ private extension DeclSyntaxProtocol {
5
+ var isObservableStoredProperty : Bool {
6
+ guard let property = self . as ( VariableDeclSyntax . self) ,
7
+ let binding = property. bindings. first
8
+ else {
9
+ return false
10
+ }
11
+
12
+ return binding. accessor == nil
13
+ }
14
+ }
15
+
16
+ public struct ObservableMacro : MemberMacro , MemberAttributeMacro {
17
+
18
+ // MARK: - MemberMacro
19
+ public static func expansion(
20
+ of node: AttributeSyntax ,
21
+ providingMembersOf declaration: some DeclGroupSyntax ,
22
+ in context: some MacroExpansionContext
23
+ ) throws -> [ DeclSyntax ] {
24
+ guard let identified = declaration. asProtocol ( IdentifiedDeclSyntax . self) else {
25
+ return [ ]
26
+ }
27
+
28
+ let parentName = identified. identifier
29
+
30
+ let registrar : DeclSyntax =
31
+ """
32
+ let _registrar = ObservationRegistrar< \( parentName) >()
33
+ """
34
+
35
+ let transactions : DeclSyntax =
36
+ """
37
+ public nonisolated func transactions<Delivery>(for keyPaths: KeyPaths< \( parentName) >, isolation: Delivery) -> ObservedTransactions< \( parentName) , Delivery> where Delivery: Actor {
38
+ _registrar.transactions(for: keyPaths, isolation: isolation)
39
+ }
40
+ """
41
+
42
+ let changes : DeclSyntax =
43
+ """
44
+ public nonisolated func changes<Member>(for keyPath: KeyPath< \( parentName) , Member>) -> ObservedChanges< \( parentName) , Member> where Member: Sendable {
45
+ _registrar.changes(for: keyPath)
46
+ }
47
+ """
48
+
49
+ let memberList = MemberDeclListSyntax (
50
+ declaration. members. members. filter {
51
+ $0. decl. isObservableStoredProperty
52
+ }
53
+ )
54
+
55
+ let storageStruct : DeclSyntax =
56
+ """
57
+ private struct _Storage {
58
+ \( memberList)
59
+ }
60
+ """
61
+
62
+ let storage : DeclSyntax =
63
+ """
64
+ private var _storage = _Storage()
65
+ """
66
+
67
+ return [
68
+ registrar,
69
+ transactions,
70
+ changes,
71
+ storageStruct,
72
+ storage,
73
+ ]
74
+ }
75
+
76
+ // MARK: - MemberAttributeMacro
77
+ public static func expansion(
78
+ of node: AttributeSyntax ,
79
+ attachedTo declaration: some DeclGroupSyntax ,
80
+ providingAttributesFor member: DeclSyntax ,
81
+ in context: some MacroExpansionContext
82
+ ) throws -> [ SwiftSyntax . AttributeSyntax ] {
83
+ guard member. isObservableStoredProperty else {
84
+ return [ ]
85
+ }
86
+
87
+ return [
88
+ AttributeSyntax (
89
+ attributeName: SimpleTypeIdentifierSyntax (
90
+ name: . identifier( " ObservableProperty " )
91
+ )
92
+ )
93
+ ]
94
+ }
95
+ }
96
+
97
+ public struct ObservablePropertyMacro : AccessorMacro {
98
+ public static func expansion(
99
+ of node: AttributeSyntax ,
100
+ providingAccessorsOf declaration: some DeclSyntaxProtocol ,
101
+ in context: some MacroExpansionContext
102
+ ) throws -> [ AccessorDeclSyntax ] {
103
+ guard let property = declaration. as ( VariableDeclSyntax . self) ,
104
+ let binding = property. bindings. first,
105
+ let identifier = binding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier,
106
+ binding. accessor == nil
107
+ else {
108
+ return [ ]
109
+ }
110
+
111
+ if identifier. text == " _registrar " || identifier. text == " _storage " { return [ ] }
112
+
113
+ let getAccessor : AccessorDeclSyntax =
114
+ """
115
+ get {
116
+ _registrar.access(self, keyPath: \\ . \( identifier) )
117
+ return _storage. \( identifier)
118
+ }
119
+ """
120
+
121
+ let setAccessor : AccessorDeclSyntax =
122
+ """
123
+ set {
124
+ _registrar.withMutation(self, keyPath: \\ . \( identifier) ) {
125
+ _storage. \( identifier) = newValue
126
+ }
127
+ }
128
+ """
129
+
130
+ return [ getAccessor, setAccessor]
131
+ }
132
+ }
0 commit comments