@@ -16,52 +16,114 @@ import SyntaxSupport
1616import Utils
1717
1818extension LayoutNode {
19- func generateInitializerDeclHeader( useDeprecatedChildName: Bool = false ) -> SyntaxNodeString {
19+
20+ func makeChildParamType( for child: Child , isOptional: Bool = false ) -> TypeSyntax {
21+ var paramType : TypeSyntax
22+
23+ if !child. kind. isNodeChoicesEmpty {
24+ paramType = " \( child. syntaxChoicesType) "
25+ } else if child. hasBaseType {
26+ paramType = " some \( child. syntaxNodeKind. protocolType) "
27+ } else {
28+ paramType = child. syntaxNodeKind. syntaxType
29+ }
30+
31+ if isOptional {
32+ if paramType. is ( SomeOrAnyTypeSyntax . self) {
33+ paramType = " ( \( paramType) )? "
34+ } else {
35+ paramType = " \( paramType) ? "
36+ }
37+ }
38+
39+ return paramType
40+ }
41+
42+ /// Generates a memberwise SyntaxNode initializer `SyntaxNodeString`.
43+ ///
44+ /// - parameters:
45+ /// - rule: The ``NodeInitRule`` to use for generating the initializer. Applying a rule will make some children non-optional, and set default values for other children.
46+ /// - useDeprecatedChildName: Whether to use the deprecated child name for the initializer parameter.
47+ func generateInitializerDeclHeader( for rule: NodeInitRule ? = nil , useDeprecatedChildName: Bool = false ) -> SyntaxNodeString {
2048 if children. isEmpty {
2149 return " public init() "
2250 }
2351
24- func createFunctionParameterSyntax( for child: Child ) -> FunctionParameterSyntax {
25- var paramType : TypeSyntax
26- if !child. kind. isNodeChoicesEmpty {
27- paramType = " \( child. syntaxChoicesType) "
28- } else if child. hasBaseType {
29- paramType = " some \( child. syntaxNodeKind. protocolType) "
52+ func childParameterName( for child: Child ) -> TokenSyntax {
53+ let parameterName : TokenSyntax
54+
55+ if useDeprecatedChildName, let deprecatedVarName = child. deprecatedVarName {
56+ parameterName = deprecatedVarName
3057 } else {
31- paramType = child. syntaxNodeKind . syntaxType
58+ parameterName = child. varOrCaseName
3259 }
60+ return parameterName
61+ }
3362
34- if child. isOptional {
35- if paramType. is ( SomeOrAnyTypeSyntax . self) {
36- paramType = " ( \( paramType) )? "
63+ func ruleBasedChildIsOptional( for child: Child , with rule: NodeInitRule ? ) -> Bool ? {
64+ if let rule = rule {
65+ if rule. nonOptionalChildName == child. name {
66+ return false
3767 } else {
38- paramType = " \( paramType ) ? "
68+ return child . isOptional
3969 }
70+ } else {
71+ return nil
4072 }
73+ }
4174
42- let parameterName : TokenSyntax
75+ func ruleBasedChildDefaultValue( for child: Child , with rule: NodeInitRule ? ) -> InitializerClauseSyntax ? {
76+ if let rule, let defaultValue = rule. childDefaultValues [ child. name] {
77+ return InitializerClauseSyntax (
78+ equal: . equalToken( leadingTrivia: . space, trailingTrivia: . space) ,
79+ value: ExprSyntax ( " . \( defaultValue. spec. varOrCaseName) Token() " )
80+ )
81+ } else {
82+ return nil
83+ }
84+ }
4385
44- if useDeprecatedChildName, let deprecatedVarName = child. deprecatedVarName {
45- parameterName = deprecatedVarName
86+ func ruleBasedShouldOverrideDefault( for child: Child , with rule: NodeInitRule ? ) -> Bool {
87+ if let rule {
88+ // If the rule provides a default for this child, override it and set the rule-based default.
89+ if rule. childDefaultValues [ child. name] != nil {
90+ return true
91+ }
92+
93+ // For the non-optional rule-based parameter, strip the default value (override, but there will be no default)
94+ return rule. nonOptionalChildName == child. name
4695 } else {
47- parameterName = child . varOrCaseName
96+ return false
4897 }
98+ }
99+
100+ func createFunctionParameterSyntax( for child: Child , overrideOptional: Bool ? = nil , shouldOverrideDefault: Bool = false , overrideDefaultValue: InitializerClauseSyntax ? = nil ) -> FunctionParameterSyntax {
101+
102+ let parameterName = childParameterName ( for: child)
49103
50104 return FunctionParameterSyntax (
51105 leadingTrivia: . newline,
52106 firstName: child. isUnexpectedNodes ? . wildcardToken( trailingTrivia: . space) : parameterName,
53107 secondName: child. isUnexpectedNodes ? parameterName : nil ,
54108 colon: . colonToken( ) ,
55- type: paramType ,
56- defaultValue: child. defaultInitialization
109+ type: makeChildParamType ( for : child , isOptional : overrideOptional ?? child . isOptional ) ,
110+ defaultValue: shouldOverrideDefault ? overrideDefaultValue : child. defaultInitialization
57111 )
58112 }
59113
114+ // For convenience initializers, we don't need unexpected tokens in the arguments list
115+ // because convenience initializers are meant to be used bo developers manually
116+ // hence there should be no unexpected tokens
117+ let childrenToIterate = rule != nil ? nonUnexpectedChildren : children
118+
60119 let params = FunctionParameterListSyntax {
61120 FunctionParameterSyntax ( " leadingTrivia: Trivia? = nil " )
62121
63- for child in children {
64- createFunctionParameterSyntax ( for: child)
122+ for child in childrenToIterate {
123+ createFunctionParameterSyntax ( for: child,
124+ overrideOptional: ruleBasedChildIsOptional ( for: child, with: rule) ,
125+ shouldOverrideDefault: ruleBasedShouldOverrideDefault ( for: child, with: rule) ,
126+ overrideDefaultValue: ruleBasedChildDefaultValue ( for: child, with: rule) )
65127 }
66128
67129 FunctionParameterSyntax ( " trailingTrivia: Trivia? = nil " )
@@ -75,6 +137,14 @@ extension LayoutNode {
75137 """
76138 }
77139
140+ func generateRuleBasedDefaultValuesDocComment( for rule: NodeInitRule ) -> SwiftSyntax . Trivia {
141+ var params = " "
142+ for (childName, defaultValue) in rule. childDefaultValues {
143+ params += " - ` \( childName) `: `TokenSyntax. \( defaultValue. spec. varOrCaseName) Token()` \n "
144+ }
145+ return docCommentTrivia ( from: params)
146+ }
147+
78148 func generateInitializerDocComment( ) -> SwiftSyntax . Trivia {
79149 func generateParamDocComment( for child: Child ) -> String ? {
80150 if child. documentationAbstract. isEmpty {
0 commit comments