Skip to content

Commit e2b0086

Browse files
authored
Merge pull request #314 from DenisFerrero/master
convert property in array type
2 parents 7b35571 + 38783bc commit e2b0086

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,19 @@ check({ roles: ["user", "admin", "user"] }); // Fail
486486
check({ roles: [1, 2, 1] }); // Fail
487487
```
488488

489+
**Example for `convert`:**
490+
491+
```js
492+
const schema = {
493+
roles: { type: "array", items: 'string', convert: true }
494+
}
495+
const check = v.compile(schema);
496+
497+
check({ roles: ["user"] }); // Valid
498+
check({ roles: "user" }); // Valid
499+
// After both validation: roles = ["user"]
500+
```
501+
489502
### Properties
490503
Property | Default | Description
491504
-------- | -------- | -----------
@@ -497,6 +510,7 @@ Property | Default | Description
497510
`unique` | `null` | The array must be unique (array of objects is always unique).
498511
`enum` | `null` | Every element must be an element of the `enum` array.
499512
`items` | `null` | Schema for array items.
513+
`convert`| `null` | Wrap value into array if different type provided
500514

501515
## `boolean`
502516
This is a `Boolean` validator.

lib/rules/array.js

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55
module.exports = function ({ schema, messages }, path, context) {
66
const src = [];
77

8+
let sanitized = false;
9+
if (schema.convert === true) {
10+
sanitized = true;
11+
// Convert to array if not and the value is not null or undefined
12+
src.push(`
13+
if (!Array.isArray(value) && value != null) {
14+
value = [value];
15+
}
16+
`);
17+
}
18+
819
src.push(`
920
if (!Array.isArray(value)) {
1021
${this.makeError({ type: "array", actual: "value", messages })}
@@ -99,6 +110,7 @@ module.exports = function ({ schema, messages }, path, context) {
99110
}
100111

101112
return {
113+
sanitized,
102114
source: src.join("\n")
103115
};
104116
};

test/rules/array.spec.js

+40
Original file line numberDiff line numberDiff line change
@@ -191,5 +191,45 @@ describe("Test rule: array", () => {
191191
expect(errors[0].type).toBe("evenNumber");
192192
expect(o.a).toEqual([2, 4, 8]);
193193
});
194+
195+
describe("conversion behavior", () => {
196+
// !! Don't use a $$root schema because the value to check will not be passed as reference but as value
197+
const check = v.compile({ data: { type: "array", items: "string", convert: true } });
198+
// Single value check
199+
it ("should wrap single value into array", () => {
200+
const value = { data: "John" };
201+
expect(check(value)).toEqual(true);
202+
expect(value.data).toEqual(["John"]);
203+
});
204+
// Already array, one element
205+
it ("should not change array with one element", () => {
206+
const value = { data: ["John"] };
207+
expect(check(value)).toEqual(true);
208+
expect(value.data).toEqual(["John"]);
209+
});
210+
// Already array, multiple elements
211+
it ("should not change array with multiple elements", () => {
212+
const value = { data: ["John", "Jane"] };
213+
expect(check(value)).toEqual(true);
214+
expect(value.data).toEqual(["John", "Jane"]);
215+
});
216+
// Empty array
217+
it ("should not change empty array", () => {
218+
const value = { data: [] };
219+
expect(check(value)).toEqual(true);
220+
expect(value.data).toEqual([]);
221+
});
222+
// Null/undefined
223+
it ("should not convert into array if null or undefined", () => {
224+
// Null check
225+
const value = { data: null };
226+
expect(check(value)).toEqual([{ type: "required", field: "data", actual: null, message: "The 'data' field is required." }]);
227+
expect(value.data).toEqual(null);
228+
// Undefined check
229+
const value2 = { data: undefined };
230+
expect(check(value2)).toEqual([{ type: "required", field: "data", actual: undefined, message: "The 'data' field is required." }]);
231+
expect(value2.data).toEqual(undefined);
232+
});
233+
});
194234
});
195235
});

test/typescript/rules/array.spec.ts

+39
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,44 @@ describe('TypeScript Definitions', () => {
129129
});
130130
});
131131

132+
describe("conversion behavior", () => {
133+
// !! Don't use a $$root schema because the value to check will not be passed as reference but as value
134+
const check = v.compile({ data: { type: "array", items: "string", convert: true } });
135+
// Single value check
136+
it ("should wrap single value into array", () => {
137+
const value = { data: "John" };
138+
expect(check(value)).toEqual(true);
139+
expect(value.data).toEqual(["John"]);
140+
});
141+
// Already array, one element
142+
it ("should not change array with one element", () => {
143+
const value = { data: ["John"] };
144+
expect(check(value)).toEqual(true);
145+
expect(value.data).toEqual(["John"]);
146+
});
147+
// Already array, multiple elements
148+
it ("should not change array with multiple elements", () => {
149+
const value = { data: ["John", "Jane"] };
150+
expect(check(value)).toEqual(true);
151+
expect(value.data).toEqual(["John", "Jane"]);
152+
});
153+
// Empty array
154+
it ("should not change empty array", () => {
155+
const value = { data: [] };
156+
expect(check(value)).toEqual(true);
157+
expect(value.data).toEqual([]);
158+
});
159+
// Null/undefined
160+
it ("should not convert into array if null or undefined", () => {
161+
// Null check
162+
const value = { data: null };
163+
expect(check(value)).toEqual([{ type: "required", field: "data", actual: null, message: "The 'data' field is required." }]);
164+
expect(value.data).toEqual(null);
165+
// Undefined check
166+
const value2 = { data: undefined };
167+
expect(check(value2)).toEqual([{ type: "required", field: "data", actual: undefined, message: "The 'data' field is required." }]);
168+
expect(value2.data).toEqual(undefined);
169+
});
170+
});
132171
});
133172
});

0 commit comments

Comments
 (0)