Skip to content

Commit

Permalink
add $ReadOnlyArray support to ramda includes + contains (#3633)
Browse files Browse the repository at this point in the history
Ramda's includes (same as contains, but contains is deprecated), would not
respect $ReadOnlyArray. These changes allow for $ReadOnlyArray and also enforce
a strict case when it comes to using strings (only strings may be compared with
strings). Tests have been added to enforce this behavior.

Some tests have been problematic to enforce - namely the all-arity version of
$ReadOnlyArray. It is not well understood why this is happening, but there are
comments noting the expected outcome vs. actual. I don't believe it's a
covariance issue, because 1) the curried form works fine, and 2) string and
number shouldn't be covariant.

I also took the liberty of sorting some of the import lists, because it's very
easy to find/place things when it's alphabetized :)
  • Loading branch information
LoganBarnett authored and AndrewSouthpaw committed Nov 5, 2019
1 parent 0a60bb2 commit 313c0f9
Show file tree
Hide file tree
Showing 8 changed files with 424 additions and 56 deletions.
7 changes: 5 additions & 2 deletions definitions/npm/ramda_v0.26.x/flow_v0.104.x-/ramda_v0.26.x.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,9 +662,12 @@ declare module ramda {
declare function concat(x: string): CurriedFunction1<string, string>;

declare type Includes =
(<A, T: Array<A> | string>(a: A) => (b: T) => boolean) &
(<A, T: Array<A> | string>(a: A, b: T) => boolean);
& ((string, string) => boolean)
& ((string) => ((string => boolean)))
& (<A, T: $ReadOnlyArray<A> | Array<A>>(a: A) => (b: T) => boolean)
& (<A, T: $ReadOnlyArray<A> | Array<A>>(a: A, b: T) => boolean)

// Contains is deprecated, and is a synonym for includes.
declare var contains: Includes;
declare var includes: Includes;

Expand Down
172 changes: 161 additions & 11 deletions definitions/npm/ramda_v0.26.x/flow_v0.104.x-/test_ramda_v0.26.x_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import _, {
type RefineFilter,
append,
compose,
groupBy,
pipe,
concat,
contains,
curry,
filter,
concat,
find,
includes,
groupBy,
length,
pipe,
reduce,
repeat,
subtract,
Expand Down Expand Up @@ -71,12 +73,6 @@ const str: string = "hello world";
});
});

const cont1: boolean = _.contains("s", ss);
const cont2: boolean = _.contains("s")(ss);

const inc1: boolean = _.includes("s", ss);
const inc2: boolean = _.includes("s")(ss);

const dropxs: Array<string> = _.drop(4, ss);
const dropxs1: string = _.drop(3)(str);
const dropxs2: Array<string> = _.dropLast(4, ss);
Expand All @@ -86,6 +82,160 @@ const str: string = "hello world";
const dropxs6: Array<number> = _.dropRepeatsWith(_.eqBy(Math.abs), ns);
const dropxs7: Array<number> = _.dropWhile(x => x === 1, ns);

// The contains libdef is the same as includes, and tests should be duplicated
// across the two. As of 0.26.0 contains is deprecated, but still present.
describe('contains', () => {
describe('uncurried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = contains(2, xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = contains(2, xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = contains('foo', xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<string> = ['bar']
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = contains(1, xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = contains('foo', 'bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = contains(1, 'bar')
})
})

describe('1 arg curried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = contains(2)(xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = contains(2)(xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// $ExpectError
const result: boolean = contains('foo')(xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<number> = [1]
// $ExpectError
const result: boolean = contains('foo')(xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = contains('foo')('bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = contains(1)('bar')
})
})
})

describe('includes', () => {
describe('uncurried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = includes(2, xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = includes(2, xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = includes('foo', xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<string> = ['bar']
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = includes(1, xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = includes('foo', 'bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = includes(1, 'bar')
})
})

describe('1 arg curried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = includes(2)(xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = includes(2)(xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// $ExpectError
const result: boolean = includes('foo')(xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<number> = [1]
// $ExpectError
const result: boolean = includes('foo')(xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = includes('foo')('bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = includes(1)('bar')
})
})
})

describe('startsWith', () => {
it('checks to see if one string is inside of another', () => {
const result: boolean = _.startsWith("a")("abc");
Expand Down Expand Up @@ -401,14 +551,14 @@ const str: string = "hello world";
const readOnly: $ReadOnlyArray<number> = [1, 2, 3];
const appendResult1: $ReadOnlyArray<number|string> = append('s', readOnly);
const appendResult2: $ReadOnlyArray<number|string> = append('s')(readOnly);

//$ExpectError
const appendResult3: $ReadOnlyArray<number|null> = append('s', readOnly);
//$ExpectError
const appendResult4: $ReadOnlyArray<number> = append('s')(readOnly);
});
});

const xxxs: Array<number> = _.intersperse(1, [1, 2, 3]);

const pairxs: [number, string] = _.pair(2, "str");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,9 +627,12 @@ declare module ramda {
declare function concat(x: string): CurriedFunction1<string, string>;

declare type Includes =
(<A, T: Array<A> | string>(a: A) => (b: T) => boolean) &
(<A, T: Array<A> | string>(a: A, b: T) => boolean);
& ((string, string) => boolean)
& ((string) => ((string => boolean)))
& (<A, T: $ReadOnlyArray<A> | Array<A>>(a: A) => (b: T) => boolean)
& (<A, T: $ReadOnlyArray<A> | Array<A>>(a: A, b: T) => boolean)

// Contains is deprecated, and is a synonym for includes.
declare var contains: Includes;
declare var includes: Includes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import _, {
type RefineFilter,
append,
compose,
groupBy,
pipe,
concat,
contains,
curry,
filter,
concat,
find,
groupBy,
includes,
length,
pipe,
reduce,
repeat,
subtract,
Expand Down Expand Up @@ -71,12 +73,6 @@ const str: string = "hello world";
});
});

const cont1: boolean = _.contains("s", ss);
const cont2: boolean = _.contains("s")(ss);

const inc1: boolean = _.includes("s", ss);
const inc2: boolean = _.includes("s")(ss);

const dropxs: Array<string> = _.drop(4, ss);
const dropxs1: string = _.drop(3)(str);
const dropxs2: Array<string> = _.dropLast(4, ss);
Expand All @@ -86,6 +82,84 @@ const str: string = "hello world";
const dropxs6: Array<number> = _.dropRepeatsWith(_.eqBy(Math.abs), ns);
const dropxs7: Array<number> = _.dropWhile(x => x === 1, ns);

// The contains libdef is the same as includes, and tests should be duplicated
// across the two. As of 0.26.0 contains is deprecated, but still present.
describe('contains', () => {
describe('uncurried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = contains(2, xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = contains(2, xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = contains('foo', xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<string> = ['bar']
// It is not understood why this fails to be flagged as an error when
// the 0.26.x libdef passes with the same declaration. The curried form
// works reliably though.
//
// $ShouldExpectErrorButInsteadWorksPleaseFix
const result: boolean = contains(1, xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = contains('foo', 'bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = contains(1, 'bar')
})
})

describe('1 arg curried form', () => {
it('returns a boolean for an Array and its element type', () => {
const xs: Array<number> = [1]
const result: boolean = contains(2)(xs)
})

it('returns a boolean for a $ReadOnlyArray and its element type', () => {
const xs: $ReadOnlyArray<number> = [1]
const result: boolean = contains(2)(xs)
})

it('does not allow a mismatched element type to the Array', () => {
const xs: Array<number> = [1]
// $ExpectError
const result: boolean = contains('foo')(xs)
})

it('does not allow a mismatched element type to the $ReadOnlyArray', () => {
const xs: $ReadOnlyArray<number> = [1]
// $ExpectError
const result: boolean = contains('foo')(xs)
})

it('returns a boolean for two strings', () => {
const result: boolean = contains('foo')('bar')
})

it('disallows a mismatched string and anything else', () => {
// $ExpectError
const result: boolean = contains(1)('bar')
})
})
})

describe('startsWith', () => {
it('checks to see if one string is inside of another', () => {
const result: boolean = _.startsWith("a")("abc");
Expand Down Expand Up @@ -385,29 +459,18 @@ const str: string = "hello world";
const readOnly: $ReadOnlyArray<number> = [1, 2, 3];
const appendResult1: $ReadOnlyArray<number|string> = append('s', readOnly);
const appendResult2: $ReadOnlyArray<number|string> = append('s')(readOnly);

//$ExpectError
const appendResult3: $ReadOnlyArray<number|null> = append('s', readOnly);
//$ExpectError
const appendResult4: $ReadOnlyArray<number> = append('s')(readOnly);
});
});

const xxxs: Array<number> = _.intersperse(1, [1, 2, 3]);

const pairxs: [number, string] = _.pair(2, "str");

const partxs: [Array<string>, Array<string>] = _.partition(_.contains("s"), [
"sss",
"ttt",
"foo",
"bars"
]);
const partxs1: [
{ [k: string]: string },
{ [k: string]: string }
] = _.partition(_.contains("s"), { a: "sss", b: "ttt", foo: "bars" });

describe('pluck', () => {
it('should works on array of objects as maps', () => {
const arr: Array<{ [string]: number | string }> = [{ a: "1" }, { a: 2 }];
Expand Down

0 comments on commit 313c0f9

Please sign in to comment.