Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

objob

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

objob - npm Package Compare versions

Comparing version 2.3.0 to 2.4.0

2

.jsdoc.json
{
"version": "2.2.0",
"version": "2.3.0",
"tags": {

@@ -4,0 +4,0 @@ "allowUnknownTags" : true

@@ -15,6 +15,2 @@ 'use strict';

var _deepmerge = require('deepmerge');
var _deepmerge2 = _interopRequireDefault(_deepmerge);
var _functions = require('./functions');

@@ -24,2 +20,4 @@

function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
/**

@@ -36,28 +34,27 @@ * @namespace

* a: 1,
* b: 2,
* c: 3,
* d: {f: 4}
* }
*
* y = ob.clone(x)
*
* (x.a === y.a && x.d.f === y.d.f)
* // → true
*
* y === x
* // → false
*
* @param {object|object[]} subject The object or array to clone.
* @returns {object|object[]} The cloned object or arraay
* @param {object|any[]} subject The object or array to clone.
* @returns {object|any[]} The cloned object or arraay
*/
clone: function clone(subject) {
return ob.expand(ob.flatten(subject));
if ((0, _typeOf2.default)(subject) === 'object' || (0, _typeOf2.default)(subject) === 'array') {
return ob.expand(ob.flatten(subject));
} else {
return subject;
}
},
/**
* Returns an object without the given keys or an array with each object not having the given keys.
* @example <caption>Basic usage.</caption>
* let x = {
* a: 1,
* b: 2,
* c: 3,
* }
*
* ob.deselect(x, ['a','b']);
* // → {c: 3}
* @example <caption>Advanced usage.</caption>
* @example
* let x = {

@@ -69,13 +66,35 @@ * c: 3,

*
* ob.deselect(x, ['d.e','d.f[].0','g[].1']);
* // → {c: 3, d: {f:[6]}, g:[7]}
* ob.omit(x, ['d.e','d.f[].0','g[].1']);
* // → {
* // c:3,
* // d: {
* // f: [6]
* // },
* // g:[7]
* //}
*
* @param {object|object[]} subject The object or array to perform the deselect operation on.
* @param {string[]} keys The keys of the object or nested object that you would like to deselect.
* @returns {object|object[]} The object or array of objects without the deselected keys
* @example
* let x = [
* 3,
* {e: 4, f: [5,6]},
* [7, 8]
* ]
*
* ob.omit(x, ['[]1.e','[]1.f[].0','[]2[].1']);
* // → {
* // 3,
* // {
* // f: [6]
* // },
* // [7]
* //}
*
* @param {object|any[]} subject The object or array to perform the omit operation on.
* @param {string|string[]} keys The keys of the object or nested object that you would like to omit.
* @returns {object|any[]} The object or array of objects without the omited keys
*/
deselect: function deselect(subject) {
omit: function omit(subject) {
var keys = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1];
var allKeys = ob.keys(ob.flatten(subject));
var subjectKeys = ob.keys(ob.flatten(subject));
var keysToKeep = [];

@@ -88,3 +107,3 @@

try {
for (var _iterator = allKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
for (var _iterator = subjectKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var subjectKey = _step.value;

@@ -94,27 +113,33 @@

var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
if ((0, _typeOf2.default)(keys) === 'array') {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var keyToRemove = _step2.value;
try {
for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var keyToRemove = _step2.value;
if (subjectKey === keyToRemove) {
keepKey = false;
if (subjectKey === keyToRemove) {
keepKey = false;
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
} else if ((0, _typeOf2.default)(keys) === 'string') {
if (subjectKey === keys) {
keepKey = false;
}
}

@@ -141,3 +166,3 @@

return ob.select(subject, keysToKeep);
return ob.pick(subject, keysToKeep);
},

@@ -148,2 +173,3 @@ /**

* @example
*
* let x = {

@@ -153,10 +179,39 @@ * 'a.b.c': 1,

* 'a.b.d[].0': 2,
* 'a.b.d[].1': 3',
* 'a.b.d[].1': 3,
* }
*
* ob.expand(x)
* // → {a: {b: {c: 1, d: [2,3]}}}
* // → {
* // a: {
* // b: {
* // c: 1,
* // d: [2,3]
* // }}}
*
* @example
* let x = {
* '[]0[].0.a.b.c': 1,
* '[]1.b.d': [2,3]
* '[]1.b.d[].0': 2
* '[]1.b.d[].1': 3
* }
*
* ob.expand(x)
* // → [
* // [{
* // a: {
* // b: {
* // c: 1,
* // },
* // },
* // }],
* // {
* // b: {
* // d: [2,3]
* // }
* // }
* //]
*
* @param {object} subject The object to expand
* @returns {object|object[]} The expanded object or array of objects.
* @returns {object|any[]} The expanded object or array of objects.
*/

@@ -169,78 +224,141 @@ expand: function expand(subject) {

// Determine if an array is represented by the flattened object
var rootObjectPresent = true;
if (depth === 1) {
rootObjectPresent = false;
for (var key in subject) {
var rootArrayPresent = key.match(/^\d/ig);
var keyChains = ob.keys(subject);
rootObjectPresent = rootObjectPresent || !rootArrayPresent;
var isArray = false;
if (true) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = keyChains[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var i = _step3.value;
if (i.startsWith('[]')) {
isArray = true;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
if (rootObjectPresent === false && depth === 1) {
// if a top level array, things need to be handled just a little bit differently
if (isArray) {
res = [];
for (var key in subject) {
res.push(subject[key]);
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = keyChains[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var keyChain = _step4.value;
// This converts something like []0.name.name or []0[].name.name to 0
var firstKey = keyChain.split('.')[0]; // eg []0[]
var fullIndex = firstKey.substr(2); // eg. 0[]
var index = fullIndex.replace('[]', ''); // eg 0
var nestedKeyChain = keyChain.replace(firstKey + '.', '');
var tmp = {};
// Make sure tmp is set correctly based on the object type
if ((0, _typeOf2.default)(res[index]) === 'array' || fullIndex.endsWith('[]')) {
tmp['[]' + nestedKeyChain] = subject[keyChain];
} else {
tmp[nestedKeyChain] = subject[keyChain];
}
if (keyChain.split('.').length === 1) {
// If there is no nested data just add to the array
res[index] = subject[keyChain];
} else if ((0, _typeOf2.default)(res[index]) === 'object' || (0, _typeOf2.default)(res[index]) === 'array') {
// If the next keyChain is an object
res[index] = ob.merge(res[index], ob.expand(tmp, depth + 1));
} else if (fullIndex.endsWith('[]')) {
res[index] = ob.expand(tmp, depth + 1);
} else {
res[index] = ob.expand(tmp, depth + 1);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
} else {
var keyChains = ob.keys(subject);
} else if (keyChains.length === 1) {
// When the object is just {'example.example': y}
// One key and one value
if (keyChains.length === 1) {
var tmp = {};
var keyChain = keyChains[0]; // something like 'first.another.another'
var value = subject[keyChain];
var count = undefined;
var tmp = {};
var keyChain = keyChains[0]; // something like 'first.another.another'
var value = subject[keyChain];
var count = undefined;
res = tmp; // Poining to tmp so that we have a place holder before nesting
count = 1;
var keys = keyChain.split('.');
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
res = tmp; // Pointing to tmp so that we have a place holder before nesting
count = 1;
var keys = keyChain.split('.');
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator3 = keys[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var key = _step3.value;
try {
for (var _iterator5 = keys[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var key = _step5.value;
if (count === keys.length) {
tmp[key] = value;
if (count === keys.length) {
tmp[key] = value;
} else {
var _isArray = (0, _stringContains2.default)(key, '[]');
if (_isArray) {
key = key.replace('[]', '');
tmp[key] = [];
} else {
var isArray = (0, _stringContains2.default)(key, '[]');
if (isArray) {
key = key.replace('[]', '');
tmp[key] = [];
} else {
tmp[key] = {};
}
tmp[key] = {};
}
tmp = tmp[key];
}
count++;
tmp = tmp[key];
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
count++;
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
if (_didIteratorError5) {
throw _iteratorError5;
}
}
} else {
// If multiple keychains in the object, simplify our logic a bit
res = {};
for (var i in subject) {
var tmp = {};
tmp[i] = subject[i];
res = (0, _deepmerge2.default)(res, ob.expand(tmp, ++depth));
}
}
} else {
// If multiple keychains in the object, simplify our logic a bit
res = {};
for (var i in subject) {
var tmp = {};
tmp[i] = subject[i];
res = ob.merge(res, ob.expand(tmp, depth + 1));
}
}

@@ -264,9 +382,33 @@ return res;

* // → {
* 'a.b.c': 1,
* 'a.b.d': [2,3]
* 'a.b.d[].0': 2,
* 'a.b.d[].1': 3',
* }
* // 'a.b.c': 1,
* // 'a.b.d': [2,3]
* // 'a.b.d[].0': 2,
* // 'a.b.d[].1': 3',
* //}
*
* @param {object|object[]} subject The object or array of objects to perform the flattening on
* @example
* let x = [
* [{
* a: {
* b: {
* c: 1,
* },
* },
* }],
* {
* b: {
* d: [2,3]
* }
* }
* ]
*
* // → {
* // '[]0[].0.a.b.c': 1,
* // '[]1.b.d': [2,3]
* // '[]1.b.d[].0': 2
* // '[]1.b.d[].1': 3
* //}
*
*
* @param {object|any[]} subject The object or array of objects to perform the flattening on
* @returns {object} The flat representation of the object

@@ -278,56 +420,30 @@ */

var res = undefined;
var res = {};
if ((0, _typeOf2.default)(subject) === 'array' && depth === 1) {
res = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = subject[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var i = _step4.value;
res = res.concat(ob.flatten(i, prefix, ++depth));
if ((0, _typeOf2.default)(subject) === 'object' || (0, _typeOf2.default)(subject) === 'array') {
for (var i in subject) {
var tmpPrefix = undefined;
if (prefix === '') {
tmpPrefix = '' + i;
} else {
tmpPrefix = prefix + '.' + i;
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
// If we're dealing with an array at the top level, we need to prefix it with [] to make it clear that we're dealing with
// an array as opposed to an object
if (depth === 1 && (0, _typeOf2.default)(subject) === 'array') {
tmpPrefix = '[]' + tmpPrefix;
}
}
return res;
} else {
res = {};
if ((0, _typeOf2.default)(subject[i]) === 'array') {
tmpPrefix = tmpPrefix + '[]';
}
if ((0, _typeOf2.default)(subject) === 'object' || (0, _typeOf2.default)(subject) === 'array') {
res[tmpPrefix] = subject[i];
for (var i in subject) {
var tmpPrefix = undefined;
if (prefix === '') {
tmpPrefix = '' + i;
} else {
tmpPrefix = prefix + '.' + i;
}
if ((0, _typeOf2.default)(subject[i]) === 'array') {
tmpPrefix = tmpPrefix + '[]';
}
res[tmpPrefix] = subject[i];
res = (0, _deepmerge2.default)(res, ob.flatten(subject[i], tmpPrefix, ++depth));
if ((0, _typeOf2.default)(subject[i]) === 'array' || (0, _typeOf2.default)(subject[i]) === 'object') {
res = ob.merge(res, ob.flatten(subject[i], tmpPrefix, depth + 1));
}
}
}
return res;

@@ -354,16 +470,19 @@ },

*
* @param {object|object[]} subject The object or array of objects whose keys you wish to retrieve.
* @param {object|any[]} subject The object or array of objects whose keys you wish to retrieve.
* @param {boolean} [unique=true] Whether the result should contain duplicates or not
* @returns {string[]} The keys
*/
keys: function keys(subject) {
var unique = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
var keys = [];
if ((0, _typeOf2.default)(subject) === 'array') {
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator5 = subject[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var i = _step5.value;
for (var _iterator6 = subject[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var i = _step6.value;

@@ -373,17 +492,15 @@ keys = keys.concat(ob.keys(i));

} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
return (0, _uniques2.default)(keys);
} else if ((0, _typeOf2.default)(subject) === 'object') {

@@ -393,6 +510,9 @@ for (var k in subject) {

};
return (0, _uniques2.default)(keys);
} else {
keys.push(subject);
}
if (unique) {
return (0, _uniques2.default)(keys);
} else {
return keys;
}

@@ -413,57 +533,101 @@ },

*
* ob.removeUndefs(x)
* ob.filter(x)
* // → {
* b: {
* d: 2,
* },
* e: [1, 2]
* }
* // b: {
* // d: 2,
* // },
* // e: [1, 2]
* //}
*
*
* @param {object|object[]} subject The object or array of objects you would like to remove undefined values from.
* @returns {object|object[]} The object or array of objects without any undefined values
* @param {object|any[]} subject The object or array of objects you would like to remove undefined values from.
* @param {function} validate The function to perform for the filter.
* @returns {object|any[]} The object or array of objects without any undefined values
*/
removeUndefs: function removeUndefs(subject) {
// Make sure we don't mutate the original object
filter: function filter(subject, validate) {
subject = ob.clone(subject);
var res = undefined;
if ((0, _typeOf2.default)(subject) === 'array') {
res = [];
for (var key in subject) {
if (subject[key] === undefined) {} else {
res.push(ob.removeUndefs(subject[key]));
if (validate(subject[key])) {
res.push(ob.filter(subject[key], validate));
}
}
subject = res;
} else if ((0, _typeOf2.default)(subject) === 'object') {
for (var key in subject) {
if (subject[key] === undefined) {
if (validate(subject[key]) === true) {
subject[key] = ob.filter(subject[key], validate);
} else {
delete subject[key];
} else {
subject[key] = ob.removeUndefs(subject[key]);
}
}
return subject;
} else {
return subject;
}
return res;
return subject;
},
/**
* Returns an object only with the given keys. If an array is passed, it will return an array of each given object only having the selected keys.
* Merges the enumerable attributes of two objects deeply.
*
* @example <caption>Basic usage.</caption>
* @example
* let x = {
* a: 1,
* b: 2,
* c: 3,
* a: {b: 1},
* }
*
* ob.select(x, ['a','b']);
* // → {a: 1, b: 2}
* let y = {
* a: {c: 1},
* }
*
* @example <caption>Advanced usage.</caption>
* ob.merge(x, y);
* // → {a: {b: 1, c:1}}
*
* @param {object|any[]} target The object or array of objects to merge into
* @param {object|any[]} src The object or array of objects to merge from
* @returns {object|any[]} The merged object or array
*/
merge: function merge(target, src) {
var array = Array.isArray(src);
var dst = array && [] || {};
if (array) {
target = target || [];
dst = dst.concat(target);
src.forEach(function (e, i) {
if (typeof dst[i] === 'undefined') {
dst[i] = e;
} else if ((typeof e === 'undefined' ? 'undefined' : _typeof(e)) === 'object') {
dst[i] = ob.merge(target[i], e);
} else {
if (target.indexOf(e) === -1) {
dst.push(e);
}
}
});
} else {
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object') {
Object.keys(target).forEach(function (key) {
dst[key] = target[key];
});
}
Object.keys(src).forEach(function (key) {
if (_typeof(src[key]) !== 'object' || !src[key]) {
dst[key] = src[key];
} else {
if (!target[key]) {
dst[key] = src[key];
} else {
dst[key] = ob.merge(target[key], src[key]);
}
}
});
}
return dst;
},
/**
* Returns an object only with the given keys. If an array is passed, it will return an array of each given object only having the picked keys.
*
* @example
* let x = {

@@ -475,10 +639,10 @@ * c: 3,

*
* ob.select(x, ['d.e','d.f[].0','g[].1']);
* ob.pick(x, ['d.e','d.f[].0','g[].1']);
* // → {d: {e: 4, f: [5]}, g: [8]}
*
* @param {object|object[]} subject The object or array of objects to perform the select operation on
* @param {string[]} keys The keys you would like to select
* @returns {object|object[]} The object or array of objects with only the selected keys.
* @param {object|any[]} subject The object or array of objects to perform the pick operation on
* @param {string|string[]} keys The keys you would like to pick
* @returns {object|any[]} The object or array of objects with only the picked keys.
*/
select: function select(subject) {
pick: function pick(subject) {
var keys = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1];

@@ -488,35 +652,8 @@

if ((0, _typeOf2.default)(subject) === 'array') {
resp = [];
resp = {};
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
var flat = ob.flatten(subject);
try {
for (var _iterator6 = subject[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var i = _step6.value;
resp = resp.concat(ob.select(i, keys));
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
} else {
resp = {};
var flat = ob.flatten(subject);
for (var actualKey in flat) {
for (var actualKey in flat) {
if ((0, _typeOf2.default)(keys) === 'array') {
var _iteratorNormalCompletion7 = true;

@@ -548,7 +685,10 @@ var _didIteratorError7 = false;

}
} else if ((0, _typeOf2.default)(keys) === 'string') {
if (actualKey === keys) {
resp[actualKey] = flat[actualKey];
}
}
resp = ob.expand(resp);
}
return resp;
return ob.expand(resp);
},

@@ -579,6 +719,9 @@ /**

*
* @param {object|object[]} subject The object or array of objects to get the values of
* @param {object|any[]} subject The object or array of objects to get the values of
* @param {boolean} [unique=true] Whether the result should contain duplicates or not
* @returns {any[]}
*/
values: function values(subject) {
var unique = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
var values = [];

@@ -611,4 +754,2 @@

}
return (0, _uniques2.default)(values);
} else if ((0, _typeOf2.default)(subject) === 'object') {

@@ -618,6 +759,9 @@ for (var k in subject) {

};
return (0, _uniques2.default)(values);
} else {
values.push(subject);
}
if (unique) {
return (0, _uniques2.default)(values);
} else {
return values;
}

@@ -624,0 +768,0 @@ }

{
"name": "objob",
"version": "2.3.0",
"version": "2.4.0",
"description": "A tool for controlling and manipulating javascript object fields and output.",

@@ -23,3 +23,2 @@ "main": "lib/objob.js",

"dependencies": {
"deepmerge": "^0.2.10",
"string-contains": "^0.1.0",

@@ -26,0 +25,0 @@ "type-of": "^2.0.1",

# Ob Job
A library of deep recursive object operations. Many functions will be similar to lodash except deeper.
A library of deep/recursive utilities for nested objects. Many functions will be similar to the object functions in lodash but will be deep/recursive versions.

@@ -15,3 +15,7 @@ ```bash

## Special Thanks
* [Kyle Matthews - Merge](https://github.com/KyleAMathews/deepmerge)
## License
MIT

@@ -6,3 +6,2 @@ 'use strict';

import contains from 'string-contains';
import merge from 'deepmerge';
import { makeFlattenedShallow } from './functions';

@@ -21,28 +20,27 @@

* a: 1,
* b: 2,
* c: 3,
* d: {f: 4}
* }
*
* y = ob.clone(x)
*
* (x.a === y.a && x.d.f === y.d.f)
* // → true
*
* y === x
* // → false
*
* @param {object|object[]} subject The object or array to clone.
* @returns {object|object[]} The cloned object or arraay
* @param {object|any[]} subject The object or array to clone.
* @returns {object|any[]} The cloned object or arraay
*/
clone: function(subject){
return ob.expand(ob.flatten(subject));
if(type(subject) === 'object' || type(subject) === 'array') {
return ob.expand(ob.flatten(subject));
} else {
return subject;
}
},
/**
* Returns an object without the given keys or an array with each object not having the given keys.
* @example <caption>Basic usage.</caption>
* let x = {
* a: 1,
* b: 2,
* c: 3,
* }
*
* ob.deselect(x, ['a','b']);
* // → {c: 3}
* @example <caption>Advanced usage.</caption>
* @example
* let x = {

@@ -54,18 +52,46 @@ * c: 3,

*
* ob.deselect(x, ['d.e','d.f[].0','g[].1']);
* // → {c: 3, d: {f:[6]}, g:[7]}
* ob.omit(x, ['d.e','d.f[].0','g[].1']);
* // → {
* // c:3,
* // d: {
* // f: [6]
* // },
* // g:[7]
* //}
*
* @param {object|object[]} subject The object or array to perform the deselect operation on.
* @param {string[]} keys The keys of the object or nested object that you would like to deselect.
* @returns {object|object[]} The object or array of objects without the deselected keys
* @example
* let x = [
* 3,
* {e: 4, f: [5,6]},
* [7, 8]
* ]
*
* ob.omit(x, ['[]1.e','[]1.f[].0','[]2[].1']);
* // → {
* // 3,
* // {
* // f: [6]
* // },
* // [7]
* //}
*
* @param {object|any[]} subject The object or array to perform the omit operation on.
* @param {string|string[]} keys The keys of the object or nested object that you would like to omit.
* @returns {object|any[]} The object or array of objects without the omited keys
*/
deselect: function(subject, keys = []){
let allKeys = ob.keys(ob.flatten(subject));
omit: function(subject, keys = []){
let subjectKeys = ob.keys(ob.flatten(subject));
let keysToKeep = [];
for( let subjectKey of allKeys ) {
for( let subjectKey of subjectKeys ) {
let keepKey = true;
for( let keyToRemove of keys ){
if(subjectKey === keyToRemove){
if(type(keys) === 'array') {
for( let keyToRemove of keys ){
if(subjectKey === keyToRemove){
keepKey = false;
}
}
} else if(type(keys) === 'string') {
if(subjectKey === keys){
keepKey = false;

@@ -78,5 +104,6 @@ }

}
}
return ob.select(subject, keysToKeep);
return ob.pick(subject, keysToKeep);
},

@@ -87,2 +114,3 @@ /**

* @example
*
* let x = {

@@ -92,10 +120,39 @@ * 'a.b.c': 1,

* 'a.b.d[].0': 2,
* 'a.b.d[].1': 3',
* 'a.b.d[].1': 3,
* }
*
* ob.expand(x)
* // → {a: {b: {c: 1, d: [2,3]}}}
* // → {
* // a: {
* // b: {
* // c: 1,
* // d: [2,3]
* // }}}
*
* @example
* let x = {
* '[]0[].0.a.b.c': 1,
* '[]1.b.d': [2,3]
* '[]1.b.d[].0': 2
* '[]1.b.d[].1': 3
* }
*
* ob.expand(x)
* // → [
* // [{
* // a: {
* // b: {
* // c: 1,
* // },
* // },
* // }],
* // {
* // b: {
* // d: [2,3]
* // }
* // }
* //]
*
* @param {object} subject The object to expand
* @returns {object|object[]} The expanded object or array of objects.
* @returns {object|any[]} The expanded object or array of objects.
*/

@@ -106,58 +163,79 @@ expand: function(subject, depth = 1){

// Determine if an array is represented by the flattened object
let rootObjectPresent = true;
if(depth === 1) {
rootObjectPresent = false;
for(let key in subject) {
let rootArrayPresent = key.match(/^\d/ig);
let keyChains = ob.keys(subject);
rootObjectPresent = (rootObjectPresent || !rootArrayPresent);
let isArray = false;
if(true) {
for(let i of keyChains) {
if(i.startsWith('[]')) {
isArray = true;
}
}
}
if(rootObjectPresent === false && depth === 1) {
// if a top level array, things need to be handled just a little bit differently
if(isArray) {
res = [];
for(let key in subject) {
res.push(subject[key]);
for(let keyChain of keyChains) {
// This converts something like []0.name.name or []0[].name.name to 0
const firstKey = keyChain.split('.')[0]; // eg []0[]
const fullIndex = firstKey.substr(2); // eg. 0[]
const index = fullIndex.replace('[]', ''); // eg 0
const nestedKeyChain = keyChain.replace(firstKey + '.', '');
let tmp = {};
// Make sure tmp is set correctly based on the object type
if(type(res[index]) === 'array' || fullIndex.endsWith('[]')) {
tmp['[]'+nestedKeyChain] = subject[keyChain];
} else {
tmp[nestedKeyChain] = subject[keyChain];
}
if(keyChain.split('.').length === 1) {
// If there is no nested data just add to the array
res[index] = subject[keyChain];
} else if(type(res[index]) === 'object' || type(res[index]) === 'array') {
// If the next keyChain is an object
res[index] = ob.merge(res[index], ob.expand(tmp, depth+1));
} else if(fullIndex.endsWith('[]')) {
res[index] = ob.expand(tmp, depth+1);
} else {
res[index] = ob.expand(tmp, depth+1);
}
}
} else {
let keyChains = ob.keys(subject);
} else if(keyChains.length === 1) {
// When the object is just {'example.example': y}
// One key and one value
if(keyChains.length === 1) {
let tmp = {};
let keyChain = keyChains[0]; // something like 'first.another.another'
let value = subject[keyChain];
let count;
let tmp = {};
let keyChain = keyChains[0]; // something like 'first.another.another'
let value = subject[keyChain];
let count;
res = tmp; // Poining to tmp so that we have a place holder before nesting
count = 1;
let keys = keyChain.split('.');
for(let key of keys) {
if(count === keys.length) {
tmp[key] = value;
res = tmp; // Pointing to tmp so that we have a place holder before nesting
count = 1;
let keys = keyChain.split('.');
for(let key of keys) {
if(count === keys.length) {
tmp[key] = value;
} else {
let isArray = contains(key, '[]');
if(isArray) {
key = key.replace('[]','');
tmp[key] = [];
} else {
let isArray = contains(key, '[]');
if(isArray) {
key = key.replace('[]','');
tmp[key] = [];
} else {
tmp[key] = {};
}
tmp = tmp[key];
tmp[key] = {};
}
count++;
}
} else {
// If multiple keychains in the object, simplify our logic a bit
res = {};
for(let i in subject) {
let tmp = {};
tmp[i] = subject[i];
res = merge(res, ob.expand(tmp, ++depth));
tmp = tmp[key];
}
count++;
}
} else {
// If multiple keychains in the object, simplify our logic a bit
res = {};
for(let i in subject) {
let tmp = {};
tmp[i] = subject[i];
res = ob.merge(res, ob.expand(tmp, depth+1));
}
}

@@ -181,45 +259,64 @@ return res;

* // → {
* 'a.b.c': 1,
* 'a.b.d': [2,3]
* 'a.b.d[].0': 2,
* 'a.b.d[].1': 3',
* }
* // 'a.b.c': 1,
* // 'a.b.d': [2,3]
* // 'a.b.d[].0': 2,
* // 'a.b.d[].1': 3',
* //}
*
* @param {object|object[]} subject The object or array of objects to perform the flattening on
* @example
* let x = [
* [{
* a: {
* b: {
* c: 1,
* },
* },
* }],
* {
* b: {
* d: [2,3]
* }
* }
* ]
*
* // → {
* // '[]0[].0.a.b.c': 1,
* // '[]1.b.d': [2,3]
* // '[]1.b.d[].0': 2
* // '[]1.b.d[].1': 3
* //}
*
*
* @param {object|any[]} subject The object or array of objects to perform the flattening on
* @returns {object} The flat representation of the object
*/
flatten: function(subject, prefix='', depth = 1){
let res;
let res = {};
if(type(subject) === 'array' && depth === 1) {
res = [];
if(type(subject) === 'object' || type(subject) === 'array'){
for(let i in subject) {
let tmpPrefix;
if(prefix === '') {
tmpPrefix = `${i}`;
} else {
tmpPrefix = `${prefix}.${i}`;
}
// If we're dealing with an array at the top level, we need to prefix it with [] to make it clear that we're dealing with
// an array as opposed to an object
if(depth === 1 && type(subject) === 'array') {
tmpPrefix = `[]${tmpPrefix}`;
}
for(let i of subject){
res = res.concat(ob.flatten(i, prefix, ++depth));
}
if(type(subject[i]) === 'array') {
tmpPrefix = tmpPrefix + '[]';
}
return res;
} else {
res = {};
res[tmpPrefix] = subject[i];
if(type(subject) === 'object' || type(subject) === 'array'){
for(let i in subject) {
let tmpPrefix;
if(prefix === '') {
tmpPrefix = `${i}`;
} else {
tmpPrefix = `${prefix}.${i}`;
}
if(type(subject[i]) === 'array') {
tmpPrefix = tmpPrefix + '[]';
}
res[tmpPrefix] = subject[i];
res = merge(res, ob.flatten(subject[i],tmpPrefix, ++depth));
if(type(subject[i]) === 'array' || type(subject[i]) === 'object') {
res = ob.merge(res, ob.flatten(subject[i],tmpPrefix, depth+1));
}
}
}
return res;

@@ -246,6 +343,7 @@ },

*
* @param {object|object[]} subject The object or array of objects whose keys you wish to retrieve.
* @param {object|any[]} subject The object or array of objects whose keys you wish to retrieve.
* @param {boolean} [unique=true] Whether the result should contain duplicates or not
* @returns {string[]} The keys
*/
keys:function(subject) {
keys:function(subject, unique=true) {
let keys = [];

@@ -258,3 +356,2 @@

return uniques(keys);
} else if(type(subject) === 'object') {

@@ -264,6 +361,9 @@ for(let k in subject) {

};
return uniques(keys);
} else {
keys.push(subject);
}
if(unique) {
return uniques(keys);
} else {
return keys;
}

@@ -284,58 +384,102 @@ },

*
* ob.removeUndefs(x)
* ob.filter(x)
* // → {
* b: {
* d: 2,
* },
* e: [1, 2]
* }
* // b: {
* // d: 2,
* // },
* // e: [1, 2]
* //}
*
*
* @param {object|object[]} subject The object or array of objects you would like to remove undefined values from.
* @returns {object|object[]} The object or array of objects without any undefined values
* @param {object|any[]} subject The object or array of objects you would like to remove undefined values from.
* @param {function} validate The function to perform for the filter.
* @returns {object|any[]} The object or array of objects without any undefined values
*/
removeUndefs: (subject) => {
// Make sure we don't mutate the original object
filter: (subject, validate) => {
subject = ob.clone(subject);
let res;
if(type(subject) === 'array') {
res = [];
for(let key in subject) {
if(subject[key] === undefined) {
} else {
res.push(ob.removeUndefs(subject[key]));
if(validate(subject[key])) {
res.push(ob.filter(subject[key], validate));
}
}
subject = res;
} else if(type(subject) === 'object') {
for(let key in subject) {
if(subject[key] === undefined) {
if(validate(subject[key]) === true ) {
subject[key] = ob.filter(subject[key], validate);
} else {
delete subject[key];
} else {
subject[key] = ob.removeUndefs(subject[key]);
}
}
return subject;
} else {
return subject;
}
return res;
return subject;
},
/**
* Returns an object only with the given keys. If an array is passed, it will return an array of each given object only having the selected keys.
* Merges the enumerable attributes of two objects deeply.
*
* @example <caption>Basic usage.</caption>
* @example
* let x = {
* a: 1,
* b: 2,
* c: 3,
* a: {b: 1},
* }
*
* ob.select(x, ['a','b']);
* // → {a: 1, b: 2}
* let y = {
* a: {c: 1},
* }
*
* @example <caption>Advanced usage.</caption>
* ob.merge(x, y);
* // → {a: {b: 1, c:1}}
*
* @param {object|any[]} target The object or array of objects to merge into
* @param {object|any[]} src The object or array of objects to merge from
* @returns {object|any[]} The merged object or array
*/
merge: function(target, src) {
let array = Array.isArray(src);
let dst = array && [] || {};
if (array) {
target = target || [];
dst = dst.concat(target);
src.forEach((e, i) => {
if (typeof dst[i] === 'undefined') {
dst[i] = e;
} else if (typeof e === 'object') {
dst[i] = ob.merge(target[i], e);
} else {
if (target.indexOf(e) === -1) {
dst.push(e);
}
}
});
} else {
if (target && typeof target === 'object') {
Object.keys(target).forEach((key) => {
dst[key] = target[key];
});
}
Object.keys(src).forEach((key) => {
if (typeof src[key] !== 'object' || !src[key]) {
dst[key] = src[key];
}
else {
if (!target[key]) {
dst[key] = src[key];
} else {
dst[key] = ob.merge(target[key], src[key]);
}
}
});
}
return dst;
},
/**
* Returns an object only with the given keys. If an array is passed, it will return an array of each given object only having the picked keys.
*
* @example
* let x = {

@@ -347,24 +491,18 @@ * c: 3,

*
* ob.select(x, ['d.e','d.f[].0','g[].1']);
* ob.pick(x, ['d.e','d.f[].0','g[].1']);
* // → {d: {e: 4, f: [5]}, g: [8]}
*
* @param {object|object[]} subject The object or array of objects to perform the select operation on
* @param {string[]} keys The keys you would like to select
* @returns {object|object[]} The object or array of objects with only the selected keys.
* @param {object|any[]} subject The object or array of objects to perform the pick operation on
* @param {string|string[]} keys The keys you would like to pick
* @returns {object|any[]} The object or array of objects with only the picked keys.
*/
select: (subject, keys = []) => {
pick: (subject, keys = []) => {
let resp;
if(type(subject) === 'array') {
resp = [];
resp = {};
for(let i of subject){
resp = resp.concat(ob.select(i, keys));
}
} else {
resp = {};
let flat = ob.flatten(subject);
let flat = ob.flatten(subject);
for (let actualKey in flat){
for (let actualKey in flat){
if(type(keys) === 'array') {
for (let desiredKey of keys){

@@ -375,7 +513,10 @@ if(actualKey === desiredKey) {

}
} else if(type(keys) === 'string') {
if(actualKey === keys) {
resp[actualKey] = flat[actualKey];
}
}
resp = ob.expand(resp);
}
return resp;
return ob.expand(resp);
},

@@ -406,6 +547,7 @@ /**

*
* @param {object|object[]} subject The object or array of objects to get the values of
* @param {object|any[]} subject The object or array of objects to get the values of
* @param {boolean} [unique=true] Whether the result should contain duplicates or not
* @returns {any[]}
*/
values:(subject) => {
values:(subject, unique=true) => {
let values = [];

@@ -418,3 +560,2 @@

return uniques(values);
} else if(type(subject) === 'object') {

@@ -424,6 +565,9 @@ for(let k in subject) {

};
return uniques(values);
} else {
values.push(subject);
}
if(unique) {
return uniques(values);
} else {
return values;
}

@@ -430,0 +574,0 @@ },

@@ -7,4 +7,4 @@ /* eslint max-nested-callbacks: 0*/

describe('Objob', () => {
let ob1, ob2, ob3, ob4;
let obArr1;
let ob1, ob2, ob3, ob4, ob5;
let arr2, arr1, arr3, arr4;

@@ -48,4 +48,18 @@ before((done) => {

obArr1 = [ob1, ob2];
ob5 = {
name: undefined,
feet: 5,
body: {
feet: {
toes: [undefined,2,10],
},
hair: undefined,
},
};
arr1 = [3, 1];
arr2 = [ob1, ob2];
arr3 = [arr2, arr2];
arr4 = [arr2, arr1];
done();

@@ -60,3 +74,3 @@ });

it('should return all keys for an array', (done) => {
expect(ob.keys(obArr1)).to.include.members(['name','age', 'weight','feet']);
expect(ob.keys(arr2)).to.include.members(['name','age', 'weight','feet']);
done();

@@ -72,3 +86,3 @@ });

it('should return all values for an array', (done) => {
expect(ob.values(obArr1)).to.include.members([ob1.name, ob1.age, ob1.weight, ob2.feet]);
expect(ob.values(arr2)).to.include.members([ob1.name, ob1.age, ob1.weight, ob2.feet]);
done();

@@ -78,7 +92,7 @@ });

describe('select', () => {
it('should return the object only select the given keys', (done) => {
expect(ob.select(ob1, ['name'])).to.deep.equal({name: ob1.name});
expect(ob.select(ob2,['name', 'age'])).to.deep.equal({name: ob2.name, age: ob2.age});
expect(ob.select(ob3, ['eyes[].0.location'])).to.deep.equal({
describe('pick', () => {
it('should return the object only pick the given keys', (done) => {
expect(ob.pick(ob1, ['name'])).to.deep.equal({name: ob1.name});
expect(ob.pick(ob2,['name', 'age'])).to.deep.equal({name: ob2.name, age: ob2.age});
expect(ob.pick(ob3, ['eyes[].0.location'])).to.deep.equal({
eyes: [{location: 'left'}],

@@ -89,9 +103,9 @@ });

it('should return the object only select the given keys using nested object', (done) => {
expect(ob.select(ob3, ['body.feet'])).to.deep.equal({body: {feet: ob3.body.feet}});
it('should return the object only pick the given keys using nested object', (done) => {
expect(ob.pick(ob3, ['body.feet'])).to.deep.equal({body: {feet: ob3.body.feet}});
done();
});
it('should return the array only select the given keys using nested object', (done) => {
expect(ob.select([ob3, ob3], ['body.feet']))
it('should return the array only pick the given keys using nested object', (done) => {
expect(ob.pick([ob3, ob3], ['[]0.body.feet', '[]1.body.feet']))
.to.deep.equal([{body: {feet: ob3.body.feet}}, {body: {feet: ob3.body.feet}}]);

@@ -101,4 +115,4 @@ done();

it('should return an array of objects only select the given keys', (done) => {
expect(ob.select(obArr1, ['name'])).to.deep.equal([{name: ob1.name},{name: ob2.name}]);
it('should return an array of objects with the given keys', (done) => {
expect(ob.pick(arr2, ['[]0.name', '[]1.name'])).to.deep.equal([{name: ob1.name},{name: ob2.name}]);
done();

@@ -108,9 +122,8 @@ });

describe('deselect', () => {
it('should return the object only deselect the given keys', (done) => {
expect(ob.deselect(ob1, ['name'])).to.deep.equal({age: ob1.age, weight: ob1.weight});
expect(ob.deselect(ob2, ['name', 'age'])).to.deep.equal({weight: ob2.weight, feet: ob2.feet});
done();
describe('omit', () => {
it('should return the object only omit the given keys', (done) => {
expect(ob.omit(ob1, ['name'])).to.deep.equal({age: ob1.age, weight: ob1.weight});
expect(ob.omit(ob2, ['name', 'age'])).to.deep.equal({weight: ob2.weight, feet: ob2.feet});
expect(ob.deselect(ob3, ['eyes[].0.location'])).to.deep.equal({
expect(ob.omit(ob3, ['eyes[].0.location'])).to.deep.equal({
name: ob3.name,

@@ -125,6 +138,7 @@ feet: ob3.feet,

});
done();
});
it('should return an array of objects only deselect the given keys', (done) => {
expect(ob.deselect(obArr1, ['name', 'weight', 'feet']))
it('should return an array of objects only omit the given keys', (done) => {
expect(ob.omit(arr2, ['[]0.name', '[]0.weight', '[]0.feet', '[]1.name', '[]1.weight', '[]1.feet']))
.to.deep.equal([{age: ob1.age}, {age: ob2.age}]);

@@ -157,2 +171,40 @@

expect(ob.flatten(ob1)).to.deep.equal(ob1);
expect(ob.flatten(arr3)).to.deep.equal({
'[]0[]': [ { name: 'Bob', age: 22, weight: 170 },{ name: 'Bob', feet: 5, age: 100, weight: 170 } ],
'[]0[].0': { name: 'Bob', age: 22, weight: 170 },
'[]0[].0.name': 'Bob',
'[]0[].0.age': 22,
'[]0[].0.weight': 170,
'[]0[].1': { name: 'Bob', feet: 5, age: 100, weight: 170 },
'[]0[].1.name': 'Bob',
'[]0[].1.feet': 5,
'[]0[].1.age': 100,
'[]0[].1.weight': 170,
'[]1[]':[ { name: 'Bob', age: 22, weight: 170 }, { name: 'Bob', feet: 5, age: 100, weight: 170 } ],
'[]1[].0': { name: 'Bob', age: 22, weight: 170 },
'[]1[].0.name': 'Bob',
'[]1[].0.age': 22,
'[]1[].0.weight': 170,
'[]1[].1': { name: 'Bob', feet: 5, age: 100, weight: 170 },
'[]1[].1.name': 'Bob',
'[]1[].1.feet': 5,
'[]1[].1.age': 100,
'[]1[].1.weight': 170,
});
expect(ob.flatten(arr4)).to.deep.equal({
'[]0[]': [ { name: 'Bob', age: 22, weight: 170 }, { name: 'Bob', feet: 5, age: 100, weight: 170 } ],
'[]0[].0': { name: 'Bob', age: 22, weight: 170 },
'[]0[].0.name': 'Bob',
'[]0[].0.age': 22,
'[]0[].0.weight': 170,
'[]0[].1': { name: 'Bob', feet: 5, age: 100, weight: 170 },
'[]0[].1.name': 'Bob',
'[]0[].1.feet': 5,
'[]0[].1.age': 100,
'[]0[].1.weight': 170,
'[]1[]': [ 3, 1 ],
'[]1[].0': 3,
'[]1[].1': 1,
});
done();

@@ -167,3 +219,7 @@ });

expect(ob.expand(ob.flatten(ob4))).to.deep.equal(ob4);
expect(ob.expand(ob.flatten(obArr1))).to.deep.equal(obArr1);
expect(ob.expand(ob.flatten(arr2))).to.deep.equal(arr2);
expect(ob.expand(ob.flatten(arr1))).to.deep.equal(arr1);
expect(ob.expand(ob.flatten(arr3))).to.deep.equal(arr3);
expect(ob.expand(ob.flatten(arr4))).to.deep.equal(arr4);
expect(ob.expand(ob.flatten({tmp: arr4}))).to.deep.equal({tmp: arr4});
done();

@@ -173,9 +229,24 @@ });

describe('clone deep', () => {
describe('clone', () => {
it('should return a clone of the object', (done) => {
expect(ob.cloneDeep(ob3)).to.deep.equal(ob3);
expect(ob.cloneDeep(ob3)).to.not.equal(ob3);
expect(ob.clone(ob3)).to.deep.equal(ob3);
expect(ob.clone(ob3)).to.not.equal(ob3);
done();
});
});
describe('filter', () => {
it('should return an object with undefineds filtered out', (done) => {
expect(ob.filter(ob5, (x) => x !== undefined)).to.deep.equal({
feet: ob5.feet,
body: {
feet: {
toes: [2,10],
},
},
});
done();
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc