Repository: char0n/ramda-adjunct (js)

Issue:
allUnique / notAllUnique
in #513, we talked about `allUnique` and `notAllUnique`.

**usage**:
```js
allUnique([1, 2, 3, 4, 5, 6]); //=> true;
allUnique([1, 1, 3, 4, 5, 6]); //=> false;

notAllUnique([1, 1, 3, 4, 5, 6]); //=> true;
notAllUnique([1, 2, 3, 4, 5, 6]); //=> false;
```

Pull request:
feat(list): add notAllUnique #515
Closes #515

Patch:
diff --git a/src/index.js b/src/index.js
index 0dbe54041a..6c210e0b67 100644
--- a/src/index.js
+++ b/src/index.js
@@ -109,6 +109,7 @@ export { default as sequencing } from './seq';
 export { default as dispatch } from './dispatch';
 export { default as async } from './async';
 export { default as anyP } from './anyP';
+export { default as firstP } from './anyP'; // alias of anyP
 // List
 export { default as mapIndexed } from './mapIndexed';
 export { default as reduceIndexed } from './reduceIndexed';
@@ -141,6 +142,7 @@ export { default as allEqualTo } from './allEqualTo';
 export { default as flattenDepth } from './flattenDepth';
 export { default as toArray } from './toArray';
 export { default as allUnique } from './allUnique';
+export { default as notAllUnique } from './notAllUnique';
 // Object
 export { default as paths } from './paths';
 export { default as renameKeys } from './renameKeys';
diff --git a/src/notAllUnique.js b/src/notAllUnique.js
new file mode 100644
index 0000000000..9cf360833a
--- /dev/null
+++ b/src/notAllUnique.js
@@ -0,0 +1,25 @@
+import { complement } from 'ramda';
+
+import allUnique from './allUnique';
+
+/**
+ * Returns true if at least one item of the list is repeated. `R.equals` is used to determine equality.
+ *
+ * @func notAllUnique
+ * @memberOf RA
+ * @since {@link https://char0n.github.io/ramda-adjunct/2.22.0|v2.22.0}
+ * @category List
+ * @sig [a] -> Boolean
+ * @param {Array} list The list of values
+ * @return {boolean}
+ * @see {@link RA.allUnique|allUnique}, {@link https://ramdajs.com/docs/#equals|equals}
+ * @example
+ *
+ * RA.notAllUnique([ 1, 1, 2, 3 ]); //=> true
+ * RA.notAllUnique([ 1, 2, 3, 4 ]); //=> false
+ * RA.notAllUnique([]); //=> false
+ *
+ */
+const notAllUnique = complement(allUnique);
+
+export default notAllUnique;
diff --git a/types/index.d.ts b/types/index.d.ts
index 56631a0cde..990271a80c 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -847,6 +847,7 @@ declare namespace RamdaAdjunct {
          * or rejected with an array of rejection reasons if all of the given promises are rejected.
          */
         anyP<T>(iterable: Iterable<T>): Promise<T>;
+        firstP<T>(iterable: Iterable<T>): Promise<T>; // alias
 
         /**
          * Composable shortcut for `Promise.resolve`.
@@ -1242,6 +1243,11 @@ declare namespace RamdaAdjunct {
          */
         allUnique<T>(list: T[]): boolean;
 
+        /**
+         * Returns true if at least one item of the list is repeated. `R.equals` is used to determine equality.
+         */
+        notAllUnique<T>(list: T[]): boolean;
+
         /**
          * Removes whitespace from the beginning of a string
          */


Test patch:
diff --git a/test/anyP.js b/test/anyP.js
index f21c2ef4f7..cfff56dc58 100644
--- a/test/anyP.js
+++ b/test/anyP.js
@@ -189,3 +189,9 @@ describe('anyP', function() {
     });
   });
 });
+
+describe('firstP', function() {
+  it('should be alias for anyP', function() {
+    assert.isTrue(RA.firstP === RA.anyP);
+  });
+});
diff --git a/test/notAllUnique.js b/test/notAllUnique.js
new file mode 100644
index 0000000000..aec4e7486f
--- /dev/null
+++ b/test/notAllUnique.js
@@ -0,0 +1,37 @@
+import { assert } from 'chai';
+import * as R from 'ramda';
+
+import * as RA from '../src';
+
+describe('notAllUnique', function() {
+  context('given an array of not unique elements', function() {
+    specify('should return true', function() {
+      assert.isTrue(RA.notAllUnique([1, 2, 3, 4, 5, 1]));
+      assert.isTrue(RA.notAllUnique(['b', 'b', 'b']));
+      assert.isTrue(RA.notAllUnique([{}, {}]));
+      assert.isTrue(RA.notAllUnique([[1], [1]]));
+      assert.isTrue(RA.notAllUnique([undefined, undefined, null]));
+    });
+  });
+
+  context('given an array of unique elements', function() {
+    specify('should return false', function() {
+      assert.isFalse(RA.notAllUnique([1, 2, 3, 4, 5, 6]));
+      assert.isFalse(RA.notAllUnique(['a', 'b', 'c']));
+      assert.isFalse(RA.notAllUnique([{}, { a: 1 }, { b: 2 }]));
+      assert.isFalse(RA.notAllUnique([null, undefined, '', 0]));
+    });
+  });
+
+  context('given an empty array', function() {
+    specify('should return false', function() {
+      assert.isFalse(RA.notAllUnique([]));
+    });
+  });
+
+  specify('should support placeholder to specify "gaps"', function() {
+    const notAllUnique = RA.notAllUnique(R.__);
+
+    assert.isTrue(notAllUnique([1, 2, 3, 4, 5, 1]));
+  });
+});
diff --git a/types/test/anyP.ts b/types/test/anyP.ts
index 73d289df86..94227b6409 100644
--- a/types/test/anyP.ts
+++ b/types/test/anyP.ts
@@ -10,3 +10,13 @@ RA.anyP(customIterable); // $ExpectType Promise<number>
 
 RA.anyP({}); // $ExpectError
 RA.anyP(1); // $ExpectError
+
+// alias
+RA.firstP([1, 2]); // $ExpectType Promise<number>
+RA.firstP(['a', 'b']); // $ExpectType Promise<string>
+RA.firstP([1, 'a']); // $ExpectType Promise<string | number>
+RA.firstP([]); // $ExpectType Promise<never>
+RA.firstP(customIterable); // $ExpectType Promise<number>
+
+RA.firstP({}); // $ExpectError
+RA.firstP(1); // $ExpectError
diff --git a/types/test/notAllUnique.ts b/types/test/notAllUnique.ts
new file mode 100644
index 0000000000..b3ec129fe2
--- /dev/null
+++ b/types/test/notAllUnique.ts
@@ -0,0 +1,12 @@
+import * as RA from 'ramda-adjunct';
+
+import { customIterable } from './helpers';
+
+RA.notAllUnique([1, 2, 3, 4]); // $ExpectType boolean
+RA.notAllUnique(['a', 'b', 'c', 'd']); // $ExpectType boolean
+RA.notAllUnique([1, 'b', 2, 'd']); // $ExpectType boolean
+RA.notAllUnique([]); // $ExpectType boolean
+
+RA.notAllUnique(1); // $ExpectError
+RA.notAllUnique({}); // $ExpectError
+RA.notAllUnique(customIterable); // $ExpectError