svelte-effect-runtime 2.4.0 → 2.5.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.
- package/.dist/chunks/{client-CfkB_G4o.js → client-Cj2X9lY-.js} +11 -24
- package/.dist/chunks/client-Cj2X9lY-.js.map +1 -0
- package/.dist/chunks/{dispatcher-8B6Ol80H.js → dispatcher-BVkm8qbG.js} +33 -13
- package/.dist/chunks/dispatcher-BVkm8qbG.js.map +1 -0
- package/.dist/chunks/{preprocess-Cn4JH9OO.js → preprocess-DseI9Doo.js} +206 -73
- package/.dist/chunks/preprocess-DseI9Doo.js.map +1 -0
- package/.dist/chunks/transform-BDfspL1K.js +59 -0
- package/.dist/chunks/transform-BDfspL1K.js.map +1 -0
- package/.dist/chunks/{transform-s9gKPYu5.js → transform-Cx5bjmP6.js} +267 -48
- package/.dist/chunks/transform-Cx5bjmP6.js.map +1 -0
- package/.dist/dispatcher.js +1 -1
- package/.dist/error.d.ts +23 -0
- package/.dist/internal/generators.js +1 -1
- package/.dist/internal/remote-client.js +1 -1
- package/.dist/markup/promise.js +1 -1
- package/.dist/markup/run.js +1 -1
- package/.dist/markup/transform/apply.d.ts +8 -2
- package/.dist/markup/transform/emit.d.ts +2 -2
- package/.dist/markup/transform/types.d.ts +9 -1
- package/.dist/markup/transform.js +1 -1
- package/.dist/markup/value.d.ts +1 -1
- package/.dist/markup/value.js +1 -1
- package/.dist/markup/value.js.map +1 -1
- package/.dist/mod.d.ts +1 -1
- package/.dist/mod.js +1 -1
- package/.dist/mod.js.map +1 -1
- package/.dist/preprocess/imports.d.ts +20 -1
- package/.dist/preprocess/index.d.ts +5 -1
- package/.dist/preprocess/runtime-block.d.ts +11 -1
- package/.dist/preprocess/types.d.ts +27 -0
- package/.dist/preprocess.js +2 -2
- package/.dist/remote/client/command.d.ts +5 -1
- package/.dist/remote/client/effect.d.ts +1 -1
- package/.dist/remote/client/failures.d.ts +3 -3
- package/.dist/remote/client/form-enhance.d.ts +1 -1
- package/.dist/remote/client/form.d.ts +1 -1
- package/.dist/remote/client/query.d.ts +12 -5
- package/.dist/remote/client/responses.d.ts +2 -2
- package/.dist/remote/client/types.d.ts +57 -13
- package/.dist/remote/client.js +1 -1
- package/.dist/runtime/preprocess.d.ts +1 -0
- package/.dist/runtime/preprocess.js +5 -29
- package/.dist/runtime/preprocess.js.map +1 -1
- package/.dist/runtime/transform.d.ts +35 -0
- package/.dist/server/effects.d.ts +3 -3
- package/.dist/server/factories.d.ts +10 -38
- package/.dist/server/index.d.ts +1 -1
- package/.dist/server/invalid.d.ts +1 -1
- package/.dist/server/schema.d.ts +1 -1
- package/.dist/server/types.d.ts +51 -31
- package/.dist/server/wrappers.d.ts +4 -6
- package/.dist/server.d.ts +1 -1
- package/.dist/server.js +8 -15
- package/.dist/server.js.map +1 -1
- package/.dist/vite.js +32 -1
- package/.dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/.dist/chunks/client-CfkB_G4o.js.map +0 -1
- package/.dist/chunks/dispatcher-8B6Ol80H.js.map +0 -1
- package/.dist/chunks/preprocess-Cn4JH9OO.js.map +0 -1
- package/.dist/chunks/transform-s9gKPYu5.js.map +0 -1
|
@@ -2,6 +2,88 @@ import { contains_top_level_yield_star } from "../detect.js";
|
|
|
2
2
|
import { parse } from "svelte/compiler";
|
|
3
3
|
import MagicString from "magic-string";
|
|
4
4
|
import ts from "typescript";
|
|
5
|
+
//#region src/preprocess/imports.ts
|
|
6
|
+
/**
|
|
7
|
+
* Builds the import statements injected by the script preprocessor.
|
|
8
|
+
*
|
|
9
|
+
* @since 2.0.0
|
|
10
|
+
* @param has_effect_import - Whether the user already imports `Effect`.
|
|
11
|
+
* @param has_dispatcher_import - Whether the user already imports
|
|
12
|
+
* `get_dispatcher`.
|
|
13
|
+
* @param has_untrack_import - Whether the user already imports `untrack`.
|
|
14
|
+
* @returns Newline-separated import statements to inject.
|
|
15
|
+
*/
|
|
16
|
+
function make_imports(has_effect_import, has_dispatcher_import, has_untrack_import, bindings = {
|
|
17
|
+
cancel: "__SER___cancel",
|
|
18
|
+
dispatcher: "get_dispatcher",
|
|
19
|
+
dispatcher_value: "__SER___dispatcher",
|
|
20
|
+
effect: "Effect",
|
|
21
|
+
program: "__SER___program",
|
|
22
|
+
untrack: "untrack"
|
|
23
|
+
}) {
|
|
24
|
+
const dispatcher_import = bindings.dispatcher === "get_dispatcher" ? `import { get_dispatcher } from "svelte-effect-runtime/internal/generators";` : `import { get_dispatcher as ${bindings.dispatcher} } from "svelte-effect-runtime/internal/generators";`;
|
|
25
|
+
const untrack_import = bindings.untrack === "untrack" ? `import { untrack } from "svelte";` : `import { untrack as ${bindings.untrack} } from "svelte";`;
|
|
26
|
+
const effect_import = has_effect_import ? false : bindings.effect === "Effect" ? `import { Effect } from "effect";` : `import { Effect as ${bindings.effect} } from "effect";`;
|
|
27
|
+
return [
|
|
28
|
+
!has_dispatcher_import && dispatcher_import,
|
|
29
|
+
!has_untrack_import && untrack_import,
|
|
30
|
+
effect_import
|
|
31
|
+
].filter(Boolean).join("\n");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks whether a source file imports a local binding from a module.
|
|
35
|
+
*
|
|
36
|
+
* @since 2.0.0
|
|
37
|
+
* @param source_file - Parsed TypeScript source file to inspect.
|
|
38
|
+
* @param module_name - Module specifier to match.
|
|
39
|
+
* @param local_name - Local binding name to look for.
|
|
40
|
+
* @returns Whether that binding is already locally available.
|
|
41
|
+
*/
|
|
42
|
+
function has_local_import_binding(source_file, module_name, local_name) {
|
|
43
|
+
return source_file.statements.some((stmt) => {
|
|
44
|
+
if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier) || stmt.moduleSpecifier.text !== module_name) return false;
|
|
45
|
+
const clause = stmt.importClause;
|
|
46
|
+
if (!clause || clause.isTypeOnly) return false;
|
|
47
|
+
if (clause.name?.text === local_name) return true;
|
|
48
|
+
const named_bindings = clause.namedBindings;
|
|
49
|
+
if (!named_bindings) return false;
|
|
50
|
+
if (ts.isNamespaceImport(named_bindings)) return named_bindings.name.text === local_name;
|
|
51
|
+
return named_bindings.elements.some((element) => !element.isTypeOnly && element.name.text === local_name);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Collects every local binding declared at module top level.
|
|
56
|
+
*
|
|
57
|
+
* @since 2.4.2
|
|
58
|
+
* @param source_file - Parsed TypeScript source file to inspect.
|
|
59
|
+
* @returns Top-level names declared by imports, declarations, and variables.
|
|
60
|
+
*/
|
|
61
|
+
function collect_top_level_binding_names(source_file) {
|
|
62
|
+
return source_file.statements.flatMap(collect_statement_binding_names);
|
|
63
|
+
}
|
|
64
|
+
function collect_statement_binding_names(stmt) {
|
|
65
|
+
if (ts.isImportDeclaration(stmt)) return collect_import_binding_names(stmt);
|
|
66
|
+
if (ts.isVariableStatement(stmt)) return stmt.declarationList.declarations.flatMap((decl) => collect_binding_name_text(decl.name));
|
|
67
|
+
if (ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt) || ts.isInterfaceDeclaration(stmt) || ts.isTypeAliasDeclaration(stmt) || ts.isEnumDeclaration(stmt) || ts.isModuleDeclaration(stmt)) return stmt.name ? [stmt.name.text] : [];
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
function collect_import_binding_names(stmt) {
|
|
71
|
+
const clause = stmt.importClause;
|
|
72
|
+
if (!clause) return [];
|
|
73
|
+
return [
|
|
74
|
+
clause.name?.text,
|
|
75
|
+
clause.namedBindings && ts.isNamespaceImport(clause.namedBindings) ? clause.namedBindings.name.text : void 0,
|
|
76
|
+
clause.namedBindings && ts.isNamedImports(clause.namedBindings) ? clause.namedBindings.elements.map((element) => element.name.text) : void 0
|
|
77
|
+
].flat().filter((name) => name !== void 0);
|
|
78
|
+
}
|
|
79
|
+
function collect_binding_name_text(name) {
|
|
80
|
+
if (ts.isIdentifier(name)) return [name.text];
|
|
81
|
+
return name.elements.flatMap((element) => {
|
|
82
|
+
if (ts.isOmittedExpression(element)) return [];
|
|
83
|
+
return collect_binding_name_text(element.name);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
5
87
|
//#region src/markup/transform/constants.ts
|
|
6
88
|
const HELPERS = {
|
|
7
89
|
value: "__SER___markup_value",
|
|
@@ -22,14 +104,13 @@ function blank_script_blocks(content) {
|
|
|
22
104
|
return match.split("\n").map((l) => " ".repeat(l.length)).join("\n");
|
|
23
105
|
});
|
|
24
106
|
}
|
|
25
|
-
function inject_helpers(magic, content, helpers = []) {
|
|
26
|
-
if (content.includes(HELPERS.value)) return;
|
|
107
|
+
function inject_helpers(magic, content, helpers = [], bindings = HELPERS) {
|
|
27
108
|
const import_helpers = unique_import_helpers(helpers);
|
|
28
109
|
const local_helpers = helpers.filter((helper) => !is_import_helper(helper));
|
|
29
110
|
const helper_segments = [
|
|
30
|
-
`import { value as ${
|
|
31
|
-
`import { promise as ${
|
|
32
|
-
`import { run as ${
|
|
111
|
+
`import { value as ${bindings.value} } from "svelte-effect-runtime/internal/generators";`,
|
|
112
|
+
`import { promise as ${bindings.promise} } from "svelte-effect-runtime/internal/generators";`,
|
|
113
|
+
`import { run as ${bindings.run} } from "svelte-effect-runtime/internal/generators";`,
|
|
33
114
|
...import_helpers,
|
|
34
115
|
...local_helpers
|
|
35
116
|
].map((helper) => typeof helper === "string" ? { text: helper } : helper);
|
|
@@ -53,6 +134,18 @@ function inject_helpers(magic, content, helpers = []) {
|
|
|
53
134
|
};
|
|
54
135
|
}
|
|
55
136
|
}
|
|
137
|
+
function make_markup_helper_bindings(content) {
|
|
138
|
+
const script_tag = find_instance_script_tag(content);
|
|
139
|
+
const name_allocator = make_name_allocator(script_tag ? collect_script_binding_names(content.slice(script_tag.start, script_tag.end)) : []);
|
|
140
|
+
return {
|
|
141
|
+
bindings: {
|
|
142
|
+
value: name_allocator.reserve(HELPERS.value),
|
|
143
|
+
promise: name_allocator.reserve(HELPERS.promise),
|
|
144
|
+
run: name_allocator.reserve(HELPERS.run)
|
|
145
|
+
},
|
|
146
|
+
name_allocator
|
|
147
|
+
};
|
|
148
|
+
}
|
|
56
149
|
function create_relocations(replacements, helper_insertion) {
|
|
57
150
|
const edits = [helper_insertion && {
|
|
58
151
|
start: helper_insertion.start,
|
|
@@ -120,6 +213,22 @@ function unique_import_helpers(helpers) {
|
|
|
120
213
|
function is_import_helper(helper) {
|
|
121
214
|
return helper.text.trimStart().startsWith("import ");
|
|
122
215
|
}
|
|
216
|
+
function collect_script_binding_names(script_content) {
|
|
217
|
+
return collect_top_level_binding_names(ts.createSourceFile("markup-script.ts", script_content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS));
|
|
218
|
+
}
|
|
219
|
+
function make_name_allocator(initial_names) {
|
|
220
|
+
const used_names = new Set(initial_names);
|
|
221
|
+
return { reserve(name) {
|
|
222
|
+
let candidate = name;
|
|
223
|
+
let suffix = 1;
|
|
224
|
+
while (used_names.has(candidate)) {
|
|
225
|
+
candidate = `${name}_${suffix}`;
|
|
226
|
+
suffix += 1;
|
|
227
|
+
}
|
|
228
|
+
used_names.add(candidate);
|
|
229
|
+
return candidate;
|
|
230
|
+
} };
|
|
231
|
+
}
|
|
123
232
|
//#endregion
|
|
124
233
|
//#region src/markup/transform/classify.ts
|
|
125
234
|
/**
|
|
@@ -168,9 +277,7 @@ function visit_ast_node(node, candidates, matched, classified) {
|
|
|
168
277
|
case "HtmlTag":
|
|
169
278
|
classify_expression(node.expression, "plain", candidates, matched, classified);
|
|
170
279
|
return;
|
|
171
|
-
case "DebugTag":
|
|
172
|
-
classify_debug_tag(node, candidates, matched, classified);
|
|
173
|
-
return;
|
|
280
|
+
case "DebugTag": return;
|
|
174
281
|
case "ConstTag":
|
|
175
282
|
case "DeclarationTag":
|
|
176
283
|
classify_declaration_tag(node, candidates, matched, classified);
|
|
@@ -198,11 +305,6 @@ function visit_ast_node(node, candidates, matched, classified) {
|
|
|
198
305
|
default: return;
|
|
199
306
|
}
|
|
200
307
|
}
|
|
201
|
-
function classify_debug_tag(node, candidates, matched, classified) {
|
|
202
|
-
const idents = node.identifiers;
|
|
203
|
-
if (!idents || idents.length === 0) return;
|
|
204
|
-
for (const ident of idents) classify_expression(ident, "plain", candidates, matched, classified);
|
|
205
|
-
}
|
|
206
308
|
function classify_declaration_tag(node, candidates, matched, classified) {
|
|
207
309
|
for (const decl of node.declaration.declarations) {
|
|
208
310
|
if (!decl.init) continue;
|
|
@@ -240,10 +342,14 @@ function classify_expression(expression, kind, candidates, matched, classified)
|
|
|
240
342
|
matched.add(candidate.placeholder);
|
|
241
343
|
classified.push({
|
|
242
344
|
candidate,
|
|
243
|
-
kind
|
|
345
|
+
kind: resolve_candidate_kind(candidate, kind)
|
|
244
346
|
});
|
|
245
347
|
}
|
|
246
348
|
}
|
|
349
|
+
function resolve_candidate_kind(candidate, context_kind) {
|
|
350
|
+
if (candidate.key === "render_argument") return "render_argument";
|
|
351
|
+
return context_kind;
|
|
352
|
+
}
|
|
247
353
|
function find_candidates(expression, candidates) {
|
|
248
354
|
const found = [];
|
|
249
355
|
visit_expression_value(expression, candidates, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), found);
|
|
@@ -589,6 +695,39 @@ var YieldStarInEventCallbackError = class extends PreprocessError {
|
|
|
589
695
|
this.expression_text = expression_text;
|
|
590
696
|
}
|
|
591
697
|
};
|
|
698
|
+
/**
|
|
699
|
+
* Thrown when async Effect work appears in a markup position SER cannot lower
|
|
700
|
+
* safely.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* ```ts
|
|
704
|
+
* throw new UnsupportedMarkupEffectPositionError(
|
|
705
|
+
* "Component.svelte",
|
|
706
|
+
* "value={yield* load()}",
|
|
707
|
+
* );
|
|
708
|
+
* ```
|
|
709
|
+
*
|
|
710
|
+
* @since 2.4.2
|
|
711
|
+
*/
|
|
712
|
+
var UnsupportedMarkupEffectPositionError = class extends PreprocessError {
|
|
713
|
+
/**
|
|
714
|
+
* The unsupported markup expression text.
|
|
715
|
+
*
|
|
716
|
+
* @since 2.4.2
|
|
717
|
+
*/
|
|
718
|
+
expression_text;
|
|
719
|
+
constructor(filename, expression_text) {
|
|
720
|
+
super([
|
|
721
|
+
make_error_message("UNSUPPORTED_MARKUP_EFFECT_POSITION", `${filename}: yield* cannot be used in this markup position.`),
|
|
722
|
+
`Move the Effect work into a supported expression tag, block expression, render expression, declaration tag, or event handler.`,
|
|
723
|
+
"",
|
|
724
|
+
`Problematic expression:`,
|
|
725
|
+
expression_text
|
|
726
|
+
].join("\n"), filename);
|
|
727
|
+
this.name = "UnsupportedMarkupEffectPositionError";
|
|
728
|
+
this.expression_text = expression_text;
|
|
729
|
+
}
|
|
730
|
+
};
|
|
592
731
|
//#endregion
|
|
593
732
|
//#region src/markup/transform/expressions.ts
|
|
594
733
|
/**
|
|
@@ -693,22 +832,45 @@ function collect_free_identifiers(expr_text) {
|
|
|
693
832
|
const fn = sf.statements[0];
|
|
694
833
|
if (!ts.isFunctionDeclaration(fn) || !fn.body) return [];
|
|
695
834
|
const ids = [];
|
|
835
|
+
const locals = /* @__PURE__ */ new Set();
|
|
696
836
|
const seen = /* @__PURE__ */ new Set();
|
|
697
|
-
visit_ids(fn.body, seen, ids);
|
|
837
|
+
visit_ids(fn.body, locals, seen, ids);
|
|
698
838
|
return ids;
|
|
699
839
|
}
|
|
700
|
-
function visit_ids(node, seen, ids) {
|
|
701
|
-
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node))
|
|
840
|
+
function visit_ids(node, locals, seen, ids) {
|
|
841
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) {
|
|
842
|
+
const scoped = new Set(locals);
|
|
843
|
+
if (ts.isFunctionDeclaration(node) && node.name) scoped.add(node.name.text);
|
|
844
|
+
for (const parameter of node.parameters) add_binding_names(parameter.name, scoped);
|
|
845
|
+
if (node.body) visit_ids(node.body, scoped, seen, ids);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
if (ts.isVariableDeclaration(node)) {
|
|
849
|
+
if (node.initializer) visit_ids(node.initializer, locals, seen, ids);
|
|
850
|
+
add_binding_names(node.name, locals);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (ts.isTypeReferenceNode(node)) return;
|
|
702
854
|
if (ts.isIdentifier(node)) {
|
|
703
855
|
if (node.text === "yield" || node.text === "undefined" || node.text === "null" || node.text === "true" || node.text === "false" || node.text === "this") return;
|
|
704
856
|
if (is_property_access_name(node)) return;
|
|
705
|
-
if (!seen.has(node.text)) {
|
|
857
|
+
if (!locals.has(node.text) && !seen.has(node.text)) {
|
|
706
858
|
seen.add(node.text);
|
|
707
859
|
ids.push(node.text);
|
|
708
860
|
}
|
|
709
861
|
return;
|
|
710
862
|
}
|
|
711
|
-
node.forEachChild((child) => visit_ids(child, seen, ids));
|
|
863
|
+
node.forEachChild((child) => visit_ids(child, locals, seen, ids));
|
|
864
|
+
}
|
|
865
|
+
function add_binding_names(name, locals) {
|
|
866
|
+
if (ts.isIdentifier(name)) {
|
|
867
|
+
locals.add(name.text);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
for (const element of name.elements) {
|
|
871
|
+
if (ts.isOmittedExpression(element)) continue;
|
|
872
|
+
add_binding_names(element.name, locals);
|
|
873
|
+
}
|
|
712
874
|
}
|
|
713
875
|
function visit_event_body(node, context, result) {
|
|
714
876
|
if (is_yield_star_expression$1(node)) {
|
|
@@ -973,10 +1135,10 @@ function to_expr_pos(pos, context) {
|
|
|
973
1135
|
* expression rewrites.
|
|
974
1136
|
* @returns Replacements ready to apply to the original component source.
|
|
975
1137
|
*/
|
|
976
|
-
function emit_replacements(classified, effect_context) {
|
|
977
|
-
return classified.map(({ candidate, kind }) => emit_replacement(candidate, kind, effect_context));
|
|
1138
|
+
function emit_replacements(classified, effect_context, helper_bindings, name_allocator) {
|
|
1139
|
+
return classified.map(({ candidate, kind }) => emit_replacement(candidate, kind, effect_context, helper_bindings, name_allocator));
|
|
978
1140
|
}
|
|
979
|
-
function emit_replacement(candidate, kind, effect_context) {
|
|
1141
|
+
function emit_replacement(candidate, kind, effect_context, helper_bindings, name_allocator) {
|
|
980
1142
|
const normalized = normalize_effect_callback_yields(candidate.expr_text, effect_context);
|
|
981
1143
|
const normalized_candidate = {
|
|
982
1144
|
...candidate,
|
|
@@ -984,24 +1146,28 @@ function emit_replacement(candidate, kind, effect_context) {
|
|
|
984
1146
|
};
|
|
985
1147
|
const id = make_cache_id(candidate);
|
|
986
1148
|
const id_text = JSON.stringify(id);
|
|
987
|
-
const helper_name = make_helper_name(candidate);
|
|
1149
|
+
const helper_name = make_helper_name(candidate, name_allocator);
|
|
988
1150
|
let replacement_text;
|
|
989
1151
|
let helpers;
|
|
990
1152
|
let relocation;
|
|
991
1153
|
if (kind === "await") {
|
|
992
1154
|
const effect = make_effect_helper(normalized_candidate, helper_name);
|
|
993
|
-
replacement_text = emit_promise_expression(id_text, effect);
|
|
1155
|
+
replacement_text = emit_promise_expression(id_text, effect, helper_bindings);
|
|
994
1156
|
helpers = [...normalized.helpers, effect.helper];
|
|
995
1157
|
} else if (kind === "render") {
|
|
996
1158
|
const effect = make_effect_helper(normalized_candidate, helper_name);
|
|
997
|
-
replacement_text = emit_render_expression(id_text, effect);
|
|
1159
|
+
replacement_text = emit_render_expression(id_text, effect, candidate, helper_bindings);
|
|
1160
|
+
helpers = [...normalized.helpers, effect.helper];
|
|
1161
|
+
} else if (kind === "render_argument") {
|
|
1162
|
+
const effect = make_effect_helper(normalized_candidate, helper_name);
|
|
1163
|
+
replacement_text = emit_each_expression(id_text, effect, helper_bindings);
|
|
998
1164
|
helpers = [...normalized.helpers, effect.helper];
|
|
999
1165
|
} else if (kind === "each") {
|
|
1000
1166
|
const effect = make_effect_helper(normalized_candidate, helper_name);
|
|
1001
|
-
replacement_text = emit_each_expression(id_text, effect);
|
|
1167
|
+
replacement_text = emit_each_expression(id_text, effect, helper_bindings);
|
|
1002
1168
|
helpers = [...normalized.helpers, effect.helper];
|
|
1003
1169
|
} else if (kind === "event") {
|
|
1004
|
-
const event = make_event_handler(normalized_candidate);
|
|
1170
|
+
const event = make_event_handler(normalized_candidate, helper_bindings);
|
|
1005
1171
|
replacement_text = event.text;
|
|
1006
1172
|
helpers = normalized.helpers;
|
|
1007
1173
|
relocation = make_relocation(candidate, replacement_text, {
|
|
@@ -1011,7 +1177,7 @@ function emit_replacement(candidate, kind, effect_context) {
|
|
|
1011
1177
|
});
|
|
1012
1178
|
} else {
|
|
1013
1179
|
const effect = make_effect_helper(normalized_candidate, helper_name);
|
|
1014
|
-
replacement_text = emit_each_expression(id_text, effect);
|
|
1180
|
+
replacement_text = emit_each_expression(id_text, effect, helper_bindings);
|
|
1015
1181
|
helpers = [...normalized.helpers, effect.helper];
|
|
1016
1182
|
}
|
|
1017
1183
|
return {
|
|
@@ -1022,31 +1188,32 @@ function emit_replacement(candidate, kind, effect_context) {
|
|
|
1022
1188
|
relocation
|
|
1023
1189
|
};
|
|
1024
1190
|
}
|
|
1025
|
-
function make_event_handler(candidate) {
|
|
1191
|
+
function make_event_handler(candidate, helper_bindings) {
|
|
1026
1192
|
const expr_text = candidate.expr_text;
|
|
1027
1193
|
if (is_callback_function_expression(expr_text)) throw new YieldStarInEventCallbackError(candidate.filename, expr_text);
|
|
1028
1194
|
if (analyze_event_body_yield_star(expr_text).has_nested_invalid_yield_star) throw new AsyncEffectInEventCallbackError(candidate.filename, expr_text);
|
|
1029
1195
|
return {
|
|
1030
1196
|
expr_text,
|
|
1031
|
-
text: `(event) => { ${
|
|
1197
|
+
text: `(event) => { ${helper_bindings.run}(function* () { ${expr_text}; }); }`
|
|
1032
1198
|
};
|
|
1033
1199
|
}
|
|
1034
|
-
function emit_promise_expression(id_text, effect) {
|
|
1035
|
-
return `${
|
|
1200
|
+
function emit_promise_expression(id_text, effect, helper_bindings) {
|
|
1201
|
+
return `${helper_bindings.promise}(${id_text}, ${effect.deps_text}, () => ${effect.call})`;
|
|
1036
1202
|
}
|
|
1037
|
-
function emit_render_expression(id_text, effect) {
|
|
1038
|
-
|
|
1203
|
+
function emit_render_expression(id_text, effect, candidate, helper_bindings) {
|
|
1204
|
+
const expression = emit_promise_expression(id_text, effect, helper_bindings);
|
|
1205
|
+
if (/^\s*yield\s*\*/.test(candidate.expr_text)) return `(await ${expression})()`;
|
|
1206
|
+
return `await ${expression}`;
|
|
1039
1207
|
}
|
|
1040
|
-
function emit_each_expression(id_text, effect) {
|
|
1041
|
-
return `await ${emit_promise_expression(id_text, effect)}`;
|
|
1208
|
+
function emit_each_expression(id_text, effect, helper_bindings) {
|
|
1209
|
+
return `await ${emit_promise_expression(id_text, effect, helper_bindings)}`;
|
|
1042
1210
|
}
|
|
1043
1211
|
function make_effect_helper(candidate, helper_name) {
|
|
1044
1212
|
const deps = collect_free_identifiers(candidate.expr_text);
|
|
1045
|
-
const params_text = deps.join(", ");
|
|
1046
1213
|
const args_text = deps.join(", ");
|
|
1047
1214
|
const deps_text = deps.length === 0 ? "[]" : `[${args_text}]`;
|
|
1048
|
-
const call = `${helper_name}(
|
|
1049
|
-
const text = `function* ${helper_name}(
|
|
1215
|
+
const call = `${helper_name}()`;
|
|
1216
|
+
const text = `function* ${helper_name}() { return (${candidate.expr_text}); }`;
|
|
1050
1217
|
const generated_start = text.indexOf(candidate.expr_text);
|
|
1051
1218
|
return {
|
|
1052
1219
|
call,
|
|
@@ -1063,10 +1230,10 @@ function make_effect_helper(candidate, helper_name) {
|
|
|
1063
1230
|
};
|
|
1064
1231
|
}
|
|
1065
1232
|
function make_cache_id(candidate) {
|
|
1066
|
-
return `${candidate.filename}:${candidate.start}:${candidate.end}`;
|
|
1233
|
+
return `${candidate.filename.replace(/[?#].*$/, "")}:${candidate.start}:${candidate.end}`;
|
|
1067
1234
|
}
|
|
1068
|
-
function make_helper_name(candidate) {
|
|
1069
|
-
return `__SER___markup_effect_${candidate.start}_${candidate.end}
|
|
1235
|
+
function make_helper_name(candidate, name_allocator) {
|
|
1236
|
+
return name_allocator.reserve(`__SER___markup_effect_${candidate.start}_${candidate.end}`);
|
|
1070
1237
|
}
|
|
1071
1238
|
function make_relocation(candidate, replacement_text, inner) {
|
|
1072
1239
|
const generated_start = replacement_text.indexOf(inner.generatedText);
|
|
@@ -1174,7 +1341,7 @@ function sanitize_markup(content, filename) {
|
|
|
1174
1341
|
const open = content.indexOf("{", cursor);
|
|
1175
1342
|
if (open === -1) break;
|
|
1176
1343
|
/** Skip braces inside <script> and <style> blocks. */
|
|
1177
|
-
if (is_inside_excluded_block(content, open)) {
|
|
1344
|
+
if (is_inside_excluded_block(content, open) || is_inside_html_comment(content, open)) {
|
|
1178
1345
|
cursor = open + 1;
|
|
1179
1346
|
continue;
|
|
1180
1347
|
}
|
|
@@ -1239,6 +1406,26 @@ function sanitize_markup(content, filename) {
|
|
|
1239
1406
|
cursor = close + 1;
|
|
1240
1407
|
continue;
|
|
1241
1408
|
}
|
|
1409
|
+
if (key === "render" && !/^\s*yield\s*\*/.test(expr_text)) {
|
|
1410
|
+
const render_arg_yields = collect_expression_yield_expressions(content, expr_start, expr_text);
|
|
1411
|
+
if (render_arg_yields.length > 0) {
|
|
1412
|
+
for (const render_arg_yield of render_arg_yields) {
|
|
1413
|
+
const placeholder = `__SER___markup_placeholder_${helper_index}`;
|
|
1414
|
+
helper_index += 1;
|
|
1415
|
+
candidates.push({
|
|
1416
|
+
placeholder,
|
|
1417
|
+
start: render_arg_yield.start,
|
|
1418
|
+
end: render_arg_yield.end,
|
|
1419
|
+
expr_text: render_arg_yield.expr_text,
|
|
1420
|
+
filename,
|
|
1421
|
+
key: "render_argument"
|
|
1422
|
+
});
|
|
1423
|
+
magic.overwrite(render_arg_yield.start, render_arg_yield.end, placeholder);
|
|
1424
|
+
}
|
|
1425
|
+
cursor = close + 1;
|
|
1426
|
+
continue;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1242
1429
|
/** Create a placeholder and replace the expression (preserving tag prefixes). */
|
|
1243
1430
|
const placeholder = `__SER___markup_placeholder_${helper_index}`;
|
|
1244
1431
|
helper_index += 1;
|
|
@@ -1258,11 +1445,36 @@ function sanitize_markup(content, filename) {
|
|
|
1258
1445
|
candidates
|
|
1259
1446
|
};
|
|
1260
1447
|
}
|
|
1448
|
+
function collect_expression_yield_expressions(content, expr_start, expr_text) {
|
|
1449
|
+
const source_file = ts.createSourceFile("markup-expression.ts", `const __SER___expr = ${expr_text};`, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
1450
|
+
const stmt = source_file.statements[0];
|
|
1451
|
+
if (!stmt || !ts.isVariableStatement(stmt)) return [];
|
|
1452
|
+
const initializer = stmt.declarationList.declarations[0]?.initializer;
|
|
1453
|
+
if (!initializer || !contains_top_level_yield_star(initializer)) return [];
|
|
1454
|
+
const prefix_length = source_file.text.indexOf(expr_text);
|
|
1455
|
+
const expressions = [];
|
|
1456
|
+
collect_yield_star_nodes(initializer, (yield_node) => {
|
|
1457
|
+
const start = expr_start + yield_node.getStart(source_file) - prefix_length;
|
|
1458
|
+
const end = expr_start + yield_node.end - prefix_length;
|
|
1459
|
+
const yielded_text = content.slice(start, end).trim();
|
|
1460
|
+
expressions.push({
|
|
1461
|
+
start,
|
|
1462
|
+
end,
|
|
1463
|
+
expr_text: yielded_text
|
|
1464
|
+
});
|
|
1465
|
+
});
|
|
1466
|
+
return expressions;
|
|
1467
|
+
}
|
|
1261
1468
|
function is_inside_excluded_block(content, pos) {
|
|
1262
1469
|
const script = find_tag_end(content, "script", pos);
|
|
1263
1470
|
const style = find_tag_end(content, "style", pos);
|
|
1264
1471
|
return script !== void 0 && pos < script.end && pos > script.start || style !== void 0 && pos < style.end && pos > style.start;
|
|
1265
1472
|
}
|
|
1473
|
+
function is_inside_html_comment(content, pos) {
|
|
1474
|
+
const open = content.lastIndexOf("<!--", pos);
|
|
1475
|
+
const close = content.lastIndexOf("-->", pos);
|
|
1476
|
+
return open !== -1 && open > close;
|
|
1477
|
+
}
|
|
1266
1478
|
function find_tag_end(content, tag, after_pos) {
|
|
1267
1479
|
const pattern = new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)<\\/${tag}\\s*>`, "gi");
|
|
1268
1480
|
for (const match of content.matchAll(pattern)) {
|
|
@@ -1388,6 +1600,7 @@ function is_event_callback_expression(inner) {
|
|
|
1388
1600
|
function analyze_event_yield(inner) {
|
|
1389
1601
|
const event = strip_arrow_function(inner);
|
|
1390
1602
|
const analysis = analyze_event_body_yield_star(event.body);
|
|
1603
|
+
if (new RegExp(`${HELPERS.run}(?:_\\d+)?\\(function\\*`).test(event.body)) return { has_top_level_yield_star: false };
|
|
1391
1604
|
return { has_top_level_yield_star: analysis.has_top_level_yield_star || analysis.has_nested_invalid_yield_star || /\byield\s*\*/.test(event.body) };
|
|
1392
1605
|
}
|
|
1393
1606
|
function contains_yield_star_in_text(text) {
|
|
@@ -1429,19 +1642,25 @@ function transform_markup_effect(content, filename) {
|
|
|
1429
1642
|
/** Find all brace expressions containing yield* and replace with placeholders. */
|
|
1430
1643
|
const work = sanitize_markup(content, filename);
|
|
1431
1644
|
const effect_context = collect_effect_callback_bindings(content);
|
|
1645
|
+
const helper_context = make_markup_helper_bindings(content);
|
|
1432
1646
|
if (work.candidates.length === 0) return {
|
|
1433
1647
|
code: content,
|
|
1434
1648
|
has_yield: false
|
|
1435
1649
|
};
|
|
1436
|
-
|
|
1650
|
+
/** Match placeholders to their AST context and build replacements. */
|
|
1651
|
+
const classified = classify_candidates(parse(blank_script_blocks(work.code), {
|
|
1437
1652
|
filename,
|
|
1438
1653
|
modern: true
|
|
1439
|
-
}), work.candidates)
|
|
1654
|
+
}), work.candidates);
|
|
1655
|
+
const matched = new Set(classified.map(({ candidate }) => candidate.placeholder));
|
|
1656
|
+
const unmatched = work.candidates.find((candidate) => !matched.has(candidate.placeholder));
|
|
1657
|
+
if (unmatched) throw new UnsupportedMarkupEffectPositionError(filename, unmatched.expr_text);
|
|
1658
|
+
const replacements = emit_replacements(classified, effect_context, helper_context.bindings, helper_context.name_allocator);
|
|
1440
1659
|
const helpers = replacements.flatMap((replacement) => replacement.helpers ?? []);
|
|
1441
1660
|
const magic = new MagicString(content);
|
|
1442
1661
|
replacements.sort((a, b) => b.start - a.start);
|
|
1443
1662
|
for (const r of replacements) magic.overwrite(r.start, r.end, r.text);
|
|
1444
|
-
const relocations = create_relocations(replacements, inject_helpers(magic, content, helpers));
|
|
1663
|
+
const relocations = create_relocations(replacements, inject_helpers(magic, content, helpers, helper_context.bindings));
|
|
1445
1664
|
return {
|
|
1446
1665
|
code: magic.toString(),
|
|
1447
1666
|
has_yield: true,
|
|
@@ -1450,6 +1669,6 @@ function transform_markup_effect(content, filename) {
|
|
|
1450
1669
|
};
|
|
1451
1670
|
}
|
|
1452
1671
|
//#endregion
|
|
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 };
|
|
1672
|
+
export { find_yield_star_node as a, AsyncEffectInSyncRuneError as c, collect_top_level_binding_names as d, has_local_import_binding as f, extract_binding_names as i, AwaitInEffectWorkError as l, collect_yield_star_nodes as n, is_yield_star_expression as o, make_imports as p, contains_top_level_await as r, collect_free_identifiers as s, transform_markup_effect as t, PreprocessError as u };
|
|
1454
1673
|
|
|
1455
|
-
//# sourceMappingURL=transform-
|
|
1674
|
+
//# sourceMappingURL=transform-Cx5bjmP6.js.map
|