Skip to content
This repository has been archived by the owner on Jan 23, 2021. It is now read-only.

Commit

Permalink
* support more property target types (Symbols, Numbers, ...)
Browse files Browse the repository at this point in the history
* unify symbol/string key handling
  • Loading branch information
schnittstabil committed Oct 7, 2015
1 parent f96ea5e commit b55d7b6
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 14 deletions.
30 changes: 16 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ function toObject(val) {
return Object(val);
}

function isFunc(val) {
return typeof val === 'function';
function assignKey(to, from, key) {
var val = from[key];

if (typeof val === 'undefined' || val === null) {
return;
}

if (typeof to[key] === 'undefined' || !isObj(val)) {
to[key] = val;
} else {
to[key] = assign(Object(to[key]), from[key]);
}
}

function base(to, from) {
function assign(to, from) {
if (to === from) {
return to;
}
Expand All @@ -24,15 +34,7 @@ function base(to, from) {

for (var key in from) {
if (hasOwnProperty.call(from, key)) {
var val = from[key];

if (Array.isArray(val)) {
to[key] = val.slice();
} else if (isObj(val) && !isFunc(val)) {
to[key] = base(to[key] || {}, val);
} else if (val !== undefined) {
to[key] = val;
}
assignKey(to, from, key);
}
}

Expand All @@ -41,7 +43,7 @@ function base(to, from) {

for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
assignKey(to, from, symbols[i]);
}
}
}
Expand All @@ -53,7 +55,7 @@ module.exports = function deepAssign(target) {
target = toObject(target);

for (var s = 1; s < arguments.length; s++) {
base(target, arguments[s]);
assign(target, arguments[s]);
}

return target;
Expand Down
77 changes: 77 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,76 @@ test('assign own enumerable propreties from source to target object', t => {
t.end();
});

test('do not assign null values', t => {
t.same(fn({}, {foo: null}), {});
t.end();
});

test('assign values to null targets', t => {
t.same(fn({foo: null}, {foo: {}}), {foo: {}});
t.end();
});

test('do not assign undefined values', t => {
t.same(fn({}, {foo: undefined}), {});
t.end();
});

test('assign values to undefined targets', t => {
t.same(fn({foo: undefined}, {foo: {}}), {foo: {}});
t.end();
});

test('support numbers as targets', t => {
var target = fn({answer: 42}, {answer: {rainbows: 'many'}});
t.is(target.answer / 7, 6);
t.is(target.answer.constructor, Number);
t.is(target.answer.rainbows, 'many');
t.end();
});

test('support boolean as targets', t => {
var target = fn({foo: true}, {foo: {rainbows: 'many'}});
t.is(target.foo.toString(), 'true');
t.is(target.foo.constructor, Boolean);
t.is(target.foo.rainbows, 'many');
t.end();
});

test('support strings as targets', t => {
var target = fn({rainbows: 'many'}, {rainbows: {answer: 42}});
t.is('' + target.rainbows, 'many');
t.is(target.rainbows.constructor, String);
t.is(target.rainbows.answer, 42);
t.end();
});

test('support arrays as targets', t => {
var target = {a: ['many']};
var source = {a: []};
source.a[2] = 'unicorns';
fn(target, source, {a: {answer: 42}});
t.is(target.a[0], 'many');
t.is(target.a[1], undefined);
t.is(target.a[2], 'unicorns');
t.is(target.a.constructor, Array);
t.is(target.a.answer, 42);
t.end();
});

test('support functions', t => {
var oracle42 = () => 42;
var oracle666 = () => 666;
oracle42.foo = true;
oracle42.bar = true;
oracle666.bar = false;
var target = fn({}, {oracle: oracle42}, {oracle: oracle666});
t.is(target.oracle(), 42);
t.is(target.oracle.foo, true);
t.is(target.oracle.bar, false);
t.end();
});

test('support multiple sources', t => {
t.same(fn({foo: 0}, {bar: 1}, {bar: 2}), {foo: 0, bar: 2});
t.same(fn({}, {}, {foo: 1}), {foo: 1});
Expand Down Expand Up @@ -93,6 +163,13 @@ if (typeof Symbol !== 'undefined') {
t.end();
});

test('support symbols as targets', t => {
var target = fn({sym: Symbol('foo')}, {sym: {rainbows: 'many'}});
t.is(target.sym.constructor, Symbol);
t.is(target.sym.rainbows, 'many');
t.end();
});

test('only copy enumerable symbols', t => {
var target = {};
var source = {};
Expand Down

0 comments on commit b55d7b6

Please sign in to comment.