Skip to content

Commit

Permalink
add pipeables
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti committed May 21, 2020
1 parent f9ff107 commit 6edd727
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 82 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
- refactoring with the new `Schemable` interface (@gcanti)
- add `interpreter` function (@gcanti)
- **Internal**
- upgrade to `typescript@3.9.2` (@gcanti)
- upgrade to `typescript@3.9.3` (@gcanti)

# 2.2.2

Expand Down
11 changes: 11 additions & 0 deletions docs/modules/Codec.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Added in v2.2.3
- [boolean](#boolean)
- [codec](#codec)
- [fromDecoder](#fromdecoder)
- [imap](#imap)
- [intersection](#intersection)
- [lazy](#lazy)
- [literal](#literal)
Expand Down Expand Up @@ -155,6 +156,16 @@ export declare function fromDecoder<A>(decoder: D.Decoder<A>): Codec<A, A>

Added in v2.2.3

# imap

**Signature**

```ts
export declare const imap: <E, A, B>(f: (a: A) => B, g: (b: B) => A) => (fa: Codec<E, A>) => Codec<E, B>
```

Added in v2.2.3

# intersection

**Signature**
Expand Down
22 changes: 0 additions & 22 deletions docs/modules/Decoder.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ Added in v2.2.0
- [UnknownRecord](#unknownrecord)
- [alt](#alt)
- [ap](#ap)
- [apFirst](#apfirst)
- [apSecond](#apsecond)
- [array](#array)
- [boolean](#boolean)
- [decoder](#decoder)
Expand Down Expand Up @@ -143,26 +141,6 @@ export declare const ap: <A>(fa: Decoder<A>) => <B>(fab: Decoder<(a: A) => B>) =
Added in v2.2.0
# apFirst
**Signature**
```ts
export declare const apFirst: <B>(fb: Decoder<B>) => <A>(fa: Decoder<A>) => Decoder<A>
```
Added in v2.2.0
# apSecond
**Signature**
```ts
export declare const apSecond: <B>(fb: Decoder<B>) => <A>(fa: Decoder<A>) => Decoder<B>
```
Added in v2.2.0
# array
**Signature**
Expand Down
11 changes: 11 additions & 0 deletions docs/modules/JsonCodec.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Added in v2.2.3
- [URI](#uri)
- [array](#array)
- [boolean](#boolean)
- [imap](#imap)
- [intersection](#intersection)
- [jsonCodec](#jsoncodec)
- [lazy](#lazy)
Expand Down Expand Up @@ -101,6 +102,16 @@ export declare const boolean: JsonCodec<boolean>
Added in v2.2.3
# imap
**Signature**
```ts
export declare const imap: <A, B>(f: (a: A) => B, g: (b: B) => A) => (fa: JsonCodec<A>) => JsonCodec<B>
```
Added in v2.2.3
# intersection
**Signature**
Expand Down
15 changes: 14 additions & 1 deletion src/Codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ export function lazy<O, A>(id: string, f: () => Codec<O, A>): Codec<O, A> {
return make(D.lazy(id, f), E.lazy(f))
}

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------

/**
* @since 2.2.3
*/
export const imap: <E, A, B>(f: (a: A) => B, g: (b: B) => A) => (fa: Codec<E, A>) => Codec<E, B> = (f, g) => (fa) =>
imap_(fa, f, g)

const imap_: <E, A, B>(fa: Codec<E, A>, f: (a: A) => B, g: (b: B) => A) => Codec<E, B> = (fa, f, g) =>
make(D.decoder.map(fa, f), E.encoder.contramap(fa, g))

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
Expand All @@ -217,5 +230,5 @@ declare module 'fp-ts/lib/HKT' {
*/
export const codec: Invariant2<URI> = {
URI,
imap: (fa, f, g) => make(D.decoder.map(fa, f), E.encoder.contramap(fa, g))
imap: imap_
}
70 changes: 35 additions & 35 deletions src/Decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Alternative1 } from 'fp-ts/lib/Alternative'
import { Applicative1 } from 'fp-ts/lib/Applicative'
import { Either, either, isLeft, isRight, left, mapLeft, right } from 'fp-ts/lib/Either'
import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
import { pipe, pipeable } from 'fp-ts/lib/pipeable'
import { pipe } from 'fp-ts/lib/pipeable'
import { Forest, Tree } from 'fp-ts/lib/Tree'
import * as G from './Guard'
import { Literal, memoize, Schemable1, WithRefinement1, WithUnion1, WithUnknownContainers1 } from './Schemable'
Expand Down Expand Up @@ -444,6 +444,37 @@ export function union<A extends ReadonlyArray<unknown>>(
}
}

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------

/**
* @since 2.2.0
*/
export const alt: <A>(that: () => Decoder<A>) => (fa: Decoder<A>) => Decoder<A> = (that) => (fa) => alt_(fa, that)

const alt_: <A>(fx: Decoder<A>, fy: () => Decoder<A>) => Decoder<A> = (fx, fy) => ({
decode: (u) => either.alt(fx.decode(u), () => fy().decode(u))
})

/**
* @since 2.2.0
*/
export const ap: <A>(fa: Decoder<A>) => <B>(fab: Decoder<(a: A) => B>) => Decoder<B> = (fa) => (fab) => ap_(fab, fa)

const ap_: <A, B>(fab: Decoder<(a: A) => B>, fa: Decoder<A>) => Decoder<B> = (fab, fa) => ({
decode: (u) => either.ap(fab.decode(u), fa.decode(u))
})

/**
* @since 2.2.0
*/
export const map: <A, B>(f: (a: A) => B) => (fa: Decoder<A>) => Decoder<B> = (f) => (fa) => map_(fa, f)

const map_: <A, B>(fa: Decoder<A>, f: (a: A) => B) => Decoder<B> = (fa, f) => ({
decode: (u) => either.map(fa.decode(u), f)
})

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
Expand Down Expand Up @@ -474,18 +505,12 @@ export const decoder: Applicative1<URI> &
WithUnion1<URI> &
WithRefinement1<URI> = {
URI,
map: (fa, f) => ({
decode: (u) => either.map(fa.decode(u), f)
}),
map: map_,
of: (a) => ({
decode: () => success(a)
}),
ap: (fab, fa) => ({
decode: (u) => either.ap(fab.decode(u), fa.decode(u))
}),
alt: (fx, fy) => ({
decode: (u) => either.alt(fx.decode(u), () => fy().decode(u))
}),
ap: ap_,
alt: alt_,
zero: () => never,
literal,
string,
Expand All @@ -505,28 +530,3 @@ export const decoder: Applicative1<URI> &
union,
refinement: refinement as WithRefinement1<URI>['refinement']
}

const { alt, ap, apFirst, apSecond, map } = pipeable(decoder)

export {
/**
* @since 2.2.0
*/
alt,
/**
* @since 2.2.0
*/
ap,
/**
* @since 2.2.0
*/
apFirst,
/**
* @since 2.2.0
*/
apSecond,
/**
* @since 2.2.0
*/
map
}
44 changes: 26 additions & 18 deletions src/Encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,30 @@ export function lazy<O, A>(f: () => Encoder<O, A>): Encoder<O, A> {
}
}

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------

/**
* @since 2.2.3
*/
export const contramap: <A, B>(f: (b: B) => A) => <E>(fa: Encoder<E, A>) => Encoder<E, B> = (f) => (fa) =>
encoder.contramap(fa, f)

const contramap_: <E, A, B>(fa: Encoder<E, A>, f: (b: B) => A) => Encoder<E, B> = (fa, f) => ({
encode: (b) => fa.encode(f(b))
})

/**
* @since 2.2.3
*/
export const compose: <E, A>(ea: Encoder<E, A>) => <B>(ab: Encoder<A, B>) => Encoder<E, B> = (ea) => (ab) =>
encoder.compose(ab, ea)

const compose_: <E, A, B>(ab: Encoder<A, B>, la: Encoder<E, A>) => Encoder<E, B> = (ab, ea) => ({
encode: (b) => ea.encode(ab.encode(b))
})

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
Expand All @@ -185,23 +209,7 @@ declare module 'fp-ts/lib/HKT' {
*/
export const encoder: Contravariant2<URI> & Category2<URI> = {
URI,
contramap: (fa, f) => ({
encode: (b) => fa.encode(f(b))
}),
compose: (ab, ea) => ({
encode: (b) => ea.encode(ab.encode(b))
}),
contramap: contramap_,
compose: compose_,
id
}

/**
* @since 2.2.3
*/
export const contramap: <A, B>(f: (b: B) => A) => <E>(fa: Encoder<E, A>) => Encoder<E, B> = (f) => (fa) =>
encoder.contramap(fa, f)

/**
* @since 2.2.3
*/
export const compose: <E, A>(ea: Encoder<E, A>) => <B>(ab: Encoder<A, B>) => Encoder<E, B> = (ea) => (ab) =>
encoder.compose(ab, ea)
4 changes: 4 additions & 0 deletions src/Eq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ export function lazy<A>(f: () => Eq<A>): Eq<A> {
}
}

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------

/**
* @since 2.2.2
*/
Expand Down
9 changes: 9 additions & 0 deletions src/JsonCodec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ export const sum: <T extends string>(
*/
export const lazy: <A>(id: string, f: () => JsonCodec<A>) => JsonCodec<A> = C.lazy

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------

/**
* @since 2.2.3
*/
export const imap: <A, B>(f: (a: A) => B, g: (b: B) => A) => (fa: JsonCodec<A>) => JsonCodec<B> = C.imap

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
Expand Down
14 changes: 9 additions & 5 deletions src/JsonEncoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ export const sum: <T extends string>(
*/
export const lazy: <A>(f: () => JsonEncoder<A>) => JsonEncoder<A> = E.lazy

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------

/**
* @since 2.2.3
*/
export const contramap: <A, B>(f: (b: B) => A) => (fa: JsonEncoder<A>) => JsonEncoder<B> = E.contramap

// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
Expand Down Expand Up @@ -143,8 +152,3 @@ export const jsonEncoder: Contravariant1<URI> & Schemable1<URI> = {
sum,
lazy: (_, f) => lazy(f)
}

/**
* @since 2.2.3
*/
export const contramap: <A, B>(f: (b: B) => A) => (fa: JsonEncoder<A>) => JsonEncoder<B> = E.contramap
13 changes: 13 additions & 0 deletions test/Codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { left, right } from 'fp-ts/lib/Either'
import * as C from '../src/Codec'
import * as D from '../src/Decoder'
import * as G from '../src/Guard'
import { pipe } from 'fp-ts/lib/pipeable'

const NumberFromString: C.Codec<string, number> = C.make(
D.parse(D.string, (s) => {
Expand Down Expand Up @@ -42,6 +43,18 @@ describe('Codec', () => {
})
})

it('imap', () => {
const codec = pipe(
C.string,
C.imap(
(s) => ({ value: s }),
({ value }) => value
)
)
assert.deepStrictEqual(codec.decode('a'), right({ value: 'a' }))
assert.deepStrictEqual(codec.encode({ value: 'a' }), 'a')
})

describe('withExpected', () => {
describe('decode', () => {
it('should, return the provided expected', () => {
Expand Down

0 comments on commit 6edd727

Please sign in to comment.