Skip to content

Commit 83e30a9

Browse files
authored
feat(seed): creates new schema.seed package (#28)
* feat(seed): creates new `schema.seed` package * chore: commits changeset
1 parent e0f08fd commit 83e30a9

28 files changed

+377
-5
lines changed

.changeset/strong-days-pay.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@traversable/schema-seed": patch
3+
"@traversable/schema": patch
4+
---
5+
6+
feat(seed): creates new schema.seed for generating arbitrary schemas

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,18 @@ options (like `treatUndefinedAndOptionalAsTheSame`) to support both.
169169
flowchart TD
170170
registry(@traversable/registry)
171171
json(@traversable/json) -.-> registry(@traversable/registry)
172-
schema-zod-adapter(@traversable/schema-zod-adapter) -.-> registry(@traversable/registry)
173172
schema-core(@traversable/schema-core) -.-> json(@traversable/json)
174173
schema-core(@traversable/schema-core) -.-> registry(@traversable/registry)
174+
schema-valibot-adapter(@traversable/schema-valibot-adapter) -.-> json(@traversable/json)
175+
schema-valibot-adapter(@traversable/schema-valibot-adapter) -.-> registry(@traversable/registry)
176+
schema-zod-adapter(@traversable/schema-zod-adapter) -.-> json(@traversable/json)
177+
schema-zod-adapter(@traversable/schema-zod-adapter) -.-> registry(@traversable/registry)
178+
schema-seed(@traversable/schema-seed) -.-> json(@traversable/json)
179+
schema-seed(@traversable/schema-seed) -.-> registry(@traversable/registry)
180+
schema-seed(@traversable/schema-seed) -.-> schema-core(@traversable/schema-core)
175181
schema(@traversable/schema) -.-> json(@traversable/json)
176182
schema(@traversable/schema) -.-> schema-core(@traversable/schema-core)
183+
schema(@traversable/schema) -.-> schema-seed(@traversable/schema-seed)
177184
schema(@traversable/schema) -.-> schema-zod-adapter(@traversable/schema-zod-adapter)
178185
schema(@traversable/schema) -.depends on.-> registry(@traversable/registry)
179186
```

config/__generated__/package-list.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/schema-seed/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# @traversable/schema-seed

packages/schema-seed/package.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "@traversable/schema-seed",
3+
"type": "module",
4+
"version": "0.0.0",
5+
"private": false,
6+
"description": "",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/traversable/schema.git",
10+
"directory": "packages/schema-seed"
11+
},
12+
"bugs": {
13+
"url": "https://github.com/traversable/schema/issues",
14+
"email": "ahrjarrett@gmail.com"
15+
},
16+
"@traversable": {
17+
"generateExports": {
18+
"include": [
19+
"**/*.ts"
20+
]
21+
},
22+
"generateIndex": {
23+
"include": [
24+
"**/*.ts"
25+
]
26+
}
27+
},
28+
"publishConfig": {
29+
"access": "public"
30+
},
31+
"scripts": {
32+
"bench": "echo NOTHING TO BENCH",
33+
"build": "pnpm build:esm && pnpm build:cjs && pnpm build:annotate",
34+
"build:annotate": "babel build --plugins annotate-pure-calls --out-dir build --source-maps",
35+
"build:esm": "tsc -b tsconfig.build.json",
36+
"build:cjs": "babel build/esm --plugins @babel/transform-export-namespace-from --plugins @babel/transform-modules-commonjs --out-dir build/cjs --source-maps",
37+
"check": "tsc -b tsconfig.json",
38+
"clean": "pnpm run \"/^clean:.*/\"",
39+
"clean:build": "rm -rf .tsbuildinfo dist build",
40+
"clean:deps": "rm -rf node_modules",
41+
"test": "vitest"
42+
},
43+
"peerDependencies": {
44+
"@traversable/json": "workspace:^",
45+
"@traversable/registry": "workspace:^",
46+
"@traversable/schema-core": "workspace:^"
47+
},
48+
"devDependencies": {
49+
"@traversable/json": "workspace:^",
50+
"@traversable/registry": "workspace:^",
51+
"@traversable/schema-core": "workspace:^",
52+
"fast-check": "^3.23.2"
53+
}
54+
}

packages/schema-seed/src/__generated__/__manifest__.ts

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { VERSION } from './version.js'
2+
export * as Seed from './seed.js'
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
export * from 'fast-check'
2+
3+
import * as fc from 'fast-check'
4+
import type { Entries, Force } from '@traversable/registry'
5+
import { symbol as Symbol } from '@traversable/registry'
6+
import type { Guard } from '@traversable/schema-core'
7+
8+
export interface Arbitrary<T = unknown> extends fc.Arbitrary<T> {
9+
readonly [Symbol.optional]?: true
10+
}
11+
12+
export type { typeOf as typeof }
13+
type typeOf<S> = S extends fc.Arbitrary<infer T> ? T : never
14+
15+
/** @internal */
16+
const Object_keys = globalThis.Object.keys
17+
/** @internal */
18+
const Array_isArray = globalThis.Array.isArray
19+
/** @internal */
20+
const isString: Guard<string> = (u): u is never => typeof u === 'string'
21+
/** @internal */
22+
const arrayOf
23+
: <T>(p: Guard<T>) => Guard<T[]>
24+
= (p) => (u): u is never => Array_isArray(u) && u.every(p)
25+
/** @internal */
26+
const has
27+
: <K extends keyof any, T>(k: K, p: Guard<T>) => Guard<{ [P in K]: T }>
28+
= (k, p) => (u: unknown): u is never =>
29+
!!u &&
30+
typeof u === 'object' &&
31+
Object.hasOwn(u, k) &&
32+
p(u[k as never])
33+
34+
const PATTERN = {
35+
identifier: /^[$_a-zA-Z][$_a-zA-Z0-9]*$/,
36+
} as const
37+
38+
/** @internal */
39+
type Keyword = keyof typeof KEYWORD
40+
const KEYWORD = {
41+
break: "break", case: "case", catch: "catch", class: "class", const: "const",
42+
continue: "continue", debugger: "debugger", default: "default", delete: "delete",
43+
do: "do", else: "else", export: "export", extends: "extends", false: "false",
44+
finally: "finally", for: "for", function: "function", if: "if", import: "import",
45+
in: "in", instanceof: "instanceof", new: "new", null: "null", return: "return",
46+
super: "super", switch: "switch", this: "this", throw: "throw", true: "true",
47+
try: "try", typeof: "typeof", var: "var", void: "void", while: "while",
48+
with: "with", let: "let", static: "static", yield: "yield",
49+
} as const satisfies Record<string, string>
50+
51+
export type UniqueArrayDefaults<T = unknown, U = unknown> = fc.UniqueArrayConstraintsRecommended<T, U>
52+
53+
export function identifier(constraints?: fc.StringMatchingConstraints): fc.Arbitrary<string>
54+
export function identifier(constraints?: fc.StringMatchingConstraints) {
55+
return fc.stringMatching(PATTERN.identifier, constraints) //.filter((ident) => !(ident in KEYWORD))
56+
}
57+
58+
export const entries
59+
: <T, U>(model: fc.Arbitrary<T>, constraints?: UniqueArrayDefaults<T, U>) => fc.Arbitrary<Entries<T>>
60+
= (model, constraints) => fc.uniqueArray(
61+
fc.tuple(identifier(), model),
62+
{ ...constraints, selector: ([k]) => k },
63+
)
64+
65+
/**
66+
* ### {@link optional `fc.optional`}
67+
*/
68+
export function optional<T>(model: fc.Arbitrary<T>, constraints?: fc.OneOfConstraints): Arbitrary<T>
69+
export function optional<T>(model: fc.Arbitrary<T>, constraints: fc.OneOfConstraints = {}): fc.Arbitrary<T | undefined> {
70+
// const arbitrary = fc.oneof(constraints, model, fc.constant(undefined));
71+
(model as any)[Symbol.optional] = true;
72+
return model
73+
// arbitrary
74+
}
75+
76+
export declare namespace record {
77+
type Keep<T, K extends keyof T> = never | { [P in K]: T[P] }
78+
type Part<T, K extends keyof T = keyof T> = never | { [P in K]+?: T[P] }
79+
type Forget<T> = never | { [K in keyof T]: T[K] }
80+
type Require<T, K extends keyof T = never> = [K] extends [never] ? T : Forget<
81+
& Keep<T, K>
82+
& Part<T, globalThis.Exclude<keyof T, K>>
83+
>
84+
}
85+
86+
export function record<
87+
T extends globalThis.Record<string, fc.Arbitrary<unknown>>,
88+
_K extends keyof T = keyof T,
89+
Opt extends
90+
| _K extends _K ? T[_K] extends { [Symbol.optional]: true } ? _K : never : never
91+
= _K extends _K ? T[_K] extends { [Symbol.optional]: true } ? _K : never : never,
92+
Req extends Exclude<_K, Opt> = Exclude<_K, Opt>
93+
>(model: T): fc.Arbitrary<Force<
94+
& { [K in Opt]+?: typeOf<T[K]> }
95+
& { [K in Req]-?: typeOf<T[K]> }
96+
>>
97+
98+
export function record<T>(model: { [K in keyof T]: fc.Arbitrary<T[K]> }): fc.Arbitrary<T>
99+
100+
export function record<T, K extends never>(
101+
model: { [K in keyof T]: fc.Arbitrary<T[K]> },
102+
constraints: { requiredKeys?: readonly [] }
103+
): fc.Arbitrary<{ [K in keyof T]+?: T[K] }>
104+
105+
export function record<T, K extends keyof T>(
106+
model: { [K in keyof T]: fc.Arbitrary<T[K]> },
107+
constraints: { requiredKeys?: K[] }
108+
): fc.Arbitrary<record.Require<T, K>>
109+
110+
export function record<T, K extends keyof T>(
111+
model: { [K in keyof T]: fc.Arbitrary<T[K]> },
112+
constraints: { withDeletedKeys?: boolean, requiredKeys?: never }
113+
): fc.Arbitrary<record.Require<T, K>>
114+
115+
export function record<T, K extends keyof T>(
116+
model: { [K in keyof T]: fc.Arbitrary<T[K]> },
117+
constraints: { withDeletedKeys: never, requiredKeys: never }
118+
): fc.Arbitrary<record.Require<T, K>>
119+
120+
// export function record<T, K extends keyof T>(
121+
// model: { [K in keyof T]: fc.Arbitrary<T[K]> },
122+
// constraints?: fc.RecordConstraints<T>
123+
// ): fc.Arbitrary<record.Require<T, K>>
124+
125+
export function record(
126+
model: { [x: string]: fc.Arbitrary<unknown> },
127+
constraints: { requiredKeys?: readonly string[] } = {}
128+
) {
129+
const keys = Object_keys(model)
130+
const opt = keys.filter((k) => (Symbol.optional in model[k]))
131+
const requiredKeys = has("requiredKeys", arrayOf(isString))(constraints)
132+
? keys
133+
.filter((k) => constraints.requiredKeys?.includes(k))
134+
.filter((k) => !opt.includes(k))
135+
: keys
136+
.filter((k) => !opt.includes(k))
137+
138+
return fc.record(model, { ...constraints, requiredKeys })
139+
}

packages/schema-seed/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './exports.js'
2+
export * as seed from './exports.js'
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Entries } from '@traversable/registry'
33
import { fn, parseKey, URI } from '@traversable/registry'
44
import { Json } from '@traversable/json'
55

6-
import { t } from './schema.js'
6+
import { t } from '@traversable/schema-core'
77
import * as fc from './fast-check.js'
88

99
export {
@@ -400,7 +400,7 @@ namespace Recursive {
400400
export type SortBias<T>
401401
= Compare<keyof T>
402402
/**
403-
* If you provide a partial weight map, missing properties will fall back to 0
403+
* If you provide a partial weight map, missing properties will fall back to `0`
404404
*/
405405
| { [K in keyof T]+?: number }
406406

0 commit comments

Comments
 (0)