svelte-effect-runtime 2.3.1 → 2.4.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 (45) hide show
  1. package/.dist/chunks/{client-LYwZZXy7.js → client-CtxuIuC8.js} +4 -5
  2. package/.dist/chunks/client-CtxuIuC8.js.map +1 -0
  3. package/.dist/chunks/{descriptors-CU2g4U_i.js → descriptors-OS4VfJuW.js} +1 -1
  4. package/.dist/chunks/{descriptors-CU2g4U_i.js.map → descriptors-OS4VfJuW.js.map} +1 -1
  5. package/.dist/chunks/{dispatcher-g0HYqHOK.js → dispatcher-8B6Ol80H.js} +1 -1
  6. package/.dist/chunks/{dispatcher-g0HYqHOK.js.map → dispatcher-8B6Ol80H.js.map} +1 -1
  7. package/.dist/chunks/{preprocess-33aQ41uE.js → preprocess-Cn4JH9OO.js} +36 -15
  8. package/.dist/chunks/preprocess-Cn4JH9OO.js.map +1 -0
  9. package/.dist/chunks/{transform-B4g76Ur4.js → transform-s9gKPYu5.js} +424 -29
  10. package/.dist/chunks/transform-s9gKPYu5.js.map +1 -0
  11. package/.dist/detect.js.map +1 -1
  12. package/.dist/dispatcher.js +1 -1
  13. package/.dist/internal/generators.js +1 -1
  14. package/.dist/internal/remote-client.js +1 -1
  15. package/.dist/markup/promise.js +1 -1
  16. package/.dist/markup/promise.js.map +1 -1
  17. package/.dist/markup/run.js +1 -1
  18. package/.dist/markup/run.js.map +1 -1
  19. package/.dist/markup/transform/constants.d.ts +3 -3
  20. package/.dist/markup/transform/effect-bindings.d.ts +41 -0
  21. package/.dist/markup/transform/effect-callbacks.d.ts +26 -0
  22. package/.dist/markup/transform/emit.d.ts +4 -1
  23. package/.dist/markup/transform.js +1 -1
  24. package/.dist/markup/value.js +1 -1
  25. package/.dist/markup/value.js.map +1 -1
  26. package/.dist/mod.js +1 -1
  27. package/.dist/mod.js.map +1 -1
  28. package/.dist/preprocess/imports.d.ts +2 -1
  29. package/.dist/preprocess.js +2 -2
  30. package/.dist/remote/client/types.d.ts +7 -7
  31. package/.dist/remote/client.js +1 -1
  32. package/.dist/remote/server.js.map +1 -1
  33. package/.dist/remote/shared.js.map +1 -1
  34. package/.dist/runtime/preprocess.js +2 -2
  35. package/.dist/runtime/preprocess.js.map +1 -1
  36. package/.dist/server/factories.d.ts +10 -1
  37. package/.dist/server/types.d.ts +10 -1
  38. package/.dist/server.js +1 -1
  39. package/.dist/server.js.map +1 -1
  40. package/.dist/vite.js +41 -6
  41. package/.dist/vite.js.map +1 -1
  42. package/package.json +6 -3
  43. package/.dist/chunks/client-LYwZZXy7.js.map +0 -1
  44. package/.dist/chunks/preprocess-33aQ41uE.js.map +0 -1
  45. package/.dist/chunks/transform-B4g76Ur4.js.map +0 -1
@@ -4,9 +4,9 @@ import MagicString from "magic-string";
4
4
  import ts from "typescript";
5
5
  //#region src/markup/transform/constants.ts
6
6
  const HELPERS = {
7
- value: "__ser_markup_value",
8
- promise: "__ser_markup_promise",
9
- run: "__ser_markup_run"
7
+ value: "__SER___markup_value",
8
+ promise: "__SER___markup_promise",
9
+ run: "__SER___markup_run"
10
10
  };
11
11
  //#endregion
12
12
  //#region src/markup/transform/apply.ts
@@ -24,11 +24,14 @@ function blank_script_blocks(content) {
24
24
  }
25
25
  function inject_helpers(magic, content, helpers = []) {
26
26
  if (content.includes(HELPERS.value)) return;
27
+ const import_helpers = unique_import_helpers(helpers);
28
+ const local_helpers = helpers.filter((helper) => !is_import_helper(helper));
27
29
  const helper_segments = [
28
30
  `import { value as ${HELPERS.value} } from "svelte-effect-runtime/internal/generators";`,
29
31
  `import { promise as ${HELPERS.promise} } from "svelte-effect-runtime/internal/generators";`,
30
32
  `import { run as ${HELPERS.run} } from "svelte-effect-runtime/internal/generators";`,
31
- ...helpers
33
+ ...import_helpers,
34
+ ...local_helpers
32
35
  ].map((helper) => typeof helper === "string" ? { text: helper } : helper);
33
36
  const helper_block = helper_segments.map((segment) => segment.text).join("\n");
34
37
  const script_tag = find_instance_script_tag(content);
@@ -105,6 +108,18 @@ function find_instance_script_tag(content) {
105
108
  };
106
109
  }
107
110
  }
111
+ function unique_import_helpers(helpers) {
112
+ const seen = /* @__PURE__ */ new Set();
113
+ return helpers.filter((helper) => {
114
+ if (!is_import_helper(helper)) return false;
115
+ if (seen.has(helper.text)) return false;
116
+ seen.add(helper.text);
117
+ return true;
118
+ });
119
+ }
120
+ function is_import_helper(helper) {
121
+ return helper.text.trimStart().startsWith("import ");
122
+ }
108
123
  //#endregion
109
124
  //#region src/markup/transform/classify.ts
110
125
  /**
@@ -254,6 +269,149 @@ function is_record(value) {
254
269
  return typeof value === "object" && value !== null;
255
270
  }
256
271
  //#endregion
272
+ //#region src/markup/transform/effect-bindings.ts
273
+ const EFFECT_PACKAGE_MODULE = "effect";
274
+ const EFFECT_DIRECT_MODULE = "effect/Effect";
275
+ const GENERATED_EFFECT_NAME = "__SER___Effect";
276
+ /**
277
+ * Collects Effect import bindings that markup callback rewriting can trust.
278
+ *
279
+ * @example
280
+ * ```ts
281
+ * const bindings = collect_effect_callback_bindings(
282
+ * `<script>import { Effect as E } from "effect";<\/script>`,
283
+ * );
284
+ * ```
285
+ *
286
+ * @since 2.4.0
287
+ * @param content - Full Svelte component source before markup lowering.
288
+ * @returns Binding metadata used to identify Effect callback combinators.
289
+ */
290
+ function collect_effect_callback_bindings(content) {
291
+ const state = make_effect_binding_state();
292
+ const scripts = collect_script_blocks(content);
293
+ for (const script of scripts) collect_source_file_bindings(ts.createSourceFile("component-script.ts", script, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS), state);
294
+ ensure_implicit_effect_binding(state);
295
+ const wrapper = choose_effect_wrapper(state);
296
+ return {
297
+ effect_object_names: new Set(state.effect_object_names),
298
+ effect_module_names: new Set(state.effect_module_names),
299
+ effect_package_names: new Set(state.effect_package_names),
300
+ direct_members: new Map(state.direct_members),
301
+ wrapper_expression: wrapper.expression,
302
+ wrapper_import: wrapper.import_text ? { text: wrapper.import_text } : void 0
303
+ };
304
+ }
305
+ function make_effect_binding_state() {
306
+ return {
307
+ effect_object_names: [],
308
+ effect_module_names: [],
309
+ effect_package_names: [],
310
+ direct_members: /* @__PURE__ */ new Map(),
311
+ local_names: /* @__PURE__ */ new Set(),
312
+ implicit_effect_import: false
313
+ };
314
+ }
315
+ function collect_script_blocks(content) {
316
+ return [...content.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script\s*>/gi)].map((match) => match[1] ?? "");
317
+ }
318
+ function collect_source_file_bindings(source_file, state) {
319
+ for (const statement of source_file.statements) collect_statement_binding(statement, state);
320
+ }
321
+ function collect_statement_binding(statement, state) {
322
+ if (ts.isImportDeclaration(statement)) {
323
+ collect_import_binding(statement, state);
324
+ return;
325
+ }
326
+ if (ts.isImportEqualsDeclaration(statement)) {
327
+ state.local_names.add(statement.name.text);
328
+ return;
329
+ }
330
+ if (ts.isVariableStatement(statement)) {
331
+ for (const declaration of statement.declarationList.declarations) collect_binding_name(declaration.name, state.local_names);
332
+ return;
333
+ }
334
+ if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isModuleDeclaration(statement)) {
335
+ if (statement.name) state.local_names.add(statement.name.text);
336
+ }
337
+ }
338
+ function collect_import_binding(statement, state) {
339
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) return;
340
+ const module_name = statement.moduleSpecifier.text;
341
+ const clause = statement.importClause;
342
+ if (!clause) return;
343
+ if (clause.name) state.local_names.add(clause.name.text);
344
+ const named_bindings = clause.namedBindings;
345
+ if (!named_bindings) return;
346
+ if (ts.isNamespaceImport(named_bindings)) {
347
+ collect_namespace_import_binding(module_name, named_bindings.name.text, state);
348
+ return;
349
+ }
350
+ for (const element of named_bindings.elements) collect_named_import_binding(module_name, element, state);
351
+ }
352
+ function collect_namespace_import_binding(module_name, local_name, state) {
353
+ state.local_names.add(local_name);
354
+ if (module_name === EFFECT_DIRECT_MODULE) {
355
+ add_ordered_name(state.effect_module_names, local_name);
356
+ return;
357
+ }
358
+ if (module_name === EFFECT_PACKAGE_MODULE) add_ordered_name(state.effect_package_names, local_name);
359
+ }
360
+ function collect_named_import_binding(module_name, element, state) {
361
+ const imported_name = element.propertyName?.text ?? element.name.text;
362
+ const local_name = element.name.text;
363
+ state.local_names.add(local_name);
364
+ if (module_name === EFFECT_PACKAGE_MODULE && imported_name === "Effect") {
365
+ add_ordered_name(state.effect_object_names, local_name);
366
+ return;
367
+ }
368
+ if (module_name === EFFECT_DIRECT_MODULE) state.direct_members.set(local_name, imported_name);
369
+ }
370
+ function collect_binding_name(name, local_names) {
371
+ if (ts.isIdentifier(name)) {
372
+ local_names.add(name.text);
373
+ return;
374
+ }
375
+ for (const element of name.elements) {
376
+ if (ts.isOmittedExpression(element)) continue;
377
+ collect_binding_name(element.name, local_names);
378
+ }
379
+ }
380
+ function ensure_implicit_effect_binding(state) {
381
+ if (has_effect_binding(state) || state.local_names.has("Effect")) return;
382
+ add_ordered_name(state.effect_object_names, "Effect");
383
+ state.implicit_effect_import = true;
384
+ }
385
+ function has_effect_binding(state) {
386
+ return state.effect_object_names.length > 0 || state.effect_module_names.length > 0 || state.effect_package_names.length > 0 || state.direct_members.size > 0;
387
+ }
388
+ function choose_effect_wrapper(state) {
389
+ const effect_object = state.effect_object_names[0];
390
+ if (effect_object) return {
391
+ expression: effect_object,
392
+ import_text: state.implicit_effect_import ? `import { Effect } from "effect";` : void 0
393
+ };
394
+ const effect_module = state.effect_module_names[0];
395
+ if (effect_module) return { expression: effect_module };
396
+ const effect_package = state.effect_package_names[0];
397
+ if (effect_package) return { expression: `${effect_package}.Effect` };
398
+ const generated_name = make_generated_effect_name(state.local_names);
399
+ return {
400
+ expression: generated_name,
401
+ import_text: `import { Effect as ${generated_name} } from "effect";`
402
+ };
403
+ }
404
+ function make_generated_effect_name(local_names) {
405
+ if (!local_names.has(GENERATED_EFFECT_NAME)) return GENERATED_EFFECT_NAME;
406
+ let index = 1;
407
+ while (local_names.has(`${GENERATED_EFFECT_NAME}_${index}`)) index += 1;
408
+ return `${GENERATED_EFFECT_NAME}_${index}`;
409
+ }
410
+ function add_ordered_name(names, name) {
411
+ if (names.includes(name)) return;
412
+ names.push(name);
413
+ }
414
+ //#endregion
257
415
  //#region src/error.ts
258
416
  /**
259
417
  * Formats a runtime-owned error message with a stable screaming-case code.
@@ -483,7 +641,7 @@ function strip_arrow_function(expr) {
483
641
  * @returns Whether the expression parses as an arrow or function expression.
484
642
  */
485
643
  function is_callback_function_expression(expr) {
486
- const wrapped = `const __ser_callback = ${expr};`;
644
+ const wrapped = `const __SER___callback = ${expr};`;
487
645
  const stmt = ts.createSourceFile("callback.ts", wrapped, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS).statements[0];
488
646
  if (!ts.isVariableStatement(stmt)) return false;
489
647
  const initializer = stmt.declarationList.declarations[0]?.initializer;
@@ -504,7 +662,7 @@ function is_callback_function_expression(expr) {
504
662
  * yield* appears inside a nested non-generator callback.
505
663
  */
506
664
  function analyze_event_body_yield_star(body) {
507
- const wrapped = `function* __ser_event() { ${body}; }`;
665
+ const wrapped = `function* __SER___event() { ${body}; }`;
508
666
  const stmt = ts.createSourceFile("event.ts", wrapped, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS).statements[0];
509
667
  if (!ts.isFunctionDeclaration(stmt) || !stmt.body) return {
510
668
  has_top_level_yield_star: false,
@@ -525,7 +683,7 @@ function analyze_event_body_yield_star(body) {
525
683
  * @returns Identifier names referenced by the expression.
526
684
  */
527
685
  function collect_free_identifiers(expr_text) {
528
- const wrapped = `function* __w() { return (${expr_text}); }`;
686
+ const wrapped = `function* __SER___w() { return (${expr_text}); }`;
529
687
  let sf;
530
688
  try {
531
689
  sf = ts.createSourceFile("expr.ts", wrapped, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
@@ -581,18 +739,249 @@ function is_property_access_name(node) {
581
739
  return ts.isPropertyAccessExpression(parent) && parent.name === node || ts.isPropertyAssignment(parent) && parent.name === node || ts.isBindingElement(parent) && parent.propertyName === node || ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent);
582
740
  }
583
741
  //#endregion
742
+ //#region src/markup/transform/effect-callbacks.ts
743
+ const MATCH_EFFECT_MEMBERS = new Map([["match", "matchEffect"], ["matchCause", "matchCauseEffect"]]);
744
+ const EFFECTFUL_CALLBACK_MEMBERS = new Set([
745
+ "andThen",
746
+ "catchAll",
747
+ "catchAllCause",
748
+ "catchCause",
749
+ "catchTag",
750
+ "flatMap",
751
+ "forEach",
752
+ "tap",
753
+ "tapError",
754
+ "tapErrorCause"
755
+ ]);
756
+ const EFFECTFUL_HANDLER_MEMBERS = new Set([
757
+ "matchCauseEffect",
758
+ "matchEffect",
759
+ "tapBoth"
760
+ ]);
761
+ /**
762
+ * Rewrites effectful callback shorthand inside event handler expressions.
763
+ *
764
+ * @example
765
+ * ```ts
766
+ * normalize_effect_callback_yields(
767
+ * `yield* action.pipe(Effect.flatMap((value) => yield* next(value)))`,
768
+ * collect_effect_callback_bindings(source),
769
+ * );
770
+ * ```
771
+ *
772
+ * @since 2.0.0
773
+ * @param expr_text - Markup expression text before it is wrapped in the
774
+ * generated Effect runner.
775
+ * @param bindings - Local Effect import bindings collected from the Svelte
776
+ * component's script blocks.
777
+ * @returns The expression with nested Effect callback `yield*` shorthand
778
+ * lowered into explicit Effect callbacks, plus any import needed by generated
779
+ * wrapper calls.
780
+ */
781
+ function normalize_effect_callback_yields(expr_text, bindings) {
782
+ const source_text = `const __SER___expression = ${expr_text};`;
783
+ const source_file = ts.createSourceFile("event-expression.ts", source_text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
784
+ const statement = source_file.statements[0];
785
+ const magic = new MagicString(expr_text);
786
+ const context = {
787
+ source_file,
788
+ source_text,
789
+ magic,
790
+ offset: 27,
791
+ bindings,
792
+ changed: false,
793
+ uses_wrapper: false
794
+ };
795
+ if (!ts.isVariableStatement(statement)) return {
796
+ expr_text,
797
+ helpers: []
798
+ };
799
+ const expression = statement.declarationList.declarations[0]?.initializer;
800
+ if (!expression) return {
801
+ expr_text,
802
+ helpers: []
803
+ };
804
+ visit_expression(expression, context);
805
+ if (!context.changed) return {
806
+ expr_text,
807
+ helpers: []
808
+ };
809
+ const helpers = context.uses_wrapper && bindings.wrapper_import ? [bindings.wrapper_import] : [];
810
+ return {
811
+ expr_text: magic.toString(),
812
+ helpers
813
+ };
814
+ }
815
+ function visit_expression(node, context) {
816
+ if (is_non_generator_callback_with_top_level_yield(node)) return;
817
+ if (ts.isCallExpression(node)) {
818
+ rewrite_match_call(node, context);
819
+ rewrite_effectful_handler_call(node, context);
820
+ rewrite_effectful_callback_arguments(node, context);
821
+ }
822
+ node.forEachChild((child) => {
823
+ visit_expression(child, context);
824
+ });
825
+ }
826
+ function rewrite_match_call(call, context) {
827
+ const member = get_effect_member(call.expression, context);
828
+ const upgraded_name = member && MATCH_EFFECT_MEMBERS.get(member.name);
829
+ const options = get_last_object_argument(call);
830
+ if (!member || !upgraded_name || !options) return;
831
+ const handlers = get_handler_properties(options);
832
+ if (!handlers.some((handler) => handler.callback && is_non_generator_callback_with_top_level_yield(handler.callback))) return;
833
+ rewrite_effect_member_name(member, upgraded_name, context);
834
+ context.changed = true;
835
+ for (const handler of handlers) {
836
+ if (!handler.callback) continue;
837
+ if (is_non_generator_callback_with_top_level_yield(handler.callback)) rewrite_callback_to_effect_gen(handler.callback, context);
838
+ else rewrite_callback_to_effect_sync(handler.callback, context);
839
+ }
840
+ }
841
+ function rewrite_effectful_handler_call(call, context) {
842
+ const member = get_effect_member(call.expression, context);
843
+ const options = get_last_object_argument(call);
844
+ if (!member || !EFFECTFUL_HANDLER_MEMBERS.has(member.name) || !options) return;
845
+ for (const handler of get_handler_properties(options)) if (handler.callback && is_non_generator_callback_with_top_level_yield(handler.callback)) rewrite_callback_to_effect_gen(handler.callback, context);
846
+ }
847
+ function rewrite_effectful_callback_arguments(call, context) {
848
+ const member = get_effect_member(call.expression, context);
849
+ if (!member || !EFFECTFUL_CALLBACK_MEMBERS.has(member.name)) return;
850
+ for (const argument of call.arguments) if (is_callback_expression(argument) && is_non_generator_callback_with_top_level_yield(argument)) rewrite_callback_to_effect_gen(argument, context);
851
+ }
852
+ function rewrite_callback_to_effect_gen(callback, context) {
853
+ if (is_async_function(callback)) return;
854
+ if (ts.isArrowFunction(callback)) {
855
+ rewrite_arrow_callback(callback, "gen", context);
856
+ return;
857
+ }
858
+ rewrite_function_body(callback, "gen", context);
859
+ }
860
+ function rewrite_callback_to_effect_sync(callback, context) {
861
+ if (is_async_function(callback)) return;
862
+ if (ts.isArrowFunction(callback)) {
863
+ rewrite_arrow_callback(callback, "sync", context);
864
+ return;
865
+ }
866
+ rewrite_function_body(callback, "sync", context);
867
+ }
868
+ function rewrite_arrow_callback(callback, wrapper, context) {
869
+ const start = to_expr_pos(callback.getStart(context.source_file), context);
870
+ const end = to_expr_pos(callback.end, context);
871
+ const params_text = context.source_text.slice(callback.getStart(context.source_file), callback.equalsGreaterThanToken.getStart(context.source_file)).trim();
872
+ const body_text = get_body_text(callback.body, context);
873
+ const replacement = `${params_text} => ${make_effect_body(callback.body, body_text, wrapper, context)}`;
874
+ context.magic.overwrite(start, end, replacement);
875
+ context.changed = true;
876
+ }
877
+ function rewrite_function_body(callback, wrapper, context) {
878
+ const body_start = to_expr_pos(callback.body.getStart(context.source_file), context);
879
+ const body_end = to_expr_pos(callback.body.end, context);
880
+ const body_text = get_body_text(callback.body, context);
881
+ const rewritten_body = make_effect_body(callback.body, body_text, wrapper, context);
882
+ context.magic.overwrite(body_start, body_end, `{ return ${rewritten_body}; }`);
883
+ context.changed = true;
884
+ }
885
+ function make_effect_body(body, body_text, wrapper, context) {
886
+ const wrapper_access = make_effect_access(wrapper, context);
887
+ if (wrapper === "gen") {
888
+ if (ts.isBlock(body)) return `${wrapper_access}(function* () ${body_text})`;
889
+ return `${wrapper_access}(function* () { return (${body_text}); })`;
890
+ }
891
+ if (ts.isBlock(body)) return `${wrapper_access}(() => ${body_text})`;
892
+ return `${wrapper_access}(() => (${body_text}))`;
893
+ }
894
+ function get_body_text(body, context) {
895
+ return context.source_text.slice(body.getStart(context.source_file), body.end).trim();
896
+ }
897
+ function get_handler_properties(object_literal) {
898
+ return object_literal.properties.flatMap((property) => {
899
+ if (!ts.isPropertyAssignment(property)) return [];
900
+ const name = get_property_name(property.name);
901
+ if (name !== "onFailure" && name !== "onSuccess") return [];
902
+ return [{ callback: is_callback_expression(property.initializer) ? property.initializer : void 0 }];
903
+ });
904
+ }
905
+ function get_last_object_argument(call) {
906
+ const last_argument = call.arguments[call.arguments.length - 1];
907
+ if (!last_argument || !ts.isObjectLiteralExpression(last_argument)) return;
908
+ return last_argument;
909
+ }
910
+ function get_effect_member(expression, context) {
911
+ if (ts.isIdentifier(expression)) {
912
+ const direct_member = context.bindings.direct_members.get(expression.text);
913
+ if (!direct_member) return;
914
+ return {
915
+ name: direct_member,
916
+ name_start: to_expr_pos(expression.getStart(context.source_file), context),
917
+ name_end: to_expr_pos(expression.end, context),
918
+ direct: true
919
+ };
920
+ }
921
+ if (!ts.isPropertyAccessExpression(expression)) return;
922
+ if (!is_effect_namespace_expression(expression.expression, context)) return;
923
+ return {
924
+ name: expression.name.text,
925
+ name_start: to_expr_pos(expression.name.getStart(context.source_file), context),
926
+ name_end: to_expr_pos(expression.name.end, context),
927
+ direct: false
928
+ };
929
+ }
930
+ function rewrite_effect_member_name(member, upgraded_name, context) {
931
+ if (member.direct) {
932
+ context.magic.overwrite(member.name_start, member.name_end, make_effect_access(upgraded_name, context));
933
+ return;
934
+ }
935
+ context.magic.overwrite(member.name_start, member.name_end, upgraded_name);
936
+ }
937
+ function make_effect_access(member_name, context) {
938
+ context.uses_wrapper = true;
939
+ return `${context.bindings.wrapper_expression}.${member_name}`;
940
+ }
941
+ function is_effect_namespace_expression(expression, context) {
942
+ if (ts.isIdentifier(expression)) return context.bindings.effect_object_names.has(expression.text) || context.bindings.effect_module_names.has(expression.text);
943
+ if (!ts.isPropertyAccessExpression(expression)) return false;
944
+ if (expression.name.text !== "Effect") return false;
945
+ if (!ts.isIdentifier(expression.expression)) return false;
946
+ return context.bindings.effect_package_names.has(expression.expression.text);
947
+ }
948
+ function get_property_name(name) {
949
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
950
+ }
951
+ function is_callback_expression(node) {
952
+ return ts.isArrowFunction(node) || ts.isFunctionExpression(node);
953
+ }
954
+ function is_non_generator_callback_with_top_level_yield(node) {
955
+ if (!is_callback_expression(node)) return false;
956
+ if (ts.isFunctionExpression(node) && node.asteriskToken) return false;
957
+ return contains_top_level_yield_star(node.body);
958
+ }
959
+ function is_async_function(node) {
960
+ return node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ?? false;
961
+ }
962
+ function to_expr_pos(pos, context) {
963
+ return pos - context.offset;
964
+ }
965
+ //#endregion
584
966
  //#region src/markup/transform/emit.ts
585
967
  /**
586
968
  * Emits source edits for classified markup Effect expressions.
587
969
  *
588
970
  * @since 2.0.0
589
971
  * @param classified - Candidates paired with their Svelte markup context.
972
+ * @param effect_context - Effect import bindings available to markup
973
+ * expression rewrites.
590
974
  * @returns Replacements ready to apply to the original component source.
591
975
  */
592
- function emit_replacements(classified) {
593
- return classified.map(({ candidate, kind }) => emit_replacement(candidate, kind));
976
+ function emit_replacements(classified, effect_context) {
977
+ return classified.map(({ candidate, kind }) => emit_replacement(candidate, kind, effect_context));
594
978
  }
595
- function emit_replacement(candidate, kind) {
979
+ function emit_replacement(candidate, kind, effect_context) {
980
+ const normalized = normalize_effect_callback_yields(candidate.expr_text, effect_context);
981
+ const normalized_candidate = {
982
+ ...candidate,
983
+ expr_text: normalized.expr_text
984
+ };
596
985
  const id = make_cache_id(candidate);
597
986
  const id_text = JSON.stringify(id);
598
987
  const helper_name = make_helper_name(candidate);
@@ -600,29 +989,30 @@ function emit_replacement(candidate, kind) {
600
989
  let helpers;
601
990
  let relocation;
602
991
  if (kind === "await") {
603
- const effect = make_effect_helper(candidate, helper_name);
992
+ const effect = make_effect_helper(normalized_candidate, helper_name);
604
993
  replacement_text = emit_promise_expression(id_text, effect);
605
- helpers = [effect.helper];
994
+ helpers = [...normalized.helpers, effect.helper];
606
995
  } else if (kind === "render") {
607
- const effect = make_effect_helper(candidate, helper_name);
996
+ const effect = make_effect_helper(normalized_candidate, helper_name);
608
997
  replacement_text = emit_render_expression(id_text, effect);
609
- helpers = [effect.helper];
998
+ helpers = [...normalized.helpers, effect.helper];
610
999
  } else if (kind === "each") {
611
- const effect = make_effect_helper(candidate, helper_name);
1000
+ const effect = make_effect_helper(normalized_candidate, helper_name);
612
1001
  replacement_text = emit_each_expression(id_text, effect);
613
- helpers = [effect.helper];
1002
+ helpers = [...normalized.helpers, effect.helper];
614
1003
  } else if (kind === "event") {
615
- replacement_text = make_event_handler(candidate).text;
616
- helpers = [];
1004
+ const event = make_event_handler(normalized_candidate);
1005
+ replacement_text = event.text;
1006
+ helpers = normalized.helpers;
617
1007
  relocation = make_relocation(candidate, replacement_text, {
618
1008
  originalStart: 0,
619
1009
  originalEnd: candidate.expr_text.length,
620
- generatedText: candidate.expr_text
1010
+ generatedText: event.expr_text
621
1011
  });
622
1012
  } else {
623
- const effect = make_effect_helper(candidate, helper_name);
1013
+ const effect = make_effect_helper(normalized_candidate, helper_name);
624
1014
  replacement_text = emit_each_expression(id_text, effect);
625
- helpers = [effect.helper];
1015
+ helpers = [...normalized.helpers, effect.helper];
626
1016
  }
627
1017
  return {
628
1018
  start: candidate.start,
@@ -633,9 +1023,13 @@ function emit_replacement(candidate, kind) {
633
1023
  };
634
1024
  }
635
1025
  function make_event_handler(candidate) {
636
- if (is_callback_function_expression(candidate.expr_text)) throw new YieldStarInEventCallbackError(candidate.filename, candidate.expr_text);
637
- if (analyze_event_body_yield_star(candidate.expr_text).has_nested_invalid_yield_star) throw new AsyncEffectInEventCallbackError(candidate.filename, candidate.expr_text);
638
- return { text: `(event) => { void ${HELPERS.run}(function* () { ${candidate.expr_text}; }); }` };
1026
+ const expr_text = candidate.expr_text;
1027
+ if (is_callback_function_expression(expr_text)) throw new YieldStarInEventCallbackError(candidate.filename, expr_text);
1028
+ if (analyze_event_body_yield_star(expr_text).has_nested_invalid_yield_star) throw new AsyncEffectInEventCallbackError(candidate.filename, expr_text);
1029
+ return {
1030
+ expr_text,
1031
+ text: `(event) => { ${HELPERS.run}(function* () { ${expr_text}; }); }`
1032
+ };
639
1033
  }
640
1034
  function emit_promise_expression(id_text, effect) {
641
1035
  return `${HELPERS.promise}(${id_text}, ${effect.deps_text}, () => ${effect.call})`;
@@ -672,7 +1066,7 @@ function make_cache_id(candidate) {
672
1066
  return `${candidate.filename}:${candidate.start}:${candidate.end}`;
673
1067
  }
674
1068
  function make_helper_name(candidate) {
675
- return `__ser_markup_effect_${candidate.start}_${candidate.end}`;
1069
+ return `__SER___markup_effect_${candidate.start}_${candidate.end}`;
676
1070
  }
677
1071
  function make_relocation(candidate, replacement_text, inner) {
678
1072
  const generated_start = replacement_text.indexOf(inner.generatedText);
@@ -797,7 +1191,7 @@ function sanitize_markup(content, filename) {
797
1191
  const declaration_yields = collect_declaration_yield_expressions(content, open, leading_ws, trimmed);
798
1192
  if (declaration_yields.length > 0) {
799
1193
  for (const declaration_yield of declaration_yields) {
800
- const placeholder = `__ser_markup_placeholder_${helper_index}`;
1194
+ const placeholder = `__SER___markup_placeholder_${helper_index}`;
801
1195
  helper_index += 1;
802
1196
  candidates.push({
803
1197
  placeholder,
@@ -846,7 +1240,7 @@ function sanitize_markup(content, filename) {
846
1240
  continue;
847
1241
  }
848
1242
  /** Create a placeholder and replace the expression (preserving tag prefixes). */
849
- const placeholder = `__ser_markup_placeholder_${helper_index}`;
1243
+ const placeholder = `__SER___markup_placeholder_${helper_index}`;
850
1244
  helper_index += 1;
851
1245
  candidates.push({
852
1246
  placeholder,
@@ -1034,6 +1428,7 @@ function transform_markup_effect(content, filename) {
1034
1428
  };
1035
1429
  /** Find all brace expressions containing yield* and replace with placeholders. */
1036
1430
  const work = sanitize_markup(content, filename);
1431
+ const effect_context = collect_effect_callback_bindings(content);
1037
1432
  if (work.candidates.length === 0) return {
1038
1433
  code: content,
1039
1434
  has_yield: false
@@ -1041,7 +1436,7 @@ function transform_markup_effect(content, filename) {
1041
1436
  const replacements = emit_replacements(classify_candidates(parse(blank_script_blocks(work.code), {
1042
1437
  filename,
1043
1438
  modern: true
1044
- }), work.candidates));
1439
+ }), work.candidates), effect_context);
1045
1440
  const helpers = replacements.flatMap((replacement) => replacement.helpers ?? []);
1046
1441
  const magic = new MagicString(content);
1047
1442
  replacements.sort((a, b) => b.start - a.start);
@@ -1057,4 +1452,4 @@ function transform_markup_effect(content, filename) {
1057
1452
  //#endregion
1058
1453
  export { find_yield_star_node as a, AsyncEffectInSyncRuneError as c, extract_binding_names as i, AwaitInEffectWorkError as l, collect_yield_star_nodes as n, is_yield_star_expression as o, contains_top_level_await as r, collect_free_identifiers as s, transform_markup_effect as t };
1059
1454
 
1060
- //# sourceMappingURL=transform-B4g76Ur4.js.map
1455
+ //# sourceMappingURL=transform-s9gKPYu5.js.map