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