From e81fb88f4113e2ddd58c548fc141a5f1a4b574ab Mon Sep 17 00:00:00 2001 From: Josh Duff Date: Wed, 28 Mar 2018 12:35:46 -0500 Subject: [PATCH 1/2] Fix backtick string literals not being recognized for the svg property Failing test for #1284 Fixes #1284 --- src/generators/Generator.ts | 3 ++- src/utils/nodeToString.ts | 11 ++++++++++ src/validate/js/index.ts | 3 ++- src/validate/js/propValidators/namespace.ts | 5 +++-- .../Rect.html | 7 +++++++ .../_config.js | 21 +++++++++++++++++++ .../main.html | 11 ++++++++++ 7 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/utils/nodeToString.ts create mode 100644 test/runtime/samples/svg-child-component-declared-namespace-backtick-string/Rect.html create mode 100644 test/runtime/samples/svg-child-component-declared-namespace-backtick-string/_config.js create mode 100644 test/runtime/samples/svg-child-component-declared-namespace-backtick-string/main.html diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 72edbe8d0e..07c4ab51e8 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -9,6 +9,7 @@ import flattenReference from '../utils/flattenReference'; import reservedNames from '../utils/reservedNames'; import namespaces from '../utils/namespaces'; import { removeNode, removeObjectKey } from '../utils/removeNode'; +import nodeToString from '../utils/nodeToString'; import wrapModule from './wrapModule'; import annotateWithScopes, { Scope } from '../utils/annotateWithScopes'; import getName from '../utils/getName'; @@ -599,7 +600,7 @@ export default class Generator { } if (templateProperties.namespace) { - const ns = templateProperties.namespace.value.value; + const ns = nodeToString(templateProperties.namespace); this.namespace = namespaces[ns] || ns; } diff --git a/src/utils/nodeToString.ts b/src/utils/nodeToString.ts new file mode 100644 index 0000000000..230214bb57 --- /dev/null +++ b/src/utils/nodeToString.ts @@ -0,0 +1,11 @@ +import { Node } from '../interfaces'; + +export default function nodeToString(prop: Node) { + if (prop.value.type === 'Literal' && typeof prop.value.value === 'string') { + return prop.value.value; + } else if (prop.value.type === 'TemplateLiteral' + && prop.value.quasis.length === 1 + && prop.value.expressions.length === 0) { + return prop.value.quasis[0].value.raw; + } +} diff --git a/src/validate/js/index.ts b/src/validate/js/index.ts index a0fc3ee017..3762cc81be 100644 --- a/src/validate/js/index.ts +++ b/src/validate/js/index.ts @@ -3,6 +3,7 @@ import fuzzymatch from '../utils/fuzzymatch'; import checkForDupes from './utils/checkForDupes'; import checkForComputedKeys from './utils/checkForComputedKeys'; import namespaces from '../../utils/namespaces'; +import nodeToString from '../../utils/nodeToString'; import getName from '../../utils/getName'; import { Validator } from '../'; import { Node } from '../../interfaces'; @@ -77,7 +78,7 @@ export default function validateJs(validator: Validator, js: Node) { }); if (props.has('namespace')) { - const ns = props.get('namespace').value.value; + const ns = nodeToString(props.get('namespace')); validator.namespace = namespaces[ns] || ns; } diff --git a/src/validate/js/propValidators/namespace.ts b/src/validate/js/propValidators/namespace.ts index cf887df2bd..a6270864ea 100644 --- a/src/validate/js/propValidators/namespace.ts +++ b/src/validate/js/propValidators/namespace.ts @@ -1,4 +1,5 @@ import * as namespaces from '../../../utils/namespaces'; +import nodeToString from '../../../utils/nodeToString' import fuzzymatch from '../../utils/fuzzymatch'; import { Validator } from '../../'; import { Node } from '../../../interfaces'; @@ -6,9 +7,9 @@ import { Node } from '../../../interfaces'; const valid = new Set(namespaces.validNamespaces); export default function namespace(validator: Validator, prop: Node) { - const ns = prop.value.value; + const ns = nodeToString(prop); - if (prop.value.type !== 'Literal' || typeof ns !== 'string') { + if (typeof ns !== 'string') { validator.error( `The 'namespace' property must be a string literal representing a valid namespace`, prop diff --git a/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/Rect.html b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/Rect.html new file mode 100644 index 0000000000..0813c3c143 --- /dev/null +++ b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/Rect.html @@ -0,0 +1,7 @@ + + + diff --git a/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/_config.js b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/_config.js new file mode 100644 index 0000000000..b4a0da70db --- /dev/null +++ b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/_config.js @@ -0,0 +1,21 @@ +export default { + data: { + x: 0, + y: 0, + width: 100, + height: 100 + }, + + html: ``, + + test ( assert, component, target ) { + const svg = target.querySelector( 'svg' ); + const rect = target.querySelector( 'rect' ); + + assert.equal( svg.namespaceURI, 'http://www.w3.org/2000/svg' ); + assert.equal( rect.namespaceURI, 'http://www.w3.org/2000/svg' ); + + component.set({ width: 150, height: 50 }); + assert.equal( target.innerHTML, `` ); + }, +}; diff --git a/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/main.html b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/main.html new file mode 100644 index 0000000000..7bef9787b0 --- /dev/null +++ b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/main.html @@ -0,0 +1,11 @@ + + + + + From 864fd313bbeb839e11a0b130a9398d01ffab9705 Mon Sep 17 00:00:00 2001 From: Josh Duff Date: Wed, 28 Mar 2018 16:12:38 -0500 Subject: [PATCH 2/2] Accept backtick string literals in tag/props properties --- src/generators/Generator.ts | 6 +++--- src/utils/nodeToString.ts | 14 +++++++------- src/validate/js/index.ts | 2 +- src/validate/js/propValidators/namespace.ts | 2 +- src/validate/js/propValidators/props.ts | 3 ++- src/validate/js/propValidators/tag.ts | 5 +++-- .../properties-props-must-be-an-array/errors.json | 12 ++++++++++++ .../properties-props-must-be-an-array/input.html | 7 +++++++ .../errors.json | 12 ++++++++++++ .../input.html | 7 +++++++ 10 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 test/validator/samples/properties-props-must-be-an-array/errors.json create mode 100644 test/validator/samples/properties-props-must-be-an-array/input.html create mode 100644 test/validator/samples/properties-props-must-be-array-of-strings/errors.json create mode 100644 test/validator/samples/properties-props-must-be-array-of-strings/input.html diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 07c4ab51e8..0c22212cbc 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -600,7 +600,7 @@ export default class Generator { } if (templateProperties.namespace) { - const ns = nodeToString(templateProperties.namespace); + const ns = nodeToString(templateProperties.namespace.value); this.namespace = namespaces[ns] || ns; } @@ -619,7 +619,7 @@ export default class Generator { } if (templateProperties.props) { - this.props = templateProperties.props.value.elements.map((element: Node) => element.value); + this.props = templateProperties.props.value.elements.map((element: Node) => nodeToString(element)); } if (templateProperties.setup) { @@ -631,7 +631,7 @@ export default class Generator { } if (templateProperties.tag) { - this.tag = templateProperties.tag.value.value; + this.tag = nodeToString(templateProperties.tag.value); } if (templateProperties.transitions) { diff --git a/src/utils/nodeToString.ts b/src/utils/nodeToString.ts index 230214bb57..1f72233596 100644 --- a/src/utils/nodeToString.ts +++ b/src/utils/nodeToString.ts @@ -1,11 +1,11 @@ import { Node } from '../interfaces'; -export default function nodeToString(prop: Node) { - if (prop.value.type === 'Literal' && typeof prop.value.value === 'string') { - return prop.value.value; - } else if (prop.value.type === 'TemplateLiteral' - && prop.value.quasis.length === 1 - && prop.value.expressions.length === 0) { - return prop.value.quasis[0].value.raw; +export default function nodeToString(node: Node) { + if (node.type === 'Literal' && typeof node.value === 'string') { + return node.value; + } else if (node.type === 'TemplateLiteral' + && node.quasis.length === 1 + && node.expressions.length === 0) { + return node.quasis[0].value.raw; } } diff --git a/src/validate/js/index.ts b/src/validate/js/index.ts index 3762cc81be..b6157578db 100644 --- a/src/validate/js/index.ts +++ b/src/validate/js/index.ts @@ -78,7 +78,7 @@ export default function validateJs(validator: Validator, js: Node) { }); if (props.has('namespace')) { - const ns = nodeToString(props.get('namespace')); + const ns = nodeToString(props.get('namespace').value); validator.namespace = namespaces[ns] || ns; } diff --git a/src/validate/js/propValidators/namespace.ts b/src/validate/js/propValidators/namespace.ts index a6270864ea..e7436f3eb4 100644 --- a/src/validate/js/propValidators/namespace.ts +++ b/src/validate/js/propValidators/namespace.ts @@ -7,7 +7,7 @@ import { Node } from '../../../interfaces'; const valid = new Set(namespaces.validNamespaces); export default function namespace(validator: Validator, prop: Node) { - const ns = nodeToString(prop); + const ns = nodeToString(prop.value); if (typeof ns !== 'string') { validator.error( diff --git a/src/validate/js/propValidators/props.ts b/src/validate/js/propValidators/props.ts index 57c1fb78ef..6731d6adcf 100644 --- a/src/validate/js/propValidators/props.ts +++ b/src/validate/js/propValidators/props.ts @@ -1,5 +1,6 @@ import { Validator } from '../../'; import { Node } from '../../../interfaces'; +import nodeToString from '../../../utils/nodeToString'; export default function props(validator: Validator, prop: Node) { if (prop.value.type !== 'ArrayExpression') { @@ -10,7 +11,7 @@ export default function props(validator: Validator, prop: Node) { } prop.value.elements.forEach((element: Node) => { - if (element.type !== 'Literal' || typeof element.value !== 'string') { + if (typeof nodeToString(element) !== 'string') { validator.error( `'props' must be an array of string literals`, element diff --git a/src/validate/js/propValidators/tag.ts b/src/validate/js/propValidators/tag.ts index 18b79760d9..80a38baa80 100644 --- a/src/validate/js/propValidators/tag.ts +++ b/src/validate/js/propValidators/tag.ts @@ -1,15 +1,16 @@ import { Validator } from '../../'; import { Node } from '../../../interfaces'; +import nodeToString from '../../../utils/nodeToString'; export default function tag(validator: Validator, prop: Node) { - if (prop.value.type !== 'Literal' || typeof prop.value.value !== 'string') { + const tag = nodeToString(prop.value); + if (typeof tag !== 'string') { validator.error( `'tag' must be a string literal`, prop.value ); } - const tag = prop.value.value; if (!/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(tag)) { validator.error( `tag name must be two or more words joined by the '-' character`, diff --git a/test/validator/samples/properties-props-must-be-an-array/errors.json b/test/validator/samples/properties-props-must-be-an-array/errors.json new file mode 100644 index 0000000000..a1d3686c9a --- /dev/null +++ b/test/validator/samples/properties-props-must-be-an-array/errors.json @@ -0,0 +1,12 @@ +[{ + "message": "'props' must be an array expression, if specified", + "loc": { + "line": 5, + "column": 9 + }, + "end": { + "line": 5, + "column": 11 + }, + "pos": 49 +}] diff --git a/test/validator/samples/properties-props-must-be-an-array/input.html b/test/validator/samples/properties-props-must-be-an-array/input.html new file mode 100644 index 0000000000..8702707db2 --- /dev/null +++ b/test/validator/samples/properties-props-must-be-an-array/input.html @@ -0,0 +1,7 @@ +
+ + diff --git a/test/validator/samples/properties-props-must-be-array-of-strings/errors.json b/test/validator/samples/properties-props-must-be-array-of-strings/errors.json new file mode 100644 index 0000000000..4d7e2ab20b --- /dev/null +++ b/test/validator/samples/properties-props-must-be-array-of-strings/errors.json @@ -0,0 +1,12 @@ +[{ + "message": "'props' must be an array of string literals", + "loc": { + "line": 5, + "column": 10 + }, + "end": { + "line": 5, + "column": 12 + }, + "pos": 50 +}] diff --git a/test/validator/samples/properties-props-must-be-array-of-strings/input.html b/test/validator/samples/properties-props-must-be-array-of-strings/input.html new file mode 100644 index 0000000000..3d1c0ba022 --- /dev/null +++ b/test/validator/samples/properties-props-must-be-array-of-strings/input.html @@ -0,0 +1,7 @@ +
+ +