svelte-effect-runtime 3.4.10 → 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-Dm3bXmR3.js → compiler-BBPNyXmQ.js} +84 -112
  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-CEK6Ccll.js → transform-jNUr65K9.js} +289 -248
  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 +38 -0
  38. package/.dist/markup/promise.js +1 -1
  39. package/.dist/markup/run.js +1 -1
  40. package/.dist/markup/transform/classify.d.ts +12 -4
  41. package/.dist/markup/transform/constants.d.ts +1 -0
  42. package/.dist/markup/transform/emit.d.ts +12 -4
  43. package/.dist/markup/transform/types.d.ts +1 -0
  44. package/.dist/markup/transform.js +1 -1
  45. package/.dist/markup/value.js +1 -1
  46. package/.dist/mod.d.ts +6 -3
  47. package/.dist/mod.js +5 -4
  48. package/.dist/mod.js.map +1 -1
  49. package/.dist/remote/cause-codec.d.ts +53 -0
  50. package/.dist/remote/client/form-transport.d.ts +4 -1
  51. package/.dist/remote/client/form.d.ts +10 -1
  52. package/.dist/remote/client/index.d.ts +1 -1
  53. package/.dist/remote/client/query.d.ts +6 -16
  54. package/.dist/remote/client/types.d.ts +32 -13
  55. package/.dist/remote/client.d.ts +1 -1
  56. package/.dist/remote/client.js +1 -1
  57. package/.dist/remote/server.d.ts +2 -12
  58. package/.dist/remote/server.js +1 -178
  59. package/.dist/runtime/transform.js +81 -68
  60. package/.dist/runtime/transform.js.map +1 -1
  61. package/.dist/script-transform/imports.d.ts +2 -0
  62. package/.dist/script-transform/types.d.ts +8 -0
  63. package/.dist/server/effects.d.ts +7 -7
  64. package/.dist/server/handler.d.ts +37 -0
  65. package/.dist/server/index.d.ts +4 -1
  66. package/.dist/server/schema.d.ts +2 -26
  67. package/.dist/server/types.d.ts +44 -50
  68. package/.dist/server/wrappers.d.ts +2 -2
  69. package/.dist/server.d.ts +2 -2
  70. package/.dist/server.js +88 -97
  71. package/.dist/server.js.map +1 -1
  72. package/.dist/yieldable.d.ts +41 -0
  73. package/README.md +1 -1
  74. package/package.json +4 -4
  75. package/.dist/chunks/client-CsVu54pU.js.map +0 -1
  76. package/.dist/chunks/descriptors-cOe9uRJz.js +0 -36
  77. package/.dist/chunks/descriptors-cOe9uRJz.js.map +0 -1
  78. package/.dist/chunks/errors-Dcf0MVbq.js.map +0 -1
  79. package/.dist/chunks/remote-client-Bj1pZXgq.js.map +0 -1
  80. package/.dist/chunks/transform-CEK6Ccll.js.map +0 -1
  81. package/.dist/chunks/vite-Dm3bXmR3.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,6 +1,6 @@
1
1
  import type { RemoteForm, RemoteFormInput, RemoteLiveQuery, RemoteQuery, RemoteQueryOverride } from "@sveltejs/kit";
2
2
  import type { RemoteFailure } from "../shared.js";
3
- import type { Effect } from "effect";
3
+ import type { Effect, Schema, Stream } from "effect";
4
4
  /**
5
5
  * Type-only marker attached to SER query and live-query adapter functions so
6
6
  * form updates can distinguish them from command adapters.
@@ -21,6 +21,34 @@ export type EffectRemoteQueryUpdateBrand = {
21
21
  type EffectRemoteFormCallable<Input extends RemoteFormInput | void, Output, ErrorType> = [
22
22
  Input
23
23
  ] extends [void] ? () => Effect.Effect<Output, RemoteFailure<ErrorType>> : undefined extends Input ? (input?: Input) => Effect.Effect<Output, RemoteFailure<ErrorType>> : (input: Input) => Effect.Effect<Output, RemoteFailure<ErrorType>>;
24
+ type NativeRemoteFormPreflightSchema<Input extends RemoteFormInput | void, Output> = Parameters<RemoteForm<Input, Output>["preflight"]>[0];
25
+ type NativeRemoteFormValidateOptions<Input extends RemoteFormInput | void, Output> = NonNullable<Parameters<RemoteForm<Input, Output>["validate"]>[0]>;
26
+ /**
27
+ * Schema values accepted by SER's remote form preflight adapter.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * form.preflight(Schema.Struct({ email: Schema.String }));
32
+ * ```
33
+ *
34
+ * @since 3.4.6
35
+ */
36
+ export type EffectRemoteFormPreflightSchema<Input extends RemoteFormInput | void, Output = unknown> = NativeRemoteFormPreflightSchema<Input, Output> | Schema.Schema<unknown>;
37
+ /**
38
+ * Options accepted by SER's remote form validation adapter.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * yield* form.validate({ all: true, preflightOnly: true });
43
+ * ```
44
+ *
45
+ * @since 3.4.6
46
+ */
47
+ export type EffectRemoteFormValidateOptions<Input extends RemoteFormInput | void, Output = unknown> = Omit<NativeRemoteFormValidateOptions<Input, Output>, "all" | "includeUntouched" | "preflightOnly"> & {
48
+ readonly all?: boolean;
49
+ readonly includeUntouched?: boolean;
50
+ readonly preflightOnly?: boolean;
51
+ };
24
52
  type EffectRemoteQueryUpdate = NativeRemoteQueryUpdate | EffectRemoteQueryUpdateFunction | EffectRemoteLiveQueryUpdateFunction;
25
53
  type EffectRemoteCommandUpdate = {
26
54
  readonly pending: number;
@@ -31,21 +59,12 @@ type EffectRemoteQueryUpdates<Updates extends readonly unknown[]> = Updates & {
31
59
  };
32
60
  type NativeRemoteQueryUpdate = RemoteQuery<unknown> | RemoteLiveQuery<unknown> | RemoteQueryOverride;
33
61
  type EffectRemoteQueryUpdateFunction = EffectRemoteQueryUpdateBrand & ((input: never) => EffectRemoteQueryUpdateResource);
34
- type EffectRemoteLiveQueryUpdateFunction = EffectRemoteQueryUpdateBrand & ((input: never) => Effect.Effect<EffectRemoteLiveQueryUpdateResource, unknown>);
62
+ type EffectRemoteLiveQueryUpdateFunction = EffectRemoteQueryUpdateBrand & ((input: never) => Stream.Stream<unknown, unknown, unknown>);
35
63
  type EffectRemoteQueryUpdateResource = Effect.Effect<unknown, unknown> & {
36
64
  readonly refresh: () => Effect.Effect<void, unknown, never>;
37
65
  readonly set: (value: never) => void;
38
66
  readonly withOverride: (update: (current: never) => unknown) => unknown;
39
67
  };
40
- type EffectRemoteLiveQueryUpdateResource = {
41
- readonly connected: boolean;
42
- readonly current: unknown;
43
- readonly done: boolean;
44
- readonly error: unknown;
45
- readonly loading: boolean;
46
- readonly ready: boolean;
47
- readonly reconnect: () => Effect.Effect<void, unknown, never>;
48
- } & AsyncIterable<unknown>;
49
68
  /**
50
69
  * Represents a pending operation counter that remote command adapters
51
70
  * use to track in-flight requests.
@@ -122,8 +141,8 @@ export type EffectRemoteFormEnhanceOptions<Input extends RemoteFormInput | void,
122
141
  export type EffectRemoteForm<Input extends RemoteFormInput | void, Output, ErrorType = never> = EffectRemoteFormCallable<Input, Output, ErrorType> & Omit<RemoteForm<Input, Output>, "enhance" | "for" | "preflight" | "submit" | "validate"> & {
123
142
  enhance(callback?: (options: EffectRemoteFormEnhanceOptions<Input, Output, ErrorType>) => void | Promise<void> | Effect.Effect<void, unknown, unknown>): ReturnType<RemoteForm<Input, Output>["enhance"]>;
124
143
  for(id: Parameters<RemoteForm<Input, Output>["for"]>[0]): Omit<EffectRemoteForm<Input, Output, ErrorType>, "for">;
125
- preflight(schema: Parameters<RemoteForm<Input, Output>["preflight"]>[0]): EffectRemoteForm<Input, Output, ErrorType>;
144
+ preflight(schema: EffectRemoteFormPreflightSchema<Input, Output>): EffectRemoteForm<Input, Output, ErrorType>;
126
145
  submit: EffectRemoteFormCallable<Input, Output, ErrorType>;
127
- validate(options?: Parameters<RemoteForm<Input, Output>["validate"]>[0]): Effect.Effect<void, RemoteFailure<ErrorType>>;
146
+ validate(options?: EffectRemoteFormValidateOptions<Input, Output>): Effect.Effect<void, RemoteFailure<ErrorType>>;
128
147
  };
129
148
  export {};
@@ -1,2 +1,2 @@
1
1
  export { create_remote_command_adapter, create_remote_form_adapter, create_remote_live_query_adapter, create_remote_query_adapter, } from "./client/index.js";
2
- export type { EffectRemoteForm, EffectRemoteFormEnhanceOptions, EffectRemoteFormSubmit, Pending, } from "./client/index.js";
2
+ export type { EffectRemoteForm, EffectRemoteFormEnhanceOptions, EffectRemoteFormPreflightSchema, EffectRemoteFormSubmit, EffectRemoteFormValidateOptions, Pending, } from "./client/index.js";
@@ -1,2 +1,2 @@
1
- import { i as create_remote_command_adapter, n as create_remote_query_adapter, r as create_remote_form_adapter, t as create_remote_live_query_adapter } from "../chunks/client-CsVu54pU.js";
1
+ import { i as create_remote_command_adapter, n as create_remote_query_adapter, r as create_remote_form_adapter, t as create_remote_live_query_adapter } from "../chunks/client-DcZUV4rR.js";
2
2
  export { create_remote_command_adapter, create_remote_form_adapter, create_remote_live_query_adapter, create_remote_query_adapter };
@@ -1,7 +1,8 @@
1
1
  import type { FormIssue } from "./shared.js";
2
- import { Cause, Effect } from "effect";
2
+ import { Effect } from "effect";
3
3
  type SvelteInvalid = (...issues: readonly (FormIssue | string)[]) => never;
4
4
  type SvelteError = (status: number, body: unknown) => never;
5
+ export { encode_remote_failure } from "./cause-codec.js";
5
6
  /**
6
7
  * Runs a user-supplied Effect program through a ManagedRuntime, maps its
7
8
  * exit into the shape expected by SvelteKit, and returns the result or
@@ -18,16 +19,6 @@ type SvelteError = (status: number, body: unknown) => never;
18
19
  export declare function run_remote_effect<A>(effect: Effect.Effect<A, unknown, unknown>, runtime: {
19
20
  runPromise: (e: Effect.Effect<unknown, unknown, unknown>) => Promise<unknown>;
20
21
  }, invalid: SvelteInvalid, error: SvelteError): Promise<A>;
21
- /**
22
- * Encodes an Effect Cause into a string that the client-side adapter can
23
- * decode back into a typed `RemoteFailure`.
24
- *
25
- * @since 2.0.0
26
- * @param cause - The Effect Cause from a failed execution.
27
- * @returns A devalue-encoded string representing the serialised failure.
28
- * @internal
29
- */
30
- export declare function encode_remote_failure(cause: Cause.Cause<unknown>): string;
31
22
  /**
32
23
  * Throws a SvelteKit `invalid` response from a {@link FormError}, calling
33
24
  * through to the request-scoped `invalid` helper.
@@ -66,4 +57,3 @@ export declare function throw_form_error(issues: readonly FormIssue[], invalid:
66
57
  * @internal
67
58
  */
68
59
  export declare function normalize_remote_helper_error(err: unknown, helper_name: string): Error;
69
- export {};
@@ -1,179 +1,2 @@
1
- import { h as RemoteHelperError, m as RemoteHelperContextError } from "../chunks/errors-Dcf0MVbq.js";
2
- import { create_serialized_remote_failure_envelope } from "./shared.js";
3
- import { Cause, Effect, Exit } from "effect";
4
- import { isHttpError, isRedirect, isValidationError } from "@sveltejs/kit";
5
- import { stringify } from "devalue";
6
- //#region src/remote/server.ts
7
- const request_event_context_error_start = "Can only read the current request event inside functions invoked during `handle`";
8
- const request_store_context_error = "Could not get the request store.";
9
- /**
10
- * Runs a user-supplied Effect program through a ManagedRuntime, maps its
11
- * exit into the shape expected by SvelteKit, and returns the result or
12
- * throws a SvelteKit-compatible error.
13
- *
14
- * @since 2.0.0
15
- * @param effect - The Effect program to execute.
16
- * @param runtime - The server-side ManagedRuntime.
17
- * @param invalid - SvelteKit's `invalid` helper (bound per-request).
18
- * @param error - SvelteKit's `error` helper.
19
- * @returns A Promise that resolves with the effect's success value.
20
- * @internal
21
- */
22
- async function run_remote_effect(effect, runtime, invalid, error) {
23
- const exit = await runtime.runPromise(Effect.exit(effect));
24
- if (Exit.isSuccess(exit)) return exit.value;
25
- handle_failure(exit.cause, invalid, error);
26
- }
27
- /**
28
- * Inspects the Effect Cause for failures and either throws a form
29
- * validation error (via SvelteKit's `invalid`) or encodes the error
30
- * and throws it via SvelteKit's `error`.
31
- */
32
- function handle_failure(cause, invalid, error) {
33
- const reasons = get_cause_reasons(cause);
34
- /**
35
- * Phase 1 — let SvelteKit's thrown control-flow sentinels escape.
36
- */
37
- for (const reason of reasons) {
38
- if (!Cause.isDieReason(reason)) continue;
39
- const defect = reason.defect;
40
- if (is_sveltekit_control_flow(defect)) throw defect;
41
- }
42
- /**
43
- * Phase 2 — let cancellation escape without becoming a remote failure.
44
- */
45
- if (Cause.hasInterruptsOnly(cause)) throw Cause.squash(cause);
46
- /**
47
- * Phase 3 — preserve typed form validation failures.
48
- */
49
- for (const reason of reasons) if (Cause.isFailReason(reason)) {
50
- const failure = reason.error;
51
- if (typeof failure === "object" && failure !== null && failure._tag === "FormError") invalid(...failure.issues ?? []);
52
- }
53
- error(500, create_serialized_remote_failure_envelope(encode_remote_failure(cause)));
54
- }
55
- /**
56
- * Encodes an Effect Cause into a string that the client-side adapter can
57
- * decode back into a typed `RemoteFailure`.
58
- *
59
- * @since 2.0.0
60
- * @param cause - The Effect Cause from a failed execution.
61
- * @returns A devalue-encoded string representing the serialised failure.
62
- * @internal
63
- */
64
- function encode_remote_failure(cause) {
65
- const reasons = get_cause_reasons(cause);
66
- for (const reason of reasons) if (Cause.isFailReason(reason)) {
67
- const encoded = stringify_failure(to_public_remote_failure(reason.error));
68
- if (encoded !== void 0) return encoded;
69
- }
70
- return stringify_unknown_remote_failure();
71
- }
72
- function get_cause_reasons(cause) {
73
- return cause.reasons ?? [];
74
- }
75
- function is_sveltekit_control_flow(value) {
76
- return isRedirect(value) || isHttpError(value) || isValidationError(value);
77
- }
78
- function stringify_failure(value) {
79
- try {
80
- return stringify(value);
81
- } catch {
82
- return;
83
- }
84
- }
85
- function to_public_remote_failure(value) {
86
- if (!has_public_remote_failure_tag(value)) return create_unknown_remote_failure();
87
- return to_serializable_public_failure(value) ?? create_unknown_remote_failure();
88
- }
89
- function to_serializable_public_failure(value, seen = /* @__PURE__ */ new WeakSet()) {
90
- if (typeof value === "function" || typeof value === "symbol") return;
91
- if (!is_object_like(value)) return value;
92
- if (stringify_failure(value) !== void 0) return value;
93
- if (is_internal_object(value)) return;
94
- if (seen.has(value)) return;
95
- seen.add(value);
96
- const serializable = Array.isArray(value) ? value.map((item) => to_serializable_public_failure(item, seen)) : to_plain_record(value, seen);
97
- seen.delete(value);
98
- return serializable;
99
- }
100
- function to_plain_record(value, seen) {
101
- const descriptors = Object.getOwnPropertyDescriptors(value);
102
- const record = {};
103
- for (const [key, descriptor] of Object.entries(descriptors)) {
104
- if (key === "stack" || !("value" in descriptor)) continue;
105
- record[key] = to_serializable_public_failure(descriptor.value, seen);
106
- }
107
- if (value instanceof Error && !("message" in record)) record.message = value.message;
108
- return record;
109
- }
110
- function is_object_like(value) {
111
- return typeof value === "object" && value !== null;
112
- }
113
- function has_public_remote_failure_tag(value) {
114
- return is_object_like(value) && typeof value._tag === "string";
115
- }
116
- function is_internal_object(value) {
117
- return !Array.isArray(value) && !is_plain_record(value) && !has_public_remote_failure_tag(value);
118
- }
119
- function is_plain_record(value) {
120
- const prototype = Object.getPrototypeOf(value);
121
- return prototype === Object.prototype || prototype === null;
122
- }
123
- function create_unknown_remote_failure() {
124
- return { message: "[UNKNOWN_REMOTE_FAILURE]: Unknown error" };
125
- }
126
- function stringify_unknown_remote_failure() {
127
- return stringify(create_unknown_remote_failure());
128
- }
129
- /**
130
- * Throws a SvelteKit `invalid` response from a {@link FormError}, calling
131
- * through to the request-scoped `invalid` helper.
132
- *
133
- * @example
134
- * ```ts
135
- * throw_form_error(
136
- * [{ message: "Name is required", path: ["name"] }],
137
- * invalid,
138
- * );
139
- * ```
140
- *
141
- * @since 2.0.0
142
- * @param issues - The list of form validation issues.
143
- * @param invalid - SvelteKit's `invalid` helper bound to the current request.
144
- * @internal
145
- */
146
- function throw_form_error(issues, invalid) {
147
- invalid(...issues);
148
- }
149
- /**
150
- * Remaps SvelteKit's unbranded request-context errors into clear, actionable
151
- * messages.
152
- *
153
- * @example
154
- * ```ts
155
- * try {
156
- * return native_query(handler);
157
- * } catch (err) {
158
- * throw normalize_remote_helper_error(err, "Query");
159
- * }
160
- * ```
161
- *
162
- * @since 2.0.0
163
- * @param err - The error thrown by SvelteKit's native functions.
164
- * @param helper_name - Name of the helper that triggered the error.
165
- * @returns A more descriptive error.
166
- * @internal
167
- */
168
- function normalize_remote_helper_error(err, helper_name) {
169
- if (is_sveltekit_remote_context_error(err)) return new RemoteHelperContextError(helper_name);
170
- return err instanceof Error ? err : new RemoteHelperError(err);
171
- }
172
- function is_sveltekit_remote_context_error(err) {
173
- if (!(err instanceof Error)) return false;
174
- return err.message.startsWith(request_event_context_error_start) || err.message === request_store_context_error;
175
- }
176
- //#endregion
1
+ import { i as encode_remote_failure, n as run_remote_effect, r as throw_form_error, t as normalize_remote_helper_error } from "../chunks/server-D1LcDnZE.js";
177
2
  export { encode_remote_failure, normalize_remote_helper_error, run_remote_effect, throw_form_error };
178
-
179
- //# sourceMappingURL=server.js.map
@@ -1,5 +1,6 @@
1
- import { d as PreprocessError, r as AwaitInEffectWorkError } from "../chunks/errors-Dcf0MVbq.js";
2
- import { a as is_yield_star_expression, c as slice, d as collect_top_level_binding_names, f as has_local_import_binding, i as find_yield_star_node, l as slice_start, n as collect_yield_star_nodes, o as validate_rune_yield_usage, p as make_imports, r as contains_top_level_await, s as create_source_map, t as transform_markup_effect, u as collect_free_identifiers } from "../chunks/transform-CEK6Ccll.js";
1
+ import { f as PreprocessError, r as AwaitInEffectWorkError } from "../chunks/errors-IJjsUwrE.js";
2
+ import { t as scan_svelte_effect_source } from "../chunks/source-scan-C4PsggID.js";
3
+ import { a as slice_start, c as contains_top_level_await, d as collect_top_level_binding_names, f as has_local_import_binding, i as slice, l as find_yield_star_node, n as validate_rune_yield_usage, o as collect_free_identifiers, p as make_imports, r as create_source_map, s as collect_yield_star_nodes, t as transform_markup_effect, u as is_yield_star_expression } from "../chunks/transform-jNUr65K9.js";
3
4
  import { contains_top_level_yield_star } from "../detect.js";
4
5
  import ts from "typescript";
5
6
  import MagicString from "magic-string";
@@ -14,9 +15,11 @@ import MagicString from "magic-string";
14
15
  * @returns Full `$effect` blocks that fork generated `Effect.gen` programs.
15
16
  */
16
17
  function make_runtime_block_with_bindings(blocks, bindings) {
17
- const merged_block = merge_effect_blocks(blocks);
18
- const dep_reads = merged_block.deps.map((dep) => ` ${dep};`);
19
- const body = merged_block.statements.map((statement) => ` ${statement}`).join("\n");
18
+ return blocks.map((block) => make_runtime_effect_block(block, bindings)).join("\n");
19
+ }
20
+ function make_runtime_effect_block(block, bindings) {
21
+ const dep_reads = block.deps.map((dep) => ` ${dep};`);
22
+ const body = block.statements.map((statement) => ` ${statement}`).join("\n");
20
23
  return [
21
24
  "",
22
25
  "$effect(() => {",
@@ -32,14 +35,6 @@ function make_runtime_block_with_bindings(blocks, bindings) {
32
35
  ""
33
36
  ].join("\n");
34
37
  }
35
- function merge_effect_blocks(blocks) {
36
- const statements = blocks.flatMap((block) => block.statements);
37
- const deps = blocks.flatMap((block) => block.deps);
38
- return {
39
- statements,
40
- deps: [...new Set(deps)]
41
- };
42
- }
43
38
  //#endregion
44
39
  //#region src/script-transform/lower.ts
45
40
  /**
@@ -58,7 +53,7 @@ function lower_statement(stmt, content, context) {
58
53
  return {
59
54
  temps: [],
60
55
  rewritten_text: "",
61
- effect_blocks: [make_effect_block([text], collect_deps(text))],
56
+ effect_blocks: [make_effect_block([wrap_yield_stars_in_node(stmt, content, context)], collect_deps(text))],
62
57
  range: {
63
58
  start: stmt.getFullStart(),
64
59
  end: stmt.end
@@ -109,7 +104,7 @@ function lower_expression_statement(stmt, content, context) {
109
104
  return {
110
105
  temps: [],
111
106
  rewritten_text: "",
112
- effect_blocks: [make_effect_block([text + ";"], collect_deps(text))],
107
+ effect_blocks: [make_effect_block([wrap_yield_text(text, context) + ";"], collect_deps(text))],
113
108
  range: {
114
109
  start: stmt.getFullStart(),
115
110
  end: stmt.end
@@ -124,7 +119,7 @@ function lower_expression_statement(stmt, content, context) {
124
119
  return {
125
120
  temps: [],
126
121
  rewritten_text: "",
127
- effect_blocks: [make_effect_block([`${target} = ${yield_text};`], collect_deps(yield_text, target_names))],
122
+ effect_blocks: [make_effect_block([`${target} = ${wrap_yield_text(yield_text, context)};`], collect_deps(yield_text, target_names))],
128
123
  range: {
129
124
  start: stmt.getStart(),
130
125
  end: stmt.end
@@ -185,7 +180,7 @@ function lower_expression_yields(expr, content, hint, context) {
185
180
  type: type_helper.type
186
181
  });
187
182
  } else temps.push({ name: temp_name });
188
- statements.push(`${temp_name} = ${yield_text};`);
183
+ statements.push(`${temp_name} = ${wrap_yield_text(yield_text, context)};`);
189
184
  deps.push(...collect_deps(yield_text));
190
185
  replacements.push({
191
186
  start: node.getStart(),
@@ -238,7 +233,7 @@ function make_awaited_yield_expression(node, content, hint, context) {
238
233
  const helper_id = make_script_effect_id(node, context);
239
234
  const deps_text = `[${collect_deps(yield_text).join(", ")}]`;
240
235
  return {
241
- declaration: `function* ${helper_name}() { return (${yield_text}); }`,
236
+ declaration: `function* ${helper_name}() { return (${wrap_yield_text(yield_text, context)}); }`,
242
237
  expression: [
243
238
  `await ${context.dispatcher_name}().promise({`,
244
239
  `id: ${JSON.stringify(helper_id)}, `,
@@ -253,11 +248,30 @@ function make_yield_type_helper(yield_text, hint, context) {
253
248
  const helper_name = context.next_type_helper_name(hint);
254
249
  return {
255
250
  declaration: `function ${helper_name}() { return (${strip_yield_star(yield_text)}); }`,
256
- type: `${context.effect_name}.Success<ReturnType<typeof ${helper_name}>> | undefined`
251
+ type: `${context.yield_success_name}<ReturnType<typeof ${helper_name}>> | undefined`
257
252
  };
258
253
  }
259
254
  function strip_yield_star(yield_text) {
260
- return yield_text.replace(/^yield\*\s*/, "");
255
+ return yield_text.replace(/^yield\s*\*\s*/, "");
256
+ }
257
+ function wrap_yield_text(yield_text, context) {
258
+ return `yield* ${context.yieldable_name}(${strip_yield_star(yield_text)})`;
259
+ }
260
+ function wrap_yield_stars_in_node(node, content, context) {
261
+ const replacements = [];
262
+ collect_yield_star_nodes(node, (yield_node) => {
263
+ const yield_text = slice_start(content, yield_node).trim();
264
+ replacements.push({
265
+ start: yield_node.getStart(),
266
+ end: yield_node.end,
267
+ text: wrap_yield_text(yield_text, context)
268
+ });
269
+ });
270
+ replacements.sort((a, b) => b.start - a.start);
271
+ const offset = node.getFullStart();
272
+ let text = slice(content, node);
273
+ for (const replacement of replacements) text = text.slice(0, replacement.start - offset) + replacement.text + text.slice(replacement.end - offset);
274
+ return text.trim();
261
275
  }
262
276
  function make_script_effect_id(expr, context) {
263
277
  return `${context.filename}:${expr.getStart()}:${expr.end}`;
@@ -341,7 +355,7 @@ function transform_script_effect(content, filename, options = {}) {
341
355
  const emit_types = options.emit_types ?? true;
342
356
  let has_effect = false;
343
357
  let uses_dispatcher_promise = false;
344
- let uses_effect_types = false;
358
+ let uses_yield_success_types = false;
345
359
  /** Phase 1: detect imports already provided by the user. */
346
360
  const has_effect_import = has_local_import_binding(source_file, "effect", "Effect");
347
361
  const has_dispatcher_import = has_local_import_binding(source_file, "svelte-effect-runtime/internal/generators", "get_dispatcher");
@@ -353,13 +367,17 @@ function transform_script_effect(content, filename, options = {}) {
353
367
  dispatcher_value: name_allocator.reserve("__SER___dispatcher"),
354
368
  effect: has_effect_import ? "Effect" : reserve_runtime_import("Effect"),
355
369
  program: name_allocator.reserve("__SER___program"),
356
- untrack: has_untrack_import ? "untrack" : reserve_runtime_import("untrack")
370
+ untrack: has_untrack_import ? "untrack" : reserve_runtime_import("untrack"),
371
+ yield_success: reserve_runtime_import("YieldSuccess"),
372
+ yieldable: reserve_runtime_import("ToEffect")
357
373
  };
358
374
  const context = {
359
375
  filename,
360
376
  dispatcher_name: runtime_bindings.dispatcher,
361
377
  effect_name: runtime_bindings.effect,
362
378
  emit_types,
379
+ yield_success_name: runtime_bindings.yield_success,
380
+ yieldable_name: runtime_bindings.yieldable,
363
381
  next_helper_name(hint) {
364
382
  return name_allocator.reserve(make_generated_name(hint ?? "helper", ""));
365
383
  },
@@ -389,7 +407,7 @@ function transform_script_effect(content, filename, options = {}) {
389
407
  }
390
408
  effect_blocks.push(...lowered.effect_blocks);
391
409
  uses_dispatcher_promise ||= lowered.uses_dispatcher_promise ?? false;
392
- uses_effect_types ||= lowered.temps.some((temp) => temp.type?.includes(`${runtime_bindings.effect}.Success`) ?? false);
410
+ uses_yield_success_types ||= lowered.temps.some((temp) => temp.type?.includes(runtime_bindings.yield_success) ?? false);
393
411
  }
394
412
  if (!has_effect) {
395
413
  block_refs.push({
@@ -404,8 +422,10 @@ function transform_script_effect(content, filename, options = {}) {
404
422
  /** Phase 3: inject runtime imports after the last user import. */
405
423
  const imports = make_imports(has_effect_import, has_dispatcher_import, has_untrack_import, runtime_bindings, {
406
424
  needs_dispatcher: effect_blocks.length > 0 || uses_dispatcher_promise,
407
- needs_effect: effect_blocks.length > 0 || uses_effect_types,
408
- needs_untrack: effect_blocks.length > 0
425
+ needs_effect: effect_blocks.length > 0,
426
+ needs_untrack: effect_blocks.length > 0,
427
+ needs_yield_success: uses_yield_success_types,
428
+ needs_yieldable: effect_blocks.length > 0 || uses_dispatcher_promise
409
429
  });
410
430
  const last_import = [...source_file.statements].reverse().find(ts.isImportDeclaration);
411
431
  if (imports) if (last_import) magic.appendRight(last_import.end, "\n" + imports);
@@ -424,33 +444,41 @@ function transform_script_effect(content, filename, options = {}) {
424
444
  code,
425
445
  blocks: block_refs,
426
446
  map: create_source_map(magic, filename),
427
- relocations: create_script_relocations(content, code, source_file)
447
+ relocations: create_script_relocations(content, code, source_file, runtime_bindings.yieldable)
428
448
  };
429
449
  }
430
- function create_script_relocations(content, code, source_file) {
450
+ function create_script_relocations(content, code, source_file, yieldable_name) {
431
451
  const candidates = source_file.statements.flatMap((stmt) => {
432
452
  const relocations = [];
433
453
  if (contains_top_level_yield_star(stmt) && ts.isVariableStatement(stmt)) for (const decl of stmt.declarationList.declarations) collect_binding_relocation_candidates(decl.name, relocations);
434
454
  collect_yield_star_nodes(stmt, (node) => {
435
- const text = content.slice(node.getStart(), node.end).trim();
455
+ const expression = ts.isBinaryExpression(node) ? node.right : node;
456
+ const text = content.slice(expression.getStart(), expression.end).trim();
436
457
  relocations.push({
437
- originalStart: node.getStart(),
438
- originalEnd: node.end,
458
+ originalStart: expression.getStart(),
459
+ originalEnd: expression.end,
439
460
  text,
440
- match: "exact"
461
+ match: "yield_operand",
462
+ wrapper: `${yieldable_name}(${text})`
441
463
  });
442
464
  });
443
465
  return relocations;
444
466
  });
445
467
  const used_ranges = [];
468
+ const search_cursors = /* @__PURE__ */ new Map();
446
469
  return candidates.flatMap((candidate) => {
447
- const generated_start = find_available_generated_text(code, candidate, used_ranges);
448
- if (generated_start < 0) return [];
470
+ const search_key = make_relocation_search_key(candidate);
471
+ const generated_start = find_available_generated_text(code, candidate, used_ranges, search_cursors.get(search_key) ?? 0);
472
+ if (generated_start < 0) {
473
+ search_cursors.set(search_key, code.length);
474
+ return [];
475
+ }
449
476
  const generated_end = generated_start + candidate.text.length;
450
477
  used_ranges.push({
451
478
  start: generated_start,
452
479
  end: generated_end
453
480
  });
481
+ search_cursors.set(search_key, generated_end);
454
482
  return [{
455
483
  originalStart: candidate.originalStart,
456
484
  originalEnd: candidate.originalEnd,
@@ -459,6 +487,9 @@ function create_script_relocations(content, code, source_file) {
459
487
  }];
460
488
  });
461
489
  }
490
+ function make_relocation_search_key(candidate) {
491
+ return `${candidate.match}:${candidate.text}`;
492
+ }
462
493
  function collect_binding_relocation_candidates(name, candidates) {
463
494
  if (ts.isIdentifier(name)) {
464
495
  candidates.push({
@@ -474,16 +505,19 @@ function collect_binding_relocation_candidates(name, candidates) {
474
505
  collect_binding_relocation_candidates(element.name, candidates);
475
506
  }
476
507
  }
477
- function find_available_generated_text(code, candidate, used_ranges) {
478
- let search_start = 0;
508
+ function find_available_generated_text(code, candidate, used_ranges, search_start) {
479
509
  while (search_start < code.length) {
480
- const index = code.indexOf(candidate.text, search_start);
510
+ const search_text = candidate.match === "yield_operand" ? candidate.wrapper : candidate.text;
511
+ if (!search_text) return -1;
512
+ const index = code.indexOf(search_text, search_start);
481
513
  if (index < 0) return -1;
482
- const end = index + candidate.text.length;
483
- const overlaps_used_range = used_ranges.some((range) => index < range.end && end > range.start);
484
- const is_text_match = candidate.match === "exact" || is_identifier_text_match(code, index, end);
485
- if (!overlaps_used_range && is_text_match) return index;
486
- search_start = candidate.match === "identifier" ? index + 1 : end;
514
+ const operand_offset = candidate.match === "yield_operand" && candidate.wrapper ? candidate.wrapper.indexOf(candidate.text) : 0;
515
+ const start = index + Math.max(operand_offset, 0);
516
+ const end = start + candidate.text.length;
517
+ const overlaps_used_range = used_ranges.some((range) => start < range.end && end > range.start);
518
+ const is_text_match = candidate.match !== "identifier" || is_identifier_text_match(code, start, end);
519
+ if (!overlaps_used_range && is_text_match) return start;
520
+ search_start = candidate.match === "identifier" ? index + 1 : index + search_text.length;
487
521
  }
488
522
  return -1;
489
523
  }
@@ -559,38 +593,17 @@ function make_generated_name(hint, suffix) {
559
593
  * @returns The transformed component source.
560
594
  */
561
595
  function transform_svelte_effect(content, filename = "unknown.svelte", options = {}) {
562
- const script = find_script(content);
596
+ const script = scan_svelte_effect_source(content, filename).effect_script;
563
597
  let combined = content;
564
- if (script?.has_effect) {
598
+ if (script) {
599
+ const effect_attribute = script.effect_attribute;
600
+ const effect_attribute_start = effect_attribute?.start ?? script.opening_tag_end;
601
+ const effect_attribute_end = effect_attribute?.end ?? script.opening_tag_end;
565
602
  const result = transform_script_effect(script.text, filename, { emit_types: script.is_typescript });
566
- combined = content.slice(0, script.effect_attr_start) + content.slice(script.effect_attr_end, script.open_end) + result.code + content.slice(script.close_start);
603
+ combined = content.slice(0, effect_attribute_start) + content.slice(effect_attribute_end, script.opening_tag_end) + result.code + content.slice(script.closing_tag_start);
567
604
  }
568
605
  return { code: transform_markup_effect(combined, filename, { target: options.target }).code };
569
606
  }
570
- function find_script(content) {
571
- for (const match of content.matchAll(/<script\b([^>]*)>([\s\S]*?)<\/script\s*>/gi)) {
572
- if (match.index === void 0 || /\bmodule\b/.test(match[1] ?? "")) continue;
573
- const attrs = match[1] ?? "";
574
- const effect_match = /\s+effect(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?/.exec(attrs);
575
- const open_end = match.index + match[0].indexOf(">") + 1;
576
- const attr_start = effect_match?.index ?? attrs.length;
577
- const attr_end = attr_start + (effect_match?.[0].length ?? 0);
578
- return {
579
- text: match[2],
580
- open_end,
581
- close_start: match.index + match[0].lastIndexOf("<"),
582
- has_effect: effect_match !== null,
583
- effect_attr_start: match.index + 7 + attr_start,
584
- effect_attr_end: match.index + 7 + attr_end,
585
- is_typescript: has_typescript_lang(attrs)
586
- };
587
- }
588
- }
589
- function has_typescript_lang(attrs) {
590
- const lang_match = /\blang\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(attrs);
591
- const lang = (lang_match?.[1] ?? lang_match?.[2] ?? lang_match?.[3] ?? "").toLowerCase();
592
- return lang === "ts" || lang === "typescript";
593
- }
594
607
  //#endregion
595
608
  export { transform_markup_effect, transform_script_effect, transform_svelte_effect };
596
609