mirror of https://github.com/sveltejs/svelte
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
7.8 KiB
288 lines
7.8 KiB
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, 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, state, node ) => {
|
|
const blocks = [];
|
|
let dynamic = false;
|
|
|
|
function attachBlocks ( node ) {
|
|
const dependencies = block.findDependencies( node.expression );
|
|
block.addDependencies( dependencies );
|
|
|
|
node._block = block.child({
|
|
name: generator.getUniqueName( `create_if_block` )
|
|
});
|
|
|
|
node._state = getChildState( state );
|
|
|
|
blocks.push( node._block );
|
|
preprocessChildren( generator, node._block, node._state, node );
|
|
|
|
if ( node._block.dependencies.size > 0 ) {
|
|
dynamic = true;
|
|
block.addDependencies( node._block.dependencies );
|
|
}
|
|
|
|
if ( isElseIf( node.else ) ) {
|
|
attachBlocks( node.else.children[0] );
|
|
} else if ( node.else ) {
|
|
node.else._block = block.child({
|
|
name: generator.getUniqueName( `create_if_block` )
|
|
});
|
|
|
|
node.else._state = getChildState( state );
|
|
|
|
blocks.push( node.else._block );
|
|
preprocessChildren( generator, node.else._block, node.else._state, node.else );
|
|
|
|
if ( node.else._block.dependencies.size > 0 ) {
|
|
dynamic = true;
|
|
block.addDependencies( node.else._block.dependencies );
|
|
}
|
|
}
|
|
}
|
|
|
|
attachBlocks( node );
|
|
|
|
blocks.forEach( block => {
|
|
block.hasUpdateMethod = dynamic;
|
|
});
|
|
|
|
generator.blocks.push( ...blocks );
|
|
},
|
|
|
|
EachBlock: ( generator, block, state, node ) => {
|
|
const dependencies = block.findDependencies( node.expression );
|
|
block.addDependencies( dependencies );
|
|
|
|
const indexNames = new Map( block.indexNames );
|
|
const indexName = node.index || block.getUniqueName( `${node.context}_index` );
|
|
indexNames.set( node.context, indexName );
|
|
|
|
const listNames = new Map( block.listNames );
|
|
const listName = block.getUniqueName( `each_block_value` );
|
|
listNames.set( node.context, listName );
|
|
|
|
const context = generator.getUniqueName( node.context );
|
|
const contexts = new Map( block.contexts );
|
|
contexts.set( node.context, context );
|
|
|
|
const indexes = new Map( block.indexes );
|
|
if ( node.index ) indexes.set( indexName, node.context );
|
|
|
|
const contextDependencies = new Map( block.contextDependencies );
|
|
contextDependencies.set( node.context, dependencies );
|
|
|
|
node._block = block.child({
|
|
name: generator.getUniqueName( 'create_each_block' ),
|
|
expression: node.expression,
|
|
context: node.context,
|
|
key: node.key,
|
|
|
|
contextDependencies,
|
|
contexts,
|
|
indexes,
|
|
|
|
listName,
|
|
indexName,
|
|
|
|
indexNames,
|
|
listNames,
|
|
params: block.params.concat( listName, context, indexName )
|
|
});
|
|
|
|
node._state = getChildState( state, {
|
|
inEachBlock: true
|
|
});
|
|
|
|
generator.blocks.push( node._block );
|
|
preprocessChildren( generator, node._block, node._state, node );
|
|
block.addDependencies( node._block.dependencies );
|
|
node._block.hasUpdateMethod = node._block.dependencies.size > 0;
|
|
|
|
if ( node.else ) {
|
|
node.else._block = block.child({
|
|
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._state, node.else );
|
|
node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0;
|
|
}
|
|
},
|
|
|
|
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 );
|
|
|
|
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 => {
|
|
if ( chunk.type !== 'Text' ) {
|
|
const dependencies = block.findDependencies( chunk.expression );
|
|
block.addDependencies( dependencies );
|
|
}
|
|
});
|
|
}
|
|
|
|
else if ( attribute.type === 'Binding' ) {
|
|
const dependencies = block.findDependencies( attribute.value );
|
|
block.addDependencies( dependencies );
|
|
}
|
|
});
|
|
|
|
if ( node.children.length ) {
|
|
if ( isComponent ) {
|
|
const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() );
|
|
|
|
node._block = block.child({
|
|
name: generator.getUniqueName( `create_${name}_yield_fragment` )
|
|
});
|
|
|
|
generator.blocks.push( node._block );
|
|
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._state, node );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function preprocessChildren ( generator, block, state, node ) {
|
|
// glue text nodes together
|
|
const cleaned = [];
|
|
let lastChild;
|
|
|
|
node.children.forEach( child => {
|
|
if ( child.type === 'Comment' ) return;
|
|
|
|
if ( child.type === 'Text' && lastChild && lastChild.type === 'Text' ) {
|
|
lastChild.data += child.data;
|
|
lastChild.end = child.end;
|
|
} else {
|
|
cleaned.push( child );
|
|
}
|
|
|
|
if ( lastChild ) lastChild.next = child;
|
|
lastChild = child;
|
|
});
|
|
|
|
node.children = cleaned;
|
|
|
|
cleaned.forEach( child => {
|
|
const preprocess = preprocessors[ child.type ];
|
|
if ( preprocess ) preprocess( generator, block, state, child );
|
|
});
|
|
}
|
|
|
|
export default function preprocess ( generator, state, node ) {
|
|
const block = new Block({
|
|
generator,
|
|
name: generator.alias( 'create_main_fragment' ),
|
|
key: null,
|
|
|
|
contexts: new Map(),
|
|
indexes: new Map(),
|
|
contextDependencies: new Map(),
|
|
|
|
params: [ 'state' ],
|
|
indexNames: new Map(),
|
|
listNames: new Map(),
|
|
|
|
dependencies: new Set()
|
|
});
|
|
|
|
generator.blocks.push( block );
|
|
preprocessChildren( generator, block, state, node );
|
|
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;
|
|
} |