Skip to content

Commit

Permalink
9.3.0 R.assoc R.isNotEmpty (#741)
Browse files Browse the repository at this point in the history
* chore@small

* fix isempty

* fix assoc typings

* chore@small

* chore@small

* chore@small

* feat@dissoc

* feat@fix modify

* chore@small

* [email protected]

* feat@build

* chore@small

* chore@small

* chore@small
  • Loading branch information
selfrefactor committed Aug 23, 2024
1 parent b900a2e commit a11a5b1
Show file tree
Hide file tree
Showing 35 changed files with 1,800 additions and 1,277 deletions.
202 changes: 124 additions & 78 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,59 +106,57 @@ One of the main issues with `Ramda` is the slow process of releasing new version

<details>
<summary>
Click to see the full list of 43 Ramda methods not implemented in Rambda and their status.
Click to see the full list of 46 Ramda methods not implemented in Rambda and their status.
</summary>

- into
- invert
- construct - Using classes is not very functional programming oriented.
- constructN - same as above
- into - no support for transducer as it is overly complex to implement, understand and read.
- invert - overly complicated and limited use case
- invertObj
- invoker
- keysIn
- keysIn - we shouldn't encourage extending object with `.prototype`
- lift
- liftN
- mapAccum
- mapAccum - `Ramda` example doesn't looks convincing
- mapAccumRight
- memoizeWith
- mergeDeepWith
- memoizeWith - hard to imagine its usage in context of `R.pipe`/`R.compose`
- mergeDeepWith - limited use case
- mergeDeepWithKey
- mergeWithKey
- nAry
- nthArg
- o
- otherwise
- pair
- partialRight
- pathSatisfies
- nAry - hard to argument about and hard to create meaningful TypeScript definitions
- nthArg - limited use case
- o - enough TypeScript issues with `R.pipe`/`R.compose` to add more composition methods
- otherwise - naming is confusing
- pair - `left-pad` types of debacles happens partially because of such methods that should not be hidden, bur rather part of your code base even if they need to exist.
- partialRight - I dislike `R.partial`, so I don't want to add more methods that are based on it
- pipeWith
- project
- project - naming is confusing, but also limited use case
- promap
- reduceRight
- reduceWhile
- reduceRight - I find `right/left` methods confusing so I added them only where it makes sense.
- reduceWhile - functions with 4 inputs - I think that even 3 is too much
- reduced
- remove
- scan
- remove - nice name but it is too generic. Also, `Rambdax` has such method and there it works very differently
- scan - hard to explain
- sequence
- splitWhenever
- symmetricDifferenceWith
- andThen
- toPairsIn
- transduce - currently is out of focus
- traverse - same as above
- unary
- uncurryN
- unfold
- unionWith
- unfold - similar to `R.scan` and I find that it doesn't help with readability
- unionWith - why it has its usage, I want to limit number of methods that accept more than 2 arguments
- until
- useWith
- useWith - hard to explain
- valuesIn
- xprod
- xprod - limited use case
- thunkify
- default

Most of above methods are in progress to be added to **Rambda**. The following methods are not going to be added:
- __ - placeholder method allows user to further customize the method call. While, it seems useful initially, the price is too high in terms of complexity for TypeScript definitions. If it is not easy exressable in TypeScript, it is not worth it as **Rambda** is a TypeScript first library.
- construct - Using classes is not very functional programming oriented.
- constructN - same as above
- transduce - currently is out of focus
- traverse - same as above

The following methods are not going to be added(reason for exclusion is provided as a comment):
</details>

[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#-missing-ramda-methods)
Expand Down Expand Up @@ -216,7 +214,7 @@ There are methods which are benchmarked only with `Ramda` and `Rambda`(i.e. no `

Note that some of these methods, are called with and without curring. This is done in order to give more detailed performance feedback.

The benchmarks results are produced from latest versions of *Rambda*, *Lodash*(4.17.21) and *Ramda*(0.30.0).
The benchmarks results are produced from latest versions of *Rambda*, *Lodash*(4.17.21) and *Ramda*(0.30.1).

</summary>

Expand Down Expand Up @@ -6196,7 +6194,7 @@ describe('R.hasPath', () => {
head(str: string): string
```

It returns the first element of list or string `input`.
It returns the first element of list or string `input`. It returns `undefined` if array has length of 0.

```javascript
const result = [
Expand All @@ -6215,6 +6213,7 @@ const result = [
```typescript
head(str: string): string;
head(str: ''): undefined;
head(list: readonly[]): undefined;
head<T>(list: never[]): undefined;
head<T extends unknown[]>(array: T): FirstArrayElement<T>
head<T extends readonly unknown[]>(array: T): FirstArrayElement<T>
Expand Down Expand Up @@ -6288,9 +6287,9 @@ describe('R.head', () => {
it('empty array', () => {
const list = [] as const
head(emptyList) // $ExpectType undefined
head(list) // $ExpectType never
head(list) // $ExpectType undefined
last(emptyList) // $ExpectType undefined
last(list) // $ExpectType never
last(list) // $ExpectType undefined
})

it('mixed', () => {
Expand Down Expand Up @@ -6993,12 +6992,6 @@ export function isEmpty(input){
return false
if (!input) return true

if (type(input.isEmpty) === 'Function') {
return input.isEmpty();
} else if (input.isEmpty) {
return !!input.isEmpty;
}

if (inputType === 'Object'){
return Object.keys(input).length === 0
}
Expand Down Expand Up @@ -7033,10 +7026,6 @@ test('happy', () => {
expect(isEmpty(0)).toBeFalse()
expect(isEmpty(NaN)).toBeFalse()
expect(isEmpty([ '' ])).toBeFalse()
expect(isEmpty({ isEmpty: false})).toBeFalse()
expect(isEmpty({ isEmpty: () => false})).toBeFalse()
expect(isEmpty({ isEmpty: true})).toBeTrue()
expect(isEmpty({ isEmpty: () => true})).toBeTrue()
})
```

Expand Down Expand Up @@ -7122,6 +7111,27 @@ test('happy', () => {

[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#isNil)

### isNotEmpty

```typescript

isNotEmpty<T>(value: T[]): value is NonEmptyArray<T>
```

<details>

<summary>All TypeScript definitions</summary>

```typescript
isNotEmpty<T>(value: T[]): value is NonEmptyArray<T>;
isNotEmpty<T>(value: readonly T[]): value is ReadonlyNonEmptyArray<T>;
isNotEmpty(value: any): boolean;
```

</details>

[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#isNotEmpty)

### isNotNil

<a title="redirect to Rambda Repl site" href="https://rambda.now.sh?const%20result%20%3D%20%5B%0A%20%20R.isNotNil(null)%2C%0A%20%20R.isNotNil(undefined)%2C%0A%20%20R.isNotNil(%5B%5D)%2C%0A%5D%0A%2F%2F%20%3D%3E%20%5Bfalse%2C%20false%2C%20true%5D">Try this <strong>R.isNotNil</strong> example in Rambda REPL</a>
Expand Down Expand Up @@ -7352,7 +7362,7 @@ test('happy', () => {
last(str: ''): undefined
```

It returns the last element of `input`, as the `input` can be either a string or an array.
It returns the last element of `input`, as the `input` can be either a string or an array. It returns `undefined` if array has length of 0.

```javascript
const result = [
Expand All @@ -7371,9 +7381,11 @@ const result = [
```typescript
last(str: ''): undefined;
last(str: string): string;
last(list: readonly[]): undefined;
last(list: never[]): undefined;
last<T extends unknown[]>(array: T): LastArrayElement<T>
last<T extends readonly unknown[]>(array: T): LastArrayElement<T>
last<T extends unknown[]>(array: T): LastArrayElement<T>;
last<T extends readonly unknown[]>(array: T): LastArrayElement<T>;
last(str: string): string | undefined;
```

</details>
Expand Down Expand Up @@ -7706,7 +7718,7 @@ export function lens(getter, setter){
<summary><strong>TypeScript</strong> test</summary>

```typescript
import {lens, assoc, lensProp, view, lensIndex, lensPath} from 'rambda'
import {lens, assoc, lensProp, view, lensIndex, over, lensPath} from 'rambda'

interface Input {
foo: string,
Expand All @@ -7730,6 +7742,10 @@ describe('R.lensProp', () => {
const result = view<Input, string>(lensProp('foo'), testObject)
result // $ExpectType string
})
it('issue 740', () => {
// @ts-expect-error
over(lensProp('x'), (n) => String(n), {x: 1})
})
})

describe('R.lensIndex', () => {
Expand Down Expand Up @@ -9385,11 +9401,7 @@ It returns the lesser value between `x` and `y` according to `compareFn` functio

```typescript

modify<T extends object, K extends keyof T, P>(
prop: K,
fn: (a: T[K]) => P,
obj: T,
): Omit<T, K> & Record<K, P>
modify<K extends PropertyKey, T>(prop: K, fn: (value: T) => T): <U extends Record<K, T>>(object: U) => U
```

```javascript
Expand All @@ -9404,15 +9416,12 @@ const result = R.modify()
<summary>All TypeScript definitions</summary>

```typescript
modify<T extends object, K extends keyof T, P>(
prop: K,
fn: (a: T[K]) => P,
obj: T,
): Omit<T, K> & Record<K, P>;
modify<K extends string, A, P>(
prop: K,
fn: (a: A) => P,
): <T extends Record<K, A>>(target: T) => Omit<T, K> & Record<K, P>;
modify<K extends PropertyKey, T>(prop: K, fn: (value: T) => T): <U extends Record<K, T>>(object: U) => U;
modify<U, K extends keyof U>(prop: K, fn: (value: U[K]) => U[K], object: U): U;
modify<K extends PropertyKey>(prop: K): {
<T>(fn: (value: T) => T): <U extends Record<K, T>>(object: U) => U;
<T, U extends Record<K, T>>(fn: (value: T) => T, object: U): U;
};
```

</details>
Expand Down Expand Up @@ -9553,23 +9562,52 @@ describe('brute force', () => {
<summary><strong>TypeScript</strong> test</summary>

```typescript
import {modify, add} from 'rambda'
const person = {name: 'James', age: 20}
import { add, identity, map, modify, pipe, toUpper } from 'rambda';

type Obj = {
foo: string;
bar: number;
};

describe('R.modify', () => {
it('happy', () => {
const {age} = modify('age', add(1), person)
const {age: ageAsString} = modify('age', String, person)
it('ramda tests', () => {
const result1 = modify('foo', toUpper, {} as Obj);
result1; // $ExpectType Obj

age // $ExpectType number
ageAsString // $ExpectType string
})
it('curried', () => {
const {age} = modify('age', add(1))(person)
const result2 = modify('bar', add(1), {} as Obj);
result2; // $ExpectType Obj

age // $ExpectType number
})
})
const result3 = modify('foo', toUpper)({} as Obj);
result3; // $ExpectType Obj

const result4 = modify('bar', add(1))({} as Obj);
result4; // $ExpectType Obj

const result5 = modify('foo')(toUpper)({} as Obj);
result5; // $ExpectType Obj

const result6 = modify('bar')(add(1))({} as Obj);
result6; // $ExpectType Obj

const result7 = modify('foo')(toUpper, {} as Obj);
result7; // $ExpectType Obj

const result8 = modify('bar')(add(1), {} as Obj);
result8; // $ExpectType Obj

const result9 = modify('foo', identity, {} as Obj);
result9; // $ExpectType Obj

// @ts-expect-error
modify('foo', add(1), {} as Obj);
// @ts-expect-error
modify('bar', toUpper, {} as Obj);

const f = pipe(map<Obj, Obj>(modify('foo', toUpper)));

f([] as Obj[]); // $ExpectType Obj[]
});
});
```

</details>
Expand Down Expand Up @@ -18536,6 +18574,14 @@ describe('R.zipWith', () => {

## ❯ CHANGELOG

9.3.0

- Breaking change in relation to TS typings of `R.assoc`, `R.dissoc` and `R.modify` - https://github.com/ramda/types/pull/37

- Add `R.isNotEmpty` as it is new method in `Ramda`

- Fix `R.head`/`R.last` TS definition - It returns `undefined` if array has length of 0. Before

9.2.1

- Broken `Deno` build - [Issue #731](https://github.com/selfrefactor/rambda/issues/731)
Expand Down Expand Up @@ -18960,11 +19006,11 @@ Fix wrong versions in changelog

> Links to Rambda

- [https://github.com/stoeffel/awesome-fp-js](awesome-fp-js)
- [awesome-fp-js](https://github.com/stoeffel/awesome-fp-js)

- [ https://mailchi.mp/webtoolsweekly/web-tools-280 ]( Web Tools Weekly #280 )
- [Web Tools Weekly #280](https://mailchi.mp/webtoolsweekly/web-tools-280)

- [https://github.com/docsifyjs/awesome-docsify](awesome-docsify)
- [awesome-docsify](https://github.com/docsifyjs/awesome-docsify)

> Deprecated from `Used by` section

Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,3 @@
*.log
coverage
node_modules
commit.js
.vscode/settings.json
compare-size-output.js
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"niketa.PERSIST_LINT_TERMINAL": true
}
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
9.3.0

- Breaking change in relation to TS typings of `R.assoc`, `R.dissoc` and `R.modify` - https://github.com/ramda/types/pull/37

- Add `R.isNotEmpty` as it is new method in `Ramda`

- Fix `R.head`/`R.last` TS definition - It returns `undefined` if array has length of 0. Before

9.2.1

- Broken `Deno` build - [Issue #731](https://github.com/selfrefactor/rambda/issues/731)
Expand Down
3 changes: 3 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Code of Conduct

Everyone is welcome to interact with and contribute to this project. Harassing people is not tolerated. Be kind in your interactions. Assume the best intentions from others in your interactions. Be patient (this is no one’s full-time job).
Loading

0 comments on commit a11a5b1

Please sign in to comment.