Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

Commit

Permalink
feat: implement encoder and codec
Browse files Browse the repository at this point in the history
Revisted the io-ts port again (likely not for the last time).
I implemented encoder.ts and codec.ts. I also found that there
were a few typing issues with Schema and the make utility so
I resolved those for now.

Cleaned up some of the organization. This included moving
memoize, typeOf, and intersect to the fns.ts file.

Since I'm not implementing Kliesli and am deferring to the
simpler base implementations for Decoder, Encoder, and Codec
I opted to remove the builder combinators fromType, fromPartial
etc, instead preferring the Schemable functions. This cuts
down on the complexity of the implementations substantially.

Also, rather than compacting a record for the partial
Schemable I created an undefinable combinator that mirrors
the nullable one. This combinator seemed more appropriate
given the intention of partial.

Lastly, I cleaned up some of the TODO items and expanded
on their tasks.
  • Loading branch information
baetheus committed Oct 21, 2020
1 parent d3c6de3 commit 5468f22
Show file tree
Hide file tree
Showing 7 changed files with 445 additions and 220 deletions.
13 changes: 10 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# Initial Push Todos

- port io-ts (likely will need additional adts for this)
- port monocle-ts (likely will need additional adts for this)
- port io-ts
- need encoder and codec
- port monocle-ts
- need to finish Traversal
- implement tests for other algebraic modules
- revisit getEitherM and getOptionM types
- need Traversal and ChainRec still
- port hyper-ts to Deno
- revisit middleware structure
- look into implementing MiddlewareStateEither (might require length 5 constructor)

# Version 1.0.0 features

- stack safe recursion for sequence constructors
- trampoline?
- auto documentation (port docs-ts)
- just use deno docs
- spend a week on examples and introduction posts
- work with tmueller?
133 changes: 133 additions & 0 deletions codec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import type { _0, _1, _2 } from "./types.ts";
import type * as S from "./schemable.ts";

import * as D from "./decoder.ts";
import * as E from "./encoder.ts";
import { identity, pipe } from "./fns.ts";

/***************************************************************************************************
* @section Types
**************************************************************************************************/

export type Codec<I, O, A> = D.Decoder<I, A> & E.Encoder<O, A>;

export type InputOf<C> = D.InputOf<C>;

export type OutputOf<C> = E.OutputOf<C>;

export type TypeOf<C> = E.TypeOf<C>;

/***************************************************************************************************
* @section Types
**************************************************************************************************/

export const make = <I, O, A>(
decoder: D.Decoder<I, A>,
encoder: E.Encoder<O, A>,
): Codec<I, O, A> => ({
decode: decoder.decode,
encode: encoder.encode,
});

export const fromDecoder = <I, A>(
decoder: D.Decoder<I, A>,
): Codec<I, A, A> => ({
decode: decoder.decode,
encode: identity,
});

/***************************************************************************************************
* @section Combinators
**************************************************************************************************/

export const literal = <A extends readonly [S.Literal, ...S.Literal[]]>(
...values: A
): Codec<unknown, A[number], A[number]> => fromDecoder(D.literal(...values));

export const string = fromDecoder(D.string);

export const number = fromDecoder(D.number);

export const boolean = fromDecoder(D.boolean);

export const unknownArray = fromDecoder(D.unknownArray);

export const unknownRecord = fromDecoder(D.unknownRecord);

export const mapLeftWithInput = <I>(
f: (i: I, e: D.DecodeError) => D.DecodeError,
) =>
<O, A>(
codec: Codec<I, O, A>,
): Codec<I, O, A> => make(pipe(codec, D.mapLeftWithInput(f)), codec);

export const refine = <A, B extends A>(
refinement: (a: A) => a is B,
id: string,
) => {
const refine = D.refine(refinement, id);
return <I, O>(from: Codec<I, O, A>): Codec<I, O, B> =>
make(refine(from), from);
};

export const nullable = <I, O, A>(
or: Codec<I, O, A>,
): Codec<null | I, null | O, null | A> => make(D.nullable(or), E.nullable(or));

export const type = <P extends Record<string, Codec<unknown, any, any>>>(
properties: P,
) => fromDecoder(D.type(properties));

export const partial = <P extends Record<string, Codec<any, any, any>>>(
properties: P,
) => fromDecoder(D.partial(properties));

export const array = <O, A>(
item: Codec<unknown, O, A>,
) => fromDecoder(D.array(item));

export const record = <O, A>(
codomain: Codec<unknown, O, A>,
) => fromDecoder(D.record(codomain));

export const tuple = <A extends ReadonlyArray<unknown>>(
...components: { [K in keyof A]: Codec<unknown, A[K], A[K]> }
): Codec<unknown, A, A> => fromDecoder(D.tuple(...components)) as any;

export const intersect = <OA, A, OB, B>(
left: Codec<unknown, OA, A>,
right: Codec<unknown, OB, B>,
) => fromDecoder(D.intersect(left, right));

export const sum = <
T extends string,
M extends Record<string, Codec<unknown, any, any>>,
>(
tag: T,
members: M,
) => fromDecoder(D.sum(tag, members));

export const lazy = <I, O, A>(
id: string,
f: () => Codec<I, O, A>,
) => fromDecoder(D.lazy(id, f));

/***************************************************************************************************
* @section Modules
**************************************************************************************************/

export const Schemable: S.Schemable<Codec<unknown, _0, _0>> = {
literal,
string: () => string,
number: () => number,
boolean: () => boolean,
nullable: nullable,
type: type as S.TypeSchemable<Codec<unknown, _0, _0>, 1>,
partial: partial as S.PartialSchemable<Codec<unknown, _0, _0>, 1>,
record,
array,
tuple: tuple as S.TupleSchemable<Codec<unknown, _0, _0>, 1>,
intersect: intersect,
sum,
lazy,
};

0 comments on commit 5468f22

Please sign in to comment.