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

deepdash

Package Overview
Dependencies
Maintainers
1
Versions
112
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

deepdash - npm Package Compare versions

Comparing version 2.1.3 to 3.1.0

docs/index.md

27

CHANGELOG.md
# Change Log
## unpublished
**Breaking Changes**
- `keepUndefined` option removed from the [filterDeep](/#filterdeep) method. Use onUndefined:{keepIfEmpty:true}, instead.
- `keys` argument of the [omitDeep](/#omitdeep) and [pickDeep](/#pickdeep) methods became `paths`
**Features added**
- `tree` option added to the [filterDeep](/#filterdeep) method.
- `tree` option added to the [indexate](/#indexate) method.
- `tree` option added to the [paths (keysDeep)](/#paths-keysdeep) method.
- `predicate` option of the [filterDeep](/#filterdeep) method is Lodash _.iteratee.
- `cloneDeep` option of the [filterDeep](/#filterdeep) now can be set to `false`.
- `callbackAfterIterate` option added to the [eachDeep](/#eachdeep-foreachdeep) method.
- `onTrue` `onUndefined` and `onFalse` options added to the [filterDeep](/#filterdeep) method. `cloneDeep`, `keepIfEmpty`, `skipChildren` default values can be overwritten for each condition.
- `onMatched` and `onNotMatched` options added to the [omitDeep](/#omitdeep) and [pickDeep](/#pickdeep) methods.
- custom object replies from [filterDeep](/#filterdeep) iteratee, with `cloneDeep`, `keepIfEmpty`, `skipChildren` and `empty` fields now are supported.
**Bugs fixed**
- [filterDeep](/#filterdeep) method continues to iterate over object's children if it passed the filter.
## v2-1-0

@@ -8,3 +31,3 @@ *(2019-03-02)*

- `tree` option added to [eachDeep](/#eachdeep-foreachdeep) method.
- `tree` option added to the [eachDeep](/#eachdeep-foreachdeep) method.
Now it's much easier to iterate over tree with known `children` collection field name / path

@@ -25,3 +48,3 @@

- checkCircular option added to [eachDeep](/#eachdeep-foreachdeep) method.
- checkCircular option added to the [eachDeep](/#eachdeep-foreachdeep) method.
- [pickDeep](/#peekdeep) method implemented.

@@ -28,0 +51,0 @@

375

deepdash.js

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

var rxVarName = /^[a-zA-Z_$]+([\w_$]*)$/;
var errorNoLeavesOnlyAndTree =
'"leavesOnly" option cannot be true in the "tree" mode.';
function pathToString(path) {

@@ -28,2 +30,48 @@ if (_.isString(path)) return path;

}
function pathMatches(path, paths) {
var pathString;
var pathArray;
if (_.isString(path)) {
pathString = path;
} else {
pathArray = path;
}
if (!_.isArray(paths)) {
paths = [paths];
}
for (var i = 0; i < paths.length; i++) {
if (_.isString(paths[i])) {
paths[i] = _.toPath(paths[i]);
}
if (_.isArray(paths[i])) {
if (pathArray === undefined) {
pathArray = _.toPath(pathString);
}
if (
pathArray.length >= paths[i].length &&
_.isEqual(_.takeRight(pathArray, paths[i].length), paths[i])
) {
// console.log('path matched');
return paths[i];
}
} else if (paths[i] instanceof RegExp) {
if (pathString === undefined) {
pathString = pathToString(path);
}
if (paths[i].test(pathString)) {
// console.log('regex matched', paths[i]);
return paths[i];
}
} else {
throw new Error(
'To match path use only string/regex or array of them.'
);
}
}
// console.log('matched nothing');
return false;
}
if (!_.pathMatches) {
_.mixin({ pathMatches: pathMatches }, { chain: false });
}
function iterate(

@@ -53,3 +101,5 @@ value,

parent: parent,
isTreeNode: parent && parent.isTreeChildren,
};
// console.log('it', currentObj.path);
var currentParents = parents.concat(currentObj);

@@ -66,6 +116,2 @@ if (options.tree) {

}
if (!_.isArray(options.tree.children)) {
options.tree.children = [options.tree.children];
}
// console.log('tree options', options.tree);
if (!depth && options.tree.rootIsChildren) {

@@ -76,32 +122,11 @@ currentObj.isTreeChildren = true;

} else {
for (var i = 0; i < options.tree.children.length; i++) {
if (_.isString(options.tree.children[i])) {
options.tree.children[i] = _.toPath(options.tree.children[i]);
}
if (
(_.isArray(options.tree.children[i]) &&
path.length >= options.tree.children[i].length &&
_.isEqual(
_.takeRight(path, options.tree.children[i].length),
options.tree.children[i]
)) ||
(options.tree.children[i].test &&
options.tree.children[i].test(
options.pathFormat == 'string'
? currentObj.path
: pathToString(path)
))
) {
currentObj.isTreeChildren = true;
currentObj.treeChildrenPath =
options.pathFormat == 'array' ||
!_.isArray(options.tree.children[i])
? options.tree.children[i]
: pathToString(options.tree.children[i]);
// console.log('✓ ' + options.tree.children[i], path);
break;
} else {
currentObj.isTreeChildren = false;
// console.log('× ' + options.tree.children[i], path);
}
var matches = pathMatches(path, options.tree.children);
if (matches !== false) {
currentObj.isTreeChildren = true;
currentObj.treeChildrenPath =
options.pathFormat == 'array' || !_.isArray(matches)
? matches
: pathToString(matches);
} else {
currentObj.isTreeChildren = false;
}

@@ -132,2 +157,5 @@ }

isCircular = circularParentIndex !== -1;
if (isCircular) {
//console.log('cr: ', pathToString(childPath));
}
if (options.tree) {

@@ -140,16 +168,18 @@ // console.log(

var res;
var context = {
path:
options.pathFormat == 'array' ? childPath : pathToString(childPath),
parent: currentObj,
parents: currentParents,
obj: obj,
depth: depth,
isCircular: isCircular,
circularParent: circularParent,
circularParentIndex: circularParentIndex,
};
if (!options.tree || currentObj.isTreeChildren) {
res = callback(childValue, childKey, value, {
path:
options.pathFormat == 'array'
? childPath
: pathToString(childPath),
parent: currentObj,
parents: currentParents,
obj: obj,
depth: depth,
isCircular: isCircular,
circularParent: circularParent,
circularParentIndex: circularParentIndex,
});
res = callback(childValue, childKey, value, context);
// console.log('cb', context.path, currentObj.isTreeChildren);
} else {
// console.log('no cb', context.path, currentObj.isTreeChildren);
}

@@ -169,2 +199,9 @@ if (res !== false && !isCircular && _.isObject(value)) {

}
if (
options.callbackAfterIterate &&
(!options.tree || currentObj.isTreeChildren)
) {
context.afterIterate = true;
callback(childValue, childKey, value, context);
}
});

@@ -197,9 +234,13 @@ }

includeCircularPath: true,
leavesOnly: true,
leavesOnly: !options || !options.tree,
},
options || {}
);
if (options.tree && options.leavesOnly) {
throw new Error(errorNoLeavesOnlyAndTree);
}
var eachDeepOptions = {
pathFormat: 'string',
checkCircular: options.checkCircular,
tree: options.tree,
};

@@ -211,3 +252,7 @@ var res = {};

if (!context.isCircular || options.includeCircularPath) {
if (options.leavesOnly && res[context.parent.path]) {
if (
!options.tree &&
options.leavesOnly &&
res[context.parent.path]
) {
delete res[context.parent.path];

@@ -233,3 +278,3 @@ }

includeCircularPath: true,
leavesOnly: true,
leavesOnly: !options || !options.tree,
pathFormat: 'string',

@@ -239,5 +284,9 @@ },

);
if (options.tree && options.leavesOnly) {
throw new Error(errorNoLeavesOnlyAndTree);
}
var eachDeepOptions = {
pathFormat: options.pathFormat,
checkCircular: options.checkCircular,
tree: options.tree,
};

@@ -249,3 +298,7 @@ var res = [];

if (!context.isCircular || options.includeCircularPath) {
if (options.leavesOnly && _.last(res) === context.parent.path) {
if (
!options.tree &&
options.leavesOnly &&
_.last(res) === context.parent.path
) {
res.pop();

@@ -302,2 +355,3 @@ }

var arrays = [];
//console.log('condenseDeep → eachDeep');
_.eachDeep(

@@ -320,5 +374,42 @@ obj,

var filterDeep = function(obj, predicate, options) {
predicate = _.iteratee(predicate);
if (options && options.leafsOnly !== undefined) {
options.leavesOnly = options.leafsOnly;
}
if (!options) {
options = {};
}
if (!options.onTrue) {
options.onTrue = {};
}
if (!options.onFalse) {
options.onFalse = {};
}
if (!options.onUndefined) {
options.onUndefined = {};
}
if (options.tree) {
if (options.leavesOnly) {
throw new Error(errorNoLeavesOnlyAndTree);
}
if (options.onTrue.skipChildren === undefined) {
options.onTrue.skipChildren = false;
}
if (options.onUndefined.skipChildren === undefined) {
options.onUndefined.skipChildren = false;
}
if (options.onFalse.skipChildren === undefined) {
options.onFalse.skipChildren = false;
}
if (options.onTrue.cloneDeep === undefined) {
options.onTrue.cloneDeep = true;
}
if (options.onUndefined.cloneDeep === undefined) {
options.onUndefined.cloneDeep = true;
}
if (options.onFalse.cloneDeep === undefined) {
options.onFalse.cloneDeep = true;
}
}
options = _.merge(

@@ -333,39 +424,108 @@ {

pathFormat: 'string',
keepUndefined: false,
onTrue: { skipChildren: true, cloneDeep: true, keepIfEmpty: true },
onUndefined: {
skipChildren: false,
cloneDeep: false,
keepIfEmpty: false,
},
onFalse: {
skipChildren: true,
cloneDeep: false,
keepIfEmpty: false,
},
},
options || {}
options
);
var eachDeepOptions = {
pathFormat: options.pathFormat,
checkCircular: options.checkCircular,
tree: options.tree,
callbackAfterIterate: true,
};
var res = _.isArray(obj) ? [] : {};
var replies = {};
var foundCircular = [];
//console.log('filterDeep → eachDeep');
_.eachDeep(
obj,
function(value, key, parent, context) {
if (!context.isCircular) {
if (
!_.isObject(value) ||
_.isEmpty(value) ||
!options.leavesOnly
) {
var condition = predicate(value, key, parent, context);
if (condition === true) {
_.set(res, context.path, options.cloneDeep(value));
} else if (condition === undefined && options.keepUndefined) {
_.set(
res,
var curPath = pathToString(context.path);
if (!context.afterIterate) {
if (!context.isCircular) {
// console.log('fr: ', context.path);
var reply;
if (
!options.leavesOnly ||
(context.parent && context.parent.isTreeChildren) ||
!_.isObject(value) ||
_.isEmpty(value)
) {
reply = predicate(value, key, parent, context);
// console.log('?', reply);
}
if (!_.isObject(reply)) {
if (reply === undefined) {
reply = _.clone(options.onUndefined);
} else if (reply) {
reply = _.clone(options.onTrue);
} else {
reply = _.clone(options.onFalse);
}
}
if (reply.empty === undefined) {
reply.empty = true;
}
replies[curPath] = reply;
// console.log('→', replies);
if (reply.keepIfEmpty || !reply.skipChildren) {
if (options.cloneDeep && reply.cloneDeep) {
_.set(res, context.path, options.cloneDeep(value));
} else {
_.set(
res,
context.path,
_.isArray(value)
? []
: _.isPlainObject(value)
? {}
: value
);
}
}
return !reply.skipChildren;
} else {
// console.log('fc: ', context.path);
_.unset(res, context.path);
if (options.keepCircular) {
foundCircular.push([
context.path,
_.isArray(value) ? [] : _.isPlainObject(value) ? {} : value
);
context.circularParent.path,
]);
}
return false;
}
} else if (context.afterIterate && !context.isCircular) {
// console.log('ai: ', context.path);
if (replies[curPath].empty && !replies[curPath].keepIfEmpty) {
_.unset(res, context.path);
} else {
var p = !options.tree
? context.parent
: _.findLast(context.parents, 'isTreeNode');
if (p) {
p = pathToString(p.path);
if (p) {
// if (!replies[p])
// console.log('no reply for "' + p + '"', p);
replies[p].empty = false;
}
}
}
delete replies[curPath];
return condition;
}
// console.log('←', replies);
return;
} else {
if (options.keepCircular) {
foundCircular.push([context.path, context.circularParent.path]);
}
return false;
// console.log('aic: ', context.path);
}

@@ -377,4 +537,5 @@ },

var cv;
var has = c[1] == '' || _.has(res, c[1]);
if (!has) return;
var exists = c[1] == '' || _.exists(res, c[1]);
if (!exists) return;
// console.log('circular: ', c[0], c[1]);
if (_.has(options, 'replaceCircularBy')) {

@@ -389,4 +550,6 @@ cv = options.replaceCircularBy;

});
if (options.condense)
if (options.condense) {
//console.log('filterDeep → condenseDeep');
return _.condenseDeep(res, { checkCircular: options.checkCircular });
}
return res;

@@ -399,10 +562,5 @@ };

if (!_.omitDeep) {
var omitDeep = function(obj, keys, options) {
var omitDeep = function(obj, paths, options) {
options = _.merge(
{
checkCircular: false,
keepCircular: true,
//replaceCircularBy: <by>,
condense: true,
cloneDeep: _.cloneDeep,
invert: false,

@@ -412,24 +570,34 @@ },

);
var isOmit = !options.invert;
options = _.merge(
{
onMatch: {
cloneDeep: false,
skipChildren: false,
keepIfEmpty: !isOmit,
},
onNotMatch: {
cloneDeep: false,
skipChildren: false,
keepIfEmpty: isOmit,
},
},
options
);
options.leavesOnly = false;
options.tree = false;
options.pathFormat = 'array';
options.keepUndefined = !options.invert;
options.onTrue = options.invert ? options.onMatch : options.onNotMatch;
options.onFalse = options.invert ? options.onNotMatch : options.onMatch;
if (!_.isArray(keys)) keys = [keys];
keys = _.groupBy(keys, function(key) {
return key instanceof RegExp ? 'regex' : 'const';
});
var test = function(value, key) {
if (_.includes(keys.const, key)) {
var test = function(value, key, parent, context) {
if (pathMatches(context.path, paths) !== false) {
// console.log('path match, return ', options.invert);
return options.invert;
} else {
// console.log('path not match, return ', !options.invert);
return !options.invert;
}
if (
_.some(keys.regex, function(rx) {
return rx.test(key);
})
) {
return options.invert;
}
if (_.isObject(value) && _.size(value) !== 0) return undefined;
return !options.invert;
};
// console.log(options);
return _.filterDeep(obj, test, options);

@@ -441,6 +609,11 @@ };

if (!_.pickDeep) {
var pickDeep = function(obj, keys, options) {
options = options || {};
var pickDeep = function(obj, paths, options) {
options = _.merge(
{
invert: false,
},
options || {}
);
options.invert = true;
return _.omitDeep(obj, keys, options);
return _.omitDeep(obj, paths, options);
};

@@ -447,0 +620,0 @@ _.mixin({ pickDeep: pickDeep });

{
"name": "deepdash",
"version": "2.1.3",
"version": "3.1.0",
"description": "➔ 𝐃eep extension for 𝐋odash: ✓ eachDeep ✓ filterDeep ✓ pickDeep ✓ omitDeep ✓ keysDeep ✓ indexate ✓ condenseDeep ⋮ Parent nodes tracking ⋮ Circular references check ⋮ Leaves only mode ⋮ Path as a valid js string or an array ⋮",

@@ -14,3 +14,3 @@ "main": "deepdash.js",

"coverage": "nyc report --reporter=text-lcov | coveralls",
"dev": "nodemon ./node_modules/.bin/mocha --reporter min --no-deprecation"
"dev": "nodemon ./node_modules/.bin/mocha -g 'pickDeep no mutation' --reporter min --no-deprecation"
},

@@ -17,0 +17,0 @@ "repository": {

@@ -9,15 +9,2 @@ <img src="deepdash.svg?sanitize=true" width="64px"/>

## Methods
(links to docs)
- [condense](https://deepdash.io/#condense) - condense sparse array
- [condenseDeep](https://deepdash.io/#condensedeep) - condense all the nested arrays
- [eachDeep](https://deepdash.io/#eachdeep-foreachdeep) - (forEachDeep) iterate over all the children and sub-children
- [exists](https://deepdash.io/#exists) - like a `_.has` but returns `false` for empty array slots
- [filterDeep](https://deepdash.io/#filterdeep) - deep filter object
- [indexate](https://deepdash.io/#indexate) - get an object with all the paths as keys and corresponding values
- [pickDeep](https://deepdash.io/#pickdeep) - get object only with keys specified by names or regexes
- [omitDeep](https://deepdash.io/#omitdeep) - get object without keys specified by names or regexes
- [paths](https://deepdash.io/#paths-keysdeep) - (keysDeep) get an array of paths
- [pathToString](https://deepdash.io/#pathtostring) - convert an array to string path (opposite to _.toPath)
### Installation

@@ -44,88 +31,642 @@ In a browser load [script](https://cdn.jsdelivr.net/npm/deepdash/deepdash.min.js) after Lodash:

```
### Usage
## Methods
### eachDeep(forEachDeep) - iterate over all the children and sub-children (📚 [docs](https://deepdash.io/#eachdeep-foreachdeep))
<details>
<summary>Example</summary>
[children example collection is here](#example-collection)
```js
let obj = {
a: {
b: {
c: {
d: [
{ i: 0 },
{ i: 1 },
{ i: 2 },
{ i: 3 },
{ i: 4 },
{ i: 5 },
{
o: {
d: new Date(),
f: function() {},
skip: {
please: {
dont: {
go: {
here: 'skip it',
},
},
},
},
},
},
],
s: 'hello',
let children = [/* ... */];
function displayField(val, key, parent, context) {
if (_.isArray(parent)) {
key = '[' + key + ']';
}
console.log(
_.repeat(' ', context.depth) +
'→ ' +
key +
': ' +
(_.isArray(val)
? '[' + val.length + ']'
: _.isObject(val)
? '{' + (val.name || '') + '}'
: val)
);
}
console.log('\n = Iterate over tree (each child object) = \n');
_.eachDeep(children, displayField, { tree: true });
console.log('\n = Iterate over object (each field) = \n');
_.eachDeep(children, displayField);
```
Console:
```
= Iterate over tree (each child object) =
→ [0]: {node 1}
→ [0]: {node 1.1}
→ [1]: {node 1.2}
→ [2]: {node 1.3}
→ [1]: {node 2}
→ [0]: {node 2.1}
→ [1]: {node 2.2}
→ [2]: {node 2.3}
→ [2]: {node 3}
→ [0]: {node 3.1}
→ [1]: {node 3.2}
→ [2]: {node 3.3}
= Iterate over object (each field) =
→ [0]: {node 1}
→ description: description for node 1
→ comment: comment for node 1
→ note: note for node 1
→ name: node 1
→ bad: false
→ children: [3]
→ [0]: {node 1.1}
→ description: description for node 1.1
→ comment: comment for node 1.1
→ note: note for node 1.1
→ name: node 1.1
→ bad: false
→ [1]: {node 1.2}
→ description: description for node 1.2
→ comment: comment for node 1.2
→ note: note for node 1.2
→ name: node 1.2
→ good: true
→ [2]: {node 1.3}
→ description: description for node 1.3
→ comment: comment for node 1.3
→ note: note for node 1.3
→ name: node 1.3
→ bad: true
→ good: false
→ [1]: {node 2}
→ description: description for node 2
→ comment: comment for node 2
→ note: note for node 2
→ name: node 2
→ good: true
→ children: [3]
→ [0]: {node 2.1}
→ description: description for node 2.1
→ comment: comment for node 2.1
→ note: note for node 2.1
→ name: node 2.1
→ bad: false
→ [1]: {node 2.2}
→ description: description for node 2.2
→ comment: comment for node 2.2
→ note: note for node 2.2
→ name: node 2.2
→ good: true
→ [2]: {node 2.3}
→ description: description for node 2.3
→ comment: comment for node 2.3
→ note: note for node 2.3
→ name: node 2.3
→ bad: true
→ good: false
→ [2]: {node 3}
→ description: description for node 3
→ comment: comment for node 3
→ note: note for node 3
→ name: node 3
→ bad: true
→ good: false
→ children: [3]
→ [0]: {node 3.1}
→ description: description for node 3.1
→ comment: comment for node 3.1
→ note: note for node 3.1
→ name: node 3.1
→ bad: false
→ [1]: {node 3.2}
→ description: description for node 3.2
→ comment: comment for node 3.2
→ note: note for node 3.2
→ name: node 3.2
→ good: true
→ [2]: {node 3.3}
→ description: description for node 3.3
→ comment: comment for node 3.3
→ note: note for node 3.3
→ name: node 3.3
→ bad: true
→ good: false
```
</details>
### filterDeep - deep filter object (📚 [docs](https://deepdash.io/#filterdeep))
<details>
<summary>Example</summary>
[children example collection is here](#example-collection)
```js
let children = [/* ... */];
console.log('\n = Filter tree (good children) = \n');
console.log(
_.filterDeep(children, 'good', { tree: true })
);
console.log('\n = Filter object (names of good children) = \n');
console.log(
_.filterDeep(children, (val, key, parent) => {
if (key == 'name' && parent.good) return true;
})
);
```
Console:
```
= Filter tree (good children) =
[
{
"description": "description for node 1",
"comment": "comment for node 1",
"note": "note for node 1",
"name": "node 1",
"bad": false,
"children": [
{
"description": "description for node 1.2",
"comment": "comment for node 1.2",
"note": "note for node 1.2",
"name": "node 1.2",
"good": true
}
]
},
{
"description": "description for node 2",
"comment": "comment for node 2",
"note": "note for node 2",
"name": "node 2",
"good": true,
"children": [
{
"description": "description for node 2.2",
"comment": "comment for node 2.2",
"note": "note for node 2.2",
"name": "node 2.2",
"good": true
}
]
},
{
"description": "description for node 3",
"comment": "comment for node 3",
"note": "note for node 3",
"name": "node 3",
"bad": true,
"good": false,
"children": [
{
"description": "description for node 3.2",
"comment": "comment for node 3.2",
"note": "note for node 3.2",
"name": "node 3.2",
"good": true
}
]
}
]
= Filter object (names of good children) =
[
{
"children": [
{
"name": "node 1.2"
}
]
},
{
"name": "node 2",
"children": [
{
"name": "node 2.2"
}
]
},
{
"children": [
{
"name": "node 3.2"
}
]
}
]
```
</details>
### pickDeep - get object only with keys specified by names or regexes (📚 [docs](https://deepdash.io/#pickdeep))
<details>
<summary>Example</summary>
[children example collection is here](#example-collection)
```js
let children = [/* ... */];
console.log('\n = Pick name and description only = \n');
console.log(
_.pickDeep(children, ['name', 'description'])
);
```
Console:
```
= Pick name and description only =
[
{
"description": "description for node 1",
"name": "node 1",
"children": [
{
"description": "description for node 1.1",
"name": "node 1.1"
},
b: true,
},
n: 12345,
u: undefined,
{
"description": "description for node 1.2",
"name": "node 1.2"
},
{
"description": "description for node 1.3",
"name": "node 1.3"
}
]
},
nl: null,
};
_.eachDeep(obj, (value, key, parent, context) => {
{
"description": "description for node 2",
"name": "node 2",
"children": [
{
"description": "description for node 2.1",
"name": "node 2.1"
},
{
"description": "description for node 2.2",
"name": "node 2.2"
},
{
"description": "description for node 2.3",
"name": "node 2.3"
}
]
},
{
"description": "description for node 3",
"name": "node 3",
"children": [
{
"description": "description for node 3.1",
"name": "node 3.1"
},
{
"description": "description for node 3.2",
"name": "node 3.2"
},
{
"description": "description for node 3.3",
"name": "node 3.3"
}
]
}
]
```
</details>
### omitDeep - get object without keys specified by names or regexes (📚 [docs](https://deepdash.io/#omitdeep))
<details>
<summary>Example</summary>
[children example collection is here](#example-collection)
```js
let children = [/* ... */];
console.log('\n = Omit paths not ending with "e" = \n');
console.log(
_.repeat(' ', context.depth) +
key +
':' +
(value === null ? 'null' : typeof value),
context.parent.path && ' @' + context.parent.path
_.omitDeep(children, /[^e]$/i, { onMatch: { skipChildren: false } }),
);
if (key == 'skip') {
return false; // return false explicitly to skip iteration over current value's children
```
Console:
```
= Omit paths not ending with "e" =
[
{
"note": "note for node 1",
"name": "node 1",
"children": [
{
"note": "note for node 1.1",
"name": "node 1.1"
},
{
"note": "note for node 1.2",
"name": "node 1.2"
},
{
"note": "note for node 1.3",
"name": "node 1.3"
}
]
},
{
"note": "note for node 2",
"name": "node 2",
"children": [
{
"note": "note for node 2.1",
"name": "node 2.1"
},
{
"note": "note for node 2.2",
"name": "node 2.2"
},
{
"note": "note for node 2.3",
"name": "node 2.3"
}
]
},
{
"note": "note for node 3",
"name": "node 3",
"children": [
{
"note": "note for node 3.1",
"name": "node 3.1"
},
{
"note": "note for node 3.2",
"name": "node 3.2"
},
{
"note": "note for node 3.3",
"name": "node 3.3"
}
]
}
});
]
```
</details>
### indexate - get an object with all the paths as keys and corresponding values (📚 [docs](https://deepdash.io/#indexate))
<details>
<summary>Example</summary>
```js
let index = _.indexate(
{
a: {
b: {
c: [1, 2, 3],
'hello world': {},
},
},
},
{ leavesOnly: true }
);
console.log(index);
```
Console:
```json
a:object
b:object @a
c:object @a.b
d:object @a.b.c
0:object @a.b.c.d
i:number @a.b.c.d[0]
1:object @a.b.c.d
i:number @a.b.c.d[1]
2:object @a.b.c.d
i:number @a.b.c.d[2]
3:object @a.b.c.d
i:number @a.b.c.d[3]
4:object @a.b.c.d
i:number @a.b.c.d[4]
5:object @a.b.c.d
i:number @a.b.c.d[5]
6:object @a.b.c.d
o:object @a.b.c.d[6]
d:object @a.b.c.d[6].o
f:function @a.b.c.d[6].o
skip:object @a.b.c.d[6].o
s:string @a.b.c
b:boolean @a.b
n:number @a
u:undefined @a
nl:null
```
Chaining works too:
{ 'a.b.c[0]': 1,
'a.b.c[1]': 2,
'a.b.c[2]': 3,
'a.b["hello world"]': {} }
```
</details>
### paths(keysDeep) - get an array of paths (📚 [docs](https://deepdash.io/#paths-keysdeep))
<details>
<summary>Example</summary>
```js
_(obj).eachDeep((value, key, parent, context) => {/* do */}).value();
let paths = _.paths(
{
a: {
b: {
c: [1, 2, 3],
'hello world': {},
},
},
},
{ leavesOnly: false }
);
console.log(paths);
```
### See [docs](https://deepdash.io) for details.
Console:
```
[ 'a',
'a.b',
'a.b.c',
'a.b.c[0]',
'a.b.c[1]',
'a.b.c[2]',
'a.b["hello world"]' ]
```
</details>
### condense - condense sparse array (📚 [docs](https://deepdash.io/#condense))
<details>
<summary>Example</summary>
```js
let arr = ['a', 'b', 'c', 'd', 'e'];
delete arr[1];
console.log(arr);
delete arr[3];
console.log(arr);
_.condense(arr);
console.log(arr);
```
Console:
```
[ 'a', <1 empty item>, 'c', 'd', 'e' ]
[ 'a', <1 empty item>, 'c', <1 empty item>, 'e' ]
[ 'a', 'c', 'e' ]
```
</details>
### condenseDeep - condense all the nested arrays (📚 [docs](https://deepdash.io/#condensedeep))
<details>
<summary>Example</summary>
```js
let obj = { arr: ['a', 'b', { c: [1, , 2, , 3] }, 'd', 'e'] };
delete obj.arr[1];
delete obj.arr[3];
_.condenseDeep(obj);
console.log(obj);
```
Console:
```
{ arr: [ 'a', { c: [ 1, 2, 3 ] }, 'e' ] }
```
</details>
### exists - like a `_.has` but returns `false` for empty array slots (📚 [docs](https://deepdash.io/#exists))
<details>
<summary>Example</summary>
```js
var obj = [, { a: [, 'b'] }];
console.log(_.exists(obj, 0)); // false
console.log(_.exists(obj, 1)); // true
console.log(_.exists(obj, '[1].a[0]')); // false
console.log(_.exists(obj, '[1].a[1]')); // true
```
</details>
### pathToString - convert an array to string path (opposite to _.toPath) (📚 [docs](https://deepdash.io/#pathtostring))
<details>
<summary>Example</summary>
```js
console.log(_.pathToString(['a', 'b', 'c', 'defg', 0, '1', 2.3]));
// a.b.c.defg[0][1]["2.3"]
console.log(_.pathToString(['"', '"', '"']));
// ["\\""]["\\""]["\\""]
console.log(_.pathToString('it.s.a.string'));
// it.s.a.string
```
</details>
#### Example Collection
<details>
<summary>'children' object used in examples above</summary>
```js
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
```
</details>
### See [full docs](https://deepdash.io) for details.

@@ -39,2 +39,10 @@ 'use strict';

});
it('Completely filtered out', () => {
let obj = { a: { b: undefined } };
let filtrate = _.filterDeep(obj, isNS, {
leavesOnly: true,
});
//console.log(filtrate);
expect(filtrate).to.deep.equal({});
});
it('Count paths circular', () => {

@@ -89,7 +97,29 @@ let filtrate = _.filterDeep(circular, isNS, {

leavesOnly: false,
cloneDeep: (o) => (_.isArray(o) ? [] : _.isObject ? {} : o),
onTrue: { skipChildren: false },
})
.paths({ leavesOnly: false })
.omitDeep('o.d', { onMatch: {} })
.value();
expect(_.size(filtrate)).equal(18);
// console.log(JSON.stringify(filtrate));
expect(filtrate).to.deep.equal({
a: {
b: {
c: {
d: [
{},
{},
{},
{},
{},
{},
{
o: {
f: {},
skip: { please: { dont: { go: {} } } },
},
},
],
},
},
},
});
});

@@ -117,10 +147,9 @@ it('Circular', () => {

});
// console.log(circular);
//console.log(filtrate);
filtrate = _.paths(filtrate, {
leavesOnly: true,
checkCircular: true,
});
// console.log(filtrate);
expect(_.size(filtrate)).equal(8);
let err;
try {
JSON.stringify(filtrate);
} catch (exc) {
err = exc;
}
expect(err).equal(undefined);
});

@@ -149,3 +178,4 @@ it('Not matched circular ', () => {

});
filtrate.should.deep.equal({ a: [, , { b: true }] });
// console.log(filtrate);
filtrate.should.deep.equal({ a: [, , { b: true }, ,] });
});

@@ -175,94 +205,3 @@ it('replaceCircularBy', () => {

});
it('array path format', () => {
const input = [
{
value: 'Miss1',
children: [
{ value: 'Miss2' },
{ value: 'Hit1', children: [{ value: 'Miss3' }] },
],
},
{
value: 'Miss4',
children: [
{ value: 'Miss5' },
{ value: 'Miss6', children: [{ value: 'Hit2' }] },
],
},
{
value: 'Miss7',
children: [
{ value: 'Miss8' },
{ value: 'Miss9', children: [{ value: 'Miss10' }] },
],
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [{ value: 'Miss13' }] },
],
},
{
value: 'Miss14',
children: [
{ value: 'Hit4' },
{ value: 'Miss15', children: [{ value: 'Miss16' }] },
],
},
];
var keyword = 'Hit';
// We will need 2 passes, first - to collect needed nodes with 'Hit' value:
var foundHit = _.filterDeep(
input,
function(value, key, parent, ctx) {
expect(ctx.path).to.be.an.array();
expect(ctx.parent.path).to.be.an.array();
if (value.value && value.value.includes(keyword)) return true;
},
{
condense: false, // keep empty slots in array to preserve correct paths
leavesOnly: false,
pathFormat: 'array',
}
);
// second pass - to add missed fields both for found 'Hit' nodes and their parents.
var filtrate = _.filterDeep(
input,
function(value, key, parent, ctx) {
expect(ctx.path).to.be.an.array();
expect(ctx.parent.path).to.be.an.array();
if (
_.get(foundHit, ctx.path) !== undefined ||
_.get(foundHit, ctx.parent.path) !== undefined
) {
return true;
}
},
{
pathFormat: 'array',
}
);
expect(filtrate).to.deep.equal([
{
value: 'Miss1',
children: [{ value: 'Hit1', children: [{ value: 'Miss3' }] }],
},
{
value: 'Miss4',
children: [{ value: 'Miss6', children: [{ value: 'Hit2' }] }],
},
{
value: 'Hit3',
children: [
{ value: 'Miss11' },
{ value: 'Miss12', children: [{ value: 'Miss13' }] },
],
},
{
value: 'Miss14',
children: [{ value: 'Hit4' }],
},
]);
});
it('keepUndefined', () => {

@@ -278,3 +217,3 @@ let filtrate = _.filterDeep(

leavesOnly: false,
keepUndefined: true,
onUndefined: { keepIfEmpty: true },
}

@@ -310,2 +249,64 @@ );

});
it('Custom reply', () => {
let filtrate = _.filterDeep(demo, (v) => {
if (v instanceof Date) {
return {
cloneDeep: false,
keepIfEmpty: false,
skipChildren: true,
empty: true,
};
}
let t = typeof v;
if (t == 'object') {
return { cloneDeep: false, keepIfEmpty: true };
}
if (t == 'string' || t == 'number') return true;
});
// console.log(JSON.stringify(filtrate, null, 2));
expect(filtrate).to.deep.equal({
a: {
b: {
c: {
d: [
{
i: 0,
},
{
i: 1,
},
{
i: 2,
},
{
i: 3,
},
{
i: 4,
},
{
i: 5,
},
{
o: {
skip: {
please: {
dont: {
go: {
here: 'skip it',
},
},
},
},
},
},
],
s: 'hello',
},
},
n: 12345,
},
nl: null,
});
});
});

@@ -12,3 +12,3 @@ 'use strict';

var { demo, circular } = require('./object');
var { demo, circular, children } = require('./object');

@@ -73,5 +73,5 @@ describe('indexate', () => {

});
it('Leafs only', () => {
let index = _.indexate(demo, { leavesOnly: true });
// console.log(index);
expect(_.size(index)).equal(14);

@@ -103,2 +103,35 @@ });

});
it('No leavesOnly in tree', () => {
try {
_.indexate(children, { tree: true, leavesOnly: true });
} catch (exc) {
expect(exc.message).equal(
'"leavesOnly" option cannot be true in the "tree" mode.'
);
}
});
it('Indexate tree', () => {
let index = _.indexate(children, { tree: true });
let names = _(index)
.values()
.map('name')
.value();
// console.log(names);
expect(names).to.deep.equal([
'grand 1',
'parent 1.1',
'child 1.1.1',
'child 1.1.2',
'parent 1.2',
'child 1.2.1',
'child 1.2.2',
'grand 2',
'parent 2.1',
'child 2.1.1',
'child 2.1.2',
'parent 2.2',
'child 2.2.1',
'child 2.2.2',
]);
});
});

@@ -41,13 +41,2 @@ 'use strict';

},
circular: {
a: {
b: {
c: {
// e: circular.a.b,
hi: 'planet',
},
},
},
i: [1, 2, 3, 4, { hello: 'world' }],
},
children: [

@@ -178,2 +167,89 @@ {

],
verifiedComments: [
{
name: 'Bob',
text: 'Perfect!',
rating: 5,
verified: true,
replies: [
{
name: 'admin',
text: 'Thank you!',
verified: true,
replies: [
{
name: 'Bob',
text: 'Write more!',
verified: true,
replies: [
{
name: 'admin',
text: 'Ok :)',
verified: true,
},
],
},
],
},
{
name: 'Augusta',
text: 'like a brillaint!11',
verified: true,
},
],
},
{
name: 'mr.John',
text: 'Well done..',
rating: 4,
verified: false,
replies: [
{
name: 'admin',
text: 'Can it be better?',
verified: true,
replies: [
{
name: 'mr.John',
text: 'May be last three lines can be shorter..',
verified: false,
replies: [
{
name: 'Bob',
verified: true,
text: "Don't listen to him, it will be unreadable!",
},
],
},
],
},
],
},
{
name: 'Mark',
rating: 5,
text: 'Any way to donate?',
verified: false,
replies: [
{
name: 'Larry',
text: '+1',
verified: true,
},
],
},
{
name: 'Regina',
rating: 2,
text: 'Not really like it',
verified: true,
replies: [
{
name: 'admin',
text: ':(',
verified: true,
},
],
},
],
deeperComments: [

@@ -343,4 +419,56 @@ {

],
badChildren: [
{
name: '1',
bad: false,
children: [
{ name: '1.1', bad: false },
{ name: '1.2' },
{ name: '1.3', bad: true },
],
},
{
name: '2',
children: [
{ name: '2.1', bad: false },
{ name: '2.2' },
{ name: '2.3', bad: true },
],
},
{
name: '3',
bad: true,
children: [
{ name: '3.1', bad: false },
{ name: '3.2' },
{ name: '3.3', bad: true },
],
},
],
};
module.exports.circular = {
a: {
b: {
c: {
// e: circular.a.b,
hi: 'planet',
},
},
},
i: [
1,
2,
3,
4,
{
hello: 'world',
} /*
,[
circular
,[circular.a]
,{j:{ hello: 'world' }
,{k:circular}}]*/,
],
};
module.exports.circular.a.b.c.e = module.exports.circular.a.b;

@@ -351,3 +479,3 @@ module.exports.circular.i.push([

{ j: module.exports.circular.i[4] },
{ k: module.exports.circular.i[5] },
{ k: undefined },
]);

@@ -354,0 +482,0 @@

@@ -19,3 +19,3 @@ 'use strict';

let clean = _.omitDeep(obj, 'skip');
clean = _.omitDeep(clean, 'o');
clean = _.omitDeep(clean, 'o', { onMatch: { skipChildren: true } });
expect(clean).to.deep.equal({

@@ -39,3 +39,3 @@ a: {

let clean = _.omitDeep(demo, 'skip');
clean = _.omitDeep(clean, 'o');
clean = _.omitDeep(clean, 'o', { onMatch: { skipChildren: true } });
expect(clean).to.deep.equal({

@@ -65,3 +65,5 @@ a: {

};
let clean = _.omitDeep(obj, ['bad1', 'bad2', 'bad3', 'bad4', 'bad5']);
let clean = _.omitDeep(obj, ['bad1', 'bad2', 'bad3', 'bad4', 'bad5'], {
onMatch: { skipChildren: true },
});
expect(clean).to.deep.equal({

@@ -82,3 +84,3 @@ good1: true,

};
let clean = _.omitDeep(obj, /^bad.*$/);
let clean = _.omitDeep(obj, /\.?bad.*$/);
expect(clean).to.deep.equal({

@@ -85,0 +87,0 @@ good1: true,

@@ -12,3 +12,3 @@ 'use strict';

var { demo, circular } = require('./object');
var { demo, circular, children } = require('./object');

@@ -162,2 +162,33 @@ describe('paths', () => {

});
it('No leavesOnly in tree', () => {
try {
_.paths(children, { tree: true, leavesOnly: true });
} catch (exc) {
expect(exc.message).equal(
'"leavesOnly" option cannot be true in the "tree" mode.'
);
}
});
it('paths of tree', () => {
let paths = _.paths(children, { tree: true });
// console.log(paths);
expect(paths).to.deep.equal([
'[0]',
'[0].children[0]',
'[0].children[0].children[0]',
'[0].children[0].children[1]',
'[0].children[1]',
'[0].children[1].children[0]',
'[0].children[1].children[1]',
'[1]',
'[1].children[0]',
'[1].children[0].children[0]',
'[1].children[0].children[1]',
'[1].children[1]',
'[1].children[1].children[0]',
'[1].children[1].children[1]',
]);
});
});

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

describe('pickDeep', () => {
it('no mutation', () => {
it('pickDeep no mutation', () => {
let orig = _.cloneDeep(demo);
let obj = _.cloneDeep(demo);
let clean = _.pickDeep(obj, 'skip');
let clean = _.pickDeep(obj, 'skip', {
onMatch: { cloneDeep: true, skipChildren: true },
});
expect(clean).to.deep.equal({

@@ -46,3 +48,5 @@ a: {

it('demo skip', () => {
let clean = _.pickDeep(demo, 'skip');
let clean = _.pickDeep(demo, 'skip', {
onMatch: { skipChildren: true, cloneDeep: true },
});

@@ -82,10 +86,7 @@ expect(clean).to.deep.equal({

};
let clean = _.pickDeep(obj, [
'good1',
'good2',
'good3',
'good',
'good4',
'good5',
]);
let clean = _.pickDeep(
obj,
['good1', 'good2', 'good3', 'good', 'good4', 'good5'],
{ onMatch: { cloneDeep: true, skipChildren: true } }
);
expect(clean).to.deep.equal({

@@ -107,3 +108,3 @@ good1: true,

};
let clean = _.pickDeep(obj, /^good.*$/);
let clean = _.pickDeep(obj, /\.?good.*$/);
expect(clean).to.deep.equal({

@@ -110,0 +111,0 @@ good1: true,

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

);
//console.log(index);
expect(index).to.deep.equal({

@@ -144,3 +145,3 @@ 'a.b.c[0]': 1,

it('keysDeep', () => {
let keys = _.keysDeep(
let paths = _.paths(
{

@@ -156,3 +157,4 @@ a: {

);
expect(keys).to.deep.equal([
// console.log(paths);
expect(paths).to.deep.equal([
'a',

@@ -273,8 +275,10 @@ 'a.b',

good2: { good3: true },
bad2: { good: true },
good4: [{ good5: true }],
});
clean = _.omitDeep(obj, /^bad.*$/);
clean = _.omitDeep(obj, /\.?bad\d?$/);
expect(clean).to.deep.equal({
good1: true,
good2: { good3: true },
bad2: { good: true },
good4: [{ good5: true }],

@@ -303,14 +307,524 @@ });

good1: true,
good2: { good3: true, bad3: true },
good2: { good3: true },
bad2: { good: true },
good4: [{ good5: true, bad5: true }],
good4: [{ good5: true }],
});
clean = _.pickDeep(obj, /^good.*$/);
clean = _.pickDeep(obj, /\.?good\d?$/);
expect(clean).to.deep.equal({
good1: true,
good2: { good3: true, bad3: true },
good2: { good3: true },
bad2: { good: true },
good4: [{ good5: true, bad5: true }],
good4: [{ good5: true }],
});
});
it('usage', () => {
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
let out = [];
function displayField(val, key, parent, context) {
if (_.isArray(parent)) {
key = '[' + key + ']';
}
// console.log(
out.push(
_.repeat(' ', context.depth) +
'→ ' +
key +
': ' +
(_.isArray(val)
? '[' + val.length + ']'
: _.isObject(val)
? '{' + (val.name || '') + '}'
: val)
);
}
// console.log('\n = Iterate over tree (each child object) = \n');
_.eachDeep(children, displayField, { tree: true });
// console.log('\n = Iterate over object (each field) = \n');
_.eachDeep(children, displayField);
expect(out).to.deep.equal([
'→ [0]: {node 1}',
' → [0]: {node 1.1}',
' → [1]: {node 1.2}',
' → [2]: {node 1.3}',
'→ [1]: {node 2}',
' → [0]: {node 2.1}',
' → [1]: {node 2.2}',
' → [2]: {node 2.3}',
'→ [2]: {node 3}',
' → [0]: {node 3.1}',
' → [1]: {node 3.2}',
' → [2]: {node 3.3}',
'→ [0]: {node 1}',
' → description: description for node 1',
' → comment: comment for node 1',
' → note: note for node 1',
' → name: node 1',
' → bad: false',
' → children: [3]',
' → [0]: {node 1.1}',
' → description: description for node 1.1',
' → comment: comment for node 1.1',
' → note: note for node 1.1',
' → name: node 1.1',
' → bad: false',
' → [1]: {node 1.2}',
' → description: description for node 1.2',
' → comment: comment for node 1.2',
' → note: note for node 1.2',
' → name: node 1.2',
' → good: true',
' → [2]: {node 1.3}',
' → description: description for node 1.3',
' → comment: comment for node 1.3',
' → note: note for node 1.3',
' → name: node 1.3',
' → bad: true',
' → good: false',
'→ [1]: {node 2}',
' → description: description for node 2',
' → comment: comment for node 2',
' → note: note for node 2',
' → name: node 2',
' → good: true',
' → children: [3]',
' → [0]: {node 2.1}',
' → description: description for node 2.1',
' → comment: comment for node 2.1',
' → note: note for node 2.1',
' → name: node 2.1',
' → bad: false',
' → [1]: {node 2.2}',
' → description: description for node 2.2',
' → comment: comment for node 2.2',
' → note: note for node 2.2',
' → name: node 2.2',
' → good: true',
' → [2]: {node 2.3}',
' → description: description for node 2.3',
' → comment: comment for node 2.3',
' → note: note for node 2.3',
' → name: node 2.3',
' → bad: true',
' → good: false',
'→ [2]: {node 3}',
' → description: description for node 3',
' → comment: comment for node 3',
' → note: note for node 3',
' → name: node 3',
' → bad: true',
' → good: false',
' → children: [3]',
' → [0]: {node 3.1}',
' → description: description for node 3.1',
' → comment: comment for node 3.1',
' → note: note for node 3.1',
' → name: node 3.1',
' → bad: false',
' → [1]: {node 3.2}',
' → description: description for node 3.2',
' → comment: comment for node 3.2',
' → note: note for node 3.2',
' → name: node 3.2',
' → good: true',
' → [2]: {node 3.3}',
' → description: description for node 3.3',
' → comment: comment for node 3.3',
' → note: note for node 3.3',
' → name: node 3.3',
' → bad: true',
' → good: false',
]);
// console.log('\n = Filter tree (good children) = \n');
// console.log(
// JSON.stringify(_.filterDeep(children, 'good', { tree: true }), null, 2)
// );
expect(_.filterDeep(children, 'good', { tree: true })).to.deep.equal([
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
],
},
]);
// console.log('\n = Filter object (names of good children) = \n');
// console.log(
// JSON.stringify(
// _.filterDeep(children, (val, key, parent) => {
// if (key == 'name' && parent.good) return true;
// }),
// null,
// 2
// )
// );
expect(
_.filterDeep(children, (val, key, parent) => {
if (key == 'name' && parent.good) return true;
})
).to.deep.equal([
{
children: [
{
name: 'node 1.2',
},
],
},
{
name: 'node 2',
children: [
{
name: 'node 2.2',
},
],
},
{
children: [
{
name: 'node 3.2',
},
],
},
]);
let badChildren = [
{
name: '1',
bad: false,
children: [
{ name: '1.1', bad: false },
{ name: '1.2' },
{ name: '1.3', bad: true },
],
},
{
name: '2',
children: [
{ name: '2.1', bad: false },
{ name: '2.2' },
{ name: '2.3', bad: true },
],
},
{
name: '3',
bad: true,
children: [
{ name: '3.1', bad: false },
{ name: '3.2' },
{ name: '3.3', bad: true },
],
},
];
let reallyBad = _.filterDeep(badChildren, 'bad', { tree: true });
// console.log(JSON.stringify(reallyBad, null, 2));
expect(reallyBad).to.deep.equal([
{
name: '1',
bad: false,
children: [
{
name: '1.3',
bad: true,
},
],
},
{
name: '2',
children: [
{
name: '2.3',
bad: true,
},
],
},
{
name: '3',
bad: true,
children: [
{
name: '3.3',
bad: true,
},
],
},
]);
// console.log('\n = Pick name and description only = \n');
// console.log(
// JSON.stringify(_.pickDeep(children, ['name', 'description']), null, 2)
// );
expect(_.pickDeep(children, ['name', 'description'])).to.deep.equal([
{
description: 'description for node 1',
name: 'node 1',
children: [
{
description: 'description for node 1.1',
name: 'node 1.1',
},
{
description: 'description for node 1.2',
name: 'node 1.2',
},
{
description: 'description for node 1.3',
name: 'node 1.3',
},
],
},
{
description: 'description for node 2',
name: 'node 2',
children: [
{
description: 'description for node 2.1',
name: 'node 2.1',
},
{
description: 'description for node 2.2',
name: 'node 2.2',
},
{
description: 'description for node 2.3',
name: 'node 2.3',
},
],
},
{
description: 'description for node 3',
name: 'node 3',
children: [
{
description: 'description for node 3.1',
name: 'node 3.1',
},
{
description: 'description for node 3.2',
name: 'node 3.2',
},
{
description: 'description for node 3.3',
name: 'node 3.3',
},
],
},
]);
// console.log('\n = Omit paths not ending with "e" = \n');
// console.log(
// JSON.stringify(
// _.omitDeep(children, /[^e]$/i, { onMatch: { skipChildren: false } }),
// null,
// 2
// )
// );
expect(
_.omitDeep(children, /[^e]$/i, { onMatch: { skipChildren: false } })
).to.deep.equal([
{
note: 'note for node 1',
name: 'node 1',
children: [
{
note: 'note for node 1.1',
name: 'node 1.1',
},
{
note: 'note for node 1.2',
name: 'node 1.2',
},
{
note: 'note for node 1.3',
name: 'node 1.3',
},
],
},
{
note: 'note for node 2',
name: 'node 2',
children: [
{
note: 'note for node 2.1',
name: 'node 2.1',
},
{
note: 'note for node 2.2',
name: 'node 2.2',
},
{
note: 'note for node 2.3',
name: 'node 2.3',
},
],
},
{
note: 'note for node 3',
name: 'node 3',
children: [
{
note: 'note for node 3.1',
name: 'node 3.1',
},
{
note: 'note for node 3.2',
name: 'node 3.2',
},
{
note: 'note for node 3.3',
name: 'node 3.3',
},
],
},
]);
});
});

@@ -93,21 +93,11 @@ 'use strict';

var idList = [2, 3];
// We will need 2 passes, first - to collect needed 'id' nodes:
var foundIds = _.filterDeep(
var found = _.filterDeep(
obj,
function(value, key) {
if (key == 'id' && _.indexOf(idList, value) !== -1) return true;
function(value) {
return _.indexOf(idList, value.id) !== -1;
},
// we need to disable condensing this time to keep all the paths in result object matching source,
// otherwise array indexes may be changed and we will not find correct values in the source object later.
{ condense: false }
{ tree: true }
);
// second pass - to put missed 'title' nodes both for found ids and their parents.
var filtrate = _.filterDeep(obj, function(value, key, parent, ctx) {
if (
_.get(foundIds, ctx.path) !== undefined ||
(key == 'title' && _.get(foundIds, ctx.parent.path) !== undefined)
)
return true;
});
expect(filtrate).to.deep.equal([
expect(found).to.deep.equal([
{

@@ -350,25 +340,11 @@ title: 'category 1',

var endsWith = 'foo';
// We will need 2 passes, first - to collect needed 'name' nodes ending with 'foo':
var foundFoo = _.filterDeep(
obj,
function(value, key) {
if (key == 'name' && _.endsWith(value, endsWith)) return true;
return _.endsWith(value.name, endsWith);
},
// we need to disable condensing this time to keep all the paths in result object matching source,
// otherwise array indexes may be changed and we will not find correct values in the source object later.
{ condense: false }
{ tree: { children: ['sub_categories', 'indicators'] } }
);
// console.log(foundFoo);
// second pass - to add missed fields both for found 'foo' nodes and their parents.
var filtrate = _.filterDeep(obj, function(value, key, parent, ctx) {
if (
_.get(foundFoo, ctx.path) !== undefined ||
(!_.isObject(value) && _.get(foundFoo, ctx.parent.path) !== undefined)
) {
// if (_.has(foundFoo, path)) console.log(`${key} has ${path}`);
// else console.log(`${key} has parent ${parentPath}`);
return true;
}
});
expect(filtrate).to.deep.equal([
expect(foundFoo).to.deep.equal([
{

@@ -450,23 +426,14 @@ id: 1,

var keyword = 'Hit';
// We will need 2 passes, first - to collect needed nodes with 'Hit' value:
var foundHit = _.filterDeep(
input,
function(value) {
if (value.value && value.value.includes(keyword)) return true;
return value.value.includes(keyword);
},
{
condense: false, // keep empty slots in array to preserve correct paths
leavesOnly: false,
tree: true,
onTrue: { skipChildren: true },
}
);
// second pass - to add missed fields both for found 'Hit' nodes and their parents.
var filtrate = _.filterDeep(input, function(value, key, parent, ctx) {
if (
_.get(foundHit, ctx.path) !== undefined ||
_.get(foundHit, ctx.parent.path) !== undefined
) {
return true;
}
});
expect(filtrate).to.deep.equal([
expect(foundHit).to.deep.equal([
{

@@ -473,0 +440,0 @@ value: 'Miss1',

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