From 5dc839d63dc0c9dcdb362f2ca6cc99b4b0b4263d Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Thu, 11 Jul 2019 09:07:49 +0800 Subject: [PATCH 1/3] add assertShape to validate templateElement --- .../scripts/utils/stringifyValidator.js | 13 +++++++++ .../babel-types/src/definitions/es2015.js | 6 +++- packages/babel-types/src/definitions/utils.js | 29 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/babel-types/scripts/utils/stringifyValidator.js b/packages/babel-types/scripts/utils/stringifyValidator.js index ff33e8e25ade..e146dcaff56a 100644 --- a/packages/babel-types/scripts/utils/stringifyValidator.js +++ b/packages/babel-types/scripts/utils/stringifyValidator.js @@ -31,6 +31,19 @@ module.exports = function stringifyValidator(validator, nodePrefix) { return validator.type; } + if (validator.shapeOf) { + return ( + "{" + + Object.keys(validator.shapeOf) + .map( + shapeKey => + shapeKey + ":" + stringifyValidator(validator.shapeOf[shapeKey]) + ) + .join(", ") + + "}" + ); + } + return ["any"]; }; diff --git a/packages/babel-types/src/definitions/es2015.js b/packages/babel-types/src/definitions/es2015.js index fb42b1390583..ea2390d3f42a 100644 --- a/packages/babel-types/src/definitions/es2015.js +++ b/packages/babel-types/src/definitions/es2015.js @@ -1,5 +1,6 @@ // @flow import defineType, { + assertShape, assertNodeType, assertValueType, chain, @@ -537,7 +538,10 @@ defineType("TemplateElement", { builder: ["value", "tail"], fields: { value: { - // todo: flatten `raw` into main node + validate: assertShape({ + raw: assertValueType("string"), + cooked: assertValueType("string"), + }), }, tail: { validate: assertValueType("boolean"), diff --git a/packages/babel-types/src/definitions/utils.js b/packages/babel-types/src/definitions/utils.js index c1d2ce762daa..ee8541f45517 100644 --- a/packages/babel-types/src/definitions/utils.js +++ b/packages/babel-types/src/definitions/utils.js @@ -161,6 +161,35 @@ export function assertValueType(type: string): Validator { return validate; } +export function assertShape(shape: {| [string]: Validator |}): Validator { + function validate(node, key, val) { + const errors = []; + for (const property of Object.keys(shape)) { + try { + const validator = shape[property]; + validator(node, property, val[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 { function validate(...args) { for (const fn of fns) { From 205828e345fb25002c7b1d0b18448186dc32ffff Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Fri, 12 Jul 2019 21:26:21 +0800 Subject: [PATCH 2/3] Update packages/babel-types/src/definitions/utils.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Nicolò Ribaudo --- packages/babel-types/src/definitions/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-types/src/definitions/utils.js b/packages/babel-types/src/definitions/utils.js index ee8541f45517..01a8f27614bb 100644 --- a/packages/babel-types/src/definitions/utils.js +++ b/packages/babel-types/src/definitions/utils.js @@ -161,7 +161,7 @@ export function assertValueType(type: string): Validator { return validate; } -export function assertShape(shape: {| [string]: Validator |}): Validator { +export function assertShape(shape: { [string]: Validator }): Validator { function validate(node, key, val) { const errors = []; for (const property of Object.keys(shape)) { From 74691efbf293c7c96342372f53a5302b0ab24fbd Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 13 Jul 2019 11:13:36 +0800 Subject: [PATCH 3/3] templateElement optional cooked --- .../scripts/utils/stringifyValidator.js | 22 ++++++++--- .../babel-types/src/definitions/es2015.js | 9 ++++- packages/babel-types/src/definitions/utils.js | 6 +-- .../babel-types/src/validators/validate.js | 9 +++++ .../__snapshots__/templateElement.js.snap | 37 +++++++++++++++++++ .../test/builders/es2015/templateElement.js | 25 +++++++++++++ 6 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 packages/babel-types/test/builders/es2015/__snapshots__/templateElement.js.snap create mode 100644 packages/babel-types/test/builders/es2015/templateElement.js diff --git a/packages/babel-types/scripts/utils/stringifyValidator.js b/packages/babel-types/scripts/utils/stringifyValidator.js index e146dcaff56a..2ea1e80357dd 100644 --- a/packages/babel-types/scripts/utils/stringifyValidator.js +++ b/packages/babel-types/scripts/utils/stringifyValidator.js @@ -33,14 +33,24 @@ module.exports = function stringifyValidator(validator, nodePrefix) { if (validator.shapeOf) { return ( - "{" + + "{ " + Object.keys(validator.shapeOf) - .map( - shapeKey => - shapeKey + ":" + stringifyValidator(validator.shapeOf[shapeKey]) - ) + .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(", ") + - "}" + " }" ); } diff --git a/packages/babel-types/src/definitions/es2015.js b/packages/babel-types/src/definitions/es2015.js index ea2390d3f42a..88da2cdd1181 100644 --- a/packages/babel-types/src/definitions/es2015.js +++ b/packages/babel-types/src/definitions/es2015.js @@ -539,8 +539,13 @@ defineType("TemplateElement", { fields: { value: { validate: assertShape({ - raw: assertValueType("string"), - cooked: assertValueType("string"), + raw: { + validate: assertValueType("string"), + }, + cooked: { + validate: assertValueType("string"), + optional: true, + }, }), }, tail: { diff --git a/packages/babel-types/src/definitions/utils.js b/packages/babel-types/src/definitions/utils.js index 01a8f27614bb..3f7225bd50b2 100644 --- a/packages/babel-types/src/definitions/utils.js +++ b/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 } = {}; export const ALIAS_KEYS: { [string]: Array } = {}; @@ -161,13 +162,12 @@ export function assertValueType(type: string): Validator { return validate; } -export function assertShape(shape: { [string]: Validator }): Validator { +export function assertShape(shape: { [string]: FieldOptions }): Validator { function validate(node, key, val) { const errors = []; for (const property of Object.keys(shape)) { try { - const validator = shape[property]; - validator(node, property, val[property]); + validateField(node, property, val[property], shape[property]); } catch (error) { if (error instanceof TypeError) { errors.push(error.message); diff --git a/packages/babel-types/src/validators/validate.js b/packages/babel-types/src/validators/validate.js index 9b2e9a8cd02a..738683849927 100644 --- a/packages/babel-types/src/validators/validate.js +++ b/packages/babel-types/src/validators/validate.js @@ -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; diff --git a/packages/babel-types/test/builders/es2015/__snapshots__/templateElement.js.snap b/packages/babel-types/test/builders/es2015/__snapshots__/templateElement.js.snap new file mode 100644 index 000000000000..a2f178169233 --- /dev/null +++ b/packages/babel-types/test/builders/es2015/__snapshots__/templateElement.js.snap @@ -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" +`; diff --git a/packages/babel-types/test/builders/es2015/templateElement.js b/packages/babel-types/test/builders/es2015/templateElement.js new file mode 100644 index 000000000000..0a93e7c8662a --- /dev/null +++ b/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(); + }); + }); + }); +});