svelte-effect-runtime 3.4.11 → 4.0.0

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 (83) hide show
  1. package/.dist/chunks/{client-CsVu54pU.js → client-DcZUV4rR.js} +76 -50
  2. package/.dist/chunks/client-DcZUV4rR.js.map +1 -0
  3. package/.dist/chunks/{vite-WGlbSnso.js → compiler-BBPNyXmQ.js} +84 -110
  4. package/.dist/chunks/compiler-BBPNyXmQ.js.map +1 -0
  5. package/.dist/chunks/{dispatcher-pHH4JcFR.js → dispatcher-DOx8iC6r.js} +2 -2
  6. package/.dist/chunks/{dispatcher-pHH4JcFR.js.map → dispatcher-DOx8iC6r.js.map} +1 -1
  7. package/.dist/chunks/{dispatcher-LtvFKYUp.js → dispatcher-H-Ia0Os4.js} +3 -3
  8. package/.dist/chunks/{dispatcher-LtvFKYUp.js.map → dispatcher-H-Ia0Os4.js.map} +1 -1
  9. package/.dist/chunks/{errors-Dcf0MVbq.js → errors-IJjsUwrE.js} +21 -65
  10. package/.dist/chunks/errors-IJjsUwrE.js.map +1 -0
  11. package/.dist/chunks/live-BXAKre_4.js +104 -0
  12. package/.dist/chunks/live-BXAKre_4.js.map +1 -0
  13. package/.dist/chunks/{remote-client-Bj1pZXgq.js → remote-client-CVI4t66c.js} +2 -2
  14. package/.dist/chunks/remote-client-CVI4t66c.js.map +1 -0
  15. package/.dist/chunks/{runtime-ekkMQ-wL.js → runtime-GBQz32DZ.js} +3 -3
  16. package/.dist/chunks/{runtime-ekkMQ-wL.js.map → runtime-GBQz32DZ.js.map} +1 -1
  17. package/.dist/chunks/schema-D9pct6Y5.js +89 -0
  18. package/.dist/chunks/schema-D9pct6Y5.js.map +1 -0
  19. package/.dist/chunks/server-D1LcDnZE.js +213 -0
  20. package/.dist/chunks/server-D1LcDnZE.js.map +1 -0
  21. package/.dist/chunks/source-scan-C4PsggID.js +341 -0
  22. package/.dist/chunks/source-scan-C4PsggID.js.map +1 -0
  23. package/.dist/chunks/{transform-CtQDGS9c.js → transform-jNUr65K9.js} +237 -239
  24. package/.dist/chunks/transform-jNUr65K9.js.map +1 -0
  25. package/.dist/compiler/source-scan.d.ts +198 -0
  26. package/.dist/{vite.d.ts → compiler.d.ts} +1 -1
  27. package/.dist/{vite.js → compiler.js} +1 -1
  28. package/.dist/dispatcher.js +1 -1
  29. package/.dist/errors.d.ts +15 -45
  30. package/.dist/generators.d.ts +3 -1
  31. package/.dist/internal/generators.js +20 -3
  32. package/.dist/internal/generators.js.map +1 -0
  33. package/.dist/internal/remote-client.js +1 -1
  34. package/.dist/internal/remote-server.js +1 -1
  35. package/.dist/internal/schema.d.ts +67 -0
  36. package/.dist/live.d.ts +123 -0
  37. package/.dist/markup/event-attributes.d.ts +16 -7
  38. package/.dist/markup/promise.js +1 -1
  39. package/.dist/markup/run.js +1 -1
  40. package/.dist/markup/transform/constants.d.ts +1 -0
  41. package/.dist/markup/transform/types.d.ts +1 -0
  42. package/.dist/markup/transform.js +1 -1
  43. package/.dist/markup/value.js +1 -1
  44. package/.dist/mod.d.ts +6 -3
  45. package/.dist/mod.js +5 -4
  46. package/.dist/mod.js.map +1 -1
  47. package/.dist/remote/cause-codec.d.ts +53 -0
  48. package/.dist/remote/client/form-transport.d.ts +4 -1
  49. package/.dist/remote/client/form.d.ts +10 -1
  50. package/.dist/remote/client/index.d.ts +1 -1
  51. package/.dist/remote/client/query.d.ts +6 -16
  52. package/.dist/remote/client/types.d.ts +32 -13
  53. package/.dist/remote/client.d.ts +1 -1
  54. package/.dist/remote/client.js +1 -1
  55. package/.dist/remote/server.d.ts +2 -12
  56. package/.dist/remote/server.js +1 -178
  57. package/.dist/runtime/transform.js +81 -68
  58. package/.dist/runtime/transform.js.map +1 -1
  59. package/.dist/script-transform/imports.d.ts +2 -0
  60. package/.dist/script-transform/types.d.ts +8 -0
  61. package/.dist/server/effects.d.ts +7 -7
  62. package/.dist/server/handler.d.ts +37 -0
  63. package/.dist/server/index.d.ts +4 -1
  64. package/.dist/server/schema.d.ts +2 -26
  65. package/.dist/server/types.d.ts +44 -50
  66. package/.dist/server/wrappers.d.ts +2 -2
  67. package/.dist/server.d.ts +2 -2
  68. package/.dist/server.js +88 -97
  69. package/.dist/server.js.map +1 -1
  70. package/.dist/yieldable.d.ts +41 -0
  71. package/README.md +1 -1
  72. package/package.json +4 -4
  73. package/.dist/chunks/client-CsVu54pU.js.map +0 -1
  74. package/.dist/chunks/descriptors-cOe9uRJz.js +0 -36
  75. package/.dist/chunks/descriptors-cOe9uRJz.js.map +0 -1
  76. package/.dist/chunks/errors-Dcf0MVbq.js.map +0 -1
  77. package/.dist/chunks/event-attributes-gHzP2ycp.js +0 -39
  78. package/.dist/chunks/event-attributes-gHzP2ycp.js.map +0 -1
  79. package/.dist/chunks/remote-client-Bj1pZXgq.js.map +0 -1
  80. package/.dist/chunks/transform-CtQDGS9c.js.map +0 -1
  81. package/.dist/chunks/vite-WGlbSnso.js.map +0 -1
  82. package/.dist/remote/server.js.map +0 -1
  83. /package/.dist/{vite → compiler}/remote-client.d.ts +0 -0
@@ -1,5 +1,5 @@
1
- import { A as YieldStarInEventCallbackError, D as UnsupportedMarkupEffectPositionError, n as AsyncEffectInSyncRuneError, t as AsyncEffectInEventCallbackError } from "./errors-Dcf0MVbq.js";
2
- import { n as normalize_event_attribute_name, t as is_event_attribute_name } from "./event-attributes-gHzP2ycp.js";
1
+ import { D as UnsupportedMarkupEffectPositionError, k as YieldStarInEventCallbackError, n as AsyncEffectInSyncRuneError, t as AsyncEffectInEventCallbackError } from "./errors-IJjsUwrE.js";
2
+ import { t as scan_svelte_effect_source } from "./source-scan-C4PsggID.js";
3
3
  import { contains_top_level_yield_star } from "../detect.js";
4
4
  import ts from "typescript";
5
5
  import { parse } from "svelte/compiler";
@@ -23,20 +23,37 @@ function make_imports(has_effect_import, has_dispatcher_import, has_untrack_impo
23
23
  dispatcher_value: "__SER___dispatcher",
24
24
  effect: "Effect",
25
25
  program: "__SER___program",
26
- untrack: "untrack"
26
+ untrack: "untrack",
27
+ yield_success: "YieldSuccess",
28
+ yieldable: "ToEffect"
27
29
  }, options = {}) {
28
30
  const needs_dispatcher = options.needs_dispatcher ?? true;
29
31
  const needs_effect = options.needs_effect ?? true;
30
32
  const needs_untrack = options.needs_untrack ?? true;
31
- const dispatcher_import = bindings.dispatcher === "get_dispatcher" ? `import { get_dispatcher } from "svelte-effect-runtime/internal/generators";` : `import { get_dispatcher as ${bindings.dispatcher} } from "svelte-effect-runtime/internal/generators";`;
33
+ const needs_yield_success = options.needs_yield_success ?? false;
34
+ const needs_yieldable = options.needs_yieldable ?? false;
35
+ const generator_import = make_generator_import(bindings, needs_dispatcher && !has_dispatcher_import, needs_yieldable, needs_yield_success);
32
36
  const untrack_import = bindings.untrack === "untrack" ? `import { untrack } from "svelte";` : `import { untrack as ${bindings.untrack} } from "svelte";`;
33
37
  const effect_import = has_effect_import ? false : bindings.effect === "Effect" ? `import { Effect } from "effect";` : `import { Effect as ${bindings.effect} } from "effect";`;
34
38
  return [
35
- needs_dispatcher && !has_dispatcher_import && dispatcher_import,
39
+ generator_import,
36
40
  needs_untrack && !has_untrack_import && untrack_import,
37
41
  needs_effect && effect_import
38
42
  ].filter(Boolean).join("\n");
39
43
  }
44
+ function make_generator_import(bindings, needs_dispatcher, needs_yieldable, needs_yield_success) {
45
+ const specifiers = [
46
+ needs_dispatcher && make_named_import("get_dispatcher", bindings.dispatcher),
47
+ needs_yieldable && make_named_import("ToEffect", bindings.yieldable),
48
+ needs_yield_success && make_named_import("YieldSuccess", bindings.yield_success, true)
49
+ ].filter((specifier) => specifier !== false);
50
+ if (specifiers.length === 0) return false;
51
+ return `import { ${specifiers.join(", ")} } from "svelte-effect-runtime/internal/generators";`;
52
+ }
53
+ function make_named_import(imported_name, local_name, type_only = false) {
54
+ const prefix = type_only ? "type " : "";
55
+ return imported_name === local_name ? `${prefix}${imported_name}` : `${prefix}${imported_name} as ${local_name}`;
56
+ }
40
57
  /**
41
58
  * Checks whether a source file imports a local binding from a module.
42
59
  *
@@ -94,7 +111,8 @@ function collect_binding_name_text(name) {
94
111
  //#region src/markup/transform/constants.ts
95
112
  const HELPERS = {
96
113
  codes: "Code",
97
- dispatcher: "Dispatcher"
114
+ dispatcher: "Dispatcher",
115
+ yieldable: "ToEffect"
98
116
  };
99
117
  //#endregion
100
118
  //#region src/markup/transform/apply.ts
@@ -145,7 +163,8 @@ function make_markup_helper_bindings(content) {
145
163
  return {
146
164
  bindings: {
147
165
  codes: name_allocator.reserve(HELPERS.codes),
148
- dispatcher: name_allocator.reserve(HELPERS.dispatcher)
166
+ dispatcher: name_allocator.reserve(HELPERS.dispatcher),
167
+ yieldable: name_allocator.reserve(HELPERS.yieldable)
149
168
  },
150
169
  name_allocator
151
170
  };
@@ -184,7 +203,7 @@ function make_import_helper(content, import_text) {
184
203
  return import_text;
185
204
  }
186
205
  function make_dispatcher_import(bindings) {
187
- return `import { ${make_import_specifier(HELPERS.dispatcher, bindings.dispatcher)}, ${make_import_specifier(HELPERS.codes, bindings.codes)} } from "svelte-effect-runtime/internal/generators";`;
206
+ return `import { ${make_import_specifier(HELPERS.dispatcher, bindings.dispatcher)}, ${make_import_specifier(HELPERS.codes, bindings.codes)}, ${make_import_specifier(HELPERS.yieldable, bindings.yieldable)} } from "svelte-effect-runtime/internal/generators";`;
188
207
  }
189
208
  function make_import_specifier(imported_name, local_name) {
190
209
  if (imported_name === local_name) return imported_name;
@@ -388,6 +407,49 @@ function add_ordered_name(names, name) {
388
407
  names.push(name);
389
408
  }
390
409
  //#endregion
410
+ //#region src/markup/event-attributes.ts
411
+ /**
412
+ * Checks whether a parsed Svelte attribute has the same event shape that
413
+ * Svelte's compiler recognizes.
414
+ *
415
+ * @example
416
+ * ```ts
417
+ * is_svelte_event_attribute({
418
+ * type: "Attribute",
419
+ * name: "onclick",
420
+ * value: { type: "ExpressionTag" },
421
+ * });
422
+ * ```
423
+ *
424
+ * @since 4.0.0
425
+ * @param attribute - Parsed Svelte attribute with its name and complete value
426
+ * shape.
427
+ * @returns Whether Svelte treats the attribute as an event attribute.
428
+ */
429
+ function is_svelte_event_attribute(attribute) {
430
+ if (attribute.type !== "Attribute" || !attribute.name?.startsWith("on")) return false;
431
+ const value = attribute.value;
432
+ return value !== true && !Array.isArray(value) || Array.isArray(value) && value.length === 1 && value[0]?.type === "ExpressionTag";
433
+ }
434
+ /**
435
+ * Normalizes an event-like attribute name to Svelte's lowercase DOM event
436
+ * spelling while keeping the legacy directive prefix intact.
437
+ *
438
+ * @example
439
+ * ```ts
440
+ * normalize_event_attribute_name("onChange");
441
+ * ```
442
+ *
443
+ * @since 3.4.11
444
+ * @param name - Event-like attribute name read from Svelte source or the
445
+ * parsed AST.
446
+ * @returns Lowercase event attribute spelling for DOM-facing Svelte nodes.
447
+ */
448
+ function normalize_event_attribute_name(name) {
449
+ if (name.startsWith("on:")) return `on:${name.slice(3).toLowerCase()}`;
450
+ return name.toLowerCase();
451
+ }
452
+ //#endregion
391
453
  //#region src/markup/transform/classify.ts
392
454
  /**
393
455
  * Matches sanitized placeholders back to their Svelte AST context.
@@ -447,6 +509,11 @@ function visit_ast_node(node, candidates, matched, classified) {
447
509
  case "SnippetBlock":
448
510
  walk_ast(node.body, candidates, matched, classified);
449
511
  return;
512
+ case "SvelteElement":
513
+ classify_expression(node.tag, "plain", candidates, matched, classified);
514
+ visit_element_attributes(node, candidates, matched, classified);
515
+ walk_ast(node.fragment, candidates, matched, classified);
516
+ return;
450
517
  case "RegularElement":
451
518
  case "Component":
452
519
  case "TitleElement":
@@ -455,7 +522,6 @@ function visit_ast_node(node, candidates, matched, classified) {
455
522
  case "SvelteBoundary":
456
523
  case "SvelteComponent":
457
524
  case "SvelteDocument":
458
- case "SvelteElement":
459
525
  case "SvelteFragment":
460
526
  case "SvelteHead":
461
527
  case "SvelteSelf":
@@ -471,7 +537,7 @@ function classify_declaration_tag(node, candidates, matched, classified) {
471
537
  }
472
538
  function visit_element_attributes(node, candidates, matched, classified) {
473
539
  for (const attr of node.attributes) {
474
- if (attr.type === "Attribute" && attr.name && is_event_attribute_name(attr.name)) {
540
+ if (is_svelte_event_attribute(attr)) {
475
541
  const attribute_name_replacement = make_attribute_name_replacement(node, attr);
476
542
  visit_attribute_value(attr.value, "event", candidates, matched, classified, attribute_name_replacement);
477
543
  continue;
@@ -557,6 +623,75 @@ function is_record(value) {
557
623
  return typeof value === "object" && value !== null;
558
624
  }
559
625
  //#endregion
626
+ //#region src/script-transform/ast.ts
627
+ /**
628
+ * Checks whether a node is a `yield*` binary expression.
629
+ *
630
+ * @since 2.0.0
631
+ * @param node - TypeScript AST node to check.
632
+ * @returns Whether the node represents `yield * operand`.
633
+ */
634
+ function is_yield_star_expression$1(node) {
635
+ return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
636
+ }
637
+ /**
638
+ * Checks whether a node owns its own yield semantics.
639
+ *
640
+ * @since 2.0.0
641
+ * @param node - TypeScript AST node to check.
642
+ * @returns Whether traversal should stop at this function boundary.
643
+ */
644
+ function is_function_boundary_node(node) {
645
+ return ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
646
+ }
647
+ /**
648
+ * Returns `true` if the node tree contains a top-level `await`.
649
+ *
650
+ * @since 2.0.0
651
+ * @param node - Root node to search.
652
+ * @returns Whether a top-level await expression was found.
653
+ */
654
+ function contains_top_level_await(node) {
655
+ if (ts.isAwaitExpression(node)) return true;
656
+ return node.getChildren().some((child) => !is_function_boundary_node(child) && contains_top_level_await(child));
657
+ }
658
+ /**
659
+ * Collects top-level `yield*` nodes under an expression.
660
+ *
661
+ * @since 2.0.0
662
+ * @param node - Root node to search.
663
+ * @param on_found - Callback invoked for each matching yield node.
664
+ * @returns Nothing.
665
+ */
666
+ function collect_yield_star_nodes(node, on_found) {
667
+ if (is_function_boundary_node(node)) return;
668
+ if (is_yield_star_expression$1(node)) {
669
+ on_found(node);
670
+ return;
671
+ }
672
+ node.forEachChild((child) => {
673
+ collect_yield_star_nodes(child, on_found);
674
+ });
675
+ }
676
+ /**
677
+ * Finds the first top-level `yield*` expression below a node.
678
+ *
679
+ * @since 2.0.0
680
+ * @param node - Root node to search.
681
+ * @param on_found - Callback invoked with the first matching node.
682
+ * @returns Nothing.
683
+ */
684
+ function find_yield_star_node(node, on_found) {
685
+ if (is_function_boundary_node(node)) return;
686
+ if (is_yield_star_expression$1(node)) {
687
+ on_found(node);
688
+ return;
689
+ }
690
+ node.forEachChild((child) => {
691
+ find_yield_star_node(child, on_found);
692
+ });
693
+ }
694
+ //#endregion
560
695
  //#region src/markup/transform/expressions.ts
561
696
  /**
562
697
  * Strips an event handler arrow function down to its executable body.
@@ -701,7 +836,7 @@ function add_binding_names(name, locals) {
701
836
  }
702
837
  }
703
838
  function visit_event_body(node, context, result) {
704
- if (is_yield_star_expression$1(node)) {
839
+ if (is_yield_star_expression(node)) {
705
840
  if (context === "top_level") result.has_top_level_yield_star = true;
706
841
  else if (context === "nested_invalid") result.has_nested_invalid_yield_star = true;
707
842
  node.forEachChild((child) => visit_event_body(child, context, result));
@@ -720,7 +855,7 @@ function is_nested_function_boundary(node) {
720
855
  function is_generator_function_boundary(node) {
721
856
  return (ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) && node.asteriskToken !== void 0;
722
857
  }
723
- function is_yield_star_expression$1(node) {
858
+ function is_yield_star_expression(node) {
724
859
  if (ts.isYieldExpression(node)) return node.asteriskToken !== void 0;
725
860
  return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
726
861
  }
@@ -996,32 +1131,28 @@ function emit_replacement(candidate, kind, effect_context, helper_bindings, name
996
1131
  let helpers;
997
1132
  let relocation;
998
1133
  if (kind === "await") {
999
- const effect = make_effect_helper(normalized_candidate, helper_name);
1134
+ const effect = make_effect_helper(normalized_candidate, helper_name, helper_bindings);
1000
1135
  replacement_text = emit_promise_expression(id_text, effect, helper_bindings, "undefined", `{ ssr: "pending" }`);
1001
1136
  helpers = [...normalized.helpers, effect.helper];
1002
1137
  } else if (kind === "render") {
1003
- const effect = make_effect_helper(normalized_candidate, helper_name);
1138
+ const effect = make_effect_helper(normalized_candidate, helper_name, helper_bindings);
1004
1139
  replacement_text = emit_render_expression(id_text, effect, candidate, helper_bindings, is_server_target);
1005
1140
  helpers = [...normalized.helpers, effect.helper];
1006
1141
  } else if (kind === "render_argument") {
1007
- const effect = make_effect_helper(normalized_candidate, helper_name);
1142
+ const effect = make_effect_helper(normalized_candidate, helper_name, helper_bindings);
1008
1143
  replacement_text = emit_await_expression(id_text, effect, helper_bindings, server_fallback(is_server_target, "undefined"));
1009
1144
  helpers = [...normalized.helpers, effect.helper];
1010
1145
  } else if (kind === "each") {
1011
- const effect = make_effect_helper(normalized_candidate, helper_name);
1146
+ const effect = make_effect_helper(normalized_candidate, helper_name, helper_bindings);
1012
1147
  replacement_text = emit_await_expression(id_text, effect, helper_bindings, server_fallback(is_server_target, "[]"));
1013
1148
  helpers = [...normalized.helpers, effect.helper];
1014
1149
  } else if (kind === "event") {
1015
1150
  const event = make_event_handler(normalized_candidate, helper_bindings);
1016
1151
  replacement_text = event.text;
1017
1152
  helpers = normalized.helpers;
1018
- relocation = make_relocation(candidate, replacement_text, {
1019
- originalStart: 0,
1020
- originalEnd: candidate.expr_text.length,
1021
- generatedText: event.expr_text
1022
- });
1153
+ relocation = make_pending_relocation(candidate, replacement_text, event.expr_text, event.relocation);
1023
1154
  } else {
1024
- const effect = make_effect_helper(normalized_candidate, helper_name);
1155
+ const effect = make_effect_helper(normalized_candidate, helper_name, helper_bindings);
1025
1156
  replacement_text = emit_await_expression(id_text, effect, helper_bindings, server_fallback(is_server_target, "undefined"));
1026
1157
  helpers = [...normalized.helpers, effect.helper];
1027
1158
  }
@@ -1037,9 +1168,11 @@ function make_event_handler(candidate, helper_bindings) {
1037
1168
  const expr_text = candidate.expr_text;
1038
1169
  if (is_callback_function_expression(expr_text)) throw new YieldStarInEventCallbackError(candidate.filename, expr_text);
1039
1170
  if (analyze_event_body_yield_star(expr_text).has_nested_invalid_yield_star) throw new AsyncEffectInEventCallbackError(candidate.filename, expr_text);
1171
+ const wrapped_expr_text = wrap_yield_stars(expr_text, helper_bindings);
1040
1172
  return {
1041
- expr_text,
1042
- text: `(event) => { ${helper_bindings.dispatcher}.emit({ type: ${helper_bindings.codes}.Markup.Run, fn: function* () { ${expr_text}; } }); }`
1173
+ expr_text: wrapped_expr_text,
1174
+ relocation: make_yield_operand_relocation(expr_text, wrapped_expr_text, helper_bindings),
1175
+ text: `(event) => { ${helper_bindings.dispatcher}.emit({ type: ${helper_bindings.codes}.Markup.Run, fn: function* () { ${wrapped_expr_text}; } }); }`
1043
1176
  };
1044
1177
  }
1045
1178
  function emit_promise_expression(id_text, effect, helper_bindings, ssr_fallback, options) {
@@ -1064,41 +1197,91 @@ function emit_await_expression(id_text, effect, helper_bindings, ssr_fallback) {
1064
1197
  function server_fallback(is_server_target, fallback) {
1065
1198
  return is_server_target ? fallback : void 0;
1066
1199
  }
1067
- function make_effect_helper(candidate, helper_name) {
1200
+ function make_effect_helper(candidate, helper_name, helper_bindings) {
1068
1201
  const deps = collect_free_identifiers(candidate.expr_text);
1069
1202
  const args_text = deps.join(", ");
1070
1203
  const deps_text = deps.length === 0 ? "[]" : `[${args_text}]`;
1071
1204
  const call = `${helper_name}()`;
1072
- const text = `function* ${helper_name}() { return (${candidate.expr_text}); }`;
1073
- const generated_start = text.indexOf(candidate.expr_text);
1205
+ const effect_text = wrap_yield_stars(candidate.expr_text, helper_bindings);
1206
+ const text = `function* ${helper_name}() { return (${effect_text}); }`;
1207
+ const generated_start = text.indexOf(effect_text);
1208
+ const relocation = make_yield_operand_relocation(candidate.expr_text, effect_text, helper_bindings) ?? {
1209
+ originalStart: 0,
1210
+ originalEnd: candidate.expr_text.length,
1211
+ generatedStart: 0,
1212
+ generatedEnd: effect_text.length
1213
+ };
1074
1214
  return {
1075
1215
  call,
1076
1216
  deps_text,
1077
1217
  helper: {
1078
1218
  text,
1079
1219
  relocation: {
1080
- originalStart: candidate.start,
1081
- originalEnd: candidate.end,
1082
- generatedStartInReplacement: generated_start,
1083
- generatedEndInReplacement: generated_start + candidate.expr_text.length
1220
+ originalStart: candidate.start + relocation.originalStart,
1221
+ originalEnd: candidate.start + relocation.originalEnd,
1222
+ generatedStartInReplacement: generated_start + relocation.generatedStart,
1223
+ generatedEndInReplacement: generated_start + relocation.generatedEnd
1084
1224
  }
1085
1225
  }
1086
1226
  };
1087
1227
  }
1228
+ function wrap_yield_stars(text, helper_bindings) {
1229
+ const source_file = ts.createSourceFile("markup-yield.ts", text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
1230
+ const replacements = [];
1231
+ collect_yield_star_nodes(source_file, (node) => {
1232
+ const yield_text = text.slice(node.getStart(source_file), node.end).trim();
1233
+ replacements.push({
1234
+ start: node.getStart(source_file),
1235
+ end: node.end,
1236
+ text: `yield* ${helper_bindings.yieldable}(${strip_yield_star(yield_text)})`
1237
+ });
1238
+ });
1239
+ if (replacements.length === 0) return text;
1240
+ replacements.sort((a, b) => b.start - a.start);
1241
+ let output = text;
1242
+ for (const replacement of replacements) output = output.slice(0, replacement.start) + replacement.text + output.slice(replacement.end);
1243
+ return output;
1244
+ }
1245
+ function strip_yield_star(yield_text) {
1246
+ return yield_text.replace(/^yield\s*\*\s*/, "");
1247
+ }
1248
+ function make_yield_operand_relocation(original_text, generated_text, helper_bindings) {
1249
+ const source_file = ts.createSourceFile("markup-yield-relocation.ts", original_text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
1250
+ let yield_node;
1251
+ collect_yield_star_nodes(source_file, (node) => {
1252
+ yield_node ??= node;
1253
+ });
1254
+ if (!yield_node || !ts.isBinaryExpression(yield_node)) return;
1255
+ const operand = yield_node.right;
1256
+ const original_start = operand.getStart(source_file);
1257
+ const original_end = operand.end;
1258
+ const operand_text = original_text.slice(original_start, original_end).trim();
1259
+ const wrapper_text = `${helper_bindings.yieldable}(${operand_text})`;
1260
+ const wrapper_start = generated_text.indexOf(wrapper_text);
1261
+ if (wrapper_start === -1) return;
1262
+ const generated_start = wrapper_start + wrapper_text.indexOf(operand_text);
1263
+ return {
1264
+ originalStart: original_start,
1265
+ originalEnd: original_end,
1266
+ generatedStart: generated_start,
1267
+ generatedEnd: generated_start + operand_text.length
1268
+ };
1269
+ }
1088
1270
  function make_cache_id(candidate) {
1089
1271
  return `${candidate.filename.replace(/[?#].*$/, "")}:${candidate.start}:${candidate.end}`;
1090
1272
  }
1091
1273
  function make_helper_name(candidate, name_allocator) {
1092
1274
  return name_allocator.reserve(`__SER___markup_effect_${candidate.start}_${candidate.end}`);
1093
1275
  }
1094
- function make_relocation(candidate, replacement_text, inner) {
1095
- const generated_start = replacement_text.indexOf(inner.generatedText);
1276
+ function make_pending_relocation(candidate, replacement_text, expression_text, relocation) {
1277
+ if (!relocation) return;
1278
+ const generated_start = replacement_text.indexOf(expression_text);
1096
1279
  if (generated_start === -1) return;
1097
1280
  return {
1098
- originalStart: candidate.start + inner.originalStart,
1099
- originalEnd: candidate.start + inner.originalEnd,
1100
- generatedStartInReplacement: generated_start,
1101
- generatedEndInReplacement: generated_start + inner.generatedText.length
1281
+ originalStart: candidate.start + relocation.originalStart,
1282
+ originalEnd: candidate.start + relocation.originalEnd,
1283
+ generatedStartInReplacement: generated_start + relocation.generatedStart,
1284
+ generatedEndInReplacement: generated_start + relocation.generatedEnd
1102
1285
  };
1103
1286
  }
1104
1287
  //#endregion
@@ -1198,75 +1381,6 @@ function is_rune_root(name) {
1198
1381
  return name === "$bindable" || name === "$derived" || name === "$effect" || name === "$host" || name === "$inspect" || name === "$props" || name === "$state";
1199
1382
  }
1200
1383
  //#endregion
1201
- //#region src/script-transform/ast.ts
1202
- /**
1203
- * Checks whether a node is a `yield*` binary expression.
1204
- *
1205
- * @since 2.0.0
1206
- * @param node - TypeScript AST node to check.
1207
- * @returns Whether the node represents `yield * operand`.
1208
- */
1209
- function is_yield_star_expression(node) {
1210
- return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
1211
- }
1212
- /**
1213
- * Checks whether a node owns its own yield semantics.
1214
- *
1215
- * @since 2.0.0
1216
- * @param node - TypeScript AST node to check.
1217
- * @returns Whether traversal should stop at this function boundary.
1218
- */
1219
- function is_function_boundary_node(node) {
1220
- return ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
1221
- }
1222
- /**
1223
- * Returns `true` if the node tree contains a top-level `await`.
1224
- *
1225
- * @since 2.0.0
1226
- * @param node - Root node to search.
1227
- * @returns Whether a top-level await expression was found.
1228
- */
1229
- function contains_top_level_await(node) {
1230
- if (ts.isAwaitExpression(node)) return true;
1231
- return node.getChildren().some((child) => !is_function_boundary_node(child) && contains_top_level_await(child));
1232
- }
1233
- /**
1234
- * Collects top-level `yield*` nodes under an expression.
1235
- *
1236
- * @since 2.0.0
1237
- * @param node - Root node to search.
1238
- * @param on_found - Callback invoked for each matching yield node.
1239
- * @returns Nothing.
1240
- */
1241
- function collect_yield_star_nodes(node, on_found) {
1242
- if (is_function_boundary_node(node)) return;
1243
- if (is_yield_star_expression(node)) {
1244
- on_found(node);
1245
- return;
1246
- }
1247
- node.forEachChild((child) => {
1248
- collect_yield_star_nodes(child, on_found);
1249
- });
1250
- }
1251
- /**
1252
- * Finds the first top-level `yield*` expression below a node.
1253
- *
1254
- * @since 2.0.0
1255
- * @param node - Root node to search.
1256
- * @param on_found - Callback invoked with the first matching node.
1257
- * @returns Nothing.
1258
- */
1259
- function find_yield_star_node(node, on_found) {
1260
- if (is_function_boundary_node(node)) return;
1261
- if (is_yield_star_expression(node)) {
1262
- on_found(node);
1263
- return;
1264
- }
1265
- node.forEachChild((child) => {
1266
- find_yield_star_node(child, on_found);
1267
- });
1268
- }
1269
- //#endregion
1270
1384
  //#region src/markup/transform/scan.ts
1271
1385
  /**
1272
1386
  * Replaces markup `yield*` expressions with placeholders before Svelte parses
@@ -1290,26 +1404,13 @@ function find_yield_star_node(node, on_found) {
1290
1404
  */
1291
1405
  function sanitize_markup(content, filename) {
1292
1406
  const candidates = [];
1293
- const excluded_ranges = collect_excluded_ranges(content);
1407
+ const source_scan = scan_svelte_effect_source(content, filename);
1294
1408
  const magic = new MagicString(content);
1295
1409
  let helper_index = 0;
1296
- let cursor = 0;
1297
- while (cursor < content.length) {
1298
- const open = content.indexOf("{", cursor);
1299
- if (open === -1) break;
1300
- /** Skip braces inside <script> and <style> blocks. */
1301
- const excluded_range = find_excluded_range(excluded_ranges, open);
1302
- if (excluded_range) {
1303
- cursor = excluded_range.end;
1304
- continue;
1305
- }
1306
- /** Find the matching closing brace. */
1307
- const close = find_closing_brace(content, open + 1);
1308
- if (close === -1) {
1309
- cursor = open + 1;
1310
- continue;
1311
- }
1312
- const inner = content.slice(open + 1, close);
1410
+ for (const expression of source_scan.markup_expressions) {
1411
+ const open = expression.open;
1412
+ const close = expression.close;
1413
+ const inner = expression.inner;
1313
1414
  const trimmed = inner.trimStart();
1314
1415
  const leading_ws = inner.length - trimmed.length;
1315
1416
  const tag_info = get_tag_info(trimmed);
@@ -1328,16 +1429,12 @@ function sanitize_markup(content, filename) {
1328
1429
  });
1329
1430
  magic.overwrite(declaration_yield.start, declaration_yield.end, placeholder);
1330
1431
  }
1331
- cursor = close + 1;
1332
1432
  continue;
1333
1433
  }
1334
1434
  let expr_body = trimmed.slice(tag_info.prefix_length);
1335
1435
  /** For @const, only use the RHS after `=` as the expression body. */
1336
1436
  const equal_idx = tag_info.kind === "plain" && trimmed.startsWith("@const ") ? expr_body.indexOf("=") : -1;
1337
- if (!((is_event_callback_expression(inner) ? analyze_event_yield(inner) : void 0)?.has_top_level_yield_star ?? contains_yield_star_in_text(expr_body))) {
1338
- cursor = close + 1;
1339
- continue;
1340
- }
1437
+ if (!((is_event_callback_expression(inner) ? analyze_event_yield(inner) : void 0)?.has_top_level_yield_star ?? contains_yield_star_in_text(expr_body))) continue;
1341
1438
  /** The expression starts after the tag prefix. For @const, after the `=`. */
1342
1439
  let extra_prefix = 0;
1343
1440
  if (equal_idx !== -1) {
@@ -1360,10 +1457,7 @@ function sanitize_markup(content, filename) {
1360
1457
  if (boundary !== Infinity) expr_end = expr_start + boundary;
1361
1458
  }
1362
1459
  const expr_text = content.slice(expr_start, expr_end).trim();
1363
- if (expr_text.length === 0) {
1364
- cursor = close + 1;
1365
- continue;
1366
- }
1460
+ if (expr_text.length === 0) continue;
1367
1461
  validate_expression_yield_usage(expr_text, filename);
1368
1462
  if (key === "render" && !/^\s*yield\s*\*/.test(expr_text)) {
1369
1463
  const render_arg_yields = collect_expression_yield_expressions(content, expr_start, expr_text, filename);
@@ -1381,7 +1475,6 @@ function sanitize_markup(content, filename) {
1381
1475
  });
1382
1476
  magic.overwrite(render_arg_yield.start, render_arg_yield.end, placeholder);
1383
1477
  }
1384
- cursor = close + 1;
1385
1478
  continue;
1386
1479
  }
1387
1480
  }
@@ -1397,7 +1490,6 @@ function sanitize_markup(content, filename) {
1397
1490
  key
1398
1491
  });
1399
1492
  magic.overwrite(expr_start, expr_end, key === "render" ? `${placeholder}()` : placeholder);
1400
- cursor = close + 1;
1401
1493
  }
1402
1494
  return {
1403
1495
  code: magic.toString(),
@@ -1425,108 +1517,6 @@ function collect_expression_yield_expressions(content, expr_start, expr_text, fi
1425
1517
  });
1426
1518
  return expressions;
1427
1519
  }
1428
- function collect_excluded_ranges(content) {
1429
- const ranges = [
1430
- ...collect_tag_ranges(content, "script"),
1431
- ...collect_tag_ranges(content, "style"),
1432
- ...collect_html_comment_ranges(content)
1433
- ];
1434
- ranges.sort((a, b) => a.start - b.start);
1435
- return merge_ranges(ranges);
1436
- }
1437
- function collect_tag_ranges(content, tag) {
1438
- const pattern = new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)<\\/${tag}\\s*>`, "gi");
1439
- return [...content.matchAll(pattern)].flatMap((match) => {
1440
- if (match.index === void 0) return [];
1441
- return [{
1442
- start: match.index,
1443
- end: match.index + match[0].length
1444
- }];
1445
- });
1446
- }
1447
- function collect_html_comment_ranges(content) {
1448
- const ranges = [];
1449
- let cursor = 0;
1450
- while (cursor < content.length) {
1451
- const start = content.indexOf("<!--", cursor);
1452
- if (start === -1) break;
1453
- const close = content.indexOf("-->", start + 4);
1454
- const end = close === -1 ? content.length : close + 3;
1455
- ranges.push({
1456
- start,
1457
- end
1458
- });
1459
- cursor = end;
1460
- }
1461
- return ranges;
1462
- }
1463
- function merge_ranges(ranges) {
1464
- const merged = [];
1465
- for (const range of ranges) {
1466
- const previous = merged.at(-1);
1467
- if (!previous || range.start > previous.end) {
1468
- merged.push({ ...range });
1469
- continue;
1470
- }
1471
- previous.end = Math.max(previous.end, range.end);
1472
- }
1473
- return merged;
1474
- }
1475
- function find_excluded_range(ranges, pos) {
1476
- let low = 0;
1477
- let high = ranges.length - 1;
1478
- while (low <= high) {
1479
- const mid = Math.floor((low + high) / 2);
1480
- const range = ranges[mid];
1481
- if (pos <= range.start) {
1482
- high = mid - 1;
1483
- continue;
1484
- }
1485
- if (pos >= range.end) {
1486
- low = mid + 1;
1487
- continue;
1488
- }
1489
- return range;
1490
- }
1491
- }
1492
- /** Brace matching helpers for extracting complete markup expressions. */
1493
- function find_closing_brace(content, start) {
1494
- let depth = 0;
1495
- for (let i = start; i < content.length; i += 1) {
1496
- const ch = content[i];
1497
- if (ch === "{" && content[i - 1] !== "$") depth += 1;
1498
- else if (ch === "}") {
1499
- if (depth === 0) return i;
1500
- depth -= 1;
1501
- } else if (ch === "'" || ch === "\"" || ch === "`") {
1502
- i = skip_string(content, i, ch);
1503
- if (i === -1) return -1;
1504
- } else if (ch === "/" && content[i + 1] === "/") i = skip_line_comment(content, i);
1505
- else if (ch === "/" && content[i + 1] === "*") {
1506
- i = skip_block_comment(content, i);
1507
- if (i === -1) return -1;
1508
- }
1509
- }
1510
- return -1;
1511
- }
1512
- function skip_string(content, start, quote) {
1513
- for (let i = start + 1; i < content.length; i += 1) {
1514
- if (content[i] === "\\") {
1515
- i += 1;
1516
- continue;
1517
- }
1518
- if (content[i] === quote) return i;
1519
- }
1520
- return -1;
1521
- }
1522
- function skip_line_comment(content, start) {
1523
- for (let i = start + 2; i < content.length; i += 1) if (content[i] === "\n") return i;
1524
- return content.length;
1525
- }
1526
- function skip_block_comment(content, start) {
1527
- for (let i = start + 2; i < content.length; i += 1) if (content[i] === "*" && content[i + 1] === "/") return i + 1;
1528
- return -1;
1529
- }
1530
1520
  function get_tag_info(trimmed) {
1531
1521
  if (trimmed.startsWith("#each ")) return {
1532
1522
  kind: "each",
@@ -1541,6 +1531,10 @@ function get_tag_info(trimmed) {
1541
1531
  prefix_length: 8
1542
1532
  };
1543
1533
  /** Strip prefix-only tags — the expression starts after the tag keyword. */
1534
+ if (trimmed.startsWith("@attach ")) return {
1535
+ kind: "plain",
1536
+ prefix_length: 8
1537
+ };
1544
1538
  if (trimmed.startsWith("#if ")) return {
1545
1539
  kind: "plain",
1546
1540
  prefix_length: 4
@@ -1565,6 +1559,10 @@ function get_tag_info(trimmed) {
1565
1559
  kind: "plain",
1566
1560
  prefix_length: 7
1567
1561
  };
1562
+ if (trimmed.startsWith("...")) return {
1563
+ kind: "plain",
1564
+ prefix_length: 3
1565
+ };
1568
1566
  return {
1569
1567
  kind: "plain",
1570
1568
  prefix_length: 0
@@ -1687,6 +1685,6 @@ function transform_markup_effect(content, filename, options = {}) {
1687
1685
  };
1688
1686
  }
1689
1687
  //#endregion
1690
- export { is_yield_star_expression as a, slice as c, collect_top_level_binding_names as d, has_local_import_binding as f, find_yield_star_node as i, slice_start as l, collect_yield_star_nodes as n, validate_rune_yield_usage as o, make_imports as p, contains_top_level_await as r, create_source_map as s, transform_markup_effect as t, collect_free_identifiers as u };
1688
+ export { slice_start as a, contains_top_level_await as c, collect_top_level_binding_names as d, has_local_import_binding as f, slice as i, find_yield_star_node as l, validate_rune_yield_usage as n, collect_free_identifiers as o, make_imports as p, create_source_map as r, collect_yield_star_nodes as s, transform_markup_effect as t, is_yield_star_expression$1 as u };
1691
1689
 
1692
- //# sourceMappingURL=transform-CtQDGS9c.js.map
1690
+ //# sourceMappingURL=transform-jNUr65K9.js.map