From 1a2538e42c5245aec759f467a33a1d915076d38d Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Fri, 5 May 2017 18:01:08 +0200 Subject: [PATCH] feat: add renameKeys Ref #27 --- src/index.d.ts | 9 +++++++++ src/index.js | 3 +++ src/renameKeys.js | 35 +++++++++++++++++++++++++++++++++++ test/renameKeys.js | 23 +++++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 src/renameKeys.js create mode 100644 test/renameKeys.js diff --git a/src/index.d.ts b/src/index.d.ts index c2b56ff91c..35361c6d2a 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -267,6 +267,15 @@ declare namespace RamdaAdjunct { (either: Catamorphism): T1|T2; } } + + /** + * Creates a new object with the own properties of the provided object, but the + * keys renamed according to the keysMap object as `{oldKey: newKey}`. + * When some key is not found in the keysMap, then it's passed as-is. + */ + renameKeys(keysMap: Object, obj: Object): Object + renameKeys(keysMap: Object): (obj: Object) => Object + } } diff --git a/src/index.js b/src/index.js index 27b1244b5f..4ab9d1c430 100644 --- a/src/index.js +++ b/src/index.js @@ -48,6 +48,7 @@ import list from './list'; import defaults from './defaults'; import resetToDefault from './resetToDefault'; import paths from './paths'; +import renameKeys from './renameKeys'; // Type export { default as isNotUndefined } from './isNotUndefined'; @@ -99,6 +100,7 @@ export { default as list } from './list'; export { default as defaults } from './defaults'; export { default as resetToDefault } from './resetToDefault'; export { default as paths } from './paths'; +export { default as renameKeys } from './renameKeys'; /** * @namespace RA @@ -154,6 +156,7 @@ const RA = { defaults, resetToDefault, paths, + renameKeys, }; export default RA; diff --git a/src/renameKeys.js b/src/renameKeys.js new file mode 100644 index 0000000000..5062970199 --- /dev/null +++ b/src/renameKeys.js @@ -0,0 +1,35 @@ +import { curry, reduce, assoc, keys, has } from 'ramda'; + +/** + * Creates a new object with the own properties of the provided object, but the + * keys renamed according to the keysMap object as `{oldKey: newKey}`. + * When some key is not found in the keysMap, then it's passed as-is. + * + * Keep in mind that in the case of keys conflict is behaviour undefined and + * the result may vary between various JS engines! + * + * @func renameKeys + * @memberOf RA + * @since {@link https://char0n.github.io/ramda-adjunct/1.5.0|v1.5.0} + * @category Object + * @sig {a: b} -> {a: *} -> {b: *} + * @param {!Object} keysMap + * @param {!Object} obj + * @return {!Object} New object with renamed keys + * @see {@link RA.renameKeysWith|renameKeysWith} + * @example + * + * const input = { firstName: 'Elisia', age: 22, type: 'human' }; + * + * renameKeys({ firstName: 'name', type: 'kind', foo: 'bar' })(input); + * //=> { name: 'Elisia', age: 22, kind: 'human' } + */ +const renameKeys = curry((keysMap, obj) => + reduce((accumulator, key) => { + const newKeyName = has(key, keysMap) ? keysMap[key] : key; + + return assoc(newKeyName, obj[key], accumulator); + }, {}, keys(obj)) +); + +export default renameKeys; diff --git a/test/renameKeys.js b/test/renameKeys.js new file mode 100644 index 0000000000..d8f34cbe2d --- /dev/null +++ b/test/renameKeys.js @@ -0,0 +1,23 @@ +import RA from '../src/index'; +import eq from './shared/eq'; + + +describe('renameKeys', function() { + it('tests renaming object keys', function() { + eq(RA.renameKeys({ key1: 'key2', key2: 'key3' }, { key1: 1, key2: 2 }), { key2: 1, key3: 2 }); + }); + + it('tests renaming non existing keys', function() { + eq(RA.renameKeys({ nonExistingKey: 'key2' }, { key1: 1 }), { key1: 1 }); + }); + + it('tests renaming keys on non object', function() { + eq(RA.renameKeys({ key1: 'key2' }, null), {}); + eq(RA.renameKeys({ key1: 'key2' }, undefined), {}); + }); + + it('tests currying', function() { + eq(RA.renameKeys({ key1: 'key2', key2: 'key3' }, { key1: 1, key2: 2 }), { key2: 1, key3: 2 }); + eq(RA.renameKeys({ key1: 'key2', key2: 'key3' })({ key1: 1, key2: 2 }), { key2: 1, key3: 2 }); + }); +});