Skip to content

Commit

Permalink
Merge pull request #259 from jacob-alford/ja/256/newtypes
Browse files Browse the repository at this point in the history
[#256] Add schemata-ts Newtypes
  • Loading branch information
jacob-alford committed Feb 14, 2023
2 parents 8e68709 + 0e42df3 commit 40ce1bc
Show file tree
Hide file tree
Showing 45 changed files with 361 additions and 47 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "schemata-ts",
"version": "1.3.0",
"version": "1.4.0",
"description": "A collection of Schemata inspired by io-ts-types and validators.js",
"homepage": "https://jacob-alford.github.io/schemata-ts/",
"repository": {
Expand Down
32 changes: 22 additions & 10 deletions scripts/generate-schemables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,16 @@ const makeSchemableExtContents: (
),
),

instanceComment('1.0.0'),
instanceComment('Schemable', '1.0.0'),
makeSchemableExtTypeclass(schemables, ''),

instanceComment('1.0.0'),
instanceComment('Schemable', '1.0.0'),
makeSchemableExtTypeclass(schemables, '1'),

instanceComment('1.0.0'),
instanceComment('Schemable', '1.0.0'),
makeSchemableExtTypeclass(schemables, '2'),

instanceComment('1.0.0'),
instanceComment('Schemable', '1.0.0'),
makeSchemableExtTypeclass(schemables, '2C'),
],
_.createNodeArray,
Expand Down Expand Up @@ -156,6 +156,7 @@ export type SchemableTypeclasses =
| SchemableTypeclass<'Arbitrary', 'Arb', 'SchemableExt1', '1.0.0'>
| SchemableTypeclass<'Printer', 'P', 'SchemableExt2', '1.1.0'>
| SchemableTypeclass<'JsonSchema', 'JS', 'SchemableExt2', '1.2.0'>
| SchemableTypeclass<'Schemable', '_', 'SchemableExt2', '1.0.0'>

// #region Typeclass modules

Expand All @@ -164,11 +165,18 @@ export const moduleHeaderComment: (module: string, version: string) => ts.JSDoc
version,
) =>
_.createJSDocComment(
`SchemableExt instances for ${module}\n\n**Warning: DO NOT EDIT, this module is autogenerated**\n\n@since ${version}`,
`SchemableExt instances for ${module}\n\n**Warning: DO NOT EDIT, this module is autogenerated**\n\n${
module === 'Type' ? `@deprecated\n` : ''
}@since ${version}`,
)

export const instanceComment: (version: SchemableTypeclasses[3]) => ts.JSDoc = verision =>
_.createJSDocComment(`@since ${verision}\n@category Instances`)
export const instanceComment: (
module: SchemableTypeclasses[0],
version: SchemableTypeclasses[3],
) => ts.JSDoc = (module, version) =>
_.createJSDocComment(
`${module === 'Type' ? '@deprecated\n' : ''}@since ${version}\n@category Instances`,
)

const makeInstanceTypeExport: (tc: SchemableTypeclasses) => ts.ExportDeclaration = ([
typeclassName,
Expand All @@ -183,7 +191,9 @@ const makeInstanceTypeExport: (tc: SchemableTypeclasses) => ts.ExportDeclaration
ts.addSyntheticLeadingComment(
_.createExportSpecifier(false, undefined, _.createIdentifier(typeclassName)),
ts.SyntaxKind.MultiLineCommentTrivia,
`* @since ${version}\n\n@category Model`,
`* ${
typeclassName === 'Type' ? '@deprecated\n' : ''
}@since ${version}\n\n@category Model`,
true,
),
]),
Expand Down Expand Up @@ -263,7 +273,9 @@ const makeInterpreter: (typeclass: SchemableTypeclasses) => ts.VariableStatement
),
),
ts.SyntaxKind.MultiLineCommentTrivia,
`* @since ${version}\n\n@category Interpreters`,
`* ${
module === 'Type' ? '@deprecated\n' : ''
}@since ${version}\n\n@category Interpreters`,
true,
)

Expand Down Expand Up @@ -299,7 +311,7 @@ const makeSchemableInstanceModuleContents: (
),
),
makeInstanceTypeExport(typeclass),
instanceComment(sinceVersion),
instanceComment(module, sinceVersion),
makeSchemableInstance(typeclass, schemables),
makeInterpreter(typeclass),
],
Expand Down
2 changes: 1 addition & 1 deletion src/base/PrinterBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { flow, identity, pipe, unsafeCoerce } from 'fp-ts/function'
import * as O from 'fp-ts/Option'
import * as RA from 'fp-ts/ReadonlyArray'
import * as RR from 'fp-ts/ReadonlyRecord'
import { Branded } from 'io-ts'
import * as S from 'io-ts/Schemable'
import { Schemable2 } from 'schemata-ts/base/SchemableBase'
import { Branded } from 'schemata-ts/brand'
import { typeOf, witherS } from 'schemata-ts/internal/util'
import * as PE from 'schemata-ts/PrintError'
import { WithRefine2 } from 'schemata-ts/schemables/WithRefine/definition'
Expand Down
22 changes: 22 additions & 0 deletions src/brand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* A port of `io-ts` branded types to schemata-ts
*
* @since 1.4.0
*/
import { Brand as Brand_ } from 'io-ts'

/**
* Represents a unique identifier to prevent non-branded types from being assigned to branded types.
*
* @since 1.4.0
* @category Model
*/
export interface Brand<B> extends Brand_<B> {}

/**
* A newtype that's assignable to its underlying type.
*
* @since 1.4.0
* @category Model
*/
export type Branded<A, B> = A & Brand<B>
117 changes: 117 additions & 0 deletions src/iso.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* A port of `monocle-ts` experimental `Iso` to schemata-ts
*
* @since 1.4.0
*/
import { Category2 } from 'fp-ts/Category'
import { flow, identity } from 'fp-ts/function'
import { Invariant2 } from 'fp-ts/Invariant'
import { Semigroupoid2 } from 'fp-ts/Semigroupoid'

/**
* Represents an isomorphism between two types.
*
* @since 1.4.0
* @category Models
*/
export interface Iso<A, B> {
readonly get: (a: A) => B
readonly reverseGet: (b: B) => A
}

/**
* @since 1.4.0
* @category Constructors
*/
export const make: <A, B>(get: (a: A) => B, reverseGet: (b: B) => A) => Iso<A, B> = (
get,
reverseGet,
) => ({
get,
reverseGet,
})

// Non-pipeables
const imap_: <S, A, B>(iso: Iso<S, A>, f: (a: A) => B, g: (b: B) => A) => Iso<S, B> = (
iso,
f,
g,
) => ({
get: flow(iso.get, f),
reverseGet: flow(g, iso.reverseGet),
})
const compose_: <A, B, C>(bc: Iso<B, C>, ab: Iso<A, B>) => Iso<A, C> = (bc, ab) => ({
get: flow(ab.get, bc.get),
reverseGet: flow(bc.reverseGet, ab.reverseGet),
})

/**
* @since 1.4.0
* @category Instance Methods
*/
export const imap: <A, B>(
f: (a: A) => B,
g: (b: B) => A,
) => <S>(iso: Iso<S, A>) => Iso<S, B> = (f, g) => iso => imap_(iso, f, g)

/**
* @since 1.4.0
* @category Instance Methods
*/
export const compose: <B, C>(ab: Iso<B, C>) => <A>(iso: Iso<A, B>) => Iso<A, C> =
bc => ab =>
compose_(bc, ab)

/**
* @since 1.4.0
* @category Instance Methods
*/
export const id: <A>() => Iso<A, A> = () => ({
get: identity,
reverseGet: identity,
})

/**
* @since 1.4.0
* @category Instances
*/
export const URI = 'schemata-ts/Iso'

/**
* @since 1.4.0
* @category Instances
*/
export type URI = typeof URI

declare module 'fp-ts/lib/HKT' {
interface URItoKind2<E, A> {
readonly [URI]: Iso<E, A>
}
}

/**
* @since 1.4.0
* @category Instances
*/
export const Invariant: Invariant2<URI> = {
URI,
imap: imap_,
}

/**
* @since 1.4.0
* @category Instances
*/
export const Semigroupoid: Semigroupoid2<URI> = {
URI,
compose: compose_,
}

/**
* @since 1.4.0
* @category Instances
*/
export const Category: Category2<URI> = {
...Semigroupoid,
id,
}
61 changes: 61 additions & 0 deletions src/newtype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* A port of `newtype-ts` to schemata-ts
*
* @since 1.4.0
*/

import { unsafeCoerce } from 'fp-ts/function'
import { Iso, make } from 'schemata-ts/iso'

/**
* Represents a wrapped type that's not assignable to its underlying type.
*
* @since 1.4.0
* @category Models
*/
export interface Newtype<URI, A> {
readonly _URI: URI
readonly _A: A
}

/**
* @since 1.4.0
* @category Type Helpers
*/
export type URIOf<N extends Newtype<any, any>> = N['_URI']

/**
* @since 1.4.0
* @category Type Helpers
*/
export type CarrierOf<N extends Newtype<any, any>> = N['_A']

/**
* @since 1.4.0
* @category Type Helpers
*/
export type CombineURIs<
N1 extends Newtype<any, any>,
N2 extends Newtype<any, CarrierOf<N1>>,
> = Newtype<URIOf<N1> & URIOf<N2>, CarrierOf<N1>>

/**
* @since 1.4.0
* @category Constructors
*/
export const iso: <Nt extends Newtype<any, any>>() => Iso<Nt, CarrierOf<Nt>> = () =>
make(unsafeCoerce, unsafeCoerce)

/**
* @since 1.4.0
* @category Constructors
*/
export const wrap: <Nt extends Newtype<any, any>>() => (a: CarrierOf<Nt>) => Nt = () =>
unsafeCoerce

/**
* @since 1.4.0
* @category Destructors
*/
export const unwrap: <Nt extends Newtype<any, any>>() => (a: Nt) => CarrierOf<Nt> = () =>
unsafeCoerce
2 changes: 1 addition & 1 deletion src/schemables/WithBrand/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @since 1.0.0
*/
import { HKT2, Kind, Kind2, URIS, URIS2 } from 'fp-ts/HKT'
import { Branded } from 'io-ts'
import { Branded } from 'schemata-ts/brand'

/**
* @since 1.0.0
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithBrand/instances/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* @since 1.0.0
*/
import { Branded } from 'io-ts'
import { Branded } from 'schemata-ts/brand'
import * as SC from 'schemata-ts/SchemaExt'

/**
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @since 1.0.0
*/
import { HKT2, Kind, Kind2, URIS, URIS2 } from 'fp-ts/HKT'
import { Branded } from 'io-ts'
import { Branded } from 'schemata-ts/brand'

/** @since 1.0.0 */
export interface CheckDigitVerified {
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/arbitrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*
* @since 1.0.0
*/
import { Branded } from 'io-ts'
import * as Arb from 'schemata-ts/base/ArbitraryBase'
import { Branded } from 'schemata-ts/brand'
import {
CheckDigitVerified,
WithCheckDigit1,
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/
import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/function'
import { Branded } from 'io-ts'
import * as D from 'schemata-ts/base/DecoderBase'
import { Branded } from 'schemata-ts/brand'
import {
CheckDigitVerified,
WithCheckDigit2C,
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*
* @since 1.0.0
*/
import { Branded } from 'io-ts'
import * as G from 'schemata-ts/base/GuardBase'
import { Branded } from 'schemata-ts/brand'
import {
CheckDigitVerified,
WithCheckDigit1,
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* @since 1.0.0
*/
import { Branded } from 'io-ts'
import { Branded } from 'schemata-ts/brand'
import { CheckDigitVerified } from 'schemata-ts/schemables/WithCheckDigit/definition'
import * as SC from 'schemata-ts/SchemaExt'

Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/task-decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/
import { pipe } from 'fp-ts/function'
import * as TE from 'fp-ts/TaskEither'
import { Branded } from 'io-ts'
import * as TD from 'schemata-ts/base/TaskDecoderBase'
import { Branded } from 'schemata-ts/brand'
import {
CheckDigitVerified,
WithCheckDigit2C,
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithCheckDigit/instances/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* @since 1.0.0
*/
import { pipe } from 'fp-ts/function'
import { Branded } from 'io-ts'
import * as t from 'schemata-ts/base/TypeBase'
import { Branded } from 'schemata-ts/brand'
import {
CheckDigitVerified,
WithCheckDigit1,
Expand Down
2 changes: 1 addition & 1 deletion src/schemables/WithFloat/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* @since 1.0.0
*/
import { HKT2, Kind, Kind2, URIS, URIS2 } from 'fp-ts/HKT'
import { Branded } from 'io-ts'
import { Branded } from 'schemata-ts/brand'

interface FloatBrand {
readonly Float: unique symbol
Expand Down

0 comments on commit 40ce1bc

Please sign in to comment.