mirror of https://github.com/sveltejs/svelte
104 lines
2.7 KiB
104 lines
2.7 KiB
import flattenReference from '../../../utils/flattenReference';
|
|
import visit from '../visit';
|
|
import { SsrGenerator } from '../index';
|
|
import Block from '../Block';
|
|
import { AppendTarget } from '../interfaces';
|
|
import { Node } from '../../../interfaces';
|
|
import getObject from '../../../utils/getObject';
|
|
import getTailSnippet from '../../../utils/getTailSnippet';
|
|
import { stringify } from '../../../utils/stringify';
|
|
|
|
export default function visitComponent(
|
|
generator: SsrGenerator,
|
|
block: Block,
|
|
node: Node
|
|
) {
|
|
function stringifyAttribute(chunk: Node) {
|
|
if (chunk.type === 'Text') return chunk.data;
|
|
if (chunk.type === 'MustacheTag') {
|
|
const { snippet } = block.contextualise(chunk.expression);
|
|
return '${__escape( ' + snippet + ')}';
|
|
}
|
|
}
|
|
|
|
const attributes: Node[] = [];
|
|
const bindings: Node[] = [];
|
|
|
|
node.attributes.forEach((attribute: Node) => {
|
|
if (attribute.type === 'Attribute') {
|
|
attributes.push(attribute);
|
|
} else if (attribute.type === 'Binding') {
|
|
bindings.push(attribute);
|
|
}
|
|
});
|
|
|
|
const props = attributes
|
|
.map(attribute => {
|
|
let value;
|
|
|
|
if (attribute.value === true) {
|
|
value = `true`;
|
|
} else if (attribute.value.length === 0) {
|
|
value = `''`;
|
|
} else if (attribute.value.length === 1) {
|
|
const chunk = attribute.value[0];
|
|
if (chunk.type === 'Text') {
|
|
value = isNaN(chunk.data) ? stringify(chunk.data) : chunk.data;
|
|
} else {
|
|
const { snippet } = block.contextualise(chunk.expression);
|
|
value = snippet;
|
|
}
|
|
} else {
|
|
value = '`' + attribute.value.map(stringifyAttribute).join('') + '`';
|
|
}
|
|
|
|
return `${attribute.name}: ${value}`;
|
|
})
|
|
.concat(
|
|
bindings.map(binding => {
|
|
const { name } = getObject(binding.value);
|
|
const tail = binding.value.type === 'MemberExpression'
|
|
? getTailSnippet(binding.value)
|
|
: '';
|
|
|
|
const keypath = block.contexts.has(name)
|
|
? `${name}${tail}`
|
|
: `state.${name}${tail}`;
|
|
return `${binding.name}: ${keypath}`;
|
|
})
|
|
)
|
|
.join(', ');
|
|
|
|
const expression = node.name === ':Self' ? generator.name : `%components-${node.name}`;
|
|
|
|
bindings.forEach(binding => {
|
|
block.addBinding(binding, expression);
|
|
});
|
|
|
|
let open = `\${${expression}.render({${props}}`;
|
|
|
|
if (node.children.length) {
|
|
const appendTarget: AppendTarget = {
|
|
slots: { default: '' },
|
|
slotStack: ['default']
|
|
};
|
|
|
|
generator.appendTargets.push(appendTarget);
|
|
|
|
node.children.forEach((child: Node) => {
|
|
visit(generator, block, child);
|
|
});
|
|
|
|
const slotted = Object.keys(appendTarget.slots)
|
|
.map(name => `${name}: () => \`${appendTarget.slots[name]}\``)
|
|
.join(', ');
|
|
|
|
open += `, { slotted: { ${slotted} } }`;
|
|
|
|
generator.appendTargets.pop();
|
|
}
|
|
|
|
generator.append(open);
|
|
generator.append(')}');
|
|
}
|