functional-models 1.1.3 → 1.1.4
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/package.json +5 -4
- package/{dist/src → src}/constants.d.ts +0 -0
- package/{dist/src → src}/constants.js +0 -0
- package/{dist/src → src}/constants.js.map +0 -0
- package/{dist/src → src}/errors.d.ts +0 -0
- package/{dist/src → src}/errors.js +0 -0
- package/{dist/src → src}/errors.js.map +0 -0
- package/{dist/src → src}/index.d.ts +0 -0
- package/{dist/src → src}/index.js +0 -0
- package/{dist/src → src}/index.js.map +0 -0
- package/{dist/src → src}/interfaces.d.ts +0 -0
- package/{dist/src → src}/interfaces.js +0 -0
- package/{dist/src → src}/interfaces.js.map +0 -0
- package/{dist/src → src}/lazy.d.ts +0 -0
- package/{dist/src → src}/lazy.js +0 -0
- package/{dist/src → src}/lazy.js.map +0 -0
- package/{dist/src → src}/methods.d.ts +0 -0
- package/{dist/src → src}/methods.js +0 -0
- package/{dist/src → src}/methods.js.map +0 -0
- package/{dist/src → src}/models.d.ts +0 -0
- package/{dist/src → src}/models.js +0 -0
- package/{dist/src → src}/models.js.map +0 -0
- package/{dist/src → src}/properties.d.ts +0 -0
- package/{dist/src → src}/properties.js +0 -0
- package/{dist/src → src}/properties.js.map +0 -0
- package/{dist/src → src}/serialization.d.ts +0 -0
- package/{dist/src → src}/serialization.js +0 -0
- package/{dist/src → src}/serialization.js.map +0 -0
- package/{dist/src → src}/utils.d.ts +0 -0
- package/{dist/src → src}/utils.js +0 -0
- package/{dist/src → src}/utils.js.map +0 -0
- package/{dist/src → src}/validation.d.ts +0 -0
- package/{dist/src → src}/validation.js +0 -0
- package/{dist/src → src}/validation.js.map +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/oldSteps.d.ts +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/oldSteps.js +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/oldSteps.js.map +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/tssteps.d.ts +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/tssteps.js +0 -0
- package/{dist/stepDefinitions → stepDefinitions}/tssteps.js.map +0 -0
- package/{dist/test → test}/src/errors.test.d.ts +0 -0
- package/{dist/test → test}/src/errors.test.js +0 -0
- package/{dist/test → test}/src/errors.test.js.map +0 -0
- package/{dist/test/src/lazy.test.d.ts → test/src/index.test.d.ts} +0 -0
- package/test/src/index.test.js +3 -0
- package/test/src/index.test.js.map +1 -0
- package/{dist/test/src/methods.test.d.ts → test/src/lazy.test.d.ts} +0 -0
- package/{dist/test → test}/src/lazy.test.js +0 -0
- package/{dist/test → test}/src/lazy.test.js.map +0 -0
- package/{dist/test/src/models.test.d.ts → test/src/methods.test.d.ts} +0 -0
- package/{dist/test → test}/src/methods.test.js +0 -0
- package/{dist/test → test}/src/methods.test.js.map +0 -0
- package/{dist/test/src/properties.test.d.ts → test/src/models.test.d.ts} +0 -0
- package/{dist/test → test}/src/models.test.js +0 -0
- package/{dist/test → test}/src/models.test.js.map +0 -0
- package/{dist/test/src/serialization.test.d.ts → test/src/properties.test.d.ts} +0 -0
- package/{dist/test → test}/src/properties.test.js +0 -0
- package/{dist/test → test}/src/properties.test.js.map +0 -0
- package/{dist/test/src/utils.test.d.ts → test/src/serialization.test.d.ts} +0 -0
- package/{dist/test → test}/src/serialization.test.js +0 -0
- package/{dist/test → test}/src/serialization.test.js.map +0 -0
- package/{dist/test/src/validation.test.d.ts → test/src/utils.test.d.ts} +0 -0
- package/{dist/test → test}/src/utils.test.js +0 -0
- package/{dist/test → test}/src/utils.test.js.map +0 -0
- package/test/src/validation.test.d.ts +1 -0
- package/{dist/test → test}/src/validation.test.js +0 -0
- package/{dist/test → test}/src/validation.test.js.map +0 -0
- package/.eslintignore +0 -5
- package/.eslintrc +0 -180
- package/.github/workflows/feature.yml +0 -26
- package/.github/workflows/ut.yml +0 -32
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -14
- package/LICENSE +0 -674
- package/cucumber.js +0 -10
- package/features/arrayFields.feature +0 -52
- package/features/basic-ts.feature +0 -13
- package/features/functions.feature +0 -10
- package/features/model.feature +0 -7
- package/features/validation.feature +0 -12
- package/index.js +0 -1
- package/src/constants.ts +0 -15
- package/src/errors.ts +0 -18
- package/src/index.ts +0 -12
- package/src/interfaces.ts +0 -323
- package/src/lazy.ts +0 -24
- package/src/methods.ts +0 -30
- package/src/models.ts +0 -183
- package/src/properties.ts +0 -375
- package/src/serialization.ts +0 -39
- package/src/utils.ts +0 -42
- package/src/validation.ts +0 -390
- package/stepDefinitions/oldSteps.ts +0 -216
- package/stepDefinitions/tssteps.ts +0 -107
- package/test/src/errors.test.ts +0 -31
- package/test/src/lazy.test.ts +0 -15
- package/test/src/methods.test.ts +0 -45
- package/test/src/models.test.ts +0 -417
- package/test/src/properties.test.ts +0 -747
- package/test/src/serialization.test.ts +0 -80
- package/test/src/utils.test.ts +0 -76
- package/test/src/validation.test.ts +0 -682
- package/tsconfig.json +0 -100
package/src/validation.ts
DELETED
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import isEmpty from 'lodash/isEmpty'
|
|
2
|
-
import merge from 'lodash/merge'
|
|
3
|
-
import flatMap from 'lodash/flatMap'
|
|
4
|
-
import {
|
|
5
|
-
FunctionalModel,
|
|
6
|
-
ModelInstance,
|
|
7
|
-
Model,
|
|
8
|
-
ModelComponentValidator,
|
|
9
|
-
PropertyValidatorComponent,
|
|
10
|
-
PropertyValidatorComponentType,
|
|
11
|
-
PropertyValidatorComponentSync,
|
|
12
|
-
PropertyValidatorComponentTypeAdvanced,
|
|
13
|
-
PropertyValidator,
|
|
14
|
-
PropertyConfig,
|
|
15
|
-
MaybeFunction,
|
|
16
|
-
PropertyValidators,
|
|
17
|
-
ValueGetter,
|
|
18
|
-
Arrayable,
|
|
19
|
-
FunctionalType,
|
|
20
|
-
ModelErrors,
|
|
21
|
-
} from './interfaces'
|
|
22
|
-
|
|
23
|
-
const TYPE_PRIMITIVES = {
|
|
24
|
-
boolean: 'boolean',
|
|
25
|
-
string: 'string',
|
|
26
|
-
object: 'object',
|
|
27
|
-
number: 'number',
|
|
28
|
-
integer: 'integer',
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const filterEmpty = <T>(
|
|
32
|
-
array: readonly (T | undefined | null)[]
|
|
33
|
-
): readonly T[] => {
|
|
34
|
-
return array.filter(x => x) as readonly T[]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const _trueOrError =
|
|
38
|
-
(method: Function, error: string): PropertyValidatorComponentSync =>
|
|
39
|
-
(value: any) => {
|
|
40
|
-
if (method(value) === false) {
|
|
41
|
-
return error
|
|
42
|
-
}
|
|
43
|
-
return undefined
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const _typeOrError =
|
|
47
|
-
(type: string, errorMessage: string): PropertyValidatorComponentSync =>
|
|
48
|
-
(value: any) => {
|
|
49
|
-
if (typeof value !== type) {
|
|
50
|
-
return errorMessage
|
|
51
|
-
}
|
|
52
|
-
return undefined
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const isType =
|
|
56
|
-
(type: string): PropertyValidatorComponentSync =>
|
|
57
|
-
(value: any) => {
|
|
58
|
-
// @ts-ignore
|
|
59
|
-
return _typeOrError(type, `Must be a ${type}`)(value)
|
|
60
|
-
}
|
|
61
|
-
const isNumber = isType('number')
|
|
62
|
-
const isInteger = _trueOrError(Number.isInteger, 'Must be an integer')
|
|
63
|
-
|
|
64
|
-
const isBoolean = isType('boolean')
|
|
65
|
-
const isString = isType('string')
|
|
66
|
-
const isArray = _trueOrError(
|
|
67
|
-
(v: any) => Array.isArray(v),
|
|
68
|
-
'Value is not an array'
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
const PRIMITIVE_TO_SPECIAL_TYPE_VALIDATOR = {
|
|
72
|
-
[TYPE_PRIMITIVES.boolean]: isBoolean,
|
|
73
|
-
[TYPE_PRIMITIVES.string]: isString,
|
|
74
|
-
[TYPE_PRIMITIVES.integer]: isInteger,
|
|
75
|
-
[TYPE_PRIMITIVES.number]: isNumber,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const arrayType =
|
|
79
|
-
(type: string): PropertyValidatorComponentSync =>
|
|
80
|
-
(value: Arrayable<FunctionalType>) => {
|
|
81
|
-
// @ts-ignore
|
|
82
|
-
const arrayError = isArray(value)
|
|
83
|
-
if (arrayError) {
|
|
84
|
-
return arrayError
|
|
85
|
-
}
|
|
86
|
-
const validator = PRIMITIVE_TO_SPECIAL_TYPE_VALIDATOR[type] || isType(type)
|
|
87
|
-
return (value as readonly []).reduce(
|
|
88
|
-
(acc: string | undefined, v: FunctionalType) => {
|
|
89
|
-
if (acc) {
|
|
90
|
-
return acc
|
|
91
|
-
}
|
|
92
|
-
// @ts-ignore
|
|
93
|
-
return validator(v)
|
|
94
|
-
},
|
|
95
|
-
undefined
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const meetsRegex =
|
|
100
|
-
(
|
|
101
|
-
regex: string | RegExp,
|
|
102
|
-
flags?: string,
|
|
103
|
-
errorMessage: string = 'Format was invalid'
|
|
104
|
-
): PropertyValidatorComponentSync =>
|
|
105
|
-
(value: FunctionalType) => {
|
|
106
|
-
const reg = new RegExp(regex, flags)
|
|
107
|
-
// @ts-ignore
|
|
108
|
-
return _trueOrError((v: string) => reg.test(v), errorMessage)(value)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const choices =
|
|
112
|
-
(choiceArray: readonly FunctionalType[]): PropertyValidatorComponentSync =>
|
|
113
|
-
(value: Arrayable<FunctionalType>) => {
|
|
114
|
-
if (Array.isArray(value)) {
|
|
115
|
-
const bad = value.find(v => !choiceArray.includes(v))
|
|
116
|
-
if (bad) {
|
|
117
|
-
return `${bad} is not a valid choice`
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
if (!choiceArray.includes(value as FunctionalType)) {
|
|
121
|
-
return `${value} is not a valid choice`
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return undefined
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const isDate: PropertyValidatorComponentType<Date> = (value: Date) => {
|
|
128
|
-
if (!value) {
|
|
129
|
-
return 'Date value is empty'
|
|
130
|
-
}
|
|
131
|
-
if (!value.toISOString) {
|
|
132
|
-
return 'Value is not a date'
|
|
133
|
-
}
|
|
134
|
-
return undefined
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const isRequired: PropertyValidatorComponentSync = (value?: any) => {
|
|
138
|
-
if (value === true || value === false) {
|
|
139
|
-
return undefined
|
|
140
|
-
}
|
|
141
|
-
// @ts-ignore
|
|
142
|
-
if (isNumber(value) === undefined) {
|
|
143
|
-
return undefined
|
|
144
|
-
}
|
|
145
|
-
const empty = isEmpty(value)
|
|
146
|
-
if (empty) {
|
|
147
|
-
// @ts-ignore
|
|
148
|
-
if (isDate(value)) {
|
|
149
|
-
return 'A value is required'
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return undefined
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const maxNumber =
|
|
156
|
-
(max: Number): PropertyValidatorComponentType<number> =>
|
|
157
|
-
(value: number) => {
|
|
158
|
-
// @ts-ignore
|
|
159
|
-
const numberError = isNumber(value)
|
|
160
|
-
if (numberError) {
|
|
161
|
-
return numberError
|
|
162
|
-
}
|
|
163
|
-
if (value && value > max) {
|
|
164
|
-
return `The maximum is ${max}`
|
|
165
|
-
}
|
|
166
|
-
return undefined
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const minNumber =
|
|
170
|
-
(min: Number): PropertyValidatorComponentType<number> =>
|
|
171
|
-
(value: Number) => {
|
|
172
|
-
// @ts-ignore
|
|
173
|
-
const numberError = isNumber(value)
|
|
174
|
-
if (numberError) {
|
|
175
|
-
return numberError
|
|
176
|
-
}
|
|
177
|
-
if (value && value < min) {
|
|
178
|
-
return `The minimum is ${min}`
|
|
179
|
-
}
|
|
180
|
-
return undefined
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const maxTextLength =
|
|
184
|
-
(max: Number): PropertyValidatorComponentType<string> =>
|
|
185
|
-
(value: string) => {
|
|
186
|
-
// @ts-ignore
|
|
187
|
-
const stringError = isString(value)
|
|
188
|
-
if (stringError) {
|
|
189
|
-
return stringError
|
|
190
|
-
}
|
|
191
|
-
if (value && value.length > max) {
|
|
192
|
-
return `The maximum length is ${max}`
|
|
193
|
-
}
|
|
194
|
-
return undefined
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const minTextLength =
|
|
198
|
-
(min: Number): PropertyValidatorComponentType<string> =>
|
|
199
|
-
(value: string) => {
|
|
200
|
-
// @ts-ignore
|
|
201
|
-
const stringError = isString(value)
|
|
202
|
-
if (stringError) {
|
|
203
|
-
return stringError
|
|
204
|
-
}
|
|
205
|
-
if (value && value.length < min) {
|
|
206
|
-
return `The minimum length is ${min}`
|
|
207
|
-
}
|
|
208
|
-
return undefined
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const referenceTypeMatch = <TModel extends FunctionalModel>(
|
|
212
|
-
referencedModel: MaybeFunction<Model<TModel>>
|
|
213
|
-
): PropertyValidatorComponentTypeAdvanced<ModelInstance<TModel>, TModel> => {
|
|
214
|
-
return (value?: ModelInstance<TModel>) => {
|
|
215
|
-
if (!value) {
|
|
216
|
-
return 'Must include a value'
|
|
217
|
-
}
|
|
218
|
-
// This needs to stay here, as it delays the creation long enough for
|
|
219
|
-
// self referencing types.
|
|
220
|
-
const model =
|
|
221
|
-
typeof referencedModel === 'function'
|
|
222
|
-
? referencedModel()
|
|
223
|
-
: referencedModel
|
|
224
|
-
// Assumption: By the time this is received, value === a model instance.
|
|
225
|
-
const eModel = model.getName()
|
|
226
|
-
const aModel = value.getModel().getName()
|
|
227
|
-
if (eModel !== aModel) {
|
|
228
|
-
return `Model should be ${eModel} instead, received ${aModel}`
|
|
229
|
-
}
|
|
230
|
-
return undefined
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const aggregateValidator = (
|
|
235
|
-
value: any,
|
|
236
|
-
methodOrMethods:
|
|
237
|
-
| PropertyValidatorComponent
|
|
238
|
-
| readonly PropertyValidatorComponent[]
|
|
239
|
-
) => {
|
|
240
|
-
const toDo = Array.isArray(methodOrMethods)
|
|
241
|
-
? methodOrMethods
|
|
242
|
-
: [methodOrMethods]
|
|
243
|
-
|
|
244
|
-
const _aggregativeValidator: PropertyValidator = async (
|
|
245
|
-
instance: ModelInstance<any>,
|
|
246
|
-
instanceData: FunctionalModel
|
|
247
|
-
) => {
|
|
248
|
-
const values = await Promise.all(
|
|
249
|
-
toDo.map(method => {
|
|
250
|
-
return method(value, instance, instanceData)
|
|
251
|
-
})
|
|
252
|
-
)
|
|
253
|
-
return filterEmpty(values)
|
|
254
|
-
}
|
|
255
|
-
return _aggregativeValidator
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const emptyValidator: PropertyValidatorComponentSync = () => undefined
|
|
259
|
-
|
|
260
|
-
const _boolChoice =
|
|
261
|
-
(method: (configValue: any) => PropertyValidatorComponentSync) =>
|
|
262
|
-
(configValue: any) => {
|
|
263
|
-
const func = method(configValue)
|
|
264
|
-
const validatorWrapper: PropertyValidatorComponentSync = (
|
|
265
|
-
value: any,
|
|
266
|
-
modelInstance: ModelInstance<any>,
|
|
267
|
-
modelData: FunctionalModel
|
|
268
|
-
) => {
|
|
269
|
-
return func(value, modelInstance, modelData)
|
|
270
|
-
}
|
|
271
|
-
return validatorWrapper
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
type MethodConfigDict = {
|
|
275
|
-
readonly [s: string]: (config: any) => PropertyValidatorComponentSync
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const simpleFuncWrap = (validator: PropertyValidatorComponentSync) => () => {
|
|
279
|
-
return validator
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const CONFIG_TO_VALIDATE_METHOD: MethodConfigDict = {
|
|
283
|
-
required: _boolChoice(simpleFuncWrap(isRequired)),
|
|
284
|
-
isInteger: _boolChoice(simpleFuncWrap(isInteger)),
|
|
285
|
-
isNumber: _boolChoice(simpleFuncWrap(isNumber)),
|
|
286
|
-
isString: _boolChoice(simpleFuncWrap(isString)),
|
|
287
|
-
isArray: _boolChoice(simpleFuncWrap(isArray)),
|
|
288
|
-
isBoolean: _boolChoice(simpleFuncWrap(isBoolean)),
|
|
289
|
-
choices: _boolChoice(choices),
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const createPropertyValidator = (
|
|
293
|
-
valueGetter: ValueGetter,
|
|
294
|
-
config: PropertyConfig
|
|
295
|
-
): PropertyValidator => {
|
|
296
|
-
const _propertyValidator: PropertyValidator = async (
|
|
297
|
-
instance,
|
|
298
|
-
instanceData: FunctionalModel
|
|
299
|
-
) => {
|
|
300
|
-
if (!config) {
|
|
301
|
-
config = {}
|
|
302
|
-
}
|
|
303
|
-
const validators: readonly PropertyValidatorComponent[] = [
|
|
304
|
-
...Object.entries(config).map(([key, value]) => {
|
|
305
|
-
const method = CONFIG_TO_VALIDATE_METHOD[key]
|
|
306
|
-
if (method) {
|
|
307
|
-
return method(value)
|
|
308
|
-
}
|
|
309
|
-
return emptyValidator
|
|
310
|
-
}),
|
|
311
|
-
...(config.validators ? config.validators : []),
|
|
312
|
-
].filter(x => x)
|
|
313
|
-
const value = await valueGetter()
|
|
314
|
-
const isRequiredValue = config.required
|
|
315
|
-
? true
|
|
316
|
-
: validators.includes(isRequired)
|
|
317
|
-
if (!value && !isRequiredValue) {
|
|
318
|
-
return []
|
|
319
|
-
}
|
|
320
|
-
const validator = aggregateValidator(value, validators)
|
|
321
|
-
const errors = await validator(instance, instanceData)
|
|
322
|
-
return [...new Set(flatMap(errors))]
|
|
323
|
-
}
|
|
324
|
-
return _propertyValidator
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const createModelValidator = (
|
|
328
|
-
validators: PropertyValidators,
|
|
329
|
-
modelValidators?: readonly ModelComponentValidator[]
|
|
330
|
-
) => {
|
|
331
|
-
const _modelValidator = async (
|
|
332
|
-
instance: ModelInstance<any>,
|
|
333
|
-
options: object
|
|
334
|
-
): Promise<ModelErrors> => {
|
|
335
|
-
return Promise.resolve().then(async () => {
|
|
336
|
-
if (!instance) {
|
|
337
|
-
throw new Error(`Instance cannot be empty`)
|
|
338
|
-
}
|
|
339
|
-
const keysAndFunctions = Object.entries(validators)
|
|
340
|
-
const instanceData = await instance.toObj()
|
|
341
|
-
const propertyValidationErrors = await Promise.all(
|
|
342
|
-
keysAndFunctions.map(async ([key, validator]) => {
|
|
343
|
-
return [key, await validator(instance, instanceData)]
|
|
344
|
-
})
|
|
345
|
-
)
|
|
346
|
-
const modelValidationErrors = (
|
|
347
|
-
await Promise.all(
|
|
348
|
-
modelValidators
|
|
349
|
-
? modelValidators.map(validator =>
|
|
350
|
-
validator(instance, instanceData, options)
|
|
351
|
-
)
|
|
352
|
-
: []
|
|
353
|
-
)
|
|
354
|
-
).filter(x => x)
|
|
355
|
-
const propertyErrors = propertyValidationErrors
|
|
356
|
-
.filter(([, errors]) => Boolean(errors) && errors.length > 0)
|
|
357
|
-
.reduce((acc, [key, errors]) => {
|
|
358
|
-
return merge(acc, { [String(key)]: errors })
|
|
359
|
-
}, {})
|
|
360
|
-
return modelValidationErrors.length > 0
|
|
361
|
-
? merge(propertyErrors, { overall: modelValidationErrors })
|
|
362
|
-
: propertyErrors
|
|
363
|
-
})
|
|
364
|
-
}
|
|
365
|
-
return _modelValidator
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export {
|
|
369
|
-
isNumber,
|
|
370
|
-
isBoolean,
|
|
371
|
-
isString,
|
|
372
|
-
isInteger,
|
|
373
|
-
isType,
|
|
374
|
-
isDate,
|
|
375
|
-
isArray,
|
|
376
|
-
isRequired,
|
|
377
|
-
maxNumber,
|
|
378
|
-
minNumber,
|
|
379
|
-
choices,
|
|
380
|
-
maxTextLength,
|
|
381
|
-
minTextLength,
|
|
382
|
-
meetsRegex,
|
|
383
|
-
aggregateValidator,
|
|
384
|
-
emptyValidator,
|
|
385
|
-
createPropertyValidator,
|
|
386
|
-
createModelValidator,
|
|
387
|
-
arrayType,
|
|
388
|
-
referenceTypeMatch,
|
|
389
|
-
TYPE_PRIMITIVES,
|
|
390
|
-
}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { assert } from 'chai'
|
|
2
|
-
import flatMap from 'lodash/flatMap'
|
|
3
|
-
import { Given, When, Then } from '@cucumber/cucumber'
|
|
4
|
-
import {
|
|
5
|
-
BaseModel,
|
|
6
|
-
UniqueId,
|
|
7
|
-
TextProperty,
|
|
8
|
-
Property,
|
|
9
|
-
WrapperModelMethod,
|
|
10
|
-
WrapperInstanceMethod,
|
|
11
|
-
ArrayProperty,
|
|
12
|
-
validation,
|
|
13
|
-
} from '../src'
|
|
14
|
-
import { ModelInstanceMethod, ModelMethod } from '../src/interfaces'
|
|
15
|
-
|
|
16
|
-
const instanceToString = WrapperInstanceMethod(modelInstance => {
|
|
17
|
-
return `${modelInstance.getModel().getName()}-Instance`
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const instanceToJson = WrapperInstanceMethod(async modelInstance => {
|
|
21
|
-
return JSON.stringify(await modelInstance.toObj())
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
const modelToString = WrapperModelMethod(model => {
|
|
25
|
-
return `${model.getName()}-[${Object.keys(
|
|
26
|
-
model.getModelDefinition().properties
|
|
27
|
-
).join(',')}]`
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const modelWrapper = WrapperModelMethod(model => {
|
|
31
|
-
return model
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
const MODEL_DEFINITIONS = {
|
|
35
|
-
FunctionModel1: BaseModel<{
|
|
36
|
-
name: string
|
|
37
|
-
modelWrapper: ModelMethod
|
|
38
|
-
toString: ModelInstanceMethod
|
|
39
|
-
toJson: ModelInstanceMethod
|
|
40
|
-
}>('FunctionModel1', {
|
|
41
|
-
properties: {
|
|
42
|
-
id: UniqueId({ required: true }),
|
|
43
|
-
name: TextProperty({ required: true }),
|
|
44
|
-
},
|
|
45
|
-
modelMethods: {
|
|
46
|
-
modelWrapper,
|
|
47
|
-
},
|
|
48
|
-
instanceMethods: {
|
|
49
|
-
toString: instanceToString,
|
|
50
|
-
toJson: instanceToJson,
|
|
51
|
-
},
|
|
52
|
-
}),
|
|
53
|
-
TestModel1: BaseModel<{ name: string; type: string; flag: number }>(
|
|
54
|
-
'TestModel1',
|
|
55
|
-
{
|
|
56
|
-
properties: {
|
|
57
|
-
name: Property('Text', { required: true }),
|
|
58
|
-
type: Property('Type', { required: true, isString: true }),
|
|
59
|
-
flag: Property('Flag', { required: true, isNumber: true }),
|
|
60
|
-
},
|
|
61
|
-
}
|
|
62
|
-
),
|
|
63
|
-
ArrayModel1: BaseModel<{ ArrayProperty: readonly number[] }>('ArrayModel1', {
|
|
64
|
-
properties: {
|
|
65
|
-
ArrayProperty: Property('Array', {
|
|
66
|
-
isArray: true,
|
|
67
|
-
validators: [validation.arrayType(validation.TYPE_PRIMITIVES.integer)],
|
|
68
|
-
}),
|
|
69
|
-
},
|
|
70
|
-
}),
|
|
71
|
-
ArrayModel2: BaseModel('ArrayModel2', {
|
|
72
|
-
properties: {
|
|
73
|
-
ArrayProperty: Property('Array', { isArray: true }),
|
|
74
|
-
},
|
|
75
|
-
}),
|
|
76
|
-
ArrayModel3: BaseModel('ArrayModel3', {
|
|
77
|
-
properties: {
|
|
78
|
-
ArrayProperty: ArrayProperty({}),
|
|
79
|
-
},
|
|
80
|
-
}),
|
|
81
|
-
ArrayModel4: BaseModel('ArrayModel4', {
|
|
82
|
-
properties: {
|
|
83
|
-
ArrayProperty: ArrayProperty({
|
|
84
|
-
choices: [4, 5, 6],
|
|
85
|
-
validators: [validation.arrayType(validation.TYPE_PRIMITIVES.integer)],
|
|
86
|
-
}),
|
|
87
|
-
},
|
|
88
|
-
}),
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const MODEL_INPUT_VALUES = {
|
|
92
|
-
FunctionModelData1: {
|
|
93
|
-
id: 'my-id',
|
|
94
|
-
name: 'function-model-name',
|
|
95
|
-
},
|
|
96
|
-
TestModel1a: {
|
|
97
|
-
name: 'my-name',
|
|
98
|
-
type: 1,
|
|
99
|
-
flag: '1',
|
|
100
|
-
},
|
|
101
|
-
TestModel1b: {
|
|
102
|
-
name: 'my-name',
|
|
103
|
-
type: 'a-type',
|
|
104
|
-
flag: 1,
|
|
105
|
-
},
|
|
106
|
-
ArrayModelData1: {
|
|
107
|
-
ArrayProperty: [1, 2, 3, 4, 5],
|
|
108
|
-
},
|
|
109
|
-
ArrayModelData2: {
|
|
110
|
-
ArrayProperty: 'a-string',
|
|
111
|
-
},
|
|
112
|
-
ArrayModelData3: {
|
|
113
|
-
ArrayProperty: ['a-string', 'a-string2'],
|
|
114
|
-
},
|
|
115
|
-
ArrayModelData4: {
|
|
116
|
-
ArrayProperty: ['a-string', 1, {}, true],
|
|
117
|
-
},
|
|
118
|
-
ArrayModelData5: {
|
|
119
|
-
ArrayProperty: [4, 5, 5, 5, 6],
|
|
120
|
-
},
|
|
121
|
-
ArrayModelData6: {
|
|
122
|
-
ArrayProperty: [4, 5, 5, 5, 6, 1],
|
|
123
|
-
},
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const EXPECTED_FIELDS = {
|
|
127
|
-
TestModel1b: ['name', 'type', 'flag'],
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
Given(
|
|
131
|
-
'the {word} has been created, with {word} inputs provided',
|
|
132
|
-
function (modelDefinition, modelInputValues) {
|
|
133
|
-
// @ts-ignore
|
|
134
|
-
const def = MODEL_DEFINITIONS[modelDefinition]
|
|
135
|
-
this.model = def
|
|
136
|
-
|
|
137
|
-
// @ts-ignore
|
|
138
|
-
const input = MODEL_INPUT_VALUES[modelInputValues]
|
|
139
|
-
if (!def) {
|
|
140
|
-
throw new Error(`${modelDefinition} did not result in a definition`)
|
|
141
|
-
}
|
|
142
|
-
if (!input) {
|
|
143
|
-
throw new Error(`${modelInputValues} did not result in an input`)
|
|
144
|
-
}
|
|
145
|
-
this.instance = def.create(input)
|
|
146
|
-
}
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
When('functions.validate is called', function () {
|
|
150
|
-
// @ts-ignore
|
|
151
|
-
return this.instance.validate().then(x => {
|
|
152
|
-
this.errors = x
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
Then('an array of {int} errors is shown', function (errorCount) {
|
|
157
|
-
const errors = flatMap(Object.values(this.errors))
|
|
158
|
-
if (errors.length !== errorCount) {
|
|
159
|
-
console.error(this.errors)
|
|
160
|
-
}
|
|
161
|
-
assert.equal(errors.length, errorCount)
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
Given('{word} model is used', function (modelDefinition) {
|
|
165
|
-
// @ts-ignore
|
|
166
|
-
const def = MODEL_DEFINITIONS[modelDefinition]
|
|
167
|
-
if (!def) {
|
|
168
|
-
throw new Error(`${modelDefinition} did not result in a definition`)
|
|
169
|
-
}
|
|
170
|
-
this.modelDefinition = def
|
|
171
|
-
this.model = def
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
When('{word} data is inserted', function (modelInputValues) {
|
|
175
|
-
// @ts-ignore
|
|
176
|
-
const input = MODEL_INPUT_VALUES[modelInputValues]
|
|
177
|
-
if (!input) {
|
|
178
|
-
throw new Error(`${modelInputValues} did not result in an input`)
|
|
179
|
-
}
|
|
180
|
-
this.instance = this.modelDefinition.create(input)
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
Then('{word} expected property is found', function (properties) {
|
|
184
|
-
// @ts-ignore
|
|
185
|
-
const propertyArray = EXPECTED_FIELDS[properties]
|
|
186
|
-
if (!propertyArray) {
|
|
187
|
-
throw new Error(`${properties} did not result in properties`)
|
|
188
|
-
}
|
|
189
|
-
// @ts-ignore
|
|
190
|
-
propertyArray.forEach(key => {
|
|
191
|
-
if (!(key in this.instance.get)) {
|
|
192
|
-
throw new Error(`Did not find ${key} in model`)
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
Then('the {word} property is called on the model', function (property) {
|
|
198
|
-
this.results = this.instance.get[property]()
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
Then('the array values match', async function (table) {
|
|
202
|
-
const expected = JSON.parse(table.rowsHash().array)
|
|
203
|
-
assert.deepEqual(await this.results, expected)
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
Then('{word} property is found', function (propertyKey) {
|
|
207
|
-
assert.isFunction(this.instance.get[propertyKey])
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
Then('{word} instance function is found', function (instanceFunctionKey) {
|
|
211
|
-
assert.isFunction(this.instance.methods[instanceFunctionKey])
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
Then('{word} model function is found', function (modelFunctionKey) {
|
|
215
|
-
assert.isFunction(this.model.methods[modelFunctionKey])
|
|
216
|
-
})
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { Given, When, Then } from '@cucumber/cucumber'
|
|
2
|
-
import { assert } from 'chai'
|
|
3
|
-
import { BaseModel } from '../src/models'
|
|
4
|
-
import { WrapperInstanceMethod, WrapperModelMethod } from '../src/methods'
|
|
5
|
-
import {
|
|
6
|
-
Model,
|
|
7
|
-
FunctionalModel,
|
|
8
|
-
ModelInstanceMethodTyped,
|
|
9
|
-
ModelMethodTyped,
|
|
10
|
-
ModelInstanceInputData,
|
|
11
|
-
Nullable,
|
|
12
|
-
} from '../src/interfaces'
|
|
13
|
-
import { ObjectProperty, TextProperty, UniqueId } from '../src/properties'
|
|
14
|
-
|
|
15
|
-
type MyTSType = {
|
|
16
|
-
name: string
|
|
17
|
-
data: FunctionalModel
|
|
18
|
-
notRequired?: Nullable<string>
|
|
19
|
-
myMethod: ModelInstanceMethodTyped<MyTSType>
|
|
20
|
-
myModelMethod: ModelMethodTyped<MyTSType>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const TE_FULL_TEST = () => {
|
|
24
|
-
const m = BaseModel<MyTSType>('TSFullTests', {
|
|
25
|
-
properties: {
|
|
26
|
-
id: UniqueId({ value: 'my-unique-id' }),
|
|
27
|
-
name: TextProperty({ required: true }),
|
|
28
|
-
data: ObjectProperty({}),
|
|
29
|
-
notRequired: TextProperty({}),
|
|
30
|
-
},
|
|
31
|
-
instanceMethods: {
|
|
32
|
-
myMethod: WrapperInstanceMethod<MyTSType>((instance, args) => {
|
|
33
|
-
return 'InstanceMethod'
|
|
34
|
-
}),
|
|
35
|
-
},
|
|
36
|
-
modelMethods: {
|
|
37
|
-
myModelMethod: WrapperModelMethod<MyTSType>((model, args) => {
|
|
38
|
-
return 'ModelMethod'
|
|
39
|
-
}),
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
return m
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const TE_FULL_TEST_1 = () => {
|
|
46
|
-
return {
|
|
47
|
-
id: 'my-unique-id',
|
|
48
|
-
name: 'My name',
|
|
49
|
-
data: { my: 'data' },
|
|
50
|
-
notRequired: null,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const DATA_SET: { [s: string]: () => ModelInstanceInputData<MyTSType> } = {
|
|
55
|
-
TE_FULL_TEST_1,
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const MODEL_SET: { [s: string]: () => Model<MyTSType> } = {
|
|
59
|
-
TE_FULL_TEST,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
Given('model {word} is used', function (modelName: string) {
|
|
63
|
-
this.theModel = MODEL_SET[modelName]()
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
When(
|
|
67
|
-
'a model instanced is created is called on model with {word}',
|
|
68
|
-
async function (dataName: string) {
|
|
69
|
-
this.theModelInstance = this.theModel.create(DATA_SET[dataName]())
|
|
70
|
-
}
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
When('toObj is called on the model instance', async function () {
|
|
74
|
-
this.results = await this.theModelInstance.toObj()
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
Then('the results match {word} obj data', function (dataName) {
|
|
78
|
-
const data = DATA_SET[dataName]()
|
|
79
|
-
assert.deepEqual(data, this.results)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
When('instance method {word} is called', async function (methodName) {
|
|
83
|
-
this.instanceMethodActual = await this.theModelInstance.methods[methodName]()
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
Then('the result of instance method is {word}', function (expected) {
|
|
87
|
-
const actual = this.instanceMethodActual
|
|
88
|
-
assert.equal(actual, expected)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
When('model method {word} is called', async function (methodName) {
|
|
92
|
-
this.modelMethodActual = await this.theModel.methods[methodName]()
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
Then('the result of model method is {word}', function (expected) {
|
|
96
|
-
const actual = this.modelMethodActual
|
|
97
|
-
assert.equal(actual, expected)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
When('validate is called on model instance', async function () {
|
|
101
|
-
this.validationActual = await this.theModelInstance.validate()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
Then('the model instance validated successfully', function () {
|
|
105
|
-
const expected = {}
|
|
106
|
-
assert.deepEqual(this.validationActual, expected)
|
|
107
|
-
})
|