exports[`compile > directives > v-pre > basic 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}", true)
+const t0 = _template("<div :id=foo><Comp></Comp>{{ bar }}", true)
export function render(_ctx, $props, $emit, $attrs, $slots) {
const n0 = t0()
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}")
+const t0 = _template("<div :id=foo><Comp></Comp>{{ bar }}")
const t1 = _template("<div> ")
export function render(_ctx, $props, $emit, $attrs, $slots) {
expect(code).toMatchSnapshot()
expect(code).contains(
- JSON.stringify('<div :id="foo"><Comp></Comp>{{ bar }}'),
+ JSON.stringify('<div :id=foo><Comp></Comp>{{ bar }}'),
)
expect(code).not.contains('effect')
})
exports[`compiler sfc: transform asset url > should allow for full base URLs, with paths 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<img src=\\"http://localhost:3000/src/logo.png\\">", true)
+const t0 = _template("<img src=http://localhost:3000/src/logo.png>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler sfc: transform asset url > should allow for full base URLs, without paths 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<img src=\\"http://localhost:3000/logo.png\\">", true)
+const t0 = _template("<img src=http://localhost:3000/logo.png>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler sfc: transform asset url > should allow for full base URLs, without port 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<img src=\\"http://localhost/logo.png\\">", true)
+const t0 = _template("<img src=http://localhost/logo.png>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler sfc: transform asset url > should allow for full base URLs, without protocol 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<img src=\\"//localhost/logo.png\\">", true)
+const t0 = _template("<img src=//localhost/logo.png>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler sfc: transform asset url > support uri is empty 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<use href=\\"\\">", true, 1)
+const t0 = _template("<use href>", true, 1)
export function render(_ctx) {
const n0 = t0()
import _imports_2 from '/fixtures/logo.png';
const t0 = _template("<img src=\\"" + _imports_0 + "\\">")
const t1 = _template("<img src=\\"" + _imports_1 + "\\">")
-const t2 = _template("<img src=\\"http://example.com/fixtures/logo.png\\">")
-const t3 = _template("<img src=\\"//example.com/fixtures/logo.png\\">")
+const t2 = _template("<img src=http://example.com/fixtures/logo.png>")
+const t3 = _template("<img src=//example.com/fixtures/logo.png>")
const t4 = _template("<img src=\\"" + _imports_2 + "\\">")
-const t5 = _template("<img src=\\"data:image/png;base64,i\\">")
+const t5 = _template("<img src=data:image/png;base64,i>")
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from './bar.png';
import _imports_1 from '/bar.png';
-const t0 = _template("<div><img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\">", true)
+const t0 = _template("<div><img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=https://foo.bar/baz.png><img src=//foo.bar/baz.png><img src=\\"" + _imports_0 + "\\">", true)
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from 'bar.png';
import _imports_1 from '@theme/bar.png';
-const t0 = _template("<img src=\\"/foo/bar.png\\">")
+const t0 = _template("<img src=/foo/bar.png>")
const t1 = _template("<img src=\\"" + _imports_0 + "\\">")
const t2 = _template("<img src=\\"" + _imports_1 + "\\">")
import _imports_1 from '/bar.png';
const t0 = _template("<img src=\\"" + _imports_0 + "\\">")
const t1 = _template("<img src=\\"" + _imports_1 + "\\">")
-const t2 = _template("<img src=\\"https://foo.bar/baz.png\\">")
-const t3 = _template("<img src=\\"//foo.bar/baz.png\\">")
+const t2 = _template("<img src=https://foo.bar/baz.png>")
+const t3 = _template("<img src=//foo.bar/baz.png>")
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from './logo.png';
import _imports_1 from '/logo.png';
-const t0 = _template("<img src=\\"" + _imports_0 + "\\" srcset>")
-const t1 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + "\\">")
-const t2 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x' + "\\">")
-const t3 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
-const t4 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\">")
-const t5 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
-const t6 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
-const t7 = _template("<img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\">")
-const t8 = _template("<img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
-const t9 = _template("<img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\">")
-const t10 = _template("<img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
+const t0 = _template("<img src=\\"" + _imports_0 + "\\"srcset>")
+const t1 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + "\\">")
+const t2 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x' + "\\">")
+const t3 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
+const t4 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\">")
+const t5 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
+const t6 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
+const t7 = _template("<img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\">")
+const t8 = _template("<img src=https://example.com/logo.png srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
+const t9 = _template("<img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\">")
+const t10 = _template("<img src=data:image/png;base64,i srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from '/logo.png';
import _imports_1 from '/foo/logo.png';
-const t0 = _template("<img src=\\"/foo/logo.png\\" srcset>")
-const t1 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png\\">")
-const t2 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png 2x\\">")
-const t3 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png, /foo/logo.png 2x\\">")
-const t4 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png 2x, /foo/logo.png\\">")
-const t5 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png 2x, /foo/logo.png 3x\\">")
-const t6 = _template("<img src=\\"/foo/logo.png\\" srcset=\\"/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x\\">")
-const t7 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
-const t8 = _template("<img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
-const t9 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_1 + ' 2x' + "\\">")
-const t10 = _template("<img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
+const t0 = _template("<img src=/foo/logo.png srcset>")
+const t1 = _template("<img src=/foo/logo.png srcset=/foo/logo.png>")
+const t2 = _template("<img src=/foo/logo.png srcset=\\"/foo/logo.png 2x\\">")
+const t3 = _template("<img src=/foo/logo.png srcset=\\"/foo/logo.png, /foo/logo.png 2x\\">")
+const t4 = _template("<img src=/foo/logo.png srcset=\\"/foo/logo.png 2x, /foo/logo.png\\">")
+const t5 = _template("<img src=/foo/logo.png srcset=\\"/foo/logo.png 2x, /foo/logo.png 3x\\">")
+const t6 = _template("<img src=/foo/logo.png srcset=\\"/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x\\">")
+const t7 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
+const t8 = _template("<img src=https://example.com/logo.png srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
+const t9 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_1 + ' 2x' + "\\">")
+const t10 = _template("<img src=data:image/png;base64,i srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from './logo.png';
import _imports_1 from '/logo.png';
-const t0 = _template("<img src=\\"" + _imports_0 + "\\" srcset>")
-const t1 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + "\\">")
-const t2 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x' + "\\">")
-const t3 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
-const t4 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\">")
-const t5 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
-const t6 = _template("<img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
-const t7 = _template("<img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\">")
-const t8 = _template("<img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
-const t9 = _template("<img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\">")
-const t10 = _template("<img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
+const t0 = _template("<img src=\\"" + _imports_0 + "\\"srcset>")
+const t1 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + "\\">")
+const t2 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x' + "\\">")
+const t3 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\">")
+const t4 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\">")
+const t5 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
+const t6 = _template("<img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\">")
+const t7 = _template("<img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\">")
+const t8 = _template("<img src=https://example.com/logo.png srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\">")
+const t9 = _template("<img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\">")
+const t10 = _template("<img src=data:image/png;base64,i srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">")
export function render(_ctx) {
const n0 = t0()
"import { template as _template } from 'vue';
import _imports_0 from './logo.png';
import _imports_1 from '/logo.png';
-const t0 = _template("<div><img src=\\"" + _imports_0 + "\\" srcset><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\"><img src=\\"" + _imports_0 + "\\" srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\"><img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\"><img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"" + _imports_1 + "\\" srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\"><img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", true)
+const t0 = _template("<div><img src=\\"" + _imports_0 + "\\"srcset><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x' + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\"><img src=\\"" + _imports_0 + "\\"srcset=\\"" + _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x' + "\\"><img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_1 + ' 2x' + "\\"><img src=https://example.com/logo.png srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"" + _imports_1 + "\\"srcset=\\"" + _imports_1 + ', ' + _imports_0 + ' 2x' + "\\"><img src=data:image/png;base64,i srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: element transform > checkbox with static indeterminate 1`] = `
"import { setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<input type=\\"checkbox\\">", true)
+const t0 = _template("<input type=checkbox>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: element transform > props + child 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<div id=\\"foo\\"><span>", true)
+const t0 = _template("<div id=foo><span>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: element transform > props + children 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<div id=\\"foo\\"><span><b></b></span><main><b></b><div><div><span></span><span>", true)
+const t0 = _template("<div id=foo><span><b></b></span><main><b></b><div><div><span></span><span>", true)
export function render(_ctx) {
const n0 = t0()
}"
`;
-exports[`compiler: element transform > static props 1`] = `
+exports[`compiler: element transform > static props quoting > escapes double quotes in value 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<div id=\\"foo\\" class=\\"bar\\">", true)
+const t0 = _template("<div title=\\"say "hello"\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > mixed quoting with boolean attribute 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div title=\\"has whitespace\\"inert data-targets=\\"foo>bar\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains < 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div data-expr=\\"a<b\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains = 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div data-expr=\\"a=b\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains > 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div data-expr=\\"a>b\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains backtick 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div title=\\"foo\`bar\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains single quote 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div title=\\"it's\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > quoted when value contains whitespace 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div title=\\"has whitespace\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > space omitted after quoted attribute 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div title=\\"has whitespace\\"alt=\\""contains quotes"\\"data-targets=\\"foo>bar\\">", true)
+
+export function render(_ctx) {
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > static props quoting > unquoted when value has no special chars 1`] = `
+"import { template as _template } from 'vue';
+const t0 = _template("<div id=foo class=bar>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: element transform > svg 1`] = `
"import { template as _template } from 'vue';
-const t0 = _template("<svg><circle r=\\"40\\">", true, 1)
+const t0 = _template("<svg><circle r=40>", true, 1)
export function render(_ctx) {
const n0 = t0()
exports[`compiler v-bind > with constant value 1`] = `
"import { setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<div e=\\"2\\" f=\\"foo1\\" g=\\"1\\" h=\\"1\\">", true)
+const t0 = _template("<div e=2 f=foo1 g=1 h=1>", true)
export function render(_ctx, $props, $emit, $attrs, $slots) {
const n0 = t0()
exports[`compiler: vModel transform > should support input (checkbox) 1`] = `
"import { applyCheckboxModel as _applyCheckboxModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"checkbox\\">", true)
+const t0 = _template("<input type=checkbox>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: vModel transform > should support input (radio) 1`] = `
"import { applyRadioModel as _applyRadioModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"radio\\">", true)
+const t0 = _template("<input type=radio>", true)
export function render(_ctx) {
const n0 = t0()
exports[`compiler: vModel transform > should support input (text) 1`] = `
"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"text\\">", true)
+const t0 = _template("<input type=text>", true)
export function render(_ctx) {
const n0 = t0()
</svg>`,
)
// should not remove it
- expect(code).toMatch(`xlink:href=\\"#myCircle\\"`) // compiled to template string, not object, so remove quotes
+ expect(code).toMatch(`xlink:href=#myCircle`) // compiled to template string, not object, so remove quotes
})
test('should allow for full base URLs, with paths', () => {
})
})
- test('static props', () => {
- const { code, ir } = compileWithElementTransform(
- `<div id="foo" class="bar" />`,
- )
-
- const template = '<div id="foo" class="bar">'
- expect(code).toMatchSnapshot()
- expect(code).contains(JSON.stringify(template))
- expect([...ir.template.keys()]).toMatchObject([template])
- expect(ir.block.effect).lengthOf(0)
- })
-
test('checkbox with static indeterminate', () => {
const { code } = compileWithElementTransform(
`<input type="checkbox" indeterminate/>`,
`<div id="foo"><span/></div>`,
)
- const template = '<div id="foo"><span>'
+ const template = '<div id=foo><span>'
expect(code).toMatchSnapshot()
expect(code).contains(JSON.stringify(template))
expect([...ir.template.keys()]).toMatchObject([template])
)
const template =
- '<div id="foo"><span><b></b></span><main><b></b><div><div><span></span><span>'
+ '<div id=foo><span><b></b></span><main><b></b><div><div><span></span><span>'
expect(code).toMatchSnapshot()
expect(code).contains(JSON.stringify(template))
expect([...ir.template.keys()]).toMatchObject([template])
const t = `<svg><circle r="40"></circle></svg>`
const { code, ir } = compileWithElementTransform(t)
expect(code).toMatchSnapshot()
- expect(code).contains('_template("<svg><circle r=\\"40\\">", true, 1)')
- expect([...ir.template.keys()]).toMatchObject(['<svg><circle r="40">'])
- expect(ir.template.get('<svg><circle r="40">')).toBe(1)
+ const expectedTemplate = '<svg><circle r=40>'
+ expect(code).contains(`_template("${expectedTemplate}", true, 1)`)
+ expect([...ir.template.keys()]).toMatchObject([expectedTemplate])
+ expect(ir.template.get(expectedTemplate)).toBe(1)
})
test('MathML', () => {
expect([...ir.template.keys()]).toMatchObject(['<math><mrow><mi>x'])
expect(ir.template.get('<math><mrow><mi>x')).toBe(2)
})
+
+ describe('static props quoting', () => {
+ test('unquoted when value has no special chars', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div id="foo" class="bar" />`,
+ )
+
+ const template = '<div id=foo class=bar>'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains whitespace', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div title="has whitespace" />`,
+ )
+
+ const template = '<div title="has whitespace">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains >', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div data-expr="a>b" />`,
+ )
+
+ const template = '<div data-expr="a>b">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains <', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div data-expr="a<b" />`,
+ )
+
+ const template = '<div data-expr="a<b">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains =', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div data-expr="a=b" />`,
+ )
+
+ const template = '<div data-expr="a=b">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains single quote', () => {
+ const { code, ir } = compileWithElementTransform(`<div title="it's" />`)
+
+ const template = `<div title="it's">`
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('quoted when value contains backtick', () => {
+ const { code, ir } = compileWithElementTransform(
+ '<div title="foo`bar" />',
+ )
+
+ const template = '<div title="foo`bar">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('escapes double quotes in value', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div title='say "hello"' />`,
+ )
+
+ const template = '<div title="say "hello"">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('mixed quoting with boolean attribute', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div title="has whitespace" inert data-targets="foo>bar" />`,
+ )
+
+ const template =
+ '<div title="has whitespace"inert data-targets="foo>bar">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+
+ test('space omitted after quoted attribute', () => {
+ const { code, ir } = compileWithElementTransform(
+ `<div title="has whitespace" alt='"contains quotes"' data-targets="foo>bar" />`,
+ )
+
+ const template =
+ '<div title="has whitespace"alt=""contains quotes""data-targets="foo>bar">'
+ expect(code).toMatchSnapshot()
+ expect(code).contains(JSON.stringify(template))
+ expect([...ir.template.keys()]).toMatchObject([template])
+ })
+ })
})
// keys cannot be a part of the template and need to be set dynamically
const dynamicKeys = ['indeterminate']
+// The attribute value can remain unquoted if it doesn't contain ASCII whitespace
+// or any of " ' ` = < or >.
+// https://html.spec.whatwg.org/multipage/introduction.html#intro-early-example
+const NEEDS_QUOTES_RE = /[\s"'`=<>]/
+
function transformNativeElement(
node: PlainElementNode,
propsResult: PropsResult,
getEffectIndex,
)
} else {
+ // tracks if previous attribute was quoted, allowing space omission
+ // e.g. `class="foo"id="bar"` is valid, `class=foo id=bar` needs space
+ let prevWasQuoted = false
for (const prop of propsResult[1]) {
const { key, values } = prop
// handling asset imports
values[0].content.includes(imported.exp.content),
)
) {
+ if (!prevWasQuoted) template += ` `
// add start and end markers to the import expression, so it can be replaced
// with string concatenation in the generator, see genTemplates
- template += ` ${key.content}="${IMPORT_EXP_START}${values[0].content}${IMPORT_EXP_END}"`
+ template += `${key.content}="${IMPORT_EXP_START}${values[0].content}${IMPORT_EXP_END}"`
+ prevWasQuoted = true
} else if (
key.isStatic &&
values.length === 1 &&
(values[0].isStatic || values[0].content === "''") &&
!dynamicKeys.includes(key.content)
) {
- template += ` ${key.content}`
- if (values[0].content)
- template += `="${values[0].content === "''" ? '' : values[0].content}"`
+ if (!prevWasQuoted) template += ` `
+ const value = values[0].content === "''" ? '' : values[0].content
+ template += key.content
+
+ if (value) {
+ template += (prevWasQuoted = NEEDS_QUOTES_RE.test(value))
+ ? `="${value.replace(/"/g, '"')}"`
+ : `=${value}`
+ } else {
+ prevWasQuoted = false
+ }
} else {
dynamicProps.push(key.content)
context.registerEffect(
expect(nthChild(root, 2)).toBe(root.childNodes[2])
expect(next(b)).toBe(root.childNodes[2])
})
+
+ test('attribute quote omission', () => {
+ {
+ const t = template('<div id=foo class=bar alt=`<="foo></div>')
+ const root = t() as HTMLElement
+
+ expect(root.attributes).toHaveLength(3)
+ expect(root.getAttribute('id')).toBe('foo')
+ expect(root.getAttribute('class')).toBe('bar')
+ expect(root.getAttribute('alt')).toBe('`<="foo')
+ }
+
+ {
+ const t = template('<div id="foo>bar"class="has whitespace"></div>')
+ const root = t() as HTMLElement
+
+ expect(root.attributes).toHaveLength(2)
+ expect(root.getAttribute('id')).toBe('foo>bar')
+ expect(root.getAttribute('class')).toBe('has whitespace')
+ }
+ })
})