diff --git a/.changeset/afraid-geckos-dance.md b/.changeset/afraid-geckos-dance.md new file mode 100644 index 0000000000..944f321cc9 --- /dev/null +++ b/.changeset/afraid-geckos-dance.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: add `anchor` support to mount() API diff --git a/.changeset/big-moons-occur.md b/.changeset/big-moons-occur.md new file mode 100644 index 0000000000..42429d31f6 --- /dev/null +++ b/.changeset/big-moons-occur.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: improve unowned derived signal heuristics diff --git a/.changeset/brave-walls-flow.md b/.changeset/brave-walls-flow.md new file mode 100644 index 0000000000..c00bdf37f9 --- /dev/null +++ b/.changeset/brave-walls-flow.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: improved effect sequencing and execution order diff --git a/.changeset/brown-houses-obey.md b/.changeset/brown-houses-obey.md new file mode 100644 index 0000000000..65c1ce4289 --- /dev/null +++ b/.changeset/brown-houses-obey.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: further improvements to effect scheduling and flushing diff --git a/.changeset/cool-peas-lick.md b/.changeset/cool-peas-lick.md new file mode 100644 index 0000000000..4b3e562c46 --- /dev/null +++ b/.changeset/cool-peas-lick.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: onDestroy functions run child-first diff --git a/.changeset/curvy-flies-exercise.md b/.changeset/curvy-flies-exercise.md new file mode 100644 index 0000000000..bcdbe1b448 --- /dev/null +++ b/.changeset/curvy-flies-exercise.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure correct context for action update/destroy functions diff --git a/.changeset/dry-pillows-exist.md b/.changeset/dry-pillows-exist.md new file mode 100644 index 0000000000..dab22ccef1 --- /dev/null +++ b/.changeset/dry-pillows-exist.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient hydration markers diff --git a/.changeset/eleven-beers-yell.md b/.changeset/eleven-beers-yell.md new file mode 100644 index 0000000000..9f38d30e9c --- /dev/null +++ b/.changeset/eleven-beers-yell.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: use implicit return for each block keys diff --git a/.changeset/few-clouds-shop.md b/.changeset/few-clouds-shop.md new file mode 100644 index 0000000000..c21f6eef6c --- /dev/null +++ b/.changeset/few-clouds-shop.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: always run pre effects immediately diff --git a/.changeset/fuzzy-donuts-provide.md b/.changeset/fuzzy-donuts-provide.md new file mode 100644 index 0000000000..ae5333e6ec --- /dev/null +++ b/.changeset/fuzzy-donuts-provide.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure effect cleanup functions are called with null `this` diff --git a/.changeset/grumpy-jars-sparkle.md b/.changeset/grumpy-jars-sparkle.md new file mode 100644 index 0000000000..8cf5bd877b --- /dev/null +++ b/.changeset/grumpy-jars-sparkle.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: correctly handle closure passed to $derived.by when destructuring diff --git a/.changeset/hot-jobs-tap.md b/.changeset/hot-jobs-tap.md new file mode 100644 index 0000000000..006b6fd106 --- /dev/null +++ b/.changeset/hot-jobs-tap.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: improve order of pre-effect execution diff --git a/.changeset/itchy-bulldogs-tan.md b/.changeset/itchy-bulldogs-tan.md new file mode 100644 index 0000000000..94d5922ec7 --- /dev/null +++ b/.changeset/itchy-bulldogs-tan.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: improve action support for nested $effect diff --git a/.changeset/late-peaches-mate.md b/.changeset/late-peaches-mate.md new file mode 100644 index 0000000000..d3009920e4 --- /dev/null +++ b/.changeset/late-peaches-mate.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +Add `name` to HTMLDetailsAttributes diff --git a/.changeset/long-humans-repair.md b/.changeset/long-humans-repair.md new file mode 100644 index 0000000000..e295d41ba6 --- /dev/null +++ b/.changeset/long-humans-repair.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: prevent unparenthesized sequence expressions in attributes diff --git a/.changeset/loud-mugs-smile.md b/.changeset/loud-mugs-smile.md new file mode 100644 index 0000000000..e8fca01a49 --- /dev/null +++ b/.changeset/loud-mugs-smile.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: expose 'svelte/internal' to prevent Vite erroring on startup diff --git a/.changeset/lovely-houses-own.md b/.changeset/lovely-houses-own.md new file mode 100644 index 0000000000..d8de72b4a9 --- /dev/null +++ b/.changeset/lovely-houses-own.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: reliably remove undefined attributes during hydration diff --git a/.changeset/many-rockets-give.md b/.changeset/many-rockets-give.md new file mode 100644 index 0000000000..b26d8ef64f --- /dev/null +++ b/.changeset/many-rockets-give.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient if block compiler output diff --git a/.changeset/metal-clouds-raise.md b/.changeset/metal-clouds-raise.md new file mode 100644 index 0000000000..9693100fb3 --- /dev/null +++ b/.changeset/metal-clouds-raise.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +breaking: move compiler.cjs to compiler/index.js diff --git a/.changeset/metal-lobsters-burn.md b/.changeset/metal-lobsters-burn.md new file mode 100644 index 0000000000..b1e241554e --- /dev/null +++ b/.changeset/metal-lobsters-burn.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: update type of `options.target` diff --git a/.changeset/neat-files-rescue.md b/.changeset/neat-files-rescue.md new file mode 100644 index 0000000000..667e70ddfc --- /dev/null +++ b/.changeset/neat-files-rescue.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: re-export built-ins from `svelte/reactivity` on the server diff --git a/.changeset/new-brooms-grin.md b/.changeset/new-brooms-grin.md new file mode 100644 index 0000000000..e69482dfa7 --- /dev/null +++ b/.changeset/new-brooms-grin.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: ensure transition errors are not swallowed diff --git a/.changeset/pre.json b/.changeset/pre.json index 0921244615..53fe075d59 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -21,15 +21,18 @@ "big-eggs-flash", "big-eyes-carry", "big-geese-act", + "big-moons-occur", "blue-ants-raise", "blue-rules-juggle", "blue-timers-film", "brave-points-sleep", "brave-shrimps-kiss", "brave-walls-destroy", + "brave-walls-flow", "breezy-carrots-flash", "bright-peas-juggle", "bright-snakes-sing", + "brown-houses-obey", "brown-months-fry", "brown-spoons-boil", "calm-ravens-sneeze", @@ -46,12 +49,14 @@ "cold-birds-own", "cold-masks-learn", "cool-ants-leave", + "cool-peas-lick", "cool-rabbits-tickle", "cool-roses-trade", "cuddly-pianos-drop", "curly-lizards-dream", "curvy-buses-laugh", "curvy-cups-cough", + "curvy-flies-exercise", "curvy-ties-shout", "cyan-flowers-destroy", "cyan-spies-grin", @@ -62,6 +67,7 @@ "dry-clocks-grow", "dry-eggs-play", "dry-eggs-retire", + "dry-pillows-exist", "dull-coins-vanish", "dull-mangos-wave", "dull-pots-add", @@ -70,6 +76,7 @@ "eight-steaks-shout", "eighty-bikes-camp", "eighty-days-cheat", + "eleven-beers-yell", "eleven-cycles-applaud", "empty-bags-heal", "empty-bulldogs-exercise", @@ -82,6 +89,7 @@ "famous-knives-sneeze", "famous-pants-pay", "fast-weeks-clean", + "few-clouds-shop", "few-mugs-fail", "fifty-rice-wait", "fifty-steaks-float", @@ -101,6 +109,7 @@ "friendly-lies-camp", "funny-wombats-argue", "fuzzy-bags-camp", + "fuzzy-donuts-provide", "gentle-dolls-juggle", "gentle-sheep-hug", "gentle-spies-happen", @@ -117,6 +126,7 @@ "green-eggs-approve", "green-hounds-play", "green-tigers-judge", + "grumpy-jars-sparkle", "happy-beds-scream", "happy-suits-film", "healthy-planes-vanish", @@ -126,12 +136,14 @@ "honest-buses-add", "honest-dragons-turn", "honest-icons-change", + "hot-jobs-tap", "hungry-boxes-relate", "hungry-dots-fry", "hungry-singers-share", "hungry-tips-unite", "hungry-trees-travel", "itchy-beans-melt", + "itchy-bulldogs-tan", "itchy-kings-deliver", "itchy-lions-wash", "itchy-terms-guess", @@ -148,6 +160,7 @@ "large-clouds-carry", "large-turkeys-deny", "late-crabs-lay", + "late-peaches-mate", "lazy-masks-sit", "lazy-months-knock", "lazy-spiders-think", @@ -159,15 +172,21 @@ "little-pans-jog", "long-buckets-lay", "long-crews-return", + "long-humans-repair", "long-lobsters-mate", "loud-cheetahs-flow", + "loud-mugs-smile", "loud-ravens-drop", "lovely-carpets-lick", + "lovely-houses-own", "lovely-items-turn", "lovely-rules-eat", "lucky-schools-hang", "lucky-toes-begin", + "many-rockets-give", "many-trees-fix", + "metal-clouds-raise", + "metal-lobsters-burn", "mighty-cooks-scream", "mighty-files-hammer", "moody-carrots-lay", @@ -179,8 +198,10 @@ "nasty-yaks-peel", "neat-boats-shake", "neat-dingos-clap", + "neat-files-rescue", "nervous-spoons-relax", "new-boats-wait", + "new-brooms-grin", "new-rabbits-flow", "nice-avocados-move", "ninety-dingos-walk", @@ -223,8 +244,10 @@ "real-guests-do", "real-items-suffer", "real-pandas-brush", + "red-cycles-pretend", "red-doors-own", "red-feet-worry", + "red-poets-study", "rich-cobras-exist", "rich-olives-yell", "rich-sheep-burn", @@ -239,8 +262,10 @@ "selfish-dragons-knock", "selfish-spies-help", "selfish-tools-hide", + "serious-gorillas-eat", "serious-kids-deliver", "serious-needles-joke", + "serious-poems-brake", "serious-socks-cover", "serious-zebras-scream", "seven-deers-jam", @@ -258,6 +283,8 @@ "short-countries-rush", "silent-apes-report", "silly-laws-happen", + "silly-lies-film", + "silly-ways-wash", "silver-points-approve", "sixty-items-crash", "slimy-clouds-talk", @@ -266,9 +293,12 @@ "slow-beds-shave", "slow-chefs-dream", "slow-kids-sparkle", + "slow-plums-chew", "slow-wombats-reply", "small-papayas-laugh", "small-sheep-type", + "small-spiders-fail", + "smart-cherries-leave", "smart-parents-swim", "smart-turkeys-tell", "smart-zebras-pay", @@ -290,6 +320,7 @@ "spotty-turkeys-sparkle", "stale-books-perform", "stale-comics-look", + "stale-fans-rest", "stale-jeans-refuse", "strange-apricots-happen", "strong-gifts-smoke", @@ -300,6 +331,7 @@ "swift-donkeys-perform", "swift-fans-stare", "swift-feet-juggle", + "swift-poets-carry", "swift-ravens-hunt", "swift-seahorses-deliver", "tall-books-grin", @@ -316,6 +348,7 @@ "ten-foxes-repeat", "ten-jokes-divide", "ten-peaches-sleep", + "ten-singers-cough", "ten-ties-repair", "ten-worms-reflect", "thick-cycles-rule", @@ -328,7 +361,9 @@ "thirty-pears-hug", "thirty-wombats-relax", "three-camels-sell", + "three-foxes-relax", "three-icons-trade", + "three-lions-visit", "three-papayas-buy", "three-suits-grin", "tidy-buses-whisper", @@ -351,6 +386,7 @@ "wicked-doors-train", "wicked-hairs-cheer", "wild-foxes-wonder", + "wild-moose-compare", "wise-apples-care", "wise-dancers-hang", "wise-dodos-tell", diff --git a/.changeset/red-cycles-pretend.md b/.changeset/red-cycles-pretend.md new file mode 100644 index 0000000000..58307066bc --- /dev/null +++ b/.changeset/red-cycles-pretend.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: Add `elementtiming` HTMLAttribute, remove `crossorigin` from HTMLInputAttributes diff --git a/.changeset/red-poets-study.md b/.changeset/red-poets-study.md new file mode 100644 index 0000000000..3a9338f32a --- /dev/null +++ b/.changeset/red-poets-study.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: allow runes for variable declarations in the template diff --git a/.changeset/serious-gorillas-eat.md b/.changeset/serious-gorillas-eat.md new file mode 100644 index 0000000000..407f2e6db8 --- /dev/null +++ b/.changeset/serious-gorillas-eat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly hydrate controlled each-else block diff --git a/.changeset/serious-poems-brake.md b/.changeset/serious-poems-brake.md new file mode 100644 index 0000000000..824bc825b8 --- /dev/null +++ b/.changeset/serious-poems-brake.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: revert SSR shorthand comments diff --git a/.changeset/silly-lies-film.md b/.changeset/silly-lies-film.md new file mode 100644 index 0000000000..4fa473f6f6 --- /dev/null +++ b/.changeset/silly-lies-film.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: child effects are removed from parent branches diff --git a/.changeset/silly-ways-wash.md b/.changeset/silly-ways-wash.md new file mode 100644 index 0000000000..5157693e80 --- /dev/null +++ b/.changeset/silly-ways-wash.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +feat: take form resets into account for two way bindings diff --git a/.changeset/slow-plums-chew.md b/.changeset/slow-plums-chew.md new file mode 100644 index 0000000000..94908bb9b9 --- /dev/null +++ b/.changeset/slow-plums-chew.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: handle multiple snippet parameters with one or more being optional diff --git a/.changeset/smart-cherries-leave.md b/.changeset/smart-cherries-leave.md new file mode 100644 index 0000000000..d844352c7f --- /dev/null +++ b/.changeset/smart-cherries-leave.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: hydrate HTML with surrounding whitespace diff --git a/.changeset/stale-fans-rest.md b/.changeset/stale-fans-rest.md new file mode 100644 index 0000000000..5e7f36b338 --- /dev/null +++ b/.changeset/stale-fans-rest.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: shorter compiler output for attribute updates diff --git a/.changeset/swift-poets-carry.md b/.changeset/swift-poets-carry.md new file mode 100644 index 0000000000..0cb65a9389 --- /dev/null +++ b/.changeset/swift-poets-carry.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: faster HTML tags diff --git a/.changeset/ten-singers-cough.md b/.changeset/ten-singers-cough.md new file mode 100644 index 0000000000..429a327f74 --- /dev/null +++ b/.changeset/ten-singers-cough.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: Add `dirname` to HTMLInputAttributes diff --git a/.changeset/three-foxes-relax.md b/.changeset/three-foxes-relax.md new file mode 100644 index 0000000000..2ad4443e30 --- /dev/null +++ b/.changeset/three-foxes-relax.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: apply animate on prefix/suffix each block mutations diff --git a/.changeset/three-lions-visit.md b/.changeset/three-lions-visit.md new file mode 100644 index 0000000000..a1576a4797 --- /dev/null +++ b/.changeset/three-lions-visit.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient each block compiler output diff --git a/.changeset/wild-moose-compare.md b/.changeset/wild-moose-compare.md new file mode 100644 index 0000000000..b50650c9d8 --- /dev/null +++ b/.changeset/wild-moose-compare.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: include compiler/package.json in package diff --git a/.eslintignore b/.eslintignore index fbab8fbc0d..3b486d3f07 100644 --- a/.eslintignore +++ b/.eslintignore @@ -11,6 +11,7 @@ **/vite.config.js **/vite.prod.config.js **/node_modules +**/compiler/index.js **/tests/** @@ -20,4 +21,4 @@ documentation/** # contains a fork of the REPL which doesn't adhere to eslint rules sites/svelte-5-preview/** # Wasn't checked previously, reenable at some point -sites/svelte.dev/** +sites/svelte.dev/** diff --git a/.prettierignore b/.prettierignore index 45e12c6e3f..558f1fcb85 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,12 +10,10 @@ packages/svelte/tests/**/_actual* packages/svelte/tests/**/expected* packages/svelte/tests/**/_output packages/svelte/tests/**/shards/*.test.js -packages/svelte/tests/hydration/samples/*/_before.html -packages/svelte/tests/hydration/samples/*/_before_head.html -packages/svelte/tests/hydration/samples/*/_after.html -packages/svelte/tests/hydration/samples/*/_after_head.html +packages/svelte/tests/hydration/samples/*/_expected.html +packages/svelte/tests/hydration/samples/*/_override.html packages/svelte/types -packages/svelte/compiler.cjs +packages/svelte/compiler/index.js playgrounds/demo/src playgrounds/sandbox/input/**.svelte playgrounds/sandbox/output diff --git a/package.json b/package.json index 6dd8df2856..0b5d4cac7e 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "eslint": "^8.56.0", "eslint-plugin-lube": "^0.4.3", "jsdom": "22.0.0", - "playwright": "^1.35.1", + "playwright": "^1.41.1", "prettier": "^3.2.4", "prettier-plugin-svelte": "^3.1.2", "typescript": "^5.3.3", diff --git a/packages/svelte/.gitignore b/packages/svelte/.gitignore index 8b3d7652a1..d0c4ba8d61 100644 --- a/packages/svelte/.gitignore +++ b/packages/svelte/.gitignore @@ -1,6 +1,6 @@ /types/*.map /types/compiler -/compiler.cjs +/compiler/index.js /action.d.ts /animate.d.ts diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 56ef4d3af2..a21bdac84e 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,125 @@ # svelte +## 5.0.0-next.93 + +### Patch Changes + +- breaking: prevent unparenthesized sequence expressions in attributes ([#11032](https://github.com/sveltejs/svelte/pull/11032)) + +- fix: ensure transition errors are not swallowed ([#11039](https://github.com/sveltejs/svelte/pull/11039)) + +## 5.0.0-next.92 + +### Patch Changes + +- fix: include compiler/package.json in package ([#11033](https://github.com/sveltejs/svelte/pull/11033)) + +## 5.0.0-next.91 + +### Patch Changes + +- fix: improve unowned derived signal heuristics ([#11029](https://github.com/sveltejs/svelte/pull/11029)) + +- fix: ensure correct context for action update/destroy functions ([#11023](https://github.com/sveltejs/svelte/pull/11023)) + +- feat: more efficient hydration markers ([#11019](https://github.com/sveltejs/svelte/pull/11019)) + +- fix: ensure effect cleanup functions are called with null `this` ([#11024](https://github.com/sveltejs/svelte/pull/11024)) + +- fix: correctly handle closure passed to $derived.by when destructuring ([#11028](https://github.com/sveltejs/svelte/pull/11028)) + +- Add `name` to HTMLDetailsAttributes ([#11013](https://github.com/sveltejs/svelte/pull/11013)) + +- breaking: move compiler.cjs to compiler/index.js ([#10988](https://github.com/sveltejs/svelte/pull/10988)) + +## 5.0.0-next.90 + +### Patch Changes + +- fix: hydrate HTML with surrounding whitespace ([#10996](https://github.com/sveltejs/svelte/pull/10996)) + +- feat: faster HTML tags ([#10986](https://github.com/sveltejs/svelte/pull/10986)) + +## 5.0.0-next.89 + +### Patch Changes + +- fix: expose 'svelte/internal' to prevent Vite erroring on startup ([#10987](https://github.com/sveltejs/svelte/pull/10987)) + +- fix: revert SSR shorthand comments ([#10980](https://github.com/sveltejs/svelte/pull/10980)) + +- fix: child effects are removed from parent branches ([#10985](https://github.com/sveltejs/svelte/pull/10985)) + +## 5.0.0-next.88 + +### Patch Changes + +- fix: further improvements to effect scheduling and flushing ([#10971](https://github.com/sveltejs/svelte/pull/10971)) + +- feat: re-export built-ins from `svelte/reactivity` on the server ([#10973](https://github.com/sveltejs/svelte/pull/10973)) + +## 5.0.0-next.87 + +### Patch Changes + +- fix: apply animate on prefix/suffix each block mutations ([#10965](https://github.com/sveltejs/svelte/pull/10965)) + +## 5.0.0-next.86 + +### Patch Changes + +- fix: improved effect sequencing and execution order ([#10949](https://github.com/sveltejs/svelte/pull/10949)) + +- breaking: onDestroy functions run child-first ([#10949](https://github.com/sveltejs/svelte/pull/10949)) + +- fix: improve action support for nested $effect ([#10962](https://github.com/sveltejs/svelte/pull/10962)) + +## 5.0.0-next.85 + +### Patch Changes + +- feat: use implicit return for each block keys ([#10938](https://github.com/sveltejs/svelte/pull/10938)) + +- breaking: always run pre effects immediately ([#10928](https://github.com/sveltejs/svelte/pull/10928)) + +- fix: improve order of pre-effect execution ([#10942](https://github.com/sveltejs/svelte/pull/10942)) + +- feat: more efficient each block compiler output ([#10937](https://github.com/sveltejs/svelte/pull/10937)) + +## 5.0.0-next.84 + +### Patch Changes + +- fix: reliably remove undefined attributes during hydration ([#10917](https://github.com/sveltejs/svelte/pull/10917)) + +- fix: Add `elementtiming` HTMLAttribute, remove `crossorigin` from HTMLInputAttributes ([#10921](https://github.com/sveltejs/svelte/pull/10921)) + +- feat: shorter compiler output for attribute updates ([#10917](https://github.com/sveltejs/svelte/pull/10917)) + +## 5.0.0-next.83 + +### Patch Changes + +- feat: more efficient if block compiler output ([#10906](https://github.com/sveltejs/svelte/pull/10906)) + +- fix: update type of `options.target` ([#10892](https://github.com/sveltejs/svelte/pull/10892)) + +- fix: correctly hydrate controlled each-else block ([#10887](https://github.com/sveltejs/svelte/pull/10887)) + +- fix: Add `dirname` to HTMLInputAttributes ([#10908](https://github.com/sveltejs/svelte/pull/10908)) + +## 5.0.0-next.82 + +### Patch Changes + +- fix: allow runes for variable declarations in the template ([#10879](https://github.com/sveltejs/svelte/pull/10879)) + +- feat: take form resets into account for two way bindings ([#10617](https://github.com/sveltejs/svelte/pull/10617)) + +- fix: handle multiple snippet parameters with one or more being optional ([#10833](https://github.com/sveltejs/svelte/pull/10833)) + +- breaking: apply fallback value every time in runes mode ([#10797](https://github.com/sveltejs/svelte/pull/10797)) + ## 5.0.0-next.81 ### Patch Changes diff --git a/packages/svelte/compiler/package.json b/packages/svelte/compiler/package.json new file mode 100644 index 0000000000..5bbefffbab --- /dev/null +++ b/packages/svelte/compiler/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/packages/svelte/elements.d.ts b/packages/svelte/elements.d.ts index 6883aa0205..0a6bcd4e78 100644 --- a/packages/svelte/elements.d.ts +++ b/packages/svelte/elements.d.ts @@ -712,6 +712,7 @@ export interface HTMLAttributes extends AriaAttributes, D contextmenu?: string | undefined | null; dir?: string | undefined | null; draggable?: Booleanish | undefined | null; + elementtiming?: string | undefined | null; enterkeyhint?: | 'enter' | 'done' @@ -905,6 +906,7 @@ export interface HTMLDataAttributes extends HTMLAttributes { export interface HTMLDetailsAttributes extends HTMLAttributes { open?: boolean | undefined | null; + name?: string | undefined | null; 'bind:open'?: boolean | undefined | null; @@ -1029,7 +1031,7 @@ export interface HTMLInputAttributes extends HTMLAttributes { autocomplete?: string | undefined | null; capture?: boolean | 'user' | 'environment' | undefined | null; // https://www.w3.org/TR/html-media-capture/#the-capture-attribute checked?: boolean | undefined | null; - crossorigin?: string | undefined | null; + dirname?: string | undefined | null; disabled?: boolean | undefined | null; form?: string | undefined | null; formaction?: string | undefined | null; diff --git a/packages/svelte/package.json b/packages/svelte/package.json index c7c2f1af04..c4bdbbab22 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.0.0-next.81", + "version": "5.0.0-next.93", "type": "module", "types": "./types/index.d.ts", "engines": { @@ -12,17 +12,17 @@ "src", "!src/**/*.test.*", "types", - "compiler.cjs", + "compiler", "*.d.ts", "README.md" ], - "module": "src/main/main-client.js", - "main": "src/main/main-client.js", + "module": "src/index-client.js", + "main": "src/index-client.js", "exports": { ".": { "types": "./types/index.d.ts", - "browser": "./src/main/main-client.js", - "default": "./src/main/main-server.js" + "browser": "./src/index-client.js", + "default": "./src/index-server.js" }, "./package.json": "./package.json", "./action": { @@ -34,7 +34,7 @@ }, "./compiler": { "types": "./types/index.d.ts", - "require": "./compiler.cjs", + "require": "./compiler/index.js", "default": "./src/compiler/index.js" }, "./easing": { @@ -47,6 +47,9 @@ "./internal": { "default": "./src/internal/index.js" }, + "./internal/client": { + "default": "./src/internal/client/index.js" + }, "./internal/disclose-version": { "default": "./src/internal/disclose-version.js" }, @@ -64,7 +67,8 @@ }, "./reactivity": { "types": "./types/index.d.ts", - "default": "./src/reactivity/index.js" + "browser": "./src/reactivity/index-client.js", + "default": "./src/reactivity/index-server.js" }, "./server": { "types": "./types/index.d.ts", @@ -137,7 +141,9 @@ "knip": { "entry": [ "src/*/index.js", - "src/*/public.d.ts" + "src/index-client.ts", + "src/index-server.ts", + "src/index.d.ts" ], "project": [ "src/**" diff --git a/packages/svelte/rollup.config.js b/packages/svelte/rollup.config.js index 5a9a220411..3e36190f9c 100644 --- a/packages/svelte/rollup.config.js +++ b/packages/svelte/rollup.config.js @@ -9,7 +9,7 @@ import './scripts/generate-version.js'; export default defineConfig({ input: 'src/compiler/index.js', output: { - file: 'compiler.cjs', + file: 'compiler/index.js', format: 'umd', name: 'svelte' }, diff --git a/packages/svelte/scripts/check-treeshakeability.js b/packages/svelte/scripts/check-treeshakeability.js index 9ded247b2b..6297dd535e 100644 --- a/packages/svelte/scripts/check-treeshakeability.js +++ b/packages/svelte/scripts/check-treeshakeability.js @@ -51,6 +51,7 @@ console.group('checking treeshakeability'); for (const key in pkg.exports) { // special cases if (key === './compiler') continue; + if (key === './internal') continue; if (key === './internal/disclose-version') continue; for (const type of ['browser', 'default']) { @@ -109,7 +110,7 @@ const bundle = await bundle_code( ).js.code ); -if (!bundle.includes('current_hydration_fragment')) { +if (!bundle.includes('hydrate_nodes') && !bundle.includes('hydrate_anchor')) { // eslint-disable-next-line no-console console.error(`✅ Hydration code treeshakeable`); } else { diff --git a/packages/svelte/scripts/generate-types.js b/packages/svelte/scripts/generate-types.js index 703180a143..c52693f5f3 100644 --- a/packages/svelte/scripts/generate-types.js +++ b/packages/svelte/scripts/generate-types.js @@ -22,14 +22,14 @@ fs.writeFileSync(`${dir}/types/compiler/interfaces.d.ts`, "import '../index.js'; await createBundle({ output: `${dir}/types/index.d.ts`, modules: { - [pkg.name]: `${dir}/src/main/public.d.ts`, + [pkg.name]: `${dir}/src/index.d.ts`, [`${pkg.name}/action`]: `${dir}/src/action/public.d.ts`, [`${pkg.name}/animate`]: `${dir}/src/animate/public.d.ts`, [`${pkg.name}/compiler`]: `${dir}/src/compiler/index.js`, [`${pkg.name}/easing`]: `${dir}/src/easing/index.js`, [`${pkg.name}/legacy`]: `${dir}/src/legacy/legacy-client.js`, [`${pkg.name}/motion`]: `${dir}/src/motion/public.d.ts`, - [`${pkg.name}/reactivity`]: `${dir}/src/reactivity/index.js`, + [`${pkg.name}/reactivity`]: `${dir}/src/reactivity/index-client.js`, [`${pkg.name}/server`]: `${dir}/src/server/index.js`, [`${pkg.name}/store`]: `${dir}/src/store/public.d.ts`, [`${pkg.name}/transition`]: `${dir}/src/transition/public.d.ts`, diff --git a/packages/svelte/src/main/ambient.d.ts b/packages/svelte/src/ambient.d.ts similarity index 92% rename from packages/svelte/src/main/ambient.d.ts rename to packages/svelte/src/ambient.d.ts index 1cb02f9f4d..a2ad6d63af 100644 --- a/packages/svelte/src/main/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -172,13 +172,24 @@ declare namespace $effect { * Declares the props that a component accepts. Example: * * ```ts - * let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props(); + * let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props(); * ``` * * https://svelte-5-preview.vercel.app/docs/runes#$props */ declare function $props(): any; +/** + * Declares a prop as bindable, meaning the parent component can use `bind:propName={value}` to bind to it. + * + * ```ts + * let { propName = $bindable() }: { propName: boolean } = $props(); + * ``` + * + * https://svelte-5-preview.vercel.app/docs/runes#$bindable + */ +declare function $bindable(t?: T): T; + /** * Inspects one or more values whenever they, or the properties they contain, change. Example: * diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 72397e1f6e..318225be95 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -182,6 +182,7 @@ const runes = { `$props() assignment must not contain nested properties or computed keys`, 'invalid-props-location': () => `$props() can only be used at the top level of components as a variable declaration initializer`, + 'invalid-bindable-location': () => `$bindable() can only be used inside a $props() declaration`, /** @param {string} rune */ 'invalid-state-location': (rune) => `${rune}(...) can only be used as a variable declaration initializer or a class field`, @@ -281,7 +282,9 @@ const attributes = { }, 'invalid-let-directive-placement': () => 'let directive at invalid position', 'invalid-style-directive-modifier': () => - `Invalid 'style:' modifier. Valid modifiers are: 'important'` + `Invalid 'style:' modifier. Valid modifiers are: 'important'`, + 'invalid-sequence-expression': () => + `Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses` }; /** @satisfies {Errors} */ diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index 509bc8714d..547901ea7b 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -41,7 +41,7 @@ export function compile(source, options) { }; } - const analysis = analyze_component(parsed, combined_options); + const analysis = analyze_component(parsed, source, combined_options); const result = transform_component(analysis, source, combined_options); return result; diff --git a/packages/svelte/src/compiler/phases/1-parse/read/context.js b/packages/svelte/src/compiler/phases/1-parse/read/context.js index 054d60cb0d..b69c16d320 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/context.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/context.js @@ -121,7 +121,10 @@ function read_type_annotation(parser, optional_allowed = false) { const template = parser.template.slice(0, a).replace(/[^\n]/g, ' ') + insert + - parser.template.slice(parser.index); + // If this is a type annotation for a function parameter, Acorn-TS will treat subsequent + // parameters as part of a sequence expression instead, and will then error on optional + // parameters (`?:`). Therefore replace that sequence with something that will not error. + parser.template.slice(parser.index).replace(/\?\s*:/g, ':'); let expression = parse_expression_at(template, parser.ts, a); // `foo: bar = baz` gets mangled — fix it diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 20d4cc4644..5773a562ee 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -258,10 +258,11 @@ export function analyze_module(ast, options) { /** * @param {import('#compiler').Root} root + * @param {string} source * @param {import('#compiler').ValidatedCompileOptions} options * @returns {import('../types.js').ComponentAnalysis} */ -export function analyze_component(root, options) { +export function analyze_component(root, source, options) { const scope_root = new ScopeRoot(); const module = js(root.module, scope_root, false, null); @@ -396,7 +397,8 @@ export function analyze_component(root, options) { }) : '', keyframes: [] - } + }, + source }; if (!options.customElement && root.options?.customElement) { @@ -436,7 +438,7 @@ export function analyze_component(root, options) { ); } } else { - instance.scope.declare(b.id('$$props'), 'prop', 'synthetic'); + instance.scope.declare(b.id('$$props'), 'bindable_prop', 'synthetic'); instance.scope.declare(b.id('$$restProps'), 'rest_prop', 'synthetic'); for (const { ast, scope, scopes } of [module, instance, template]) { @@ -466,7 +468,10 @@ export function analyze_component(root, options) { } for (const [name, binding] of instance.scope.declarations) { - if (binding.kind === 'prop' && binding.node.name !== '$$props') { + if ( + (binding.kind === 'prop' || binding.kind === 'bindable_prop') && + binding.node.name !== '$$props' + ) { const references = binding.references.filter( (r) => r.node !== binding.node && r.path.at(-1)?.type !== 'ExportSpecifier' ); @@ -605,20 +610,38 @@ const legacy_scope_tweaker = { /** @type {import('../types.js').ReactiveStatement} */ const reactive_statement = { assignments: new Set(), - dependencies: new Set() + dependencies: [] }; next({ ...state, reactive_statement, function_depth: state.scope.function_depth + 1 }); + // Every referenced binding becomes a dependency, unless it's on + // the left-hand side of an `=` assignment for (const [name, nodes] of state.scope.references) { const binding = state.scope.get(name); if (binding === null) continue; - // Include bindings that have references other than assignments and their own declarations - if ( - nodes.some((n) => n.node !== binding.node && !reactive_statement.assignments.has(n.node)) - ) { - reactive_statement.dependencies.add(binding); + for (const { node, path } of nodes) { + /** @type {import('estree').Expression} */ + let left = node; + + let i = path.length - 1; + let parent = /** @type {import('estree').Expression} */ (path.at(i)); + while (parent.type === 'MemberExpression') { + left = parent; + parent = /** @type {import('estree').Expression} */ (path.at(--i)); + } + + if ( + parent.type === 'AssignmentExpression' && + parent.operator === '=' && + parent.left === left + ) { + continue; + } + + reactive_statement.dependencies.push(binding); + break; } } @@ -627,8 +650,8 @@ const legacy_scope_tweaker = { // Ideally this would be in the validation file, but that isn't possible because this visitor // calls "next" before setting the reactive statements. if ( - reactive_statement.dependencies.size && - [...reactive_statement.dependencies].every( + reactive_statement.dependencies.length && + reactive_statement.dependencies.every( (d) => d.scope === state.analysis.module.scope && d.declaration_kind !== 'const' ) ) { @@ -657,15 +680,29 @@ const legacy_scope_tweaker = { } }, AssignmentExpression(node, { state, next }) { - if (state.reactive_statement && node.operator === '=') { - if (node.left.type === 'MemberExpression') { - const id = object(node.left); - if (id !== null) { - state.reactive_statement.assignments.add(id); - } - } else { + if (state.reactive_statement) { + const id = node.left.type === 'MemberExpression' ? object(node.left) : node.left; + if (id !== null) { for (const id of extract_identifiers(node.left)) { - state.reactive_statement.assignments.add(id); + const binding = state.scope.get(id.name); + + if (binding) { + state.reactive_statement.assignments.add(binding); + } + } + } + } + + next(); + }, + UpdateExpression(node, { state, next }) { + if (state.reactive_statement) { + const id = node.argument.type === 'MemberExpression' ? object(node.argument) : node.argument; + if (id?.type === 'Identifier') { + const binding = state.scope.get(id.name); + + if (binding) { + state.reactive_statement.assignments.add(binding); } } } @@ -753,12 +790,13 @@ const legacy_scope_tweaker = { state.scope.get(specifier.local.name) ); if ( - binding.kind === 'state' || - binding.kind === 'frozen_state' || - (binding.kind === 'normal' && - (binding.declaration_kind === 'let' || binding.declaration_kind === 'var')) + binding !== null && + (binding.kind === 'state' || + binding.kind === 'frozen_state' || + (binding.kind === 'normal' && + (binding.declaration_kind === 'let' || binding.declaration_kind === 'var'))) ) { - binding.kind = 'prop'; + binding.kind = 'bindable_prop'; if (specifier.exported.name !== specifier.local.name) { binding.prop_alias = specifier.exported.name; } @@ -796,7 +834,7 @@ const legacy_scope_tweaker = { for (const declarator of node.declaration.declarations) { for (const id of extract_identifiers(declarator.id)) { const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name)); - binding.kind = 'prop'; + binding.kind = 'bindable_prop'; } } } @@ -885,11 +923,24 @@ const runes_scope_tweaker = { property.key.type === 'Identifier' ? property.key.name : /** @type {string} */ (/** @type {import('estree').Literal} */ (property.key).value); - const initial = property.value.type === 'AssignmentPattern' ? property.value.right : null; + let initial = property.value.type === 'AssignmentPattern' ? property.value.right : null; const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(name)); binding.prop_alias = alias; - binding.initial = initial; // rewire initial from $props() to the actual initial value + + // rewire initial from $props() to the actual initial value, stripping $bindable() if necessary + if ( + initial?.type === 'CallExpression' && + initial.callee.type === 'Identifier' && + initial.callee.name === '$bindable' + ) { + binding.initial = /** @type {import('estree').Expression | null} */ ( + initial.arguments[0] ?? null + ); + binding.kind = 'bindable_prop'; + } else { + binding.initial = initial; + } } } }, @@ -935,25 +986,6 @@ const runes_scope_tweaker = { function is_known_safe_call(node, context) { const callee = node.callee; - // Check for selector() API calls - if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier') { - const binding = context.state.scope.get(callee.object.name); - const selector_binding = context.state.scope.get('selector'); - if ( - selector_binding !== null && - selector_binding.declaration_kind === 'import' && - selector_binding.initial !== null && - selector_binding.initial.type === 'ImportDeclaration' && - selector_binding.initial.source.value === 'svelte' && - binding !== null && - binding.initial !== null && - binding.initial.type === 'CallExpression' && - binding.initial.callee.type === 'Identifier' && - binding.initial.callee.name === 'selector' - ) { - return true; - } - } // String / Number / BigInt / Boolean casting calls if (callee.type === 'Identifier') { const name = callee.name; @@ -1345,21 +1377,21 @@ function order_reactive_statements(unsorted_reactive_declarations) { const lookup = new Map(); for (const [node, declaration] of unsorted_reactive_declarations) { - declaration.assignments.forEach(({ name }) => { - const statements = lookup.get(name) ?? []; + for (const binding of declaration.assignments) { + const statements = lookup.get(binding.node.name) ?? []; statements.push([node, declaration]); - lookup.set(name, statements); - }); + lookup.set(binding.node.name, statements); + } } /** @type {Array<[string, string]>} */ const edges = []; for (const [, { assignments, dependencies }] of unsorted_reactive_declarations) { - for (const { name } of assignments) { - for (const { node } of dependencies) { - if (![...assignments].find(({ name }) => node.name === name)) { - edges.push([name, node.name]); + for (const assignment of assignments) { + for (const dependency of dependencies) { + if (!assignments.has(dependency)) { + edges.push([assignment.node.name, dependency.node.name]); } } } @@ -1383,14 +1415,17 @@ function order_reactive_statements(unsorted_reactive_declarations) { */ const add_declaration = (node, declaration) => { if ([...reactive_declarations.values()].includes(declaration)) return; - declaration.dependencies.forEach(({ node: { name } }) => { - if ([...declaration.assignments].some((a) => a.name === name)) return; - for (const [node, earlier] of lookup.get(name) ?? []) { + + for (const binding of declaration.dependencies) { + if (declaration.assignments.has(binding)) continue; + for (const [node, earlier] of lookup.get(binding.node.name) ?? []) { add_declaration(node, earlier); } - }); + } + reactive_declarations.set(node, declaration); }; + for (const [node, declaration] of unsorted_reactive_declarations) { add_declaration(node, declaration); } diff --git a/packages/svelte/src/compiler/phases/2-analyze/utils/push_array.js b/packages/svelte/src/compiler/phases/2-analyze/utils/push_array.js deleted file mode 100644 index ee6a9f7c26..0000000000 --- a/packages/svelte/src/compiler/phases/2-analyze/utils/push_array.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Pushes all `items` into `array` using `push`, therefore mutating the array. - * We do this for memory and perf reasons, and because `array.push(...items)` would - * run into a "max call stack size exceeded" error with too many items (~65k). - * @template T - * @param {T[]} array - * @param {T[]} items - */ -export function push_array(array, items) { - for (let i = 0; i < items.length; i++) { - array.push(items[i]); - } -} diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index cf6f00637f..69d879d021 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -50,6 +50,18 @@ function validate_component(node, context) { } if (attribute.type === 'Attribute') { + if (context.state.analysis.runes && is_expression_attribute(attribute)) { + const expression = attribute.value[0].expression; + if (expression.type === 'SequenceExpression') { + let i = /** @type {number} */ (expression.start); + while (--i > 0) { + const char = context.state.analysis.source[i]; + if (char === '(') break; // parenthesized sequence expressions are ok + if (char === '{') error(expression, 'invalid-sequence-expression'); + } + } + } + validate_attribute_name(attribute, context); if (attribute.name === 'slot') { @@ -81,12 +93,21 @@ function validate_element(node, context) { for (const attribute of node.attributes) { if (attribute.type === 'Attribute') { + const is_expression = is_expression_attribute(attribute); + + if (context.state.analysis.runes && is_expression) { + const expression = attribute.value[0].expression; + if (expression.type === 'SequenceExpression') { + error(expression, 'invalid-sequence-expression'); + } + } + if (regex_illegal_attribute_character.test(attribute.name)) { error(attribute, 'invalid-attribute-name', attribute.name); } if (attribute.name.startsWith('on') && attribute.name.length > 2) { - if (!is_expression_attribute(attribute)) { + if (!is_expression) { error(attribute, 'invalid-event-attribute-value'); } @@ -299,17 +320,19 @@ const validation = { error(node, 'invalid-binding-expression'); } + const binding = context.state.scope.get(left.name); + if ( assignee.type === 'Identifier' && node.name !== 'this' // bind:this also works for regular variables ) { - const binding = context.state.scope.get(left.name); // reassignment if ( !binding || (binding.kind !== 'state' && binding.kind !== 'frozen_state' && binding.kind !== 'prop' && + binding.kind !== 'bindable_prop' && binding.kind !== 'each' && binding.kind !== 'store_sub' && !binding.mutated) @@ -328,8 +351,6 @@ const validation = { // TODO handle mutations of non-state/props in runes mode } - const binding = context.state.scope.get(left.name); - if (node.name === 'group') { if (!binding) { error(node, 'INTERNAL', 'Cannot find declaration for bind:group'); @@ -780,7 +801,25 @@ function validate_call_expression(node, scope, path) { error(node, 'invalid-props-location'); } - if (rune === '$state' || rune === '$derived' || rune === '$derived.by') { + if (rune === '$bindable') { + if (parent.type === 'AssignmentPattern' && path.at(-3)?.type === 'ObjectPattern') { + const declarator = path.at(-4); + if ( + declarator?.type === 'VariableDeclarator' && + get_rune(declarator.init, scope) === '$props' + ) { + return; + } + } + error(node, 'invalid-bindable-location'); + } + + if ( + rune === '$state' || + rune === '$state.frozen' || + rune === '$derived' || + rune === '$derived.by' + ) { if (parent.type === 'VariableDeclarator') return; if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return; error(node, 'invalid-state-location', rune); @@ -873,6 +912,8 @@ export const validation_runes_js = { error(node, 'invalid-rune-args-length', rune, [0, 1]); } else if (rune === '$props') { error(node, 'invalid-props-location'); + } else if (rune === '$bindable') { + error(node, 'invalid-bindable-location'); } }, AssignmentExpression(node, { state }) { @@ -1022,6 +1063,9 @@ export const validation_runes = merge(validation, a11y_validators, { } }, CallExpression(node, { state, path }) { + if (get_rune(node, state.scope) === '$bindable' && node.arguments.length > 1) { + error(node, 'invalid-rune-args-length', '$bindable', [0, 1]); + } validate_call_expression(node, state.scope, path); }, EachBlock(node, { next, state }) { @@ -1062,7 +1106,7 @@ export const validation_runes = merge(validation, a11y_validators, { state.has_props_rune = true; if (args.length > 0) { - error(node, 'invalid-rune-args-length', '$props', [0]); + error(node, 'invalid-rune-args-length', rune, [0]); } if (node.id.type !== 'ObjectPattern') { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index b13ec8e627..8c88a405f1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -46,27 +46,27 @@ export function client_component(source, analysis, options) { options, scope: analysis.module.scope, scopes: analysis.template.scopes, - hoisted: [b.import_all('$', 'svelte/internal')], + hoisted: [b.import_all('$', 'svelte/internal/client')], node: /** @type {any} */ (null), // populated by the root node // these should be set by create_block - if they're called outside, it's a bug - get init() { + get before_init() { /** @type {any[]} */ const a = []; - a.push = () => error(null, 'INTERNAL', 'init.push should not be called outside create_block'); + a.push = () => + error(null, 'INTERNAL', 'before_init.push should not be called outside create_block'); return a; }, - get update() { + get init() { /** @type {any[]} */ const a = []; - a.push = () => - error(null, 'INTERNAL', 'update.push should not be called outside create_block'); + a.push = () => error(null, 'INTERNAL', 'init.push should not be called outside create_block'); return a; }, - get update_effects() { + get update() { /** @type {any[]} */ const a = []; a.push = () => - error(null, 'INTERNAL', 'update_effects.push should not be called outside create_block'); + error(null, 'INTERNAL', 'update.push should not be called outside create_block'); return a; }, get after_update() { @@ -239,7 +239,7 @@ export function client_component(source, analysis, options) { ); }); - const properties = analysis.exports.map(({ name, alias }) => { + const component_returned_object = analysis.exports.map(({ name, alias }) => { const expression = serialize_get_binding(b.id(name), instance_state); if (expression.type === 'Identifier' && !options.dev) { @@ -249,17 +249,33 @@ export function client_component(source, analysis, options) { return b.get(alias ?? name, [b.return(expression)]); }); - if (analysis.accessors) { - for (const [name, binding] of analysis.instance.scope.declarations) { - if (binding.kind !== 'prop' || name.startsWith('$$')) continue; + const properties = [...analysis.instance.scope.declarations].filter( + ([name, binding]) => + (binding.kind === 'prop' || binding.kind === 'bindable_prop') && !name.startsWith('$$') + ); + + if (analysis.runes && options.dev) { + /** @type {import('estree').Literal[]} */ + const bindable = []; + for (const [name, binding] of properties) { + if (binding.kind === 'bindable_prop') { + bindable.push(b.literal(binding.prop_alias ?? name)); + } + } + instance.body.unshift( + b.stmt(b.call('$.validate_prop_bindings', b.id('$$props'), b.array(bindable))) + ); + } + if (analysis.accessors) { + for (const [name, binding] of properties) { const key = binding.prop_alias ?? name; const getter = b.get(key, [b.return(b.call(b.id(name)))]); const setter = b.set(key, [ b.stmt(b.call(b.id(name), b.id('$$value'))), - b.stmt(b.call('$.flushSync')) + b.stmt(b.call('$.flush_sync')) ]); if (analysis.runes && binding.initial) { @@ -271,12 +287,12 @@ export function client_component(source, analysis, options) { }; } - properties.push(getter, setter); + component_returned_object.push(getter, setter); } } if (options.legacy.componentApi) { - properties.push( + component_returned_object.push( b.init('$set', b.id('$.update_legacy_props')), b.init( '$on', @@ -292,7 +308,7 @@ export function client_component(source, analysis, options) { ) ); } else if (options.dev) { - properties.push( + component_returned_object.push( b.init( '$set', b.thunk( @@ -360,8 +376,8 @@ export function client_component(source, analysis, options) { append_styles(); component_block.body.push( - properties.length > 0 - ? b.return(b.call('$.pop', b.object(properties))) + component_returned_object.length > 0 + ? b.return(b.call('$.pop', b.object(component_returned_object))) : b.stmt(b.call('$.pop')) ); @@ -369,7 +385,7 @@ export function client_component(source, analysis, options) { /** @type {string[]} */ const named_props = analysis.exports.map(({ name, alias }) => alias ?? name); for (const [name, binding] of analysis.instance.scope.declarations) { - if (binding.kind === 'prop') named_props.push(binding.prop_alias ?? name); + if (binding.kind === 'bindable_prop') named_props.push(binding.prop_alias ?? name); } component_block.body.unshift( @@ -476,9 +492,7 @@ export function client_component(source, analysis, options) { /** @type {import('estree').Property[]} */ const props_str = []; - for (const [name, binding] of analysis.instance.scope.declarations) { - if (binding.kind !== 'prop' || name.startsWith('$$')) continue; - + for (const [name, binding] of properties) { const key = binding.prop_alias ?? name; const prop_def = typeof ce === 'boolean' ? {} : ce.props?.[key] || {}; if ( @@ -568,6 +582,6 @@ export function client_module(analysis, options) { return { type: 'Program', sourceType: 'module', - body: [b.import_all('$', 'svelte/internal'), ...module.body] + body: [b.import_all('$', 'svelte/internal/client'), ...module.body] }; } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 96fce18986..c9287554a9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -29,18 +29,12 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly hoisted: Array; readonly events: Set; + /** Stuff that happens before the render effect(s) */ + readonly before_init: Statement[]; /** Stuff that happens before the render effect(s) */ readonly init: Statement[]; - /** Stuff that happens inside separate render effects (due to call expressions) */ - readonly update_effects: Statement[]; /** Stuff that happens inside the render effect */ - readonly update: { - init?: Statement; - /** If the update array only contains a single entry, this singular entry will be used, if present */ - singular?: Statement; - /** Used if condition for singular prop is false (see comment above) */ - grouped: Statement; - }[]; + readonly update: Statement[]; /** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */ readonly after_update: Statement[]; /** The HTML template string */ diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index d93f8f5b92..cd274eef23 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -78,7 +78,7 @@ export function serialize_get_binding(node, state) { return typeof binding.expression === 'function' ? binding.expression(node) : binding.expression; } - if (binding.kind === 'prop') { + if (binding.kind === 'prop' || binding.kind === 'bindable_prop') { if (binding.node.name === '$$props') { // Special case for $$props which only exists in the old world // TODO this probably shouldn't have a 'prop' binding kind @@ -377,6 +377,7 @@ export function serialize_set_binding(node, context, fallback, options) { binding.kind !== 'state' && binding.kind !== 'frozen_state' && binding.kind !== 'prop' && + binding.kind !== 'bindable_prop' && binding.kind !== 'each' && binding.kind !== 'legacy_reactive' && !is_store @@ -389,7 +390,7 @@ export function serialize_set_binding(node, context, fallback, options) { const serialize = () => { if (left === node.left) { - if (binding.kind === 'prop') { + if (binding.kind === 'prop' || binding.kind === 'bindable_prop') { return b.call(left, value); } else if (is_store) { return b.call('$.store_set', serialize_get_binding(b.id(left_name), state), value); @@ -467,7 +468,7 @@ export function serialize_set_binding(node, context, fallback, options) { b.call('$.untrack', b.id('$' + left_name)) ); } else if (!state.analysis.runes) { - if (binding.kind === 'prop') { + if (binding.kind === 'bindable_prop') { return b.call( left, b.sequence([ @@ -571,7 +572,7 @@ function get_hoistable_params(node, context) { params.push(b.id(binding.expression.object.arguments[0].name)); } else if ( // If we are referencing a simple $$props value, then we need to reference the object property instead - binding.kind === 'prop' && + (binding.kind === 'prop' || binding.kind === 'bindable_prop') && !binding.reassigned && binding.initial === null && !context.state.analysis.accessors diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js index 5d1689cadc..c299dd99ef 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js @@ -52,6 +52,7 @@ export const global_visitors = { binding?.kind === 'each' || binding?.kind === 'legacy_reactive' || binding?.kind === 'prop' || + binding?.kind === 'bindable_prop' || is_store ) { /** @type {import('estree').Expression[]} */ @@ -64,7 +65,7 @@ export const global_visitors = { fn += '_store'; args.push(serialize_get_binding(b.id(name), state), b.call('$' + name)); } else { - if (binding.kind === 'prop') fn += '_prop'; + if (binding.kind === 'prop' || binding.kind === 'bindable_prop') fn += '_prop'; args.push(b.id(name)); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-legacy.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-legacy.js index ed4c6e8474..ffb089bf83 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-legacy.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-legacy.js @@ -40,7 +40,7 @@ export const javascript_visitors_legacy = { state.scope.get_bindings(declarator) ); const has_state = bindings.some((binding) => binding.kind === 'state'); - const has_props = bindings.some((binding) => binding.kind === 'prop'); + const has_props = bindings.some((binding) => binding.kind === 'bindable_prop'); if (!has_state && !has_props) { const init = declarator.init; @@ -80,7 +80,7 @@ export const javascript_visitors_legacy = { declarations.push( b.declarator( path.node, - binding.kind === 'prop' + binding.kind === 'bindable_prop' ? get_prop_source(binding, state, binding.prop_alias ?? name, value) : value ) @@ -168,7 +168,7 @@ export const javascript_visitors_legacy = { // If the binding is a prop, we need to deep read it because it could be fine-grained $state // from a runes-component, where mutations don't trigger an update on the prop as a whole. - if (name === '$$props' || name === '$$restProps' || binding.kind === 'prop') { + if (name === '$$props' || name === '$$restProps' || binding.kind === 'bindable_prop') { serialized = b.call('$.deep_read_state', serialized); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js index 3eb43322b7..25a2564453 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js @@ -207,33 +207,30 @@ export const javascript_visitors_runes = { seen.push(name); - let id = property.value; - let initial = undefined; - - if (property.value.type === 'AssignmentPattern') { - id = property.value.left; - initial = /** @type {import('estree').Expression} */ (visit(property.value.right)); - } - + let id = + property.value.type === 'AssignmentPattern' ? property.value.left : property.value; assert.equal(id.type, 'Identifier'); - const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name)); + const initial = + binding.initial && + /** @type {import('estree').Expression} */ (visit(binding.initial)); if (binding.reassigned || state.analysis.accessors || initial) { declarations.push(b.declarator(id, get_prop_source(binding, state, name, initial))); } } else { // RestElement - declarations.push( - b.declarator( - property.argument, - b.call( - '$.rest_props', - b.id('$$props'), - b.array(seen.map((name) => b.literal(name))) - ) - ) - ); + /** @type {import('estree').Expression[]} */ + const args = [b.id('$$props'), b.array(seen.map((name) => b.literal(name)))]; + + if (state.options.dev) { + // include rest name, so we can provide informative error messages + args.push( + b.literal(/** @type {import('estree').Identifier} */ (property.argument).name) + ); + } + + declarations.push(b.declarator(property.argument, b.call('$.rest_props', ...args))); } } @@ -304,7 +301,7 @@ export const javascript_visitors_runes = { declarations.push( b.declarator( b.id(object_id), - b.call('$.derived', b.thunk(rune === '$derived.by' ? b.call(value) : value)) + b.call('$.derived', rune === '$derived.by' ? value : b.thunk(value)) ) ); declarations.push( @@ -374,7 +371,7 @@ export const javascript_visitors_runes = { const func = context.visit(node.expression.arguments[0]); return { ...node, - expression: b.call('$.pre_effect', /** @type {import('estree').Expression} */ (func)) + expression: b.call('$.user_pre_effect', /** @type {import('estree').Expression} */ (func)) }; } } @@ -392,7 +389,7 @@ export const javascript_visitors_runes = { const args = /** @type {import('estree').Expression[]} */ ( node.arguments.map((arg) => context.visit(arg)) ); - return b.call('$.user_root_effect', ...args); + return b.call('$.effect_root', ...args); } if (rune === '$inspect' || rune === '$inspect().with') { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 89976461d6..0b9f865f9f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -33,6 +33,8 @@ import { EACH_IS_STRICT_EQUALS, EACH_ITEM_REACTIVE, EACH_KEYED, + TEMPLATE_FRAGMENT, + TEMPLATE_USE_IMPORT_NODE, TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT @@ -59,7 +61,7 @@ function get_attribute_name(element, attribute, context) { } /** - * Serializes each style directive into something like `$.style(element, style_property, value)` + * Serializes each style directive into something like `$.set_style(element, style_property, value)` * and adds it either to init or update, depending on whether or not the value or the attributes are dynamic. * @param {import('#compiler').StyleDirective[]} style_directives * @param {import('estree').Identifier} element_id @@ -74,9 +76,10 @@ function serialize_style_directives(style_directives, element_id, context, is_at directive.value === true ? serialize_get_binding({ name: directive.name, type: 'Identifier' }, context.state) : serialize_attribute_value(directive.value, context)[1]; - const grouped = b.stmt( + + const update = b.stmt( b.call( - '$.style', + '$.set_style', element_id, b.literal(directive.name), value, @@ -85,17 +88,6 @@ function serialize_style_directives(style_directives, element_id, context, is_at ) ) ); - const singular = b.stmt( - b.call( - '$.style_effect', - element_id, - b.literal(directive.name), - b.arrow([], value), - /** @type {import('estree').Expression} */ ( - directive.modifiers.includes('important') ? b.true : undefined - ) - ) - ); const contains_call_expression = Array.isArray(directive.value) && @@ -104,11 +96,11 @@ function serialize_style_directives(style_directives, element_id, context, is_at ); if (!is_attributes_reactive && contains_call_expression) { - state.update_effects.push(singular); + state.init.push(serialize_update(update)); } else if (is_attributes_reactive || directive.metadata.dynamic || contains_call_expression) { - state.update.push({ grouped, singular }); + state.update.push(update); } else { - state.init.push(grouped); + state.init.push(update); } } } @@ -146,18 +138,15 @@ function serialize_class_directives(class_directives, element_id, context, is_at const state = context.state; for (const directive of class_directives) { const value = /** @type {import('estree').Expression} */ (context.visit(directive.expression)); - const grouped = b.stmt(b.call('$.class_toggle', element_id, b.literal(directive.name), value)); - const singular = b.stmt( - b.call('$.class_toggle_effect', element_id, b.literal(directive.name), b.arrow([], value)) - ); + const update = b.stmt(b.call('$.toggle_class', element_id, b.literal(directive.name), value)); const contains_call_expression = directive.expression.type === 'CallExpression'; if (!is_attributes_reactive && contains_call_expression) { - state.update_effects.push(singular); + state.init.push(serialize_update(update)); } else if (is_attributes_reactive || directive.metadata.dynamic || contains_call_expression) { - state.update.push({ grouped, singular }); + state.update.push(update); } else { - state.init.push(grouped); + state.init.push(update); } } } @@ -244,7 +233,7 @@ function setup_select_synchronization(value_binding, context) { context.state.init.push( b.stmt( b.call( - '$.invalidate_effect', + '$.render_effect', b.thunk( b.block([ b.stmt( @@ -293,23 +282,14 @@ function serialize_element_spread_attributes( const lowercase_attributes = element.metadata.svg || is_custom_element_node(element) ? b.false : b.true; - const id = context.state.scope.generate('spread_attributes'); + const id = context.state.scope.generate('attributes'); - const standalone = b.stmt( - b.call( - '$.spread_attributes_effect', - element_id, - b.thunk(b.array(values)), - lowercase_attributes, - b.literal(context.state.analysis.css.hash) - ) - ); - const inside_effect = b.stmt( + const update = b.stmt( b.assignment( '=', b.id(id), b.call( - '$.spread_attributes', + '$.set_attributes', element_id, b.id(id), b.array(values), @@ -319,32 +299,21 @@ function serialize_element_spread_attributes( ) ); - if (!needs_isolation || needs_select_handling) { - context.state.init.push(b.let(id)); - } + context.state.init.push(b.let(id)); // objects could contain reactive getters -> play it safe and always assume spread attributes are reactive if (needs_isolation) { - if (needs_select_handling) { - context.state.update_effects.push( - b.stmt(b.call('$.render_effect', b.arrow([], b.block([inside_effect])))) - ); - } else { - context.state.update_effects.push(standalone); - } + context.state.init.push(serialize_update(update)); } else { - context.state.update.push({ - singular: needs_select_handling ? undefined : standalone, - grouped: inside_effect - }); + context.state.update.push(update); } if (needs_select_handling) { context.state.init.push( b.stmt(b.call('$.init_select', element_id, b.thunk(b.member(b.id(id), b.id('value'))))) ); - context.state.update.push({ - grouped: b.if( + context.state.update.push( + b.if( b.binary('in', b.literal('value'), b.id(id)), b.block([ // This ensures a one-way street to the DOM in case it's -

Hello world!

diff --git a/packages/svelte/tests/hydration/samples/binding-input/_expected.html b/packages/svelte/tests/hydration/samples/binding-input/_expected.html new file mode 100644 index 0000000000..b5bc6af161 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/binding-input/_expected.html @@ -0,0 +1 @@ +

Hello world!

diff --git a/packages/svelte/tests/hydration/samples/claim-comment/_before.html b/packages/svelte/tests/hydration/samples/claim-comment/_before.html deleted file mode 100644 index e1bab99a66..0000000000 --- a/packages/svelte/tests/hydration/samples/claim-comment/_before.html +++ /dev/null @@ -1,3 +0,0 @@ -
-p -
diff --git a/packages/svelte/tests/hydration/samples/claim-static/_before.html b/packages/svelte/tests/hydration/samples/claim-static/_before.html deleted file mode 100644 index bfbe85f59c..0000000000 --- a/packages/svelte/tests/hydration/samples/claim-static/_before.html +++ /dev/null @@ -1,8 +0,0 @@ -
hello
- -
bye
- -
-
aaa
-
bbb
-
diff --git a/packages/svelte/tests/hydration/samples/claim-text/_before.html b/packages/svelte/tests/hydration/samples/claim-text/_before.html deleted file mode 100644 index 98702233ff..0000000000 --- a/packages/svelte/tests/hydration/samples/claim-text/_before.html +++ /dev/null @@ -1,5 +0,0 @@ - -

This p and the slot below are direct children of the root.

-
There should be one
- - diff --git a/packages/svelte/tests/hydration/samples/component-in-element/_before.html b/packages/svelte/tests/hydration/samples/component-in-element/_before.html deleted file mode 100644 index c95522231e..0000000000 --- a/packages/svelte/tests/hydration/samples/component-in-element/_before.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

nested

-
diff --git a/packages/svelte/tests/hydration/samples/component/_before.html b/packages/svelte/tests/hydration/samples/component/_before.html deleted file mode 100644 index bc73093efd..0000000000 --- a/packages/svelte/tests/hydration/samples/component/_before.html +++ /dev/null @@ -1,3 +0,0 @@ - -

nested

- diff --git a/packages/svelte/tests/hydration/samples/dynamic-text-changed/_before.html b/packages/svelte/tests/hydration/samples/dynamic-text-changed/_before.html deleted file mode 100644 index f97ad9726b..0000000000 --- a/packages/svelte/tests/hydration/samples/dynamic-text-changed/_before.html +++ /dev/null @@ -1 +0,0 @@ -

Hello world!

diff --git a/packages/svelte/tests/hydration/samples/dynamic-text-changed/_config.js b/packages/svelte/tests/hydration/samples/dynamic-text-changed/_config.js index 4c00df87e5..9852c25463 100644 --- a/packages/svelte/tests/hydration/samples/dynamic-text-changed/_config.js +++ b/packages/svelte/tests/hydration/samples/dynamic-text-changed/_config.js @@ -1,6 +1,10 @@ import { test } from '../../test'; export default test({ + server_props: { + name: 'world' + }, + props: { name: 'everybody' }, diff --git a/packages/svelte/tests/hydration/samples/dynamic-text-changed/_after.html b/packages/svelte/tests/hydration/samples/dynamic-text-changed/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/dynamic-text-changed/_after.html rename to packages/svelte/tests/hydration/samples/dynamic-text-changed/_expected.html diff --git a/packages/svelte/tests/hydration/samples/dynamic-text-nil/_before.html b/packages/svelte/tests/hydration/samples/dynamic-text-nil/_before.html deleted file mode 100644 index 7508e31db6..0000000000 --- a/packages/svelte/tests/hydration/samples/dynamic-text-nil/_before.html +++ /dev/null @@ -1 +0,0 @@ -

diff --git a/packages/svelte/tests/hydration/samples/dynamic-text/_before.html b/packages/svelte/tests/hydration/samples/dynamic-text/_before.html deleted file mode 100644 index f97ad9726b..0000000000 --- a/packages/svelte/tests/hydration/samples/dynamic-text/_before.html +++ /dev/null @@ -1 +0,0 @@ -

Hello world!

diff --git a/packages/svelte/tests/hydration/samples/each-block-arg-clash/_before.html b/packages/svelte/tests/hydration/samples/each-block-arg-clash/_before.html deleted file mode 100644 index 184a66ac72..0000000000 --- a/packages/svelte/tests/hydration/samples/each-block-arg-clash/_before.html +++ /dev/null @@ -1,5 +0,0 @@ -
    -
  • animal
  • -
  • vegetable
  • -
  • mineral
  • -
diff --git a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_before.html b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_before.html deleted file mode 100644 index 215e1e3c8e..0000000000 --- a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_before.html +++ /dev/null @@ -1,2 +0,0 @@ -

empty

-

a

diff --git a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_config.js b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_config.js index f47bee71df..0b7783bd1c 100644 --- a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_config.js +++ b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_config.js @@ -1,3 +1,13 @@ import { test } from '../../test'; -export default test({}); +export default test({ + server_props: { + items1: [], + items2: [{ name: 'a' }] + }, + + props: { + items1: [{ name: 'a' }], + items2: [] + } +}); diff --git a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_after.html b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_after.html rename to packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/_expected.html diff --git a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/main.svelte b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/main.svelte index 835f726435..c130034bbe 100644 --- a/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/main.svelte +++ b/packages/svelte/tests/hydration/samples/each-block-fallback-mismatch/main.svelte @@ -1,6 +1,5 @@ {#each items1 as item} diff --git a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_before.html b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_before.html deleted file mode 100644 index f480ea096d..0000000000 --- a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_before.html +++ /dev/null @@ -1,12 +0,0 @@ -
  • a
  • b
-
  • a
  • b
-
  • a
  • b
-
  • a
  • -
  • a
  • b
  • -
  • b
  • -
  • a
  • -
  • a
  • b
  • -
  • b
  • -
  • a
  • -
  • a
  • b
  • -
  • b
  • diff --git a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_config.js b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_config.js index 5b0adcfd86..fa28dbe009 100644 --- a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_config.js +++ b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_config.js @@ -1,6 +1,14 @@ import { assert_ok, test } from '../../test'; export default test({ + server_props: { + items: [{ name: 'a' }, { name: 'b' }] + }, + + props: { + items: [{ name: 'a' }] + }, + snapshot(target) { const ul = target.querySelector('ul'); assert_ok(ul); diff --git a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_after.html b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_after.html rename to packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/_expected.html diff --git a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/main.svelte b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/main.svelte index e2ff0750e3..093e59cef9 100644 --- a/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/main.svelte +++ b/packages/svelte/tests/hydration/samples/each-block-less-nodes-on-client/main.svelte @@ -1,5 +1,5 @@
      diff --git a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_before.html b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_before.html deleted file mode 100644 index 7c3233df17..0000000000 --- a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_before.html +++ /dev/null @@ -1,9 +0,0 @@ -
      • a
      -
      • a
      -
      • a
      -
    • a
    • -
    • a
    • -
    • a
    • -
    • a
    • -
    • a
    • -
    • a
    • diff --git a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_config.js b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_config.js index 5b0adcfd86..baffef3b8b 100644 --- a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_config.js +++ b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_config.js @@ -1,6 +1,14 @@ import { assert_ok, test } from '../../test'; export default test({ + server_props: { + items: [{ name: 'x' }] + }, + + props: { + items: [{ name: 'a' }, { name: 'b' }] + }, + snapshot(target) { const ul = target.querySelector('ul'); assert_ok(ul); diff --git a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_after.html b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_after.html rename to packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/_expected.html diff --git a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/main.svelte b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/main.svelte index 7df2b52e2e..093e59cef9 100644 --- a/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/main.svelte +++ b/packages/svelte/tests/hydration/samples/each-block-more-nodes-on-client/main.svelte @@ -1,5 +1,5 @@
        diff --git a/packages/svelte/tests/hydration/samples/each-block/_before.html b/packages/svelte/tests/hydration/samples/each-block/_before.html deleted file mode 100644 index 184a66ac72..0000000000 --- a/packages/svelte/tests/hydration/samples/each-block/_before.html +++ /dev/null @@ -1,5 +0,0 @@ -
          -
        • animal
        • -
        • vegetable
        • -
        • mineral
        • -
        diff --git a/packages/svelte/tests/hydration/samples/each-else/_before.html b/packages/svelte/tests/hydration/samples/each-else/_before.html deleted file mode 100644 index 3335979fb8..0000000000 --- a/packages/svelte/tests/hydration/samples/each-else/_before.html +++ /dev/null @@ -1,3 +0,0 @@ -

        Hello, world

        -

        foo

        -

        foo

        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-added/_before.html b/packages/svelte/tests/hydration/samples/element-attribute-added/_before.html deleted file mode 100644 index fec75ee427..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-added/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-added/_config.js b/packages/svelte/tests/hydration/samples/element-attribute-added/_config.js index 3972adadfe..e432ceb468 100644 --- a/packages/svelte/tests/hydration/samples/element-attribute-added/_config.js +++ b/packages/svelte/tests/hydration/samples/element-attribute-added/_config.js @@ -1,6 +1,8 @@ import { test } from '../../test'; export default test({ + server_props: {}, + props: { className: 'bar' }, diff --git a/packages/svelte/tests/hydration/samples/element-attribute-added/_after.html b/packages/svelte/tests/hydration/samples/element-attribute-added/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/element-attribute-added/_after.html rename to packages/svelte/tests/hydration/samples/element-attribute-added/_expected.html diff --git a/packages/svelte/tests/hydration/samples/element-attribute-changed/_before.html b/packages/svelte/tests/hydration/samples/element-attribute-changed/_before.html deleted file mode 100644 index fec75ee427..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-changed/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-changed/_config.js b/packages/svelte/tests/hydration/samples/element-attribute-changed/_config.js index 3972adadfe..fe02d429b3 100644 --- a/packages/svelte/tests/hydration/samples/element-attribute-changed/_config.js +++ b/packages/svelte/tests/hydration/samples/element-attribute-changed/_config.js @@ -1,6 +1,10 @@ import { test } from '../../test'; export default test({ + server_props: { + className: 'foo' + }, + props: { className: 'bar' }, diff --git a/packages/svelte/tests/hydration/samples/element-attribute-changed/_after.html b/packages/svelte/tests/hydration/samples/element-attribute-changed/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/element-attribute-changed/_after.html rename to packages/svelte/tests/hydration/samples/element-attribute-changed/_expected.html diff --git a/packages/svelte/tests/hydration/samples/element-attribute-removed/_after.html b/packages/svelte/tests/hydration/samples/element-attribute-removed/_after.html deleted file mode 100644 index 59cd21e928..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-removed/_after.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-removed/_before.html b/packages/svelte/tests/hydration/samples/element-attribute-removed/_before.html deleted file mode 100644 index 4bb2d47ff3..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-removed/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-removed/_config.js b/packages/svelte/tests/hydration/samples/element-attribute-removed/_config.js index a6b6b845f7..62c72f3f7c 100644 --- a/packages/svelte/tests/hydration/samples/element-attribute-removed/_config.js +++ b/packages/svelte/tests/hydration/samples/element-attribute-removed/_config.js @@ -1,6 +1,10 @@ import { test } from '../../test'; export default test({ + server_props: { + id: 'foo' + }, + snapshot(target) { const div = target.querySelector('div'); diff --git a/packages/svelte/tests/hydration/samples/element-attribute-removed/_expected.html b/packages/svelte/tests/hydration/samples/element-attribute-removed/_expected.html new file mode 100644 index 0000000000..bbd534112d --- /dev/null +++ b/packages/svelte/tests/hydration/samples/element-attribute-removed/_expected.html @@ -0,0 +1 @@ +
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-removed/main.svelte b/packages/svelte/tests/hydration/samples/element-attribute-removed/main.svelte index 959352e727..d5e18e5cb4 100644 --- a/packages/svelte/tests/hydration/samples/element-attribute-removed/main.svelte +++ b/packages/svelte/tests/hydration/samples/element-attribute-removed/main.svelte @@ -2,4 +2,11 @@ export let id; +
        + +{#if true} + +
        +
        +{/if} diff --git a/packages/svelte/tests/hydration/samples/element-attribute-unchanged-2/_before.html b/packages/svelte/tests/hydration/samples/element-attribute-unchanged-2/_before.html deleted file mode 100644 index 433df7f9d1..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-unchanged-2/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-attribute-unchanged/_before.html b/packages/svelte/tests/hydration/samples/element-attribute-unchanged/_before.html deleted file mode 100644 index fec75ee427..0000000000 --- a/packages/svelte/tests/hydration/samples/element-attribute-unchanged/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        diff --git a/packages/svelte/tests/hydration/samples/element-nested-sibling/_before.html b/packages/svelte/tests/hydration/samples/element-nested-sibling/_before.html deleted file mode 100644 index 78323f1806..0000000000 --- a/packages/svelte/tests/hydration/samples/element-nested-sibling/_before.html +++ /dev/null @@ -1,3 +0,0 @@ -

        1 - - 2

        diff --git a/packages/svelte/tests/hydration/samples/element-nested/_before.html b/packages/svelte/tests/hydration/samples/element-nested/_before.html deleted file mode 100644 index a3bf64142d..0000000000 --- a/packages/svelte/tests/hydration/samples/element-nested/_before.html +++ /dev/null @@ -1,3 +0,0 @@ -
        -

        nested

        -
        diff --git a/packages/svelte/tests/hydration/samples/element-ref/_before.html b/packages/svelte/tests/hydration/samples/element-ref/_before.html deleted file mode 100644 index f97ad9726b..0000000000 --- a/packages/svelte/tests/hydration/samples/element-ref/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        Hello world!

        diff --git a/packages/svelte/tests/hydration/samples/event-handler/_before.html b/packages/svelte/tests/hydration/samples/event-handler/_before.html deleted file mode 100644 index 833699217c..0000000000 --- a/packages/svelte/tests/hydration/samples/event-handler/_before.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/svelte/tests/hydration/samples/expression-sibling/_before.html b/packages/svelte/tests/hydration/samples/expression-sibling/_before.html deleted file mode 100644 index 0ce5257133..0000000000 --- a/packages/svelte/tests/hydration/samples/expression-sibling/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        1 2 3

        diff --git a/packages/svelte/tests/hydration/samples/head-html-and-component/_before.html b/packages/svelte/tests/hydration/samples/head-html-and-component/_before.html deleted file mode 100644 index bb7c602edf..0000000000 --- a/packages/svelte/tests/hydration/samples/head-html-and-component/_before.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/svelte/tests/hydration/samples/head-html-and-component/_before_head.html b/packages/svelte/tests/hydration/samples/head-html-and-component/_before_head.html deleted file mode 100644 index cc1d406e3d..0000000000 --- a/packages/svelte/tests/hydration/samples/head-html-and-component/_before_head.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before.html b/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before.html deleted file mode 100644 index 7217379ee6..0000000000 --- a/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        Just a dummy page.
        diff --git a/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before_head.html b/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before_head.html deleted file mode 100644 index 040469d618..0000000000 --- a/packages/svelte/tests/hydration/samples/head-meta-hydrate-duplicate/_before_head.html +++ /dev/null @@ -1,4 +0,0 @@ -Some Title - - - \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/html-tag-hydration/_after.html b/packages/svelte/tests/hydration/samples/html-tag-hydration/_after.html deleted file mode 100644 index b85905ec0b..0000000000 --- a/packages/svelte/tests/hydration/samples/html-tag-hydration/_after.html +++ /dev/null @@ -1 +0,0 @@ -1 2 3 diff --git a/packages/svelte/tests/hydration/samples/html-tag-hydration/_before.html b/packages/svelte/tests/hydration/samples/html-tag-hydration/_before.html deleted file mode 100644 index 2d1b0bd6c3..0000000000 --- a/packages/svelte/tests/hydration/samples/html-tag-hydration/_before.html +++ /dev/null @@ -1 +0,0 @@ - 1 2 3 diff --git a/packages/svelte/tests/hydration/samples/if-block-anchor/_before.html b/packages/svelte/tests/hydration/samples/if-block-anchor/_before.html deleted file mode 100644 index 163050a1a6..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-anchor/_before.html +++ /dev/null @@ -1,2 +0,0 @@ -

        foo!

        -

        bar!

        diff --git a/packages/svelte/tests/hydration/samples/if-block-empty/_after.html b/packages/svelte/tests/hydration/samples/if-block-empty/_after.html deleted file mode 100644 index 9c71a6ffee..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-empty/_after.html +++ /dev/null @@ -1,4 +0,0 @@ - - -x - diff --git a/packages/svelte/tests/hydration/samples/if-block-empty/_before.html b/packages/svelte/tests/hydration/samples/if-block-empty/_before.html deleted file mode 100644 index 88c34c8f29..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-empty/_before.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/svelte/tests/hydration/samples/if-block-empty/_config.js b/packages/svelte/tests/hydration/samples/if-block-empty/_config.js index f47bee71df..78f00a1b51 100644 --- a/packages/svelte/tests/hydration/samples/if-block-empty/_config.js +++ b/packages/svelte/tests/hydration/samples/if-block-empty/_config.js @@ -1,3 +1,11 @@ import { test } from '../../test'; -export default test({}); +export default test({ + server_props: { + foo: '' + }, + + props: { + foo: 'x' + } +}); diff --git a/packages/svelte/tests/hydration/samples/if-block-false/_before.html b/packages/svelte/tests/hydration/samples/if-block-false/_before.html deleted file mode 100644 index 7911a5ef45..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-false/_before.html +++ /dev/null @@ -1,5 +0,0 @@ -

        before

        - - - -

        after

        diff --git a/packages/svelte/tests/hydration/samples/if-block-mismatch/_after.html b/packages/svelte/tests/hydration/samples/if-block-mismatch/_after.html deleted file mode 100644 index b98a7cb541..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-mismatch/_after.html +++ /dev/null @@ -1 +0,0 @@ -

        foo

        diff --git a/packages/svelte/tests/hydration/samples/if-block-mismatch/_before.html b/packages/svelte/tests/hydration/samples/if-block-mismatch/_before.html deleted file mode 100644 index fe8876acb7..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-mismatch/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        bar

        diff --git a/packages/svelte/tests/hydration/samples/if-block-mismatch/_config.js b/packages/svelte/tests/hydration/samples/if-block-mismatch/_config.js index 9bf1e9b276..f93877415f 100644 --- a/packages/svelte/tests/hydration/samples/if-block-mismatch/_config.js +++ b/packages/svelte/tests/hydration/samples/if-block-mismatch/_config.js @@ -3,5 +3,13 @@ import { test } from '../../test'; // even {#if true} or {#if false} should be kept as an if block, because it could be {#if browser} originally, // which is then different between client and server. export default test({ + server_props: { + condition: false + }, + + props: { + condition: true + }, + trim_whitespace: false }); diff --git a/packages/svelte/tests/hydration/samples/if-block-mismatch/main.svelte b/packages/svelte/tests/hydration/samples/if-block-mismatch/main.svelte index 4059553992..c6799c5f95 100644 --- a/packages/svelte/tests/hydration/samples/if-block-mismatch/main.svelte +++ b/packages/svelte/tests/hydration/samples/if-block-mismatch/main.svelte @@ -1,3 +1,7 @@ + + {#if true}

        foo

        {:else} diff --git a/packages/svelte/tests/hydration/samples/if-block-update/_before.html b/packages/svelte/tests/hydration/samples/if-block-update/_before.html deleted file mode 100644 index 5821b859a7..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block-update/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        foo!

        diff --git a/packages/svelte/tests/hydration/samples/if-block/_before.html b/packages/svelte/tests/hydration/samples/if-block/_before.html deleted file mode 100644 index ebd6a90aad..0000000000 --- a/packages/svelte/tests/hydration/samples/if-block/_before.html +++ /dev/null @@ -1,4 +0,0 @@ - - -

        foo!

        - diff --git a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_before.html b/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_before.html deleted file mode 100644 index afeffd5eb6..0000000000 --- a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_before.html +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_config.js b/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_config.js index cc24163f2c..ce81251e5e 100644 --- a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_config.js +++ b/packages/svelte/tests/hydration/samples/ignore-mismatched-href/_config.js @@ -1,6 +1,14 @@ import { test } from '../../test'; export default test({ + server_props: { + browser: false + }, + + props: { + browser: true + }, + test(assert, target) { assert.equal(target.querySelector('a')?.getAttribute('href'), '/bar'); } diff --git a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/main.svelte b/packages/svelte/tests/hydration/samples/ignore-mismatched-href/main.svelte index 5dcd4d4002..de78109c00 100644 --- a/packages/svelte/tests/hydration/samples/ignore-mismatched-href/main.svelte +++ b/packages/svelte/tests/hydration/samples/ignore-mismatched-href/main.svelte @@ -1,5 +1,5 @@ foo diff --git a/packages/svelte/tests/hydration/samples/noscript/_before.html b/packages/svelte/tests/hydration/samples/noscript/_before.html deleted file mode 100644 index 34ac9d9bc3..0000000000 --- a/packages/svelte/tests/hydration/samples/noscript/_before.html +++ /dev/null @@ -1,2 +0,0 @@ - -

        Hello!

        Count: 0

        diff --git a/packages/svelte/tests/hydration/samples/noscript/_after.html b/packages/svelte/tests/hydration/samples/noscript/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/noscript/_after.html rename to packages/svelte/tests/hydration/samples/noscript/_expected.html diff --git a/packages/svelte/tests/hydration/samples/raw-mismatch/_after.html b/packages/svelte/tests/hydration/samples/raw-mismatch/_after.html deleted file mode 100644 index d28ae350fb..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-mismatch/_after.html +++ /dev/null @@ -1 +0,0 @@ -

        foo

        \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/raw-mismatch/_before.html b/packages/svelte/tests/hydration/samples/raw-mismatch/_before.html deleted file mode 100644 index 4c04a81f66..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-mismatch/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        bar

        \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/raw-repair/_after.html b/packages/svelte/tests/hydration/samples/raw-repair/_after.html deleted file mode 100644 index 31cdc12015..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-repair/_after.html +++ /dev/null @@ -1,2 +0,0 @@ -

        invalid

        -

        invalid

        \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/raw-repair/_before.html b/packages/svelte/tests/hydration/samples/raw-repair/_before.html deleted file mode 100644 index 3e2942c4be..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-repair/_before.html +++ /dev/null @@ -1,6 +0,0 @@ -

        -

        invalid

        -

        -

        invalid

        - -

        \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/raw-svg/_before.html b/packages/svelte/tests/hydration/samples/raw-svg/_before.html deleted file mode 100644 index 7ec08fa13f..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-svg/_before.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/svelte/tests/hydration/samples/raw-with-empty-line-at-top/_before.html b/packages/svelte/tests/hydration/samples/raw-with-empty-line-at-top/_before.html deleted file mode 100644 index 6aea13491a..0000000000 --- a/packages/svelte/tests/hydration/samples/raw-with-empty-line-at-top/_before.html +++ /dev/null @@ -1,10 +0,0 @@ -
        before
        -
        - - -a -b -c - - -
        after
        diff --git a/packages/svelte/tests/hydration/samples/raw/_before.html b/packages/svelte/tests/hydration/samples/raw/_before.html deleted file mode 100644 index be89227a9b..0000000000 --- a/packages/svelte/tests/hydration/samples/raw/_before.html +++ /dev/null @@ -1,4 +0,0 @@ - -

        this is some html

        -

        and so is this

        - diff --git a/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_after.html b/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_after.html deleted file mode 100644 index d20b3ed496..0000000000 --- a/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_after.html +++ /dev/null @@ -1 +0,0 @@ -

        Hello client!

        diff --git a/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_before.html b/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_before.html deleted file mode 100644 index f97ad9726b..0000000000 --- a/packages/svelte/tests/hydration/samples/repairs-apparent-static-content/_before.html +++ /dev/null @@ -1 +0,0 @@ -

        Hello world!

        diff --git a/packages/svelte/tests/hydration/samples/surrounding-whitespace/_config.js b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_config.js new file mode 100644 index 0000000000..f47bee71df --- /dev/null +++ b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/hydration/samples/surrounding-whitespace/_override.html b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_override.html new file mode 100644 index 0000000000..e728b682d0 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_override.html @@ -0,0 +1,2 @@ + + hello diff --git a/packages/svelte/tests/hydration/samples/surrounding-whitespace/main.svelte b/packages/svelte/tests/hydration/samples/surrounding-whitespace/main.svelte new file mode 100644 index 0000000000..7d6fe33113 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/surrounding-whitespace/main.svelte @@ -0,0 +1 @@ +{#if true}hello{/if} diff --git a/packages/svelte/tests/hydration/samples/text-empty/_before.html b/packages/svelte/tests/hydration/samples/text-empty/_before.html deleted file mode 100644 index a8cad39ae7..0000000000 --- a/packages/svelte/tests/hydration/samples/text-empty/_before.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/text-empty/_config.js b/packages/svelte/tests/hydration/samples/text-empty/_config.js index f47bee71df..4067b68b04 100644 --- a/packages/svelte/tests/hydration/samples/text-empty/_config.js +++ b/packages/svelte/tests/hydration/samples/text-empty/_config.js @@ -1,3 +1,11 @@ import { test } from '../../test'; -export default test({}); +export default test({ + server_props: { + x: '' + }, + + props: { + x: 'x' + } +}); diff --git a/packages/svelte/tests/hydration/samples/text-empty/_after.html b/packages/svelte/tests/hydration/samples/text-empty/_expected.html similarity index 100% rename from packages/svelte/tests/hydration/samples/text-empty/_after.html rename to packages/svelte/tests/hydration/samples/text-empty/_expected.html diff --git a/packages/svelte/tests/hydration/samples/text-empty/main.svelte b/packages/svelte/tests/hydration/samples/text-empty/main.svelte index d88ec4833c..90451138d3 100644 --- a/packages/svelte/tests/hydration/samples/text-empty/main.svelte +++ b/packages/svelte/tests/hydration/samples/text-empty/main.svelte @@ -1,5 +1,5 @@ {x} diff --git a/packages/svelte/tests/hydration/samples/text-fallback/_before.html b/packages/svelte/tests/hydration/samples/text-fallback/_before.html deleted file mode 100644 index d5d3925b3b..0000000000 --- a/packages/svelte/tests/hydration/samples/text-fallback/_before.html +++ /dev/null @@ -1 +0,0 @@ -
        foo override
        default
        diff --git a/packages/svelte/tests/hydration/samples/top-level-text/_before.html b/packages/svelte/tests/hydration/samples/top-level-text/_before.html deleted file mode 100644 index 8f4d4886d4..0000000000 --- a/packages/svelte/tests/hydration/samples/top-level-text/_before.html +++ /dev/null @@ -1 +0,0 @@ -Text diff --git a/packages/svelte/tests/hydration/test.ts b/packages/svelte/tests/hydration/test.ts index c9db5d7e6f..6884504718 100644 --- a/packages/svelte/tests/hydration/test.ts +++ b/packages/svelte/tests/hydration/test.ts @@ -4,14 +4,14 @@ import * as fs from 'node:fs'; import { assert } from 'vitest'; import { compile_directory, should_update_expected } from '../helpers.js'; import { assert_html_equal } from '../html_equal.js'; -import { suite, assert_ok } from '../suite.js'; +import { suite, assert_ok, type BaseTest } from '../suite.js'; import { createClassComponent } from 'svelte/legacy'; +import { render } from 'svelte/server'; import type { CompileOptions } from '#compiler'; -interface HydrationTest { - solo?: boolean; - skip?: boolean; +interface HydrationTest extends BaseTest { load_compiled?: boolean; + server_props?: Record; props?: Record; compileOptions?: Partial; /** @@ -34,17 +34,11 @@ interface HydrationTest { after_test?: () => void; } -const { test, run } = suite(async (config, cwd) => { - /** - * Read file and remove whitespace between ssr comments - */ - function read_html(path: string, fallback?: string): string { - const html = fs.readFileSync(fallback && !fs.existsSync(path) ? fallback : path, 'utf-8'); - return config.trim_whitespace !== false - ? html.replace(/()[ \t\n\r\f]+()/g, '$1$2') - : html; - } +function read(path: string): string | void { + return fs.existsSync(path) ? fs.readFileSync(path, 'utf-8') : undefined; +} +const { test, run } = suite(async (config, cwd) => { if (!config.load_compiled) { await compile_directory(cwd, 'client', { accessors: true, ...config.compileOptions }); await compile_directory(cwd, 'server', config.compileOptions); @@ -53,14 +47,16 @@ const { test, run } = suite(async (config, cwd) => { const target = window.document.body; const head = window.document.head; - target.innerHTML = read_html(`${cwd}/_before.html`); + const rendered = render((await import(`${cwd}/_output/server/main.svelte.js`)).default, { + props: config.server_props ?? config.props ?? {} + }); - let before_head; - try { - before_head = read_html(`${cwd}/_before_head.html`); - head.innerHTML = before_head; - } catch (err) { - // continue regardless of error + fs.writeFileSync(`${cwd}/_output/body.html`, rendered.html + '\n'); + target.innerHTML = read(`${cwd}/_override.html`) ?? rendered.html; + + if (rendered.head) { + fs.writeFileSync(`${cwd}/_output/head.html`, rendered.head + '\n'); + head.innerHTML = rendered.head; } config.before_test?.(); @@ -95,29 +91,12 @@ const { test, run } = suite(async (config, cwd) => { assert.ok(!got_hydration_error, 'Unexpected hydration error'); } - try { - assert_html_equal(target.innerHTML, read_html(`${cwd}/_after.html`, `${cwd}/_before.html`)); - } catch (error) { - if (should_update_expected()) { - fs.writeFileSync(`${cwd}/_after.html`, target.innerHTML); - console.log(`Updated ${cwd}/_after.html.`); - } else { - throw error; - } - } + const expected = read(`${cwd}/_expected.html`) ?? rendered.html; + assert_html_equal(target.innerHTML, expected); - if (before_head) { - try { - const after_head = read_html(`${cwd}/_after_head.html`, `${cwd}/_before_head.html`); - assert_html_equal(head.innerHTML, after_head); - } catch (error) { - if (should_update_expected()) { - fs.writeFileSync(`${cwd}/_after_head.html`, head.innerHTML); - console.log(`Updated ${cwd}/_after_head.html.`); - } else { - throw error; - } - } + if (rendered.head) { + const expected = read(`${cwd}/_expected_head.html`) ?? rendered.head; + assert_html_equal(head.innerHTML, expected); } if (config.snapshot) { diff --git a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json index 4891e70c92..794e80f66f 100644 --- a/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json +++ b/packages/svelte/tests/parser-modern/samples/comment-before-script/output.json @@ -44,7 +44,6 @@ "column": 0 } }, - "leadingComments": [{ "type": "Line", "value": "should not error out" }], "body": [ { "type": "VariableDeclaration", @@ -127,7 +126,13 @@ "kind": "let" } ], - "sourceType": "module" + "sourceType": "module", + "leadingComments": [ + { + "type": "Line", + "value": "should not error out" + } + ] } } } diff --git a/packages/svelte/tests/runtime-browser/assert.js b/packages/svelte/tests/runtime-browser/assert.js index 8f8ec80b7f..c2c265d90f 100644 --- a/packages/svelte/tests/runtime-browser/assert.js +++ b/packages/svelte/tests/runtime-browser/assert.js @@ -111,9 +111,9 @@ function normalize_children(node) { * @template Props * @param {{ * skip?: boolean; - * skip_if_ssr?: boolean | 'permanent'; - * skip_if_hydrate?: boolean | 'permanent'; * solo?: boolean; + * mode?: Array<'server' | 'client' | 'hydrate'>; + * skip_mode?: Array<'server' | 'client' | 'hydrate'>; * html?: string; * ssrHtml?: string; * props?: Props; diff --git a/packages/svelte/tests/runtime-browser/driver.js b/packages/svelte/tests/runtime-browser/driver.js index 7c8d32274d..7a5603e9b8 100644 --- a/packages/svelte/tests/runtime-browser/driver.js +++ b/packages/svelte/tests/runtime-browser/driver.js @@ -25,7 +25,8 @@ export default async function (target) { target, props: config.props, intro: config.intro, - hydrate: __HYDRATE__ + hydrate: __HYDRATE__, + recover: false }, config.options || {} ); diff --git a/packages/svelte/tests/runtime-browser/samples/dynamic-element-custom-element/_config.js b/packages/svelte/tests/runtime-browser/samples/dynamic-element-custom-element/_config.js index 7db4f5e7b0..743ae378cb 100644 --- a/packages/svelte/tests/runtime-browser/samples/dynamic-element-custom-element/_config.js +++ b/packages/svelte/tests/runtime-browser/samples/dynamic-element-custom-element/_config.js @@ -1,8 +1,8 @@ import { test } from '../../assert'; export default test({ - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', + mode: ['client'], + props: { tag: /** @type {string | null} */ ('my-custom-element'), name: /** @type {string | null | undefined} */ (null) diff --git a/packages/svelte/tests/runtime-browser/samples/html-tag-script/_config.js b/packages/svelte/tests/runtime-browser/samples/html-tag-script/_config.js index d9cab08587..130d23d0b5 100644 --- a/packages/svelte/tests/runtime-browser/samples/html-tag-script/_config.js +++ b/packages/svelte/tests/runtime-browser/samples/html-tag-script/_config.js @@ -4,6 +4,5 @@ export default test({ // Test that @html does not execute scripts when instantiated in the client. // Needs to be in this test suite because JSDOM does not quite get this right. html: `
        `, - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent' + mode: ['client'] }); diff --git a/packages/svelte/tests/runtime-browser/test-ssr.ts b/packages/svelte/tests/runtime-browser/test-ssr.ts index 27cf2334c3..698ae382ab 100644 --- a/packages/svelte/tests/runtime-browser/test-ssr.ts +++ b/packages/svelte/tests/runtime-browser/test-ssr.ts @@ -46,7 +46,8 @@ export async function run_ssr_test( } const { run } = suite>(async (config, test_dir) => { - if (config.skip_if_ssr) return; + if (config.mode && !config.mode.includes('server')) return; + if (config.skip_mode?.includes('server')) return; await run_ssr_test(config, test_dir); }); diff --git a/packages/svelte/tests/runtime-browser/test.ts b/packages/svelte/tests/runtime-browser/test.ts index 215b7fd415..c47a72ccb4 100644 --- a/packages/svelte/tests/runtime-browser/test.ts +++ b/packages/svelte/tests/runtime-browser/test.ts @@ -28,7 +28,11 @@ const { run: run_browser_tests } = suite_with_variants< >( ['dom', 'hydrate'], (variant, config) => { - if (variant === 'hydrate' && config.skip_if_hydrate) return true; + if (variant === 'hydrate') { + if (config.mode && !config.mode.includes('hydrate')) return 'no-test'; + if (config.skip_mode?.includes('hydrate')) return true; + } + return false; }, () => {}, @@ -116,7 +120,7 @@ async function run_test( let build_result_ssr; if (hydrate) { - const ssr_entry = path.resolve(__dirname, '../../src/main/main-server.js'); + const ssr_entry = path.resolve(__dirname, '../../src/index-server.js'); build_result_ssr = await build({ entryPoints: [`${__dirname}/driver-ssr.js`], diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js index 9d5e45e05a..a2edd90f8b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js @@ -1,7 +1,7 @@ import { ok, test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // unnecessary to test this in ssr mode + mode: ['client', 'hydrate'], html: '', diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte new file mode 100644 index 0000000000..e38a0fff64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte @@ -0,0 +1,27 @@ + + + +{#if selected} +
        {item.id}
        +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js new file mode 100644 index 0000000000..328d67cb2c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + html: ` + +
        1
        + `, + async test({ assert, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + /** + * @type {any[]} + */ + const messages = []; + const log = console.log; + console.log = (msg) => messages.push(msg); + + flushSync(() => { + // @ts-ignore + button.dispatchEvent(event); + }); + + console.log = log; + assert.deepEqual(messages, ['afterUpdate', 'onDestroy']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte new file mode 100644 index 0000000000..7f99ce0f38 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte @@ -0,0 +1,10 @@ + + +{#each Object.values($items) as item (item.id)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js new file mode 100644 index 0000000000..39c0ef7f53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

        hello!

        +

        hello!

        + `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

        goodbye!

        +

        goodbye!

        + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte new file mode 100644 index 0000000000..688a25b124 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte @@ -0,0 +1,13 @@ + + +

        {value}

        +

        {mirror}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js new file mode 100644 index 0000000000..39c0ef7f53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

        hello!

        +

        hello!

        + `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

        goodbye!

        +

        goodbye!

        + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte new file mode 100644 index 0000000000..3f4c15cd96 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte @@ -0,0 +1,15 @@ + + +

        {value}

        +

        diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js new file mode 100644 index 0000000000..848da78b2d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js @@ -0,0 +1,61 @@ +// @ts-nocheck +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
        a
        +
        b
        +
        c
        +
        d
        +
        e
        + `, + + test({ assert, component, target, raf }) { + let divs = target.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + divs = target.querySelectorAll('div'); + assert.ok(~divs[0].style.animation.indexOf('__svelte')); + assert.equal(divs[1].style.animation, ''); + assert.equal(divs[2].style.animation, ''); + assert.equal(divs[3].style.animation, ''); + assert.ok(~divs[4].style.animation.indexOf('__svelte')); + + raf.tick(100); + assert.deepEqual([divs[0].style.animation, divs[4].style.animation], ['', '']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte new file mode 100644 index 0000000000..bd3647d73c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte @@ -0,0 +1,17 @@ + + +{#each things as thing (thing.id)} +
        {thing.name}
        +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js new file mode 100644 index 0000000000..a72aed883b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js @@ -0,0 +1,91 @@ +// @ts-nocheck +import { ok, test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
        a
        +
        b
        +
        c
        +
        d
        +
        e
        + `, + + test({ assert, component, window, raf }) { + let divs = window.document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + divs = window.document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 108); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 48); + assert.equal(divs[4].dy, 0); + + raf.tick(150); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + + component.things = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ]; + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(200); + assert.equal(divs[0].dy, 108); + assert.equal(divs[4].dy, -60); + + raf.tick(250); + assert.equal(divs[0].dy, 48); + assert.equal(divs[4].dy, 0); + + raf.tick(300); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte new file mode 100644 index 0000000000..c29394fa67 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte @@ -0,0 +1,21 @@ + + +{#each things as thing, i (thing.id)} +
        {thing.name}
        +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js new file mode 100644 index 0000000000..5b7ed1c732 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js @@ -0,0 +1,61 @@ +// @ts-nocheck +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
        a
        +
        b
        +
        c
        +
        d
        +
        e
        + `, + + test({ assert, component, raf }) { + let divs = document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte new file mode 100644 index 0000000000..b376452e15 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte @@ -0,0 +1,25 @@ + + +{#each things as thing (thing.id)} +
        {thing.name}
        +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js new file mode 100644 index 0000000000..3606f7d17b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js @@ -0,0 +1,82 @@ +// @ts-nocheck +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
        a
        +
        b
        +
        c
        +
        d
        +
        e
        + `, + + test({ assert, component, raf }) { + let divs = document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + + component.things = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ]; + + divs = document.querySelectorAll('div'); + + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(150); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(200); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte new file mode 100644 index 0000000000..4d060dd140 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte @@ -0,0 +1,20 @@ + + +{#each things as thing (thing.id)} +
        {thing.name}
        +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/_config.js index e614f3bfc7..3fd470057f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-custom-element/_config.js @@ -1,8 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', + mode: ['client'], html: ` Hello World! ` diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/_config.js new file mode 100644 index 0000000000..4777a268bc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + html: ` + + + + + `, + + compileOptions: { + namespace: 'foreign' + }, + + test({ assert, target }) { + // @ts-ignore + const attr = (/** @type {string} */ sel) => target.querySelector(sel).attributes[0].name; + assert.equal(attr('page'), 'horizontalAlignment'); + assert.equal(attr('button'), 'textWrap'); + assert.equal(attr('text'), 'wordWrap'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/main.svelte new file mode 100644 index 0000000000..52b3e646e1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-casing-foreign-namespace-compiler-option/main.svelte @@ -0,0 +1,4 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js new file mode 100644 index 0000000000..e71ef46849 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js @@ -0,0 +1,11 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const [btn1] = target.querySelectorAll('button'); + flushSync(() => { + // This test would result in an infinite loop, so if this doesn't error, then the test is working. + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte new file mode 100644 index 0000000000..908d07f39a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte @@ -0,0 +1,9 @@ + + +{#each items as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte new file mode 100644 index 0000000000..f2568e2652 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte @@ -0,0 +1,12 @@ + + +{foo} diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/List.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/List.svelte new file mode 100644 index 0000000000..5b12d8a104 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/List.svelte @@ -0,0 +1,13 @@ + + +{#each items as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js new file mode 100644 index 0000000000..c21b68106d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + html: ` + 3 + 2 + 1 + `, + + async test({ assert, component, target }) { + await component.list.update(); + + assert.htmlEqual( + target.innerHTML, + ` + 1 + 2 + 3 + 4 + 5 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/main.svelte new file mode 100644 index 0000000000..4f6e432aa8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/main.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js new file mode 100644 index 0000000000..39c0ef7f53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

        hello!

        +

        hello!

        + `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

        goodbye!

        +

        goodbye!

        + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte new file mode 100644 index 0000000000..8e86aa77cb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte @@ -0,0 +1,13 @@ + + +

        {value}

        +

        {mirror}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js index b0db992d3b..d0b46cffa6 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js @@ -5,7 +5,7 @@ import { flushSync } from 'svelte'; let tasks = []; export default test({ - skip_if_ssr: 'permanent', // unnecessary to test this in ssr mode + mode: ['client', 'hydrate'], // unnecessary to test this in ssr mode get props() { tasks = [ diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte new file mode 100644 index 0000000000..565c3bc6b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js new file mode 100644 index 0000000000..60c22ebfc7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + html: ` + +

        1

        + `, + + async test({ assert, component, target, window }) { + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + + assert.equal(component.tasks_touched, 1); + + const change = new window.Event('change'); + options[1].selected = true; + // @ts-ignore + await select.dispatchEvent(change); + + assert.equal(component.selected, options[1].value); + assert.equal(component.tasks_touched, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte new file mode 100644 index 0000000000..3c21eba829 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte @@ -0,0 +1,19 @@ + + + + + +

        {tasks_touched}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte new file mode 100644 index 0000000000..565c3bc6b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js new file mode 100644 index 0000000000..20806b3eeb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + + const change = new window.Event('change'); + options[1].selected = true; + // @ts-ignore + await select.dispatchEvent(change); + + assert.equal(component.selected, options[1].value); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte new file mode 100644 index 0000000000..494653bb4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js index 0590c6eef1..cb5d26b913 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js @@ -1,7 +1,7 @@ import { ok, test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: `

        selected: b

        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js index 3550d3786d..9b25c0bc58 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js @@ -1,7 +1,7 @@ import { ok, test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: `

        selected: a

        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js index 8d5ebfc9d5..48659c4527 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js @@ -1,7 +1,7 @@ import { ok, test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: `

        selected: a

        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js index 05b485a066..c0e64521d1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js @@ -2,7 +2,7 @@ import { ok, test } from '../../test'; // test select binding behavior when a selected option is removed export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: `

        selected: a

        `, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js index cd0690f2dc..80f7b58975 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js @@ -1,7 +1,7 @@ import { ok, test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: ` diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js index a26d35406b..ff7d99e2e4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode html: `
        foo
        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js index 006e59a153..7e624e3a2f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode html: `
        foo
        first has foo: true
        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js index 1b1e3454e0..1f42696432 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode html: `
        foo
        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js index a26d35406b..ff7d99e2e4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode html: `
        foo
        diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js index 985d5c0bd6..a10ea16843 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode get props() { return { visible: true }; }, diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js index 9ab70994e8..151f389f67 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // there's no class instance to retrieve in SSR mode + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode html: '
        has div: true
        ' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js index 3ec47f10d3..db21b69d2f 100644 --- a/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js @@ -1,6 +1,6 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // doesn't work in SSR + mode: ['client', 'hydrate'], // doesn't work in SSR html: '
        object
        ' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js index f1947417a8..f9427690ae 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js @@ -2,7 +2,7 @@ import { ok, test } from '../../test'; import { flushSync } from 'svelte'; export default test({ - skip_if_ssr: 'permanent', // relies on onMount firing, which does not happen in SSR mode + mode: ['client', 'hydrate'], // relies on onMount firing, which does not happen in SSR mode get props() { return { count: 3 }; diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js index 5deac8345b..b866160fb0 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js @@ -2,7 +2,7 @@ import { ok, test } from '../../test'; import { flushSync } from 'svelte'; export default test({ - skip_if_ssr: 'permanent', // relies on onMount firing, which does not happen in SSR mode + mode: ['client', 'hydrate'], // relies on onMount firing, which does not happen in SSR mode get props() { return { count: 3 }; diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte new file mode 100644 index 0000000000..cc77c331fa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte @@ -0,0 +1 @@ +

        does nothing

        diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js new file mode 100644 index 0000000000..6012649c5f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; +// @ts-nocheck + +export default test({ + test({ assert, component }) { + let count = 0; + + // @ts-ignore + component.$on('state', ({ changed }) => { + if (changed.bar) count += 1; + }); + + component.x = true; + assert.equal(count, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte new file mode 100644 index 0000000000..f77bc8c2ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte @@ -0,0 +1,12 @@ + + +{#if x} + +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte new file mode 100644 index 0000000000..f0aa73f4f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte new file mode 100644 index 0000000000..e2b38acd87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte @@ -0,0 +1,6 @@ + + +level 2 + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte new file mode 100644 index 0000000000..f961776bd1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte @@ -0,0 +1 @@ +level 3 diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js new file mode 100644 index 0000000000..e61d8d7b38 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; +import { unmount } from 'svelte'; + +export default test({ + test({ component }) { + unmount(component.l1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte new file mode 100644 index 0000000000..5c2407898e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor-dev/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor-dev/_config.js index e5ce1d2df0..db235a0ea1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor-dev/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor-dev/_config.js @@ -1,10 +1,11 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', + mode: ['client'], + compileOptions: { dev: true }, + error: 'this={...} of should specify a Svelte component.' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js index 77a0a67a74..f4edaf5223 100644 --- a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js @@ -1,8 +1,8 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', + mode: ['client'], + get props() { return { selected: false }; }, diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte new file mode 100644 index 0000000000..af77418a1f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte @@ -0,0 +1,6 @@ + + +
        Value in child component: {value}
        diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js new file mode 100644 index 0000000000..e05bb35637 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + html: ` +
        Value in child component:
        + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte new file mode 100644 index 0000000000..fbaa4780d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte @@ -0,0 +1,15 @@ + + +
        diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js index 0e8e34bde2..68d1168b32 100644 --- a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js @@ -14,6 +14,6 @@ export default test({ }; }, test({ assert }) { - assert.deepEqual(result, ['import_action', 'each_action']); + assert.deepEqual(result, ['each_action', 'import_action']); // ideally this would be reversed, but it doesn't matter a whole lot } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js index d004cd7ed3..38cb3aad6a 100644 --- a/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: `

        Reactive: foo

        diff --git a/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js new file mode 100644 index 0000000000..4fe9fbaf45 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; +import { unmount } from 'svelte'; + +export default test({ + test({ component }) { + unmount(component); + unmount(component); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte new file mode 100644 index 0000000000..61da16d026 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte @@ -0,0 +1 @@ +
        diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js new file mode 100644 index 0000000000..2c7865b82e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + compileOptions: { + dev: true + }, + error: '{#each} only works with iterable values.' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte new file mode 100644 index 0000000000..7225319e14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte @@ -0,0 +1,3 @@ +{#each {} as item} +
        {item}
        +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js new file mode 100644 index 0000000000..333ad48ba5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing, error message is wrong + + compileOptions: { + dev: true + }, + + get props() { + return { a: 42 }; + }, + + test({ assert, component }) { + try { + component.foo = 1; + throw new Error('Expected an error'); + } catch (err) { + // @ts-ignore + assert.equal(err.message, "
        : Cannot set read-only property 'foo'"); + } + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte new file mode 100644 index 0000000000..5b7ebf809c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte @@ -0,0 +1,7 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte new file mode 100644 index 0000000000..d4fe28a8a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte @@ -0,0 +1,5 @@ + + +

        value(1) = {value}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte new file mode 100644 index 0000000000..07d41f3d84 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte @@ -0,0 +1,5 @@ + + +

        value(2) = {value}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js new file mode 100644 index 0000000000..eb02214ae8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

        value(1) = 1

        + + `, + + async test({ assert, component, window, target }) { + const button = target.querySelector('button'); + // @ts-ignore + await button.dispatchEvent(new window.Event('click')); + assert.htmlEqual( + target.innerHTML, + ` +

        value(2) = 2

        + + ` + ); + assert.equal(component.n, 2); + // @ts-ignore + await button.dispatchEvent(new window.Event('click')); + assert.htmlEqual( + target.innerHTML, + ` +

        value(1) = 3

        + + ` + ); + assert.equal(component.n, 3); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte new file mode 100644 index 0000000000..3a5805b3e5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte @@ -0,0 +1,12 @@ + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte new file mode 100644 index 0000000000..e87e7ec699 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte @@ -0,0 +1,9 @@ + + +

        value(1) = {value}

        +

        foo={foo}

        +

        typeof cb={typeof cb}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte new file mode 100644 index 0000000000..06c4c7acfe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte @@ -0,0 +1,9 @@ + + +

        value(2) = {value}

        +

        foo={foo}

        +

        typeof cb={typeof cb}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js new file mode 100644 index 0000000000..8e224b3eb3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

        value(1) = 1

        +

        foo=bar

        +

        typeof cb=function

        + + `, + + async test({ assert, window, target }) { + const button = target.querySelector('button'); + // @ts-ignore + await button.dispatchEvent(new window.Event('click')); + assert.htmlEqual( + target.innerHTML, + ` +

        value(2) = 2

        +

        foo=bar

        +

        typeof cb=function

        + + ` + ); + // @ts-ignore + await button.dispatchEvent(new window.Event('click')); + assert.htmlEqual( + target.innerHTML, + ` +

        value(1) = 1

        +

        foo=bar

        +

        typeof cb=function

        + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte new file mode 100644 index 0000000000..082ebbcda2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte @@ -0,0 +1,14 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js index 2da6d5ffb1..364a30066c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js @@ -9,7 +9,7 @@ let originalSpanGetBoundingClientRect; let originalParagraphGetBoundingClientRect; export default test({ - skip_if_ssr: 'permanent', // no animations in SSR + mode: ['client', 'hydrate'], // no animations in SSR get props() { return { things: [ diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js index 2b9204ed95..608defe96d 100644 --- a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js @@ -1,12 +1,15 @@ import { test } from '../../test'; export default test({ - skip_if_hydrate: 'permanent', // SSR errors on render already + mode: ['client', 'server'], // SSR errors on render already + compileOptions: { dev: true }, + get props() { return { tag: 123 }; }, + error: ' expects "this" attribute to be a string.' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte new file mode 100644 index 0000000000..616839ee0e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte @@ -0,0 +1,8 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js new file mode 100644 index 0000000000..a47e7976eb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +/** + * @type {{ (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }} + */ +let log; + +export default test({ + html: ` + + `, + + before_test() { + log = console.log; + }, + after_test() { + console.log = log; + }, + + async test({ assert, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + /** + * @type {any[]} + */ + const messages = []; + console.log = (msg) => messages.push(msg); + // @ts-ignore + await button.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + assert.deepEqual(messages, ['destroy']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte new file mode 100644 index 0000000000..0ee5ef4a04 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js new file mode 100644 index 0000000000..fdd881ddd9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { items: ['foo', 'bar', 'baz'] }; + }, + + html: ` + + + + `, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const event = new window.MouseEvent('click'); + + /** + * @type {any[]} + */ + const clicked = []; + + component.$on('clicked', (/** @type {{ detail: { node: any; }; }} */ event) => { + clicked.push(event.detail.node); + }); + + buttons[1].dispatchEvent(event); + + assert.equal(clicked.length, 1); + assert.equal(clicked[0].nodeName, 'BUTTON'); + assert.equal(clicked[0].textContent, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte new file mode 100644 index 0000000000..56ae6b2de2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte @@ -0,0 +1,11 @@ + + +{#each items as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte new file mode 100644 index 0000000000..45f55baae1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js new file mode 100644 index 0000000000..0201f3da3d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + let answer; + component.$on('foo', (/** @type {{ detail: { answer: any; }; }} */ event) => { + answer = event.detail.answer; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.equal(answer, 42); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte new file mode 100644 index 0000000000..d70ec7290e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte new file mode 100644 index 0000000000..45f55baae1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js new file mode 100644 index 0000000000..0201f3da3d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + let answer; + component.$on('foo', (/** @type {{ detail: { answer: any; }; }} */ event) => { + answer = event.detail.answer; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.equal(answer, 42); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/main.svelte new file mode 100644 index 0000000000..f6c5494ce4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js new file mode 100644 index 0000000000..47dac62117 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.Event('click-now'); + + let clicked; + component.$on('click-now', () => { + clicked = true; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.ok(clicked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte new file mode 100644 index 0000000000..8241f05659 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js index 0b24498670..1aa70d7deb 100644 --- a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js @@ -1,4 +1,4 @@ -import { flushSync } from '../../../../src/main/main-client'; +import { flushSync } from '../../../../src/index-client'; import { test } from '../../test'; export default test({ diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js index 9f085360aa..8cce427bbc 100644 --- a/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js @@ -1,6 +1,6 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', + mode: ['client', 'hydrate'], html: '
        object
        ' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js index 3bf5c9d6d1..96e388a7e1 100644 --- a/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js @@ -2,17 +2,16 @@ import { test } from '../../test'; import { destroyed, reset } from './destroyed.js'; export default test({ - test({ assert, component }) { - // for hydration, ssr may have pushed to `destroyed` + before_test() { reset(); + }, + test({ assert, component }) { component.visible = false; - assert.deepEqual(destroyed, ['A', 'B', 'C']); - - reset(); + assert.deepEqual(destroyed, ['C', 'B', 'A']); }, test_ssr({ assert }) { - assert.deepEqual(destroyed, ['A', 'B', 'C']); + assert.deepEqual(destroyed, ['C', 'B', 'A']); } }); diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js index 22050485a9..4f0f7b5b03 100644 --- a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // uses oncreate + mode: ['client', 'hydrate'], // uses oncreate html: '

        true

        \n

        true

        ' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js index 831023584a..9cb2d1716b 100644 --- a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // uses oncreate + mode: ['client', 'hydrate'], // uses oncreate html: '

        true

        ', diff --git a/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js index d5a18488e2..f1a42e996a 100644 --- a/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_hydrate: 'permanent', // output is correct, but test suite chokes on the extra ssr comment which is harmless + mode: ['client', 'server'], // output is correct, but test suite chokes on the extra ssr comment which is harmless withoutNormalizeHtml: true, html: get_html(false), ssrHtml: get_html(true) @@ -12,7 +12,7 @@ function get_html(ssr) { // ssr rendered HTML has an extra newline prefixed within `
        ` tag,
         	// if the 
         tag starts with `\n`
         	// because when browser parses the SSR rendered HTML, it will ignore the 1st '\n' character
        -	return `${ssr ? '' : ''}
          A
        +	return `${ssr ? '' : ''}
          A
           B
           
             C
        @@ -35,5 +35,5 @@ function get_html(ssr) {
         leading newlines
        without spaces
          with spaces  
        ${' '}
         newline after leading space
         
        -multiple leading newlines
        ${ssr ? '' : ''}`; +multiple leading newlines${ssr ? '' : ''}`; } diff --git a/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js b/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js index 7d180eaad0..b94abcbfa9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // a separate SSR test exists + mode: ['client', 'hydrate'], // a separate SSR test exists compileOptions: { preserveComments: true diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte new file mode 100644 index 0000000000..392bc7555d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte @@ -0,0 +1,7 @@ + + +

        a: {a}

        +

        b: {b}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js new file mode 100644 index 0000000000..040b911cc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 3, b: 4 }; + }, + + html: ` +

        a: 3

        +

        b: 2

        + `, + + async test({ assert, component, target }) { + await component.$set({ + a: 5, + b: 6 + }); + + assert.htmlEqual( + target.innerHTML, + ` +

        a: 5

        +

        b: 2

        + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte new file mode 100644 index 0000000000..e9184c8da4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js new file mode 100644 index 0000000000..b92d81bd53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js @@ -0,0 +1,37 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 1, b: 2 }; + }, + + html: ` +

        a: 1

        +

        b: 2

        +

        c: 3

        + `, + + async test({ assert, component, target }) { + await component.$set({ a: 4 }); + + assert.htmlEqual( + target.innerHTML, + ` +

        a: 4

        +

        b: 2

        +

        c: 6

        + ` + ); + + await component.$set({ b: 5 }); + + assert.htmlEqual( + target.innerHTML, + ` +

        a: 4

        +

        b: 5

        +

        c: 9

        + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte new file mode 100644 index 0000000000..1c40f4a344 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte @@ -0,0 +1,8 @@ + + +

        a: {a}

        +

        b: {$$props.b}

        +

        c: {c}

        diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js index c9137c3ca9..f575b3274e 100644 --- a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js @@ -11,7 +11,7 @@ export default test({ if (variant === 'dom') { assert.ok(!span.previousSibling); } else { - assert.ok(span.previousSibling?.textContent?.startsWith('ssr:')); // ssr commment node + assert.ok(span.previousSibling?.textContent === '['); // ssr commment node } component.raw = 'bar'; diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js index c6194149f1..35619e3a0a 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js @@ -1,12 +1,21 @@ -import { tick } from 'svelte'; +import { flushSync } from 'svelte'; import { test } from '../../test'; +import { log } from './log.js'; export default test({ html: '', - async test({ assert, target }) { + + before_test() { + log.length = 0; + }, + + test({ assert, target }) { + assert.deepEqual(log, [2, 1]); + const button = target.querySelector('button'); - button?.click(); - await tick(); + + flushSync(() => button?.click()); + assert.deepEqual(log, [2, 1, 2, 1]); assert.htmlEqual(target.innerHTML, ''); } diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/log.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte index 91aff79c89..c65c992b0c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte @@ -1,9 +1,22 @@ diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js index e05e8180b2..ea3ab4b356 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js @@ -1,3 +1,4 @@ +import { flushSync } from 'svelte'; import { ok, test } from '../../test'; import { reset_numbers } from './data'; @@ -18,7 +19,9 @@ export default test({ const clickEvent = new window.MouseEvent('click', { bubbles: true }); - await btn.dispatchEvent(clickEvent); + flushSync(() => { + btn.dispatchEvent(clickEvent); + }); assert.htmlEqual( target.innerHTML, @@ -31,7 +34,9 @@ export default test({ ` ); - await btn.dispatchEvent(clickEvent); + flushSync(() => { + btn.dispatchEvent(clickEvent); + }); assert.htmlEqual( target.innerHTML, diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js index 0b705cc4f1..99007bfdd9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js @@ -2,7 +2,6 @@ import { tick } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, // failing test for https://github.com/sveltejs/svelte/issues/10787 html: ``, async test({ assert, target }) { target.querySelector('button')?.click(); diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js index c86fbf0291..e68fc225d4 100644 --- a/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // uses oncreate + mode: ['client', 'hydrate'], // uses oncreate html: '

        2

        ' }); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js index 3d02c0571a..57f88880e9 100644 --- a/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // DOM and SSR output is different, a separate SSR test exists + mode: ['client', 'hydrate'], // DOM and SSR output is different, a separate SSR test exists html: '', test({ assert, target }) { diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-from-import/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/_config.js new file mode 100644 index 0000000000..d81175494f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
        +

        static stuff

        +
        +
        +

        dynamic stuff

        +
        + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-from-import/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/main.svelte new file mode 100644 index 0000000000..5cec0ebb08 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/main.svelte @@ -0,0 +1,14 @@ + + +
        +

        static stuff

        +
        + +
        +

        {dynamic} stuff

        +
        + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-from-import/spread.js b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/spread.js new file mode 100644 index 0000000000..8ecf7628f3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-from-import/spread.js @@ -0,0 +1,6 @@ +export function spread() { + return { + class: 'tooltip', + id: null + }; +} diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte new file mode 100644 index 0000000000..4ec51de6d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte @@ -0,0 +1,11 @@ + + +
        Hello {name}
        + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js new file mode 100644 index 0000000000..42b7254c6b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual(component.div.innerHTML, '
        Hello World
        '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte new file mode 100644 index 0000000000..eb2d6c0ee6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte @@ -0,0 +1,18 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte new file mode 100644 index 0000000000..4ec51de6d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte @@ -0,0 +1,11 @@ + + +
        Hello {name}
        + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js new file mode 100644 index 0000000000..42b7254c6b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual(component.div.innerHTML, '
        Hello World
        '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte new file mode 100644 index 0000000000..4d5a825ad3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte @@ -0,0 +1,18 @@ + + +
        diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte new file mode 100644 index 0000000000..4ec51de6d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte @@ -0,0 +1,11 @@ + + +
        Hello {name}
        + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js new file mode 100644 index 0000000000..cf720ec48b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual( + component.div.shadowRoot.innerHTML, + '
        Hello World
        ' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte new file mode 100644 index 0000000000..8674130bb8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte @@ -0,0 +1,19 @@ + + +
        diff --git a/packages/svelte/tests/runtime-legacy/samples/textarea-children/_config.js b/packages/svelte/tests/runtime-legacy/samples/textarea-children/_config.js index ede4825d44..6a550f4957 100644 --- a/packages/svelte/tests/runtime-legacy/samples/textarea-children/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/textarea-children/_config.js @@ -1,7 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_ssr: 'permanent', // SSR behaviour is awkwardly different + mode: ['client', 'hydrate'], // SSR behaviour is awkwardly different get props() { return { foo: 42 }; diff --git a/packages/svelte/tests/runtime-legacy/samples/textarea-content/_config.js b/packages/svelte/tests/runtime-legacy/samples/textarea-content/_config.js index 080976c518..7cd7c553e0 100644 --- a/packages/svelte/tests/runtime-legacy/samples/textarea-content/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/textarea-content/_config.js @@ -4,17 +4,17 @@ export default test({ withoutNormalizeHtml: true, // Unable to test `html` with `
        `, +multiple leading newlines
        `, test({ assert, target }) { // Test for + + + diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js index e0f3a58f3f..ca82a28623 100644 --- a/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js @@ -4,7 +4,7 @@ import { log } from './log.js'; export default test({ // The component context class instance gets shared between tests, strangely, causing hydration to fail? - skip_if_hydrate: 'permanent', + mode: ['client', 'server'], before_test() { log.length = 0; diff --git a/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/_config.js new file mode 100644 index 0000000000..1b6357656a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + html: ``, + + async test({ assert, target, window }) { + const btn = target.querySelector('button'); + const clickEvent = new window.Event('click', { bubbles: true }); + await btn?.dispatchEvent(clickEvent); + + assert.htmlEqual(target.innerHTML, ``); + assert.deepEqual(log, ['create_derived']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/log.js b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/main.svelte new file mode 100644 index 0000000000..520765469b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-fn-destructure/main.svelte @@ -0,0 +1,18 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js index c9d17a200a..3604000543 100644 --- a/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned-2/_config.js @@ -1,8 +1,9 @@ import { test } from '../../test'; export default test({ + mode: ['client', 'server'], + html: '
        d2: 3
        d3: 3
        d4: 3
        ', - skip_if_hydrate: 'permanent', async test({ assert, target }) { await Promise.resolve(); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/_config.js new file mode 100644 index 0000000000..4868a77076 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/_config.js @@ -0,0 +1,17 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + let [btn1] = target.querySelectorAll('button'); + + flushSync(() => { + btn1.click(); + }); + + assert.htmlEqual( + target.innerHTML, + `
        2
        2
        2
        2
        ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/main.svelte new file mode 100644 index 0000000000..7bc28312a5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned-4/main.svelte @@ -0,0 +1,33 @@ + + + + +
        + {thing?.data?.name} +
        +
        + {thing?.name} +
        +
        + {thing?.data?.position} +
        +
        + {thing?.position} +
        diff --git a/packages/svelte/tests/runtime-runes/samples/derived-unowned/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-unowned/_config.js index b7278fe9b1..87b23d6d16 100644 --- a/packages/svelte/tests/runtime-runes/samples/derived-unowned/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/derived-unowned/_config.js @@ -2,7 +2,8 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ - skip_if_hydrate: 'permanent', + mode: ['client', 'server'], + async test({ assert, target }) { let [btn1, btn2] = target.querySelectorAll('button'); const input = target.querySelector('input'); diff --git a/packages/svelte/tests/runtime-runes/samples/each-bind-this-member/main.svelte b/packages/svelte/tests/runtime-runes/samples/each-bind-this-member/main.svelte index a685cc9c84..7d46ea90f0 100644 --- a/packages/svelte/tests/runtime-runes/samples/each-bind-this-member/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/each-bind-this-member/main.svelte @@ -1,5 +1,5 @@ {#each items as item, i} diff --git a/packages/svelte/tests/runtime-runes/samples/each-updates/_config.js b/packages/svelte/tests/runtime-runes/samples/each-updates/_config.js index 13b0b4aed7..0bbfa27631 100644 --- a/packages/svelte/tests/runtime-runes/samples/each-updates/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/each-updates/_config.js @@ -2,9 +2,9 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ + mode: ['client'], + html: `

        test costs $1

        test 2 costs $2

        test costs $1

        test 2 costs $2

        `, - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', async test({ assert, target }) { const [btn1, btn2, btn3] = target.querySelectorAll('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js index b745e0de3d..e61a6bffdd 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/_config.js @@ -15,6 +15,6 @@ export default test({ flushSync(() => { b1.click(); }); - assert.deepEqual(log, ['init 0', 'cleanup 2', 'init 2', 'cleanup 4', 'init 4']); + assert.deepEqual(log, ['init 0', 'cleanup 2', null, 'init 2', 'cleanup 4', null, 'init 4']); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte index a67624b760..1a5f7b632f 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-cleanup/main.svelte @@ -8,8 +8,10 @@ log.push('init ' + double); - return () => { + return function() { log.push('cleanup ' + double); + // @ts-expect-error + log.push(this); }; }) diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-2/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-order-2/_config.js new file mode 100644 index 0000000000..302026493f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-2/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + const [b1] = target.querySelectorAll('button'); + flushSync(() => { + b1.click(); + }); + flushSync(() => { + b1.click(); + }); + assert.deepEqual(log, [ + { a: 1 }, + { b: 1 }, + { c: 1 }, + { a: 2 }, + { b: 2 }, + { c: 2 }, + { a: 3 }, + { b: 3 }, + { c: 3 } + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-2/log.js b/packages/svelte/tests/runtime-runes/samples/effect-order-2/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-2/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-2/main.svelte new file mode 100644 index 0000000000..fb9e9a6c53 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-2/main.svelte @@ -0,0 +1,28 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-root-2/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-root-2/_config.js new file mode 100644 index 0000000000..f6d99a0f5d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-root-2/_config.js @@ -0,0 +1,31 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + const [b1, b2] = target.querySelectorAll('button'); + + flushSync(() => { + b1.click(); + }); + + assert.deepEqual(log, [0]); + + flushSync(() => { + b2.click(); + }); + + assert.deepEqual(log, [0, 'cleanup']); + + flushSync(() => { + b1.click(); + }); + + assert.deepEqual(log, [0, 'cleanup']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-root-2/log.js b/packages/svelte/tests/runtime-runes/samples/effect-root-2/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-root-2/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/effect-root-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-root-2/main.svelte new file mode 100644 index 0000000000..591975ce54 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-root-2/main.svelte @@ -0,0 +1,13 @@ + + + + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-root/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-root/main.svelte index 7a93718659..f7e8275aae 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-root/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-root/main.svelte @@ -11,7 +11,7 @@ const nested_cleanup = $effect.root(() => { return () => { - log.push('cleanup 2') ; + log.push('cleanup 2'); } }); @@ -22,6 +22,6 @@ }); - - - + + + diff --git a/packages/svelte/tests/runtime-runes/samples/event-exported/_config.js b/packages/svelte/tests/runtime-runes/samples/event-exported/_config.js index 527170e1da..6dd1f8181e 100644 --- a/packages/svelte/tests/runtime-runes/samples/event-exported/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/event-exported/_config.js @@ -1,8 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_hydrate: 'permanent', // unnecessary to test - skip_if_ssr: 'permanent', // unnecessary to test + mode: ['client'], async test({ assert, target }) { const [b1, b2] = target.querySelectorAll('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/event-used-in-component-and-element/_config.js b/packages/svelte/tests/runtime-runes/samples/event-used-in-component-and-element/_config.js index 527170e1da..6dd1f8181e 100644 --- a/packages/svelte/tests/runtime-runes/samples/event-used-in-component-and-element/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/event-used-in-component-and-element/_config.js @@ -1,8 +1,7 @@ import { test } from '../../test'; export default test({ - skip_if_hydrate: 'permanent', // unnecessary to test - skip_if_ssr: 'permanent', // unnecessary to test + mode: ['client'], async test({ assert, target }) { const [b1, b2] = target.querySelectorAll('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/nested-script-tag/_config.js b/packages/svelte/tests/runtime-runes/samples/nested-script-tag/_config.js index 29b236d929..051f54889d 100644 --- a/packages/svelte/tests/runtime-runes/samples/nested-script-tag/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/nested-script-tag/_config.js @@ -10,8 +10,8 @@ let log; let original_log; export default test({ - skip_if_ssr: 'permanent', - skip_if_hydrate: 'permanent', // log patching will be too late + mode: ['client'], + before_test() { log = []; original_log = console.log; diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-discouraged/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-discouraged/Counter.svelte index d1be326830..57cbebde12 100644 --- a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-discouraged/Counter.svelte +++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-discouraged/Counter.svelte @@ -1,6 +1,6 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding/Counter.svelte index d1be326830..57cbebde12 100644 --- a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding/Counter.svelte +++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding/Counter.svelte @@ -1,6 +1,6 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/props-bound-fallback/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/props-bound-fallback/Counter.svelte index 6b9240c70e..a2bda4c70b 100644 --- a/packages/svelte/tests/runtime-runes/samples/props-bound-fallback/Counter.svelte +++ b/packages/svelte/tests/runtime-runes/samples/props-bound-fallback/Counter.svelte @@ -1,5 +1,5 @@ {count} diff --git a/packages/svelte/tests/runtime-runes/samples/props-bound-to-normal/Inner.svelte b/packages/svelte/tests/runtime-runes/samples/props-bound-to-normal/Inner.svelte index 82b2f0648a..3d1261071e 100644 --- a/packages/svelte/tests/runtime-runes/samples/props-bound-to-normal/Inner.svelte +++ b/packages/svelte/tests/runtime-runes/samples/props-bound-to-normal/Inner.svelte @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/props-bound/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/props-bound/Counter.svelte index e9bcb945b2..67b08a561f 100644 --- a/packages/svelte/tests/runtime-runes/samples/props-bound/Counter.svelte +++ b/packages/svelte/tests/runtime-runes/samples/props-bound/Counter.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-reactivity/Counter.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-reactivity/Counter.svelte index 2ba2ed9100..077eda5709 100644 --- a/packages/svelte/tests/runtime-runes/samples/props-default-reactivity/Counter.svelte +++ b/packages/svelte/tests/runtime-runes/samples/props-default-reactivity/Counter.svelte @@ -1,6 +1,6 @@ `, + + async test({ assert, target }) { + const btn = target.querySelector('button'); + + flushSync(() => { + btn?.click(); + }); + + assert.htmlEqual( + target.innerHTML, + `
        ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/state-in-template/main.svelte b/packages/svelte/tests/runtime-runes/samples/state-in-template/main.svelte new file mode 100644 index 0000000000..b0eb8f8c6d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/state-in-template/main.svelte @@ -0,0 +1,19 @@ + + +
        { + e.preventDefault(); + const data = new FormData(e.target); + const state = $state({ name: data.get('name') }); + set.add(state); + e.target.reset(); +}}> + + +
        + +{#each set as item} +
        {item.name}
        +{/each} diff --git a/packages/svelte/tests/runtime-runes/samples/state-store-props/_config.js b/packages/svelte/tests/runtime-runes/samples/state-store-props/_config.js index 916aabc9a5..9723cfd589 100644 --- a/packages/svelte/tests/runtime-runes/samples/state-store-props/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/state-store-props/_config.js @@ -1,4 +1,4 @@ -import { flushSync } from '../../../../src/main/main-client'; +import { flushSync } from '../../../../src/index-client'; import { test } from '../../test'; export default test({ diff --git a/packages/svelte/tests/runtime-runes/samples/state-store/_config.js b/packages/svelte/tests/runtime-runes/samples/state-store/_config.js index cfdcc0433d..bd77c82e00 100644 --- a/packages/svelte/tests/runtime-runes/samples/state-store/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/state-store/_config.js @@ -1,4 +1,4 @@ -import { flushSync } from '../../../../src/main/main-client'; +import { flushSync } from '../../../../src/index-client'; import { test } from '../../test'; export default test({ diff --git a/packages/svelte/tests/server-side-rendering/samples/comment-preserve/_expected.html b/packages/svelte/tests/server-side-rendering/samples/comment-preserve/_expected.html index a3ab0f8ea6..3eb11afc34 100644 --- a/packages/svelte/tests/server-side-rendering/samples/comment-preserve/_expected.html +++ b/packages/svelte/tests/server-side-rendering/samples/comment-preserve/_expected.html @@ -1,5 +1 @@ - -

        before

        - -

        after

        - +

        before

        after

        diff --git a/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html b/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html index 74821a4d73..0e12a4a9de 100644 --- a/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html +++ b/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected-head.html @@ -1,6 +1,6 @@ - + Some Title - + diff --git a/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html b/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html index b5fd3947d5..8fb1be347c 100644 --- a/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html +++ b/packages/svelte/tests/server-side-rendering/samples/head-meta-hydrate-duplicate/_expected.html @@ -1 +1 @@ -
        Just a dummy page.
        \ No newline at end of file +
        Just a dummy page.
        diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 248046073c..a6efb9aefa 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -1,8 +1,9 @@ import { describe, assert, it } from 'vitest'; +import { flushSync } from '../../src/index-client'; import * as $ from '../../src/internal/client/runtime'; import { - destroy_effect, effect, + effect_root, render_effect, user_effect } from '../../src/internal/client/reactivity/effects'; @@ -22,17 +23,12 @@ function run_test(runes: boolean, fn: (runes: boolean) => () => void) { $.push({}, runes); // Create a render context so that effect validations etc don't fail let execute: any; - const signal = render_effect( - () => { - execute = fn(runes); - }, - null, - true, - true - ); + const destroy = effect_root(() => { + execute = fn(runes); + }); $.pop(); execute(); - destroy_effect(signal); + destroy(); }; } @@ -52,8 +48,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.deepEqual(log, ['0:0', '1:2', '2:4']); }; @@ -73,8 +69,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.deepEqual(log, ['A:0:0', 'B:0', 'A:1:2', 'B:2', 'A:2:4', 'B:4']); }; @@ -94,8 +90,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.deepEqual(log, ['A:0', 'B:0:0', 'A:2', 'B:1:2', 'A:4', 'B:2:4']); }; @@ -112,8 +108,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.deepEqual(log, [0, 2, 4]); }; @@ -131,8 +127,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.deepEqual(log, [0, 4, 8]); }; @@ -163,18 +159,18 @@ describe('signals', () => { }); return () => { - $.flushSync(); + flushSync(); let i = 2; while (--i) { res.length = 0; set(B, 1); set(A, 1 + i * 2); - $.flushSync(); + flushSync(); set(A, 2 + i * 2); set(B, 2); - $.flushSync(); + flushSync(); assert.equal(res.length, 4); assert.deepEqual(res, [3198, 1601, 3195, 1598]); @@ -196,13 +192,13 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); + flushSync(() => set(count, 1)); // Ensure we're not leaking consumers assert.deepEqual(count.reactions?.length, 1); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 2)); // Ensure we're not leaking consumers assert.deepEqual(count.reactions?.length, 1); - $.flushSync(() => set(count, 3)); + flushSync(() => set(count, 3)); // Ensure we're not leaking consumers assert.deepEqual(count.reactions?.length, 1); assert.deepEqual(log, [0, 1, 2, 3]); @@ -225,11 +221,11 @@ describe('signals', () => { $.get(c); - $.flushSync(() => set(a, 1)); + flushSync(() => set(a, 1)); $.get(c); - $.flushSync(() => set(b, 1)); + flushSync(() => set(b, 1)); $.get(c); @@ -253,20 +249,22 @@ describe('signals', () => { test('effect with derived using unowned derived every time', () => { const log: Array = []; - const effect = user_effect(() => { - log.push($.get(calc)); + const destroy = effect_root(() => { + user_effect(() => { + log.push($.get(calc)); + }); }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); - $.flushSync(() => set(count, 3)); - $.flushSync(() => set(count, 4)); - $.flushSync(() => set(count, 0)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); + flushSync(() => set(count, 3)); + flushSync(() => set(count, 4)); + flushSync(() => set(count, 0)); // Ensure we're not leaking consumers assert.deepEqual(count.reactions?.length, 1); assert.deepEqual(log, [0, 2, 'limit', 0]); - destroy_effect(effect); + destroy(); // Ensure we're not leaking consumers assert.deepEqual(count.reactions, null); }; @@ -288,7 +286,7 @@ describe('signals', () => { }); return () => { - $.flushSync(); + flushSync(); assert.deepEqual(log, [[], []]); }; }); @@ -310,7 +308,7 @@ describe('signals', () => { }); return () => { - $.flushSync(); + flushSync(); assert.deepEqual(log, [[{}], [{}]]); }; }); @@ -327,7 +325,7 @@ describe('signals', () => { return () => { let errored = false; try { - $.flushSync(); + flushSync(); } catch (e: any) { assert.include(e.message, 'ERR_SVELTE_TOO_MANY_UPDATES'); errored = true; @@ -348,7 +346,7 @@ describe('signals', () => { return () => { let errored = false; try { - $.flushSync(); + flushSync(); } catch (e: any) { assert.include(e.message, 'ERR_SVELTE_TOO_MANY_UPDATES'); errored = true; @@ -373,8 +371,8 @@ describe('signals', () => { }); return () => { - $.flushSync(() => set(count, 1)); - $.flushSync(() => set(count, 2)); + flushSync(() => set(count, 1)); + flushSync(() => set(count, 2)); assert.equal(teardown, 1); }; }); diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js index 78ae1ffc52..b14eaa71a9 100644 --- a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js @@ -1,17 +1,16 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export default function Bind_this($$anchor, $$props) { $.push($$props, false); $.init(); - /* Init */ - var fragment = $.comment($$anchor); - var node = $.child_frag(fragment); + var fragment = $.comment(); + var node = $.first_child(fragment); $.bind_this(Foo(node, {}), ($$value) => foo = $$value, () => foo); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js index 71b688fe37..bd1d1ec711 100644 --- a/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/server/index.svelte.js @@ -4,11 +4,8 @@ import * as $ from "svelte/internal/server"; export default function Bind_this($$payload, $$props) { $.push(false); - - const anchor = $.create_anchor($$payload); - - $$payload.out += `${anchor}`; + $$payload.out += ``; Foo($$payload, {}); - $$payload.out += `${anchor}`; + $$payload.out += ``; $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js index 38a74ef9bb..d2c1c9c540 100644 --- a/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/class-state-field-constructor-assignment/_expected/client/index.svelte.js @@ -1,7 +1,7 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export default function Class_state_field_constructor_assignment($$anchor, $$props) { $.push($$props, true); diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js index 6494d2436a..9d6dff7a3b 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js @@ -1,9 +1,9 @@ // main.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; -var frag = $.template(`
        `, true); +var root = $.template(`
        `, 3); export default function Main($$anchor, $$props) { $.push($$props, true); @@ -11,38 +11,28 @@ export default function Main($$anchor, $$props) { // needs to be a snapshot test because jsdom does auto-correct the attribute casing let x = 'test'; let y = () => 'test'; - /* Init */ - var fragment = $.open_frag($$anchor, false, frag); - var div = $.child_frag(fragment); + var fragment = root(); + var div = $.first_child(fragment); var svg = $.sibling($.sibling(div, true)); var custom_element = $.sibling($.sibling(svg, true)); var div_1 = $.sibling($.sibling(custom_element, true)); - var svg_1 = $.sibling($.sibling(div_1, true)); - var custom_element_1 = $.sibling($.sibling(svg_1, true)); - /* Update */ - $.attr_effect(div_1, "foobar", y); - $.attr_effect(svg_1, "viewBox", y); - $.set_custom_element_data_effect(custom_element_1, "fooBar", y); + $.render_effect(() => $.set_attribute(div_1, "foobar", y())); - var div_foobar; - var svg_viewBox; - var custom_element_fooBar; + var svg_1 = $.sibling($.sibling(div_1, true)); - $.render_effect(() => { - if (div_foobar !== (div_foobar = x)) { - $.attr(div, "foobar", div_foobar); - } + $.render_effect(() => $.set_attribute(svg_1, "viewBox", y())); - if (svg_viewBox !== (svg_viewBox = x)) { - $.attr(svg, "viewBox", svg_viewBox); - } + var custom_element_1 = $.sibling($.sibling(svg_1, true)); + + $.render_effect(() => $.set_custom_element_data(custom_element_1, "fooBar", y())); - if (custom_element_fooBar !== (custom_element_fooBar = x)) { - $.set_custom_element_data(custom_element, "fooBar", custom_element_fooBar); - } + $.render_effect(() => { + $.set_attribute(div, "foobar", x); + $.set_attribute(svg, "viewBox", x); + $.set_custom_element_data(custom_element, "fooBar", x); }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js index 3a88121a38..56e320506f 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -1,31 +1,22 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export default function Each_string_template($$anchor, $$props) { $.push($$props, false); $.init(); - /* Init */ - var fragment = $.comment($$anchor); - var node = $.child_frag(fragment); + var fragment = $.comment(); + var node = $.first_child(fragment); - $.each_indexed( - node, - () => ['foo', 'bar', 'baz'], - 1, - ($$anchor, thing, $$index) => { - /* Init */ - var text = $.space_frag($$anchor); + $.each_indexed(node, 1, () => ['foo', 'bar', 'baz'], ($$anchor, thing, $$index) => { + var text = $.text($$anchor); - /* Update */ - $.text_effect(text, () => `${$.stringify($.unwrap(thing))}, `); - return $.close($$anchor, text); - }, - null - ); + $.render_effect(() => $.set_text(text, `${$.stringify($.unwrap(thing))}, `)); + $.append($$anchor, text); + }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); -} +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js index b23b316e3d..afb1daa750 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js @@ -5,18 +5,18 @@ import * as $ from "svelte/internal/server"; export default function Each_string_template($$payload, $$props) { $.push(false); - const anchor = $.create_anchor($$payload); const each_array = $.ensure_array_like(['foo', 'bar', 'baz']); - $$payload.out += `${anchor}`; + $$payload.out += ``; for (let $$index = 0; $$index < each_array.length; $$index++) { const thing = each_array[$$index]; - const anchor_1 = $.create_anchor($$payload); - $$payload.out += `${anchor_1}${$.escape(thing)}, ${anchor_1}`; + $$payload.out += ""; + $$payload.out += `${$.escape(thing)}, `; + $$payload.out += ""; } - $$payload.out += `${anchor}`; + $$payload.out += ""; $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js index 4cc594e9d0..bab47c8c50 100644 --- a/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/export-state/_expected/client/index.svelte.js @@ -1,4 +1,4 @@ /* index.svelte.js generated by Svelte VERSION */ -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export const object = $.proxy({ ok: true }); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js index 365ab43598..564d421d1a 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js @@ -1,7 +1,7 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export default function Function_prop_no_getter($$anchor, $$props) { $.push($$props, true); @@ -13,24 +13,21 @@ export default function Function_prop_no_getter($$anchor, $$props) { } const plusOne = (num) => num + 1; - /* Init */ - var fragment = $.comment($$anchor); - var node = $.child_frag(fragment); + var fragment = $.comment(); + var node = $.first_child(fragment); Button(node, { onmousedown: () => $.set(count, $.get(count) + 1), onmouseup, onmouseenter: () => $.set(count, $.proxy(plusOne($.get(count)))), children: $.add_snippet_symbol(($$anchor, $$slotProps) => { - /* Init */ - var text = $.space_frag($$anchor); + var text = $.text($$anchor); - /* Update */ - $.text_effect(text, () => `clicks: ${$.stringify($.get(count))}`); - return $.close($$anchor, text); + $.render_effect(() => $.set_text(text, `clicks: ${$.stringify($.get(count))}`)); + $.append($$anchor, text); }) }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); -} +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js index 03534f14c2..d646ae1f5a 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/server/index.svelte.js @@ -12,9 +12,8 @@ export default function Function_prop_no_getter($$payload, $$props) { } const plusOne = (num) => num + 1; - const anchor = $.create_anchor($$payload); - $$payload.out += `${anchor}`; + $$payload.out += ``; Button($$payload, { onmousedown: () => count += 1, @@ -25,6 +24,6 @@ export default function Function_prop_no_getter($$payload, $$props) { }) }); - $$payload.out += `${anchor}`; + $$payload.out += ``; $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js index f57dd8a9fd..4f0aadff19 100644 --- a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js @@ -1,17 +1,16 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; -var frag = $.template(`

        hello world

        `); +var root = $.template(`

        hello world

        `); export default function Hello_world($$anchor, $$props) { $.push($$props, false); $.init(); - /* Init */ - var h1 = $.open($$anchor, true, frag); + var h1 = root(); - $.close($$anchor, h1); + $.append($$anchor, h1); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js index 3da681ea53..9d5954ade2 100644 --- a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js @@ -1,7 +1,7 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; function reset(_, str, tpl) { $.set(str, ''); @@ -10,16 +10,15 @@ function reset(_, str, tpl) { $.set(tpl, ``); } -var frag = $.template(` `, true); +var root = $.template(` `, 1); export default function State_proxy_literal($$anchor, $$props) { $.push($$props, true); let str = $.source(''); let tpl = $.source(``); - /* Init */ - var fragment = $.open_frag($$anchor, true, frag); - var input = $.child_frag(fragment); + var fragment = root(); + var input = $.first_child(fragment); $.remove_input_attr_defaults(input); @@ -29,10 +28,10 @@ export default function State_proxy_literal($$anchor, $$props) { var button = $.sibling($.sibling(input_1, true)); + button.__click = [reset, str, tpl]; $.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value)); $.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value)); - button.__click = [reset, str, tpl]; - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index b2734b8c46..e9db44cd7a 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -1,17 +1,16 @@ // index.svelte (Svelte VERSION) // Note: compiler output will change before 5.0 is released! import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; +import * as $ from "svelte/internal/client"; export default function Svelte_element($$anchor, $$props) { $.push($$props, true); let tag = $.prop($$props, "tag", 3, 'hr'); - /* Init */ - var fragment = $.comment($$anchor); - var node = $.child_frag(fragment); + var fragment = $.comment(); + var node = $.first_child(fragment); $.element(node, tag, false); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js index 88a0ca6dcd..2bd6400a5c 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/server/index.svelte.js @@ -6,11 +6,9 @@ export default function Svelte_element($$payload, $$props) { $.push(true); let { tag = 'hr' } = $$props; - const anchor = $.create_anchor($$payload); - $$payload.out += `${anchor}`; + $$payload.out += ``; if (tag) $.element($$payload, tag, () => {}, () => {}); - $$payload.out += `${anchor}`; - $.bind_props($$props, { tag }); + $$payload.out += ``; $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/types/component.ts b/packages/svelte/tests/types/component.ts index 8ef5274016..d4ed55121f 100644 --- a/packages/svelte/tests/types/component.ts +++ b/packages/svelte/tests/types/component.ts @@ -105,7 +105,7 @@ const newComponentEvents2: ComponentEvents = { }; mount(NewComponent, { - target: null as any as Document | Element | ShadowRoot | Text | Comment, + target: null as any as Document | Element | ShadowRoot, props: { prop: 'foo', // @ts-expect-error @@ -120,7 +120,7 @@ mount(NewComponent, { }); hydrate(NewComponent, { - target: null as any as Document | Element | ShadowRoot | Text | Comment, + target: null as any as Document | Element | ShadowRoot, props: { prop: 'foo', // @ts-expect-error diff --git a/packages/svelte/tsconfig.json b/packages/svelte/tsconfig.json index 0764cde0cb..8c27517244 100644 --- a/packages/svelte/tsconfig.json +++ b/packages/svelte/tsconfig.json @@ -16,16 +16,18 @@ "checkJs": true, "paths": { "acorn-typescript": ["./src/compiler/phases/1-parse/ambient.d.ts"], - "svelte": ["./src/main/public.d.ts"], + "svelte": ["./src/index.d.ts"], "svelte/action": ["./src/action/public.d.ts"], "svelte/compiler": ["./src/compiler/public.d.ts"], - "svelte/internal": ["./src/internal/index.js"], + "svelte/internal/client": ["./src/internal/client/index.js"], "svelte/legacy": ["./src/legacy/legacy-client.js"], "svelte/motion": ["./src/motion/public.d.ts"], "svelte/server": ["./src/server/index.js"], "svelte/store": ["./src/store/public.d.ts"], "#compiler": ["./src/compiler/types/index.d.ts"], - "#client": ["./src/internal/client/types.d.ts"] + "#client": ["./src/internal/client/types.d.ts"], + "#server": ["./src/internal/server/types.d.ts"], + "#shared": ["./src/internal/shared/types.d.ts"] } }, "include": [ diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index c2b1c1ad5b..22406fe281 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -288,19 +288,19 @@ declare module 'svelte' { * */ export function afterUpdate(fn: () => void): void; /** - * Anything except a function - */ + * Synchronously flushes any pending state changes and those that result from it. + * */ + export function flushSync(fn?: (() => void) | undefined): void; + /** Anything except a function */ type NotFunction = T extends Function ? never : T; - /** - * @deprecated Use `mount` or `hydrate` instead - */ - export function createRoot(): void; + export function unstate(value: T): T; /** * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component * * */ export function mount, Exports extends Record, Events extends Record>(component: ComponentType>, options: { - target: Node; + target: Document | Element | ShadowRoot; + anchor?: Node | undefined; props?: Props | undefined; events?: { [Property in keyof Events]: (e: Events[Property]) => any; } | undefined; context?: Map | undefined; @@ -311,7 +311,7 @@ declare module 'svelte' { * * */ export function hydrate, Exports extends Record, Events extends Record>(component: ComponentType>, options: { - target: Node; + target: Document | Element | ShadowRoot; props?: Props | undefined; events?: { [Property in keyof Events]: (e: Events[Property]) => any; } | undefined; context?: Map | undefined; @@ -322,10 +322,6 @@ declare module 'svelte' { * Unmounts a component that was previously mounted using `mount` or `hydrate`. * */ export function unmount(component: Record): void; - /** - * Synchronously flushes any pending state changes and those that result from it. - * */ - export function flushSync(fn?: (() => void) | undefined): void; /** * Returns a promise that resolves once any pending state changes have been applied. * */ @@ -368,7 +364,6 @@ declare module 'svelte' { * https://svelte.dev/docs/svelte#getallcontexts * */ export function getAllContexts = Map>(): T; - export function unstate(value: T): T; } declare module 'svelte/action' { @@ -708,7 +703,8 @@ declare module 'svelte/compiler' { node: Identifier; /** * - `normal`: A variable that is not in any way special - * - `prop`: A normal prop (possibly mutated) + * - `prop`: A normal prop (possibly reassigned or mutated) + * - `bindable_prop`: A prop one can `bind:` to (possibly reassigned or mutated) * - `rest_prop`: A rest prop * - `state`: A state variable * - `derived`: A derived variable @@ -720,6 +716,7 @@ declare module 'svelte/compiler' { kind: | 'normal' | 'prop' + | 'bindable_prop' | 'rest_prop' | 'state' | 'frozen_state' @@ -747,7 +744,7 @@ declare module 'svelte/compiler' { scope: Scope; /** For `legacy_reactive`: its reactive dependencies */ legacy_dependencies: Binding[]; - /** Legacy props: the `class` in `{ export klass as class}` */ + /** Legacy props: the `class` in `{ export klass as class}`. $props(): The `class` in { class: klass } = $props() */ prop_alias: string | null; /** * If this is set, all references should use this expression instead of the identifier name. @@ -1849,7 +1846,7 @@ declare module 'svelte/reactivity' { } declare module 'svelte/server' { - export function render(component: (...args: any[]) => void, options: { + export function render(component: typeof import('svelte').SvelteComponent, options: { props: Record; context?: Map; }): RenderOutput; @@ -2501,13 +2498,24 @@ declare namespace $effect { * Declares the props that a component accepts. Example: * * ```ts - * let { optionalProp = 42, requiredProp }: { optionalProp?: number; requiredProps: string } = $props(); + * let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props(); * ``` * * https://svelte-5-preview.vercel.app/docs/runes#$props */ declare function $props(): any; +/** + * Declares a prop as bindable, meaning the parent component can use `bind:propName={value}` to bind to it. + * + * ```ts + * let { propName = $bindable() }: { propName: boolean } = $props(); + * ``` + * + * https://svelte-5-preview.vercel.app/docs/runes#$bindable + */ +declare function $bindable(t?: T): T; + /** * Inspects one or more values whenever they, or the properties they contain, change. Example: * diff --git a/playgrounds/demo/package.json b/playgrounds/demo/package.json index 9eaec0254f..f2c8195592 100644 --- a/playgrounds/demo/package.json +++ b/playgrounds/demo/package.json @@ -12,9 +12,9 @@ }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.1", - "express": "^4.18.2", + "express": "^4.19.2", "nodemon": "^3.0.3", "svelte": "workspace:*", - "vite": "^5.0.12" + "vite": "^5.0.13" } } diff --git a/playgrounds/demo/src/entry-client.ts b/playgrounds/demo/src/entry-client.ts index 1dcfc17b9c..1cb573735c 100644 --- a/playgrounds/demo/src/entry-client.ts +++ b/playgrounds/demo/src/entry-client.ts @@ -1,8 +1,8 @@ // @ts-ignore -import { hydrate, unmount } from 'svelte'; +import { mount, unmount } from 'svelte'; // @ts-ignore you need to create this file import App from './App.svelte'; -const component = hydrate(App, { +const component = mount(App, { target: document.getElementById('root')! }); // @ts-ignore diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9486865eeb..ff616d0e7c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: specifier: 22.0.0 version: 22.0.0 playwright: - specifier: ^1.35.1 + specifier: ^1.41.1 version: 1.41.1 prettier: specifier: ^3.2.4 @@ -146,10 +146,10 @@ importers: devDependencies: '@sveltejs/vite-plugin-svelte': specifier: ^3.0.1 - version: 3.0.1(svelte@packages+svelte)(vite@5.0.12) + version: 3.0.1(svelte@packages+svelte)(vite@5.0.13) express: - specifier: ^4.18.2 - version: 4.18.2 + specifier: ^4.19.2 + version: 4.19.2 nodemon: specifier: ^3.0.3 version: 3.0.3 @@ -157,8 +157,8 @@ importers: specifier: workspace:* version: link:../../packages/svelte vite: - specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + specifier: ^5.0.13 + version: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) playgrounds/sandbox: dependencies: @@ -258,13 +258,13 @@ importers: version: 5.1.0(@sveltejs/kit@2.5.2) '@sveltejs/kit': specifier: ^2.5.0 - version: 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12) + version: 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13) '@sveltejs/site-kit': specifier: 6.0.0-next.59 version: 6.0.0-next.59(@sveltejs/kit@2.5.2)(svelte@packages+svelte) '@sveltejs/vite-plugin-svelte': specifier: ^3.0.0 - version: 3.0.1(svelte@packages+svelte)(vite@5.0.12) + version: 3.0.1(svelte@packages+svelte)(vite@5.0.13) '@types/marked': specifier: ^6.0.0 version: 6.0.0 @@ -293,8 +293,8 @@ importers: specifier: ^5.3.3 version: 5.3.3 vite: - specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + specifier: ^5.0.13 + version: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) sites/svelte.dev: dependencies: @@ -331,13 +331,13 @@ importers: version: 4.0.5(@sveltejs/kit@2.4.3) '@sveltejs/kit': specifier: ^2.4.3 - version: 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12) + version: 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13) '@sveltejs/site-kit': specifier: 6.0.0-next.59 version: 6.0.0-next.59(@sveltejs/kit@2.4.3)(svelte@4.2.9) '@sveltejs/vite-plugin-svelte': specifier: ^3.0.1 - version: 3.0.1(svelte@4.2.9)(vite@5.0.12) + version: 3.0.1(svelte@4.2.9)(vite@5.0.13) '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -405,8 +405,8 @@ importers: specifier: ^5.3.3 version: 5.3.3 vite: - specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + specifier: ^5.0.13 + version: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) vite-imagetools: specifier: ^6.2.9 version: 6.2.9 @@ -2461,7 +2461,7 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 dependencies: - '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13) dev: true /@sveltejs/adapter-vercel@4.0.5(@sveltejs/kit@2.4.3): @@ -2469,7 +2469,7 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 dependencies: - '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13) '@vercel/nft': 0.26.2 esbuild: 0.19.11 transitivePeerDependencies: @@ -2482,7 +2482,7 @@ packages: peerDependencies: '@sveltejs/kit': ^2.4.0 dependencies: - '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13) '@vercel/nft': 0.26.2 esbuild: 0.19.11 transitivePeerDependencies: @@ -2510,7 +2510,7 @@ packages: typescript: 5.3.3 dev: true - /@sveltejs/kit@2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12): + /@sveltejs/kit@2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13): resolution: {integrity: sha512-nKNhUdt61vtD961kQpUk6vLDhpnV0yku5F1uYNWvrJYFV0+cGfmW7ol0JVMSjHMXlMtmmv2FTc+nPRrTFwb2UA==} engines: {node: '>=18.13'} hasBin: true @@ -2520,7 +2520,7 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.3 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.13) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 4.3.2 @@ -2534,9 +2534,9 @@ packages: sirv: 2.0.4 svelte: 4.2.9 tiny-glob: 0.2.9 - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) - /@sveltejs/kit@2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12): + /@sveltejs/kit@2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13): resolution: {integrity: sha512-1Pm2lsBYURQsjnLyZa+jw75eVD4gYHxGRwPyFe4DAmB3FjTVR8vRNWGeuDLGFcKMh/B1ij6FTUrc9GrerogCng==} engines: {node: '>=18.13'} hasBin: true @@ -2546,7 +2546,7 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.3 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@packages+svelte)(vite@5.0.13) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 4.3.2 @@ -2560,7 +2560,7 @@ packages: sirv: 2.0.4 svelte: link:packages/svelte tiny-glob: 0.2.9 - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) dev: true /@sveltejs/repl@0.6.0(@codemirror/lang-html@6.4.8)(@codemirror/search@6.5.6)(@lezer/common@1.2.1)(@lezer/javascript@1.4.13)(@lezer/lr@1.4.0)(@sveltejs/kit@2.4.3)(svelte@4.2.9): @@ -2609,7 +2609,7 @@ packages: '@sveltejs/kit': ^1.0.0 svelte: ^3.54.0 dependencies: - '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13) esm-env: 1.0.0 svelte: 4.2.9 svelte-local-storage-store: 0.4.0(svelte@4.2.9) @@ -2621,7 +2621,7 @@ packages: '@sveltejs/kit': ^1.20.0 svelte: ^4.0.0 dependencies: - '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/kit': 2.4.3(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13) esm-env: 1.0.0 svelte: 4.2.9 svelte-local-storage-store: 0.6.4(svelte@4.2.9) @@ -2633,13 +2633,13 @@ packages: '@sveltejs/kit': ^1.20.0 svelte: ^4.0.0 dependencies: - '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13) esm-env: 1.0.0 svelte: link:packages/svelte svelte-local-storage-store: 0.6.4(svelte@packages+svelte) dev: true - /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12): + /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13): resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} engines: {node: ^18.0.0 || >=20} peerDependencies: @@ -2647,14 +2647,14 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.13) debug: 4.3.4(supports-color@5.5.0) svelte: 4.2.9 - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) transitivePeerDependencies: - supports-color - /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12): + /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13): resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} engines: {node: ^18.0.0 || >=20} peerDependencies: @@ -2662,49 +2662,49 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte': 3.0.1(svelte@packages+svelte)(vite@5.0.13) debug: 4.3.4(supports-color@5.5.0) svelte: link:packages/svelte - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte@3.0.1(svelte@4.2.9)(vite@5.0.12): + /@sveltejs/vite-plugin-svelte@3.0.1(svelte@4.2.9)(vite@5.0.13): resolution: {integrity: sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==} engines: {node: ^18.0.0 || >=20} peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.13) debug: 4.3.4(supports-color@5.5.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.5 svelte: 4.2.9 svelte-hmr: 0.15.3(svelte@4.2.9) - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) - vitefu: 0.2.5(vite@5.0.12) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vitefu: 0.2.5(vite@5.0.13) transitivePeerDependencies: - supports-color - /@sveltejs/vite-plugin-svelte@3.0.1(svelte@packages+svelte)(vite@5.0.12): + /@sveltejs/vite-plugin-svelte@3.0.1(svelte@packages+svelte)(vite@5.0.13): resolution: {integrity: sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==} engines: {node: ^18.0.0 || >=20} peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.12) + '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@packages+svelte)(vite@5.0.13) debug: 4.3.4(supports-color@5.5.0) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.5 svelte: link:packages/svelte svelte-hmr: 0.15.3(svelte@packages+svelte) - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) - vitefu: 0.2.5(vite@5.0.12) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vitefu: 0.2.5(vite@5.0.13) transitivePeerDependencies: - supports-color dev: true @@ -3341,8 +3341,8 @@ packages: resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} dev: true - /body-parser@1.20.1: - resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + /body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dependencies: bytes: 3.1.2 @@ -3354,7 +3354,7 @@ packages: iconv-lite: 0.4.24 on-finished: 2.4.1 qs: 6.11.0 - raw-body: 2.5.1 + raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: @@ -3728,11 +3728,6 @@ packages: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} dev: true - /cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - dev: true - /cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -4469,16 +4464,16 @@ packages: resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} dev: true - /express@4.18.2: - resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + /express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.1 + body-parser: 1.20.2 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.5.0 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 @@ -6722,14 +6717,6 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.4.33: - resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.0.2 - /postcss@8.4.35: resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} engines: {node: ^10 || ^12 || >=14} @@ -6737,7 +6724,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true /preferred-pm@3.1.2: resolution: {integrity: sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q==} @@ -6895,8 +6881,8 @@ packages: engines: {node: '>= 0.6'} dev: true - /raw-body@2.5.1: - resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + /raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} dependencies: bytes: 3.1.2 @@ -8429,7 +8415,7 @@ packages: debug: 4.3.4(supports-color@5.5.0) pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) transitivePeerDependencies: - '@types/node' - less @@ -8441,8 +8427,8 @@ packages: - terser dev: true - /vite@5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0): - resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==} + /vite@5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0): + resolution: {integrity: sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -8472,13 +8458,13 @@ packages: '@types/node': 20.11.5 esbuild: 0.19.11 lightningcss: 1.23.0 - postcss: 8.4.33 + postcss: 8.4.35 rollup: 4.9.5 sass: 1.70.0 optionalDependencies: fsevents: 2.3.3 - /vitefu@0.2.5(vite@5.0.12): + /vitefu@0.2.5(vite@5.0.13): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -8486,7 +8472,7 @@ packages: vite: optional: true dependencies: - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) /vitest@1.2.1(@types/node@20.11.5)(jsdom@22.0.0): resolution: {integrity: sha512-TRph8N8rnSDa5M2wKWJCMnztCZS9cDcgVTQ6tsTFTG/odHJ4l5yNVqvbeDJYJRZ6is3uxaEpFs8LL6QM+YFSdA==} @@ -8533,7 +8519,7 @@ packages: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.0.12(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) + vite: 5.0.13(@types/node@20.11.5)(lightningcss@1.23.0)(sass@1.70.0) vite-node: 1.2.1(@types/node@20.11.5) why-is-node-running: 2.2.2 transitivePeerDependencies: diff --git a/sites/svelte-5-preview/package.json b/sites/svelte-5-preview/package.json index 2346515fd6..21690b1d42 100644 --- a/sites/svelte-5-preview/package.json +++ b/sites/svelte-5-preview/package.json @@ -28,7 +28,7 @@ "svelte-check": "^3.6.3", "tslib": "^2.6.2", "typescript": "^5.3.3", - "vite": "^5.0.12" + "vite": "^5.0.13" }, "dependencies": { "@codemirror/autocomplete": "^6.12.0", diff --git a/sites/svelte-5-preview/src/lib/CodeMirror.svelte b/sites/svelte-5-preview/src/lib/CodeMirror.svelte index 3f29dfe176..530e1e59c2 100644 --- a/sites/svelte-5-preview/src/lib/CodeMirror.svelte +++ b/sites/svelte-5-preview/src/lib/CodeMirror.svelte @@ -220,12 +220,17 @@ boost: 5 }), { label: '$state.frozen', type: 'keyword', boost: 4 }, + { label: '$bindable', type: 'keyword', boost: 4 }, snip('$effect.root(() => {\n\t${}\n});', { label: '$effect.root', type: 'keyword', boost: 3 }), - { label: '$effect.active', type: 'keyword', boost: 2 }, + snip('$effect.active()', { + label: '$effect.active', + type: 'keyword', + boost: 2 + }), { label: '$inspect', type: 'keyword', boost: 1 } ] }; diff --git a/sites/svelte-5-preview/src/lib/workers/bundler/index.js b/sites/svelte-5-preview/src/lib/workers/bundler/index.js index bd0ee9d67e..80e14badbf 100644 --- a/sites/svelte-5-preview/src/lib/workers/bundler/index.js +++ b/sites/svelte-5-preview/src/lib/workers/bundler/index.js @@ -48,10 +48,8 @@ self.addEventListener( const { version } = await fetch(`${svelte_url}/package.json`).then((r) => r.json()); console.log(`Using Svelte compiler version ${version}`); - // unpkg doesn't set the correct MIME type for .cjs files - // https://github.com/mjackson/unpkg/issues/355 - const compiler = await fetch(`${svelte_url}/compiler.cjs`).then((r) => r.text()); - (0, eval)(compiler + '\n//# sourceURL=compiler.cjs@' + version); + const compiler = await fetch(`${svelte_url}/compiler/index.js`).then((r) => r.text()); + (0, eval)(compiler + '\n//# sourceURL=compiler/index.js@' + version); svelte = globalThis.svelte; diff --git a/sites/svelte-5-preview/src/lib/workers/compiler/index.js b/sites/svelte-5-preview/src/lib/workers/compiler/index.js index d3d7e475d1..d264e702a0 100644 --- a/sites/svelte-5-preview/src/lib/workers/compiler/index.js +++ b/sites/svelte-5-preview/src/lib/workers/compiler/index.js @@ -29,10 +29,8 @@ self.addEventListener( .then((r) => r.json()) .catch(() => ({ version: 'experimental' })); - // unpkg doesn't set the correct MIME type for .cjs files - // https://github.com/mjackson/unpkg/issues/355 - const compiler = await fetch(`${svelte_url}/compiler.cjs`).then((r) => r.text()); - (0, eval)(compiler + '\n//# sourceURL=compiler.cjs@' + version); + const compiler = await fetch(`${svelte_url}/compiler/index.js`).then((r) => r.text()); + (0, eval)(compiler + '\n//# sourceURL=compiler/index.js@' + version); svelte = globalThis.svelte; diff --git a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md index 94de0eaff0..3b24ad004e 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md @@ -490,7 +490,7 @@ let { a, b, c, ...everythingElse }: MyProps = $props(); > > ...TypeScript [widens the type](https://www.typescriptlang.org/play?#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwBIAHGHIgZwB4AVeAXnilQE8A+ACgEoAueagbgBQgiCAzwA3vAAe9eABYATPAC+c4qQqUp03uQwwsqAOaqOnIfCsB6a-AB6AfiA) of `x` to be `string | number`, instead of erroring. -Props cannot be mutated, unless the parent component uses `bind:`. During development, attempts to mutate props will result in an error. +By default props are treated as readonly, meaning reassignments will not propagate upwards and mutations will result in a warning at runtime in development mode. You will also get a runtime error when trying to `bind:` to a readonly prop in a parent component. To declare props as bindable, use [`$bindable()`](#bindable). ### What this replaces @@ -498,6 +498,26 @@ Props cannot be mutated, unless the parent component uses `bind:`. During develo Note that you can still use `export const` and `export function` to expose things to users of your component (if they're using `bind:this`, for example). +## `$bindable` + +To declare props as bindable, use `$bindable()`. Besides using them as regular props, the parent can (_can_, not _must_) then also `bind:` to them. + +```svelte + +``` + +You can pass an argument to `$bindable()`. This argument is used as a fallback value when the property is `undefined`. + +```svelte + +``` + +Note that the parent is not allowed to pass `undefined` to a property with a fallback if it `bind:`s to that property. + ## `$inspect` The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its diff --git a/sites/svelte-5-preview/src/routes/docs/content/01-api/05-functions.md b/sites/svelte-5-preview/src/routes/docs/content/01-api/05-functions.md index 278a71db7f..a0b1651109 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/01-api/05-functions.md +++ b/sites/svelte-5-preview/src/routes/docs/content/01-api/05-functions.md @@ -49,7 +49,7 @@ This is handy when you want to pass some state to an external library or API tha Instantiates a component and mounts it to the given target: ```js -// @errors: 2724 2305 +// @errors: 2322 import { mount } from 'svelte'; import App from './App.svelte'; @@ -64,7 +64,7 @@ const app = mount(App, { Like `mount`, but will pick up any HTML rendered by Svelte's SSR output (from the `render` function) inside the target and make it interactive: ```js -// @errors: 2724 2305 +// @errors: 2322 import { hydrate } from 'svelte'; import App from './App.svelte'; diff --git a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md index 205bdd2bf2..d88a749bc8 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md @@ -179,3 +179,7 @@ In Svelte 4, `null` and `undefined` were printed as the corresponding string. In ### `bind:files` values can only be `null`, `undefined` or `FileList` `bind:files` is now a two-way binding. As such, when setting a value, it needs to be either falsy (`null` or `undefined`) or of type `FileList`. + +### Bindings now react to form resets + +Previously, bindings did not take into account `reset` event of forms, and therefore values could get out of sync with the DOM. Svelte 5 fixes this by placing a `reset` listener on the document and invoking bindings where necessary. diff --git a/sites/svelte-5-preview/src/routes/svelte/[...path]/+server.js b/sites/svelte-5-preview/src/routes/svelte/[...path]/+server.js index 7e0c82b33d..8ac64dd223 100644 --- a/sites/svelte-5-preview/src/routes/svelte/[...path]/+server.js +++ b/sites/svelte-5-preview/src/routes/svelte/[...path]/+server.js @@ -1,10 +1,11 @@ -import compiler_cjs from '../../../../../../packages/svelte/compiler.cjs?url'; +import compiler_cjs from '../../../../../../packages/svelte/compiler/index.js?url'; import package_json from '../../../../../../packages/svelte/package.json?url'; import { read } from '$app/server'; const files = import.meta.glob('../../../../../../packages/svelte/src/**/*.js', { eager: true, - as: 'url' + query: '?url', + import: 'default' }); const prefix = '../../../../../../packages/svelte/'; @@ -13,14 +14,14 @@ export const prerender = true; export function entries() { const entries = Object.keys(files).map((path) => ({ path: path.replace(prefix, '') })); - entries.push({ path: 'compiler.cjs' }, { path: 'package.json' }); + entries.push({ path: 'compiler/index.js' }, { path: 'package.json' }); return entries; } // service worker requests files under this path to load the compiler and runtime export async function GET({ params }) { let url = ''; - if (params.path === 'compiler.cjs') { + if (params.path === 'compiler/index.js') { url = compiler_cjs; } else if (params.path === 'package.json') { url = package_json; diff --git a/sites/svelte.dev/package.json b/sites/svelte.dev/package.json index dd19042fd6..845199d942 100644 --- a/sites/svelte.dev/package.json +++ b/sites/svelte.dev/package.json @@ -54,7 +54,7 @@ "svelte-preprocess": "^5.1.3", "tiny-glob": "^0.2.9", "typescript": "^5.3.3", - "vite": "^5.0.12", + "vite": "^5.0.13", "vite-imagetools": "^6.2.9" } }