svelte
Advanced tools
Comparing version 5.0.0-next.106 to 5.0.0-next.107
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "5.0.0-next.106", | ||
"version": "5.0.0-next.107", | ||
"type": "module", | ||
@@ -8,0 +8,0 @@ "types": "./types/index.d.ts", |
@@ -111,2 +111,4 @@ /** @typedef {{ start?: number, end?: number }} NodeLike */ | ||
`:global(...) must not contain type or universal selectors when used in a compound selector`, | ||
'invalid-css-type-selector-placement': () => | ||
`:global(...) must not be followed with a type selector`, | ||
'invalid-css-selector': () => `Invalid selector`, | ||
@@ -113,0 +115,0 @@ 'invalid-css-identifier': () => 'Expected a valid CSS identifier', |
@@ -102,20 +102,3 @@ import { walk } from 'zimmerframe'; | ||
// ensure `:global(...)`contains a single selector | ||
// (standalone :global() with multiple selectors is OK) | ||
if (node.children.length > 1 || node.children[0].selectors.length > 1) { | ||
for (const relative_selector of node.children) { | ||
for (const selector of relative_selector.selectors) { | ||
if ( | ||
selector.type === 'PseudoClassSelector' && | ||
selector.name === 'global' && | ||
selector.args !== null && | ||
selector.args.children.length > 1 | ||
) { | ||
error(selector, 'invalid-css-global-selector'); | ||
} | ||
} | ||
} | ||
} | ||
// ensure `:global(...)` is not part of a larger compound selector | ||
// ensure `:global(...)` do not lead to invalid css after `:global()` is removed | ||
for (const relative_selector of node.children) { | ||
@@ -127,13 +110,20 @@ for (let i = 0; i < relative_selector.selectors.length; i++) { | ||
const child = selector.args?.children[0].children[0]; | ||
// ensure `:global(element)` to be at the first position in a compound selector | ||
if (child?.selectors[0].type === 'TypeSelector' && i !== 0) { | ||
error(selector, 'invalid-css-global-selector-list'); | ||
} | ||
// ensure `:global(.class)` is not followed by a type selector, eg: `:global(.class)element` | ||
if (relative_selector.selectors[i + 1]?.type === 'TypeSelector') { | ||
error(relative_selector.selectors[i + 1], 'invalid-css-type-selector-placement'); | ||
} | ||
// ensure `:global(...)`contains a single selector | ||
// (standalone :global() with multiple selectors is OK) | ||
if ( | ||
child?.selectors[0].type === 'TypeSelector' && | ||
!/[.:#]/.test(child.selectors[0].name[0]) && | ||
(i !== 0 || | ||
relative_selector.selectors | ||
.slice(1) | ||
.some( | ||
(s) => s.type !== 'PseudoElementSelector' && s.type !== 'PseudoClassSelector' | ||
)) | ||
selector.args !== null && | ||
selector.args.children.length > 1 && | ||
(node.children.length > 1 || relative_selector.selectors.length > 1) | ||
) { | ||
error(selector, 'invalid-css-global-selector-list'); | ||
error(selector, 'invalid-css-global-selector'); | ||
} | ||
@@ -140,0 +130,0 @@ } |
@@ -1177,2 +1177,11 @@ import { | ||
}, | ||
AssignmentPattern(node, { state, path }) { | ||
if ( | ||
node.right.type === 'Identifier' && | ||
node.right.name === '$bindable' && | ||
!state.scope.get('bindable') | ||
) { | ||
warn(state.analysis.warnings, node, path, 'invalid-bindable-declaration'); | ||
} | ||
}, | ||
// TODO this is a code smell. need to refactor this stuff | ||
@@ -1179,0 +1188,0 @@ ClassBody: validation_runes_js.ClassBody, |
@@ -233,3 +233,3 @@ import MagicString from 'magic-string'; | ||
// TODO err... can this happen? | ||
// for any :global() at the middle of compound selector | ||
for (const selector of relative_selector.selectors) { | ||
@@ -236,0 +236,0 @@ if (selector.type === 'PseudoClassSelector' && selector.name === 'global') { |
@@ -42,3 +42,5 @@ import { | ||
'invalid-props-declaration': () => | ||
`Component properties are declared using $props() in runes mode. Did you forget to call the function?` | ||
`Component properties are declared using $props() in runes mode. Did you forget to call the function?`, | ||
'invalid-bindable-declaration': () => | ||
`Bindable component properties are declared using $bindable() in runes mode. Did you forget to call the function?` | ||
}; | ||
@@ -45,0 +47,0 @@ |
import { derived } from '../../reactivity/deriveds.js'; | ||
import { render_effect } from '../../reactivity/effects.js'; | ||
import { get } from '../../runtime.js'; | ||
import { current_effect, get } from '../../runtime.js'; | ||
import { is_array } from '../../utils.js'; | ||
import { hydrate_nodes, hydrating } from '../hydration.js'; | ||
import { create_fragment_from_html, remove } from '../reconciler.js'; | ||
import { push_template_node } from '../template.js'; | ||
/** | ||
* @param {import('#client').Effect} effect | ||
* @param {(Element | Comment | Text)[]} to_remove | ||
* @returns {void} | ||
*/ | ||
function remove_from_parent_effect(effect, to_remove) { | ||
const dom = effect.dom; | ||
if (is_array(dom)) { | ||
for (let i = dom.length - 1; i >= 0; i--) { | ||
if (to_remove.includes(dom[i])) { | ||
dom.splice(i, 1); | ||
break; | ||
} | ||
} | ||
} else if (dom !== null && to_remove.includes(dom)) { | ||
effect.dom = null; | ||
} | ||
} | ||
/** | ||
* @param {Element | Text | Comment} anchor | ||
@@ -14,9 +36,15 @@ * @param {() => string} get_value | ||
export function html(anchor, get_value, svg) { | ||
const parent_effect = anchor.parentNode !== current_effect?.dom ? current_effect : null; | ||
let value = derived(get_value); | ||
render_effect(() => { | ||
var dom = html_to_dom(anchor, get(value), svg); | ||
var dom = html_to_dom(anchor, parent_effect, get(value), svg); | ||
if (dom) { | ||
return () => remove(dom); | ||
return () => { | ||
if (parent_effect !== null) { | ||
remove_from_parent_effect(parent_effect, is_array(dom) ? dom : [dom]); | ||
} | ||
remove(dom); | ||
}; | ||
} | ||
@@ -31,2 +59,3 @@ }); | ||
* @param {Element | Text | Comment} target | ||
* @param {import('#client').Effect | null} effect | ||
* @param {V} value | ||
@@ -36,3 +65,3 @@ * @param {boolean} svg | ||
*/ | ||
function html_to_dom(target, value, svg) { | ||
function html_to_dom(target, effect, value, svg) { | ||
if (hydrating) return hydrate_nodes; | ||
@@ -55,2 +84,5 @@ | ||
target.before(child); | ||
if (effect !== null) { | ||
push_template_node(effect, child); | ||
} | ||
return child; | ||
@@ -69,3 +101,7 @@ } | ||
if (effect !== null) { | ||
push_template_node(effect, nodes); | ||
} | ||
return nodes; | ||
} |
@@ -16,2 +16,3 @@ import { namespace_svg } from '../../../../constants.js'; | ||
import { current_effect } from '../../runtime.js'; | ||
import { push_template_node } from '../template.js'; | ||
@@ -135,2 +136,4 @@ /** | ||
prev_element.remove(); | ||
} else if (!hydrating) { | ||
push_template_node(parent_effect, element); | ||
} | ||
@@ -137,0 +140,0 @@ }); |
import { STATE_SYMBOL } from '../../../constants.js'; | ||
import { effect, render_effect } from '../../../reactivity/effects.js'; | ||
import { untrack } from '../../../runtime.js'; | ||
import { queue_task } from '../../task.js'; | ||
@@ -50,3 +51,4 @@ /** | ||
return () => { | ||
effect(() => { | ||
// We cannot use effects in the teardown phase, we we use a microtask instead. | ||
queue_task(() => { | ||
if (parts && is_bound_this(get_value(...parts), element_or_component)) { | ||
@@ -53,0 +55,0 @@ update(null, ...parts); |
import { run_all } from '../../shared/utils.js'; | ||
let is_task_queued = false; | ||
let is_raf_queued = false; | ||
/** @type {Array<() => void>} */ | ||
let current_queued_tasks = []; | ||
/** @type {Array<() => void>} */ | ||
let current_raf_tasks = []; | ||
@@ -18,7 +15,11 @@ function process_task() { | ||
function process_raf_task() { | ||
is_raf_queued = false; | ||
const tasks = current_raf_tasks.slice(); | ||
current_raf_tasks = []; | ||
run_all(tasks); | ||
/** | ||
* @param {() => void} fn | ||
*/ | ||
export function queue_task(fn) { | ||
if (!is_task_queued) { | ||
is_task_queued = true; | ||
queueMicrotask(process_task); | ||
} | ||
current_queued_tasks.push(fn); | ||
} | ||
@@ -33,5 +34,2 @@ | ||
} | ||
if (is_raf_queued) { | ||
process_raf_task(); | ||
} | ||
} |
@@ -7,4 +7,34 @@ import { hydrate_nodes, hydrating } from './hydration.js'; | ||
import { effect } from '../reactivity/effects.js'; | ||
import { is_array } from '../utils.js'; | ||
/** | ||
* @param {import("#client").Effect} effect | ||
* @param {import("#client").TemplateNode | import("#client").TemplateNode[]} dom | ||
*/ | ||
export function push_template_node(effect, dom) { | ||
var current_dom = effect.dom; | ||
if (current_dom === null) { | ||
effect.dom = dom; | ||
} else { | ||
if (!is_array(current_dom)) { | ||
current_dom = effect.dom = [current_dom]; | ||
} | ||
var anchor; | ||
// If we're working with an anchor, then remove it and put it at the end. | ||
if (current_dom[0].nodeType === 8) { | ||
anchor = current_dom.pop(); | ||
} | ||
if (is_array(dom)) { | ||
current_dom.push(...dom); | ||
} else { | ||
current_dom.push(dom); | ||
} | ||
if (anchor !== undefined) { | ||
current_dom.push(anchor); | ||
} | ||
} | ||
return dom; | ||
} | ||
/** | ||
* @param {string} content | ||
@@ -23,4 +53,9 @@ * @param {number} flags | ||
return () => { | ||
var effect = /** @type {import('#client').Effect} */ (current_effect); | ||
if (hydrating) { | ||
return is_fragment ? hydrate_nodes : /** @type {Node} */ (hydrate_nodes[0]); | ||
var hydration_content = push_template_node( | ||
effect, | ||
is_fragment ? hydrate_nodes : hydrate_nodes[0] | ||
); | ||
return /** @type {Node} */ (hydration_content); | ||
} | ||
@@ -32,4 +67,14 @@ | ||
} | ||
var clone = use_import_node ? document.importNode(node, true) : clone_node(node, true); | ||
return use_import_node ? document.importNode(node, true) : clone_node(node, true); | ||
if (is_fragment) { | ||
push_template_node( | ||
effect, | ||
/** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes]) | ||
); | ||
} else { | ||
push_template_node(effect, /** @type {import('#client').TemplateNode} */ (clone)); | ||
} | ||
return clone; | ||
}; | ||
@@ -76,4 +121,9 @@ } | ||
return () => { | ||
var effect = /** @type {import('#client').Effect} */ (current_effect); | ||
if (hydrating) { | ||
return is_fragment ? hydrate_nodes : /** @type {Node} */ (hydrate_nodes[0]); | ||
var hydration_content = push_template_node( | ||
effect, | ||
is_fragment ? hydrate_nodes : hydrate_nodes[0] | ||
); | ||
return /** @type {Node} */ (hydration_content); | ||
} | ||
@@ -94,3 +144,14 @@ | ||
return clone_node(node, true); | ||
var clone = clone_node(node, true); | ||
if (is_fragment) { | ||
push_template_node( | ||
effect, | ||
/** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes]) | ||
); | ||
} else { | ||
push_template_node(effect, /** @type {import('#client').TemplateNode} */ (clone)); | ||
} | ||
return clone; | ||
}; | ||
@@ -160,3 +221,4 @@ } | ||
export function text(anchor) { | ||
if (!hydrating) return empty(); | ||
var effect = /** @type {import('#client').Effect} */ (current_effect); | ||
if (!hydrating) return push_template_node(effect, empty()); | ||
@@ -171,3 +233,3 @@ var node = hydrate_nodes[0]; | ||
return node; | ||
return push_template_node(effect, node); | ||
} | ||
@@ -184,17 +246,5 @@ | ||
export function append(anchor, dom) { | ||
var current = dom; | ||
if (!hydrating) { | ||
var node = /** @type {Node} */ (dom); | ||
if (node.nodeType === 11) { | ||
// if hydrating, `dom` is already an array of nodes, but if not then | ||
// we need to create an array to store it on the current effect | ||
current = /** @type {import('#client').Dom} */ ([...node.childNodes]); | ||
} | ||
anchor.before(node); | ||
anchor.before(/** @type {Node} */ (dom)); | ||
} | ||
/** @type {import('#client').Effect} */ (current_effect).dom = current; | ||
} |
@@ -10,5 +10,7 @@ import { DEV } from 'esm-env'; | ||
get, | ||
is_destroying_effect, | ||
is_flushing_effect, | ||
remove_reactions, | ||
schedule_effect, | ||
set_is_destroying_effect, | ||
set_is_flushing_effect, | ||
@@ -113,2 +115,8 @@ set_signal_status, | ||
} | ||
if (is_destroying_effect) { | ||
throw new Error( | ||
'ERR_SVELTE_EFFECT_IN_TEARDOWN' + | ||
(DEV ? ': The Svelte $effect rune can not be used in the teardown phase of an effect.' : '') | ||
); | ||
} | ||
@@ -145,2 +153,10 @@ // Non-nested `$effect(...)` in a component should be deferred | ||
} | ||
if (is_destroying_effect) { | ||
throw new Error( | ||
'ERR_SVELTE_EFFECT_IN_TEARDOWN' + | ||
(DEV | ||
? ': The Svelte $effect.pre rune can not be used in the teardown phase of an effect.' | ||
: '') | ||
); | ||
} | ||
@@ -235,2 +251,18 @@ return render_effect(fn); | ||
/** | ||
* @param {import("#client").Effect} effect | ||
*/ | ||
export function execute_effect_teardown(effect) { | ||
var teardown = effect.teardown; | ||
if (teardown !== null) { | ||
const previously_destroying_effect = is_destroying_effect; | ||
set_is_destroying_effect(true); | ||
try { | ||
teardown.call(null); | ||
} finally { | ||
set_is_destroying_effect(previously_destroying_effect); | ||
} | ||
} | ||
} | ||
/** | ||
* @param {import('#client').Effect} effect | ||
@@ -256,3 +288,3 @@ * @returns {void} | ||
effect.teardown?.call(null); | ||
execute_effect_teardown(effect); | ||
@@ -259,0 +291,0 @@ var parent = effect.parent; |
@@ -11,4 +11,9 @@ import { DEV } from 'esm-env'; | ||
import { snapshot } from './proxy.js'; | ||
import { destroy_effect, effect, user_pre_effect } from './reactivity/effects.js'; | ||
import { | ||
destroy_effect, | ||
effect, | ||
execute_effect_teardown, | ||
user_pre_effect | ||
} from './reactivity/effects.js'; | ||
import { | ||
EFFECT, | ||
@@ -41,2 +46,3 @@ RENDER_EFFECT, | ||
export let is_flushing_effect = false; | ||
export let is_destroying_effect = false; | ||
@@ -48,2 +54,7 @@ /** @param {boolean} value */ | ||
/** @param {boolean} value */ | ||
export function set_is_destroying_effect(value) { | ||
is_destroying_effect = value; | ||
} | ||
// Used for $inspect | ||
@@ -412,3 +423,3 @@ export let is_batching_effect = false; | ||
effect.teardown?.call(null); | ||
execute_effect_teardown(effect); | ||
var teardown = execute_reaction_fn(effect); | ||
@@ -665,2 +676,3 @@ effect.teardown = typeof teardown === 'function' ? teardown : null; | ||
flush_tasks(); | ||
if (current_queued_root_effects.length > 0 || root_effects.length > 0) { | ||
@@ -670,3 +682,2 @@ flush_sync(); | ||
flush_tasks(); | ||
flush_count = 0; | ||
@@ -673,0 +684,0 @@ |
@@ -31,3 +31,2 @@ import { DEV } from 'esm-env'; | ||
sources.set(key, source(v)); | ||
super.set(key, v); | ||
} | ||
@@ -66,3 +65,4 @@ | ||
return super.forEach(callbackfn, this_arg); | ||
var bound_callbackfn = callbackfn.bind(this_arg); | ||
this.#sources.forEach((s, key) => bound_callbackfn(s.v, key, this)); | ||
} | ||
@@ -101,3 +101,3 @@ | ||
return super.set(key, value); | ||
return this; | ||
} | ||
@@ -111,9 +111,10 @@ | ||
if (s !== undefined) { | ||
sources.delete(key); | ||
var removed = sources.delete(key); | ||
set(this.#size, sources.size); | ||
set(s, /** @type {V} */ (UNINITIALIZED)); | ||
this.#increment_version(); | ||
return removed; | ||
} | ||
return super.delete(key); | ||
return false; | ||
} | ||
@@ -133,3 +134,2 @@ | ||
sources.clear(); | ||
super.clear(); | ||
} | ||
@@ -136,0 +136,0 @@ |
@@ -34,3 +34,2 @@ import { DEV } from 'esm-env'; | ||
sources.set(element, source(true)); | ||
super.add(element); | ||
} | ||
@@ -101,3 +100,3 @@ | ||
return super.add(value); | ||
return this; | ||
} | ||
@@ -111,9 +110,10 @@ | ||
if (s !== undefined) { | ||
sources.delete(value); | ||
var removed = sources.delete(value); | ||
set(this.#size, sources.size); | ||
set(s, false); | ||
this.#increment_version(); | ||
return removed; | ||
} | ||
return super.delete(value); | ||
return false; | ||
} | ||
@@ -133,3 +133,2 @@ | ||
sources.clear(); | ||
super.clear(); | ||
} | ||
@@ -136,0 +135,0 @@ |
@@ -9,3 +9,3 @@ // generated during release, do not modify | ||
*/ | ||
export const VERSION = '5.0.0-next.106'; | ||
export const VERSION = '5.0.0-next.107'; | ||
export const PUBLIC_VERSION = '5'; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
1944427
41939