use DomGenerator subclass, instead of events

pull/204/head
Rich-Harris 9 years ago
parent 8a99178070
commit 443d7d825a

@ -6,16 +6,34 @@ import processCss from '../shared/css/process.js';
import visitors from './visitors/index.js'; import visitors from './visitors/index.js';
import Generator from '../Generator.js'; import Generator from '../Generator.js';
export default function dom ( parsed, source, options, names ) { class DomGenerator extends Generator {
const format = options.format || 'es'; constructor ( parsed, source, names, visitors ) {
const name = options.name || 'SvelteComponent'; super( parsed, source, names, visitors );
this.renderers = [];
}
const generator = new Generator( parsed, source, names, visitors ); addElement ( name, renderStatement, needsIdentifier = false ) {
const isToplevel = this.current.localElementDepth === 0;
if ( needsIdentifier || isToplevel ) {
this.current.builders.init.addLine(
`var ${name} = ${renderStatement};`
);
const { computations, templateProperties } = generator.parseJs(); this.createMountStatement( name );
} else {
this.current.builders.init.addLine(
`${this.current.target}.appendChild( ${renderStatement} );`
);
}
const renderers = []; if ( isToplevel ) {
function addRenderer ( fragment ) { this.current.builders.detach.addLine(
`${name}.parentNode.removeChild( ${name} );`
);
}
}
addRenderer ( fragment ) {
if ( fragment.autofocus ) { if ( fragment.autofocus ) {
fragment.builders.init.addLine( `${fragment.autofocus}.focus();` ); fragment.builders.init.addLine( `${fragment.autofocus}.focus();` );
} }
@ -32,7 +50,7 @@ export default function dom ( parsed, source, options, names ) {
` ); ` );
} }
renderers.push( deindent` this.renderers.push( deindent`
function ${fragment.name} ( ${fragment.params}, component ) { function ${fragment.name} ( ${fragment.params}, component ) {
${fragment.builders.init} ${fragment.builders.init}
@ -53,67 +71,48 @@ export default function dom ( parsed, source, options, names ) {
` ); ` );
} }
generator.on( 'addRenderer', addRenderer ); createAnchor ( name, description = '' ) {
generator.on( 'addElement', ({ name, renderStatement, needsIdentifier }) => {
const isToplevel = generator.current.localElementDepth === 0;
if ( needsIdentifier || isToplevel ) {
generator.current.builders.init.addLine(
`var ${name} = ${renderStatement};`
);
generator.fire( 'createMountStatement', name );
} else {
generator.current.builders.init.addLine(
`${generator.current.target}.appendChild( ${renderStatement} );`
);
}
if ( isToplevel ) {
generator.current.builders.detach.addLine(
`${name}.parentNode.removeChild( ${name} );`
);
}
});
generator.on( 'createAnchor', ({ name, description = '' }) => {
const renderStatement = `document.createComment( ${JSON.stringify( description )} )`; const renderStatement = `document.createComment( ${JSON.stringify( description )} )`;
this.addElement( name, renderStatement, true );
}
generator.fire( 'addElement', { createMountStatement ( name ) {
name, if ( this.current.target === 'target' ) {
renderStatement, this.current.builders.mount.addLine(
needsIdentifier: true
});
});
generator.on( 'createMountStatement', name => {
if ( generator.current.target === 'target' ) {
generator.current.builders.mount.addLine(
`target.insertBefore( ${name}, anchor );` `target.insertBefore( ${name}, anchor );`
); );
} else { } else {
generator.current.builders.init.addLine( this.current.builders.init.addLine(
`${generator.current.target}.appendChild( ${name} );` ); `${this.current.target}.appendChild( ${name} );` );
} }
}); }
generator.on( 'generateBlock', ({ node, name }) => { generateBlock ( node, name ) {
generator.push({ this.push({
name, name,
target: 'target', target: 'target',
localElementDepth: 0, localElementDepth: 0,
builders: getBuilders(), builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker() getUniqueName: this.getUniqueNameMaker()
}); });
// walk the children here // walk the children here
node.children.forEach( node => generator.visit( node ) ); node.children.forEach( node => this.visit( node ) );
generator.fire( 'addRenderer', generator.current ); this.addRenderer( this.current );
generator.pop(); this.pop();
// unset the children, to avoid them being visited again // unset the children, to avoid them being visited again
node.children = []; node.children = [];
}); }
}
export default function dom ( parsed, source, options, names ) {
const format = options.format || 'es';
const name = options.name || 'SvelteComponent';
const generator = new DomGenerator( parsed, source, names, visitors );
const { computations, templateProperties } = generator.parseJs();
let namespace = null; let namespace = null;
if ( templateProperties.namespace ) { if ( templateProperties.namespace ) {
@ -142,7 +141,7 @@ export default function dom ( parsed, source, options, names ) {
parsed.html.children.forEach( node => generator.visit( node ) ); parsed.html.children.forEach( node => generator.visit( node ) );
addRenderer( generator.pop() ); generator.addRenderer( generator.pop() );
const builders = { const builders = {
main: new CodeBuilder(), main: new CodeBuilder(),
@ -196,8 +195,8 @@ export default function dom ( parsed, source, options, names ) {
` ); ` );
} }
let i = renderers.length; let i = generator.renderers.length;
while ( i-- ) builders.main.addBlock( renderers[i] ); while ( i-- ) builders.main.addBlock( generator.renderers[i] );
if ( parsed.css && options.css !== false ) { if ( parsed.css && options.css !== false ) {
builders.init.addLine( `if ( !addedCss ) addCss();` ); builders.init.addLine( `if ( !addedCss ) addCss();` );

@ -33,10 +33,7 @@ export default {
if ( hasChildren ) { if ( hasChildren ) {
const yieldName = generator.current.getUniqueName( `render${name}YieldFragment` ); const yieldName = generator.current.getUniqueName( `render${name}YieldFragment` );
generator.fire( 'generateBlock', { generator.generateBlock( node, yieldName );
node,
name: yieldName
});
generator.current.builders.init.addLine( generator.current.builders.init.addLine(
`var ${name}_yieldFragment = ${yieldName}( root, component );` `var ${name}_yieldFragment = ${yieldName}( root, component );`

@ -20,10 +20,7 @@ export default {
const { dependencies, snippet } = generator.contextualise( node.expression ); const { dependencies, snippet } = generator.contextualise( node.expression );
const anchor = `${name}_anchor`; const anchor = `${name}_anchor`;
generator.fire( 'createAnchor', { generator.createAnchor( anchor, `#each ${generator.source.slice( node.expression.start, node.expression.end )}` );
name: anchor,
description: `#each ${generator.source.slice( node.expression.start, node.expression.end )}`
});
generator.current.builders.init.addBlock( deindent` generator.current.builders.init.addBlock( deindent`
var ${name}_value = ${snippet}; var ${name}_value = ${snippet};
@ -106,10 +103,7 @@ export default {
} }
if ( node.else ) { if ( node.else ) {
generator.fire( 'generateBlock', { generator.generateBlock( node.else, renderElse );
node: node.else,
name: renderElse
});
} }
const indexNames = Object.assign( {}, generator.current.indexNames ); const indexNames = Object.assign( {}, generator.current.indexNames );
@ -159,7 +153,7 @@ export default {
}, },
leave ( generator ) { leave ( generator ) {
generator.fire( 'addRenderer', generator.current ); generator.addRenderer( generator.current );
generator.pop(); generator.pop();
} }
}; };

@ -82,7 +82,7 @@ export default {
generator.current.builders.init.addBlock( local.init ); generator.current.builders.init.addBlock( local.init );
if ( !local.update.isEmpty() ) generator.current.builders.update.addBlock( local.update ); if ( !local.update.isEmpty() ) generator.current.builders.update.addBlock( local.update );
generator.fire( 'createMountStatement', name ); generator.createMountStatement( name );
generator.push({ generator.push({
namespace: local.namespace, namespace: local.namespace,

@ -9,26 +9,22 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
block: name block: name
}]; }];
generator.fire( 'generateBlock', { generator.generateBlock( node, name );
node,
name
});
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' ) {
conditionsAndBlocks.push( conditionsAndBlocks.push(
...getConditionsAndBlocks( generator, node.else.children[0], _name, i + 1 ) ); ...getConditionsAndBlocks( generator, node.else.children[0], _name, i + 1 )
);
} else { } else {
const name = `${_name}_${i + 1}`; const name = `${_name}_${i + 1}`;
conditionsAndBlocks.push({ conditionsAndBlocks.push({
condition: null, condition: null,
block: node.else ? name : null, block: node.else ? name : null,
}); });
if (node.else) {
generator.fire( 'generateBlock', { if ( node.else ) {
node: node.else, generator.generateBlock( node.else, name );
name
});
} }
} }
return conditionsAndBlocks; return conditionsAndBlocks;
@ -45,10 +41,7 @@ export default {
const conditionsAndBlocks = getConditionsAndBlocks( generator, node, generator.getUniqueName( `renderIfBlock` ) ); const conditionsAndBlocks = getConditionsAndBlocks( generator, node, generator.getUniqueName( `renderIfBlock` ) );
const anchor = `${name}_anchor`; const anchor = `${name}_anchor`;
generator.fire( 'createAnchor', { generator.createAnchor( anchor, `#if ${generator.source.slice( node.expression.start, node.expression.end )}` );
name: anchor,
description: `#if ${generator.source.slice( node.expression.start, node.expression.end )}`
});
generator.current.builders.init.addBlock( deindent` generator.current.builders.init.addBlock( deindent`
function ${getBlock} ( ${params} ) { function ${getBlock} ( ${params} ) {

@ -7,11 +7,7 @@ export default {
generator.addSourcemapLocations( node.expression ); generator.addSourcemapLocations( node.expression );
const { snippet } = generator.contextualise( node.expression ); const { snippet } = generator.contextualise( node.expression );
generator.fire( 'addElement', { generator.addElement( name, `document.createTextNode( ${snippet} )`, true );
name,
renderStatement: `document.createTextNode( ${snippet} )`,
needsIdentifier: true
});
generator.current.builders.update.addBlock( deindent` generator.current.builders.update.addBlock( deindent`
${name}.data = ${snippet}; ${name}.data = ${snippet};

@ -10,18 +10,10 @@ export default {
// we would have used comments here, but the `insertAdjacentHTML` api only // we would have used comments here, but the `insertAdjacentHTML` api only
// exists for `Element`s. // exists for `Element`s.
const before = `${name}_before`; const before = `${name}_before`;
generator.fire( 'addElement', { generator.addElement( before, `document.createElement( 'noscript' )`, true );
name: before,
renderStatement: `document.createElement( 'noscript' )`,
needsIdentifier: true
});
const after = `${name}_after`; const after = `${name}_after`;
generator.fire( 'addElement', { generator.addElement( after, `document.createElement( 'noscript' )`, true );
name: after,
renderStatement: `document.createElement( 'noscript' )`,
needsIdentifier: true
});
const isToplevel = generator.current.localElementDepth === 0; const isToplevel = generator.current.localElementDepth === 0;

@ -5,10 +5,6 @@ export default {
} }
const name = generator.current.getUniqueName( `text` ); const name = generator.current.getUniqueName( `text` );
generator.fire( 'addElement', { generator.addElement( name, `document.createTextNode( ${JSON.stringify( node.data )} )`, false );
name,
renderStatement: `document.createTextNode( ${JSON.stringify( node.data )} )`,
needsIdentifier: false
});
} }
}; };

@ -1,10 +1,7 @@
export default { export default {
enter ( generator ) { enter ( generator ) {
const anchor = `yield_anchor`; const anchor = `yield_anchor`;
generator.fire( 'createAnchor', { generator.createAnchor( anchor, 'yield' );
name: anchor,
description: 'yield'
});
generator.current.builders.mount.addLine( generator.current.builders.mount.addLine(
`component.yield && component.yield.mount( ${generator.current.target}, ${anchor} );` `component.yield && component.yield.mount( ${generator.current.target}, ${anchor} );`

Loading…
Cancel
Save