diff --git a/src/generators/Generator.js b/src/generators/Generator.js index 39569cc1da..cf6ec0548c 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -102,7 +102,7 @@ export default class Generator { else if ( contexts.has( name ) ) { const contextName = contexts.get( name ); if ( contextName !== name ) { - // this is true for 'reserved' names like `root` and `component` + // this is true for 'reserved' names like `state` and `component` code.overwrite( node.start, node.start + name.length, contextName, true ); } @@ -124,13 +124,13 @@ export default class Generator { } if ( globalWhitelist.has( name ) ) { - code.prependRight( node.start, `( '${name}' in root ? root.` ); + code.prependRight( node.start, `( '${name}' in state ? state.` ); code.appendLeft( node.object ? node.object.end : node.end, ` : ${name} )` ); } else { - code.prependRight( node.start, `root.` ); + code.prependRight( node.start, `state.` ); } - if ( !~usedContexts.indexOf( 'root' ) ) usedContexts.push( 'root' ); + if ( !~usedContexts.indexOf( 'state' ) ) usedContexts.push( 'state' ); } this.skip(); diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 68b783aaaa..f8ab06ddc3 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -191,7 +191,7 @@ export default function preprocess ( generator, node ) { indexes: new Map(), contextDependencies: new Map(), - params: [ 'root' ], + params: [ 'state' ], indexNames: new Map(), listNames: new Map(), diff --git a/src/generators/dom/visitors/Component/Binding.js b/src/generators/dom/visitors/Component/Binding.js index c40d788cba..9465eca810 100644 --- a/src/generators/dom/visitors/Component/Binding.js +++ b/src/generators/dom/visitors/Component/Binding.js @@ -24,7 +24,7 @@ export default function visitBinding ( generator, block, state, node, attribute, prop = `'[✂${attribute.value.property.start}-${attribute.value.property.end}✂]'`; obj = `[✂${attribute.value.object.start}-${attribute.value.object.end}✂]`; } else { - obj = 'root'; + obj = 'state'; prop = `'${name}'`; } diff --git a/src/generators/dom/visitors/Component/Component.js b/src/generators/dom/visitors/Component/Component.js index 60905a7729..c54945338d 100644 --- a/src/generators/dom/visitors/Component/Component.js +++ b/src/generators/dom/visitors/Component/Component.js @@ -66,7 +66,7 @@ export default function visitComponent ( generator, block, state, node ) { if ( local.allUsedContexts.length ) { const initialProps = local.allUsedContexts.map( contextName => { - if ( contextName === 'root' ) return `root: root`; + if ( contextName === 'state' ) return `state: state`; const listName = block.listNames.get( contextName ); const indexName = block.indexNames.get( contextName ); @@ -75,7 +75,7 @@ export default function visitComponent ( generator, block, state, node ) { }).join( ',\n' ); const updates = local.allUsedContexts.map( contextName => { - if ( contextName === 'root' ) return `${name}._context.root = root;`; + if ( contextName === 'state' ) return `${name}._context.state = state;`; const listName = block.listNames.get( contextName ); const indexName = block.indexNames.get( contextName ); diff --git a/src/generators/dom/visitors/Component/EventHandler.js b/src/generators/dom/visitors/Component/EventHandler.js index 7e2ed9b0da..43aecb6efa 100644 --- a/src/generators/dom/visitors/Component/EventHandler.js +++ b/src/generators/dom/visitors/Component/EventHandler.js @@ -17,7 +17,7 @@ export default function visitEventHandler ( generator, block, state, node, attri // TODO hoist event handlers? can do `this.__component.method(...)` const declarations = usedContexts.map( name => { - if ( name === 'root' ) return 'var root = this._context.root;'; + if ( name === 'state' ) return 'var state = this._context.state;'; const listName = block.listNames.get( name ); const indexName = block.indexNames.get( name ); diff --git a/src/generators/dom/visitors/Element/Element.js b/src/generators/dom/visitors/Element/Element.js index 190835b343..7f55d84ec9 100644 --- a/src/generators/dom/visitors/Element/Element.js +++ b/src/generators/dom/visitors/Element/Element.js @@ -86,7 +86,7 @@ export default function visitElement ( generator, block, state, node ) { } childState.allUsedContexts.forEach( contextName => { - if ( contextName === 'root' ) return; + if ( contextName === 'state' ) return; const listName = block.listNames.get( contextName ); const indexName = block.indexNames.get( contextName ); diff --git a/src/generators/dom/visitors/Element/EventHandler.js b/src/generators/dom/visitors/Element/EventHandler.js index f2affc2708..5439bceee2 100644 --- a/src/generators/dom/visitors/Element/EventHandler.js +++ b/src/generators/dom/visitors/Element/EventHandler.js @@ -30,9 +30,9 @@ export default function visitEventHandler ( generator, block, state, node, attri const _this = context || 'this'; const declarations = usedContexts.map( name => { - if ( name === 'root' ) { + if ( name === 'state' ) { if ( shouldHoist ) state.usesComponent = true; - return `var root = ${block.component}.get();`; + return `var state = ${block.component}.get();`; } const listName = block.listNames.get( name ); diff --git a/src/generators/dom/visitors/Element/meta/Window.js b/src/generators/dom/visitors/Element/meta/Window.js index 7c5a1166dc..c89f11c47c 100644 --- a/src/generators/dom/visitors/Element/meta/Window.js +++ b/src/generators/dom/visitors/Element/meta/Window.js @@ -43,7 +43,7 @@ export default function visitWindow ( generator, block, node ) { } const handlerName = block.getUniqueName( `onwindow${attribute.name}` ); - const handlerBody = ( usesState ? `var root = ${block.component}.get();\n` : '' ) + + const handlerBody = ( usesState ? `var state = ${block.component}.get();\n` : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`; block.builders.create.addBlock( deindent` diff --git a/src/generators/server-side-rendering/Block.js b/src/generators/server-side-rendering/Block.js index ca08a529e4..fa317721e0 100644 --- a/src/generators/server-side-rendering/Block.js +++ b/src/generators/server-side-rendering/Block.js @@ -7,7 +7,7 @@ export default class Block { } addBinding ( binding, name ) { - const conditions = [ `!( '${binding.name}' in root )`].concat( // TODO handle contextual bindings... + const conditions = [ `!( '${binding.name}' in state )`].concat( // TODO handle contextual bindings... this.conditions.map( c => `(${c})` ) ); @@ -17,7 +17,7 @@ export default class Block { if ( ${conditions.join( '&&' )} ) { tmp = ${name}.data(); if ( '${keypath}' in tmp ) { - root.${binding.name} = tmp.${keypath}; + state.${binding.name} = tmp.${keypath}; settled = false; } } diff --git a/src/generators/server-side-rendering/index.js b/src/generators/server-side-rendering/index.js index 80caa90f86..02e4e39bf2 100644 --- a/src/generators/server-side-rendering/index.js +++ b/src/generators/server-side-rendering/index.js @@ -44,12 +44,12 @@ export default function ssr ( parsed, source, options ) { }); builders.render.addLine( - templateProperties.data ? `root = Object.assign( ${generator.alias( 'template' )}.data(), root || {} );` : `root = root || {};` + templateProperties.data ? `state = Object.assign( ${generator.alias( 'template' )}.data(), state || {} );` : `state = state || {};` ); computations.forEach( ({ key, deps }) => { builders.render.addLine( - `root.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `root.${dep}` ).join( ', ' )} );` + `state.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );` ); }); @@ -129,7 +129,7 @@ export default function ssr ( parsed, source, options ) { return ${templateProperties.data ? `${generator.alias( 'template' )}.data()` : `{}`}; }; - ${name}.render = function ( root, options ) { + ${name}.render = function ( state, options ) { ${builders.render} }; diff --git a/src/generators/server-side-rendering/visitors/Component.js b/src/generators/server-side-rendering/visitors/Component.js index fccc7d6bc0..6290ca0710 100644 --- a/src/generators/server-side-rendering/visitors/Component.js +++ b/src/generators/server-side-rendering/visitors/Component.js @@ -45,7 +45,7 @@ export default function visitComponent ( generator, block, node ) { }) .concat( bindings.map( binding => { const { name, keypath } = flattenReference( binding.value ); - const value = block.contexts.has( name ) ? keypath : `root.${keypath}`; + const value = block.contexts.has( name ) ? keypath : `state.${keypath}`; return `${binding.name}: ${value}`; })) .join( ', ' ); diff --git a/src/utils/reservedNames.js b/src/utils/reservedNames.js index f4522d15b8..cc44bbd873 100644 --- a/src/utils/reservedNames.js +++ b/src/utils/reservedNames.js @@ -1 +1,6 @@ -export default new Set( [ 'arguments', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield' ] ); +const reservedNames = new Set( [ 'arguments', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield' ] ); + +// prevent e.g. `{{#each states as state}}` breaking +reservedNames.add( 'state' ); + +export default reservedNames; \ No newline at end of file diff --git a/src/validate/js/index.js b/src/validate/js/index.js index 013e75f04c..6817382496 100644 --- a/src/validate/js/index.js +++ b/src/validate/js/index.js @@ -63,14 +63,6 @@ export default function validateJs ( validator, js ) { validator.defaultExport = node; } - - if ( node.type === 'ImportDeclaration' ) { - node.specifiers.forEach( specifier => { - if ( specifier.local.name === 'root' ) { - validator.error( `Imported identifiers cannot have a name of 'root' due to technical limitations`, specifier.start ); - } - }); - } }); [ 'components', 'methods', 'helpers' ].forEach( key => { diff --git a/src/validate/js/propValidators/components.js b/src/validate/js/propValidators/components.js index 81745bdf92..06bb504ecf 100644 --- a/src/validate/js/propValidators/components.js +++ b/src/validate/js/propValidators/components.js @@ -11,6 +11,10 @@ export default function components ( validator, prop ) { checkForComputedKeys( validator, prop.value.properties ); prop.value.properties.forEach( component => { + if ( component.key.name === 'state' ) { + validator.error( `Component constructors cannot be called 'state' due to technical limitations`, component.start ); + } + if ( !/^[A-Z]/.test( component.key.name ) ) { validator.warn( `Component names should be capitalised`, component.start ); } diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index aa6aa8f8bd..dd6f2a3f27 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -17,12 +17,12 @@ function add_css () { added_css = true; } -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { var text_value; var p = createElement( 'p' ); setAttribute( p, 'svelte-3842350206', '' ); - var text = createText( text_value = root.foo ); + var text = createText( text_value = state.foo ); appendNode( text, p ); return { @@ -30,8 +30,8 @@ function create_main_fragment ( root, component ) { insertNode( p, target, anchor ); }, - update: function ( changed, root ) { - if ( text_value !== ( text_value = root.foo ) ) { + update: function ( changed, state ) { + if ( text_value !== ( text_value = state.foo ) ) { text.data = text_value; } }, diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index 50ca020f2b..96eb2a6202 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -16,7 +16,7 @@ var template = (function () { }; }()); -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { return { diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 026b253240..ea742ff8ed 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -1,19 +1,19 @@ import { appendNode, assign, createComment, createElement, createText, destroyEach, detachBetween, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { var text_1_value; var each_block_anchor = createComment(); - var each_block_value = root.comments; + var each_block_value = state.comments; var each_block_iterations = []; for ( var i = 0; i < each_block_value.length; i += 1 ) { - each_block_iterations[i] = create_each_block( root, each_block_value, each_block_value[i], i, component ); + each_block_iterations[i] = create_each_block( state, each_block_value, each_block_value[i], i, component ); } var text = createText( "\n\n" ); var p = createElement( 'p' ); - var text_1 = createText( text_1_value = root.foo ); + var text_1 = createText( text_1_value = state.foo ); appendNode( text_1, p ); return { @@ -28,15 +28,15 @@ function create_main_fragment ( root, component ) { insertNode( p, target, anchor ); }, - update: function ( changed, root ) { - var each_block_value = root.comments; + update: function ( changed, state ) { + var each_block_value = state.comments; if ( 'comments' in changed || 'elapsed' in changed || 'time' in changed ) { for ( var i = 0; i < each_block_value.length; i += 1 ) { if ( each_block_iterations[i] ) { - each_block_iterations[i].update( changed, root, each_block_value, each_block_value[i], i ); + each_block_iterations[i].update( changed, state, each_block_value, each_block_value[i], i ); } else { - each_block_iterations[i] = create_each_block( root, each_block_value, each_block_value[i], i, component ); + each_block_iterations[i] = create_each_block( state, each_block_value, each_block_value[i], i, component ); each_block_iterations[i].mount( each_block_anchor.parentNode, each_block_anchor ); } } @@ -46,7 +46,7 @@ function create_main_fragment ( root, component ) { each_block_iterations.length = each_block_value.length; } - if ( text_1_value !== ( text_1_value = root.foo ) ) { + if ( text_1_value !== ( text_1_value = state.foo ) ) { text_1.data = text_1_value; } }, @@ -63,7 +63,7 @@ function create_main_fragment ( root, component ) { }; } -function create_each_block ( root, each_block_value, comment, i, component ) { +function create_each_block ( state, each_block_value, comment, i, component ) { var text_value, text_2_value, text_4_value; var div = createElement( 'div' ); @@ -79,7 +79,7 @@ function create_each_block ( root, each_block_value, comment, i, component ) { var text_2 = createText( text_2_value = comment.author ); appendNode( text_2, span ); appendNode( createText( " wrote " ), span ); - var text_4 = createText( text_4_value = root.elapsed(comment.time, root.time) ); + var text_4 = createText( text_4_value = state.elapsed(comment.time, state.time) ); appendNode( text_4, span ); appendNode( createText( " ago:" ), span ); appendNode( createText( "\n\n\t\t" ), div ); @@ -95,7 +95,7 @@ function create_each_block ( root, each_block_value, comment, i, component ) { insertNode( div, target, anchor ); }, - update: function ( changed, root, each_block_value, comment, i ) { + update: function ( changed, state, each_block_value, comment, i ) { if ( text_value !== ( text_value = i ) ) { text.data = text_value; } @@ -104,7 +104,7 @@ function create_each_block ( root, each_block_value, comment, i, component ) { text_2.data = text_2_value; } - if ( text_4_value !== ( text_4_value = root.elapsed(comment.time, root.time) ) ) { + if ( text_4_value !== ( text_4_value = state.elapsed(comment.time, state.time) ) ) { text_4.data = text_4_value; } @@ -164,4 +164,4 @@ SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = functio this._torndown = true; }; -export default SvelteComponent; \ No newline at end of file +export default SvelteComponent; diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js index 528bcfe5af..5fcfff19e2 100644 --- a/test/js/samples/event-handlers-custom/expected.js +++ b/test/js/samples/event-handlers-custom/expected.js @@ -15,12 +15,12 @@ var template = (function () { }; }()); -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { var button = createElement( 'button' ); var foo_handler = template.events.foo.call( component, button, function ( event ) { - var root = component.get(); - component.foo( root.bar ); + var state = component.get(); + component.foo( state.bar ); }); appendNode( createText( "foo" ), button ); diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index f0fbc2b6d5..1ed5eb2e7f 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -1,15 +1,15 @@ import { appendNode, assign, createComment, createElement, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { var if_block_anchor = createComment(); - function get_block ( root ) { - if ( root.foo ) return create_if_block; + function get_block ( state ) { + if ( state.foo ) return create_if_block; return create_if_block_1; } - var current_block = get_block( root ); - var if_block = current_block && current_block( root, component ); + var current_block = get_block( state ); + var if_block = current_block && current_block( state, component ); return { mount: function ( target, anchor ) { @@ -17,10 +17,10 @@ function create_main_fragment ( root, component ) { if ( if_block ) if_block.mount( target, if_block_anchor ); }, - update: function ( changed, root ) { - if ( current_block !== ( current_block = get_block( root ) ) ) { + update: function ( changed, state ) { + if ( current_block !== ( current_block = get_block( state ) ) ) { if ( if_block ) if_block.destroy( true ); - if_block = current_block && current_block( root, component ); + if_block = current_block && current_block( state, component ); if ( if_block ) if_block.mount( if_block_anchor.parentNode, if_block_anchor ); } }, @@ -35,7 +35,7 @@ function create_main_fragment ( root, component ) { }; } -function create_if_block ( root, component ) { +function create_if_block ( state, component ) { var p = createElement( 'p' ); appendNode( createText( "foo!" ), p ); @@ -52,7 +52,7 @@ function create_if_block ( root, component ) { }; } -function create_if_block_1 ( root, component ) { +function create_if_block_1 ( state, component ) { var p = createElement( 'p' ); appendNode( createText( "not foo!" ), p ); diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index f1ca09dc3a..fcdd72f55d 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -1,9 +1,9 @@ import { appendNode, assign, createComment, createElement, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; -function create_main_fragment ( root, component ) { +function create_main_fragment ( state, component ) { var if_block_anchor = createComment(); - var if_block = root.foo && create_if_block( root, component ); + var if_block = state.foo && create_if_block( state, component ); return { mount: function ( target, anchor ) { @@ -11,10 +11,10 @@ function create_main_fragment ( root, component ) { if ( if_block ) if_block.mount( target, if_block_anchor ); }, - update: function ( changed, root ) { - if ( root.foo ) { + update: function ( changed, state ) { + if ( state.foo ) { if ( !if_block ) { - if_block = create_if_block( root, component ); + if_block = create_if_block( state, component ); if_block.mount( if_block_anchor.parentNode, if_block_anchor ); } } else if ( if_block ) { @@ -33,7 +33,7 @@ function create_main_fragment ( root, component ) { }; } -function create_if_block ( root, component ) { +function create_if_block ( state, component ) { var p = createElement( 'p' ); appendNode( createText( "foo!" ), p ); diff --git a/test/runtime/samples/state-deconflicted/_config.js b/test/runtime/samples/state-deconflicted/_config.js new file mode 100644 index 0000000000..05678a857f --- /dev/null +++ b/test/runtime/samples/state-deconflicted/_config.js @@ -0,0 +1,54 @@ +export default { + data: { + state: 'deconflicted', + states: [ + 'Alabama', + 'Alaska', + 'Arizona', + 'Arkansas', + '...and some others' + ] + }, + + html: ` +

Current state: deconflicted

+ + + `, + + test ( assert, component, target ) { + component.set({ + states: [ + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Mississippi', + 'Missouri', + 'Montana' + ] + }); + + assert.htmlEqual( target.innerHTML, ` +

Current state: deconflicted

+ + + ` ); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/state-deconflicted/main.html b/test/runtime/samples/state-deconflicted/main.html new file mode 100644 index 0000000000..b5ce111cae --- /dev/null +++ b/test/runtime/samples/state-deconflicted/main.html @@ -0,0 +1,7 @@ +

Current state: {{state}}

+ + \ No newline at end of file diff --git a/test/validator/samples/component-cannot-be-called-state/errors.json b/test/validator/samples/component-cannot-be-called-state/errors.json new file mode 100644 index 0000000000..5c6badc8e7 --- /dev/null +++ b/test/validator/samples/component-cannot-be-called-state/errors.json @@ -0,0 +1,8 @@ +[{ + "message": "Component constructors cannot be called 'state' due to technical limitations", + "pos": 73, + "loc": { + "line": 6, + "column": 3 + } +}] diff --git a/test/validator/samples/component-cannot-be-called-state/input.html b/test/validator/samples/component-cannot-be-called-state/input.html new file mode 100644 index 0000000000..33f42f04b2 --- /dev/null +++ b/test/validator/samples/component-cannot-be-called-state/input.html @@ -0,0 +1,9 @@ + diff --git a/test/validator/samples/import-root/errors.json b/test/validator/samples/import-root/errors.json deleted file mode 100644 index ec9384b0c8..0000000000 --- a/test/validator/samples/import-root/errors.json +++ /dev/null @@ -1,8 +0,0 @@ -[{ - "message": "Imported identifiers cannot have a name of 'root' due to technical limitations", - "pos": 17, - "loc": { - "line": 2, - "column": 8 - } -}] diff --git a/test/validator/samples/import-root/input.html b/test/validator/samples/import-root/input.html deleted file mode 100644 index d1cda13562..0000000000 --- a/test/validator/samples/import-root/input.html +++ /dev/null @@ -1,3 +0,0 @@ -