Merge branch 'master' into gh-442

pull/444/head
Rich Harris 8 years ago committed by GitHub
commit b2ec4afdb8

@ -242,7 +242,7 @@ export default class Generator {
getUniqueName ( name ) { getUniqueName ( name ) {
let alias = name; let alias = name;
for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ); alias = `${name}$${i++}` ); for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ); alias = `${name}_${i++}` );
this._usedNames.add( alias ); this._usedNames.add( alias );
return alias; return alias;
} }
@ -251,7 +251,7 @@ export default class Generator {
const localUsedNames = new Set( params ); const localUsedNames = new Set( params );
return name => { return name => {
let alias = name; let alias = name;
for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ) || localUsedNames.has( alias ); alias = `${name}$${i++}` ); for ( let i = 1; reservedNames.has( alias ) || this.importedNames.has( alias ) || this._usedNames.has( alias ) || localUsedNames.has( alias ); alias = `${name}_${i++}` );
localUsedNames.add( alias ); localUsedNames.add( alias );
return alias; return alias;
}; };
@ -296,7 +296,7 @@ export default class Generator {
} else { } else {
const { declarations } = annotateWithScopes( js ); const { declarations } = annotateWithScopes( js );
let template = 'template'; let template = 'template';
for ( let i = 1; declarations.has( template ); template = `template$${i++}` ); for ( let i = 1; declarations.has( template ); template = `template_${i++}` );
this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `var ${template} = ` ); this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `var ${template} = ` );

@ -78,7 +78,7 @@ class DomGenerator extends Generator {
} else { } else {
properties.addBlock( deindent` properties.addBlock( deindent`
update: function ( changed, ${fragment.params.join( ', ' )} ) { update: function ( changed, ${fragment.params.join( ', ' )} ) {
var __tmp; ${fragment.tmp ? `var ${fragment.tmp};` : ''}
${fragment.builders.update} ${fragment.builders.update}
}, },
@ -119,8 +119,9 @@ class DomGenerator extends Generator {
} }
} }
generateBlock ( node, name ) { generateBlock ( node, name, type ) {
this.push({ this.push({
type,
name, name,
target: 'target', target: 'target',
localElementDepth: 0, localElementDepth: 0,
@ -203,7 +204,8 @@ export default function dom ( parsed, source, options ) {
const component = getUniqueName( 'component' ); const component = getUniqueName( 'component' );
generator.push({ generator.push({
name: generator.alias( 'renderMainFragment' ), type: 'block',
name: generator.alias( 'render_main_fragment' ),
namespace, namespace,
target: 'target', target: 'target',
localElementDepth: 0, localElementDepth: 0,
@ -241,7 +243,7 @@ export default function dom ( parsed, source, options ) {
} }
builders._set.addLine( 'var oldState = this._state;' ); builders._set.addLine( 'var oldState = this._state;' );
builders._set.addLine( 'this._state = Object.assign( {}, oldState, newState );' ); builders._set.addLine( `this._state = ${generator.helper( 'assign' )}( {}, oldState, newState );` );
if ( computations.length ) { if ( computations.length ) {
const builder = new CodeBuilder(); const builder = new CodeBuilder();
@ -277,13 +279,13 @@ export default function dom ( parsed, source, options ) {
if ( generator.css && options.css !== false ) { if ( generator.css && options.css !== false ) {
builders.main.addBlock( deindent` builders.main.addBlock( deindent`
var ${generator.alias( 'addedCss' )} = false; var ${generator.alias( 'added_css' )} = false;
function ${generator.alias( 'addCss' )} () { function ${generator.alias( 'add_css' )} () {
var style = ${generator.helper( 'createElement' )}( 'style' ); var style = ${generator.helper( 'createElement' )}( 'style' );
style.textContent = ${JSON.stringify( generator.css )}; style.textContent = ${JSON.stringify( generator.css )};
${generator.helper( 'appendNode' )}( style, document.head ); ${generator.helper( 'appendNode' )}( style, document.head );
${generator.alias( 'addedCss' )} = true; ${generator.alias( 'added_css' )} = true;
} }
` ); ` );
} }
@ -294,7 +296,7 @@ export default function dom ( parsed, source, options ) {
builders.init.addLine( `this._torndown = false;` ); builders.init.addLine( `this._torndown = false;` );
if ( parsed.css && options.css !== false ) { if ( parsed.css && options.css !== false ) {
builders.init.addLine( `if ( !${generator.alias( 'addedCss' )} ) ${generator.alias( 'addCss' )}();` ); builders.init.addLine( `if ( !${generator.alias( 'added_css' )} ) ${generator.alias( 'add_css' )}();` );
} }
if ( generator.hasComponents ) { if ( generator.hasComponents ) {
@ -304,7 +306,7 @@ export default function dom ( parsed, source, options ) {
if ( generator.hasComplexBindings ) { if ( generator.hasComplexBindings ) {
builders.init.addBlock( deindent` builders.init.addBlock( deindent`
this._bindings = []; this._bindings = [];
this._fragment = ${generator.alias( 'renderMainFragment' )}( this._state, this ); this._fragment = ${generator.alias( 'render_main_fragment' )}( this._state, this );
if ( options.target ) this._fragment.mount( options.target, null ); if ( options.target ) this._fragment.mount( options.target, null );
while ( this._bindings.length ) this._bindings.pop()(); while ( this._bindings.length ) this._bindings.pop()();
` ); ` );
@ -312,7 +314,7 @@ export default function dom ( parsed, source, options ) {
builders._set.addLine( `while ( this._bindings.length ) this._bindings.pop()();` ); builders._set.addLine( `while ( this._bindings.length ) this._bindings.pop()();` );
} else { } else {
builders.init.addBlock( deindent` builders.init.addBlock( deindent`
this._fragment = ${generator.alias( 'renderMainFragment' )}( this._state, this ); this._fragment = ${generator.alias( 'render_main_fragment' )}( this._state, this );
if ( options.target ) this._fragment.mount( options.target, null ); if ( options.target ) this._fragment.mount( options.target, null );
` ); ` );
} }
@ -340,7 +342,7 @@ export default function dom ( parsed, source, options ) {
if ( generator.usesRefs ) constructorBlock.addLine( `this.refs = {};` ); if ( generator.usesRefs ) constructorBlock.addLine( `this.refs = {};` );
constructorBlock.addLine( constructorBlock.addLine(
`this._state = ${templateProperties.data ? `Object.assign( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`};` `this._state = ${templateProperties.data ? `${generator.helper( 'assign' )}( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`};`
); );
if ( !generator.builders.metaBindings.isEmpty() ) { if ( !generator.builders.metaBindings.isEmpty() ) {
@ -393,7 +395,7 @@ export default function dom ( parsed, source, options ) {
if ( sharedPath ) { if ( sharedPath ) {
const base = templateProperties.methods ? `{}, ${generator.alias( 'template' )}.methods` : `{}`; const base = templateProperties.methods ? `{}, ${generator.alias( 'template' )}.methods` : `{}`;
builders.main.addBlock( `${name}.prototype = Object.assign( ${base}, ${generator.helper( 'proto' )} );` ); builders.main.addBlock( `${name}.prototype = ${generator.helper( 'assign' )}( ${base}, ${generator.helper( 'proto' )} );` );
} else { } else {
if ( templateProperties.methods ) { if ( templateProperties.methods ) {
builders.main.addBlock( `${name}.prototype = ${generator.alias( 'template' )}.methods;` ); builders.main.addBlock( `${name}.prototype = ${generator.alias( 'template' )}.methods;` );

@ -0,0 +1,4 @@
export default function findBlock ( fragment ) {
while ( fragment.type !== 'block' ) fragment = fragment.parent;
return fragment;
}

@ -76,12 +76,12 @@ export default {
// Component has children, put them in a separate {{yield}} block // Component has children, put them in a separate {{yield}} block
if ( hasChildren ) { if ( hasChildren ) {
const yieldName = generator.getUniqueName( `render${name}YieldFragment` ); const yieldName = generator.getUniqueName( `render_${name}_yield_fragment` );
const params = current.params.join( ', ' ); const params = current.params.join( ', ' );
generator.generateBlock( node, yieldName ); generator.generateBlock( node, yieldName, 'block' );
const yieldFragment = current.getUniqueName( `${name}_yieldFragment` ); const yieldFragment = current.getUniqueName( `${name}_yield_fragment` );
current.builders.init.addLine( current.builders.init.addLine(
`var ${yieldFragment} = ${yieldName}( ${params}, ${current.component} );` `var ${yieldFragment} = ${yieldName}( ${params}, ${current.component} );`
@ -104,9 +104,9 @@ export default {
const initialPropString = stringifyProps( initialProps ); const initialPropString = stringifyProps( initialProps );
if ( local.bindings.length ) { if ( local.bindings.length ) {
const initialData = current.getUniqueName( `${name}_initialData` ); const initialData = current.getUniqueName( `${name}_initial_data` );
statements.push( `var ${name}_initialData = ${initialPropString};` ); statements.push( `var ${name}_initial_data = ${initialPropString};` );
local.bindings.forEach( binding => { local.bindings.forEach( binding => {
statements.push( `if ( ${binding.prop} in ${binding.obj} ) ${initialData}.${binding.name} = ${binding.value};` ); statements.push( `if ( ${binding.prop} in ${binding.obj} ) ${initialData}.${binding.name} = ${binding.value};` );
@ -159,6 +159,7 @@ export default {
if ( !local.update.isEmpty() ) current.builders.update.addBlock( local.update ); if ( !local.update.isEmpty() ) current.builders.update.addBlock( local.update );
generator.push({ generator.push({
type: 'component',
namespace: local.namespace, namespace: local.namespace,
target: name, target: name,
parent: current, parent: current,

@ -4,8 +4,8 @@ import getBuilders from '../utils/getBuilders.js';
export default { export default {
enter ( generator, node ) { enter ( generator, node ) {
const name = generator.getUniqueName( `eachBlock` ); const name = generator.getUniqueName( `each_block` );
const renderer = generator.getUniqueName( `renderEachBlock` ); const renderer = generator.getUniqueName( `render_each_block` );
const elseName = generator.getUniqueName( `${name}_else` ); const elseName = generator.getUniqueName( `${name}_else` );
const renderElse = generator.getUniqueName( `${renderer}_else` ); const renderElse = generator.getUniqueName( `${renderer}_else` );
const i = generator.current.getUniqueName( `i` ); const i = generator.current.getUniqueName( `i` );
@ -168,11 +168,11 @@ export default {
} }
if ( node.else ) { if ( node.else ) {
generator.generateBlock( node.else, renderElse ); generator.generateBlock( node.else, renderElse, 'block' );
} }
const indexNames = new Map( generator.current.indexNames ); const indexNames = new Map( generator.current.indexNames );
const indexName = node.index || generator.current.getUniqueName( `${node.context}__index` ); const indexName = node.index || generator.current.getUniqueName( `${node.context}_index` );
indexNames.set( node.context, indexName ); indexNames.set( node.context, indexName );
const listNames = new Map( generator.current.listNames ); const listNames = new Map( generator.current.listNames );
@ -193,6 +193,7 @@ export default {
const getUniqueName = generator.getUniqueNameMaker( blockParams ); const getUniqueName = generator.getUniqueNameMaker( blockParams );
generator.push({ generator.push({
type: 'block',
name: renderer, name: renderer,
target: 'target', target: 'target',
expression: node.expression, expression: node.expression,

@ -101,6 +101,7 @@ export default {
generator.createMountStatement( name ); generator.createMountStatement( name );
generator.push({ generator.push({
type: 'element',
namespace: local.namespace, namespace: local.namespace,
target: name, target: name,
parent: generator.current, parent: generator.current,

@ -9,7 +9,7 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
block: name block: name
}]; }];
generator.generateBlock( node, name ); generator.generateBlock( node, name, 'block' );
if ( node.else && node.else.children.length === 1 && if ( node.else && node.else.children.length === 1 &&
node.else.children[0].type === 'IfBlock' ) { node.else.children[0].type === 'IfBlock' ) {
@ -24,7 +24,7 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
}); });
if ( node.else ) { if ( node.else ) {
generator.generateBlock( node.else, name ); generator.generateBlock( node.else, name, 'block' );
} }
} }
return conditionsAndBlocks; return conditionsAndBlocks;
@ -33,13 +33,13 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
export default { export default {
enter ( generator, node ) { enter ( generator, node ) {
const params = generator.current.params.join( ', ' ); const params = generator.current.params.join( ', ' );
const name = generator.getUniqueName( `ifBlock` ); const name = generator.getUniqueName( `if_block` );
const getBlock = generator.current.getUniqueName( `getBlock` ); const getBlock = generator.current.getUniqueName( `get_block` );
const currentBlock = generator.current.getUniqueName( `currentBlock` ); const currentBlock = generator.current.getUniqueName( `current_block` );
const _currentBlock = generator.current.getUniqueName( `_currentBlock` ); const _currentBlock = generator.current.getUniqueName( `_current_block` );
const isToplevel = generator.current.localElementDepth === 0; const isToplevel = generator.current.localElementDepth === 0;
const conditionsAndBlocks = getConditionsAndBlocks( generator, node, generator.getUniqueName( `renderIfBlock` ) ); const conditionsAndBlocks = getConditionsAndBlocks( generator, node, generator.getUniqueName( `render_if_block` ) );
const anchor = `${name}_anchor`; const anchor = `${name}_anchor`;
generator.createAnchor( anchor ); generator.createAnchor( anchor );

@ -1,4 +1,5 @@
import deindent from '../../../utils/deindent.js'; import deindent from '../../../utils/deindent.js';
import findBlock from '../utils/findBlock.js';
export default { export default {
enter ( generator, node ) { enter ( generator, node ) {
@ -9,9 +10,12 @@ export default {
generator.current.builders.init.addLine( `var last_${name} = ${snippet};` ); generator.current.builders.init.addLine( `var last_${name} = ${snippet};` );
generator.addElement( name, `${generator.helper( 'createText' )}( last_${name} )`, true ); generator.addElement( name, `${generator.helper( 'createText' )}( last_${name} )`, true );
const fragment = findBlock( generator.current );
if ( !fragment.tmp ) fragment.tmp = fragment.getUniqueName( 'tmp' );
generator.current.builders.update.addBlock( deindent` generator.current.builders.update.addBlock( deindent`
if ( ( __tmp = ${snippet} ) !== last_${name} ) { if ( ( ${fragment.tmp} = ${snippet} ) !== last_${name} ) {
${name}.data = last_${name} = __tmp; ${name}.data = last_${name} = ${fragment.tmp};
} }
` ); ` );
} }

@ -1,4 +1,5 @@
import deindent from '../../../utils/deindent.js'; import deindent from '../../../utils/deindent.js';
import findBlock from '../utils/findBlock.js';
export default { export default {
enter ( generator, node ) { enter ( generator, node ) {
@ -26,9 +27,12 @@ export default {
generator.current.builders.init.addLine( mountStatement ); generator.current.builders.init.addLine( mountStatement );
} }
const fragment = findBlock( generator.current );
if ( !fragment.tmp ) fragment.tmp = fragment.getUniqueName( 'tmp' );
generator.current.builders.update.addBlock( deindent` generator.current.builders.update.addBlock( deindent`
if ( ( __tmp = ${snippet} ) !== last_${name} ) { if ( ( ${fragment.tmp} = ${snippet} ) !== last_${name} ) {
last_${name} = __tmp; last_${name} = ${fragment.tmp};
${detachStatement} ${detachStatement}
${mountStatement} ${mountStatement}
} }

@ -3,6 +3,7 @@ import addElementBinding from './addElementBinding';
import deindent from '../../../../utils/deindent.js'; import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.js'; import flattenReference from '../../../../utils/flattenReference.js';
import getStaticAttributeValue from './binding/getStaticAttributeValue.js'; import getStaticAttributeValue from './binding/getStaticAttributeValue.js';
import findBlock from '../../utils/findBlock.js';
export default function addElementAttributes ( generator, node, local ) { export default function addElementAttributes ( generator, node, local ) {
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
@ -105,9 +106,12 @@ export default function addElementAttributes ( generator, node, local ) {
} }
local.init.addLine( updater ); local.init.addLine( updater );
const fragment = findBlock( generator.current );
if ( !fragment.tmp ) fragment.tmp = fragment.getUniqueName( 'tmp' );
local.update.addBlock( deindent` local.update.addBlock( deindent`
if ( ( __tmp = ${snippet} ) !== ${last} ) { if ( ( ${fragment.tmp} = ${snippet} ) !== ${last} ) {
${last} = __tmp; ${last} = ${fragment.tmp};
${updater} ${updater}
} }
` ); ` );
@ -177,7 +181,7 @@ export default function addElementAttributes ( generator, node, local ) {
return `var ${listName} = this.__svelte.${listName}, ${indexName} = this.__svelte.${indexName}, ${name} = ${listName}[${indexName}]`; return `var ${listName} = this.__svelte.${listName}, ${indexName} = this.__svelte.${indexName}, ${name} = ${listName}[${indexName}]`;
}); });
const handlerName = generator.current.getUniqueName( `${name}Handler` ); const handlerName = generator.current.getUniqueName( `${name}_handler` );
const handlerBody = ( declarations.length ? declarations.join( '\n' ) + '\n\n' : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`; const handlerBody = ( declarations.length ? declarations.join( '\n' ) + '\n\n' : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`;
if ( generator.events.has( name ) ) { if ( generator.events.has( name ) ) {

@ -13,7 +13,7 @@ export default function createBinding ( generator, node, attribute, current, loc
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context ); if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
}); });
const handler = current.getUniqueName( `${local.name}ChangeHandler` ); const handler = current.getUniqueName( `${local.name}_change_handler` );
const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue
const type = getStaticAttributeValue( node, 'type' ); const type = getStaticAttributeValue( node, 'type' );

@ -3,6 +3,15 @@ export * from './methods.js';
export function noop () {} export function noop () {}
export function assign ( target ) {
for ( var i = 1; i < arguments.length; i += 1 ) {
var source = arguments[i];
for ( var k in source ) target[k] = source[k];
}
return target;
}
export function differs ( a, b ) { export function differs ( a, b ) {
return ( a !== b ) || ( a && ( typeof a === 'object' ) || ( typeof a === 'function' ) ); return ( a !== b ) || ( a && ( typeof a === 'object' ) || ( typeof a === 'function' ) );
} }

@ -30,6 +30,8 @@ require.extensions[ '.html' ] = function ( module, filename ) {
return module._compile( code, filename ); return module._compile( code, filename );
}; };
const Object_assign = Object.assign;
describe( 'generate', () => { describe( 'generate', () => {
before( setupHtmlEqual ); before( setupHtmlEqual );
@ -67,7 +69,7 @@ describe( 'generate', () => {
// check that no ES2015+ syntax slipped in // check that no ES2015+ syntax slipped in
if ( !config.allowES2015 ) { if ( !config.allowES2015 ) {
try { try {
const startIndex = code.indexOf( 'function renderMainFragment' ); // may change! const startIndex = code.indexOf( 'function render_main_fragment' ); // may change!
const es5 = spaces( startIndex ) + code.slice( startIndex ).replace( /export default .+/, '' ); const es5 = spaces( startIndex ) + code.slice( startIndex ).replace( /export default .+/, '' );
acorn.parse( es5, { ecmaVersion: 5 }); acorn.parse( es5, { ecmaVersion: 5 });
} catch ( err ) { } catch ( err ) {
@ -93,6 +95,10 @@ describe( 'generate', () => {
return env() return env()
.then( window => { .then( window => {
Object.assign = () => {
throw new Error( 'cannot use Object.assign in generated code, as it is not supported everywhere' );
};
global.window = window; global.window = window;
// Put the constructor on window for testing // Put the constructor on window for testing
@ -145,6 +151,9 @@ describe( 'generate', () => {
if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console if ( !config.show ) console.log( addLineNumbers( code ) ); // eslint-disable-line no-console
throw err; throw err;
} }
})
.then( () => {
Object.assign = Object_assign;
}); });
}); });
} }

Loading…
Cancel
Save