pols-validator 2.4.4 → 2.4.5

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/dist/rules.js CHANGED
@@ -36,7 +36,7 @@ const isObject = (context, wrapper, schema) => {
36
36
  errorMessages.push(...result2.messages);
37
37
  }
38
38
  else {
39
- if (result2 !== undefined)
39
+ if (result2.result !== undefined)
40
40
  newWrapperValue[key] = result2.result;
41
41
  }
42
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pols-validator",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- import { PRules } from "./rules"
2
- import { PRulesParams } from "./rulesEngine"
3
-
4
- export const rules = (params?: PRulesParams) => new PRules(params)
5
-
6
- export { PRules, PRulesParams }
7
-
8
- export { PRulesResponse, PRulesWrapper, PRulesFunction } from './rulesEngine'
package/src/rules.ts DELETED
@@ -1,426 +0,0 @@
1
- import { PRulesEngine, PRulesWrapper } from "./rulesEngine"
2
- import { PDate } from "pols-date"
3
- import { sanitize } from 'isomorphic-dompurify'
4
- import { PUtilsNumber, PUtilsString } from "pols-utils"
5
-
6
- const isObject = (context: PRules, wrapper: PRulesWrapper, schema?: Record<string, PRules>) => {
7
- const message = `'${wrapper.label}' debe ser un objeto`
8
-
9
- if (typeof wrapper.value == 'string') {
10
- try {
11
- wrapper.value = JSON.parse(wrapper.value)
12
- } catch {
13
- return message
14
- }
15
- if (wrapper.value == null || typeof wrapper.value != 'object') return message
16
- } else if (wrapper.value != null) {
17
- if (typeof wrapper.value != 'object') return message
18
- } else {
19
- return message
20
- }
21
-
22
- /* Realiza la validación de cada propiedad */
23
- const newWrapperValue: Record<string, unknown> = {}
24
- const errorMessages: string[] = []
25
- for (const key in schema) {
26
- const rulesInside = schema[key]
27
- const labelIndise = rulesInside.label ?? key
28
- rulesInside.label = `${context.label ? `${context.label}${context.separator}` : ''}${labelIndise}`
29
-
30
- const result2 = rulesInside.validate(wrapper.value[key], false)
31
- if (result2.error == true) {
32
- errorMessages.push(...result2.messages)
33
- } else {
34
- if (result2 !== undefined) newWrapperValue[key] = result2.result
35
- }
36
- }
37
- if (errorMessages.length) {
38
- return errorMessages
39
- } else {
40
- wrapper.value = newWrapperValue
41
- }
42
- }
43
-
44
- export class PRules extends PRulesEngine {
45
- isAlphanumeric() {
46
- this.add(this.isAlphanumeric.name, (wrapper: PRulesWrapper) => {
47
- if (typeof wrapper.value == 'number') {
48
- wrapper.value = wrapper.value.toString()
49
- } else if (typeof wrapper.value != 'string') {
50
- return `'${wrapper.label}' debe ser un alfanumérico`
51
- }
52
- })
53
- return this
54
- }
55
-
56
- isEmailAddress() {
57
- this.isAlphanumeric()
58
- this.add(this.isEmailAddress.name, (wrapper: PRulesWrapper) => {
59
- if (!(wrapper.value as string).match(/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/)) return `'${wrapper.label}' debe ser una dirección de correo`
60
- })
61
- return this
62
- }
63
-
64
- isDateTime() {
65
- this.add(this.isDateTime.name, (wrapper: PRulesWrapper) => {
66
- const message = `'${wrapper.label}' tiene un formato de fecha y hora no válido`
67
- const newDate = new PDate(wrapper.value)
68
- if (newDate.isInvalidDate) return message
69
- wrapper.value = newDate
70
- })
71
- return this
72
- }
73
-
74
- isDate() {
75
- return this.isDateTime().add(this.isDate.name, (wrapper: PRulesWrapper<PDate>) => {
76
- wrapper.value.clearClockTime()
77
- })
78
- }
79
-
80
- isTime() {
81
- this.add(this.isTime.name, (wrapper: PRulesWrapper) => {
82
- const message = `'${wrapper.label}' contiene un formato de hora no válido`
83
- const value = wrapper.value.toString()
84
- const parts = value.replace(/[.,]/g, ':').replace('m', '').match(/^([0-2]?[0-9])(:?)([0-5]?[0-9]?)(:?)([0-5]?[0-9]?)([ap]?)\.?m?\.?$/)
85
- if (!parts) return message
86
- let hours = Number(parts[1])
87
- const minutes = Number(parts[3])
88
- const seconds = Number(parts[5])
89
- const middle = parts[6]
90
- if (minutes < 60 && seconds < 60) {
91
- /* Si middle es diferente de vacío, es porque el usuario tiene la intención de especificar una hora del día, caso contrario, está indicando una duración. */
92
- if (middle) {
93
- if (hours >= 1 && hours <= 12) {
94
- if (middle === 'p') hours += 12
95
- wrapper.value = `${PUtilsString.padStart(hours, 2)}:${PUtilsString.padStart(minutes, 2)}:${PUtilsString.padStart(seconds, 2)}`
96
- return
97
- }
98
- } else if (hours >= 0 && hours <= 23) {
99
- wrapper.value = `${PUtilsString.padStart(hours, 2)}:${PUtilsString.padStart(minutes, 2)}:${PUtilsString.padStart(seconds, 2)}`
100
- return
101
- }
102
- }
103
- return message
104
- })
105
- return this
106
- }
107
-
108
- match(pattern: RegExp) {
109
- this.isAlphanumeric()
110
- this.add(this.match.name, (wrapper: PRulesWrapper) => {
111
- if (!(wrapper.value as string).match(pattern)) return `'${wrapper.label}' no cumple con el formato de texto deseado`
112
- })
113
- return this
114
- }
115
-
116
- isNumber() {
117
- this.add(this.isNumber.name, (wrapper: PRulesWrapper) => {
118
- const message = `'${wrapper.label}' debe ser un número`
119
- const value = Number(wrapper.value)
120
- if (isNaN(value) || value == Infinity) return message
121
- wrapper.value = value
122
- })
123
- return this
124
- }
125
-
126
- isInteger() {
127
- this.isNumber()
128
- this.add(this.isInteger.name, (wrapper: PRulesWrapper) => {
129
- if (wrapper.value != Math.floor(wrapper.value as number)) return `'${wrapper.label}' debe ser un número entero`
130
- })
131
- return this
132
- }
133
-
134
- isNatural() {
135
- return this.isInteger().isGte(0)
136
- }
137
-
138
- isNaturalNoZero() {
139
- return this.isInteger().isGt(0)
140
- }
141
-
142
- onlyNumbers() {
143
- this.isAlphanumeric()
144
- this.add(this.onlyNumbers.name, (wrapper: PRulesWrapper) => {
145
- if (!(wrapper.value as string).match(/^[0-9]+$/)) return `'${wrapper.label}' debe contener sólo números`
146
- })
147
- return this
148
- }
149
-
150
- maxLength(limit: number) {
151
- return this.add(this.maxLength.name, (wrapper: PRulesWrapper) => {
152
- if (wrapper.value instanceof Array) {
153
- return wrapper.value.length > limit ? `'${wrapper.label}' debe contener '${limit} ${limit == 1 ? 'elementos' : 'elementos'}' como máximo` : null
154
- } else if (typeof wrapper.value == 'string') {
155
- return wrapper.value.length > limit ? `'${wrapper.label}' debe contener '${limit} ${limit == 1 ? 'caracter' : 'caracteres'}' como máximo` : null
156
- } else {
157
- return `'${wrapper.label}' no es de un tipo válido`
158
- }
159
- })
160
- }
161
-
162
- minLength(limit: number) {
163
- return this.add(this.minLength.name, (wrapper: PRulesWrapper) => {
164
- if (wrapper.value instanceof Array) {
165
- return wrapper.value.length < limit ? `'${wrapper.label}' debe contener '${limit} ${limit == 1 ? 'elementos' : 'elementos'}' como mínimo` : null
166
- } else if (typeof wrapper.value == 'string') {
167
- return wrapper.value.length < limit ? `'${wrapper.label}' debe contener '${limit} ${limit == 1 ? 'caracter' : 'caracteres'}' como mínimo` : null
168
- } else {
169
- return `'${wrapper.label}' no es de un tipo válido`
170
- }
171
- })
172
- }
173
-
174
- hasFixedLength(limit: number) {
175
- return this.add(this.hasFixedLength.name, (wrapper: PRulesWrapper) => {
176
- if (wrapper.value instanceof Array) {
177
- return wrapper.value.length < limit ? `'${wrapper.label}' debe contener sólo '${limit} ${limit == 1 ? 'elementos' : 'elementos'}'` : null
178
- } else if (typeof wrapper.value == 'string') {
179
- return wrapper.value.length < limit ? `'${wrapper.label}' debe contener sólo '${limit} ${limit == 1 ? 'caracter' : 'caracteres'}'` : null
180
- } else {
181
- return `'${wrapper.label}' no es de un tipo válido`
182
- }
183
- })
184
- }
185
-
186
- left(limit: number) {
187
- return this.isAlphanumeric().add(this.left.name, (wrapper: PRulesWrapper) => {
188
- (wrapper.value as string) = (wrapper.value as string).substring(0, limit)
189
- })
190
- }
191
-
192
- isArray(rulesGenerator?: (index: number) => PRules) {
193
- return this.add(this.isArray.name, (wrapper: PRulesWrapper<unknown[]>) => {
194
- const message = `'${wrapper.label}' debe ser una lista de elementos`
195
- if (typeof wrapper.value == 'string') {
196
- try {
197
- const value = JSON.parse(wrapper.value)
198
- if (!(value instanceof Array)) return message
199
- wrapper.value = value
200
- } catch (err) {
201
- return message
202
- }
203
- } else {
204
- if (!(wrapper.value instanceof Array)) return message
205
- }
206
-
207
- if (!rulesGenerator) return
208
-
209
- /* Si se ha definido un generador de reglas, se itera cada elemento */
210
- const messages: string[] = []
211
- for (const [i, element] of wrapper.value.entries()) {
212
- const rules = rulesGenerator(i)
213
- rules.label = `${this.label ? `${this.label}${rules.label ? this.separator : ''}` : ''}${rules.label ?? ''}`
214
- const result = rules.validate(element, false)
215
- if (result.error == true) {
216
- messages.push(...result.messages)
217
- } else {
218
- wrapper.value[i] = result.result
219
- }
220
- }
221
- if (messages.length) return messages
222
- })
223
- }
224
-
225
- isIn(...elements: unknown[]) {
226
- return this.add(this.isIn.name, (wrapper: PRulesWrapper) => {
227
- if (wrapper.value instanceof Array) {
228
- for (const v of wrapper.value) {
229
- if (!elements.includes(v)) return `'${wrapper.label}' no contiene valores válidos`
230
- }
231
- } else {
232
- if (!elements.includes(wrapper.value)) return `'${wrapper.label}' no tiene un valor válido`
233
- }
234
- })
235
- }
236
-
237
- isNotIn(...elements: unknown[]) {
238
- return this.add(this.isNotIn.name, (wrapper: PRulesWrapper) => {
239
- if (elements.includes(wrapper.value)) return `'${wrapper.label}' no tiene un valor válido`
240
- })
241
- }
242
-
243
- hasElements() {
244
- return this.isArray().add(this.hasElements.name, (wrapper: PRulesWrapper<unknown[]>) => {
245
- if (!wrapper.value.length) return `'${wrapper.label}' debe contenedor al menos un elemento`
246
- })
247
- }
248
-
249
- isGt(limit: number) {
250
- return this.isNumber().add(this.isGt.name, (wrapper: PRulesWrapper) => {
251
- if (wrapper.value as number <= limit) return `'${wrapper.label}' debe ser mayor a '${limit}'`
252
- })
253
- }
254
-
255
- isGte(limit: number) {
256
- return this.isNumber().add(this.isGte.name, (wrapper: PRulesWrapper) => {
257
- if (wrapper.value as number < limit) return `'${wrapper.label}' debe ser mayor o igual a '${limit}'`
258
- })
259
- }
260
-
261
- isLt(limit: number) {
262
- return this.isNumber().add(this.isLt.name, (wrapper: PRulesWrapper) => {
263
- if (wrapper.value as number >= limit) return `'${wrapper.label}' debe ser menor a '${limit}'`
264
- })
265
- }
266
-
267
- isLte(limit: number) {
268
- return this.isNumber().add(this.isLte.name, (wrapper: PRulesWrapper) => {
269
- if (wrapper.value as number > limit) return `'${wrapper.label}' debe ser menor o igual a '${limit}'`
270
- })
271
- }
272
-
273
- beforeOrSameAsNow() {
274
- return this.isDateTime().add(this.beforeOrSameAsNow.name, (wrapper: PRulesWrapper<PDate>) => {
275
- const now = new PDate
276
- if (wrapper.value.timestamp > now.timestamp) return `'${wrapper.label}' debe ser anterior o igual a 'ahora'`
277
- })
278
- }
279
-
280
- isObject(schema?: Record<string, PRules>) {
281
- return this.add(this.isObject.name, (wrapper: PRulesWrapper) => {
282
- return isObject(this, wrapper, schema)
283
- })
284
- }
285
-
286
- isBoolean() {
287
- return this.add(this.isBoolean.name, (wrapper: PRulesWrapper) => {
288
- const message = `'${wrapper.label}' debe ser de tipo booleano`
289
- if (typeof wrapper.value == 'string') {
290
- const value = wrapper.value.trim().toUpperCase()
291
- switch (value) {
292
- case '1':
293
- case 'S':
294
- case 'SÍ':
295
- case 'Y':
296
- case 'YES':
297
- wrapper.value = true
298
- return
299
- case '0':
300
- case 'N':
301
- case 'NO':
302
- wrapper.value = false
303
- return
304
- default: {
305
- let json
306
- try {
307
- json = JSON.parse(wrapper.value)
308
- } catch {
309
- return message
310
- }
311
- if (typeof json != 'boolean' && !([0, 1]).includes(json)) return message
312
- wrapper.value = json
313
- return
314
- }
315
- }
316
- } else if (typeof wrapper.value == 'number') {
317
- switch (wrapper.value) {
318
- case 0:
319
- wrapper.value = false
320
- return
321
- case 1:
322
- wrapper.value = true
323
- return
324
- default:
325
- return message
326
- }
327
- } else {
328
- return typeof wrapper.value == 'boolean' ? null : message
329
- }
330
- })
331
- }
332
-
333
- upper() {
334
- this.isAlphanumeric()
335
- this.add(this.upper.name, (wrapper: PRulesWrapper) => {
336
- wrapper.value = (wrapper.value as string).toUpperCase()
337
- })
338
- return this
339
- }
340
-
341
- lower() {
342
- this.isAlphanumeric()
343
- this.add(this.lower.name, (wrapper: PRulesWrapper) => {
344
- wrapper.value = (wrapper.value as string).toLowerCase()
345
- })
346
- return this
347
- }
348
-
349
- decodeURI() {
350
- this.isAlphanumeric()
351
- this.add(this.decodeURI.name, (wrapper: PRulesWrapper) => {
352
- wrapper.value = decodeURI(wrapper.value as string)
353
- })
354
- return this
355
- }
356
-
357
- round(decimals: number) {
358
- this.isNumber()
359
- this.add(this.round.name, (wrapper: PRulesWrapper) => {
360
- wrapper.value = PUtilsNumber.round(wrapper.value as number, decimals)
361
- })
362
- return this
363
- }
364
-
365
- /* Reemplaza todos los dobles (o más) espacios juntos por uno simple */
366
- cleanDoubleSpaces() {
367
- this.isAlphanumeric()
368
- this.add(this.cleanDoubleSpaces.name, (wrapper: PRulesWrapper) => {
369
- wrapper.value = (wrapper.value as string).replace(/\s{2,}/g, ' ')
370
- })
371
- return this
372
- }
373
-
374
- noSpaces() {
375
- this.isAlphanumeric()
376
- this.add(this.noSpaces.name, (wrapper: PRulesWrapper) => {
377
- if ((wrapper.value as string).match(/\s/)) return `'${wrapper.label}' no debe contener 'espacios'`
378
- })
379
- return this
380
- }
381
-
382
-
383
- replace(search: string | RegExp, replace: string | ((substring: string, ...args: any[]) => string)) {
384
- return this.isAlphanumeric().add(this.replace.name, (wrapper: PRulesWrapper) => {
385
- wrapper.value = (wrapper.value as string).replace(search, replace as any)
386
- })
387
- }
388
-
389
- capitalize() {
390
- this.isAlphanumeric()
391
- this.add(this.capitalize.name, (wrapper: PRulesWrapper) => {
392
- wrapper.value = PUtilsString.capitalize(wrapper.value as string)
393
- })
394
- return this
395
- }
396
-
397
- split(separator: string | RegExp) {
398
- return this.isAlphanumeric().add(this.split.name, (wrapper: PRulesWrapper<string>) => {
399
- wrapper.value = wrapper.value.split(separator) as any
400
- })
401
- }
402
-
403
- join(separator: string) {
404
- return this.isArray().add(this.join.name, (wrapper: PRulesWrapper<unknown[]>) => {
405
- wrapper.value = wrapper.value.join(separator) as any
406
- })
407
- }
408
-
409
- floor() {
410
- return this.isNumber().add(this.floor.name, (wrapper: PRulesWrapper<number>) => {
411
- wrapper.value = Math.floor(wrapper.value)
412
- })
413
- }
414
-
415
- ceil() {
416
- return this.isNumber().add(this.ceil.name, (wrapper: PRulesWrapper<number>) => {
417
- wrapper.value = Math.ceil(wrapper.value)
418
- })
419
- }
420
-
421
- sanitize(...allowedTags: string[]) {
422
- return this.isAlphanumeric().add(this.sanitize.name, (wrapper: PRulesWrapper) => {
423
- wrapper.value = sanitize((wrapper.value as string).trim(), { ALLOWED_TAGS: allowedTags })
424
- })
425
- }
426
- }
@@ -1,111 +0,0 @@
1
- export type PRulesParams = {
2
- label?: string
3
- separator?: string
4
- } & ({
5
- required?: boolean
6
- } | {
7
- default?: unknown
8
- })
9
-
10
- export type PRulesFunction = (wrapper: PRulesWrapper, ...args: unknown[]) => string | string[] | void | null | undefined
11
-
12
- export type PRulesWrapper<T = unknown> = {
13
- value: T
14
- label: string
15
- }
16
-
17
- export type PRulesResponse<T> = {
18
- error: false
19
- success: true
20
- result: T
21
- } | {
22
- error: true
23
- success: false
24
- messages: string[]
25
- }
26
-
27
- export class PRulesEngine {
28
- prefix: string
29
- label: string
30
- separator: string
31
- required: boolean = false
32
- default: unknown = null
33
-
34
- private collectionFunctions: PRulesFunction[] = []
35
- private collectionNames: string[] = []
36
-
37
- constructor(params?: PRulesParams) {
38
- this.label = params?.label
39
- this.separator = params?.separator ?? ' > '
40
- this.required = params && 'required' in params ? params?.required : false
41
- this.default = params && 'default' in params ? params?.default : null
42
- }
43
-
44
- protected add(name: string, validationFunction: PRulesFunction) {
45
- if (!this.collectionNames.includes(name)) {
46
- this.collectionNames.push(name)
47
- this.collectionFunctions.push(validationFunction)
48
- }
49
- return this
50
- }
51
-
52
- validate<T>(target: unknown, safe = true): PRulesResponse<T> {
53
- const errorMessages: string[] = []
54
-
55
- if (typeof target == 'string') target = target.trim()
56
-
57
- const defaultIsEmpty = this.default == null || (typeof this.default == 'string' && !this.default)
58
- const isEmpty = target == null || (typeof target == 'string' && !target)
59
-
60
- const label = this.label
61
-
62
- if (this.required && isEmpty) {
63
- return {
64
- error: true,
65
- success: false,
66
- messages: [`'${label}' es requerido`]
67
- }
68
- }
69
-
70
- if (isEmpty) {
71
- if (!defaultIsEmpty) {
72
- target = this.default
73
- } else {
74
- return {
75
- error: false,
76
- success: true,
77
- result: this.default as T
78
- }
79
- }
80
- }
81
-
82
- const wrapper: PRulesWrapper<T> = {
83
- value: safe ? JSON.parse(JSON.stringify(target)) : target,
84
- label
85
- }
86
- for (const validationFunction of this.collectionFunctions) {
87
- const result = validationFunction(wrapper)
88
- if (!result) continue
89
- if (typeof result == 'string') {
90
- errorMessages.push(result)
91
- break
92
- } else {
93
- errorMessages.push(...result)
94
- }
95
- }
96
-
97
- if (errorMessages.length) {
98
- return {
99
- error: true,
100
- success: false,
101
- messages: errorMessages
102
- }
103
- } else {
104
- return {
105
- error: false,
106
- success: true,
107
- result: wrapper.value
108
- }
109
- }
110
- }
111
- }