@gunubin/vorm-core 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 +2 -0
- package/dist/index.cjs +22 -143
- package/dist/index.d.cts +37 -66
- package/dist/index.d.ts +37 -66
- package/dist/index.js +21 -138
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @gunubin/vorm-core
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@gunubin/vorm-core)
|
|
4
|
+
|
|
3
5
|
VO-first form validation core — branded types, field schemas, and validation logic.
|
|
4
6
|
|
|
5
7
|
Part of the [vorm](https://github.com/gunubin/vorm) monorepo.
|
package/dist/index.cjs
CHANGED
|
@@ -21,14 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
VOValidationError: () => VOValidationError,
|
|
24
|
-
buildOutputValues: () => buildOutputValues,
|
|
25
|
-
createField: () => createField,
|
|
26
|
-
createFormSchema: () => createFormSchema,
|
|
27
24
|
createRule: () => createRule,
|
|
28
25
|
safeValidateAndCreate: () => safeValidateAndCreate,
|
|
26
|
+
toStandardSchema: () => toStandardSchema,
|
|
29
27
|
validateAndCreate: () => validateAndCreate,
|
|
30
|
-
validateField: () => validateField,
|
|
31
|
-
validateForm: () => validateForm,
|
|
32
28
|
vo: () => vo
|
|
33
29
|
});
|
|
34
30
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -74,124 +70,6 @@ function createRule(code, validate) {
|
|
|
74
70
|
}));
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
// src/create-field.ts
|
|
78
|
-
function createField(voOrConfig, options) {
|
|
79
|
-
if (voOrConfig && "create" in voOrConfig && typeof voOrConfig.create === "function") {
|
|
80
|
-
let factory2 = function(config2 = {}) {
|
|
81
|
-
return {
|
|
82
|
-
vo: voDef,
|
|
83
|
-
required: config2.required ?? false,
|
|
84
|
-
messages: mergeMessages(definitionMessages2, config2.messages),
|
|
85
|
-
rules: [...voDef.rules],
|
|
86
|
-
parse: parse2,
|
|
87
|
-
format: format2
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
var factory = factory2;
|
|
91
|
-
const voDef = voOrConfig;
|
|
92
|
-
const definitionMessages2 = options?.messages;
|
|
93
|
-
const parse2 = options?.parse;
|
|
94
|
-
const format2 = options?.format;
|
|
95
|
-
return factory2;
|
|
96
|
-
}
|
|
97
|
-
const config = voOrConfig ?? {};
|
|
98
|
-
const definitionMessages = config.messages;
|
|
99
|
-
const definitionRules = config.rules ?? [];
|
|
100
|
-
const parse = config.parse;
|
|
101
|
-
const format = config.format;
|
|
102
|
-
function factory(factoryConfig = {}) {
|
|
103
|
-
return {
|
|
104
|
-
vo: null,
|
|
105
|
-
required: factoryConfig.required ?? false,
|
|
106
|
-
messages: mergeMessages(definitionMessages, factoryConfig.messages),
|
|
107
|
-
rules: [...definitionRules],
|
|
108
|
-
parse,
|
|
109
|
-
format
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
return factory;
|
|
113
|
-
}
|
|
114
|
-
function mergeMessages(definition, factory) {
|
|
115
|
-
if (!definition && !factory) return {};
|
|
116
|
-
if (!definition) return factory;
|
|
117
|
-
if (!factory) return definition;
|
|
118
|
-
if (typeof factory === "function") return factory;
|
|
119
|
-
if (typeof definition === "function") return factory;
|
|
120
|
-
return { ...definition, ...factory };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/create-form-schema.ts
|
|
124
|
-
function createFormSchema(config) {
|
|
125
|
-
return {
|
|
126
|
-
fields: config.fields,
|
|
127
|
-
messages: config.messages,
|
|
128
|
-
resolver: config.resolver
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// src/resolve-message.ts
|
|
133
|
-
var DEFAULT_MESSAGES = {
|
|
134
|
-
REQUIRED: "This field is required"
|
|
135
|
-
};
|
|
136
|
-
function resolveMessage(code, ...messageSources) {
|
|
137
|
-
for (const source of messageSources) {
|
|
138
|
-
if (!source) continue;
|
|
139
|
-
if (typeof source === "function") {
|
|
140
|
-
const result = source({ code });
|
|
141
|
-
if (result) return result;
|
|
142
|
-
} else {
|
|
143
|
-
const msg = source[code];
|
|
144
|
-
if (msg) return msg;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return DEFAULT_MESSAGES[code] ?? code;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// src/validate-field.ts
|
|
151
|
-
function validateField(value, fieldSchema, formMessages) {
|
|
152
|
-
if (fieldSchema.required) {
|
|
153
|
-
if (value === void 0 || value === null || value === "") {
|
|
154
|
-
const code = "REQUIRED";
|
|
155
|
-
const message = resolveMessage(code, formMessages, fieldSchema.messages);
|
|
156
|
-
return { code, message };
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
if (value === void 0 || value === null || value === "") {
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
for (const rule of fieldSchema.rules) {
|
|
164
|
-
if (!rule.validate(value)) {
|
|
165
|
-
const message = resolveMessage(rule.code, formMessages, fieldSchema.messages);
|
|
166
|
-
return { code: rule.code, message };
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// src/validate-form.ts
|
|
173
|
-
function validateForm(values, schema) {
|
|
174
|
-
const errors = {};
|
|
175
|
-
for (const [name, fieldSchema] of Object.entries(schema.fields)) {
|
|
176
|
-
const value = values[name];
|
|
177
|
-
const formMessages = schema.messages?.[name];
|
|
178
|
-
const error = validateField(value, fieldSchema, formMessages);
|
|
179
|
-
if (error) {
|
|
180
|
-
errors[name] = error;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (Object.keys(errors).length > 0) {
|
|
184
|
-
return errors;
|
|
185
|
-
}
|
|
186
|
-
if (schema.resolver) {
|
|
187
|
-
const resolverErrors = schema.resolver(values);
|
|
188
|
-
if (resolverErrors) {
|
|
189
|
-
return { ...errors, ...resolverErrors };
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return errors;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
73
|
// src/validate-and-create.ts
|
|
196
74
|
function validateAndCreate(value, rules, name) {
|
|
197
75
|
for (const rule of rules) {
|
|
@@ -210,33 +88,34 @@ function safeValidateAndCreate(value, rules) {
|
|
|
210
88
|
return { success: true, data: value };
|
|
211
89
|
}
|
|
212
90
|
|
|
213
|
-
// src/
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
91
|
+
// src/standard-schema.ts
|
|
92
|
+
function toStandardSchema(voDef) {
|
|
93
|
+
return {
|
|
94
|
+
"~standard": {
|
|
95
|
+
version: 1,
|
|
96
|
+
vendor: "vorm",
|
|
97
|
+
validate(value) {
|
|
98
|
+
const issues = [];
|
|
99
|
+
for (const rule of voDef.rules) {
|
|
100
|
+
if (!rule.validate(value)) {
|
|
101
|
+
issues.push({ message: rule.code });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (issues.length > 0) {
|
|
105
|
+
return { issues };
|
|
106
|
+
}
|
|
107
|
+
return { value };
|
|
108
|
+
},
|
|
109
|
+
types: void 0
|
|
225
110
|
}
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
return output;
|
|
111
|
+
};
|
|
229
112
|
}
|
|
230
113
|
// Annotate the CommonJS export names for ESM import in node:
|
|
231
114
|
0 && (module.exports = {
|
|
232
115
|
VOValidationError,
|
|
233
|
-
buildOutputValues,
|
|
234
|
-
createField,
|
|
235
|
-
createFormSchema,
|
|
236
116
|
createRule,
|
|
237
117
|
safeValidateAndCreate,
|
|
118
|
+
toStandardSchema,
|
|
238
119
|
validateAndCreate,
|
|
239
|
-
validateField,
|
|
240
|
-
validateForm,
|
|
241
120
|
vo
|
|
242
121
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -23,46 +23,10 @@ type VODefinition<TInput, TBrand extends string, TCodes extends string = string>
|
|
|
23
23
|
type Infer<D> = D extends VODefinition<infer T, infer B, any> ? Brand<T, B> : D extends {
|
|
24
24
|
create: (input: any) => infer R;
|
|
25
25
|
} ? R : never;
|
|
26
|
-
type ErrorMessageMap<C extends string = string> = {
|
|
27
|
-
[K in C]?: string;
|
|
28
|
-
};
|
|
29
|
-
type ErrorMessageFn<C extends string = string> = (error: {
|
|
30
|
-
code: C;
|
|
31
|
-
}) => string;
|
|
32
|
-
type ErrorMessages<C extends string = string> = ErrorMessageMap<C> | ErrorMessageFn<C>;
|
|
33
26
|
type VOLike<TInput, TOutput, TCodes extends string = string> = {
|
|
34
27
|
rules: ValidationRule<TInput, TCodes>[];
|
|
35
28
|
create: (input: TInput) => TOutput;
|
|
36
29
|
};
|
|
37
|
-
type FieldSchema<T, TOutput, TRequired extends boolean, TCodes extends string = string> = {
|
|
38
|
-
vo: VOLike<T, TOutput, TCodes> | null;
|
|
39
|
-
required: TRequired;
|
|
40
|
-
messages: ErrorMessages<TCodes | (TRequired extends true ? 'REQUIRED' : never)>;
|
|
41
|
-
rules: ValidationRule<T, TCodes>[];
|
|
42
|
-
parse?: (raw: string) => T;
|
|
43
|
-
format?: (value: T) => string;
|
|
44
|
-
};
|
|
45
|
-
type FieldError = {
|
|
46
|
-
code: string;
|
|
47
|
-
message: string;
|
|
48
|
-
};
|
|
49
|
-
type FormErrors = Record<string, FieldError>;
|
|
50
|
-
type FormSchemaConfig<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
51
|
-
fields: TFields;
|
|
52
|
-
messages?: Record<string, ErrorMessages>;
|
|
53
|
-
resolver?: (values: FormInputValues<TFields>) => FormErrors | null;
|
|
54
|
-
};
|
|
55
|
-
type FormSchema<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
56
|
-
fields: TFields;
|
|
57
|
-
messages?: Record<string, ErrorMessages>;
|
|
58
|
-
resolver?: (values: FormInputValues<TFields>) => FormErrors | null;
|
|
59
|
-
};
|
|
60
|
-
type FormInputValues<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
61
|
-
[K in keyof TFields]: TFields[K] extends FieldSchema<infer TInput, any, infer TRequired, any> ? TRequired extends true ? TInput : TInput | undefined : never;
|
|
62
|
-
};
|
|
63
|
-
type FormOutputValues<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
64
|
-
[K in keyof TFields]: TFields[K] extends FieldSchema<any, infer TOutput, infer TRequired, any> ? TRequired extends true ? TOutput : TOutput | undefined : never;
|
|
65
|
-
};
|
|
66
30
|
|
|
67
31
|
declare class VOValidationError extends Error {
|
|
68
32
|
readonly brand: string;
|
|
@@ -75,34 +39,6 @@ declare function vo<B extends string, T = string, C extends string = string>(bra
|
|
|
75
39
|
type RuleCreator<T, O, C extends string = string> = O extends void ? () => ValidationRule<T, C> : (option: O) => ValidationRule<T, C>;
|
|
76
40
|
declare function createRule<T, O = void, C extends string = string>(code: C, validate: (value: T, option: O) => boolean): RuleCreator<T, O, C>;
|
|
77
41
|
|
|
78
|
-
type FieldFactory<TInput, TOutput, TCodes extends string> = {
|
|
79
|
-
(config: {
|
|
80
|
-
required: true;
|
|
81
|
-
messages?: ErrorMessages<TCodes | 'REQUIRED'>;
|
|
82
|
-
}): FieldSchema<TInput, TOutput, true, TCodes>;
|
|
83
|
-
(config?: {
|
|
84
|
-
required?: false;
|
|
85
|
-
messages?: ErrorMessages<TCodes>;
|
|
86
|
-
}): FieldSchema<TInput, TOutput, false, TCodes>;
|
|
87
|
-
};
|
|
88
|
-
declare function createField<TInput, TOutput, TCodes extends string>(vo: VOLike<TInput, TOutput, TCodes>, options?: {
|
|
89
|
-
messages?: ErrorMessages<TCodes>;
|
|
90
|
-
parse?: (raw: string) => TInput;
|
|
91
|
-
format?: (value: TInput) => string;
|
|
92
|
-
}): FieldFactory<TInput, TOutput, TCodes>;
|
|
93
|
-
declare function createField<T, TOut = T, TCodes extends string = string>(config?: {
|
|
94
|
-
rules?: ValidationRule<T, TCodes>[];
|
|
95
|
-
messages?: ErrorMessages<TCodes>;
|
|
96
|
-
parse?: (raw: string) => T;
|
|
97
|
-
format?: (value: T) => string;
|
|
98
|
-
}): FieldFactory<T, TOut, TCodes>;
|
|
99
|
-
|
|
100
|
-
declare function createFormSchema<TFields extends Record<string, FieldSchema<any, any, boolean, any>>>(config: FormSchemaConfig<TFields>): FormSchema<TFields>;
|
|
101
|
-
|
|
102
|
-
declare function validateField<T>(value: T | undefined | null, fieldSchema: FieldSchema<T, any, boolean, any>, formMessages?: ErrorMessages): FieldError | null;
|
|
103
|
-
|
|
104
|
-
declare function validateForm<TFields extends Record<string, FieldSchema<any, any, boolean, any>>>(values: FormInputValues<TFields>, schema: FormSchema<TFields>): FormErrors;
|
|
105
|
-
|
|
106
42
|
declare function validateAndCreate<T>(value: T, rules: readonly {
|
|
107
43
|
code: string;
|
|
108
44
|
validate: (value: T) => boolean;
|
|
@@ -112,6 +48,41 @@ declare function safeValidateAndCreate<T>(value: T, rules: readonly {
|
|
|
112
48
|
validate: (value: T) => boolean;
|
|
113
49
|
}[]): CreateResult<T>;
|
|
114
50
|
|
|
115
|
-
|
|
51
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
52
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
53
|
+
}
|
|
54
|
+
declare namespace StandardSchemaV1 {
|
|
55
|
+
interface Props<Input = unknown, Output = Input> {
|
|
56
|
+
readonly version: 1;
|
|
57
|
+
readonly vendor: string;
|
|
58
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
59
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
60
|
+
}
|
|
61
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
62
|
+
interface SuccessResult<Output> {
|
|
63
|
+
readonly value: Output;
|
|
64
|
+
readonly issues?: undefined;
|
|
65
|
+
}
|
|
66
|
+
interface FailureResult {
|
|
67
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
68
|
+
}
|
|
69
|
+
interface Issue {
|
|
70
|
+
readonly message: string;
|
|
71
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
72
|
+
}
|
|
73
|
+
interface PathSegment {
|
|
74
|
+
readonly key: PropertyKey;
|
|
75
|
+
}
|
|
76
|
+
interface Types<Input = unknown, Output = Input> {
|
|
77
|
+
readonly input?: Input;
|
|
78
|
+
readonly output?: Output;
|
|
79
|
+
}
|
|
80
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
|
|
81
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wraps a VODefinition as a Standard Schema v1 compliant object.
|
|
85
|
+
*/
|
|
86
|
+
declare function toStandardSchema<TInput, TBrand extends string, TCodes extends string>(voDef: VODefinition<TInput, TBrand, TCodes>): StandardSchemaV1<TInput, Brand<TInput, TBrand>>;
|
|
116
87
|
|
|
117
|
-
export { type Brand, type CreateResult, type
|
|
88
|
+
export { type Brand, type CreateResult, type Infer, StandardSchemaV1, type VODefinition, type VOLike, VOValidationError, type ValidationRule, createRule, safeValidateAndCreate, toStandardSchema, validateAndCreate, vo };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,46 +23,10 @@ type VODefinition<TInput, TBrand extends string, TCodes extends string = string>
|
|
|
23
23
|
type Infer<D> = D extends VODefinition<infer T, infer B, any> ? Brand<T, B> : D extends {
|
|
24
24
|
create: (input: any) => infer R;
|
|
25
25
|
} ? R : never;
|
|
26
|
-
type ErrorMessageMap<C extends string = string> = {
|
|
27
|
-
[K in C]?: string;
|
|
28
|
-
};
|
|
29
|
-
type ErrorMessageFn<C extends string = string> = (error: {
|
|
30
|
-
code: C;
|
|
31
|
-
}) => string;
|
|
32
|
-
type ErrorMessages<C extends string = string> = ErrorMessageMap<C> | ErrorMessageFn<C>;
|
|
33
26
|
type VOLike<TInput, TOutput, TCodes extends string = string> = {
|
|
34
27
|
rules: ValidationRule<TInput, TCodes>[];
|
|
35
28
|
create: (input: TInput) => TOutput;
|
|
36
29
|
};
|
|
37
|
-
type FieldSchema<T, TOutput, TRequired extends boolean, TCodes extends string = string> = {
|
|
38
|
-
vo: VOLike<T, TOutput, TCodes> | null;
|
|
39
|
-
required: TRequired;
|
|
40
|
-
messages: ErrorMessages<TCodes | (TRequired extends true ? 'REQUIRED' : never)>;
|
|
41
|
-
rules: ValidationRule<T, TCodes>[];
|
|
42
|
-
parse?: (raw: string) => T;
|
|
43
|
-
format?: (value: T) => string;
|
|
44
|
-
};
|
|
45
|
-
type FieldError = {
|
|
46
|
-
code: string;
|
|
47
|
-
message: string;
|
|
48
|
-
};
|
|
49
|
-
type FormErrors = Record<string, FieldError>;
|
|
50
|
-
type FormSchemaConfig<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
51
|
-
fields: TFields;
|
|
52
|
-
messages?: Record<string, ErrorMessages>;
|
|
53
|
-
resolver?: (values: FormInputValues<TFields>) => FormErrors | null;
|
|
54
|
-
};
|
|
55
|
-
type FormSchema<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
56
|
-
fields: TFields;
|
|
57
|
-
messages?: Record<string, ErrorMessages>;
|
|
58
|
-
resolver?: (values: FormInputValues<TFields>) => FormErrors | null;
|
|
59
|
-
};
|
|
60
|
-
type FormInputValues<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
61
|
-
[K in keyof TFields]: TFields[K] extends FieldSchema<infer TInput, any, infer TRequired, any> ? TRequired extends true ? TInput : TInput | undefined : never;
|
|
62
|
-
};
|
|
63
|
-
type FormOutputValues<TFields extends Record<string, FieldSchema<any, any, boolean, any>>> = {
|
|
64
|
-
[K in keyof TFields]: TFields[K] extends FieldSchema<any, infer TOutput, infer TRequired, any> ? TRequired extends true ? TOutput : TOutput | undefined : never;
|
|
65
|
-
};
|
|
66
30
|
|
|
67
31
|
declare class VOValidationError extends Error {
|
|
68
32
|
readonly brand: string;
|
|
@@ -75,34 +39,6 @@ declare function vo<B extends string, T = string, C extends string = string>(bra
|
|
|
75
39
|
type RuleCreator<T, O, C extends string = string> = O extends void ? () => ValidationRule<T, C> : (option: O) => ValidationRule<T, C>;
|
|
76
40
|
declare function createRule<T, O = void, C extends string = string>(code: C, validate: (value: T, option: O) => boolean): RuleCreator<T, O, C>;
|
|
77
41
|
|
|
78
|
-
type FieldFactory<TInput, TOutput, TCodes extends string> = {
|
|
79
|
-
(config: {
|
|
80
|
-
required: true;
|
|
81
|
-
messages?: ErrorMessages<TCodes | 'REQUIRED'>;
|
|
82
|
-
}): FieldSchema<TInput, TOutput, true, TCodes>;
|
|
83
|
-
(config?: {
|
|
84
|
-
required?: false;
|
|
85
|
-
messages?: ErrorMessages<TCodes>;
|
|
86
|
-
}): FieldSchema<TInput, TOutput, false, TCodes>;
|
|
87
|
-
};
|
|
88
|
-
declare function createField<TInput, TOutput, TCodes extends string>(vo: VOLike<TInput, TOutput, TCodes>, options?: {
|
|
89
|
-
messages?: ErrorMessages<TCodes>;
|
|
90
|
-
parse?: (raw: string) => TInput;
|
|
91
|
-
format?: (value: TInput) => string;
|
|
92
|
-
}): FieldFactory<TInput, TOutput, TCodes>;
|
|
93
|
-
declare function createField<T, TOut = T, TCodes extends string = string>(config?: {
|
|
94
|
-
rules?: ValidationRule<T, TCodes>[];
|
|
95
|
-
messages?: ErrorMessages<TCodes>;
|
|
96
|
-
parse?: (raw: string) => T;
|
|
97
|
-
format?: (value: T) => string;
|
|
98
|
-
}): FieldFactory<T, TOut, TCodes>;
|
|
99
|
-
|
|
100
|
-
declare function createFormSchema<TFields extends Record<string, FieldSchema<any, any, boolean, any>>>(config: FormSchemaConfig<TFields>): FormSchema<TFields>;
|
|
101
|
-
|
|
102
|
-
declare function validateField<T>(value: T | undefined | null, fieldSchema: FieldSchema<T, any, boolean, any>, formMessages?: ErrorMessages): FieldError | null;
|
|
103
|
-
|
|
104
|
-
declare function validateForm<TFields extends Record<string, FieldSchema<any, any, boolean, any>>>(values: FormInputValues<TFields>, schema: FormSchema<TFields>): FormErrors;
|
|
105
|
-
|
|
106
42
|
declare function validateAndCreate<T>(value: T, rules: readonly {
|
|
107
43
|
code: string;
|
|
108
44
|
validate: (value: T) => boolean;
|
|
@@ -112,6 +48,41 @@ declare function safeValidateAndCreate<T>(value: T, rules: readonly {
|
|
|
112
48
|
validate: (value: T) => boolean;
|
|
113
49
|
}[]): CreateResult<T>;
|
|
114
50
|
|
|
115
|
-
|
|
51
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
52
|
+
readonly '~standard': StandardSchemaV1.Props<Input, Output>;
|
|
53
|
+
}
|
|
54
|
+
declare namespace StandardSchemaV1 {
|
|
55
|
+
interface Props<Input = unknown, Output = Input> {
|
|
56
|
+
readonly version: 1;
|
|
57
|
+
readonly vendor: string;
|
|
58
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
59
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
60
|
+
}
|
|
61
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
62
|
+
interface SuccessResult<Output> {
|
|
63
|
+
readonly value: Output;
|
|
64
|
+
readonly issues?: undefined;
|
|
65
|
+
}
|
|
66
|
+
interface FailureResult {
|
|
67
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
68
|
+
}
|
|
69
|
+
interface Issue {
|
|
70
|
+
readonly message: string;
|
|
71
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
72
|
+
}
|
|
73
|
+
interface PathSegment {
|
|
74
|
+
readonly key: PropertyKey;
|
|
75
|
+
}
|
|
76
|
+
interface Types<Input = unknown, Output = Input> {
|
|
77
|
+
readonly input?: Input;
|
|
78
|
+
readonly output?: Output;
|
|
79
|
+
}
|
|
80
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
|
|
81
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wraps a VODefinition as a Standard Schema v1 compliant object.
|
|
85
|
+
*/
|
|
86
|
+
declare function toStandardSchema<TInput, TBrand extends string, TCodes extends string>(voDef: VODefinition<TInput, TBrand, TCodes>): StandardSchemaV1<TInput, Brand<TInput, TBrand>>;
|
|
116
87
|
|
|
117
|
-
export { type Brand, type CreateResult, type
|
|
88
|
+
export { type Brand, type CreateResult, type Infer, StandardSchemaV1, type VODefinition, type VOLike, VOValidationError, type ValidationRule, createRule, safeValidateAndCreate, toStandardSchema, validateAndCreate, vo };
|
package/dist/index.js
CHANGED
|
@@ -39,124 +39,6 @@ function createRule(code, validate) {
|
|
|
39
39
|
}));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
// src/create-field.ts
|
|
43
|
-
function createField(voOrConfig, options) {
|
|
44
|
-
if (voOrConfig && "create" in voOrConfig && typeof voOrConfig.create === "function") {
|
|
45
|
-
let factory2 = function(config2 = {}) {
|
|
46
|
-
return {
|
|
47
|
-
vo: voDef,
|
|
48
|
-
required: config2.required ?? false,
|
|
49
|
-
messages: mergeMessages(definitionMessages2, config2.messages),
|
|
50
|
-
rules: [...voDef.rules],
|
|
51
|
-
parse: parse2,
|
|
52
|
-
format: format2
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
var factory = factory2;
|
|
56
|
-
const voDef = voOrConfig;
|
|
57
|
-
const definitionMessages2 = options?.messages;
|
|
58
|
-
const parse2 = options?.parse;
|
|
59
|
-
const format2 = options?.format;
|
|
60
|
-
return factory2;
|
|
61
|
-
}
|
|
62
|
-
const config = voOrConfig ?? {};
|
|
63
|
-
const definitionMessages = config.messages;
|
|
64
|
-
const definitionRules = config.rules ?? [];
|
|
65
|
-
const parse = config.parse;
|
|
66
|
-
const format = config.format;
|
|
67
|
-
function factory(factoryConfig = {}) {
|
|
68
|
-
return {
|
|
69
|
-
vo: null,
|
|
70
|
-
required: factoryConfig.required ?? false,
|
|
71
|
-
messages: mergeMessages(definitionMessages, factoryConfig.messages),
|
|
72
|
-
rules: [...definitionRules],
|
|
73
|
-
parse,
|
|
74
|
-
format
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return factory;
|
|
78
|
-
}
|
|
79
|
-
function mergeMessages(definition, factory) {
|
|
80
|
-
if (!definition && !factory) return {};
|
|
81
|
-
if (!definition) return factory;
|
|
82
|
-
if (!factory) return definition;
|
|
83
|
-
if (typeof factory === "function") return factory;
|
|
84
|
-
if (typeof definition === "function") return factory;
|
|
85
|
-
return { ...definition, ...factory };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// src/create-form-schema.ts
|
|
89
|
-
function createFormSchema(config) {
|
|
90
|
-
return {
|
|
91
|
-
fields: config.fields,
|
|
92
|
-
messages: config.messages,
|
|
93
|
-
resolver: config.resolver
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// src/resolve-message.ts
|
|
98
|
-
var DEFAULT_MESSAGES = {
|
|
99
|
-
REQUIRED: "This field is required"
|
|
100
|
-
};
|
|
101
|
-
function resolveMessage(code, ...messageSources) {
|
|
102
|
-
for (const source of messageSources) {
|
|
103
|
-
if (!source) continue;
|
|
104
|
-
if (typeof source === "function") {
|
|
105
|
-
const result = source({ code });
|
|
106
|
-
if (result) return result;
|
|
107
|
-
} else {
|
|
108
|
-
const msg = source[code];
|
|
109
|
-
if (msg) return msg;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return DEFAULT_MESSAGES[code] ?? code;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/validate-field.ts
|
|
116
|
-
function validateField(value, fieldSchema, formMessages) {
|
|
117
|
-
if (fieldSchema.required) {
|
|
118
|
-
if (value === void 0 || value === null || value === "") {
|
|
119
|
-
const code = "REQUIRED";
|
|
120
|
-
const message = resolveMessage(code, formMessages, fieldSchema.messages);
|
|
121
|
-
return { code, message };
|
|
122
|
-
}
|
|
123
|
-
} else {
|
|
124
|
-
if (value === void 0 || value === null || value === "") {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
for (const rule of fieldSchema.rules) {
|
|
129
|
-
if (!rule.validate(value)) {
|
|
130
|
-
const message = resolveMessage(rule.code, formMessages, fieldSchema.messages);
|
|
131
|
-
return { code: rule.code, message };
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// src/validate-form.ts
|
|
138
|
-
function validateForm(values, schema) {
|
|
139
|
-
const errors = {};
|
|
140
|
-
for (const [name, fieldSchema] of Object.entries(schema.fields)) {
|
|
141
|
-
const value = values[name];
|
|
142
|
-
const formMessages = schema.messages?.[name];
|
|
143
|
-
const error = validateField(value, fieldSchema, formMessages);
|
|
144
|
-
if (error) {
|
|
145
|
-
errors[name] = error;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (Object.keys(errors).length > 0) {
|
|
149
|
-
return errors;
|
|
150
|
-
}
|
|
151
|
-
if (schema.resolver) {
|
|
152
|
-
const resolverErrors = schema.resolver(values);
|
|
153
|
-
if (resolverErrors) {
|
|
154
|
-
return { ...errors, ...resolverErrors };
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return errors;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
42
|
// src/validate-and-create.ts
|
|
161
43
|
function validateAndCreate(value, rules, name) {
|
|
162
44
|
for (const rule of rules) {
|
|
@@ -175,32 +57,33 @@ function safeValidateAndCreate(value, rules) {
|
|
|
175
57
|
return { success: true, data: value };
|
|
176
58
|
}
|
|
177
59
|
|
|
178
|
-
// src/
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
60
|
+
// src/standard-schema.ts
|
|
61
|
+
function toStandardSchema(voDef) {
|
|
62
|
+
return {
|
|
63
|
+
"~standard": {
|
|
64
|
+
version: 1,
|
|
65
|
+
vendor: "vorm",
|
|
66
|
+
validate(value) {
|
|
67
|
+
const issues = [];
|
|
68
|
+
for (const rule of voDef.rules) {
|
|
69
|
+
if (!rule.validate(value)) {
|
|
70
|
+
issues.push({ message: rule.code });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (issues.length > 0) {
|
|
74
|
+
return { issues };
|
|
75
|
+
}
|
|
76
|
+
return { value };
|
|
77
|
+
},
|
|
78
|
+
types: void 0
|
|
190
79
|
}
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
return output;
|
|
80
|
+
};
|
|
194
81
|
}
|
|
195
82
|
export {
|
|
196
83
|
VOValidationError,
|
|
197
|
-
buildOutputValues,
|
|
198
|
-
createField,
|
|
199
|
-
createFormSchema,
|
|
200
84
|
createRule,
|
|
201
85
|
safeValidateAndCreate,
|
|
86
|
+
toStandardSchema,
|
|
202
87
|
validateAndCreate,
|
|
203
|
-
validateField,
|
|
204
|
-
validateForm,
|
|
205
88
|
vo
|
|
206
89
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gunubin/vorm-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Branded value object definitions with type-safe validation rules",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"form",
|
|
7
7
|
"validation",
|