@temelj/standard-schema 0.1.0 → 0.2.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/README.md +6 -0
- package/dist/mod.d.mts +105 -29
- package/dist/mod.d.mts.map +1 -1
- package/dist/mod.mjs +213 -37
- package/dist/mod.mjs.map +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -43,3 +43,9 @@ import { ss } from "@temelj/standard-schema";
|
|
|
43
43
|
const schema = ss.string();
|
|
44
44
|
const result = schema["~standard"].validate("hello");
|
|
45
45
|
```
|
|
46
|
+
|
|
47
|
+
`SchemaFields` names an object's field schemas. `object` validates those fields and strips other keys; `strictObject` rejects extra keys. `looseObject` preserves extra keys at runtime, but its output type exposes only the validated fields.
|
|
48
|
+
|
|
49
|
+
`array()` checks the container and returns `unknown[]`. Pass an element schema, such as `array(string())`, to validate its elements. `fn()` checks that a value is callable; it does not validate the function's parameters or result.
|
|
50
|
+
|
|
51
|
+
`defaulted(schema, value)` uses the supplied value, including function values. Use `defaultedWith(schema, () => value)` to create a default only when the input is `undefined`.
|
package/dist/mod.d.mts
CHANGED
|
@@ -1,54 +1,130 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
-
|
|
3
2
|
//#region src/mod.d.ts
|
|
4
|
-
type Schema<TInput = unknown, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;
|
|
5
|
-
type
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
-
type
|
|
9
|
-
type
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
export type Schema<TInput = unknown, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;
|
|
4
|
+
export type SchemaInput<TSchema extends Schema> = StandardSchemaV1.InferInput<TSchema>;
|
|
5
|
+
export type SchemaOutput<TSchema extends Schema> = StandardSchemaV1.InferOutput<TSchema>;
|
|
6
|
+
export type SchemaResult<TOutput> = StandardSchemaV1.Result<TOutput>;
|
|
7
|
+
export type SchemaIssue = StandardSchemaV1.Issue;
|
|
8
|
+
export type SchemaValidator<TOutput> = (value: unknown) => SchemaResult<TOutput>;
|
|
9
|
+
export type SchemaFields = Record<string, Schema>;
|
|
10
|
+
export type ObjectOutput<TFields extends SchemaFields> = { readonly [TKey in keyof TFields]: SchemaOutput<TFields[TKey]>; };
|
|
11
|
+
export type ObjectInput<TFields extends SchemaFields> = { readonly [TKey in keyof TFields]: SchemaInput<TFields[TKey]>; };
|
|
12
|
+
export type SafeParseResult<T> = {
|
|
13
|
+
readonly success: true;
|
|
14
|
+
readonly value: T;
|
|
15
|
+
} | {
|
|
16
|
+
readonly success: false;
|
|
15
17
|
readonly issues: ReadonlyArray<SchemaIssue>;
|
|
16
|
-
|
|
18
|
+
};
|
|
19
|
+
export interface ObjectOptions {
|
|
20
|
+
readonly unknownKeys?: "strip" | "passthrough" | "strict";
|
|
21
|
+
}
|
|
22
|
+
interface Constructor<T> extends Function {
|
|
23
|
+
readonly prototype: T;
|
|
24
|
+
readonly name: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function schema<TInput, TOutput>(validate: SchemaValidator<TOutput>): Schema<TInput, TOutput>;
|
|
27
|
+
export declare function success<T>(value: T): StandardSchemaV1.SuccessResult<T>;
|
|
28
|
+
export declare function failure(message: string, path?: ReadonlyArray<PropertyKey>): StandardSchemaV1.FailureResult;
|
|
29
|
+
export declare class StandardSchemaValidationError extends Error {
|
|
30
|
+
readonly issues: ReadonlyArray<SchemaIssue>;
|
|
31
|
+
constructor(message: string, issues: ReadonlyArray<SchemaIssue>, context?: Function);
|
|
32
|
+
static failed(this: void, message: string, issues: ReadonlyArray<SchemaIssue>): never;
|
|
33
|
+
}
|
|
34
|
+
export declare class StandardSchemaAsyncValidationError extends Error {
|
|
35
|
+
constructor(message: string, context?: Function);
|
|
36
|
+
static unsupported(this: void): never;
|
|
17
37
|
}
|
|
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
|
|
21
|
-
declare function
|
|
22
|
-
declare function
|
|
23
|
-
declare function
|
|
24
|
-
declare function
|
|
25
|
-
declare function
|
|
26
|
-
declare function
|
|
27
|
-
declare function
|
|
28
|
-
declare function
|
|
29
|
-
declare function
|
|
30
|
-
declare function
|
|
31
|
-
declare function
|
|
32
|
-
declare
|
|
38
|
+
export declare function validateStandardSchema<TSchema extends Schema>(inputSchema: TSchema, value: unknown, message?: string): Promise<SchemaOutput<TSchema>>;
|
|
39
|
+
export declare function validateStandardSchemaSync<TSchema extends Schema>(inputSchema: TSchema, value: unknown, message?: string): SchemaOutput<TSchema>;
|
|
40
|
+
export declare function safeParse<TSchema extends Schema>(inputSchema: TSchema, value: SchemaInput<TSchema>): Promise<SafeParseResult<SchemaOutput<TSchema>>>;
|
|
41
|
+
export declare function safeParseSync<TSchema extends Schema>(inputSchema: TSchema, value: SchemaInput<TSchema>): SafeParseResult<SchemaOutput<TSchema>>;
|
|
42
|
+
export declare function parse<TSchema extends Schema>(inputSchema: TSchema, value: SchemaInput<TSchema>, message?: string): Promise<SchemaOutput<TSchema>>;
|
|
43
|
+
export declare function parseSync<TSchema extends Schema>(inputSchema: TSchema, value: SchemaInput<TSchema>, message?: string): SchemaOutput<TSchema>;
|
|
44
|
+
export declare function unknown(): Schema<unknown>;
|
|
45
|
+
export declare function string(message?: string): Schema<unknown, string>;
|
|
46
|
+
export declare function number(message?: string): Schema<unknown, number>;
|
|
47
|
+
export declare function finite(message?: string): Schema<unknown, number>;
|
|
48
|
+
export declare function integer(message?: string): Schema<unknown, number>;
|
|
49
|
+
export declare function safeInteger(message?: string): Schema<unknown, number>;
|
|
50
|
+
export declare function positiveNumber(message?: string): Schema<unknown, number>;
|
|
51
|
+
export declare function nonNegativeNumber(message?: string): Schema<unknown, number>;
|
|
52
|
+
export declare function positiveSafeInteger(message?: string): Schema<unknown, number>;
|
|
53
|
+
export declare function nonNegativeSafeInteger(message?: string): Schema<unknown, number>;
|
|
54
|
+
export declare function min(inner: Schema<unknown, number>, minimum: number, message?: string): Schema<unknown, number>;
|
|
55
|
+
export declare function max(inner: Schema<unknown, number>, maximum: number, message?: string): Schema<unknown, number>;
|
|
56
|
+
export declare function nonEmptyString(message?: string): Schema<unknown, string>;
|
|
57
|
+
export declare function nonBlankString(message?: string): Schema<unknown, string>;
|
|
58
|
+
export declare function boolean(message?: string): Schema<unknown, boolean>;
|
|
59
|
+
export declare function fn(message?: string): Schema<unknown, Function>;
|
|
60
|
+
export declare function instanceOf<T>(constructor: Constructor<T>, message?: string): Schema<unknown, T>;
|
|
61
|
+
export declare function literal<const TValue extends string | number | boolean | null | undefined>(expected: TValue, message?: string): Schema<unknown, TValue>;
|
|
62
|
+
export declare function picklist<const TValues extends readonly [unknown, ...unknown[]]>(values: TValues, message?: string): Schema<unknown, TValues[number]>;
|
|
63
|
+
export declare function union<const TSchemas extends readonly [Schema, ...Schema[]]>(schemas: TSchemas, message?: string): Schema<unknown, SchemaOutput<TSchemas[number]>>;
|
|
64
|
+
export declare function array(): Schema<unknown, unknown[]>;
|
|
65
|
+
export declare function array<TItem extends Schema>(itemSchema: TItem, message?: string): Schema<unknown, SchemaOutput<TItem>[]>;
|
|
66
|
+
export declare function object<TFields extends SchemaFields>(fields: TFields, message?: string, options?: ObjectOptions): Schema<unknown, ObjectOutput<TFields>>;
|
|
67
|
+
export declare function strictObject<TFields extends SchemaFields>(fields: TFields, message?: string): Schema<unknown, ObjectOutput<TFields>>;
|
|
68
|
+
export declare function looseObject<TFields extends SchemaFields>(fields: TFields, message?: string): Schema<unknown, ObjectOutput<TFields>>;
|
|
69
|
+
export declare function record<TValue extends Schema>(valueSchema: TValue, message?: string): Schema<unknown, Record<string, SchemaOutput<TValue>>>;
|
|
70
|
+
export declare function optional<TSchema extends Schema>(inner: TSchema): Schema<unknown, SchemaOutput<TSchema> | undefined>;
|
|
71
|
+
export declare function defaulted<TSchema extends Schema>(inner: TSchema, defaultValue: SchemaOutput<TSchema>): Schema<unknown, SchemaOutput<TSchema>>;
|
|
72
|
+
export declare function defaultedWith<TSchema extends Schema>(inner: TSchema, createDefault: () => SchemaOutput<TSchema>): Schema<unknown, SchemaOutput<TSchema>>;
|
|
73
|
+
export declare function refine<TSchema extends Schema, TOutput extends SchemaOutput<TSchema>>(inner: TSchema, predicate: (value: SchemaOutput<TSchema>) => value is TOutput, message?: string): Schema<SchemaInput<TSchema>, TOutput>;
|
|
74
|
+
export declare function refine<TSchema extends Schema>(inner: TSchema, predicate: (value: SchemaOutput<TSchema>) => boolean, message?: string): Schema<SchemaInput<TSchema>, SchemaOutput<TSchema>>;
|
|
75
|
+
export declare function transform<TSchema extends Schema, TOutput>(inner: TSchema, mapper: (value: SchemaOutput<TSchema>) => TOutput): Schema<SchemaInput<TSchema>, TOutput>;
|
|
76
|
+
export declare function pipe<TLeft extends Schema, TRight extends Schema>(left: TLeft, right: TRight): Schema<SchemaInput<TLeft>, SchemaOutput<TRight>>;
|
|
77
|
+
export declare function extend<TBase extends SchemaFields, TExtension extends SchemaFields>(base: TBase, extension: TExtension): Omit<TBase, keyof TExtension> & TExtension;
|
|
78
|
+
export declare function pick<TFields extends SchemaFields, const TKeys extends readonly (keyof TFields)[]>(fields: TFields, keys: TKeys): Pick<TFields, TKeys[number]>;
|
|
79
|
+
export declare function omit<TFields extends SchemaFields, const TKeys extends readonly (keyof TFields)[]>(fields: TFields, keys: TKeys): Omit<TFields, TKeys[number]>;
|
|
80
|
+
export declare function partial<TFields extends SchemaFields>(fields: TFields): { readonly [TKey in keyof TFields]: Schema<unknown, SchemaOutput<TFields[TKey]> | undefined>; };
|
|
81
|
+
export declare const ss: {
|
|
33
82
|
schema: typeof schema;
|
|
34
83
|
success: typeof success;
|
|
35
84
|
failure: typeof failure;
|
|
36
85
|
StandardSchemaValidationError: typeof StandardSchemaValidationError;
|
|
37
86
|
validateStandardSchema: typeof validateStandardSchema;
|
|
38
87
|
validateStandardSchemaSync: typeof validateStandardSchemaSync;
|
|
88
|
+
safeParse: typeof safeParse;
|
|
89
|
+
safeParseSync: typeof safeParseSync;
|
|
90
|
+
parse: typeof parse;
|
|
91
|
+
parseSync: typeof parseSync;
|
|
39
92
|
unknown: typeof unknown;
|
|
40
93
|
string: typeof string;
|
|
41
94
|
number: typeof number;
|
|
95
|
+
finite: typeof finite;
|
|
96
|
+
integer: typeof integer;
|
|
97
|
+
safeInteger: typeof safeInteger;
|
|
98
|
+
positiveNumber: typeof positiveNumber;
|
|
99
|
+
nonNegativeNumber: typeof nonNegativeNumber;
|
|
100
|
+
positiveSafeInteger: typeof positiveSafeInteger;
|
|
101
|
+
nonNegativeSafeInteger: typeof nonNegativeSafeInteger;
|
|
102
|
+
min: typeof min;
|
|
103
|
+
max: typeof max;
|
|
104
|
+
nonEmptyString: typeof nonEmptyString;
|
|
105
|
+
nonBlankString: typeof nonBlankString;
|
|
42
106
|
boolean: typeof boolean;
|
|
107
|
+
fn: typeof fn;
|
|
108
|
+
instanceOf: typeof instanceOf;
|
|
43
109
|
literal: typeof literal;
|
|
44
110
|
picklist: typeof picklist;
|
|
45
111
|
union: typeof union;
|
|
46
112
|
array: typeof array;
|
|
47
113
|
object: typeof object;
|
|
114
|
+
strictObject: typeof strictObject;
|
|
115
|
+
looseObject: typeof looseObject;
|
|
48
116
|
record: typeof record;
|
|
49
117
|
optional: typeof optional;
|
|
50
118
|
defaulted: typeof defaulted;
|
|
119
|
+
defaultedWith: typeof defaultedWith;
|
|
120
|
+
refine: typeof refine;
|
|
121
|
+
transform: typeof transform;
|
|
122
|
+
pipe: typeof pipe;
|
|
123
|
+
extend: typeof extend;
|
|
124
|
+
pick: typeof pick;
|
|
125
|
+
omit: typeof omit;
|
|
126
|
+
partial: typeof partial;
|
|
51
127
|
};
|
|
52
128
|
//#endregion
|
|
53
|
-
export {
|
|
129
|
+
export {};
|
|
54
130
|
//# sourceMappingURL=mod.d.mts.map
|
package/dist/mod.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.mts","names":[],"sources":["../src/mod.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"mod.d.mts","names":[],"sources":["../src/mod.ts"],"mappings":"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"}
|
package/dist/mod.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBoolean, isFunction, isNumber, isObject, isString } from "@temelj/value";
|
|
1
2
|
//#region src/mod.ts
|
|
2
3
|
function schema(validate) {
|
|
3
4
|
return { "~standard": {
|
|
@@ -12,56 +13,134 @@ function success(value) {
|
|
|
12
13
|
function failure(message, path) {
|
|
13
14
|
return { issues: [{
|
|
14
15
|
message,
|
|
15
|
-
|
|
16
|
+
path
|
|
16
17
|
}] };
|
|
17
18
|
}
|
|
18
|
-
var StandardSchemaValidationError = class extends Error {
|
|
19
|
+
var StandardSchemaValidationError = class StandardSchemaValidationError extends Error {
|
|
19
20
|
issues;
|
|
20
|
-
constructor(message, issues) {
|
|
21
|
+
constructor(message, issues, context) {
|
|
21
22
|
super(message);
|
|
22
23
|
this.name = "StandardSchemaValidationError";
|
|
23
24
|
this.issues = issues;
|
|
25
|
+
if (Error.captureStackTrace !== void 0) Error.captureStackTrace(this, context ?? this.constructor);
|
|
26
|
+
}
|
|
27
|
+
static failed(message, issues) {
|
|
28
|
+
throw new StandardSchemaValidationError(message, issues, StandardSchemaValidationError.failed);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var StandardSchemaAsyncValidationError = class StandardSchemaAsyncValidationError extends Error {
|
|
32
|
+
constructor(message, context) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "StandardSchemaAsyncValidationError";
|
|
35
|
+
if (Error.captureStackTrace !== void 0) Error.captureStackTrace(this, context ?? this.constructor);
|
|
36
|
+
}
|
|
37
|
+
static unsupported() {
|
|
38
|
+
throw new StandardSchemaAsyncValidationError("Async schema validation is not supported", StandardSchemaAsyncValidationError.unsupported);
|
|
24
39
|
}
|
|
25
40
|
};
|
|
26
41
|
async function validateStandardSchema(inputSchema, value, message = "Schema validation failed") {
|
|
27
42
|
const result = await inputSchema["~standard"].validate(value);
|
|
28
43
|
if (!result.issues) return result.value;
|
|
29
|
-
|
|
44
|
+
StandardSchemaValidationError.failed(message, result.issues);
|
|
30
45
|
}
|
|
31
46
|
function validateStandardSchemaSync(inputSchema, value, message = "Schema validation failed") {
|
|
32
|
-
const result = inputSchema
|
|
33
|
-
ensureSynchronous(result);
|
|
47
|
+
const result = evaluate(inputSchema, value);
|
|
34
48
|
if (!result.issues) return result.value;
|
|
35
|
-
|
|
49
|
+
StandardSchemaValidationError.failed(message, result.issues);
|
|
50
|
+
}
|
|
51
|
+
async function safeParse(inputSchema, value) {
|
|
52
|
+
const result = await inputSchema["~standard"].validate(value);
|
|
53
|
+
return result.issues ? {
|
|
54
|
+
success: false,
|
|
55
|
+
issues: result.issues
|
|
56
|
+
} : {
|
|
57
|
+
success: true,
|
|
58
|
+
value: result.value
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function safeParseSync(inputSchema, value) {
|
|
62
|
+
const result = evaluate(inputSchema, value);
|
|
63
|
+
return result.issues ? {
|
|
64
|
+
success: false,
|
|
65
|
+
issues: result.issues
|
|
66
|
+
} : {
|
|
67
|
+
success: true,
|
|
68
|
+
value: result.value
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function parse(inputSchema, value, message) {
|
|
72
|
+
return await validateStandardSchema(inputSchema, value, message);
|
|
73
|
+
}
|
|
74
|
+
function parseSync(inputSchema, value, message) {
|
|
75
|
+
return validateStandardSchemaSync(inputSchema, value, message);
|
|
36
76
|
}
|
|
37
77
|
function unknown() {
|
|
38
78
|
return schema((value) => success(value));
|
|
39
79
|
}
|
|
40
80
|
function string(message = "Expected a string") {
|
|
41
|
-
return schema((value) =>
|
|
81
|
+
return schema((value) => isString(value) ? success(value) : failure(message));
|
|
42
82
|
}
|
|
43
83
|
function number(message = "Expected a number") {
|
|
44
|
-
return schema((value) =>
|
|
84
|
+
return schema((value) => isNumber(value) ? success(value) : failure(message));
|
|
85
|
+
}
|
|
86
|
+
function finite(message = "Expected a finite number") {
|
|
87
|
+
return refine(number(), Number.isFinite, message);
|
|
88
|
+
}
|
|
89
|
+
function integer(message = "Expected an integer") {
|
|
90
|
+
return refine(number(), Number.isInteger, message);
|
|
91
|
+
}
|
|
92
|
+
function safeInteger(message = "Expected a safe integer") {
|
|
93
|
+
return refine(number(), Number.isSafeInteger, message);
|
|
94
|
+
}
|
|
95
|
+
function positiveNumber(message = "Expected a positive number") {
|
|
96
|
+
return refine(number(), (value) => Number.isFinite(value) && value > 0, message);
|
|
97
|
+
}
|
|
98
|
+
function nonNegativeNumber(message = "Expected a non-negative number") {
|
|
99
|
+
return refine(number(), (value) => Number.isFinite(value) && value >= 0, message);
|
|
100
|
+
}
|
|
101
|
+
function positiveSafeInteger(message = "Expected a positive safe integer") {
|
|
102
|
+
return refine(number(), (value) => Number.isSafeInteger(value) && value > 0, message);
|
|
103
|
+
}
|
|
104
|
+
function nonNegativeSafeInteger(message = "Expected a non-negative safe integer") {
|
|
105
|
+
return refine(number(), (value) => Number.isSafeInteger(value) && value >= 0, message);
|
|
106
|
+
}
|
|
107
|
+
function min(inner, minimum, message = `Expected a number greater than or equal to ${minimum}`) {
|
|
108
|
+
return refine(inner, (value) => value >= minimum, message);
|
|
109
|
+
}
|
|
110
|
+
function max(inner, maximum, message = `Expected a number less than or equal to ${maximum}`) {
|
|
111
|
+
return refine(inner, (value) => value <= maximum, message);
|
|
112
|
+
}
|
|
113
|
+
function nonEmptyString(message = "Expected a non-empty string") {
|
|
114
|
+
return refine(string(), (value) => value.length > 0, message);
|
|
115
|
+
}
|
|
116
|
+
function nonBlankString(message = "Expected a non-blank string") {
|
|
117
|
+
return refine(string(), (value) => value.trim().length > 0, message);
|
|
45
118
|
}
|
|
46
119
|
function boolean(message = "Expected a boolean") {
|
|
47
|
-
return schema((value) =>
|
|
120
|
+
return schema((value) => isBoolean(value) ? success(value) : failure(message));
|
|
121
|
+
}
|
|
122
|
+
function fn(message = "Expected a function") {
|
|
123
|
+
return schema((value) => isFunction(value) ? success(value) : failure(message));
|
|
124
|
+
}
|
|
125
|
+
function instanceOf(constructor, message = `Expected ${constructor.name}`) {
|
|
126
|
+
return schema((value) => value instanceof constructor ? success(value) : failure(message));
|
|
48
127
|
}
|
|
49
128
|
function literal(expected, message = `Expected ${String(expected)}`) {
|
|
50
129
|
return schema((value) => Object.is(value, expected) ? success(expected) : failure(message));
|
|
51
130
|
}
|
|
52
131
|
function picklist(values, message = `Expected one of ${values.map(String).join(", ")}`) {
|
|
53
|
-
return schema((value) =>
|
|
132
|
+
return schema((value) => {
|
|
133
|
+
const match = values.findIndex((item) => Object.is(item, value));
|
|
134
|
+
return match === -1 ? failure(message) : success(values[match]);
|
|
135
|
+
});
|
|
54
136
|
}
|
|
55
137
|
function union(schemas, message = "Expected a union match") {
|
|
56
138
|
return schema((value) => {
|
|
57
|
-
const issues = [];
|
|
58
139
|
for (const itemSchema of schemas) {
|
|
59
|
-
const result = itemSchema
|
|
60
|
-
ensureSynchronous(result);
|
|
140
|
+
const result = evaluate(itemSchema, value);
|
|
61
141
|
if (!result.issues) return success(result.value);
|
|
62
|
-
issues.push(...result.issues);
|
|
63
142
|
}
|
|
64
|
-
return
|
|
143
|
+
return failure(message);
|
|
65
144
|
});
|
|
66
145
|
}
|
|
67
146
|
function array(itemSchema, message = "Expected an array") {
|
|
@@ -71,37 +150,62 @@ function array(itemSchema, message = "Expected an array") {
|
|
|
71
150
|
const output = [];
|
|
72
151
|
const issues = [];
|
|
73
152
|
for (let index = 0; index < value.length; index++) {
|
|
74
|
-
const result = itemSchema
|
|
75
|
-
ensureSynchronous(result);
|
|
153
|
+
const result = evaluate(itemSchema, value[index]);
|
|
76
154
|
if (result.issues) issues.push(...result.issues.map((issue) => withPath(index, issue)));
|
|
77
155
|
else output.push(result.value);
|
|
78
156
|
}
|
|
79
157
|
return issues.length > 0 ? { issues } : success(output);
|
|
80
158
|
});
|
|
81
159
|
}
|
|
82
|
-
function object(
|
|
160
|
+
function object(fields, message = "Expected an object", options = {}) {
|
|
83
161
|
return schema((value) => {
|
|
84
|
-
if (value
|
|
162
|
+
if (!isObject(value) || Array.isArray(value)) return failure(message);
|
|
85
163
|
const input = value;
|
|
86
164
|
const output = {};
|
|
165
|
+
if (options.unknownKeys === "passthrough") for (const key of Reflect.ownKeys(input)) {
|
|
166
|
+
if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue;
|
|
167
|
+
Object.defineProperty(output, key, {
|
|
168
|
+
value: input[key],
|
|
169
|
+
enumerable: true,
|
|
170
|
+
writable: true,
|
|
171
|
+
configurable: true
|
|
172
|
+
});
|
|
173
|
+
}
|
|
87
174
|
const issues = [];
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
175
|
+
const fieldKeys = Object.keys(fields);
|
|
176
|
+
if (options.unknownKeys === "strict") {
|
|
177
|
+
for (const key of Object.keys(input)) if (!fieldKeys.includes(key)) issues.push({
|
|
178
|
+
message: "Unexpected key",
|
|
179
|
+
path: [key]
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
for (const key of fieldKeys) {
|
|
183
|
+
const hasOwnField = Object.prototype.hasOwnProperty.call(input, key);
|
|
184
|
+
const result = evaluate(fields[key], hasOwnField ? input[key] : void 0);
|
|
91
185
|
if (result.issues) issues.push(...result.issues.map((issue) => withPath(key, issue)));
|
|
92
|
-
else
|
|
186
|
+
else if (hasOwnField || result.value !== void 0) Object.defineProperty(output, key, {
|
|
187
|
+
value: result.value,
|
|
188
|
+
enumerable: true,
|
|
189
|
+
writable: true,
|
|
190
|
+
configurable: true
|
|
191
|
+
});
|
|
93
192
|
}
|
|
94
193
|
return issues.length > 0 ? { issues } : success(output);
|
|
95
194
|
});
|
|
96
195
|
}
|
|
196
|
+
function strictObject(fields, message = "Expected an object") {
|
|
197
|
+
return object(fields, message, { unknownKeys: "strict" });
|
|
198
|
+
}
|
|
199
|
+
function looseObject(fields, message = "Expected an object") {
|
|
200
|
+
return object(fields, message, { unknownKeys: "passthrough" });
|
|
201
|
+
}
|
|
97
202
|
function record(valueSchema, message = "Expected an object") {
|
|
98
203
|
return schema((value) => {
|
|
99
|
-
if (value
|
|
204
|
+
if (!isObject(value) || Array.isArray(value)) return failure(message);
|
|
100
205
|
const output = {};
|
|
101
206
|
const issues = [];
|
|
102
207
|
for (const [key, item] of Object.entries(value)) {
|
|
103
|
-
const result = valueSchema
|
|
104
|
-
ensureSynchronous(result);
|
|
208
|
+
const result = evaluate(valueSchema, item);
|
|
105
209
|
if (result.issues) issues.push(...result.issues.map((issue) => withPath(key, issue)));
|
|
106
210
|
else output[key] = result.value;
|
|
107
211
|
}
|
|
@@ -111,21 +215,66 @@ function record(valueSchema, message = "Expected an object") {
|
|
|
111
215
|
function optional(inner) {
|
|
112
216
|
return schema((value) => {
|
|
113
217
|
if (value === void 0) return success(void 0);
|
|
114
|
-
|
|
115
|
-
ensureSynchronous(result);
|
|
116
|
-
return result;
|
|
218
|
+
return evaluate(inner, value);
|
|
117
219
|
});
|
|
118
220
|
}
|
|
119
221
|
function defaulted(inner, defaultValue) {
|
|
120
222
|
return schema((value) => {
|
|
121
|
-
if (value === void 0) return success(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
223
|
+
if (value === void 0) return success(defaultValue);
|
|
224
|
+
return evaluate(inner, value);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function defaultedWith(inner, createDefault) {
|
|
228
|
+
return schema((value) => value === void 0 ? success(createDefault()) : evaluate(inner, value));
|
|
229
|
+
}
|
|
230
|
+
function refine(inner, predicate, message = "Invalid value") {
|
|
231
|
+
return schema((value) => {
|
|
232
|
+
const result = evaluate(inner, value);
|
|
233
|
+
if (result.issues) return result;
|
|
234
|
+
return predicate(result.value) ? result : failure(message);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function transform(inner, mapper) {
|
|
238
|
+
return schema((value) => {
|
|
239
|
+
const result = evaluate(inner, value);
|
|
240
|
+
if (result.issues) return result;
|
|
241
|
+
return success(mapper(result.value));
|
|
125
242
|
});
|
|
126
243
|
}
|
|
244
|
+
function pipe(left, right) {
|
|
245
|
+
return schema((value) => {
|
|
246
|
+
const leftResult = evaluate(left, value);
|
|
247
|
+
if (leftResult.issues) return leftResult;
|
|
248
|
+
return evaluate(right, leftResult.value);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function extend(base, extension) {
|
|
252
|
+
return {
|
|
253
|
+
...base,
|
|
254
|
+
...extension
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function pick(fields, keys) {
|
|
258
|
+
return Object.fromEntries(keys.map((key) => [key, fields[key]]));
|
|
259
|
+
}
|
|
260
|
+
function omit(fields, keys) {
|
|
261
|
+
const result = { ...fields };
|
|
262
|
+
for (const key of keys) delete result[key];
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
function partial(fields) {
|
|
266
|
+
const entries = Reflect.ownKeys(fields).map((key) => {
|
|
267
|
+
return [key, optional(fields[key])];
|
|
268
|
+
});
|
|
269
|
+
return Object.fromEntries(entries);
|
|
270
|
+
}
|
|
271
|
+
function evaluate(inputSchema, value) {
|
|
272
|
+
const result = inputSchema["~standard"].validate(value);
|
|
273
|
+
ensureSynchronous(result);
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
127
276
|
function ensureSynchronous(value) {
|
|
128
|
-
if (value instanceof Promise)
|
|
277
|
+
if (value instanceof Promise) StandardSchemaAsyncValidationError.unsupported();
|
|
129
278
|
}
|
|
130
279
|
function withPath(key, issue) {
|
|
131
280
|
return {
|
|
@@ -140,20 +289,47 @@ const ss = {
|
|
|
140
289
|
StandardSchemaValidationError,
|
|
141
290
|
validateStandardSchema,
|
|
142
291
|
validateStandardSchemaSync,
|
|
292
|
+
safeParse,
|
|
293
|
+
safeParseSync,
|
|
294
|
+
parse,
|
|
295
|
+
parseSync,
|
|
143
296
|
unknown,
|
|
144
297
|
string,
|
|
145
298
|
number,
|
|
299
|
+
finite,
|
|
300
|
+
integer,
|
|
301
|
+
safeInteger,
|
|
302
|
+
positiveNumber,
|
|
303
|
+
nonNegativeNumber,
|
|
304
|
+
positiveSafeInteger,
|
|
305
|
+
nonNegativeSafeInteger,
|
|
306
|
+
min,
|
|
307
|
+
max,
|
|
308
|
+
nonEmptyString,
|
|
309
|
+
nonBlankString,
|
|
146
310
|
boolean,
|
|
311
|
+
fn,
|
|
312
|
+
instanceOf,
|
|
147
313
|
literal,
|
|
148
314
|
picklist,
|
|
149
315
|
union,
|
|
150
316
|
array,
|
|
151
317
|
object,
|
|
318
|
+
strictObject,
|
|
319
|
+
looseObject,
|
|
152
320
|
record,
|
|
153
321
|
optional,
|
|
154
|
-
defaulted
|
|
322
|
+
defaulted,
|
|
323
|
+
defaultedWith,
|
|
324
|
+
refine,
|
|
325
|
+
transform,
|
|
326
|
+
pipe,
|
|
327
|
+
extend,
|
|
328
|
+
pick,
|
|
329
|
+
omit,
|
|
330
|
+
partial
|
|
155
331
|
};
|
|
156
332
|
//#endregion
|
|
157
|
-
export { StandardSchemaValidationError, array, boolean, defaulted, failure, literal, number, object, optional, picklist, record, schema, ss, string, success, union, unknown, validateStandardSchema, validateStandardSchemaSync };
|
|
333
|
+
export { StandardSchemaAsyncValidationError, StandardSchemaValidationError, array, boolean, defaulted, defaultedWith, extend, failure, finite, fn, instanceOf, integer, literal, looseObject, max, min, nonBlankString, nonEmptyString, nonNegativeNumber, nonNegativeSafeInteger, number, object, omit, optional, parse, parseSync, partial, pick, picklist, pipe, positiveNumber, positiveSafeInteger, record, refine, safeInteger, safeParse, safeParseSync, schema, ss, strictObject, string, success, transform, union, unknown, validateStandardSchema, validateStandardSchemaSync };
|
|
158
334
|
|
|
159
335
|
//# sourceMappingURL=mod.mjs.map
|
package/dist/mod.mjs.map
CHANGED
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"mod.mjs","names":[],"sources":["../src/mod.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nimport { isString, isNumber, isBoolean, isFunction, isObject } from \"@temelj/value\";\n\nexport type Schema<TInput = unknown, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;\n\nexport type SchemaInput<TSchema extends Schema> = StandardSchemaV1.InferInput<TSchema>;\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\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Standard Schema validators receive untrusted input before validating it.\nexport type SchemaValidator<TOutput> = (value: unknown) => SchemaResult<TOutput>;\n\nexport type SchemaFields = Record<string, Schema>;\n\nexport type ObjectOutput<TFields extends SchemaFields> = {\n readonly [TKey in keyof TFields]: SchemaOutput<TFields[TKey]>;\n};\n\nexport type ObjectInput<TFields extends SchemaFields> = {\n readonly [TKey in keyof TFields]: SchemaInput<TFields[TKey]>;\n};\n\nexport type SafeParseResult<T> =\n | { readonly success: true; readonly value: T }\n | { readonly success: false; readonly issues: ReadonlyArray<SchemaIssue> };\n\nexport interface ObjectOptions {\n readonly unknownKeys?: \"strip\" | \"passthrough\" | \"strict\";\n}\n\ninterface Constructor<T> extends Function {\n readonly prototype: T;\n readonly name: string;\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,\n },\n ],\n };\n}\n\nexport class StandardSchemaValidationError extends Error {\n public readonly issues: ReadonlyArray<SchemaIssue>;\n\n constructor(message: string, issues: ReadonlyArray<SchemaIssue>, context?: Function) {\n super(message);\n this.name = \"StandardSchemaValidationError\";\n this.issues = issues;\n\n if (Error.captureStackTrace !== undefined) {\n Error.captureStackTrace(this, context ?? this.constructor);\n }\n }\n\n static failed(this: void, message: string, issues: ReadonlyArray<SchemaIssue>): never {\n throw new StandardSchemaValidationError(message, issues, StandardSchemaValidationError.failed);\n }\n}\n\nexport class StandardSchemaAsyncValidationError extends Error {\n constructor(message: string, context?: Function) {\n super(message);\n this.name = \"StandardSchemaAsyncValidationError\";\n\n if (Error.captureStackTrace !== undefined) {\n Error.captureStackTrace(this, context ?? this.constructor);\n }\n }\n\n static unsupported(this: void): never {\n throw new StandardSchemaAsyncValidationError(\n \"Async schema validation is not supported\",\n StandardSchemaAsyncValidationError.unsupported,\n );\n }\n}\n\nexport async function validateStandardSchema<TSchema extends Schema>(\n inputSchema: TSchema,\n // oxlint-disable-next-line anti-slop/no-unknown-parameters -- Schema validation is the boundary that converts untrusted input to its declared output.\n value: unknown,\n message: string = \"Schema validation failed\",\n): Promise<SchemaOutput<TSchema>> {\n const result = await inputSchema[\"~standard\"].validate(value);\n\n if (!result.issues) {\n // SAFETY: this success result was returned by the supplied TSchema validator.\n return result.value as SchemaOutput<TSchema>;\n }\n\n StandardSchemaValidationError.failed(message, result.issues);\n}\n\nexport function validateStandardSchemaSync<TSchema extends Schema>(\n inputSchema: TSchema,\n // oxlint-disable-next-line anti-slop/no-unknown-parameters -- Schema validation is the boundary that converts untrusted input to its declared output.\n value: unknown,\n message: string = \"Schema validation failed\",\n): SchemaOutput<TSchema> {\n const result = evaluate(inputSchema, value);\n\n if (!result.issues) {\n return result.value;\n }\n\n StandardSchemaValidationError.failed(message, result.issues);\n}\n\nexport async function safeParse<TSchema extends Schema>(\n inputSchema: TSchema,\n value: SchemaInput<TSchema>,\n): Promise<SafeParseResult<SchemaOutput<TSchema>>> {\n const result = await inputSchema[\"~standard\"].validate(value);\n\n // SAFETY: the success value was returned by the supplied TSchema validator.\n return result.issues\n ? { success: false, issues: result.issues }\n : { success: true, value: result.value as SchemaOutput<TSchema> };\n}\n\nexport function safeParseSync<TSchema extends Schema>(\n inputSchema: TSchema,\n value: SchemaInput<TSchema>,\n): SafeParseResult<SchemaOutput<TSchema>> {\n const result = evaluate(inputSchema, value);\n\n return result.issues\n ? { success: false, issues: result.issues }\n : { success: true, value: result.value };\n}\n\nexport async function parse<TSchema extends Schema>(\n inputSchema: TSchema,\n value: SchemaInput<TSchema>,\n message?: string,\n): Promise<SchemaOutput<TSchema>> {\n return await validateStandardSchema(inputSchema, value, message);\n}\n\nexport function parseSync<TSchema extends Schema>(\n inputSchema: TSchema,\n value: SchemaInput<TSchema>,\n message?: string,\n): SchemaOutput<TSchema> {\n return validateStandardSchemaSync(inputSchema, value, message);\n}\n\nexport function unknown(): Schema<unknown> {\n return schema((value) => success(value));\n}\n\nexport function string(message: string = \"Expected a string\"): Schema<unknown, string> {\n return schema((value) => (isString(value) ? success(value) : failure(message)));\n}\n\nexport function number(message: string = \"Expected a number\"): Schema<unknown, number> {\n return schema((value) => (isNumber(value) ? success(value) : failure(message)));\n}\n\nexport function finite(message: string = \"Expected a finite number\"): Schema<unknown, number> {\n return refine(number(), Number.isFinite, message);\n}\n\nexport function integer(message: string = \"Expected an integer\"): Schema<unknown, number> {\n return refine(number(), Number.isInteger, message);\n}\n\nexport function safeInteger(message: string = \"Expected a safe integer\"): Schema<unknown, number> {\n return refine(number(), Number.isSafeInteger, message);\n}\n\nexport function positiveNumber(\n message: string = \"Expected a positive number\",\n): Schema<unknown, number> {\n return refine(number(), (value) => Number.isFinite(value) && value > 0, message);\n}\n\nexport function nonNegativeNumber(\n message: string = \"Expected a non-negative number\",\n): Schema<unknown, number> {\n return refine(number(), (value) => Number.isFinite(value) && value >= 0, message);\n}\n\nexport function positiveSafeInteger(\n message: string = \"Expected a positive safe integer\",\n): Schema<unknown, number> {\n return refine(number(), (value) => Number.isSafeInteger(value) && value > 0, message);\n}\n\nexport function nonNegativeSafeInteger(\n message: string = \"Expected a non-negative safe integer\",\n): Schema<unknown, number> {\n return refine(number(), (value) => Number.isSafeInteger(value) && value >= 0, message);\n}\n\nexport function min(\n inner: Schema<unknown, number>,\n minimum: number,\n message: string = `Expected a number greater than or equal to ${minimum}`,\n): Schema<unknown, number> {\n return refine(inner, (value) => value >= minimum, message);\n}\n\nexport function max(\n inner: Schema<unknown, number>,\n maximum: number,\n message: string = `Expected a number less than or equal to ${maximum}`,\n): Schema<unknown, number> {\n return refine(inner, (value) => value <= maximum, message);\n}\n\nexport function nonEmptyString(\n message: string = \"Expected a non-empty string\",\n): Schema<unknown, string> {\n return refine(string(), (value) => value.length > 0, message);\n}\n\nexport function nonBlankString(\n message: string = \"Expected a non-blank string\",\n): Schema<unknown, string> {\n return refine(string(), (value) => value.trim().length > 0, message);\n}\n\nexport function boolean(message: string = \"Expected a boolean\"): Schema<unknown, boolean> {\n return schema((value) => (isBoolean(value) ? success(value) : failure(message)));\n}\n\nexport function fn(message: string = \"Expected a function\"): Schema<unknown, Function> {\n return schema((value) => (isFunction(value) ? success(value) : failure(message)));\n}\n\nexport function instanceOf<T>(\n constructor: Constructor<T>,\n message: string = `Expected ${constructor.name}`,\n): Schema<unknown, T> {\n return schema((value) => (value instanceof constructor ? success(value) : failure(message)));\n}\n\nexport function literal<const TValue extends string | number | boolean | null | undefined>(\n expected: TValue,\n message: string = `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: string = `Expected one of ${values.map(String).join(\", \")}`,\n): Schema<unknown, TValues[number]> {\n return schema((value) => {\n const match = values.findIndex((item) => Object.is(item, value));\n\n return match === -1 ? failure(message) : success(values[match]);\n });\n}\n\nexport function union<const TSchemas extends readonly [Schema, ...Schema[]]>(\n schemas: TSchemas,\n message: string = \"Expected a union match\",\n): Schema<unknown, SchemaOutput<TSchemas[number]>> {\n return schema((value) => {\n for (const itemSchema of schemas) {\n const result = evaluate<TSchemas[number]>(itemSchema, value);\n\n if (!result.issues) {\n return success(result.value);\n }\n }\n\n return failure(message);\n });\n}\n\nexport function array(): Schema<unknown, unknown[]>;\nexport function array<TItem extends Schema>(\n itemSchema: TItem,\n message?: string,\n): Schema<unknown, SchemaOutput<TItem>[]>;\nexport function array<TItem extends Schema>(\n itemSchema?: TItem,\n message: string = \"Expected an array\",\n): Schema<unknown, unknown[]> {\n return schema((value) => {\n if (!Array.isArray(value)) {\n return failure(message);\n }\n\n if (itemSchema === undefined) {\n return success(value);\n }\n\n const output: SchemaOutput<TItem>[] = [];\n const issues: SchemaIssue[] = [];\n\n for (let index = 0; index < value.length; index++) {\n const result: SchemaResult<SchemaOutput<TItem>> = evaluate(itemSchema, value[index]);\n\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(index, issue)));\n } else {\n output.push(result.value);\n }\n }\n\n return issues.length > 0 ? { issues } : success(output);\n });\n}\n\nexport function object<TFields extends SchemaFields>(\n fields: TFields,\n message: string = \"Expected an object\",\n options: ObjectOptions = {},\n): Schema<unknown, ObjectOutput<TFields>> {\n return schema((value) => {\n if (!isObject(value) || Array.isArray(value)) {\n return failure(message);\n }\n\n // SAFETY: the object check above establishes key lookup; each field remains unknown until its schema validates it.\n // oxlint-disable-next-line anti-slop/no-unsafe-dictionary-type -- Temporary untrusted object at the schema parsing boundary.\n const input = value as Record<PropertyKey, unknown>;\n\n const output: Partial<{ -readonly [K in keyof TFields]: SchemaOutput<TFields[K]> }> = {};\n\n if (options.unknownKeys === \"passthrough\") {\n for (const key of Reflect.ownKeys(input)) {\n if (!Object.prototype.propertyIsEnumerable.call(input, key)) {\n continue;\n }\n\n Object.defineProperty(output, key, {\n value: input[key],\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n\n const issues: SchemaIssue[] = [];\n const fieldKeys = Object.keys(fields);\n\n if (options.unknownKeys === \"strict\") {\n for (const key of Object.keys(input)) {\n if (!fieldKeys.includes(key)) {\n issues.push({ message: \"Unexpected key\", path: [key] });\n }\n }\n }\n\n // SAFETY: these are the enumerable keys of the supplied field schema object.\n for (const key of fieldKeys as Array<keyof TFields & string>) {\n const hasOwnField = Object.prototype.hasOwnProperty.call(input, key);\n const result = evaluate(fields[key], hasOwnField ? input[key] : undefined);\n\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(key, issue)));\n } else if (hasOwnField || result.value !== undefined) {\n Object.defineProperty(output, key, {\n value: result.value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n\n // SAFETY: all schema fields have succeeded; absent optional fields are represented by undefined in ObjectOutput.\n return issues.length > 0 ? { issues } : success(output as ObjectOutput<TFields>);\n });\n}\n\nexport function strictObject<TFields extends SchemaFields>(\n fields: TFields,\n message: string = \"Expected an object\",\n): Schema<unknown, ObjectOutput<TFields>> {\n return object(fields, message, { unknownKeys: \"strict\" });\n}\n\nexport function looseObject<TFields extends SchemaFields>(\n fields: TFields,\n message: string = \"Expected an object\",\n): Schema<unknown, ObjectOutput<TFields>> {\n return object(fields, message, { unknownKeys: \"passthrough\" });\n}\n\nexport function record<TValue extends Schema>(\n valueSchema: TValue,\n message: string = \"Expected an object\",\n): Schema<unknown, Record<string, SchemaOutput<TValue>>> {\n return schema((value) => {\n if (!isObject(value) || Array.isArray(value)) {\n return failure(message);\n }\n\n const output: Record<string, SchemaOutput<TValue>> = {};\n const issues: SchemaIssue[] = [];\n\n for (const [key, item] of Object.entries(value)) {\n const result = evaluate(valueSchema, item);\n\n if (result.issues) {\n issues.push(...result.issues.map((issue: SchemaIssue) => withPath(key, issue)));\n } else {\n output[key] = result.value;\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 = evaluate(inner, value);\n\n return result;\n });\n}\n\nexport function defaulted<TSchema extends Schema>(\n inner: TSchema,\n defaultValue: SchemaOutput<TSchema>,\n): Schema<unknown, SchemaOutput<TSchema>> {\n return schema((value) => {\n if (value === undefined) {\n return success(defaultValue);\n }\n\n const result = evaluate(inner, value);\n\n return result;\n });\n}\n\nexport function defaultedWith<TSchema extends Schema>(\n inner: TSchema,\n createDefault: () => SchemaOutput<TSchema>,\n): Schema<unknown, SchemaOutput<TSchema>> {\n return schema((value) =>\n value === undefined ? success(createDefault()) : evaluate(inner, value),\n );\n}\n\nexport function refine<TSchema extends Schema, TOutput extends SchemaOutput<TSchema>>(\n inner: TSchema,\n predicate: (value: SchemaOutput<TSchema>) => value is TOutput,\n message?: string,\n): Schema<SchemaInput<TSchema>, TOutput>;\nexport function refine<TSchema extends Schema>(\n inner: TSchema,\n predicate: (value: SchemaOutput<TSchema>) => boolean,\n message?: string,\n): Schema<SchemaInput<TSchema>, SchemaOutput<TSchema>>;\nexport function refine<TSchema extends Schema>(\n inner: TSchema,\n predicate: (value: SchemaOutput<TSchema>) => boolean,\n message: string = \"Invalid value\",\n): Schema<SchemaInput<TSchema>, SchemaOutput<TSchema>> {\n return schema((value) => {\n const result = evaluate(inner, value);\n\n if (result.issues) {\n return result;\n }\n\n return predicate(result.value) ? result : failure(message);\n });\n}\n\nexport function transform<TSchema extends Schema, TOutput>(\n inner: TSchema,\n mapper: (value: SchemaOutput<TSchema>) => TOutput,\n): Schema<SchemaInput<TSchema>, TOutput> {\n return schema((value) => {\n const result = evaluate(inner, value);\n\n if (result.issues) {\n return result;\n }\n\n return success(mapper(result.value));\n });\n}\n\nexport function pipe<TLeft extends Schema, TRight extends Schema>(\n left: TLeft,\n right: TRight,\n): Schema<SchemaInput<TLeft>, SchemaOutput<TRight>> {\n return schema((value) => {\n const leftResult = evaluate(left, value);\n\n if (leftResult.issues) {\n return leftResult;\n }\n\n const rightResult = evaluate(right, leftResult.value);\n\n return rightResult;\n });\n}\n\nexport function extend<TBase extends SchemaFields, TExtension extends SchemaFields>(\n base: TBase,\n extension: TExtension,\n): Omit<TBase, keyof TExtension> & TExtension {\n return { ...base, ...extension };\n}\n\nexport function pick<TFields extends SchemaFields, const TKeys extends readonly (keyof TFields)[]>(\n fields: TFields,\n keys: TKeys,\n): Pick<TFields, TKeys[number]> {\n // SAFETY: each requested key is constrained to TFields and is copied with its corresponding schema.\n return Object.fromEntries(keys.map((key) => [key, fields[key]])) as Pick<TFields, TKeys[number]>;\n}\n\nexport function omit<TFields extends SchemaFields, const TKeys extends readonly (keyof TFields)[]>(\n fields: TFields,\n keys: TKeys,\n): Omit<TFields, TKeys[number]> {\n const result = { ...fields };\n\n for (const key of keys) {\n delete result[key];\n }\n\n return result;\n}\n\nexport function partial<TFields extends SchemaFields>(\n fields: TFields,\n): { readonly [TKey in keyof TFields]: Schema<unknown, SchemaOutput<TFields[TKey]> | undefined> } {\n const entries = Reflect.ownKeys(fields).map((key) => {\n // SAFETY: key is an own key of the supplied field schema object.\n return [key, optional(fields[key as keyof TFields])];\n });\n\n // SAFETY: each own field is preserved under its key and optional retains its output type while adding undefined.\n return Object.fromEntries(entries) as {\n readonly [TKey in keyof TFields]: Schema<unknown, SchemaOutput<TFields[TKey]> | undefined>;\n };\n}\n\nfunction evaluate<TSchema extends Schema>(\n inputSchema: TSchema,\n // oxlint-disable-next-line anti-slop/no-unknown-parameters -- This helper invokes the schema validator on untrusted input.\n value: unknown,\n): SchemaResult<SchemaOutput<TSchema>> {\n const result = inputSchema[\"~standard\"].validate(value);\n ensureSynchronous(result);\n\n // SAFETY: StandardSchemaV1 ties the validator success type to TSchema's declared output.\n return result as SchemaResult<SchemaOutput<TSchema>>;\n}\n\nfunction ensureSynchronous<T>(value: T | Promise<T>): asserts value is T {\n if (value instanceof Promise) {\n StandardSchemaAsyncValidationError.unsupported();\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 safeParse,\n safeParseSync,\n parse,\n parseSync,\n unknown,\n string,\n number,\n finite,\n integer,\n safeInteger,\n positiveNumber,\n nonNegativeNumber,\n positiveSafeInteger,\n nonNegativeSafeInteger,\n min,\n max,\n nonEmptyString,\n nonBlankString,\n boolean,\n fn,\n instanceOf,\n literal,\n picklist,\n union,\n array,\n object,\n strictObject,\n looseObject,\n record,\n optional,\n defaulted,\n defaultedWith,\n refine,\n transform,\n pipe,\n extend,\n pick,\n omit,\n partial,\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temelj/standard-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Standard Schema construction utilities.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,14 +19,15 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@standard-schema/spec": "^1.1.0"
|
|
22
|
+
"@standard-schema/spec": "^1.1.0",
|
|
23
|
+
"@temelj/value": "0.15.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
|
-
"@types/node": "
|
|
26
|
+
"@types/node": "26.6.5",
|
|
26
27
|
"shx": "^0.4.0",
|
|
27
|
-
"tsdown": "^0.
|
|
28
|
-
"typescript": "^
|
|
29
|
-
"vitest": "^
|
|
28
|
+
"tsdown": "^0.23.1",
|
|
29
|
+
"typescript": "^7.0.2",
|
|
30
|
+
"vitest": "^5.0.4"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"build": "tsdown",
|