informed
Version:
A lightweight framework and utility for building powerful forms in React applications
360 lines (331 loc) • 11.8 kB
JavaScript
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 };