use DomGenerator subclass, instead of events

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save