Skip to content

Commit

Permalink
Merge pull request #291 from jacob-alford/ja/pick-omit
Browse files Browse the repository at this point in the history
Add Struct > `.pick`, `.omit`
  • Loading branch information
jacob-alford authored Oct 8, 2023
2 parents bcc4af1 + 65a445f commit f5503b9
Show file tree
Hide file tree
Showing 24 changed files with 1,136 additions and 88 deletions.
60 changes: 60 additions & 0 deletions docs/Schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ Added in v1.0.0
- [InputOf (type alias)](#inputof-type-alias)
- [OutputOf (type alias)](#outputof-type-alias)
- [TypeOf (type alias)](#typeof-type-alias)
- [utils](#utils)
- [SchemaImplementation (class)](#schemaimplementation-class)
- [[SchemaSymbol] (property)](#schemasymbol-property)
- [input (property)](#input-property)
- [output (property)](#output-property)
- [runSchema (property)](#runschema-property)

---

Expand Down Expand Up @@ -93,3 +99,57 @@ export type TypeOf<S> = S extends Schema<any, infer A> ? A : never
```
Added in v1.0.0
# utils
## SchemaImplementation (class)
**Signature**
```ts
export declare class SchemaImplementation<I, O> {
protected constructor(runSchema: <S extends hkt.SchemableLambda>(S: Schemable<S>) => hkt.SchemableKind<S, I, O>)
}
```

Added in v2.1.0

### [SchemaSymbol] (property)

**Signature**

```ts
readonly [SchemaSymbol]: typeof SchemaSymbol
```

Added in v2.0.0

### input (property)

**Signature**

```ts
readonly input: (_: I) => I
```

Added in v2.0.0

### output (property)

**Signature**

```ts
readonly output: (_: O) => O
```

Added in v2.0.0

### runSchema (property)

**Signature**

```ts
readonly runSchema: <S extends hkt.SchemableLambda>(S: Schemable<S>) => hkt.SchemableKind<S, I, O>
```

Added in v2.0.0
5 changes: 4 additions & 1 deletion docs/schemata/Either.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ The fp-ts Either type as a schemata-ts schema.
export declare const Either: <EI, EO, AI, AO>(
left: Schema<EI, EO>,
right: Schema<AI, AO>
) => Schema<{ readonly _tag: 'Left'; left: EI } | { readonly _tag: 'Right'; right: AI }, Either_<EO, AO>>
) => Schema<
{ readonly _tag: 'Left'; readonly left: EI } | { readonly _tag: 'Right'; readonly right: AI },
Either_<EO, AO>
>
```
Added in v2.1.0
4 changes: 2 additions & 2 deletions docs/schemata/Intersect.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Added in v1.0.0
<h2 class="text-delta">Table of contents</h2>

- [Combinators](#combinators)
- [Intersect](#intersect)
- [~~Intersect~~](#intersect)

---

# Combinators

## Intersect
## ~~Intersect~~

An intersection of two struct-derived types.

Expand Down
4 changes: 2 additions & 2 deletions docs/schemata/Partial.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Added in v1.0.0
<h2 class="text-delta">Table of contents</h2>

- [Combinators](#combinators)
- [Partial](#partial)
- [~~Partial~~](#partial)

---

# Combinators

## Partial
## ~~Partial~~

Used to construct a struct schema with enumerated keys where any number of known keys
are permitted.
Expand Down
4 changes: 2 additions & 2 deletions docs/schemata/Strict.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Added in v1.4.0
<h2 class="text-delta">Table of contents</h2>

- [Combinators](#combinators)
- [Strict](#strict)
- [~~Strict~~](#strict)

---

# Combinators

## Strict
## ~~Strict~~

Same as `Struct` combinator, but disallows additional properties.

Expand Down
22 changes: 6 additions & 16 deletions docs/schemata/Struct.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,16 @@ Used to construct a struct schema with enumerated keys.
enumerated keys. It will decode properly otherwise, but TypeScript will not permit
construction of such a type

**Note:** The second parameter `extraProps` is deprecated, use `Struct({}).strict()` or
`Struct({}).addIndexSignature()` instead

**Signature**

```ts
export declare const Struct: <
T extends Record<string, Schema<any, any>>,
IndexSignature extends Schema<any, any> | undefined
>(
export declare const Struct: <T extends Record<string, Schema<any, any>>, Ix extends IxSigBase = undefined>(
props: T,
extraProps?: IndexSignature | 'strip' | 'error'
) => Schema<
{
[KeyType in keyof (RestInput<IndexSignature> &
RequiredInputProps<T> &
OptionalInputProps<T>)]: (RestInput<IndexSignature> & RequiredInputProps<T> & OptionalInputProps<T>)[KeyType]
},
{
[KeyType in keyof (RestOutput<IndexSignature> & OutputProps<T>)]: (RestOutput<IndexSignature> &
OutputProps<T>)[KeyType]
}
>
extraProps?: ExtraProps<Ix>
) => StructSchema<T, Ix>
```
Added in v1.0.0
30 changes: 15 additions & 15 deletions docs/schemata/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,23 @@ has_children: true

### String (17)

* Ascii ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Ascii.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Ascii.ts)) (e.g: `DMBp]3`, `
* Base64 ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Base64.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Base64.ts)) (e.g: `+/A+K/87a/lV+y7/+28=`, `d/1Xc5eE+/E/+E==`, `4/S0++w/A+b/+4d/+0++Zk188/81++b=`)
* Base64Url ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Base64Url.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Base64Url.ts)) (e.g: `ABaw_9N4-9`, `d_uCP7__`, `X_-m-8`)
* BitcoinAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/BitcoinAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/BitcoinAddress.ts)) (e.g: `2e7AKymhN3LWikM8VDrjEK5DFmKP8mbj`, `bc19vebs1b1s23v10199az22ucc7`, `bc11x70o9g7c9831508kx4penko7vh`)
* Ascii ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Ascii.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Ascii.ts)) (e.g: `z_Wn=W.rTe`, `zaJ$`, `@&ly*#`)
* Base64 ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Base64.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Base64.ts)) (e.g: `+i0s/YU6/pq+/oMhx+oJJk+ba3H/`, `/2/SijcCIMe+2LDB+f/+3/++HJCKW/3//++N++++`, `/Ec0e4/Ij+0g20+3C/z+/ED=`)
* Base64Url ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Base64Url.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Base64Url.ts)) (e.g: `_-hr-__-_-`, `--O--x_0Js`, `1_---__80F`)
* BitcoinAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/BitcoinAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/BitcoinAddress.ts)) (e.g: `bc113b3v73m296c0m4ez01d0cl006d0`, `bc10se9unaag1g9348agc2690w38t0a33bzb7y8`, `bc14de1w009332i78ex713e1o7d1`)
* CamelCaseString ([docs](https://jacob-alford.github.io/schemata-ts/schemata/CamelCaseString.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/CamelCaseString.ts)) (e.g: `Camel_case-string``camelCaseString`)
* CreditCard ([docs](https://jacob-alford.github.io/schemata-ts/schemata/CreditCard.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/CreditCard.ts)) (e.g: `6221272306310132`, `62844733161743063`, `3529393243393399`)
* EmailAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/EmailAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/EmailAddress.ts)) (e.g: `"㑂鑬"@.42l346MlA.7.s4j.5.9-.qwxbrcLjdceQc`, `%^|.a~-?~9!~.$~##+.r'*R}~^_k.+.*.|{*@[5.1.919.8]`, `_}&$!'*$W#.#&.'^*_#+~d%@[279.977.590.6]`)
* EthereumAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/EthereumAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/EthereumAddress.ts)) (e.g: `0x2A80CeC004780fbfacD0DbFcbCBbc4Dee1A8Fa7E`, `0x3BAdfaC5bA8cfcf7bC3AdFbf11CaFBC70A19D6E1`, `0x7aA8dAAab980a7BcBEcaEcFcfaa3afE7ea372bB2`)
* HexColor ([docs](https://jacob-alford.github.io/schemata-ts/schemata/HexColor.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/HexColor.ts)) (e.g: `DacDac`, `bbcaD7`, `00cEa60c`)
* Hexadecimal ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Hexadecimal.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Hexadecimal.ts)) (e.g: `c9A41aAec`, `0XD6C3C`, `64Ce0b4e1847`)
* HslColor ([docs](https://jacob-alford.github.io/schemata-ts/schemata/HslColor.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/HslColor.ts)) (e.g: `hsl(.7829e59446263,000.3985798%,00031.1226%)`, `hsl(+88,000000.37242374%,+00000.900%)`, `hsla(04e-416988rad,000.38e+638451659%,+0.0062e384754552%,2.3255934e26914606)`)
* Jwt ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Jwt.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Jwt.ts)) (e.g: `1.__8rl--6_.__0`, `Wug.-0z-9A._`, `_a.e_c`)
* LatLong ([docs](https://jacob-alford.github.io/schemata-ts/schemata/LatLong.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/LatLong.ts)) (e.g: `-90.0000,+180`, `(81,+5)`, `-90.000,180`)
* NonEmptyString ([docs](https://jacob-alford.github.io/schemata-ts/schemata/NonEmptyString.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/NonEmptyString.ts)) (e.g: `}N2fg`, `]L)w:9=<b`, `WM9WXXSW4Cz=`)
* RGB ([docs](https://jacob-alford.github.io/schemata-ts/schemata/RGB.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/RGB.ts)) (e.g: `rgb(117,254,123)`, `rgba(100%,95%,90%,1)`, `rgb(239,202,204)`)
* CreditCard ([docs](https://jacob-alford.github.io/schemata-ts/schemata/CreditCard.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/CreditCard.ts)) (e.g: `6282395537285124`, `6507812336159728314`, `6283187900719014`)
* EmailAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/EmailAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/EmailAddress.ts)) (e.g: `%$.~=|-%_-&@[0.0.01.6]`, `"⧛碒応癅쑸㏉縋襬℧"@82--we.7-T-.Y-..cDVbpExvnEpuiE`, `"웿雊"@g-njj.PBzyAabc..zwce`)
* EthereumAddress ([docs](https://jacob-alford.github.io/schemata-ts/schemata/EthereumAddress.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/EthereumAddress.ts)) (e.g: `0x126F117E3E433eFb159e80ecC66193DC6Eb9d8Be`, `0xd212fBA3aCab1adEC3721a18AA5BAB8EABFbfCed`, `0xBcccBcA2dFc39131e02bf7AF22DCaFF7aa1c13Ac`)
* HexColor ([docs](https://jacob-alford.github.io/schemata-ts/schemata/HexColor.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/HexColor.ts)) (e.g: `92DbccFB`, `#F4878a`, `db531a`)
* Hexadecimal ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Hexadecimal.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Hexadecimal.ts)) (e.g: `0hD3F7aFd65`, `b5e99F1f9`, `AffA0cDc853`)
* HslColor ([docs](https://jacob-alford.github.io/schemata-ts/schemata/HslColor.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/HslColor.ts)) (e.g: `hsla(+.2e35063810,0100%,.0081%)`, `hsl(+.589+0000000000.36%8%/24615646.25%)`, `hsl(+36.45,0100e+382179358%,+03.48708057%)`)
* Jwt ([docs](https://jacob-alford.github.io/schemata-ts/schemata/Jwt.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/Jwt.ts)) (e.g: `_3.-Q_cuO-_-.AWV-1P8`, `o-KZ4L6_H_.-135__V0__`, `d3_7W98a6._-9__Og__`)
* LatLong ([docs](https://jacob-alford.github.io/schemata-ts/schemata/LatLong.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/LatLong.ts)) (e.g: `+90,98`, `+90.0000000,180.0000000000`, `-90,180`)
* NonEmptyString ([docs](https://jacob-alford.github.io/schemata-ts/schemata/NonEmptyString.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/NonEmptyString.ts)) (e.g: `B9O7Rf`, `58eeb8`, `cAB+K3/0CDC=`)
* RGB ([docs](https://jacob-alford.github.io/schemata-ts/schemata/RGB.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/RGB.ts)) (e.g: `rgb(11,216,110)`, `rgb(240,94,253)`, `rgba(96%,100%,91%,1.0)`)
* String ([docs](https://jacob-alford.github.io/schemata-ts/schemata/String.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/String.ts))
* UUID ([docs](https://jacob-alford.github.io/schemata-ts/schemata/UUID.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/UUID.ts)) (e.g: `c0dACC1a-360c-7a69-CC51-E8cc7EFBAcdc`, `afA1B1CA-5371-EDCc-1Cb8-A7a7ce3aaFDC`, `ddCd08e3-dc37-5cAa-EDf0-9ADbffBbb3B6`)
* UUID ([docs](https://jacob-alford.github.io/schemata-ts/schemata/UUID.html)) ([source](https://github.com/jacob-alford/schemata-ts/tree/main/src/schemata/UUID.ts)) (e.g: `bf7F0ACe-b9C3-deE7-aaaA-BdB1F1a2AAcA`, `AbBffAdE-460d-bBFC-53C7-6B729Cde0Be6`, `1DA197F8-F0fB-1fFA-630e-89DBCCcba9ef`)

### Unit (1)

Expand Down
6 changes: 5 additions & 1 deletion src/JsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,11 @@ export const annotate: (params?: {
}) => (schema: JsonSchema) => Const<JsonSchema, never> =
({ title, description, references, deprecated, readOnly } = {}) =>
schema =>
title === undefined && description === undefined && references === undefined
title === undefined &&
description === undefined &&
references === undefined &&
deprecated === undefined &&
readOnly === undefined
? make(schema)
: make({
...schema,
Expand Down
49 changes: 49 additions & 0 deletions src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* @since 1.0.0
*/
import { identity, unsafeCoerce } from 'fp-ts/function'
import type * as hkt from 'schemata-ts/internal/schemable'
import { type Schemable } from 'schemata-ts/Schemable'

Expand All @@ -22,6 +23,41 @@ export interface Schema<I, O = I> {
) => hkt.SchemableKind<S, I, O>
}

/** @since 2.1.0 */
export class SchemaImplementation<I, O = I> implements Schema<I, O> {
/** @since 2.0.0 */
readonly [SchemaSymbol]: SchemaSymbol = SchemaSymbol

/** @since 2.0.0 */
readonly input: (_: I) => I = identity

/** @since 2.0.0 */
readonly output: (_: O) => O = identity

/** @since 2.0.0 */
readonly runSchema: <S extends hkt.SchemableLambda>(
S: Schemable<S>,
) => hkt.SchemableKind<S, I, O>

protected constructor(
runSchema: <S extends hkt.SchemableLambda>(
S: Schemable<S>,
) => hkt.SchemableKind<S, I, O>,
) {
this.runSchema = memoize(runSchema)
}

/** @internal */
public static make = <S extends Schema<any, any>['runSchema']>(
f: S,
): S extends (...args: ReadonlyArray<any>) => {
Input: (...args: ReadonlyArray<any>) => infer I
Output: (...args: ReadonlyArray<any>) => infer O
}
? Schema<I, O>
: never => unsafeCoerce(new SchemaImplementation(f))
}

/**
* @since 2.0.0
* @category Guards
Expand Down Expand Up @@ -54,3 +90,16 @@ export type OutputOf<S> = TypeOf<S>
* @category Type Helpers
*/
export type InputOf<S> = S extends Schema<infer I, any> ? I : never

/** @internal */
export const memoize = <A, B>(f: (a: A) => B): ((a: A) => B) => {
const cache = new Map()
return a => {
if (!cache.has(a)) {
const b = f(a)
cache.set(a, b)
return b
}
return cache.get(a)
}
}
39 changes: 14 additions & 25 deletions src/internal/schema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
/* eslint-disable @typescript-eslint/ban-types */
import { identity, unsafeCoerce } from 'fp-ts/function'
import { type Option } from 'schemata-ts/internal/option'
import { type SchemableKind, type SchemableLambda } from 'schemata-ts/internal/schemable'
import type * as s from 'schemata-ts/internal/struct'
import { type InputOf, type OutputOf, type Schema } from 'schemata-ts/Schema'
import {
type InputOf,
type OutputOf,
type Schema,
SchemaImplementation,
} from 'schemata-ts/Schema'
import { type Schemable } from 'schemata-ts/Schemable'

/** @since 2.0.0 */
Expand All @@ -29,6 +33,10 @@ export type PartialOutputProps<T extends Record<string, Schema<any, any>>> = {
: OutputOf<T[K]> | undefined
}

export type OptionOutputProps<T extends Record<string, Schema<any, any>>> = {
[K in keyof T]: Option<NonNullable<OutputOf<T[K]>>>
}

/** @since 2.0.0 */
export type RestInput<RestKind> = RestKind extends undefined
? unknown
Expand All @@ -39,21 +47,6 @@ export type RestOutput<RestKind> = RestKind extends undefined
? unknown
: { [key: string]: RestKind extends Schema<any, infer O> ? O : never }

/** @internal */
export const memoize = <A, B>(f: (a: A) => B): ((a: A) => B) => {
const cache = new Map()
return a => {
if (!cache.has(a)) {
const b = f(a)
cache.set(a, b)
return b
}
return cache.get(a)
}
}

const SchemaSymbol = Symbol.for('schemata-ts/Schema')

/** @internal */
export const make = <S extends Schema<any, any>['runSchema']>(
f: S,
Expand All @@ -62,13 +55,7 @@ export const make = <S extends Schema<any, any>['runSchema']>(
Output: (...args: ReadonlyArray<any>) => infer A
}
? Schema<E, A>
: never =>
unsafeCoerce({
[SchemaSymbol]: SchemaSymbol,
runSchema: memoize(f),
input: identity,
output: identity,
})
: never => SchemaImplementation.make(f)

/** @since 2.0.0 */
export type Interpreter<S extends SchemableLambda> = <I, O>(
Expand All @@ -79,3 +66,5 @@ export type Interpreter<S extends SchemableLambda> = <I, O>(
export const interpret: <S extends SchemableLambda>(S: Schemable<S>) => Interpreter<S> =
S => schema =>
schema.runSchema(S)

export { memoize } from 'schemata-ts/Schema'
1 change: 1 addition & 0 deletions src/schemata/Intersect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { type Schema } from 'schemata-ts/Schema'
/**
* An intersection of two struct-derived types.
*
* @deprecated Use `Struct({}).intersect()` instead.
* @since 1.0.0
* @category Combinators
*/
Expand Down
2 changes: 2 additions & 0 deletions src/schemata/Partial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import { StructTypeString } from 'schemata-ts/schemables/struct/instances/type-s
import type * as s from 'schemata-ts/schemables/struct/type-utils'
import { Optional } from 'schemata-ts/schemata/Optional'
import { type Simplify } from 'type-fest'

/**
* Used to construct a struct schema with enumerated keys where any number of known keys
* are permitted.
*
* @deprecated Use `Struct({}).partial()` instead
* @since 1.0.0
* @category Combinators
*/
Expand Down
1 change: 1 addition & 0 deletions src/schemata/Strict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { type Simplify } from 'type-fest'
/**
* Same as `Struct` combinator, but disallows additional properties.
*
* @deprecated Use `Struct({}).strict()` instead
* @since 2.0.0
* @category Combinators
*/
Expand Down
Loading

0 comments on commit f5503b9

Please sign in to comment.