Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor #453

Merged
merged 32 commits into from
Apr 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
803d1d2
move test/generator to test/runtime, and have separate input -> outpu…
Rich-Harris Apr 4, 2017
f43e71b
remove #433 test for now
Rich-Harris Apr 4, 2017
77eee86
remove some long-since obsolete generator code
Rich-Harris Apr 4, 2017
00f1eae
remove this._callbacks
Rich-Harris Apr 4, 2017
2d4f9ea
make visitors responsible for visiting their own children
Rich-Harris Apr 5, 2017
e7d324f
visitors can just be functions now
Rich-Harris Apr 5, 2017
b8705a5
turn dom generator visitors into functions
Rich-Harris Apr 5, 2017
11033c2
minor test tweaks
Rich-Harris Apr 6, 2017
3006a24
more consistent naming
Rich-Harris Apr 6, 2017
063e76f
baby steps...
Rich-Harris Apr 6, 2017
d0752cd
another half-done commit
Rich-Harris Apr 6, 2017
c0442b5
another horrible half-done commit
Rich-Harris Apr 7, 2017
cdb8b9d
get yield blocks working
Rich-Harris Apr 8, 2017
d93a369
all tests passing once more. now the real work begins
Rich-Harris Apr 8, 2017
abf774b
remove generator.push and generator.pop
Rich-Harris Apr 8, 2017
421f3d6
separate current *fragment* from current *generator state*
Rich-Harris Apr 8, 2017
a9fb93e
remove redundant localElementDepth
Rich-Harris Apr 8, 2017
4b3bdcf
use isTopLevel instead of elementDepth
Rich-Harris Apr 8, 2017
c87967b
rename state.target to more self-explanatory state.parentNode
Rich-Harris Apr 8, 2017
96eca12
get rid of findBlock
Rich-Harris Apr 8, 2017
078f36b
get rid of fragment.type
Rich-Harris Apr 8, 2017
cc2b6fd
make fragment constructor more explicit
Rich-Harris Apr 8, 2017
cca91f8
remove getBuilders
Rich-Harris Apr 8, 2017
858c6b5
add gitkeep file so tests pass in CI
Rich-Harris Apr 8, 2017
bd85ffb
move render logic into fragment
Rich-Harris Apr 8, 2017
552820c
rename Fragment to Block
Rich-Harris Apr 8, 2017
aa41135
remove redundant addSourcemapLocations calls
Rich-Harris Apr 8, 2017
0050871
more consistent naming
Rich-Harris Apr 8, 2017
f88788c
rename fragment to block everywhere
Rich-Harris Apr 8, 2017
8148230
align SSR compiler with DOM compiler
Rich-Harris Apr 8, 2017
67967b1
DRY out block.tmp stuff
Rich-Harris Apr 8, 2017
731f09d
Merge branch 'master' into refactor
Rich-Harris Apr 8, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 3 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
src/shared
shared.js
test/test.js
test/test.js
**/_actual.js
**/expected.js
66 changes: 3 additions & 63 deletions src/generators/Generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import processCss from './shared/processCss.js';
import annotateWithScopes from './annotateWithScopes.js';

export default class Generator {
constructor ( parsed, source, name, visitors, options ) {
constructor ( parsed, source, name, options ) {
this.parsed = parsed;
this.source = source;
this.name = name;
this.visitors = visitors;
this.options = options;

this.imports = [];
Expand All @@ -31,8 +30,6 @@ export default class Generator {
// in dev mode
this.expectedProperties = new Set();

this.elementDepth = 0;

this.code = new MagicString( source );
this.css = parsed.css ? processCss( parsed, this.code ) : null;
this.cssId = parsed.css ? `svelte-${parsed.hash}` : '';
Expand All @@ -43,8 +40,6 @@ export default class Generator {
this.importedNames = new Set();
this._aliases = new Map();
this._usedNames = new Set();

this._callbacks = new Map();
}

addSourcemapLocations ( node ) {
Expand All @@ -65,14 +60,14 @@ export default class Generator {
return alias;
}

contextualise ( expression, isEventHandler ) {
contextualise ( fragment, expression, isEventHandler ) {
this.addSourcemapLocations( expression );

const usedContexts = [];
const dependencies = [];

const { code, helpers } = this;
const { contextDependencies, contexts, indexes } = this.current;
const { contextDependencies, contexts, indexes } = fragment;

let scope = annotateWithScopes( expression );

Expand Down Expand Up @@ -154,15 +149,6 @@ export default class Generator {
};
}

fire ( eventName, data ) {
const handlers = this._callbacks.has( eventName ) && this._callbacks.get( eventName ).slice();
if ( !handlers ) return;

for ( let i = 0; i < handlers.length; i += 1 ) {
handlers[i].call( this, data );
}
}

generate ( result, options, { name, format } ) {
if ( this.imports.length ) {
const statements = [];
Expand Down Expand Up @@ -430,50 +416,4 @@ export default class Generator {
templateProperties
};
}

on ( eventName, handler ) {
if ( this._callbacks.has( eventName ) ) {
this._callbacks.get( eventName ).push( handler );
} else {
this._callbacks.set( eventName, [ handler ] );
}
}

pop () {
const tail = this.current;
this.current = tail.parent;

return tail;
}

push ( fragment ) {
const newFragment = Object.assign( {}, this.current, fragment, {
parent: this.current
});

this.current = newFragment;
}

visit ( node ) {
const visitor = this.visitors[ node.type ];
if ( !visitor ) throw new Error( `Not implemented: ${node.type}` );

if ( visitor.enter ) visitor.enter( this, node );

if ( visitor.type === 'Element' ) {
this.elementDepth += 1;
}

if ( node.children ) {
node.children.forEach( child => {
this.visit( child );
});
}

if ( visitor.type === 'Element' ) {
this.elementDepth -= 1;
}

if ( visitor.leave ) visitor.leave( this, node );
}
}
140 changes: 140 additions & 0 deletions src/generators/dom/Block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import CodeBuilder from '../../utils/CodeBuilder.js';
import deindent from '../../utils/deindent.js';

export default class Block {
constructor ({ generator, name, key, expression, context, contextDependencies, contexts, indexes, params, indexNames, listNames }) {
this.generator = generator;
this.name = name;
this.key = key;
this.expression = expression;
this.context = context;

this.contexts = contexts;
this.indexes = indexes;
this.contextDependencies = contextDependencies;

this.params = params;
this.indexNames = indexNames;
this.listNames = listNames;

this.builders = {
create: new CodeBuilder(),
mount: new CodeBuilder(),
update: new CodeBuilder(),
detach: new CodeBuilder(),
detachRaw: new CodeBuilder(),
destroy: new CodeBuilder()
};

this.getUniqueName = generator.getUniqueNameMaker( params );

// unique names
this.component = this.getUniqueName( 'component' );
}

addElement ( name, renderStatement, parentNode, needsIdentifier = false ) {
const isToplevel = !parentNode;
if ( needsIdentifier || isToplevel ) {
this.builders.create.addLine(
`var ${name} = ${renderStatement};`
);

this.createMountStatement( name, parentNode );
} else {
this.builders.create.addLine( `${this.generator.helper( 'appendNode' )}( ${renderStatement}, ${parentNode} );` );
}

if ( isToplevel ) {
this.builders.detach.addLine( `${this.generator.helper( 'detachNode' )}( ${name} );` );
}
}

child ( options ) {
return new Block( Object.assign( {}, this, options, { parent: this } ) );
}

createAnchor ( name, parentNode ) {
const renderStatement = `${this.generator.helper( 'createComment' )}()`;
this.addElement( name, renderStatement, parentNode, true );
}

createMountStatement ( name, parentNode ) {
if ( parentNode ) {
this.builders.create.addLine( `${this.generator.helper( 'appendNode' )}( ${name}, ${parentNode} );` );
} else {
this.builders.mount.addLine( `${this.generator.helper( 'insertNode' )}( ${name}, target, anchor );` );
}
}

render () {
if ( this.autofocus ) {
this.builders.create.addLine( `${this.autofocus}.focus();` );
}

// minor hack – we need to ensure that any {{{triples}}} are detached
// first, so we append normal detach statements to detachRaw
this.builders.detachRaw.addBlock( this.builders.detach );

if ( !this.builders.detachRaw.isEmpty() ) {
this.builders.destroy.addBlock( deindent`
if ( detach ) {
${this.builders.detachRaw}
}
` );
}

const properties = new CodeBuilder();

let localKey;
if ( this.key ) {
localKey = this.getUniqueName( 'key' );
properties.addBlock( `key: ${localKey},` );
}

if ( this.builders.mount.isEmpty() ) {
properties.addBlock( `mount: ${this.generator.helper( 'noop' )},` );
} else {
properties.addBlock( deindent`
mount: function ( target, anchor ) {
${this.builders.mount}
},
` );
}

if ( this.builders.update.isEmpty() ) {
properties.addBlock( `update: ${this.generator.helper( 'noop' )},` );
} else {
if ( this._tmp ) this.builders.update.addBlockAtStart( `var ${this._tmp};` );
properties.addBlock( deindent`
update: function ( changed, ${this.params.join( ', ' )} ) {
${this.builders.update}
},
` );
}

if ( this.builders.destroy.isEmpty() ) {
properties.addBlock( `destroy: ${this.generator.helper( 'noop' )}` );
} else {
properties.addBlock( deindent`
destroy: function ( detach ) {
${this.builders.destroy}
}
` );
}

return deindent`
function ${this.name} ( ${this.params.join( ', ' )}, ${this.component}${this.key ? `, ${localKey}` : ''} ) {
${this.builders.create}

return {
${properties}
};
}
`;
}

tmp () {
if ( !this._tmp ) this._tmp = this.getUniqueName( 'tmp' );
return this._tmp;
}
}
Loading