@orioro/util 0.0.0 → 0.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 (163) hide show
  1. package/README.md +1 -0
  2. package/babel.config.cjs +13 -0
  3. package/coverage/clover.xml +488 -45
  4. package/coverage/coverage-final.json +28 -2
  5. package/coverage/lcov-report/ValidationError.ts.html +184 -0
  6. package/coverage/lcov-report/base.css +19 -7
  7. package/coverage/lcov-report/block-navigation.js +87 -0
  8. package/coverage/lcov-report/favicon.png +0 -0
  9. package/coverage/lcov-report/index.html +248 -58
  10. package/coverage/lcov-report/prettify.js +1 -0
  11. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  12. package/coverage/lcov-report/sorter.js +52 -14
  13. package/coverage/lcov-report/src/debug/deepFreeze.ts.html +157 -0
  14. package/coverage/lcov-report/src/debug/index.html +146 -0
  15. package/coverage/lcov-report/src/debug/index.ts.html +91 -0
  16. package/coverage/lcov-report/src/debug/wait.ts.html +127 -0
  17. package/coverage/lcov-report/src/index.html +131 -0
  18. package/coverage/lcov-report/src/interpolate/index.html +116 -0
  19. package/coverage/lcov-report/src/interpolate/index.ts.html +277 -0
  20. package/coverage/lcov-report/src/maybeFn.ts.html +94 -0
  21. package/coverage/lcov-report/src/promise/index.html +146 -0
  22. package/coverage/lcov-report/src/promise/index.ts.html +91 -0
  23. package/coverage/lcov-report/src/promise/promiseReduce.ts.html +130 -0
  24. package/coverage/lcov-report/src/promise/resolveNestedPromises.ts.html +271 -0
  25. package/coverage/lcov-report/src/switchValue.ts.html +253 -0
  26. package/coverage/lcov-report/src/typeOf.ts.html +328 -0
  27. package/coverage/lcov-report/src/validate/ValidationError.ts.html +184 -0
  28. package/coverage/lcov-report/src/validate/async/index.html +131 -0
  29. package/coverage/lcov-report/src/validate/async/index.ts.html +241 -0
  30. package/coverage/lcov-report/src/validate/async/parseValidator.ts.html +136 -0
  31. package/coverage/lcov-report/src/validate/async/validateAsyncFn.ts.html +208 -0
  32. package/coverage/lcov-report/src/validate/async/validators/and.ts.html +154 -0
  33. package/coverage/lcov-report/src/validate/async/validators/index.html +146 -0
  34. package/coverage/lcov-report/src/validate/async/validators/index.ts.html +91 -0
  35. package/coverage/lcov-report/src/validate/async/validators/logical.ts.html +253 -0
  36. package/coverage/lcov-report/src/validate/async/validators/or.ts.html +151 -0
  37. package/coverage/lcov-report/src/validate/async/validators/shape.ts.html +565 -0
  38. package/coverage/lcov-report/src/validate/common/ValidationError.ts.html +184 -0
  39. package/coverage/lcov-report/src/validate/common/index.html +116 -0
  40. package/coverage/lcov-report/src/validate/common/util/defaultErrorMessage.ts.html +163 -0
  41. package/coverage/lcov-report/src/validate/common/util/index.html +161 -0
  42. package/coverage/lcov-report/src/validate/common/util/index.ts.html +94 -0
  43. package/coverage/lcov-report/src/validate/common/util/parseValidator.ts.html +316 -0
  44. package/coverage/lcov-report/src/validate/common/util/parseValidatorInput.ts.html +316 -0
  45. package/coverage/lcov-report/src/validate/common/util/resolveValidationResult.ts.html +277 -0
  46. package/coverage/lcov-report/src/validate/common/util/validatorParser.ts.html +316 -0
  47. package/coverage/lcov-report/src/validate/common/validators/index.html +131 -0
  48. package/coverage/lcov-report/src/validate/common/validators/index.ts.html +88 -0
  49. package/coverage/lcov-report/src/validate/common/validators/type.ts.html +388 -0
  50. package/coverage/lcov-report/src/validate/fmtValidationResult.ts.html +268 -0
  51. package/coverage/lcov-report/src/validate/index.html +116 -0
  52. package/coverage/lcov-report/src/validate/index.ts.html +94 -0
  53. package/coverage/lcov-report/src/validate/makeValidate.ts.html +634 -0
  54. package/coverage/lcov-report/src/validate/specUtil/commonTests.js.html +1324 -0
  55. package/coverage/lcov-report/src/validate/specUtil/index.html +116 -0
  56. package/coverage/lcov-report/src/validate/sync/index.html +131 -0
  57. package/coverage/lcov-report/src/validate/sync/index.ts.html +244 -0
  58. package/coverage/lcov-report/src/validate/sync/parseValidator.ts.html +136 -0
  59. package/coverage/lcov-report/src/validate/sync/validateSyncFn.ts.html +223 -0
  60. package/coverage/lcov-report/src/validate/sync/validators/and.ts.html +148 -0
  61. package/coverage/lcov-report/src/validate/sync/validators/index.html +146 -0
  62. package/coverage/lcov-report/src/validate/sync/validators/index.ts.html +91 -0
  63. package/coverage/lcov-report/src/validate/sync/validators/logical.ts.html +226 -0
  64. package/coverage/lcov-report/src/validate/sync/validators/or.ts.html +130 -0
  65. package/coverage/lcov-report/src/validate/sync/validators/shape.ts.html +523 -0
  66. package/coverage/lcov-report/src/validate/sync/validators/type.ts.html +154 -0
  67. package/coverage/lcov-report/src/validate/syncValidators/and.ts.html +157 -0
  68. package/coverage/lcov-report/src/validate/syncValidators/index.html +176 -0
  69. package/coverage/lcov-report/src/validate/syncValidators/index.ts.html +97 -0
  70. package/coverage/lcov-report/src/validate/syncValidators/or.ts.html +127 -0
  71. package/coverage/lcov-report/src/validate/syncValidators/shape.ts.html +559 -0
  72. package/coverage/lcov-report/src/validate/syncValidators/string.ts.html +163 -0
  73. package/coverage/lcov-report/src/validate/syncValidators/type.ts.html +154 -0
  74. package/coverage/lcov-report/src/validate/util/defaultErrorMessage.ts.html +169 -0
  75. package/coverage/lcov-report/src/validate/util/index.html +146 -0
  76. package/coverage/lcov-report/src/validate/util/index.ts.html +91 -0
  77. package/coverage/lcov-report/src/validate/util/resolveValidationResult.ts.html +253 -0
  78. package/coverage/lcov-report/src/validate/validate.ts.html +220 -0
  79. package/coverage/lcov-report/src/validate/validateAsync.ts.html +220 -0
  80. package/coverage/lcov-report/src/validate/validators/and.ts.html +157 -0
  81. package/coverage/lcov-report/src/validate/validators/index.html +176 -0
  82. package/coverage/lcov-report/src/validate/validators/index.ts.html +97 -0
  83. package/coverage/lcov-report/src/validate/validators/or.ts.html +127 -0
  84. package/coverage/lcov-report/src/validate/validators/shape.ts.html +541 -0
  85. package/coverage/lcov-report/src/validate/validators/type.ts.html +154 -0
  86. package/coverage/lcov-report/src/validate_/ValidationError.ts.html +184 -0
  87. package/coverage/lcov-report/src/validate_/fmtValidationResult.ts.html +268 -0
  88. package/coverage/lcov-report/src/validate_/index.html +161 -0
  89. package/coverage/lcov-report/src/validate_/makeValidate.ts.html +634 -0
  90. package/coverage/lcov-report/src/validate_/validate.ts.html +220 -0
  91. package/coverage/lcov-report/switchValue.ts.html +253 -0
  92. package/coverage/lcov-report/typeOf.ts.html +331 -0
  93. package/coverage/lcov-report/validate.ts.html +757 -0
  94. package/coverage/lcov.info +1045 -74
  95. package/dist/index.mjs +1428 -74
  96. package/jest.config.js +6 -0
  97. package/package.json +27 -27
  98. package/rollup.config.mjs +6 -0
  99. package/src/PromiseLikeEventEmitter/index.ts +35 -0
  100. package/src/array/arrayChunk.ts +7 -0
  101. package/src/array/index.ts +1 -0
  102. package/src/debug/debugFn/index.ts +48 -0
  103. package/src/debug/debugFn/util.ts +27 -0
  104. package/src/debug/deepFreeze.ts +26 -0
  105. package/src/debug/index.ts +3 -0
  106. package/src/debug/wait.ts +14 -0
  107. package/src/index.ts +8 -0
  108. package/src/interpolate/index.spec.ts +20 -0
  109. package/src/interpolate/index.ts +64 -0
  110. package/src/maybeFn.ts +3 -0
  111. package/src/promise/batchFn.spec.ts +92 -0
  112. package/src/promise/batchFn.ts +176 -0
  113. package/src/promise/index.ts +3 -0
  114. package/src/promise/promiseReduce.ts +15 -0
  115. package/src/promise/resolveNestedPromises.spec.ts +205 -0
  116. package/src/promise/resolveNestedPromises.ts +83 -0
  117. package/src/promise/types.ts +2 -0
  118. package/src/switchValue.spec.ts +30 -0
  119. package/src/switchValue.ts +59 -0
  120. package/src/typeOf.spec.ts +47 -0
  121. package/src/typeOf.ts +81 -0
  122. package/src/validate/__snapshots__/index.spec.ts.snap +9 -0
  123. package/src/validate/async/index.spec.ts +236 -0
  124. package/src/validate/async/index.ts +52 -0
  125. package/src/validate/async/validateAsyncFn.ts +41 -0
  126. package/src/validate/async/validators/index.ts +2 -0
  127. package/src/validate/async/validators/logical.ts +56 -0
  128. package/src/validate/async/validators/shape.ts +160 -0
  129. package/src/validate/async/validators/tmpand.ts +24 -0
  130. package/src/validate/async/validators/tmpor.ts +21 -0
  131. package/src/validate/common/ValidationError.ts +33 -0
  132. package/src/validate/common/util/defaultErrorMessage.ts +26 -0
  133. package/src/validate/common/util/index.ts +3 -0
  134. package/src/validate/common/util/parseValidatorInput.ts +77 -0
  135. package/src/validate/common/util/resolveValidationResult.ts +64 -0
  136. package/src/validate/common/validators/index.ts +1 -0
  137. package/src/validate/common/validators/type.ts +101 -0
  138. package/src/validate/index.spec.ts +5 -0
  139. package/src/validate/index.ts +3 -0
  140. package/src/validate/specUtil/commonTests.js +413 -0
  141. package/src/validate/sync/index.spec.ts +81 -0
  142. package/src/validate/sync/index.ts +53 -0
  143. package/src/validate/sync/validateSyncFn.ts +46 -0
  144. package/src/validate/sync/validators/index.ts +2 -0
  145. package/src/validate/sync/validators/logical.ts +47 -0
  146. package/src/validate/sync/validators/shape.ts +146 -0
  147. package/src/validate/types/async.ts +20 -0
  148. package/src/validate/types/common.ts +70 -0
  149. package/src/validate/types/index.ts +3 -0
  150. package/src/validate/types/sync.ts +20 -0
  151. package/tsconfig.json +11 -0
  152. package/array/index.js +0 -11
  153. package/coverage/lcov-report/array/index.html +0 -93
  154. package/coverage/lcov-report/array/index.js.html +0 -98
  155. package/coverage/lcov-report/coverage/coverage-final.json.html +0 -95
  156. package/coverage/lcov-report/coverage/index.html +0 -93
  157. package/coverage/lcov-report/coverage/lcov-report/index.html +0 -106
  158. package/coverage/lcov-report/coverage/lcov-report/prettify.js.html +0 -68
  159. package/coverage/lcov-report/coverage/lcov-report/sorter.js.html +0 -539
  160. package/coverage/lcov-report/fn/index.html +0 -93
  161. package/coverage/lcov-report/fn/index.js.html +0 -215
  162. package/dist/index.js +0 -116
  163. package/fn/index.js +0 -50
@@ -0,0 +1,77 @@
1
+ import { defaultErrorMessage } from './defaultErrorMessage'
2
+ import { typeValidator } from '../validators'
3
+ import { DEFAULT_TYPE_NAMES, typeOf } from '../../../typeOf'
4
+ import {
5
+ DetailedInvalid,
6
+ ValidatorErrorMessageFn,
7
+ ValidatorErrorMessageInput,
8
+ } from '../../types'
9
+ import { interpolate } from '../../../interpolate'
10
+
11
+ export function parseValidatorInput<ValidatorInputT, ValidatorFnT, ValidatorT>(
12
+ {
13
+ objValidator,
14
+ }: {
15
+ objValidator: (objShape: { [key: string]: ValidatorInputT }) => ValidatorFnT
16
+ },
17
+ validatorInput: ValidatorInputT,
18
+ ) {
19
+ //
20
+ // Parses the validator fn.
21
+ // If provided with a string, will return a type validator
22
+ // If provided with a function, will return the function itself
23
+ //
24
+ function _parseValidatorFn(
25
+ fnInput:
26
+ | DEFAULT_TYPE_NAMES
27
+ | { [key: string]: ValidatorInputT }
28
+ | ((input: any) => any),
29
+ ): ValidatorFnT {
30
+ switch (typeOf(fnInput)) {
31
+ case 'string': {
32
+ return typeValidator(fnInput as DEFAULT_TYPE_NAMES) as ValidatorFnT
33
+ }
34
+ case 'object': {
35
+ return objValidator(fnInput as { [key: string]: ValidatorInputT })
36
+ }
37
+ case 'function': {
38
+ return fnInput as ValidatorFnT
39
+ }
40
+ default: {
41
+ throw new TypeError(`Unsupported fnInput ${fnInput}`)
42
+ }
43
+ }
44
+ }
45
+
46
+ function _parseValidatorErrorMessageFn(
47
+ fnInput: ValidatorErrorMessageInput,
48
+ ): ValidatorErrorMessageFn {
49
+ switch (typeof fnInput) {
50
+ case 'string': {
51
+ return (details: DetailedInvalid) => interpolate(fnInput, details)
52
+ }
53
+ case 'function': {
54
+ return fnInput
55
+ }
56
+ default: {
57
+ throw new TypeError(`Unsupported error message input ${fnInput}`)
58
+ }
59
+ }
60
+ }
61
+
62
+ //
63
+ // Parses the validator input. For more details, see:
64
+ // types/common.ts -> ValidatorSystem
65
+ //
66
+ // Ensures the return result is always of the following format:
67
+ // [ValidatorFn, ValidatorErrorMessageInput]
68
+ //
69
+ const [fnInput, errorMessageInput] = Array.isArray(validatorInput)
70
+ ? validatorInput
71
+ : [validatorInput, defaultErrorMessage]
72
+
73
+ return [
74
+ _parseValidatorFn(fnInput),
75
+ _parseValidatorErrorMessageFn(errorMessageInput),
76
+ ] as ValidatorT
77
+ }
@@ -0,0 +1,64 @@
1
+ import { typeOf } from '../../../typeOf'
2
+ import { switchExec } from '../../../switchValue'
3
+ import {
4
+ DetailedInvalid,
5
+ Valid,
6
+ ValidatorErrorMessageFn,
7
+ ValidatorResult,
8
+ } from '../../types'
9
+
10
+ export function resolveValidationResult({
11
+ input,
12
+ result,
13
+ errorMessage,
14
+ }: {
15
+ input: any
16
+ result: ValidatorResult
17
+ errorMessage: ValidatorErrorMessageFn
18
+ }): Valid | DetailedInvalid {
19
+ if (result === true) {
20
+ return true
21
+ } else {
22
+ const _falseLikeResult = () => ({
23
+ message: errorMessage({ input }),
24
+ })
25
+
26
+ return {
27
+ input,
28
+ ...switchExec(typeOf(result), {
29
+ string: () =>
30
+ ({
31
+ message: result,
32
+ }) as DetailedInvalid,
33
+ error: () => ({
34
+ message: (result as Error).message,
35
+ error: result,
36
+ }),
37
+ object: () => {
38
+ const result_ = result as DetailedInvalid
39
+
40
+ return {
41
+ ...result_,
42
+ message: errorMessage(result_),
43
+ }
44
+ },
45
+
46
+ //
47
+ // Boolean result here MUST be false, as true was tested earlier
48
+ //
49
+ boolean: _falseLikeResult,
50
+ null: _falseLikeResult,
51
+ undefined: _falseLikeResult,
52
+
53
+ //
54
+ // Unsupported validation result
55
+ //
56
+ default: () => {
57
+ throw new Error(
58
+ `Invalid validation result: ${result} (${typeOf(result)})`,
59
+ )
60
+ },
61
+ }),
62
+ }
63
+ }
64
+ }
@@ -0,0 +1 @@
1
+ export * from './type'
@@ -0,0 +1,101 @@
1
+ import { switchExec } from '../../../switchValue'
2
+ import { DEFAULT_TYPE_NAMES, typeOf } from '../../../typeOf'
3
+ import { DetailedInvalid, Valid, CommonValidatorFn } from '../../types'
4
+
5
+ type ParsedExpectedType = {
6
+ type: DEFAULT_TYPE_NAMES
7
+ required: boolean
8
+ }
9
+
10
+ type ExpectedTypesInput =
11
+ | (string | ParsedExpectedType)[]
12
+ | string
13
+ | ParsedExpectedType
14
+
15
+ const TYPE_RE = /([a-z0-9]+)(\!)?$/i
16
+ const TYPE_SEPARATOR_RE = /\s*\|\s*/g
17
+
18
+ function parseSingleType(typeInput: string): ParsedExpectedType {
19
+ const match = typeInput.match(TYPE_RE)
20
+
21
+ if (!match) {
22
+ throw new Error(`Invalid type ${typeInput}`)
23
+ } else {
24
+ const [, typeName, requiredSignal] = match
25
+
26
+ return {
27
+ type: typeName as DEFAULT_TYPE_NAMES,
28
+ required: requiredSignal === '!',
29
+ }
30
+ }
31
+ }
32
+
33
+ function serializeExpectedTypes(expectedTypes: ParsedExpectedType[]) {
34
+ return expectedTypes
35
+ .map(
36
+ (expectedType) =>
37
+ `${expectedType.type}${expectedType.required ? '!' : ''}`,
38
+ )
39
+ .join(' | ')
40
+ }
41
+
42
+ function parseExpectedTypes(
43
+ expectedTypesInput: ExpectedTypesInput,
44
+ ): ParsedExpectedType[] {
45
+ switch (typeOf(expectedTypesInput)) {
46
+ case 'string': {
47
+ return (expectedTypesInput as string)
48
+ .split(TYPE_SEPARATOR_RE)
49
+ .map((typeInput) => parseSingleType(typeInput))
50
+ }
51
+ case 'array': {
52
+ return (expectedTypesInput as (string | ParsedExpectedType)[]).map(
53
+ (expectedType) =>
54
+ typeof expectedType === 'string'
55
+ ? parseSingleType(expectedType)
56
+ : expectedType,
57
+ )
58
+ }
59
+ case 'object': {
60
+ return [expectedTypesInput as ParsedExpectedType]
61
+ }
62
+ default: {
63
+ throw new Error(`Invalid expectedType ${expectedTypesInput}`)
64
+ }
65
+ }
66
+ }
67
+
68
+ export function typeValidator(
69
+ expectedTypesInput: ExpectedTypesInput,
70
+ ): CommonValidatorFn {
71
+ const expectedTypes: ParsedExpectedType[] =
72
+ parseExpectedTypes(expectedTypesInput)
73
+
74
+ return function validateType(input) {
75
+ const inputType = typeOf(input)
76
+
77
+ const nullOrUndefined = () =>
78
+ expectedTypes.some(
79
+ (expectedType) =>
80
+ expectedType.type === 'undefined' ||
81
+ expectedType.type === 'null' ||
82
+ expectedType.required === false,
83
+ )
84
+
85
+ const isValid = switchExec(inputType, {
86
+ null: nullOrUndefined,
87
+ undefined: nullOrUndefined,
88
+ default: () =>
89
+ expectedTypes.some((expectedType) => expectedType.type === inputType),
90
+ })
91
+
92
+ if (isValid) {
93
+ return true
94
+ } else {
95
+ return {
96
+ expectedTypes: serializeExpectedTypes(expectedTypes),
97
+ input,
98
+ }
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,5 @@
1
+ import * as validateAPI from './index'
2
+
3
+ test('validateAPI', () => {
4
+ expect(Object.keys(validateAPI)).toMatchSnapshot()
5
+ })
@@ -0,0 +1,3 @@
1
+ export * from './sync'
2
+ export * from './async'
3
+ export * from './common/ValidationError'
@@ -0,0 +1,413 @@
1
+ export function commonTests({ describe, test, expect }, { validate }) {
2
+ describe('basic', () => {
3
+ test('non-required', () => {
4
+ const isString = validate.type('string')
5
+
6
+ expect(validate(isString, 'Some text')).toEqual(true)
7
+ expect(validate(isString, null)).toEqual(true)
8
+ expect(validate(isString, undefined)).toEqual(true)
9
+ expect(validate(isString)).toEqual(true)
10
+ expect(validate(isString, false)).toMatchObject({
11
+ message:
12
+ "Invalid input: 'false'. Expected type(s) `string`, but got type `boolean`",
13
+ })
14
+ expect(validate(isString, 8)).toEqual({
15
+ input: 8,
16
+ expectedTypes: 'string',
17
+ message:
18
+ "Invalid input: '8'. Expected type(s) `string`, but got type `number`",
19
+ })
20
+ })
21
+
22
+ test('required', () => {
23
+ const isString = validate.type('string!')
24
+
25
+ expect(validate(isString, 'Some text')).toEqual(true)
26
+ expect(validate(isString, null)).toMatchObject({
27
+ message:
28
+ "Invalid input: 'null'. Expected type(s) `string!`, but got type `null`",
29
+ })
30
+ expect(validate(isString, undefined)).toMatchObject({
31
+ message:
32
+ "Invalid input: 'undefined'. Expected type(s) `string!`, but got type `undefined`",
33
+ })
34
+
35
+ expect(validate(isString, 8)).toEqual({
36
+ input: 8,
37
+ expectedTypes: 'string!',
38
+ message:
39
+ "Invalid input: '8'. Expected type(s) `string!`, but got type `number`",
40
+ })
41
+ })
42
+
43
+ test('basic fn', () => {
44
+ const fnValidator = (input) =>
45
+ typeof input === 'string' && input.length > 5
46
+
47
+ expect(validate(fnValidator, 'Some text')).toEqual(true)
48
+ expect(validate(fnValidator, 'Some')).toEqual({
49
+ input: 'Some',
50
+ message: "Invalid input: 'Some'.",
51
+ })
52
+ })
53
+ })
54
+
55
+ describe('shorthand type declaration', () => {
56
+ test('string validator', () => {
57
+ expect(validate('string', 'Some string')).toEqual(true)
58
+ expect(validate('string', null)).toEqual(true)
59
+ expect(validate('string!', null)).not.toEqual(true)
60
+
61
+ expect(validate('string', 9)).toEqual({
62
+ input: 9,
63
+ expectedTypes: 'string',
64
+ message:
65
+ "Invalid input: '9'. Expected type(s) `string`, but got type `number`",
66
+ })
67
+ })
68
+
69
+ test('multitype', () => {
70
+ const validator = 'string! | number! | function!'
71
+ expect(validate(validator, 'str')).toEqual(true)
72
+ expect(validate(validator, 10)).toEqual(true)
73
+ expect(validate(validator, () => {})).toEqual(true)
74
+ expect(validate(validator, undefined)).not.toEqual(true)
75
+ })
76
+
77
+ test('object shorthand', () => {
78
+ const validator = {
79
+ givenName: 'string',
80
+ age: 'number',
81
+ someFn: 'function!',
82
+ }
83
+ expect(
84
+ validate(validator, {
85
+ givenName: 'Boo',
86
+ age: 9,
87
+ someFn: () => {},
88
+ }),
89
+ ).toEqual(true)
90
+
91
+ expect(
92
+ validate(validator, {
93
+ givenName: 'Boo',
94
+ age: 9,
95
+ // someFn: () => {},
96
+ }),
97
+ ).toMatchObject({
98
+ nestedErrors: [
99
+ {
100
+ message:
101
+ "Invalid input: 'undefined'. Expected type(s) `function!`, but got type `undefined`",
102
+ path: 'someFn',
103
+ },
104
+ ],
105
+ message:
106
+ 'Invalid input: `{"givenName":"Boo","age":9}`.\n' +
107
+ " - someFn: Invalid input: 'undefined'. Expected type(s) `function!`, but got type `undefined`",
108
+ })
109
+ })
110
+ })
111
+
112
+ describe('obj', () => {
113
+ test('basic', () => {
114
+ const validator = validate.obj({
115
+ paramA: validate.type('number'),
116
+ paramB: validate.type('string'),
117
+ })
118
+
119
+ expect(
120
+ validate(validator, {
121
+ paramA: 10,
122
+ paramB: 'Hello',
123
+ }),
124
+ ).toEqual(true)
125
+
126
+ expect(
127
+ validate(validator, {
128
+ paramA: '10',
129
+ paramB: 'Hello',
130
+ }),
131
+ ).toEqual({
132
+ input: { paramA: '10', paramB: 'Hello' },
133
+ message:
134
+ 'Invalid input: `{"paramA":"10","paramB":"Hello"}`.\n' +
135
+ " - paramA: Invalid input: '10'. Expected type(s) `number`, but got type `string`",
136
+ nestedErrors: [
137
+ {
138
+ input: '10',
139
+ message:
140
+ "Invalid input: '10'. Expected type(s) `number`, but got type `string`",
141
+ path: 'paramA',
142
+ expectedTypes: 'number',
143
+ },
144
+ ],
145
+ })
146
+ })
147
+ })
148
+
149
+ describe('logical', () => {
150
+ test('and', () => {
151
+ const validator = validate.and([
152
+ validate.type('string'),
153
+ [(input) => input.length >= 8, 'Must have at least 8 characters'],
154
+ [(input) => input.length <= 20, 'Must have at most 20 characters'],
155
+ ])
156
+
157
+ expect(validate(validator, '12345678')).toEqual(true)
158
+ expect(validate(validator, '1234567')).toEqual({
159
+ input: '1234567',
160
+ message: 'Must have at least 8 characters',
161
+ })
162
+ expect(validate(validator, '12345678901234567890_1')).toEqual({
163
+ input: '12345678901234567890_1',
164
+ message: 'Must have at most 20 characters',
165
+ })
166
+ })
167
+
168
+ test('or', () => {
169
+ const validator = validate.or([
170
+ validate.type('string!'),
171
+ validate.type('number!'),
172
+ ])
173
+
174
+ expect(validate(validator, 'Hello')).toEqual(true)
175
+ expect(validate(validator, 90)).toEqual(true)
176
+ expect(validate(validator, undefined)).toEqual({
177
+ input: undefined,
178
+ message: "Invalid input: 'undefined'.",
179
+ })
180
+ })
181
+
182
+ test('nested', () => {
183
+ const validator = validate.and([
184
+ validate.type('string'),
185
+ [
186
+ validate.or([
187
+ (input) => input.length <= 8,
188
+ (input) => input.length >= 16,
189
+ ]),
190
+ 'Must have either 8 chars or less or 16 or more',
191
+ ],
192
+ ])
193
+
194
+ expect(validate(validator, '1234567')).toEqual(true)
195
+ expect(validate(validator, '123456712345671234567')).toEqual(true)
196
+ expect(validate(validator, '12345671234567')).toEqual({
197
+ input: '12345671234567',
198
+ message: 'Must have either 8 chars or less or 16 or more',
199
+ })
200
+ })
201
+
202
+ test('with object shape', () => {
203
+ const validator = validate.obj({
204
+ username: [
205
+ validate.and([
206
+ validate.type('string'),
207
+ (str) => str.length >= 5,
208
+ (str) => str.length <= 10,
209
+ (str) => /^[a-zA-Z0-9]+$/.test(str),
210
+ ]),
211
+ 'Username must be have at least 5 chars, at most 10 chars and contain only alphanumeric characters (0-9,a-Z)',
212
+ ],
213
+ password: [
214
+ validate.and([
215
+ validate.type('string'),
216
+ (str) => str.length >= 8,
217
+ (str) => str.length <= 15,
218
+ ]),
219
+ 'Password must have at leadt 8 chars and at most 15',
220
+ ],
221
+ })
222
+
223
+ expect(
224
+ validate(validator, {
225
+ username: 'username',
226
+ password: 'testpassword',
227
+ }),
228
+ ).toEqual(true)
229
+
230
+ expect(
231
+ validate(validator, {
232
+ username: 'username_',
233
+ password: 'testpassword',
234
+ }),
235
+ ).not.toEqual(true)
236
+
237
+ expect(
238
+ validate(validator, {
239
+ username: null,
240
+ password: 'testpassword',
241
+ }),
242
+ ).not.toEqual(true)
243
+
244
+ expect(
245
+ validate(validator, {
246
+ username: 'username123123',
247
+ password: 'testpassword',
248
+ }),
249
+ ).toEqual({
250
+ input: { username: 'username123123', password: 'testpassword' },
251
+ nestedErrors: [
252
+ {
253
+ input: 'username123123',
254
+ message:
255
+ 'Username must be have at least 5 chars, at most 10 chars and contain only alphanumeric characters (0-9,a-Z)',
256
+ path: 'username',
257
+ },
258
+ ],
259
+ message:
260
+ 'Invalid input: `{"username":"username123123","password":"testpassword"}`.\n' +
261
+ ' - username: Username must be have at least 5 chars, at most 10 chars and contain only alphanumeric characters (0-9,a-Z)',
262
+ })
263
+ })
264
+ })
265
+
266
+ describe('objOf', () => {
267
+ test('basic', () => {
268
+ const validator = validate.objOf(validate.type('string'))
269
+
270
+ expect(
271
+ validate(validator, {
272
+ key1: 'v1',
273
+ key2: 'v2',
274
+ }),
275
+ ).toEqual(true)
276
+ expect(
277
+ validate(validator, {
278
+ key1: 'v1',
279
+ key2: 6,
280
+ }),
281
+ ).toMatchObject({
282
+ nestedErrors: [
283
+ {
284
+ path: 'key2',
285
+ message:
286
+ "Invalid input: '6'. Expected type(s) `string`, but got type `number`",
287
+ },
288
+ ],
289
+ })
290
+ })
291
+ })
292
+
293
+ describe('tuple', () => {
294
+ test('basic', () => {
295
+ const validator = validate.tuple([
296
+ validate.type('function!'),
297
+ validate.tuple([validate.type('string!'), validate.type('number!')]),
298
+ ])
299
+
300
+ expect(validate(validator, [() => {}, ['string', 10]])).toEqual(true)
301
+
302
+ expect(validate(validator, [['string', 10]])).toMatchObject({
303
+ input: [['string', 10]],
304
+ nestedErrors: [
305
+ {
306
+ message:
307
+ "Invalid input: 'string,10'. Expected type(s) `function!`, but got type `array`",
308
+ path: '0',
309
+ },
310
+ {
311
+ message:
312
+ "Invalid input: 'undefined'. Expected type(s) `array!`, but got type `undefined`",
313
+ path: '1',
314
+ },
315
+ ],
316
+ message:
317
+ 'Invalid input: `[["string",10]]`.\n' +
318
+ " - 0: Invalid input: 'string,10'. Expected type(s) `function!`, but got type `array`\n" +
319
+ " - 1: Invalid input: 'undefined'. Expected type(s) `array!`, but got type `undefined`",
320
+ })
321
+ })
322
+ })
323
+
324
+ describe('arrayOf', () => {
325
+ test('basic', () => {
326
+ const validator = validate.arrayOf(
327
+ validate.or([
328
+ validate.type('string'),
329
+ validate.obj({
330
+ givenName: validate.type('string'),
331
+ age: validate.type('number'),
332
+ }),
333
+ ]),
334
+ )
335
+
336
+ expect(
337
+ validate(validator, [
338
+ 'Lee',
339
+ {
340
+ givenName: 'Andressa',
341
+ age: 40,
342
+ },
343
+ 'Amanda',
344
+ ]),
345
+ ).toEqual(true)
346
+
347
+ expect(
348
+ validate(validator, [
349
+ 50,
350
+ {
351
+ givenName: 'Andressa',
352
+ age: 40,
353
+ },
354
+ 'Amanda',
355
+ ]),
356
+ ).toMatchObject({
357
+ nestedErrors: [
358
+ { input: 50, message: "Invalid input: '50'.", path: '0' },
359
+ ],
360
+ message:
361
+ 'Invalid input: `[50,{"givenName":"Andressa","age":40},"Amanda"]`.\n' +
362
+ " - 0: Invalid input: '50'.",
363
+ })
364
+ })
365
+
366
+ test('minLength / maxLength', () => {
367
+ const validator = validate.and([
368
+ validate.arrayOf('string'),
369
+ (arr) => arr.length >= 5,
370
+ ])
371
+
372
+ expect(validate(validator, ['1', '2', '3', '4', '5'])).toEqual(true)
373
+ expect(validate(validator, ['1', '2', '3', '4'])).toEqual({
374
+ input: ['1', '2', '3', '4'],
375
+ message: "Invalid input: '1,2,3,4'.",
376
+ })
377
+ })
378
+ })
379
+
380
+ describe('not', () => {
381
+ test('basic', () => {
382
+ const notUndefinedOrNull = validate.not('undefined | null')
383
+ expect(validate(notUndefinedOrNull, 10)).toEqual(true)
384
+ expect(validate(notUndefinedOrNull, '10')).toEqual(true)
385
+ expect(validate(notUndefinedOrNull, false)).toEqual(true)
386
+ expect(validate(notUndefinedOrNull, null)).toEqual({
387
+ input: null,
388
+ message: "Invalid input: 'null'.",
389
+ })
390
+ expect(validate(notUndefinedOrNull)).toEqual({
391
+ input: undefined,
392
+ message: "Invalid input: 'undefined'.",
393
+ })
394
+ })
395
+ test('custom error message', () => {
396
+ const notUndefinedOrNull = [
397
+ validate.not('undefined | null'),
398
+ 'Must not be undefined or null',
399
+ ]
400
+ expect(validate(notUndefinedOrNull, 10)).toEqual(true)
401
+ expect(validate(notUndefinedOrNull, '10')).toEqual(true)
402
+ expect(validate(notUndefinedOrNull, false)).toEqual(true)
403
+ expect(validate(notUndefinedOrNull, null)).toEqual({
404
+ input: null,
405
+ message: 'Must not be undefined or null',
406
+ })
407
+ expect(validate(notUndefinedOrNull)).toEqual({
408
+ input: undefined,
409
+ message: 'Must not be undefined or null',
410
+ })
411
+ })
412
+ })
413
+ }