Gathering detailed insights and metrics for underscore.deep
Gathering detailed insights and metrics for underscore.deep
Gathering detailed insights and metrics for underscore.deep
Gathering detailed insights and metrics for underscore.deep
Underscore utilities for operating on nested objects
npm install underscore.deep
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
27 Stars
102 Commits
4 Forks
66 Watching
4 Branches
14 Contributors
Updated on 23 Sept 2024
CoffeeScript (95.49%)
Makefile (4.51%)
Cumulative downloads
Total Downloads
Last day
-7.1%
19,020
Compared to previous day
Last week
1.5%
99,160
Compared to previous week
Last month
-16.3%
420,765
Compared to previous month
Last year
26.2%
6,193,334
Compared to previous year
1
3
This repo is not actively maintained by Clever. We currently do not have a drop-in replacement to recommend.
Underscore.deep is a collection of Underscore mixins that operate on nested objects.
This README is written in Literate CoffeeScript as a Mocha test suite, so you can execute all of the examples - just run:
make README.coffee.md
npm install underscore
npm install underscore.deep
_ = require 'underscore'
_.mixin require 'underscore.deep'
describe 'underscore.deep', ->
assert = require 'assert'
_ = require 'underscore'
_.mixin require './underscore.deep'
Takes an object and produces a new object with no nested objects, converting any nested objects to sets of fields with dot-notation keys, recursively.
describe '_.deepToFlat', ->
it 'does nothing with shallow objects', ->
assert.deepEqual _.deepToFlat({}), {}
assert.deepEqual _.deepToFlat( shallow: 1 ), shallow: 1
it 'deepToFlats nested objects', ->
assert.deepEqual _.deepToFlat( deeply: { nested: 2 } ), 'deeply.nested': 2
assert.deepEqual _.deepToFlat(
user1:
name:
first: 'Deep'
last: 'Blue'
age: 33
),
'user1.name.first': 'Deep'
'user1.name.last': 'Blue'
'user1.age': '33'
Takes an object and produces a new object with no dot-notation keys, converting any set of dot-notation keys with the same prefix to a nested object, recursively.
Warning: Any keys with a dot (.
) in the input object will be converted to nested objects, so if you use dots in your keys you may want to replace them before you call _.deepFromFlat
.
describe '_.deepFromFlat', ->
it 'does nothing with objects with no dot-notation', ->
assert.deepEqual _.deepFromFlat({}), {}
assert.deepEqual _.deepFromFlat( shallow: 1 ), shallow: 1
it 'deepFromFlats a flat object', ->
assert.deepEqual _.deepFromFlat( 'deeply.nested': 2 ), deeply: { nested: 2 }
assert.deepEqual _.deepFromFlat(
'user1.name.first': 'Deep'
'user1.name.last': 'Blue'
'user1.age': '33'
),
user1:
name:
first: 'Deep'
last: 'Blue'
age: 33
Taken as a pair, _.deepToFlat
and _.deepFromFlat
have an interesting relationship:
describe '_.deepToFlat and _.deepFromFlat', ->
it 'they undo each other', ->
deepObj = a: 1, b: { c: 2 }
flatObj = a: 1, 'b.c': 2
assert.deepEqual flatObj, _.deepToFlat deepObj
assert.deepEqual deepObj, _.deepFromFlat flatObj
They are inverses (of a sort)! We can reformulate this as a property that holds for any flatObj
and deepObj
:
assert.deepEqual flatObj, _.deepToFlat _.deepFromFlat flatObj
assert.deepEqual deepObj, _.deepFromFlat _.deepToFlat deepObj
Takes an object and makes a copy of it, recursively copying any nested objects
or arrays. Instances of classes, like Number
or String
, are not cloned.
describe '_.deepClone', ->
orig =
deepThings:
proverbs:
quote: 'Computer science is no more about computers' +
'than astronomy is about telescopes.'
sayer: 'Dijkstra'
pools: [
{ depth: 10 }
{ depth: 20 }
{ depth: 30 }
]
it 'clones an object deeply', ->
copy = _.deepClone orig
assert.deepEqual copy, orig
assert.notStrictEqual copy, orig
assert.notStrictEqual copy.deepThings.proverbs, orig.deepThings.proverbs
assert.notStrictEqual copy.deepThings.pools, orig.deepThings.pools
it 'is equivalent to the composition of _.deepFromFlat, _.clone, and _.deepToFlat', ->
copy2 = _.deepFromFlat _.clone _.deepToFlat orig
assert.deepEqual copy2, orig
assert.notEqual copy2, orig
Takes an object obj
and a string key
(which should be a dot-notation key) and returns true if obj
has a nested field named key
.
describe '_.deepHas', ->
obj = we: have: to: go: 'deeper'
it 'returns true if a regular key exists', ->
assert.equal _.deepHas(obj, 'we'), true
it 'returns true if the deep key exists', ->
assert.equal _.deepHas(obj, 'we.have'), true
assert.equal _.deepHas(obj, 'we.have.to'), true
assert.equal _.deepHas(obj, 'we.have.to.go'), true
it 'returns false if the deep key does not exist', ->
assert.equal _.deepHas(obj, 'we.have.to.goop'), false
it 'is not equivalent to the composition of _.has and _.deepToFlat', ->
assert.equal _.deepHas(obj, 'we.have.to.go'), _.has(_.deepToFlat(obj), 'we.have.to.go')
assert.equal _.deepHas(obj, 'we.have.to.goop'), _.has(_.deepToFlat(obj), 'we.have.to.goop')
assert.notEqual _.deepHas(obj, 'we'), _.has(_.deepToFlat(obj), 'we')
Takes an object and returns all of its nested keys in dot-notation.
If you think of a deeply-nested object as a tree, then it will return the paths to all of the tree's leaves. That means it won't return intermediate keys. As a consequence, _.deepHas(obj, key)
is not equivalent to _.contains _.deepKeys(obj), key
.
describe '_.deepKeys', ->
obj =
node1:
leaf1: 1
node2:
node3:
leaf2: 2
leaf3: 3
it 'returns dot-notation keys for only the leaf fields of an object', ->
assert.deepEqual _.deepKeys(obj), [
'node1.leaf1'
'node2.node3.leaf2'
'node2.node3.leaf3'
]
it 'is equivalent to the composition of _.keys and _.deepToFlat', ->
assert.deepEqual _.deepKeys(obj), _.keys(_.deepToFlat obj)
it 'does not make _.deepHas equivalent to the composition of _.contains and _.deepKeys', ->
assert.notDeepEqual _.contains(_.deepKeys(obj), 'node1'), _.has(obj, 'node1')
Takes an object and a list of dot-notation keys and returns a new object without those keys.
foods =
fruit:
apple: true
orange: true
carrot: true
vegetables:
banana: true
describe '_.deepOmit', ->
it 'returns an object without the given keys', ->
assert.deepEqual _.deepOmit(foods, ['fruit.carrot', 'vegetables']),
fruit:
apple: true
orange: true
Takes an object and a list of dot-notation keys and returns a new object with only those keys. If you pick a key that has a subobject below it, the entire subobject will be included, regardless of whether its subkeys are also picked.
describe '_.deepPick', ->
it 'returns an object with only the given keys', ->
assert.deepEqual _.deepPick(foods, ['fruit.carrot', 'vegetables']),
fruit:
carrot: true
vegetables:
banana: true
Takes an object destination
and an object source
and creates a new object with all the deep fields of destination
and all the deep fields of source
. Any deep fields with the same deep key in destination
and source
will have the value from source
(so source
fields overwrite destination
fields).
Unlike _.extend
, _.deepExtend
is pure, so the original objects destination
and source
will not be modified. If you really want to mutate destination
by adding the deep fields of source
, pass true
as the third parameter mutate
.
describe '_.deepExtend', ->
destination =
name: 'heaven'
angels:
michael: true
it 'combines all the deep fields of destination and source', ->
assert.deepEqual _.deepExtend(destination, { angels: gabriel: false }),
name: 'heaven'
angels:
michael: true
gabriel: false
it 'overwrites fields of destination with fields from source', ->
assert.deepEqual _.deepExtend(destination, { angels: michael: false }),
name: 'heaven'
angels:
michael: false
it 'does not mutate the input objects', ->
assert.notStrictEqual destination, _.deepExtend(destination, { name: 'hell' })
it 'is equivalent to a weird composition of _.deepFromFlat, _.extend, and _.deepToFlat', ->
assert.deepEqual _.deepExtend(destination, { angels: gabriel: false }),
_.deepFromFlat _.extend _.deepToFlat(destination), _.deepToFlat({ angels: gabriel: false })
Like _.mapValues, but for deep objects. Constructs a new object by applying function func
to the value for every deep field in object obj
.
describe '_.deepMapValues', ->
obj =
values:
empathy: true
responsibility: false
it 'creates an object by applying func to each deep value in obj', ->
assert.deepEqual _.deepMapValues(obj, (v) -> not v),
values:
empathy: false
responsibility: true
it 'is equivalent to the composition of _.deepFromFlat, _.mapValues, and _.deepToFlat', ->
assert.deepEqual _.deepMapValues(obj, (v) -> String v),
_.deepFromFlat _.mapValues _.deepToFlat(obj), (v) -> String v
Someday these will probably be moved into their own library, but for now they live here.
Takes a value val
and returns true
if it's a vanilla JS object (i.e. not an instance of any built-in or custom class). Otherwise returns false.
describe '_.isPlainObject', ->
it 'returns true for vanilla objects', ->
assert.equal _.isPlainObject({}), true
assert.equal _.isPlainObject({ vanilla: 'is so plain' }), true
it 'returns false for other values', ->
assert.equal _.isPlainObject(1), false
assert.equal _.isPlainObject('chocolate'), false
assert.equal _.isPlainObject(new Date()), false
Takes an object obj
and a function func
and constructs a new object by applying func
to every value in obj
. func
receives two arguments, the value and the key for that value.
Some have described this function as "the fundamental map over dictionaries." Others have said its not "mainstream enough to deserve to make it into Underscore proper." We take no stance in the debate, but we have to admit we use it on the daily.
describe '_.mapValues', ->
obj =
respect: 1
fairness: 2
it 'creates an object by applying func to each value in obj', ->
assert.deepEqual _.mapValues(obj, (v) -> v * 10),
respect: 10
fairness: 20
Exactly like _.mapValues but for keys.
Note that the function takes a function takes a key and optionally a value, not the usual mapping function pattern of taking a value and optionally a key
describe '_.mapKeys', ->
obj =
animate: 1
charge: 2
it 'creates an object by applying func to each key in obj', ->
assert.deepEqual _.mapKeys(obj, (key) -> 're' + key),
reanimate: 1
recharge: 2
it 'creates an object by applying func to each key, val in obj', ->
assert.deepEqual _.mapKeys(obj, (key, val) -> 're' + key + val),
reanimate1: 1
recharge2: 2
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
branch protection is not maximal on development and all release branches
Details
Reason
Found 2/13 approved changesets -- score normalized to 1
Reason
2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
Reason
9 existing vulnerabilities detected
Details
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More