diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index 72edbe8d0e5c..0c22212cbc5a 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.value); this.namespace = namespaces[ns] || ns; } @@ -618,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) { @@ -630,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 new file mode 100644 index 000000000000..1f7223359652 --- /dev/null +++ b/src/utils/nodeToString.ts @@ -0,0 +1,11 @@ +import { Node } from '../interfaces'; + +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 a0fc3ee017e1..b6157578dbc6 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').value); validator.namespace = namespaces[ns] || ns; } diff --git a/src/validate/js/propValidators/namespace.ts b/src/validate/js/propValidators/namespace.ts index cf887df2bdbf..e7436f3eb472 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.value); - 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/src/validate/js/propValidators/props.ts b/src/validate/js/propValidators/props.ts index 57c1fb78ef8e..6731d6adcf1d 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 18b79760d9af..80a38baa80a6 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/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 000000000000..0813c3c14376 --- /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 000000000000..b4a0da70db75 --- /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 000000000000..7bef9787b0f1 --- /dev/null +++ b/test/runtime/samples/svg-child-component-declared-namespace-backtick-string/main.html @@ -0,0 +1,11 @@ + + + + + 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 000000000000..a1d3686c9a81 --- /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 000000000000..8702707db259 --- /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 000000000000..4d7e2ab20b82 --- /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 000000000000..3d1c0ba022ea --- /dev/null +++ b/test/validator/samples/properties-props-must-be-array-of-strings/input.html @@ -0,0 +1,7 @@ +
+ +