functional-models 1.0.25 → 1.1.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.
Files changed (42) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc +9 -15
  3. package/cucumber.js +10 -0
  4. package/features/arrayFields.feature +7 -7
  5. package/features/basic-ts.feature +13 -0
  6. package/features/functions.feature +2 -3
  7. package/package.json +34 -10
  8. package/src/constants.ts +15 -0
  9. package/src/errors.ts +18 -0
  10. package/src/index.ts +11 -0
  11. package/src/interfaces.ts +323 -0
  12. package/src/lazy.ts +24 -0
  13. package/src/methods.ts +30 -0
  14. package/src/models.ts +183 -0
  15. package/src/properties.ts +375 -0
  16. package/src/serialization.ts +39 -0
  17. package/src/utils.ts +42 -0
  18. package/src/validation.ts +390 -0
  19. package/{features/stepDefinitions/steps.js → stepDefinitions/oldSteps.ts} +76 -53
  20. package/stepDefinitions/tssteps.ts +107 -0
  21. package/test/src/errors.test.ts +31 -0
  22. package/test/src/{lazy.test.js → lazy.test.ts} +4 -4
  23. package/test/src/methods.test.ts +45 -0
  24. package/test/src/models.test.ts +417 -0
  25. package/test/src/{properties.test.js → properties.test.ts} +257 -64
  26. package/test/src/serialization.test.ts +80 -0
  27. package/test/src/{utils.test.js → utils.test.ts} +29 -7
  28. package/test/src/{validation.test.js → validation.test.ts} +278 -210
  29. package/tsconfig.json +100 -0
  30. package/src/functions.js +0 -7
  31. package/src/index.js +0 -7
  32. package/src/lazy.js +0 -19
  33. package/src/models.js +0 -150
  34. package/src/properties.js +0 -261
  35. package/src/serialization.js +0 -47
  36. package/src/utils.js +0 -42
  37. package/src/validation.js +0 -274
  38. package/test/base/index.test.js +0 -5
  39. package/test/src/functions.test.js +0 -45
  40. package/test/src/index.test.js +0 -5
  41. package/test/src/models.test.js +0 -380
  42. package/test/src/serialization.test.js +0 -127
package/src/models.ts ADDED
@@ -0,0 +1,183 @@
1
+ import merge from 'lodash/merge'
2
+ import { toJsonAble } from './serialization'
3
+ import { createModelValidator } from './validation'
4
+ import { UniqueId } from './properties'
5
+ import {
6
+ Model,
7
+ InstanceMethodGetters,
8
+ Nullable,
9
+ ModelDefinition,
10
+ ModelInstance,
11
+ ModelOptions,
12
+ ReferenceFunctions,
13
+ PropertyGetters,
14
+ OptionalModelOptions,
15
+ ReferencePropertyInstance,
16
+ ReferenceValueType,
17
+ PropertyValidators,
18
+ FunctionalModel,
19
+ ModelInstanceInputData,
20
+ ModelInstanceMethodTyped,
21
+ ModelMethodTyped,
22
+ ModelMethodGetters,
23
+ } from './interfaces'
24
+
25
+ const _defaultOptions = (): ModelOptions => ({
26
+ instanceCreatedCallback: null,
27
+ })
28
+
29
+ const _convertOptions = (options?: OptionalModelOptions) => {
30
+ const r: ModelOptions = merge({}, _defaultOptions(), options)
31
+ return r
32
+ }
33
+
34
+ const _createModelDefWithPrimaryKey = <T extends FunctionalModel>(
35
+ keyToProperty: ModelDefinition<T>
36
+ ): ModelDefinition<T> => {
37
+ return {
38
+ getPrimaryKeyName: () => 'id',
39
+ modelMethods: keyToProperty.modelMethods,
40
+ instanceMethods: keyToProperty.instanceMethods,
41
+ properties: {
42
+ id: UniqueId({ required: true }),
43
+ ...keyToProperty.properties,
44
+ },
45
+ modelValidators: keyToProperty.modelValidators,
46
+ }
47
+ }
48
+
49
+ const BaseModel = <T extends FunctionalModel>(
50
+ modelName: string,
51
+ modelDefinition: ModelDefinition<T>,
52
+ //keyToProperty: IModelDefinition2<T>,
53
+ options?: OptionalModelOptions
54
+ ) => {
55
+ /*
56
+ * This non-functional approach is specifically used to
57
+ * allow instances to be able to refer back to its parent without
58
+ * having to duplicate it for every instance.
59
+ * This is set at the very end and returned, so it can be referenced
60
+ * throughout instance methods.
61
+ */
62
+ // eslint-disable-next-line functional/no-let
63
+ let model: Nullable<Model<T>> = null
64
+ const theOptions = _convertOptions(options)
65
+ modelDefinition = !modelDefinition.getPrimaryKeyName
66
+ ? _createModelDefWithPrimaryKey(modelDefinition)
67
+ : modelDefinition
68
+
69
+ // @ts-ignore
70
+ const getPrimaryKeyName = () => modelDefinition.getPrimaryKeyName()
71
+ const getPrimaryKey = (t: ModelInstanceInputData<T>) =>
72
+ // @ts-ignore
73
+ t[getPrimaryKeyName()] as string
74
+
75
+ const create = (instanceValues: ModelInstanceInputData<T>) => {
76
+ // eslint-disable-next-line functional/no-let
77
+ let instance: Nullable<ModelInstance<T>> = null
78
+ const startingInternals: {
79
+ readonly get: PropertyGetters<T> & { readonly id: () => string }
80
+ readonly validators: PropertyValidators
81
+ readonly references: ReferenceFunctions
82
+ } = {
83
+ get: {} as PropertyGetters<T> & { readonly id: () => string },
84
+ validators: {},
85
+ references: {},
86
+ }
87
+ const loadedInternals = Object.entries(modelDefinition.properties).reduce(
88
+ (acc, [key, property]) => {
89
+ // @ts-ignore
90
+ const propertyGetter = property.createGetter(instanceValues[key])
91
+ // @ts-ignore
92
+ const propertyValidator = property.getValidator(propertyGetter)
93
+ const fleshedOutInstanceProperties = {
94
+ get: {
95
+ [key]: propertyGetter,
96
+ },
97
+ validators: {
98
+ [key]: propertyValidator,
99
+ },
100
+ }
101
+ const asReferenced = property as ReferencePropertyInstance<any>
102
+ const referencedProperty = asReferenced.getReferencedId
103
+ ? {
104
+ references: {
105
+ [key]: () =>
106
+ asReferenced.getReferencedId(
107
+ // @ts-ignore
108
+ instanceValues[key] as ReferenceValueType<any>
109
+ ),
110
+ },
111
+ }
112
+ : {}
113
+
114
+ return merge(acc, fleshedOutInstanceProperties, referencedProperty)
115
+ },
116
+ startingInternals
117
+ )
118
+ const methods = Object.entries(
119
+ modelDefinition.instanceMethods || {}
120
+ ).reduce((acc, [key, func]) => {
121
+ return merge(acc, {
122
+ [key]: (...args: readonly any[]) => {
123
+ return (func as ModelInstanceMethodTyped<T>)(
124
+ instance as ModelInstance<T>,
125
+ ...args
126
+ )
127
+ },
128
+ })
129
+ }, {}) as InstanceMethodGetters<T>
130
+
131
+ const getModel = () => model as Model<T>
132
+ const toObj = toJsonAble(loadedInternals.get)
133
+ const validate = (options = {}) => {
134
+ return createModelValidator(
135
+ loadedInternals.validators,
136
+ modelDefinition.modelValidators || []
137
+ )(instance as ModelInstance<T>, options)
138
+ }
139
+
140
+ instance = merge(loadedInternals, {
141
+ getModel,
142
+ toObj,
143
+ getPrimaryKey: () => getPrimaryKey(instanceValues),
144
+ getPrimaryKeyName,
145
+ validate,
146
+ methods,
147
+ })
148
+
149
+ if (theOptions.instanceCreatedCallback) {
150
+ const toCall = Array.isArray(theOptions.instanceCreatedCallback)
151
+ ? theOptions.instanceCreatedCallback
152
+ : [theOptions.instanceCreatedCallback]
153
+ toCall.map(func => func(instance as ModelInstance<T>))
154
+ }
155
+ return instance
156
+ }
157
+
158
+ const fleshedOutModelFunctions = Object.entries(
159
+ modelDefinition.modelMethods || {}
160
+ ).reduce((acc, [key, func]) => {
161
+ return merge(acc, {
162
+ [key]: (...args: readonly any[]) => {
163
+ return (func as ModelMethodTyped<T>)(model as Model<T>, ...args)
164
+ },
165
+ })
166
+ }, {}) as ModelMethodGetters<T>
167
+
168
+ // This sets the model that is used by the instances later.
169
+ model = merge(
170
+ {},
171
+ {
172
+ create,
173
+ getName: () => modelName,
174
+ getModelDefinition: () => modelDefinition,
175
+ getPrimaryKeyName,
176
+ getPrimaryKey,
177
+ methods: fleshedOutModelFunctions,
178
+ }
179
+ )
180
+ return model as Model<T>
181
+ }
182
+
183
+ export { BaseModel }
@@ -0,0 +1,375 @@
1
+ import identity from 'lodash/identity'
2
+ import merge from 'lodash/merge'
3
+ import {
4
+ createPropertyValidator,
5
+ emptyValidator,
6
+ maxTextLength,
7
+ minTextLength,
8
+ minNumber,
9
+ maxNumber,
10
+ isType,
11
+ referenceTypeMatch,
12
+ meetsRegex,
13
+ } from './validation'
14
+ import { PROPERTY_TYPES } from './constants'
15
+ import { lazyValue } from './lazy'
16
+ import { createUuid } from './utils'
17
+ import {
18
+ ReferenceValueType,
19
+ ModelInstance,
20
+ MaybeEmpty,
21
+ Nullable,
22
+ PrimaryKeyType,
23
+ Model,
24
+ PropertyInstance,
25
+ FunctionalType,
26
+ PropertyConfig,
27
+ ValueGetter,
28
+ MaybeFunction,
29
+ Arrayable,
30
+ PropertyValidatorComponent,
31
+ PropertyValidator,
32
+ ReferencePropertyInstance,
33
+ ModelInstanceInputData,
34
+ FunctionalModel,
35
+ JsonAble,
36
+ } from './interfaces'
37
+
38
+ const EMAIL_REGEX =
39
+ /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/u
40
+
41
+ function _getValidatorFromConfigElseEmpty<T>(
42
+ input: T | undefined,
43
+ // eslint-disable-next-line no-unused-vars
44
+ validatorGetter: (t: T) => PropertyValidatorComponent
45
+ ) {
46
+ if (input !== undefined) {
47
+ const validator = validatorGetter(input)
48
+ return validator
49
+ }
50
+ return emptyValidator
51
+ }
52
+
53
+ const _mergeValidators = (
54
+ config: PropertyConfig | undefined,
55
+ validators: readonly PropertyValidatorComponent[]
56
+ ) => {
57
+ return [...validators, ...(config?.validators ? config.validators : [])]
58
+ }
59
+
60
+ function Property<T extends Arrayable<FunctionalType>>(
61
+ type: string,
62
+ config: PropertyConfig = {},
63
+ additionalMetadata = {}
64
+ ) {
65
+ if (!type && !config?.type) {
66
+ throw new Error(`Property type must be provided.`)
67
+ }
68
+ if (config?.type) {
69
+ type = config.type
70
+ }
71
+ const getConstantValue = () =>
72
+ (config?.value !== undefined ? config.value : undefined) as T
73
+ const getDefaultValue = () =>
74
+ (config?.defaultValue !== undefined ? config.defaultValue : undefined) as T
75
+ const getChoices = () => config?.choices || []
76
+ const lazyLoadMethod = config?.lazyLoadMethod || false
77
+ const valueSelector = config?.valueSelector || identity
78
+ if (typeof valueSelector !== 'function') {
79
+ throw new Error(`valueSelector must be a function`)
80
+ }
81
+
82
+ const r: PropertyInstance<T> = {
83
+ ...additionalMetadata,
84
+ getConfig: () => config || {},
85
+ getChoices,
86
+ getDefaultValue,
87
+ getConstantValue,
88
+ getPropertyType: () => type,
89
+ createGetter: (instanceValue: T): ValueGetter => {
90
+ const value = getConstantValue()
91
+ if (value !== undefined) {
92
+ return () => value
93
+ }
94
+ const defaultValue = getDefaultValue()
95
+ if (
96
+ defaultValue !== undefined &&
97
+ (instanceValue === null || instanceValue === undefined)
98
+ ) {
99
+ return () => defaultValue
100
+ }
101
+ const method = lazyLoadMethod
102
+ ? // eslint-disable-next-line no-unused-vars
103
+ (lazyValue(lazyLoadMethod) as (value: T) => Promise<T>)
104
+ : typeof instanceValue === 'function'
105
+ ? (instanceValue as () => T)
106
+ : () => instanceValue
107
+ return () => {
108
+ return valueSelector(method(instanceValue))
109
+ }
110
+ },
111
+ getValidator: valueGetter => {
112
+ const validator = createPropertyValidator(valueGetter, config)
113
+ const _propertyValidatorWrapper: PropertyValidator = async (
114
+ instance,
115
+ instanceData
116
+ ) => {
117
+ return validator(instance, instanceData)
118
+ }
119
+ return _propertyValidatorWrapper
120
+ },
121
+ }
122
+ return r
123
+ }
124
+
125
+ const DateProperty = (config: PropertyConfig = {}, additionalMetadata = {}) =>
126
+ Property<MaybeEmpty<Date>>(
127
+ PROPERTY_TYPES.DateProperty,
128
+ merge(
129
+ {
130
+ lazyLoadMethod: (value: Arrayable<FunctionalType>) => {
131
+ if (!value && config?.autoNow) {
132
+ return new Date()
133
+ }
134
+ return value
135
+ },
136
+ },
137
+ config
138
+ ),
139
+ additionalMetadata
140
+ )
141
+
142
+ const ArrayProperty = <T extends FunctionalType>(
143
+ config = {},
144
+ additionalMetadata = {}
145
+ ) =>
146
+ Property<readonly T[]>(
147
+ PROPERTY_TYPES.ArrayProperty,
148
+ {
149
+ defaultValue: [],
150
+ ...config,
151
+ isArray: true,
152
+ },
153
+ additionalMetadata
154
+ )
155
+
156
+ const ObjectProperty = (config = {}, additionalMetadata = {}) =>
157
+ Property<{ readonly [s: string]: JsonAble }>(
158
+ PROPERTY_TYPES.ObjectProperty,
159
+ merge(config, {
160
+ validators: _mergeValidators(config, [isType('object')]),
161
+ }),
162
+ additionalMetadata
163
+ )
164
+
165
+ const TextProperty = (config: PropertyConfig = {}, additionalMetadata = {}) =>
166
+ Property<MaybeEmpty<string>>(
167
+ PROPERTY_TYPES.TextProperty,
168
+ merge(config, {
169
+ isString: true,
170
+ validators: _mergeValidators(config, [
171
+ _getValidatorFromConfigElseEmpty(config?.maxLength, (value: number) =>
172
+ maxTextLength(value)
173
+ ),
174
+ _getValidatorFromConfigElseEmpty(config?.minLength, (value: number) =>
175
+ minTextLength(value)
176
+ ),
177
+ ]),
178
+ }),
179
+ additionalMetadata
180
+ )
181
+
182
+ const IntegerProperty = (
183
+ config: PropertyConfig = {},
184
+ additionalMetadata = {}
185
+ ) =>
186
+ Property<MaybeEmpty<number>>(
187
+ PROPERTY_TYPES.IntegerProperty,
188
+ merge(config, {
189
+ isInteger: true,
190
+ validators: _mergeValidators(config, [
191
+ _getValidatorFromConfigElseEmpty(config?.minValue, value =>
192
+ minNumber(value)
193
+ ),
194
+ _getValidatorFromConfigElseEmpty(config?.maxValue, value =>
195
+ maxNumber(value)
196
+ ),
197
+ ]),
198
+ }),
199
+ additionalMetadata
200
+ )
201
+
202
+ const NumberProperty = (config: PropertyConfig = {}, additionalMetadata = {}) =>
203
+ Property<MaybeEmpty<number>>(
204
+ PROPERTY_TYPES.NumberProperty,
205
+ merge(config, {
206
+ isNumber: true,
207
+ validators: _mergeValidators(config, [
208
+ _getValidatorFromConfigElseEmpty(config?.minValue, value =>
209
+ minNumber(value)
210
+ ),
211
+ _getValidatorFromConfigElseEmpty(config?.maxValue, value =>
212
+ maxNumber(value)
213
+ ),
214
+ ]),
215
+ }),
216
+ additionalMetadata
217
+ )
218
+
219
+ const ConstantValueProperty = (
220
+ value: string,
221
+ config: PropertyConfig = {},
222
+ additionalMetadata = {}
223
+ ) =>
224
+ TextProperty(
225
+ merge(config, {
226
+ type: PROPERTY_TYPES.ConstantValueProperty,
227
+ value,
228
+ }),
229
+ additionalMetadata
230
+ )
231
+
232
+ const EmailProperty = (config: PropertyConfig = {}, additionalMetadata = {}) =>
233
+ TextProperty(
234
+ merge(config, {
235
+ type: PROPERTY_TYPES.EmailProperty,
236
+ validators: _mergeValidators(config, [meetsRegex(EMAIL_REGEX)]),
237
+ }),
238
+ additionalMetadata
239
+ )
240
+
241
+ const BooleanProperty = (
242
+ config: PropertyConfig = {},
243
+ additionalMetadata = {}
244
+ ) =>
245
+ Property<MaybeEmpty<boolean>>(
246
+ PROPERTY_TYPES.BooleanProperty,
247
+ merge(config, {
248
+ isBoolean: true,
249
+ }),
250
+ additionalMetadata
251
+ )
252
+
253
+ const UniqueId = (config: PropertyConfig = {}, additionalMetadata = {}) =>
254
+ Property<string>(
255
+ PROPERTY_TYPES.UniqueId,
256
+ merge(
257
+ {
258
+ lazyLoadMethod: (value: Arrayable<FunctionalType>) => {
259
+ if (!value) {
260
+ return createUuid()
261
+ }
262
+ return value
263
+ },
264
+ },
265
+ config
266
+ ),
267
+ additionalMetadata
268
+ )
269
+
270
+ const ReferenceProperty = <T extends FunctionalModel>(
271
+ model: MaybeFunction<Model<T>>,
272
+ config: PropertyConfig = {},
273
+ additionalMetadata = {}
274
+ ) => {
275
+ if (!model) {
276
+ throw new Error('Must include the referenced model')
277
+ }
278
+
279
+ const _getModel = () => {
280
+ if (typeof model === 'function') {
281
+ return model()
282
+ }
283
+ return model
284
+ }
285
+
286
+ const validators = _mergeValidators(config, [referenceTypeMatch<T>(model)])
287
+
288
+ const _getId =
289
+ (instanceValues: ReferenceValueType<T>) =>
290
+ (): MaybeEmpty<PrimaryKeyType> => {
291
+ if (!instanceValues) {
292
+ return null
293
+ }
294
+ if (typeof instanceValues === 'number') {
295
+ return instanceValues
296
+ }
297
+ if (typeof instanceValues === 'string') {
298
+ return instanceValues
299
+ }
300
+ if ((instanceValues as ModelInstance<T>).getPrimaryKey) {
301
+ return (instanceValues as ModelInstance<T>).getPrimaryKey()
302
+ }
303
+
304
+ const theModel = _getModel()
305
+ const primaryKey = theModel.getPrimaryKeyName()
306
+
307
+ // @ts-ignore
308
+ return (instanceValues as ModelInstanceInputData<T>)[
309
+ primaryKey
310
+ ] as PrimaryKeyType
311
+ }
312
+
313
+ const lazyLoadMethod = async (instanceValues: ReferenceValueType<T>) => {
314
+ const valueIsModelInstance =
315
+ instanceValues && (instanceValues as ModelInstance<T>).getPrimaryKeyName
316
+ const _getInstanceReturn = (objToUse: ReferenceValueType<T>) => {
317
+ // We need to determine if the object we just go is an actual model instance to determine if we need to make one.
318
+ const objIsModelInstance =
319
+ instanceValues && (instanceValues as ModelInstance<T>).getPrimaryKeyName
320
+
321
+ const instance = objIsModelInstance
322
+ ? objToUse
323
+ : _getModel().create(objToUse as ModelInstanceInputData<T>)
324
+ return merge({}, instance, {
325
+ toObj: _getId(instanceValues),
326
+ })
327
+ }
328
+
329
+ if (valueIsModelInstance) {
330
+ return _getInstanceReturn(instanceValues)
331
+ }
332
+ if (config?.fetcher) {
333
+ const id = await _getId(instanceValues)()
334
+ const model = _getModel()
335
+ if (id !== null && id !== undefined) {
336
+ const obj = await config.fetcher(model, id)
337
+ return _getInstanceReturn(obj)
338
+ }
339
+ return null
340
+ }
341
+ return _getId(instanceValues)()
342
+ }
343
+
344
+ const p: ReferencePropertyInstance<T> = merge(
345
+ Property<ModelInstance<T> | T | MaybeEmpty<PrimaryKeyType>>(
346
+ PROPERTY_TYPES.ReferenceProperty,
347
+ merge({}, config, {
348
+ validators,
349
+ lazyLoadMethod,
350
+ }),
351
+ additionalMetadata
352
+ ),
353
+ {
354
+ getReferencedId: (instanceValues: ReferenceValueType<T>) =>
355
+ _getId(instanceValues)(),
356
+ getReferencedModel: _getModel,
357
+ }
358
+ )
359
+ return p
360
+ }
361
+
362
+ export {
363
+ Property,
364
+ UniqueId,
365
+ DateProperty,
366
+ ArrayProperty,
367
+ ReferenceProperty,
368
+ IntegerProperty,
369
+ TextProperty,
370
+ ConstantValueProperty,
371
+ NumberProperty,
372
+ ObjectProperty,
373
+ EmailProperty,
374
+ BooleanProperty,
375
+ }
@@ -0,0 +1,39 @@
1
+ import merge from 'lodash/merge'
2
+ import { PropertyGetters, JsonAble, toObj } from './interfaces'
3
+
4
+ const _getValue = async (value: any): Promise<JsonAble> => {
5
+ if (value === undefined) {
6
+ return null
7
+ }
8
+ if (value === null) {
9
+ return null
10
+ }
11
+ const type = typeof value
12
+ const asFunction = value as Function
13
+ if (type === 'function') {
14
+ return _getValue(await asFunction())
15
+ }
16
+ // Nested Object
17
+ const asModel = value.toObj
18
+ if (asModel) {
19
+ return _getValue(await asModel())
20
+ }
21
+ // Dates
22
+ const asDate = value as Date
23
+ if (type === 'object' && asDate.toISOString) {
24
+ return _getValue(asDate.toISOString())
25
+ }
26
+ return value
27
+ }
28
+
29
+ const toJsonAble =
30
+ (keyToFunc: PropertyGetters<any>): toObj =>
31
+ async () => {
32
+ return Object.entries(keyToFunc).reduce(async (acc, [key, value]) => {
33
+ const realAcc = await acc
34
+ const trueValue = await _getValue(await value)
35
+ return merge(realAcc, { [key]: trueValue })
36
+ }, Promise.resolve({}))
37
+ }
38
+
39
+ export { toJsonAble }
package/src/utils.ts ADDED
@@ -0,0 +1,42 @@
1
+ // @ts-ignore
2
+ import getRandomValuesFunc from 'get-random-values'
3
+
4
+ const HEX = 16
5
+ const FOUR = 4
6
+ const FIFTEEN = 15
7
+
8
+ const getRandomValues = (): Uint8Array => {
9
+ const array = new Uint8Array(1)
10
+ if (typeof window !== 'undefined') {
11
+ if (window.crypto) {
12
+ return window.crypto.getRandomValues(array)
13
+ }
14
+ // @ts-ignore
15
+ if (window.msCrypto) {
16
+ // @ts-ignore
17
+ return window.msCrypto.getRandomValues(array)
18
+ }
19
+ }
20
+
21
+ return getRandomValuesFunc(array)
22
+ }
23
+
24
+ const createUuid = (): string => {
25
+ // eslint-disable-next-line no-magic-numbers,require-unicode-regexp
26
+ // @ts-ignore
27
+ // eslint-disable-next-line no-magic-numbers,require-unicode-regexp
28
+ return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: any) => {
29
+ const value = getRandomValues()[0] & (FIFTEEN >> (c / FOUR))
30
+ return (c ^ value).toString(HEX)
31
+ })
32
+ }
33
+
34
+ const toTitleCase = (string: string) => {
35
+ return `${string.slice(0, 1).toUpperCase()}${string.slice(1)}`
36
+ }
37
+
38
+ const loweredTitleCase = (string: string) => {
39
+ return `${string.slice(0, 1).toLowerCase()}${string.slice(1)}`
40
+ }
41
+
42
+ export { loweredTitleCase, toTitleCase, createUuid }