Skip to content

Commit 56f4ff9

Browse files
committed
merge text a like together
1 parent ebf7a90 commit 56f4ff9

File tree

6 files changed

+162
-4
lines changed

6 files changed

+162
-4
lines changed

src/compiler/compile/index.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { CompileOptions, Warning } from '../interfaces';
77
import Component from './Component';
88
import fuzzymatch from '../utils/fuzzymatch';
99
import get_name_from_filename from './utils/get_name_from_filename';
10+
import optimise from '../parse/optimise/index';
1011

1112
const valid_options = [
1213
'format',
@@ -25,7 +26,7 @@ const valid_options = [
2526
'tag',
2627
'css',
2728
'preserveComments',
28-
'preserveWhitespace'
29+
'preserveWhitespace',
2930
];
3031

3132
function validate_options(options: CompileOptions, warnings: Warning[]) {
@@ -68,6 +69,10 @@ export default function compile(source: string, options: CompileOptions = {}) {
6869
const ast = parse(source, options);
6970
stats.stop('parse');
7071

72+
stats.start('optimise-ast');
73+
optimise(ast);
74+
stats.stop('optimise-ast');
75+
7176
stats.start('create component');
7277
const component = new Component(
7378
ast,
@@ -79,9 +84,10 @@ export default function compile(source: string, options: CompileOptions = {}) {
7984
);
8085
stats.stop('create component');
8186

82-
const js = options.generate === false
83-
? null
84-
: options.generate === 'ssr'
87+
const js =
88+
options.generate === false
89+
? null
90+
: options.generate === 'ssr'
8591
? render_ssr(component, options)
8692
: render_dom(component, options);
8793

src/compiler/parse/optimise/index.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { walk } from 'estree-walker';
2+
import { Text, MustacheTag } from '../../interfaces';
3+
4+
const node_type_can_merge = new Set(['MustacheTag', 'Text']);
5+
6+
export default function optimise(ast) {
7+
walk(ast, {
8+
enter(node: any) {
9+
if (node.type === 'Element') {
10+
let i = 0;
11+
while (i + 1 < node.children.length) {
12+
let prev = node.children[i];
13+
let next = node.children[i + 1];
14+
if (can_merge_siblings(prev, next)) {
15+
// merge `i` and `i+1`
16+
node.children.splice(i, 2, merge_siblings(prev, next));
17+
} else {
18+
i++;
19+
}
20+
}
21+
}
22+
},
23+
});
24+
}
25+
26+
function can_merge_siblings(prev, next) {
27+
return (
28+
node_type_can_merge.has(prev.type) && node_type_can_merge.has(next.type)
29+
);
30+
}
31+
32+
function merge_siblings(prev, next) {
33+
return {
34+
start: prev.start,
35+
end: next.end,
36+
type: 'MustacheTag',
37+
expression: {
38+
type: 'BinaryExpression',
39+
start: prev.start,
40+
end: next.end,
41+
left: to_expression(prev),
42+
operator: '+',
43+
right: to_expression(next),
44+
loc: {},
45+
},
46+
};
47+
}
48+
49+
function to_expression(node: Text | MustacheTag) {
50+
switch (node.type) {
51+
case 'MustacheTag':
52+
return node.expression;
53+
case 'Text':
54+
return {
55+
type: 'Literal',
56+
start: node.start,
57+
end: node.end,
58+
value: node.data,
59+
raw: JSON.stringify(node.data),
60+
};
61+
}
62+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {
2+
SvelteComponent,
3+
append,
4+
detach,
5+
element,
6+
init,
7+
insert,
8+
listen,
9+
noop,
10+
safe_not_equal,
11+
set_data,
12+
text
13+
} from "svelte/internal";
14+
15+
function create_fragment(ctx) {
16+
let button;
17+
let t_value = "\n\tClicked " + ctx.count + " " + (ctx.count === 1 ? "time" : "times") + "\n" + "";
18+
let t;
19+
let dispose;
20+
21+
return {
22+
c() {
23+
button = element("button");
24+
t = text(t_value);
25+
dispose = listen(button, "click", ctx.increment);
26+
},
27+
m(target, anchor) {
28+
insert(target, button, anchor);
29+
append(button, t);
30+
},
31+
p(changed, ctx) {
32+
if (changed.count && t_value !== (t_value = "\n\tClicked " + ctx.count + " " + (ctx.count === 1 ? "time" : "times") + "\n" + "")) set_data(t, t_value);
33+
},
34+
i: noop,
35+
o: noop,
36+
d(detaching) {
37+
if (detaching) detach(button);
38+
dispose();
39+
}
40+
};
41+
}
42+
43+
function instance($$self, $$props, $$invalidate) {
44+
let count = 0;
45+
46+
function increment() {
47+
$$invalidate("count", count = count + 1);
48+
}
49+
50+
return { count, increment };
51+
}
52+
53+
class Component extends SvelteComponent {
54+
constructor(options) {
55+
super();
56+
init(this, options, instance, create_fragment, safe_not_equal, []);
57+
}
58+
}
59+
60+
export default Component;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
let count = 0;
3+
function increment() {
4+
count = count + 1;
5+
}
6+
</script>
7+
<button on:click={increment}>
8+
Clicked {count} {count === 1 ? 'time' : 'times'}
9+
</button>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default {
2+
html: `<button>Clicked 0 times</button>`,
3+
async test({ assert, target, window }) {
4+
const buttons = target.querySelectorAll('button');
5+
const event = new window.MouseEvent('click');
6+
await buttons[0].dispatchEvent(event);
7+
assert.htmlEqual(target.innerHTML, `<button>Clicked 1 time</button>`);
8+
9+
await buttons[0].dispatchEvent(event);
10+
assert.htmlEqual(target.innerHTML, `<button>Clicked 2 times</button>`);
11+
},
12+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
let count = 0;
3+
function increment() {
4+
count = count + 1;
5+
}
6+
</script>
7+
<button on:click={increment}>
8+
Clicked {count} {count === 1 ? 'time' : 'times'}
9+
</button>

0 commit comments

Comments
 (0)