Mirror: The small sibling of the graphql package, slimmed down for client-side libraries.
1import { getVisitFn, visitInParallel, BREAK } from 'graphql/language/visitor';
2
3export { getVisitFn, visitInParallel, BREAK };
4
5export function visit(node, visitor) {
6 const path = [];
7 const ancestors = [];
8
9 function callback(node, key, parent, isLeaving) {
10 const visitFn = getVisitFn(visitor, node.kind, isLeaving)
11 if (visitFn) {
12 const result = visitFn.call(visitor, node, key, parent, path, ancestors)
13 if (result === BREAK) throw BREAK
14 return result
15 }
16 }
17
18 function traverse(node, key, parent) {
19 let result;
20
21 result = callback(node, key, parent, false);
22 if (result === false) {
23 return;
24 } else if (result && typeof result.kind === 'string') {
25 node = result;
26 }
27
28 ancestors.push(node);
29 const copy = {};
30
31 let hasEdited = false;
32 for (const nodeKey in node) {
33 const value = node[nodeKey];
34
35 let newValue;
36 path.push(nodeKey);
37 if (Array.isArray(value)) {
38 newValue = value.slice();
39 for (let index = 0; index < value.length; index++) {
40 if (value[index] != null && typeof value[index].kind === 'string') {
41 path.push(index);
42 result = traverse(value[index], index, node);
43 path.pop();
44 if (result !== undefined) {
45 newValue[index] = result;
46 hasEdited = true;
47 }
48 }
49 }
50
51 } else if (value != null && typeof value.kind === 'string') {
52 result = traverse(value, nodeKey, node);
53 if (result !== undefined) {
54 newValue = result;
55 hasEdited = true;
56 }
57 }
58
59 path.pop();
60 copy[nodeKey] = hasEdited ? newValue : value;
61 }
62
63 ancestors.pop();
64
65 if (hasEdited) node = copy;
66 return callback(node, key, parent, true);
67 }
68
69 try {
70 const result = traverse(node);
71 return result !== undefined ? result : node;
72 } catch (error) {
73 if (error !== BREAK) throw error;
74 return node;
75 }
76}