@gunubin/vorm-core 0.1.0 → 0.3.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 +0 -146
- package/dist/index.d.cts +33 -66
- package/dist/index.d.ts +33 -66
- package/dist/index.js +0 -141
- 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,9 @@ 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,
|
|
29
26
|
validateAndCreate: () => validateAndCreate,
|
|
30
|
-
validateField: () => validateField,
|
|
31
|
-
validateForm: () => validateForm,
|
|
32
27
|
vo: () => vo
|
|
33
28
|
});
|
|
34
29
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -74,124 +69,6 @@ function createRule(code, validate) {
|
|
|
74
69
|
}));
|
|
75
70
|
}
|
|
76
71
|
|
|
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
72
|
// src/validate-and-create.ts
|
|
196
73
|
function validateAndCreate(value, rules, name) {
|
|
197
74
|
for (const rule of rules) {
|
|
@@ -209,34 +86,11 @@ function safeValidateAndCreate(value, rules) {
|
|
|
209
86
|
}
|
|
210
87
|
return { success: true, data: value };
|
|
211
88
|
}
|
|
212
|
-
|
|
213
|
-
// src/build-output-values.ts
|
|
214
|
-
function buildOutputValues(values, fields) {
|
|
215
|
-
const output = {};
|
|
216
|
-
for (const [name, fieldSchema] of Object.entries(fields)) {
|
|
217
|
-
let value = values[name];
|
|
218
|
-
const isEmpty = value === void 0 || value === null || value === "";
|
|
219
|
-
if (isEmpty) {
|
|
220
|
-
output[name] = void 0;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
if (fieldSchema.vo) {
|
|
224
|
-
value = fieldSchema.vo.create(value);
|
|
225
|
-
}
|
|
226
|
-
output[name] = value;
|
|
227
|
-
}
|
|
228
|
-
return output;
|
|
229
|
-
}
|
|
230
89
|
// Annotate the CommonJS export names for ESM import in node:
|
|
231
90
|
0 && (module.exports = {
|
|
232
91
|
VOValidationError,
|
|
233
|
-
buildOutputValues,
|
|
234
|
-
createField,
|
|
235
|
-
createFormSchema,
|
|
236
92
|
createRule,
|
|
237
93
|
safeValidateAndCreate,
|
|
238
94
|
validateAndCreate,
|
|
239
|
-
validateField,
|
|
240
|
-
validateForm,
|
|
241
95
|
vo
|
|
242
96
|
});
|
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,37 @@ 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
|
+
}
|
|
116
83
|
|
|
117
|
-
export { type Brand, type CreateResult, type
|
|
84
|
+
export { type Brand, type CreateResult, type Infer, StandardSchemaV1, type VODefinition, type VOLike, VOValidationError, type ValidationRule, createRule, safeValidateAndCreate, 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,37 @@ 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
|
+
}
|
|
116
83
|
|
|
117
|
-
export { type Brand, type CreateResult, type
|
|
84
|
+
export { type Brand, type CreateResult, type Infer, StandardSchemaV1, type VODefinition, type VOLike, VOValidationError, type ValidationRule, createRule, safeValidateAndCreate, 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) {
|
|
@@ -174,33 +56,10 @@ function safeValidateAndCreate(value, rules) {
|
|
|
174
56
|
}
|
|
175
57
|
return { success: true, data: value };
|
|
176
58
|
}
|
|
177
|
-
|
|
178
|
-
// src/build-output-values.ts
|
|
179
|
-
function buildOutputValues(values, fields) {
|
|
180
|
-
const output = {};
|
|
181
|
-
for (const [name, fieldSchema] of Object.entries(fields)) {
|
|
182
|
-
let value = values[name];
|
|
183
|
-
const isEmpty = value === void 0 || value === null || value === "";
|
|
184
|
-
if (isEmpty) {
|
|
185
|
-
output[name] = void 0;
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
if (fieldSchema.vo) {
|
|
189
|
-
value = fieldSchema.vo.create(value);
|
|
190
|
-
}
|
|
191
|
-
output[name] = value;
|
|
192
|
-
}
|
|
193
|
-
return output;
|
|
194
|
-
}
|
|
195
59
|
export {
|
|
196
60
|
VOValidationError,
|
|
197
|
-
buildOutputValues,
|
|
198
|
-
createField,
|
|
199
|
-
createFormSchema,
|
|
200
61
|
createRule,
|
|
201
62
|
safeValidateAndCreate,
|
|
202
63
|
validateAndCreate,
|
|
203
|
-
validateField,
|
|
204
|
-
validateForm,
|
|
205
64
|
vo
|
|
206
65
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gunubin/vorm-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Branded value object definitions with type-safe validation rules",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"form",
|
|
7
7
|
"validation",
|