import Wrapper from './shared/Wrapper';
import AwaitBlock from './AwaitBlock';
import Body from './Body';
import DebugTag from './DebugTag';
import EachBlock from './EachBlock';
import Element from './Element';
import Head from './Head';
import IfBlock from './IfBlock';
import InlineComponent from './InlineComponent';
import MustacheTag from './MustacheTag';
import RawMustacheTag from './RawMustacheTag';
import Slot from './Slot';
import Text from './Text';
import Title from './Title';
import Window from './Window';
import Node from '../../nodes/shared/Node';
import { trimStart, trimEnd } from '../../../utils/trim';
import TextWrapper from './Text';
import Renderer from '../Renderer';
import Block from '../Block';
const wrappers = {
AwaitBlock,
Body,
Comment: null,
DebugTag,
EachBlock,
Element,
Head,
IfBlock,
InlineComponent,
Meta: null,
MustacheTag,
RawMustacheTag,
Slot,
Text,
Title,
Window
};
function link(next: Wrapper, prev: Wrapper) {
prev.next = next;
if (next) next.prev = prev;
}
export default class FragmentWrapper {
nodes: Wrapper[];
constructor(
renderer: Renderer,
block: Block,
nodes: Node[],
parent: Wrapper,
stripWhitespace: boolean,
nextSibling: Wrapper
) {
this.nodes = [];
let lastChild: Wrapper;
let windowWrapper;
let i = nodes.length;
while (i--) {
const child = nodes[i];
if (!(child.type in wrappers)) {
throw new Error(`TODO implement ${child.type}`);
}
// special case — this is an easy way to remove whitespace surrounding
// . lil hacky but it works
if (child.type === 'Window') {
windowWrapper = new Window(renderer, block, parent, child);
continue;
}
if (child.type === 'Text') {
let { data } = child;
// We want to remove trailing whitespace inside an element/component/block,
// *unless* there is no whitespace between this node and its next sibling
if (this.nodes.length === 0) {
const shouldTrim = (
nextSibling ? (nextSibling.node.type === 'Text' && /^\s/.test(nextSibling.data)) : !child.hasAncestor('EachBlock')
);
if (shouldTrim) {
data = trimEnd(data);
if (!data) continue;
}
}
// glue text nodes (which could e.g. be separated by comments) together
if (lastChild && lastChild.node.type === 'Text') {
lastChild.data = data + lastChild.data;
continue;
}
const wrapper = new TextWrapper(renderer, block, parent, child, data);
if (wrapper.skip) continue;
this.nodes.unshift(wrapper);
link(lastChild, lastChild = wrapper);
} else {
const Wrapper = wrappers[child.type];
if (!Wrapper) continue;
const wrapper = new Wrapper(renderer, block, parent, child, stripWhitespace, lastChild || nextSibling);
this.nodes.unshift(wrapper);
link(lastChild, lastChild = wrapper);
}
}
if (stripWhitespace) {
const first = this.nodes[0];
if (first && first.node.type === 'Text') {
first.data = trimStart(first.data);
if (!first.data) {
first.var = null;
this.nodes.shift();
if (this.nodes[0]) {
this.nodes[0].prev = null;
}
}
}
}
if (windowWrapper) {
this.nodes.unshift(windowWrapper);
link(lastChild, windowWrapper);
}
}
render(block: Block, parentNode: string, parentNodes: string) {
for (let i = 0; i < this.nodes.length; i += 1) {
this.nodes[i].render(block, parentNode, parentNodes);
}
}
}