import Block from './Block'; import { trimStart, trimEnd } from '../../utils/trim'; import { assign } from '../../shared/index.js'; import getStaticAttributeValue from '../../utils/getStaticAttributeValue'; import { DomGenerator } from './index'; import { Node } from '../../interfaces'; import { State } from './interfaces'; function isElseIf(node: Node) { return ( node && node.children.length === 1 && node.children[0].type === 'IfBlock' ); } function getChildState(parent: State, child = {}) { return assign( {}, parent, { parentNode: null, parentNodes: 'nodes' }, 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: DomGenerator, block: Block, state: State, node: Node, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean ) => { node.var = block.getUniqueName('text'); const dependencies = block.findDependencies(node.expression); block.addDependencies(dependencies); }, RawMustacheTag: ( generator: DomGenerator, block: Block, state: State, node: Node, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean ) => { node.var = block.getUniqueName('raw'); const dependencies = block.findDependencies(node.expression); block.addDependencies(dependencies); }, Text: ( generator: DomGenerator, block: Block, state: State, node: Node, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean ) => { if (!/\S/.test(node.data) && (state.namespace || elementsWithoutText.has(state.parentNodeName))) { node.shouldSkip = true; return; } node.var = block.getUniqueName(`text`); }, IfBlock: ( generator: DomGenerator, block: Block, state: State, node: Node, inEachBlock: boolean, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean, nextSibling: Node ) => { const blocks: Block[] = []; let dynamic = false; let hasIntros = false; let hasOutros = false; function attachBlocks(node: Node) { node.var = block.getUniqueName(`if_block`); 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, inEachBlock, elementStack, componentStack, stripWhitespace, nextSibling); if (node._block.dependencies.size > 0) { dynamic = true; block.addDependencies(node._block.dependencies); } if (node._block.hasIntroMethod) hasIntros = true; if (node._block.hasOutroMethod) hasOutros = true; 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, inEachBlock, elementStack, componentStack, stripWhitespace, nextSibling ); if (node.else._block.dependencies.size > 0) { dynamic = true; block.addDependencies(node.else._block.dependencies); } } } attachBlocks(node); blocks.forEach(block => { block.hasUpdateMethod = dynamic; block.hasIntroMethod = hasIntros; block.hasOutroMethod = hasOutros; }); generator.blocks.push(...blocks); }, EachBlock: ( generator: DomGenerator, block: Block, state: State, node: Node, inEachBlock: boolean, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean, nextSibling: Node ) => { node.var = block.getUniqueName(`each_block`); 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(node.index, node.context); const changeableIndexes = new Map(block.changeableIndexes); if (node.index) changeableIndexes.set(node.index, node.key); 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, changeableIndexes, 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, true, elementStack, componentStack, stripWhitespace, nextSibling); 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, inEachBlock, elementStack, componentStack, stripWhitespace, nextSibling ); node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0; } }, Element: ( generator: DomGenerator, block: Block, state: State, node: Node, inEachBlock: boolean, elementStack: Node[], componentStack: Node[], stripWhitespace: boolean, nextSibling: Node ) => { node.attributes.forEach((attribute: Node) => { if (attribute.type === 'Attribute' && attribute.value !== true) { attribute.value.forEach((chunk: Node) => { if (chunk.type !== 'Text') { const dependencies = block.findDependencies(chunk.expression); block.addDependencies(dependencies); // special case —