@4riders/reform 3.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/dist/index.d.ts +2715 -0
- package/dist/index.es.js +1715 -0
- package/dist/index.es.js.map +1 -0
- package/package.json +70 -0
- package/src/index.ts +90 -0
- package/src/reform/ArrayHelper.ts +164 -0
- package/src/reform/Form.tsx +81 -0
- package/src/reform/FormManager.ts +494 -0
- package/src/reform/Reform.ts +15 -0
- package/src/reform/components/BaseCheckboxField.tsx +72 -0
- package/src/reform/components/BaseDateField.tsx +84 -0
- package/src/reform/components/BaseRadioField.tsx +72 -0
- package/src/reform/components/BaseSelectField.tsx +103 -0
- package/src/reform/components/BaseTextAreaField.tsx +87 -0
- package/src/reform/components/BaseTextField.tsx +135 -0
- package/src/reform/components/InputHTMLProps.tsx +89 -0
- package/src/reform/observers/observer.ts +131 -0
- package/src/reform/observers/observerPath.ts +327 -0
- package/src/reform/observers/useObservers.ts +232 -0
- package/src/reform/useForm.ts +246 -0
- package/src/reform/useFormContext.tsx +37 -0
- package/src/reform/useFormField.ts +75 -0
- package/src/reform/useRender.ts +12 -0
- package/src/yop/MessageProvider.ts +204 -0
- package/src/yop/Metadata.ts +304 -0
- package/src/yop/ObjectsUtil.ts +811 -0
- package/src/yop/TypesUtil.ts +148 -0
- package/src/yop/ValidationContext.ts +207 -0
- package/src/yop/Yop.ts +430 -0
- package/src/yop/constraints/CommonConstraints.ts +124 -0
- package/src/yop/constraints/Constraint.ts +135 -0
- package/src/yop/constraints/MinMaxConstraints.ts +53 -0
- package/src/yop/constraints/OneOfConstraint.ts +40 -0
- package/src/yop/constraints/TestConstraint.ts +176 -0
- package/src/yop/decorators/array.ts +157 -0
- package/src/yop/decorators/boolean.ts +69 -0
- package/src/yop/decorators/date.ts +73 -0
- package/src/yop/decorators/email.ts +66 -0
- package/src/yop/decorators/file.ts +69 -0
- package/src/yop/decorators/id.ts +35 -0
- package/src/yop/decorators/ignored.ts +40 -0
- package/src/yop/decorators/instance.ts +110 -0
- package/src/yop/decorators/number.ts +73 -0
- package/src/yop/decorators/string.ts +90 -0
- package/src/yop/decorators/test.ts +41 -0
- package/src/yop/decorators/time.ts +112 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Type for a class constructor of a given type.
|
|
4
|
+
* @template Type - The type of the class instance.
|
|
5
|
+
* @ignore
|
|
6
|
+
*/
|
|
7
|
+
export type ClassConstructor<Type> = new (...args: any) => NonNullable<Type>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Checks if a class constructor is a subclass of another.
|
|
11
|
+
* @template T - The parent class type.
|
|
12
|
+
* @param value - The class constructor to check.
|
|
13
|
+
* @param parent - The parent class constructor.
|
|
14
|
+
* @returns True if value is a subclass of parent.
|
|
15
|
+
* @ignore
|
|
16
|
+
*/
|
|
17
|
+
export const isSubclassOf = <T>(value: ClassConstructor<any>, parent: ClassConstructor<T>): value is ClassConstructor<T> =>
|
|
18
|
+
value.prototype instanceof parent
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Type for a constructor of a given type, including primitive constructors.
|
|
22
|
+
* @template Type - The type to construct.
|
|
23
|
+
* @ignore
|
|
24
|
+
*/
|
|
25
|
+
export type Constructor<Type = unknown> =
|
|
26
|
+
Type extends unknown ? ClassConstructor<Type> | StringConstructor | BooleanConstructor | NumberConstructor :
|
|
27
|
+
[Type] extends [string | null | undefined] ? StringConstructor :
|
|
28
|
+
[Type] extends [boolean | null | undefined] ? BooleanConstructor :
|
|
29
|
+
[Type] extends [number | null | undefined] ? NumberConstructor :
|
|
30
|
+
ClassConstructor<Type>
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Type for extracting the element type from an array type.
|
|
34
|
+
* @template ArrayType - The array type.
|
|
35
|
+
* @ignore
|
|
36
|
+
*/
|
|
37
|
+
export type ArrayElementType<ArrayType> = ArrayType extends Array<infer ElementType> ? ElementType : never
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Checks if a value is a boolean.
|
|
41
|
+
* @template T - The boolean type.
|
|
42
|
+
* @param value - The value to check.
|
|
43
|
+
* @returns True if value is boolean.
|
|
44
|
+
* @ignore
|
|
45
|
+
*/
|
|
46
|
+
export const isBoolean = <T extends boolean>(value: any): value is T => typeof value === "boolean"
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a value is a valid number (not NaN).
|
|
49
|
+
* @template T - The number type.
|
|
50
|
+
* @param value - The value to check.
|
|
51
|
+
* @returns True if value is a valid number.
|
|
52
|
+
* @ignore
|
|
53
|
+
*/
|
|
54
|
+
export const isNumber = <T extends number>(value: any): value is T => typeof value === "number" && !isNaN(value)
|
|
55
|
+
/**
|
|
56
|
+
* Checks if a value is a string.
|
|
57
|
+
* @template T - The string type.
|
|
58
|
+
* @param value - The value to check.
|
|
59
|
+
* @returns True if value is a string.
|
|
60
|
+
* @ignore
|
|
61
|
+
*/
|
|
62
|
+
export const isString = <T extends string>(value: any): value is T => typeof value === "string"
|
|
63
|
+
/**
|
|
64
|
+
* Checks if a value is a non-null object (not an array).
|
|
65
|
+
* @template T - The object type.
|
|
66
|
+
* @param value - The value to check.
|
|
67
|
+
* @returns True if value is an object.
|
|
68
|
+
* @ignore
|
|
69
|
+
*/
|
|
70
|
+
export const isObject = <T extends object>(value: any): value is T => value != null && !Array.isArray(value) && typeof value === "object"
|
|
71
|
+
/**
|
|
72
|
+
* Checks if a value is a function.
|
|
73
|
+
* @template T - The function type.
|
|
74
|
+
* @param value - The value to check.
|
|
75
|
+
* @returns True if value is a function.
|
|
76
|
+
* @ignore
|
|
77
|
+
*/
|
|
78
|
+
export const isFunction = <T extends Function>(value: any): value is T => typeof value === "function"
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a value is a valid Date object.
|
|
81
|
+
* @template T - The Date type.
|
|
82
|
+
* @param value - The value to check.
|
|
83
|
+
* @returns True if value is a valid Date.
|
|
84
|
+
* @ignore
|
|
85
|
+
*/
|
|
86
|
+
export const isDate = <T extends Date>(value: any): value is T => value instanceof Date && !isNaN(value.getTime())
|
|
87
|
+
/**
|
|
88
|
+
* Checks if a value is a File object.
|
|
89
|
+
* @template T - The File type.
|
|
90
|
+
* @param value - The value to check.
|
|
91
|
+
* @returns True if value is a File.
|
|
92
|
+
* @ignore
|
|
93
|
+
*/
|
|
94
|
+
export const isFile = <T extends File>(value: any): value is T => value instanceof File
|
|
95
|
+
/**
|
|
96
|
+
* Checks if a value is a RegExp object.
|
|
97
|
+
* @param value - The value to check.
|
|
98
|
+
* @returns True if value is a RegExp.
|
|
99
|
+
* @ignore
|
|
100
|
+
*/
|
|
101
|
+
export const isRegExp = (value: any): value is RegExp => value instanceof RegExp
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Checks if a value is an array of strings.
|
|
105
|
+
* @template T - The string type.
|
|
106
|
+
* @param value - The value to check.
|
|
107
|
+
* @returns True if value is an array of strings.
|
|
108
|
+
* @ignore
|
|
109
|
+
*/
|
|
110
|
+
export const isStringArray = <T extends string>(value: any): value is Array<T> => Array.isArray(value) && value.every(isString)
|
|
111
|
+
/**
|
|
112
|
+
* Checks if a value is an array of booleans.
|
|
113
|
+
* @template T - The boolean type.
|
|
114
|
+
* @param value - The value to check.
|
|
115
|
+
* @returns True if value is an array of booleans.
|
|
116
|
+
* @ignore
|
|
117
|
+
*/
|
|
118
|
+
export const isBooleanArray = <T extends boolean>(value: any): value is Array<T> => Array.isArray(value) && value.every(isBoolean)
|
|
119
|
+
/**
|
|
120
|
+
* Checks if a value is an array of numbers.
|
|
121
|
+
* @template T - The number type.
|
|
122
|
+
* @param value - The value to check.
|
|
123
|
+
* @returns True if value is an array of numbers.
|
|
124
|
+
* @ignore
|
|
125
|
+
*/
|
|
126
|
+
export const isNumberArray = <T extends number>(value: any): value is Array<T> => Array.isArray(value) && value.every(isNumber)
|
|
127
|
+
/**
|
|
128
|
+
* Checks if a value is an array of Date objects.
|
|
129
|
+
* @template T - The Date type.
|
|
130
|
+
* @param value - The value to check.
|
|
131
|
+
* @returns True if value is an array of Dates.
|
|
132
|
+
* @ignore
|
|
133
|
+
*/
|
|
134
|
+
export const isDateArray = <T extends Date>(value: any): value is Array<T> => Array.isArray(value) && value.every(isDate)
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a value is a Promise.
|
|
138
|
+
* @template T - The Promise type.
|
|
139
|
+
* @param value - The value to check.
|
|
140
|
+
* @returns True if value is a Promise.
|
|
141
|
+
* @ignore
|
|
142
|
+
*/
|
|
143
|
+
export const isPromise = <T>(value: any): value is Promise<T> => (
|
|
144
|
+
value != null &&
|
|
145
|
+
typeof value === "object" &&
|
|
146
|
+
"then" in value && typeof value["then"] === "function" &&
|
|
147
|
+
"catch" in value && typeof value["catch"] === "function"
|
|
148
|
+
)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { ConstraintMessage } from "./constraints/Constraint"
|
|
2
|
+
import { joinPath, Path } from "./ObjectsUtil"
|
|
3
|
+
import { ValidationForm, ValidationSettings, Yop } from "./Yop"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type representing the validation group or groups being currently validated. `undefined` means the default group.
|
|
7
|
+
* @category Validation Management
|
|
8
|
+
*/
|
|
9
|
+
export type Group = string | ((string | undefined)[])
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The types of validation status levels. "pending" and "unavailable" are only used for asynchronous validations.
|
|
13
|
+
* "pending" indicates that the asynchronous validation is in progress, while "unavailable" indicates that the validation
|
|
14
|
+
* couldn't be performed (e.g., due to an unreachable server).
|
|
15
|
+
* @see {@link ValidationStatus}
|
|
16
|
+
* @category Validation Management
|
|
17
|
+
*/
|
|
18
|
+
export type Level = "info" | "warning" | "error" | "pending" | "unavailable"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Interface representing the status of a validation, including its level, path, value, kind, code, constraint, and message.
|
|
22
|
+
* This is used to track the results of validation operations and provide feedback to the user.
|
|
23
|
+
* @category Validation Management
|
|
24
|
+
*/
|
|
25
|
+
export type ValidationStatus = {
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The severity level of the validation status, or the status of asynchronous validation.
|
|
29
|
+
* @see {@link Level}
|
|
30
|
+
*/
|
|
31
|
+
level: Level
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The path to the validated value, represented as a string (e.g., "users[0].address.street").
|
|
35
|
+
*/
|
|
36
|
+
path: string
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The value that was validated.
|
|
40
|
+
*/
|
|
41
|
+
value: any
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The kind of validation (e.g., "string", "number", "array"), used for message resolution.
|
|
45
|
+
*/
|
|
46
|
+
kind: string
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A code representing the specific validation type (e.g., "required", "min"), used for message resolution.
|
|
50
|
+
*/
|
|
51
|
+
code: string
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The constraint value that caused the validation error (e.g., `true` for a "required" constraint, `1` for a "min" constraint).
|
|
55
|
+
*/
|
|
56
|
+
constraint: any
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The resolved message for this validation status, which can be displayed to the user.
|
|
60
|
+
*/
|
|
61
|
+
message: ConstraintMessage
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Interface representing the context of a validation operation, providing access to the value being validated, its path,
|
|
66
|
+
* parent context, root context, settings, form, and a store for sharing data across validations.
|
|
67
|
+
*
|
|
68
|
+
* @template Value - The type of the value being validated.
|
|
69
|
+
* @template Parent - The type of the parent object containing the value.
|
|
70
|
+
* @category Validation Management
|
|
71
|
+
*/
|
|
72
|
+
export interface ValidationContext<Value, Parent = unknown> {
|
|
73
|
+
|
|
74
|
+
readonly kind: string
|
|
75
|
+
|
|
76
|
+
readonly value: Value
|
|
77
|
+
readonly path: Path
|
|
78
|
+
|
|
79
|
+
readonly parent: Parent
|
|
80
|
+
readonly parentContext: ValidationContext<Parent> | undefined
|
|
81
|
+
|
|
82
|
+
getRoot<T>(): T | undefined
|
|
83
|
+
readonly rootContext: ValidationContext<unknown> | undefined
|
|
84
|
+
|
|
85
|
+
readonly settings: ValidationSettings | undefined
|
|
86
|
+
|
|
87
|
+
readonly form: ValidationForm | undefined
|
|
88
|
+
|
|
89
|
+
readonly store: Map<string, any>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @ignore
|
|
94
|
+
*/
|
|
95
|
+
export const UndefinedParent = Object.freeze(Object.create(null))
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Internal implementation of the ValidationContext interface, used for managing validation state and providing utility methods
|
|
99
|
+
* for creating child contexts and statuses.
|
|
100
|
+
* @ignore
|
|
101
|
+
*/
|
|
102
|
+
export class InternalValidationContext<Value, Parent = unknown> implements ValidationContext<Value, Parent> {
|
|
103
|
+
|
|
104
|
+
readonly yop: Yop
|
|
105
|
+
|
|
106
|
+
readonly kind: string
|
|
107
|
+
|
|
108
|
+
readonly value: Value
|
|
109
|
+
readonly path: Path
|
|
110
|
+
|
|
111
|
+
readonly parentContext: InternalValidationContext<Parent> | undefined
|
|
112
|
+
readonly rootContext: InternalValidationContext<unknown> | undefined
|
|
113
|
+
|
|
114
|
+
readonly settings: ValidationSettings | undefined
|
|
115
|
+
|
|
116
|
+
readonly store: Map<string, any>
|
|
117
|
+
|
|
118
|
+
readonly statuses: Map<string, ValidationStatus>
|
|
119
|
+
|
|
120
|
+
constructor(props: {
|
|
121
|
+
yop: Yop
|
|
122
|
+
kind: string
|
|
123
|
+
value: Value
|
|
124
|
+
key?: string | number | undefined
|
|
125
|
+
parentContext?: InternalValidationContext<Parent> | undefined
|
|
126
|
+
rootContext?: InternalValidationContext<unknown> | undefined
|
|
127
|
+
userContext?: unknown | undefined
|
|
128
|
+
statuses?: Map<string, ValidationStatus>
|
|
129
|
+
settings?: ValidationSettings
|
|
130
|
+
}) {
|
|
131
|
+
if (props.parentContext != null && props.key == null)
|
|
132
|
+
throw new Error("key must be provided when parentContext is provided")
|
|
133
|
+
|
|
134
|
+
this.yop = props.yop
|
|
135
|
+
this.kind = props.kind
|
|
136
|
+
this.value = props.value
|
|
137
|
+
this.parentContext = props.parentContext
|
|
138
|
+
this.rootContext = props.rootContext
|
|
139
|
+
this.settings = props.settings
|
|
140
|
+
this.statuses = props.statuses ?? new Map()
|
|
141
|
+
|
|
142
|
+
this.store = props.yop.store
|
|
143
|
+
|
|
144
|
+
this.path = props.key == null ? [] : (props.parentContext?.path.concat(props.key) ?? [props.key])
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
ignored() {
|
|
148
|
+
return this.settings?.ignore?.(this.path) ?? false
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get parent() {
|
|
152
|
+
return this.parentContext?.value || UndefinedParent as Parent
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
get groups() {
|
|
156
|
+
return this.settings?.groups
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get form() {
|
|
160
|
+
return this.settings?.form
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
getRoot<T>() {
|
|
164
|
+
return this.rootContext?.value as T | undefined
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
createChildContext(props: {
|
|
168
|
+
kind: string
|
|
169
|
+
value: Value
|
|
170
|
+
key: string | number
|
|
171
|
+
}) {
|
|
172
|
+
return new InternalValidationContext({
|
|
173
|
+
yop: this.yop,
|
|
174
|
+
kind: props.kind,
|
|
175
|
+
value: props.value,
|
|
176
|
+
key: props.key,
|
|
177
|
+
parentContext: this,
|
|
178
|
+
rootContext: this.rootContext ?? this,
|
|
179
|
+
settings: this.settings,
|
|
180
|
+
statuses: this.statuses
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
createStatus(code: string, constraint: any, message?: ConstraintMessage, level: Level = "error"): ValidationStatus {
|
|
185
|
+
return {
|
|
186
|
+
level,
|
|
187
|
+
path: joinPath(this.path),
|
|
188
|
+
value: this.value,
|
|
189
|
+
kind: this.kind,
|
|
190
|
+
code,
|
|
191
|
+
constraint,
|
|
192
|
+
message: this.yop.messageProvider.getMessage(this, code, constraint, message, level),
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
setStatus(code: string, constraint: any, message?: ConstraintMessage, level: Level = "error"): ValidationStatus {
|
|
197
|
+
const status = this.createStatus(code, constraint, message, level)
|
|
198
|
+
this.statuses.set(status.path, status)
|
|
199
|
+
return status
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @ignore
|
|
205
|
+
*/
|
|
206
|
+
export type ValuedContext<Value, Parent> = InternalValidationContext<NonNullable<Value>, Parent>
|
|
207
|
+
|