[IMP] validation: add support for value types

This commit add supports for value types in prop validation. To describe
a value V type, one has to simply write {value: V}.

Note that this commit also improves the validation typing.

closes #1198
closes #910
This commit is contained in:
Géry Debongnie
2022-06-14 18:05:58 +02:00
committed by Sam Degueldre
parent 55ac43c1db
commit 9c4c3e3b83
3 changed files with 38 additions and 4 deletions
+2
View File
@@ -159,6 +159,7 @@ For each key, a `prop` definition is either a boolean, a constructor, a list of
- a boolean: indicate that the props exists, and is mandatory.
- a constructor: this should describe the type, for example: `id: Number` describe
the props `id` as a number
- an object describing a value as type. This is done by using the `value` key. For example, `{value: false}` specifies that the corresponding value should be equal to false.
- a list of constructors. In that case, this means that we allow more than one
type. For example, `id: [Number, String]` means that `id` can be either a string
or a number.
@@ -240,6 +241,7 @@ class ComponentB extends owl.Component {
size: {
validate: e => ["small", "medium", "large"].includes(e)
},
someId: [Number, {value: false}], // either a number or false
};
```
+10 -4
View File
@@ -8,9 +8,6 @@ type BaseType =
| true
| "*";
type UnionType = (TypeInfo | BaseType)[];
type TypeDescription = BaseType | UnionType | TypeInfo;
interface TypeInfo {
type?: TypeDescription;
optional?: boolean;
@@ -19,6 +16,9 @@ interface TypeInfo {
element?: TypeDescription;
}
type ValueType = { value: any };
type TypeDescription = BaseType | TypeInfo | ValueType | TypeDescription[];
type SimplifiedSchema = string[];
type NormalizedSchema = { [key: string]: TypeDescription };
export type Schema = SimplifiedSchema | NormalizedSchema;
@@ -26,8 +26,10 @@ export type Schema = SimplifiedSchema | NormalizedSchema;
// -----------------------------------------------------------------------------
// helpers
// -----------------------------------------------------------------------------
const isUnionType = (t: TypeDescription): t is UnionType => Array.isArray(t);
const isUnionType = (t: TypeDescription): t is TypeDescription[] => Array.isArray(t);
const isBaseType = (t: TypeDescription): t is BaseType => typeof t !== "object";
const isValueType = (t: TypeDescription): t is ValueType =>
typeof t === "object" && t && "value" in t;
export function isOptional(t: TypeDescription): Boolean {
return typeof t === "object" && "optional" in t ? t.optional || false : false;
@@ -42,6 +44,8 @@ function describe(info: TypeDescription): string {
return describeType(info);
} else if (isUnionType(info)) {
return info.map(describe).join(" or ");
} else if (isValueType(info)) {
return String(info.value);
}
if ("element" in info) {
return `list of ${describe({ type: info.element, optional: false })}s`;
@@ -134,6 +138,8 @@ function validateType(key: string, value: any, descr: TypeDescription): string |
return isOptional(descr) ? null : `'${key}' is undefined (should be a ${describe(descr)})`;
} else if (isBaseType(descr)) {
return validateBaseType(key, value, descr);
} else if (isValueType(descr)) {
return value === descr.value ? null : `'${key}' is not equal to '${descr.value}'`;
} else if (isUnionType(descr)) {
let validDescr = descr.find((p) => !validateType(key, value, p));
return validDescr ? null : `'${key}' is not a ${describe(descr)}`;
+26
View File
@@ -248,4 +248,30 @@ describe("validateSchema", () => {
expect(validateSchema({ size: "sall" }, schema)).toEqual(["'size' is not valid"]);
expect(validateSchema({ size: 1 }, schema)).toEqual(["'size' is not a string"]);
});
test("value as type", () => {
expect(validateSchema({ a: false }, { a: { value: false } })).toEqual([]);
expect(validateSchema({ a: true }, { a: { value: false } })).toEqual([
"'a' is not equal to 'false'",
]);
});
test("value as type (some other values)", () => {
expect(validateSchema({ a: null }, { a: { value: null } })).toEqual([]);
expect(validateSchema({ a: false }, { a: { value: null } })).toEqual([
"'a' is not equal to 'null'",
]);
expect(validateSchema({ a: "hey" }, { a: { value: "hey" } })).toEqual([]);
expect(validateSchema({ a: true }, { a: { value: "hey" } })).toEqual([
"'a' is not equal to 'hey'",
]);
});
test("value as type work in union type", () => {
expect(validateSchema({ a: false }, { a: [String, { value: false }] })).toEqual([]);
expect(validateSchema({ a: true }, { a: [String, { value: false }] })).toEqual([
"'a' is not a string or false",
]);
expect(validateSchema({ a: "string" }, { a: [String, { value: false }] })).toEqual([]);
});
});