Repository: char0n/ramda-adjunct
Pull request #1558 (2020-08-06 11:07:16)

copyKeys
[#516](https://github.com/char0n/ramda-adjunct/issues/516)

char0n: Closing this due to unresponsiveness of author in this PRs.
FelipeParreira: Hey, @char0n sorry for my unresponsiveness. I can take a look at this PR again. What are the issues?
char0n: Reopening and doing CR, glad to hear from you ;]

Patch:
diff --git a/src/copyKeys.js b/src/copyKeys.js
new file mode 100644
index 0000000000..6d9793b07f
--- /dev/null
+++ b/src/copyKeys.js
@@ -0,0 +1,31 @@
+import { curryN } from 'ramda';
+
+import renameKeys from './renameKeys';
+
+/**
+ * Creates a new object with the own properties of the provided object, and the
+ * keys copied according to the keysMap object as `{oldKey: newKey}`.
+ * When no key from the keysMap is found, then a shallow clone of an object is returned.
+ *
+ * Keep in mind that in the case of keys conflict is behaviour undefined and
+ * the result may vary between various JS engines!
+ *
+ * @func copyKeys
+ * @memberOf RA
+ * @category Object
+ * @sig {a: b} -> {a: *} -> {b: *}
+ * @param {!Object} keysMap
+ * @param {!Object} obj
+ * @return {!Object} New object with copied keys
+ * @see {@link RA.renameKeys|renameKeys}
+ * @example
+ *
+ * copyKeys({ a: 'b' }, { a: true }); //=> { a: true, b: true }
+ * copyKeys({ a: 'b' }, { a: true, b: false }); //=> { a: true, b: true }
+ */
+const copyKeys = curryN(2, (keysMap, obj) => ({
+  ...obj,
+  ...renameKeys(keysMap, obj),
+}));
+
+export default copyKeys;
diff --git a/src/index.js b/src/index.js
index 603944f724..1a820329b8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -171,6 +171,7 @@ export { default as paths } from './paths';
 export { default as renameKeys } from './renameKeys';
 export { default as renameKeysWith } from './renameKeysWith';
 export { default as renameKeyWith } from './renameKeyWith';
+export { default as copyKeys } from './copyKeys';
 export { default as mergeRight } from './mergeRight';
 export { default as mergeLeft } from './mergeRight';
 export { default as resetToDefault } from './mergeRight';
diff --git a/types/index.d.ts b/types/index.d.ts
index 887853ce30..6ddba660c8 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -594,6 +594,14 @@ declare namespace RamdaAdjunct {
         renameKeys(keysMap: Dictionary<string>, obj: object): object;
         renameKeys(keysMap: Dictionary<string>): (obj: object) => object;
 
+        /**
+         * Creates a new object with the own properties of the provided object, and the
+         * keys copied according to the keysMap object as `{oldKey: newKey}`.
+         * When no key from the keysMap is found, then a shallow clone of an object is returned.
+         */
+        copyKeys(keysMap: Dictionary<string>, obj: object): object;
+        copyKeys(keysMap: Dictionary<string>): (obj: object) => object;
+
         /**
          * Creates a new object with the own properties of the provided object, but the
          * keys renamed according to logic of renaming function.


Test patch:
diff --git a/test/copyKeys.js b/test/copyKeys.js
new file mode 100644
index 0000000000..93239a0620
--- /dev/null
+++ b/test/copyKeys.js
@@ -0,0 +1,62 @@
+import { assert } from 'chai';
+
+import * as RA from '../src';
+
+describe('copyKeys', function () {
+  it('should copy object keys', function () {
+    assert.deepEqual(
+      RA.copyKeys(
+        { key1: 'key2', key2: 'key3' },
+        { key1: 1, key2: 2, key4: 4 }
+      ),
+      {
+        key1: 1,
+        key2: 1,
+        key3: 2,
+        key4: 4,
+      }
+    );
+  });
+
+  context('given non existing keys', function () {
+    specify('should ignore them', function () {
+      assert.deepEqual(RA.copyKeys({ nonExistingKey: 'key2' }, { key1: 1 }), {
+        key1: 1,
+      });
+    });
+
+    specify('should create shallow clone', function () {
+      const obj = { key1: 1 };
+
+      assert.notStrictEqual(RA.copyKeys({ nonExistingKey: 'key2' }, obj), obj);
+    });
+  });
+
+  context('given non object value', function () {
+    specify('should return empty object', function () {
+      assert.deepEqual(RA.copyKeys({ key1: 'key2' }, null), {});
+      assert.deepEqual(RA.copyKeys({ key1: 'key2' }, undefined), {});
+      assert.deepEqual(RA.copyKeys({ key1: 'key2' }, ''), {});
+      assert.deepEqual(RA.copyKeys({ key1: 'key2' }, 3), {});
+    });
+  });
+
+  it('should be curried', function () {
+    assert.deepEqual(
+      RA.copyKeys({ key1: 'key2', key2: 'key3' }, { key1: 1, key2: 2 }),
+      {
+        key1: 1,
+        key2: 1,
+        key3: 2,
+      }
+    );
+    assert.deepEqual(
+      RA.copyKeys({ key1: 'key2', key2: 'key3' })({ key1: 1, key2: 2 }),
+      {
+        key1: 1,
+        key2: 1,
+        key3: 2,
+      }
+    );
+  });
+});
diff --git a/types/test/copyKeys.ts b/types/test/copyKeys.ts
new file mode 100644
index 0000000000..52543cce4b
--- /dev/null
+++ b/types/test/copyKeys.ts
@@ -0,0 +1,11 @@
+import * as RA from 'ramda-adjunct';
+
+RA.copyKeys({ a: 'b' }, { a: true }); // $ExpectType object
+RA.copyKeys({ a: 'b' }, { a: true, b: false }); // $ExpectType object
+RA.copyKeys({ a: 'b' })({ a: true }); // $ExpectType object
+
+RA.copyKeys()(); // $ExpectError
+RA.copyKeys(); // $ExpectError
+RA.copyKeys(1, {}); // $ExpectError
+RA.copyKeys(null, {}); // $ExpectError
+RA.copyKeys({}, ''); // $ExpectError