UNPKG

informed

Version:

A lightweight framework and utility for building powerful forms in React applications

360 lines (331 loc) 11.8 kB
import { createClass as _createClass, typeof as _typeof, classCallCheck as _classCallCheck } from './_virtual/_rollupPluginBabelHelpers.js'; import { Debug } from './debug.js'; var debug = Debug('informed:ObjMap' + '\t'); /** * * A data structure to read and write to a JS object via * JSPAN ( Java Script Property Access Notation ) */ /* -------------------- toPath -------------------- */ var ldtoPath = function ldtoPath() { var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; return String.prototype.replace.call(path, /\['(.+?)'\]/g, '.$1').split(/[,[\].]+?/).filter(Boolean); }; /* --------------------- get --------------------- */ var ldget = function ldget(obj) { var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var defaultValue = arguments.length > 2 ? arguments[2] : undefined; var result = String.prototype.replace.call(path, /\['(.+?)'\]/g, '.$1').split(/[,[\].]+?/).filter(Boolean).reduce(function (res, key) { return res !== null && res !== undefined ? res[key] : res; }, obj); return result === undefined || result === obj ? defaultValue : result; }; /* --------------------- swap --------------------- */ var ldSwap = function ldSwap(arr, a, b) { // if (arr[a] && arr[b]) { var oldA = arr[a]; var oldB = arr[b]; arr[a] = oldB; arr[b] = oldA; // } else { // eslint-disable-next-line no-console // console.warn( // `Attempted to swap ${a} with ${b} but one of them does not exist :(` // ); // } }; /* --------------------- move --------------------- */ var ldmove = function ldmove(arr, fromIndex, toIndex) { if (Array.isArray(arr) && fromIndex < arr.length && toIndex < arr.length) { var item = arr.splice(fromIndex, 1)[0]; arr.splice(toIndex, 0, item); } else { // Handle invalid operation more gracefully in real scenarios console.warn("Attempted to move from ".concat(fromIndex, " to ").concat(toIndex, " but the operation is not valid.")); } }; /* --------------------- insert --------------------- */ var ldInsert = function ldInsert(arr, index, value) { if (Array.isArray(arr) && index <= arr.length) { arr.splice(index, 0, value); } else { console.warn("Attempted to insert at index ".concat(index, ", but the operation is not valid.")); } }; /* --------------------- has --------------------- */ // foo --> // foo.bar --> foo // foo.bar[3] --> foo.bar // foo.bar.baz[2].raz.taz[5].laz --> foo.bar.baz[2].raz.taz[5] var parentPath = function parentPath(path) { return ".".concat(path).replace(/(.*)[.[].*/, '$1').replace(/\./, ''); }; // foo --> foo // foo.bar --> bar // foo.bar[3] --> [3] // foo.bar.baz[2].raz.taz[5].laz --> laz var pathKey = function pathKey(path) { return path.replace(parentPath(path), '').replace(/\./, ''); }; var ldhas = function ldhas(obj, path) { var pPath = parentPath(path); var key = pathKey(path); // If we have parent path then get the object at that location // .. otherwise its the root object var parentObj = pPath ? ldget(obj, pPath) : obj; // If its [3] turn key into 3 return !!(parentObj && Object.hasOwnProperty.call(parentObj, key.replace(/\[(.*)\]/, '$1'))); }; /* --------------------- set --------------------- */ var ldset = function ldset(obj) { var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var val = arguments.length > 2 ? arguments[2] : undefined; String.prototype.replace.call(path, /\['(.+?)'\]/g, '.$1').split(/[,[\].]+?/).filter(Boolean).reduce(function (res, key, i, arr) { //console.log('RES', res, 'Key', key, 'I', i, 'Arr', arr, 'OBJ', obj); // At the leaf set the value if (i === arr.length - 1) { res[key] = val; return res[key]; } // Initialize to new array or object if needed // OLD CODE: if (res[key] === undefined) { // Note I left comment above because it used to be undefined check // I had to change it to object in case someone tried to set // a value on an existing non object type // Example ldSet({ foo: 'HelloWorld' }, 'foo.bar', 'Hello World') // ==> { foo: { bar: 'HelloWorld' } } if (_typeof(res[key]) !== 'object') { if (Number.isInteger(+arr[i + 1])) { res[key] = []; } else { res[key] = {}; } return res[key]; } // Exception for if the value is changeing to an array if (Number.isInteger(+arr[i + 1]) && !Array.isArray(res[key])) { res[key] = []; } //TODO exception for if object ?? // Otherwise keep whats there return res[key]; }, obj); }; /* --------------------- unset --------------------- */ var ldunset = function ldunset(obj) { var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var found = false; String.prototype.replace.call(path, /\['(.+?)'\]/g, '.$1').split(/[,[\].]+?/).filter(Boolean).reduce(function (res, key, i, arr) { // Base case res is undefined if (res === undefined) { return res; } // At the leaf delete the value if (i === arr.length - 1) { delete res[key]; found = true; return res[key]; } // Otherwise keep going return res[key]; }, obj); return found; }; /* --------------------- pullAt --------------------- */ var ldpullAt = function ldpullAt(obj) { var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var pulled; String.prototype.replace.call(path, /\['(.+?)'\]/g, '.$1').split(/[,[\].]+?/).filter(Boolean).reduce(function (res, key, i, arr) { // Base case res is undefined if (res === undefined) { return res; } // At the leaf delete the value if (i === arr.length - 1 && Array.isArray(res)) { // Pull out one value at index ( key ) pulled = res.splice(key, 1); return res[key]; } // Otherwise keep going return res[key]; }, obj); return pulled; }; var pathToArrayElem = function pathToArrayElem(path) { var pathArray = ldtoPath(path); return Number.isInteger(+pathArray[pathArray.length - 1]); }; var ObjectMap = /*#__PURE__*/function () { function ObjectMap() { _classCallCheck(this, ObjectMap); } _createClass(ObjectMap, null, [{ key: "empty", value: function empty(object) { // return ldvalues(object).length === 0; for (var i in object) return false; return true; } }, { key: "get", value: function get(object, path) { var val = ldget(object, path); //debug('GOT', path, val); return val; } }, { key: "has", value: function has(object, path) { return ldhas(object, path); } }, { key: "set", value: function set(object, path, value) { if (value !== undefined) { debug('Setting', path, value); ldset(object, path, value); } else { // Setting things to undefined in informed is special! // so in this else statement we deal with that // If the path is to an array leaf then we want to set to undefined // Example: // path = 'foo.bar[2]' // foo.bar = [ 'baz', 'raz', 'taz' ] // setting taz to undefined ^^^ if (pathToArrayElem(path) && ObjectMap.get(object, path) !== undefined) { debug('Special case SETTING', path, 'to undefined'); ldset(object, path, undefined); var pathArray = ldtoPath(path); pathArray = pathArray.slice(0, pathArray.length - 1); cleanup(object, pathArray); } // Only delete the field if it needs to be deleted and its not a path to an array ( array leaf ) // Example: // path = 'foo.bar' // foo.bar = 'baz' // removing foo.bar from the object completley else if (!pathToArrayElem(path) && ObjectMap.get(object, path) !== undefined) { debug('Special case REMOVING', path, 'from object completley'); ObjectMap["delete"](object, path); } } } }, { key: "delete", value: function _delete(object, path) { debug('DELETE', path); // Special case for arrays if (pathToArrayElem(path)) { debug('ARRAY PATH', path); //ldunset(object, path); this.pullOut(object, path); } else { ldunset(object, path); } var pathArray = ldtoPath(path); pathArray = pathArray.slice(0, pathArray.length - 1); cleanup(object, pathArray); debug('DELETED', path); } // Very important ;) }, { key: "pullOut", value: function pullOut(object, path) { // Get the path to the array var pathArray = ldtoPath(path); // debug('PathArray1', pathArray); var index = pathArray[pathArray.length - 1]; pathArray = pathArray.slice(0, pathArray.length - 1); debug('Pulling out:', pathArray, 'index', index); // Get the array var arr = ldget(object, pathArray); debug('Array Before', JSON.stringify(arr)); // Pull out of array if (Array.isArray(arr)) { ldpullAt(arr, index); } debug('Array After', JSON.stringify(arr)); cleanup(object, pathArray); } }, { key: "purge", value: function purge(obj) { var newObj = Array.isArray(obj) ? [] : {}; Object.keys(obj).forEach(function (key) { // Its an object recur if (_typeof(obj[key]) === 'object') { newObj[key] = ObjectMap.purge(obj[key]); // If its empty after purge delete if (Object.keys(newObj[key]).length === 0) { delete newObj[key]; } } else if (obj[key] !== undefined) { newObj[key] = obj[key]; } }); return newObj; } }, { key: "swap", value: function swap(object, path, i, j) { // Get the path to the array debug("Swaping out out: ".concat(path, ", ").concat(i, ", ").concat(j)); // Get the array var arr = ldget(object, path); debug('Array', JSON.stringify(arr)); // Pull out of array if (Array.isArray(arr)) { ldSwap(arr, i, j); } } }, { key: "move", value: function move(object, path, fromIndex, toIndex) { debug("Moving: ".concat(path, ", from index ").concat(fromIndex, " to ").concat(toIndex)); // Get the array at the specified path var arr = ldget(object, path); debug("Array before move: ".concat(JSON.stringify(arr))); // Use ldmove to perform the operation ldmove(arr, fromIndex, toIndex); debug("Array after move: ".concat(JSON.stringify(arr))); } }, { key: "insert", value: function insert(object, path, index, value) { debug("Inserting: ".concat(value, " at ").concat(path, ", index ").concat(index)); // Get the array at the specified path var arr = ldget(object, path); debug("Array before insert: ".concat(JSON.stringify(arr))); // Use ldInsert to perform the operation if (Array.isArray(arr)) { ldInsert(arr, index, value); } else { debug("Path ".concat(path, " does not point to an array.")); } debug("Array after insert: ".concat(JSON.stringify(arr))); } }]); return ObjectMap; }(); function cleanup(obj, path) { // uncomment this to add third param back //,pull = true) { // Base case no path left if (path.length === 0) { return; } var object = ldget(obj, path); // Clean up undefined from array // if (Array.isArray(object) && pull) { // ldpull(object, undefined); // } // Delete object if its empty if (Array.isArray(object) ? object.every(function (e) { return e == null; }) : JSON.stringify(object) === '{}') { ldunset(obj, path); } // Recur cleanup(obj, path.slice(0, path.length - 1)); } export { ObjectMap, ldtoPath };