mirror of https://github.com/sveltejs/svelte
commit
df3b6c0ca6
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': minor
|
||||
---
|
||||
|
||||
feat: export `parseCss` from `svelte/compiler`
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: trigger `selectedcontent` reactivity
|
||||
@ -1,91 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { busy } from './util.js';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let computed1 = $.derived(() => $.get(head));
|
||||
let computed2 = $.derived(() => ($.get(computed1), 0));
|
||||
let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation
|
||||
let computed4 = $.derived(() => $.get(computed3) + 2);
|
||||
let computed5 = $.derived(() => $.get(computed4) + 3);
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(computed5);
|
||||
busy(); // heavy side effect
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(computed5) === 6);
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(computed5) === 6);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_avoidable_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_avoidable_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_avoidable_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_avoidable_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let last = head;
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let current = $.derived(() => {
|
||||
return $.get(head) + i;
|
||||
});
|
||||
let current2 = $.derived(() => {
|
||||
return $.get(current) + 1;
|
||||
});
|
||||
$.render_effect(() => {
|
||||
$.get(current2);
|
||||
counter++;
|
||||
});
|
||||
last = current2;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(last) === i + 50);
|
||||
}
|
||||
assert(counter === 50 * 50);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_broad_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_broad_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_broad_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_broad_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let len = 50;
|
||||
const iter = 50;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let c = current;
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < iter; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(current) === len + i);
|
||||
}
|
||||
assert(counter === iter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_deep_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_deep_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_deep_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_deep_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 5;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
current.push(
|
||||
$.derived(() => {
|
||||
return $.get(head) + 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(sum) === 2 * width);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 500; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(sum) === (i + 1) * width);
|
||||
}
|
||||
assert(counter === 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_diamond_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_diamond_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_diamond_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_diamond_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let heads = new Array(100).fill(null).map((_) => $.state(0));
|
||||
const mux = $.derived(() => {
|
||||
return Object.fromEntries(heads.map((h) => $.get(h)).entries());
|
||||
});
|
||||
const splited = heads
|
||||
.map((_, index) => $.derived(() => $.get(mux)[index]))
|
||||
.map((x) => $.derived(() => $.get(x) + 1));
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
splited.forEach((x) => {
|
||||
$.render_effect(() => {
|
||||
$.get(x);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i);
|
||||
});
|
||||
assert($.get(splited[i]) === i + 1);
|
||||
}
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i * 2);
|
||||
});
|
||||
assert($.get(splited[i]) === i * 2 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_mux_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_mux_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_mux_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_mux_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let size = 30;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
result += $.get(head);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(current) === size);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(current) === i * size);
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_repeated_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_repeated_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_repeated_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_repeated_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,111 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 10;
|
||||
|
||||
function count(number) {
|
||||
return new Array(number)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1)
|
||||
.reduce((x, y) => x + y, 0);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
let list = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
let c = current;
|
||||
list.push(current);
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
const constant = count(width);
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(sum) === constant);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(sum) === constant - width + i * width);
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_triangle_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_triangle_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_triangle_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_triangle_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
const double = $.derived(() => $.get(head) * 2);
|
||||
const inverse = $.derived(() => -$.get(head));
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < 20; i++) {
|
||||
result += $.get(head) % 2 ? $.get(double) : $.get(inverse);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(current) === 40);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_unstable_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_unstable_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_unstable_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_unstable_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
export function busy() {
|
||||
let a = 0;
|
||||
for (let i = 0; i < 1_00; i++) {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { busy } from '../util.js';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let computed1 = $.derived(() => $.get(head));
|
||||
let computed2 = $.derived(() => ($.get(computed1), 0));
|
||||
let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation
|
||||
let computed4 = $.derived(() => $.get(computed3) + 2);
|
||||
let computed5 = $.derived(() => $.get(computed4) + 3);
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(computed5);
|
||||
busy(); // heavy side effect
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(computed5), 6);
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(computed5), 6);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let last = head;
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let current = $.derived(() => {
|
||||
return $.get(head) + i;
|
||||
});
|
||||
let current2 = $.derived(() => {
|
||||
return $.get(current) + 1;
|
||||
});
|
||||
$.render_effect(() => {
|
||||
$.get(current2);
|
||||
counter++;
|
||||
});
|
||||
last = current2;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(last), i + 50);
|
||||
}
|
||||
assert.equal(counter, 50 * 50);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let len = 50;
|
||||
const iter = 50;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let c = current;
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < iter; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(current), len + i);
|
||||
}
|
||||
assert.equal(counter, iter);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,45 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 5;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
current.push(
|
||||
$.derived(() => {
|
||||
return $.get(head) + 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(sum), 2 * width);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 500; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(sum), (i + 1) * width);
|
||||
}
|
||||
assert.equal(counter, 500);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,38 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let heads = new Array(100).fill(null).map((_) => $.state(0));
|
||||
const mux = $.derived(() => {
|
||||
return Object.fromEntries(heads.map((h) => $.get(h)).entries());
|
||||
});
|
||||
const splited = heads
|
||||
.map((_, index) => $.derived(() => $.get(mux)[index]))
|
||||
.map((x) => $.derived(() => $.get(x) + 1));
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
splited.forEach((x) => {
|
||||
$.render_effect(() => {
|
||||
$.get(x);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i);
|
||||
});
|
||||
assert.equal($.get(splited[i]), i + 1);
|
||||
}
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i * 2);
|
||||
});
|
||||
assert.equal($.get(splited[i]), i * 2 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,42 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let size = 30;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
result += $.get(head);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(current), size);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(current), i * size);
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 10;
|
||||
|
||||
function count(number) {
|
||||
return new Array(number)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1)
|
||||
.reduce((x, y) => x + y, 0);
|
||||
}
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
let list = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
let c = current;
|
||||
list.push(current);
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
const constant = count(width);
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(sum), constant);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(sum), constant - width + i * width);
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
const double = $.derived(() => $.get(head) * 2);
|
||||
const inverse = $.derived(() => -$.get(head));
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < 20; i++) {
|
||||
result += $.get(head) % 2 ? $.get(double) : $.get(inverse);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(current), 40);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,35 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
const ARRAY_SIZE = 1000;
|
||||
|
||||
export default () => {
|
||||
const signals = Array.from({ length: ARRAY_SIZE }, (_, i) => $.state(i));
|
||||
const order = $.state(0);
|
||||
|
||||
// break skipped_deps fast path by changing order of reads
|
||||
const total = $.derived(() => {
|
||||
const ord = $.get(order);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < ARRAY_SIZE; i++) {
|
||||
sum += /** @type {number} */ ($.get(signals[(i + ord) % ARRAY_SIZE]));
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(total);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
$.flush(() => $.set(order, i));
|
||||
assert.equal($.get(total), (ARRAY_SIZE * (ARRAY_SIZE - 1)) / 2); // sum of 0..999
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,71 @@
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { fastest_test } from '../../utils.js';
|
||||
|
||||
export function busy() {
|
||||
let a = 0;
|
||||
for (let i = 0; i < 1_00; i++) {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} label
|
||||
* @param {() => { run: (i?: number) => void, destroy: () => void }} setup
|
||||
*/
|
||||
export function create_test(label, setup) {
|
||||
return {
|
||||
unowned: {
|
||||
label: `${label}_unowned`,
|
||||
fn: async () => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run(0);
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const result = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run(i);
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return result;
|
||||
}
|
||||
},
|
||||
owned: {
|
||||
label: `${label}_owned`,
|
||||
fn: async () => {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run(0);
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const result = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run(i);
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
import { reactivity_benchmarks } from '../benchmarks/reactivity/index.js';
|
||||
|
||||
const results = [];
|
||||
for (const benchmark of reactivity_benchmarks) {
|
||||
const result = await benchmark();
|
||||
console.error(result.benchmark);
|
||||
results.push(result);
|
||||
|
||||
for (let i = 0; i < reactivity_benchmarks.length; i += 1) {
|
||||
const benchmark = reactivity_benchmarks[i];
|
||||
|
||||
process.stderr.write(`Running ${i + 1}/${reactivity_benchmarks.length} ${benchmark.label} `);
|
||||
results.push({ benchmark: benchmark.label, ...(await benchmark.fn()) });
|
||||
process.stderr.write('\x1b[2K\r');
|
||||
}
|
||||
|
||||
process.send(results);
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
import { assert, describe, it } from 'vitest';
|
||||
import { parseCss } from 'svelte/compiler';
|
||||
|
||||
describe('parseCss', () => {
|
||||
it('parses a simple rule', () => {
|
||||
const ast = parseCss('div { color: red; }');
|
||||
assert.equal(ast.type, 'StyleSheet');
|
||||
assert.equal(ast.children.length, 1);
|
||||
assert.equal(ast.children[0].type, 'Rule');
|
||||
});
|
||||
|
||||
it('parses at-rules', () => {
|
||||
const ast = parseCss('@media (min-width: 800px) { div { color: red; } }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
assert.equal(ast.children[0].type, 'Atrule');
|
||||
if (ast.children[0].type === 'Atrule') {
|
||||
assert.equal(ast.children[0].name, 'media');
|
||||
}
|
||||
});
|
||||
|
||||
it('parses @import', () => {
|
||||
const ast = parseCss("@import 'foo.css';");
|
||||
assert.equal(ast.children.length, 1);
|
||||
assert.equal(ast.children[0].type, 'Atrule');
|
||||
if (ast.children[0].type === 'Atrule') {
|
||||
assert.equal(ast.children[0].name, 'import');
|
||||
assert.equal(ast.children[0].block, null);
|
||||
}
|
||||
});
|
||||
|
||||
it('parses multiple rules', () => {
|
||||
const ast = parseCss('div { color: red; } span { color: blue; }');
|
||||
assert.equal(ast.children.length, 2);
|
||||
});
|
||||
|
||||
it('has correct start/end positions', () => {
|
||||
const ast = parseCss('div { color: red; }');
|
||||
assert.equal(ast.start, 0);
|
||||
assert.equal(ast.end, 19);
|
||||
});
|
||||
|
||||
it('strips BOM', () => {
|
||||
const ast = parseCss('\uFEFFdiv { color: red; }');
|
||||
assert.equal(ast.start, 0);
|
||||
assert.equal(ast.end, 19);
|
||||
});
|
||||
|
||||
it('parses nested rules', () => {
|
||||
const ast = parseCss('div { color: red; span { color: blue; } }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
const rule = ast.children[0];
|
||||
assert.equal(rule.type, 'Rule');
|
||||
if (rule.type === 'Rule') {
|
||||
assert.equal(rule.block.children.length, 2); // declaration + nested rule
|
||||
}
|
||||
});
|
||||
|
||||
it('parses empty stylesheet', () => {
|
||||
const ast = parseCss('');
|
||||
assert.equal(ast.type, 'StyleSheet');
|
||||
assert.equal(ast.children.length, 0);
|
||||
assert.equal(ast.start, 0);
|
||||
assert.equal(ast.end, 0);
|
||||
});
|
||||
|
||||
it('parses whitespace-only stylesheet', () => {
|
||||
const ast = parseCss(' \n\t ');
|
||||
assert.equal(ast.children.length, 0);
|
||||
});
|
||||
|
||||
it('parses comments', () => {
|
||||
const ast = parseCss('/* comment */ div { color: red; }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
assert.equal(ast.children[0].type, 'Rule');
|
||||
});
|
||||
|
||||
it('parses complex selectors', () => {
|
||||
const ast = parseCss('div > span + p ~ a { color: red; }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
const rule = ast.children[0];
|
||||
if (rule.type === 'Rule') {
|
||||
assert.equal(rule.prelude.type, 'SelectorList');
|
||||
assert.equal(rule.prelude.children.length, 1);
|
||||
// div > span + p ~ a has 4 relative selectors
|
||||
assert.equal(rule.prelude.children[0].children.length, 4);
|
||||
}
|
||||
});
|
||||
|
||||
it('parses pseudo-classes and pseudo-elements', () => {
|
||||
const ast = parseCss('div:hover::before { color: red; }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
const rule = ast.children[0];
|
||||
if (rule.type === 'Rule') {
|
||||
const selectors = rule.prelude.children[0].children[0].selectors;
|
||||
assert.equal(selectors.length, 3); // div, :hover, ::before
|
||||
assert.equal(selectors[0].type, 'TypeSelector');
|
||||
assert.equal(selectors[1].type, 'PseudoClassSelector');
|
||||
assert.equal(selectors[2].type, 'PseudoElementSelector');
|
||||
}
|
||||
});
|
||||
|
||||
it('parses @keyframes', () => {
|
||||
const ast = parseCss('@keyframes fade { from { opacity: 0; } to { opacity: 1; } }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
assert.equal(ast.children[0].type, 'Atrule');
|
||||
if (ast.children[0].type === 'Atrule') {
|
||||
assert.equal(ast.children[0].name, 'keyframes');
|
||||
assert.notEqual(ast.children[0].block, null);
|
||||
}
|
||||
});
|
||||
|
||||
it('parses class and id selectors', () => {
|
||||
const ast = parseCss('.foo#bar { color: red; }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
const rule = ast.children[0];
|
||||
if (rule.type === 'Rule') {
|
||||
const selectors = rule.prelude.children[0].children[0].selectors;
|
||||
assert.equal(selectors.length, 2);
|
||||
assert.equal(selectors[0].type, 'ClassSelector');
|
||||
assert.equal(selectors[1].type, 'IdSelector');
|
||||
}
|
||||
});
|
||||
|
||||
it('parses attribute selectors', () => {
|
||||
const ast = parseCss('[data-foo="bar"] { color: red; }');
|
||||
assert.equal(ast.children.length, 1);
|
||||
const rule = ast.children[0];
|
||||
if (rule.type === 'Rule') {
|
||||
const selectors = rule.prelude.children[0].children[0].selectors;
|
||||
assert.equal(selectors.length, 1);
|
||||
assert.equal(selectors[0].type, 'AttributeSelector');
|
||||
if (selectors[0].type === 'AttributeSelector') {
|
||||
assert.equal(selectors[0].name, 'data-foo');
|
||||
assert.equal(selectors[0].value, 'bar');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue