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}