Skip to content

Commit

Permalink
.extend() option 'mask' now supports a number, the rank at which the …
Browse files Browse the repository at this point in the history
…masking starts
  • Loading branch information
cronvel committed Sep 18, 2021
1 parent 4722ed4 commit 22b10eb
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@

v0.7.3
------

.extend() option 'mask' now supports a number, the rank at which the masking starts


v0.7.2
------

Expand Down
29 changes: 15 additions & 14 deletions browser/tree-kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,15 @@ dotPath.prepend = ( object , path , value ) => {
(it is a replacement for deepFilter.blacklist which was removed in Tree Kit 0.6).
* maxDepth: used in conjunction with deep, when max depth is reached an exception is raised, default to 100 when
the 'circular' option is off, or default to null if 'circular' is on
* circular: circular references reconnection
* move: move properties to target (delete properties from the sources)
* preserve: existing properties in the target object are not overwritten
* mask: reverse of 'preserve', only update existing properties in the target, do not create new keys
* circular: boolean, circular references reconnection
* move: boolean, move properties to target (delete properties from the sources)
* preserve: boolean, existing properties in the target object are not overwritten
* mask: boolean or number, reverse of 'preserve', only update existing properties in the target, do not create new keys,
if its a number, the mask effect is only effective for the Nth element.
E.g: .extend( {mask:2} , {} , object1 , object2 )
So object1 extends the empty object like, but object2 do not create new keys not present in object1.
With mask:true or mask:1, the mask behavior would apply at step 1 too, when object1 would try to extend the empty object,
and since an empty object has no key, nothing would change, and the whole extend would return an empty object.
* nofunc: skip functions
* deepFunc: in conjunction with 'deep', this will process sources functions like objects rather than
copying/referencing them directly into the source, thus, the result will not be a function, it forces 'deep'
Expand All @@ -529,7 +534,6 @@ dotPath.prepend = ( object , path , value ) => {
* unflat: assume sources are in the 'flat' format, expand all properties deeply into the target, disable 'flat'
*/
function extend( options , target , ... sources ) {
//console.log( "\nextend():\n" , arguments ) ;
var i , source , newTarget = false , length = sources.length ;

if ( ! length ) { return target ; }
Expand Down Expand Up @@ -603,7 +607,7 @@ function extend( options , target , ... sources ) {
for ( i = 0 ; i < length ; i ++ ) {
source = sources[ i ] ;
if ( ! source || ( typeof source !== 'object' && typeof source !== 'function' ) ) { continue ; }
extendOne( runtime , options , target , source ) ;
extendOne( runtime , options , target , source , options.mask <= i + 1 ) ;
}

return target ;
Expand All @@ -613,10 +617,7 @@ module.exports = extend ;



function extendOne( runtime , options , target , source ) {
//console.log( "\nextendOne():\n" , arguments ) ;
//process.exit() ;

function extendOne( runtime , options , target , source , mask ) {
var j , jmax , path ,
sourceKeys , sourceKey , sourceValue , sourceValueIsObject , sourceValueProto , sourceDescriptor ,
targetKey , targetPointer , targetValue , targetValueIsObject ,
Expand Down Expand Up @@ -696,7 +697,7 @@ function extendOne( runtime , options , target , source ) {
&& ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) )
&& ( ! options.immutables || ! options.immutables.has( sourceValueProto ) )
&& ( ! options.preserve || targetValueIsObject )
&& ( ! options.mask || targetValueIsObject )
&& ( ! mask || targetValueIsObject )
) {
if ( options.circular ) {
indexOfSource = runtime.references.sources.indexOf( sourceValue ) ;
Expand All @@ -708,7 +709,7 @@ function extendOne( runtime , options , target , source ) {

extendOne(
{ depth: runtime.depth + 1 , prefix: runtime.prefix + sourceKey + options.flat , references: runtime.references } ,
options , targetPointer , sourceValue
options , targetPointer , sourceValue , mask
) ;
}
else {
Expand Down Expand Up @@ -764,11 +765,11 @@ function extendOne( runtime , options , target , source ) {
// Recursively extends sub-object
extendOne(
{ depth: runtime.depth + 1 , prefix: '' , references: runtime.references } ,
options , targetValue , sourceValue
options , targetValue , sourceValue , mask
) ;
}
}
else if ( options.mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) {
else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) {
// Do not create new value, and so do not delete source's properties that were not moved.
// We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy)
continue ;
Expand Down
2 changes: 1 addition & 1 deletion browser/tree-kit.min.js

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions lib/extend.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,15 @@
(it is a replacement for deepFilter.blacklist which was removed in Tree Kit 0.6).
* maxDepth: used in conjunction with deep, when max depth is reached an exception is raised, default to 100 when
the 'circular' option is off, or default to null if 'circular' is on
* circular: circular references reconnection
* move: move properties to target (delete properties from the sources)
* preserve: existing properties in the target object are not overwritten
* mask: reverse of 'preserve', only update existing properties in the target, do not create new keys
* circular: boolean, circular references reconnection
* move: boolean, move properties to target (delete properties from the sources)
* preserve: boolean, existing properties in the target object are not overwritten
* mask: boolean or number, reverse of 'preserve', only update existing properties in the target, do not create new keys,
if its a number, the mask effect is only effective for the Nth element.
E.g: .extend( {mask:2} , {} , object1 , object2 )
So object1 extends the empty object like, but object2 do not create new keys not present in object1.
With mask:true or mask:1, the mask behavior would apply at step 1 too, when object1 would try to extend the empty object,
and since an empty object has no key, nothing would change, and the whole extend would return an empty object.
* nofunc: skip functions
* deepFunc: in conjunction with 'deep', this will process sources functions like objects rather than
copying/referencing them directly into the source, thus, the result will not be a function, it forces 'deep'
Expand All @@ -61,7 +66,6 @@
* unflat: assume sources are in the 'flat' format, expand all properties deeply into the target, disable 'flat'
*/
function extend( options , target , ... sources ) {
//console.log( "\nextend():\n" , arguments ) ;
var i , source , newTarget = false , length = sources.length ;

if ( ! length ) { return target ; }
Expand Down Expand Up @@ -135,7 +139,7 @@ function extend( options , target , ... sources ) {
for ( i = 0 ; i < length ; i ++ ) {
source = sources[ i ] ;
if ( ! source || ( typeof source !== 'object' && typeof source !== 'function' ) ) { continue ; }
extendOne( runtime , options , target , source ) ;
extendOne( runtime , options , target , source , options.mask <= i + 1 ) ;
}

return target ;
Expand All @@ -145,10 +149,7 @@ module.exports = extend ;



function extendOne( runtime , options , target , source ) {
//console.log( "\nextendOne():\n" , arguments ) ;
//process.exit() ;

function extendOne( runtime , options , target , source , mask ) {
var j , jmax , path ,
sourceKeys , sourceKey , sourceValue , sourceValueIsObject , sourceValueProto , sourceDescriptor ,
targetKey , targetPointer , targetValue , targetValueIsObject ,
Expand Down Expand Up @@ -228,7 +229,7 @@ function extendOne( runtime , options , target , source ) {
&& ( ! ( options.deep instanceof Set ) || options.deep.has( sourceValueProto ) )
&& ( ! options.immutables || ! options.immutables.has( sourceValueProto ) )
&& ( ! options.preserve || targetValueIsObject )
&& ( ! options.mask || targetValueIsObject )
&& ( ! mask || targetValueIsObject )
) {
if ( options.circular ) {
indexOfSource = runtime.references.sources.indexOf( sourceValue ) ;
Expand All @@ -240,7 +241,7 @@ function extendOne( runtime , options , target , source ) {

extendOne(
{ depth: runtime.depth + 1 , prefix: runtime.prefix + sourceKey + options.flat , references: runtime.references } ,
options , targetPointer , sourceValue
options , targetPointer , sourceValue , mask
) ;
}
else {
Expand Down Expand Up @@ -296,11 +297,11 @@ function extendOne( runtime , options , target , source ) {
// Recursively extends sub-object
extendOne(
{ depth: runtime.depth + 1 , prefix: '' , references: runtime.references } ,
options , targetValue , sourceValue
options , targetValue , sourceValue , mask
) ;
}
}
else if ( options.mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) {
else if ( mask && ( targetValue === undefined || targetValueIsObject || sourceValueIsObject ) ) {
// Do not create new value, and so do not delete source's properties that were not moved.
// We also do not overwrite object with non-object, and we don't overwrite non-object with object (preserve hierarchy)
continue ;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tree-kit",
"version": "0.7.2",
"version": "0.7.3",
"description": "Tree utilities which provides a full-featured extend and object-cloning facility, and various tools to deal with nested object structures.",
"main": "lib/tree.js",
"directories": {
Expand Down
35 changes: 30 additions & 5 deletions test/extend-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,30 @@ describe( "extend()" , () => {
expect( o ).to.equal( { two: { sub: 'TWO' } } ) ;
} ) ;

it( "with 'mask' option as a number" , () => {
var e , o , r ;

e = {
one: '1' ,
two: 2 ,
three: 'THREE'
} ;

o = {
three: 3 ,
four: '4'
} ;

r = extend( { mask: true } , {} , e , o ) ;
expect( r ).to.equal( {} ) ;

r = extend( { mask: 1 } , {} , e , o ) ;
expect( r ).to.equal( {} ) ;

r = extend( { mask: 2 } , {} , e , o ) ;
expect( r ).to.equal( { one: '1' , two: 2 , three: 3 } ) ;
} ) ;

it( "with 'preserve' option should not overwrite existing properties in the target" , () => {
var e , o ;

Expand All @@ -571,14 +595,15 @@ describe( "extend()" , () => {
} ;

o = {
two: 'TWO' ,
three: { sub: 3 } ,
four: '4'
two: 'TWO' , // Can't replace, even if base is an object
three: { sub: 3 } , // Can't replace, even by an object
four: '4' ,
five: { sub: 'FIVE' } // It's a new key, so it should be added
} ;

extend( { deep: true , preserve: true } , e , o ) ;
expect( e ).to.equal( { one: '1' , two: { sub: 2 } , three: 'THREE' , four: '4' } ) ;
expect( o ).to.equal( { two: 'TWO' , three: { sub: 3 } , four: '4' } ) ;
expect( e ).to.equal( { one: '1' , two: { sub: 2 } , three: 'THREE' , four: '4' , five: { sub: 'FIVE' } } ) ;
expect( o ).to.equal( { two: 'TWO' , three: { sub: 3 } , four: '4' , five: { sub: 'FIVE' } } ) ;
} ) ;

it( "with 'move' option should move source properties to target properties, i.e. delete them form the source" , () => {
Expand Down

0 comments on commit 22b10eb

Please sign in to comment.