@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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/dist/index.d.ts +2715 -0
  4. package/dist/index.es.js +1715 -0
  5. package/dist/index.es.js.map +1 -0
  6. package/package.json +70 -0
  7. package/src/index.ts +90 -0
  8. package/src/reform/ArrayHelper.ts +164 -0
  9. package/src/reform/Form.tsx +81 -0
  10. package/src/reform/FormManager.ts +494 -0
  11. package/src/reform/Reform.ts +15 -0
  12. package/src/reform/components/BaseCheckboxField.tsx +72 -0
  13. package/src/reform/components/BaseDateField.tsx +84 -0
  14. package/src/reform/components/BaseRadioField.tsx +72 -0
  15. package/src/reform/components/BaseSelectField.tsx +103 -0
  16. package/src/reform/components/BaseTextAreaField.tsx +87 -0
  17. package/src/reform/components/BaseTextField.tsx +135 -0
  18. package/src/reform/components/InputHTMLProps.tsx +89 -0
  19. package/src/reform/observers/observer.ts +131 -0
  20. package/src/reform/observers/observerPath.ts +327 -0
  21. package/src/reform/observers/useObservers.ts +232 -0
  22. package/src/reform/useForm.ts +246 -0
  23. package/src/reform/useFormContext.tsx +37 -0
  24. package/src/reform/useFormField.ts +75 -0
  25. package/src/reform/useRender.ts +12 -0
  26. package/src/yop/MessageProvider.ts +204 -0
  27. package/src/yop/Metadata.ts +304 -0
  28. package/src/yop/ObjectsUtil.ts +811 -0
  29. package/src/yop/TypesUtil.ts +148 -0
  30. package/src/yop/ValidationContext.ts +207 -0
  31. package/src/yop/Yop.ts +430 -0
  32. package/src/yop/constraints/CommonConstraints.ts +124 -0
  33. package/src/yop/constraints/Constraint.ts +135 -0
  34. package/src/yop/constraints/MinMaxConstraints.ts +53 -0
  35. package/src/yop/constraints/OneOfConstraint.ts +40 -0
  36. package/src/yop/constraints/TestConstraint.ts +176 -0
  37. package/src/yop/decorators/array.ts +157 -0
  38. package/src/yop/decorators/boolean.ts +69 -0
  39. package/src/yop/decorators/date.ts +73 -0
  40. package/src/yop/decorators/email.ts +66 -0
  41. package/src/yop/decorators/file.ts +69 -0
  42. package/src/yop/decorators/id.ts +35 -0
  43. package/src/yop/decorators/ignored.ts +40 -0
  44. package/src/yop/decorators/instance.ts +110 -0
  45. package/src/yop/decorators/number.ts +73 -0
  46. package/src/yop/decorators/string.ts +90 -0
  47. package/src/yop/decorators/test.ts +41 -0
  48. 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
+