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