more refactoring

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

@ -1,11 +1,11 @@
import MagicString from 'magic-string';
import CodeBuilder from '../utils/CodeBuilder.js';
import MagicString, { Bundle } from 'magic-string';
import { walk } from 'estree-walker';
import deindent from '../utils/deindent.js';
import isReference from '../utils/isReference.js';
import counter from './shared/utils/counter.js';
import flattenReference from '../utils/flattenReference.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 {
constructor ( parsed, source, names, visitors ) {
@ -14,22 +14,17 @@ export default class Generator {
this.names = names;
this.visitors = visitors;
this.templateProperties = {};
this.imports = [];
this.helpers = {};
this.components = {};
this.events = {};
this.imports = [];
this.computations = [];
this.code = new MagicString( source );
this.getUniqueName = counter( names );
this.cssId = parsed.css ? `svelte-${parsed.hash}` : '';
this.usesRefs = false;
this._callbacks = {};
this.init();
}
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 ) {
const handlers = eventName in this._callbacks && this._callbacks[ eventName ].slice();
if ( !handlers ) return;
@ -116,30 +100,45 @@ export default class Generator {
}
}
generateBlock ( node, name ) {
this.push({
name,
target: 'target',
localElementDepth: 0,
builders: this.getBuilders(),
getUniqueName: this.getUniqueNameMaker()
generate ( result, 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, 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 {
init: new CodeBuilder(),
mount: new CodeBuilder(),
update: new CodeBuilder(),
detach: new CodeBuilder(),
detachRaw: new CodeBuilder(),
teardown: new CodeBuilder()
code: compiled.toString(),
map: compiled.generateMap({ includeContent: true })
};
}
@ -147,10 +146,14 @@ export default class Generator {
return counter( this.names );
}
init () {
const { computations, imports, source } = this;
parseJs () {
const { source } = this;
const { js } = this.parsed;
const imports = this.imports;
const computations = [];
const templateProperties = {};
if ( js ) {
this.addSourcemapLocations( js.content );
@ -188,7 +191,7 @@ export default class Generator {
}
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 () {' );
@ -199,17 +202,17 @@ export default class Generator {
this.code.appendLeft( js.content.end, '}());' );
[ 'helpers', 'events', 'components' ].forEach( key => {
if ( this.templateProperties[ key ] ) {
this.templateProperties[ key ].properties.forEach( prop => {
if ( templateProperties[ key ] ) {
templateProperties[ key ].properties.forEach( prop => {
this[ key ][ prop.key.name ] = prop.value;
});
}
});
if ( this.templateProperties.computed ) {
if ( templateProperties.computed ) {
const dependencies = new Map();
this.templateProperties.computed.properties.forEach( prop => {
templateProperties.computed.properties.forEach( prop => {
const key = prop.key.name;
const value = prop.value;
@ -231,9 +234,15 @@ export default class Generator {
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 ) {

@ -1,9 +1,7 @@
import MagicString, { Bundle } from 'magic-string';
import deindent from '../../utils/deindent.js';
import getBuilders from './utils/getBuilders.js';
import CodeBuilder from '../../utils/CodeBuilder.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 visitors from './visitors/index.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 { computations, imports, templateProperties } = generator; // TODO make this generator.parseJs() or similar?
const { computations, imports, templateProperties } = generator.parseJs();
const renderers = [];
function addRenderer ( fragment ) {
@ -63,7 +61,7 @@ export default function dom ( parsed, source, options, names ) {
`var ${name} = ${renderStatement};`
);
generator.createMountStatement( name );
generator.fire( 'createMountStatement', name );
} else {
generator.current.builders.init.addLine(
`${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;
if ( templateProperties.namespace ) {
const ns = templateProperties.namespace.value;
@ -109,7 +136,7 @@ export default function dom ( parsed, source, options, names ) {
indexNames: {},
listNames: {},
builders: generator.getBuilders(),
builders: getBuilders(),
getUniqueName: generator.getUniqueNameMaker()
});
@ -353,45 +380,5 @@ export default function dom ( parsed, source, options, names ) {
builders.main.addBlock( `${constructorName}.prototype = template.methods;` );
}
const result = builders.main.toString();
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 })
};
return generator.generate( builders.main.toString(), options, { constructorName, format } );
}

@ -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 ) {
const yieldName = generator.current.getUniqueName( `render${name}YieldFragment` );
generator.generateBlock( node, yieldName );
generator.fire( 'generateBlock', {
node,
name: yieldName
});
generator.current.builders.init.addLine(
`var ${name}_yieldFragment = ${yieldName}( root, component );`

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

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

@ -8,7 +8,11 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
condition: generator.contextualise( node.expression ).snippet,
block: name
}];
generator.generateBlock( node, name );
generator.fire( 'generateBlock', {
node,
name
});
if ( node.else && node.else.children.length === 1 &&
node.else.children[0].type === 'IfBlock' ) {
@ -21,7 +25,10 @@ function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
block: node.else ? name : null,
});
if (node.else) {
generator.generateBlock( node.else, name );
generator.fire( 'generateBlock', {
node: node.else,
name
});
}
}
return conditionsAndBlocks;

Loading…
Cancel
Save