Skip to content

Commit

Permalink
Add deno compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
hermann-p committed Jan 18, 2023
1 parent 5645e52 commit e019cb7
Show file tree
Hide file tree
Showing 284 changed files with 21,305 additions and 20 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ Alternatively, include it in your webpage via ~jsdelivr~:
<script src="https://cdn.jsdelivr.net/npm/pragmatic-fp-ts@1/dist/pragmatic-fp-ts.min.js"></script>
```

## Deno

Alternate source format created automatically with
[Denoify](https://github.com/garronej/denoify).

'import * as f from 'http://github.com/hermann-p/pragmatic-fp-ts/deno_lib/main.ts'

# Breaking changes

## 1.0
Expand Down
39 changes: 39 additions & 0 deletions deno_lib/Chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getValueOr, MonadType, Mappable, Predicate, Effect } from "./main.ts";

import { Monad } from "./types.ts";

export class Chain<A> extends Monad<A> {
readonly __value: A;
constructor(value: A) {
super();
this.__value = value;
}
_<B>(fn: Mappable<A, MonadType<B>>): Chain<B> {
return chain(fn(this.__value));
}
bind = this._;
bindM<B>(fn: Mappable<Monad<A>, Monad<B>>): Chain<B> {
return chain(fn(this));
}
filter(pred: Predicate<A>): Chain<A> {
return pred(this.__value) ? this : chain(null as any);
}
getValue() {
return this.__value;
}
getValueOr(alt: A) {
return this.__value || alt;
}
effect(eff: Effect<A>) {
eff(this.__value);
return this;
}
}

export function chain<A>(value: MonadType<A>): Chain<A> {
return new Chain(getValueOr(null as any, value));
}

export function isChain(candidate: unknown) {
return candidate instanceof Chain;
}
Empty file added deno_lib/CustomError.ts
Empty file.
150 changes: 150 additions & 0 deletions deno_lib/Either.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { Effect, identity, isNil, getValue, Mappable, Predicate } from "./main.ts";
import { Monad, MonadType, NilError, InvalidValueError } from "./types.ts";

export type Either<R, L = Error> = Left<R, L> | Right<R, L>;

export type EitherMatcher<R, L, B> = {
left?: (err: L) => B;
right?: (val: R) => B;
};
export class Left<R, L = Error> extends Monad<R> {
readonly errorValue: L;

constructor(errVal: L) {
super();
this.errorValue = errVal;
}

_<B>(_: Mappable<R, B>, _hint?: L): Either<NonNullable<B>, L> {
return this as any;
}
bind = this._;
bindM<B>(_: Mappable<Monad<R>, Monad<B>>): Either<NonNullable<B>, L> {
return this as any;
}
filter(_: any, _hint?: L): Either<NonNullable<R>, L> {
return this as any;
}
effect(_: any): Either<NonNullable<R>, L> {
return this as any;
}
getValue(): NonNullable<R> {
throw new Error(`Can not get value of Left(${String(this.errorValue)})`);
}
getValueOr(alt: R): R {
return alt;
}
match<B>(matcher: EitherMatcher<R, L, B>): Either<NonNullable<B>, L | Error> {
return matcher.left ? either<B, L>(matcher.left(this.errorValue)) : (this as any);
}
isLeft() {
return true;
}
isRight() {
return false;
}
getReason() {
return this.errorValue;
}
}

export class Right<R extends NonNullable<any>, L = Error> extends Monad<R> {
readonly value: R;
constructor(value: R) {
super();
this.value = value;
}
_<B>(fn: Mappable<R, B>, hint?: L): Either<NonNullable<B>, L | Error> {
try {
const result = fn(this.value);
const bound = either(getValue(result));
return bound.isLeft() && hint ? left(hint) : bound;
} catch (err) {
return left<NonNullable<B>, Error>(err);
}
}
bind = this._;
bindM<B>(fn: Mappable<Monad<R>, Monad<B>>): Either<NonNullable<B>, L | Error> {
try {
const result = fn(this);
return either(getValue(result));
} catch (err) {
return left<NonNullable<B>, L>(err);
}
}
filter(fn: Predicate<R>, hint?: L): Either<NonNullable<R>, L | Error> {
try {
return fn(this.value)
? (this as any)
: left<NonNullable<R>>(hint instanceof Error ? hint : new InvalidValueError(hint as any));
} catch (err) {
return left<NonNullable<R>>(new Error(`Exception while filtering: ${err.text}`));
}
}

effect(fn: Effect<R>): Either<NonNullable<R>, L> {
try {
fn(this.value);
} catch (err) {}
return this as any;
}
getValue(): NonNullable<R> {
return this.value as NonNullable<R>;
}
getValueOr(_: R): R {
return this.value;
}
match<B>(matcher: EitherMatcher<R, L, B>): Either<NonNullable<B>, L> {
const m = matcher.right ?? (identity as any);
return either(m(this.value)) as any;
}
isLeft() {
return false;
}
isRight() {
return true;
}
getReason() {
throw new Error("Can not get error reason for Right");
}
}

export function left<R, L = Error>(errVal: L) {
return new Left<R, L>(errVal);
}

export function right<R, L = Error>(value: R) {
return new Right<R, L>(value);
}

export function either<R, L = Error>(
value: MonadType<R>,
errVal?: L
): Either<NonNullable<R>, L | Error> {
const innerValue = getValue(value);
return isNil(innerValue)
? errVal
? new Left<NonNullable<R>, L>(errVal)
: new Left<NonNullable<R>, Error>(new NilError())
: new Right<NonNullable<R>, L>(innerValue as any);
}

export function isLeft<R = any, L = Error>(el: unknown): el is Left<R, L> {
return el instanceof Left;
}

export function isRight<R = any, L = Error>(el: unknown): el is Right<R, L> {
return el instanceof Right;
}

export function isEither<R = any, L = Error>(el: unknown): el is Either<R, L> {
return isLeft<R>(el) || isRight<L>(el);
}

export const throwLeftAsError = {
right: (data: any) => data,
left: (reason: Error | string) => {
throw reason instanceof Error ? reason : new Error(reason);
return reason as any;
},
};
71 changes: 71 additions & 0 deletions deno_lib/ErrorLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Effect, Mappable, UnboxPromise } from "./types.ts";

export interface ErrorLog<T> {
_: <U>(f: Mappable<T, U>) => ErrorLog<U>;
effect: (f: Effect<T>) => ErrorLog<T>;
try: <U>(f: Mappable<T, U>, alt: U) => ErrorLog<U>;
getErrors: () => Error[];
getValue: () => T;
getValueOr: <U>(alt: U) => NonNullable<T> | U;
hasErrors: () => boolean;
}
function ErrorLog<T>(expr: T, errors: Array<Error> = []) {
return {
_: <U>(f: Mappable<T, U>) => ErrorLog(f(expr), errors),
try: <U>(f: Mappable<T, U>, alt: U): ErrorLog<U> => {
try {
return ErrorLog(f(expr), errors);
} catch (err) {
return ErrorLog(alt, [...errors, err]);
}
},
effect: (f: Effect<T>): ErrorLog<T> => {
try {
f(expr);
return ErrorLog(expr, errors);
} catch (err) {
return ErrorLog(expr, [...errors, err]);
}
},
getErrors: () => errors,
getValue: () => expr,
getValueOr: <U>(alt: T | U) => (expr || alt) as NonNullable<T> | U,
hasErrors: () => errors.length > 0,
};
}

export interface FutureErrorLog<T> {
_: <U>(f: Mappable<T, U>) => FutureErrorLog<U>;
effect: (f: Effect<T>) => FutureErrorLog<T>;
try: <U>(f: Mappable<T, U>, alt: UnboxPromise<U>) => FutureErrorLog<U>;
getErrors: () => Promise<Error[]>;
getValue: () => Promise<UnboxPromise<T>>;
getValueOr: <U>(alt: U) => Promise<NonNullable<UnboxPromise<T>> | UnboxPromise<U>>;
hasErrors: () => Promise<boolean>;
}
const FutureErrorLog = <T>(
expr: T | Promise<T>,
errors: Promise<Error[]> = Promise.resolve([])
): FutureErrorLog<T> => {
const exprP = expr instanceof Promise ? expr : Promise.resolve(expr);
const tryOrAppendError = (p: Promise<any>, es: Promise<Error[]>) =>
p.then(() => es).catch(async (err) => [...(await errors), err]);
return {
_: <U>(f: Mappable<T, U>): FutureErrorLog<U> => FutureErrorLog(exprP.then(f), errors),
effect: (fx: Effect<T>) => FutureErrorLog(exprP, tryOrAppendError(exprP.then(fx), errors)),
try: <U>(f: Mappable<T, U>, alt: UnboxPromise<U>): FutureErrorLog<U> => {
const p = exprP.then(f);
return FutureErrorLog(
p.catch(() => alt as any),
tryOrAppendError(p, errors)
);
},
getErrors: () => errors,
getValue: () => (exprP as unknown) as Promise<UnboxPromise<T>>,
getValueOr: async <U>(alt: U) => (await exprP) || (alt instanceof Promise ? await alt : alt),
hasErrors: () => errors.then((e) => e.length > 0),
};
};

export const errorLogged = <T>(value: T) => ErrorLog(value);
export const errorLoggedFuture = <T>(value: T) => FutureErrorLog(value);
3 changes: 3 additions & 0 deletions deno_lib/F.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function F(..._: any) {
return false;
}
12 changes: 12 additions & 0 deletions deno_lib/Free.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Mappable } from "./types.ts";

export class Free<T> {
private val: T = undefined as any;
static of = <A>(val: A) => {
const m = new Free<A>();
m.val = val;
return m;
};

_ = <U>(f: Mappable<T, U>) => Free.of(f(this.val));
}
Loading

0 comments on commit e019cb7

Please sign in to comment.