-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathCodedBy.swift
More file actions
109 lines (103 loc) · 3.98 KB
/
CodedBy.swift
File metadata and controls
109 lines (103 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import SwiftSyntax
/// Attribute type for `CodedBy` macro-attribute.
///
/// This type can validate`CodedBy` macro-attribute
/// usage and extract data for `Codable` macro to
/// generate implementation.
package struct CodedBy: PropertyAttribute {
/// The node syntax provided
/// during initialization.
let node: AttributeSyntax
/// The helper coding arguments provided.
var args: LabeledExprListSyntax {
node.arguments!.as(LabeledExprListSyntax.self)!
}
/// Creates a new instance with the provided node.
///
/// The initializer fails to create new instance if the name
/// of the provided node is different than this attribute.
///
/// - Parameter node: The attribute syntax to create with.
/// - Returns: Newly created attribute instance.
init?(from node: AttributeSyntax) {
guard
node.attributeName.as(IdentifierTypeSyntax.self)!
.name.text == Self.name
else { return nil }
self.node = node
}
/// Builds diagnoser that can validate this macro
/// attached declaration.
///
/// The following conditions are checked by the
/// built diagnoser:
/// * Macro usage is not duplicated for the same declaration.
/// * If attached declaration is enum/protocol declaration:
/// * This attribute must be combined with `Codable`
/// and `CodedAt` attribute.
/// * If macro has one argument provided:
/// * Attached declaration is a variable declaration.
/// * Attached declaration is not a static variable
/// declaration
/// * This attribute isn't used combined with
/// `IgnoreCoding` attribute.
///
/// - Returns: The built diagnoser instance.
func diagnoser() -> DiagnosticProducer {
AggregatedDiagnosticProducer {
cantDuplicate()
`if`(
isEnum || isProtocol,
AggregatedDiagnosticProducer {
mustBeCombined(with: Codable.self)
`if`(
isRawRepresentableEnum,
mustBeCombined(with: Codable.self),
else: mustBeCombined(
with: CodedAt.self,
or: DecodedAt.self, EncodedAt.self
)
)
},
else: AggregatedDiagnosticProducer {
expect(syntaxes: VariableDeclSyntax.self)
attachedToNonStaticVariable()
cantBeCombined(with: IgnoreCoding.self)
}
)
}
}
}
extension Registration
where
Decl: AttributableDeclSyntax, Var: DefaultPropertyVariable,
Var.Initialization == RequiredInitialization
{
/// The optional variable data with helper expression
/// that output registration will have.
typealias CodedByOutput = AnyPropertyVariable<Var.Initialization>
/// Update registration with helper expressions data.
///
/// New registration is updated with helper expressions data that will be
/// used for decoding/encoding, if provided.
///
/// - Returns: Newly built registration with helper expressions data.
func useHelperCoderIfExists() -> Registration<Decl, Key, CodedByOutput> {
guard let attr = CodedBy(from: self.decl)
else { return self.updating(with: self.variable.any) }
let newVar = self.variable.with(helper: attr.args)
return self.updating(with: newVar.any)
}
}
fileprivate extension DefaultPropertyVariable {
/// Update variable data with the helper instance expressions provided.
///
/// `HelperCodedVariable` is created with this variable as base
/// and helper expressions provided.
///
/// - Parameter args: The helper coding arguments provided.
/// - Returns: Created variable data with helper expression.
func with(helper args: LabeledExprListSyntax) -> HelperCodedVariable<Self> {
.init(base: self, options: .init(parsing: args))
}
}