most ssr-only tests passing

pull/3539/head
Richard Harris 6 years ago
parent a2e96dbaba
commit 9fa133765d

@ -13,7 +13,7 @@ import Text from './handlers/Text';
import Title from './handlers/Title'; import Title from './handlers/Title';
import { AppendTarget, CompileOptions } from '../../interfaces'; import { AppendTarget, CompileOptions } from '../../interfaces';
import { INode } from '../nodes/interfaces'; import { INode } from '../nodes/interfaces';
import { Expression } from 'estree'; import { Expression, TemplateLiteral } from 'estree';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
@ -45,22 +45,17 @@ export interface RenderOptions extends CompileOptions{
export default class Renderer { export default class Renderer {
has_bindings = false; has_bindings = false;
state = { stack: { current: { value: string }, literal: TemplateLiteral }[] = [];
quasi: { current: { value: string };
type: 'TemplateElement', literal: TemplateLiteral;
value: { raw: '' }
}
};
literal = {
type: 'TemplateLiteral',
expressions: [],
quasis: []
};
targets: AppendTarget[] = []; targets: AppendTarget[] = [];
append(code: string) { constructor() {
this.push();
}
append() {
throw new Error('no more append'); throw new Error('no more append');
// if (this.targets.length) { // if (this.targets.length) {
// const target = this.targets[this.targets.length - 1]; // const target = this.targets[this.targets.length - 1];
@ -72,17 +67,48 @@ export default class Renderer {
} }
add_string(str: string) { add_string(str: string) {
this.state.quasi.value.raw += str; this.current.value += str;
} }
add_expression(node: Expression) { add_expression(node: Expression) {
this.literal.quasis.push(this.state.quasi); this.literal.quasis.push({
type: 'TemplateElement',
value: { raw: this.current.value, cooked: null },
tail: false
});
this.literal.expressions.push(node); this.literal.expressions.push(node);
this.current = { value: '' };
}
this.state.quasi = { push() {
type: 'TemplateElement', const current = this.current = { value: '' };
value: { raw: '' }
const literal = this.literal = {
type: 'TemplateLiteral',
expressions: [],
quasis: []
}; };
this.stack.push({ current, literal })
}
pop() {
this.literal.quasis.push({
type: 'TemplateElement',
value: { raw: this.current.value, cooked: null },
tail: true
});
const popped = this.stack.pop();
const last = this.stack[this.stack.length - 1];
if (last) {
this.literal = last.literal;
this.current = last.current;
}
return popped.literal;
} }
render(nodes: INode[], options: RenderOptions) { render(nodes: INode[], options: RenderOptions) {

@ -1,29 +1,24 @@
import { snip } from '../../utils/snip';
import Renderer, { RenderOptions } from '../Renderer'; import Renderer, { RenderOptions } from '../Renderer';
import EachBlock from '../../nodes/EachBlock'; import EachBlock from '../../nodes/EachBlock';
import { x } from 'code-red';
export default function(node: EachBlock, renderer: Renderer, options: RenderOptions) { export default function(node: EachBlock, renderer: Renderer, options: RenderOptions) {
const snippet = snip(node.expression); const args = [node.context_node];
if (node.index) args.push({ type: 'Identifier', name: node.index });
const { start, end } = node.context_node as any;
const ctx = node.index
? `([✂${start}-${end}✂], ${node.index})`
: `([✂${start}-${end}✂])`;
const open = `\${${node.else ? `${snippet}.length ? ` : ''}@each(${snippet}, ${ctx} => \``;
renderer.append(open);
renderer.push();
renderer.render(node.children, options); renderer.render(node.children, options);
const result = renderer.pop();
const close = `\`)`; const consequent = x`@each(${node.expression.node}, (${args}) => ${result})`;
renderer.append(close);
if (node.else) { if (node.else) {
renderer.append(` : \``); renderer.push();
renderer.render(node.else.children, options); renderer.render(node.else.children, options);
renderer.append(`\``); const alternate = renderer.pop();
}
renderer.append('}'); renderer.add_expression(x`${node.expression.node}.length ? ${consequent} : ${alternate}`);
} else {
renderer.add_expression(consequent);
}
} }

@ -143,7 +143,6 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
} else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') {
const { name } = attribute; const { name } = attribute;
const snippet = attribute.chunks[0].node; const snippet = attribute.chunks[0].node;
console.log(snippet);
renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); renderer.add_expression(x`@add_attribute("${name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`);
} else { } else {
renderer.add_string(` ${attribute.name}="`); renderer.add_string(` ${attribute.name}="`);

@ -1,10 +1,11 @@
import Renderer, { RenderOptions } from '../Renderer'; import Renderer, { RenderOptions } from '../Renderer';
import Head from '../../nodes/Head'; import Head from '../../nodes/Head';
import { x } from 'code-red';
export default function(node: Head, renderer: Renderer, options: RenderOptions) { export default function(node: Head, renderer: Renderer, options: RenderOptions) {
renderer.append('${($$result.head += `'); renderer.push();
renderer.render(node.children, options); renderer.render(node.children, options);
const result = renderer.pop();
renderer.append('`, "")}'); renderer.add_expression(x`($$result.head += ${result}, "")`);
} }

@ -1,7 +1,6 @@
import { snip } from '../../utils/snip';
import Renderer, { RenderOptions } from '../Renderer'; import Renderer, { RenderOptions } from '../Renderer';
import RawMustacheTag from '../../nodes/RawMustacheTag'; import RawMustacheTag from '../../nodes/RawMustacheTag';
export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) { export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) {
renderer.append('${' + snip(node.expression) + '}'); renderer.add_expression(node.expression.node);
} }

@ -1,18 +1,17 @@
import { snip } from '../../utils/snip';
import IfBlock from '../../nodes/IfBlock'; import IfBlock from '../../nodes/IfBlock';
import Renderer, { RenderOptions } from '../Renderer'; import Renderer, { RenderOptions } from '../Renderer';
export default function(node: IfBlock, renderer: Renderer, options: RenderOptions) { import { x } from 'code-red';
const snippet = snip(node.expression);
renderer.append('${ ' + snippet + ' ? `'); export default function(node: IfBlock, renderer: Renderer, options: RenderOptions) {
const condition = node.expression.node;
renderer.push();
renderer.render(node.children, options); renderer.render(node.children, options);
const consequent = renderer.pop();
renderer.append('` : `'); renderer.push();
if (node.else) renderer.render(node.else.children, options);
if (node.else) { const alternate = renderer.pop();
renderer.render(node.else.children, options);
}
renderer.append('` }'); renderer.add_expression(x`${condition} ? ${consequent} : ${alternate}`);
} }

@ -81,29 +81,24 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
const slot_fns = []; const slot_fns = [];
if (node.children.length) { if (node.children.length) {
const target: AppendTarget = {
slots: { default: '' },
slot_stack: ['default']
};
renderer.targets.push(target);
const slot_scopes = new Map(); const slot_scopes = new Map();
slot_scopes.set('default', get_slot_scope(node.lets));
renderer.push();
renderer.render(node.children, Object.assign({}, options, { renderer.render(node.children, Object.assign({}, options, {
slot_scopes slot_scopes
})); }));
Object.keys(target.slots).forEach(name => { slot_scopes.set('default', {
const slot_scope = slot_scopes.get(name); input: get_slot_scope(node.lets),
output: renderer.pop()
});
slot_scopes.forEach(({ input, output }, name) => {
slot_fns.push( slot_fns.push(
`${quote_name_if_necessary(name)}: (${slot_scope}) => \`${target.slots[name]}\`` p`${name}: (${input}) => ${output}`
); );
}); });
renderer.targets.pop();
} }
const slots = x`{ const slots = x`{

@ -2,15 +2,20 @@ import { quote_prop_if_necessary } from '../../../utils/names';
import get_slot_data from '../../utils/get_slot_data'; import get_slot_data from '../../utils/get_slot_data';
import Renderer, { RenderOptions } from '../Renderer'; import Renderer, { RenderOptions } from '../Renderer';
import Slot from '../../nodes/Slot'; import Slot from '../../nodes/Slot';
import { x } from 'code-red';
export default function(node: Slot, renderer: Renderer, options: RenderOptions) { export default function(node: Slot, renderer: Renderer, options: RenderOptions) {
const prop = quote_prop_if_necessary(node.slot_name);
const slot_data = get_slot_data(node.values, true); const slot_data = get_slot_data(node.values, true);
renderer.append(`\${$$slots${prop} ? $$slots${prop}(${slot_data}) : \``); console.group('push');
renderer.push();
console.groupEnd();
renderer.render(node.children, options); renderer.render(node.children, options);
const result = renderer.pop();
renderer.append(`\`}`); renderer.add_expression(x`
$$slots.${node.slot_name}
? $$slots.${node.slot_name}(${slot_data})
: ${result}
`);
} }

@ -2,9 +2,9 @@ import Renderer, { RenderOptions } from '../Renderer';
import Title from '../../nodes/Title'; import Title from '../../nodes/Title';
export default function(node: Title, renderer: Renderer, options: RenderOptions) { export default function(node: Title, renderer: Renderer, options: RenderOptions) {
renderer.append(`<title>`); renderer.add_string(`<title>`);
renderer.render(node.children, options); renderer.render(node.children, options);
renderer.append(`</title>`); renderer.add_string(`</title>`);
} }

@ -1,6 +1,21 @@
import Let from '../../../nodes/Let'; import Let from '../../../nodes/Let';
import { ObjectPattern } from 'estree';
export function get_slot_scope(lets: Let[]) { export function get_slot_scope(lets: Let[]): ObjectPattern {
if (lets.length === 0) return ''; if (lets.length === 0) return null;
return `{ ${lets.map(l => l.value ? `${l.name}: ${l.value}` : l.name).join(', ')} }`;
return {
type: 'ObjectPattern',
properties: lets.map(l => {
return {
type: 'Property',
kind: 'init',
method: false,
shorthand: false,
computed: false,
key: l.name,
value: l.value || l.name
};
})
};
} }

@ -20,7 +20,7 @@ export default function ssr(
}, options)); }, options));
// TODO put this inside the Renderer class // TODO put this inside the Renderer class
renderer.literal.quasis.push(renderer.state.quasi); const literal = renderer.pop();
// TODO concatenate CSS maps // TODO concatenate CSS maps
const css = options.customElement ? const css = options.customElement ?
@ -108,7 +108,7 @@ export default function ssr(
${reactive_declarations} ${reactive_declarations}
$$rendered = ${renderer.literal}; $$rendered = ${literal};
} while (!$$settled); } while (!$$settled);
return $$rendered; return $$rendered;
@ -118,7 +118,7 @@ export default function ssr(
${reactive_declarations} ${reactive_declarations}
return ${renderer.literal};`; return ${literal};`;
const blocks = [ const blocks = [
...reactive_stores.map(({ name }) => { ...reactive_stores.map(({ name }) => {

Loading…
Cancel
Save