mirror of https://github.com/sveltejs/svelte
parent
11d396f769
commit
b2b3bda85a
@ -1,13 +0,0 @@
|
||||
import visitors from './visitors/index';
|
||||
import { SsrGenerator } from './index';
|
||||
import Block from './Block';
|
||||
import { Node } from '../../interfaces';
|
||||
|
||||
export default function visit(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const visitor = visitors[node.type];
|
||||
visitor(generator, block, node);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitAwaitBlock(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const { snippet } = node.expression;
|
||||
|
||||
const childBlock = block.child({});
|
||||
|
||||
generator.append('${(function(__value) { if(__isPromise(__value)) return `');
|
||||
|
||||
node.pending.children.forEach((child: Node) => {
|
||||
visit(generator, childBlock, child);
|
||||
});
|
||||
|
||||
generator.append('`; return function(ctx) { return `');
|
||||
|
||||
node.then.children.forEach((child: Node) => {
|
||||
visit(generator, childBlock, child);
|
||||
});
|
||||
|
||||
generator.append(`\`;}(Object.assign({}, ctx, { ${node.value}: __value }));}(${snippet})) }`);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitComment(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
// Allow option to preserve comments, otherwise ignore
|
||||
if (generator && generator.options && generator.options.preserveComments) {
|
||||
generator.append(`<!--${node.data}-->`);
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
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 { escape, escapeTemplate, stringify } from '../../../utils/stringify';
|
||||
|
||||
export default function visitComponent(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
function stringifyAttribute(chunk: Node) {
|
||||
if (chunk.type === 'Text') {
|
||||
return escapeTemplate(escape(chunk.data));
|
||||
}
|
||||
|
||||
return '${__escape( ' + chunk.snippet + ')}';
|
||||
}
|
||||
|
||||
const bindingProps = node.bindings.map(binding => {
|
||||
const { name } = getObject(binding.value.node);
|
||||
const tail = binding.value.node.type === 'MemberExpression'
|
||||
? getTailSnippet(binding.value.node)
|
||||
: '';
|
||||
|
||||
return `${binding.name}: ctx.${name}${tail}`;
|
||||
});
|
||||
|
||||
function getAttributeValue(attribute) {
|
||||
if (attribute.isTrue) return `true`;
|
||||
if (attribute.chunks.length === 0) return `''`;
|
||||
|
||||
if (attribute.chunks.length === 1) {
|
||||
const chunk = attribute.chunks[0];
|
||||
if (chunk.type === 'Text') {
|
||||
return stringify(chunk.data);
|
||||
}
|
||||
|
||||
return chunk.snippet;
|
||||
}
|
||||
|
||||
return '`' + attribute.chunks.map(stringifyAttribute).join('') + '`';
|
||||
}
|
||||
|
||||
const usesSpread = node.attributes.find(attr => attr.isSpread);
|
||||
|
||||
const props = usesSpread
|
||||
? `Object.assign(${
|
||||
node.attributes
|
||||
.map(attribute => {
|
||||
if (attribute.isSpread) {
|
||||
return attribute.expression.snippet;
|
||||
} else {
|
||||
return `{ ${attribute.name}: ${getAttributeValue(attribute)} }`;
|
||||
}
|
||||
})
|
||||
.concat(bindingProps.map(p => `{ ${p} }`))
|
||||
.join(', ')
|
||||
})`
|
||||
: `{ ${node.attributes
|
||||
.map(attribute => `${attribute.name}: ${getAttributeValue(attribute)}`)
|
||||
.concat(bindingProps)
|
||||
.join(', ')} }`;
|
||||
|
||||
const isDynamicComponent = node.name === 'svelte:component';
|
||||
|
||||
const expression = (
|
||||
node.name === 'svelte:self' ? generator.name :
|
||||
isDynamicComponent ? `((${node.expression.snippet}) || __missingComponent)` :
|
||||
`%components-${node.name}`
|
||||
);
|
||||
|
||||
node.bindings.forEach(binding => {
|
||||
block.addBinding(binding, expression);
|
||||
});
|
||||
|
||||
let open = `\${${expression}._render(__result, ${props}`;
|
||||
|
||||
const options = [];
|
||||
options.push(`store: options.store`);
|
||||
|
||||
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(', ');
|
||||
|
||||
options.push(`slotted: { ${slotted} }`);
|
||||
|
||||
generator.appendTargets.pop();
|
||||
}
|
||||
|
||||
if (options.length) {
|
||||
open += `, { ${options.join(', ')} }`;
|
||||
}
|
||||
|
||||
generator.append(open);
|
||||
generator.append(')}');
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitEachBlock(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const { snippet } = node.expression;
|
||||
|
||||
const props = [`${node.context}: item`]
|
||||
.concat(node.destructuredContexts.map((name, i) => `${name}: item[${i}]`));
|
||||
|
||||
const getContext = node.index
|
||||
? `(item, i) => Object.assign({}, ctx, { ${props.join(', ')}, ${node.index}: i })`
|
||||
: `item => Object.assign({}, ctx, { ${props.join(', ')} })`;
|
||||
|
||||
const open = `\${ ${node.else ? `${snippet}.length ? ` : ''}__each(${snippet}, ${getContext}, ctx => \``;
|
||||
generator.append(open);
|
||||
|
||||
const childBlock = block.child({});
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, childBlock, child);
|
||||
});
|
||||
|
||||
const close = `\`)`;
|
||||
generator.append(close);
|
||||
|
||||
if (node.else) {
|
||||
generator.append(` : \``);
|
||||
node.else.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
generator.append(`\``);
|
||||
}
|
||||
|
||||
generator.append('}');
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
import visitComponent from './Component';
|
||||
import visitSlot from './Slot';
|
||||
import isVoidElementName from '../../../utils/isVoidElementName';
|
||||
import quoteIfNecessary from '../../../utils/quoteIfNecessary';
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Element from '../../nodes/Element';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
import stringifyAttributeValue from './shared/stringifyAttributeValue';
|
||||
import { escape } from '../../../utils/stringify';
|
||||
|
||||
// source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7
|
||||
const booleanAttributes = new Set('async autocomplete autofocus autoplay border challenge checked compact contenteditable controls default defer disabled formnovalidate frameborder hidden indeterminate ismap loop multiple muted nohref noresize noshade novalidate nowrap open readonly required reversed scoped scrolling seamless selected sortable spellcheck translate'.split(' '));
|
||||
|
||||
export default function visitElement(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Element
|
||||
) {
|
||||
if (node.name === 'slot') {
|
||||
visitSlot(generator, block, node);
|
||||
return;
|
||||
}
|
||||
|
||||
let openingTag = `<${node.name}`;
|
||||
let textareaContents; // awkward special case
|
||||
|
||||
const slot = node.getStaticAttributeValue('slot');
|
||||
if (slot && node.hasAncestor('Component')) {
|
||||
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot');
|
||||
const slotName = slot.chunks[0].data;
|
||||
const appendTarget = generator.appendTargets[generator.appendTargets.length - 1];
|
||||
appendTarget.slotStack.push(slotName);
|
||||
appendTarget.slots[slotName] = '';
|
||||
}
|
||||
|
||||
if (node.attributes.find(attr => attr.isSpread)) {
|
||||
// TODO dry this out
|
||||
const args = [];
|
||||
node.attributes.forEach(attribute => {
|
||||
if (attribute.isSpread) {
|
||||
args.push(attribute.expression.snippet);
|
||||
} else {
|
||||
if (attribute.name === 'value' && node.name === 'textarea') {
|
||||
textareaContents = stringifyAttributeValue(block, attribute.chunks);
|
||||
} else if (attribute.isTrue) {
|
||||
args.push(`{ ${quoteIfNecessary(attribute.name)}: true }`);
|
||||
} else if (
|
||||
booleanAttributes.has(attribute.name) &&
|
||||
attribute.chunks.length === 1 &&
|
||||
attribute.chunks[0].type !== 'Text'
|
||||
) {
|
||||
// a boolean attribute with one non-Text chunk
|
||||
args.push(`{ ${quoteIfNecessary(attribute.name)}: ${attribute.chunks[0].snippet} }`);
|
||||
} else {
|
||||
args.push(`{ ${quoteIfNecessary(attribute.name)}: \`${stringifyAttributeValue(block, attribute.chunks)}\` }`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openingTag += "${__spread([" + args.join(', ') + "])}";
|
||||
} else {
|
||||
node.attributes.forEach((attribute: Node) => {
|
||||
if (attribute.type !== 'Attribute') return;
|
||||
|
||||
if (attribute.name === 'value' && node.name === 'textarea') {
|
||||
textareaContents = stringifyAttributeValue(block, attribute.chunks);
|
||||
} else if (attribute.isTrue) {
|
||||
openingTag += ` ${attribute.name}`;
|
||||
} else if (
|
||||
booleanAttributes.has(attribute.name) &&
|
||||
attribute.chunks.length === 1 &&
|
||||
attribute.chunks[0].type !== 'Text'
|
||||
) {
|
||||
// a boolean attribute with one non-Text chunk
|
||||
openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }';
|
||||
} else {
|
||||
openingTag += ` ${attribute.name}="${stringifyAttributeValue(block, attribute.chunks)}"`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (node._cssRefAttribute) {
|
||||
openingTag += ` svelte-ref-${node._cssRefAttribute}`;
|
||||
}
|
||||
|
||||
openingTag += '>';
|
||||
|
||||
generator.append(openingTag);
|
||||
|
||||
if (node.name === 'textarea' && textareaContents !== undefined) {
|
||||
generator.append(textareaContents);
|
||||
} else {
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
}
|
||||
|
||||
if (!isVoidElementName(node.name)) {
|
||||
generator.append(`</${node.name}>`);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
import stringifyAttributeValue from './shared/stringifyAttributeValue';
|
||||
import visit from '../visit';
|
||||
|
||||
export default function visitDocument(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
generator.append('${(__result.head += `');
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
|
||||
generator.append('`, "")}');
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitIfBlock(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const { snippet } = node.expression;
|
||||
|
||||
generator.append('${ ' + snippet + ' ? `');
|
||||
|
||||
const childBlock = block.child({
|
||||
conditions: block.conditions.concat(snippet),
|
||||
});
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, childBlock, child);
|
||||
});
|
||||
|
||||
generator.append('` : `');
|
||||
|
||||
if (node.else) {
|
||||
node.else.children.forEach((child: Node) => {
|
||||
visit(generator, childBlock, child);
|
||||
});
|
||||
}
|
||||
|
||||
generator.append('` }');
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitMustacheTag(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const { snippet } = node.expression;
|
||||
|
||||
generator.append(
|
||||
node.parent &&
|
||||
node.parent.type === 'Element' &&
|
||||
node.parent.name === 'style'
|
||||
? '${' + snippet + '}'
|
||||
: '${__escape(' + snippet + ')}'
|
||||
);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitRawMustacheTag(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const { snippet } = node.expression;
|
||||
|
||||
generator.append('${' + snippet + '}');
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import visit from '../visit';
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitSlot(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
const name = node.attributes.find((attribute: Node) => attribute.name);
|
||||
const slotName = name && name.chunks[0].data || 'default';
|
||||
|
||||
generator.append(`\${options && options.slotted && options.slotted.${slotName} ? options.slotted.${slotName}() : \``);
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
|
||||
generator.append(`\`}`);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { escape, escapeHTML, escapeTemplate } from '../../../utils/stringify';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitText(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
let text = node.data;
|
||||
if (
|
||||
!node.parent ||
|
||||
node.parent.type !== 'Element' ||
|
||||
(node.parent.name !== 'script' && node.parent.name !== 'style')
|
||||
) {
|
||||
// unless this Text node is inside a <script> or <style> element, escape &,<,>
|
||||
text = escapeHTML(text);
|
||||
}
|
||||
generator.append(escape(escapeTemplate(text)));
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { SsrGenerator } from '../index';
|
||||
import Block from '../Block';
|
||||
import { escape } from '../../../utils/stringify';
|
||||
import visit from '../visit';
|
||||
import { Node } from '../../../interfaces';
|
||||
|
||||
export default function visitTitle(
|
||||
generator: SsrGenerator,
|
||||
block: Block,
|
||||
node: Node
|
||||
) {
|
||||
generator.append(`<title>`);
|
||||
|
||||
node.children.forEach((child: Node) => {
|
||||
visit(generator, block, child);
|
||||
});
|
||||
|
||||
generator.append(`</title>`);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export default function visitWindow() {
|
||||
// noop
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import AwaitBlock from './AwaitBlock';
|
||||
import Comment from './Comment';
|
||||
import Component from './Component';
|
||||
import EachBlock from './EachBlock';
|
||||
import Element from './Element';
|
||||
import Head from './Head';
|
||||
import IfBlock from './IfBlock';
|
||||
import MustacheTag from './MustacheTag';
|
||||
import RawMustacheTag from './RawMustacheTag';
|
||||
import Slot from './Slot';
|
||||
import Text from './Text';
|
||||
import Title from './Title';
|
||||
import Window from './Window';
|
||||
|
||||
export default {
|
||||
AwaitBlock,
|
||||
Comment,
|
||||
Component,
|
||||
EachBlock,
|
||||
Element,
|
||||
Head,
|
||||
IfBlock,
|
||||
MustacheTag,
|
||||
RawMustacheTag,
|
||||
Slot,
|
||||
Text,
|
||||
Title,
|
||||
Window
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
import Block from '../../Block';
|
||||
import { escape, escapeTemplate } from '../../../../utils/stringify';
|
||||
import { Node } from '../../../../interfaces';
|
||||
|
||||
export default function stringifyAttributeValue(block: Block, chunks: Node[]) {
|
||||
return chunks
|
||||
.map((chunk: Node) => {
|
||||
if (chunk.type === 'Text') {
|
||||
return escapeTemplate(escape(chunk.data).replace(/"/g, '"'));
|
||||
}
|
||||
|
||||
return '${__escape(' + chunk.snippet + ')}';
|
||||
})
|
||||
.join('');
|
||||
}
|
Loading…
Reference in new issue