@@ -90,7 +90,217 @@ class VisitorTests: XCTestCase {
90
90
}
91
91
) )
92
92
}
93
-
93
+
94
+ func testAllowsEditingANodeBothOnEnterAndOnLeave( ) throws {
95
+ let ast = try parse ( source: " { a, b, c { a, b, c } } " , noLocation: true )
96
+
97
+ var selectionSet : SelectionSet ? = nil
98
+
99
+ let editedASTNode = visit ( root: ast, visitor: . init(
100
+ enter: { node, key, parent, path, ancestors in
101
+ if let node = node as? OperationDefinition {
102
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors)
103
+ selectionSet = node. selectionSet
104
+ let newName = node. name
105
+ . map { Name ( loc: $0. loc, value: $0. value + " .enter " ) } ??
106
+ Name ( value: " enter " )
107
+ node. set ( value: . node( newName) , key: " name " )
108
+ node. set ( value: . node( SelectionSet ( selections: [ ] ) ) , key: " selectionSet " )
109
+ return . node( node)
110
+ }
111
+ return . continue
112
+ } ,
113
+ leave: { node, key, parent, path, ancestors in
114
+ if let node = node as? OperationDefinition {
115
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors, isEdited: true )
116
+ let newName = node. name
117
+ . map { Name ( loc: $0. loc, value: $0. value + " .leave " ) } ??
118
+ Name ( value: " leave " )
119
+ node. set ( value: . node( newName) , key: " name " )
120
+ node. set ( value: . node( selectionSet!) , key: " selectionSet " )
121
+ return . node( node)
122
+ }
123
+ return . continue
124
+ }
125
+ ) )
126
+
127
+ let editedAST = try XCTUnwrap ( editedASTNode as? Document )
128
+ let operations = try XCTUnwrap ( editedAST. definitions as? [ OperationDefinition ] )
129
+ XCTAssertEqual ( operations. count, 1 )
130
+ XCTAssertEqual ( operations. first? . name? . value, " enter.leave " )
131
+ let operationSelections = try XCTUnwrap ( operations. first? . selectionSet. selections)
132
+ XCTAssertEqual ( operationSelections. count, 3 )
133
+ }
134
+
135
+ func testAllowsEditingTheRootNodeOnEnterAndOnLeave( ) throws {
136
+ let ast = try parse ( source: " { a, b, c { a, b, c } } " , noLocation: true )
137
+
138
+ let editedASTNode = visit ( root: ast, visitor: . init(
139
+ enter: { node, key, parent, path, ancestors in
140
+ if let node = node as? Document {
141
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors)
142
+ var newDefinitions = node. definitions
143
+ newDefinitions. append (
144
+ DirectiveDefinition (
145
+ name: . init( value: " enter " ) ,
146
+ locations: [ . init( value: " root " ) ]
147
+ )
148
+ )
149
+ node. set (
150
+ value: . array( newDefinitions) ,
151
+ key: " definitions "
152
+ )
153
+ return . node( node)
154
+ }
155
+ return . continue
156
+ } ,
157
+ leave: { node, key, parent, path, ancestors in
158
+ if let node = node as? Document {
159
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors, isEdited: true )
160
+ var newDefinitions = node. definitions
161
+ newDefinitions. append (
162
+ DirectiveDefinition (
163
+ name: . init( value: " leave " ) ,
164
+ locations: [ . init( value: " root " ) ]
165
+ )
166
+ )
167
+ node. set (
168
+ value: . array( newDefinitions) ,
169
+ key: " definitions "
170
+ )
171
+ return . node( node)
172
+ }
173
+ return . continue
174
+ }
175
+ ) )
176
+
177
+ let editedAST = try XCTUnwrap ( editedASTNode as? Document )
178
+ XCTAssertEqual ( editedAST. definitions. count, 3 )
179
+ try XCTAssertEqual (
180
+ XCTUnwrap ( editedAST. definitions [ 1 ] as? DirectiveDefinition ) . name. value,
181
+ " enter "
182
+ )
183
+ try XCTAssertEqual (
184
+ XCTUnwrap ( editedAST. definitions [ 2 ] as? DirectiveDefinition ) . name. value,
185
+ " leave "
186
+ )
187
+ }
188
+
189
+ func testAllowsForEditingOnEnter( ) throws {
190
+ let ast = try parse ( source: " { a, b, c { a, b, c } } " , noLocation: true )
191
+
192
+ let editedASTNode = visit ( root: ast, visitor: . init(
193
+ enter: { node, key, parent, path, ancestors in
194
+ if let node = node as? Field {
195
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors)
196
+ if node. name. value == " b " {
197
+ return . node( nil )
198
+ }
199
+ }
200
+ return . continue
201
+ }
202
+ ) )
203
+
204
+ let editedAST = try XCTUnwrap ( editedASTNode as? Document )
205
+ let operation = try XCTUnwrap ( editedAST. definitions [ 0 ] as? OperationDefinition )
206
+ XCTAssertEqual (
207
+ operation. selectionSet. selections. count,
208
+ 2 // "b" is ignored
209
+ )
210
+
211
+ let cField = try XCTUnwrap ( operation. selectionSet. selections [ 1 ] as? Field )
212
+ XCTAssertEqual (
213
+ cField. selectionSet? . selections. count,
214
+ 2 // "b" is ignored
215
+ )
216
+ }
217
+
218
+ func testAllowsForEditingOnLeave( ) throws {
219
+ let ast = try parse ( source: " { a, b, c { a, b, c } } " , noLocation: true )
220
+
221
+ let editedASTNode = visit ( root: ast, visitor: . init(
222
+ leave: { node, key, parent, path, ancestors in
223
+ if let node = node as? Field {
224
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors)
225
+ if node. name. value == " b " {
226
+ return . node( nil )
227
+ }
228
+ }
229
+ return . continue
230
+ }
231
+ ) )
232
+
233
+ let editedAST = try XCTUnwrap ( editedASTNode as? Document )
234
+ let operation = try XCTUnwrap ( editedAST. definitions [ 0 ] as? OperationDefinition )
235
+ XCTAssertEqual (
236
+ operation. selectionSet. selections. count,
237
+ 2 // "b" is removed
238
+ )
239
+
240
+ let cField = try XCTUnwrap ( operation. selectionSet. selections [ 1 ] as? Field )
241
+ XCTAssertEqual (
242
+ cField. selectionSet? . selections. count,
243
+ 2 // "b" is removed
244
+ )
245
+ }
246
+
247
+ func testIgnoresSkipReturnedOnLeave( ) throws {
248
+ let ast = try parse ( source: " { a, b, c { a, b, c } } " , noLocation: true )
249
+
250
+ let editedASTNode = visit ( root: ast, visitor: . init(
251
+ leave: { _, _, _, _, _ in
252
+ . skip // graphql-js 'false' is Swift '.skip'
253
+ }
254
+ ) )
255
+
256
+ let editedAST = try XCTUnwrap ( editedASTNode as? Document )
257
+ let operation = try XCTUnwrap ( editedAST. definitions [ 0 ] as? OperationDefinition )
258
+ XCTAssertEqual (
259
+ operation. selectionSet. selections. count,
260
+ 3 // "b" remains
261
+ )
262
+
263
+ let cField = try XCTUnwrap ( operation. selectionSet. selections [ 2 ] as? Field )
264
+ XCTAssertEqual (
265
+ cField. selectionSet? . selections. count,
266
+ 3 // "b" remains
267
+ )
268
+ }
269
+
270
+ func testVisitsEditedNode( ) throws {
271
+ let addedField = Field (
272
+ name: Name ( value: " __typename " )
273
+ )
274
+
275
+ var didVisitAddedField = false
276
+
277
+ let ast = try parse ( source: " { a { x } } " , noLocation: true )
278
+ visit ( root: ast, visitor: . init(
279
+ enter: { node, key, parent, path, ancestors in
280
+ checkVisitorFnArgs ( ast, node, key, parent, path, ancestors, isEdited: true )
281
+ if let node = node as? Field , node. name. value == " a " {
282
+ if let selectionSet = node. selectionSet {
283
+ var newSelections = selectionSet. selections
284
+ newSelections. append ( addedField)
285
+
286
+ let newSelectionSet = selectionSet
287
+ newSelectionSet. set ( value: . array( newSelections) , key: " selections " )
288
+
289
+ let newNode = node
290
+ newNode. set ( value: . node( newSelectionSet) , key: " selectionSet " )
291
+ return . node( newNode)
292
+ }
293
+ }
294
+ if let node = node as? Field , node. name. value == " __typename " {
295
+ didVisitAddedField = true
296
+ }
297
+ return . continue
298
+ }
299
+ ) )
300
+
301
+ XCTAssert ( didVisitAddedField)
302
+ }
303
+
94
304
func testAllowsSkippingASubTree( ) throws {
95
305
struct VisitedElement : Equatable {
96
306
let direction : VisitDirection
0 commit comments