react-json-editor-ajrm-ts-platform
Version:
A stylish, editor-like, modular, react component for viewing, editing, and debugging javascript object syntax!
1,023 lines (1,022 loc) • 37.2 kB
JavaScript
"use strict";
/**
* @author Andrew Redican <andrew.redican.mejia@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getType = exports.sameType = exports.sameStructure = exports.identical = exports.isIterable = exports.containsKeys = exports.trim = exports.locate = exports.deepGet = exports.locateAll = exports.deepFilter = exports.exists = exports.onlyExisting = exports.onlyMissing = exports.getLength = exports.falser = exports.isFalsy = exports.isTruthy = exports.singleProperty = exports.foundTruthy = exports.onlyTruthy = exports.foundFalsy = exports.onlyFalsy = exports.countMatches = exports.maxDepth = exports.matchDepth = exports.locate_Key = exports.deepGet_Key = exports.locateAll_Key = exports.deepFilter_Key = exports.deepClone = exports.renameKey = exports.renameKeys = exports.deepRemove_Key = exports.deepRemoveAll_Key = void 0;
/**
* Performs deep search on object tree, removes all properties with matching key, returns a new identity without the specified property
* @param {Any} identity
* @param {string} keyName
* @param {Optional Number} maxDepth
* @return {Any} identity
*/
function deepRemoveAll_Key(identity, keyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
let clonedIdentity = deepClone(identity);
var paths = locateAll_Key(clonedIdentity, keyName, maxDepth);
if (!paths.lenght || paths === false)
return clonedIdentity;
paths.forEach((path) => {
if (path === "")
path = keyName;
else
path += "." + keyName;
path = path.split(".");
var ref = clonedIdentity;
if (!Array.isArray(path))
delete ref[path];
for (var i = 0; i < path.length; i++) {
var key = path[i];
if (key in ref) {
if (i < path.length - 1)
ref = ref[key];
else
delete ref[key];
}
else
break;
}
});
return clonedIdentity;
}
exports.deepRemoveAll_Key = deepRemoveAll_Key;
/**
* Performs deep search on object tree, removes the first property with matching key, returns a new identity without the specified property
* @param {Any} identity
* @param {string} keyName
* @param {Optional Number} maxDepth
* @return {Any} identity
*/
function deepRemove_Key(identity, keyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
let clonedIdentity = deepClone(identity);
var path = locate_Key(clonedIdentity, keyName, maxDepth);
if (path === false)
return clonedIdentity;
if (path === "")
path = keyName;
else
path += "." + keyName;
path = path.split(".");
var ref = clonedIdentity;
if (!Array.isArray(path))
delete ref[path];
path.forEach((key, i) => {
if (i < path.length - 1)
ref = ref[key];
else
delete ref[key];
});
return clonedIdentity;
}
exports.deepRemove_Key = deepRemove_Key;
/**
* Performs deep search on object tree, and renames the all matching keys
* @param {Any} identity
* @param {string} keyName
* @param {string} newKeyName
* @param {Optional Number} maxDepth
* @return {Any} identity
*/
function renameKeys(identity, keyName, newKeyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (getType(newKeyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
if (newKeyName === "")
return undefined;
function _renameKeys(identity, keyName, newKeyName, maxDepth, currentDepth = 0) {
let keys;
switch (getType(identity)) {
case "array":
var Arr = [];
keys = Object.keys(identity);
for (var i = 0, l = keys.length; i < l; i++) {
let key = keys[i], subIdentity = identity[key];
Arr[key] = _renameKeys(subIdentity, keyName, newKeyName, maxDepth, currentDepth + 1);
}
return Arr;
case "object":
var Obj = {};
keys = Object.keys(identity);
for (var i = 0, l = keys.length; i < l; i++) {
let key = keys[i], subIdentity = identity[key];
if (maxDepth !== null ? currentDepth < maxDepth : true)
if (key === keyName)
key = newKeyName;
Obj[key] = _renameKeys(subIdentity, keyName, newKeyName, maxDepth, currentDepth + 1);
}
return Obj;
case "string":
return "" + identity;
case "number":
return 0 + identity;
case "boolean":
if (identity)
return true;
return false;
case "null":
return null;
case "undefined":
return undefined;
}
}
return _renameKeys(identity, keyName, newKeyName, maxDepth, 0);
}
exports.renameKeys = renameKeys;
/**
* Performs deep search on object tree, then renames the first matching key
* @param {Any} identity
* @param {string} keyName
* @param {string} newKeyName
* @param {Optional Number} maxDepth
* @return {Any} identity
*/
function renameKey(identity, keyName, newKeyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (getType(newKeyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
if (newKeyName === "")
return undefined;
var applied = false;
function _renameKey(identity, keyName, newKeyName, maxDepth, currentDepth = 0) {
let keys;
switch (getType(identity)) {
case "array":
var Arr = [];
keys = Object.keys(identity);
for (var i = 0, l = keys.length; i < l; i++) {
let key = keys[i], subIdentity = identity[key];
Arr[key] = _renameKey(subIdentity, keyName, newKeyName, maxDepth, currentDepth + 1);
}
return Arr;
case "object":
var Obj = {};
keys = Object.keys(identity);
for (var i = 0, l = keys.length; i < l; i++) {
let key = keys[i], subIdentity = identity[key];
if (maxDepth !== null ? currentDepth < maxDepth : true)
if (!applied)
if (key === keyName) {
key = newKeyName;
applied = true;
}
Obj[key] = _renameKey(subIdentity, keyName, newKeyName, maxDepth, currentDepth + 1);
}
return Obj;
case "string":
return "" + identity;
case "number":
return 0 + identity;
case "boolean":
if (identity)
return true;
return false;
case "null":
return null;
case "undefined":
return undefined;
}
}
return _renameKey(identity, keyName, newKeyName, maxDepth, 0);
}
exports.renameKey = renameKey;
/**
* Creates a non-reference clone that is an exact copy to the identity provided.
* @param {Any} identity
* @param {Optional Number} maxDepth
* @param {Optional Number} startDepth
* @return {Any} identity
*/
function deepClone(identity, maxDepth = 0, startDepth = 0) {
var R = [];
function _deepClone(identity, maxDepth, startDepth, currentDepth = 0) {
let keys;
if (startDepth !== null ? currentDepth < startDepth : false) {
if (isIterable(identity)) {
keys = Object.keys(identity);
keys.forEach((key) => {
_deepClone(identity[key], maxDepth, startDepth, currentDepth + 1);
});
}
return;
}
if (startDepth !== null ? currentDepth == startDepth : false) {
if (startDepth == 0) {
R = _deepClone(identity, maxDepth, null, currentDepth);
return;
}
if (isIterable(identity))
R.push(_deepClone(identity, maxDepth, startDepth, currentDepth + 1));
return;
}
switch (getType(identity)) {
case "array":
var Arr = [];
keys = Object.keys(identity);
if (maxDepth !== null ? currentDepth < maxDepth : true)
for (var i = 0, l = keys.length; i < l; i++) {
const key = keys[i], subIdentity = identity[key];
Arr[key] = _deepClone(subIdentity, maxDepth, startDepth, currentDepth + 1);
}
return Arr;
case "object":
var Obj = {};
keys = Object.keys(identity);
if (maxDepth !== null ? currentDepth < maxDepth : true)
for (var i = 0, l = keys.length; i < l; i++) {
const key = keys[i], subIdentity = identity[key];
Obj[key] = _deepClone(subIdentity, maxDepth, startDepth, currentDepth + 1);
}
return Obj;
case "string":
return "" + identity;
case "number":
return 0 + identity;
case "boolean":
if (identity)
return true;
return false;
case "null":
return null;
case "undefined":
return undefined;
}
}
if (startDepth === null)
return _deepClone(identity, maxDepth, startDepth, 0);
_deepClone(identity, maxDepth, startDepth, 0);
return R;
}
exports.deepClone = deepClone;
/**
* Performs deep search on collection to find all matches to the key name, and returns a list of identities containing the matched instances. If no matches found, it returns `undefined`.
* @param {Any} collection
* @param {Any} keyName
* @param {Optional Number} maxDepth
* @return {Array || undefined} Identities
*/
function deepFilter_Key(collection, keyName, maxDepth = 0) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
var paths = locateAll_Key(collection, keyName, maxDepth);
if (paths === false)
return undefined;
const results = paths.map((path) => {
if (path === false)
return undefined;
if (path === "")
path = keyName;
else
path += "." + keyName;
path = path.split(".");
var result = collection;
if (!Array.isArray(path))
return result[path];
path.forEach((key) => {
result = result[key];
});
return result;
});
return results;
}
exports.deepFilter_Key = deepFilter_Key;
/**
* Performs deep search on collection to find all matches to the key name, returns the location of each match in a string array. If no matches found, it returns `false`.
* @param {Any} collection
* @param {Any} keyName
* @param {Optional Number} maxDepth
* @return {Array || false} Paths
*/
function locateAll_Key(collection, keyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
var R = [];
function _locateAll_Key(collection, keyName, xKey = "", path = "", maxDepth, currentDepth = 0) {
if (xKey === keyName)
R[R.length] = path;
var result = false;
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return result;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key];
_locateAll_Key(subcollection, keyName, key, (path === "" ? path : path + ".") + key, maxDepth, currentDepth + 1);
}
}
_locateAll_Key(collection, keyName, "", "", maxDepth);
R = R.map((path) => {
if (getType(path) === "boolean")
return path;
if (path === "")
return path;
path = path.split(".");
path.pop();
path = path.join(".");
return path;
});
return R.length === 0 ? false : R;
}
exports.locateAll_Key = locateAll_Key;
/**
* Performs deep search on collection to find a match to the key name, and returns the first identity containing the match. If no match found, it returns `undefined`.
* @param {Any} collection
* @param {Any} keyName
* @param {Optional number} maxDepth
* @return {Identity || undefined} identity
*/
function deepGet_Key(collection, keyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
var path = locate_Key(collection, keyName, maxDepth);
if (path === false)
return undefined;
if (path === "")
path = keyName;
else
path += "." + keyName;
path = path.split(".");
var result = collection;
if (!Array.isArray(path))
return result[path];
path.forEach((key) => {
result = result[key];
});
return result;
}
exports.deepGet_Key = deepGet_Key;
/**
* Performs deep search on collection to find a match to the key name, will return the path of the first instance matched. If no match found, it returns `false`.
* @param {Any} collection
* @param {Any} keyName
* @param {Optional number} maxDepth
* @return {String || false} Path
*/
function locate_Key(collection, keyName, maxDepth) {
if (getType(keyName) !== "string")
return undefined;
if (keyName === "")
return undefined;
function _locate_Key(collection, keyName, path = "", maxDepth, currentDepth = 0) {
if (path === keyName)
return path;
var result = false;
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return result;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key], res = _locate_Key(subcollection, keyName, key, maxDepth, currentDepth + 1);
if (res) {
path = path === "" ? path : path + ".";
result = path + res;
break;
}
}
return result;
}
var path = _locate_Key(collection, keyName, "", maxDepth, 0);
if (getType(path) === "boolean")
return path;
if (path === "")
return path;
path = path.split(".");
path.pop();
path = path.join(".");
return path;
}
exports.locate_Key = locate_Key;
/**
* Performs deep search for identity on collection to return the location's depth of the first match. If no match found, it returns `false`.
* @param {Any} collection
* @param {Any} identity
* @param {Optional Number} maxDepth
* @return {boolean}
*/
function matchDepth(collection, identity, maxDepth) {
var path = locate(collection, identity, maxDepth);
if (path === false)
return false;
if (path === "")
return 0;
path = path.split(".");
return path.length;
}
exports.matchDepth = matchDepth;
/**
* Walks through the entire object tree to return the maximum number of layers it contains.
* @param {Any} identity
* @param {Optional Number} maxLayer
*/
function maxDepth(identity, maxLayer) {
let R = 0;
function _maxDepth(identity, maxLayer, currentDepth = 0) {
if (R < currentDepth)
R = currentDepth;
if (maxLayer !== null)
if (currentDepth >= maxLayer)
return;
if (isIterable(identity)) {
var keys = Object.keys(identity);
keys.forEach((key) => {
var subIdentity = identity[key];
_maxDepth(subIdentity, maxLayer, currentDepth + 1);
});
}
}
_maxDepth(identity, maxLayer);
return R;
}
exports.maxDepth = maxDepth;
/**
* Performs deep search for identity on collection, returns the number of matches found.
* @param {Any} collection
* @param {Any} identity
* @param {Number} nthDepth
* @param {Optional Number} maxDepth
* @return {Any} Returns number of matches found.
*/
function countMatches(collection, identity, nthDepth, maxDepth) {
var depth, nthDepth_isNull = nthDepth === null, maxDepth_isNull = maxDepth === null;
if (nthDepth_isNull && maxDepth_isNull)
depth = null;
else if (!nthDepth_isNull && !maxDepth_isNull)
if (nthDepth < maxDepth)
depth = nthDepth;
else
depth = maxDepth;
else if (nthDepth)
depth = nthDepth;
else
depth = maxDepth;
var paths = locateAll(collection, identity, depth);
if (paths === false)
return 0;
if (nthDepth === null)
return paths.length;
if (getType(nthDepth) === "number") {
let count = 0;
paths.forEach((path) => {
path = path.split(".");
if (path.length === nthDepth)
count++;
});
return count;
}
return undefined;
}
exports.countMatches = countMatches;
/**
* Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria
* @param {Any} collection
* @param {Any} identities
* @param {Any} property
* @param {Optional Number} maxDepth
* @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched.
*/
function onlyFalsy(collection, identities, property, maxDepth) {
if (getType(identities) === "array") {
let result = [];
identities.forEach((identity) => {
const subCollection = deepFilter(collection, identity);
if (isTruthy(subCollection))
if (foundFalsy(subCollection, property, maxDepth))
result.push(identity);
});
return result;
}
if (getType(identities) === "object") {
let result = {};
Object.keys(identities).forEach((key) => {
const identity = identities[key], subCollection = deepFilter(collection, identity);
if (isTruthy(subCollection))
if (foundFalsy(subCollection, property, maxDepth))
result[key] = identity;
});
return result;
}
if (foundFalsy(collection, property, maxDepth))
return identities;
}
exports.onlyFalsy = onlyFalsy;
/**
* Performs deep search on collection to find any match to the property and evalutates if truthy
* @param {Any} collection
* @param {Property} identity
* @param {Optional Number} maxDepth
* @return {boolean} If match confirmed and truthy will return true, otherwise false
*/
function foundFalsy(collection, identity, maxDepth) {
identity = singleProperty(identity);
if (isFalsy(identity))
return undefined;
function _foundFalsy(collection, identity, maxDepth, currentDepth = 0) {
if (containsKeys(collection, [identity]))
return isFalsy(collection[identity]);
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return false;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key], res = _foundFalsy(subcollection, identity, maxDepth, currentDepth + 1);
if (res)
return true;
}
return false;
}
return _foundFalsy(collection, identity, maxDepth);
}
exports.foundFalsy = foundFalsy;
/**
* Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria
* @param {Any} collection
* @param {Any} identities
* @param {Any} property
* @param {Optional Number} maxDepth
* @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched.
*/
function onlyTruthy(collection, identities, property, maxDepth) {
if (getType(identities) === "array") {
let result = [];
identities.forEach((identity) => {
const subCollection = deepFilter(collection, identity);
if (isTruthy(subCollection))
if (foundTruthy(subCollection, property, maxDepth))
result.push(identity);
});
return result;
}
if (getType(identities) === "object") {
let result = {};
Object.keys(identities).forEach((key) => {
const identity = identities[key], subCollection = deepFilter(collection, identity);
if (isTruthy(subCollection))
if (foundTruthy(subCollection, property, maxDepth))
result[key] = identity;
});
return result;
}
if (foundTruthy(collection, property, maxDepth))
return identities;
}
exports.onlyTruthy = onlyTruthy;
/**
* Performs deep search on collection to find any match to the property and evalutates if truthy
* @param {Any} collection
* @param {Property} identity
* @param {Optional Number} maxDepth
* @return {boolean} If match confirmed and truthy will return true, otherwise false
*/
function foundTruthy(collection, identity, maxDepth) {
identity = singleProperty(identity);
if (isFalsy(identity))
return undefined;
function _foundTruthy(collection, identity, maxDepth, currentDepth = 0) {
if (containsKeys(collection, [identity]))
return isTruthy(collection[identity]);
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return false;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key], res = _foundTruthy(subcollection, identity, maxDepth, currentDepth + 1);
if (res)
return true;
}
return false;
}
return _foundTruthy(collection, identity, maxDepth, 0);
}
exports.foundTruthy = foundTruthy;
/**
* Validates if identity is equal to a property definition or contains a single property key.
* @param {Property} identity
* @return {String || boolean} If criteria matched will return property name as string, otherwise false
*/
function singleProperty(identity) {
const propCount = getLength(identity);
if (propCount > 1)
return false;
if (propCount === 1)
return Object.keys(identity)[0];
if (propCount === 0)
if (["string", "number"].indexOf(getType(identity)) > -1)
return identity;
return false;
}
exports.singleProperty = singleProperty;
/**
* Determines if identity is non-falsy
* @param {Any} identity
* @return {boolean} Returns true if criteria matched, otherwise false.
*/
function isTruthy(identity) {
return !isFalsy(identity);
}
exports.isTruthy = isTruthy;
/**
* Determines if identity is falsy
* @param {Any} identity
* @return {boolean} Returns true if criteria matched, otherwise false.
*/
function isFalsy(identity) {
if (falser(identity) === false)
return true;
return false;
}
exports.isFalsy = isFalsy;
/**
* Converts false-like values into actual boolean value of false
* @param {Any} identity
* @return {Any || boolean} Returns false is value is falsy, otherwise returns original value.
*/
function falser(identity) {
if (isIterable(identity))
return identity;
if (["null", "undefined"].indexOf(getType(identity)) > -1)
return false;
if (["", 0, false].indexOf(identity) > -1)
return false;
return identity;
}
exports.falser = falser;
/**
* Check the length of the top-most depth of the identity
* @param {Any} identity
* @return {integer} Greater than or equal to 0.
*/
function getLength(identity) {
if (["array", "object"].indexOf(getType(identity)) === -1)
return 0;
return Object.keys(identity).length;
}
exports.getLength = getLength;
/**
* Performs deep search for each identity on collection, to shorten the identities to those that does meets the match criteria
* @param {Any} collection
* @param {Any} identities
* @param {Optional Number} maxDepth
* @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that were not matched.
*/
function onlyMissing(collection, identities, maxDepth) {
if (getType(identities) === "array") {
let result = [];
identities.forEach((identity) => {
if (!exists(collection, identity, maxDepth))
result.push(identity);
});
return result;
}
if (getType(identities) === "object") {
let result = {};
Object.keys(identities).forEach((key) => {
let identity = identities[key];
if (!exists(collection, identity, maxDepth))
result[key] = identity;
});
return result;
}
if (!exists(collection, identities, maxDepth))
return identities;
}
exports.onlyMissing = onlyMissing;
/**
* Performs deep search for each identity on collection, to shorten the identities to those that meets the match criteria
* @param {Any} collection
* @param {Any} identities
* @param {Optional Number} maxDepth
* @return {Any} Returns a collection of the same type as the 'identities' parameter provided with only the identities that matched.
*/
function onlyExisting(collection, identities, maxDepth) {
if (getType(identities) === "array") {
let result = [];
identities.forEach((identity) => {
if (exists(collection, identity, maxDepth))
result.push(identity);
});
return result;
}
if (getType(identities) === "object") {
let result = {};
Object.keys(identities).forEach((key) => {
let identity = identities[key];
if (exists(collection, identity, maxDepth))
result[key] = identity;
});
return result;
}
if (exists(collection, identities, maxDepth))
return identities;
}
exports.onlyExisting = onlyExisting;
/**
* Performs deep search on collection to find any match to the identity
* @param {Any} collection
* @param {Any} identity
* @param {Optional Number} maxDepth
* @param {Optional Number} currentDepth
* @return {boolean} If a match is confirmed will return true, otherwise false
*/
function exists(collection, identity, maxDepth, currentDepth = 0) {
if (identical(collection, identity))
return true;
if (isIterable(identity))
if (sameType(collection, identity))
if (containsKeys(collection, Object.keys(identity))) {
const trimmed = trim(collection, Object.keys(identity));
if (identical(trimmed, identity))
return true;
}
if (maxDepth === null ? true : currentDepth < maxDepth)
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key], res = exists(subcollection, identity, maxDepth, currentDepth + 1);
if (res)
return true;
}
return false;
}
exports.exists = exists;
/**
* Performs deep search on collection to find all matches to the identity, will return a list of identities containing the match. If no matches found, it returns `undefined`.
* @param {Any} collection
* @param {Any} identity
* @param {Optional Number} maxDepth
* @return {Array || undefined} identities
*/
function deepFilter(collection, identity, maxDepth) {
var paths = locateAll(collection, identity, maxDepth);
if (paths === false)
return undefined;
const results = paths.map((path) => {
if (path === "")
return collection;
path = path.split(".");
if (["array", "object"].indexOf(getType(identity)) === -1)
path.splice(-1, 1);
var result = collection;
if (!Array.isArray(path))
return result[path];
path.forEach((key) => {
result = result[key];
});
return result;
});
return results;
}
exports.deepFilter = deepFilter;
/**
* Performs deep search on collection to find all matches to the identity, returns a string array containing the location of all matches. If no matches found, it returns `false`.
* @param {Any} collection
* @param {Any} identity
* @param {Optional Number} maxDepth
* @return {Array || false} Paths
*/
function locateAll(collection, identity, maxDepth) {
var R = [];
function _locateAll(collection, identity, path = "", maxDepth, currentDepth = 0) {
if (isIterable(identity))
if (sameType(collection, identity))
if (containsKeys(collection, Object.keys(identity))) {
const trimmed = trim(collection, Object.keys(identity));
if (identical(trimmed, identity))
R[R.length] = path;
}
if (identical(collection, identity))
R[R.length] = path;
var result = false;
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return result;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key];
_locateAll(subcollection, identity, (path === "" ? path : path + ".") + key, maxDepth, currentDepth + 1);
}
}
_locateAll(collection, identity, "", maxDepth, 0);
return R.length === 0 ? false : R;
}
exports.locateAll = locateAll;
/**
* Performs deep search on collection to find a match to the identity, will return the identity containing of the first instance matched. If no matches found, it returns `undefined`.
* @param {Any} collection
* @param {Any} identity
* @param {Optional Number} maxDepth
* @return {identity || undefined} identity
*/
function deepGet(collection, identity, maxDepth) {
var path = locate(collection, identity, maxDepth);
if (path === false)
return undefined;
if (path === "")
return collection;
path = path.split(".");
if (["array", "object"].indexOf(getType(identity)) === -1)
path.splice(-1, 1);
var result = collection;
if (!Array.isArray(path))
return result[path];
path.forEach((key) => {
result = result[key];
});
return result;
}
exports.deepGet = deepGet;
/**
* Performs deep search on collection to find a match to the identity, will return the path of the first instance matched as string. If no matches found, returns `false`.
* @param {Any} collection
* @param {Any} identity
* @param {Optional number} maxDepth
* @return {string || false} path
*/
function locate(collection, identity, maxDepth) {
function _locate(collection, identity, path = "", maxDepth, currentDepth = 0) {
if (isIterable(identity))
if (sameType(collection, identity))
if (containsKeys(collection, Object.keys(identity))) {
const trimmed = trim(collection, Object.keys(identity));
if (identical(trimmed, identity))
return path;
}
if (identical(collection, identity))
return path;
var result = false;
if (maxDepth !== null)
if (currentDepth >= maxDepth)
return result;
if (isIterable(collection))
for (var i = 0, keys = Object.keys(collection), l = keys.length; i < l; i++) {
const key = keys[i], subcollection = collection[key], res = _locate(subcollection, identity, key, maxDepth, currentDepth + 1);
if (res) {
path = path === "" ? path : path + ".";
result = path + res;
break;
}
}
return result;
}
return _locate(collection, identity, "", maxDepth, 0);
}
exports.locate = locate;
/**
* Trims an identity to only contain the specified properties.
* @param {Any} identity
* @param {Any} keyList
* @return {Object or Array} Returns , otherwise false
*/
function trim(identity, keyList) {
const identityType = getType(identity);
if (["array", "object"].indexOf(identityType) === -1)
return undefined;
const keyCount = keyList.length;
if (keyCount === 0)
return undefined;
var newIdentity;
switch (identityType) {
case "object":
newIdentity = {};
keyList.forEach((key) => {
if (key in identity)
newIdentity[key] = identity[key];
});
break;
case "array":
newIdentity = [];
keyList.forEach((key) => {
if (key in identity)
newIdentity.push(identity[key]);
});
break;
}
return newIdentity;
}
exports.trim = trim;
/**
* Check if identity contains all of the specified keys
* @param {Any} identity
* @param {Array} keyList
* @return {boolean} true || false
*/
function containsKeys(identity, keyList) {
const keyCount = keyList.length;
if (keyCount === 0 || !isIterable(identity))
return false;
const identitykeys = Object.keys(identity);
var result = true;
for (var i = 0; i < keyCount; i++) {
const key = "" + keyList[i];
if (identitykeys.indexOf(key) === -1) {
result = false;
break;
}
}
return result;
}
exports.containsKeys = containsKeys;
/**
* Check if identity has one or more keys to iterate
* @param {Any} identity
* @return {boolean} true || false
*/
function isIterable(identity) {
if (["array", "object"].indexOf(getType(identity)) === -1)
return false;
if (Object.keys(identity).length === 0)
return false;
return true;
}
exports.isIterable = isIterable;
/**
* Compares two identities, will return either true if identical, otherwise false.
* @param {Any} identityA
* @param {Any} identityB
* @return {boolean} true || false
*/
function identical(identityA, identityB) {
const structureMatch = sameStructure(identityA, identityB);
if (structureMatch === false)
return structureMatch;
if (["array", "object"].indexOf(structureMatch) === -1)
return identityA === identityB;
const Keys = Object.keys(identityA), KeyCount = Keys.length;
var childMatch = true;
for (var i = 0; i < KeyCount; i++) {
const Key = Keys[i], identicalMatch = identical(identityA[Key], identityB[Key]);
if (identicalMatch === false) {
childMatch = identicalMatch;
break;
}
}
return childMatch;
}
exports.identical = identical;
/**
* Compares data structure of two identities, will return either the dataType or true/false.
* @param {Any} identityA
* @param {Any} identityB
* @return {String || False} DataType as string for positive match, otherwise false
*/
function sameStructure(identityA, identityB) {
const typeMatch = sameType(identityA, identityB);
if (typeMatch === false)
return false;
if (["array", "object"].indexOf(typeMatch) > -1) {
const AKeys = Object.keys(identityA), BKeys = Object.keys(identityB), AKeyCount = AKeys.length, BKeyCount = BKeys.length;
if (!(AKeyCount === BKeyCount))
return false;
if (AKeyCount === 0)
return true;
for (var i = 0; i < AKeyCount; i++) {
if (AKeys[i] !== BKeys[i])
return false;
}
}
return typeMatch;
}
exports.sameStructure = sameStructure;
/**
* Compares data type of two identities, will dataType if true.
* @param {Any} identityA
* @param {Any} identityB
* @return {boolean} true || false
*/
function sameType(identityA, identityB) {
const typeA = getType(identityA);
return typeA === getType(identityB) ? typeA : false;
}
exports.sameType = sameType;
/**
* Gets data type; makes distintion between object, array, and null.
* @param {Any} identity
* @return {String} dataType
*/
function getType(identity) {
if (identity === null)
return "null";
const it = typeof identity;
if (it === "object")
if (Array.isArray(identity))
return "array";
return it;
}
exports.getType = getType;