diff --git a/CHANGELOG.md b/CHANGELOG.md index 98068b6b26..05d03f06f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Svelte changelog +## 1.41.4 + +* Handle self-destructive bindings ([#917](https://github.com/sveltejs/svelte/issues/917)) +* Prevent `innerHTML` with ` + // + if (node.name === 'option' && !valueAttribute) { + node.attributes.push({ + type: 'Attribute', + name: 'value', + value: node.children + }); + } + // special case — in a case like this... // // `? - const dependencies = block.findDependencies(value.value); + const dependencies = block.findDependencies(valueAttribute.value); state.selectBindingDependencies = dependencies; dependencies.forEach((prop: string) => { generator.indirectDependencies.set(prop, new Set()); diff --git a/src/generators/dom/visitors/Element/Attribute.ts b/src/generators/dom/visitors/Element/Attribute.ts index 837e0945db..2baf4a7d96 100644 --- a/src/generators/dom/visitors/Element/Attribute.ts +++ b/src/generators/dom/visitors/Element/Attribute.ts @@ -3,7 +3,6 @@ import deindent from '../../../../utils/deindent'; import visitStyleAttribute, { optimizeStyle } from './StyleAttribute'; import { stringify } from '../../../../utils/stringify'; import getExpressionPrecedence from '../../../../utils/getExpressionPrecedence'; -import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue'; import { DomGenerator } from '../../index'; import Block from '../../Block'; import { Node } from '../../../../interfaces'; @@ -56,6 +55,11 @@ export default function visitAttribute( const isLegacyInputType = generator.legacy && name === 'type' && node.name === 'input'; + const isDataSet = /^data-/.test(name) && !generator.legacy; + const camelCaseName = isDataSet ? name.replace('data-', '').replace(/(-\w)/g, function (m) { + return m[1].toUpperCase(); + }) : name; + if (isDynamic) { let value; @@ -163,6 +167,11 @@ export default function visitAttribute( `${state.parentNode}.${propertyName} = ${init};` ); updater = `${state.parentNode}.${propertyName} = ${shouldCache || isSelectValueAttribute ? last : value};`; + } else if (isDataSet) { + block.builders.hydrate.addLine( + `${state.parentNode}.dataset.${camelCaseName} = ${init};` + ); + updater = `${state.parentNode}.dataset.${camelCaseName} = ${shouldCache || isSelectValueAttribute ? last : value};`; } else { block.builders.hydrate.addLine( `${method}(${state.parentNode}, "${name}", ${init});` @@ -198,6 +207,7 @@ export default function visitAttribute( const statement = ( isLegacyInputType ? `@setInputType(${state.parentNode}, ${value});` : propertyName ? `${state.parentNode}.${propertyName} = ${value};` : + isDataSet ? `${state.parentNode}.dataset.${camelCaseName} = ${value};` : `${method}(${state.parentNode}, "${name}", ${value});` ); @@ -221,4 +231,4 @@ export default function visitAttribute( block.builders.hydrate.addLine(updateValue); if (isDynamic) block.builders.update.addLine(updateValue); } -} \ No newline at end of file +} diff --git a/src/generators/dom/visitors/Element/Element.ts b/src/generators/dom/visitors/Element/Element.ts index 6c7a307fab..f678dec9e8 100644 --- a/src/generators/dom/visitors/Element/Element.ts +++ b/src/generators/dom/visitors/Element/Element.ts @@ -190,19 +190,6 @@ export default function visitElement( visitAttributesAndAddProps(); } - // special case – bound + // + const valueAttribute = node.attributes.find((attribute: Node) => attribute.name === 'value'); + + if (node.name === 'option' && !valueAttribute) { + node.attributes.push({ + type: 'Attribute', + name: 'value', + value: node.children + }); + } } if (node.children.length) { diff --git a/src/shared/index.js b/src/shared/index.js index d55e55c22b..f9d0f91998 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -156,9 +156,12 @@ export function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } export function _setDev(newState) { diff --git a/src/utils/getName.ts b/src/utils/getName.ts new file mode 100644 index 0000000000..d236bbaec8 --- /dev/null +++ b/src/utils/getName.ts @@ -0,0 +1,6 @@ +import { Node } from '../interfaces'; + +export default function getMethodName(node: Node) { + if (node.type === 'Identifier') return node.name; + if (node.type === 'Literal') return String(node.value); +} \ No newline at end of file diff --git a/src/utils/removeNode.ts b/src/utils/removeNode.ts index 6abea2f8c9..26095b483c 100644 --- a/src/utils/removeNode.ts +++ b/src/utils/removeNode.ts @@ -1,4 +1,5 @@ import MagicString from 'magic-string'; +import getName from '../utils/getName'; import { Node } from '../interfaces'; const keys = { @@ -51,7 +52,7 @@ export function removeObjectKey(code: MagicString, node: Node, key: string) { let i = node.properties.length; while (i--) { const property = node.properties[i]; - if (property.key.type === 'Identifier' && property.key.name === key) { + if (property.key.type === 'Identifier' && getName(property.key) === key) { removeNode(code, node, property); } } diff --git a/src/validate/js/index.ts b/src/validate/js/index.ts index 01754b7d00..be120c5a4a 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 getName from '../../utils/getName'; import { Validator } from '../'; import { Node } from '../../interfaces'; @@ -29,7 +30,7 @@ export default function validateJs(validator: Validator, js: Node) { const props = validator.properties; node.declaration.properties.forEach((prop: Node) => { - props.set(prop.key.name, prop); + props.set(getName(prop.key), prop); }); // Remove these checks in version 2 @@ -49,25 +50,26 @@ export default function validateJs(validator: Validator, js: Node) { // ensure all exported props are valid node.declaration.properties.forEach((prop: Node) => { - const propValidator = propValidators[prop.key.name]; + const name = getName(prop.key); + const propValidator = propValidators[name]; if (propValidator) { propValidator(validator, prop); } else { - const match = fuzzymatch(prop.key.name, validPropList); + const match = fuzzymatch(name, validPropList); if (match) { validator.error( - `Unexpected property '${prop.key.name}' (did you mean '${match}'?)`, + `Unexpected property '${name}' (did you mean '${match}'?)`, prop.start ); } else if (/FunctionExpression/.test(prop.value.type)) { validator.error( - `Unexpected property '${prop.key.name}' (did you mean to include it in 'methods'?)`, + `Unexpected property '${name}' (did you mean to include it in 'methods'?)`, prop.start ); } else { validator.error( - `Unexpected property '${prop.key.name}'`, + `Unexpected property '${name}'`, prop.start ); } @@ -86,7 +88,7 @@ export default function validateJs(validator: Validator, js: Node) { ['components', 'methods', 'helpers', 'transitions'].forEach(key => { if (validator.properties.has(key)) { validator.properties.get(key).value.properties.forEach((prop: Node) => { - validator[key].set(prop.key.name, prop.value); + validator[key].set(getName(prop.key), prop.value); }); } }); diff --git a/src/validate/js/propValidators/components.ts b/src/validate/js/propValidators/components.ts index a7ca5eb990..7d46470d0b 100644 --- a/src/validate/js/propValidators/components.ts +++ b/src/validate/js/propValidators/components.ts @@ -1,5 +1,6 @@ import checkForDupes from '../utils/checkForDupes'; import checkForComputedKeys from '../utils/checkForComputedKeys'; +import getName from '../../../utils/getName'; import { Validator } from '../../'; import { Node } from '../../../interfaces'; @@ -16,14 +17,16 @@ export default function components(validator: Validator, prop: Node) { checkForComputedKeys(validator, prop.value.properties); prop.value.properties.forEach((component: Node) => { - if (component.key.name === 'state') { + const name = getName(component.key); + + if (name === 'state') { validator.error( `Component constructors cannot be called 'state' due to technical limitations`, component.start ); } - if (!/^[A-Z]/.test(component.key.name)) { + if (!/^[A-Z]/.test(name)) { validator.warn(`Component names should be capitalised`, component.start); } }); diff --git a/src/validate/js/propValidators/methods.ts b/src/validate/js/propValidators/methods.ts index 7d8547ef39..66fd27eea1 100644 --- a/src/validate/js/propValidators/methods.ts +++ b/src/validate/js/propValidators/methods.ts @@ -2,6 +2,7 @@ import checkForAccessors from '../utils/checkForAccessors'; import checkForDupes from '../utils/checkForDupes'; import checkForComputedKeys from '../utils/checkForComputedKeys'; import usesThisOrArguments from '../utils/usesThisOrArguments'; +import getName from '../../../utils/getName'; import { Validator } from '../../'; import { Node } from '../../../interfaces'; @@ -21,9 +22,11 @@ export default function methods(validator: Validator, prop: Node) { checkForComputedKeys(validator, prop.value.properties); prop.value.properties.forEach((prop: Node) => { - if (builtin.has(prop.key.name)) { + const name = getName(prop.key); + + if (builtin.has(name)) { validator.error( - `Cannot overwrite built-in method '${prop.key.name}'`, + `Cannot overwrite built-in method '${name}'`, prop.start ); } diff --git a/src/validate/js/utils/checkForDupes.ts b/src/validate/js/utils/checkForDupes.ts index 8565ab5388..0473d7a265 100644 --- a/src/validate/js/utils/checkForDupes.ts +++ b/src/validate/js/utils/checkForDupes.ts @@ -1,5 +1,6 @@ import { Validator } from '../../'; import { Node } from '../../../interfaces'; +import getName from '../../../utils/getName'; export default function checkForDupes( validator: Validator, @@ -8,10 +9,12 @@ export default function checkForDupes( const seen = new Set(); properties.forEach(prop => { - if (seen.has(prop.key.name)) { - validator.error(`Duplicate property '${prop.key.name}'`, prop.start); + const name = getName(prop.key); + + if (seen.has(name)) { + validator.error(`Duplicate property '${name}'`, prop.start); } - seen.add(prop.key.name); + seen.add(name); }); } diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 7fb59ff390..a5776bc195 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -157,9 +157,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/component-static/expected-bundle.js b/test/js/samples/component-static/expected-bundle.js index c3a2661cc5..94f69ca2ca 100644 --- a/test/js/samples/component-static/expected-bundle.js +++ b/test/js/samples/component-static/expected-bundle.js @@ -133,9 +133,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index 8a703ed250..c378d78026 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -133,9 +133,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/css-media-query/expected-bundle.js b/test/js/samples/css-media-query/expected-bundle.js index 6fa07bfcdb..11ffa87f21 100644 --- a/test/js/samples/css-media-query/expected-bundle.js +++ b/test/js/samples/css-media-query/expected-bundle.js @@ -153,9 +153,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js index 89287471cb..86edac7465 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js @@ -145,9 +145,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/do-use-dataset/expected-bundle.js b/test/js/samples/do-use-dataset/expected-bundle.js new file mode 100644 index 0000000000..42de89fd93 --- /dev/null +++ b/test/js/samples/do-use-dataset/expected-bundle.js @@ -0,0 +1,239 @@ +function noop() {} + +function assign(target) { + var k, + source, + i = 1, + len = arguments.length; + for (; i < len; i++) { + source = arguments[i]; + for (k in source) target[k] = source[k]; + } + + return target; +} + +function insertNode(node, target, anchor) { + target.insertBefore(node, anchor); +} + +function detachNode(node) { + node.parentNode.removeChild(node); +} + +function createElement(name) { + return document.createElement(name); +} + +function createText(data) { + return document.createTextNode(data); +} + +function blankObject() { + return Object.create(null); +} + +function destroy(detach) { + this.destroy = noop; + this.fire('destroy'); + this.set = this.get = noop; + + if (detach !== false) this._fragment.u(); + this._fragment.d(); + this._fragment = this._state = null; +} + +function differs(a, b) { + return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +function dispatchObservers(component, group, changed, newState, oldState) { + for (var key in group) { + if (!changed[key]) continue; + + var newValue = newState[key]; + var oldValue = oldState[key]; + + var callbacks = group[key]; + if (!callbacks) continue; + + for (var i = 0; i < callbacks.length; i += 1) { + var callback = callbacks[i]; + if (callback.__calling) continue; + + callback.__calling = true; + callback.call(component, newValue, oldValue); + callback.__calling = false; + } + } +} + +function fire(eventName, data) { + var handlers = + eventName in this._handlers && this._handlers[eventName].slice(); + if (!handlers) return; + + for (var i = 0; i < handlers.length; i += 1) { + handlers[i].call(this, data); + } +} + +function get(key) { + return key ? this._state[key] : this._state; +} + +function init(component, options) { + component.options = options; + + component._observers = { pre: blankObject(), post: blankObject() }; + component._handlers = blankObject(); + component._root = options._root || component; + component._bind = options._bind; +} + +function observe(key, callback, options) { + var group = options && options.defer + ? this._observers.post + : this._observers.pre; + + (group[key] || (group[key] = [])).push(callback); + + if (!options || options.init !== false) { + callback.__calling = true; + callback.call(this, this._state[key]); + callback.__calling = false; + } + + return { + cancel: function() { + var index = group[key].indexOf(callback); + if (~index) group[key].splice(index, 1); + } + }; +} + +function on(eventName, handler) { + if (eventName === 'teardown') return this.on('destroy', handler); + + var handlers = this._handlers[eventName] || (this._handlers[eventName] = []); + handlers.push(handler); + + return { + cancel: function() { + var index = handlers.indexOf(handler); + if (~index) handlers.splice(index, 1); + } + }; +} + +function set(newState) { + this._set(assign({}, newState)); + if (this._root._lock) return; + this._root._lock = true; + callAll(this._root._beforecreate); + callAll(this._root._oncreate); + callAll(this._root._aftercreate); + this._root._lock = false; +} + +function _set(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (differs(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign({}, oldState, newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } +} + +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} + +function _mount(target, anchor) { + this._fragment.m(target, anchor); +} + +function _unmount() { + this._fragment.u(); +} + +var proto = { + destroy: destroy, + get: get, + fire: fire, + observe: observe, + on: on, + set: set, + teardown: destroy, + _recompute: noop, + _set: _set, + _mount: _mount, + _unmount: _unmount +}; + +/* generated by Svelte vX.Y.Z */ +function create_main_fragment(state, component) { + var div, text, div_1; + + return { + c: function create() { + div = createElement("div"); + text = createText("\n"); + div_1 = createElement("div"); + this.h(); + }, + + h: function hydrate() { + div.dataset.foo = "bar"; + div_1.dataset.foo = state.bar; + }, + + m: function mount(target, anchor) { + insertNode(div, target, anchor); + insertNode(text, target, anchor); + insertNode(div_1, target, anchor); + }, + + p: function update(changed, state) { + if (changed.bar) { + div_1.dataset.foo = state.bar; + } + }, + + u: function unmount() { + detachNode(div); + detachNode(text); + detachNode(div_1); + }, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + } +} + +assign(SvelteComponent.prototype, proto); + +export default SvelteComponent; diff --git a/test/js/samples/do-use-dataset/expected.js b/test/js/samples/do-use-dataset/expected.js new file mode 100644 index 0000000000..1ae7417469 --- /dev/null +++ b/test/js/samples/do-use-dataset/expected.js @@ -0,0 +1,55 @@ +/* generated by Svelte vX.Y.Z */ +import { assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js"; + +function create_main_fragment(state, component) { + var div, text, div_1; + + return { + c: function create() { + div = createElement("div"); + text = createText("\n"); + div_1 = createElement("div"); + this.h(); + }, + + h: function hydrate() { + div.dataset.foo = "bar"; + div_1.dataset.foo = state.bar; + }, + + m: function mount(target, anchor) { + insertNode(div, target, anchor); + insertNode(text, target, anchor); + insertNode(div_1, target, anchor); + }, + + p: function update(changed, state) { + if (changed.bar) { + div_1.dataset.foo = state.bar; + } + }, + + u: function unmount() { + detachNode(div); + detachNode(text); + detachNode(div_1); + }, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + } +} + +assign(SvelteComponent.prototype, proto); +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/do-use-dataset/input.html b/test/js/samples/do-use-dataset/input.html new file mode 100644 index 0000000000..acd9d623b4 --- /dev/null +++ b/test/js/samples/do-use-dataset/input.html @@ -0,0 +1,2 @@ +
+
diff --git a/test/js/samples/dont-use-dataset-in-legacy/_config.js b/test/js/samples/dont-use-dataset-in-legacy/_config.js new file mode 100644 index 0000000000..67924a4ffe --- /dev/null +++ b/test/js/samples/dont-use-dataset-in-legacy/_config.js @@ -0,0 +1,5 @@ +export default { + options: { + legacy: true + } +}; diff --git a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js new file mode 100644 index 0000000000..2d25e23a10 --- /dev/null +++ b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js @@ -0,0 +1,243 @@ +function noop() {} + +function assign(target) { + var k, + source, + i = 1, + len = arguments.length; + for (; i < len; i++) { + source = arguments[i]; + for (k in source) target[k] = source[k]; + } + + return target; +} + +function insertNode(node, target, anchor) { + target.insertBefore(node, anchor); +} + +function detachNode(node) { + node.parentNode.removeChild(node); +} + +function createElement(name) { + return document.createElement(name); +} + +function createText(data) { + return document.createTextNode(data); +} + +function setAttribute(node, attribute, value) { + node.setAttribute(attribute, value); +} + +function blankObject() { + return Object.create(null); +} + +function destroy(detach) { + this.destroy = noop; + this.fire('destroy'); + this.set = this.get = noop; + + if (detach !== false) this._fragment.u(); + this._fragment.d(); + this._fragment = this._state = null; +} + +function differs(a, b) { + return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +function dispatchObservers(component, group, changed, newState, oldState) { + for (var key in group) { + if (!changed[key]) continue; + + var newValue = newState[key]; + var oldValue = oldState[key]; + + var callbacks = group[key]; + if (!callbacks) continue; + + for (var i = 0; i < callbacks.length; i += 1) { + var callback = callbacks[i]; + if (callback.__calling) continue; + + callback.__calling = true; + callback.call(component, newValue, oldValue); + callback.__calling = false; + } + } +} + +function fire(eventName, data) { + var handlers = + eventName in this._handlers && this._handlers[eventName].slice(); + if (!handlers) return; + + for (var i = 0; i < handlers.length; i += 1) { + handlers[i].call(this, data); + } +} + +function get(key) { + return key ? this._state[key] : this._state; +} + +function init(component, options) { + component.options = options; + + component._observers = { pre: blankObject(), post: blankObject() }; + component._handlers = blankObject(); + component._root = options._root || component; + component._bind = options._bind; +} + +function observe(key, callback, options) { + var group = options && options.defer + ? this._observers.post + : this._observers.pre; + + (group[key] || (group[key] = [])).push(callback); + + if (!options || options.init !== false) { + callback.__calling = true; + callback.call(this, this._state[key]); + callback.__calling = false; + } + + return { + cancel: function() { + var index = group[key].indexOf(callback); + if (~index) group[key].splice(index, 1); + } + }; +} + +function on(eventName, handler) { + if (eventName === 'teardown') return this.on('destroy', handler); + + var handlers = this._handlers[eventName] || (this._handlers[eventName] = []); + handlers.push(handler); + + return { + cancel: function() { + var index = handlers.indexOf(handler); + if (~index) handlers.splice(index, 1); + } + }; +} + +function set(newState) { + this._set(assign({}, newState)); + if (this._root._lock) return; + this._root._lock = true; + callAll(this._root._beforecreate); + callAll(this._root._oncreate); + callAll(this._root._aftercreate); + this._root._lock = false; +} + +function _set(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (differs(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign({}, oldState, newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } +} + +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} + +function _mount(target, anchor) { + this._fragment.m(target, anchor); +} + +function _unmount() { + this._fragment.u(); +} + +var proto = { + destroy: destroy, + get: get, + fire: fire, + observe: observe, + on: on, + set: set, + teardown: destroy, + _recompute: noop, + _set: _set, + _mount: _mount, + _unmount: _unmount +}; + +/* generated by Svelte vX.Y.Z */ +function create_main_fragment(state, component) { + var div, text, div_1; + + return { + c: function create() { + div = createElement("div"); + text = createText("\n"); + div_1 = createElement("div"); + this.h(); + }, + + h: function hydrate() { + setAttribute(div, "data-foo", "bar"); + setAttribute(div_1, "data-foo", state.bar); + }, + + m: function mount(target, anchor) { + insertNode(div, target, anchor); + insertNode(text, target, anchor); + insertNode(div_1, target, anchor); + }, + + p: function update(changed, state) { + if (changed.bar) { + setAttribute(div_1, "data-foo", state.bar); + } + }, + + u: function unmount() { + detachNode(div); + detachNode(text); + detachNode(div_1); + }, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + } +} + +assign(SvelteComponent.prototype, proto); + +export default SvelteComponent; diff --git a/test/js/samples/dont-use-dataset-in-legacy/expected.js b/test/js/samples/dont-use-dataset-in-legacy/expected.js new file mode 100644 index 0000000000..03eef26ced --- /dev/null +++ b/test/js/samples/dont-use-dataset-in-legacy/expected.js @@ -0,0 +1,55 @@ +/* generated by Svelte vX.Y.Z */ +import { assign, createElement, createText, detachNode, init, insertNode, noop, proto, setAttribute } from "svelte/shared.js"; + +function create_main_fragment(state, component) { + var div, text, div_1; + + return { + c: function create() { + div = createElement("div"); + text = createText("\n"); + div_1 = createElement("div"); + this.h(); + }, + + h: function hydrate() { + setAttribute(div, "data-foo", "bar"); + setAttribute(div_1, "data-foo", state.bar); + }, + + m: function mount(target, anchor) { + insertNode(div, target, anchor); + insertNode(text, target, anchor); + insertNode(div_1, target, anchor); + }, + + p: function update(changed, state) { + if (changed.bar) { + setAttribute(div_1, "data-foo", state.bar); + } + }, + + u: function unmount() { + detachNode(div); + detachNode(text); + detachNode(div_1); + }, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + } +} + +assign(SvelteComponent.prototype, proto); +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/dont-use-dataset-in-legacy/input.html b/test/js/samples/dont-use-dataset-in-legacy/input.html new file mode 100644 index 0000000000..acd9d623b4 --- /dev/null +++ b/test/js/samples/dont-use-dataset-in-legacy/input.html @@ -0,0 +1,2 @@ +
+
diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index c73357a79d..f421b344b2 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -165,9 +165,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 24b32d9b1a..46c109100a 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -145,9 +145,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/if-block-no-update/expected-bundle.js b/test/js/samples/if-block-no-update/expected-bundle.js index aea386c29a..0277095a83 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index be77d10110..40acbe3959 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js index e36eec0994..eff6f53cfa 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/inline-style-optimized-url/expected-bundle.js b/test/js/samples/inline-style-optimized-url/expected-bundle.js index cbd51d1473..3a126946ad 100644 --- a/test/js/samples/inline-style-optimized-url/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-url/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/inline-style-optimized/expected-bundle.js b/test/js/samples/inline-style-optimized/expected-bundle.js index 7dd9e42578..0c127a6391 100644 --- a/test/js/samples/inline-style-optimized/expected-bundle.js +++ b/test/js/samples/inline-style-optimized/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/inline-style-unoptimized/expected-bundle.js b/test/js/samples/inline-style-unoptimized/expected-bundle.js index 8d383eb38b..d6f545111a 100644 --- a/test/js/samples/inline-style-unoptimized/expected-bundle.js +++ b/test/js/samples/inline-style-unoptimized/expected-bundle.js @@ -149,9 +149,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/input-without-blowback-guard/expected-bundle.js b/test/js/samples/input-without-blowback-guard/expected-bundle.js index 4b42f9e572..03756ad56c 100644 --- a/test/js/samples/input-without-blowback-guard/expected-bundle.js +++ b/test/js/samples/input-without-blowback-guard/expected-bundle.js @@ -153,9 +153,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/legacy-input-type/expected-bundle.js b/test/js/samples/legacy-input-type/expected-bundle.js index 19c61b0d19..7211738f45 100644 --- a/test/js/samples/legacy-input-type/expected-bundle.js +++ b/test/js/samples/legacy-input-type/expected-bundle.js @@ -151,9 +151,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/legacy-quote-class/expected-bundle.js b/test/js/samples/legacy-quote-class/expected-bundle.js index a88e843b6f..1575bf4064 100644 --- a/test/js/samples/legacy-quote-class/expected-bundle.js +++ b/test/js/samples/legacy-quote-class/expected-bundle.js @@ -168,9 +168,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/media-bindings/expected-bundle.js b/test/js/samples/media-bindings/expected-bundle.js index 19b7247c74..92eb665731 100644 --- a/test/js/samples/media-bindings/expected-bundle.js +++ b/test/js/samples/media-bindings/expected-bundle.js @@ -161,9 +161,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index 549c018e7e..575be613fa 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -147,9 +147,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index 6199e5061f..f1e701bd04 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -133,9 +133,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/setup-method/expected-bundle.js b/test/js/samples/setup-method/expected-bundle.js index 3ec6edbb1b..0c545ea70c 100644 --- a/test/js/samples/setup-method/expected-bundle.js +++ b/test/js/samples/setup-method/expected-bundle.js @@ -133,9 +133,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index 0529108287..8805cc3847 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -157,9 +157,12 @@ function _set(newState) { this._state = assign({}, oldState, newState); this._recompute(changed, this._state); if (this._bind) this._bind(changed, this._state); - dispatchObservers(this, this._observers.pre, changed, this._state, oldState); - this._fragment.p(changed, this._state); - dispatchObservers(this, this._observers.post, changed, this._state, oldState); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } } function callAll(fns) { diff --git a/test/runtime/samples/binding-select-implicit-option-value/_config.js b/test/runtime/samples/binding-select-implicit-option-value/_config.js new file mode 100644 index 0000000000..40a7364797 --- /dev/null +++ b/test/runtime/samples/binding-select-implicit-option-value/_config.js @@ -0,0 +1,40 @@ +export default { + data: { + values: [1, 2, 3], + foo: 2 + }, + + html: ` + + +

foo: 2

+ `, + + test(assert, component, target, window) { + const select = target.querySelector('select'); + const options = [...target.querySelectorAll('option')]; + + assert.ok(options[1].selected); + assert.equal(component.get('foo'), 2); + + const change = new window.Event('change'); + + options[2].selected = true; + select.dispatchEvent(change); + + assert.equal(component.get('foo'), 3); + assert.htmlEqual( target.innerHTML, ` + + +

foo: 3

+ ` ); + } +}; diff --git a/test/runtime/samples/binding-select-implicit-option-value/main.html b/test/runtime/samples/binding-select-implicit-option-value/main.html new file mode 100644 index 0000000000..ec5cc84a8d --- /dev/null +++ b/test/runtime/samples/binding-select-implicit-option-value/main.html @@ -0,0 +1,7 @@ + + +

foo: {{foo}}

\ No newline at end of file diff --git a/test/runtime/samples/binding-select-initial-value-undefined/_config.js b/test/runtime/samples/binding-select-initial-value-undefined/_config.js index d5944ae815..f625000edb 100644 --- a/test/runtime/samples/binding-select-initial-value-undefined/_config.js +++ b/test/runtime/samples/binding-select-initial-value-undefined/_config.js @@ -5,9 +5,9 @@ export default {

selected: a

selected: a

diff --git a/test/runtime/samples/binding-select-initial-value/_config.js b/test/runtime/samples/binding-select-initial-value/_config.js index 99a7129262..7338af165f 100644 --- a/test/runtime/samples/binding-select-initial-value/_config.js +++ b/test/runtime/samples/binding-select-initial-value/_config.js @@ -3,9 +3,9 @@ export default {

selected: b

selected: b

diff --git a/test/runtime/samples/binding-select-late/_config.js b/test/runtime/samples/binding-select-late/_config.js index 2fffa0e4ed..04b94613fc 100644 --- a/test/runtime/samples/binding-select-late/_config.js +++ b/test/runtime/samples/binding-select-late/_config.js @@ -22,9 +22,9 @@ export default { assert.htmlEqual( target.innerHTML, `

selected: two

` ); diff --git a/test/runtime/samples/binding-select-optgroup/_config.js b/test/runtime/samples/binding-select-optgroup/_config.js new file mode 100644 index 0000000000..0d651b6654 --- /dev/null +++ b/test/runtime/samples/binding-select-optgroup/_config.js @@ -0,0 +1,39 @@ +export default { + skip: true, // JSDOM + + html: ` +

Hello Harry!

+ + + `, + + test(assert, component, target, window) { + const select = target.querySelector('select'); + const options = [...target.querySelectorAll('option')]; + + assert.deepEqual(options, select.options); + assert.equal(component.get('name'), 'Harry'); + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + + assert.equal(component.get('name'), 'World'); + assert.htmlEqual(target.innerHTML, ` +

Hello World!

+ + + `); + }, +}; diff --git a/test/runtime/samples/binding-select-optgroup/main.html b/test/runtime/samples/binding-select-optgroup/main.html new file mode 100644 index 0000000000..2160d0e2a8 --- /dev/null +++ b/test/runtime/samples/binding-select-optgroup/main.html @@ -0,0 +1,8 @@ +

Hello {{name}}!

+ + \ No newline at end of file diff --git a/test/runtime/samples/binding-select/_config.js b/test/runtime/samples/binding-select/_config.js index 7fce00f327..8c8eced7bc 100644 --- a/test/runtime/samples/binding-select/_config.js +++ b/test/runtime/samples/binding-select/_config.js @@ -3,9 +3,9 @@ export default {

selected: one

selected: one

@@ -32,9 +32,9 @@ export default {

selected: two

selected: two

diff --git a/test/runtime/samples/component-binding-self-destroying/Nested.html b/test/runtime/samples/component-binding-self-destroying/Nested.html new file mode 100644 index 0000000000..3fb5ca4da3 --- /dev/null +++ b/test/runtime/samples/component-binding-self-destroying/Nested.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/component-binding-self-destroying/_config.js b/test/runtime/samples/component-binding-self-destroying/_config.js new file mode 100644 index 0000000000..27a7ab108e --- /dev/null +++ b/test/runtime/samples/component-binding-self-destroying/_config.js @@ -0,0 +1,27 @@ +export default { + data: { + show: true + }, + + html: ` + + `, + + test(assert, component, target, window) { + const click = new window.MouseEvent('click'); + + target.querySelector('button').dispatchEvent(click); + + assert.equal(component.get('show'), false); + assert.htmlEqual(target.innerHTML, ` + + `); + + target.querySelector('button').dispatchEvent(click); + + assert.equal(component.get('show'), true); + assert.htmlEqual(target.innerHTML, ` + + `); + } +}; diff --git a/test/runtime/samples/component-binding-self-destroying/main.html b/test/runtime/samples/component-binding-self-destroying/main.html new file mode 100644 index 0000000000..74fa144d02 --- /dev/null +++ b/test/runtime/samples/component-binding-self-destroying/main.html @@ -0,0 +1,14 @@ +{{#if show}} + +{{else}} + +{{/if}} + + \ No newline at end of file diff --git a/test/validator/samples/method-quoted/errors.json b/test/validator/samples/method-quoted/errors.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/test/validator/samples/method-quoted/errors.json @@ -0,0 +1 @@ +[] diff --git a/test/validator/samples/method-quoted/input.html b/test/validator/samples/method-quoted/input.html new file mode 100644 index 0000000000..790276eebc --- /dev/null +++ b/test/validator/samples/method-quoted/input.html @@ -0,0 +1,10 @@ + + + \ No newline at end of file