@ng-formworks/core 17.2.7 → 17.4.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/LICENSE +21 -0
- package/README.md +836 -0
- package/esm2022/lib/framework-library/framework-library.service.mjs +175 -0
- package/esm2022/lib/framework-library/framework.mjs +15 -0
- package/esm2022/lib/framework-library/no-framework.component.mjs +18 -0
- package/esm2022/lib/framework-library/no-framework.module.mjs +27 -0
- package/esm2022/lib/framework-library/no.framework.mjs +19 -0
- package/esm2022/lib/json-schema-form.component.mjs +765 -0
- package/esm2022/lib/json-schema-form.module.mjs +26 -0
- package/esm2022/lib/json-schema-form.service.mjs +679 -0
- package/esm2022/lib/locale/de-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/en-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/es-validation-messages.mjs +57 -0
- package/esm2022/lib/locale/fr-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/index.mjs +8 -0
- package/esm2022/lib/locale/it-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/pt-validation-messages.mjs +60 -0
- package/esm2022/lib/locale/zh-validation-messages.mjs +60 -0
- package/esm2022/lib/shared/convert-schema-to-draft6.function.mjs +300 -0
- package/esm2022/lib/shared/form-group.functions.mjs +442 -0
- package/esm2022/lib/shared/format-regex.constants.mjs +54 -0
- package/esm2022/lib/shared/index.mjs +12 -0
- package/esm2022/lib/shared/json-schema.functions.mjs +784 -0
- package/esm2022/lib/shared/json.validators.mjs +884 -0
- package/esm2022/lib/shared/jsonpointer.functions.mjs +1026 -0
- package/esm2022/lib/shared/layout.functions.mjs +1154 -0
- package/esm2022/lib/shared/merge-schemas.function.mjs +345 -0
- package/esm2022/lib/shared/utility.functions.mjs +380 -0
- package/esm2022/lib/shared/validator.functions.mjs +584 -0
- package/esm2022/lib/widget-library/add-reference.component.mjs +61 -0
- package/esm2022/lib/widget-library/button.component.mjs +72 -0
- package/esm2022/lib/widget-library/checkbox.component.mjs +105 -0
- package/esm2022/lib/widget-library/checkboxes.component.mjs +147 -0
- package/esm2022/lib/widget-library/file.component.mjs +35 -0
- package/esm2022/lib/widget-library/hidden.component.mjs +54 -0
- package/esm2022/lib/widget-library/index.mjs +55 -0
- package/esm2022/lib/widget-library/input.component.mjs +119 -0
- package/esm2022/lib/widget-library/message.component.mjs +38 -0
- package/esm2022/lib/widget-library/none.component.mjs +21 -0
- package/esm2022/lib/widget-library/number.component.mjs +123 -0
- package/esm2022/lib/widget-library/one-of.component.mjs +35 -0
- package/esm2022/lib/widget-library/orderable.directive.mjs +123 -0
- package/esm2022/lib/widget-library/radios.component.mjs +153 -0
- package/esm2022/lib/widget-library/root.component.mjs +79 -0
- package/esm2022/lib/widget-library/section.component.mjs +199 -0
- package/esm2022/lib/widget-library/select-framework.component.mjs +51 -0
- package/esm2022/lib/widget-library/select-widget.component.mjs +46 -0
- package/esm2022/lib/widget-library/select.component.mjs +150 -0
- package/esm2022/lib/widget-library/submit.component.mjs +82 -0
- package/esm2022/lib/widget-library/tab.component.mjs +41 -0
- package/esm2022/lib/widget-library/tabs.component.mjs +108 -0
- package/esm2022/lib/widget-library/template.component.mjs +46 -0
- package/esm2022/lib/widget-library/textarea.component.mjs +104 -0
- package/esm2022/lib/widget-library/widget-library.module.mjs +42 -0
- package/esm2022/lib/widget-library/widget-library.service.mjs +226 -0
- package/esm2022/ng-formworks-core.mjs +5 -0
- package/esm2022/public_api.mjs +13 -0
- package/fesm2022/ng-formworks-core.mjs +10149 -0
- package/fesm2022/ng-formworks-core.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/framework-library/framework-library.service.d.ts +55 -0
- package/lib/framework-library/framework.d.ts +13 -0
- package/lib/framework-library/no-framework.component.d.ts +8 -0
- package/lib/framework-library/no-framework.module.d.ts +9 -0
- package/lib/framework-library/no.framework.d.ts +10 -0
- package/lib/json-schema-form.component.d.ts +218 -0
- package/lib/json-schema-form.module.d.ts +11 -0
- package/lib/json-schema-form.service.d.ts +115 -0
- package/lib/locale/de-validation-messages.d.ts +1 -0
- package/lib/locale/en-validation-messages.d.ts +1 -0
- package/lib/locale/es-validation-messages.d.ts +1 -0
- package/lib/locale/fr-validation-messages.d.ts +1 -0
- package/{src/lib/locale/index.ts → lib/locale/index.d.ts} +7 -7
- package/lib/locale/it-validation-messages.d.ts +1 -0
- package/lib/locale/pt-validation-messages.d.ts +1 -0
- package/lib/locale/zh-validation-messages.d.ts +1 -0
- package/lib/shared/convert-schema-to-draft6.function.d.ts +21 -0
- package/lib/shared/form-group.functions.d.ts +100 -0
- package/lib/shared/format-regex.constants.d.ts +19 -0
- package/lib/shared/index.d.ts +9 -0
- package/lib/shared/json-schema.functions.d.ts +193 -0
- package/lib/shared/json.validators.d.ts +441 -0
- package/lib/shared/jsonpointer.functions.d.ts +416 -0
- package/lib/shared/layout.functions.d.ts +83 -0
- package/lib/shared/merge-schemas.function.d.ts +19 -0
- package/lib/shared/utility.functions.d.ts +165 -0
- package/{src/lib/shared/validator.functions.ts → lib/shared/validator.functions.d.ts} +364 -601
- package/lib/widget-library/add-reference.component.d.ts +20 -0
- package/lib/widget-library/button.component.d.ts +21 -0
- package/lib/widget-library/checkbox.component.d.ts +24 -0
- package/lib/widget-library/checkboxes.component.d.ts +24 -0
- package/lib/widget-library/file.component.d.ts +21 -0
- package/lib/widget-library/hidden.component.d.ts +19 -0
- package/{src/lib/widget-library/index.ts → lib/widget-library/index.d.ts} +47 -56
- package/lib/widget-library/input.component.d.ts +22 -0
- package/lib/widget-library/message.component.d.ts +15 -0
- package/lib/widget-library/none.component.d.ts +8 -0
- package/lib/widget-library/number.component.d.ts +25 -0
- package/lib/widget-library/one-of.component.d.ts +21 -0
- package/lib/widget-library/orderable.directive.d.ts +41 -0
- package/lib/widget-library/radios.component.d.ts +23 -0
- package/lib/widget-library/root.component.d.ts +17 -0
- package/lib/widget-library/section.component.d.ts +19 -0
- package/lib/widget-library/select-framework.component.d.ts +18 -0
- package/lib/widget-library/select-widget.component.d.ts +18 -0
- package/lib/widget-library/select.component.d.ts +24 -0
- package/lib/widget-library/submit.component.d.ts +24 -0
- package/lib/widget-library/tab.component.d.ts +14 -0
- package/lib/widget-library/tabs.component.d.ts +20 -0
- package/lib/widget-library/template.component.d.ts +18 -0
- package/lib/widget-library/textarea.component.d.ts +21 -0
- package/lib/widget-library/widget-library.module.d.ts +31 -0
- package/lib/widget-library/widget-library.service.d.ts +22 -0
- package/package.json +64 -53
- package/{src/public_api.ts → public_api.d.ts} +9 -21
- package/karma.conf.js +0 -46
- package/ng-package.json +0 -11
- package/src/lib/framework-library/framework-library.service.ts +0 -195
- package/src/lib/framework-library/framework.ts +0 -11
- package/src/lib/framework-library/no-framework.component.html +0 -2
- package/src/lib/framework-library/no-framework.component.ts +0 -11
- package/src/lib/framework-library/no-framework.module.ts +0 -18
- package/src/lib/framework-library/no.framework.ts +0 -11
- package/src/lib/json-schema-form.component.html +0 -7
- package/src/lib/json-schema-form.component.ts +0 -809
- package/src/lib/json-schema-form.module.ts +0 -17
- package/src/lib/json-schema-form.service.ts +0 -907
- package/src/lib/locale/de-validation-messages.ts +0 -58
- package/src/lib/locale/en-validation-messages.ts +0 -58
- package/src/lib/locale/es-validation-messages.ts +0 -55
- package/src/lib/locale/fr-validation-messages.ts +0 -58
- package/src/lib/locale/it-validation-messages.ts +0 -58
- package/src/lib/locale/pt-validation-messages.ts +0 -58
- package/src/lib/locale/zh-validation-messages.ts +0 -58
- package/src/lib/locale-dates/en-US.ts +0 -5
- package/src/lib/shared/convert-schema-to-draft6.function.ts +0 -321
- package/src/lib/shared/form-group.functions.ts +0 -522
- package/src/lib/shared/format-regex.constants.ts +0 -73
- package/src/lib/shared/index.ts +0 -40
- package/src/lib/shared/json-schema.functions.ts +0 -788
- package/src/lib/shared/json.validators.ts +0 -878
- package/src/lib/shared/jsonpointer.functions.ts +0 -1012
- package/src/lib/shared/jspointer.functions.json.spec.ts +0 -103
- package/src/lib/shared/layout.functions.ts +0 -1233
- package/src/lib/shared/merge-schemas.function.ts +0 -329
- package/src/lib/shared/utility.functions.ts +0 -373
- package/src/lib/shared/validator.functions.spec.ts +0 -55
- package/src/lib/widget-library/add-reference.component.ts +0 -59
- package/src/lib/widget-library/button.component.ts +0 -54
- package/src/lib/widget-library/checkbox.component.ts +0 -74
- package/src/lib/widget-library/checkboxes.component.ts +0 -104
- package/src/lib/widget-library/file.component.ts +0 -36
- package/src/lib/widget-library/hidden.component.ts +0 -39
- package/src/lib/widget-library/input.component.ts +0 -76
- package/src/lib/widget-library/message.component.ts +0 -29
- package/src/lib/widget-library/none.component.ts +0 -12
- package/src/lib/widget-library/number.component.ts +0 -79
- package/src/lib/widget-library/one-of.component.ts +0 -36
- package/src/lib/widget-library/orderable.directive.ts +0 -130
- package/src/lib/widget-library/radios.component.ts +0 -101
- package/src/lib/widget-library/root.component.ts +0 -78
- package/src/lib/widget-library/section.component.ts +0 -133
- package/src/lib/widget-library/select-framework.component.ts +0 -50
- package/src/lib/widget-library/select-widget.component.ts +0 -46
- package/src/lib/widget-library/select.component.ts +0 -96
- package/src/lib/widget-library/submit.component.ts +0 -68
- package/src/lib/widget-library/tab.component.ts +0 -29
- package/src/lib/widget-library/tabs.component.ts +0 -83
- package/src/lib/widget-library/template.component.ts +0 -52
- package/src/lib/widget-library/textarea.component.ts +0 -68
- package/src/lib/widget-library/widget-library.module.ts +0 -13
- package/src/lib/widget-library/widget-library.service.ts +0 -234
- package/src/test.ts +0 -18
- package/tsconfig.lib.json +0 -25
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -17
- package/tslint.json +0 -11
|
@@ -1,878 +0,0 @@
|
|
|
1
|
-
import isEqual from 'lodash/isEqual';
|
|
2
|
-
import {
|
|
3
|
-
_executeAsyncValidators,
|
|
4
|
-
_executeValidators,
|
|
5
|
-
_mergeErrors,
|
|
6
|
-
_mergeObjects,
|
|
7
|
-
AsyncIValidatorFn,
|
|
8
|
-
getType,
|
|
9
|
-
hasValue,
|
|
10
|
-
isArray,
|
|
11
|
-
isBoolean,
|
|
12
|
-
isDefined,
|
|
13
|
-
isEmpty,
|
|
14
|
-
isNumber,
|
|
15
|
-
isString,
|
|
16
|
-
isType,
|
|
17
|
-
IValidatorFn,
|
|
18
|
-
SchemaPrimitiveType,
|
|
19
|
-
toJavaScriptType,
|
|
20
|
-
toObservable,
|
|
21
|
-
xor
|
|
22
|
-
} from './validator.functions';
|
|
23
|
-
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
|
|
24
|
-
import { forEachCopy } from './utility.functions';
|
|
25
|
-
import { forkJoin } from 'rxjs';
|
|
26
|
-
import { JsonSchemaFormatNames, jsonSchemaFormatTests } from './format-regex.constants';
|
|
27
|
-
import { map } from 'rxjs/operators';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 'JsonValidators' class
|
|
33
|
-
*
|
|
34
|
-
* Provides an extended set of validators to be used by form controls,
|
|
35
|
-
* compatible with standard JSON Schema validation options.
|
|
36
|
-
* http://json-schema.org/latest/json-schema-validation.html
|
|
37
|
-
*
|
|
38
|
-
* Note: This library is designed as a drop-in replacement for the Angular
|
|
39
|
-
* Validators library, and except for one small breaking change to the 'pattern'
|
|
40
|
-
* validator (described below) it can even be imported as a substitute, like so:
|
|
41
|
-
*
|
|
42
|
-
* import { JsonValidators as Validators } from 'json-validators';
|
|
43
|
-
*
|
|
44
|
-
* and it should work with existing code as a complete replacement.
|
|
45
|
-
*
|
|
46
|
-
* The one exception is the 'pattern' validator, which has been changed to
|
|
47
|
-
* matche partial values by default (the standard 'pattern' validator wrapped
|
|
48
|
-
* all patterns in '^' and '$', forcing them to always match an entire value).
|
|
49
|
-
* However, the old behavior can be restored by simply adding '^' and '$'
|
|
50
|
-
* around your patterns, or by passing an optional second parameter of TRUE.
|
|
51
|
-
* This change is to make the 'pattern' validator match the behavior of a
|
|
52
|
-
* JSON Schema pattern, which allows partial matches, rather than the behavior
|
|
53
|
-
* of an HTML input control pattern, which does not.
|
|
54
|
-
*
|
|
55
|
-
* This library replaces Angular's validators and combination functions
|
|
56
|
-
* with the following validators and transformation functions:
|
|
57
|
-
*
|
|
58
|
-
* Validators:
|
|
59
|
-
* For all formControls: required (*), type, enum, const
|
|
60
|
-
* For text formControls: minLength (*), maxLength (*), pattern (*), format
|
|
61
|
-
* For numeric formControls: maximum, exclusiveMaximum,
|
|
62
|
-
* minimum, exclusiveMinimum, multipleOf
|
|
63
|
-
* For formGroup objects: minProperties, maxProperties, dependencies
|
|
64
|
-
* For formArray arrays: minItems, maxItems, uniqueItems, contains
|
|
65
|
-
* Not used by JSON Schema: min (*), max (*), requiredTrue (*), email (*)
|
|
66
|
-
* (Validators originally included with Angular are maked with (*).)
|
|
67
|
-
*
|
|
68
|
-
* NOTE / TODO: The dependencies validator is not complete.
|
|
69
|
-
* NOTE / TODO: The contains validator is not complete.
|
|
70
|
-
*
|
|
71
|
-
* Validators not used by JSON Schema (but included for compatibility)
|
|
72
|
-
* and their JSON Schema equivalents:
|
|
73
|
-
*
|
|
74
|
-
* Angular validator | JSON Schema equivalent
|
|
75
|
-
* ------------------|-----------------------
|
|
76
|
-
* min(number) | minimum(number)
|
|
77
|
-
* max(number) | maximum(number)
|
|
78
|
-
* requiredTrue() | const(true)
|
|
79
|
-
* email() | format('email')
|
|
80
|
-
*
|
|
81
|
-
* Validator transformation functions:
|
|
82
|
-
* composeAnyOf, composeOneOf, composeAllOf, composeNot
|
|
83
|
-
* (Angular's original combination funciton, 'compose', is also included for
|
|
84
|
-
* backward compatibility, though it is functionally equivalent to composeAllOf,
|
|
85
|
-
* asside from its more generic error message.)
|
|
86
|
-
*
|
|
87
|
-
* All validators have also been extended to accept an optional second argument
|
|
88
|
-
* which, if passed a TRUE value, causes the validator to perform the opposite
|
|
89
|
-
* of its original finction. (This is used internally to enable 'not' and
|
|
90
|
-
* 'composeOneOf' to function and return useful error messages.)
|
|
91
|
-
*
|
|
92
|
-
* The 'required' validator has also been overloaded so that if called with
|
|
93
|
-
* a boolean parameter (or no parameters) it returns the original validator
|
|
94
|
-
* function (rather than executing it). However, if it is called with an
|
|
95
|
-
* AbstractControl parameter (as was previously required), it behaves
|
|
96
|
-
* exactly as before.
|
|
97
|
-
*
|
|
98
|
-
* This enables all validators (including 'required') to be constructed in
|
|
99
|
-
* exactly the same way, so they can be automatically applied using the
|
|
100
|
-
* equivalent key names and values taken directly from a JSON Schema.
|
|
101
|
-
*
|
|
102
|
-
* This source code is partially derived from Angular,
|
|
103
|
-
* which is Copyright (c) 2014-2017 Google, Inc.
|
|
104
|
-
* Use of this source code is therefore governed by the same MIT-style license
|
|
105
|
-
* that can be found in the LICENSE file at https://angular.io/license
|
|
106
|
-
*
|
|
107
|
-
* Original Angular Validators:
|
|
108
|
-
* https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts
|
|
109
|
-
*/
|
|
110
|
-
export class JsonValidators {
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Validator functions:
|
|
114
|
-
*
|
|
115
|
-
* For all formControls: required, type, enum, const
|
|
116
|
-
* For text formControls: minLength, maxLength, pattern, format
|
|
117
|
-
* For numeric formControls: maximum, exclusiveMaximum,
|
|
118
|
-
* minimum, exclusiveMinimum, multipleOf
|
|
119
|
-
* For formGroup objects: minProperties, maxProperties, dependencies
|
|
120
|
-
* For formArray arrays: minItems, maxItems, uniqueItems, contains
|
|
121
|
-
*
|
|
122
|
-
* TODO: finish dependencies validator
|
|
123
|
-
*/
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 'required' validator
|
|
127
|
-
*
|
|
128
|
-
* This validator is overloaded, compared to the default required validator.
|
|
129
|
-
* If called with no parameters, or TRUE, this validator returns the
|
|
130
|
-
* 'required' validator function (rather than executing it). This matches
|
|
131
|
-
* the behavior of all other validators in this library.
|
|
132
|
-
*
|
|
133
|
-
* If this validator is called with an AbstractControl parameter
|
|
134
|
-
* (as was previously required) it behaves the same as Angular's default
|
|
135
|
-
* required validator, and returns an error if the control is empty.
|
|
136
|
-
*
|
|
137
|
-
* Old behavior: (if input type = AbstractControl)
|
|
138
|
-
* // {AbstractControl} control - required control
|
|
139
|
-
* // {{[key: string]: boolean}} - returns error message if no input
|
|
140
|
-
*
|
|
141
|
-
* New behavior: (if no input, or input type = boolean)
|
|
142
|
-
* // {boolean = true} required? - true to validate, false to disable
|
|
143
|
-
* // {IValidatorFn} - returns the 'required' validator function itself
|
|
144
|
-
*/
|
|
145
|
-
static required(input: AbstractControl): ValidationErrors|null;
|
|
146
|
-
static required(input?: boolean): IValidatorFn;
|
|
147
|
-
|
|
148
|
-
static required(input?: AbstractControl|boolean): ValidationErrors|null|IValidatorFn {
|
|
149
|
-
if (input === undefined) { input = true; }
|
|
150
|
-
switch (input) {
|
|
151
|
-
case true: // Return required function (do not execute it yet)
|
|
152
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
153
|
-
if (invert) { return null; } // if not required, always return valid
|
|
154
|
-
return hasValue(control.value) ? null : { 'required': true };
|
|
155
|
-
};
|
|
156
|
-
case false: // Do nothing (if field is not required, it is always valid)
|
|
157
|
-
return JsonValidators.nullValidator;
|
|
158
|
-
default: // Execute required function
|
|
159
|
-
return hasValue((<AbstractControl>input).value) ? null : { 'required': true };
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* 'type' validator
|
|
165
|
-
*
|
|
166
|
-
* Requires a control to only accept values of a specified type,
|
|
167
|
-
* or one of an array of types.
|
|
168
|
-
*
|
|
169
|
-
* Note: SchemaPrimitiveType = 'string'|'number'|'integer'|'boolean'|'null'
|
|
170
|
-
*
|
|
171
|
-
* // {SchemaPrimitiveType|SchemaPrimitiveType[]} type - type(s) to accept
|
|
172
|
-
* // {IValidatorFn}
|
|
173
|
-
*/
|
|
174
|
-
static type(requiredType: SchemaPrimitiveType|SchemaPrimitiveType[]): IValidatorFn {
|
|
175
|
-
if (!hasValue(requiredType)) { return JsonValidators.nullValidator; }
|
|
176
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
177
|
-
if (isEmpty(control.value)) { return null; }
|
|
178
|
-
const currentValue: any = control.value;
|
|
179
|
-
const isValid = isArray(requiredType) ?
|
|
180
|
-
(<SchemaPrimitiveType[]>requiredType).some(type => isType(currentValue, type)) :
|
|
181
|
-
isType(currentValue, <SchemaPrimitiveType>requiredType);
|
|
182
|
-
return xor(isValid, invert) ?
|
|
183
|
-
null : { 'type': { requiredType, currentValue } };
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* 'enum' validator
|
|
189
|
-
*
|
|
190
|
-
* Requires a control to have a value from an enumerated list of values.
|
|
191
|
-
*
|
|
192
|
-
* Converts types as needed to allow string inputs to still correctly
|
|
193
|
-
* match number, boolean, and null enum values.
|
|
194
|
-
*
|
|
195
|
-
* // {any[]} allowedValues - array of acceptable values
|
|
196
|
-
* // {IValidatorFn}
|
|
197
|
-
*/
|
|
198
|
-
static enum(allowedValues: any[]): IValidatorFn {
|
|
199
|
-
if (!isArray(allowedValues)) { return JsonValidators.nullValidator; }
|
|
200
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
201
|
-
if (isEmpty(control.value)) { return null; }
|
|
202
|
-
const currentValue: any = control.value;
|
|
203
|
-
const isEqualVal = (enumValue, inputValue) =>
|
|
204
|
-
enumValue === inputValue ||
|
|
205
|
-
(isNumber(enumValue) && +inputValue === +enumValue) ||
|
|
206
|
-
(isBoolean(enumValue, 'strict') &&
|
|
207
|
-
toJavaScriptType(inputValue, 'boolean') === enumValue) ||
|
|
208
|
-
(enumValue === null && !hasValue(inputValue)) ||
|
|
209
|
-
isEqual(enumValue, inputValue);
|
|
210
|
-
const isValid = isArray(currentValue) ?
|
|
211
|
-
currentValue.every(inputValue => allowedValues.some(enumValue =>
|
|
212
|
-
isEqualVal(enumValue, inputValue)
|
|
213
|
-
)) :
|
|
214
|
-
allowedValues.some(enumValue => isEqualVal(enumValue, currentValue));
|
|
215
|
-
return xor(isValid, invert) ?
|
|
216
|
-
null : { 'enum': { allowedValues, currentValue } };
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 'const' validator
|
|
222
|
-
*
|
|
223
|
-
* Requires a control to have a specific value.
|
|
224
|
-
*
|
|
225
|
-
* Converts types as needed to allow string inputs to still correctly
|
|
226
|
-
* match number, boolean, and null values.
|
|
227
|
-
*
|
|
228
|
-
* TODO: modify to work with objects
|
|
229
|
-
*
|
|
230
|
-
* // {any[]} requiredValue - required value
|
|
231
|
-
* // {IValidatorFn}
|
|
232
|
-
*/
|
|
233
|
-
static const(requiredValue: any): IValidatorFn {
|
|
234
|
-
if (!hasValue(requiredValue)) { return JsonValidators.nullValidator; }
|
|
235
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
236
|
-
if (isEmpty(control.value)) { return null; }
|
|
237
|
-
const currentValue: any = control.value;
|
|
238
|
-
const isEqualVal = (constValue, inputValue) =>
|
|
239
|
-
constValue === inputValue ||
|
|
240
|
-
isNumber(constValue) && +inputValue === +constValue ||
|
|
241
|
-
isBoolean(constValue, 'strict') &&
|
|
242
|
-
toJavaScriptType(inputValue, 'boolean') === constValue ||
|
|
243
|
-
constValue === null && !hasValue(inputValue);
|
|
244
|
-
const isValid = isEqualVal(requiredValue, currentValue);
|
|
245
|
-
return xor(isValid, invert) ?
|
|
246
|
-
null : { 'const': { requiredValue, currentValue } };
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* 'minLength' validator
|
|
252
|
-
*
|
|
253
|
-
* Requires a control's text value to be greater than a specified length.
|
|
254
|
-
*
|
|
255
|
-
* // {number} minimumLength - minimum allowed string length
|
|
256
|
-
* // {boolean = false} invert - instead return error object only if valid
|
|
257
|
-
* // {IValidatorFn}
|
|
258
|
-
*/
|
|
259
|
-
static minLength(minimumLength: number): IValidatorFn {
|
|
260
|
-
if (!hasValue(minimumLength)) { return JsonValidators.nullValidator; }
|
|
261
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
262
|
-
if (isEmpty(control.value)) { return null; }
|
|
263
|
-
const currentLength = isString(control.value) ? control.value.length : 0;
|
|
264
|
-
const isValid = currentLength >= minimumLength;
|
|
265
|
-
return xor(isValid, invert) ?
|
|
266
|
-
null : { 'minLength': { minimumLength, currentLength } };
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* 'maxLength' validator
|
|
272
|
-
*
|
|
273
|
-
* Requires a control's text value to be less than a specified length.
|
|
274
|
-
*
|
|
275
|
-
* // {number} maximumLength - maximum allowed string length
|
|
276
|
-
* // {boolean = false} invert - instead return error object only if valid
|
|
277
|
-
* // {IValidatorFn}
|
|
278
|
-
*/
|
|
279
|
-
static maxLength(maximumLength: number): IValidatorFn {
|
|
280
|
-
if (!hasValue(maximumLength)) { return JsonValidators.nullValidator; }
|
|
281
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
282
|
-
const currentLength = isString(control.value) ? control.value.length : 0;
|
|
283
|
-
const isValid = currentLength <= maximumLength;
|
|
284
|
-
return xor(isValid, invert) ?
|
|
285
|
-
null : { 'maxLength': { maximumLength, currentLength } };
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* 'pattern' validator
|
|
291
|
-
*
|
|
292
|
-
* Note: NOT the same as Angular's default pattern validator.
|
|
293
|
-
*
|
|
294
|
-
* Requires a control's value to match a specified regular expression pattern.
|
|
295
|
-
*
|
|
296
|
-
* This validator changes the behavior of default pattern validator
|
|
297
|
-
* by replacing RegExp(`^${pattern}$`) with RegExp(`${pattern}`),
|
|
298
|
-
* which allows for partial matches.
|
|
299
|
-
*
|
|
300
|
-
* To return to the default funcitonality, and match the entire string,
|
|
301
|
-
* pass TRUE as the optional second parameter.
|
|
302
|
-
*
|
|
303
|
-
* // {string} pattern - regular expression pattern
|
|
304
|
-
* // {boolean = false} wholeString - match whole value string?
|
|
305
|
-
* // {IValidatorFn}
|
|
306
|
-
*/
|
|
307
|
-
static pattern(pattern: string|RegExp, wholeString = false): IValidatorFn {
|
|
308
|
-
if (!hasValue(pattern)) { return JsonValidators.nullValidator; }
|
|
309
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
310
|
-
if (isEmpty(control.value)) { return null; }
|
|
311
|
-
let regex: RegExp;
|
|
312
|
-
let requiredPattern: string;
|
|
313
|
-
if (typeof pattern === 'string') {
|
|
314
|
-
requiredPattern = (wholeString) ? `^${pattern}$` : pattern;
|
|
315
|
-
regex = new RegExp(requiredPattern);
|
|
316
|
-
} else {
|
|
317
|
-
requiredPattern = pattern.toString();
|
|
318
|
-
regex = pattern;
|
|
319
|
-
}
|
|
320
|
-
const currentValue: string = control.value;
|
|
321
|
-
const isValid = isString(currentValue) ? regex.test(currentValue) : false;
|
|
322
|
-
return xor(isValid, invert) ?
|
|
323
|
-
null : { 'pattern': { requiredPattern, currentValue } };
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* 'format' validator
|
|
329
|
-
*
|
|
330
|
-
* Requires a control to have a value of a certain format.
|
|
331
|
-
*
|
|
332
|
-
* This validator currently checks the following formsts:
|
|
333
|
-
* date, time, date-time, email, hostname, ipv4, ipv6,
|
|
334
|
-
* uri, uri-reference, uri-template, url, uuid, color,
|
|
335
|
-
* json-pointer, relative-json-pointer, regex
|
|
336
|
-
*
|
|
337
|
-
* Fast format regular expressions copied from AJV:
|
|
338
|
-
* https://github.com/epoberezkin/ajv/blob/master/lib/compile/formats.js
|
|
339
|
-
*
|
|
340
|
-
* // {JsonSchemaFormatNames} requiredFormat - format to check
|
|
341
|
-
* // {IValidatorFn}
|
|
342
|
-
*/
|
|
343
|
-
static format(requiredFormat: JsonSchemaFormatNames): IValidatorFn {
|
|
344
|
-
if (!hasValue(requiredFormat)) { return JsonValidators.nullValidator; }
|
|
345
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
346
|
-
if (isEmpty(control.value)) { return null; }
|
|
347
|
-
let isValid: boolean;
|
|
348
|
-
const currentValue: string|Date = control.value;
|
|
349
|
-
if (isString(currentValue)) {
|
|
350
|
-
const formatTest: Function|RegExp = jsonSchemaFormatTests[requiredFormat];
|
|
351
|
-
if (typeof formatTest === 'object') {
|
|
352
|
-
isValid = (<RegExp>formatTest).test(<string>currentValue);
|
|
353
|
-
} else if (typeof formatTest === 'function') {
|
|
354
|
-
isValid = (<Function>formatTest)(<string>currentValue);
|
|
355
|
-
} else {
|
|
356
|
-
console.error(`format validator error: "${requiredFormat}" is not a recognized format.`);
|
|
357
|
-
isValid = true;
|
|
358
|
-
}
|
|
359
|
-
} else {
|
|
360
|
-
// Allow JavaScript Date objects
|
|
361
|
-
isValid = ['date', 'time', 'date-time'].includes(requiredFormat) &&
|
|
362
|
-
Object.prototype.toString.call(currentValue) === '[object Date]';
|
|
363
|
-
}
|
|
364
|
-
return xor(isValid, invert) ?
|
|
365
|
-
null : { 'format': { requiredFormat, currentValue } };
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* 'minimum' validator
|
|
371
|
-
*
|
|
372
|
-
* Requires a control's numeric value to be greater than or equal to
|
|
373
|
-
* a minimum amount.
|
|
374
|
-
*
|
|
375
|
-
* Any non-numeric value is also valid (according to the HTML forms spec,
|
|
376
|
-
* a non-numeric value doesn't have a minimum).
|
|
377
|
-
* https://www.w3.org/TR/html5/forms.html#attr-input-max
|
|
378
|
-
*
|
|
379
|
-
* // {number} minimum - minimum allowed value
|
|
380
|
-
* // {IValidatorFn}
|
|
381
|
-
*/
|
|
382
|
-
static minimum(minimumValue: number): IValidatorFn {
|
|
383
|
-
if (!hasValue(minimumValue)) { return JsonValidators.nullValidator; }
|
|
384
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
385
|
-
if (isEmpty(control.value)) { return null; }
|
|
386
|
-
const currentValue = control.value;
|
|
387
|
-
const isValid = !isNumber(currentValue) || currentValue >= minimumValue;
|
|
388
|
-
return xor(isValid, invert) ?
|
|
389
|
-
null : { 'minimum': { minimumValue, currentValue } };
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* 'exclusiveMinimum' validator
|
|
395
|
-
*
|
|
396
|
-
* Requires a control's numeric value to be less than a maximum amount.
|
|
397
|
-
*
|
|
398
|
-
* Any non-numeric value is also valid (according to the HTML forms spec,
|
|
399
|
-
* a non-numeric value doesn't have a maximum).
|
|
400
|
-
* https://www.w3.org/TR/html5/forms.html#attr-input-max
|
|
401
|
-
*
|
|
402
|
-
* // {number} exclusiveMinimumValue - maximum allowed value
|
|
403
|
-
* // {IValidatorFn}
|
|
404
|
-
*/
|
|
405
|
-
static exclusiveMinimum(exclusiveMinimumValue: number): IValidatorFn {
|
|
406
|
-
if (!hasValue(exclusiveMinimumValue)) { return JsonValidators.nullValidator; }
|
|
407
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
408
|
-
if (isEmpty(control.value)) { return null; }
|
|
409
|
-
const currentValue = control.value;
|
|
410
|
-
const isValid = !isNumber(currentValue) || +currentValue < exclusiveMinimumValue;
|
|
411
|
-
return xor(isValid, invert) ?
|
|
412
|
-
null : { 'exclusiveMinimum': { exclusiveMinimumValue, currentValue } };
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* 'maximum' validator
|
|
418
|
-
*
|
|
419
|
-
* Requires a control's numeric value to be less than or equal to
|
|
420
|
-
* a maximum amount.
|
|
421
|
-
*
|
|
422
|
-
* Any non-numeric value is also valid (according to the HTML forms spec,
|
|
423
|
-
* a non-numeric value doesn't have a maximum).
|
|
424
|
-
* https://www.w3.org/TR/html5/forms.html#attr-input-max
|
|
425
|
-
*
|
|
426
|
-
* // {number} maximumValue - maximum allowed value
|
|
427
|
-
* // {IValidatorFn}
|
|
428
|
-
*/
|
|
429
|
-
static maximum(maximumValue: number): IValidatorFn {
|
|
430
|
-
if (!hasValue(maximumValue)) { return JsonValidators.nullValidator; }
|
|
431
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
432
|
-
if (isEmpty(control.value)) { return null; }
|
|
433
|
-
const currentValue = control.value;
|
|
434
|
-
const isValid = !isNumber(currentValue) || +currentValue <= maximumValue;
|
|
435
|
-
return xor(isValid, invert) ?
|
|
436
|
-
null : { 'maximum': { maximumValue, currentValue } };
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* 'exclusiveMaximum' validator
|
|
442
|
-
*
|
|
443
|
-
* Requires a control's numeric value to be less than a maximum amount.
|
|
444
|
-
*
|
|
445
|
-
* Any non-numeric value is also valid (according to the HTML forms spec,
|
|
446
|
-
* a non-numeric value doesn't have a maximum).
|
|
447
|
-
* https://www.w3.org/TR/html5/forms.html#attr-input-max
|
|
448
|
-
*
|
|
449
|
-
* // {number} exclusiveMaximumValue - maximum allowed value
|
|
450
|
-
* // {IValidatorFn}
|
|
451
|
-
*/
|
|
452
|
-
static exclusiveMaximum(exclusiveMaximumValue: number): IValidatorFn {
|
|
453
|
-
if (!hasValue(exclusiveMaximumValue)) { return JsonValidators.nullValidator; }
|
|
454
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
455
|
-
if (isEmpty(control.value)) { return null; }
|
|
456
|
-
const currentValue = control.value;
|
|
457
|
-
const isValid = !isNumber(currentValue) || +currentValue < exclusiveMaximumValue;
|
|
458
|
-
return xor(isValid, invert) ?
|
|
459
|
-
null : { 'exclusiveMaximum': { exclusiveMaximumValue, currentValue } };
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* 'multipleOf' validator
|
|
465
|
-
*
|
|
466
|
-
* Requires a control to have a numeric value that is a multiple
|
|
467
|
-
* of a specified number.
|
|
468
|
-
*
|
|
469
|
-
* // {number} multipleOfValue - number value must be a multiple of
|
|
470
|
-
* // {IValidatorFn}
|
|
471
|
-
*/
|
|
472
|
-
static multipleOf(multipleOfValue: number): IValidatorFn {
|
|
473
|
-
if (!hasValue(multipleOfValue)) { return JsonValidators.nullValidator; }
|
|
474
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
475
|
-
if (isEmpty(control.value)) { return null; }
|
|
476
|
-
const currentValue = control.value;
|
|
477
|
-
const isValid = isNumber(currentValue) &&
|
|
478
|
-
currentValue % multipleOfValue === 0;
|
|
479
|
-
return xor(isValid, invert) ?
|
|
480
|
-
null : { 'multipleOf': { multipleOfValue, currentValue } };
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* 'minProperties' validator
|
|
486
|
-
*
|
|
487
|
-
* Requires a form group to have a minimum number of properties (i.e. have
|
|
488
|
-
* values entered in a minimum number of controls within the group).
|
|
489
|
-
*
|
|
490
|
-
* // {number} minimumProperties - minimum number of properties allowed
|
|
491
|
-
* // {IValidatorFn}
|
|
492
|
-
*/
|
|
493
|
-
static minProperties(minimumProperties: number): IValidatorFn {
|
|
494
|
-
if (!hasValue(minimumProperties)) { return JsonValidators.nullValidator; }
|
|
495
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
496
|
-
if (isEmpty(control.value)) { return null; }
|
|
497
|
-
const currentProperties = Object.keys(control.value).length || 0;
|
|
498
|
-
const isValid = currentProperties >= minimumProperties;
|
|
499
|
-
return xor(isValid, invert) ?
|
|
500
|
-
null : { 'minProperties': { minimumProperties, currentProperties } };
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* 'maxProperties' validator
|
|
506
|
-
*
|
|
507
|
-
* Requires a form group to have a maximum number of properties (i.e. have
|
|
508
|
-
* values entered in a maximum number of controls within the group).
|
|
509
|
-
*
|
|
510
|
-
* Note: Has no effect if the form group does not contain more than the
|
|
511
|
-
* maximum number of controls.
|
|
512
|
-
*
|
|
513
|
-
* // {number} maximumProperties - maximum number of properties allowed
|
|
514
|
-
* // {IValidatorFn}
|
|
515
|
-
*/
|
|
516
|
-
static maxProperties(maximumProperties: number): IValidatorFn {
|
|
517
|
-
if (!hasValue(maximumProperties)) { return JsonValidators.nullValidator; }
|
|
518
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
519
|
-
const currentProperties = Object.keys(control.value).length || 0;
|
|
520
|
-
const isValid = currentProperties <= maximumProperties;
|
|
521
|
-
return xor(isValid, invert) ?
|
|
522
|
-
null : { 'maxProperties': { maximumProperties, currentProperties } };
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* 'dependencies' validator
|
|
528
|
-
*
|
|
529
|
-
* Requires the controls in a form group to meet additional validation
|
|
530
|
-
* criteria, depending on the values of other controls in the group.
|
|
531
|
-
*
|
|
532
|
-
* Examples:
|
|
533
|
-
* https://spacetelescope.github.io/understanding-json-schema/reference/object.html#dependencies
|
|
534
|
-
*
|
|
535
|
-
* // {any} dependencies - required dependencies
|
|
536
|
-
* // {IValidatorFn}
|
|
537
|
-
*/
|
|
538
|
-
static dependencies(dependencies: any): IValidatorFn {
|
|
539
|
-
if (getType(dependencies) !== 'object' || isEmpty(dependencies)) {
|
|
540
|
-
return JsonValidators.nullValidator;
|
|
541
|
-
}
|
|
542
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
543
|
-
if (isEmpty(control.value)) { return null; }
|
|
544
|
-
const allErrors = _mergeObjects(
|
|
545
|
-
forEachCopy(dependencies, (value, requiringField) => {
|
|
546
|
-
if (!hasValue(control.value[requiringField])) { return null; }
|
|
547
|
-
let requiringFieldErrors: ValidationErrors = { };
|
|
548
|
-
let requiredFields: string[];
|
|
549
|
-
let properties: ValidationErrors = { };
|
|
550
|
-
if (getType(dependencies[requiringField]) === 'array') {
|
|
551
|
-
requiredFields = dependencies[requiringField];
|
|
552
|
-
} else if (getType(dependencies[requiringField]) === 'object') {
|
|
553
|
-
requiredFields = dependencies[requiringField]['required'] || [];
|
|
554
|
-
properties = dependencies[requiringField]['properties'] || { };
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Validate property dependencies
|
|
558
|
-
for (const requiredField of requiredFields) {
|
|
559
|
-
if (xor(!hasValue(control.value[requiredField]), invert)) {
|
|
560
|
-
requiringFieldErrors[requiredField] = { 'required': true };
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// Validate schema dependencies
|
|
565
|
-
requiringFieldErrors = _mergeObjects(requiringFieldErrors,
|
|
566
|
-
forEachCopy(properties, (requirements, requiredField) => {
|
|
567
|
-
const requiredFieldErrors = _mergeObjects(
|
|
568
|
-
forEachCopy(requirements, (requirement, parameter) => {
|
|
569
|
-
let validator: IValidatorFn = null;
|
|
570
|
-
if (requirement === 'maximum' || requirement === 'minimum') {
|
|
571
|
-
const exclusive = !!requirements['exclusiveM' + requirement.slice(1)];
|
|
572
|
-
validator = JsonValidators[requirement](parameter, exclusive);
|
|
573
|
-
} else if (typeof JsonValidators[requirement] === 'function') {
|
|
574
|
-
validator = JsonValidators[requirement](parameter);
|
|
575
|
-
}
|
|
576
|
-
return !isDefined(validator) ?
|
|
577
|
-
null : validator(control.value[requiredField]);
|
|
578
|
-
})
|
|
579
|
-
);
|
|
580
|
-
return isEmpty(requiredFieldErrors) ?
|
|
581
|
-
null : { [requiredField]: requiredFieldErrors };
|
|
582
|
-
})
|
|
583
|
-
);
|
|
584
|
-
return isEmpty(requiringFieldErrors) ?
|
|
585
|
-
null : { [requiringField]: requiringFieldErrors };
|
|
586
|
-
})
|
|
587
|
-
);
|
|
588
|
-
return isEmpty(allErrors) ? null : allErrors;
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
/**
|
|
593
|
-
* 'minItems' validator
|
|
594
|
-
*
|
|
595
|
-
* Requires a form array to have a minimum number of values.
|
|
596
|
-
*
|
|
597
|
-
* // {number} minimumItems - minimum number of items allowed
|
|
598
|
-
* // {IValidatorFn}
|
|
599
|
-
*/
|
|
600
|
-
static minItems(minimumItems: number): IValidatorFn {
|
|
601
|
-
if (!hasValue(minimumItems)) { return JsonValidators.nullValidator; }
|
|
602
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
603
|
-
if (isEmpty(control.value)) { return null; }
|
|
604
|
-
const currentItems = isArray(control.value) ? control.value.length : 0;
|
|
605
|
-
const isValid = currentItems >= minimumItems;
|
|
606
|
-
return xor(isValid, invert) ?
|
|
607
|
-
null : { 'minItems': { minimumItems, currentItems } };
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* 'maxItems' validator
|
|
613
|
-
*
|
|
614
|
-
* Requires a form array to have a maximum number of values.
|
|
615
|
-
*
|
|
616
|
-
* // {number} maximumItems - maximum number of items allowed
|
|
617
|
-
* // {IValidatorFn}
|
|
618
|
-
*/
|
|
619
|
-
static maxItems(maximumItems: number): IValidatorFn {
|
|
620
|
-
if (!hasValue(maximumItems)) { return JsonValidators.nullValidator; }
|
|
621
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
622
|
-
const currentItems = isArray(control.value) ? control.value.length : 0;
|
|
623
|
-
const isValid = currentItems <= maximumItems;
|
|
624
|
-
return xor(isValid, invert) ?
|
|
625
|
-
null : { 'maxItems': { maximumItems, currentItems } };
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* 'uniqueItems' validator
|
|
631
|
-
*
|
|
632
|
-
* Requires values in a form array to be unique.
|
|
633
|
-
*
|
|
634
|
-
* // {boolean = true} unique? - true to validate, false to disable
|
|
635
|
-
* // {IValidatorFn}
|
|
636
|
-
*/
|
|
637
|
-
static uniqueItems(unique = true): IValidatorFn {
|
|
638
|
-
if (!unique) { return JsonValidators.nullValidator; }
|
|
639
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
640
|
-
if (isEmpty(control.value)) { return null; }
|
|
641
|
-
const sorted: any[] = control.value.slice().sort();
|
|
642
|
-
const duplicateItems = [];
|
|
643
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
644
|
-
if (sorted[i - 1] === sorted[i] && duplicateItems.includes(sorted[i])) {
|
|
645
|
-
duplicateItems.push(sorted[i]);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
const isValid = !duplicateItems.length;
|
|
649
|
-
return xor(isValid, invert) ?
|
|
650
|
-
null : { 'uniqueItems': { duplicateItems } };
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* 'contains' validator
|
|
656
|
-
*
|
|
657
|
-
* TODO: Complete this validator
|
|
658
|
-
*
|
|
659
|
-
* Requires values in a form array to be unique.
|
|
660
|
-
*
|
|
661
|
-
* // {boolean = true} unique? - true to validate, false to disable
|
|
662
|
-
* // {IValidatorFn}
|
|
663
|
-
*/
|
|
664
|
-
static contains(requiredItem = true): IValidatorFn {
|
|
665
|
-
if (!requiredItem) { return JsonValidators.nullValidator; }
|
|
666
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
667
|
-
if (isEmpty(control.value) || !isArray(control.value)) { return null; }
|
|
668
|
-
const currentItems = control.value;
|
|
669
|
-
// const isValid = currentItems.some(item =>
|
|
670
|
-
//
|
|
671
|
-
// );
|
|
672
|
-
const isValid = true;
|
|
673
|
-
return xor(isValid, invert) ?
|
|
674
|
-
null : { 'contains': { requiredItem, currentItems } };
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* No-op validator. Included for backward compatibility.
|
|
680
|
-
*/
|
|
681
|
-
static nullValidator(control: AbstractControl): ValidationErrors|null {
|
|
682
|
-
return null;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Validator transformation functions:
|
|
687
|
-
* composeAnyOf, composeOneOf, composeAllOf, composeNot,
|
|
688
|
-
* compose, composeAsync
|
|
689
|
-
*
|
|
690
|
-
* TODO: Add composeAnyOfAsync, composeOneOfAsync,
|
|
691
|
-
* composeAllOfAsync, composeNotAsync
|
|
692
|
-
*/
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* 'composeAnyOf' validator combination function
|
|
696
|
-
*
|
|
697
|
-
* Accepts an array of validators and returns a single validator that
|
|
698
|
-
* evaluates to valid if any one or more of the submitted validators are
|
|
699
|
-
* valid. If every validator is invalid, it returns combined errors from
|
|
700
|
-
* all validators.
|
|
701
|
-
*
|
|
702
|
-
* // {IValidatorFn[]} validators - array of validators to combine
|
|
703
|
-
* // {IValidatorFn} - single combined validator function
|
|
704
|
-
*/
|
|
705
|
-
static composeAnyOf(validators: IValidatorFn[]): IValidatorFn {
|
|
706
|
-
if (!validators) { return null; }
|
|
707
|
-
const presentValidators = validators.filter(isDefined);
|
|
708
|
-
if (presentValidators.length === 0) { return null; }
|
|
709
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
710
|
-
const arrayOfErrors =
|
|
711
|
-
_executeValidators(control, presentValidators, invert).filter(isDefined);
|
|
712
|
-
const isValid = validators.length > arrayOfErrors.length;
|
|
713
|
-
return xor(isValid, invert) ?
|
|
714
|
-
null : _mergeObjects(...arrayOfErrors, { 'anyOf': !invert });
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
/**
|
|
719
|
-
* 'composeOneOf' validator combination function
|
|
720
|
-
*
|
|
721
|
-
* Accepts an array of validators and returns a single validator that
|
|
722
|
-
* evaluates to valid only if exactly one of the submitted validators
|
|
723
|
-
* is valid. Otherwise returns combined information from all validators,
|
|
724
|
-
* both valid and invalid.
|
|
725
|
-
*
|
|
726
|
-
* // {IValidatorFn[]} validators - array of validators to combine
|
|
727
|
-
* // {IValidatorFn} - single combined validator function
|
|
728
|
-
*/
|
|
729
|
-
static composeOneOf(validators: IValidatorFn[]): IValidatorFn {
|
|
730
|
-
if (!validators) { return null; }
|
|
731
|
-
const presentValidators = validators.filter(isDefined);
|
|
732
|
-
if (presentValidators.length === 0) { return null; }
|
|
733
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
734
|
-
const arrayOfErrors =
|
|
735
|
-
_executeValidators(control, presentValidators);
|
|
736
|
-
const validControls =
|
|
737
|
-
validators.length - arrayOfErrors.filter(isDefined).length;
|
|
738
|
-
const isValid = validControls === 1;
|
|
739
|
-
if (xor(isValid, invert)) { return null; }
|
|
740
|
-
const arrayOfValids =
|
|
741
|
-
_executeValidators(control, presentValidators, invert);
|
|
742
|
-
return _mergeObjects(...arrayOfErrors, ...arrayOfValids, { 'oneOf': !invert });
|
|
743
|
-
};
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/**
|
|
747
|
-
* 'composeAllOf' validator combination function
|
|
748
|
-
*
|
|
749
|
-
* Accepts an array of validators and returns a single validator that
|
|
750
|
-
* evaluates to valid only if all the submitted validators are individually
|
|
751
|
-
* valid. Otherwise it returns combined errors from all invalid validators.
|
|
752
|
-
*
|
|
753
|
-
* // {IValidatorFn[]} validators - array of validators to combine
|
|
754
|
-
* // {IValidatorFn} - single combined validator function
|
|
755
|
-
*/
|
|
756
|
-
static composeAllOf(validators: IValidatorFn[]): IValidatorFn {
|
|
757
|
-
if (!validators) { return null; }
|
|
758
|
-
const presentValidators = validators.filter(isDefined);
|
|
759
|
-
if (presentValidators.length === 0) { return null; }
|
|
760
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
761
|
-
const combinedErrors = _mergeErrors(
|
|
762
|
-
_executeValidators(control, presentValidators, invert)
|
|
763
|
-
);
|
|
764
|
-
const isValid = combinedErrors === null;
|
|
765
|
-
return (xor(isValid, invert)) ?
|
|
766
|
-
null : _mergeObjects(combinedErrors, { 'allOf': !invert });
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* 'composeNot' validator inversion function
|
|
772
|
-
*
|
|
773
|
-
* Accepts a single validator function and inverts its result.
|
|
774
|
-
* Returns valid if the submitted validator is invalid, and
|
|
775
|
-
* returns invalid if the submitted validator is valid.
|
|
776
|
-
* (Note: this function can itself be inverted
|
|
777
|
-
* - e.g. composeNot(composeNot(validator)) -
|
|
778
|
-
* but this can be confusing and is therefore not recommended.)
|
|
779
|
-
*
|
|
780
|
-
* // {IValidatorFn[]} validators - validator(s) to invert
|
|
781
|
-
* // {IValidatorFn} - new validator function that returns opposite result
|
|
782
|
-
*/
|
|
783
|
-
static composeNot(validator: IValidatorFn): IValidatorFn {
|
|
784
|
-
if (!validator) { return null; }
|
|
785
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null => {
|
|
786
|
-
if (isEmpty(control.value)) { return null; }
|
|
787
|
-
const error = validator(control, !invert);
|
|
788
|
-
const isValid = error === null;
|
|
789
|
-
return (xor(isValid, invert)) ?
|
|
790
|
-
null : _mergeObjects(error, { 'not': !invert });
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
/**
|
|
795
|
-
* 'compose' validator combination function
|
|
796
|
-
*
|
|
797
|
-
* // {IValidatorFn[]} validators - array of validators to combine
|
|
798
|
-
* // {IValidatorFn} - single combined validator function
|
|
799
|
-
*/
|
|
800
|
-
static compose(validators: IValidatorFn[]): IValidatorFn {
|
|
801
|
-
if (!validators) { return null; }
|
|
802
|
-
const presentValidators = validators.filter(isDefined);
|
|
803
|
-
if (presentValidators.length === 0) { return null; }
|
|
804
|
-
return (control: AbstractControl, invert = false): ValidationErrors|null =>
|
|
805
|
-
_mergeErrors(_executeValidators(control, presentValidators, invert));
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
* 'composeAsync' async validator combination function
|
|
810
|
-
*
|
|
811
|
-
* // {AsyncIValidatorFn[]} async validators - array of async validators
|
|
812
|
-
* // {AsyncIValidatorFn} - single combined async validator function
|
|
813
|
-
*/
|
|
814
|
-
static composeAsync(validators: AsyncIValidatorFn[]): AsyncIValidatorFn {
|
|
815
|
-
if (!validators) { return null; }
|
|
816
|
-
const presentValidators = validators.filter(isDefined);
|
|
817
|
-
if (presentValidators.length === 0) { return null; }
|
|
818
|
-
return (control: AbstractControl) => {
|
|
819
|
-
const observables =
|
|
820
|
-
_executeAsyncValidators(control, presentValidators).map(toObservable);
|
|
821
|
-
return map.call(forkJoin(observables), _mergeErrors);
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// Additional angular validators (not used by Angualr JSON Schema Form)
|
|
826
|
-
// From https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts
|
|
827
|
-
|
|
828
|
-
/**
|
|
829
|
-
* Validator that requires controls to have a value greater than a number.
|
|
830
|
-
*/
|
|
831
|
-
static min(min: number): ValidatorFn {
|
|
832
|
-
if (!hasValue(min)) { return JsonValidators.nullValidator; }
|
|
833
|
-
return (control: AbstractControl): ValidationErrors|null => {
|
|
834
|
-
// don't validate empty values to allow optional controls
|
|
835
|
-
if (isEmpty(control.value) || isEmpty(min)) { return null; }
|
|
836
|
-
const value = parseFloat(control.value);
|
|
837
|
-
const actual = control.value;
|
|
838
|
-
// Controls with NaN values after parsing should be treated as not having a
|
|
839
|
-
// minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
|
|
840
|
-
return isNaN(value) || value >= min ? null : { 'min': { min, actual } };
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* Validator that requires controls to have a value less than a number.
|
|
846
|
-
*/
|
|
847
|
-
static max(max: number): ValidatorFn {
|
|
848
|
-
if (!hasValue(max)) { return JsonValidators.nullValidator; }
|
|
849
|
-
return (control: AbstractControl): ValidationErrors|null => {
|
|
850
|
-
// don't validate empty values to allow optional controls
|
|
851
|
-
if (isEmpty(control.value) || isEmpty(max)) { return null; }
|
|
852
|
-
const value = parseFloat(control.value);
|
|
853
|
-
const actual = control.value;
|
|
854
|
-
// Controls with NaN values after parsing should be treated as not having a
|
|
855
|
-
// maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
|
|
856
|
-
return isNaN(value) || value <= max ? null : { 'max': { max, actual } };
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
/**
|
|
861
|
-
* Validator that requires control value to be true.
|
|
862
|
-
*/
|
|
863
|
-
static requiredTrue(control: AbstractControl): ValidationErrors|null {
|
|
864
|
-
if (!control) { return JsonValidators.nullValidator; }
|
|
865
|
-
return control.value === true ? null : { 'required': true };
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
/**
|
|
869
|
-
* Validator that performs email validation.
|
|
870
|
-
*/
|
|
871
|
-
static email(control: AbstractControl): ValidationErrors|null {
|
|
872
|
-
if (!control) { return JsonValidators.nullValidator; }
|
|
873
|
-
const EMAIL_REGEXP =
|
|
874
|
-
// tslint:disable-next-line:max-line-length
|
|
875
|
-
/^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
|
|
876
|
-
return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
|
|
877
|
-
}
|
|
878
|
-
}
|