From 078f3ad8b6984b2c823cb3d568d81cccc6ae46c5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 25 Jun 2017 00:25:29 -0400 Subject: [PATCH 1/8] simplify helpers --- mocha.opts | 3 +- src/generators/dom/Block.ts | 20 ++++---- src/generators/dom/index.ts | 48 +++++++++---------- .../dom/visitors/Component/Binding.ts | 4 +- src/generators/dom/visitors/EachBlock.ts | 10 ++-- .../dom/visitors/Element/Attribute.ts | 16 ++----- .../dom/visitors/Element/Binding.ts | 31 ++++-------- .../dom/visitors/Element/Element.ts | 20 ++++---- .../dom/visitors/Element/EventHandler.ts | 16 +++---- .../dom/visitors/Element/addTransitions.ts | 8 ++-- src/generators/dom/visitors/IfBlock.ts | 4 +- src/generators/dom/visitors/MustacheTag.ts | 4 +- src/generators/dom/visitors/RawMustacheTag.ts | 12 ++--- src/generators/dom/visitors/Text.ts | 4 +- src/shared/transitions.js | 3 +- 15 files changed, 85 insertions(+), 118 deletions(-) diff --git a/mocha.opts b/mocha.opts index 4e8a550a4c..af6b17a845 100644 --- a/mocha.opts +++ b/mocha.opts @@ -1 +1,2 @@ -test/test.js +--bail +test/test.js \ No newline at end of file diff --git a/src/generators/dom/Block.ts b/src/generators/dom/Block.ts index e7187e309d..f706a48807 100644 --- a/src/generators/dom/Block.ts +++ b/src/generators/dom/Block.ts @@ -2,6 +2,7 @@ import CodeBuilder from '../../utils/CodeBuilder'; import deindent from '../../utils/deindent'; import { DomGenerator } from './index'; import { Node } from '../../interfaces'; +import shared from './shared'; export interface BlockOptions { name: string; @@ -140,7 +141,7 @@ export default class Block { if (isToplevel) { this.builders.unmount.addLine( - `${this.generator.helper('detachNode')}( ${name} );` + `@detachNode( ${name} );` ); } } @@ -187,12 +188,11 @@ export default class Block { mount(name: string, parentNode: string) { if (parentNode) { this.builders.mount.addLine( - `${this.generator.helper('appendNode')}( ${name}, ${parentNode} );` + `@appendNode( ${name}, ${parentNode} );` ); } else { this.builders.mount.addLine( - `${this.generator.helper('insertNode')}( ${name}, ${this - .target}, anchor );` + `@insertNode( ${name}, ${this.target}, anchor );` ); } } @@ -233,7 +233,7 @@ export default class Block { } if (this.builders.create.isEmpty()) { - properties.addBlock(`create: ${this.generator.helper('noop')},`); + properties.addBlock(`create: @noop,`); } else { properties.addBlock(deindent` create: function () { @@ -245,7 +245,7 @@ export default class Block { if (this.generator.hydratable) { if (this.builders.claim.isEmpty()) { - properties.addBlock(`claim: ${this.generator.helper('noop')},`); + properties.addBlock(`claim: @noop,`); } else { properties.addBlock(deindent` claim: function ( nodes ) { @@ -265,7 +265,7 @@ export default class Block { } if (this.builders.mount.isEmpty()) { - properties.addBlock(`mount: ${this.generator.helper('noop')},`); + properties.addBlock(`mount: @noop,`); } else { properties.addBlock(deindent` mount: function ( ${this.target}, anchor ) { @@ -276,7 +276,7 @@ export default class Block { if (this.hasUpdateMethod) { if (this.builders.update.isEmpty()) { - properties.addBlock(`update: ${this.generator.helper('noop')},`); + properties.addBlock(`update: @noop,`); } else { properties.addBlock(deindent` update: function ( changed, ${this.params.join(', ')} ) { @@ -331,7 +331,7 @@ export default class Block { } if (this.builders.unmount.isEmpty()) { - properties.addBlock(`unmount: ${this.generator.helper('noop')},`); + properties.addBlock(`unmount: @noop,`); } else { properties.addBlock(deindent` unmount: function () { @@ -341,7 +341,7 @@ export default class Block { } if (this.builders.destroy.isEmpty()) { - properties.addBlock(`destroy: ${this.generator.helper('noop')}`); + properties.addBlock(`destroy: @noop`); } else { properties.addBlock(deindent` destroy: function () { diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 2c54e573a1..a3728e5939 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -12,6 +12,8 @@ import preprocess from './preprocess'; import Block from './Block'; import { Parsed, CompileOptions, Node } from '../../interfaces'; +const helperPattern = new RegExp(`@(${Object.keys(shared).join('|')})\\b`, 'g'); + export class DomGenerator extends Generator { blocks: Block[]; uses: Set; @@ -83,7 +85,6 @@ export default function dom( if (computations.length) { const builder = new CodeBuilder(); - const differs = generator.helper('differs'); computations.forEach(({ key, deps }) => { if (generator.readonly.has(key)) { @@ -98,7 +99,7 @@ export default function dom( const condition = `isInitial || ${deps .map( dep => - `( '${dep}' in newState && ${differs}( state.${dep}, oldState.${dep} ) )` + `( '${dep}' in newState && @differs( state.${dep}, oldState.${dep} ) )` ) .join(' || ')}`; const statement = `state.${key} = newState.${key} = ${generator.alias( @@ -131,18 +132,14 @@ export default function dom( `} var oldState = this._state; - this._state = ${generator.helper('assign')}( {}, oldState, newState ); + this._state = @assign( {}, oldState, newState ); ${computations.length && `${generator.alias( 'recompute' )}( this._state, newState, oldState, false )`} - ${generator.helper( - 'dispatchObservers' - )}( this, this._observers.pre, newState, oldState ); + @dispatchObservers( this, this._observers.pre, newState, oldState ); ${block.hasUpdateMethod && `this._fragment.update( newState, this._state );`} - ${generator.helper( - 'dispatchObservers' - )}( this, this._observers.post, newState, oldState ); + @dispatchObservers( this, this._observers.post, newState, oldState ); ${generator.hasComplexBindings && `while ( this._bindings.length ) this._bindings.pop()();`} ${(generator.hasComponents || generator.hasIntroTransitions) && @@ -158,10 +155,10 @@ export default function dom( if (generator.css && options.css !== false) { builders.main.addBlock(deindent` function ${generator.alias('add_css')} () { - var style = ${generator.helper('createElement')}( 'style' ); + var style = @createElement( 'style' ); style.id = ${JSON.stringify(generator.cssId + '-style')}; style.textContent = ${JSON.stringify(generator.css)}; - ${generator.helper('appendNode')}( style, document.head ); + @appendNode( style, document.head ); } `); } @@ -180,7 +177,7 @@ export default function dom( ? `, ${generator.alias('template')}.methods` : ''); const proto = sharedPath - ? `${generator.helper('proto')} ` + ? `@proto ` : deindent` { ${['get', 'fire', 'observe', 'on', 'set', '_flush'] @@ -196,7 +193,7 @@ export default function dom( `if ( !options.target && !options._root ) throw new Error( "'target' is a required option" );`} ${generator.usesRefs && `this.refs = {};`} this._state = ${templateProperties.data - ? `${generator.helper('assign')}( ${generator.alias( + ? `@assign( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`}; @@ -242,9 +239,9 @@ export default function dom( if ( options.target ) { ${generator.hydratable ? deindent` - var nodes = ${generator.helper('children')}( options.target ); + var nodes = @children( options.target ); options.hydrate ? this._fragment.claim( nodes ) : this._fragment.create(); - nodes.forEach( ${generator.helper('detachNode')} ); + nodes.forEach( @detachNode ); ` : deindent` this._fragment.create(); @@ -269,7 +266,7 @@ export default function dom( `} } - ${generator.helper('assign')}( ${prototypeBase}, ${proto}); + @assign( ${prototypeBase}, ${proto}); ${name}.prototype._set = function _set ( newState ) { ${builders._set} @@ -289,6 +286,9 @@ export default function dom( }; `); + let result = builders.main.toString() + .replace(helperPattern, (match: string, name: string) => generator.helper(name)); + if (sharedPath) { if (format !== 'es') { throw new Error( @@ -302,9 +302,7 @@ export default function dom( : name; }); - builders.main.addLineAtStart( - `import { ${names.join(', ')} } from ${JSON.stringify(sharedPath)};` - ); + result = `import { ${names.join(', ')} } from ${JSON.stringify(sharedPath)};\n\n` + result; } else { generator.uses.forEach(key => { const str = shared[key]; @@ -343,22 +341,20 @@ export default function dom( // special case const global = `_svelteTransitionManager`; - builders.main.addBlock( - `var ${generator.alias( - 'transitionManager' - )} = window.${global} || ( window.${global} = ${code});` - ); + result += `\n\nvar ${generator.alias( + 'transitionManager' + )} = window.${global} || ( window.${global} = ${code});`; } else { const alias = generator.alias(expression.id.name); if (alias !== expression.id.name) code.overwrite(expression.id.start, expression.id.end, alias); - builders.main.addBlock(code.toString()); + result += `\n\n${code}`; } }); } - return generator.generate(builders.main.toString(), options, { + return generator.generate(result, options, { name, format, }); diff --git a/src/generators/dom/visitors/Component/Binding.ts b/src/generators/dom/visitors/Component/Binding.ts index ac8e90f0f2..a071dc1439 100644 --- a/src/generators/dom/visitors/Component/Binding.ts +++ b/src/generators/dom/visitors/Component/Binding.ts @@ -73,9 +73,7 @@ export default function visitBinding( ${updating} = true; ${setter} ${updating} = false; - }, { init: ${generator.helper( - 'differs' - )}( ${local.name}.get( '${attribute.name}' ), ${snippet} ) }); + }, { init: @differs( ${local.name}.get( '${attribute.name}' ), ${snippet} ) }); }); `); diff --git a/src/generators/dom/visitors/EachBlock.ts b/src/generators/dom/visitors/EachBlock.ts index 4be9059e52..aab9372725 100644 --- a/src/generators/dom/visitors/EachBlock.ts +++ b/src/generators/dom/visitors/EachBlock.ts @@ -48,8 +48,8 @@ export default function visitEachBlock( if (node.needsAnchor) { block.addElement( anchor, - `${generator.helper('createComment')}()`, - `${generator.helper('createComment')}()`, + `@createComment()`, + `@createComment()`, state.parentNode, true ); @@ -162,8 +162,8 @@ function keyed( node._block.first = node._block.getUniqueName('first'); node._block.addElement( node._block.first, - `${generator.helper('createComment')}()`, - `${generator.helper('createComment')}()`, + `@createComment()`, + `@createComment()`, null, true ); @@ -479,6 +479,6 @@ function unkeyed( `); block.builders.destroy.addBlock( - `${generator.helper('destroyEach')}( ${iterations}, false, 0 );` + `@destroyEach( ${iterations}, false, 0 );` ); } diff --git a/src/generators/dom/visitors/Element/Attribute.ts b/src/generators/dom/visitors/Element/Attribute.ts index 97d2bfe8be..a3e21953d7 100644 --- a/src/generators/dom/visitors/Element/Attribute.ts +++ b/src/generators/dom/visitors/Element/Attribute.ts @@ -36,8 +36,8 @@ export default function visitAttribute( // namespaced attributes but I'm not sure that's applicable in // HTML5? const method = name.slice(0, 6) === 'xlink:' - ? 'setXlinkAttribute' - : 'setAttribute'; + ? '@setXlinkAttribute' + : '@setAttribute'; const isDynamic = (attribute.value !== true && attribute.value.length > 1) || @@ -112,13 +112,9 @@ export default function visitAttribute( updater = `${state.parentNode}.${propertyName} = ${last};`; } else { block.builders.hydrate.addLine( - `${generator.helper( - method - )}( ${state.parentNode}, '${name}', ${last} = ${value} );` + `${method}( ${state.parentNode}, '${name}', ${last} = ${value} );` ); - updater = `${generator.helper( - method - )}( ${state.parentNode}, '${name}', ${last} );`; + updater = `${method}( ${state.parentNode}, '${name}', ${last} );`; } block.builders.update.addBlock(deindent` @@ -135,9 +131,7 @@ export default function visitAttribute( const statement = propertyName ? `${state.parentNode}.${propertyName} = ${value};` - : `${generator.helper( - method - )}( ${state.parentNode}, '${name}', ${value} );`; + : `${method}( ${state.parentNode}, '${name}', ${value} );`; block.builders.hydrate.addLine(statement); diff --git a/src/generators/dom/visitors/Element/Binding.ts b/src/generators/dom/visitors/Element/Binding.ts index 3610ce4e75..185996b898 100644 --- a/src/generators/dom/visitors/Element/Binding.ts +++ b/src/generators/dom/visitors/Element/Binding.ts @@ -152,11 +152,9 @@ export default function visitBinding( } `); - block.builders.hydrate.addBlock(deindent` - ${generator.helper( - 'addListener' - )}( ${state.parentNode}, '${eventName}', ${handler} ); - `); + block.builders.hydrate.addBlock( + `@addListener( ${state.parentNode}, '${eventName}', ${handler} );` + ); if (node.name !== 'audio' && node.name !== 'video') node.initialUpdate = updateElement; @@ -170,22 +168,15 @@ export default function visitBinding( `); } - block.builders.destroy.addLine(deindent` - ${generator.helper( - 'removeListener' - )}( ${state.parentNode}, '${eventName}', ${handler} ); - `); + block.builders.destroy.addLine( + `@removeListener( ${state.parentNode}, '${eventName}', ${handler} );`); if (attribute.name === 'paused') { block.builders.create.addLine( - `${generator.helper( - 'addListener' - )}( ${state.parentNode}, 'play', ${handler} );` + `@addListener( ${state.parentNode}, 'play', ${handler} );` ); block.builders.destroy.addLine( - `${generator.helper( - 'removeListener' - )}( ${state.parentNode}, 'play', ${handler} );` + `@removeListener( ${state.parentNode}, 'play', ${handler} );` ); } } @@ -231,9 +222,7 @@ function getBindingValue( // if (attribute.name === 'group') { if (type === 'checkbox') { - return `${generator.helper( - 'getBindingGroupValue' - )}( ${block.component}._bindingGroups[${bindingGroup}] )`; + return `@getBindingGroupValue( ${block.component}._bindingGroups[${bindingGroup}] )`; } return `${state.parentNode}.__value`; @@ -241,9 +230,7 @@ function getBindingValue( // if (type === 'range' || type === 'number') { - return `${generator.helper( - 'toNumber' - )}( ${state.parentNode}.${attribute.name} )`; + return `@toNumber( ${state.parentNode}.${attribute.name} )`; } // everything else diff --git a/src/generators/dom/visitors/Element/Element.ts b/src/generators/dom/visitors/Element/Element.ts index 5e16abb3eb..946f716b73 100644 --- a/src/generators/dom/visitors/Element/Element.ts +++ b/src/generators/dom/visitors/Element/Element.ts @@ -56,22 +56,20 @@ export default function visitElement( if (generator.hydratable) { block.builders.claim.addBlock(deindent` ${name} = ${getClaimStatement(generator, childState.namespace, state.parentNodes, node)}; - var ${childState.parentNodes} = ${generator.helper('children')}( ${name} ); + var ${childState.parentNodes} = @children( ${name} ); `); } if (state.parentNode) { - block.builders.mount.addLine(`${block.generator.helper('appendNode')}( ${name}, ${state.parentNode} );`); + block.builders.mount.addLine(`@appendNode( ${name}, ${state.parentNode} );`); } else { - block.builders.mount.addLine(`${block.generator.helper('insertNode')}( ${name}, ${block.target}, anchor );`); + block.builders.mount.addLine(`@insertNode( ${name}, ${block.target}, anchor );`); } // add CSS encapsulation attribute if (generator.cssId && (!generator.cascade || state.isTopLevel)) { block.builders.hydrate.addLine( - `${generator.helper( - 'setAttribute' - )}( ${name}, '${generator.cssId}', '' );` + `@setAttribute( ${name}, '${generator.cssId}', '' );` ); } @@ -134,7 +132,7 @@ export default function visitElement( // TODO we eventually need to consider what happens to elements // that belong to the same outgroup as an outroing element... block.builders.unmount.addLine( - `${generator.helper('detachNode')}( ${name} );` + `@detachNode( ${name} );` ); } @@ -188,7 +186,7 @@ export default function visitElement( } block.builders.claim.addLine( - `${childState.parentNodes}.forEach( ${generator.helper('detachNode')} );` + `${childState.parentNodes}.forEach( @detachNode );` ); } @@ -198,14 +196,14 @@ function getRenderStatement( name: string ) { if (namespace === 'http://www.w3.org/2000/svg') { - return `${generator.helper('createSvgElement')}( '${name}' )`; + return `@createSvgElement( '${name}' )`; } if (namespace) { return `document.createElementNS( '${namespace}', '${name}' )`; } - return `${generator.helper('createElement')}( '${name}' )`; + return `@createElement( '${name}' )`; } function getClaimStatement( @@ -221,7 +219,7 @@ function getClaimStatement( const name = namespace ? node.name : node.name.toUpperCase(); - return `${generator.helper('claimElement')}( ${nodes}, '${name}', ${attributes ? `{ ${attributes} }` : `{}`}, ${namespace === namespaces.svg ? true : false} )`; + return `@claimElement( ${nodes}, '${name}', ${attributes ? `{ ${attributes} }` : `{}`}, ${namespace === namespaces.svg ? true : false} )`; } function quoteProp(name: string) { diff --git a/src/generators/dom/visitors/Element/EventHandler.ts b/src/generators/dom/visitors/Element/EventHandler.ts index 8a84e004ca..8edb614a62 100644 --- a/src/generators/dom/visitors/Element/EventHandler.ts +++ b/src/generators/dom/visitors/Element/EventHandler.ts @@ -99,16 +99,12 @@ export default function visitEventHandler( block.builders.init.addBlock(handler); } - block.builders.hydrate.addLine(deindent` - ${generator.helper( - 'addListener' - )}( ${state.parentNode}, '${name}', ${handlerName} ); - `); + block.builders.hydrate.addLine( + `@addListener( ${state.parentNode}, '${name}', ${handlerName} );` + ); - block.builders.destroy.addLine(deindent` - ${generator.helper( - 'removeListener' - )}( ${state.parentNode}, '${name}', ${handlerName} ); - `); + block.builders.destroy.addLine( + `@removeListener( ${state.parentNode}, '${name}', ${handlerName} );` + ); } } diff --git a/src/generators/dom/visitors/Element/addTransitions.ts b/src/generators/dom/visitors/Element/addTransitions.ts index 358c6d7d6c..2a0a52b41e 100644 --- a/src/generators/dom/visitors/Element/addTransitions.ts +++ b/src/generators/dom/visitors/Element/addTransitions.ts @@ -12,8 +12,6 @@ export default function addTransitions( intro, outro ) { - const wrapTransition = generator.helper('wrapTransition'); - if (intro === outro) { const name = block.getUniqueName(`${state.name}_transition`); const snippet = intro.expression @@ -26,7 +24,7 @@ export default function addTransitions( block.builders.intro.addBlock(deindent` ${block.component}._renderHooks.push( function () { - if ( !${name} ) ${name} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, true, null ); + if ( !${name} ) ${name} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, true, null ); ${name}.run( true, function () { ${block.component}.fire( 'intro.end', { node: ${state.name} }); }); @@ -61,7 +59,7 @@ export default function addTransitions( block.builders.intro.addBlock(deindent` ${block.component}._renderHooks.push( function () { - ${introName} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, true, null ); + ${introName} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, true, null ); ${introName}.run( true, function () { ${block.component}.fire( 'intro.end', { node: ${state.name} }); }); @@ -80,7 +78,7 @@ export default function addTransitions( // TODO hide elements that have outro'd (unless they belong to a still-outroing // group) prior to their removal from the DOM block.builders.outro.addBlock(deindent` - ${outroName} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, false, null ); + ${outroName} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, false, null ); ${outroName}.run( false, function () { ${block.component}.fire( 'outro.end', { node: ${state.name} }); if ( --${block.alias('outros')} === 0 ) ${block.alias('outrocallback')}(); diff --git a/src/generators/dom/visitors/IfBlock.ts b/src/generators/dom/visitors/IfBlock.ts index fc2c54ca97..ace976952d 100644 --- a/src/generators/dom/visitors/IfBlock.ts +++ b/src/generators/dom/visitors/IfBlock.ts @@ -116,8 +116,8 @@ export default function visitIfBlock( if (node.needsAnchor) { block.addElement( anchor, - `${generator.helper('createComment')}()`, - `${generator.helper('createComment')}()`, + `@createComment()`, + `@createComment()`, state.parentNode, true ); diff --git a/src/generators/dom/visitors/MustacheTag.ts b/src/generators/dom/visitors/MustacheTag.ts index 7ab106a650..77f874db36 100644 --- a/src/generators/dom/visitors/MustacheTag.ts +++ b/src/generators/dom/visitors/MustacheTag.ts @@ -18,8 +18,8 @@ export default function visitMustacheTag( block.addVariable(value); block.addElement( name, - `${generator.helper('createText')}( ${value} = ${snippet} )`, - generator.hydratable ? `${generator.helper('claimText')}( ${state.parentNodes}, ${value} = ${snippet} )` : '', + `@createText( ${value} = ${snippet} )`, + generator.hydratable ? `@claimText( ${state.parentNodes}, ${value} = ${snippet} )` : '', state.parentNode, true ); diff --git a/src/generators/dom/visitors/RawMustacheTag.ts b/src/generators/dom/visitors/RawMustacheTag.ts index ff487302b3..41c3af9aa4 100644 --- a/src/generators/dom/visitors/RawMustacheTag.ts +++ b/src/generators/dom/visitors/RawMustacheTag.ts @@ -23,15 +23,15 @@ export default function visitRawMustacheTag( // exists for `Element`s. block.addElement( before, - `${generator.helper('createElement')}( 'noscript' )`, - `${generator.helper('createElement')}( 'noscript' )`, + `@createElement( 'noscript' )`, + `@createElement( 'noscript' )`, state.parentNode, true ); block.addElement( after, - `${generator.helper('createElement')}( 'noscript' )`, - `${generator.helper('createElement')}( 'noscript' )`, + `@createElement( 'noscript' )`, + `@createElement( 'noscript' )`, state.parentNode, true ); @@ -39,9 +39,7 @@ export default function visitRawMustacheTag( const isToplevel = !state.parentNode; const mountStatement = `${before}.insertAdjacentHTML( 'afterend', ${value} = ${snippet} );`; - const detachStatement = `${generator.helper( - 'detachBetween' - )}( ${before}, ${after} );`; + const detachStatement = `@detachBetween( ${before}, ${after} );`; block.builders.mount.addLine(mountStatement); diff --git a/src/generators/dom/visitors/Text.ts b/src/generators/dom/visitors/Text.ts index a14c25208c..7d4eaba770 100644 --- a/src/generators/dom/visitors/Text.ts +++ b/src/generators/dom/visitors/Text.ts @@ -12,8 +12,8 @@ export default function visitText( if (!node._state.shouldCreate) return; block.addElement( node._state.name, - `${generator.helper('createText')}( ${JSON.stringify(node.data)} )`, - generator.hydratable ? `${generator.helper('claimText')}( ${state.parentNodes}, ${JSON.stringify(node.data)} )` : '', + `@createText( ${JSON.stringify(node.data)} )`, + generator.hydratable ? `@claimText( ${state.parentNodes}, ${JSON.stringify(node.data)} )` : '', state.parentNode, node.usedAsAnchor ); diff --git a/src/shared/transitions.js b/src/shared/transitions.js index ded3a35b4d..df03646510 100644 --- a/src/shared/transitions.js +++ b/src/shared/transitions.js @@ -1,4 +1,5 @@ import { assign, noop } from './utils.js'; +import { createElement } from './dom.js'; export function linear(t) { return t; @@ -45,7 +46,7 @@ export function wrapTransition(node, fn, params, intro, outgroup) { // TODO share