svelte-effect-runtime 2.0.1 → 2.1.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 (37) hide show
  1. package/.dist/chunks/{client-BeOE81fW.js → client-zavjI3Qd.js} +9 -9
  2. package/.dist/chunks/client-zavjI3Qd.js.map +1 -0
  3. package/.dist/chunks/{dispatcher-BSg2-ttN.js → dispatcher-g0HYqHOK.js} +3 -3
  4. package/.dist/chunks/{dispatcher-BSg2-ttN.js.map → dispatcher-g0HYqHOK.js.map} +1 -1
  5. package/.dist/chunks/{preprocess-BZyUYWY7.js → preprocess-33aQ41uE.js} +185 -156
  6. package/.dist/chunks/preprocess-33aQ41uE.js.map +1 -0
  7. package/.dist/chunks/{transform-BtlxgJrg.js → transform-B4g76Ur4.js} +337 -113
  8. package/.dist/chunks/transform-B4g76Ur4.js.map +1 -0
  9. package/.dist/dispatcher.js +1 -1
  10. package/.dist/error.d.ts +54 -14
  11. package/.dist/internal/generators.js +1 -1
  12. package/.dist/internal/remote-client.js +1 -1
  13. package/.dist/markup/promise.js +1 -1
  14. package/.dist/markup/run.js +1 -1
  15. package/.dist/markup/transform/expressions.d.ts +8 -0
  16. package/.dist/markup/transform.js +1 -1
  17. package/.dist/markup/value.js +1 -1
  18. package/.dist/mod.d.ts +1 -1
  19. package/.dist/mod.js +2 -2
  20. package/.dist/mod.js.map +1 -1
  21. package/.dist/preprocess/imports.d.ts +1 -2
  22. package/.dist/preprocess/index.d.ts +1 -1
  23. package/.dist/preprocess/lower.d.ts +1 -1
  24. package/.dist/preprocess/runes.d.ts +24 -0
  25. package/.dist/preprocess/runtime-block.d.ts +5 -4
  26. package/.dist/preprocess/types.d.ts +15 -3
  27. package/.dist/preprocess.js +2 -2
  28. package/.dist/remote/client.js +1 -1
  29. package/.dist/remote/server.js +3 -3
  30. package/.dist/remote/server.js.map +1 -1
  31. package/.dist/runtime/preprocess.js +2 -2
  32. package/.dist/server.js +8 -8
  33. package/.dist/server.js.map +1 -1
  34. package/package.json +1 -1
  35. package/.dist/chunks/client-BeOE81fW.js.map +0 -1
  36. package/.dist/chunks/preprocess-BZyUYWY7.js.map +0 -1
  37. package/.dist/chunks/transform-BtlxgJrg.js.map +0 -1
@@ -196,7 +196,7 @@ function classify_declaration_tag(node, candidates, matched, classified) {
196
196
  }
197
197
  function visit_element_attributes(node, candidates, matched, classified) {
198
198
  for (const attr of node.attributes) {
199
- if (attr.type === "Attribute" && attr.name && (attr.name.startsWith("on:") || /^on[a-z]/.test(attr.name))) {
199
+ if (attr.type === "Attribute" && attr.name && is_event_attribute_name(attr.name)) {
200
200
  visit_attribute_value(attr.value, "event", candidates, matched, classified);
201
201
  continue;
202
202
  }
@@ -206,6 +206,9 @@ function visit_element_attributes(node, candidates, matched, classified) {
206
206
  }
207
207
  }
208
208
  }
209
+ function is_event_attribute_name(name) {
210
+ return name.startsWith("on:") || /^on[a-z]/.test(name);
211
+ }
209
212
  function visit_attribute_value(value, kind, candidates, matched, classified) {
210
213
  if (value === true) return;
211
214
  if (Array.isArray(value)) {
@@ -216,19 +219,219 @@ function visit_attribute_value(value, kind, candidates, matched, classified) {
216
219
  }
217
220
  function classify_expression(expression, kind, candidates, matched, classified) {
218
221
  if (!expression) return;
219
- const candidate = find_candidate(expression, candidates);
220
- if (!candidate || matched.has(candidate.placeholder)) return;
221
- matched.add(candidate.placeholder);
222
- classified.push({
223
- candidate,
224
- kind
225
- });
222
+ const found_candidates = find_candidates(expression, candidates);
223
+ for (const candidate of found_candidates) {
224
+ if (matched.has(candidate.placeholder)) continue;
225
+ matched.add(candidate.placeholder);
226
+ classified.push({
227
+ candidate,
228
+ kind
229
+ });
230
+ }
226
231
  }
227
- function find_candidate(expression, candidates) {
228
- if (expression.type === "Identifier" && expression.name) return candidates.get(expression.name);
229
- if (expression.type === "CallExpression" && expression.callee?.type === "Identifier" && expression.callee.name) return candidates.get(expression.callee.name);
232
+ function find_candidates(expression, candidates) {
233
+ const found = [];
234
+ visit_expression_value(expression, candidates, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), found);
235
+ return found;
236
+ }
237
+ function visit_expression_value(value, candidates, seen_nodes, seen_placeholders, found) {
238
+ if (Array.isArray(value)) {
239
+ for (const item of value) visit_expression_value(item, candidates, seen_nodes, seen_placeholders, found);
240
+ return;
241
+ }
242
+ if (!is_record(value) || seen_nodes.has(value)) return;
243
+ seen_nodes.add(value);
244
+ if (value.type === "Identifier" && typeof value.name === "string") {
245
+ const candidate = candidates.get(value.name);
246
+ if (candidate && !seen_placeholders.has(candidate.placeholder)) {
247
+ seen_placeholders.add(candidate.placeholder);
248
+ found.push(candidate);
249
+ }
250
+ }
251
+ for (const child of Object.values(value)) visit_expression_value(child, candidates, seen_nodes, seen_placeholders, found);
252
+ }
253
+ function is_record(value) {
254
+ return typeof value === "object" && value !== null;
230
255
  }
231
256
  //#endregion
257
+ //#region src/error.ts
258
+ /**
259
+ * Formats a runtime-owned error message with a stable screaming-case code.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * throw new Error(make_error_message("DISPATCHER_DISPOSED", "Dispatcher has been disposed"));
264
+ * ```
265
+ *
266
+ * @since 2.0.0
267
+ * @param code - Stable screaming-case identifier for the error category.
268
+ * @param message - Human-readable error message without the leading code.
269
+ * @returns The complete error message prefixed with the stable code.
270
+ */
271
+ function make_error_message(code, message) {
272
+ return `[${code}]: ${message}`;
273
+ }
274
+ /**
275
+ * Base error class for all preprocessor errors emitted during script and
276
+ * markup transformation. Carries the source filename so error messages can
277
+ * reference the affected file.
278
+ *
279
+ * @since 2.0.0
280
+ */
281
+ var PreprocessError = class extends Error {
282
+ /**
283
+ * The source filename that triggered this error.
284
+ *
285
+ * @since 2.0.0
286
+ */
287
+ filename;
288
+ constructor(message, filename) {
289
+ super(message);
290
+ this.name = "PreprocessError";
291
+ this.filename = filename;
292
+ }
293
+ };
294
+ /**
295
+ * Thrown when a statement mixes JavaScript `await` with Effect `yield*` work
296
+ * that must be lowered into an `Effect.gen` program.
297
+ *
298
+ * @since 2.0.0
299
+ */
300
+ var AwaitInEffectWorkError = class extends PreprocessError {
301
+ /**
302
+ * The full text of the problematic statement containing mixed async work.
303
+ *
304
+ * @since 2.0.0
305
+ */
306
+ statement_text;
307
+ constructor(filename, statement_text) {
308
+ super([
309
+ make_error_message("AWAIT_IN_EFFECT_WORK", `${filename}: await cannot be mixed with yield* in Effect work.`),
310
+ `Top-level await is supported as ordinary Svelte async rendering, but statements lowered into Effect.gen must use yield* for async Effect work.`,
311
+ "",
312
+ `Problematic statement:`,
313
+ statement_text
314
+ ].join("\n"), filename);
315
+ this.name = "AwaitInEffectWorkError";
316
+ this.statement_text = statement_text;
317
+ }
318
+ };
319
+ /**
320
+ * Thrown when async Effect work appears inside a Svelte rune position that
321
+ * must stay synchronous.
322
+ *
323
+ * @since 2.0.0
324
+ */
325
+ var AsyncEffectInSyncRuneError = class extends PreprocessError {
326
+ /**
327
+ * The name of the rune that contained async Effect work.
328
+ *
329
+ * @since 2.0.0
330
+ */
331
+ rune_name;
332
+ /**
333
+ * The full text of the expression that triggered the error.
334
+ *
335
+ * @since 2.0.0
336
+ */
337
+ expression_text;
338
+ constructor(rune_name, expression_text, filename) {
339
+ super([
340
+ make_error_message("ASYNC_EFFECT_IN_SYNC_RUNE", `${filename}: yield* cannot be used inside ${rune_name}().`),
341
+ `${rune_name}() must stay synchronous. Do not put async Effect work inside this rune.`,
342
+ "",
343
+ `Problematic expression:`,
344
+ expression_text
345
+ ].join("\n"), filename);
346
+ this.name = "AsyncEffectInSyncRuneError";
347
+ this.rune_name = rune_name;
348
+ this.expression_text = expression_text;
349
+ }
350
+ };
351
+ /**
352
+ * Thrown when async Effect work appears inside a non-generator callback nested
353
+ * in a markup event handler.
354
+ *
355
+ * @example
356
+ * ```ts
357
+ * throw new AsyncEffectInEventCallbackError(
358
+ * "Component.svelte",
359
+ * "Effect.try(() => yield* save())",
360
+ * );
361
+ * ```
362
+ *
363
+ * @since 2.0.0
364
+ */
365
+ var AsyncEffectInEventCallbackError = class extends PreprocessError {
366
+ /**
367
+ * The full text of the problematic event handler body.
368
+ *
369
+ * @since 2.0.0
370
+ */
371
+ expression_text;
372
+ constructor(filename, expression_text) {
373
+ super([
374
+ make_error_message("ASYNC_EFFECT_IN_EVENT_CALLBACK", `${filename}: yield* cannot be used inside a nested non-generator callback in a markup event handler.`),
375
+ `Move the yield* to the event handler body. Effect.try and Effect.sync callbacks are plain synchronous JavaScript; do not call Effect-returning functions inside them.`,
376
+ "",
377
+ `Run the remote Effect directly:`,
378
+ ` onclick={yield* UpvotePost(id)}`,
379
+ "",
380
+ `Recover from remote failures by composing the Effect value:`,
381
+ ` onclick={yield* UpvotePost(id).pipe(Effect.catch(() => Effect.void))}`,
382
+ "",
383
+ `Problematic expression:`,
384
+ expression_text
385
+ ].join("\n"), filename);
386
+ this.name = "AsyncEffectInEventCallbackError";
387
+ this.expression_text = expression_text;
388
+ }
389
+ };
390
+ /**
391
+ * Thrown when an event handler callback contains the old raw `yield*`
392
+ * shorthand. Effectful event handlers must put `yield*` directly in the event
393
+ * attribute so the callback boundary is generated by the markup runtime.
394
+ *
395
+ * @example
396
+ * ```ts
397
+ * throw new YieldStarInEventCallbackError(
398
+ * "Component.svelte",
399
+ * "() => yield* save()",
400
+ * );
401
+ * ```
402
+ *
403
+ * @since 2.0.0
404
+ * @param filename - Svelte component filename used to identify where the
405
+ * invalid event handler callback was found.
406
+ * @param expression_text - Original event handler callback text that contained
407
+ * `yield*` and should be rewritten as a direct event Effect expression.
408
+ */
409
+ var YieldStarInEventCallbackError = class extends PreprocessError {
410
+ /**
411
+ * The full text of the problematic event handler callback.
412
+ *
413
+ * @since 2.0.0
414
+ */
415
+ expression_text;
416
+ constructor(filename, expression_text) {
417
+ super([
418
+ make_error_message("ASYNC_EFFECT_IN_EVENT_HANDLER_CALLBACK", `${filename}: yield* in markup event handlers must be written directly as the event attribute value.`),
419
+ `SER generates the event callback for effectful event handlers; do not put yield* inside a JavaScript callback.`,
420
+ "",
421
+ `Use this form:`,
422
+ ` onclick={yield* UpvotePost(id)}`,
423
+ "",
424
+ `Instead of this form:`,
425
+ ` onclick={() => yield* UpvotePost(id)}`,
426
+ "",
427
+ `Problematic expression:`,
428
+ expression_text
429
+ ].join("\n"), filename);
430
+ this.name = "YieldStarInEventCallbackError";
431
+ this.expression_text = expression_text;
432
+ }
433
+ };
434
+ //#endregion
232
435
  //#region src/markup/transform/expressions.ts
233
436
  /**
234
437
  * Strips an event handler arrow function down to its executable body.
@@ -273,6 +476,20 @@ function strip_arrow_function(expr) {
273
476
  };
274
477
  }
275
478
  /**
479
+ * Returns whether an expression is a callback function.
480
+ *
481
+ * @since 2.0.0
482
+ * @param expr - Expression text from a markup attribute or expression tag.
483
+ * @returns Whether the expression parses as an arrow or function expression.
484
+ */
485
+ function is_callback_function_expression(expr) {
486
+ const wrapped = `const __ser_callback = ${expr};`;
487
+ const stmt = ts.createSourceFile("callback.ts", wrapped, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS).statements[0];
488
+ if (!ts.isVariableStatement(stmt)) return false;
489
+ const initializer = stmt.declarationList.declarations[0]?.initializer;
490
+ return initializer !== void 0 && (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer));
491
+ }
492
+ /**
276
493
  * Classifies `yield*` placement inside an event handler body.
277
494
  *
278
495
  * @example
@@ -336,7 +553,7 @@ function visit_ids(node, seen, ids) {
336
553
  node.forEachChild((child) => visit_ids(child, seen, ids));
337
554
  }
338
555
  function visit_event_body(node, context, result) {
339
- if (is_yield_star_expression(node)) {
556
+ if (is_yield_star_expression$1(node)) {
340
557
  if (context === "top_level") result.has_top_level_yield_star = true;
341
558
  else if (context === "nested_invalid") result.has_nested_invalid_yield_star = true;
342
559
  node.forEachChild((child) => visit_event_body(child, context, result));
@@ -355,7 +572,7 @@ function is_nested_function_boundary(node) {
355
572
  function is_generator_function_boundary(node) {
356
573
  return (ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) && node.asteriskToken !== void 0;
357
574
  }
358
- function is_yield_star_expression(node) {
575
+ function is_yield_star_expression$1(node) {
359
576
  if (ts.isYieldExpression(node)) return node.asteriskToken !== void 0;
360
577
  return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
361
578
  }
@@ -395,13 +612,12 @@ function emit_replacement(candidate, kind) {
395
612
  replacement_text = emit_each_expression(id_text, effect);
396
613
  helpers = [effect.helper];
397
614
  } else if (kind === "event") {
398
- const event = strip_arrow_function(candidate.expr_text);
399
- replacement_text = `${event.params} => { void ${HELPERS.run}(function* () { ${event.body}; }); }`;
615
+ replacement_text = make_event_handler(candidate).text;
400
616
  helpers = [];
401
617
  relocation = make_relocation(candidate, replacement_text, {
402
- originalStart: event.body_start,
403
- originalEnd: event.body_end,
404
- generatedText: event.body
618
+ originalStart: 0,
619
+ originalEnd: candidate.expr_text.length,
620
+ generatedText: candidate.expr_text
405
621
  });
406
622
  } else {
407
623
  const effect = make_effect_helper(candidate, helper_name);
@@ -416,6 +632,11 @@ function emit_replacement(candidate, kind) {
416
632
  relocation
417
633
  };
418
634
  }
635
+ 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}; }); }` };
639
+ }
419
640
  function emit_promise_expression(id_text, effect) {
420
641
  return `${HELPERS.promise}(${id_text}, ${effect.deps_text}, () => ${effect.call})`;
421
642
  }
@@ -464,92 +685,90 @@ function make_relocation(candidate, replacement_text, inner) {
464
685
  };
465
686
  }
466
687
  //#endregion
467
- //#region src/error.ts
688
+ //#region src/preprocess/ast.ts
468
689
  /**
469
- * Base error class for all preprocessor errors emitted during script and
470
- * markup transformation. Carries the source filename so error messages can
471
- * reference the affected file.
690
+ * Checks whether a node is a `yield*` binary expression.
472
691
  *
473
692
  * @since 2.0.0
693
+ * @param node - TypeScript AST node to check.
694
+ * @returns Whether the node represents `yield * operand`.
474
695
  */
475
- var PreprocessError = class extends Error {
476
- /**
477
- * The source filename that triggered this error.
478
- *
479
- * @since 2.0.0
480
- */
481
- filename;
482
- constructor(message, filename) {
483
- super(message);
484
- this.name = "PreprocessError";
485
- this.filename = filename;
486
- }
487
- };
696
+ function is_yield_star_expression(node) {
697
+ return ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AsteriskToken && ts.isIdentifier(node.left) && node.left.text === "yield";
698
+ }
488
699
  /**
489
- * Thrown when `await` is used at the top level of a `<script effect>` block.
490
- * Top-level `await` is not supported — users should use
491
- * `yield* Effect.promise(...)` or `yield* Effect.tryPromise(...)` instead.
700
+ * Checks whether a node owns its own yield semantics.
492
701
  *
493
702
  * @since 2.0.0
703
+ * @param node - TypeScript AST node to check.
704
+ * @returns Whether traversal should stop at this function boundary.
494
705
  */
495
- var TopLevelAwaitError = class extends PreprocessError {
496
- /**
497
- * The full text of the problematic statement containing the `await`.
498
- *
499
- * @since 2.0.0
500
- */
501
- statement_text;
502
- constructor(filename, statement_text) {
503
- super([
504
- `${filename}: top-level await is not supported in <script effect>.`,
505
- `Use yield* Effect.promise(...) or yield* Effect.tryPromise(...) instead.`,
506
- "",
507
- `Problematic statement:`,
508
- statement_text
509
- ].join("\n"), filename);
510
- this.name = "TopLevelAwaitError";
511
- this.statement_text = statement_text;
706
+ function is_function_boundary_node(node) {
707
+ return ts.isArrowFunction(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
708
+ }
709
+ /**
710
+ * Returns `true` if the node tree contains a top-level `await`.
711
+ *
712
+ * @since 2.0.0
713
+ * @param node - Root node to search.
714
+ * @returns Whether a top-level await expression was found.
715
+ */
716
+ function contains_top_level_await(node) {
717
+ if (ts.isAwaitExpression(node)) return true;
718
+ return node.getChildren().some((child) => !is_function_boundary_node(child) && contains_top_level_await(child));
719
+ }
720
+ /**
721
+ * Collects top-level `yield*` nodes under an expression.
722
+ *
723
+ * @since 2.0.0
724
+ * @param node - Root node to search.
725
+ * @param on_found - Callback invoked for each matching yield node.
726
+ * @returns Nothing.
727
+ */
728
+ function collect_yield_star_nodes(node, on_found) {
729
+ if (is_function_boundary_node(node)) return;
730
+ if (is_yield_star_expression(node)) {
731
+ on_found(node);
732
+ return;
512
733
  }
513
- };
734
+ node.forEachChild((child) => {
735
+ collect_yield_star_nodes(child, on_found);
736
+ });
737
+ }
514
738
  /**
515
- * Thrown when an event handler contains `yield*` inside a nested callback that
516
- * is not itself a generator function.
739
+ * Finds the first top-level `yield*` expression below a node.
517
740
  *
518
- * @example
519
- * ```ts
520
- * throw new NestedYieldStarInEventHandlerError(
521
- * "Component.svelte",
522
- * "Effect.try(() => yield* save())",
523
- * );
524
- * ```
741
+ * @since 2.0.0
742
+ * @param node - Root node to search.
743
+ * @param on_found - Callback invoked with the first matching node.
744
+ * @returns Nothing.
745
+ */
746
+ function find_yield_star_node(node, on_found) {
747
+ if (is_function_boundary_node(node)) return;
748
+ if (is_yield_star_expression(node)) {
749
+ on_found(node);
750
+ return;
751
+ }
752
+ node.forEachChild((child) => {
753
+ find_yield_star_node(child, on_found);
754
+ });
755
+ }
756
+ /**
757
+ * Extracts identifier names from a TypeScript binding name.
525
758
  *
526
759
  * @since 2.0.0
760
+ * @param name - Binding name node to flatten.
761
+ * @returns Identifier names from identifiers and destructuring patterns.
527
762
  */
528
- var NestedYieldStarInEventHandlerError = class extends PreprocessError {
529
- /**
530
- * The full text of the problematic event handler body.
531
- *
532
- * @since 2.0.0
533
- */
534
- expression_text;
535
- constructor(filename, expression_text) {
536
- super([
537
- `${filename}: yield* cannot be used inside a nested non-generator callback in a markup event handler.`,
538
- `Move the yield* to the event handler body. Effect.try and Effect.sync callbacks are plain synchronous JavaScript; do not call Effect-returning functions inside them.`,
539
- "",
540
- `Run the remote Effect directly:`,
541
- ` onclick={() => yield* UpvotePost(id)}`,
542
- "",
543
- `Recover from remote failures by composing the Effect value:`,
544
- ` onclick={() => yield* UpvotePost(id).pipe(Effect.catch(() => Effect.void))}`,
545
- "",
546
- `Problematic expression:`,
547
- expression_text
548
- ].join("\n"), filename);
549
- this.name = "NestedYieldStarInEventHandlerError";
550
- this.expression_text = expression_text;
763
+ function extract_binding_names(name) {
764
+ if (ts.isIdentifier(name)) return [name.text];
765
+ const result = [];
766
+ for (const element of name.elements) {
767
+ if (ts.isOmittedExpression(element)) continue;
768
+ result.push(...extract_binding_names(element.name));
551
769
  }
552
- };
770
+ return result;
771
+ }
553
772
  //#endregion
554
773
  //#region src/markup/transform/scan.ts
555
774
  function sanitize_markup(content, filename) {
@@ -575,20 +794,20 @@ function sanitize_markup(content, filename) {
575
794
  const trimmed = inner.trimStart();
576
795
  const leading_ws = inner.length - trimmed.length;
577
796
  const tag_info = get_tag_info(trimmed);
578
- const declaration_initializers = collect_declaration_initializers(content, open, leading_ws, trimmed);
579
- if (declaration_initializers.length > 0) {
580
- for (const initializer of declaration_initializers) {
797
+ const declaration_yields = collect_declaration_yield_expressions(content, open, leading_ws, trimmed);
798
+ if (declaration_yields.length > 0) {
799
+ for (const declaration_yield of declaration_yields) {
581
800
  const placeholder = `__ser_markup_placeholder_${helper_index}`;
582
801
  helper_index += 1;
583
802
  candidates.push({
584
803
  placeholder,
585
- start: initializer.start,
586
- end: initializer.end,
587
- expr_text: initializer.expr_text,
804
+ start: declaration_yield.start,
805
+ end: declaration_yield.end,
806
+ expr_text: declaration_yield.expr_text,
588
807
  filename,
589
808
  key: "plain"
590
809
  });
591
- magic.overwrite(initializer.start, initializer.end, placeholder);
810
+ magic.overwrite(declaration_yield.start, declaration_yield.end, placeholder);
592
811
  }
593
812
  cursor = close + 1;
594
813
  continue;
@@ -596,7 +815,7 @@ function sanitize_markup(content, filename) {
596
815
  let expr_body = trimmed.slice(tag_info.prefix_length);
597
816
  /** For @const, only use the RHS after `=` as the expression body. */
598
817
  const equal_idx = tag_info.kind === "plain" && trimmed.startsWith("@const ") ? expr_body.indexOf("=") : -1;
599
- if (!((is_event_expression(inner) ? analyze_event_yield(inner, filename) : void 0)?.has_top_level_yield_star ?? contains_yield_star_in_text(expr_body))) {
818
+ if (!((is_event_callback_expression(inner) ? analyze_event_yield(inner) : void 0)?.has_top_level_yield_star ?? contains_yield_star_in_text(expr_body))) {
600
819
  cursor = close + 1;
601
820
  continue;
602
821
  }
@@ -742,35 +961,40 @@ function get_tag_info(trimmed) {
742
961
  prefix_length: 0
743
962
  };
744
963
  }
745
- function collect_declaration_initializers(content, open, leading_ws, trimmed) {
964
+ function collect_declaration_yield_expressions(content, open, leading_ws, trimmed) {
746
965
  if (!is_declaration_tag_text(trimmed)) return [];
747
966
  const source_file = ts.createSourceFile("declaration-tag.ts", `${trimmed};`, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
748
967
  const stmt = source_file.statements[0];
749
968
  if (!stmt || !ts.isVariableStatement(stmt)) return [];
750
969
  const tag_start = open + 1 + leading_ws;
751
- return stmt.declarationList.declarations.filter((decl) => decl.initializer && contains_top_level_yield_star(decl.initializer)).map((decl) => {
970
+ return stmt.declarationList.declarations.flatMap((decl) => {
752
971
  const initializer = decl.initializer;
753
- const start = tag_start + initializer.getStart(source_file);
754
- const end = tag_start + initializer.end;
755
- return {
756
- start,
757
- end,
758
- expr_text: content.slice(start, end).trim()
759
- };
972
+ if (!initializer || !contains_top_level_yield_star(initializer)) return [];
973
+ const expressions = [];
974
+ collect_yield_star_nodes(initializer, (yield_node) => {
975
+ const start = tag_start + yield_node.getStart(source_file);
976
+ const end = tag_start + yield_node.end;
977
+ const expr_text = content.slice(start, end).trim();
978
+ expressions.push({
979
+ start,
980
+ end,
981
+ expr_text
982
+ });
983
+ });
984
+ return expressions;
760
985
  });
761
986
  }
762
987
  function is_declaration_tag_text(trimmed) {
763
988
  return /^(?:const|let)\s/.test(trimmed);
764
989
  }
765
- function is_event_expression(inner) {
990
+ function is_event_callback_expression(inner) {
766
991
  const trimmed = inner.trimStart();
767
- return /^(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>/.test(trimmed);
992
+ return /^(?:async\s+)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>/.test(trimmed) || /^(?:async\s+)?function\b/.test(trimmed);
768
993
  }
769
- function analyze_event_yield(inner, filename) {
994
+ function analyze_event_yield(inner) {
770
995
  const event = strip_arrow_function(inner);
771
996
  const analysis = analyze_event_body_yield_star(event.body);
772
- if (analysis.has_nested_invalid_yield_star) throw new NestedYieldStarInEventHandlerError(filename, event.body);
773
- return { has_top_level_yield_star: analysis.has_top_level_yield_star };
997
+ return { has_top_level_yield_star: analysis.has_top_level_yield_star || analysis.has_nested_invalid_yield_star || /\byield\s*\*/.test(event.body) };
774
998
  }
775
999
  function contains_yield_star_in_text(text) {
776
1000
  if (!/\byield\s*\*/.test(text)) return false;
@@ -831,6 +1055,6 @@ function transform_markup_effect(content, filename) {
831
1055
  };
832
1056
  }
833
1057
  //#endregion
834
- export { TopLevelAwaitError as n, transform_markup_effect as t };
1058
+ 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 };
835
1059
 
836
- //# sourceMappingURL=transform-BtlxgJrg.js.map
1060
+ //# sourceMappingURL=transform-B4g76Ur4.js.map