more refactoring

pull/204/head
Rich Harris 9 years ago
parent b71ec52cae
commit 47f64be928

@ -1,11 +1,11 @@
import MagicString from 'magic-string'; import MagicString, { Bundle } from 'magic-string';
import CodeBuilder from '../utils/CodeBuilder.js';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import deindent from '../utils/deindent.js';
import isReference from '../utils/isReference.js'; import isReference from '../utils/isReference.js';
import counter from './shared/utils/counter.js'; import counter from './shared/utils/counter.js';
import flattenReference from '../utils/flattenReference.js'; import flattenReference from '../utils/flattenReference.js';
import globalWhitelist from '../utils/globalWhitelist.js'; import globalWhitelist from '../utils/globalWhitelist.js';
import getIntro from './shared/utils/getIntro.js';
import getOutro from './shared/utils/getOutro.js';
export default class Generator { export default class Generator {
constructor ( parsed, source, names, visitors ) { constructor ( parsed, source, names, visitors ) {
@ -14,22 +14,17 @@ export default class Generator {
this.names = names; this.names = names;
this.visitors = visitors; this.visitors = visitors;
this.templateProperties = {}; this.imports = [];
this.helpers = {}; this.helpers = {};
this.components = {}; this.components = {};
this.events = {}; this.events = {};
this.imports = [];
this.computations = [];
this.code = new MagicString( source ); this.code = new MagicString( source );
this.getUniqueName = counter( names ); this.getUniqueName = counter( names );
this.cssId = parsed.css ? `svelte-${parsed.hash}` : ''; this.cssId = parsed.css ? `svelte-${parsed.hash}` : '';
this.usesRefs = false; this.usesRefs = false;
this._callbacks = {}; this._callbacks = {};
this.init();
} }
addSourcemapLocations ( node ) { addSourcemapLocations ( node ) {
@ -96,17 +91,6 @@ export default class Generator {
}; };
} }
createMountStatement ( name ) {
if ( this.current.target === 'target' ) {
this.current.builders.mount.addLine(
`target.insertBefore( ${name}, anchor );`
);
} else {
this.current.builders.init.addLine(
`${this.current.target}.appendChild( ${name} );` );
}
}
fire ( eventName, data ) { fire ( eventName, data ) {
const handlers = eventName in this._callbacks && this._callbacks[ eventName ].slice(); const handlers = eventName in this._callbacks && this._callbacks[ eventName ].slice();
if ( !handlers ) return; if ( !handlers ) return;
@ -116,30 +100,45 @@ export default class Generator {
} }
} }
generateBlock ( node, name ) { generate ( result, options, { constructorName, format } ) {
this.push({ const pattern = /\[✂(\d+)-(\d+)$/;
name,
target: 'target', const parts = result.split( '✂]' );
localElementDepth: 0, const finalChunk = parts.pop();
builders: this.getBuilders(),
getUniqueName: this.getUniqueNameMaker() const compiled = new Bundle({ separator: '' });
function addString ( str ) {
compiled.addSource({
content: new MagicString( str )
});
}
const intro = getIntro( format, options, this.imports );
if ( intro ) addString( intro );
const { filename } = options;
parts.forEach( str => {
const chunk = str.replace( pattern, '' );
if ( chunk ) addString( chunk );
const match = pattern.exec( str );
const snippet = this.code.snip( +match[1], +match[2] );
compiled.addSource({
filename,
content: snippet
});
}); });
// walk the children here
node.children.forEach( node => this.visit( node ) );
this.fire( 'addRenderer', this.current );
this.pop();
// unset the children, to avoid them being visited again
node.children = [];
}
getBuilders () { addString( finalChunk );
addString( '\n\n' + getOutro( format, constructorName, options, this.imports ) );
return { return {
init: new CodeBuilder(), code: compiled.toString(),
mount: new CodeBuilder(), map: compiled.generateMap({ includeContent: true })
update: new CodeBuilder(),
detach: new CodeBuilder(),
detachRaw: new CodeBuilder(),
teardown: new CodeBuilder()
}; };
} }
@ -147,10 +146,14 @@ export default class Generator {
return counter( this.names ); return counter( this.names );
} }
init () { parseJs () {
const { computations, imports, source } = this; const { source } = this;
const { js } = this.parsed; const { js } = this.parsed;
const imports = this.imports;
const computations = [];
const templateProperties = {};
if ( js ) { if ( js ) {
this.addSourcemapLocations( js.content ); this.addSourcemapLocations( js.content );
@ -188,7 +191,7 @@ export default class Generator {
} }
defaultExport.declaration.properties.forEach( prop => { defaultExport.declaration.properties.forEach( prop => {
this.templateProperties[ prop.key.name ] = prop.value; templateProperties[ prop.key.name ] = prop.value;
}); });
this.code.prependRight( js.content.start, 'var template = (function () {' ); this.code.prependRight( js.content.start, 'var template = (function () {' );
@ -199,17 +202,17 @@ export default class Generator {
this.code.appendLeft( js.content.end, '}());' ); this.code.appendLeft( js.content.end, '}());' );
[ 'helpers', 'events', 'components' ].forEach( key => { [ 'helpers', 'events', 'components' ].forEach( key => {
if ( this.templateProperties[ key ] ) { if ( templateProperties[ key ] ) {
this.templateProperties[ key ].properties.forEach( prop => { templateProperties[ key ].properties.forEach( prop => {
this[ key ][ prop.key.name ] = prop.value; this[ key ][ prop.key.name ] = prop.value;
}); });
} }
}); });
if ( this.templateProperties.computed ) { if ( templateProperties.computed ) {
const dependencies = new Map(); const dependencies = new Map();
this.templateProperties.computed.properties.forEach( prop => { templateProperties.computed.properties.forEach( prop => {
const key = prop.key.name; const key = prop.key.name;
const value = prop.value; const value = prop.value;
@ -231,9 +234,15 @@ export default class Generator {
computations.push({ key, deps }); computations.push({ key, deps });
} }
this.templateProperties.computed.properties.forEach( prop => visit( prop.key.name ) ); templateProperties.computed.properties.forEach( prop => visit( prop.key.name ) );
} }
} }
return {
computations,
imports,
templateProperties
};
} }
on ( eventName, handler ) { on ( eventName, handler ) {

@ -1,9 +1,7 @@
import MagicString, { Bundle } from 'magic-string';
import deindent from '../../utils/deindent.js'; import deindent from '../../utils/deindent.js';
import getBuilders from './utils/getBuilders.js';
import CodeBuilder from '../../utils/CodeBuilder.js'; import CodeBuilder from '../../utils/CodeBuilder.js';
import namespaces from '../../utils/namespaces.js'; import namespaces from '../../utils/namespaces.js';
import getIntro from '../shared/utils/getIntro.js';
import getOutro from '../shared/utils/getOutro.js';
import processCss from '../shared/css/process.js'; 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';
@ -13,7 +11,7 @@ export default function dom ( parsed, source, options, names ) {
const generator = new Generator( parsed, source, names, visitors ); const generator = new Generator( parsed, source, names, visitors );
const { computations, imports, templateProperties } = generator; // TODO make this generator.parseJs() or similar? const { computations, imports, templateProperties } = generator.parseJs();
const renderers = []; const renderers = [];
function addRenderer ( fragment ) { function addRenderer ( fragment ) {
@ -63,7 +61,7 @@ export default function dom ( parsed, source, options, names ) {
`var ${name} = ${renderStatement};` `var ${name} = ${renderStatement};`
); );
generator.createMountStatement( name ); generator.fire( 'createMountStatement', name );
} else { } else {
generator.current.builders.init.addLine( generator.current.builders.init.addLine(
`${generator.current.target}.appendChild( ${renderStatement} );` `${generator.current.target}.appendChild( ${renderStatement} );`
@ -87,6 +85,35 @@ export default function dom ( parsed, source, options, names ) {
}); });
}); });
generator.on( 'createMountStatement', name => {
if ( generator.current.target === 'target' ) {
generator.current.builders.mount.addLine(
`target.insertBefore( ${name}, anchor );`
);
} else {
generator.current.builders.init.addLine(
`${generator.current.target}.appendChild( ${name} );` );
}
});
generator.on( 'generateBlock', ({ node, name }) => {
generator.push({
name,
target: 'target',
localElementDepth: 0,
builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker()
});
// walk the children here
node.children.forEach( node => generator.visit( node ) );
generator.fire( 'addRenderer', generator.current );
generator.pop();
// unset the children, to avoid them being visited again
node.children = [];
});
let namespace = null; let namespace = null;
if ( templateProperties.namespace ) { if ( templateProperties.namespace ) {
const ns = templateProperties.namespace.value; const ns = templateProperties.namespace.value;
@ -109,7 +136,7 @@ export default function dom ( parsed, source, options, names ) {
indexNames: {}, indexNames: {},
listNames: {}, listNames: {},
builders: generator.getBuilders(), builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker() getUniqueName: generator.getUniqueNameMaker()
}); });
@ -353,45 +380,5 @@ export default function dom ( parsed, source, options, names ) {
builders.main.addBlock( `${constructorName}.prototype = template.methods;` ); builders.main.addBlock( `${constructorName}.prototype = template.methods;` );
} }
const result = builders.main.toString(); return generator.generate( builders.main.toString(), options, { constructorName, format } );
const pattern = /\[✂(\d+)-(\d+)$/;
const parts = result.split( '✂]' );
const finalChunk = parts.pop();
const compiled = new Bundle({ separator: '' });
function addString ( str ) {
compiled.addSource({
content: new MagicString( str )
});
}
const intro = getIntro( format, options, imports );
if ( intro ) addString( intro );
const { filename } = options;
parts.forEach( str => {
const chunk = str.replace( pattern, '' );
if ( chunk ) addString( chunk );
const match = pattern.exec( str );
const snippet = generator.code.snip( +match[1], +match[2] );
compiled.addSource({
filename,
content: snippet
});
});
addString( finalChunk );
addString( '\n\n' + getOutro( format, constructorName, options, imports ) );
return {
code: compiled.toString(),
map: compiled.generateMap({ includeContent: true })
};
} }

@ -0,0 +1,12 @@
import CodeBuilder from '../../../utils/CodeBuilder.js';
export default function getBuilders () {
return {
init: new CodeBuilder(),
mount: new CodeBuilder(),
update: new CodeBuilder(),
detach: new CodeBuilder(),
detachRaw: new CodeBuilder(),
teardown: new CodeBuilder()
};
}

@ -33,7 +33,10 @@ export default {
if ( hasChildren ) { if ( hasChildren ) {
const yieldName = generator.current.getUniqueName( `render${name}YieldFragment` ); const yieldName = generator.current.getUniqueName( `render${name}YieldFragment` );
generator.generateBlock( node, yieldName ); generator.fire( 'generateBlock', {
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 );`

@ -1,4 +1,5 @@
import deindent from '../../../utils/deindent.js'; import deindent from '../../../utils/deindent.js';
import getBuilders from '../utils/getBuilders.js';
export default { export default {
enter ( generator, node ) { enter ( generator, node ) {
@ -105,7 +106,10 @@ export default {
} }
if ( node.else ) { if ( node.else ) {
generator.generateBlock( node.else, renderElse ); generator.fire( 'generateBlock', {
node: node.else,
name: renderElse
});
} }
const indexNames = Object.assign( {}, generator.current.indexNames ); const indexNames = Object.assign( {}, generator.current.indexNames );
@ -140,7 +144,7 @@ export default {
listNames, listNames,
params: blockParams, params: blockParams,
builders: generator.getBuilders(), builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker() getUniqueName: generator.getUniqueNameMaker()
}); });

@ -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.createMountStatement( name ); generator.fire( 'createMountStatement', name );
generator.push({ generator.push({
namespace: local.namespace, namespace: local.namespace,

@ -8,7 +8,11 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
condition: generator.contextualise( node.expression ).snippet, condition: generator.contextualise( node.expression ).snippet,
block: name block: name
}]; }];
generator.generateBlock( node, name );
generator.fire( 'generateBlock', {
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' ) {
@ -21,7 +25,10 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
block: node.else ? name : null, block: node.else ? name : null,
}); });
if (node.else) { if (node.else) {
generator.generateBlock( node.else, name ); generator.fire( 'generateBlock', {
node: node.else,
name
});
} }
} }
return conditionsAndBlocks; return conditionsAndBlocks;

Loading…
Cancel
Save