Skip to content

Commit

Permalink
feat: expand Guard combinators
Browse files Browse the repository at this point in the history
  • Loading branch information
TylorS committed Feb 24, 2024
1 parent d285001 commit a2150dc
Show file tree
Hide file tree
Showing 10 changed files with 437 additions and 44 deletions.
6 changes: 6 additions & 0 deletions .changeset/unlucky-yaks-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@typed/guard": patch
"@typed/route": patch
---

Expand Guard combinators
134 changes: 134 additions & 0 deletions docs/guard/index.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ Added in v1.0.0
- [Input (type alias)](#input-type-alias)
- [Output (type alias)](#output-type-alias)
- [GuardInput (type alias)](#guardinput-type-alias)
- [addTag](#addtag)
- [any](#any)
- [bind](#bind)
- [bindTo](#bindto)
- [catchAll](#catchall)
- [catchAllCause](#catchallcause)
- [compose](#compose)
- [decode](#decode)
- [encode](#encode)
- [filter](#filter)
- [filterMap](#filtermap)
- [fromSchemaDecode](#fromschemadecode)
- [fromSchemaEncode](#fromschemaencode)
- [getGuard](#getguard)
- [let](#let)
- [liftPredicate](#liftpredicate)
- [map](#map)
- [mapEffect](#mapeffect)
Expand Down Expand Up @@ -166,6 +174,19 @@ export type GuardInput<I, O, E = never, R = never> = Guard<I, O, E, R> | AsGuard
Added in v1.0.0
## addTag
**Signature**
```ts
export declare const addTag: {
<B>(value: B): <I, O, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O & { readonly _tag: B }, E, R>
<I, O, E, R, B>(guard: Guard<I, O, E, R>, value: B): Guard<I, O & { readonly _tag: B }, E, R>
}
```
Added in v1.0.0
## any
**Signature**
Expand All @@ -178,6 +199,39 @@ export declare function any<const GS extends Readonly<Record<string, GuardInput<

Added in v1.0.0

## bind

**Signature**

```ts
export declare const bind: {
<I, O, E, R, K extends PropertyKey, B, E2, R2>(
key: K,
f: GuardInput<O, B, E2, R2>
): (guard: GuardInput<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E | E2, R | R2>
<I, O, E, R, K extends PropertyKey, B, E2, R2>(
guard: GuardInput<I, O, E, R>,
key: K,
f: GuardInput<O, B, E2, R2>
): Guard<I, O & { [k in K]: B }, E | E2, R | R2>
}
```

Added in v1.0.0

## bindTo

**Signature**

```ts
export declare const bindTo: {
<K extends PropertyKey>(key: K): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, { [k in K]: O }, E, R>
<I, O, E, R, K extends PropertyKey>(guard: GuardInput<I, O, E, R>, key: K): Guard<I, { [k in K]: O }, E, R>
}
```

Added in v1.0.0

## catchAll

**Signature**
Expand Down Expand Up @@ -229,6 +283,42 @@ export declare const compose: {

Added in v1.0.0

## decode

**Signature**

```ts
export declare const decode: {
<A, O, R2>(
schema: Schema.Schema<A, O, R2>
): <I, E = never, R = never>(guard: GuardInput<I, O, E, R>) => Guard<I, A, E | ParseResult.ParseError, R2 | R>
<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<A, O, R2>
): Guard<I, A, E | ParseResult.ParseError, R | R2>
}
```

Added in v1.0.0

## encode

**Signature**

```ts
export declare const encode: {
<O, A, R2>(
schema: Schema.Schema<O, A, R2>
): <I, E = never, R = never>(guard: GuardInput<I, O, E, R>) => Guard<I, A, ParseResult.ParseError | E, R2 | R>
<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<O, A, R2>
): Guard<I, A, ParseResult.ParseError | E, R | R2>
}
```

Added in v1.0.0

## filter

**Signature**
Expand Down Expand Up @@ -257,6 +347,30 @@ export declare const filterMap: {

Added in v1.0.0

## fromSchemaDecode

**Signature**

```ts
export declare function fromSchemaDecode<A, I, R>(
schema: Schema.Schema<A, I, R>
): Guard<I, A, ParseResult.ParseError, R>
```

Added in v1.0.0

## fromSchemaEncode

**Signature**

```ts
export declare function fromSchemaEncode<A, I, R>(
schema: Schema.Schema<A, I, R>
): Guard<A, I, ParseResult.ParseError, R>
```

Added in v1.0.0

## getGuard

**Signature**
Expand All @@ -267,6 +381,26 @@ export declare const getGuard: <I, O, E = never, R = never>(guard: GuardInput<I,

Added in v1.0.0

## let

**Signature**

```ts
export declare const let: {
<K extends PropertyKey, B>(
key: K,
value: B
): <I, O, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E, R>
<I, O, E, R, K extends PropertyKey, B>(
guard: Guard<I, O, E, R>,
key: K,
value: B
): Guard<I, O & { [k in K]: B }, E, R>
}
```

Added in v1.0.0

## liftPredicate

**Signature**
Expand Down
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"@effect/docgen": "^0.3.8",
"@effect/eslint-plugin": "^0.1.2",
"@effect/language-service": "0.1.0",
"@effect/typeclass": "0.23.0",
"@types/chai": "^4.3.12",
"@types/node": "^20.11.20",
"@typescript-eslint/eslint-plugin": "^7.0.2",
Expand All @@ -59,7 +58,6 @@
"babel-plugin-annotate-pure-calls": "^0.4.0",
"cac": "^6.7.14",
"concurrently": "^8.2.2",
"effect": "^2.4.0",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-codegen": "0.23.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
"typed-query-selector": "^2.11.0"
},
"peerDependencies": {
"@effect/schema": "0.61.5",
"@effect/schema": "0.63.0",
"@typed/context": "workspace:*",
"effect": "^2.2.3"
"effect": "^2.4.0"
}
}
7 changes: 4 additions & 3 deletions packages/guard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"author": "Typed contributors",
"license": "MIT",
"sideEffects": [],
"dependencies": {},
"peerDependencies": {},
"devDependencies": {}
"dependencies": {
"@effect/schema": "0.63.0",
"effect": "^2.4.0"
}
}
141 changes: 141 additions & 0 deletions packages/guard/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* @since 1.0.0
*/

import type { ParseOptions } from "@effect/schema/AST"
import type * as ParseResult from "@effect/schema/ParseResult"
import * as Schema from "@effect/schema/Schema"
import type { Cause, Context, Layer, Predicate, Runtime } from "effect"
import * as Effect from "effect/Effect"
import { dual } from "effect/Function"
Expand Down Expand Up @@ -319,3 +322,141 @@ export const provideServiceEffect: {
const g = getGuard(guard)
return (i) => Effect.provideServiceEffect(g(i), tag, service)
})

const parseOptions: ParseOptions = { errors: "all", onExcessProperty: "ignore" }

/**
* @since 1.0.0
*/
export function fromSchemaDecode<A, I, R>(schema: Schema.Schema<A, I, R>): Guard<I, A, ParseResult.ParseError, R> {
const decode_ = Schema.decode(schema)
return (i: I) => Effect.asSome(decode_(i, parseOptions))
}

/**
* @since 1.0.0
*/
export function fromSchemaEncode<A, I, R>(schema: Schema.Schema<A, I, R>): Guard<A, I, ParseResult.ParseError, R> {
const encode_ = Schema.encode(schema)
return (a: A) => Effect.asSome(encode_(a, parseOptions))
}

/**
* @since 1.0.0
*/
export const decode: {
<A, O, R2>(
schema: Schema.Schema<A, O, R2>
): <I, E = never, R = never>(guard: GuardInput<I, O, E, R>) => Guard<I, A, ParseResult.ParseError | E, R | R2>

<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<A, O, R2>
): Guard<I, A, ParseResult.ParseError | E, R | R2>
} = dual(2, function decode<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<A, O, R2>
): Guard<I, A, E | ParseResult.ParseError, R | R2> {
return compose(guard, fromSchemaDecode(schema))
})

/**
* @since 1.0.0
*/
export const encode: {
<O, A, R2>(
schema: Schema.Schema<O, A, R2>
): <I, E = never, R = never>(guard: GuardInput<I, O, E, R>) => Guard<I, A, ParseResult.ParseError | E, R | R2>

<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<O, A, R2>
): Guard<I, A, ParseResult.ParseError | E, R | R2>
} = dual(2, function encode<I, O, E, R, A, R2>(
guard: GuardInput<I, O, E, R>,
schema: Schema.Schema<O, A, R2>
): Guard<I, A, E | ParseResult.ParseError, R | R2> {
return compose(guard, fromSchemaEncode(schema))
})

/**
* @since 1.0.0
*/
const let_: {
<K extends PropertyKey, B>(
key: K,
value: B
): <I, O, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E, R>

<I, O, E, R, K extends PropertyKey, B>(
guard: Guard<I, O, E, R>,
key: K,
value: B
): Guard<I, O & { [k in K]: B }, E, R>
} = dual(3, function attachProperty<I, O, E, R, K extends PropertyKey, B>(
guard: Guard<I, O, E, R>,
key: K,
value: B
): Guard<I, O & { [k in K]: B }, E, R> {
return map(guard, (a) => ({ ...a, [key]: value } as O & { [k in K]: B }))
})

export {
/**
* @since 1.0.0
*/
let_ as let
}

/**
* @since 1.0.0
*/
export const addTag: {
<B>(
value: B
): <I, O, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O & { readonly _tag: B }, E, R>

<I, O, E, R, B>(
guard: Guard<I, O, E, R>,
value: B
): Guard<I, O & { readonly _tag: B }, E, R>
} = dual(2, function attachProperty<I, O, E, R, B>(
guard: Guard<I, O, E, R>,
value: B
): Guard<I, O & { readonly _tag: B }, E, R> {
return map(guard, (a) => ({ ...a, _tag: value } as O & { readonly _tag: B }))
})
/**
* @since 1.0.0
*/
export const bindTo: {
<K extends PropertyKey>(key: K): <I, O, E, R>(guard: GuardInput<I, O, E, R>) => Guard<I, { [k in K]: O }, E, R>
<I, O, E, R, K extends PropertyKey>(guard: GuardInput<I, O, E, R>, key: K): Guard<I, { [k in K]: O }, E, R>
} = dual(2, <I, O, E, R, K extends PropertyKey>(
guard: GuardInput<I, O, E, R>,
key: K
): Guard<I, { [k in K]: O }, E, R> => map(guard, (a) => ({ [key]: a } as { [k in K]: O })))

/**
* @since 1.0.0
*/
export const bind: {
<I, O, E, R, K extends PropertyKey, B, E2, R2>(
key: K,
f: GuardInput<O, B, E2, R2>
): (guard: GuardInput<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E | E2, R | R2>

<I, O, E, R, K extends PropertyKey, B, E2, R2>(
guard: GuardInput<I, O, E, R>,
key: K,
f: GuardInput<O, B, E2, R2>
): Guard<I, O & { [k in K]: B }, E | E2, R | R2>
} = dual(3, function bind<I, O, E, R, K extends PropertyKey, B, E2, R2>(
guard: GuardInput<I, O, E, R>,
key: K,
f: GuardInput<O, B, E2, R2>
): Guard<I, O & { [k in K]: B }, E | E2, R | R2> {
const f_ = bindTo(f, key)

return compose(guard, (o) => Effect.map(f_(o), Option.map((b) => ({ ...o, ...b }))))
})
3 changes: 3 additions & 0 deletions packages/route/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@
"license": "MIT",
"sideEffects": [],
"dependencies": {
"@effect/schema": "0.63.0",
"@typed/guard": "workspace:*",
"@typed/path": "workspace:*",
"effect": "^2.4.0",
"path-to-regexp": "^6.2.1"
},
"peerDependencies": {
"@effect/schema": "0.63.0",
"@typed/guard": "workspace:*",
"@typed/path": "workspace:*",
"effect": "^2.2.3",
"path-to-regexp": "^6.2.1"
Expand Down
Loading

0 comments on commit a2150dc

Please sign in to comment.