Skip to content

Commit

Permalink
add assertShape to validate templateElement (#10198)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tanhauhau authored and nicolo-ribaudo committed Jul 14, 2019
1 parent d3fe22f commit ee68d6d
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 1 deletion.
23 changes: 23 additions & 0 deletions packages/babel-types/scripts/utils/stringifyValidator.js
Expand Up @@ -31,6 +31,29 @@ module.exports = function stringifyValidator(validator, nodePrefix) {
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"];
};

Expand Down
11 changes: 10 additions & 1 deletion packages/babel-types/src/definitions/es2015.js
@@ -1,5 +1,6 @@
// @flow
import defineType, {
assertShape,
assertNodeType,
assertValueType,
chain,
Expand Down Expand Up @@ -542,7 +543,15 @@ defineType("TemplateElement", {
builder: ["value", "tail"],
fields: {
value: {
// todo: flatten `raw` into main node
validate: assertShape({
raw: {
validate: assertValueType("string"),
},
cooked: {
validate: assertValueType("string"),
optional: true,
},
}),
},
tail: {
validate: assertValueType("boolean"),
Expand Down
29 changes: 29 additions & 0 deletions packages/babel-types/src/definitions/utils.js
@@ -1,5 +1,6 @@
// @flow
import is from "../validators/is";
import { validateField } from "../validators/validate";

export const VISITOR_KEYS: { [string]: Array<string> } = {};
export const ALIAS_KEYS: { [string]: Array<string> } = {};
Expand Down Expand Up @@ -161,6 +162,34 @@ export function assertValueType(type: string): Validator {
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 {
function validate(...args) {
for (const fn of fns) {
Expand Down
9 changes: 9 additions & 0 deletions packages/babel-types/src/validators/validate.js
Expand Up @@ -8,6 +8,15 @@ export default function validate(node?: Object, key: string, val: any): void {
if (!fields) return;

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.optional && val == null) return;

Expand Down
@@ -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 changes: 25 additions & 0 deletions packages/babel-types/test/builders/es2015/templateElement.js
@@ -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();
});
});
});
});

0 comments on commit ee68d6d

Please sign in to comment.