toolcraft-schema 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +19 -5
- package/dist/index.js +41 -0
- package/dist/json.compile-check.d.ts +1 -0
- package/dist/json.compile-check.js +2 -0
- package/dist/json.d.ts +10 -0
- package/dist/json.js +5 -0
- package/dist/oneof.compile-check.d.ts +1 -0
- package/dist/oneof.compile-check.js +12 -0
- package/dist/oneof.d.ts +15 -0
- package/dist/oneof.js +13 -0
- package/dist/record.compile-check.d.ts +1 -0
- package/dist/record.compile-check.js +2 -0
- package/dist/record.d.ts +5 -0
- package/dist/record.js +6 -0
- package/dist/union.compile-check.d.ts +1 -0
- package/dist/union.compile-check.js +9 -0
- package/dist/union.d.ts +7 -0
- package/dist/union.js +29 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -14,8 +14,8 @@ Zero-dependency schema builder for typed command inputs and JSON Schema generati
|
|
|
14
14
|
## Usage
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
|
-
import { S, toJsonSchema } from "
|
|
18
|
-
import type { Static } from "
|
|
17
|
+
import { S, toJsonSchema } from "toolcraft-schema";
|
|
18
|
+
import type { Static } from "toolcraft-schema";
|
|
19
19
|
|
|
20
20
|
const schema = S.Object({
|
|
21
21
|
name: S.String({ description: "User name" }),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import { Json } from "./json.js";
|
|
2
|
+
import { OneOf } from "./oneof.js";
|
|
3
|
+
import { Record as RecordBuilder } from "./record.js";
|
|
4
|
+
import { Union } from "./union.js";
|
|
5
|
+
import type { JsonValue, JsonValueSchema } from "./json.js";
|
|
6
|
+
import type { OneOfSchema } from "./oneof.js";
|
|
7
|
+
import type { RecordSchema } from "./record.js";
|
|
8
|
+
import type { UnionSchema } from "./union.js";
|
|
1
9
|
type JsonSchemaType = "string" | "number" | "integer" | "boolean" | "array" | "object";
|
|
2
|
-
type SchemaKind = "string" | "number" | "boolean" | "enum" | "array" | "object" | "optional";
|
|
10
|
+
type SchemaKind = "string" | "number" | "boolean" | "enum" | "array" | "object" | "optional" | "oneOf" | "union" | "record" | "json";
|
|
3
11
|
type EnumValue = string | number | boolean;
|
|
4
12
|
type JsonSchemaEnumValue = EnumValue | null;
|
|
5
13
|
type NumberJsonType = "number" | "integer";
|
|
@@ -41,7 +49,7 @@ type SchemaOptions<TDefault> = {
|
|
|
41
49
|
short?: string;
|
|
42
50
|
scope?: readonly SchemaScope[];
|
|
43
51
|
};
|
|
44
|
-
interface SchemaBase<TKind extends SchemaKind, TStatic> {
|
|
52
|
+
export interface SchemaBase<TKind extends SchemaKind, TStatic> {
|
|
45
53
|
readonly kind: TKind;
|
|
46
54
|
readonly description?: string;
|
|
47
55
|
readonly default?: TStatic;
|
|
@@ -52,7 +60,7 @@ interface SchemaBase<TKind extends SchemaKind, TStatic> {
|
|
|
52
60
|
readonly __static?: TStatic;
|
|
53
61
|
}
|
|
54
62
|
export interface JsonSchema {
|
|
55
|
-
additionalProperties?: boolean;
|
|
63
|
+
additionalProperties?: boolean | JsonSchema;
|
|
56
64
|
type?: JsonSchemaType;
|
|
57
65
|
description?: string;
|
|
58
66
|
default?: unknown;
|
|
@@ -66,6 +74,7 @@ export interface JsonSchema {
|
|
|
66
74
|
minimum?: number;
|
|
67
75
|
minLength?: number;
|
|
68
76
|
nullable?: boolean;
|
|
77
|
+
oneOf?: JsonSchema[];
|
|
69
78
|
pattern?: string;
|
|
70
79
|
properties?: Record<string, JsonSchema>;
|
|
71
80
|
required?: string[];
|
|
@@ -97,7 +106,7 @@ export interface ObjectSchema<TShape extends ObjectShape> extends SchemaBase<"ob
|
|
|
97
106
|
export interface OptionalSchema<TInner extends AnySchema> extends SchemaBase<"optional", Static<TInner> | undefined> {
|
|
98
107
|
readonly inner: TInner;
|
|
99
108
|
}
|
|
100
|
-
export type AnySchema = StringSchema | NumberSchema | BooleanSchema | EnumSchema<NonEmptyReadonlyArray<EnumValue>> | ArraySchema<AnySchema> | ObjectSchema<ObjectShape> | OptionalSchema<AnySchema
|
|
109
|
+
export type AnySchema = StringSchema | NumberSchema | BooleanSchema | EnumSchema<NonEmptyReadonlyArray<EnumValue>> | ArraySchema<AnySchema> | ObjectSchema<ObjectShape> | OptionalSchema<AnySchema> | OneOfSchema<Record<string, ObjectSchema<any>>, string> | UnionSchema<readonly ObjectSchema<any>[]> | RecordSchema<AnySchema> | JsonValueSchema;
|
|
101
110
|
export type Static<TSchema extends AnySchema> = TSchema extends SchemaBase<any, infer TStatic> ? TStatic : never;
|
|
102
111
|
export declare const S: {
|
|
103
112
|
readonly String: (options?: SchemaOptions<string> & StringMetadata) => StringSchema;
|
|
@@ -119,6 +128,11 @@ export declare const S: {
|
|
|
119
128
|
readonly Array: <TItem extends AnySchema>(item: TItem, options?: SchemaOptions<Array<Static<TItem>>> & ArrayMetadata) => ArraySchema<TItem>;
|
|
120
129
|
readonly Object: <const TShape extends ObjectShape>(shape: TShape, options?: SchemaOptions<InferObject<TShape>> & ObjectMetadata) => ObjectSchema<TShape>;
|
|
121
130
|
readonly Optional: <TInner extends AnySchema>(inner: TInner) => OptionalSchema<TInner>;
|
|
131
|
+
readonly OneOf: typeof OneOf;
|
|
132
|
+
readonly Union: typeof Union;
|
|
133
|
+
readonly Record: typeof RecordBuilder;
|
|
134
|
+
readonly Json: typeof Json;
|
|
122
135
|
};
|
|
123
136
|
export declare function toJsonSchema(schema: AnySchema): JsonSchema;
|
|
124
|
-
export {};
|
|
137
|
+
export { Json, OneOf, RecordBuilder as Record, Union };
|
|
138
|
+
export type { JsonValue, JsonValueSchema, OneOfSchema, RecordSchema, UnionSchema };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { Json } from "./json.js";
|
|
2
|
+
import { OneOf } from "./oneof.js";
|
|
3
|
+
import { Record as RecordBuilder } from "./record.js";
|
|
4
|
+
import { Union } from "./union.js";
|
|
1
5
|
function withMetadata(schema, jsonSchema) {
|
|
2
6
|
if (schema.description !== undefined) {
|
|
3
7
|
jsonSchema.description = schema.description;
|
|
@@ -82,6 +86,23 @@ function unwrapOptional(schema) {
|
|
|
82
86
|
}
|
|
83
87
|
return schema;
|
|
84
88
|
}
|
|
89
|
+
function withInjectedDiscriminator(schema, discriminator, branchName) {
|
|
90
|
+
const branchJsonSchema = toJsonSchema(schema);
|
|
91
|
+
const properties = {
|
|
92
|
+
...(branchJsonSchema.properties ?? {}),
|
|
93
|
+
[discriminator]: {
|
|
94
|
+
type: "string",
|
|
95
|
+
enum: [branchName],
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const required = [...new Set([...(branchJsonSchema.required ?? []), discriminator])];
|
|
99
|
+
return {
|
|
100
|
+
...branchJsonSchema,
|
|
101
|
+
type: "object",
|
|
102
|
+
properties,
|
|
103
|
+
required,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
85
106
|
export const S = {
|
|
86
107
|
String(options = {}) {
|
|
87
108
|
return {
|
|
@@ -129,6 +150,10 @@ export const S = {
|
|
|
129
150
|
inner,
|
|
130
151
|
};
|
|
131
152
|
},
|
|
153
|
+
OneOf,
|
|
154
|
+
Union,
|
|
155
|
+
Record: RecordBuilder,
|
|
156
|
+
Json,
|
|
132
157
|
};
|
|
133
158
|
export function toJsonSchema(schema) {
|
|
134
159
|
const unwrappedSchema = unwrapOptional(schema);
|
|
@@ -171,5 +196,21 @@ export function toJsonSchema(schema) {
|
|
|
171
196
|
required,
|
|
172
197
|
});
|
|
173
198
|
}
|
|
199
|
+
case "oneOf":
|
|
200
|
+
return withMetadata(unwrappedSchema, {
|
|
201
|
+
oneOf: Object.entries(unwrappedSchema.branches).map(([branchName, branchSchema]) => withInjectedDiscriminator(branchSchema, unwrappedSchema.discriminator, branchName)),
|
|
202
|
+
});
|
|
203
|
+
case "union":
|
|
204
|
+
return withMetadata(unwrappedSchema, {
|
|
205
|
+
oneOf: unwrappedSchema.branches.map((branchSchema) => toJsonSchema(branchSchema)),
|
|
206
|
+
});
|
|
207
|
+
case "record":
|
|
208
|
+
return withMetadata(unwrappedSchema, {
|
|
209
|
+
type: "object",
|
|
210
|
+
additionalProperties: toJsonSchema(unwrappedSchema.value),
|
|
211
|
+
});
|
|
212
|
+
case "json":
|
|
213
|
+
return withMetadata(unwrappedSchema, {});
|
|
174
214
|
}
|
|
175
215
|
}
|
|
216
|
+
export { Json, OneOf, RecordBuilder as Record, Union };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/json.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SchemaBase } from "./index.js";
|
|
2
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
3
|
+
export type JsonValue = JsonPrimitive | {
|
|
4
|
+
[key: string]: JsonValue;
|
|
5
|
+
} | JsonValue[];
|
|
6
|
+
export interface JsonValueSchema extends SchemaBase<"json", JsonValue> {
|
|
7
|
+
readonly kind: "json";
|
|
8
|
+
}
|
|
9
|
+
export declare function Json(): JsonValueSchema;
|
|
10
|
+
export {};
|
package/dist/json.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/oneof.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ObjectSchema, SchemaBase, Static } from "./index.js";
|
|
2
|
+
type OneOfStatic<TBranches extends Record<string, ObjectSchema<any>>, TDiscriminator extends string> = {
|
|
3
|
+
[TBranchName in keyof TBranches & string]: Omit<Static<TBranches[TBranchName]>, TDiscriminator> & {
|
|
4
|
+
[TFieldName in TDiscriminator]: TBranchName;
|
|
5
|
+
};
|
|
6
|
+
}[keyof TBranches & string];
|
|
7
|
+
export interface OneOfSchema<TBranches extends Record<string, ObjectSchema<any>>, TDiscriminator extends string = string> extends SchemaBase<"oneOf", OneOfStatic<TBranches, TDiscriminator>> {
|
|
8
|
+
readonly discriminator: TDiscriminator;
|
|
9
|
+
readonly branches: TBranches;
|
|
10
|
+
}
|
|
11
|
+
export declare function OneOf<TDiscriminator extends string, TBranches extends Record<string, ObjectSchema<any>>>(config: {
|
|
12
|
+
discriminator: TDiscriminator;
|
|
13
|
+
branches: TBranches;
|
|
14
|
+
}): OneOfSchema<TBranches, TDiscriminator>;
|
|
15
|
+
export {};
|
package/dist/oneof.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function assertValidBranches(branches) {
|
|
2
|
+
if (Object.keys(branches).length === 0) {
|
|
3
|
+
throw new Error("OneOf schema requires at least one branch");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
export function OneOf(config) {
|
|
7
|
+
assertValidBranches(config.branches);
|
|
8
|
+
return {
|
|
9
|
+
kind: "oneOf",
|
|
10
|
+
discriminator: config.discriminator,
|
|
11
|
+
branches: config.branches,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/record.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AnySchema, SchemaBase, Static } from "./index.js";
|
|
2
|
+
export interface RecordSchema<TValue extends AnySchema> extends SchemaBase<"record", Record<string, Static<TValue>>> {
|
|
3
|
+
readonly value: TValue;
|
|
4
|
+
}
|
|
5
|
+
export declare function Record<TValue extends AnySchema>(value: TValue): RecordSchema<TValue>;
|
package/dist/record.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/union.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ObjectSchema, SchemaBase, Static } from "./index.js";
|
|
2
|
+
type UnionStatic<TBranches extends readonly ObjectSchema<any>[]> = Static<TBranches[number]>;
|
|
3
|
+
export interface UnionSchema<TBranches extends readonly ObjectSchema<any>[]> extends SchemaBase<"union", UnionStatic<TBranches>> {
|
|
4
|
+
readonly branches: TBranches;
|
|
5
|
+
}
|
|
6
|
+
export declare function Union<const TBranches extends readonly ObjectSchema<any>[]>(branches: TBranches): UnionSchema<TBranches>;
|
|
7
|
+
export {};
|
package/dist/union.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function isOptionalSchema(schema) {
|
|
2
|
+
return schema.kind === "optional";
|
|
3
|
+
}
|
|
4
|
+
function getRequiredKeyFingerprint(schema) {
|
|
5
|
+
const requiredKeys = Object.keys(schema.shape)
|
|
6
|
+
.filter((key) => !isOptionalSchema(schema.shape[key]))
|
|
7
|
+
.sort();
|
|
8
|
+
return JSON.stringify(requiredKeys);
|
|
9
|
+
}
|
|
10
|
+
function assertValidBranches(branches) {
|
|
11
|
+
if (branches.length === 0) {
|
|
12
|
+
throw new Error("Union schema requires at least one branch");
|
|
13
|
+
}
|
|
14
|
+
const fingerprints = new Set();
|
|
15
|
+
for (const branch of branches) {
|
|
16
|
+
const fingerprint = getRequiredKeyFingerprint(branch);
|
|
17
|
+
if (fingerprints.has(fingerprint)) {
|
|
18
|
+
throw new Error("Union schema branches must have unique required-key fingerprints");
|
|
19
|
+
}
|
|
20
|
+
fingerprints.add(fingerprint);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function Union(branches) {
|
|
24
|
+
assertValidBranches(branches);
|
|
25
|
+
return {
|
|
26
|
+
kind: "union",
|
|
27
|
+
branches,
|
|
28
|
+
};
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft-schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "rm -rf dist && tsc",
|
|
15
|
-
"test": "cd ../.. && vitest run packages/
|
|
16
|
-
"test:unit": "cd ../.. && vitest run packages/
|
|
17
|
-
"lint": "cd ../.. && eslint packages/
|
|
15
|
+
"test": "cd ../.. && vitest run packages/toolcraft-schema/src/index.test.ts",
|
|
16
|
+
"test:unit": "cd ../.. && vitest run packages/toolcraft-schema/src/index.test.ts",
|
|
17
|
+
"lint": "cd ../.. && eslint packages/toolcraft-schema/src --ext ts && tsc -p packages/toolcraft-schema/tsconfig.json --noEmit"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist"
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
27
|
"url": "git+https://github.com/poe-platform/poe-code.git",
|
|
28
|
-
"directory": "packages/
|
|
28
|
+
"directory": "packages/toolcraft-schema"
|
|
29
29
|
}
|
|
30
30
|
}
|