Skip to content

Commit

Permalink
V3 (#33)
Browse files Browse the repository at this point in the history
* feat(std): implement type inferring

* release(cmp): reimplement cmp package

* fix(cmp): tests and registration for global registry

* release(cmp): update types and jsdoc.
  • Loading branch information
vitalics committed Apr 10, 2024
1 parent a9d6803 commit 861b1fb
Show file tree
Hide file tree
Showing 31 changed files with 4,207 additions and 1,824 deletions.
183 changes: 183 additions & 0 deletions .changeset/tame-buses-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
"@rslike/std": major
"@rslike/cmp": major
"@rslike/dbg": major
---

## What's new

### std

All changes applies to `Option` and `Result` objects.

#### Symbols for Option and Result objects

Implements `Symbol.iterator`, `Symbol.asyncIterator`, `Symbol.search`, `Symbol.split`, `Symbol.inspect`, `Symbol.toPrimitive`, `Symbol.toStringTag` for `Option` and `Result` objects

Example:

```ts
// Before
const arr = Some([1, 2, 3]);
// error, for..of only supports with arrays
for (let el of arr) {
}
```

As a workaround you may unwrap the value:

```ts
// workaround
const arr = Some([1, 2, 3]);
// error, for..of now works with arrays
for (let el of arr.unwrap()) {
}
```

Now you can "just call for..of".

```ts
// now it works
const arr = Some([1, 2, 3]);
// error, for..of only supports with arrays
for (let el of arr) {
// works now!
}
```

**Note**: This method will only yeild if the `Option` is `Some`

**Note**: throws `UndefinedBehaviorError` for `Some(value)` if `value` is not implements `Symbol.iterator`

More about examples with Symbols implementation you can found in [wiki](https://github.com/vitalics/rslike/wiki)

#### Symbol.hasInstance for `Some`, `None`, `Ok` and `Err` functions

Now you can call `instanceof` keyword for functions. From now you can skip importing `Result` and `Option` classes.

Example:

```ts
// Before
import { Ok, Err, Result } from "@rslike/std";
const a = Ok(3);
a instanceof Ok; // false
a instanceof Result; // true

// now, less imports
import { Ok, Err } from "@rslike/std";
const b = Ok(3);
b instanceof Ok; // true
b instanceof Err; // false
Err("Some Err") instanceof Err; // true
```

#### Advanced Types inferring

Add more complex TS types to understands have value or not.

Example:

```ts
// Before
const a = Some(3);

a.isSome(); // TS type: boolean

// now
a.isSome(); // TS type: true
```

#### double unwraping in match function for `Result<Option<T>, E>`

From now you just can use `match` function with only 1 unwrapping.

If you're using `Async` or `Bind` functions - your result will be wraped to `Result<Option<_>>`. To unwrap this result you must to use double matching.

Example (before - 67 lines):

```ts
import { Bind, match, Err } from "@rslike/std";
function divide(a: number, b: number) {
if (b === 0) Err("Divide to zero");
if (a === 0) Ok(0);
if (Number.isNaN(a) || Number.isNaN(b)) return undefined;
return a / b;
}

const binded = Bind(divide);
const fn1 = binded(1, 1); // Result<Option<number | undefined>, string>
const fn2 = binded(NaN, 1); // Result<Option<undefined>, string>

const res1 = match(
fn1, // or fn2
(res) => {
return match(
res,
(value) => {
console.log("value is:", value);
},
() => {
console.log("value is None");
},
);
},
(err) => {
console.error(err);
},
);

console.log(res1); // value is: 1
console.log(res2); // value is None
```

Example (now - 27 lines):

```ts
import { Bind, match, Err } from "@rslike/std";
function divide(a: number, b: number) {
if (b === 0) Err("Divide to zero");
if (a === 0) Ok(0);
if (Number.isNaN(a) || Number.isNaN(b)) return undefined;
return a / b;
}

const binded = Bind(divide);
const fn1 = binded(1, 1); // Result<Option<number | undefined>, string>
const fn2 = binded(NaN, 1); // Result<Option<undefined>, string>

const res1 = match(
fn1, // or fn2
(value) => {
console.log("value is:", value);
},
(err) => {
if (err) console.error(err);
else console.log("value is None");
},
);

console.log(res1); // value is: 1
console.log(res2); // value is None
```

### cmp

Compare package now register in global scope `Symbol.compare`, `Symbol.partialEquals` and `Symbol.equals`.

for more examples how to work with theese symbols see at [wiki](https://github.com/vitalics/rslike/wiki)

#### Definitions for built-in objects.

- `Number` and `NumberConstructor` implements `Symbol.compare`, `Symbol.partialEquals` and `Symbol.equals`
- `String` and `StringConstructor` implements `Symbol.compare`, `Symbol.partialEquals` and `Symbol.equals`
- `Boolean` and `BooleanConstructor` implements `Symbol.compare`, `Symbol.partialEquals` and `Symbol.equals`
- `Date` and `DateConstructor` implements `Symbol.compare`, `Symbol.partialEquals` and `Symbol.equals`

#### utilities function

`@rslike/cmp` now export utilities function `compare`, `partialEquals` and `equals`. All this functions call Symbols implementation. (e.g. `compare` calls `Symbol.compare` implementation)

- `compare` calls `Symbol.compare` implementation
- `partialEquals` calls `Symbol.partialEquals` implementation
- `equals` calls `Symbol.equals` implementation
141 changes: 21 additions & 120 deletions packages/cmp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pnpm add @rslike/cmp
// your main file

// add global types in globalThis Some,None,Option, Result,Ok,Err functions
import '@rslike/cmp/globals';
import "@rslike/cmp/globals";

// rest your file
```
Expand All @@ -33,137 +33,38 @@ Available by link: https://github.com/vitalics/rslike/wiki
- [std](https://www.npmjs.com/package/@rslike/std)
- [dbg](https://www.npmjs.com/package/@rslike/dbg)

## API
## Globals

### Ordering
This package patch `Symbol` and global object. So to make sure that this package is works correctly - you need to import **1 time-only** `@rslike/cmp/globals`

An Ordering is the result of a comparison between two values.

**NOTE**: Constructor is private, you cannot call this instance with new keyword.

## Properties

### Greater

Indicates that some value is more than another

### Less

Indicates that some value is less than another

### Equal

Indicates that some value is equals than another

## Static methods

### is

Checks than incoming value is instance of `Ordering`

### from

tries to transform incoming value to instance of `Ordering`

## Methods

### isEq

Returns `true` if the ordering is the [`Equal`](#equal) variant.

```ts
Ordering.Less.isEq() // false
Ordering.Equal.isEq() // true
Ordering.Greater.isEq() // false
```

### isNe

Returns `true` if the ordering is not the [`Equal`](#equal) variant.

```ts

Ordering.Less.isNe() // true
Ordering.Equal.isNe() // false
Ordering.Greater.isNe() // true
```

### isLt

Returns `true` if the ordering is the [`Less`](#less) variant.
Example:

```ts
// entry.ts
import "@rslike/cmp/globals";

Ordering.Less.isLt() // true
Ordering.Equal.isLt() // false
Ordering.Greater.isLt() // false
```

### isLe

Returns `true` if the ordering is either the [`Less`](#less) or [`Equal`](#equal) variant.

### isGt

Returns `true` if the ordering is the [`Greater`](#greater) variant.

```ts
// file.ts

Ordering.Less.isGt() // false
Ordering.Equal.isGt() // false
Ordering.Greater.isGt() // true
const a = {
// works!
[Symbol.compare]() {
return 1;
},
};
```

### isGe

Returns `true` if the ordering is either the [`Greater`](#greater) or [`Equal`](#equal) variant

### reverse

Reverses the `Ordering`.

- [`Less`](#less) becomes [`Greater`](#greater).
- [`Greater`](#greater) becomes [`Less`](#less).
- [`Equal`](#equal) becomes [`Equal`](#equal).

```ts
Ordering.Less.reverse() === Ordering.Greater
```

### then

Chains two orderings.

Returns `this` when it’s not `Equal`. Otherwise returns `other`.

#### Throws

[`UndefinedBehaviorError`](../std/UndefinedBehaviorError.md) if argument is not instance of `Ordering`

```ts
const result = Ordering.Equal.then(Ordering.Less);
result === Ordering.Less // true
```

### thenWith

Chains the ordering with the given function.

Returns `this` when it’s not `Equal`. Otherwise calls `f` and returns the result.

#### Throws

[`UndefinedBehaviorError`](../std/UndefinedBehaviorError.md) if function is not returns instance of `Ordering`.
## Usage

### valueOf
This package exports next useful functions/types/constants:

Returns the numeric value of the `Ordering` state.
- Utilities functions (`compare`, `equals`, `partialEquals`)
- Types (`Eq`, `Ord`, `PartialEq`)
- Symbols (`Symbol.compare`, `Symbol.equals`, `Symbol.partialEquals`)

## Example
Example:

```ts
import { compare } from "@rslike/cmp";

(1).compare(2) === Ordering.Less;
(2).compare(2) === Ordering.Equal;
(3).compare(2) === Ordering.Greater;
compare(2, 3); // -1
```

0 comments on commit 861b1fb

Please sign in to comment.