From 2d4f9eac00fce55b56b1de50d231f79e904b9fa4 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Tue, 4 Apr 2017 22:55:30 -0400 Subject: [PATCH] make visitors responsible for visiting their own children --- src/generators/Generator.js | 26 +------------------ src/generators/dom/index.js | 14 +++++----- src/generators/dom/visit.js | 8 ++++++ src/generators/dom/visitors/Component.js | 11 ++++++-- src/generators/dom/visitors/EachBlock.js | 7 +++-- src/generators/dom/visitors/Element.js | 17 ++++++------ src/generators/server-side-rendering/index.js | 12 +++++---- src/generators/server-side-rendering/visit.js | 8 ++++++ .../visitors/Component.js | 11 ++++++-- .../visitors/EachBlock.js | 8 ++++-- .../server-side-rendering/visitors/Element.js | 11 ++++++-- .../server-side-rendering/visitors/IfBlock.js | 16 +++++++++--- 12 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 src/generators/dom/visit.js create mode 100644 src/generators/server-side-rendering/visit.js diff --git a/src/generators/Generator.js b/src/generators/Generator.js index ddd2dec797..d1956ed734 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -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 = []; @@ -434,27 +433,4 @@ export default class Generator { 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 ); - } } diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 4f829776fd..3e86ead435 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -1,13 +1,13 @@ import deindent from '../../utils/deindent.js'; import getBuilders from './utils/getBuilders.js'; import CodeBuilder from '../../utils/CodeBuilder.js'; -import visitors from './visitors/index.js'; +import visit from './visit.js'; import Generator from '../Generator.js'; import * as shared from '../../shared/index.js'; class DomGenerator extends Generator { - constructor ( parsed, source, name, visitors, options ) { - super( parsed, source, name, visitors, options ); + constructor ( parsed, source, name, options ) { + super( parsed, source, name, options ); this.renderers = []; this.uses = new Set(); @@ -126,7 +126,7 @@ class DomGenerator extends Generator { }); // walk the children here - node.children.forEach( node => this.visit( node ) ); + node.children.forEach( node => visit( node, this ) ); this.addRenderer( this.current ); this.pop(); @@ -149,7 +149,7 @@ export default function dom ( parsed, source, options ) { const format = options.format || 'es'; const name = options.name || 'SvelteComponent'; - const generator = new DomGenerator( parsed, source, name, visitors, options ); + const generator = new DomGenerator( parsed, source, name, options ); const { computations, hasJs, templateProperties, namespace } = generator.parseJs(); @@ -177,7 +177,9 @@ export default function dom ( parsed, source, options ) { getUniqueName, }); - parsed.html.children.forEach( node => generator.visit( node ) ); + parsed.html.children.forEach( node => { + visit( node, generator ); + }); generator.addRenderer( generator.pop() ); diff --git a/src/generators/dom/visit.js b/src/generators/dom/visit.js new file mode 100644 index 0000000000..5f688e76ac --- /dev/null +++ b/src/generators/dom/visit.js @@ -0,0 +1,8 @@ +import visitors from './visitors/index.js'; + +export default function visit ( node, generator ) { + const visitor = visitors[ node.type ]; + + if ( visitor.enter ) visitor.enter( generator, node ); + if ( visitor.leave ) visitor.leave( generator, node ); +} \ No newline at end of file diff --git a/src/generators/dom/visitors/Component.js b/src/generators/dom/visitors/Component.js index 69e2e3c2ac..ed9cae8921 100644 --- a/src/generators/dom/visitors/Component.js +++ b/src/generators/dom/visitors/Component.js @@ -1,5 +1,6 @@ import deindent from '../../../utils/deindent.js'; import CodeBuilder from '../../../utils/CodeBuilder.js'; +import visit from '../visit.js'; import addComponentAttributes from './attributes/addComponentAttributes.js'; function capDown ( name ) { @@ -166,9 +167,15 @@ export default { localElementDepth: current.localElementDepth + 1, key: null }); - }, - leave ( generator ) { + this.elementDepth += 1; + + node.children.forEach( child => { + visit( child, generator ); + }); + + this.elementDepth -= 1; + generator.pop(); } }; diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index df9936197f..716c5c1e34 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -1,6 +1,7 @@ import CodeBuilder from '../../../utils/CodeBuilder.js'; import deindent from '../../../utils/deindent.js'; import getBuilders from '../utils/getBuilders.js'; +import visit from '../visit.js'; export default { enter ( generator, node ) { @@ -214,9 +215,11 @@ export default { builders: getBuilders(), getUniqueName, }); - }, - leave ( generator ) { + node.children.forEach( child => { + visit( child, generator ); + }); + generator.addRenderer( generator.current ); generator.pop(); } diff --git a/src/generators/dom/visitors/Element.js b/src/generators/dom/visitors/Element.js index 566a535bab..a056c2957f 100644 --- a/src/generators/dom/visitors/Element.js +++ b/src/generators/dom/visitors/Element.js @@ -1,5 +1,6 @@ import CodeBuilder from '../../../utils/CodeBuilder.js'; import deindent from '../../../utils/deindent.js'; +import visit from '../visit.js'; import addElementAttributes from './attributes/addElementAttributes.js'; import Component from './Component.js'; import Window from './meta/Window.js'; @@ -108,20 +109,20 @@ export default { localElementDepth: generator.current.localElementDepth + 1, key: null }); - }, - leave ( generator, node ) { + this.elementDepth += 1; + + node.children.forEach( child => { + visit( child, generator ); + }); + + this.elementDepth -= 1; + if ( node.name in meta ) { if ( meta[ node.name ].leave ) meta[ node.name ].leave( generator, node ); return; } - const isComponent = generator.components.has( node.name ); - - if ( isComponent ) { - return Component.leave( generator, node ); - } - if ( node.initialUpdate ) { generator.current.builders.init.addBlock( node.initialUpdate ); } diff --git a/src/generators/server-side-rendering/index.js b/src/generators/server-side-rendering/index.js index c28b4aeef9..3189fdd583 100644 --- a/src/generators/server-side-rendering/index.js +++ b/src/generators/server-side-rendering/index.js @@ -1,12 +1,12 @@ import deindent from '../../utils/deindent.js'; import CodeBuilder from '../../utils/CodeBuilder.js'; import flattenReference from '../../utils/flattenReference.js'; -import visitors from './visitors/index.js'; import Generator from '../Generator.js'; +import visit from './visit.js'; class SsrGenerator extends Generator { - constructor ( parsed, source, name, visitors, options ) { - super( parsed, source, name, visitors, options ); + constructor ( parsed, source, name, options ) { + super( parsed, source, name, options ); this.bindings = []; this.renderCode = ''; } @@ -38,7 +38,7 @@ export default function ssr ( parsed, source, options ) { const format = options.format || 'cjs'; const name = options.name || 'SvelteComponent'; - const generator = new SsrGenerator( parsed, source, name, visitors, options ); + const generator = new SsrGenerator( parsed, source, name, options ); const { computations, hasJs, templateProperties } = generator.parseJs( true ); @@ -56,7 +56,9 @@ export default function ssr ( parsed, source, options ) { conditions: [] }); - parsed.html.children.forEach( node => generator.visit( node ) ); + parsed.html.children.forEach( node => { + visit( node, generator ); + }); builders.render.addLine( templateProperties.data ? `root = Object.assign( ${generator.alias( 'template' )}.data(), root || {} );` : `root = root || {};` diff --git a/src/generators/server-side-rendering/visit.js b/src/generators/server-side-rendering/visit.js new file mode 100644 index 0000000000..5f688e76ac --- /dev/null +++ b/src/generators/server-side-rendering/visit.js @@ -0,0 +1,8 @@ +import visitors from './visitors/index.js'; + +export default function visit ( node, generator ) { + const visitor = visitors[ node.type ]; + + if ( visitor.enter ) visitor.enter( generator, node ); + if ( visitor.leave ) visitor.leave( generator, node ); +} \ No newline at end of file diff --git a/src/generators/server-side-rendering/visitors/Component.js b/src/generators/server-side-rendering/visitors/Component.js index aef098a024..688f70f614 100644 --- a/src/generators/server-side-rendering/visitors/Component.js +++ b/src/generators/server-side-rendering/visitors/Component.js @@ -1,4 +1,5 @@ import flattenReference from '../../../utils/flattenReference.js'; +import visit from '../visit.js'; export default { enter ( generator, node ) { @@ -63,9 +64,15 @@ export default { } generator.append( open ); - }, - leave ( generator, node ) { + this.elementDepth += 1; + + node.children.forEach( child => { + visit( child, generator ); + }); + + this.elementDepth -= 1; + const close = node.children.length ? `\` })}` : ')}'; generator.append( close ); } diff --git a/src/generators/server-side-rendering/visitors/EachBlock.js b/src/generators/server-side-rendering/visitors/EachBlock.js index 0fbe3ee995..da97500a43 100644 --- a/src/generators/server-side-rendering/visitors/EachBlock.js +++ b/src/generators/server-side-rendering/visitors/EachBlock.js @@ -1,3 +1,5 @@ +import visit from '../visit.js'; + export default { enter ( generator, node ) { const { dependencies, snippet } = generator.contextualise( node.expression ); @@ -21,9 +23,11 @@ export default { indexes, contextDependencies }); - }, - leave ( generator ) { + node.children.forEach( child => { + visit( child, generator ); + }); + const close = `\` ).join( '' )}`; generator.append( close ); diff --git a/src/generators/server-side-rendering/visitors/Element.js b/src/generators/server-side-rendering/visitors/Element.js index d50f795b6c..f452a37e07 100644 --- a/src/generators/server-side-rendering/visitors/Element.js +++ b/src/generators/server-side-rendering/visitors/Element.js @@ -1,5 +1,6 @@ import Component from './Component.js'; import isVoidElementName from '../../../utils/isVoidElementName.js'; +import visit from '../visit.js'; import Window from './meta/Window.js'; const meta = { @@ -45,9 +46,15 @@ export default { openingTag += '>'; generator.append( openingTag ); - }, - leave ( generator, node ) { + this.elementDepth += 1; + + node.children.forEach( child => { + visit( child, generator ); + }); + + this.elementDepth -= 1; + if ( node.name in meta ) { if ( meta[ node.name ].leave ) meta[ node.name ].leave( generator, node ); return; diff --git a/src/generators/server-side-rendering/visitors/IfBlock.js b/src/generators/server-side-rendering/visitors/IfBlock.js index dd21ff8b4f..1d093db358 100644 --- a/src/generators/server-side-rendering/visitors/IfBlock.js +++ b/src/generators/server-side-rendering/visitors/IfBlock.js @@ -1,3 +1,5 @@ +import visit from '../visit.js'; + export default { enter ( generator, node ) { const { snippet } = generator.contextualise( node.expression ); @@ -7,11 +9,19 @@ export default { generator.push({ conditions: generator.current.conditions.concat( snippet ) }); - }, - leave ( generator, node ) { + node.children.forEach( child => { + visit( child, generator ); + }); + generator.append( '` : `' ); - if ( node.else ) node.else.children.forEach( child => generator.visit( child ) ); + + if ( node.else ) { + node.else.children.forEach( child => { + visit( child, generator ); + }); + } + generator.append( '` }' ); generator.pop();