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}