Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Tree utilities which provides a full-featured extend and object-cloning facility, and various tools to deal with nested object structures.
The tree-kit npm package provides utilities for manipulating and traversing tree-like structures in JavaScript. It offers a variety of functions to work with nested objects and arrays, making it easier to manage hierarchical data.
Deep cloning
This feature allows you to create a deep clone of an object, ensuring that nested objects are also cloned rather than referenced.
const tree = require('tree-kit');
const original = { a: 1, b: { c: 2 } };
const clone = tree.clone(original);
console.log(clone); // { a: 1, b: { c: 2 } }
Deep merging
This feature allows you to merge multiple objects deeply, combining their properties and nested structures.
const tree = require('tree-kit');
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { b: { d: 3 }, e: 4 };
const merged = tree.extend(null, obj1, obj2);
console.log(merged); // { a: 1, b: { c: 2, d: 3 }, e: 4 }
Path-based access
This feature allows you to access nested properties using a dot-separated path string, making it easier to retrieve deeply nested values.
const tree = require('tree-kit');
const obj = { a: { b: { c: 42 } } };
const value = tree.get(obj, 'a.b.c');
console.log(value); // 42
Path-based setting
This feature allows you to set nested properties using a dot-separated path string, making it easier to update deeply nested values.
const tree = require('tree-kit');
const obj = { a: { b: { c: 42 } } };
tree.set(obj, 'a.b.d', 100);
console.log(obj); // { a: { b: { c: 42, d: 100 } } }
Lodash is a popular utility library that provides a wide range of functions for manipulating arrays, objects, and other data structures. It includes deep cloning and merging functionalities similar to tree-kit, but also offers a broader set of utilities for general-purpose programming.
Deepmerge is a specialized library for deep merging of JavaScript objects. It focuses specifically on merging nested structures, similar to the deep merging feature of tree-kit, but does not offer the broader range of tree manipulation utilities.
Dot-prop is a utility for accessing and manipulating object properties using dot-separated path strings. It provides similar path-based access and setting functionalities as tree-kit, but is more focused on these specific operations.
This lib is a toolbox that provide functions to operate with nested Object
structure.
It features the best .extend()
method, providing dozen of options that all others libs miss.
Some tutorials are available at blog.soulserv.net/tag/tree-kit.
Use Node Package Manager:
npm install tree-kit
In all examples below, it is assumed that you have required the lib into the tree
variable:
var tree = require( 'tree-kit' ) ;
Object
extend options, it supports the properties:
boolean
only copy enumerable own properties from the sourcesboolean
copy non-enumerable properties as well, works only with own:trueboolean
preserve property's descriptor (i.e. writable, enumerable, configurable, get & set)boolean
perform a deep (recursive) extendboolean
(default to false) if true then circular references are checked and each identical objects are reconnected
(referenced), if false then nested object are blindly clonedinteger
used in conjunction with deep, when the max depth is reached an exception is raised, it defaults to 100
when the 'circular' option is off, or defaults to null if 'circular' is onboolean
move properties from the sources object to the target object (delete properties from the sources object)boolean
existing properties in the target object will not be overwrittenboolean
skip properties that are functionsboolean
in conjunction with 'deep', this will process sources functions like objects rather than
copying/referencing them directly into the source (default behaviour), thus, the result will not be a function,
it forces 'deep' optionsboolean
alter the target's prototype so that it matches the source's prototype.
It forces option 'own'. Specifying multiple sources does not make sens here.boolean
make the target inherit from the source (the target's prototype will be the source itself, not its prototype).
It forces option 'own' and disable 'proto'. Specifying multiple sources does not make sens here.boolean
prevent the prototype of the target root object from mutation.
Only nested objects' prototype will be mutated.boolean|string
sources properties are copied in a way to produce a flat target, the target's key
is the full path (separated by '.') of the source's key, also if a string is provided it will be used as
the path separatorboolean|string
it is the opposite of 'flat': assuming that the sources are in the flat format,
it expands all flat properties -- whose name are path with '.' as the separator -- deeply into the target,
also if a string is provided it will be used as the path separatorObject
filter the recursiveness of the 'deep' option, filtered objects will be referenced
just the way it would be if the 'deep' option was turned off, objects are filtered based upon their
prototypes (only direct prototype match, for performance purpose the rest of the prototype chain will
not be checked)
Array
list of black-listed prototypeArray
list of white-listed prototypeObject
the target of the extend, properties will be copied to this objectObject
the source of the extend, properties will be copied from this objectThis is a full-featured extend of an object with one or more source object.
It is easily translated from jQuery-like extend():
extend( target , source )
translate into tree.extend( null , target , source )
extend( true , target , source )
translate into tree.extend( { deep: true } , target , source )
However, here we have full control over what will be extended and how.
All the options above are inactive by default.
You can pass null as argument #0 to get the default behaviour (= all options are inactive).
So using the default behaviour, tree.extend()
will copy all enumerable properties, and perform a shallow copy (a nested object
is not cloned, it remains a reference of the original one).
With the deep option, a deep copy is performed, so nested object are cloned too.
The own option clone only owned properties from the sources, properties that are part of the source's prototype would not be copied/cloned.
The nonEnum option will clone properties that are not enumerable.
The descriptor option will preserve property's descriptor, e.g. if the source property is not writable and not enumerable, so will be the copied property.
In case of a getter properties:
If circular is on, the lib will detect when the source's data structure reuses the same object multiple time and will preserve it. We can see this circular feature in action in this example.
Mixing inherit and deep provides a nice multi-level inheritance.
With the flat option example:
var o = {
one: 1,
sub: {
two: 2,
three: 3
}
} ;
var flatCopy = tree.extend( { flat: true } , {} , o ) ;
... it will produce:
{
one: 1,
"sub.two": 2,
"sub.three": 3
}
By the way, the unflat option does the opposite, and thus can reverse this back to the original form.
The deepFilter option is used when you do not want to clone some type of object.
Let's say you want a deep copy except for Buffer
objects, you simply want them to share the same reference:
var o = {
one: '1' ,
buf: new Buffer( "My buffer" ) ,
subtree: {
two: 2 ,
three: 'THREE'
}
} ;
// either
var extended1 = tree.extend( { deep: true, deepFilter: { whitelist: [ Object.prototype ] } } , {} , o ) ;
// or
var extended2 = tree.extend( { deep: true, deepFilter: { blacklist: [ Buffer.prototype ] } } , {} , o ) ;
Doing this, we have o.buf === extended1.buf === extended2.buf
, and o.subtree !== extended1.subtree !== extended2.subtree
.
Object
the source object to cloneboolean
(default to false) if true then circular references are checked and each identical objects are reconnected
(referenced), if false then nested object are blindly clonedIt returns a clone of the original object, providing the best object-cloning facility that this lib can offer.
The clone produced are perfect independant copy in 99% of use case, but there is one big limitation: method that access variables in the parent's scope.
The clone will share those variables with the original object, so they are not totally independant entity. Design pattern using closure to emulate private member (e.g. the revealing pattern) can cause trouble.
If circular is on, the lib will detect when the source's data structure reuses the same object multiple time and will preserve it.
Here is an example of this circular feature:
var o = {
a: 'a',
sub: {
b: 'b'
},
sub2: {
c: 'c'
}
} ;
o.loop = o ;
o.sub.loop = o ;
o.subcopy = o.sub ;
o.sub.link = o.sub2 ;
o.sub2.link = o.sub ;
var c = tree.clone( o , true ) ;
expect( c.loop ).to.be( c ) ;
expect( c.sub ).to.be( c.subcopy ) ;
expect( c.sub.loop ).to.be( c ) ;
expect( c.subcopy.loop ).to.be( c ) ;
expect( c.sub.link ).to.be( c.sub2 ) ;
expect( c.sub2.link ).to.be( c.sub ) ;
... without circular on, the clone()
method would run forever, creating a new object independant nested object each time
it reaches the loop property.
We can see that the subcopy property remains a reference of sub even in the clone, thanks to the circular option.
However, if we are sure that there isn't multiple reference to the same object or circular references, we can gain a lot of
performances by leaving that options off.
It can save a lot of .indexOf()
call on big data structure.
This method does not uses extend()
anymore like in version 0.3.x, it now uses its own optimized code.
However it is equivalent to an extend()
with those options turned on: deep, own, nonEnum, descriptor & proto.
If circular is on, it has the same effect than the extend()
's circular option.
Also please note that design pattern emulating private members using a closure's scope cannot be truly cloned (e.g. the revealing pattern). This is not possible to mutate a function's scope. So the clone's methods will continue to inherit the parent's scope of the original function.
Object
the left-hand side object structureObject
the right-hand side object structureObject
containing options, it supports:
string
the initial path, default: empty stringstring
the path separator, default: '.'This tool reports diff between a left-hand side and right-hand side object structure. It returns an object, each key is a path where a difference is reported, the value being an object containing (again) the path and a human-readable message.
See this example:
var left = {
a: 'a',
b: 2,
c: 'three',
sub: {
e: 5,
f: 'six',
}
} ;
var right = {
b: 2,
c: 3,
d: 'dee',
sub: {
e: 5,
f: 6,
}
} ;
console.log( tree.diff( a , b ) ) ;
It will output:
{ '.a': { path: '.a', message: 'does not exist in right-hand side' },
'.c': { path: '.c', message: 'different typeof: string - number' },
'.sub.f': { path: '.sub.f', message: 'different typeof: string - number' },
'.d': { path: '.d', message: 'does not exist in left-hand side' } }
FAQs
Tree utilities which provides a full-featured extend and object-cloning facility, and various tools to deal with nested object structures.
The npm package tree-kit receives a total of 73,836 weekly downloads. As such, tree-kit popularity was classified as popular.
We found that tree-kit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.