Skip to content

Commit

Permalink
Merge pull request #512 from sveltejs/gh-3
Browse files Browse the repository at this point in the history
Anchor-less if and each blocks
  • Loading branch information
Rich-Harris authored Apr 25, 2017
2 parents 09b1635 + 4fe20fb commit b42ef49
Show file tree
Hide file tree
Showing 17 changed files with 464 additions and 128 deletions.
5 changes: 0 additions & 5 deletions src/generators/dom/Block.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,6 @@ export default class Block {
return this.generator.contextualise( this, expression, context, isEventHandler );
}

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

findDependencies ( expression ) {
return this.generator.findDependencies( this.contextDependencies, this.indexes, expression );
}
Expand Down
4 changes: 2 additions & 2 deletions src/generators/dom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ export default function dom ( parsed, source, options ) {

const { computations, hasJs, templateProperties, namespace } = generator.parseJs();

const block = preprocess( generator, parsed.html );

const state = {
namespace,
parentNode: null,
isTopLevel: true
};

const block = preprocess( generator, state, parsed.html );

parsed.html.children.forEach( node => {
visit( generator, block, state, node );
});
Expand Down
147 changes: 115 additions & 32 deletions src/generators/dom/preprocess.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,62 @@
import Block from './Block.js';
import { trimStart, trimEnd } from '../../utils/trim.js';
import { assign } from '../../shared/index.js';

function isElseIf ( node ) {
return node && node.children.length === 1 && node.children[0].type === 'IfBlock';
}

function getChildState ( parent, child ) {
return assign( {}, parent, { name: null, parentNode: null }, child || {} );
}

// Whitespace inside one of these elements will not result in
// a whitespace node being created in any circumstances. (This
// list is almost certainly very incomplete)
const elementsWithoutText = new Set([
'audio',
'datalist',
'dl',
'ol',
'optgroup',
'select',
'ul',
'video'
]);

const preprocessors = {
MustacheTag: ( generator, block, node ) => {
MustacheTag: ( generator, block, state, node ) => {
const dependencies = block.findDependencies( node.expression );
block.addDependencies( dependencies );

node._state = getChildState( state, {
name: block.getUniqueName( 'text' )
});
},

RawMustacheTag: ( generator, block, state, node ) => {
const dependencies = block.findDependencies( node.expression );
block.addDependencies( dependencies );

const basename = block.getUniqueName( 'raw' );
const name = block.getUniqueName( `${basename}_before` );

node._state = getChildState( state, { basename, name });
},

Text: ( generator, block, state, node ) => {
node._state = getChildState( state );

if ( !/\S/.test( node.data ) ) {
if ( state.namespace ) return;
if ( elementsWithoutText.has( state.parentNodeName ) ) return;
}

node._state.shouldCreate = true;
node._state.name = block.getUniqueName( `text` );
},

IfBlock: ( generator, block, node ) => {
IfBlock: ( generator, block, state, node ) => {
const blocks = [];
let dynamic = false;

Expand All @@ -23,8 +68,10 @@ const preprocessors = {
name: generator.getUniqueName( `create_if_block` )
});

node._state = getChildState( state );

blocks.push( node._block );
preprocessChildren( generator, node._block, node );
preprocessChildren( generator, node._block, node._state, node );

if ( node._block.dependencies.size > 0 ) {
dynamic = true;
Expand All @@ -38,8 +85,10 @@ const preprocessors = {
name: generator.getUniqueName( `create_if_block` )
});

node.else._state = getChildState( state );

blocks.push( node.else._block );
preprocessChildren( generator, node.else._block, node.else );
preprocessChildren( generator, node.else._block, node.else._state, node.else );

if ( node.else._block.dependencies.size > 0 ) {
dynamic = true;
Expand All @@ -57,7 +106,7 @@ const preprocessors = {
generator.blocks.push( ...blocks );
},

EachBlock: ( generator, block, node ) => {
EachBlock: ( generator, block, state, node ) => {
const dependencies = block.findDependencies( node.expression );
block.addDependencies( dependencies );

Expand Down Expand Up @@ -97,8 +146,12 @@ const preprocessors = {
params: block.params.concat( listName, context, indexName )
});

node._state = getChildState( state, {
inEachBlock: true
});

generator.blocks.push( node._block );
preprocessChildren( generator, node._block, node );
preprocessChildren( generator, node._block, node._state, node );
block.addDependencies( node._block.dependencies );
node._block.hasUpdateMethod = node._block.dependencies.size > 0;

Expand All @@ -107,13 +160,32 @@ const preprocessors = {
name: generator.getUniqueName( `${node._block.name}_else` )
});

node.else._state = getChildState( state );

generator.blocks.push( node.else._block );
preprocessChildren( generator, node.else._block, node.else );
preprocessChildren( generator, node.else._block, node.else._state, node.else );
node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0;
}
},

Element: ( generator, block, node ) => {
Element: ( generator, block, state, node ) => {
const isComponent = generator.components.has( node.name ) || node.name === ':Self';

if ( isComponent ) {
node._state = getChildState( state );
} else {
const name = block.getUniqueName( node.name.replace( /[^a-zA-Z0-9_$]/g, '_' ) );

node._state = getChildState( state, {
isTopLevel: false,
name,
parentNode: name,
parentNodeName: node.name,
namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace,
allUsedContexts: []
});
}

node.attributes.forEach( attribute => {
if ( attribute.type === 'Attribute' && attribute.value !== true ) {
attribute.value.forEach( chunk => {
Expand All @@ -130,8 +202,6 @@ const preprocessors = {
}
});

const isComponent = generator.components.has( node.name ) || node.name === ':Self';

if ( node.children.length ) {
if ( isComponent ) {
const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() );
Expand All @@ -141,21 +211,19 @@ const preprocessors = {
});

generator.blocks.push( node._block );
preprocessChildren( generator, node._block, node );
preprocessChildren( generator, node._block, node._state, node );
block.addDependencies( node._block.dependencies );
node._block.hasUpdateMethod = node._block.dependencies.size > 0;
}

else {
preprocessChildren( generator, block, node );
preprocessChildren( generator, block, node._state, node );
}
}
}
};

preprocessors.RawMustacheTag = preprocessors.MustacheTag;

function preprocessChildren ( generator, block, node ) {
function preprocessChildren ( generator, block, state, node, isTopLevel ) {
// glue text nodes together
const cleaned = [];
let lastChild;
Expand All @@ -173,15 +241,43 @@ function preprocessChildren ( generator, block, node ) {
lastChild = child;
});

node.children = cleaned;
if ( isTopLevel ) {
// trim leading and trailing whitespace from the top level
const firstChild = cleaned[0];
if ( firstChild && firstChild.type === 'Text' ) {
firstChild.data = trimStart( firstChild.data );
if ( !firstChild.data ) cleaned.shift();
}

const lastChild = cleaned[ cleaned.length - 1 ];
if ( lastChild && lastChild.type === 'Text' ) {
lastChild.data = trimEnd( lastChild.data );
if ( !lastChild.data ) cleaned.pop();
}
}

lastChild = null;

cleaned.forEach( child => {
const preprocess = preprocessors[ child.type ];
if ( preprocess ) preprocess( generator, block, child );
if ( preprocess ) preprocess( generator, block, state, child );

if ( lastChild ) {
lastChild.next = child;
lastChild.needsAnchor = !child._state.name;
}

lastChild = child;
});

if ( lastChild ) {
lastChild.needsAnchor = !state.parentNode;
}

node.children = cleaned;
}

export default function preprocess ( generator, node ) {
export default function preprocess ( generator, state, node ) {
const block = new Block({
generator,
name: generator.alias( 'create_main_fragment' ),
Expand All @@ -199,21 +295,8 @@ export default function preprocess ( generator, node ) {
});

generator.blocks.push( block );
preprocessChildren( generator, block, node );
preprocessChildren( generator, block, state, node, true );
block.hasUpdateMethod = block.dependencies.size > 0;

// trim leading and trailing whitespace from the top level
const firstChild = node.children[0];
if ( firstChild && firstChild.type === 'Text' ) {
firstChild.data = trimStart( firstChild.data );
if ( !firstChild.data ) node.children.shift();
}

const lastChild = node.children[ node.children.length - 1 ];
if ( lastChild && lastChild.type === 'Text' ) {
lastChild.data = trimEnd( lastChild.data );
if ( !lastChild.data ) node.children.pop();
}

return block;
}
4 changes: 1 addition & 3 deletions src/generators/dom/visitors/Component/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ export default function visitComponent ( generator, block, state, node ) {
const hasChildren = node.children.length > 0;
const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() );

const childState = Object.assign( {}, state, {
parentNode: null
});
const childState = node._state;

const local = {
name,
Expand Down
Loading

0 comments on commit b42ef49

Please sign in to comment.