diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml index 71df3242e8f1..9be1f0010494 100644 --- a/.github/workflows/ecosystem-ci-trigger.yml +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -8,9 +8,17 @@ jobs: trigger: runs-on: ubuntu-latest if: github.repository == 'sveltejs/svelte' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run') + permissions: + issues: write # to add / delete reactions + pull-requests: write # to read PR data, and to add labels + actions: read # to check workflow status + contents: read # to clone the repo steps: - - uses: GitHubSecurityLab/actions-permissions/monitor@v1 - - uses: actions/github-script@v6 + - name: monitor action permissions + uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - name: check user authorization # user needs triage permission + uses: actions/github-script@v7 + id: check-permissions with: script: | const user = context.payload.sender.login @@ -29,7 +37,7 @@ jobs: } if (hasTriagePermission) { - console.log('Allowed') + console.log('User is allowed. Adding +1 reaction.') await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, @@ -37,16 +45,18 @@ jobs: content: '+1', }) } else { - console.log('Not allowed') + console.log('User is not allowed. Adding -1 reaction.') await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, content: '-1', }) - throw new Error('not allowed') + throw new Error('User does not have the necessary permissions.') } - - uses: actions/github-script@v6 + + - name: Get PR Data + uses: actions/github-script@v7 id: get-pr-data with: script: | @@ -59,21 +69,27 @@ jobs: return { num: context.issue.number, branchName: pr.head.ref, + commit: pr.head.sha, repo: pr.head.repo.full_name } - - id: generate-token - uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 #keep pinned for security reasons, currently 1.8.0 + + - name: Generate Token + id: generate-token + uses: actions/create-github-app-token@v2 with: - app_id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }} - private_key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }} - repository: '${{ github.repository_owner }}/svelte-ecosystem-ci' - - uses: actions/github-script@v6 + app-id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }} + private-key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }} + repositories: | + svelte + svelte-ecosystem-ci + + - name: Trigger Downstream Workflow + uses: actions/github-script@v7 id: trigger env: COMMENT: ${{ github.event.comment.body }} with: github-token: ${{ steps.generate-token.outputs.token }} - result-encoding: string script: | const comment = process.env.COMMENT.trim() const prData = ${{ steps.get-pr-data.outputs.result }} @@ -89,6 +105,7 @@ jobs: prNumber: '' + prData.num, branchName: prData.branchName, repo: prData.repo, + commit: prData.commit, suite: suite === '' ? '-' : suite } }) diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 19aa1466c069..8f158c528f6d 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,13 @@ # svelte +## 5.35.6 + +### Patch Changes + +- chore: simplify reaction/source ownership tracking ([#16333](https://github.com/sveltejs/svelte/pull/16333)) + +- chore: simplify internal component `pop()` ([#16331](https://github.com/sveltejs/svelte/pull/16331)) + ## 5.35.5 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 4ac497ed4131..4eed145f3fd1 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.35.5", + "version": "5.35.6", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/internal/client/context.js b/packages/svelte/src/internal/client/context.js index 736b81c1726a..6876a89f57e6 100644 --- a/packages/svelte/src/internal/client/context.js +++ b/packages/svelte/src/internal/client/context.js @@ -139,16 +139,14 @@ export function getAllContexts() { * @returns {void} */ export function push(props, runes = false, fn) { - var ctx = (component_context = { + component_context = { p: component_context, c: null, - d: false, e: null, - m: false, s: props, x: null, l: null - }); + }; if (legacy_mode_flag && !runes) { component_context.l = { @@ -159,10 +157,6 @@ export function push(props, runes = false, fn) { }; } - teardown(() => { - /** @type {ComponentContext} */ (ctx).d = true; - }); - if (DEV) { // component function component_context.function = fn; @@ -176,37 +170,28 @@ export function push(props, runes = false, fn) { * @returns {T} */ export function pop(component) { - const context_stack_item = component_context; - if (context_stack_item !== null) { - if (component !== undefined) { - context_stack_item.x = component; - } - const component_effects = context_stack_item.e; - if (component_effects !== null) { - var previous_effect = active_effect; - var previous_reaction = active_reaction; - context_stack_item.e = null; - try { - for (var i = 0; i < component_effects.length; i++) { - var component_effect = component_effects[i]; - set_active_effect(component_effect.effect); - set_active_reaction(component_effect.reaction); - create_user_effect(component_effect.fn); - } - } finally { - set_active_effect(previous_effect); - set_active_reaction(previous_reaction); - } - } - component_context = context_stack_item.p; - if (DEV) { - dev_current_component_function = context_stack_item.p?.function ?? null; + var context = /** @type {ComponentContext} */ (component_context); + var effects = context.e; + + if (effects !== null) { + context.e = null; + + for (var fn of effects) { + create_user_effect(fn); } - context_stack_item.m = true; } - // Micro-optimization: Don't set .a above to the empty object - // so it can be garbage-collected when the return here is unused - return component || /** @type {T} */ ({}); + + if (component !== undefined) { + context.x = component; + } + + component_context = context.p; + + if (DEV) { + dev_current_component_function = component_context?.function ?? null; + } + + return component ?? /** @type {T} */ ({}); } /** @returns {boolean} */ diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index 38100e982cce..00fad9ffdb58 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -209,21 +209,14 @@ export function transition(flags, element, get_fn, get_params) { var outro; function get_options() { - var previous_reaction = active_reaction; - var previous_effect = active_effect; - set_active_reaction(null); - set_active_effect(null); - try { + return without_reactive_context(() => { // If a transition is still ongoing, we use the existing options rather than generating // new ones. This ensures that reversible transitions reverse smoothly, rather than // jumping to a new spot because (for example) a different `duration` was used return (current_options ??= get_fn()(element, get_params?.() ?? /** @type {P} */ ({}), { direction })); - } finally { - set_active_reaction(previous_reaction); - set_active_effect(previous_effect); - } + }); } /** @type {TransitionManager} */ diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index d9063aee3436..5da1b7e188fd 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -1,6 +1,13 @@ /** @import { Source } from '#client' */ import { DEV } from 'esm-env'; -import { get, active_effect, active_reaction, set_active_reaction } from './runtime.js'; +import { + get, + active_effect, + update_version, + active_reaction, + set_update_version, + set_active_reaction +} from './runtime.js'; import { array_prototype, get_descriptor, @@ -8,7 +15,7 @@ import { is_array, object_prototype } from '../shared/utils.js'; -import { state as source, set } from './reactivity/sources.js'; +import { state as source, set, increment } from './reactivity/sources.js'; import { PROXY_PATH_SYMBOL, STATE_SYMBOL } from '#client/constants'; import { UNINITIALIZED } from '../../constants.js'; import * as e from './errors.js'; @@ -41,7 +48,7 @@ export function proxy(value) { var version = source(0); var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null; - var reaction = active_reaction; + var parent_version = update_version; /** * Executes the proxy in the context of the reaction it was originally created in, if any @@ -49,13 +56,23 @@ export function proxy(value) { * @param {() => T} fn */ var with_parent = (fn) => { - var previous_reaction = active_reaction; - set_active_reaction(reaction); + if (update_version === parent_version) { + return fn(); + } + + // child source is being created after the initial proxy — + // prevent it from being associated with the current reaction + var reaction = active_reaction; + var version = update_version; + + set_active_reaction(null); + set_update_version(parent_version); - /** @type {T} */ var result = fn(); - set_active_reaction(previous_reaction); + set_active_reaction(reaction); + set_update_version(version); + return result; }; @@ -118,7 +135,7 @@ export function proxy(value) { if (prop in target) { const s = with_parent(() => source(UNINITIALIZED, stack)); sources.set(prop, s); - update_version(version); + increment(version); if (DEV) { tag(s, get_label(path, prop)); @@ -136,7 +153,7 @@ export function proxy(value) { } } set(s, UNINITIALIZED); - update_version(version); + increment(version); } return true; @@ -304,7 +321,7 @@ export function proxy(value) { } } - update_version(version); + increment(version); } return true; @@ -343,14 +360,6 @@ function get_label(path, prop) { return /^\d+$/.test(prop) ? `${path}[${prop}]` : `${path}['${prop}']`; } -/** - * @param {Source} signal - * @param {1 | -1} [d] - */ -function update_version(signal, d = 1) { - set(signal, signal.v + d); -} - /** * @param {any} value */ diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index df2afd3e386e..51c68055295a 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -179,28 +179,18 @@ export function teardown(fn) { export function user_effect(fn) { validate_effect('$effect'); - // Non-nested `$effect(...)` in a component should be deferred - // until the component is mounted - var defer = - active_effect !== null && - (active_effect.f & BRANCH_EFFECT) !== 0 && - component_context !== null && - !component_context.m; - if (DEV) { define_property(fn, 'name', { value: '$effect' }); } - if (defer) { + if (!active_reaction && active_effect && (active_effect.f & BRANCH_EFFECT) !== 0) { + // Top-level `$effect(...)` in a component — defer until mount var context = /** @type {ComponentContext} */ (component_context); - (context.e ??= []).push({ - fn, - effect: active_effect, - reaction: active_reaction - }); + (context.e ??= []).push(fn); } else { + // Everything else — create immediately return create_user_effect(fn); } } diff --git a/packages/svelte/src/internal/client/reactivity/props.js b/packages/svelte/src/internal/client/reactivity/props.js index 03daad5251f2..f39d45bb049c 100644 --- a/packages/svelte/src/internal/client/reactivity/props.js +++ b/packages/svelte/src/internal/client/reactivity/props.js @@ -268,14 +268,6 @@ export function spread_props(...props) { return new Proxy({ props }, spread_props_handler); } -/** - * @param {Derived} current_value - * @returns {boolean} - */ -function has_destroyed_component_ctx(current_value) { - return current_value.ctx?.d ?? false; -} - /** * This function is responsible for synchronizing a possibly bound prop with the inner component state. * It is used whenever the compiler sees that the component writes to the prop, or when it has a default prop_value. diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index a86ccfee4ff4..f84312e31cfd 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -11,7 +11,7 @@ import { untrack, increment_write_version, update_effect, - source_ownership, + current_sources, check_dirtiness, untracking, is_destroying_effect, @@ -140,7 +140,7 @@ export function set(source, value, should_proxy = false) { (!untracking || (active_reaction.f & INSPECT_EFFECT) !== 0) && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT | INSPECT_EFFECT)) !== 0 && - !(source_ownership?.reaction === active_reaction && source_ownership.sources.includes(source)) + !current_sources?.includes(source) ) { e.state_unsafe_mutation(); } @@ -259,6 +259,14 @@ export function update_pre(source, d = 1) { return set(source, d === 1 ? ++value : --value); } +/** + * Silently (without using `get`) increment a source + * @param {Source} source + */ +export function increment(source) { + set(source, source.v + 1); +} + /** * @param {Value} signal * @param {number} status should be DIRTY or MAYBE_DIRTY diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index cd7170d32699..6477e2942a4f 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -88,17 +88,17 @@ export function set_active_effect(effect) { /** * When sources are created within a reaction, reading and writing * them within that reaction should not cause a re-run - * @type {null | { reaction: Reaction, sources: Source[] }} + * @type {null | Source[]} */ -export let source_ownership = null; +export let current_sources = null; /** @param {Value} value */ export function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { - if (source_ownership === null) { - source_ownership = { reaction: active_reaction, sources: [value] }; + if (current_sources === null) { + current_sources = [value]; } else { - source_ownership.sources.push(value); + current_sources.push(value); } } } @@ -136,6 +136,11 @@ let read_version = 0; export let update_version = read_version; +/** @param {number} value */ +export function set_update_version(value) { + update_version = value; +} + // If we are working with a get() chain that has no active container, // to prevent memory leaks, we skip adding the reaction. export let skip_reaction = false; @@ -236,16 +241,13 @@ function schedule_possible_effect_self_invalidation(signal, effect, root = true) var reactions = signal.reactions; if (reactions === null) return; + if (current_sources?.includes(signal)) { + return; + } + for (var i = 0; i < reactions.length; i++) { var reaction = reactions[i]; - if ( - source_ownership?.reaction === active_reaction && - source_ownership.sources.includes(signal) - ) { - continue; - } - if ((reaction.f & DERIVED) !== 0) { schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false); } else if (effect === reaction) { @@ -266,7 +268,7 @@ export function update_reaction(reaction) { var previous_untracked_writes = untracked_writes; var previous_reaction = active_reaction; var previous_skip_reaction = skip_reaction; - var previous_reaction_sources = source_ownership; + var previous_sources = current_sources; var previous_component_context = component_context; var previous_untracking = untracking; var previous_update_version = update_version; @@ -280,7 +282,7 @@ export function update_reaction(reaction) { (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; - source_ownership = null; + current_sources = null; set_component_context(reaction.ctx); untracking = false; update_version = ++read_version; @@ -368,7 +370,7 @@ export function update_reaction(reaction) { untracked_writes = previous_untracked_writes; active_reaction = previous_reaction; skip_reaction = previous_skip_reaction; - source_ownership = previous_reaction_sources; + current_sources = previous_sources; set_component_context(previous_component_context); untracking = previous_untracking; update_version = previous_update_version; @@ -762,10 +764,7 @@ export function get(signal) { // Register the dependency on the current reaction signal. if (active_reaction !== null && !untracking) { - if ( - source_ownership?.reaction !== active_reaction || - !source_ownership?.sources.includes(signal) - ) { + if (!current_sources?.includes(signal)) { var deps = active_reaction.deps; if (signal.rv < read_version) { signal.rv = read_version; diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index 0b7310e1726b..a42f91343c6f 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -14,16 +14,8 @@ export type ComponentContext = { p: null | ComponentContext; /** context */ c: null | Map; - /** destroyed */ - d: boolean; /** deferred effects */ - e: null | Array<{ - fn: () => void | (() => void); - effect: null | Effect; - reaction: null | Reaction; - }>; - /** mounted */ - m: boolean; + e: null | Array<() => void | (() => void)>; /** * props — needed for legacy mode lifecycle functions, and for `createEventDispatcher` * @deprecated remove in 6.0 diff --git a/packages/svelte/src/reactivity/create-subscriber.js b/packages/svelte/src/reactivity/create-subscriber.js index 491ffb45cba7..67a92ceb7b54 100644 --- a/packages/svelte/src/reactivity/create-subscriber.js +++ b/packages/svelte/src/reactivity/create-subscriber.js @@ -1,8 +1,7 @@ import { get, tick, untrack } from '../internal/client/runtime.js'; import { effect_tracking, render_effect } from '../internal/client/reactivity/effects.js'; -import { source } from '../internal/client/reactivity/sources.js'; +import { source, increment } from '../internal/client/reactivity/sources.js'; import { tag } from '../internal/client/dev/tracing.js'; -import { increment } from './utils.js'; import { DEV } from 'esm-env'; /** diff --git a/packages/svelte/src/reactivity/map.js b/packages/svelte/src/reactivity/map.js index 4fa2dfd7b2fc..014b5e7c7ca1 100644 --- a/packages/svelte/src/reactivity/map.js +++ b/packages/svelte/src/reactivity/map.js @@ -1,9 +1,8 @@ /** @import { Source } from '#client' */ import { DEV } from 'esm-env'; -import { set, source, state } from '../internal/client/reactivity/sources.js'; +import { set, source, state, increment } from '../internal/client/reactivity/sources.js'; import { label, tag } from '../internal/client/dev/tracing.js'; import { get, update_version } from '../internal/client/runtime.js'; -import { increment } from './utils.js'; /** * A reactive version of the built-in [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object. diff --git a/packages/svelte/src/reactivity/set.js b/packages/svelte/src/reactivity/set.js index 9e3c330beb36..d7c2deeaae86 100644 --- a/packages/svelte/src/reactivity/set.js +++ b/packages/svelte/src/reactivity/set.js @@ -1,9 +1,8 @@ /** @import { Source } from '#client' */ import { DEV } from 'esm-env'; -import { source, set, state } from '../internal/client/reactivity/sources.js'; +import { source, set, state, increment } from '../internal/client/reactivity/sources.js'; import { label, tag } from '../internal/client/dev/tracing.js'; import { get, update_version } from '../internal/client/runtime.js'; -import { increment } from './utils.js'; var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf']; var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union']; diff --git a/packages/svelte/src/reactivity/url-search-params.js b/packages/svelte/src/reactivity/url-search-params.js index 389da7cdb67a..2381e118755d 100644 --- a/packages/svelte/src/reactivity/url-search-params.js +++ b/packages/svelte/src/reactivity/url-search-params.js @@ -1,9 +1,8 @@ import { DEV } from 'esm-env'; -import { state } from '../internal/client/reactivity/sources.js'; +import { state, increment } from '../internal/client/reactivity/sources.js'; import { tag } from '../internal/client/dev/tracing.js'; import { get } from '../internal/client/runtime.js'; import { get_current_url } from './url.js'; -import { increment } from './utils.js'; export const REPLACE = Symbol(); diff --git a/packages/svelte/src/reactivity/utils.js b/packages/svelte/src/reactivity/utils.js deleted file mode 100644 index cd55e0e0baac..000000000000 --- a/packages/svelte/src/reactivity/utils.js +++ /dev/null @@ -1,7 +0,0 @@ -/** @import { Source } from '#client' */ -import { set } from '../internal/client/reactivity/sources.js'; - -/** @param {Source} source */ -export function increment(source) { - set(source, source.v + 1); -} diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index eb68753d7129..266b0b94910d 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.35.5'; +export const VERSION = '5.35.6'; export const PUBLIC_VERSION = '5'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy