@tinymce/tinymce-svelte 4.0.1 → 4.0.2-feature.20260514214723764.sha51bac15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +752 -257
- package/dist/index.umd.js +752 -257
- package/dist/index.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -97,6 +97,8 @@ const INERT = 1 << 13;
|
|
|
97
97
|
const DESTROYED = 1 << 14;
|
|
98
98
|
/** Set once a reaction has run for the first time */
|
|
99
99
|
const REACTION_RAN = 1 << 15;
|
|
100
|
+
/** Effect is in the process of getting destroyed. Can be observed in child teardown functions */
|
|
101
|
+
const DESTROYING = 1 << 25;
|
|
100
102
|
|
|
101
103
|
// Flags exclusive to effects
|
|
102
104
|
/**
|
|
@@ -113,7 +115,8 @@ const USER_EFFECT = 1 << 20;
|
|
|
113
115
|
/**
|
|
114
116
|
* Tells that we marked this derived and its reactions as visited during the "mark as (maybe) dirty"-phase.
|
|
115
117
|
* Will be lifted during execution of the derived and during checking its dirty state (both are necessary
|
|
116
|
-
* because a derived might be checked but not executed).
|
|
118
|
+
* because a derived might be checked but not executed). This is a pure performance optimization flag and
|
|
119
|
+
* should not be used for any other purpose!
|
|
117
120
|
*/
|
|
118
121
|
const WAS_MARKED = 1 << 16;
|
|
119
122
|
|
|
@@ -127,6 +130,10 @@ const STATE_SYMBOL = Symbol('$state');
|
|
|
127
130
|
const LEGACY_PROPS = Symbol('legacy props');
|
|
128
131
|
const LOADING_ATTR_SYMBOL = Symbol('');
|
|
129
132
|
const PROXY_PATH_SYMBOL = Symbol('proxy path');
|
|
133
|
+
const ATTRIBUTES_CACHE = Symbol('attributes');
|
|
134
|
+
const CLASS_CACHE = Symbol('class');
|
|
135
|
+
/** An anchor might change, via this symbol on the original anchor we can tell HMR about the updated anchor */
|
|
136
|
+
const HMR_ANCHOR = Symbol('hmr anchor');
|
|
130
137
|
|
|
131
138
|
/** allow users to ignore aborted signal errors if `reason.name === 'StaleReactionError` */
|
|
132
139
|
const STALE_REACTION = new (class StaleReactionError extends Error {
|
|
@@ -136,6 +143,25 @@ const STALE_REACTION = new (class StaleReactionError extends Error {
|
|
|
136
143
|
|
|
137
144
|
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
|
|
138
145
|
|
|
146
|
+
/**
|
|
147
|
+
* An invariant violation occurred, meaning Svelte's internal assumptions were flawed. This is a bug in Svelte, not your app — please open an issue at https://github.com/sveltejs/svelte, citing the following message: "%message%"
|
|
148
|
+
* @param {string} message
|
|
149
|
+
* @returns {never}
|
|
150
|
+
*/
|
|
151
|
+
function invariant_violation(message) {
|
|
152
|
+
if (DEV) {
|
|
153
|
+
const error = new Error(`invariant_violation\nAn invariant violation occurred, meaning Svelte's internal assumptions were flawed. This is a bug in Svelte, not your app — please open an issue at https://github.com/sveltejs/svelte, citing the following message: "${message}"\nhttps://svelte.dev/e/invariant_violation`);
|
|
154
|
+
|
|
155
|
+
error.name = 'Svelte error';
|
|
156
|
+
|
|
157
|
+
throw error;
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error(`https://svelte.dev/e/invariant_violation`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
|
|
164
|
+
|
|
139
165
|
/**
|
|
140
166
|
* Cannot create a `$derived(...)` with an `await` expression outside of an effect tree
|
|
141
167
|
* @returns {never}
|
|
@@ -338,6 +364,18 @@ function state_unsafe_mutation() {
|
|
|
338
364
|
var bold$1 = 'font-weight: bold';
|
|
339
365
|
var normal$1 = 'font-weight: normal';
|
|
340
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await`
|
|
369
|
+
* @param {string} name
|
|
370
|
+
*/
|
|
371
|
+
function await_reactivity_loss(name) {
|
|
372
|
+
if (DEV) {
|
|
373
|
+
console.warn(`%c[svelte] await_reactivity_loss\n%cDetected reactivity loss when reading \`${name}\`. This happens when state is read in an async function after an earlier \`await\`\nhttps://svelte.dev/e/await_reactivity_loss`, bold$1, normal$1);
|
|
374
|
+
} else {
|
|
375
|
+
console.warn(`https://svelte.dev/e/await_reactivity_loss`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
341
379
|
/**
|
|
342
380
|
* An async derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app
|
|
343
381
|
* @param {string} name
|
|
@@ -351,6 +389,17 @@ function await_waterfall(name, location) {
|
|
|
351
389
|
}
|
|
352
390
|
}
|
|
353
391
|
|
|
392
|
+
/**
|
|
393
|
+
* Reading a derived belonging to a now-destroyed effect may result in stale values
|
|
394
|
+
*/
|
|
395
|
+
function derived_inert() {
|
|
396
|
+
if (DEV) {
|
|
397
|
+
console.warn(`%c[svelte] derived_inert\n%cReading a derived belonging to a now-destroyed effect may result in stale values\nhttps://svelte.dev/e/derived_inert`, bold$1, normal$1);
|
|
398
|
+
} else {
|
|
399
|
+
console.warn(`https://svelte.dev/e/derived_inert`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
354
403
|
/** @import { Equals } from '#client' */
|
|
355
404
|
|
|
356
405
|
/** @type {Equals} */
|
|
@@ -630,6 +679,18 @@ function get_stack() {
|
|
|
630
679
|
return new_lines;
|
|
631
680
|
}
|
|
632
681
|
|
|
682
|
+
/**
|
|
683
|
+
* @param {boolean} condition
|
|
684
|
+
* @param {string} message
|
|
685
|
+
*/
|
|
686
|
+
function invariant(condition, message) {
|
|
687
|
+
if (!DEV) {
|
|
688
|
+
throw new Error('invariant(...) was not guarded by if (DEV)');
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (!condition) invariant_violation(message);
|
|
692
|
+
}
|
|
693
|
+
|
|
633
694
|
/** @import { ComponentContext, DevStackEntry, Effect } from '#client' */
|
|
634
695
|
|
|
635
696
|
/** @type {ComponentContext | null} */
|
|
@@ -679,6 +740,7 @@ function push(props, runes = false, fn) {
|
|
|
679
740
|
e: null,
|
|
680
741
|
s: props,
|
|
681
742
|
x: null,
|
|
743
|
+
r: /** @type {Effect} */ (active_effect),
|
|
682
744
|
l: null
|
|
683
745
|
};
|
|
684
746
|
|
|
@@ -969,12 +1031,21 @@ function capture_store_binding(fn) {
|
|
|
969
1031
|
|
|
970
1032
|
/** @import { Fork } from 'svelte' */
|
|
971
1033
|
|
|
972
|
-
/** @type {
|
|
973
|
-
|
|
1034
|
+
/** @type {Batch | null} */
|
|
1035
|
+
let first_batch = null;
|
|
1036
|
+
|
|
1037
|
+
/** @type {Batch | null} */
|
|
1038
|
+
let last_batch = null;
|
|
974
1039
|
|
|
975
1040
|
/** @type {Batch | null} */
|
|
976
1041
|
let current_batch = null;
|
|
977
1042
|
|
|
1043
|
+
/**
|
|
1044
|
+
* This is needed to avoid overwriting inputs
|
|
1045
|
+
* @type {Batch | null}
|
|
1046
|
+
*/
|
|
1047
|
+
let previous_batch = null;
|
|
1048
|
+
|
|
978
1049
|
/**
|
|
979
1050
|
* When time travelling (i.e. working in one batch, while other batches
|
|
980
1051
|
* still have ongoing work), we ignore the real values of affected
|
|
@@ -1007,28 +1078,51 @@ let collected_effects = null;
|
|
|
1007
1078
|
let legacy_updates = null;
|
|
1008
1079
|
|
|
1009
1080
|
var flush_count = 0;
|
|
1010
|
-
|
|
1081
|
+
|
|
1082
|
+
/** @type {Set<Value>} */
|
|
1083
|
+
var source_stacks = new Set();
|
|
1011
1084
|
|
|
1012
1085
|
let uid = 1;
|
|
1013
1086
|
|
|
1014
1087
|
class Batch {
|
|
1015
|
-
// for debugging. TODO remove once async is stable
|
|
1016
1088
|
id = uid++;
|
|
1017
1089
|
|
|
1090
|
+
/** True as soon as `#process` was called */
|
|
1091
|
+
#started = false;
|
|
1092
|
+
|
|
1093
|
+
linked = true;
|
|
1094
|
+
|
|
1095
|
+
/** @type {Batch | null} */
|
|
1096
|
+
#prev = null;
|
|
1097
|
+
|
|
1098
|
+
/** @type {Batch | null} */
|
|
1099
|
+
#next = null;
|
|
1100
|
+
|
|
1101
|
+
/** @type {Map<Effect, ReturnType<typeof deferred<any>>>} */
|
|
1102
|
+
async_deriveds = new Map();
|
|
1103
|
+
|
|
1018
1104
|
/**
|
|
1019
|
-
* The current values of any
|
|
1105
|
+
* The current values of any signals that are updated in this batch.
|
|
1106
|
+
* Tuple format: [value, is_derived] (note: is_derived is false for deriveds, too, if they were overridden via assignment)
|
|
1020
1107
|
* They keys of this map are identical to `this.#previous`
|
|
1021
|
-
* @type {Map<
|
|
1108
|
+
* @type {Map<Value, [any, boolean]>}
|
|
1022
1109
|
*/
|
|
1023
1110
|
current = new Map();
|
|
1024
1111
|
|
|
1025
1112
|
/**
|
|
1026
|
-
* The values of any sources that are updated in this batch _before_ those updates took place.
|
|
1113
|
+
* The values of any signals (sources and deriveds) that are updated in this batch _before_ those updates took place.
|
|
1027
1114
|
* They keys of this map are identical to `this.#current`
|
|
1028
|
-
* @type {Map<
|
|
1115
|
+
* @type {Map<Value, any>}
|
|
1029
1116
|
*/
|
|
1030
1117
|
previous = new Map();
|
|
1031
1118
|
|
|
1119
|
+
/**
|
|
1120
|
+
* Async effects which this batch doesn't take into account anymore when calculating blockers,
|
|
1121
|
+
* as it has a value for it already.
|
|
1122
|
+
* @type {Set<Effect>}
|
|
1123
|
+
*/
|
|
1124
|
+
unblocked = new Set();
|
|
1125
|
+
|
|
1032
1126
|
/**
|
|
1033
1127
|
* When the batch is committed (and the DOM is updated), we need to remove old branches
|
|
1034
1128
|
* and append new ones by calling the functions added inside (if/each/key/etc) blocks
|
|
@@ -1042,15 +1136,22 @@ class Batch {
|
|
|
1042
1136
|
*/
|
|
1043
1137
|
#discard_callbacks = new Set();
|
|
1044
1138
|
|
|
1139
|
+
/**
|
|
1140
|
+
* Callbacks that should run only when a fork is committed.
|
|
1141
|
+
* @type {Set<(batch: Batch) => void>}
|
|
1142
|
+
*/
|
|
1143
|
+
#fork_commit_callbacks = new Set();
|
|
1144
|
+
|
|
1045
1145
|
/**
|
|
1046
1146
|
* The number of async effects that are currently in flight
|
|
1047
1147
|
*/
|
|
1048
1148
|
#pending = 0;
|
|
1049
1149
|
|
|
1050
1150
|
/**
|
|
1051
|
-
*
|
|
1151
|
+
* Async effects that are currently in flight, _not_ inside a pending boundary
|
|
1152
|
+
* @type {Map<Effect, number>}
|
|
1052
1153
|
*/
|
|
1053
|
-
#blocking_pending =
|
|
1154
|
+
#blocking_pending = new Map();
|
|
1054
1155
|
|
|
1055
1156
|
/**
|
|
1056
1157
|
* A deferred that resolves when the batch is committed, used with `settled()`
|
|
@@ -1065,6 +1166,12 @@ class Batch {
|
|
|
1065
1166
|
*/
|
|
1066
1167
|
#roots = [];
|
|
1067
1168
|
|
|
1169
|
+
/**
|
|
1170
|
+
* Effects created while this batch was active.
|
|
1171
|
+
* @type {Effect[]}
|
|
1172
|
+
*/
|
|
1173
|
+
#new_effects = [];
|
|
1174
|
+
|
|
1068
1175
|
/**
|
|
1069
1176
|
* Deferred effects (which run after async work has completed) that are DIRTY
|
|
1070
1177
|
* @type {Set<Effect>}
|
|
@@ -1086,12 +1193,38 @@ class Batch {
|
|
|
1086
1193
|
*/
|
|
1087
1194
|
#skipped_branches = new Map();
|
|
1088
1195
|
|
|
1196
|
+
/**
|
|
1197
|
+
* Inverse of #skipped_branches which we need to tell prior batches to unskip them when committing
|
|
1198
|
+
* @type {Set<Effect>}
|
|
1199
|
+
*/
|
|
1200
|
+
#unskipped_branches = new Set();
|
|
1201
|
+
|
|
1089
1202
|
is_fork = false;
|
|
1090
1203
|
|
|
1091
1204
|
#decrement_queued = false;
|
|
1092
1205
|
|
|
1093
1206
|
#is_deferred() {
|
|
1094
|
-
|
|
1207
|
+
if (this.is_fork) return true;
|
|
1208
|
+
|
|
1209
|
+
for (const effect of this.#blocking_pending.keys()) {
|
|
1210
|
+
var e = effect;
|
|
1211
|
+
var skipped = false;
|
|
1212
|
+
|
|
1213
|
+
while (e.parent !== null) {
|
|
1214
|
+
if (this.#skipped_branches.has(e)) {
|
|
1215
|
+
skipped = true;
|
|
1216
|
+
break;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
e = e.parent;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (!skipped) {
|
|
1223
|
+
return true;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
return false;
|
|
1095
1228
|
}
|
|
1096
1229
|
|
|
1097
1230
|
/**
|
|
@@ -1102,35 +1235,64 @@ class Batch {
|
|
|
1102
1235
|
if (!this.#skipped_branches.has(effect)) {
|
|
1103
1236
|
this.#skipped_branches.set(effect, { d: [], m: [] });
|
|
1104
1237
|
}
|
|
1238
|
+
this.#unskipped_branches.delete(effect);
|
|
1105
1239
|
}
|
|
1106
1240
|
|
|
1107
1241
|
/**
|
|
1108
1242
|
* Remove an effect from the #skipped_branches map and reschedule
|
|
1109
1243
|
* any tracked dirty/maybe_dirty child effects
|
|
1110
1244
|
* @param {Effect} effect
|
|
1245
|
+
* @param {(e: Effect) => void} callback
|
|
1111
1246
|
*/
|
|
1112
|
-
unskip_effect(effect) {
|
|
1247
|
+
unskip_effect(effect, callback = (e) => this.schedule(e)) {
|
|
1113
1248
|
var tracked = this.#skipped_branches.get(effect);
|
|
1114
1249
|
if (tracked) {
|
|
1115
1250
|
this.#skipped_branches.delete(effect);
|
|
1116
1251
|
|
|
1117
1252
|
for (var e of tracked.d) {
|
|
1118
1253
|
set_signal_status(e, DIRTY);
|
|
1119
|
-
|
|
1254
|
+
callback(e);
|
|
1120
1255
|
}
|
|
1121
1256
|
|
|
1122
1257
|
for (e of tracked.m) {
|
|
1123
1258
|
set_signal_status(e, MAYBE_DIRTY);
|
|
1124
|
-
|
|
1259
|
+
callback(e);
|
|
1125
1260
|
}
|
|
1126
1261
|
}
|
|
1262
|
+
this.#unskipped_branches.add(effect);
|
|
1127
1263
|
}
|
|
1128
1264
|
|
|
1129
1265
|
#process() {
|
|
1266
|
+
this.#started = true;
|
|
1267
|
+
|
|
1130
1268
|
if (flush_count++ > 1000) {
|
|
1269
|
+
this.#unlink();
|
|
1131
1270
|
infinite_loop_guard();
|
|
1132
1271
|
}
|
|
1133
1272
|
|
|
1273
|
+
if (DEV) {
|
|
1274
|
+
// track all the values that were updated during this flush,
|
|
1275
|
+
// so that they can be reset afterwards
|
|
1276
|
+
for (const value of this.current.keys()) {
|
|
1277
|
+
source_stacks.add(value);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// we only reschedule previously-deferred effects if we expect
|
|
1282
|
+
// to be able to run them after processing the batch
|
|
1283
|
+
if (!this.#is_deferred()) {
|
|
1284
|
+
for (const e of this.#dirty_effects) {
|
|
1285
|
+
this.#maybe_dirty_effects.delete(e);
|
|
1286
|
+
set_signal_status(e, DIRTY);
|
|
1287
|
+
this.schedule(e);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
for (const e of this.#maybe_dirty_effects) {
|
|
1291
|
+
set_signal_status(e, MAYBE_DIRTY);
|
|
1292
|
+
this.schedule(e);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1134
1296
|
const roots = this.#roots;
|
|
1135
1297
|
this.#roots = [];
|
|
1136
1298
|
|
|
@@ -1149,7 +1311,12 @@ class Batch {
|
|
|
1149
1311
|
var updates = (legacy_updates = []);
|
|
1150
1312
|
|
|
1151
1313
|
for (const root of roots) {
|
|
1152
|
-
|
|
1314
|
+
try {
|
|
1315
|
+
this.#traverse(root, effects, render_effects);
|
|
1316
|
+
} catch (e) {
|
|
1317
|
+
reset_all(root);
|
|
1318
|
+
throw e;
|
|
1319
|
+
}
|
|
1153
1320
|
}
|
|
1154
1321
|
|
|
1155
1322
|
// any writes should take effect in a subsequent batch
|
|
@@ -1165,6 +1332,7 @@ class Batch {
|
|
|
1165
1332
|
collected_effects = null;
|
|
1166
1333
|
legacy_updates = null;
|
|
1167
1334
|
|
|
1335
|
+
// if the batch has outstanding pending work, stash effects and bail
|
|
1168
1336
|
if (this.#is_deferred()) {
|
|
1169
1337
|
this.#defer_effects(render_effects);
|
|
1170
1338
|
this.#defer_effects(effects);
|
|
@@ -1172,35 +1340,56 @@ class Batch {
|
|
|
1172
1340
|
for (const [e, t] of this.#skipped_branches) {
|
|
1173
1341
|
reset_branch(e, t);
|
|
1174
1342
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
this.#maybe_dirty_effects.clear();
|
|
1179
|
-
|
|
1180
|
-
// append/remove branches
|
|
1181
|
-
for (const fn of this.#commit_callbacks) fn(this);
|
|
1182
|
-
this.#commit_callbacks.clear();
|
|
1183
|
-
flush_queued_effects(render_effects);
|
|
1184
|
-
flush_queued_effects(effects);
|
|
1185
|
-
|
|
1186
|
-
if (this.#pending === 0) {
|
|
1187
|
-
this.#commit();
|
|
1343
|
+
|
|
1344
|
+
if (updates.length > 0) {
|
|
1345
|
+
/** @type {Batch} */ (/** @type {unknown} */ (current_batch)).#process();
|
|
1188
1346
|
}
|
|
1189
1347
|
|
|
1190
|
-
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const earlier_batch = this.#find_earlier_batch();
|
|
1352
|
+
|
|
1353
|
+
if (earlier_batch) {
|
|
1354
|
+
earlier_batch.#merge(this);
|
|
1355
|
+
return;
|
|
1191
1356
|
}
|
|
1192
1357
|
|
|
1358
|
+
// clear effects. Those that are still needed will be rescheduled through unskipping the skipped branches.
|
|
1359
|
+
this.#dirty_effects.clear();
|
|
1360
|
+
this.#maybe_dirty_effects.clear();
|
|
1361
|
+
|
|
1362
|
+
// append/remove branches
|
|
1363
|
+
for (const fn of this.#commit_callbacks) fn(this);
|
|
1364
|
+
this.#commit_callbacks.clear();
|
|
1365
|
+
|
|
1366
|
+
previous_batch = this;
|
|
1367
|
+
flush_queued_effects(render_effects);
|
|
1368
|
+
flush_queued_effects(effects);
|
|
1369
|
+
previous_batch = null;
|
|
1370
|
+
|
|
1371
|
+
this.#deferred?.resolve();
|
|
1372
|
+
|
|
1193
1373
|
var next_batch = /** @type {Batch | null} */ (/** @type {unknown} */ (current_batch));
|
|
1194
1374
|
|
|
1195
|
-
if (
|
|
1196
|
-
|
|
1375
|
+
if (this.linked && this.#pending === 0) {
|
|
1376
|
+
this.#unlink();
|
|
1377
|
+
}
|
|
1197
1378
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1379
|
+
// Edge case: During traversal new branches might create effects that run immediately and set state,
|
|
1380
|
+
// causing an effect and therefore a root to be scheduled again. We need to traverse the current batch
|
|
1381
|
+
// once more in that case - most of the time this will just clean up dirty branches.
|
|
1382
|
+
if (this.#roots.length > 0) {
|
|
1383
|
+
if (next_batch === null) {
|
|
1384
|
+
next_batch = this;
|
|
1385
|
+
this.#link();
|
|
1202
1386
|
}
|
|
1203
1387
|
|
|
1388
|
+
const batch = next_batch;
|
|
1389
|
+
batch.#roots.push(...this.#roots.filter((r) => !batch.#roots.includes(r)));
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (next_batch !== null) {
|
|
1204
1393
|
next_batch.#process();
|
|
1205
1394
|
}
|
|
1206
1395
|
}
|
|
@@ -1255,6 +1444,82 @@ class Batch {
|
|
|
1255
1444
|
}
|
|
1256
1445
|
}
|
|
1257
1446
|
|
|
1447
|
+
#find_earlier_batch() {
|
|
1448
|
+
var batch = this.#prev;
|
|
1449
|
+
|
|
1450
|
+
while (batch !== null) {
|
|
1451
|
+
if (!batch.is_fork) {
|
|
1452
|
+
// if the batches are connected, break
|
|
1453
|
+
for (const [value, [, is_derived]] of this.current) {
|
|
1454
|
+
if (batch.current.has(value) && !is_derived) {
|
|
1455
|
+
return batch;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
batch = batch.#prev;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/**
|
|
1467
|
+
* @param {Batch} batch
|
|
1468
|
+
*/
|
|
1469
|
+
#merge(batch) {
|
|
1470
|
+
for (const [source, value] of batch.current) {
|
|
1471
|
+
if (!this.previous.has(source) && batch.previous.has(source)) {
|
|
1472
|
+
this.previous.set(source, batch.previous.get(source));
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
this.current.set(source, value);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
for (const [effect, deferred] of batch.async_deriveds) {
|
|
1479
|
+
const d = this.async_deriveds.get(effect);
|
|
1480
|
+
if (d) deferred.promise.then(d.resolve);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/**
|
|
1484
|
+
* mark all effects that depend on `batch.current`, except the
|
|
1485
|
+
* async effects that we just resolved (TODO unless they depend
|
|
1486
|
+
* on values in this batch that are NOT in the later batch?).
|
|
1487
|
+
* Through this we also will populate the correct #skipped_branches,
|
|
1488
|
+
* oncommit callbacks etc, so we don't need to merge them separately.
|
|
1489
|
+
* @param {Value} value
|
|
1490
|
+
*/
|
|
1491
|
+
const mark = (value) => {
|
|
1492
|
+
var reactions = value.reactions;
|
|
1493
|
+
if (reactions === null) return;
|
|
1494
|
+
|
|
1495
|
+
for (const reaction of reactions) {
|
|
1496
|
+
var flags = reaction.f;
|
|
1497
|
+
|
|
1498
|
+
if ((flags & DERIVED) !== 0) {
|
|
1499
|
+
mark(/** @type {Derived} */ (reaction));
|
|
1500
|
+
} else {
|
|
1501
|
+
var effect = /** @type {Effect} */ (reaction);
|
|
1502
|
+
|
|
1503
|
+
if (flags & (ASYNC | BLOCK_EFFECT) && !this.async_deriveds.has(effect)) {
|
|
1504
|
+
this.#maybe_dirty_effects.delete(effect);
|
|
1505
|
+
set_signal_status(effect, DIRTY);
|
|
1506
|
+
this.schedule(effect);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
|
|
1512
|
+
for (const source of this.current.keys()) {
|
|
1513
|
+
mark(source);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
this.oncommit(() => batch.discard());
|
|
1517
|
+
batch.#unlink();
|
|
1518
|
+
|
|
1519
|
+
current_batch = this;
|
|
1520
|
+
this.#process();
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1258
1523
|
/**
|
|
1259
1524
|
* @param {Effect[]} effects
|
|
1260
1525
|
*/
|
|
@@ -1267,18 +1532,23 @@ class Batch {
|
|
|
1267
1532
|
/**
|
|
1268
1533
|
* Associate a change to a given source with the current
|
|
1269
1534
|
* batch, noting its previous and current values
|
|
1270
|
-
* @param {
|
|
1535
|
+
* @param {Value} source
|
|
1271
1536
|
* @param {any} value
|
|
1537
|
+
* @param {boolean} [is_derived]
|
|
1272
1538
|
*/
|
|
1273
|
-
capture(source, value) {
|
|
1274
|
-
if (
|
|
1275
|
-
this.previous.set(source,
|
|
1539
|
+
capture(source, value, is_derived = false) {
|
|
1540
|
+
if (source.v !== UNINITIALIZED && !this.previous.has(source)) {
|
|
1541
|
+
this.previous.set(source, source.v);
|
|
1276
1542
|
}
|
|
1277
1543
|
|
|
1278
1544
|
// Don't save errors in `batch_values`, or they won't be thrown in `runtime.js#get`
|
|
1279
1545
|
if ((source.f & ERROR_VALUE) === 0) {
|
|
1280
|
-
this.current.set(source,
|
|
1281
|
-
batch_values?.set(source,
|
|
1546
|
+
this.current.set(source, [value, is_derived]);
|
|
1547
|
+
batch_values?.set(source, value);
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
if (!this.is_fork) {
|
|
1551
|
+
source.v = value;
|
|
1282
1552
|
}
|
|
1283
1553
|
}
|
|
1284
1554
|
|
|
@@ -1292,27 +1562,14 @@ class Batch {
|
|
|
1292
1562
|
}
|
|
1293
1563
|
|
|
1294
1564
|
flush() {
|
|
1295
|
-
var source_stacks = DEV ? new Set() : null;
|
|
1296
|
-
|
|
1297
1565
|
try {
|
|
1566
|
+
if (DEV) {
|
|
1567
|
+
source_stacks.clear();
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1298
1570
|
is_processing = true;
|
|
1299
1571
|
current_batch = this;
|
|
1300
1572
|
|
|
1301
|
-
// we only reschedule previously-deferred effects if we expect
|
|
1302
|
-
// to be able to run them after processing the batch
|
|
1303
|
-
if (!this.#is_deferred()) {
|
|
1304
|
-
for (const e of this.#dirty_effects) {
|
|
1305
|
-
this.#maybe_dirty_effects.delete(e);
|
|
1306
|
-
set_signal_status(e, DIRTY);
|
|
1307
|
-
this.schedule(e);
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
for (const e of this.#maybe_dirty_effects) {
|
|
1311
|
-
set_signal_status(e, MAYBE_DIRTY);
|
|
1312
|
-
this.schedule(e);
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
1573
|
this.#process();
|
|
1317
1574
|
} finally {
|
|
1318
1575
|
flush_count = 0;
|
|
@@ -1327,7 +1584,7 @@ class Batch {
|
|
|
1327
1584
|
old_values.clear();
|
|
1328
1585
|
|
|
1329
1586
|
if (DEV) {
|
|
1330
|
-
for (const source of
|
|
1587
|
+
for (const source of source_stacks) {
|
|
1331
1588
|
source.updated = null;
|
|
1332
1589
|
}
|
|
1333
1590
|
}
|
|
@@ -1337,109 +1594,195 @@ class Batch {
|
|
|
1337
1594
|
discard() {
|
|
1338
1595
|
for (const fn of this.#discard_callbacks) fn(this);
|
|
1339
1596
|
this.#discard_callbacks.clear();
|
|
1597
|
+
this.#fork_commit_callbacks.clear();
|
|
1598
|
+
|
|
1599
|
+
this.#unlink();
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* @param {Effect} effect
|
|
1604
|
+
*/
|
|
1605
|
+
register_created_effect(effect) {
|
|
1606
|
+
this.#new_effects.push(effect);
|
|
1340
1607
|
}
|
|
1341
1608
|
|
|
1342
1609
|
#commit() {
|
|
1610
|
+
this.#unlink();
|
|
1611
|
+
|
|
1343
1612
|
// If there are other pending batches, they now need to be 'rebased' —
|
|
1344
1613
|
// in other words, we re-run block/async effects with the newly
|
|
1345
1614
|
// committed state, unless the batch in question has a more
|
|
1346
1615
|
// recent value for a given source
|
|
1347
|
-
|
|
1348
|
-
this.
|
|
1616
|
+
for (let batch = first_batch; batch !== null; batch = batch.#next) {
|
|
1617
|
+
var is_earlier = batch.id < this.id;
|
|
1349
1618
|
|
|
1350
|
-
|
|
1351
|
-
var
|
|
1352
|
-
var is_earlier = true;
|
|
1619
|
+
/** @type {Source[]} */
|
|
1620
|
+
var sources = [];
|
|
1353
1621
|
|
|
1354
|
-
for (const
|
|
1355
|
-
if (batch
|
|
1356
|
-
|
|
1357
|
-
continue;
|
|
1358
|
-
}
|
|
1622
|
+
for (const [source, [value, is_derived]] of this.current) {
|
|
1623
|
+
if (batch.current.has(source)) {
|
|
1624
|
+
var batch_value = /** @type {[any, boolean]} */ (batch.current.get(source))[0]; // faster than destructuring
|
|
1359
1625
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
batch.current.set(source, value);
|
|
1368
|
-
} else {
|
|
1369
|
-
// same value or later batch has more recent value,
|
|
1370
|
-
// no need to re-run these effects
|
|
1371
|
-
continue;
|
|
1372
|
-
}
|
|
1626
|
+
if (is_earlier && value !== batch_value) {
|
|
1627
|
+
// bring the value up to date
|
|
1628
|
+
batch.current.set(source, [value, is_derived]);
|
|
1629
|
+
} else {
|
|
1630
|
+
// same value or later batch has more recent value,
|
|
1631
|
+
// no need to re-run these effects
|
|
1632
|
+
continue;
|
|
1373
1633
|
}
|
|
1634
|
+
}
|
|
1374
1635
|
|
|
1375
|
-
|
|
1636
|
+
sources.push(source);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
if (is_earlier) {
|
|
1640
|
+
// TODO do we need to restart these in some cases, instead of
|
|
1641
|
+
// immediately resolving them? Likely not because of how this.apply() works.
|
|
1642
|
+
for (const [effect, deferred] of this.async_deriveds) {
|
|
1643
|
+
const d = batch.async_deriveds.get(effect);
|
|
1644
|
+
if (d) deferred.promise.then(d.resolve);
|
|
1376
1645
|
}
|
|
1646
|
+
}
|
|
1377
1647
|
|
|
1378
|
-
|
|
1379
|
-
|
|
1648
|
+
if (!batch.#started) continue;
|
|
1649
|
+
|
|
1650
|
+
// Re-run async/block effects that depend on distinct values changed in both batches
|
|
1651
|
+
var others = [...batch.current.keys()].filter((s) => !this.current.has(s));
|
|
1652
|
+
|
|
1653
|
+
if (others.length === 0) {
|
|
1654
|
+
if (is_earlier) {
|
|
1655
|
+
// this batch is now obsolete and can be discarded
|
|
1656
|
+
batch.discard();
|
|
1657
|
+
}
|
|
1658
|
+
} else if (sources.length > 0) {
|
|
1659
|
+
if (DEV) {
|
|
1660
|
+
invariant(batch.#roots.length === 0, 'Batch has scheduled roots');
|
|
1380
1661
|
}
|
|
1381
1662
|
|
|
1382
|
-
//
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
mark_effects(source, others, marked, checked);
|
|
1663
|
+
// A batch was unskipped in a later batch -> tell prior batches to unskip it, too
|
|
1664
|
+
if (is_earlier) {
|
|
1665
|
+
for (const unskipped of this.#unskipped_branches) {
|
|
1666
|
+
batch.unskip_effect(unskipped, (e) => {
|
|
1667
|
+
if ((e.f & (BLOCK_EFFECT | ASYNC)) !== 0) {
|
|
1668
|
+
batch.schedule(e);
|
|
1669
|
+
} else {
|
|
1670
|
+
batch.#defer_effects([e]);
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1393
1673
|
}
|
|
1674
|
+
}
|
|
1394
1675
|
|
|
1395
|
-
|
|
1396
|
-
batch.apply();
|
|
1676
|
+
batch.activate();
|
|
1397
1677
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1678
|
+
/** @type {Set<Value>} */
|
|
1679
|
+
var marked = new Set();
|
|
1680
|
+
|
|
1681
|
+
/** @type {Map<Reaction, boolean>} */
|
|
1682
|
+
var checked = new Map();
|
|
1683
|
+
|
|
1684
|
+
for (var source of sources) {
|
|
1685
|
+
mark_effects(source, others, marked, checked);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
checked = new Map();
|
|
1689
|
+
var current_unequal = [...batch.current.keys()].filter((c) =>
|
|
1690
|
+
this.current.has(c)
|
|
1691
|
+
? /** @type {[any, boolean]} */ (this.current.get(c))[0] !== c.v
|
|
1692
|
+
: true
|
|
1693
|
+
);
|
|
1694
|
+
|
|
1695
|
+
if (current_unequal.length > 0) {
|
|
1696
|
+
for (const effect of this.#new_effects) {
|
|
1697
|
+
if (
|
|
1698
|
+
(effect.f & (DESTROYED | INERT | EAGER_EFFECT)) === 0 &&
|
|
1699
|
+
depends_on(effect, current_unequal, checked)
|
|
1700
|
+
) {
|
|
1701
|
+
if ((effect.f & (ASYNC | BLOCK_EFFECT)) !== 0) {
|
|
1702
|
+
set_signal_status(effect, DIRTY);
|
|
1703
|
+
batch.schedule(effect);
|
|
1704
|
+
} else {
|
|
1705
|
+
batch.#dirty_effects.add(effect);
|
|
1706
|
+
}
|
|
1400
1707
|
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1401
1710
|
|
|
1402
|
-
|
|
1711
|
+
// Only apply and traverse when we know we triggered async work with marking the effects
|
|
1712
|
+
if (batch.#roots.length > 0) {
|
|
1713
|
+
batch.apply();
|
|
1714
|
+
|
|
1715
|
+
for (var root of batch.#roots) {
|
|
1716
|
+
batch.#traverse(root, [], []);
|
|
1403
1717
|
}
|
|
1404
1718
|
|
|
1405
|
-
batch
|
|
1719
|
+
batch.#roots = [];
|
|
1406
1720
|
}
|
|
1407
|
-
}
|
|
1408
1721
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1722
|
+
batch.deactivate();
|
|
1723
|
+
}
|
|
1411
1724
|
}
|
|
1412
|
-
|
|
1413
|
-
this.#skipped_branches.clear();
|
|
1414
|
-
batches.delete(this);
|
|
1415
1725
|
}
|
|
1416
1726
|
|
|
1417
1727
|
/**
|
|
1418
|
-
*
|
|
1419
1728
|
* @param {boolean} blocking
|
|
1729
|
+
* @param {Effect} effect
|
|
1420
1730
|
*/
|
|
1421
|
-
increment(blocking) {
|
|
1731
|
+
increment(blocking, effect) {
|
|
1422
1732
|
this.#pending += 1;
|
|
1423
|
-
|
|
1733
|
+
|
|
1734
|
+
if (blocking) {
|
|
1735
|
+
let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0;
|
|
1736
|
+
this.#blocking_pending.set(effect, blocking_pending_count + 1);
|
|
1737
|
+
}
|
|
1424
1738
|
}
|
|
1425
1739
|
|
|
1426
1740
|
/**
|
|
1427
1741
|
* @param {boolean} blocking
|
|
1428
|
-
* @param {
|
|
1742
|
+
* @param {Effect} effect
|
|
1429
1743
|
*/
|
|
1430
|
-
decrement(blocking,
|
|
1744
|
+
decrement(blocking, effect) {
|
|
1431
1745
|
this.#pending -= 1;
|
|
1432
|
-
if (blocking) this.#blocking_pending -= 1;
|
|
1433
1746
|
|
|
1434
|
-
if (
|
|
1747
|
+
if (blocking) {
|
|
1748
|
+
let blocking_pending_count = this.#blocking_pending.get(effect) ?? 0;
|
|
1749
|
+
|
|
1750
|
+
if (blocking_pending_count === 1) {
|
|
1751
|
+
this.#blocking_pending.delete(effect);
|
|
1752
|
+
} else {
|
|
1753
|
+
this.#blocking_pending.set(effect, blocking_pending_count - 1);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
if (this.#decrement_queued) return;
|
|
1435
1758
|
this.#decrement_queued = true;
|
|
1436
1759
|
|
|
1437
1760
|
queue_micro_task(() => {
|
|
1438
1761
|
this.#decrement_queued = false;
|
|
1439
|
-
|
|
1762
|
+
|
|
1763
|
+
if (this.linked) {
|
|
1764
|
+
this.flush();
|
|
1765
|
+
}
|
|
1440
1766
|
});
|
|
1441
1767
|
}
|
|
1442
1768
|
|
|
1769
|
+
/**
|
|
1770
|
+
* @param {Set<Effect>} dirty_effects
|
|
1771
|
+
* @param {Set<Effect>} maybe_dirty_effects
|
|
1772
|
+
*/
|
|
1773
|
+
transfer_effects(dirty_effects, maybe_dirty_effects) {
|
|
1774
|
+
for (const e of dirty_effects) {
|
|
1775
|
+
this.#dirty_effects.add(e);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
for (const e of maybe_dirty_effects) {
|
|
1779
|
+
this.#maybe_dirty_effects.add(e);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
dirty_effects.clear();
|
|
1783
|
+
maybe_dirty_effects.clear();
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1443
1786
|
/** @param {(batch: Batch) => void} fn */
|
|
1444
1787
|
oncommit(fn) {
|
|
1445
1788
|
this.#commit_callbacks.add(fn);
|
|
@@ -1450,6 +1793,16 @@ class Batch {
|
|
|
1450
1793
|
this.#discard_callbacks.add(fn);
|
|
1451
1794
|
}
|
|
1452
1795
|
|
|
1796
|
+
/** @param {(batch: Batch) => void} fn */
|
|
1797
|
+
on_fork_commit(fn) {
|
|
1798
|
+
this.#fork_commit_callbacks.add(fn);
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
run_fork_commit_callbacks() {
|
|
1802
|
+
for (const fn of this.#fork_commit_callbacks) fn(this);
|
|
1803
|
+
this.#fork_commit_callbacks.clear();
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1453
1806
|
settled() {
|
|
1454
1807
|
return (this.#deferred ??= deferred()).promise;
|
|
1455
1808
|
}
|
|
@@ -1457,20 +1810,14 @@ class Batch {
|
|
|
1457
1810
|
static ensure() {
|
|
1458
1811
|
if (current_batch === null) {
|
|
1459
1812
|
const batch = (current_batch = new Batch());
|
|
1813
|
+
batch.#link();
|
|
1460
1814
|
|
|
1461
|
-
if (!is_processing) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
{
|
|
1465
|
-
queue_micro_task(() => {
|
|
1466
|
-
if (current_batch !== batch) {
|
|
1467
|
-
// a flushSync happened in the meantime
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1815
|
+
if (!is_processing && !is_flushing_sync) {
|
|
1816
|
+
queue_micro_task(() => {
|
|
1817
|
+
if (!batch.#started) {
|
|
1471
1818
|
batch.flush();
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1474
1821
|
}
|
|
1475
1822
|
}
|
|
1476
1823
|
|
|
@@ -1478,7 +1825,10 @@ class Batch {
|
|
|
1478
1825
|
}
|
|
1479
1826
|
|
|
1480
1827
|
apply() {
|
|
1481
|
-
|
|
1828
|
+
{
|
|
1829
|
+
batch_values = null;
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1482
1832
|
}
|
|
1483
1833
|
|
|
1484
1834
|
/**
|
|
@@ -1536,6 +1886,36 @@ class Batch {
|
|
|
1536
1886
|
|
|
1537
1887
|
this.#roots.push(e);
|
|
1538
1888
|
}
|
|
1889
|
+
|
|
1890
|
+
#link() {
|
|
1891
|
+
if (last_batch === null) {
|
|
1892
|
+
first_batch = last_batch = this;
|
|
1893
|
+
} else {
|
|
1894
|
+
last_batch.#next = this;
|
|
1895
|
+
this.#prev = last_batch;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
last_batch = this;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
#unlink() {
|
|
1902
|
+
var prev = this.#prev;
|
|
1903
|
+
var next = this.#next;
|
|
1904
|
+
|
|
1905
|
+
if (prev === null) {
|
|
1906
|
+
first_batch = next;
|
|
1907
|
+
} else {
|
|
1908
|
+
prev.#next = next;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
if (next === null) {
|
|
1912
|
+
last_batch = prev;
|
|
1913
|
+
} else {
|
|
1914
|
+
next.#prev = prev;
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
this.linked = false;
|
|
1918
|
+
}
|
|
1539
1919
|
}
|
|
1540
1920
|
|
|
1541
1921
|
function infinite_loop_guard() {
|
|
@@ -1745,6 +2125,20 @@ function reset_branch(effect, tracked) {
|
|
|
1745
2125
|
}
|
|
1746
2126
|
}
|
|
1747
2127
|
|
|
2128
|
+
/**
|
|
2129
|
+
* Mark an entire effect tree clean following an error
|
|
2130
|
+
* @param {Effect} effect
|
|
2131
|
+
*/
|
|
2132
|
+
function reset_all(effect) {
|
|
2133
|
+
set_signal_status(effect, CLEAN);
|
|
2134
|
+
|
|
2135
|
+
var e = effect.first;
|
|
2136
|
+
while (e !== null) {
|
|
2137
|
+
reset_all(e);
|
|
2138
|
+
e = e.next;
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
|
|
1748
2142
|
/** @import { Blocker, Effect, Value } from '#client' */
|
|
1749
2143
|
|
|
1750
2144
|
/**
|
|
@@ -1776,33 +2170,38 @@ function flatten(blockers, sync, async, fn) {
|
|
|
1776
2170
|
|
|
1777
2171
|
/** @param {Value[]} values */
|
|
1778
2172
|
function finish(values) {
|
|
2173
|
+
if ((parent.f & DESTROYED) !== 0) {
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
|
|
1779
2177
|
restore();
|
|
1780
2178
|
|
|
1781
2179
|
try {
|
|
1782
2180
|
fn(values);
|
|
1783
2181
|
} catch (error) {
|
|
1784
|
-
|
|
1785
|
-
invoke_error_boundary(error, parent);
|
|
1786
|
-
}
|
|
2182
|
+
invoke_error_boundary(error, parent);
|
|
1787
2183
|
}
|
|
1788
2184
|
|
|
1789
2185
|
unset_context();
|
|
1790
2186
|
}
|
|
1791
2187
|
|
|
2188
|
+
var decrement_pending = increment_pending();
|
|
2189
|
+
|
|
1792
2190
|
// Fast path: blockers but no async expressions
|
|
1793
2191
|
if (async.length === 0) {
|
|
1794
|
-
/** @type {Promise<any>} */ (blocker_promise)
|
|
2192
|
+
/** @type {Promise<any>} */ (blocker_promise)
|
|
2193
|
+
.then(() => finish(sync.map(d)))
|
|
2194
|
+
.finally(decrement_pending);
|
|
2195
|
+
|
|
1795
2196
|
return;
|
|
1796
2197
|
}
|
|
1797
2198
|
|
|
1798
|
-
var decrement_pending = increment_pending();
|
|
1799
|
-
|
|
1800
2199
|
// Full path: has async expressions
|
|
1801
2200
|
function run() {
|
|
1802
2201
|
Promise.all(async.map((expression) => async_derived(expression)))
|
|
1803
2202
|
.then((result) => finish([...sync.map(d), ...result]))
|
|
1804
2203
|
.catch((error) => invoke_error_boundary(error, parent))
|
|
1805
|
-
.finally(
|
|
2204
|
+
.finally(decrement_pending);
|
|
1806
2205
|
}
|
|
1807
2206
|
|
|
1808
2207
|
if (blocker_promise) {
|
|
@@ -1844,6 +2243,7 @@ function capture() {
|
|
|
1844
2243
|
}
|
|
1845
2244
|
|
|
1846
2245
|
if (DEV) {
|
|
2246
|
+
set_reactivity_loss_tracker(null);
|
|
1847
2247
|
set_dev_stack(previous_dev_stack);
|
|
1848
2248
|
}
|
|
1849
2249
|
};
|
|
@@ -1856,6 +2256,7 @@ function unset_context(deactivate_batch = true) {
|
|
|
1856
2256
|
if (deactivate_batch) current_batch?.deactivate();
|
|
1857
2257
|
|
|
1858
2258
|
if (DEV) {
|
|
2259
|
+
set_reactivity_loss_tracker(null);
|
|
1859
2260
|
set_dev_stack(null);
|
|
1860
2261
|
}
|
|
1861
2262
|
}
|
|
@@ -1864,20 +2265,33 @@ function unset_context(deactivate_batch = true) {
|
|
|
1864
2265
|
* @returns {(skip?: boolean) => void}
|
|
1865
2266
|
*/
|
|
1866
2267
|
function increment_pending() {
|
|
1867
|
-
var
|
|
2268
|
+
var effect = /** @type {Effect} */ (active_effect);
|
|
2269
|
+
var boundary = /** @type {Boundary} */ (effect.b);
|
|
1868
2270
|
var batch = /** @type {Batch} */ (current_batch);
|
|
1869
2271
|
var blocking = boundary.is_rendered();
|
|
1870
2272
|
|
|
1871
2273
|
boundary.update_pending_count(1, batch);
|
|
1872
|
-
batch.increment(blocking);
|
|
2274
|
+
batch.increment(blocking, effect);
|
|
1873
2275
|
|
|
1874
|
-
return (
|
|
2276
|
+
return () => {
|
|
1875
2277
|
boundary.update_pending_count(-1, batch);
|
|
1876
|
-
batch.decrement(blocking,
|
|
2278
|
+
batch.decrement(blocking, effect);
|
|
1877
2279
|
};
|
|
1878
2280
|
}
|
|
1879
2281
|
|
|
1880
|
-
/** @import { Derived, Effect, Source } from '#client' */
|
|
2282
|
+
/** @import { Derived, Effect, Reaction, Source, Value } from '#client' */
|
|
2283
|
+
|
|
2284
|
+
/**
|
|
2285
|
+
* This allows us to track 'reactivity loss' that occurs when signals
|
|
2286
|
+
* are read after a non-context-restoring `await`. Dev-only
|
|
2287
|
+
* @type {{ effect: Effect, effect_deps: Set<Value>, warned: boolean } | null}
|
|
2288
|
+
*/
|
|
2289
|
+
let reactivity_loss_tracker = null;
|
|
2290
|
+
|
|
2291
|
+
/** @param {{ effect: Effect, effect_deps: Set<Value>, warned: boolean } | null} v */
|
|
2292
|
+
function set_reactivity_loss_tracker(v) {
|
|
2293
|
+
reactivity_loss_tracker = v;
|
|
2294
|
+
}
|
|
1881
2295
|
|
|
1882
2296
|
const recent_async_deriveds = new Set();
|
|
1883
2297
|
|
|
@@ -1889,10 +2303,6 @@ const recent_async_deriveds = new Set();
|
|
|
1889
2303
|
/*#__NO_SIDE_EFFECTS__*/
|
|
1890
2304
|
function derived(fn) {
|
|
1891
2305
|
var flags = DERIVED | DIRTY;
|
|
1892
|
-
var parent_derived =
|
|
1893
|
-
active_reaction !== null && (active_reaction.f & DERIVED) !== 0
|
|
1894
|
-
? /** @type {Derived} */ (active_reaction)
|
|
1895
|
-
: null;
|
|
1896
2306
|
|
|
1897
2307
|
if (active_effect !== null) {
|
|
1898
2308
|
// Since deriveds are evaluated lazily, any effects created inside them are
|
|
@@ -1912,7 +2322,7 @@ function derived(fn) {
|
|
|
1912
2322
|
rv: 0,
|
|
1913
2323
|
v: /** @type {V} */ (UNINITIALIZED),
|
|
1914
2324
|
wv: 0,
|
|
1915
|
-
parent:
|
|
2325
|
+
parent: active_effect,
|
|
1916
2326
|
ac: null
|
|
1917
2327
|
};
|
|
1918
2328
|
|
|
@@ -1923,6 +2333,8 @@ function derived(fn) {
|
|
|
1923
2333
|
return signal;
|
|
1924
2334
|
}
|
|
1925
2335
|
|
|
2336
|
+
const OBSOLETE = Symbol('obsolete');
|
|
2337
|
+
|
|
1926
2338
|
/**
|
|
1927
2339
|
* @template V
|
|
1928
2340
|
* @param {() => V | Promise<V>} fn
|
|
@@ -1941,18 +2353,21 @@ function async_derived(fn, label, location) {
|
|
|
1941
2353
|
var promise = /** @type {Promise<V>} */ (/** @type {unknown} */ (undefined));
|
|
1942
2354
|
var signal = source(/** @type {V} */ (UNINITIALIZED));
|
|
1943
2355
|
|
|
1944
|
-
if (DEV) signal.label = label;
|
|
2356
|
+
if (DEV) signal.label = label ?? fn.toString();
|
|
1945
2357
|
|
|
1946
2358
|
// only suspend in async deriveds created on initialisation
|
|
1947
2359
|
var should_suspend = !active_reaction;
|
|
1948
2360
|
|
|
1949
|
-
/** @type {
|
|
1950
|
-
var deferreds = new
|
|
2361
|
+
/** @type {Set<ReturnType<typeof deferred<V>>>} */
|
|
2362
|
+
var deferreds = new Set();
|
|
1951
2363
|
|
|
1952
2364
|
async_effect(() => {
|
|
1953
|
-
|
|
1954
2365
|
var effect = /** @type {Effect} */ (active_effect);
|
|
1955
2366
|
|
|
2367
|
+
if (DEV) {
|
|
2368
|
+
reactivity_loss_tracker = { effect, effect_deps: new Set(), warned: false };
|
|
2369
|
+
}
|
|
2370
|
+
|
|
1956
2371
|
/** @type {ReturnType<typeof deferred<V>>} */
|
|
1957
2372
|
var d = deferred();
|
|
1958
2373
|
promise = d.promise;
|
|
@@ -1961,12 +2376,40 @@ function async_derived(fn, label, location) {
|
|
|
1961
2376
|
// If this code is changed at some point, make sure to still access the then property
|
|
1962
2377
|
// of fn() to read any signals it might access, so that we track them as dependencies.
|
|
1963
2378
|
// We call `unset_context` to undo any `save` calls that happen inside `fn()`
|
|
1964
|
-
Promise.resolve(fn())
|
|
2379
|
+
Promise.resolve(fn())
|
|
2380
|
+
.then(d.resolve, (e) => {
|
|
2381
|
+
// if the promise was rejected by the user, via `getAbortSignal`, then
|
|
2382
|
+
// wait for a subsequent resolution instead of flushing the batch
|
|
2383
|
+
if (e !== STALE_REACTION) d.reject(e);
|
|
2384
|
+
})
|
|
2385
|
+
.finally(unset_context);
|
|
1965
2386
|
} catch (error) {
|
|
1966
2387
|
d.reject(error);
|
|
1967
2388
|
unset_context();
|
|
1968
2389
|
}
|
|
1969
2390
|
|
|
2391
|
+
if (DEV) {
|
|
2392
|
+
if (reactivity_loss_tracker) {
|
|
2393
|
+
// Reused deps from previous run (indices 0 to skipped_deps-1)
|
|
2394
|
+
// We deliberately only track direct dependencies of the async expression to encourage
|
|
2395
|
+
// dependencies being directly visible at the point of the expression
|
|
2396
|
+
if (effect.deps !== null) {
|
|
2397
|
+
for (let i = 0; i < skipped_deps; i += 1) {
|
|
2398
|
+
reactivity_loss_tracker.effect_deps.add(effect.deps[i]);
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
// New deps discovered this run
|
|
2403
|
+
if (new_deps !== null) {
|
|
2404
|
+
for (let i = 0; i < new_deps.length; i += 1) {
|
|
2405
|
+
reactivity_loss_tracker.effect_deps.add(new_deps[i]);
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
reactivity_loss_tracker = null;
|
|
2411
|
+
}
|
|
2412
|
+
|
|
1970
2413
|
var batch = /** @type {Batch} */ (current_batch);
|
|
1971
2414
|
|
|
1972
2415
|
if (should_suspend) {
|
|
@@ -1978,18 +2421,17 @@ function async_derived(fn, label, location) {
|
|
|
1978
2421
|
}
|
|
1979
2422
|
|
|
1980
2423
|
if (/** @type {Boundary} */ (parent.b).is_rendered()) {
|
|
1981
|
-
|
|
1982
|
-
deferreds.delete(batch); // delete to ensure correct order in Map iteration below
|
|
2424
|
+
batch.async_deriveds.get(effect)?.reject(OBSOLETE);
|
|
1983
2425
|
} else {
|
|
1984
2426
|
// While the boundary is still showing pending, a new run supersedes all older in-flight runs
|
|
1985
2427
|
// for this async expression. Cancel eagerly so resolution cannot commit stale values.
|
|
1986
2428
|
for (const d of deferreds.values()) {
|
|
1987
|
-
d.reject(
|
|
2429
|
+
d.reject(OBSOLETE);
|
|
1988
2430
|
}
|
|
1989
|
-
deferreds.clear();
|
|
1990
2431
|
}
|
|
1991
2432
|
|
|
1992
|
-
deferreds.
|
|
2433
|
+
deferreds.add(d);
|
|
2434
|
+
batch.async_deriveds.set(effect, d);
|
|
1993
2435
|
}
|
|
1994
2436
|
|
|
1995
2437
|
/**
|
|
@@ -1997,17 +2439,14 @@ function async_derived(fn, label, location) {
|
|
|
1997
2439
|
* @param {unknown} error
|
|
1998
2440
|
*/
|
|
1999
2441
|
const handler = (value, error = undefined) => {
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
// don't trigger an update if we're only here because
|
|
2003
|
-
// the promise was superseded before it could resolve
|
|
2004
|
-
var skip = error === STALE_REACTION;
|
|
2005
|
-
decrement_pending(skip);
|
|
2442
|
+
if (DEV) {
|
|
2443
|
+
reactivity_loss_tracker = null;
|
|
2006
2444
|
}
|
|
2007
2445
|
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2446
|
+
decrement_pending?.();
|
|
2447
|
+
deferreds.delete(d);
|
|
2448
|
+
|
|
2449
|
+
if (error === OBSOLETE) return;
|
|
2011
2450
|
|
|
2012
2451
|
batch.activate();
|
|
2013
2452
|
|
|
@@ -2023,18 +2462,11 @@ function async_derived(fn, label, location) {
|
|
|
2023
2462
|
|
|
2024
2463
|
internal_set(signal, value);
|
|
2025
2464
|
|
|
2026
|
-
// All prior async derived runs are now stale
|
|
2027
|
-
for (const [b, d] of deferreds) {
|
|
2028
|
-
deferreds.delete(b);
|
|
2029
|
-
if (b === batch) break;
|
|
2030
|
-
d.reject(STALE_REACTION);
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
2465
|
if (DEV && location !== undefined) {
|
|
2034
2466
|
recent_async_deriveds.add(signal);
|
|
2035
2467
|
|
|
2036
2468
|
setTimeout(() => {
|
|
2037
|
-
if (recent_async_deriveds.has(signal)) {
|
|
2469
|
+
if (recent_async_deriveds.has(signal) && (effect.f & DESTROYED) === 0) {
|
|
2038
2470
|
await_waterfall(/** @type {string} */ (signal.label), location);
|
|
2039
2471
|
recent_async_deriveds.delete(signal);
|
|
2040
2472
|
}
|
|
@@ -2049,8 +2481,8 @@ function async_derived(fn, label, location) {
|
|
|
2049
2481
|
});
|
|
2050
2482
|
|
|
2051
2483
|
teardown(() => {
|
|
2052
|
-
for (const d of deferreds
|
|
2053
|
-
d.reject(
|
|
2484
|
+
for (const d of deferreds) {
|
|
2485
|
+
d.reject(OBSOLETE);
|
|
2054
2486
|
}
|
|
2055
2487
|
});
|
|
2056
2488
|
|
|
@@ -2115,23 +2547,6 @@ function destroy_derived_effects(derived) {
|
|
|
2115
2547
|
*/
|
|
2116
2548
|
let stack = [];
|
|
2117
2549
|
|
|
2118
|
-
/**
|
|
2119
|
-
* @param {Derived} derived
|
|
2120
|
-
* @returns {Effect | null}
|
|
2121
|
-
*/
|
|
2122
|
-
function get_derived_parent_effect(derived) {
|
|
2123
|
-
var parent = derived.parent;
|
|
2124
|
-
while (parent !== null) {
|
|
2125
|
-
if ((parent.f & DERIVED) === 0) {
|
|
2126
|
-
// The original parent effect might've been destroyed but the derived
|
|
2127
|
-
// is used elsewhere now - do not return the destroyed effect in that case
|
|
2128
|
-
return (parent.f & DESTROYED) === 0 ? /** @type {Effect} */ (parent) : null;
|
|
2129
|
-
}
|
|
2130
|
-
parent = parent.parent;
|
|
2131
|
-
}
|
|
2132
|
-
return null;
|
|
2133
|
-
}
|
|
2134
|
-
|
|
2135
2550
|
/**
|
|
2136
2551
|
* @template T
|
|
2137
2552
|
* @param {Derived} derived
|
|
@@ -2140,8 +2555,15 @@ function get_derived_parent_effect(derived) {
|
|
|
2140
2555
|
function execute_derived(derived) {
|
|
2141
2556
|
var value;
|
|
2142
2557
|
var prev_active_effect = active_effect;
|
|
2558
|
+
var parent = derived.parent;
|
|
2559
|
+
|
|
2560
|
+
if (!is_destroying_effect && parent !== null && (parent.f & (DESTROYED | INERT)) !== 0) {
|
|
2561
|
+
derived_inert();
|
|
2143
2562
|
|
|
2144
|
-
|
|
2563
|
+
return derived.v;
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
set_active_effect(parent);
|
|
2145
2567
|
|
|
2146
2568
|
if (DEV) {
|
|
2147
2569
|
let prev_eager_effects = eager_effects;
|
|
@@ -2189,7 +2611,18 @@ function update_derived(derived) {
|
|
|
2189
2611
|
// otherwise, the next time we get here after a 'real world' state
|
|
2190
2612
|
// change, `derived.equals` may incorrectly return `true`
|
|
2191
2613
|
if (!current_batch?.is_fork || derived.deps === null) {
|
|
2192
|
-
|
|
2614
|
+
if (current_batch !== null) {
|
|
2615
|
+
// We also write to previous_batch because if it exists, it is a sign that we're
|
|
2616
|
+
// currently in the process of flushing effects. These updates to deriveds may belong
|
|
2617
|
+
// to the previous batch, not the new one (which can already exist if an earlier
|
|
2618
|
+
// effect wrote to a source). This can cause bugs when running batch.#commit() later,
|
|
2619
|
+
// but not adding it to current_batch can, too, so we add it to both.
|
|
2620
|
+
// See https://github.com/sveltejs/svelte/pull/18117 for more details.
|
|
2621
|
+
current_batch.capture(derived, value, true);
|
|
2622
|
+
previous_batch?.capture(derived, value, true);
|
|
2623
|
+
} else {
|
|
2624
|
+
derived.v = value;
|
|
2625
|
+
}
|
|
2193
2626
|
|
|
2194
2627
|
// deriveds without dependencies should never be recomputed
|
|
2195
2628
|
if (derived.deps === null) {
|
|
@@ -2260,7 +2693,7 @@ function unfreeze_derived_effects(derived) {
|
|
|
2260
2693
|
|
|
2261
2694
|
/** @import { Derived, Effect, Source, Value } from '#client' */
|
|
2262
2695
|
|
|
2263
|
-
/** @type {Set<
|
|
2696
|
+
/** @type {Set<Effect>} */
|
|
2264
2697
|
let eager_effects = new Set();
|
|
2265
2698
|
|
|
2266
2699
|
/** @type {Map<Source, any>} */
|
|
@@ -2359,18 +2792,10 @@ function set(source, value, should_proxy = false) {
|
|
|
2359
2792
|
*/
|
|
2360
2793
|
function internal_set(source, value, updated_during_traversal = null) {
|
|
2361
2794
|
if (!source.equals(value)) {
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
if (is_destroying_effect) {
|
|
2365
|
-
old_values.set(source, value);
|
|
2366
|
-
} else {
|
|
2367
|
-
old_values.set(source, old_value);
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2370
|
-
source.v = value;
|
|
2795
|
+
old_values.set(source, is_destroying_effect ? value : source.v);
|
|
2371
2796
|
|
|
2372
2797
|
var batch = Batch.ensure();
|
|
2373
|
-
batch.capture(source,
|
|
2798
|
+
batch.capture(source, value);
|
|
2374
2799
|
|
|
2375
2800
|
if (DEV) {
|
|
2376
2801
|
if (active_effect !== null) {
|
|
@@ -2410,7 +2835,11 @@ function internal_set(source, value, updated_during_traversal = null) {
|
|
|
2410
2835
|
execute_derived(derived);
|
|
2411
2836
|
}
|
|
2412
2837
|
|
|
2413
|
-
|
|
2838
|
+
// During time traveling we don't want to reset the status so that
|
|
2839
|
+
// traversal of the graph in the other batches still happens
|
|
2840
|
+
if (batch_values === null) {
|
|
2841
|
+
update_derived_status(derived);
|
|
2842
|
+
}
|
|
2414
2843
|
}
|
|
2415
2844
|
|
|
2416
2845
|
source.wv = increment_write_version();
|
|
@@ -2453,7 +2882,18 @@ function flush_eager_effects() {
|
|
|
2453
2882
|
set_signal_status(effect, MAYBE_DIRTY);
|
|
2454
2883
|
}
|
|
2455
2884
|
|
|
2456
|
-
|
|
2885
|
+
let dirty;
|
|
2886
|
+
|
|
2887
|
+
try {
|
|
2888
|
+
dirty = is_dirty(effect);
|
|
2889
|
+
} catch {
|
|
2890
|
+
// Dirty-checking can evaluate derived dependencies and throw in cases where
|
|
2891
|
+
// parent effects are about to destroy this eager effect. Run the effect so
|
|
2892
|
+
// its own error handling can deal with transient failures.
|
|
2893
|
+
dirty = true;
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
if (dirty) {
|
|
2457
2897
|
update_effect(effect);
|
|
2458
2898
|
}
|
|
2459
2899
|
}
|
|
@@ -2484,12 +2924,6 @@ function mark_reactions(signal, status, updated_during_traversal) {
|
|
|
2484
2924
|
var reaction = reactions[i];
|
|
2485
2925
|
var flags = reaction.f;
|
|
2486
2926
|
|
|
2487
|
-
// Inspect effects need to run immediately, so that the stack trace makes sense
|
|
2488
|
-
if (DEV && (flags & EAGER_EFFECT) !== 0) {
|
|
2489
|
-
eager_effects.add(reaction);
|
|
2490
|
-
continue;
|
|
2491
|
-
}
|
|
2492
|
-
|
|
2493
2927
|
var not_dirty = (flags & DIRTY) === 0;
|
|
2494
2928
|
|
|
2495
2929
|
// don't set a DIRTY reaction to MAYBE_DIRTY
|
|
@@ -2497,14 +2931,22 @@ function mark_reactions(signal, status, updated_during_traversal) {
|
|
|
2497
2931
|
set_signal_status(reaction, status);
|
|
2498
2932
|
}
|
|
2499
2933
|
|
|
2500
|
-
if ((flags &
|
|
2934
|
+
if ((flags & EAGER_EFFECT) !== 0) {
|
|
2935
|
+
// Eager effects need to run immediately:
|
|
2936
|
+
// - for $inspect so that the stack trace makes sense
|
|
2937
|
+
// - for $state.eager because they might be without an effect parent
|
|
2938
|
+
eager_effects.add(/** @type {Effect} */ (reaction));
|
|
2939
|
+
} else if ((flags & DERIVED) !== 0) {
|
|
2501
2940
|
var derived = /** @type {Derived} */ (reaction);
|
|
2502
2941
|
|
|
2503
2942
|
batch_values?.delete(derived);
|
|
2504
2943
|
|
|
2505
2944
|
if ((flags & WAS_MARKED) === 0) {
|
|
2506
|
-
// Only connected deriveds can be reliably unmarked right away
|
|
2507
|
-
if (
|
|
2945
|
+
// Only connected deriveds being executed outside the update cycle can be reliably unmarked right away
|
|
2946
|
+
if (
|
|
2947
|
+
flags & CONNECTED &&
|
|
2948
|
+
(active_effect === null || (active_effect.f & REACTION_IS_UPDATING) === 0)
|
|
2949
|
+
) {
|
|
2508
2950
|
reaction.f |= WAS_MARKED;
|
|
2509
2951
|
}
|
|
2510
2952
|
|
|
@@ -3066,6 +3508,8 @@ function create_effect(type, fn) {
|
|
|
3066
3508
|
effect.component_function = dev_current_component_function;
|
|
3067
3509
|
}
|
|
3068
3510
|
|
|
3511
|
+
current_batch?.register_created_effect(effect);
|
|
3512
|
+
|
|
3069
3513
|
/** @type {Effect | null} */
|
|
3070
3514
|
var e = effect;
|
|
3071
3515
|
|
|
@@ -3314,9 +3758,9 @@ function destroy_effect(effect, remove_dom = true) {
|
|
|
3314
3758
|
removed = true;
|
|
3315
3759
|
}
|
|
3316
3760
|
|
|
3761
|
+
set_signal_status(effect, DESTROYING);
|
|
3317
3762
|
destroy_effect_children(effect, remove_dom && !removed);
|
|
3318
3763
|
remove_reactions(effect, 0);
|
|
3319
|
-
set_signal_status(effect, DESTROYED);
|
|
3320
3764
|
|
|
3321
3765
|
var transitions = effect.nodes && effect.nodes.t;
|
|
3322
3766
|
|
|
@@ -3328,6 +3772,9 @@ function destroy_effect(effect, remove_dom = true) {
|
|
|
3328
3772
|
|
|
3329
3773
|
execute_effect_teardown(effect);
|
|
3330
3774
|
|
|
3775
|
+
effect.f ^= DESTROYING;
|
|
3776
|
+
effect.f |= DESTROYED;
|
|
3777
|
+
|
|
3331
3778
|
var parent = effect.parent;
|
|
3332
3779
|
|
|
3333
3780
|
// If the parent doesn't have any children, then skip this work altogether
|
|
@@ -3349,6 +3796,7 @@ function destroy_effect(effect, remove_dom = true) {
|
|
|
3349
3796
|
effect.fn =
|
|
3350
3797
|
effect.nodes =
|
|
3351
3798
|
effect.ac =
|
|
3799
|
+
effect.b =
|
|
3352
3800
|
null;
|
|
3353
3801
|
}
|
|
3354
3802
|
|
|
@@ -3441,16 +3889,22 @@ function pause_children(effect, transitions, local) {
|
|
|
3441
3889
|
|
|
3442
3890
|
while (child !== null) {
|
|
3443
3891
|
var sibling = child.next;
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3892
|
+
|
|
3893
|
+
// If this child is a root effect, then it will become an independent root when its parent
|
|
3894
|
+
// is destroyed, it should therefore not become inert nor partake in transitions.
|
|
3895
|
+
if ((child.f & ROOT_EFFECT) === 0) {
|
|
3896
|
+
var transparent =
|
|
3897
|
+
(child.f & EFFECT_TRANSPARENT) !== 0 ||
|
|
3898
|
+
// If this is a branch effect without a block effect parent,
|
|
3899
|
+
// it means the parent block effect was pruned. In that case,
|
|
3900
|
+
// transparency information was transferred to the branch effect.
|
|
3901
|
+
((child.f & BRANCH_EFFECT) !== 0 && (effect.f & BLOCK_EFFECT) !== 0);
|
|
3902
|
+
// TODO we don't need to call pause_children recursively with a linked list in place
|
|
3903
|
+
// it's slightly more involved though as we have to account for `transparent` changing
|
|
3904
|
+
// through the tree.
|
|
3905
|
+
pause_children(child, transitions, transparent ? local : false);
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3454
3908
|
child = sibling;
|
|
3455
3909
|
}
|
|
3456
3910
|
}
|
|
@@ -3873,7 +4327,14 @@ function remove_reaction(signal, dependency) {
|
|
|
3873
4327
|
derived.f &= ~WAS_MARKED;
|
|
3874
4328
|
}
|
|
3875
4329
|
|
|
3876
|
-
|
|
4330
|
+
// In a fork it's possible that a derived is executed and gets reactions, then commits, but is
|
|
4331
|
+
// never re-executed. This is possible when the derived is only executed once in the context
|
|
4332
|
+
// of a new branch which happens before fork.commit() runs. In this case, the derived still has
|
|
4333
|
+
// UNINITIALIZED as its value, and then when it's loosing its reactions we need to ensure it stays
|
|
4334
|
+
// DIRTY so it is reexecuted once someone wants its value again.
|
|
4335
|
+
if (derived.v !== UNINITIALIZED) {
|
|
4336
|
+
update_derived_status(derived);
|
|
4337
|
+
}
|
|
3877
4338
|
|
|
3878
4339
|
// freeze any effects inside this derived
|
|
3879
4340
|
freeze_derived_effects(derived);
|
|
@@ -4011,19 +4472,21 @@ function get(signal) {
|
|
|
4011
4472
|
}
|
|
4012
4473
|
|
|
4013
4474
|
if (DEV) {
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4475
|
+
if (
|
|
4476
|
+
!untracking &&
|
|
4477
|
+
reactivity_loss_tracker &&
|
|
4478
|
+
!reactivity_loss_tracker.warned &&
|
|
4479
|
+
(reactivity_loss_tracker.effect.f & REACTION_IS_UPDATING) === 0 &&
|
|
4480
|
+
!reactivity_loss_tracker.effect_deps.has(signal)
|
|
4481
|
+
) {
|
|
4482
|
+
reactivity_loss_tracker.warned = true;
|
|
4018
4483
|
|
|
4019
|
-
|
|
4020
|
-
// w.await_reactivity_loss(/** @type {string} */ (signal.label));
|
|
4484
|
+
await_reactivity_loss(/** @type {string} */ (signal.label));
|
|
4021
4485
|
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
// }
|
|
4486
|
+
var trace = get_error('traced at');
|
|
4487
|
+
// eslint-disable-next-line no-console
|
|
4488
|
+
if (trace) console.warn(trace);
|
|
4489
|
+
}
|
|
4027
4490
|
|
|
4028
4491
|
recent_async_deriveds.delete(signal);
|
|
4029
4492
|
}
|
|
@@ -4332,6 +4795,12 @@ class BranchManager {
|
|
|
4332
4795
|
this.#onscreen.set(key, offscreen.effect);
|
|
4333
4796
|
this.#offscreen.delete(key);
|
|
4334
4797
|
|
|
4798
|
+
if (DEV) {
|
|
4799
|
+
// Tell hmr.js about the anchor it should use for updates,
|
|
4800
|
+
// since the initial one will be removed
|
|
4801
|
+
/** @type {any} */ (offscreen.fragment.lastChild)[HMR_ANCHOR] = this.anchor;
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4335
4804
|
// remove the anchor...
|
|
4336
4805
|
/** @type {TemplateNode} */ (offscreen.fragment.lastChild).remove();
|
|
4337
4806
|
|
|
@@ -4604,8 +5073,7 @@ function to_class(value, hash, directives) {
|
|
|
4604
5073
|
* @returns {Record<string, boolean> | undefined}
|
|
4605
5074
|
*/
|
|
4606
5075
|
function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
|
|
4607
|
-
|
|
4608
|
-
var prev = dom.__className;
|
|
5076
|
+
var prev = /** @type {any} */ (dom)[CLASS_CACHE];
|
|
4609
5077
|
|
|
4610
5078
|
if (
|
|
4611
5079
|
prev !== value ||
|
|
@@ -4627,8 +5095,7 @@ function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
|
|
|
4627
5095
|
}
|
|
4628
5096
|
}
|
|
4629
5097
|
|
|
4630
|
-
|
|
4631
|
-
dom.__className = value;
|
|
5098
|
+
/** @type {any} */ (dom)[CLASS_CACHE] = value;
|
|
4632
5099
|
} else if (next_classes && prev_classes !== next_classes) {
|
|
4633
5100
|
for (var key in next_classes) {
|
|
4634
5101
|
var is_present = !!next_classes[key];
|
|
@@ -4679,8 +5146,7 @@ function set_attribute(element, attribute, value, skip_warning) {
|
|
|
4679
5146
|
*/
|
|
4680
5147
|
function get_attributes(element) {
|
|
4681
5148
|
return /** @type {Record<string | symbol, unknown>} **/ (
|
|
4682
|
-
|
|
4683
|
-
element.__attributes ??= {
|
|
5149
|
+
/** @type {any} */ (element)[ATTRIBUTES_CACHE] ??= {
|
|
4684
5150
|
[IS_CUSTOM_ELEMENT]: element.nodeName.includes('-'),
|
|
4685
5151
|
[IS_HTML]: element.namespaceURI === NAMESPACE_HTML
|
|
4686
5152
|
}
|
|
@@ -4701,13 +5167,19 @@ function get_setters(element) {
|
|
|
4701
5167
|
var proto = element; // In the case of custom elements there might be setters on the instance
|
|
4702
5168
|
var element_proto = Element.prototype;
|
|
4703
5169
|
|
|
4704
|
-
// Stop at Element, from there on there's only unnecessary setters we're not interested in
|
|
4705
|
-
// Do not use
|
|
5170
|
+
// Stop at Element, from there on there's only unnecessary (and dangerous, like innerHTML) setters we're not interested in
|
|
5171
|
+
// Do not use constructor.name here as that's unreliable in some browser environments
|
|
4706
5172
|
while (element_proto !== proto) {
|
|
4707
5173
|
descriptors = get_descriptors(proto);
|
|
4708
5174
|
|
|
4709
5175
|
for (var key in descriptors) {
|
|
4710
|
-
if (
|
|
5176
|
+
if (
|
|
5177
|
+
descriptors[key].set &&
|
|
5178
|
+
// better safe than sorry, we don't want spread attributes to mess with HTML content
|
|
5179
|
+
key !== 'innerHTML' &&
|
|
5180
|
+
key !== 'textContent' &&
|
|
5181
|
+
key !== 'innerText'
|
|
5182
|
+
) {
|
|
4711
5183
|
setters.push(key);
|
|
4712
5184
|
}
|
|
4713
5185
|
}
|
|
@@ -4718,6 +5190,8 @@ function get_setters(element) {
|
|
|
4718
5190
|
return setters;
|
|
4719
5191
|
}
|
|
4720
5192
|
|
|
5193
|
+
/** @import { ComponentContext, Effect } from '#client' */
|
|
5194
|
+
|
|
4721
5195
|
/**
|
|
4722
5196
|
* @param {any} bound_value
|
|
4723
5197
|
* @param {Element} element_or_component
|
|
@@ -4738,6 +5212,9 @@ function is_bound_this(bound_value, element_or_component) {
|
|
|
4738
5212
|
* @returns {void}
|
|
4739
5213
|
*/
|
|
4740
5214
|
function bind_this(element_or_component = {}, update, get_value, get_parts) {
|
|
5215
|
+
var component_effect = /** @type {ComponentContext} */ (component_context).r;
|
|
5216
|
+
var parent = /** @type {Effect} */ (active_effect);
|
|
5217
|
+
|
|
4741
5218
|
effect(() => {
|
|
4742
5219
|
/** @type {unknown[]} */
|
|
4743
5220
|
var old_parts;
|
|
@@ -4751,7 +5228,7 @@ function bind_this(element_or_component = {}, update, get_value, get_parts) {
|
|
|
4751
5228
|
parts = get_parts?.() || [];
|
|
4752
5229
|
|
|
4753
5230
|
untrack(() => {
|
|
4754
|
-
if (
|
|
5231
|
+
if (!is_bound_this(get_value(...parts), element_or_component)) {
|
|
4755
5232
|
update(element_or_component, ...parts);
|
|
4756
5233
|
// If this is an effect rerun (cause: each block context changes), then nullify the binding at
|
|
4757
5234
|
// the previous position if it isn't already taken over by a different effect.
|
|
@@ -4763,19 +5240,32 @@ function bind_this(element_or_component = {}, update, get_value, get_parts) {
|
|
|
4763
5240
|
});
|
|
4764
5241
|
|
|
4765
5242
|
return () => {
|
|
4766
|
-
//
|
|
4767
|
-
|
|
5243
|
+
// When the bind:this effect is destroyed, we go up the effect parent chain until we find the last parent effect that is destroyed,
|
|
5244
|
+
// or the effect containing the component bind:this is in (whichever comes first). That way we can time the nulling of the binding
|
|
5245
|
+
// as close to user/developer expectation as possible.
|
|
5246
|
+
// TODO Svelte 6: Decide if we want to keep this logic or just always null the binding in the component effect's teardown
|
|
5247
|
+
// (which would be simpler, but less intuitive in some cases, and breaks the `ondestroy-before-cleanup` test)
|
|
5248
|
+
let p = parent;
|
|
5249
|
+
while (p !== component_effect && p.parent !== null && p.parent.f & DESTROYING) {
|
|
5250
|
+
p = p.parent;
|
|
5251
|
+
}
|
|
5252
|
+
const teardown = () => {
|
|
4768
5253
|
if (parts && is_bound_this(get_value(...parts), element_or_component)) {
|
|
4769
5254
|
update(null, ...parts);
|
|
4770
5255
|
}
|
|
4771
|
-
}
|
|
5256
|
+
};
|
|
5257
|
+
const original_teardown = p.teardown;
|
|
5258
|
+
p.teardown = () => {
|
|
5259
|
+
teardown();
|
|
5260
|
+
original_teardown?.();
|
|
5261
|
+
};
|
|
4772
5262
|
};
|
|
4773
5263
|
});
|
|
4774
5264
|
|
|
4775
5265
|
return element_or_component;
|
|
4776
5266
|
}
|
|
4777
5267
|
|
|
4778
|
-
/** @import { Effect, Source } from './types.js' */
|
|
5268
|
+
/** @import { Derived, Effect, Source } from './types.js' */
|
|
4779
5269
|
|
|
4780
5270
|
/**
|
|
4781
5271
|
* The proxy handler for rest props (i.e. `const { x, ...rest } = $props()`).
|
|
@@ -4839,13 +5329,20 @@ function rest_props(props, exclude, name) {
|
|
|
4839
5329
|
* @returns {(() => V | ((arg: V) => V) | ((arg: V, mutation: boolean) => V))}
|
|
4840
5330
|
*/
|
|
4841
5331
|
function prop(props, key, flags, fallback) {
|
|
5332
|
+
var runes = !legacy_mode_flag ;
|
|
4842
5333
|
var bindable = (flags & PROPS_IS_BINDABLE) !== 0;
|
|
4843
5334
|
var lazy = (flags & PROPS_IS_LAZY_INITIAL) !== 0;
|
|
4844
5335
|
|
|
4845
5336
|
var fallback_value = /** @type {V} */ (fallback);
|
|
4846
5337
|
var fallback_dirty = true;
|
|
5338
|
+
var fallback_signal = /** @type {Derived<V> | undefined} */ (undefined);
|
|
4847
5339
|
|
|
4848
5340
|
var get_fallback = () => {
|
|
5341
|
+
if (lazy && runes) {
|
|
5342
|
+
fallback_signal ??= derived(/** @type {() => V} */ (fallback));
|
|
5343
|
+
return get(fallback_signal);
|
|
5344
|
+
}
|
|
5345
|
+
|
|
4849
5346
|
if (fallback_dirty) {
|
|
4850
5347
|
fallback_dirty = false;
|
|
4851
5348
|
|
|
@@ -4966,9 +5463,7 @@ function prop(props, key, flags, fallback) {
|
|
|
4966
5463
|
|
|
4967
5464
|
// special case — avoid recalculating the derived if we're in a
|
|
4968
5465
|
// teardown function and the prop was overridden locally, or the
|
|
4969
|
-
// component was already destroyed (
|
|
4970
|
-
// because `bind:this` can read props after the component has
|
|
4971
|
-
// been destroyed. TODO simplify `bind:this`
|
|
5466
|
+
// component was already destroyed (people could access props in a timeout)
|
|
4972
5467
|
if ((is_destroying_effect && overridden) || (parent_effect.f & DESTROYED) !== 0) {
|
|
4973
5468
|
return d.v;
|
|
4974
5469
|
}
|