@temelj/standard-schema 0.1.0
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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/mod.d.mts +54 -0
- package/dist/mod.d.mts.map +1 -0
- package/dist/mod.mjs +159 -0
- package/dist/mod.mjs.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tin Rabzelj
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center" style="text-decoration:none;">@temelj/standard-schema</h1>
|
|
3
|
+
<br/>
|
|
4
|
+
<p align="center">
|
|
5
|
+
Standard Schema construction utilities.
|
|
6
|
+
</p>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://twitter.com/tinrab" rel="nofollow"><img src="https://img.shields.io/badge/created%20by-@tinrab-1d9bf0.svg" alt="Created by Tin Rabzelj"></a>
|
|
11
|
+
<a href="https://jsr.io/@temelj/standard-schema" rel="nofollow"><img src="https://jsr.io/badges/@temelj/standard-schema" alt="jsr"></a>
|
|
12
|
+
<a href="https://opensource.org/licenses/MIT" rel="nofollow"><img src="https://img.shields.io/github/license/tinrab/temelj" alt="License"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<div align="center">
|
|
16
|
+
<a href="https://jsr.io/@temelj/standard-schema">jsr</a>
|
|
17
|
+
<span> • </span>
|
|
18
|
+
<a href="https://www.npmjs.com/package/@temelj/standard-schema">npm</a>
|
|
19
|
+
<span> • </span>
|
|
20
|
+
<a href="https://github.com/tinrab/temelj/issues/new">Issues</a>
|
|
21
|
+
<span> • </span>
|
|
22
|
+
<a href="https://twitter.com/tinrab">@tinrab</a>
|
|
23
|
+
<br />
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<br/>
|
|
27
|
+
<br/>
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
# npm
|
|
33
|
+
$ npm install @temelj/standard-schema
|
|
34
|
+
# jsr
|
|
35
|
+
$ deno add jsr:@temelj/standard-schema # or jsr add @temelj/standard-schema
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { ss } from "@temelj/standard-schema";
|
|
42
|
+
|
|
43
|
+
const schema = ss.string();
|
|
44
|
+
const result = schema["~standard"].validate("hello");
|
|
45
|
+
```
|
package/dist/mod.d.mts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
|
|
3
|
+
//#region src/mod.d.ts
|
|
4
|
+
type Schema<TInput = unknown, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;
|
|
5
|
+
type SchemaOutput<TSchema extends Schema> = StandardSchemaV1.InferOutput<TSchema>;
|
|
6
|
+
type SchemaResult<TOutput> = StandardSchemaV1.Result<TOutput>;
|
|
7
|
+
type SchemaIssue = StandardSchemaV1.Issue;
|
|
8
|
+
type SchemaValidator<TOutput> = (value: unknown) => SchemaResult<TOutput>;
|
|
9
|
+
type SchemaShape = Record<string, Schema>;
|
|
10
|
+
type ObjectOutput<TShape extends SchemaShape> = { readonly [TKey in keyof TShape]: SchemaOutput<TShape[TKey]> };
|
|
11
|
+
declare function schema<TInput, TOutput>(validate: SchemaValidator<TOutput>): Schema<TInput, TOutput>;
|
|
12
|
+
declare function success<T>(value: T): StandardSchemaV1.SuccessResult<T>;
|
|
13
|
+
declare function failure(message: string, path?: ReadonlyArray<PropertyKey>): StandardSchemaV1.FailureResult;
|
|
14
|
+
declare class StandardSchemaValidationError extends Error {
|
|
15
|
+
readonly issues: ReadonlyArray<SchemaIssue>;
|
|
16
|
+
constructor(message: string, issues: ReadonlyArray<SchemaIssue>);
|
|
17
|
+
}
|
|
18
|
+
declare function validateStandardSchema<TSchema extends Schema>(inputSchema: TSchema, value: unknown, message?: string): Promise<SchemaOutput<TSchema>>;
|
|
19
|
+
declare function validateStandardSchemaSync<TSchema extends Schema>(inputSchema: TSchema, value: unknown, message?: string): SchemaOutput<TSchema>;
|
|
20
|
+
declare function unknown(): Schema<unknown>;
|
|
21
|
+
declare function string(message?: string): Schema<unknown, string>;
|
|
22
|
+
declare function number(message?: string): Schema<unknown, number>;
|
|
23
|
+
declare function boolean(message?: string): Schema<unknown, boolean>;
|
|
24
|
+
declare function literal<const TValue extends string | number | boolean | null | undefined>(expected: TValue, message?: string): Schema<unknown, TValue>;
|
|
25
|
+
declare function picklist<const TValues extends readonly [unknown, ...unknown[]]>(values: TValues, message?: string): Schema<unknown, TValues[number]>;
|
|
26
|
+
declare function union<const TSchemas extends readonly [Schema, ...Schema[]]>(schemas: TSchemas, message?: string): Schema<unknown, SchemaOutput<TSchemas[number]>>;
|
|
27
|
+
declare function array<TItem extends Schema = Schema<unknown>>(itemSchema?: TItem, message?: string): Schema<unknown, SchemaOutput<TItem>[]>;
|
|
28
|
+
declare function object<TShape extends SchemaShape>(shape: TShape, message?: string): Schema<unknown, ObjectOutput<TShape>>;
|
|
29
|
+
declare function record<TValue extends Schema>(valueSchema: TValue, message?: string): Schema<unknown, Record<string, SchemaOutput<TValue>>>;
|
|
30
|
+
declare function optional<TSchema extends Schema>(inner: TSchema): Schema<unknown, SchemaOutput<TSchema> | undefined>;
|
|
31
|
+
declare function defaulted<TSchema extends Schema>(inner: TSchema, defaultValue: SchemaOutput<TSchema> | (() => SchemaOutput<TSchema>)): Schema<unknown, SchemaOutput<TSchema>>;
|
|
32
|
+
declare const ss: {
|
|
33
|
+
schema: typeof schema;
|
|
34
|
+
success: typeof success;
|
|
35
|
+
failure: typeof failure;
|
|
36
|
+
StandardSchemaValidationError: typeof StandardSchemaValidationError;
|
|
37
|
+
validateStandardSchema: typeof validateStandardSchema;
|
|
38
|
+
validateStandardSchemaSync: typeof validateStandardSchemaSync;
|
|
39
|
+
unknown: typeof unknown;
|
|
40
|
+
string: typeof string;
|
|
41
|
+
number: typeof number;
|
|
42
|
+
boolean: typeof boolean;
|
|
43
|
+
literal: typeof literal;
|
|
44
|
+
picklist: typeof picklist;
|
|
45
|
+
union: typeof union;
|
|
46
|
+
array: typeof array;
|
|
47
|
+
object: typeof object;
|
|
48
|
+
record: typeof record;
|
|
49
|
+
optional: typeof optional;
|
|
50
|
+
defaulted: typeof defaulted;
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { ObjectOutput, Schema, SchemaIssue, SchemaOutput, SchemaResult, SchemaShape, SchemaValidator, StandardSchemaValidationError, array, boolean, defaulted, failure, literal, number, object, optional, picklist, record, schema, ss, string, success, union, unknown, validateStandardSchema, validateStandardSchemaSync };
|
|
54
|
+
//# sourceMappingURL=mod.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.mts","names":[],"sources":["../src/mod.ts"],"mappings":";;;KAEY,MAAA,6BAAmC,MAAA,IAAU,gBAAA,CAAiB,MAAA,EAAQ,OAAA;AAAA,KAEtE,YAAA,iBAA6B,MAAA,IAAU,gBAAA,CAAiB,WAAA,CAAY,OAAA;AAAA,KAEpE,YAAA,YAAwB,gBAAA,CAAiB,MAAM,CAAC,OAAA;AAAA,KAEhD,WAAA,GAAc,gBAAA,CAAiB,KAAK;AAAA,KAEpC,eAAA,aAA4B,KAAA,cAAmB,YAAY,CAAC,OAAA;AAAA,KAE5D,WAAA,GAAc,MAAM,SAAS,MAAA;AAAA,KAE7B,YAAA,gBAA4B,WAAA,8BACd,MAAA,GAAS,YAAA,CAAa,MAAA,CAAO,IAAA;AAAA,iBAGvC,MAAA,kBACd,QAAA,EAAU,eAAA,CAAgB,OAAA,IACzB,MAAA,CAAO,MAAA,EAAQ,OAAA;AAAA,iBAUF,OAAA,IAAW,KAAA,EAAO,CAAA,GAAI,gBAAA,CAAiB,aAAA,CAAc,CAAA;AAAA,iBAIrD,OAAA,CACd,OAAA,UACA,IAAA,GAAO,aAAA,CAAc,WAAA,IACpB,gBAAA,CAAiB,aAAA;AAAA,cAWP,6BAAA,SAAsC,KAAA;EAAA,SACjC,MAAA,EAAQ,aAAA,CAAc,WAAA;cAE1B,OAAA,UAAiB,MAAA,EAAQ,aAAA,CAAc,WAAA;AAAA;AAAA,iBAO/B,sBAAA,iBAAuC,MAAA,EAC3D,WAAA,EAAa,OAAA,EACb,KAAA,WACA,OAAA,YACC,OAAA,CAAQ,YAAA,CAAa,OAAA;AAAA,iBAQR,0BAAA,iBAA2C,MAAA,EACzD,WAAA,EAAa,OAAA,EACb,KAAA,WACA,OAAA,YACC,YAAA,CAAa,OAAA;AAAA,iBASA,OAAA,IAAW,MAAM;AAAA,iBAIjB,MAAA,CAAO,OAAA,YAAgC,MAAM;AAAA,iBAI7C,MAAA,CAAO,OAAA,YAAgC,MAAM;AAAA,iBAI7C,OAAA,CAAQ,OAAA,YAAiC,MAAM;AAAA,iBAI/C,OAAA,oEACd,QAAA,EAAU,MAAA,EACV,OAAA,YACC,MAAA,UAAgB,MAAA;AAAA,iBAIH,QAAA,yDACd,MAAA,EAAQ,OAAA,EACR,OAAA,YACC,MAAA,UAAgB,OAAA;AAAA,iBAQH,KAAA,kCAAuC,MAAA,KAAW,MAAA,KAChE,OAAA,EAAS,QAAA,EACT,OAAA,YACC,MAAA,UAAgB,YAAA,CAAa,QAAA;AAAA,iBAoBhB,KAAA,eAAoB,MAAA,GAAS,MAAA,WAC3C,UAAA,GAAa,KAAA,EACb,OAAA,YACC,MAAA,UAAgB,YAAA,CAAa,KAAA;AAAA,iBA2BhB,MAAA,gBAAsB,WAAA,EACpC,KAAA,EAAO,MAAA,EACP,OAAA,YACC,MAAA,UAAgB,YAAA,CAAa,MAAA;AAAA,iBA4BhB,MAAA,gBAAsB,MAAA,EACpC,WAAA,EAAa,MAAA,EACb,OAAA,YACC,MAAA,UAAgB,MAAA,SAAe,YAAA,CAAa,MAAA;AAAA,iBAwB/B,QAAA,iBAAyB,MAAA,EACvC,KAAA,EAAO,OAAA,GACN,MAAA,UAAgB,YAAA,CAAa,OAAA;AAAA,iBAYhB,SAAA,iBAA0B,MAAA,EACxC,KAAA,EAAO,OAAA,EACP,YAAA,EAAc,YAAA,CAAa,OAAA,WAAkB,YAAA,CAAa,OAAA,KACzD,MAAA,UAAgB,YAAA,CAAa,OAAA;AAAA,cA6BnB,EAAA"}
|
package/dist/mod.mjs
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
//#region src/mod.ts
|
|
2
|
+
function schema(validate) {
|
|
3
|
+
return { "~standard": {
|
|
4
|
+
version: 1,
|
|
5
|
+
vendor: "@temelj/standard-schema",
|
|
6
|
+
validate
|
|
7
|
+
} };
|
|
8
|
+
}
|
|
9
|
+
function success(value) {
|
|
10
|
+
return { value };
|
|
11
|
+
}
|
|
12
|
+
function failure(message, path) {
|
|
13
|
+
return { issues: [{
|
|
14
|
+
message,
|
|
15
|
+
...path === void 0 ? {} : { path }
|
|
16
|
+
}] };
|
|
17
|
+
}
|
|
18
|
+
var StandardSchemaValidationError = class extends Error {
|
|
19
|
+
issues;
|
|
20
|
+
constructor(message, issues) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "StandardSchemaValidationError";
|
|
23
|
+
this.issues = issues;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
async function validateStandardSchema(inputSchema, value, message = "Schema validation failed") {
|
|
27
|
+
const result = await inputSchema["~standard"].validate(value);
|
|
28
|
+
if (!result.issues) return result.value;
|
|
29
|
+
throw new StandardSchemaValidationError(message, result.issues);
|
|
30
|
+
}
|
|
31
|
+
function validateStandardSchemaSync(inputSchema, value, message = "Schema validation failed") {
|
|
32
|
+
const result = inputSchema["~standard"].validate(value);
|
|
33
|
+
ensureSynchronous(result);
|
|
34
|
+
if (!result.issues) return result.value;
|
|
35
|
+
throw new StandardSchemaValidationError(message, result.issues);
|
|
36
|
+
}
|
|
37
|
+
function unknown() {
|
|
38
|
+
return schema((value) => success(value));
|
|
39
|
+
}
|
|
40
|
+
function string(message = "Expected a string") {
|
|
41
|
+
return schema((value) => typeof value === "string" ? success(value) : failure(message));
|
|
42
|
+
}
|
|
43
|
+
function number(message = "Expected a number") {
|
|
44
|
+
return schema((value) => typeof value === "number" ? success(value) : failure(message));
|
|
45
|
+
}
|
|
46
|
+
function boolean(message = "Expected a boolean") {
|
|
47
|
+
return schema((value) => typeof value === "boolean" ? success(value) : failure(message));
|
|
48
|
+
}
|
|
49
|
+
function literal(expected, message = `Expected ${String(expected)}`) {
|
|
50
|
+
return schema((value) => Object.is(value, expected) ? success(expected) : failure(message));
|
|
51
|
+
}
|
|
52
|
+
function picklist(values, message = `Expected one of ${values.map(String).join(", ")}`) {
|
|
53
|
+
return schema((value) => values.some((item) => Object.is(item, value)) ? success(value) : failure(message));
|
|
54
|
+
}
|
|
55
|
+
function union(schemas, message = "Expected a union match") {
|
|
56
|
+
return schema((value) => {
|
|
57
|
+
const issues = [];
|
|
58
|
+
for (const itemSchema of schemas) {
|
|
59
|
+
const result = itemSchema["~standard"].validate(value);
|
|
60
|
+
ensureSynchronous(result);
|
|
61
|
+
if (!result.issues) return success(result.value);
|
|
62
|
+
issues.push(...result.issues);
|
|
63
|
+
}
|
|
64
|
+
return issues.length > 0 ? failure(message) : failure(message);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function array(itemSchema, message = "Expected an array") {
|
|
68
|
+
return schema((value) => {
|
|
69
|
+
if (!Array.isArray(value)) return failure(message);
|
|
70
|
+
if (itemSchema === void 0) return success(value);
|
|
71
|
+
const output = [];
|
|
72
|
+
const issues = [];
|
|
73
|
+
for (let index = 0; index < value.length; index++) {
|
|
74
|
+
const result = itemSchema["~standard"].validate(value[index]);
|
|
75
|
+
ensureSynchronous(result);
|
|
76
|
+
if (result.issues) issues.push(...result.issues.map((issue) => withPath(index, issue)));
|
|
77
|
+
else output.push(result.value);
|
|
78
|
+
}
|
|
79
|
+
return issues.length > 0 ? { issues } : success(output);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function object(shape, message = "Expected an object") {
|
|
83
|
+
return schema((value) => {
|
|
84
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return failure(message);
|
|
85
|
+
const input = value;
|
|
86
|
+
const output = {};
|
|
87
|
+
const issues = [];
|
|
88
|
+
for (const key of Object.keys(shape)) {
|
|
89
|
+
const result = shape[key]["~standard"].validate(input[key]);
|
|
90
|
+
ensureSynchronous(result);
|
|
91
|
+
if (result.issues) issues.push(...result.issues.map((issue) => withPath(key, issue)));
|
|
92
|
+
else output[key] = result.value;
|
|
93
|
+
}
|
|
94
|
+
return issues.length > 0 ? { issues } : success(output);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function record(valueSchema, message = "Expected an object") {
|
|
98
|
+
return schema((value) => {
|
|
99
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return failure(message);
|
|
100
|
+
const output = {};
|
|
101
|
+
const issues = [];
|
|
102
|
+
for (const [key, item] of Object.entries(value)) {
|
|
103
|
+
const result = valueSchema["~standard"].validate(item);
|
|
104
|
+
ensureSynchronous(result);
|
|
105
|
+
if (result.issues) issues.push(...result.issues.map((issue) => withPath(key, issue)));
|
|
106
|
+
else output[key] = result.value;
|
|
107
|
+
}
|
|
108
|
+
return issues.length > 0 ? { issues } : success(output);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function optional(inner) {
|
|
112
|
+
return schema((value) => {
|
|
113
|
+
if (value === void 0) return success(void 0);
|
|
114
|
+
const result = inner["~standard"].validate(value);
|
|
115
|
+
ensureSynchronous(result);
|
|
116
|
+
return result;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function defaulted(inner, defaultValue) {
|
|
120
|
+
return schema((value) => {
|
|
121
|
+
if (value === void 0) return success(typeof defaultValue === "function" ? defaultValue() : defaultValue);
|
|
122
|
+
const result = inner["~standard"].validate(value);
|
|
123
|
+
ensureSynchronous(result);
|
|
124
|
+
return result;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function ensureSynchronous(value) {
|
|
128
|
+
if (value instanceof Promise) throw new Error("Async schema validation is not supported");
|
|
129
|
+
}
|
|
130
|
+
function withPath(key, issue) {
|
|
131
|
+
return {
|
|
132
|
+
...issue,
|
|
133
|
+
path: [key, ...issue.path ?? []]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const ss = {
|
|
137
|
+
schema,
|
|
138
|
+
success,
|
|
139
|
+
failure,
|
|
140
|
+
StandardSchemaValidationError,
|
|
141
|
+
validateStandardSchema,
|
|
142
|
+
validateStandardSchemaSync,
|
|
143
|
+
unknown,
|
|
144
|
+
string,
|
|
145
|
+
number,
|
|
146
|
+
boolean,
|
|
147
|
+
literal,
|
|
148
|
+
picklist,
|
|
149
|
+
union,
|
|
150
|
+
array,
|
|
151
|
+
object,
|
|
152
|
+
record,
|
|
153
|
+
optional,
|
|
154
|
+
defaulted
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
export { StandardSchemaValidationError, array, boolean, defaulted, failure, literal, number, object, optional, picklist, record, schema, ss, string, success, union, unknown, validateStandardSchema, validateStandardSchemaSync };
|
|
158
|
+
|
|
159
|
+
//# sourceMappingURL=mod.mjs.map
|
package/dist/mod.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.mjs","names":[],"sources":["../src/mod.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nexport type Schema<TInput = unknown, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;\n\nexport type SchemaOutput<TSchema extends Schema> = StandardSchemaV1.InferOutput<TSchema>;\n\nexport type SchemaResult<TOutput> = StandardSchemaV1.Result<TOutput>;\n\nexport type SchemaIssue = StandardSchemaV1.Issue;\n\nexport type SchemaValidator<TOutput> = (value: unknown) => SchemaResult<TOutput>;\n\nexport type SchemaShape = Record<string, Schema>;\n\nexport type ObjectOutput<TShape extends SchemaShape> = {\n readonly [TKey in keyof TShape]: SchemaOutput<TShape[TKey]>;\n};\n\nexport function schema<TInput, TOutput>(\n validate: SchemaValidator<TOutput>,\n): Schema<TInput, TOutput> {\n return {\n \"~standard\": {\n version: 1,\n vendor: \"@temelj/standard-schema\",\n validate,\n },\n };\n}\n\nexport function success<T>(value: T): StandardSchemaV1.SuccessResult<T> {\n return { value };\n}\n\nexport function failure(\n message: string,\n path?: ReadonlyArray<PropertyKey>,\n): StandardSchemaV1.FailureResult {\n return {\n issues: [\n {\n message,\n ...(path === undefined ? {} : { path }),\n },\n ],\n };\n}\n\nexport class StandardSchemaValidationError extends Error {\n public readonly issues: ReadonlyArray<SchemaIssue>;\n\n constructor(message: string, issues: ReadonlyArray<SchemaIssue>) {\n super(message);\n this.name = \"StandardSchemaValidationError\";\n this.issues = issues;\n }\n}\n\nexport async function validateStandardSchema<TSchema extends Schema>(\n inputSchema: TSchema,\n value: unknown,\n message = \"Schema validation failed\",\n): Promise<SchemaOutput<TSchema>> {\n const result = await inputSchema[\"~standard\"].validate(value);\n if (!result.issues) {\n return result.value as SchemaOutput<TSchema>;\n }\n throw new StandardSchemaValidationError(message, result.issues);\n}\n\nexport function validateStandardSchemaSync<TSchema extends Schema>(\n inputSchema: TSchema,\n value: unknown,\n message = \"Schema validation failed\",\n): SchemaOutput<TSchema> {\n const result = inputSchema[\"~standard\"].validate(value);\n ensureSynchronous(result);\n if (!result.issues) {\n return result.value as SchemaOutput<TSchema>;\n }\n throw new StandardSchemaValidationError(message, result.issues);\n}\n\nexport function unknown(): Schema<unknown> {\n return schema((value) => success(value));\n}\n\nexport function string(message = \"Expected a string\"): Schema<unknown, string> {\n return schema((value) => (typeof value === \"string\" ? success(value) : failure(message)));\n}\n\nexport function number(message = \"Expected a number\"): Schema<unknown, number> {\n return schema((value) => (typeof value === \"number\" ? success(value) : failure(message)));\n}\n\nexport function boolean(message = \"Expected a boolean\"): Schema<unknown, boolean> {\n return schema((value) => (typeof value === \"boolean\" ? success(value) : failure(message)));\n}\n\nexport function literal<const TValue extends string | number | boolean | null | undefined>(\n expected: TValue,\n message = `Expected ${String(expected)}`,\n): Schema<unknown, TValue> {\n return schema((value) => (Object.is(value, expected) ? success(expected) : failure(message)));\n}\n\nexport function picklist<const TValues extends readonly [unknown, ...unknown[]]>(\n values: TValues,\n message = `Expected one of ${values.map(String).join(\", \")}`,\n): Schema<unknown, TValues[number]> {\n return schema((value) =>\n values.some((item) => Object.is(item, value))\n ? success(value as TValues[number])\n : failure(message),\n );\n}\n\nexport function union<const TSchemas extends readonly [Schema, ...Schema[]]>(\n schemas: TSchemas,\n message = \"Expected a union match\",\n): Schema<unknown, SchemaOutput<TSchemas[number]>> {\n return schema((value) => {\n const issues: SchemaIssue[] = [];\n\n for (const itemSchema of schemas) {\n const result:\n | SchemaResult<SchemaOutput<TSchemas[number]>>\n | Promise<SchemaResult<SchemaOutput<TSchemas[number]>>> =\n itemSchema[\"~standard\"].validate(value);\n ensureSynchronous(result);\n if (!result.issues) {\n return success(result.value as SchemaOutput<TSchemas[number]>);\n }\n issues.push(...result.issues);\n }\n\n return issues.length > 0 ? failure(message) : failure(message);\n });\n}\n\nexport function array<TItem extends Schema = Schema<unknown>>(\n itemSchema?: TItem,\n message = \"Expected an array\",\n): Schema<unknown, SchemaOutput<TItem>[]> {\n return schema((value) => {\n if (!Array.isArray(value)) {\n return failure(message);\n }\n\n if (itemSchema === undefined) {\n return success(value as SchemaOutput<TItem>[]);\n }\n\n const output: SchemaOutput<TItem>[] = [];\n const issues: SchemaIssue[] = [];\n for (let index = 0; index < value.length; index++) {\n const result: SchemaResult<SchemaOutput<TItem>> | Promise<SchemaResult<SchemaOutput<TItem>>> =\n itemSchema[\"~standard\"].validate(value[index]);\n ensureSynchronous(result);\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(index, issue)));\n } else {\n output.push(result.value as SchemaOutput<TItem>);\n }\n }\n\n return issues.length > 0 ? { issues } : success(output);\n });\n}\n\nexport function object<TShape extends SchemaShape>(\n shape: TShape,\n message = \"Expected an object\",\n): Schema<unknown, ObjectOutput<TShape>> {\n return schema((value) => {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return failure(message);\n }\n\n const input = value as Record<string, unknown>;\n const output: Partial<ObjectOutput<TShape>> = {};\n const issues: SchemaIssue[] = [];\n\n for (const key of Object.keys(shape) as Array<keyof TShape & string>) {\n const result:\n | SchemaResult<SchemaOutput<TShape[typeof key]>>\n | Promise<SchemaResult<SchemaOutput<TShape[typeof key]>>> = shape[key][\n \"~standard\"\n ].validate(input[key]);\n ensureSynchronous(result);\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(key, issue)));\n } else {\n output[key] = result.value as ObjectOutput<TShape>[typeof key];\n }\n }\n\n return issues.length > 0 ? { issues } : success(output as ObjectOutput<TShape>);\n });\n}\n\nexport function record<TValue extends Schema>(\n valueSchema: TValue,\n message = \"Expected an object\",\n): Schema<unknown, Record<string, SchemaOutput<TValue>>> {\n return schema((value) => {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return failure(message);\n }\n\n const output: Record<string, SchemaOutput<TValue>> = {};\n const issues: SchemaIssue[] = [];\n for (const [key, item] of Object.entries(value)) {\n const result:\n | SchemaResult<SchemaOutput<TValue>>\n | Promise<SchemaResult<SchemaOutput<TValue>>> = valueSchema[\"~standard\"].validate(item);\n ensureSynchronous(result);\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(key, issue)));\n } else {\n output[key] = result.value as SchemaOutput<TValue>;\n }\n }\n\n return issues.length > 0 ? { issues } : success(output);\n });\n}\n\nexport function optional<TSchema extends Schema>(\n inner: TSchema,\n): Schema<unknown, SchemaOutput<TSchema> | undefined> {\n return schema((value) => {\n if (value === undefined) {\n return success(undefined);\n }\n\n const result = inner[\"~standard\"].validate(value);\n ensureSynchronous(result);\n return result;\n });\n}\n\nexport function defaulted<TSchema extends Schema>(\n inner: TSchema,\n defaultValue: SchemaOutput<TSchema> | (() => SchemaOutput<TSchema>),\n): Schema<unknown, SchemaOutput<TSchema>> {\n return schema((value) => {\n if (value === undefined) {\n return success(\n typeof defaultValue === \"function\"\n ? (defaultValue as () => SchemaOutput<TSchema>)()\n : defaultValue,\n );\n }\n\n const result = inner[\"~standard\"].validate(value);\n ensureSynchronous(result);\n return result;\n });\n}\n\nfunction ensureSynchronous<T>(value: T | Promise<T>): asserts value is T {\n if (value instanceof Promise) {\n throw new Error(\"Async schema validation is not supported\");\n }\n}\n\nfunction withPath(key: PropertyKey, issue: SchemaIssue): SchemaIssue {\n return {\n ...issue,\n path: [key, ...(issue.path ?? [])],\n };\n}\n\nexport const ss = {\n schema,\n success,\n failure,\n StandardSchemaValidationError,\n validateStandardSchema,\n validateStandardSchemaSync,\n unknown,\n string,\n number,\n boolean,\n literal,\n picklist,\n union,\n array,\n object,\n record,\n optional,\n defaulted,\n};\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@temelj/standard-schema",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Standard Schema construction utilities.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/tinrab/temelj"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/mod.mjs",
|
|
14
|
+
"types": "./dist/mod.d.mts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/mod.d.mts",
|
|
18
|
+
"import": "./dist/mod.mjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@standard-schema/spec": "^1.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "25.9.2",
|
|
26
|
+
"shx": "^0.4.0",
|
|
27
|
+
"tsdown": "^0.22.2",
|
|
28
|
+
"typescript": "^6.0.3",
|
|
29
|
+
"vitest": "^4.1.8"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsdown",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"clean": "shx rm -rf dist"
|
|
36
|
+
}
|
|
37
|
+
}
|