Skip to content

Commit bd87fd3

Browse files
committed
Parallel visitor supports editing
1 parent b2bdae0 commit bd87fd3

File tree

2 files changed

+127
-2
lines changed

2 files changed

+127
-2
lines changed

src/language/__tests__/visitor.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,128 @@ describe('Visitor', () => {
851851
]);
852852
});
853853

854+
it('allows for editing on enter', () => {
855+
var visited = [];
856+
857+
var ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
858+
var editedAst = visit(ast, visitInParallel([
859+
{
860+
enter(node) {
861+
if (node.kind === 'Field' && node.name.value === 'b') {
862+
return null;
863+
}
864+
}
865+
},
866+
{
867+
enter(node) {
868+
visited.push([ 'enter', node.kind, node.value ]);
869+
},
870+
leave(node) {
871+
visited.push([ 'leave', node.kind, node.value ]);
872+
}
873+
},
874+
]));
875+
876+
expect(ast).to.deep.equal(
877+
parse('{ a, b, c { a, b, c } }', { noLocation: true })
878+
);
879+
880+
expect(editedAst).to.deep.equal(
881+
parse('{ a, c { a, c } }', { noLocation: true })
882+
);
883+
884+
expect(visited).to.deep.equal([
885+
[ 'enter', 'Document', undefined ],
886+
[ 'enter', 'OperationDefinition', undefined ],
887+
[ 'enter', 'SelectionSet', undefined ],
888+
[ 'enter', 'Field', undefined ],
889+
[ 'enter', 'Name', 'a' ],
890+
[ 'leave', 'Name', 'a' ],
891+
[ 'leave', 'Field', undefined ],
892+
[ 'enter', 'Field', undefined ],
893+
[ 'enter', 'Name', 'c' ],
894+
[ 'leave', 'Name', 'c' ],
895+
[ 'enter', 'SelectionSet', undefined ],
896+
[ 'enter', 'Field', undefined ],
897+
[ 'enter', 'Name', 'a' ],
898+
[ 'leave', 'Name', 'a' ],
899+
[ 'leave', 'Field', undefined ],
900+
[ 'enter', 'Field', undefined ],
901+
[ 'enter', 'Name', 'c' ],
902+
[ 'leave', 'Name', 'c' ],
903+
[ 'leave', 'Field', undefined ],
904+
[ 'leave', 'SelectionSet', undefined ],
905+
[ 'leave', 'Field', undefined ],
906+
[ 'leave', 'SelectionSet', undefined ],
907+
[ 'leave', 'OperationDefinition', undefined ],
908+
[ 'leave', 'Document', undefined ]
909+
]);
910+
});
911+
912+
it('allows for editing on leave', () => {
913+
var visited = [];
914+
915+
var ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
916+
var editedAst = visit(ast, visitInParallel([
917+
{
918+
leave(node) {
919+
if (node.kind === 'Field' && node.name.value === 'b') {
920+
return null;
921+
}
922+
}
923+
},
924+
{
925+
enter(node) {
926+
visited.push([ 'enter', node.kind, node.value ]);
927+
},
928+
leave(node) {
929+
visited.push([ 'leave', node.kind, node.value ]);
930+
}
931+
},
932+
]));
933+
934+
expect(ast).to.deep.equal(
935+
parse('{ a, b, c { a, b, c } }', { noLocation: true })
936+
);
937+
938+
expect(editedAst).to.deep.equal(
939+
parse('{ a, c { a, c } }', { noLocation: true })
940+
);
941+
942+
expect(visited).to.deep.equal([
943+
[ 'enter', 'Document', undefined ],
944+
[ 'enter', 'OperationDefinition', undefined ],
945+
[ 'enter', 'SelectionSet', undefined ],
946+
[ 'enter', 'Field', undefined ],
947+
[ 'enter', 'Name', 'a' ],
948+
[ 'leave', 'Name', 'a' ],
949+
[ 'leave', 'Field', undefined ],
950+
[ 'enter', 'Field', undefined ],
951+
[ 'enter', 'Name', 'b' ],
952+
[ 'leave', 'Name', 'b' ],
953+
[ 'enter', 'Field', undefined ],
954+
[ 'enter', 'Name', 'c' ],
955+
[ 'leave', 'Name', 'c' ],
956+
[ 'enter', 'SelectionSet', undefined ],
957+
[ 'enter', 'Field', undefined ],
958+
[ 'enter', 'Name', 'a' ],
959+
[ 'leave', 'Name', 'a' ],
960+
[ 'leave', 'Field', undefined ],
961+
[ 'enter', 'Field', undefined ],
962+
[ 'enter', 'Name', 'b' ],
963+
[ 'leave', 'Name', 'b' ],
964+
[ 'enter', 'Field', undefined ],
965+
[ 'enter', 'Name', 'c' ],
966+
[ 'leave', 'Name', 'c' ],
967+
[ 'leave', 'Field', undefined ],
968+
[ 'leave', 'SelectionSet', undefined ],
969+
[ 'leave', 'Field', undefined ],
970+
[ 'leave', 'SelectionSet', undefined ],
971+
[ 'leave', 'OperationDefinition', undefined ],
972+
[ 'leave', 'Document', undefined ]
973+
]);
974+
});
975+
854976
});
855977

856978
});

src/language/visitor.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ function isNode(maybeNode) {
268268
* Creates a new visitor instance which delegates to many visitors to run in
269269
* parallel. Each visitor will be visited for each node before moving on.
270270
*
271-
* Visitors must not directly modify the AST nodes and only returning false to
272-
* skip sub-branches or BREAK to exit early is supported.
271+
* If a prior visitor edits a node, no following visitors will see that node.
273272
*/
274273
export function visitInParallel(visitors) {
275274
const skipping = new Array(visitors.length);
@@ -285,6 +284,8 @@ export function visitInParallel(visitors) {
285284
skipping[i] = node;
286285
} else if (result === BREAK) {
287286
skipping[i] = BREAK;
287+
} else if (result !== undefined) {
288+
return result;
288289
}
289290
}
290291
}
@@ -298,6 +299,8 @@ export function visitInParallel(visitors) {
298299
const result = fn.apply(visitors[i], arguments);
299300
if (result === BREAK) {
300301
skipping[i] = BREAK;
302+
} else if (result !== undefined && result !== false) {
303+
return result;
301304
}
302305
}
303306
} else if (skipping[i] === node) {

0 commit comments

Comments
 (0)