@agentuity/schema 0.0.69
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/AGENTS.md +86 -0
- package/README.md +323 -0
- package/dist/base.d.ts +111 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +93 -0
- package/dist/base.js.map +1 -0
- package/dist/coerce/boolean.d.ts +37 -0
- package/dist/coerce/boolean.d.ts.map +1 -0
- package/dist/coerce/boolean.js +49 -0
- package/dist/coerce/boolean.js.map +1 -0
- package/dist/coerce/date.d.ts +36 -0
- package/dist/coerce/date.d.ts.map +1 -0
- package/dist/coerce/date.js +60 -0
- package/dist/coerce/date.js.map +1 -0
- package/dist/coerce/number.d.ts +36 -0
- package/dist/coerce/number.d.ts.map +1 -0
- package/dist/coerce/number.js +59 -0
- package/dist/coerce/number.js.map +1 -0
- package/dist/coerce/string.d.ts +35 -0
- package/dist/coerce/string.d.ts.map +1 -0
- package/dist/coerce/string.js +47 -0
- package/dist/coerce/string.js.map +1 -0
- package/dist/complex/array.d.ts +56 -0
- package/dist/complex/array.d.ts.map +1 -0
- package/dist/complex/array.js +96 -0
- package/dist/complex/array.js.map +1 -0
- package/dist/complex/object.d.ts +76 -0
- package/dist/complex/object.d.ts.map +1 -0
- package/dist/complex/object.js +104 -0
- package/dist/complex/object.js.map +1 -0
- package/dist/complex/record.d.ts +53 -0
- package/dist/complex/record.d.ts.map +1 -0
- package/dist/complex/record.js +109 -0
- package/dist/complex/record.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/json-schema.d.ts +60 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +280 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/primitives/any.d.ts +44 -0
- package/dist/primitives/any.d.ts.map +1 -0
- package/dist/primitives/any.js +57 -0
- package/dist/primitives/any.js.map +1 -0
- package/dist/primitives/boolean.d.ts +39 -0
- package/dist/primitives/boolean.d.ts.map +1 -0
- package/dist/primitives/boolean.js +53 -0
- package/dist/primitives/boolean.js.map +1 -0
- package/dist/primitives/null.d.ts +26 -0
- package/dist/primitives/null.d.ts.map +1 -0
- package/dist/primitives/null.js +40 -0
- package/dist/primitives/null.js.map +1 -0
- package/dist/primitives/number.d.ts +87 -0
- package/dist/primitives/number.d.ts.map +1 -0
- package/dist/primitives/number.js +129 -0
- package/dist/primitives/number.js.map +1 -0
- package/dist/primitives/string.d.ts +64 -0
- package/dist/primitives/string.d.ts.map +1 -0
- package/dist/primitives/string.js +102 -0
- package/dist/primitives/string.js.map +1 -0
- package/dist/primitives/undefined.d.ts +26 -0
- package/dist/primitives/undefined.d.ts.map +1 -0
- package/dist/primitives/undefined.js +40 -0
- package/dist/primitives/undefined.js.map +1 -0
- package/dist/primitives/unknown.d.ts +47 -0
- package/dist/primitives/unknown.d.ts.map +1 -0
- package/dist/primitives/unknown.js +56 -0
- package/dist/primitives/unknown.js.map +1 -0
- package/dist/utils/literal.d.ts +47 -0
- package/dist/utils/literal.d.ts.map +1 -0
- package/dist/utils/literal.js +64 -0
- package/dist/utils/literal.js.map +1 -0
- package/dist/utils/nullable.d.ts +50 -0
- package/dist/utils/nullable.d.ts.map +1 -0
- package/dist/utils/nullable.js +69 -0
- package/dist/utils/nullable.js.map +1 -0
- package/dist/utils/optional.d.ts +50 -0
- package/dist/utils/optional.d.ts.map +1 -0
- package/dist/utils/optional.js +69 -0
- package/dist/utils/optional.js.map +1 -0
- package/dist/utils/union.d.ts +60 -0
- package/dist/utils/union.d.ts.map +1 -0
- package/dist/utils/union.js +87 -0
- package/dist/utils/union.js.map +1 -0
- package/package.json +39 -0
- package/src/__tests__/coerce.test.ts +88 -0
- package/src/__tests__/complex.test.ts +124 -0
- package/src/__tests__/errors.test.ts +129 -0
- package/src/__tests__/json-schema.test.ts +138 -0
- package/src/__tests__/primitives.test.ts +184 -0
- package/src/__tests__/type-inference.test.ts +68 -0
- package/src/__tests__/utils.test.ts +100 -0
- package/src/base.ts +185 -0
- package/src/coerce/boolean.ts +56 -0
- package/src/coerce/date.ts +68 -0
- package/src/coerce/number.ts +67 -0
- package/src/coerce/string.ts +54 -0
- package/src/complex/array.ts +108 -0
- package/src/complex/object.ts +141 -0
- package/src/complex/record.ts +129 -0
- package/src/index.ts +177 -0
- package/src/json-schema.ts +331 -0
- package/src/primitives/any.ts +64 -0
- package/src/primitives/boolean.ts +60 -0
- package/src/primitives/null.ts +47 -0
- package/src/primitives/number.ts +141 -0
- package/src/primitives/string.ts +113 -0
- package/src/primitives/undefined.ts +47 -0
- package/src/primitives/unknown.ts +63 -0
- package/src/utils/literal.ts +71 -0
- package/src/utils/nullable.ts +80 -0
- package/src/utils/optional.ts +80 -0
- package/src/utils/union.ts +103 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nullable.d.ts","sourceRoot":"","sources":["../../src/utils/nullable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAG7C;;;;;;;;;;;;;GAaG;AAEH,qBAAa,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CACrD,YAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAEnD,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,WAAW;;;0BAGD,OAAO;eAMM;YAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;SAAE;MACjF;IAGF,OAAO,CAAC,YAAY,CAAyC;gBAEjD,MAAM,EAAE,CAAC;IAIrB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKnC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAO5E,QAAQ;IAIR,KAAK,0EAA2B;IAChC,SAAS,wGAA+B;CACxC;AAED;;;;;;;;;;;;GAYG;AAEH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAEjF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { success, createParseMethods } from '../base';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for nullable values (T | null).
|
|
4
|
+
* Accepts null or the wrapped schema's type.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The wrapped schema type
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const schema = s.nullable(s.string());
|
|
11
|
+
* schema.parse('hello'); // 'hello'
|
|
12
|
+
* schema.parse(null); // null
|
|
13
|
+
* schema.parse(123); // throws ValidationError
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
export class NullableSchema {
|
|
18
|
+
schema;
|
|
19
|
+
description;
|
|
20
|
+
'~standard' = {
|
|
21
|
+
version: 1,
|
|
22
|
+
vendor: 'agentuity',
|
|
23
|
+
validate: (value) => {
|
|
24
|
+
if (value === null) {
|
|
25
|
+
return success(null);
|
|
26
|
+
}
|
|
27
|
+
return this.schema['~standard'].validate(value);
|
|
28
|
+
},
|
|
29
|
+
types: undefined,
|
|
30
|
+
};
|
|
31
|
+
// Type-safe parse methods for this instance
|
|
32
|
+
parseMethods = createParseMethods();
|
|
33
|
+
constructor(schema) {
|
|
34
|
+
this.schema = schema;
|
|
35
|
+
}
|
|
36
|
+
describe(description) {
|
|
37
|
+
this.description = description;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
optional() {
|
|
41
|
+
// Import here to avoid circular dependency
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
|
+
const { optional } = require('./optional.js');
|
|
44
|
+
return optional(this);
|
|
45
|
+
}
|
|
46
|
+
nullable() {
|
|
47
|
+
return this; // Already nullable
|
|
48
|
+
}
|
|
49
|
+
parse = this.parseMethods.parse;
|
|
50
|
+
safeParse = this.parseMethods.safeParse;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Make a schema nullable (T | null).
|
|
54
|
+
*
|
|
55
|
+
* @param schema - The schema to make nullable
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const userSchema = s.object({
|
|
60
|
+
* name: s.string(),
|
|
61
|
+
* bio: s.nullable(s.string())
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
export function nullable(schema) {
|
|
67
|
+
return new NullableSchema(schema);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=nullable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nullable.js","sourceRoot":"","sources":["../../src/utils/nullable.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,8DAA8D;AAC9D,MAAM,OAAO,cAAc;IAGjB,MAAM,CAAI;IACnB,WAAW,CAAU;IAEZ,WAAW,GAAG;QACtB,OAAO,EAAE,CAAU;QACnB,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE;YAC5B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,OAAO,CAAC,IAAuB,CAAC,CAAC;YACzC,CAAC;YACD,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC;QACD,KAAK,EAAE,SAA2E;KAClF,CAAC;IAEF,4CAA4C;IACpC,YAAY,GAAG,kBAAkB,EAAmB,CAAC;IAE7D,YAAY,MAAS;QACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,QAAQ,CAAC,WAAmB;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,QAAQ;QACP,2CAA2C;QAC3C,iEAAiE;QACjE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QAC9C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,QAAQ;QACP,OAAO,IAAI,CAAC,CAAC,mBAAmB;IACjC,CAAC;IAED,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IAChC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;GAYG;AACH,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CAA6B,MAAS;IAC7D,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Schema, Infer } from '../base';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for optional values (T | undefined).
|
|
4
|
+
* Accepts undefined or the wrapped schema's type.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The wrapped schema type
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const schema = s.optional(s.string());
|
|
11
|
+
* schema.parse('hello'); // 'hello'
|
|
12
|
+
* schema.parse(undefined); // undefined
|
|
13
|
+
* schema.parse(123); // throws ValidationError
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare class OptionalSchema<T extends Schema<any, any>> implements Schema<Infer<T> | undefined, Infer<T> | undefined> {
|
|
17
|
+
readonly schema: T;
|
|
18
|
+
description?: string;
|
|
19
|
+
readonly '~standard': {
|
|
20
|
+
version: 1;
|
|
21
|
+
vendor: string;
|
|
22
|
+
validate: (value: unknown) => import("@agentuity/core").StandardSchemaV1.Result<any> | Promise<import("@agentuity/core").StandardSchemaV1.Result<any>>;
|
|
23
|
+
types: {
|
|
24
|
+
input: Infer<T> | undefined;
|
|
25
|
+
output: Infer<T> | undefined;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
private parseMethods;
|
|
29
|
+
constructor(schema: T);
|
|
30
|
+
describe(description: string): this;
|
|
31
|
+
optional(): this;
|
|
32
|
+
nullable(): Schema<Infer<T> | undefined | null, Infer<T> | undefined | null>;
|
|
33
|
+
parse: (this: Schema<any, Infer<T> | undefined>, value: unknown) => Infer<T> | undefined;
|
|
34
|
+
safeParse: (this: Schema<any, Infer<T> | undefined>, value: unknown) => import("..").SafeParseResult<Infer<T> | undefined>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Make a schema optional (T | undefined).
|
|
38
|
+
*
|
|
39
|
+
* @param schema - The schema to make optional
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const userSchema = s.object({
|
|
44
|
+
* name: s.string(),
|
|
45
|
+
* nickname: s.optional(s.string())
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function optional<T extends Schema<any, any>>(schema: T): OptionalSchema<T>;
|
|
50
|
+
//# sourceMappingURL=optional.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optional.d.ts","sourceRoot":"","sources":["../../src/utils/optional.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAG7C;;;;;;;;;;;;;GAaG;AAEH,qBAAa,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CACrD,YAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE7D,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,WAAW;;;0BAGD,OAAO;eAMM;YAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;YAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;SAAE;MAC3F;IAGF,OAAO,CAAC,YAAY,CAA8C;gBAEtD,MAAM,EAAE,CAAC;IAIrB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKnC,QAAQ;IAIR,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;IAO5E,KAAK,oFAA2B;IAChC,SAAS,kHAA+B;CACxC;AAED;;;;;;;;;;;;GAYG;AAEH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAEjF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { success, createParseMethods } from '../base';
|
|
2
|
+
/**
|
|
3
|
+
* Schema for optional values (T | undefined).
|
|
4
|
+
* Accepts undefined or the wrapped schema's type.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The wrapped schema type
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const schema = s.optional(s.string());
|
|
11
|
+
* schema.parse('hello'); // 'hello'
|
|
12
|
+
* schema.parse(undefined); // undefined
|
|
13
|
+
* schema.parse(123); // throws ValidationError
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
export class OptionalSchema {
|
|
18
|
+
schema;
|
|
19
|
+
description;
|
|
20
|
+
'~standard' = {
|
|
21
|
+
version: 1,
|
|
22
|
+
vendor: 'agentuity',
|
|
23
|
+
validate: (value) => {
|
|
24
|
+
if (value === undefined) {
|
|
25
|
+
return success(undefined);
|
|
26
|
+
}
|
|
27
|
+
return this.schema['~standard'].validate(value);
|
|
28
|
+
},
|
|
29
|
+
types: undefined,
|
|
30
|
+
};
|
|
31
|
+
// Type-safe parse methods for this instance
|
|
32
|
+
parseMethods = createParseMethods();
|
|
33
|
+
constructor(schema) {
|
|
34
|
+
this.schema = schema;
|
|
35
|
+
}
|
|
36
|
+
describe(description) {
|
|
37
|
+
this.description = description;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
optional() {
|
|
41
|
+
return this; // Already optional
|
|
42
|
+
}
|
|
43
|
+
nullable() {
|
|
44
|
+
// Import here to avoid circular dependency
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
46
|
+
const { nullable } = require('./nullable.js');
|
|
47
|
+
return nullable(this);
|
|
48
|
+
}
|
|
49
|
+
parse = this.parseMethods.parse;
|
|
50
|
+
safeParse = this.parseMethods.safeParse;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Make a schema optional (T | undefined).
|
|
54
|
+
*
|
|
55
|
+
* @param schema - The schema to make optional
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const userSchema = s.object({
|
|
60
|
+
* name: s.string(),
|
|
61
|
+
* nickname: s.optional(s.string())
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
export function optional(schema) {
|
|
67
|
+
return new OptionalSchema(schema);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=optional.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optional.js","sourceRoot":"","sources":["../../src/utils/optional.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,8DAA8D;AAC9D,MAAM,OAAO,cAAc;IAGjB,MAAM,CAAI;IACnB,WAAW,CAAU;IAEZ,WAAW,GAAG;QACtB,OAAO,EAAE,CAAU;QACnB,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE;YAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,OAAO,CAAC,SAAiC,CAAC,CAAC;YACnD,CAAC;YACD,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC;QACD,KAAK,EAAE,SAAqF;KAC5F,CAAC;IAEF,4CAA4C;IACpC,YAAY,GAAG,kBAAkB,EAAwB,CAAC;IAElE,YAAY,MAAS;QACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,QAAQ,CAAC,WAAmB;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,QAAQ;QACP,OAAO,IAAI,CAAC,CAAC,mBAAmB;IACjC,CAAC;IAED,QAAQ;QACP,2CAA2C;QAC3C,iEAAiE;QACjE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;QAC9C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IAChC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;GAYG;AACH,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CAA6B,MAAS;IAC7D,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Schema, Infer } from '../base';
|
|
2
|
+
type InferUnion<T extends Schema<any, any>[]> = Infer<T[number]>;
|
|
3
|
+
/**
|
|
4
|
+
* Schema for union types (one of multiple possible schemas).
|
|
5
|
+
* Validates against each schema until one succeeds.
|
|
6
|
+
*
|
|
7
|
+
* @template T - Array of schema types
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const idSchema = s.union(s.string(), s.number());
|
|
12
|
+
* idSchema.parse('abc123'); // 'abc123'
|
|
13
|
+
* idSchema.parse(123); // 123
|
|
14
|
+
*
|
|
15
|
+
* const roleSchema = s.union(
|
|
16
|
+
* s.literal('admin'),
|
|
17
|
+
* s.literal('user'),
|
|
18
|
+
* s.literal('guest')
|
|
19
|
+
* );
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class UnionSchema<T extends Schema<any, any>[]> implements Schema<InferUnion<T>, InferUnion<T>> {
|
|
23
|
+
private schemas;
|
|
24
|
+
description?: string;
|
|
25
|
+
private parseMethods;
|
|
26
|
+
constructor(schemas: T);
|
|
27
|
+
readonly '~standard': {
|
|
28
|
+
version: 1;
|
|
29
|
+
vendor: string;
|
|
30
|
+
validate: (value: unknown) => any;
|
|
31
|
+
types: {
|
|
32
|
+
input: InferUnion<T>;
|
|
33
|
+
output: InferUnion<T>;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
describe(description: string): this;
|
|
37
|
+
optional(): import("..").OptionalSchema<this>;
|
|
38
|
+
nullable(): import("..").NullableSchema<this>;
|
|
39
|
+
parse: (this: Schema<any, InferUnion<T>>, value: unknown) => InferUnion<T>;
|
|
40
|
+
safeParse: (this: Schema<any, InferUnion<T>>, value: unknown) => import("..").SafeParseResult<InferUnion<T>>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a union schema (one of multiple possible types).
|
|
44
|
+
*
|
|
45
|
+
* @param schemas - Variable number of schemas to union
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const idSchema = s.union(s.string(), s.number());
|
|
50
|
+
*
|
|
51
|
+
* const roleSchema = s.union(
|
|
52
|
+
* s.literal('admin'),
|
|
53
|
+
* s.literal('user'),
|
|
54
|
+
* s.literal('guest')
|
|
55
|
+
* );
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function union<T extends Schema<any, any>[]>(...schemas: T): UnionSchema<T>;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=union.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union.d.ts","sourceRoot":"","sources":["../../src/utils/union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAM7C,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;AAEH,qBAAa,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CACpD,YAAW,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAKnC,OAAO,CAAC,OAAO;IAH3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,YAAY,CAAuC;gBAEvC,OAAO,EAAE,CAAC;IAE9B,QAAQ,CAAC,WAAW;;;0BAGD,OAAO;eAwBM;YAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;SAAE;MAC7E;IAEF,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKnC,QAAQ;IAIR,QAAQ;IAIR,KAAK,sEAA2B;IAChC,SAAS,oGAA+B;CACxC;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAEjF"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createIssue, failure, createParseMethods } from '../base';
|
|
2
|
+
import { optional } from '../utils/optional';
|
|
3
|
+
import { nullable } from '../utils/nullable';
|
|
4
|
+
/**
|
|
5
|
+
* Schema for union types (one of multiple possible schemas).
|
|
6
|
+
* Validates against each schema until one succeeds.
|
|
7
|
+
*
|
|
8
|
+
* @template T - Array of schema types
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const idSchema = s.union(s.string(), s.number());
|
|
13
|
+
* idSchema.parse('abc123'); // 'abc123'
|
|
14
|
+
* idSchema.parse(123); // 123
|
|
15
|
+
*
|
|
16
|
+
* const roleSchema = s.union(
|
|
17
|
+
* s.literal('admin'),
|
|
18
|
+
* s.literal('user'),
|
|
19
|
+
* s.literal('guest')
|
|
20
|
+
* );
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
export class UnionSchema {
|
|
25
|
+
schemas;
|
|
26
|
+
description;
|
|
27
|
+
parseMethods = createParseMethods();
|
|
28
|
+
constructor(schemas) {
|
|
29
|
+
this.schemas = schemas;
|
|
30
|
+
}
|
|
31
|
+
'~standard' = {
|
|
32
|
+
version: 1,
|
|
33
|
+
vendor: 'agentuity',
|
|
34
|
+
validate: (value) => {
|
|
35
|
+
const allIssues = [];
|
|
36
|
+
for (const schema of this.schemas) {
|
|
37
|
+
const result = schema['~standard'].validate(value);
|
|
38
|
+
// Only support synchronous validation for now
|
|
39
|
+
if (result instanceof Promise) {
|
|
40
|
+
throw new Error('Async validation not supported');
|
|
41
|
+
}
|
|
42
|
+
if (!result.issues) {
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
allIssues.push(...result.issues);
|
|
47
|
+
}
|
|
48
|
+
return failure([
|
|
49
|
+
createIssue(`Value did not match any of the union types (${allIssues.length} validation errors)`),
|
|
50
|
+
]);
|
|
51
|
+
},
|
|
52
|
+
types: undefined,
|
|
53
|
+
};
|
|
54
|
+
describe(description) {
|
|
55
|
+
this.description = description;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
optional() {
|
|
59
|
+
return optional(this);
|
|
60
|
+
}
|
|
61
|
+
nullable() {
|
|
62
|
+
return nullable(this);
|
|
63
|
+
}
|
|
64
|
+
parse = this.parseMethods.parse;
|
|
65
|
+
safeParse = this.parseMethods.safeParse;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a union schema (one of multiple possible types).
|
|
69
|
+
*
|
|
70
|
+
* @param schemas - Variable number of schemas to union
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const idSchema = s.union(s.string(), s.number());
|
|
75
|
+
*
|
|
76
|
+
* const roleSchema = s.union(
|
|
77
|
+
* s.literal('admin'),
|
|
78
|
+
* s.literal('user'),
|
|
79
|
+
* s.literal('guest')
|
|
80
|
+
* );
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
export function union(...schemas) {
|
|
85
|
+
return new UnionSchema(schemas);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=union.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union.js","sourceRoot":"","sources":["../../src/utils/union.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C;;;;;;;;;;;;;;;;;;GAkBG;AACH,8DAA8D;AAC9D,MAAM,OAAO,WAAW;IAMH;IAHpB,WAAW,CAAU;IACb,YAAY,GAAG,kBAAkB,EAAiB,CAAC;IAE3D,YAAoB,OAAU;QAAV,YAAO,GAAP,OAAO,CAAG;IAAG,CAAC;IAEzB,WAAW,GAAG;QACtB,OAAO,EAAE,CAAU;QACnB,MAAM,EAAE,WAAW;QACnB,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE;YAC5B,MAAM,SAAS,GAAqC,EAAE,CAAC;YAEvD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACnC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAEnD,8CAA8C;gBAC9C,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;gBACnD,CAAC;gBAED,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;oBACpB,8DAA8D;oBAC9D,OAAO,MAAa,CAAC;gBACtB,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC;YAED,OAAO,OAAO,CAAC;gBACd,WAAW,CACV,+CAA+C,SAAS,CAAC,MAAM,qBAAqB,CACpF;aACD,CAAC,CAAC;QACJ,CAAC;QACD,KAAK,EAAE,SAAuE;KAC9E,CAAC;IAEF,QAAQ,CAAC,WAAmB;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAED,QAAQ;QACP,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,QAAQ;QACP,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IAChC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;;;;GAeG;AACH,8DAA8D;AAC9D,MAAM,UAAU,KAAK,CAA+B,GAAG,OAAU;IAChE,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentuity/schema",
|
|
3
|
+
"version": "0.0.69",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"author": "Agentuity employees and contributors",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"AGENTS.md",
|
|
11
|
+
"README.md",
|
|
12
|
+
"src",
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "rm -rf dist",
|
|
23
|
+
"build": "bunx tsc --build --force",
|
|
24
|
+
"typecheck": "bunx tsc --noEmit",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"prepublishOnly": "bun run clean && bun run build"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@agentuity/core": "0.0.69"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/bun": "latest",
|
|
33
|
+
"bun-types": "latest",
|
|
34
|
+
"typescript": "^5.9.0"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { s, ValidationError } from '../index.js';
|
|
3
|
+
|
|
4
|
+
describe('Coercion Schemas', () => {
|
|
5
|
+
describe('coerce.string', () => {
|
|
6
|
+
const schema = s.coerce.string();
|
|
7
|
+
|
|
8
|
+
test('should coerce numbers to strings', () => {
|
|
9
|
+
expect(schema.parse(123)).toBe('123');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('should coerce booleans to strings', () => {
|
|
13
|
+
expect(schema.parse(true)).toBe('true');
|
|
14
|
+
expect(schema.parse(false)).toBe('false');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should keep strings as-is', () => {
|
|
18
|
+
expect(schema.parse('hello')).toBe('hello');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('coerce.number', () => {
|
|
23
|
+
const schema = s.coerce.number();
|
|
24
|
+
|
|
25
|
+
test('should coerce string numbers', () => {
|
|
26
|
+
expect(schema.parse('123')).toBe(123);
|
|
27
|
+
expect(schema.parse('45.67')).toBe(45.67);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('should coerce booleans', () => {
|
|
31
|
+
expect(schema.parse(true)).toBe(1);
|
|
32
|
+
expect(schema.parse(false)).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('should keep numbers as-is', () => {
|
|
36
|
+
expect(schema.parse(42)).toBe(42);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should reject invalid coercions', () => {
|
|
40
|
+
expect(() => schema.parse('not-a-number')).toThrow(ValidationError);
|
|
41
|
+
expect(() => schema.parse(NaN)).toThrow(ValidationError);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('coerce.boolean', () => {
|
|
46
|
+
const schema = s.coerce.boolean();
|
|
47
|
+
|
|
48
|
+
test('should coerce truthy values', () => {
|
|
49
|
+
expect(schema.parse(1)).toBe(true);
|
|
50
|
+
expect(schema.parse('hello')).toBe(true);
|
|
51
|
+
expect(schema.parse([])).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('should coerce falsy values', () => {
|
|
55
|
+
expect(schema.parse(0)).toBe(false);
|
|
56
|
+
expect(schema.parse('')).toBe(false);
|
|
57
|
+
expect(schema.parse(null)).toBe(false);
|
|
58
|
+
expect(schema.parse(undefined)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('coerce.date', () => {
|
|
63
|
+
const schema = s.coerce.date();
|
|
64
|
+
|
|
65
|
+
test('should coerce ISO strings', () => {
|
|
66
|
+
const result = schema.parse('2025-01-01');
|
|
67
|
+
expect(result).toBeInstanceOf(Date);
|
|
68
|
+
expect(result.getFullYear()).toBe(2025);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should coerce timestamps', () => {
|
|
72
|
+
const timestamp = Date.now();
|
|
73
|
+
const result = schema.parse(timestamp);
|
|
74
|
+
expect(result).toBeInstanceOf(Date);
|
|
75
|
+
expect(result.getTime()).toBe(timestamp);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should keep dates as-is', () => {
|
|
79
|
+
const date = new Date('2025-01-01');
|
|
80
|
+
const result = schema.parse(date);
|
|
81
|
+
expect(result).toBe(date);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('should reject invalid dates', () => {
|
|
85
|
+
expect(() => schema.parse('invalid-date')).toThrow(ValidationError);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { s, ValidationError } from '../index.js';
|
|
3
|
+
|
|
4
|
+
describe('Complex Schemas', () => {
|
|
5
|
+
describe('object', () => {
|
|
6
|
+
const schema = s.object({
|
|
7
|
+
name: s.string(),
|
|
8
|
+
age: s.number(),
|
|
9
|
+
active: s.boolean(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('should validate objects', () => {
|
|
13
|
+
const result = schema.parse({
|
|
14
|
+
name: 'John',
|
|
15
|
+
age: 30,
|
|
16
|
+
active: true,
|
|
17
|
+
});
|
|
18
|
+
expect(result.name).toBe('John');
|
|
19
|
+
expect(result.age).toBe(30);
|
|
20
|
+
expect(result.active).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('should reject invalid objects', () => {
|
|
24
|
+
expect(() =>
|
|
25
|
+
schema.parse({
|
|
26
|
+
name: 'John',
|
|
27
|
+
age: 'thirty',
|
|
28
|
+
active: true,
|
|
29
|
+
})
|
|
30
|
+
).toThrow(ValidationError);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should report field path in errors', () => {
|
|
34
|
+
try {
|
|
35
|
+
schema.parse({
|
|
36
|
+
name: 'John',
|
|
37
|
+
age: 'invalid',
|
|
38
|
+
active: true,
|
|
39
|
+
});
|
|
40
|
+
throw new Error('Expected parse to throw');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
expect(error).toBeInstanceOf(ValidationError);
|
|
43
|
+
if (error instanceof ValidationError) {
|
|
44
|
+
expect(error.issues[0].path).toEqual(['age']);
|
|
45
|
+
} else {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('should work with nested objects', () => {
|
|
52
|
+
const nested = s.object({
|
|
53
|
+
user: s.object({
|
|
54
|
+
name: s.string(),
|
|
55
|
+
email: s.string(),
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const result = nested.parse({
|
|
60
|
+
user: {
|
|
61
|
+
name: 'Alice',
|
|
62
|
+
email: 'alice@example.com',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
expect(result.user.name).toBe('Alice');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('array', () => {
|
|
70
|
+
const schema = s.array(s.string());
|
|
71
|
+
|
|
72
|
+
test('should validate arrays', () => {
|
|
73
|
+
const result = schema.parse(['a', 'b', 'c']);
|
|
74
|
+
expect(result).toEqual(['a', 'b', 'c']);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('should reject non-arrays', () => {
|
|
78
|
+
expect(() => schema.parse('not-an-array')).toThrow(ValidationError);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should validate array items', () => {
|
|
82
|
+
expect(() => schema.parse(['a', 123, 'c'])).toThrow(ValidationError);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('should report array index in errors', () => {
|
|
86
|
+
try {
|
|
87
|
+
schema.parse(['a', 123, 'c']);
|
|
88
|
+
throw new Error('Expected parse to throw');
|
|
89
|
+
} catch (error) {
|
|
90
|
+
expect(error).toBeInstanceOf(ValidationError);
|
|
91
|
+
if (error instanceof ValidationError) {
|
|
92
|
+
expect(error.issues[0].path).toContain(1);
|
|
93
|
+
} else {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('should work with array of objects', () => {
|
|
100
|
+
const objArray = s.array(
|
|
101
|
+
s.object({
|
|
102
|
+
id: s.number(),
|
|
103
|
+
name: s.string(),
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const result = objArray.parse([
|
|
108
|
+
{ id: 1, name: 'First' },
|
|
109
|
+
{ id: 2, name: 'Second' },
|
|
110
|
+
]);
|
|
111
|
+
expect(result.length).toBe(2);
|
|
112
|
+
expect(result[0].id).toBe(1);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('record', () => {
|
|
117
|
+
const schema = s.record(s.string(), s.number());
|
|
118
|
+
test('should validate records', () => {
|
|
119
|
+
expect(schema.parse({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
|
120
|
+
});
|
|
121
|
+
test('should reject non-objects', () => {
|
|
122
|
+
expect(() => schema.parse([])).toThrow(ValidationError);
|
|
123
|
+
});
|
|
124
|
+
});
|