svelte-effect-runtime 3.0.0 → 3.0.1

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.
Files changed (42) hide show
  1. package/.dist/chunks/dispatcher-FCsx1Hlh.js +22 -0
  2. package/.dist/chunks/dispatcher-FCsx1Hlh.js.map +1 -0
  3. package/.dist/chunks/runtime-Sl685BVb.js +79 -0
  4. package/.dist/chunks/runtime-Sl685BVb.js.map +1 -0
  5. package/.dist/chunks/{transform-CMvL4SBp.js → transform-CebZMD6u.js} +5 -5
  6. package/.dist/chunks/transform-CebZMD6u.js.map +1 -0
  7. package/.dist/error.d.ts +1 -1
  8. package/.dist/generated/dispatcher.d.ts +13 -0
  9. package/.dist/generators.d.ts +4 -4
  10. package/.dist/internal/generators.d.ts +1 -1
  11. package/.dist/internal/generators.js +1 -1
  12. package/.dist/markup/promise.d.ts +1 -1
  13. package/.dist/markup/promise.js +2 -2
  14. package/.dist/markup/promise.js.map +1 -1
  15. package/.dist/markup/run.d.ts +1 -1
  16. package/.dist/markup/run.js +2 -2
  17. package/.dist/markup/run.js.map +1 -1
  18. package/.dist/markup/transform/types.d.ts +1 -1
  19. package/.dist/markup/transform.js +1 -1
  20. package/.dist/markup/value.d.ts +1 -1
  21. package/.dist/markup/value.js +2 -2
  22. package/.dist/markup/value.js.map +1 -1
  23. package/.dist/runtime/transform.d.ts +2 -2
  24. package/.dist/runtime/transform.js +654 -3
  25. package/.dist/runtime/transform.js.map +1 -1
  26. package/.dist/{preprocess → script-transform}/imports.d.ts +1 -1
  27. package/.dist/{preprocess → script-transform}/types.d.ts +2 -2
  28. package/.dist/server/runtime.d.ts +14 -0
  29. package/.dist/server.js +2 -56
  30. package/.dist/server.js.map +1 -1
  31. package/package.json +1 -1
  32. package/.dist/chunks/preprocess-BhoCga82.js +0 -656
  33. package/.dist/chunks/preprocess-BhoCga82.js.map +0 -1
  34. package/.dist/chunks/transform-CMvL4SBp.js.map +0 -1
  35. package/.dist/preprocess.d.ts +0 -2
  36. package/.dist/preprocess.js +0 -3
  37. /package/.dist/{preprocess → script-transform}/ast.d.ts +0 -0
  38. /package/.dist/{preprocess → script-transform}/index.d.ts +0 -0
  39. /package/.dist/{preprocess → script-transform}/lower.d.ts +0 -0
  40. /package/.dist/{preprocess → script-transform}/runes.d.ts +0 -0
  41. /package/.dist/{preprocess → script-transform}/runtime-block.d.ts +0 -0
  42. /package/.dist/{preprocess → script-transform}/source.d.ts +0 -0
@@ -1,656 +0,0 @@
1
- import { a as find_yield_star_node, c as AsyncEffectInSyncRuneError, d as collect_top_level_binding_names, f as has_local_import_binding, i as extract_binding_names, l as AwaitInEffectWorkError, n as collect_yield_star_nodes, o as is_yield_star_expression, p as make_imports, r as contains_top_level_await, s as collect_free_identifiers, u as PreprocessError } from "./transform-CMvL4SBp.js";
2
- import { contains_top_level_yield_star } from "../detect.js";
3
- import MagicString from "magic-string";
4
- import ts from "typescript";
5
- //#region src/preprocess/source.ts
6
- /**
7
- * Creates a source map from transformed script back to the original block.
8
- *
9
- * @since 2.0.0
10
- * @param magic - MagicString instance holding the transformed source.
11
- * @param filename - Source filename used for the source map entry.
12
- * @returns A plain source map object.
13
- */
14
- function create_source_map(magic, filename) {
15
- return magic.generateMap({
16
- hires: true,
17
- includeContent: true,
18
- source: filename
19
- });
20
- }
21
- /**
22
- * Slices a substring matching a node's full source range.
23
- *
24
- * @since 2.0.0
25
- * @param content - Original source text.
26
- * @param node - AST node whose full range should be extracted.
27
- * @returns Source text including leading trivia.
28
- */
29
- function slice(content, node) {
30
- return content.slice(node.getFullStart(), node.end);
31
- }
32
- /**
33
- * Slices a substring matching a node's source range without leading trivia.
34
- *
35
- * @since 2.0.0
36
- * @param content - Original source text.
37
- * @param node - AST node whose non-trivia range should be extracted.
38
- * @returns Source text excluding leading trivia.
39
- */
40
- function slice_start(content, node) {
41
- return content.slice(node.getStart(), node.end);
42
- }
43
- //#endregion
44
- //#region src/preprocess/runtime-block.ts
45
- /**
46
- * Builds the runtime blocks appended to lowered script effect code with
47
- * explicit runtime import bindings.
48
- *
49
- * @since 2.4.2
50
- * @param blocks - Effect bodies and dependency reads to emit.
51
- * @param bindings - Runtime binding names available in the generated code.
52
- * @returns Full `$effect` blocks that fork generated `Effect.gen` programs.
53
- */
54
- function make_runtime_block_with_bindings(blocks, bindings) {
55
- const merged_block = merge_effect_blocks(blocks);
56
- const dep_reads = merged_block.deps.map((dep) => ` ${dep};`);
57
- const body = merged_block.statements.map((statement) => ` ${statement}`).join("\n");
58
- return [
59
- "",
60
- "$effect(() => {",
61
- ...dep_reads,
62
- ` const ${bindings.dispatcher_value} = ${bindings.dispatcher}();`,
63
- ` const ${bindings.program} = ${bindings.effect}.gen(function* () {`,
64
- body,
65
- " });",
66
- ` const ${bindings.cancel} = ${bindings.untrack}(() => ${bindings.dispatcher_value}.fork(${bindings.program}));`,
67
- ` import.meta.hot?.dispose(${bindings.cancel});`,
68
- ` return ${bindings.cancel};`,
69
- "});",
70
- ""
71
- ].join("\n");
72
- }
73
- function merge_effect_blocks(blocks) {
74
- const statements = blocks.flatMap((block) => block.statements);
75
- const deps = blocks.flatMap((block) => block.deps);
76
- return {
77
- statements,
78
- deps: [...new Set(deps)]
79
- };
80
- }
81
- //#endregion
82
- //#region src/preprocess/runes.ts
83
- const ASYNC_EXPRESSION_RUNES = new Set([
84
- "$derived",
85
- "$inspect",
86
- "$state",
87
- "$state.raw"
88
- ]);
89
- const CALLBACK_RUNES = new Set([
90
- "$derived.by",
91
- "$effect",
92
- "$effect.pre",
93
- "$effect.root"
94
- ]);
95
- /**
96
- * Validates that `yield*` only appears in rune positions the script-effect
97
- * transform can lower without changing the rune's normal Svelte contract.
98
- *
99
- * @since 2.0.0
100
- * @param node - AST node to scan.
101
- * @param content - Original script source used for diagnostics.
102
- * @param filename - Source filename used for diagnostics.
103
- * @returns Nothing.
104
- */
105
- function validate_rune_yield_usage(node, content, filename) {
106
- visit_rune_yield_usage(node, content, filename);
107
- }
108
- /**
109
- * Identifies `$state(...)` and `$state.raw(...)` initializer calls.
110
- *
111
- * @since 2.0.0
112
- * @param expr - Expression to classify.
113
- * @param content - Original script source used to preserve argument text.
114
- * @returns State rune details when the expression is a state initializer.
115
- */
116
- function get_state_rune_initializer(expr, content) {
117
- if (!ts.isCallExpression(expr)) return;
118
- const rune_name = get_rune_name(expr.expression);
119
- if (rune_name !== "$state" && rune_name !== "$state.raw") return;
120
- const first_arg = expr.arguments[0];
121
- if (!first_arg) return;
122
- return {
123
- rune_name,
124
- value_text: slice(content, first_arg).trim()
125
- };
126
- }
127
- function visit_rune_yield_usage(node, content, filename) {
128
- if (ts.isCallExpression(node)) validate_call_expression(node, content, filename);
129
- node.forEachChild((child) => {
130
- visit_rune_yield_usage(child, content, filename);
131
- });
132
- }
133
- function validate_call_expression(call, content, filename) {
134
- const rune_name = get_rune_name(call.expression);
135
- if (!rune_name) return;
136
- if (!ASYNC_EXPRESSION_RUNES.has(rune_name) && contains_top_level_yield_star(call)) throw new AsyncEffectInSyncRuneError(rune_name, slice(content, call), filename);
137
- if (!CALLBACK_RUNES.has(rune_name)) return;
138
- const callback = call.arguments[0];
139
- if (!callback || !callback_has_top_level_yield_star(callback)) return;
140
- throw new AsyncEffectInSyncRuneError(rune_name, slice(content, call), filename);
141
- }
142
- function callback_has_top_level_yield_star(node) {
143
- if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && node.body !== void 0) return contains_top_level_yield_star(node.body);
144
- return contains_top_level_yield_star(node);
145
- }
146
- function get_rune_name(expr) {
147
- if (ts.isIdentifier(expr) && is_rune_root(expr.text)) return expr.text;
148
- if (!ts.isPropertyAccessExpression(expr)) return;
149
- const root_name = get_rune_name(expr.expression);
150
- if (!root_name) return;
151
- return `${root_name}.${expr.name.text}`;
152
- }
153
- function is_rune_root(name) {
154
- return name === "$bindable" || name === "$derived" || name === "$effect" || name === "$host" || name === "$inspect" || name === "$props" || name === "$state";
155
- }
156
- //#endregion
157
- //#region src/preprocess/lower.ts
158
- /**
159
- * Delegates a statement to the correct lowerer based on syntax kind.
160
- *
161
- * @since 2.0.0
162
- * @param stmt - Statement to lower.
163
- * @param content - Original source text.
164
- * @param context - Lowering services for this transform pass.
165
- * @returns Lowered statement descriptor.
166
- */
167
- function lower_statement(stmt, content, context) {
168
- if (ts.isExpressionStatement(stmt)) return lower_expression_statement(stmt, content, context);
169
- if (ts.isVariableStatement(stmt)) return lower_variable_statement(stmt, content, context);
170
- const text = slice(content, stmt);
171
- return {
172
- temps: [],
173
- rewritten_text: "",
174
- effect_blocks: [make_effect_block([text], collect_deps(text))],
175
- range: {
176
- start: stmt.getFullStart(),
177
- end: stmt.end
178
- }
179
- };
180
- }
181
- function lower_variable_statement(stmt, content, context) {
182
- const temps = [];
183
- const type_helpers = [];
184
- const rewritten_decls = [];
185
- const statements = [];
186
- const deps = [];
187
- const decl_list = stmt.declarationList;
188
- const kind = (decl_list.flags & ts.NodeFlags.Let) !== 0 ? "let" : "const";
189
- let has_bare_yield = false;
190
- let uses_dispatcher_promise = false;
191
- for (const decl of decl_list.declarations) {
192
- if (!decl.initializer || !contains_top_level_yield_star(decl.initializer)) {
193
- if (contains_top_level_yield_star(decl.name)) {
194
- has_bare_yield = true;
195
- const binding_text = slice(content, decl.name).trim();
196
- const initializer_text = decl.initializer ? slice(content, decl.initializer).trim() : "undefined";
197
- const names = extract_binding_names(decl.name);
198
- const statement = `(${binding_text} = ${initializer_text});`;
199
- temps.push(...names.map((name) => make_unknown_temp(name, context)));
200
- statements.push(statement);
201
- deps.push(...collect_deps(statement, names));
202
- continue;
203
- }
204
- rewritten_decls.push(slice(content, decl).trim());
205
- continue;
206
- }
207
- const binding_text = slice(content, decl.name).trim();
208
- if (ts.isIdentifier(decl.name)) {
209
- const original_name = binding_text;
210
- if (is_yield_star_expression(decl.initializer)) {
211
- if (kind === "const") {
212
- const awaited = make_awaited_yield_initializer(decl.initializer, content, original_name, context);
213
- type_helpers.push(awaited.declaration);
214
- rewritten_decls.push(`${original_name} = ${awaited.expression}`);
215
- uses_dispatcher_promise = true;
216
- continue;
217
- }
218
- const temp_name = context.next_temp_name(original_name);
219
- const yield_text = extract_yield_star_full_text(decl.initializer, content);
220
- const type_helper = make_yield_type_helper(yield_text, original_name, context);
221
- if (type_helper) {
222
- type_helpers.push(type_helper.declaration);
223
- temps.push({
224
- name: temp_name,
225
- type: type_helper.type
226
- });
227
- } else temps.push({ name: temp_name });
228
- has_bare_yield = true;
229
- rewritten_decls.push(`${original_name} = $derived(${temp_name})`);
230
- statements.push(`${temp_name} = ${yield_text};`);
231
- deps.push(...collect_deps(yield_text));
232
- } else {
233
- const state_rune = get_state_rune_initializer(decl.initializer, content);
234
- if (state_rune) {
235
- const state_type = extract_yield_star_full_text(decl.initializer, content) === state_rune.value_text ? make_yield_type_helper(state_rune.value_text, original_name, context) : void 0;
236
- if (state_type) type_helpers.push(state_type.declaration);
237
- has_bare_yield = true;
238
- rewritten_decls.push(`${original_name} = ${make_state_placeholder(state_rune.rune_name, state_type?.type, context)}`);
239
- statements.push(`${original_name} = ${state_rune.value_text};`);
240
- deps.push(...collect_deps(state_rune.value_text));
241
- continue;
242
- }
243
- const lowered = lower_expression_yields(decl.initializer, content, original_name, context);
244
- temps.push(...lowered.temps);
245
- type_helpers.push(...lowered.type_helpers ?? []);
246
- for (const block of lowered.effect_blocks) {
247
- statements.push(...block.statements);
248
- deps.push(...block.deps);
249
- }
250
- const rewritten_expr = rewrite_state_rune_as_derived(lowered.rewritten_expr);
251
- const final_expr = should_wrap_complex_initializer_as_derived(decl.initializer, content) ? `$derived(${rewritten_expr})` : rewritten_expr;
252
- if (final_expr !== rewritten_expr) has_bare_yield = true;
253
- rewritten_decls.push(`${original_name} = ${final_expr}`);
254
- }
255
- } else {
256
- has_bare_yield = true;
257
- const temp_name = context.next_temp_name("destructure");
258
- const names = extract_binding_names(decl.name);
259
- const yield_text = extract_yield_star_full_text(decl.initializer, content);
260
- const type_helper = make_yield_type_helper(yield_text, "destructure", context);
261
- if (type_helper) {
262
- type_helpers.push(type_helper.declaration);
263
- temps.push({
264
- name: temp_name,
265
- type: type_helper.type
266
- });
267
- } else temps.push({ name: temp_name });
268
- temps.push(...names.map((name) => make_unknown_temp(name, context)));
269
- statements.push(`${temp_name} = ${yield_text};`);
270
- statements.push(`(${binding_text} = ${temp_name});`);
271
- deps.push(...collect_deps(yield_text));
272
- }
273
- }
274
- return {
275
- temps,
276
- type_helpers,
277
- rewritten_text: rewritten_decls.length === 0 ? "" : `${has_bare_yield ? "let" : kind} ${rewritten_decls.join(", ")};`,
278
- effect_blocks: statements.length === 0 ? [] : [make_effect_block(statements, deps)],
279
- uses_dispatcher_promise,
280
- range: {
281
- start: stmt.getStart(),
282
- end: stmt.end
283
- }
284
- };
285
- }
286
- function lower_expression_statement(stmt, content, context) {
287
- const expr = stmt.expression;
288
- if (!contains_top_level_yield_star(expr)) return {
289
- temps: [],
290
- rewritten_text: slice(content, stmt).trim(),
291
- effect_blocks: [],
292
- range: {
293
- start: stmt.getStart(),
294
- end: stmt.end
295
- }
296
- };
297
- if (is_yield_star_expression(expr)) {
298
- const text = slice(content, expr).trim();
299
- return {
300
- temps: [],
301
- rewritten_text: "",
302
- effect_blocks: [make_effect_block([text + ";"], collect_deps(text))],
303
- range: {
304
- start: stmt.getFullStart(),
305
- end: stmt.end
306
- }
307
- };
308
- }
309
- if (ts.isBinaryExpression(expr) && is_assignment_operator(expr)) {
310
- const target = slice(content, expr.left).trim();
311
- const target_names = collect_assignment_target_names(expr.left);
312
- if (expr.operatorToken.kind === ts.SyntaxKind.EqualsToken && is_yield_star_expression(expr.right)) {
313
- const yield_text = extract_yield_star_full_text(expr.right, content);
314
- return {
315
- temps: [],
316
- rewritten_text: "",
317
- effect_blocks: [make_effect_block([`${target} = ${yield_text};`], collect_deps(yield_text, target_names))],
318
- range: {
319
- start: stmt.getStart(),
320
- end: stmt.end
321
- }
322
- };
323
- }
324
- const lowered = lower_expression_yields(expr.right, content, make_temp_hint(target), context);
325
- const temp_names = lowered.temps.map((temp) => temp.name);
326
- const statement = `${target} ${slice(content, expr.operatorToken).trim()} ${lowered.rewritten_expr};`;
327
- return {
328
- temps: lowered.temps,
329
- type_helpers: lowered.type_helpers,
330
- rewritten_text: "",
331
- effect_blocks: [make_effect_block([...lowered.effect_blocks.flatMap((block) => block.statements), statement], [...lowered.effect_blocks.flatMap((block) => block.deps), ...collect_deps(lowered.rewritten_expr, [...target_names, ...temp_names])])],
332
- range: {
333
- start: stmt.getStart(),
334
- end: stmt.end
335
- }
336
- };
337
- }
338
- const lowered = lower_expression_yields(expr, content, "call", context);
339
- if (is_top_level_rune_call(expr)) return {
340
- temps: lowered.temps,
341
- type_helpers: lowered.type_helpers,
342
- rewritten_text: lowered.rewritten_expr + ";",
343
- effect_blocks: lowered.effect_blocks,
344
- range: {
345
- start: stmt.getStart(),
346
- end: stmt.end
347
- }
348
- };
349
- const temp_names = lowered.temps.map((temp) => temp.name);
350
- return {
351
- temps: lowered.temps,
352
- type_helpers: lowered.type_helpers,
353
- rewritten_text: "",
354
- effect_blocks: [make_effect_block([...lowered.effect_blocks.flatMap((block) => block.statements), lowered.rewritten_expr + ";"], [...lowered.effect_blocks.flatMap((block) => block.deps), ...collect_deps(lowered.rewritten_expr, temp_names)])],
355
- range: {
356
- start: stmt.getStart(),
357
- end: stmt.end
358
- }
359
- };
360
- }
361
- function lower_expression_yields(expr, content, hint, context) {
362
- const replacements = [];
363
- const temps = [];
364
- const type_helpers = [];
365
- const statements = [];
366
- const deps = [];
367
- collect_yield_star_nodes(expr, (node) => {
368
- const temp_name = context.next_temp_name(hint);
369
- const yield_text = slice_start(content, node).trim();
370
- const type_helper = make_yield_type_helper(yield_text, hint, context);
371
- if (type_helper) {
372
- type_helpers.push(type_helper.declaration);
373
- temps.push({
374
- name: temp_name,
375
- type: type_helper.type
376
- });
377
- } else temps.push({ name: temp_name });
378
- statements.push(`${temp_name} = ${yield_text};`);
379
- deps.push(...collect_deps(yield_text));
380
- replacements.push({
381
- start: node.getStart(),
382
- end: node.end,
383
- text: temp_name
384
- });
385
- });
386
- if (replacements.length === 0) return {
387
- temps,
388
- type_helpers,
389
- rewritten_expr: slice(content, expr).trim(),
390
- effect_blocks: []
391
- };
392
- replacements.sort((a, b) => b.start - a.start);
393
- let text = slice(content, expr);
394
- const offset_in_expr = expr.getFullStart();
395
- for (const replacement of replacements) text = text.slice(0, replacement.start - offset_in_expr) + replacement.text + text.slice(replacement.end - offset_in_expr);
396
- return {
397
- temps,
398
- type_helpers,
399
- rewritten_expr: text.trim(),
400
- effect_blocks: [make_effect_block(statements, deps)]
401
- };
402
- }
403
- function make_awaited_yield_initializer(expr, content, hint, context) {
404
- const yield_text = extract_yield_star_full_text(expr, content);
405
- const helper_name = context.next_helper_name(`effect_${hint}`);
406
- const helper_id = make_script_effect_id(expr, context);
407
- const deps_text = `[${collect_deps(yield_text).join(", ")}]`;
408
- return {
409
- declaration: `function* ${helper_name}() { return (${yield_text}); }`,
410
- expression: [
411
- `await ${context.dispatcher_name}().promise({`,
412
- `id: ${JSON.stringify(helper_id)}, `,
413
- `deps: ${deps_text}, `,
414
- `factory: () => ${helper_name}()`,
415
- `})`
416
- ].join("")
417
- };
418
- }
419
- function make_yield_type_helper(yield_text, hint, context) {
420
- if (!context.emit_types) return;
421
- const helper_name = context.next_type_helper_name(hint);
422
- return {
423
- declaration: `function ${helper_name}() { return (${strip_yield_star(yield_text)}); }`,
424
- type: `${context.effect_name}.Success<ReturnType<typeof ${helper_name}>> | undefined`
425
- };
426
- }
427
- function make_unknown_temp(name, context) {
428
- return {
429
- name,
430
- type: context.emit_types ? "unknown" : void 0
431
- };
432
- }
433
- function make_state_placeholder(rune_name, type, context) {
434
- if (type) return `${rune_name}<${type}>(undefined)`;
435
- if (context.emit_types) return `${rune_name}<unknown>(undefined)`;
436
- return `${rune_name}(undefined)`;
437
- }
438
- function strip_yield_star(yield_text) {
439
- return yield_text.replace(/^yield\*\s*/, "");
440
- }
441
- function make_script_effect_id(expr, context) {
442
- return `${context.filename}:${expr.getStart()}:${expr.end}`;
443
- }
444
- function rewrite_state_rune_as_derived(expression) {
445
- const state_call = expression.match(/^\$state(?:\.raw)?\(([\s\S]*)\)$/);
446
- if (!state_call) return expression;
447
- return `$derived(${state_call[1]})`;
448
- }
449
- function should_wrap_complex_initializer_as_derived(expr, content) {
450
- const text = slice(content, expr).trim();
451
- return !/^\$derived(?:\.by)?\(/.test(text) && !/^\$inspect(?:\.trace)?\(/.test(text);
452
- }
453
- function is_assignment_operator(expr) {
454
- return expr.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && expr.operatorToken.kind <= ts.SyntaxKind.LastAssignment;
455
- }
456
- function is_top_level_rune_call(expr) {
457
- if (!ts.isCallExpression(expr)) return false;
458
- const callee = expr.expression;
459
- if (ts.isIdentifier(callee)) return callee.text.startsWith("$");
460
- return ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression) && callee.expression.text.startsWith("$");
461
- }
462
- function make_temp_hint(target) {
463
- return target.match(/[A-Za-z_$][\w$]*$/)?.[0] ?? "assignment";
464
- }
465
- function extract_yield_star_full_text(expr, content) {
466
- let found;
467
- find_yield_star_node(expr, (node) => {
468
- found = slice_start(content, node).trim();
469
- });
470
- return found ?? "undefined";
471
- }
472
- function make_effect_block(statements, deps) {
473
- return {
474
- statements,
475
- deps: [...new Set(deps)]
476
- };
477
- }
478
- function collect_deps(expr_text, excluded_names = []) {
479
- const excluded = new Set(excluded_names);
480
- return collect_free_identifiers(expr_text).filter((identifier) => !identifier.startsWith("__SER___") && !excluded.has(identifier));
481
- }
482
- function collect_assignment_target_names(node) {
483
- if (ts.isIdentifier(node)) return [node.text];
484
- if (ts.isParenthesizedExpression(node)) return collect_assignment_target_names(node.expression);
485
- if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) return collect_assignment_target_names(node.expression);
486
- if (ts.isObjectLiteralExpression(node)) return node.properties.flatMap((property) => {
487
- if (ts.isShorthandPropertyAssignment(property)) return [property.name.text];
488
- if (ts.isPropertyAssignment(property)) return collect_assignment_target_names(property.initializer);
489
- if (ts.isSpreadAssignment(property)) return collect_assignment_target_names(property.expression);
490
- return [];
491
- });
492
- if (ts.isArrayLiteralExpression(node)) return node.elements.flatMap((element) => ts.isSpreadElement(element) ? collect_assignment_target_names(element.expression) : collect_assignment_target_names(element));
493
- return [];
494
- }
495
- //#endregion
496
- //#region src/preprocess/index.ts
497
- /**
498
- * Transforms a `<script effect>` body by extracting top-level `yield*`
499
- * expressions into `$state` temp bindings and wrapping the lowered
500
- * assignments in a dependency-tracked `$effect` block.
501
- *
502
- * @example
503
- * ```ts
504
- * const result = transform_script_effect(
505
- * `let user = $state(yield* getUser(id));`,
506
- * "App.svelte",
507
- * );
508
- * ```
509
- *
510
- * @since 2.0.0
511
- * @param content - The raw `<script effect>` body content.
512
- * @param filename - The source filename, used in error messages.
513
- * @param options - Optional transform settings for generated script code.
514
- * @returns The transformed code and any block references.
515
- */
516
- function transform_script_effect(content, filename, options = {}) {
517
- let temp_counter = 0;
518
- const source_file = ts.createSourceFile(filename, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
519
- const magic = new MagicString(content);
520
- const effect_blocks = [];
521
- const block_refs = [];
522
- const top_level_binding_names = collect_top_level_binding_names(source_file);
523
- const top_level_binding_names_set = new Set(top_level_binding_names);
524
- const name_allocator = make_name_allocator(top_level_binding_names);
525
- const emit_types = options.emit_types ?? true;
526
- let has_effect = false;
527
- let uses_dispatcher_promise = false;
528
- let uses_effect_types = false;
529
- /** Phase 1: detect imports already provided by the user. */
530
- const has_effect_import = has_local_import_binding(source_file, "effect", "Effect");
531
- const has_dispatcher_import = has_local_import_binding(source_file, "svelte-effect-runtime/internal/generators", "get_dispatcher");
532
- const has_untrack_import = has_local_import_binding(source_file, "svelte", "untrack");
533
- const reserve_runtime_import = (name) => top_level_binding_names_set.has(name) ? name_allocator.reserve(make_generated_name(name, "")) : name_allocator.reserve(name);
534
- const runtime_bindings = {
535
- cancel: name_allocator.reserve("__SER___cancel"),
536
- dispatcher: has_dispatcher_import ? "get_dispatcher" : reserve_runtime_import("get_dispatcher"),
537
- dispatcher_value: name_allocator.reserve("__SER___dispatcher"),
538
- effect: has_effect_import ? "Effect" : reserve_runtime_import("Effect"),
539
- program: name_allocator.reserve("__SER___program"),
540
- untrack: has_untrack_import ? "untrack" : reserve_runtime_import("untrack")
541
- };
542
- const context = {
543
- filename,
544
- dispatcher_name: runtime_bindings.dispatcher,
545
- effect_name: runtime_bindings.effect,
546
- emit_types,
547
- next_helper_name(hint) {
548
- return name_allocator.reserve(make_generated_name(hint ?? "helper", ""));
549
- },
550
- next_temp_name(hint) {
551
- const suffix = temp_counter === 0 ? "" : `_${temp_counter}`;
552
- const name = make_generated_name(hint ?? String(temp_counter), suffix);
553
- temp_counter += 1;
554
- return name_allocator.reserve(name);
555
- },
556
- next_type_helper_name(hint) {
557
- return name_allocator.reserve(make_generated_name(`type_${hint ?? "effect"}`, ""));
558
- }
559
- };
560
- /** Phase 2: lower every top-level statement that contains `yield*`. */
561
- for (const stmt of source_file.statements) {
562
- validate_rune_yield_usage(stmt, content, filename);
563
- validate_script_yield_boundaries(stmt, content, filename);
564
- if (!contains_top_level_yield_star(stmt)) continue;
565
- if (contains_top_level_await(stmt)) throw new AwaitInEffectWorkError(filename, slice(content, stmt));
566
- has_effect = true;
567
- const lowered = lower_statement(stmt, content, context);
568
- magic.overwrite(lowered.range.start, lowered.range.end, lowered.rewritten_text);
569
- if (lowered.temps.length > 0 || lowered.type_helpers?.length) {
570
- const temp_declarations = lowered.temps.map((temp) => temp.type ? `let ${temp.name} = $state<${temp.type}>(undefined);` : `let ${temp.name} = $state(undefined);`);
571
- const prefix = [...lowered.type_helpers ?? [], ...temp_declarations].join("\n");
572
- magic.appendLeft(lowered.range.start, prefix + "\n");
573
- }
574
- effect_blocks.push(...lowered.effect_blocks);
575
- uses_dispatcher_promise ||= lowered.uses_dispatcher_promise ?? false;
576
- uses_effect_types ||= lowered.temps.some((temp) => temp.type?.includes(`${runtime_bindings.effect}.Success`) ?? false);
577
- }
578
- if (!has_effect) {
579
- block_refs.push({
580
- id: filename,
581
- kind: "script"
582
- });
583
- return {
584
- code: content,
585
- blocks: block_refs
586
- };
587
- }
588
- /** Phase 3: inject runtime imports after the last user import. */
589
- const imports = make_imports(has_effect_import, has_dispatcher_import, has_untrack_import, runtime_bindings, {
590
- needs_dispatcher: effect_blocks.length > 0 || uses_dispatcher_promise,
591
- needs_effect: effect_blocks.length > 0 || uses_effect_types,
592
- needs_untrack: effect_blocks.length > 0
593
- });
594
- const last_import = [...source_file.statements].reverse().find(ts.isImportDeclaration);
595
- if (imports) if (last_import) magic.appendRight(last_import.end, "\n" + imports);
596
- else magic.prepend(imports + "\n");
597
- /** Phase 4: append the runtime program and lifecycle wiring. */
598
- if (effect_blocks.length > 0) {
599
- const runtime_block = make_runtime_block_with_bindings(effect_blocks, runtime_bindings);
600
- magic.append("\n" + runtime_block);
601
- }
602
- block_refs.push({
603
- id: filename,
604
- kind: "script"
605
- });
606
- return {
607
- code: magic.toString(),
608
- blocks: block_refs,
609
- map: create_source_map(magic, filename)
610
- };
611
- }
612
- function validate_script_yield_boundaries(stmt, content, filename) {
613
- const bad_member = find_class_member_with_yield_star(stmt);
614
- if (!bad_member) return;
615
- throw new PreprocessError([
616
- `[ASYNC_EFFECT_IN_CLASS_MEMBER]: ${filename}: yield* cannot be used inside class members.`,
617
- `Class fields and methods are not component top-level reactive work. Move the Effect work into a script effect statement before assigning it to the class instance.`,
618
- "",
619
- "Problematic member:",
620
- slice(content, bad_member)
621
- ].join("\n"), filename);
622
- }
623
- function find_class_member_with_yield_star(stmt) {
624
- let found;
625
- function visit(node) {
626
- if (found) return;
627
- if (ts.isPropertyDeclaration(node) && node.initializer && contains_top_level_yield_star(node.initializer)) {
628
- found = node;
629
- return;
630
- }
631
- node.forEachChild(visit);
632
- }
633
- visit(stmt);
634
- return found;
635
- }
636
- function make_name_allocator(initial_names) {
637
- const used_names = new Set(initial_names);
638
- return { reserve(name) {
639
- let candidate = name;
640
- let suffix = 1;
641
- while (used_names.has(candidate)) {
642
- candidate = `${name}_${suffix}`;
643
- suffix += 1;
644
- }
645
- used_names.add(candidate);
646
- return candidate;
647
- } };
648
- }
649
- function make_generated_name(hint, suffix) {
650
- const normalized_hint = hint.replace(/[^A-Za-z0-9_$]/g, "_");
651
- return `__SER___${/^[A-Za-z_$]/.test(normalized_hint) ? normalized_hint : `temp_${normalized_hint}`}${suffix}`;
652
- }
653
- //#endregion
654
- export { transform_script_effect as t };
655
-
656
- //# sourceMappingURL=preprocess-BhoCga82.js.map