@player-ui/common-types-plugin 0.8.0--canary.307.9621 → 0.8.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommonTypesPlugin.native.js +11903 -0
- package/dist/CommonTypesPlugin.native.js.map +1 -0
- package/dist/{index.cjs.js → cjs/index.cjs} +273 -233
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/{index.esm.js → index.legacy-esm.js} +246 -220
- package/dist/index.mjs +782 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +26 -58
- package/src/__tests__/index.test.ts +198 -0
- package/src/data-types/types.ts +27 -37
- package/src/formats/__tests__/formats.test.ts +264 -0
- package/src/formats/__tests__/utils.test.ts +44 -0
- package/src/formats/index.ts +71 -69
- package/src/formats/utils.ts +16 -16
- package/src/index.ts +12 -12
- package/src/validators/__tests__/index.test.ts +472 -0
- package/src/validators/index.ts +67 -68
- package/types/data-types/types.d.ts +10 -0
- package/types/formats/index.d.ts +24 -0
- package/types/formats/utils.d.ts +41 -0
- package/types/index.d.ts +27 -0
- package/types/validators/index.d.ts +68 -0
- package/dist/common-types-plugin.dev.js +0 -11388
- package/dist/common-types-plugin.prod.js +0 -2
- package/dist/index.d.ts +0 -260
- package/dist/xlr/BooleanType.json +0 -72
- package/dist/xlr/CollectionType.json +0 -39
- package/dist/xlr/DateType.json +0 -55
- package/dist/xlr/IntegerNNType.json +0 -75
- package/dist/xlr/IntegerPosType.json +0 -75
- package/dist/xlr/IntegerType.json +0 -55
- package/dist/xlr/PhoneType.json +0 -55
- package/dist/xlr/StringType.json +0 -62
- package/dist/xlr/manifest.js +0 -21
- package/dist/xlr/manifest.json +0 -26
- package/src/data-types/refs.ts +0 -33
package/src/formats/utils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { FormatType } from
|
|
1
|
+
import type { FormatType } from "@player-ui/player";
|
|
2
2
|
|
|
3
|
-
export const PLACEHOLDER =
|
|
3
|
+
export const PLACEHOLDER = "#";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Remove any formatting characters in the 'mask' from 'value'
|
|
@@ -15,14 +15,14 @@ export const PLACEHOLDER = '#';
|
|
|
15
15
|
export const removeFormatCharactersFromMaskedString = (
|
|
16
16
|
value: string,
|
|
17
17
|
mask: string,
|
|
18
|
-
reserved: string[] = [PLACEHOLDER]
|
|
18
|
+
reserved: string[] = [PLACEHOLDER],
|
|
19
19
|
): string => {
|
|
20
20
|
const reservedMatchesLength = mask
|
|
21
|
-
.split(
|
|
21
|
+
.split("")
|
|
22
22
|
.filter((val) => reserved.includes(val)).length;
|
|
23
23
|
let replacements = 0;
|
|
24
24
|
|
|
25
|
-
return value.split(
|
|
25
|
+
return value.split("").reduce((newString, nextChar, nextIndex) => {
|
|
26
26
|
const maskedVal = mask[nextIndex];
|
|
27
27
|
|
|
28
28
|
if (maskedVal === undefined) {
|
|
@@ -49,7 +49,7 @@ export const removeFormatCharactersFromMaskedString = (
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
return newString;
|
|
52
|
-
},
|
|
52
|
+
}, "");
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -66,7 +66,7 @@ export const formatAsEnum = (
|
|
|
66
66
|
|
|
67
67
|
/** If only 1 option is viable, autocomplete the value to the accepted one */
|
|
68
68
|
autocomplete?: boolean;
|
|
69
|
-
}
|
|
69
|
+
},
|
|
70
70
|
): string | undefined => {
|
|
71
71
|
const autoCompletionsByOverlapCount = acceptedValues
|
|
72
72
|
.reduce<
|
|
@@ -122,7 +122,7 @@ export const formatAsEnum = (
|
|
|
122
122
|
|
|
123
123
|
return autoCompletionsByOverlapCount[0].target.substr(
|
|
124
124
|
0,
|
|
125
|
-
autoCompletionsByOverlapCount[0].count
|
|
125
|
+
autoCompletionsByOverlapCount[0].count,
|
|
126
126
|
);
|
|
127
127
|
};
|
|
128
128
|
|
|
@@ -136,13 +136,13 @@ export const formatAsEnum = (
|
|
|
136
136
|
export const formatAsMasked = (
|
|
137
137
|
value: string | number,
|
|
138
138
|
valueCharMaskMatch: RegExp,
|
|
139
|
-
mask: string
|
|
139
|
+
mask: string,
|
|
140
140
|
): string => {
|
|
141
141
|
const valStr = String(value);
|
|
142
142
|
let withMask = mask;
|
|
143
143
|
|
|
144
|
-
if (valStr.trim() ===
|
|
145
|
-
return
|
|
144
|
+
if (valStr.trim() === "") {
|
|
145
|
+
return "";
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
valStr.replace(valueCharMaskMatch, (match) => {
|
|
@@ -160,7 +160,7 @@ export const formatAsMasked = (
|
|
|
160
160
|
*/
|
|
161
161
|
export const createMaskedNumericFormatter = (
|
|
162
162
|
name: string,
|
|
163
|
-
mask: string
|
|
163
|
+
mask: string,
|
|
164
164
|
): FormatType<
|
|
165
165
|
string,
|
|
166
166
|
string,
|
|
@@ -172,7 +172,7 @@ export const createMaskedNumericFormatter = (
|
|
|
172
172
|
return {
|
|
173
173
|
name,
|
|
174
174
|
format: (value, options) => {
|
|
175
|
-
if (typeof value !==
|
|
175
|
+
if (typeof value !== "string") {
|
|
176
176
|
return value;
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -183,7 +183,7 @@ export const createMaskedNumericFormatter = (
|
|
|
183
183
|
{
|
|
184
184
|
autocomplete: true,
|
|
185
185
|
ignoreCase: true,
|
|
186
|
-
}
|
|
186
|
+
},
|
|
187
187
|
);
|
|
188
188
|
|
|
189
189
|
if (formattedUsingExceptions !== undefined) {
|
|
@@ -194,7 +194,7 @@ export const createMaskedNumericFormatter = (
|
|
|
194
194
|
return formatAsMasked(value, /\d/g, mask);
|
|
195
195
|
},
|
|
196
196
|
deformat: (value, options) => {
|
|
197
|
-
if (typeof value !==
|
|
197
|
+
if (typeof value !== "string") {
|
|
198
198
|
return value;
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -209,7 +209,7 @@ export const createMaskedNumericFormatter = (
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
return formatAsMasked(value, /\d/g, mask.replace(/[^#]/g,
|
|
212
|
+
return formatAsMasked(value, /\d/g, mask.replace(/[^#]/g, ""));
|
|
213
213
|
},
|
|
214
214
|
};
|
|
215
215
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { Player, ExtendedPlayerPlugin } from
|
|
2
|
-
import { TypesProviderPlugin } from
|
|
1
|
+
import type { Player, ExtendedPlayerPlugin } from "@player-ui/player";
|
|
2
|
+
import { TypesProviderPlugin } from "@player-ui/types-provider-plugin";
|
|
3
3
|
|
|
4
|
-
import * as validators from
|
|
5
|
-
import * as dataTypes from
|
|
6
|
-
import * as
|
|
7
|
-
import * as formats from './formats';
|
|
4
|
+
import * as validators from "./validators";
|
|
5
|
+
import * as dataTypes from "./data-types/types";
|
|
6
|
+
import * as formats from "./formats";
|
|
8
7
|
import type {
|
|
9
8
|
BooleanType,
|
|
10
9
|
IntegerType,
|
|
@@ -14,10 +13,11 @@ import type {
|
|
|
14
13
|
CollectionType,
|
|
15
14
|
DateType,
|
|
16
15
|
PhoneType,
|
|
17
|
-
} from
|
|
16
|
+
} from "./data-types/types";
|
|
18
17
|
|
|
19
|
-
export { validators, dataTypes,
|
|
20
|
-
|
|
18
|
+
export { validators, dataTypes, formats };
|
|
19
|
+
|
|
20
|
+
export * from "./formats/utils";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Exposes a lot of common DataTypes, validations, and formats to Player instance.
|
|
@@ -36,11 +36,11 @@ export class CommonTypesPlugin
|
|
|
36
36
|
typeof StringType,
|
|
37
37
|
typeof CollectionType,
|
|
38
38
|
typeof DateType,
|
|
39
|
-
typeof PhoneType
|
|
39
|
+
typeof PhoneType,
|
|
40
40
|
]
|
|
41
41
|
>
|
|
42
42
|
{
|
|
43
|
-
name =
|
|
43
|
+
name = "CommonTypes";
|
|
44
44
|
|
|
45
45
|
apply(player: Player) {
|
|
46
46
|
player.registerPlugin(
|
|
@@ -48,7 +48,7 @@ export class CommonTypesPlugin
|
|
|
48
48
|
types: Object.values(dataTypes),
|
|
49
49
|
formats: Object.values(formats),
|
|
50
50
|
validators: Object.entries(validators),
|
|
51
|
-
})
|
|
51
|
+
}),
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { describe, test, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
BindingParser,
|
|
4
|
+
ConstantsController,
|
|
5
|
+
ExpressionEvaluator,
|
|
6
|
+
LocalModel,
|
|
7
|
+
withParser,
|
|
8
|
+
NoopLogger,
|
|
9
|
+
} from "@player-ui/player";
|
|
10
|
+
import type {
|
|
11
|
+
DataModelWithParser,
|
|
12
|
+
ValidationObject,
|
|
13
|
+
ValidatorContext,
|
|
14
|
+
} from "@player-ui/player";
|
|
15
|
+
import {
|
|
16
|
+
expression,
|
|
17
|
+
required,
|
|
18
|
+
readonly,
|
|
19
|
+
string,
|
|
20
|
+
integer,
|
|
21
|
+
collection,
|
|
22
|
+
length,
|
|
23
|
+
oneOf,
|
|
24
|
+
regex,
|
|
25
|
+
phone,
|
|
26
|
+
email,
|
|
27
|
+
zip,
|
|
28
|
+
min,
|
|
29
|
+
max,
|
|
30
|
+
} from "..";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
function create(
|
|
36
|
+
validation: Partial<ValidationObject> = {},
|
|
37
|
+
data: Record<string, unknown> = {},
|
|
38
|
+
) {
|
|
39
|
+
const fullValidation: ValidationObject = {
|
|
40
|
+
message: "Something is wrong",
|
|
41
|
+
type: "unknown",
|
|
42
|
+
severity: "error",
|
|
43
|
+
trigger: "change",
|
|
44
|
+
...validation,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const localModel = new LocalModel(data);
|
|
48
|
+
const parser = new BindingParser({
|
|
49
|
+
get: localModel.get,
|
|
50
|
+
set: localModel.set,
|
|
51
|
+
});
|
|
52
|
+
const model: DataModelWithParser = withParser(localModel, parser.parse);
|
|
53
|
+
const context: ValidatorContext = {
|
|
54
|
+
model,
|
|
55
|
+
parseBinding: parser.parse,
|
|
56
|
+
logger: new NoopLogger(),
|
|
57
|
+
validation: fullValidation,
|
|
58
|
+
constants: new ConstantsController(),
|
|
59
|
+
evaluate: new ExpressionEvaluator({ model }).evaluate,
|
|
60
|
+
schemaType: undefined,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return { context, validation: fullValidation };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
describe("required", () => {
|
|
67
|
+
it("returns nothing for valid data", () => {
|
|
68
|
+
const { context } = create({
|
|
69
|
+
type: "required",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(required(context, 0)).toBe(undefined);
|
|
73
|
+
expect(required(context, [])).toBe(undefined);
|
|
74
|
+
expect(required(context, "foo")).toBe(undefined);
|
|
75
|
+
expect(required(context, {})).toBe(undefined);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("errors on empty data", () => {
|
|
79
|
+
const { context } = create({
|
|
80
|
+
type: "required",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(required(context, "")?.message).toBe("A value is required");
|
|
84
|
+
expect(required(context, undefined)?.message).toBe("A value is required");
|
|
85
|
+
expect(required(context, null)?.message).toBe("A value is required");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("handles required-if expressions", () => {
|
|
89
|
+
const { context } = create(
|
|
90
|
+
{
|
|
91
|
+
type: "required",
|
|
92
|
+
},
|
|
93
|
+
{ foo: "bar" },
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(required(context, undefined, { if: '{{foo}} == "foo"' })).toBe(
|
|
97
|
+
undefined,
|
|
98
|
+
);
|
|
99
|
+
expect(
|
|
100
|
+
required(context, undefined, { if: '{{foo}} == "bar"' })?.message,
|
|
101
|
+
).toBe("A value is required");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("handles required-if-not expressions", () => {
|
|
105
|
+
const { context } = create(
|
|
106
|
+
{
|
|
107
|
+
type: "required",
|
|
108
|
+
},
|
|
109
|
+
{ foo: "bar" },
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
expect(
|
|
113
|
+
required(context, undefined, { ifNot: '{{foo}} == "foo"' })?.message,
|
|
114
|
+
).toBe("A value is required");
|
|
115
|
+
expect(required(context, undefined, { ifNot: '{{foo}} == "bar"' })).toBe(
|
|
116
|
+
undefined,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("expressions", () => {
|
|
122
|
+
it("no error on valid expressions", () => {
|
|
123
|
+
const { context, validation } = create({
|
|
124
|
+
type: "expression",
|
|
125
|
+
exp: '"foo" == "foo"',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(expression(context, undefined, validation as any)).toBe(undefined);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("error on invalid expressions", () => {
|
|
132
|
+
const { context, validation } = create({
|
|
133
|
+
type: "expression",
|
|
134
|
+
exp: '"foo" == "bar"',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(expression(context, undefined, validation as any)?.message).toBe(
|
|
138
|
+
"Expression evaluation failed",
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("does nothing with no expression", () => {
|
|
143
|
+
const { context, validation } = create({
|
|
144
|
+
type: "expression",
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(expression(context, undefined, validation as any)).toBe(undefined);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("readonly", () => {
|
|
152
|
+
it("only returns an error", () => {
|
|
153
|
+
const { context } = create({ type: "readonly" });
|
|
154
|
+
expect(readonly(context, "foo")?.message).toBe("Value cannot be modified");
|
|
155
|
+
expect(readonly(context, undefined)?.message).toBe(
|
|
156
|
+
"Value cannot be modified",
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("string", () => {
|
|
162
|
+
const { context } = create({ type: "string" });
|
|
163
|
+
|
|
164
|
+
it("works for strings", () => {
|
|
165
|
+
expect(string(context, "")).toBe(undefined);
|
|
166
|
+
expect(string(context, "foo")).toBe(undefined);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("handles nullish values", () => {
|
|
170
|
+
expect(string(context, null)).toBe(undefined);
|
|
171
|
+
expect(string(context, undefined)).toBe(undefined);
|
|
172
|
+
});
|
|
173
|
+
it("errors on non-strings", () => {
|
|
174
|
+
expect(string(context, {})?.message).toBe("Value must be a string");
|
|
175
|
+
expect(string(context, [])?.message).toBe("Value must be a string");
|
|
176
|
+
expect(string(context, 1234)?.message).toBe("Value must be a string");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("parameters on non-strings", () => {
|
|
180
|
+
expect(string(context, {})?.parameters?.type).toBe("object");
|
|
181
|
+
expect(string(context, [])?.parameters?.type).toBe("object");
|
|
182
|
+
expect(string(context, 1234)?.parameters?.type).toBe("number");
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("integer", () => {
|
|
187
|
+
const { context } = create({ type: "string" });
|
|
188
|
+
|
|
189
|
+
it("works for integers", () => {
|
|
190
|
+
expect(integer(context, -100)).toBe(undefined);
|
|
191
|
+
expect(integer(context, 100)).toBe(undefined);
|
|
192
|
+
expect(integer(context, 0)).toBe(undefined);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("handles nullish values", () => {
|
|
196
|
+
expect(integer(context, null)).toBe(undefined);
|
|
197
|
+
expect(integer(context, undefined)).toBe(undefined);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("errors on non-integers", () => {
|
|
201
|
+
expect(integer(context, 1234.567)?.message).toBe(
|
|
202
|
+
"Value must be an integer",
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("parameters on non-integers", () => {
|
|
207
|
+
expect(integer(context, 1234.567)?.parameters?.type).toBe("number");
|
|
208
|
+
expect(integer(context, 1234.567)?.parameters?.flooredValue).toBe(1234);
|
|
209
|
+
|
|
210
|
+
expect(integer(context, "test")?.parameters?.type).toBe("string");
|
|
211
|
+
expect(integer(context, "test")?.parameters?.flooredValue).toBe(NaN);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("errors on out of bounds integers", () => {
|
|
215
|
+
expect(integer(context, Number.MAX_SAFE_INTEGER + 1)?.message).toBe(
|
|
216
|
+
"Value must be an integer",
|
|
217
|
+
);
|
|
218
|
+
expect(integer(context, Number.MIN_SAFE_INTEGER - 1)?.message).toBe(
|
|
219
|
+
"Value must be an integer",
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("treats empty value as valid", () => {
|
|
224
|
+
expect(integer(context, "")).toBe(undefined);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("collection", () => {
|
|
229
|
+
const { context } = create({ type: "string" });
|
|
230
|
+
|
|
231
|
+
it("works for arrays", () => {
|
|
232
|
+
expect(collection(context, [])).toBe(undefined);
|
|
233
|
+
expect(collection(context, ["foo"])).toBe(undefined);
|
|
234
|
+
expect(collection(context, [1, 2, 3])).toBe(undefined);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("handles nullish values", () => {
|
|
238
|
+
expect(collection(context, null)).toBe(undefined);
|
|
239
|
+
expect(collection(context, undefined)).toBe(undefined);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("errors on non-arrays", () => {
|
|
243
|
+
expect(collection(context, 1234.567)?.message).toBe(
|
|
244
|
+
"Cannot set collection to non-array",
|
|
245
|
+
);
|
|
246
|
+
expect(collection(context, { 1: "a" })?.message).toBe(
|
|
247
|
+
"Cannot set collection to non-array",
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe("oneOf", () => {
|
|
253
|
+
const { context } = create({ type: "oneOf" });
|
|
254
|
+
|
|
255
|
+
it("does nothing if no options are provided", () => {
|
|
256
|
+
expect(oneOf(context, "foo")).toBe(undefined);
|
|
257
|
+
expect(oneOf(context, "foo", {} as any)).toBe(undefined);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("handles nullish values", () => {
|
|
261
|
+
expect(oneOf(context, null, { options: ["foo", "bar"] })).toBe(undefined);
|
|
262
|
+
expect(oneOf(context, undefined, { options: ["foo", "bar"] })).toBe(
|
|
263
|
+
undefined,
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
it("works across types", () => {
|
|
267
|
+
expect(oneOf(context, "foo", { options: ["foo", "bar"] })).toBe(undefined);
|
|
268
|
+
expect(
|
|
269
|
+
oneOf(context, "not foo", { options: ["foo", "bar"] })?.message,
|
|
270
|
+
).toBe("Invalid entry");
|
|
271
|
+
expect(oneOf(context, true, { options: ["foo", "bar", true] })).toBe(
|
|
272
|
+
undefined,
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe("regex", () => {
|
|
278
|
+
const { context } = create({ type: "regex" }, { foo: "asset" });
|
|
279
|
+
|
|
280
|
+
it("does nothing with invalid entries", () => {
|
|
281
|
+
expect(regex(context, undefined)).toBe(undefined);
|
|
282
|
+
expect(regex(context, null)).toBe(undefined);
|
|
283
|
+
expect(regex(context, "foo", { regex: 345 } as any)).toBe(undefined);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("validates", () => {
|
|
287
|
+
expect(regex(context, "asset_text", { regex: "asset" })).toBe(undefined);
|
|
288
|
+
expect(regex(context, "", { regex: "asset" })).toBe(undefined);
|
|
289
|
+
expect(regex(context, "asset_text", { regex: "view" })?.message).toBe(
|
|
290
|
+
"Invalid entry",
|
|
291
|
+
);
|
|
292
|
+
expect(regex(context, "view_info", { regex: "view" })).toBe(undefined);
|
|
293
|
+
expect(regex(context, "view_info", { regex: "asset" })?.message).toBe(
|
|
294
|
+
"Invalid entry",
|
|
295
|
+
);
|
|
296
|
+
expect(regex(context, "FOO", { regex: "foo" })?.message).toBe(
|
|
297
|
+
"Invalid entry",
|
|
298
|
+
);
|
|
299
|
+
// i ignores case
|
|
300
|
+
expect(regex(context, "FOO", { regex: "/foo/i" })).toBe(undefined);
|
|
301
|
+
|
|
302
|
+
// Regex uses data reference
|
|
303
|
+
expect(regex(context, "asset_text", { regex: "{{foo}}" })).toBe(undefined);
|
|
304
|
+
expect(regex(context, "asset_text", { regex: "@[{{foo}}]@" })).toBe(
|
|
305
|
+
undefined,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
expect(regex(context, "asset_text", { regex: "a{{foo}}" })?.message).toBe(
|
|
309
|
+
"Invalid entry",
|
|
310
|
+
);
|
|
311
|
+
expect(regex(context, "view_info", { regex: "{{foo}}" })?.message).toBe(
|
|
312
|
+
"Invalid entry",
|
|
313
|
+
);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe("length", () => {
|
|
318
|
+
const { context } = create({ type: "length" });
|
|
319
|
+
|
|
320
|
+
it("works on strings", () => {
|
|
321
|
+
expect(length(context, "123", { exact: 3 })).toBe(undefined);
|
|
322
|
+
expect(length(context, "123", { exact: 5 })?.message).toBe(
|
|
323
|
+
"Must be exactly 5 characters long",
|
|
324
|
+
);
|
|
325
|
+
expect(
|
|
326
|
+
length(context, "123", { exact: 5 })?.parameters?.validationLength,
|
|
327
|
+
).toBe(3);
|
|
328
|
+
|
|
329
|
+
expect(length(context, "123", { min: 3 })).toBe(undefined);
|
|
330
|
+
expect(length(context, "123", { min: 10 })?.message).toBe(
|
|
331
|
+
"At least 10 characters needed",
|
|
332
|
+
);
|
|
333
|
+
expect(
|
|
334
|
+
length(context, "123", { min: 10 })?.parameters?.validationLength,
|
|
335
|
+
).toBe(3);
|
|
336
|
+
|
|
337
|
+
expect(length(context, "12345", { max: 3 })?.message).toBe(
|
|
338
|
+
"Up to 3 characters allowed",
|
|
339
|
+
);
|
|
340
|
+
expect(
|
|
341
|
+
length(context, "12345", { max: 3 })?.parameters?.validationLength,
|
|
342
|
+
).toBe(5);
|
|
343
|
+
expect(length(context, "12345", { max: 10 })).toBe(undefined);
|
|
344
|
+
});
|
|
345
|
+
it("works on objects", () => {
|
|
346
|
+
expect(length(context, { 1: "1", 2: "2", 3: "3" }, { exact: 3 })).toBe(
|
|
347
|
+
undefined,
|
|
348
|
+
);
|
|
349
|
+
expect(
|
|
350
|
+
length(context, { a: "a", b: "b", c: "c" }, { exact: 5 })?.message,
|
|
351
|
+
).toBe("Must be exactly 5 items long");
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("works on arrays", () => {
|
|
355
|
+
expect(length(context, ["a", "b", "c"], { exact: 3 })).toBe(undefined);
|
|
356
|
+
expect(length(context, ["a", "b", "c"], { exact: 5 })?.message).toBe(
|
|
357
|
+
"Must be exactly 5 items long",
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it("does nothing when no length is present", () => {
|
|
362
|
+
expect(length(context, "123")).toBe(undefined);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("does nothing if it cant determine the length", () => {
|
|
366
|
+
expect(length(context, undefined, { exact: 10 })).toBe(undefined);
|
|
367
|
+
expect(length(context, null, { exact: 10 })).toBe(undefined);
|
|
368
|
+
expect(length(context, 1234)).toBe(undefined);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("min", () => {
|
|
373
|
+
const { context } = create({ type: "min" });
|
|
374
|
+
|
|
375
|
+
expect(min(context, undefined, { value: 1 })).toBeUndefined();
|
|
376
|
+
expect(min(context, null, { value: 1 })).toBeUndefined();
|
|
377
|
+
|
|
378
|
+
expect(min(context, 1)).toBeUndefined();
|
|
379
|
+
expect(min(context, 1, { value: 1 })).toBeUndefined();
|
|
380
|
+
expect(min(context, 2, { value: 1 })).toBeUndefined();
|
|
381
|
+
expect(min(context, 0, { value: 1 })).toStrictEqual({
|
|
382
|
+
message: "Must be at least 1",
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("max", () => {
|
|
387
|
+
const { context } = create({ type: "min" });
|
|
388
|
+
expect(max(context, undefined, { value: 1 })).toBeUndefined();
|
|
389
|
+
expect(max(context, null, { value: 1 })).toBeUndefined();
|
|
390
|
+
expect(max(context, 1)).toBeUndefined();
|
|
391
|
+
expect(max(context, 1, { value: 1 })).toBeUndefined();
|
|
392
|
+
expect(max(context, 2, { value: 1 })).toStrictEqual({
|
|
393
|
+
message: "Cannot exceed 1",
|
|
394
|
+
});
|
|
395
|
+
expect(max(context, 0, { value: 1 })).toBeUndefined();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test("email", () => {
|
|
399
|
+
const { context } = create({ type: "email" });
|
|
400
|
+
expect(email(context, undefined)).toBeUndefined();
|
|
401
|
+
expect(email(context, null)).toBeUndefined();
|
|
402
|
+
|
|
403
|
+
expect(email(context, "abc.xyz@pqr.com")).toBeUndefined();
|
|
404
|
+
expect(email(context, "")).toBeUndefined();
|
|
405
|
+
expect(email(context, "x.com")).toStrictEqual({
|
|
406
|
+
message: "Improper email format",
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
describe("phone", () => {
|
|
411
|
+
const { context } = create({ type: "phone" });
|
|
412
|
+
const invalid = { message: "Invalid phone number" };
|
|
413
|
+
it("works for good values", () => {
|
|
414
|
+
expect(phone(context, "1234567890")).toBeUndefined();
|
|
415
|
+
expect(phone(context, "")).toBeUndefined();
|
|
416
|
+
expect(phone(context, "345-222-1212")).toBeUndefined();
|
|
417
|
+
expect(phone(context, "+1-345-222-1212")).toBeUndefined();
|
|
418
|
+
expect(phone(context, "3452221212")).toBeUndefined();
|
|
419
|
+
expect(phone(context, "13452221212")).toBeUndefined();
|
|
420
|
+
expect(phone(context, "1 345 222 1212")).toBeUndefined();
|
|
421
|
+
expect(phone(context, "345 222 1212")).toBeUndefined();
|
|
422
|
+
expect(phone(context, "(345) 222 1212")).toBeUndefined();
|
|
423
|
+
expect(phone(context, "(345)222-1212")).toBeUndefined();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("handles nullish values", () => {
|
|
427
|
+
expect(phone(context, undefined)).toBeUndefined();
|
|
428
|
+
expect(phone(context, null)).toBeUndefined();
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("returns error for invalid values", () => {
|
|
432
|
+
expect(phone(context, "(345)222-121")).toStrictEqual(invalid);
|
|
433
|
+
expect(phone(context, "(345) 222-121")).toStrictEqual(invalid);
|
|
434
|
+
expect(phone(context, "(345)222-121B")).toStrictEqual(invalid);
|
|
435
|
+
expect(phone(context, "(2345)222-1212")).toStrictEqual(invalid);
|
|
436
|
+
expect(phone(context, "(345) aaa888-1212")).toStrictEqual(invalid);
|
|
437
|
+
expect(phone(context, "+2-345-222-1212")).toStrictEqual(invalid);
|
|
438
|
+
expect(phone(context, "+1-345-222-121")).toStrictEqual(invalid);
|
|
439
|
+
expect(phone(context, "3")).toStrictEqual(invalid);
|
|
440
|
+
expect(phone(context, "A")).toStrictEqual(invalid);
|
|
441
|
+
expect(phone(context, "+2-345-222-1212")).toStrictEqual(invalid);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test("zip", () => {
|
|
446
|
+
const { context } = create({ type: "zip" });
|
|
447
|
+
expect(zip(context, undefined)).toBeUndefined();
|
|
448
|
+
expect(zip(context, null)).toBeUndefined();
|
|
449
|
+
expect(zip(context, "21216-1213")).toBeUndefined();
|
|
450
|
+
expect(zip(context, "2122")).toStrictEqual({ message: "Invalid zip code" });
|
|
451
|
+
expect(zip(context, "")).toBeUndefined();
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
describe("testing localization overrides", () => {
|
|
455
|
+
it("should take the new message then the old message after rest", () => {
|
|
456
|
+
const { context } = create({
|
|
457
|
+
type: "required",
|
|
458
|
+
});
|
|
459
|
+
const newMessages = {
|
|
460
|
+
validation: {
|
|
461
|
+
required: "Wow thats like, super wrong",
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
context.constants.setTemporaryValues(newMessages, "constants");
|
|
465
|
+
expect(required(context, "")?.message).toStrictEqual(
|
|
466
|
+
newMessages.validation.required,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
context.constants.clearTemporaryValues();
|
|
470
|
+
expect(required(context, "")?.message).toStrictEqual("A value is required");
|
|
471
|
+
});
|
|
472
|
+
});
|