Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 275 B After Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 168 B |
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 155 B |
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 155 B |
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 415 B After Width: | Height: | Size: 344 B |
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 258 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 260 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 242 B |
Before Width: | Height: | Size: 260 B After Width: | Height: | Size: 200 B |
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 239 B |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 108 KiB |
@ -0,0 +1,73 @@
|
||||
import { INode } from '../../../nodes/interfaces';
|
||||
import { trim_end, trim_start } from '../../../../utils/trim';
|
||||
import { link } from '../../../../utils/link';
|
||||
|
||||
// similar logic from `compile/render_dom/wrappers/Fragment`
|
||||
// We want to remove trailing whitespace inside an element/component/block,
|
||||
// *unless* there is no whitespace between this node and its next sibling
|
||||
export default function remove_whitespace_children(children: INode[], next?: INode): INode[] {
|
||||
const nodes: INode[] = [];
|
||||
let last_child: INode;
|
||||
let i = children.length;
|
||||
while (i--) {
|
||||
const child = children[i];
|
||||
|
||||
if (child.type === 'Text') {
|
||||
if (child.should_skip()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let { data } = child;
|
||||
|
||||
if (nodes.length === 0) {
|
||||
const should_trim = next
|
||||
? next.type === 'Text' &&
|
||||
/^\s/.test(next.data) &&
|
||||
trimmable_at(child, next)
|
||||
: !child.has_ancestor('EachBlock');
|
||||
|
||||
if (should_trim) {
|
||||
data = trim_end(data);
|
||||
if (!data) continue;
|
||||
}
|
||||
}
|
||||
|
||||
// glue text nodes (which could e.g. be separated by comments) together
|
||||
if (last_child && last_child.type === 'Text') {
|
||||
last_child.data = data + last_child.data;
|
||||
continue;
|
||||
}
|
||||
|
||||
nodes.unshift(child);
|
||||
link(last_child, last_child = child);
|
||||
} else {
|
||||
nodes.unshift(child);
|
||||
link(last_child, last_child = child);
|
||||
}
|
||||
}
|
||||
|
||||
const first = nodes[0];
|
||||
if (first && first.type === 'Text') {
|
||||
first.data = trim_start(first.data);
|
||||
if (!first.data) {
|
||||
first.var = null;
|
||||
nodes.shift();
|
||||
|
||||
if (nodes[0]) {
|
||||
nodes[0].prev = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function trimmable_at(child: INode, next_sibling: INode): boolean {
|
||||
// Whitespace is trimmable if one of the following is true:
|
||||
// The child and its sibling share a common nearest each block (not at an each block boundary)
|
||||
// The next sibling's previous node is an each block
|
||||
return (
|
||||
next_sibling.find_nearest(/EachBlock/) ===
|
||||
child.find_nearest(/EachBlock/) || next_sibling.prev.type === 'EachBlock'
|
||||
);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export const reserved_keywords = new Set(["$$props", "$$restProps"]);
|
||||
|
||||
export function is_reserved_keyword(name) {
|
||||
return reserved_keywords.has(name);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import { Pattern, Identifier, RestElement } from "estree";
|
||||
import { Node } from "acorn";
|
||||
|
||||
export default function traverse_destructure_pattern(
|
||||
node: Pattern,
|
||||
callback: (node: Identifier, parent: Node, key: string | number) => void
|
||||
) {
|
||||
function traverse(node: Pattern, parent, key) {
|
||||
switch (node.type) {
|
||||
case "Identifier":
|
||||
return callback(node, parent, key);
|
||||
case "ArrayPattern":
|
||||
for (let i = 0; i < node.elements.length; i++) {
|
||||
const element = node.elements[i];
|
||||
traverse(element, node.elements, i);
|
||||
}
|
||||
break;
|
||||
case "ObjectPattern":
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
const property = node.properties[i];
|
||||
if (property.type === "Property") {
|
||||
traverse(property.value, property, "value");
|
||||
} else {
|
||||
traverse((property as any) as RestElement, node.properties, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "RestElement":
|
||||
return traverse(node.argument, node, 'argument');
|
||||
case "AssignmentPattern":
|
||||
return traverse(node.left, node, 'left');
|
||||
}
|
||||
}
|
||||
traverse(node, null, null);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
const SQUARE_BRACKET_OPEN = "[".charCodeAt(0);
|
||||
const SQUARE_BRACKET_CLOSE = "]".charCodeAt(0);
|
||||
const CURLY_BRACKET_OPEN = "{".charCodeAt(0);
|
||||
const CURLY_BRACKET_CLOSE = "}".charCodeAt(0);
|
||||
|
||||
export function is_bracket_open(code) {
|
||||
return code === SQUARE_BRACKET_OPEN || code === CURLY_BRACKET_OPEN;
|
||||
}
|
||||
|
||||
export function is_bracket_close(code) {
|
||||
return code === SQUARE_BRACKET_CLOSE || code === CURLY_BRACKET_CLOSE;
|
||||
}
|
||||
|
||||
export function is_bracket_pair(open, close) {
|
||||
return (
|
||||
(open === SQUARE_BRACKET_OPEN && close === SQUARE_BRACKET_CLOSE) ||
|
||||
(open === CURLY_BRACKET_OPEN && close === CURLY_BRACKET_CLOSE)
|
||||
);
|
||||
}
|
||||
|
||||
export function get_bracket_close(open) {
|
||||
if (open === SQUARE_BRACKET_OPEN) {
|
||||
return SQUARE_BRACKET_CLOSE;
|
||||
}
|
||||
if (open === CURLY_BRACKET_OPEN) {
|
||||
return CURLY_BRACKET_CLOSE;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
export function link<T extends { next?: T; prev?: T }>(next: T, prev: T) {
|
||||
prev.next = next;
|
||||
if (next) next.prev = prev;
|
||||
}
|
@ -0,0 +1 @@
|
||||
<div>Hello world</div>
|
@ -0,0 +1,2 @@
|
||||
<main>This should be thrown away</main>
|
||||
<div>hello</div>
|
@ -0,0 +1 @@
|
||||
export default {};
|
@ -0,0 +1 @@
|
||||
<div>Hello world</div>
|
@ -0,0 +1 @@
|
||||
<div>Hello world</div>
|
@ -0,0 +1 @@
|
||||
<main>This should be thrown away</main>
|
@ -0,0 +1 @@
|
||||
export default {};
|
@ -0,0 +1 @@
|
||||
<div>Hello world</div>
|
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
export let a;
|
||||
export function b() {}
|
||||
export let c = 1;
|
||||
|
||||
$: length = Object.keys($$restProps).length;
|
||||
$: values = Object.values($$restProps);
|
||||
</script>
|
||||
<div>Length: {length}</div>
|
||||
<div>Values: {values.join(',')}</div>
|
||||
|
||||
<div {...$$restProps} />
|
@ -0,0 +1,54 @@
|
||||
export default {
|
||||
props: {
|
||||
a: 3,
|
||||
b: 4,
|
||||
c: 5,
|
||||
d: 6
|
||||
},
|
||||
html: `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 4,5,1</div>
|
||||
<div d="4" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`,
|
||||
async test({ assert, target, window, }) {
|
||||
const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button');
|
||||
const clickEvent = new window.MouseEvent('click');
|
||||
|
||||
await btn1.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 4,5,1</div>
|
||||
<div d="4" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn2.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 34,5,1</div>
|
||||
<div d="34" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn3.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 34,5,31</div>
|
||||
<div d="34" e="5" foo="31"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn4.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 4</div>
|
||||
<div>Values: 34,5,31,2</div>
|
||||
<div d="34" e="5" foo="31" bar="2"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
}
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import App from './App.svelte';
|
||||
let a = 1, b = 2, c = 3, d = 4, e = 5;
|
||||
let f = { foo: 1 };
|
||||
|
||||
function updateProps() {
|
||||
a = 31;
|
||||
b = 32;
|
||||
}
|
||||
function updateRest() {
|
||||
d = 34;
|
||||
}
|
||||
function updateSpread() {
|
||||
f.foo = 31;
|
||||
}
|
||||
function updateSpread2() {
|
||||
f.bar = 2;
|
||||
}
|
||||
</script>
|
||||
|
||||
<App {a} {b} {c} {d} {e} {...f} />
|
||||
<button on:click={updateProps}></button>
|
||||
<button on:click={updateRest}></button>
|
||||
<button on:click={updateSpread}></button>
|
||||
<button on:click={updateSpread2}></button>
|
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
export let a;
|
||||
export function b() {}
|
||||
export let c = 1;
|
||||
|
||||
$: length = Object.keys($$restProps).length;
|
||||
$: values = Object.values($$restProps);
|
||||
</script>
|
||||
<div>Length: {length}</div>
|
||||
<div>Values: {values.join(',')}</div>
|
||||
|
||||
<div {...$$restProps} />
|
||||
<div {...$$props} />
|
@ -0,0 +1,60 @@
|
||||
export default {
|
||||
props: {
|
||||
a: 3,
|
||||
b: 4,
|
||||
c: 5,
|
||||
d: 6
|
||||
},
|
||||
html: `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 4,5,1</div>
|
||||
<div d="4" e="5" foo="1"></div>
|
||||
<div a="1" b="2" c="3" d="4" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`,
|
||||
|
||||
async test({ assert, target, window, }) {
|
||||
const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button');
|
||||
const clickEvent = new window.MouseEvent('click');
|
||||
|
||||
await btn1.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 4,5,1</div>
|
||||
<div d="4" e="5" foo="1"></div>
|
||||
<div a="31" b="32" c="3" d="4" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn2.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 34,5,1</div>
|
||||
<div d="34" e="5" foo="1"></div>
|
||||
<div a="31" b="32" c="3" d="34" e="5" foo="1"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn3.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 3</div>
|
||||
<div>Values: 34,5,31</div>
|
||||
<div d="34" e="5" foo="31"></div>
|
||||
<div a="31" b="32" c="3" d="34" e="5" foo="31"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
|
||||
await btn4.dispatchEvent(clickEvent);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>Length: 4</div>
|
||||
<div>Values: 34,5,31,2</div>
|
||||
<div d="34" e="5" foo="31" bar="2"></div>
|
||||
<div a="31" b="32" c="3" d="34" e="5" foo="31" bar="2"></div>
|
||||
<button></button><button></button><button></button><button></button>
|
||||
`);
|
||||
}
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import App from './App.svelte';
|
||||
let a = 1, b = 2, c = 3, d = 4, e = 5;
|
||||
let f = { foo: 1 };
|
||||
|
||||
function updateProps() {
|
||||
a = 31;
|
||||
b = 32;
|
||||
}
|
||||
function updateRest() {
|
||||
d = 34;
|
||||
}
|
||||
function updateSpread() {
|
||||
f.foo = 31;
|
||||
}
|
||||
function updateSpread2() {
|
||||
f.bar = 2;
|
||||
}
|
||||
</script>
|
||||
|
||||
<App {a} {b} {c} {d} {e} {...f} />
|
||||
<button on:click={updateProps}></button>
|
||||
<button on:click={updateRest}></button>
|
||||
<button on:click={updateSpread}></button>
|
||||
<button on:click={updateSpread2}></button>
|
@ -0,0 +1,61 @@
|
||||
export default {
|
||||
props: {
|
||||
thePromise: new Promise(resolve => {})
|
||||
},
|
||||
|
||||
html: `
|
||||
loading...
|
||||
`,
|
||||
|
||||
async test({ assert, component, target }) {
|
||||
await (component.thePromise = Promise.resolve([1, 2]));
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>a: 1</p>
|
||||
<p>b: 2</p>
|
||||
`
|
||||
);
|
||||
|
||||
await (component.thePromise = Promise.resolve([4, 5]));
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>a: 4</p>
|
||||
<p>b: 5</p>
|
||||
`
|
||||
);
|
||||
|
||||
try {
|
||||
await (component.thePromise = Promise.reject(['a', [6, 7]]));
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>c: a</p>
|
||||
<p>d: 6</p>
|
||||
<p>e: 7</p>
|
||||
`
|
||||
);
|
||||
|
||||
try {
|
||||
await (component.thePromise = Promise.reject(['b', [8, 9]]));
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>c: b</p>
|
||||
<p>d: 8</p>
|
||||
<p>e: 9</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let thePromise;
|
||||
</script>
|
||||
|
||||
{#await thePromise}
|
||||
loading...
|
||||
{:then [ a, b ]}
|
||||
<p>a: {a}</p>
|
||||
<p>b: {b}</p>
|
||||
{:catch [c, [d, e]]}
|
||||
<p>c: {c}</p>
|
||||
<p>d: {d}</p>
|
||||
<p>e: {e}</p>
|
||||
{/await}
|