Skip to content

Commit 81d2280

Browse files
committed
Add missing transform feature.
1 parent 7871f65 commit 81d2280

File tree

4 files changed

+71
-5
lines changed

4 files changed

+71
-5
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,6 @@
165165
"space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
166166
"space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
167167
"space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
168-
"spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment
168+
"spaced-line-comment": 2 // http://eslint.org/docs/rules/spaced-line-comment
169169
}
170170
}

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
Mixes/merges/extends your object in multiple ways.
55

6+
Unlike underscore/lodash utility methods this module allows you to:
7+
* mix or deep merge objects' prototype chain. Regular mixin/extend/assign implementations can't do that.
8+
* mix or deep merge unique properties only. I.e. no data will be overwritten if a property already exists.
9+
* filter each individual property by target value, source value, and key. See API.
10+
* transform each value by target value, source value, and key. See API.
11+
612
## Install
713
```sh
814
$ npm install supermixer
@@ -42,7 +48,7 @@ functionMixer({}, { a: "x" }, { b: function(){} });
4248

4349
### Mixin functions including prototype chain.
4450
```js
45-
// assigns functions only, but traverse through the protorype chain
51+
// assigns functions only, but traverse through the prototype chain
4652
var chainFunctionMixer = mixer({
4753
filter: function (val) { return typeof val === 'function' ; },
4854
chain: true
@@ -97,5 +103,29 @@ mergeChainData(new EventEmitter());
97103
// { hello: "world" }
98104
```
99105

106+
## API
107+
108+
### supermixer(opts = {})
109+
The `opts`:
110+
```
111+
* @param {Object} opts
112+
* @param {Function} opts.filter Function which filters value and key.
113+
* @param {Function} opts.transform Function which transforms each value.
114+
* @param {Boolean} opts.chain Loop through prototype properties too.
115+
* @param {Boolean} opts.deep Deep looping through the nested properties.
116+
* @param {Boolean} opts.noOverwrite Do not overwrite any existing data (aka first one wins).
117+
```
118+
119+
Usage:
120+
```js
121+
mixer({
122+
filter(sourceValue, targetValue, key) { return key[0] !== '_'; }, // do not copy "private" values
123+
transform(resultValue, targetValue, key) { console.log(key); return resultValue; }, // log each key which gets set
124+
chain: true,
125+
deep: true,
126+
noOverwrite: true
127+
});
128+
```
129+
100130
## Want to contribute?
101131
This project is Open Open Source. This means whoever submits an accepted PR will receive write permissions to the project.

src/mixer.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import isUndefined from 'lodash/lang/isUndefined';
99
*
1010
* @param {Object} opts
1111
* @param {Function} opts.filter Function which filters value and key.
12+
* @param {Function} opts.transform Function which transforms each value.
1213
* @param {Boolean} opts.chain Loop through prototype properties too.
1314
* @param {Boolean} opts.deep Deep looping through the nested properties.
1415
* @param {Boolean} opts.noOverwrite Do not overwrite any existing data (aka first one wins).
@@ -45,12 +46,14 @@ export default function mixer(opts = {}) {
4546
}
4647
}
4748

48-
function iteratee(srcValue, key) {
49-
if (opts.filter && !opts.filter(srcValue, target[key], key)) {
49+
function iteratee(sourceValue, key) {
50+
const targetValue = target[key];
51+
if (opts.filter && !opts.filter(sourceValue, targetValue, key)) {
5052
return;
5153
}
5254

53-
target[key] = opts.deep ? opts._innerMixer(target[key], srcValue) : srcValue;
55+
const result = opts.deep ? opts._innerMixer(targetValue, sourceValue) : sourceValue;
56+
target[key] = opts.transform ? opts.transform(result, targetValue, key) : result;
5457
}
5558

5659
const loop = opts.chain ? forIn : forOwn;

test/all-options.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import test from 'tape';
2+
import mixer from '../src/index';
3+
4+
test('all options work together', (t) => {
5+
var mix = mixer({
6+
filter(sourceValue, targetValue, key) { return key[0] !== '_'; },
7+
transform(resultingValue, targetValue, key) { return key === 'name' ? 'new name' : resultingValue; },
8+
chain: true,
9+
deep: true,
10+
noOverwrite: true
11+
});
12+
13+
// Using tape.Test as a good example of a complex object.
14+
const obj = new test.Test('old name');
15+
obj.deep = { deeper: true };
16+
const result = mix({ readable: 'no overwrite please' }, obj);
17+
18+
t.equal(obj.readable, true, 'pre check source object');
19+
t.notEqual(obj.name, 'new name', 'pre check source object');
20+
21+
t.ok(result.assert, 'should grab prototype properties');
22+
t.ok(result.emit, 'should grab prototype of prototype properties');
23+
t.notOk(result._ok, 'should filter out private properties');
24+
t.notOk(result._skip, 'should filter out private properties');
25+
t.notOk(result._end, 'should filter out private properties');
26+
t.notOk(result._assert, 'should filter out private properties');
27+
t.ok(result.deep.deeper, 'should grab deep properties');
28+
t.equal(result.name, 'new name', 'should transform values');
29+
t.equal(result.readable, 'no overwrite please', 'should not overwrite properties');
30+
31+
t.end();
32+
});
33+

0 commit comments

Comments
 (0)