feat: merge neighboring text and expressions into 1 text node

pull/3766/head
Tan Li Hau 6 years ago
parent 1273f97808
commit f209ae5dcb

@ -7,6 +7,7 @@ import { CompileOptions, Warning } from '../interfaces';
import Component from './Component'; import Component from './Component';
import fuzzymatch from '../utils/fuzzymatch'; import fuzzymatch from '../utils/fuzzymatch';
import get_name_from_filename from './utils/get_name_from_filename'; import get_name_from_filename from './utils/get_name_from_filename';
import optimise from '../parse/optimise/index';
const valid_options = [ const valid_options = [
'format', 'format',
@ -25,7 +26,8 @@ const valid_options = [
'tag', 'tag',
'css', 'css',
'preserveComments', 'preserveComments',
'preserveWhitespace' 'preserveWhitespace',
'optimiseAst',
]; ];
function validate_options(options: CompileOptions, warnings: Warning[]) { function validate_options(options: CompileOptions, warnings: Warning[]) {
@ -57,7 +59,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
} }
export default function compile(source: string, options: CompileOptions = {}) { export default function compile(source: string, options: CompileOptions = {}) {
options = assign({ generate: 'dom', dev: false }, options); options = assign({ generate: 'dom', dev: false, optimiseAst: true }, options);
const stats = new Stats(); const stats = new Stats();
const warnings = []; const warnings = [];
@ -68,6 +70,12 @@ export default function compile(source: string, options: CompileOptions = {}) {
const ast = parse(source, options); const ast = parse(source, options);
stats.stop('parse'); stats.stop('parse');
if (options.optimiseAst) {
stats.start('optimise-ast');
optimise(ast);
stats.stop('optimise-ast');
}
stats.start('create component'); stats.start('create component');
const component = new Component( const component = new Component(
ast, ast,
@ -79,9 +87,10 @@ export default function compile(source: string, options: CompileOptions = {}) {
); );
stats.stop('create component'); stats.stop('create component');
const js = options.generate === false const js =
? null options.generate === false
: options.generate === 'ssr' ? null
: options.generate === 'ssr'
? render_ssr(component, options) ? render_ssr(component, options)
: render_dom(component, options); : render_dom(component, options);

@ -297,6 +297,13 @@ export default class ElementWrapper extends Wrapper {
// @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead? // @ts-ignore todo: should it be this.fragment.nodes[0].node.data instead?
b`${node}.textContent = ${string_literal(this.fragment.nodes[0].data)};` b`${node}.textContent = ${string_literal(this.fragment.nodes[0].data)};`
); );
} else if (
this.fragment.nodes.length === 1 &&
this.fragment.nodes[0].node.type === 'MustacheTag' &&
this.fragment.nodes[0].node.expression.node.type === 'TemplateLiteral') {
block.chunks.create.push(
b`${node}.textContent = ${this.fragment.nodes[0].node.expression.manipulate(block)};`
);
} else { } else {
const state = { const state = {
quasi: { quasi: {

@ -4,6 +4,7 @@ import Renderer from '../../Renderer';
import Block from '../../Block'; import Block from '../../Block';
import MustacheTag from '../../../nodes/MustacheTag'; import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag'; import RawMustacheTag from '../../../nodes/RawMustacheTag';
import { is_string } from './is_string';
import { Node } from 'estree'; import { Node } from 'estree';
export default class Tag extends Wrapper { export default class Tag extends Wrapper {
@ -29,14 +30,20 @@ export default class Tag extends Wrapper {
update: ((value: Node) => (Node | Node[])) update: ((value: Node) => (Node | Node[]))
) { ) {
const dependencies = this.node.expression.dynamic_dependencies(); const dependencies = this.node.expression.dynamic_dependencies();
const should_extract = this.node.should_cache && dependencies.length > 0;
let snippet = this.node.expression.manipulate(block); let snippet = this.node.expression.manipulate(block);
snippet = is_string(snippet) ? snippet : x`${snippet} + ""`;
if (should_extract) {
const fn_name = block.get_unique_name(`${this.var.name}_fn`);
block.add_variable(fn_name, x`(#ctx) => ${snippet}`);
snippet = x`${fn_name}(#ctx)`;
}
const value = this.node.should_cache && block.get_unique_name(`${this.var.name}_value`); const value = this.node.should_cache && block.get_unique_name(`${this.var.name}_value`);
const content = this.node.should_cache ? value : snippet; const content = this.node.should_cache ? value : snippet;
snippet = x`${snippet} + ""`; if (this.node.should_cache) block.add_variable(value, snippet);
if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string
if (dependencies.length > 0) { if (dependencies.length > 0) {
let condition = x`#changed.${dependencies[0]}`; let condition = x`#changed.${dependencies[0]}`;

@ -0,0 +1,3 @@
export function is_string(node) {
return node.type === 'TemplateLiteral' || (node.type === 'Literal' && typeof node.value === 'string');
}

@ -124,6 +124,7 @@ export interface CompileOptions {
preserveComments?: boolean; preserveComments?: boolean;
preserveWhitespace?: boolean; preserveWhitespace?: boolean;
optimiseAst?: boolean;
} }
export interface ParserOptions { export interface ParserOptions {

@ -0,0 +1,85 @@
import { walk } from 'estree-walker';
import { Text, MustacheTag } from '../../interfaces';
export default function optimise(ast) {
walk(ast, {
enter(node: any) {
if (node.type === 'Element') {
optimise_text_content(node.children);
}
},
});
}
const text_like_node_type = new Set(['MustacheTag', 'Text']);
function optimise_text_content(children) {
let start = 0;
let end = 0;
do {
while (
start < children.length &&
!text_like_node_type.has(children[start].type)
)
start++;
end = start;
while (end < children.length && text_like_node_type.has(children[end].type))
end++;
if (end > start) {
const merged = merge_text_siblings(children.slice(start, end));
children.splice(start, end - start, ...merged);
start = end;
}
} while (start < children.length);
}
function merge_text_siblings(children: Array<Text | MustacheTag>) {
if (children.length < 3) {
return children;
}
const literal = {
type: 'TemplateLiteral',
expressions: [],
quasis: [],
};
const state = {
quasi: {
type: 'TemplateElement',
value: { raw: '' },
start: children[0].start,
end: children[0].start
},
};
for (const child of children) {
if (child.type === 'MustacheTag') {
literal.quasis.push(state.quasi);
literal.expressions.push(child.expression);
state.quasi = {
type: 'TemplateElement',
value: { raw: '' },
// @ts-ignore
start: child.expression.end + 1,
// @ts-ignore
end: child.expression.end + 1
};
} else if (child.type === 'Text') {
state.quasi.value.raw += child.data;
state.quasi.end = child.end;
}
}
literal.quasis.push(state.quasi);
return [{
type: 'MustacheTag',
expression: literal,
start: children[0].start,
end: children[children.length - 1].end,
}];
}

@ -36,6 +36,10 @@ describe("js", () => {
const expected = fs.readFileSync(`${dir}/expected.js`, "utf-8"); const expected = fs.readFileSync(`${dir}/expected.js`, "utf-8");
if (process.env.UPDATE_EXPECTED) {
fs.writeFileSync(`${dir}/expected.js`, actual);
}
assert.equal( assert.equal(
actual.trim().replace(/^[ \t]+$/gm, ""), actual.trim().replace(/^[ \t]+$/gm, ""),
expected.trim().replace(/^[ \t]+$/gm, "") expected.trim().replace(/^[ \t]+$/gm, "")

@ -24,7 +24,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
p = element("p"); p = element("p");
t0 = text(ctx.foo); t0 = text(ctx.foo + "");
t1 = space(); t1 = space();
input = element("input"); input = element("input");
dispose = listen(input, "input", ctx.input_input_handler); dispose = listen(input, "input", ctx.input_input_handler);
@ -37,7 +37,7 @@ function create_fragment(ctx) {
set_input_value(input, ctx.foo); set_input_value(input, ctx.foo);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.foo) set_data(t0, ctx.foo); if (changed.foo) set_data(t0, ctx.foo + "");
if (changed.foo && input.value !== ctx.foo) { if (changed.foo && input.value !== ctx.foo) {
set_input_value(input, ctx.foo); set_input_value(input, ctx.foo);

@ -26,7 +26,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
p = element("p"); p = element("p");
t = text(ctx.foo); t = text(ctx.foo + "");
attr(p, "class", "svelte-1a7i8ec"); attr(p, "class", "svelte-1a7i8ec");
}, },
m(target, anchor) { m(target, anchor) {
@ -34,7 +34,7 @@ function create_fragment(ctx) {
append(p, t); append(p, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.foo) set_data(t, ctx.foo); if (changed.foo) set_data(t, ctx.foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -21,14 +21,14 @@ function create_fragment(ctx) {
return { return {
c() { c() {
h1 = element("h1"); h1 = element("h1");
t = text(ctx.$foo); t = text(ctx.$foo + "");
}, },
m(target, anchor) { m(target, anchor) {
insert(target, h1, anchor); insert(target, h1, anchor);
append(h1, t); append(h1, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.$foo) set_data(t, ctx.$foo); if (changed.$foo) set_data(t, ctx.$foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -26,7 +26,7 @@ function create_fragment(ctx) {
return { return {
c() { c() {
h1 = element("h1"); h1 = element("h1");
t0 = text(ctx.$foo); t0 = text(ctx.$foo + "");
t1 = space(); t1 = space();
button = element("button"); button = element("button");
button.textContent = "reset"; button.textContent = "reset";
@ -39,7 +39,7 @@ function create_fragment(ctx) {
insert(target, button, anchor); insert(target, button, anchor);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.$foo) set_data(t0, ctx.$foo); if (changed.$foo) set_data(t0, ctx.$foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -18,18 +18,16 @@ const file = undefined;
function create_fragment(ctx) { function create_fragment(ctx) {
let h1; let h1;
let t0_fn = ctx => `Hello ${ctx.name}!`;
let t0_value = t0_fn(ctx);
let t0; let t0;
let t1; let t1;
let t2;
let t3;
const block = { const block = {
c: function create() { c: function create() {
h1 = element("h1"); h1 = element("h1");
t0 = text("Hello "); t0 = text(t0_value);
t1 = text(ctx.name); t1 = space();
t2 = text("!");
t3 = space();
debugger; debugger;
add_location(h1, file, 4, 0, 38); add_location(h1, file, 4, 0, 38);
}, },
@ -39,19 +37,17 @@ function create_fragment(ctx) {
m: function mount(target, anchor) { m: function mount(target, anchor) {
insert_dev(target, h1, anchor); insert_dev(target, h1, anchor);
append_dev(h1, t0); append_dev(h1, t0);
append_dev(h1, t1); insert_dev(target, t1, anchor);
append_dev(h1, t2);
insert_dev(target, t3, anchor);
}, },
p: function update(changed, ctx) { p: function update(changed, ctx) {
if (changed.name) set_data_dev(t1, ctx.name); if (changed.name && t0_value !== (t0_value = t0_fn(ctx))) set_data_dev(t0, t0_value);
debugger; debugger;
}, },
i: noop, i: noop,
o: noop, o: noop,
d: function destroy(detaching) { d: function destroy(detaching) {
if (detaching) detach_dev(h1); if (detaching) detach_dev(h1);
if (detaching) detach_dev(t3); if (detaching) detach_dev(t1);
} }
}; };

@ -25,7 +25,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(ctx) { function create_each_block(ctx) {
let span; let span;
let t0_value = ctx.thing.name + ""; let t0_fn = ctx => ctx.thing.name + "";
let t0_value = t0_fn(ctx);
let t0; let t0;
let t1; let t1;
@ -49,7 +50,7 @@ function create_each_block(ctx) {
insert_dev(target, t1, anchor); insert_dev(target, t1, anchor);
}, },
p: function update(changed, ctx) { p: function update(changed, ctx) {
if (changed.things && t0_value !== (t0_value = ctx.thing.name + "")) set_data_dev(t0, t0_value); if (changed.things && t0_value !== (t0_value = t0_fn(ctx))) set_data_dev(t0, t0_value);
if (changed.foo || changed.bar || changed.baz || changed.things) { if (changed.foo || changed.bar || changed.baz || changed.things) {
const { foo, bar, baz, thing } = ctx; const { foo, bar, baz, thing } = ctx;
@ -95,7 +96,7 @@ function create_fragment(ctx) {
t0 = space(); t0 = space();
p = element("p"); p = element("p");
t1 = text("foo: "); t1 = text("foo: ");
t2 = text(ctx.foo); t2 = text(ctx.foo + "");
add_location(p, file, 12, 0, 182); add_location(p, file, 12, 0, 182);
}, },
l: function claim(nodes) { l: function claim(nodes) {
@ -135,7 +136,7 @@ function create_fragment(ctx) {
each_blocks.length = each_value.length; each_blocks.length = each_value.length;
} }
if (changed.foo) set_data_dev(t2, ctx.foo); if (changed.foo) set_data_dev(t2, ctx.foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -25,7 +25,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(ctx) { function create_each_block(ctx) {
let span; let span;
let t0_value = ctx.thing.name + ""; let t0_fn = ctx => ctx.thing.name + "";
let t0_value = t0_fn(ctx);
let t0; let t0;
let t1; let t1;
@ -49,7 +50,7 @@ function create_each_block(ctx) {
insert_dev(target, t1, anchor); insert_dev(target, t1, anchor);
}, },
p: function update(changed, ctx) { p: function update(changed, ctx) {
if (changed.things && t0_value !== (t0_value = ctx.thing.name + "")) set_data_dev(t0, t0_value); if (changed.things && t0_value !== (t0_value = t0_fn(ctx))) set_data_dev(t0, t0_value);
if (changed.foo) { if (changed.foo) {
const { foo } = ctx; const { foo } = ctx;
@ -95,7 +96,7 @@ function create_fragment(ctx) {
t0 = space(); t0 = space();
p = element("p"); p = element("p");
t1 = text("foo: "); t1 = text("foo: ");
t2 = text(ctx.foo); t2 = text(ctx.foo + "");
add_location(p, file, 10, 0, 131); add_location(p, file, 10, 0, 131);
}, },
l: function claim(nodes) { l: function claim(nodes) {
@ -135,7 +136,7 @@ function create_fragment(ctx) {
each_blocks.length = each_value.length; each_blocks.length = each_value.length;
} }
if (changed.foo) set_data_dev(t2, ctx.foo); if (changed.foo) set_data_dev(t2, ctx.foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -21,7 +21,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(ctx) { function create_each_block(ctx) {
let span; let span;
let t_value = ctx.node + ""; let t_fn = ctx => ctx.node + "";
let t_value = t_fn(ctx);
let t; let t;
return { return {
@ -34,7 +35,7 @@ function create_each_block(ctx) {
append(span, t); append(span, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.createElement && t_value !== (t_value = ctx.node + "")) set_data(t, t_value); if (changed.createElement && t_value !== (t_value = t_fn(ctx))) set_data(t, t_value);
}, },
d(detaching) { d(detaching) {
if (detaching) detach(span); if (detaching) detach(span);

@ -10,7 +10,6 @@ import {
noop, noop,
safe_not_equal, safe_not_equal,
set_data_dev, set_data_dev,
space,
text text
} from "svelte/internal"; } from "svelte/internal";
@ -18,17 +17,19 @@ const file = undefined;
function create_fragment(ctx) { function create_fragment(ctx) {
let p; let p;
let t0_value = Math.max(0, ctx.foo) + "";
let t0; let t_fn = ctx => `
let t1; ${Math.max(0, ctx.foo)}
let t2; ${ctx.bar}
`;
let t_value = t_fn(ctx);
let t;
const block = { const block = {
c: function create() { c: function create() {
p = element("p"); p = element("p");
t0 = text(t0_value); t = text(t_value);
t1 = space();
t2 = text(ctx.bar);
add_location(p, file, 7, 0, 67); add_location(p, file, 7, 0, 67);
}, },
l: function claim(nodes) { l: function claim(nodes) {
@ -36,13 +37,10 @@ function create_fragment(ctx) {
}, },
m: function mount(target, anchor) { m: function mount(target, anchor) {
insert_dev(target, p, anchor); insert_dev(target, p, anchor);
append_dev(p, t0); append_dev(p, t);
append_dev(p, t1);
append_dev(p, t2);
}, },
p: function update(changed, ctx) { p: function update(changed, ctx) {
if (changed.foo && t0_value !== (t0_value = Math.max(0, ctx.foo) + "")) set_data_dev(t0, t0_value); if ((changed.foo || changed.bar) && t_value !== (t_value = t_fn(ctx))) set_data_dev(t, t_value);
if (changed.bar) set_data_dev(t2, ctx.bar);
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -21,7 +21,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(ctx) { function create_each_block(ctx) {
let span; let span;
let t_value = ctx.num + ""; let t_fn = ctx => ctx.num + "";
let t_value = t_fn(ctx);
let t; let t;
return { return {
@ -34,7 +35,7 @@ function create_each_block(ctx) {
append(span, t); append(span, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if ((changed.a || changed.b || changed.c || changed.d || changed.e) && t_value !== (t_value = ctx.num + "")) set_data(t, t_value); if ((changed.a || changed.b || changed.c || changed.d || changed.e) && t_value !== (t_value = t_fn(ctx))) set_data(t, t_value);
}, },
d(detaching) { d(detaching) {
if (detaching) detach(span); if (detaching) detach(span);

@ -28,28 +28,27 @@ function create_each_block(ctx) {
let t0; let t0;
let t1; let t1;
let span; let span;
let t2_value = ctx.comment.author + "";
let t2_fn = ctx => `
${ctx.comment.author} wrote ${ctx.elapsed(ctx.comment.time, ctx.time)} ago:
`;
let t2_value = t2_fn(ctx);
let t2; let t2;
let t3; let t3;
let t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + "";
let t4;
let t5;
let t6;
let html_tag; let html_tag;
let raw_value = ctx.comment.html + ""; let raw_fn = ctx => ctx.comment.html + "";
let raw_value = raw_fn(ctx);
return { return {
c() { c() {
div = element("div"); div = element("div");
strong = element("strong"); strong = element("strong");
t0 = text(ctx.i); t0 = text(ctx.i + "");
t1 = space(); t1 = space();
span = element("span"); span = element("span");
t2 = text(t2_value); t2 = text(t2_value);
t3 = text(" wrote "); t3 = space();
t4 = text(t4_value);
t5 = text(" ago:");
t6 = space();
attr(span, "class", "meta"); attr(span, "class", "meta");
html_tag = new HtmlTag(raw_value, null); html_tag = new HtmlTag(raw_value, null);
attr(div, "class", "comment"); attr(div, "class", "comment");
@ -61,16 +60,12 @@ function create_each_block(ctx) {
append(div, t1); append(div, t1);
append(div, span); append(div, span);
append(span, t2); append(span, t2);
append(span, t3); append(div, t3);
append(span, t4);
append(span, t5);
append(div, t6);
html_tag.m(div); html_tag.m(div);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.comments && t2_value !== (t2_value = ctx.comment.author + "")) set_data(t2, t2_value); if ((changed.comments || changed.elapsed || changed.time) && t2_value !== (t2_value = t2_fn(ctx))) set_data(t2, t2_value);
if ((changed.elapsed || changed.comments || changed.time) && t4_value !== (t4_value = ctx.elapsed(ctx.comment.time, ctx.time) + "")) set_data(t4, t4_value); if (changed.comments && raw_value !== (raw_value = raw_fn(ctx))) html_tag.p(raw_value);
if (changed.comments && raw_value !== (raw_value = ctx.comment.html + "")) html_tag.p(raw_value);
}, },
d(detaching) { d(detaching) {
if (detaching) detach(div); if (detaching) detach(div);
@ -97,7 +92,7 @@ function create_fragment(ctx) {
t0 = space(); t0 = space();
p = element("p"); p = element("p");
t1 = text(ctx.foo); t1 = text(ctx.foo + "");
}, },
m(target, anchor) { m(target, anchor) {
for (let i = 0; i < each_blocks.length; i += 1) { for (let i = 0; i < each_blocks.length; i += 1) {
@ -132,7 +127,7 @@ function create_fragment(ctx) {
each_blocks.length = each_value.length; each_blocks.length = each_value.length;
} }
if (changed.foo) set_data(t1, ctx.foo); if (changed.foo) set_data(t1, ctx.foo + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -24,7 +24,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(key_1, ctx) { function create_each_block(key_1, ctx) {
let div; let div;
let t_value = ctx.thing.name + ""; let t_fn = ctx => ctx.thing.name + "";
let t_value = t_fn(ctx);
let t; let t;
let rect; let rect;
let stop_animation = noop; let stop_animation = noop;
@ -42,7 +43,7 @@ function create_each_block(key_1, ctx) {
append(div, t); append(div, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.things && t_value !== (t_value = ctx.thing.name + "")) set_data(t, t_value); if (changed.things && t_value !== (t_value = t_fn(ctx))) set_data(t, t_value);
}, },
r() { r() {
rect = div.getBoundingClientRect(); rect = div.getBoundingClientRect();

@ -22,7 +22,8 @@ function get_each_context(ctx, list, i) {
function create_each_block(key_1, ctx) { function create_each_block(key_1, ctx) {
let div; let div;
let t_value = ctx.thing.name + ""; let t_fn = ctx => ctx.thing.name + "";
let t_value = t_fn(ctx);
let t; let t;
return { return {
@ -38,7 +39,7 @@ function create_each_block(key_1, ctx) {
append(div, t); append(div, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.things && t_value !== (t_value = ctx.thing.name + "")) set_data(t, t_value); if (changed.things && t_value !== (t_value = t_fn(ctx))) set_data(t, t_value);
}, },
d(detaching) { d(detaching) {
if (detaching) detach(div); if (detaching) detach(div);

@ -28,7 +28,7 @@ function create_fragment(ctx) {
t1 = space(); t1 = space();
p = element("p"); p = element("p");
t2 = text("x: "); t2 = text("x: ");
t3 = text(ctx.x); t3 = text(ctx.x + "");
dispose = listen(button, "click", ctx.foo); dispose = listen(button, "click", ctx.foo);
}, },
m(target, anchor) { m(target, anchor) {
@ -39,7 +39,7 @@ function create_fragment(ctx) {
append(p, t3); append(p, t3);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.x) set_data(t3, ctx.x); if (changed.x) set_data(t3, ctx.x + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -18,7 +18,8 @@ function create_fragment(ctx) {
let t1; let t1;
let p; let p;
let t2; let t2;
let t3_value = ctx.things.length + ""; let t3_fn = ctx => ctx.things.length + "";
let t3_value = t3_fn(ctx);
let t3; let t3;
let dispose; let dispose;
@ -40,7 +41,7 @@ function create_fragment(ctx) {
append(p, t3); append(p, t3);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.things && t3_value !== (t3_value = ctx.things.length + "")) set_data(t3, t3_value); if (changed.things && t3_value !== (t3_value = t3_fn(ctx))) set_data(t3, t3_value);
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -28,7 +28,7 @@ function create_fragment(ctx) {
t1 = space(); t1 = space();
p = element("p"); p = element("p");
t2 = text("x: "); t2 = text("x: ");
t3 = text(ctx.x); t3 = text(ctx.x + "");
dispose = listen(button, "click", ctx.click_handler); dispose = listen(button, "click", ctx.click_handler);
}, },
m(target, anchor) { m(target, anchor) {
@ -39,7 +39,7 @@ function create_fragment(ctx) {
append(p, t3); append(p, t3);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.x) set_data(t3, ctx.x); if (changed.x) set_data(t3, ctx.x + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -18,7 +18,8 @@ function create_fragment(ctx) {
let t1; let t1;
let p; let p;
let t2; let t2;
let t3_value = ctx.things.length + ""; let t3_fn = ctx => ctx.things.length + "";
let t3_value = t3_fn(ctx);
let t3; let t3;
let dispose; let dispose;
@ -40,7 +41,7 @@ function create_fragment(ctx) {
append(p, t3); append(p, t3);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.things && t3_value !== (t3_value = ctx.things.length + "")) set_data(t3, t3_value); if (changed.things && t3_value !== (t3_value = t3_fn(ctx))) set_data(t3, t3_value);
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -0,0 +1,65 @@
import {
SvelteComponent,
append,
detach,
element,
init,
insert,
listen,
noop,
safe_not_equal,
set_data,
text
} from "svelte/internal";
function create_fragment(ctx) {
let button;
let t_fn = ctx => `
Clicked ${ctx.count} ${ctx.count === 1 ? "time" : "times"}
`;
let t_value = t_fn(ctx);
let t;
let dispose;
return {
c() {
button = element("button");
t = text(t_value);
dispose = listen(button, "click", ctx.increment);
},
m(target, anchor) {
insert(target, button, anchor);
append(button, t);
},
p(changed, ctx) {
if (changed.count && t_value !== (t_value = t_fn(ctx))) set_data(t, t_value);
},
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(button);
dispose();
}
};
}
function instance($$self, $$props, $$invalidate) {
let count = 0;
function increment() {
$$invalidate("count", count = count + 1);
}
return { count, increment };
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, {});
}
}
export default Component;

@ -0,0 +1,9 @@
<script>
let count = 0;
function increment() {
count = count + 1;
}
</script>
<button on:click={increment}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

@ -40,7 +40,7 @@ function create_fragment(ctx) {
div1 = element("div"); div1 = element("div");
p3 = element("p"); p3 = element("p");
t8 = text("Hello "); t8 = text("Hello ");
t9 = text(ctx.world3); t9 = text(ctx.world3 + "");
}, },
m(target, anchor) { m(target, anchor) {
insert(target, div0, anchor); insert(target, div0, anchor);
@ -56,7 +56,7 @@ function create_fragment(ctx) {
append(p3, t9); append(p3, t9);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.world3) set_data(t9, ctx.world3); if (changed.world3) set_data(t9, ctx.world3 + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -20,14 +20,14 @@ function create_fragment(ctx) {
return { return {
c() { c() {
p = element("p"); p = element("p");
t = text(ctx.y); t = text(ctx.y + "");
}, },
m(target, anchor) { m(target, anchor) {
insert(target, p, anchor); insert(target, p, anchor);
append(p, t); append(p, t);
}, },
p(changed, ctx) { p(changed, ctx) {
if (changed.y) set_data(t, ctx.y); if (changed.y) set_data(t, ctx.y + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -31,7 +31,7 @@ function create_fragment(ctx) {
c() { c() {
p = element("p"); p = element("p");
t0 = text("scrolled to "); t0 = text("scrolled to ");
t1 = text(ctx.y); t1 = text(ctx.y + "");
dispose = listen(window, "scroll", () => { dispose = listen(window, "scroll", () => {
scrolling = true; scrolling = true;
@ -53,7 +53,7 @@ function create_fragment(ctx) {
scrolling_timeout = setTimeout(clear_scrolling, 100); scrolling_timeout = setTimeout(clear_scrolling, 100);
} }
if (changed.y) set_data(t1, ctx.y); if (changed.y) set_data(t1, ctx.y + "");
}, },
i: noop, i: noop,
o: noop, o: noop,

@ -23,9 +23,10 @@ describe('parse', () => {
const expectedError = tryToLoadJson(`${__dirname}/samples/${dir}/error.json`); const expectedError = tryToLoadJson(`${__dirname}/samples/${dir}/error.json`);
try { try {
const { ast } = svelte.compile(input, Object.assign(options, { const { ast } = svelte.compile(
generate: false input,
})); Object.assign({ optimiseAst: false }, options, { generate: false })
);
fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.json`, JSON.stringify(ast, null, '\t')); fs.writeFileSync(`${__dirname}/samples/${dir}/_actual.json`, JSON.stringify(ast, null, '\t'));

@ -0,0 +1,4 @@
<script>let name;</script>
<div>Hello {name}!</div>
<div>Hello <span>{name}</span>!</div>
<div><span>Hello</span> {name}!</div>

@ -0,0 +1,249 @@
{
"html": {
"start": 27,
"end": 127,
"type": "Fragment",
"children": [
{
"start": 26,
"end": 27,
"type": "Text",
"raw": "\n",
"data": "\n"
},
{
"start": 27,
"end": 51,
"type": "Element",
"name": "div",
"attributes": [],
"children": [
{
"type": "MustacheTag",
"expression": {
"type": "TemplateLiteral",
"expressions": [
{
"type": "Identifier",
"start": 39,
"end": 43,
"name": "name"
}
],
"quasis": [
{
"type": "TemplateElement",
"value": {
"raw": "Hello "
},
"start": 32,
"end": 38
},
{
"type": "TemplateElement",
"value": {
"raw": "!"
},
"start": 44,
"end": 45
}
]
},
"start": 32,
"end": 45
}
]
},
{
"start": 51,
"end": 52,
"type": "Text",
"raw": "\n",
"data": "\n"
},
{
"start": 52,
"end": 89,
"type": "Element",
"name": "div",
"attributes": [],
"children": [
{
"start": 57,
"end": 63,
"type": "Text",
"raw": "Hello ",
"data": "Hello "
},
{
"start": 63,
"end": 82,
"type": "Element",
"name": "span",
"attributes": [],
"children": [
{
"start": 69,
"end": 75,
"type": "MustacheTag",
"expression": {
"type": "Identifier",
"start": 70,
"end": 74,
"name": "name"
}
}
]
},
{
"start": 82,
"end": 83,
"type": "Text",
"raw": "!",
"data": "!"
}
]
},
{
"start": 89,
"end": 90,
"type": "Text",
"raw": "\n",
"data": "\n"
},
{
"start": 90,
"end": 127,
"type": "Element",
"name": "div",
"attributes": [],
"children": [
{
"start": 95,
"end": 113,
"type": "Element",
"name": "span",
"attributes": [],
"children": [
{
"start": 101,
"end": 106,
"type": "Text",
"raw": "Hello",
"data": "Hello"
}
]
},
{
"type": "MustacheTag",
"expression": {
"type": "TemplateLiteral",
"expressions": [
{
"type": "Identifier",
"start": 115,
"end": 119,
"name": "name"
}
],
"quasis": [
{
"type": "TemplateElement",
"value": {
"raw": " "
},
"start": 113,
"end": 114
},
{
"type": "TemplateElement",
"value": {
"raw": "!"
},
"start": 120,
"end": 121
}
]
},
"start": 113,
"end": 121
}
]
}
]
},
"instance": {
"type": "Script",
"start": 0,
"end": 26,
"context": "default",
"content": {
"type": "Program",
"start": 8,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 17
}
},
"body": [
{
"type": "VariableDeclaration",
"start": 8,
"end": 17,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 17
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 12,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 16
}
},
"id": {
"type": "Identifier",
"start": 12,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 16
}
},
"name": "name"
},
"init": null
}
],
"kind": "let"
}
],
"sourceType": "module"
}
}
}

@ -0,0 +1,12 @@
export default {
html: `<button>Clicked 0 times</button>`,
async test({ assert, target, window }) {
const buttons = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `<button>Clicked 1 time</button>`);
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `<button>Clicked 2 times</button>`);
},
};

@ -0,0 +1,9 @@
<script>
let count = 0;
function increment() {
count = count + 1;
}
</script>
<button on:click={increment}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

@ -1,26 +1,9 @@
export function test({ assert, smc, locateInSource, locateInGenerated }) { export function test({ assert, smc, locateInSource, locateInGenerated }) {
const expected = locateInSource( 'foo.bar.baz' ); const expected = locateInSource( 'foo.bar.baz' );
let start; const start = locateInGenerated('foo.bar.baz');
let actual;
start = locateInGenerated('foo.bar.baz'); const actual = smc.originalPositionFor({
actual = smc.originalPositionFor({
line: start.line + 1,
column: start.column
});
assert.deepEqual( actual, {
source: 'input.svelte',
name: null,
line: expected.line + 1,
column: expected.column
});
start = locateInGenerated( 'foo.bar.baz', start.character + 1 );
actual = smc.originalPositionFor({
line: start.line + 1, line: start.line + 1,
column: start.column column: start.column
}); });

Loading…
Cancel
Save