pull/3539/head
Richard Harris 6 years ago
parent c4b8af9b21
commit 6e00b68015

@ -1,7 +1,7 @@
import { is_void, quote_prop_if_necessary } from '../../../utils/names';
import Attribute from '../../nodes/Attribute';
import Class from '../../nodes/Class';
import { stringify_attribute, stringify_class_attribute } from '../../utils/stringify_attribute';
import { get_attribute_value, get_class_attribute_value } from './shared/get_attribute_value';
import { get_slot_scope } from './shared/get_slot_scope';
import Renderer, { RenderOptions } from '../Renderer';
import Element from '../../nodes/Element';
@ -99,7 +99,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
args.push(attribute.expression.node);
} else {
if (attribute.name === 'value' && node.name === 'textarea') {
node_contents = stringify_attribute(attribute, true);
node_contents = get_attribute_value(attribute);
} else if (attribute.is_true) {
args.push(x`{ ${attribute.name}: true }`);
} else if (
@ -111,9 +111,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
args.push(x`{ ${attribute.name}: ${attribute.chunks[0].node} }`);
} else if (attribute.name === 'class' && class_expression) {
// Add class expression
args.push(x`{ ${attribute.name}: [${stringify_class_attribute(attribute)}, ${class_expression}}].join(' ').trim() }`);
args.push(x`{ ${attribute.name}: [${get_class_attribute_value(attribute)}, ${class_expression}}].join(' ').trim() }`);
} else {
args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? stringify_class_attribute(attribute) : stringify_attribute(attribute, true)} }`);
args.push(x`{ ${attribute.name}: ${attribute.name === 'class' ? get_class_attribute_value(attribute) : get_attribute_value(attribute, true)} }`);
}
}
});
@ -124,7 +124,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
if (attribute.type !== 'Attribute') return;
if (attribute.name === 'value' && node.name === 'textarea') {
node_contents = stringify_attribute(attribute, true);
node_contents = get_attribute_value(attribute);
} else if (attribute.is_true) {
renderer.add_string(` ${attribute.name}`);
} else if (
@ -133,12 +133,12 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
attribute.chunks[0].type !== 'Text'
) {
// a boolean attribute with one non-Text chunk
throw new Error('here');
renderer.add_expression(x`${attribute.chunks[0]} ? "${attribute.name}" : ""`);
renderer.add_string(` `);
renderer.add_expression(x`${attribute.chunks[0].node} ? "${attribute.name}" : ""`);
} else if (attribute.name === 'class' && class_expression) {
add_class_attribute = false;
renderer.add_string(` class="`);
renderer.add_expression(x`[${stringify_class_attribute(attribute)}, ${class_expression}].join(' ').trim()`);
renderer.add_expression(x`[${get_class_attribute_value(attribute)}, ${class_expression}].join(' ').trim()`);
renderer.add_string(`"`);
} else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') {
const { name } = attribute;
@ -146,10 +146,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`);
} else {
renderer.add_string(` ${attribute.name}="`);
attribute.chunks.forEach(chunk => {
if (chunk.type === 'Text') renderer.add_string(chunk.data);
else renderer.add_expression(x`@escape(${chunk.node})`);
});
renderer.add_expression(attribute.name === 'class' ? get_class_attribute_value(attribute) : get_attribute_value(attribute));
renderer.add_string(`"`);
}
});

@ -6,18 +6,7 @@ import InlineComponent from '../../nodes/InlineComponent';
import { INode } from '../../nodes/interfaces';
import { p, x } from 'code-red';
function stringify_attribute(chunk: INode) {
if (chunk.type === 'Text') {
return string_literal(chunk.data);
// return escape_template(escape((chunk as Text).data));
}
return x`@escape(${chunk})`;
return '${@escape(' + snip(chunk) + ')}';
}
function get_attribute_value(attribute) {
function get_prop_value(attribute) {
if (attribute.is_true) return x`true`;
if (attribute.chunks.length === 0) return x`''`;
@ -54,7 +43,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
if (attribute.is_spread) {
return snip(attribute.expression);
} else {
return `{ ${quote_name_if_necessary(attribute.name)}: ${get_attribute_value(attribute)} }`;
return `{ ${quote_name_if_necessary(attribute.name)}: ${get_prop_value(attribute)} }`;
}
})
.concat(binding_props.map(p => `{ ${p} }`))
@ -62,7 +51,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
})`;
} else {
props = x`{
${node.attributes.map(attribute => p`${attribute.name}: ${get_attribute_value(attribute)}`)},
${node.attributes.map(attribute => p`${attribute.name}: ${get_prop_value(attribute)}`)},
${binding_props}
}`;
}

@ -0,0 +1,28 @@
import Attribute from '../../../nodes/Attribute';
import { string_literal } from '../../../utils/stringify';
import Text from '../../../nodes/Text';
import { x } from 'code-red';
import Expression from '../../../nodes/shared/Expression';
import { Expression as ESTreeExpression } from 'estree';
export function get_class_attribute_value(attribute: Attribute): ESTreeExpression {
// handle special case — `class={possiblyUndefined}` with scoped CSS
if (attribute.chunks.length === 2 && (attribute.chunks[1] as Text).synthetic) {
const value = (attribute.chunks[0] as Expression).node;
return x`@escape(@null_to_empty(${value})) + "${(attribute.chunks[1] as Text).data}"`;
}
return get_attribute_value(attribute);
}
export function get_attribute_value(attribute: Attribute): ESTreeExpression {
if (attribute.chunks.length === 0) return x`""`;
return attribute.chunks
.map((chunk) => {
return chunk.type === 'Text'
? string_literal(chunk.data.replace(/"/g, '"')) as ESTreeExpression
: x`@escape(${chunk.node})`;
})
.reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
}

@ -1,28 +0,0 @@
import Attribute from '../nodes/Attribute';
import { string_literal } from './stringify';
import { snip } from './snip';
import Text from '../nodes/Text';
import { x } from 'code-red';
export function stringify_class_attribute(attribute: Attribute) {
// handle special case — `class={possiblyUndefined}` with scoped CSS
if (attribute.chunks.length === 2 && (attribute.chunks[1] as Text).synthetic) {
return '${@escape(@null_to_empty(' + snip(attribute.chunks[0]) + '))}' + (attribute.chunks[1] as Text).data;
}
return stringify_attribute(attribute, true);
}
export function stringify_attribute(attribute: Attribute, is_ssr: boolean) {
return attribute.chunks
.map((chunk) => {
if (chunk.type === 'Text') {
return string_literal(chunk.data.replace(/"/g, '"'));
}
return is_ssr
? x`@escape(${chunk.node})`
: chunk.node;
})
.reduce((lhs, rhs) => x`${lhs} + ${rhs}`);
}

@ -81,9 +81,6 @@ describe.only("ssr", () => {
});
});
// TODO re-enable SSR tests
return;
// duplicate client-side tests, as far as possible
fs.readdirSync("test/runtime/samples").forEach(dir => {
if (dir[0] === ".") return;
@ -133,6 +130,8 @@ describe.only("ssr", () => {
showOutput(cwd, compileOptions);
}
} catch (err) {
err.stack += `\n\ncmd-click: ${path.relative(process.cwd(), cwd)}/main.svelte`;
if (config.error) {
if (typeof config.error === 'function') {
config.error(assert, err);

Loading…
Cancel
Save