Skip to content

Commit 77884f1

Browse files
authored
Merge pull request #538 from traversable/seed-algebra-type
optimize(*): optimizes type-level performance of `catamorphism`, `fold` functions
2 parents bf21997 + 2b54afa commit 77884f1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+975
-370
lines changed

.changeset/bright-adults-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@traversable/registry": patch
3+
---
4+
5+
feat(registry): adds more robust type for `catamorphism`

.changeset/little-parents-hope.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@traversable/arktype-types": patch
3+
"@traversable/arktype-test": patch
4+
---
5+
6+
optimize(arktype-test,arktype-types): optimizes type-level performance of `ark.fold`

.changeset/rotten-melons-wave.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@traversable/json-schema-types": patch
3+
"@traversable/json-schema-test": patch
4+
---
5+
6+
optimize(json-schema-test,json-schema-types): optimizes type-level performance of `JsonSchema.fold`

.changeset/rude-trams-clap.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@traversable/typebox-types": patch
3+
"@traversable/typebox-test": patch
4+
---
5+
6+
optimize(typebox-test,typebox-types): optimizes type-level performance of `box.fold`

.changeset/smooth-queens-allow.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@traversable/zod-types": patch
3+
"@traversable/zod-test": patch
4+
"@traversable/zod": patch
5+
---
6+
7+
optimize(zod,zod-test,zod-types): optimizes type-level performance of `zx.fold`

.changeset/wicked-buckets-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@traversable/schema": patch
3+
---
4+
5+
optimize(schema): optimizes type-level performance of `t.fold`

.changeset/young-flies-drop.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@traversable/valibot-types": patch
3+
"@traversable/valibot-test": patch
4+
"@traversable/valibot": patch
5+
---
6+
7+
optimize(valibot,valibot-test,valibot-types): optimizes type-level performance of `vx.fold`

packages/arktype-test/README.md

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
1. [`arktype`](https://arktype.io/) (v2.1)
3838
2. [`fast-check`](https://fast-check.dev/)
3939

40+
4041
## Usage
4142

4243
```bash
@@ -52,12 +53,28 @@ import { arkTest } from '@traversable/arktype-test'
5253
// see below for specifc examples
5354
```
5455

56+
5557
## Table of contents
5658

57-
- [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator)
5859
- [`arkTest.seedToSchema`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedtoschema)
5960
- [`arkTest.seedToValidData`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedtovaliddata)
6061
- [`arkTest.seedToInvalidData`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedtoinvaliddata)
62+
- [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator)
63+
- [`arkTest.SeedValidDataGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arkseedvaliddatagenerator)
64+
- [`arkTest.SeedInvalidDataGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arkseedinvaliddatagenerator)
65+
66+
67+
## Track record
68+
69+
`@traversable/arktype-test` has found several upstream bugs:
70+
71+
1. Array + tuple union unsatisfied by empty array
72+
- [Issue](https://github.com/arktypeio/arktype/issues/1441)
73+
- [Sandbox](https://stackblitz.com/edit/vitest-dev-vitest-nho5vqwa?file=test%2Frepro.test.ts)
74+
75+
2. Discriminated union bug
76+
- [Issue](https://github.com/arktypeio/arktype/issues/1440)
77+
- [Sandbox](https://stackblitz.com/edit/vitest-dev-vitest-ddhwwn9j?file=test%2Frepro.test.ts)
6178

6279

6380
### `arkTest.seedToSchema`
@@ -78,6 +95,7 @@ const mySchema = arkTest.seedToSchema(mySeed)
7895
// ^? const mySchema: type.Any
7996
```
8097

98+
8199
### `arkTest.seedToValidData`
82100

83101
Use `arkTest.seedToValidData` to convert a seed generated by `arkTest.SeedGenerator` into
@@ -101,6 +119,7 @@ const validData = arkTest.seedToValidData(mySeed)
101119
mySchema(validData) instanceof type.errors // always `false`
102120
```
103121

122+
104123
### `arkTest.seedToInvalidData`
105124

106125
Use `arkTest.seedToInvalidData` to convert a seed generated by `arkTest.SeedGenerator` into
@@ -124,8 +143,13 @@ const invalidData = arkTest.seedToValidData(mySeed)
124143
mySchema(invalidData) instanceof type.errors // always `true`
125144
```
126145

146+
127147
### `arkTest.SeedGenerator`
128148

149+
> [!NOTE]
150+
>
151+
> `arkTest.SeedGenerator` is fairly low-level. All of the other exports of this library have been implemented in terms of `arkTest.SeedGenerator`.
152+
129153
Generates a configurable, pseudo-random "seed builder".
130154

131155
- Use [`arkTest.seedToSchema`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedtoschema) to convert a seed into an ArkType schema
@@ -136,13 +160,13 @@ Generates a configurable, pseudo-random "seed builder".
136160

137161
```typescript
138162
import { type } from 'arktype'
139-
import { arkTest } from '@traversable/arktype-test'
140163
import * as fc from 'fast-check'
164+
import { arkTest } from '@traversable/arktype-test'
141165

142166
const builder = arkTest.SeedGenerator({
143167
include: ["boolean", "string", "object"],
144168
// 𐙘 use `include` to only include certain schema types
145-
exclude: ["boolean", "unknown"],
169+
exclude: ["boolean", "any"],
146170
// 𐙘 use `exclude` to exclude certain schema types altogether (overrides `include`)
147171
object: { maxKeys: 5 },
148172
// 𐙘 specific arbitraries are configurable by name
@@ -180,14 +204,20 @@ const invalidData = arkTest.seedToInvalidData(mySeed)
180204
// parsing `invalidData` should always fail
181205
```
182206

183-
#### Track record
184207

185-
`arkTest.SeedGenerator` has found several upstream bugs:
208+
### `arkTest.SeedValidDataGenerator`
186209

187-
1. Array + tuple union unsatisfied by empty array
188-
- [Issue](https://github.com/arktypeio/arktype/issues/1441)
189-
- [Sandbox](https://stackblitz.com/edit/vitest-dev-vitest-nho5vqwa?file=test%2Frepro.test.ts)
210+
Like [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator), except `arkTest.SeedValidDataGenerator` comes pre-configured to exclude schemas that make it impossible to reliably generate valid data.
190211

191-
2. Discriminated union bug
192-
- [Issue](https://github.com/arktypeio/arktype/issues/1440)
193-
- [Sandbox](https://stackblitz.com/edit/vitest-dev-vitest-ddhwwn9j?file=test%2Frepro.test.ts)
212+
> [!NOTE]
213+
>
214+
> `arkTest.SeedValidDataGenerator` does not accept any options. If you need more fine-grained control of the schemas being generated, use [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator).
215+
216+
217+
### `arkTest.SeedInvalidDataGenerator`
218+
219+
Like [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator), except `arkTest.SeedValidDataGenerator` comes pre-configured to exclude schemas that make it impossible to reliably generate invalid data.
220+
221+
> [!NOTE]
222+
>
223+
> `arkTest.SeedInvalidDataGenerator` does not accept any options. If you need more fine-grained control of the schemas being generated, use [`arkTest.SeedGenerator`](https://github.com/traversable/schema/tree/main/packages/arktype-test#arktestseedgenerator).

packages/arktype-test/src/generator-options.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ export interface OptionsBase<
7777
export interface Config<T = never> extends OptionsBase<T>, byTypeName {}
7878

7979
export type Constraints = {
80-
array?: { minLength?: number, maxLength?: number }
81-
bigint?: { min: undefined | bigint, max: undefined | bigint, multipleOf?: bigint | null }
80+
array?: { minLength?: number, maxLength?: number, unbounded?: boolean }
81+
bigint?: { min: undefined | bigint, max: undefined | bigint, multipleOf?: bigint | null, unbounded?: boolean }
8282
boolean?: {}
8383
date?: {}
8484
enum?: {}
@@ -87,11 +87,11 @@ export type Constraints = {
8787
literal?: {}
8888
never?: {}
8989
null?: {}
90-
number?: { min?: undefined | number, max?: undefined | number, multipleOf?: number } & fc.DoubleConstraints
90+
number?: { min?: undefined | number, max?: undefined | number, multipleOf?: number, unbounded?: boolean } & fc.DoubleConstraints
9191
object?: ObjectConstraints
9292
optional?: {}
9393
record?: fc.DictionaryConstraints
94-
string?: fc.StringConstraints
94+
string?: fc.StringConstraints & { unbounded?: boolean }
9595
symbol?: {}
9696
tuple?: fc.ArrayConstraints
9797
undefined?: {}
@@ -103,7 +103,7 @@ export type Constraints = {
103103

104104
export interface byTypeName extends Required<Omit<Constraints, 'array' | 'object'>> {
105105
object: fc.UniqueArrayConstraintsRecommended<[k: string, v: unknown], string>
106-
array: fc.IntegerConstraints
106+
array: fc.IntegerConstraints & { unbounded?: boolean }
107107
}
108108

109109
export type ObjectConstraints =
@@ -127,12 +127,14 @@ export const defaultConstraints = {
127127
object: objectDefaults,
128128
array: {
129129
minLength: 0,
130-
maxLength: 0x10
130+
maxLength: 0x10,
131+
unbounded: false,
131132
},
132133
bigint: {
133134
min: undefined,
134135
max: undefined,
135136
multipleOf: null,
137+
unbounded: false,
136138
},
137139
boolean: {},
138140
date: {},
@@ -155,6 +157,7 @@ export const defaultConstraints = {
155157
minExcluded: false,
156158
maxExcluded: false,
157159
noInteger: false,
160+
unbounded: false,
158161
},
159162
optional: {},
160163
record: {
@@ -169,7 +172,8 @@ export const defaultConstraints = {
169172
maxLength: 0x100,
170173
size: 'xsmall',
171174
unit: 'grapheme-ascii',
172-
} satisfies fc.StringConstraints,
175+
unbounded: false,
176+
},
173177
symbol: {},
174178
tuple: {
175179
minLength: 1,
@@ -224,6 +228,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
224228
array: {
225229
maxLength: arrayMax = defaultConstraints.array.maxLength,
226230
minLength: arrayMin = defaultConstraints.array.minLength,
231+
unbounded: arrayUnbounded = defaultConstraints.array.unbounded,
227232
...ARRAY
228233
} = defaultConstraints.array,
229234
bigint: {
@@ -248,6 +253,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
248253
maxExcluded: numberMaxExcluded,
249254
min: numberMin,
250255
minExcluded: numberMinExcluded,
256+
unbounded: numberUnbounded,
251257
// ...NUMBER
252258
} = defaultConstraints.number,
253259
optional = defaultConstraints.optional,
@@ -261,6 +267,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
261267
minLength: stringMinLength,
262268
maxLength: stringMaxLength,
263269
size: stringSize = defaultConstraints.string.size,
270+
unbounded: stringUnbounded,
264271
// ...STRING
265272
} = defaultConstraints.string,
266273
symbol = defaultConstraints.symbol,
@@ -315,6 +322,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
315322
...ARRAY,
316323
min: arrayMin,
317324
max: arrayMax,
325+
unbounded: arrayUnbounded,
318326
},
319327
bigint: {
320328
...BIGINT,
@@ -338,6 +346,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
338346
min: numberMin,
339347
maxExcluded: numberMaxExcluded,
340348
minExcluded: numberMinExcluded,
349+
unbounded: numberUnbounded,
341350
},
342351
optional,
343352
record: {
@@ -351,6 +360,7 @@ export function parseOptions(options: Options<any> = defaults as never): Config
351360
minLength: stringMinLength,
352361
maxLength: stringMaxLength,
353362
size: stringSize,
363+
unbounded: stringUnbounded,
354364
},
355365
symbol,
356366
tuple: {

packages/arktype-test/src/generator-seed.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export declare namespace Seed {
148148
type AllOf<T = unknown> = [intersection: byTag['allOf'], def: [A: T, B: T]]
149149
}
150150

151-
export const Functor: T.Functor.Ix<boolean, Seed.Free, Seed.F<unknown>> = {
151+
export const Functor: T.Functor.Ix<boolean, Seed.Free, Seed.F<any>> = {
152152
map(f) {
153153
return (x) => {
154154
switch (true) {
@@ -205,6 +205,4 @@ export const Functor: T.Functor.Ix<boolean, Seed.Free, Seed.F<unknown>> = {
205205
}
206206
}
207207

208-
export const fold
209-
: <T>(g: (src: Seed.F<T>, ix: boolean, x: Seed.Fixpoint) => T) => (src: Seed.F<T>, isProperty?: boolean) => T
210-
= (g) => (src, isProperty = false) => fn.catamorphism(Functor, false)(g)(src, isProperty)
208+
export const fold = fn.catamorphism(Functor, false)

0 commit comments

Comments
 (0)