Skip to content

Commit

Permalink
Added support for Custom TypeOf adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
alexindigo committed Nov 27, 2018
1 parent 06612f3 commit 3ed3a3f
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 15 deletions.
47 changes: 39 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ A toolkit for deep structure manipulations, provides deep merge/clone functional
and exposes hooks and custom adapters for more control and greater flexibility.

[![PhantomJS Build](https://img.shields.io/travis/alexindigo/deeply/canary.svg?label=browser&style=flat)](https://travis-ci.org/alexindigo/deeply)
[![Linux Build](https://img.shields.io/travis/alexindigo/deeply/canary.svg?label=linux:0.10-6.x&style=flat)](https://travis-ci.org/alexindigo/deeply)
[![MacOS Build](https://img.shields.io/travis/alexindigo/deeply/canary.svg?label=macos:0.10-6.x&style=flat)](https://travis-ci.org/alexindigo/deeply)
[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/deeply/canary.svg?label=windows:0.10-6.x&style=flat)](https://ci.appveyor.com/project/alexindigo/deeply)
[![Linux Build](https://img.shields.io/travis/alexindigo/deeply/canary.svg?label=linux:6.x-11.x&style=flat)](https://travis-ci.org/alexindigo/deeply)
[![MacOS Build](https://img.shields.io/travis/alexindigo/deeply/canary.svg?label=macos:6.x-11.x&style=flat)](https://travis-ci.org/alexindigo/deeply)
[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/deeply/canary.svg?label=windows:6.x-11.x&style=flat)](https://ci.appveyor.com/project/alexindigo/deeply)

[![Coverage Status](https://img.shields.io/coveralls/alexindigo/deeply/canary.svg?label=code+coverage&style=flat)](https://coveralls.io/github/alexindigo/deeply?branch=canary)
[![Dependency Status](https://img.shields.io/david/alexindigo/deeply.svg?style=flat)](https://david-dm.org/alexindigo/deeply)
[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://opensource.org/licenses/MIT)

[![Readme](https://img.shields.io/badge/readme-tested-brightgreen.svg?style=flat)](https://www.npmjs.com/package/reamde)

| compression | size |
| :--------------- | -------: |
| deeply.js | 15.08 kB |
| deeply.min.js | 4.95 kB |
| deeply.min.js.gz | 1.48 kB |
| compression | size |
| :--------------- | ------: |
| deeply.js | 15.6 kB |
| deeply.min.js | 5.11 kB |
| deeply.min.js.gz | 1.53 kB |


## Table of Contents
Expand All @@ -38,6 +38,8 @@ and exposes hooks and custom adapters for more control and greater flexibility.
- [Cloning Prototype Chain](#cloning-prototype-chain)
- [Extend Original Function Prototype](#extend-original-function-prototype)
- [Custom hooks](#custom-hooks)
- [`useCustomAdapters`](#usecustomadapters)
- [`useCustomTypeOf`](#usecustomtypeof)
- [Mutable Operations](#mutable-operations)
- [Ludicrous Mode](#ludicrous-mode)
- [Want to Know More?](#want-to-know-more)
Expand Down Expand Up @@ -360,6 +362,8 @@ assert.equal(s2 instanceof Subj, true);

### Custom hooks

#### `useCustomAdapters`

As shown in [Custom Merge Function](#custom-merge-function) example,
you can add custom adapters for any data type
that supported by [precise-typeof](https://www.npmjs.com/precise-typeof).
Expand Down Expand Up @@ -388,6 +392,33 @@ function addNumbers(to, from)
}
```

#### `useCustomTypeOf`

In some cases you might need to have more control over type detection,
for that you can supply your own type detection function.

In following example we'd use same `precise-typeof` library,
but with `pojoOnly: true` flag:

```javascript
var merge = require('deeply');
var typeOf = require('precise-typeof');
var moment = require('moment');

var context =
{
useCustomTypeOf: merge.behaviors.useCustomTypeOf,
'typeof' : (input) => typeOf(input, {pojoOnly: true})
};

var result = merge.call(context, { a: {someField: 'value'}, b: 'other thing'}, { a: moment.utc('2018-11-27') });

assert.equal(result, { a: moment.utc('2018-11-27'), b: 'other thing' });
```

In the above example, it would treat `moment` object as atomic,
and won't mix it's properties with other properties.

### Mutable Operations

Mutable interface supports all the described operations,
Expand Down
3 changes: 2 additions & 1 deletion flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
module.exports =
{
// to prevent (reduce chance of) accidental leaking of the global variables into runtime flags
useCustomAdapters: 'deeply:useCustomAdapters:' + Math.random()
useCustomAdapters: 'deeply:useCustomAdapters:' + Math.random(),
useCustomTypeOf: 'deeply:useCustomTypeOf:' + Math.random()
};
28 changes: 24 additions & 4 deletions merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ function merge(to, from)
// if no suitable adapters found
// just return overriding value
var result = from
, type = preciseTypeOf(from)
, adapter = getTypeAdapter.call(this, type)
, typeOf = getTypeOfAdapter.call(this)
, type = typeOf(from)
, adapter = getMergeByTypeAdapter.call(this, type)
;

// if target object isn't the same type as the source object,
// then override with new instance of the same type
if (preciseTypeOf(to) != type)
if (typeOf(to) != type)
{
to = getInitialValue(type, adapter);
}
Expand All @@ -38,14 +39,33 @@ function merge(to, from)
return result;
}

/**
* Returns typeof adapter, either default one or custom one if provided
*
* @returns {function} - typeof custom adapter or default one
*/
function getTypeOfAdapter()
{
var adapter = preciseTypeOf;

// only if usage of custom adapters is authorized
// to prevent global context leaking in
if (this.useCustomTypeOf === behaviors.useCustomTypeOf)
{
adapter = this['typeof'];
}

return adapter;
}

/**
* Returns merge adapter for the requested type
* either default one or custom one if provided
*
* @param {string} type - hook type to look for
* @returns {function} - merge adapter or pass-thru function, if not adapter found
*/
function getTypeAdapter(type)
function getMergeByTypeAdapter(type)
{
var adapter = adapters[type] || passThru;

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"eslint": "^5.9.0",
"istanbul": "^0.4.5",
"lodash.partialright": "^4.2.1",
"moment": "^2.22.2",
"nyc": "^13.1.0",
"obake": "^0.1.2",
"phantomjs-prebuilt": "^2.1.12",
Expand Down
31 changes: 31 additions & 0 deletions test/test-compatibility.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
var test = require('tape').test
, partial = require('lodash.partialright')
, typeOf = require('precise-typeof')
, deeply = require('../')
, moment = require('moment')
, stringify = partial(require('util').inspect, {depth: 8})
, now = new Date()
, withStuffOnPrototype
Expand Down Expand Up @@ -55,6 +57,30 @@ var inout = [
}
}

// non-pojo objects
, {
customTypeOf: {
typeof: function(input) { return typeOf(input, {pojoOnly: true}); }
},
in: [
{
a: {datetime: 'now'},
b: moment.utc('2017-11-27'),
c: moment.utc('2018-05-25')
},
{
a: moment.utc('2018-11-27'),
b: {pojo: {on: 'top'}},
c: moment.utc('2018-08-12')
}
],
out: {
a: moment.utc('2018-11-27'),
b: {pojo: {on: 'top'}},
c: moment.utc('2018-08-12')
}
}

// default array merging: replacement
, {
in: [ { a: { b: [0, 2, 4] }}, { a: {b: [1, 3, 5] }} ],
Expand Down Expand Up @@ -200,6 +226,11 @@ test('merge', function test_deep_merge(t)
context = pair.customAdapters;
context['useCustomAdapters'] = deeply.behaviors.useCustomAdapters;
}
else if ('customTypeOf' in pair)
{
context = pair.customTypeOf;
context['useCustomTypeOf'] = deeply.behaviors.useCustomTypeOf;
}

// default - immutable

Expand Down
9 changes: 7 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3214,6 +3214,11 @@ module-deps@^6.0.0:
through2 "^2.0.0"
xtend "^4.0.0"

moment@^2.22.2:
version "2.22.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=

ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
Expand Down Expand Up @@ -4992,9 +4997,9 @@ uglify-js@^3.1.4:
commander "~2.17.1"
source-map "~0.6.1"

"uglify-stream@git+https://github.com/michaelrhodes/uglify-stream#1.1.1":
uglify-stream@michaelrhodes/uglify-stream#1.1.1:
version "1.1.1"
resolved "git+https://github.com/michaelrhodes/uglify-stream#0a6a56b9101e2339af159a346d4b901d9480c5c8"
resolved "https://codeload.github.com/michaelrhodes/uglify-stream/tar.gz/0a6a56b9101e2339af159a346d4b901d9480c5c8"
dependencies:
duplexify "^3.0.1"
uglify-js "^2.4.15"
Expand Down

0 comments on commit 3ed3a3f

Please sign in to comment.