From 8d69ebb8f4bc92b0090cb27950081ecdb4ab342d Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Fri, 30 Mar 2018 20:55:30 -0400 Subject: [PATCH] SSR spread elements --- src/generators/server-side-rendering/index.ts | 18 +++++ .../server-side-rendering/visitors/Element.ts | 65 ++++++++++++++----- src/utils/quoteIfNecessary.ts | 2 +- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/generators/server-side-rendering/index.ts b/src/generators/server-side-rendering/index.ts index c998cb894b..0bb88c7c68 100644 --- a/src/generators/server-side-rendering/index.ts +++ b/src/generators/server-side-rendering/index.ts @@ -236,6 +236,24 @@ export default function ssr( }; ` } + + ${ + /__spread/.test(generator.renderCode) && deindent` + function __spread(args) { + const attributes = Object.assign({}, ...args); + let str = ''; + + Object.keys(attributes).forEach(name => { + const value = attributes[name]; + if (value === undefined) return; + if (value === true) str += " " + name; + str += " " + name + "=" + JSON.stringify(value); + }); + + return str; + } + ` + } `.replace(/(@+|#+|%+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => { if (sigil === '@') return generator.alias(name); if (sigil === '%') return generator.templateVars.get(name); diff --git a/src/generators/server-side-rendering/visitors/Element.ts b/src/generators/server-side-rendering/visitors/Element.ts index 62c1fc8703..9fbb56165f 100644 --- a/src/generators/server-side-rendering/visitors/Element.ts +++ b/src/generators/server-side-rendering/visitors/Element.ts @@ -1,6 +1,7 @@ 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'; @@ -34,25 +35,53 @@ export default function visitElement( appendTarget.slots[slotName] = ''; } - node.attributes.forEach((attribute: Node) => { - if (attribute.type !== 'Attribute') return; + if (node.attributes.find(attr => attr.type === 'Spread')) { + const args = []; + node.attributes.forEach((attribute: Node) => { + if (attribute.type === 'Spread') { + block.contextualise(attribute.expression); + args.push(attribute.metadata.snippet); + } else if (attribute.type === 'Attribute') { + if (attribute.name === 'value' && node.name === 'textarea') { + textareaContents = stringifyAttributeValue(block, attribute.value); + } else if (attribute.value === true) { + args.push(`{ ${quoteIfNecessary(attribute.name)}: true }`); + } else if ( + booleanAttributes.has(attribute.name) && + attribute.value.length === 1 && + attribute.value[0].type !== 'Text' + ) { + // a boolean attribute with one non-Text chunk + block.contextualise(attribute.value[0].expression); + args.push(`{ ${quoteIfNecessary(attribute.name)}: ${attribute.value[0].metadata.snippet} }`); + } else { + args.push(`{ ${quoteIfNecessary(attribute.name)}: "${stringifyAttributeValue(block, attribute.value)}" }`); + } + } + }); + + 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.value); - } else if (attribute.value === true) { - openingTag += ` ${attribute.name}`; - } else if ( - booleanAttributes.has(attribute.name) && - attribute.value.length === 1 && - attribute.value[0].type !== 'Text' - ) { - // a boolean attribute with one non-Text chunk - block.contextualise(attribute.value[0].expression); - openingTag += '${' + attribute.value[0].metadata.snippet + ' ? " ' + attribute.name + '" : "" }'; - } else { - openingTag += ` ${attribute.name}="${stringifyAttributeValue(block, attribute.value)}"`; - } - }); + if (attribute.name === 'value' && node.name === 'textarea') { + textareaContents = stringifyAttributeValue(block, attribute.value); + } else if (attribute.value === true) { + openingTag += ` ${attribute.name}`; + } else if ( + booleanAttributes.has(attribute.name) && + attribute.value.length === 1 && + attribute.value[0].type !== 'Text' + ) { + // a boolean attribute with one non-Text chunk + block.contextualise(attribute.value[0].expression); + openingTag += '${' + attribute.value[0].metadata.snippet + ' ? " ' + attribute.name + '" : "" }'; + } else { + openingTag += ` ${attribute.name}="${stringifyAttributeValue(block, attribute.value)}"`; + } + }); + } if (node._cssRefAttribute) { openingTag += ` svelte-ref-${node._cssRefAttribute}`; diff --git a/src/utils/quoteIfNecessary.ts b/src/utils/quoteIfNecessary.ts index 206767f721..82a7901a7f 100644 --- a/src/utils/quoteIfNecessary.ts +++ b/src/utils/quoteIfNecessary.ts @@ -1,7 +1,7 @@ import isValidIdentifier from './isValidIdentifier'; import reservedNames from './reservedNames'; -export default function quoteIfNecessary(name, legacy) { +export default function quoteIfNecessary(name: string, legacy?: boolean) { if (!isValidIdentifier(name) || (legacy && reservedNames.has(name))) return `"${name}"`; return name; } \ No newline at end of file