# copy-props

[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coveralls Status][coveralls-image]][coveralls-url]

Copy properties between two objects deeply.

## Install

To install from npm:

```sh
$ npm i copy-props --save
```

## Usage

Copy _src_ to _dst_ simply (and return _dst_) :

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { b1: 'bbb' }, c: 'ccc' };
var dst = { a: 2, b: { b1: 'xxx', b2: 'yyy' } };

copyProps(src, dst);
// => { a: 1, b: { b1: 'bbb', b2: 'yyy' }, c: 'ccc' }
```

Copy _src_ to _dst_ with property mapping (and return _dst_) :

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { b1: 'bbb' }, c: 'ccc', d: 'ddd' };
var dst = { f: { a: 2, b1: 'xxx', b2: 'yyy' }, e: 'zzz' };

copyProps(src, dst, {
  a: 'f.a',
  'b.b1': 'f.b1',
  'b.b2': 'f.b2',
  c: 'f.c',
});
// => { f: { a: 1, b1: 'bbb', b2: 'yyy', c: 'ccc' }, e: 'zzz' }
```

Copy _src_ to _dst_ with convert function (and return _dst_) :

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { b1: 'bbb' } };
var dst = { a: 0 };

copyProps(src, dst, function (srcInfo) {
  if (srcInfo.keyChain === 'a') {
    return srcInfo.value * 2;
  }
  if (srcInfo.keyChain === 'b.b1') {
    return srcInfo.value.toUpperCase();
  }
});
// => { a: 2, b: { b1: 'BBB' } }
```

Can use an array instead of a map as property mapping :

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { c: 'CCC' }, d: { e: 'EEE' } };
var dst = { a: 9, b: { c: 'xxx' }, d: { e: 'yyy' } };
var fromto = ['b.c', 'd.e'];
copyProps(src, dst, fromto);
// => { a: 9, b: { c: 'CCC' }, d: { e: 'EEE' } }
```

Can copy reversively (from _dst_ to _src_) by reverse flag (and return _src_):

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { b1: 'bbb' }, c: 'ccc' };
var dst = { a: 2, b: { b1: 'xxx', b2: 'yyy' } };

copyProps(src, dst, true);
// => { a: 2, b: { b1: 'xxx', b2: 'yyy' }, c: 'ccc' }
```

```js
const copyProps = require('copy-props');

var src = { a: 1, b: { b1: 'bbb' }, c: 'ccc', d: 'ddd' };
var dst = { f: { a: 2, b1: 'xxx', b2: 'yyy' }, e: 'zzz' };

copyProps(
  src,
  dst,
  {
    a: 'f.a',
    'b.b2': 'f.b2',
    c: 'f.c',
  },
  true
);
// => { a: 2, b: { b1: 'bbb', b2: 'yyy' }, c: 'ccc', d: 'ddd' }
```

If a value of source property is undefined (when not using converter), or a result of converter is undefined (when using converter), the value is not copied.

```js
const copyProps = require('copy-props');

var src = { a: 'A', b: undefined, c: null, d: 1 };
var dst = { a: 'a', b: 'b', c: 'c' };

copyProps(src, dst, function (srcInfo) {
  if (srcInfo.keyChain === 'd') {
    return undefined;
  } else {
    return srcInfo.value;
  }
});
// => { a: 'A', b: 'b', c: null }
```

You can operate the parent node object directly in converter.

```js
const copyProps = require('copy-props');

var src = { a: 1, b: 2 };
var dst = {};

copyProps(src, dst, function (srcInfo, dstInfo) {
  Object.defineProperty(dstInfo.parent, dstInfo.key, {
    writable: false,
    enumerable: true,
    configurable: false,
    value: srcInfo.value * 2,
  });
}); // => { a: 2, b: 4 }

dst; // => { a: 2, b: 4 }
dst.a = 9;
dst; // -> { a: 2, b: 4 }
```

## API

### copyProps(src, dst [, fromto] [, converter] [, reverse]) => object

Copy properties of _src_ to _dst_ deeply.
If _fromto_ is given, it is able to copy between different properties.
If _converter_ is given, it is able to convert the terminal values.

#### Parameters:

| Parameter   |        Type         | Description                                                                                                                                                         |
| :---------- | :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| _src_       |       object        | A source object of copy.                                                                                                                                            |
| _dst_       |       object        | A destinate object of copy.                                                                                                                                         |
| _fromto_    | object | array | An object mapping properties between _src_ and _dst_. (Optional)                                                                                                    |
| _converter_ |      function       | A function to convert terminal values in _src_. (Optional)                                                                                                          |
| _reverse_   |       boolean       | True, if copying reversively from dst to src and returns src object. `fromto` is also reversively used from value to key. This default value is `false`. (Optional) |

#### Returns:

_dst_ object after copying.

**Type:** object

- **Format of fromto**

  _fromto_ is a non-nested key-value object. And the *key*s are property key chains of _src_ and the *value*s are property key chains of _dst_.
  The key chain is a string which is concatenated property keys on each level with dots, like `'aaa.bbb.ccc'`.

  The following example copys the value of `src.aaa.bbb.ccc` to `dst.xxx.yyy`.

  ```js
  copyProps(src, dst, {
    'aaa.bbb.ccc': 'xxx.yyy',
  });
  ```

  _fromto_ can be an array. In that case, the array works as a map which has pairs of same key and value.

- **API of converter**

  **converter(srcInfo, dstInfo) : Any**

  _converter_ is a function to convert terminal values of propeerties of _src_.

  **Parameters:**

  | Parameter |  Type  | Description                                                       |
  | :-------- | :----: | :---------------------------------------------------------------- |
  | _srcInfo_ | object | An object which has informations about the current node of _src_. |
  | _dstInfo_ | object | An object which has informations about the current node of _dst_. |

  **Return:**

  The converted value to be set as a destination property value. If this value is undefined, the destination property is not set to the destination node object.

  **Type:** _Any_

  - **Properties of srcInfo and dstInfo**

    _srcInfo_ and _dstInfo_ has same properties, as follows:

    | Property   |  Type  | Description                                             |
    | :--------- | :----: | :------------------------------------------------------ |
    | _value_    | _Any_  | The value of the current node.                          |
    | _key_      | string | The key name of the current node.                       |
    | _keyChain_ | string | The full key of the current node concatenated with dot. |
    | _depth_    | number | The depth of the current node.                          |
    | _parent_   | object | The parent node of the current node.                    |

## License

MIT


[downloads-image]: https://img.shields.io/npm/dm/copy-props.svg?style=flat-square
[npm-url]: https://www.npmjs.org/package/copy-props
[npm-image]: https://img.shields.io/npm/v/copy-props.svg?style=flat-square

[ci-url]: https://github.com/gulpjs/copy-props/actions?query=workflow:dev
[ci-image]: https://img.shields.io/github/workflow/status/gulpjs/copy-props/dev?style=flat-square

[coveralls-url]: https://coveralls.io/r/gulpjs/copy-props
[coveralls-image]: https://img.shields.io/coveralls/gulpjs/copy-props/master.svg

