Skip to content

Commit

Permalink
test(types): wip testing
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFedaikin committed Jan 22, 2023
1 parent 442b8a8 commit 79de7e8
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/__tests__/@helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ export const expectedParsers = [
'whole'
] as const

export { describe, expect, it } from 'vitest'
export { describe, expect, it, assertType, expectTypeOf } from 'vitest'
24 changes: 24 additions & 0 deletions src/__tests__/combinators/sequence.type.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { sequence } from '@combinators'
import { describe, it, expectTypeOf } from '@testing'
import { Parser } from '@types'

describe('sequence', () => {
type StringParser = Parser<string>
type NumberParser = Parser<number>

it('should have correct inferred signature', () => {
expectTypeOf(sequence<[StringParser, StringParser]>).returns.toMatchTypeOf<
Parser<[string, string]>
>()
expectTypeOf(sequence<[StringParser, NumberParser]>).returns.toMatchTypeOf<
Parser<[string, number]>
>()
expectTypeOf(sequence<StringParser[]>).returns.toMatchTypeOf<Parser<string[]>>()
expectTypeOf(sequence<NumberParser[]>).returns.toMatchTypeOf<Parser<number[]>>()

// Fix this ?
expectTypeOf(sequence<(NumberParser | StringParser)[]>).returns.toMatchTypeOf<
Parser<string[] | number[]>
>()
})
})
87 changes: 87 additions & 0 deletions src/__tests__/types.type.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { describe, it, expectTypeOf } from '@testing'
import * as t from '@types'

describe('parsers', () => {
it('`SucceedingParser` should correctly infer right signature', () => {
type SucceedingNumberParser = t.SucceedingParser<number>

expectTypeOf<SucceedingNumberParser>().toBeObject()
expectTypeOf<SucceedingNumberParser>().not.toBeAny()
expectTypeOf<SucceedingNumberParser>()
.toHaveProperty('parse')
.returns.toMatchTypeOf<t.Success<number>>()
})

it('`UnsafeParser` should correctly infer right signature', () => {
type UnsafeNumberParser = t.UnsafeParser<number>

expectTypeOf<UnsafeNumberParser>().toBeObject()
expectTypeOf<UnsafeNumberParser>().not.toBeAny()
expectTypeOf<UnsafeNumberParser>()
.toHaveProperty('parse')
.returns.toMatchTypeOf<t.Result<number>>()
})

it('`Parser` should correctly infer right signature', () => {
type NumberParser = t.Parser<number>
expectTypeOf<NumberParser>().toBeObject()
expectTypeOf<NumberParser>().not.toBeAny()
expectTypeOf<NumberParser>()
.toHaveProperty('parse')
.toMatchTypeOf<
| ((input: string, pos: number) => t.Success<number>)
| ((input: string, pos: number) => t.Result<number>)
| ((input: string, pos: number) => t.Failure)
>()
})
})

describe('state', () => {
it('`Success` should correctly infer right signature', () => {
type SuccessWithNumber = t.Success<number>

expectTypeOf<SuccessWithNumber>().not.toBeAny()
expectTypeOf<SuccessWithNumber>().toMatchTypeOf<{
readonly span: t.Span
readonly pos: number
readonly value: number
}>()
})
})

describe('utils', () => {
type ParsersTuple = [t.Parser<string>, t.Parser<number>, t.Parser<boolean>]
type NumberParsersArray = Array<t.Parser<number>>
type TupleResult = [string, number, boolean]

it('`ToTuple` should correctly infer right signature', () => {
expectTypeOf<t.ToTuple<ParsersTuple>>().toMatchTypeOf<TupleResult>()

expectTypeOf<t.ToTuple<NumberParsersArray>>().toMatchTypeOf<[]>()
})

it('`ToTupleOrArray` should correctly infer right signature', () => {
expectTypeOf<t.ToTupleOrArray<ParsersTuple>>().toMatchTypeOf<TupleResult>()
expectTypeOf<t.ToTupleOrArray<NumberParsersArray>>().toMatchTypeOf<number[]>()

expectTypeOf<t.ToTupleOrArray<NumberParsersArray>>().not.toMatchTypeOf<string[]>()
})

it('`ToUnion` should correctly infer right signature', () => {
expectTypeOf<t.ToUnion<ParsersTuple>>().toMatchTypeOf<string | number | boolean>()

expectTypeOf<t.ToUnion<NumberParsersArray>>().toMatchTypeOf<number>()
expectTypeOf<t.ToUnion<NumberParsersArray>>().not.toMatchTypeOf<string>()
})

it('`UnwrapUnion` should correctly infer right signature', () => {
type ParsersUnion = t.Parser<string> | t.Parser<number> | t.Parser<boolean>

expectTypeOf<t.UnwrapUnion<ParsersUnion>>().toMatchTypeOf<
[boolean] | [number] | [unknown] | [string]
>()

expectTypeOf<t.ToUnion<NumberParsersArray>>().toMatchTypeOf<number>()
expectTypeOf<t.ToUnion<NumberParsersArray>>().not.toMatchTypeOf<string>()
})
})
3 changes: 2 additions & 1 deletion src/combinators/sequence.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Parser, ToTuple } from '@types'
import type { Parser, ToTuple, ToTupleOrArray } from '@types'

/**
* Applies `ps` parsers in order, until *all* of them succeed.
Expand All @@ -8,6 +8,7 @@ import type { Parser, ToTuple } from '@types'
* @returns Tuple of values returned by `ps` parsers
*/
export function sequence<T extends Array<Parser<unknown>>>(...ps: T): Parser<ToTuple<T>>
export function sequence<T extends Array<Parser<unknown>>>(...ps: T): Parser<ToTupleOrArray<T>>
export function sequence<T>(...ps: Array<Parser<T>>): Parser<Array<T>> {
return {
parse(input, pos) {
Expand Down
21 changes: 21 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ export type ToTuple<T> = T extends [Parser<infer Head>, ...infer Tail]
? [Head, ...ToTuple<Tail>]
: []

/**
* Given a an array or a tuple of `Parser<T>`s, recursively extracts inner `T`s into a tuple or array.
*
* @example
*
* ```ts
* type U = [Parser<string>, Parser<number>, Parser<boolean>]
* type R = ToTuple<U> // type R = [string, number, boolean]
*
* type A = Parser<Array<string>>
* type T = ToTupleOrArray<A> // type T = string[]
* ```
*/
export type ToTupleOrArray<T> = T extends Array<Parser<infer Inner>>
? Inner extends unknown
? T extends [Parser<infer Head>, ...infer Tail]
? [Head, ...ToTuple<Tail>]
: Inner[]
: []
: []

/**
* Given a tuple of `Parser<T>`s, recursively extracts inner `T`s into a union.
*
Expand Down

0 comments on commit 79de7e8

Please sign in to comment.