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 hasEdited = false;
20 let result;
21
22 result = callback(node, key, parent, false);
23 if (result === false) {
24 return;
25 } else if (result && typeof result.kind === 'string') {
26 hasEdited = true;
27 node = result;
28 }
29
30 ancestors.push(node);
31 const copy = { ...node };
32
33 for (const nodeKey in node) {
34 let value = node[nodeKey];
35 path.push(nodeKey);
36 if (Array.isArray(value)) {
37 value = value.slice();
38 for (let index = 0; index < value.length; index++) {
39 if (value[index] != null && typeof value[index].kind === 'string') {
40 path.push(index);
41 result = traverse(value[index], index, node);
42 path.pop();
43 if (result !== undefined) {
44 value[index] = result;
45 hasEdited = true;
46 }
47 }
48 }
49 } else if (value != null && typeof value.kind === 'string') {
50 result = traverse(value, nodeKey, node);
51 if (result !== undefined) {
52 value = result;
53 hasEdited = true;
54 }
55 }
56
57 path.pop();
58 if (hasEdited) copy[nodeKey] = value;
59 }
60
61 ancestors.pop();
62
63 if (hasEdited) node = copy;
64 result = callback(node, key, parent, true);
65 return hasEdited && result === undefined ? node : result;
66 }
67
68 try {
69 const result = traverse(node);
70 return result !== undefined ? result : node;
71 } catch (error) {
72 if (error !== BREAK) throw error;
73 return node;
74 }
75}