UNPKG

@expo/cli

Version:
150 lines (149 loc) 5.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "jsonSchemaDeref", { enumerable: true, get: function() { return jsonSchemaDeref; } }); /** Return JSON schema ref if input is of `NodeRef` type */ const getRef = (node)=>node != null && typeof node === 'object' && '$ref' in node && typeof node.$ref === 'string' ? node.$ref : undefined; /** Parse a JSON schema ref into a path array, or return undefined */ const parseRefMaybe = (ref)=>{ if (ref[0] !== '#') { return undefined; } const props = []; let startIndex = 1; let index = 1; let char; while(index < ref.length){ while((char = ref.charCodeAt(index++)) && char !== 47 /*'/'*/ ); const prop = ref.slice(startIndex, index - 1); startIndex = index; if (prop) props.push(prop); } return props.length ? props : undefined; }; const NOT_FOUND_SYMBOL = Symbol(); /** Get value at given JSON schema path or return `NOT_FOUND_SYMBOL` */ const getValueAtPath = (input, ref)=>{ let node = input; for(let index = 0; index < ref.length; index++){ const part = ref[index]; if (node != null && typeof node === 'object' && part in node) { node = node[part]; } else { node = NOT_FOUND_SYMBOL; break; } } return node; }; /** Find all JSON schema refs recursively and add them to `refs` Map */ const findRefsRec = (node, refs, path)=>{ if (node == null || typeof node !== 'object') {} else if (Array.isArray(node)) { for(let index = 0, l = node.length; index < l; index++){ const value = node[index]; const ref = getRef(value); if (ref) { const targetRef = parseRefMaybe(ref); if (targetRef) refs.set([ ...path, index ], targetRef); } else if (value != null && typeof value === 'object') { path.push(index); findRefsRec(value, refs, path); path.pop(); } } } else { const record = node; for(const key in record){ const value = record[key]; const ref = getRef(value); if (ref) { const targetRef = parseRefMaybe(ref); if (targetRef) refs.set([ ...path, key ], targetRef); } else if (value != null && typeof value === 'object') { path.push(key); findRefsRec(value, refs, path); path.pop(); } } } }; /** Detect whether target (where we set the source value) is a nested path inside the source path */ const isSelfReferencingRefEntry = (target, source)=>{ for(let index = 0; index < source.length; index++){ if (source[index] !== target[index]) return false; } return true; }; /** Return sorted refs entries. Longest target paths will be returned first */ const getSortedRefEntries = (refs)=>{ const entries = [ ...refs.entries() ].sort((a, b)=>b[1].length - a[1].length); // Filter out self-referenceing paths. If we set nested targets to source values, we'd // create unserializable circular references return entries.filter((entry)=>!isSelfReferencingRefEntry(entry[0], entry[1])); }; function jsonSchemaDeref(input) { // Find all JSON schema refs paths const refs = new Map(); findRefsRec(input, refs, []); // Shallow copy output const output = { ...input }; // Process all ref entries with deepest targets first nextRef: for (const [target, source] of getSortedRefEntries(refs)){ let inputNode = input; let outputNode = output; let targetIndex = 0; // For each path part on the target, traverse the output and clone the input // to not pollute it for(; targetIndex < target.length - 1; targetIndex++){ const part = target[targetIndex]; if (inputNode == null || typeof inputNode !== 'object' || !(part in inputNode)) { break; } else if (outputNode[part] === inputNode[part]) { // Copy the input on the output if references are equal outputNode[part] = Array.isArray(inputNode[part]) ? [ ...inputNode[part] ] : { ...inputNode[part] }; inputNode = inputNode[part]; outputNode = outputNode[part]; } else { break; } } // For each remaining part on the target, continue traversing the output for(; targetIndex < target.length - 1; targetIndex++){ const part = target[targetIndex]; if (outputNode == null || typeof outputNode !== 'object' || !(part in outputNode)) { continue nextRef; } else { outputNode = outputNode[part]; } } // Get value from output let sourceValue = getValueAtPath(output, source); if (sourceValue === NOT_FOUND_SYMBOL) { // If no value was found, try to get a value from the input instead sourceValue = getValueAtPath(input, source); // Otherwise, skip this ref if (sourceValue === NOT_FOUND_SYMBOL) continue; } // Set the source value on the target path // The for-loops prior have made sure that the output has already been deeply // cloned and traversed for the entire path outputNode[target[target.length - 1]] = sourceValue; } // Return the output with resolved refs return output; } //# sourceMappingURL=jsonSchemaDeref.js.map