From e71d4e0d53e0a9ee2f10d15fb6bbea5616598e99 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 Mar 2017 15:49:21 -0400 Subject: [PATCH 1/2] allow reserved words in tags e.g. {{class}} (#383) --- src/parse/read/expression.js | 17 +- .../attribute-dynamic-reserved/_config.js | 14 ++ .../attribute-dynamic-reserved/main.html | 1 + .../attribute-dynamic-reserved/input.html | 1 + .../attribute-dynamic-reserved/output.json | 40 +++++ tmp.js | 167 ++++++++++++++++++ 6 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 test/generator/samples/attribute-dynamic-reserved/_config.js create mode 100644 test/generator/samples/attribute-dynamic-reserved/main.html create mode 100644 test/parser/samples/attribute-dynamic-reserved/input.html create mode 100644 test/parser/samples/attribute-dynamic-reserved/output.json create mode 100644 tmp.js diff --git a/src/parse/read/expression.js b/src/parse/read/expression.js index e0d5812d72..61cebc9cc7 100644 --- a/src/parse/read/expression.js +++ b/src/parse/read/expression.js @@ -1,13 +1,24 @@ import { parseExpressionAt } from 'acorn'; export default function readExpression ( parser ) { + const start = parser.index; + + const name = parser.readUntil( /\s*}}/ ); + if ( name && /^\w+$/.test( name ) ) { + return { + type: 'Identifier', + start, + end: start + name.length, + name + }; + } + + parser.index = start; + try { const node = parseExpressionAt( parser.template, parser.index ); parser.index = node.end; - // TODO check it's a valid expression. probably shouldn't have - // [arrow] function expressions, etc - return node; } catch ( err ) { parser.acornError( err ); diff --git a/test/generator/samples/attribute-dynamic-reserved/_config.js b/test/generator/samples/attribute-dynamic-reserved/_config.js new file mode 100644 index 0000000000..e14059fec0 --- /dev/null +++ b/test/generator/samples/attribute-dynamic-reserved/_config.js @@ -0,0 +1,14 @@ +export default { + data: { + class: 'foo' + }, + + html: `
`, + + test ( assert, component, target ) { + component.set({ class: 'bar' }); + assert.equal( target.innerHTML, `
` ); + + component.destroy(); + } +}; diff --git a/test/generator/samples/attribute-dynamic-reserved/main.html b/test/generator/samples/attribute-dynamic-reserved/main.html new file mode 100644 index 0000000000..6b149d165f --- /dev/null +++ b/test/generator/samples/attribute-dynamic-reserved/main.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic-reserved/input.html b/test/parser/samples/attribute-dynamic-reserved/input.html new file mode 100644 index 0000000000..6b149d165f --- /dev/null +++ b/test/parser/samples/attribute-dynamic-reserved/input.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/parser/samples/attribute-dynamic-reserved/output.json b/test/parser/samples/attribute-dynamic-reserved/output.json new file mode 100644 index 0000000000..a097655e2a --- /dev/null +++ b/test/parser/samples/attribute-dynamic-reserved/output.json @@ -0,0 +1,40 @@ +{ + "hash": 3305933215, + "html": { + "start": 0, + "end": 29, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 29, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 22, + "type": "Attribute", + "name": "class", + "value": [ + { + "start": 12, + "end": 21, + "type": "MustacheTag", + "expression": { + "type": "Identifier", + "start": 14, + "end": 19, + "name": "class" + } + } + ] + } + ], + "children": [] + } + ] + }, + "css": null, + "js": null +} \ No newline at end of file diff --git a/tmp.js b/tmp.js new file mode 100644 index 0000000000..7caf1af725 --- /dev/null +++ b/tmp.js @@ -0,0 +1,167 @@ +import { createComment, insertNode, detachNode, teardownEach, createElement, addEventListener, removeEventListener, appendNode, createText, dispatchObservers, proto } from "/Users/rharris/Documents/www/SVELTE/svelte/shared.js" + +function renderMainFragment ( root, component ) { + var eachBlock_anchor = createComment(); + var eachBlock_value = root.values; + var eachBlock_iterations = []; + + for ( var i = 0; i < eachBlock_value.length; i += 1 ) { + eachBlock_iterations[i] = renderEachBlock( root, eachBlock_value, eachBlock_value[i], i, component ); + } + + var text = createText( "\n\n" ); + + var p = createElement( 'p' ); + + var last_text1 = root.selected + var text1 = createText( last_text1 ); + appendNode( text1, p ); + + return { + mount: function ( target, anchor ) { + insertNode( eachBlock_anchor, target, anchor ); + + for ( var i = 0; i < eachBlock_iterations.length; i += 1 ) { + eachBlock_iterations[i].mount( eachBlock_anchor.parentNode, eachBlock_anchor ); + } + + insertNode( text, target, anchor ); + insertNode( p, target, anchor ); + }, + + update: function ( changed, root ) { + var __tmp; + + var eachBlock_value = root.values; + + for ( var i = 0; i < eachBlock_value.length; i += 1 ) { + if ( !eachBlock_iterations[i] ) { + eachBlock_iterations[i] = renderEachBlock( root, eachBlock_value, eachBlock_value[i], i, component ); + eachBlock_iterations[i].mount( eachBlock_anchor.parentNode, eachBlock_anchor ); + } else { + eachBlock_iterations[i].update( changed, root, eachBlock_value, eachBlock_value[i], i ); + } + } + + teardownEach( eachBlock_iterations, true, eachBlock_value.length ); + + eachBlock_iterations.length = eachBlock_value.length; + + if ( ( __tmp = root.selected ) !== last_text1 ) { + text1.data = last_text1 = __tmp; + } + }, + + teardown: function ( detach ) { + teardownEach( eachBlock_iterations, detach ); + + if ( detach ) { + detachNode( eachBlock_anchor ); + detachNode( text ); + detachNode( p ); + } + } + }; +} + +function renderEachBlock ( root, eachBlock_value, value, value__index, component ) { + var label = createElement( 'label' ); + + var input = createElement( 'input' ); + input.type = "checkbox"; + var last_input_value = value; + input.value = input.__value = last_input_value; + + var input_updating = false; + + function inputChangeHandler () { + input_updating = true; + component._set({ selected: getBindingGroupValue( component._bindingGroups[0] ) }); + input_updating = false; + } + + addEventListener( input, 'change', inputChangeHandler ); + + appendNode( input, label ); + + input.group = root.selected; + + appendNode( createText( " " ), label ); + var last_text1 = value + var text1 = createText( last_text1 ); + appendNode( text1, label ); + + return { + mount: function ( target, anchor ) { + insertNode( label, target, anchor ); + }, + + update: function ( changed, root, eachBlock_value, value, value__index ) { + var __tmp; + + if ( ( __tmp = value ) !== last_input_value ) { + last_input_value = __tmp; + input.value = input.__value = last_input_value; + } + + if ( !input_updating ) { + input.checked = root.selected.indexOf( last_input_value ) !== -1; + } + + if ( ( __tmp = value ) !== last_text1 ) { + text1.data = last_text1 = __tmp; + } + }, + + teardown: function ( detach ) { + removeEventListener( input, 'change', inputChangeHandler ); + + if ( detach ) { + detachNode( label ); + } + } + }; +} + +function SvelteComponent ( options ) { + options = options || {}; + this._state = options.data || {}; + + this._observers = { + pre: Object.create( null ), + post: Object.create( null ) + }; + + this._handlers = Object.create( null ); + + this._root = options._root; + this._yield = options._yield; + + this._torndown = false; + + this._fragment = renderMainFragment( this._state, this ); + if ( options.target ) this._fragment.mount( options.target, null ); +} + +SvelteComponent.prototype = Object.assign( {}, proto ); + +SvelteComponent.prototype._set = function _set ( newState ) { + var oldState = this._state; + this._state = Object.assign( {}, oldState, newState ); + + dispatchObservers( this, this._observers.pre, newState, oldState ); + if ( this._fragment ) this._fragment.update( newState, this._state ); + dispatchObservers( this, this._observers.post, newState, oldState ); +}; + +SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { + this.fire( 'destroy' ); + + this._fragment.teardown( detach !== false ); + this._fragment = null; + + this._state = {}; + this._torndown = true; +}; + +export default SvelteComponent; \ No newline at end of file From 3bae049a51caf4e9ba2e12267cd1745911ab2271 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 Mar 2017 15:50:12 -0400 Subject: [PATCH 2/2] remove tmp file that snuck into the commit --- tmp.js | 167 --------------------------------------------------------- 1 file changed, 167 deletions(-) delete mode 100644 tmp.js diff --git a/tmp.js b/tmp.js deleted file mode 100644 index 7caf1af725..0000000000 --- a/tmp.js +++ /dev/null @@ -1,167 +0,0 @@ -import { createComment, insertNode, detachNode, teardownEach, createElement, addEventListener, removeEventListener, appendNode, createText, dispatchObservers, proto } from "/Users/rharris/Documents/www/SVELTE/svelte/shared.js" - -function renderMainFragment ( root, component ) { - var eachBlock_anchor = createComment(); - var eachBlock_value = root.values; - var eachBlock_iterations = []; - - for ( var i = 0; i < eachBlock_value.length; i += 1 ) { - eachBlock_iterations[i] = renderEachBlock( root, eachBlock_value, eachBlock_value[i], i, component ); - } - - var text = createText( "\n\n" ); - - var p = createElement( 'p' ); - - var last_text1 = root.selected - var text1 = createText( last_text1 ); - appendNode( text1, p ); - - return { - mount: function ( target, anchor ) { - insertNode( eachBlock_anchor, target, anchor ); - - for ( var i = 0; i < eachBlock_iterations.length; i += 1 ) { - eachBlock_iterations[i].mount( eachBlock_anchor.parentNode, eachBlock_anchor ); - } - - insertNode( text, target, anchor ); - insertNode( p, target, anchor ); - }, - - update: function ( changed, root ) { - var __tmp; - - var eachBlock_value = root.values; - - for ( var i = 0; i < eachBlock_value.length; i += 1 ) { - if ( !eachBlock_iterations[i] ) { - eachBlock_iterations[i] = renderEachBlock( root, eachBlock_value, eachBlock_value[i], i, component ); - eachBlock_iterations[i].mount( eachBlock_anchor.parentNode, eachBlock_anchor ); - } else { - eachBlock_iterations[i].update( changed, root, eachBlock_value, eachBlock_value[i], i ); - } - } - - teardownEach( eachBlock_iterations, true, eachBlock_value.length ); - - eachBlock_iterations.length = eachBlock_value.length; - - if ( ( __tmp = root.selected ) !== last_text1 ) { - text1.data = last_text1 = __tmp; - } - }, - - teardown: function ( detach ) { - teardownEach( eachBlock_iterations, detach ); - - if ( detach ) { - detachNode( eachBlock_anchor ); - detachNode( text ); - detachNode( p ); - } - } - }; -} - -function renderEachBlock ( root, eachBlock_value, value, value__index, component ) { - var label = createElement( 'label' ); - - var input = createElement( 'input' ); - input.type = "checkbox"; - var last_input_value = value; - input.value = input.__value = last_input_value; - - var input_updating = false; - - function inputChangeHandler () { - input_updating = true; - component._set({ selected: getBindingGroupValue( component._bindingGroups[0] ) }); - input_updating = false; - } - - addEventListener( input, 'change', inputChangeHandler ); - - appendNode( input, label ); - - input.group = root.selected; - - appendNode( createText( " " ), label ); - var last_text1 = value - var text1 = createText( last_text1 ); - appendNode( text1, label ); - - return { - mount: function ( target, anchor ) { - insertNode( label, target, anchor ); - }, - - update: function ( changed, root, eachBlock_value, value, value__index ) { - var __tmp; - - if ( ( __tmp = value ) !== last_input_value ) { - last_input_value = __tmp; - input.value = input.__value = last_input_value; - } - - if ( !input_updating ) { - input.checked = root.selected.indexOf( last_input_value ) !== -1; - } - - if ( ( __tmp = value ) !== last_text1 ) { - text1.data = last_text1 = __tmp; - } - }, - - teardown: function ( detach ) { - removeEventListener( input, 'change', inputChangeHandler ); - - if ( detach ) { - detachNode( label ); - } - } - }; -} - -function SvelteComponent ( options ) { - options = options || {}; - this._state = options.data || {}; - - this._observers = { - pre: Object.create( null ), - post: Object.create( null ) - }; - - this._handlers = Object.create( null ); - - this._root = options._root; - this._yield = options._yield; - - this._torndown = false; - - this._fragment = renderMainFragment( this._state, this ); - if ( options.target ) this._fragment.mount( options.target, null ); -} - -SvelteComponent.prototype = Object.assign( {}, proto ); - -SvelteComponent.prototype._set = function _set ( newState ) { - var oldState = this._state; - this._state = Object.assign( {}, oldState, newState ); - - dispatchObservers( this, this._observers.pre, newState, oldState ); - if ( this._fragment ) this._fragment.update( newState, this._state ); - dispatchObservers( this, this._observers.post, newState, oldState ); -}; - -SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { - this.fire( 'destroy' ); - - this._fragment.teardown( detach !== false ); - this._fragment = null; - - this._state = {}; - this._torndown = true; -}; - -export default SvelteComponent; \ No newline at end of file