add assertShape to validate templateElement (#10198)
* add assertShape to validate templateElement * Update packages/babel-types/src/definitions/utils.js Co-Authored-By: Nicolò Ribaudo <nicolo.ribaudo@gmail.com> * templateElement optional cooked
This commit is contained in:
parent
d3fe22f0e1
commit
ee68d6d1b0
@ -31,6 +31,29 @@ module.exports = function stringifyValidator(validator, nodePrefix) {
|
|||||||
return validator.type;
|
return validator.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validator.shapeOf) {
|
||||||
|
return (
|
||||||
|
"{ " +
|
||||||
|
Object.keys(validator.shapeOf)
|
||||||
|
.map(shapeKey => {
|
||||||
|
const propertyDefinition = validator.shapeOf[shapeKey];
|
||||||
|
if (propertyDefinition.validate) {
|
||||||
|
const isOptional =
|
||||||
|
propertyDefinition.optional || propertyDefinition.default != null;
|
||||||
|
return (
|
||||||
|
shapeKey +
|
||||||
|
(isOptional ? "?: " : ": ") +
|
||||||
|
stringifyValidator(propertyDefinition.validate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(", ") +
|
||||||
|
" }"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ["any"];
|
return ["any"];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import defineType, {
|
import defineType, {
|
||||||
|
assertShape,
|
||||||
assertNodeType,
|
assertNodeType,
|
||||||
assertValueType,
|
assertValueType,
|
||||||
chain,
|
chain,
|
||||||
@ -542,7 +543,15 @@ defineType("TemplateElement", {
|
|||||||
builder: ["value", "tail"],
|
builder: ["value", "tail"],
|
||||||
fields: {
|
fields: {
|
||||||
value: {
|
value: {
|
||||||
// todo: flatten `raw` into main node
|
validate: assertShape({
|
||||||
|
raw: {
|
||||||
|
validate: assertValueType("string"),
|
||||||
|
},
|
||||||
|
cooked: {
|
||||||
|
validate: assertValueType("string"),
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
tail: {
|
tail: {
|
||||||
validate: assertValueType("boolean"),
|
validate: assertValueType("boolean"),
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import is from "../validators/is";
|
import is from "../validators/is";
|
||||||
|
import { validateField } from "../validators/validate";
|
||||||
|
|
||||||
export const VISITOR_KEYS: { [string]: Array<string> } = {};
|
export const VISITOR_KEYS: { [string]: Array<string> } = {};
|
||||||
export const ALIAS_KEYS: { [string]: Array<string> } = {};
|
export const ALIAS_KEYS: { [string]: Array<string> } = {};
|
||||||
@ -161,6 +162,34 @@ export function assertValueType(type: string): Validator {
|
|||||||
return validate;
|
return validate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function assertShape(shape: { [string]: FieldOptions }): Validator {
|
||||||
|
function validate(node, key, val) {
|
||||||
|
const errors = [];
|
||||||
|
for (const property of Object.keys(shape)) {
|
||||||
|
try {
|
||||||
|
validateField(node, property, val[property], shape[property]);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof TypeError) {
|
||||||
|
errors.push(error.message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errors.length) {
|
||||||
|
throw new TypeError(
|
||||||
|
`Property ${key} of ${
|
||||||
|
node.type
|
||||||
|
} expected to have the following:\n${errors.join("\n")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validate.shapeOf = shape;
|
||||||
|
|
||||||
|
return validate;
|
||||||
|
}
|
||||||
|
|
||||||
export function chain(...fns: Array<Validator>): Validator {
|
export function chain(...fns: Array<Validator>): Validator {
|
||||||
function validate(...args) {
|
function validate(...args) {
|
||||||
for (const fn of fns) {
|
for (const fn of fns) {
|
||||||
|
|||||||
@ -8,6 +8,15 @@ export default function validate(node?: Object, key: string, val: any): void {
|
|||||||
if (!fields) return;
|
if (!fields) return;
|
||||||
|
|
||||||
const field = fields[key];
|
const field = fields[key];
|
||||||
|
validateField(node, key, val, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateField(
|
||||||
|
node?: Object,
|
||||||
|
key: string,
|
||||||
|
val: any,
|
||||||
|
field: any,
|
||||||
|
): void {
|
||||||
if (!field || !field.validate) return;
|
if (!field || !field.validate) return;
|
||||||
if (field.optional && val == null) return;
|
if (field.optional && val == null) return;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`builders es2015 templateElement should validate 1`] = `
|
||||||
|
Object {
|
||||||
|
"tail": false,
|
||||||
|
"type": "TemplateElement",
|
||||||
|
"value": Object {
|
||||||
|
"cooked": "foo",
|
||||||
|
"raw": "foo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`builders es2015 templateElement should validate 2`] = `
|
||||||
|
Object {
|
||||||
|
"tail": false,
|
||||||
|
"type": "TemplateElement",
|
||||||
|
"value": Object {
|
||||||
|
"raw": "foo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`builders es2015 templateElement should validate 3`] = `
|
||||||
|
"Property value of TemplateElement expected to have the following:
|
||||||
|
Property raw expected type of string but got number"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`builders es2015 templateElement should validate 4`] = `
|
||||||
|
"Property value of TemplateElement expected to have the following:
|
||||||
|
Property cooked expected type of string but got number"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`builders es2015 templateElement should validate 5`] = `
|
||||||
|
"Property value of TemplateElement expected to have the following:
|
||||||
|
Property raw expected type of string but got undefined"
|
||||||
|
`;
|
||||||
25
packages/babel-types/test/builders/es2015/templateElement.js
Normal file
25
packages/babel-types/test/builders/es2015/templateElement.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import * as t from "../../..";
|
||||||
|
|
||||||
|
describe("builders", function() {
|
||||||
|
describe("es2015", function() {
|
||||||
|
describe("templateElement", function() {
|
||||||
|
it("should validate", function() {
|
||||||
|
expect(
|
||||||
|
t.templateElement({ raw: "foo", cooked: "foo" }),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
|
||||||
|
expect(t.templateElement({ raw: "foo" })).toMatchSnapshot();
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
t.templateElement({ raw: 1 }),
|
||||||
|
).toThrowErrorMatchingSnapshot();
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
t.templateElement({ raw: "foo", cooked: 1 }),
|
||||||
|
).toThrowErrorMatchingSnapshot();
|
||||||
|
|
||||||
|
expect(() => t.templateElement("foo")).toThrowErrorMatchingSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user