ripple 0.2.208 → 0.2.211
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/CHANGELOG.md +57 -0
- package/README.md +2 -1
- package/package.json +2 -6
- package/shims/rollup-estree-types.d.ts +1 -1
- package/src/compiler/index.d.ts +1 -0
- package/src/compiler/index.js +7 -1
- package/src/compiler/phases/1-parse/index.js +24 -7
- package/src/compiler/phases/2-analyze/css-analyze.js +100 -104
- package/src/compiler/phases/2-analyze/index.js +215 -2
- package/src/compiler/phases/3-transform/client/index.js +388 -50
- package/src/compiler/phases/3-transform/segments.js +123 -39
- package/src/compiler/phases/3-transform/server/index.js +266 -13
- package/src/compiler/types/index.d.ts +15 -3
- package/src/compiler/utils.js +1 -15
- package/src/constants.js +0 -2
- package/src/helpers.d.ts +4 -0
- package/src/html-tree-validation.js +211 -0
- package/src/jsx-runtime.d.ts +260 -259
- package/src/jsx-runtime.js +12 -12
- package/src/runtime/array.js +17 -17
- package/src/runtime/create-subscriber.js +1 -1
- package/src/runtime/index-client.js +1 -5
- package/src/runtime/index-server.js +15 -0
- package/src/runtime/internal/client/compat.js +3 -3
- package/src/runtime/internal/client/composite.js +6 -1
- package/src/runtime/internal/client/head.js +50 -4
- package/src/runtime/internal/client/html.js +73 -12
- package/src/runtime/internal/client/hydration.js +12 -0
- package/src/runtime/internal/client/index.js +1 -1
- package/src/runtime/internal/client/portal.js +54 -29
- package/src/runtime/internal/client/rpc.js +3 -1
- package/src/runtime/internal/client/switch.js +5 -0
- package/src/runtime/internal/client/template.js +119 -12
- package/src/runtime/internal/client/try.js +1 -0
- package/src/runtime/internal/server/index.js +113 -1
- package/src/runtime/internal/server/rpc.js +4 -4
- package/src/runtime/map.js +2 -2
- package/src/runtime/object.js +6 -6
- package/src/runtime/proxy.js +12 -11
- package/src/runtime/reactive-value.js +9 -1
- package/src/runtime/set.js +12 -7
- package/src/runtime/url-search-params.js +0 -1
- package/src/server/index.js +4 -0
- package/src/utils/hashing.js +15 -0
- package/src/utils/normalize_css_property_name.js +1 -1
- package/tests/client/array/array.mutations.test.ripple +8 -8
- package/tests/client/basic/basic.errors.test.ripple +28 -0
- package/tests/client/basic/basic.events.test.ripple +6 -3
- package/tests/client/basic/basic.utilities.test.ripple +1 -1
- package/tests/client/compiler/compiler.regex.test.ripple +10 -8
- package/tests/client/composite/composite.generics.test.ripple +5 -2
- package/tests/client/dynamic-elements.test.ripple +30 -1
- package/tests/client/function-overload-import.ripple +6 -7
- package/tests/client/html.test.ripple +0 -1
- package/tests/client/object.test.ripple +2 -2
- package/tests/client/portal.test.ripple +3 -3
- package/tests/client/return.test.ripple +2500 -0
- package/tests/client/try.test.ripple +69 -0
- package/tests/client/typescript-generics.test.ripple +1 -1
- package/tests/client/url/url.derived.test.ripple +1 -1
- package/tests/client/url/url.parsing.test.ripple +3 -3
- package/tests/client/url/url.partial-removal.test.ripple +7 -7
- package/tests/client/url/url.reactivity.test.ripple +15 -15
- package/tests/client/url/url.serialization.test.ripple +2 -2
- package/tests/hydration/basic.test.js +23 -0
- package/tests/hydration/build-components.js +10 -4
- package/tests/hydration/compiled/client/basic.js +165 -3
- package/tests/hydration/compiled/client/composite.js +139 -0
- package/tests/hydration/compiled/client/for.js +1140 -23
- package/tests/hydration/compiled/client/head.js +234 -0
- package/tests/hydration/compiled/client/html.js +135 -0
- package/tests/hydration/compiled/client/portal.js +172 -0
- package/tests/hydration/compiled/client/reactivity.js +3 -1
- package/tests/hydration/compiled/client/return.js +1976 -0
- package/tests/hydration/compiled/client/switch.js +162 -0
- package/tests/hydration/compiled/server/basic.js +249 -0
- package/tests/hydration/compiled/server/composite.js +176 -0
- package/tests/hydration/compiled/server/events.js +1 -1
- package/tests/hydration/compiled/server/for.js +891 -1
- package/tests/hydration/compiled/server/head.js +291 -0
- package/tests/hydration/compiled/server/html.js +133 -0
- package/tests/hydration/compiled/server/if.js +1 -1
- package/tests/hydration/compiled/server/portal.js +250 -0
- package/tests/hydration/compiled/server/reactivity.js +1 -1
- package/tests/hydration/compiled/server/return.js +1969 -0
- package/tests/hydration/compiled/server/switch.js +130 -0
- package/tests/hydration/components/basic.ripple +55 -0
- package/tests/hydration/components/composite.ripple +37 -0
- package/tests/hydration/components/for.ripple +403 -0
- package/tests/hydration/components/head.ripple +111 -0
- package/tests/hydration/components/html.ripple +38 -0
- package/tests/hydration/components/portal.ripple +49 -0
- package/tests/hydration/components/return.ripple +564 -0
- package/tests/hydration/components/switch.ripple +51 -0
- package/tests/hydration/composite.test.js +42 -0
- package/tests/hydration/for.test.js +363 -0
- package/tests/hydration/head.test.js +105 -0
- package/tests/hydration/html.test.js +46 -0
- package/tests/hydration/portal.test.js +71 -0
- package/tests/hydration/return.test.js +544 -0
- package/tests/hydration/switch.test.js +42 -0
- package/tests/server/basic.attributes.test.ripple +1 -1
- package/tests/server/compiler.test.ripple +22 -0
- package/tests/server/composite.test.ripple +5 -2
- package/tests/server/html-nesting-validation.test.ripple +237 -0
- package/tests/server/return.test.ripple +1379 -0
- package/tests/setup-hydration.js +6 -1
- package/tests/utils/escaping.test.js +3 -1
- package/tests/utils/normalize_css_property_name.test.js +0 -1
- package/tests/utils/patterns.test.js +6 -2
- package/tests/utils/sanitize_template_string.test.js +3 -2
- package/types/server.d.ts +16 -0
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
index_to_key,
|
|
56
56
|
is_element_dynamic,
|
|
57
57
|
is_inside_left_side_assignment,
|
|
58
|
+
hash,
|
|
58
59
|
} from '../../../utils.js';
|
|
59
60
|
import {
|
|
60
61
|
CSS_HASH_IDENTIFIER,
|
|
@@ -130,9 +131,10 @@ function visit_function(node, context) {
|
|
|
130
131
|
|
|
131
132
|
/**
|
|
132
133
|
* @param {AST.Element} node
|
|
134
|
+
* @param {number} index
|
|
133
135
|
* @param {TransformClientContext} context
|
|
134
136
|
*/
|
|
135
|
-
function visit_head_element(node, context) {
|
|
137
|
+
function visit_head_element(node, index, context) {
|
|
136
138
|
const { state, visit } = context;
|
|
137
139
|
|
|
138
140
|
/** @type {TransformClientState['init']} */
|
|
@@ -154,10 +156,16 @@ function visit_head_element(node, context) {
|
|
|
154
156
|
);
|
|
155
157
|
|
|
156
158
|
if (init.length > 0 || update.length > 0 || final.length > 0) {
|
|
159
|
+
// Generate a hash for this head element based on filename and index
|
|
160
|
+
// Use both filename and index to ensure uniqueness across multiple head blocks
|
|
161
|
+
const hash_source = `${state.filename}:head:${index}:${node.start ?? 0}`;
|
|
162
|
+
const hash_value = hash(hash_source);
|
|
163
|
+
|
|
157
164
|
context.state.init?.push(
|
|
158
165
|
b.stmt(
|
|
159
166
|
b.call(
|
|
160
167
|
'_$_.head',
|
|
168
|
+
b.literal(hash_value),
|
|
161
169
|
b.arrow(
|
|
162
170
|
[b.id('__anchor')],
|
|
163
171
|
b.block([
|
|
@@ -1466,7 +1474,13 @@ const visitors = {
|
|
|
1466
1474
|
node.children,
|
|
1467
1475
|
/** @type {VisitorClientContext} */ ({
|
|
1468
1476
|
visit,
|
|
1469
|
-
state: {
|
|
1477
|
+
state: {
|
|
1478
|
+
...state,
|
|
1479
|
+
init,
|
|
1480
|
+
update,
|
|
1481
|
+
namespace: child_namespace,
|
|
1482
|
+
skip_children_traversal: true,
|
|
1483
|
+
},
|
|
1470
1484
|
root: false,
|
|
1471
1485
|
}),
|
|
1472
1486
|
);
|
|
@@ -2105,6 +2119,44 @@ const visitors = {
|
|
|
2105
2119
|
const id = context.state.flush_node?.();
|
|
2106
2120
|
const statements = [];
|
|
2107
2121
|
|
|
2122
|
+
// Optimize lone return: if (cond) { return; } with no alternate
|
|
2123
|
+
if (node.metadata?.lone_return && context.state.return_flags) {
|
|
2124
|
+
const consequent_body =
|
|
2125
|
+
node.consequent.type === 'BlockStatement' ? node.consequent.body : [node.consequent];
|
|
2126
|
+
const ret = /** @type {AST.ReturnStatement} */ (consequent_body[0]);
|
|
2127
|
+
const info = context.state.return_flags.get(ret);
|
|
2128
|
+
|
|
2129
|
+
if (info) {
|
|
2130
|
+
/** @type {AST.Statement[]} */
|
|
2131
|
+
const callback_body = [];
|
|
2132
|
+
|
|
2133
|
+
if (info.tracked) {
|
|
2134
|
+
callback_body.push(b.stmt(b.call('_$_.set', b.id(info.name), b.false)));
|
|
2135
|
+
callback_body.push(
|
|
2136
|
+
b.if(
|
|
2137
|
+
/** @type {AST.Expression} */ (context.visit(node.test)),
|
|
2138
|
+
b.stmt(b.call('_$_.set', b.id(info.name), b.true)),
|
|
2139
|
+
),
|
|
2140
|
+
);
|
|
2141
|
+
} else {
|
|
2142
|
+
callback_body.push(b.stmt(b.assignment('=', b.id(info.name), b.false)));
|
|
2143
|
+
callback_body.push(
|
|
2144
|
+
b.if(
|
|
2145
|
+
/** @type {AST.Expression} */ (context.visit(node.test)),
|
|
2146
|
+
b.stmt(b.assignment('=', b.id(info.name), b.true)),
|
|
2147
|
+
),
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
statements.push(
|
|
2152
|
+
b.stmt(b.call('_$_.if', id, b.arrow([b.id('__render')], b.block(callback_body)))),
|
|
2153
|
+
);
|
|
2154
|
+
|
|
2155
|
+
context.state.init?.push(b.block(statements));
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2108
2160
|
const consequent_scope =
|
|
2109
2161
|
/** @type {ScopeInterface} */ (context.state.scopes.get(node.consequent)) ||
|
|
2110
2162
|
context.state.scope;
|
|
@@ -2137,36 +2189,65 @@ const visitors = {
|
|
|
2137
2189
|
statements.push(b.var(b.id(alternate_id), b.arrow([b.id('__anchor')], alternate_block)));
|
|
2138
2190
|
}
|
|
2139
2191
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2192
|
+
// Collect return flag resets for IfStatements that contain returns
|
|
2193
|
+
/** @type {AST.Statement[]} */
|
|
2194
|
+
const callback_body = [];
|
|
2195
|
+
|
|
2196
|
+
if (node.metadata?.has_return && context.state.return_flags) {
|
|
2197
|
+
const returns = node.metadata.returns || [];
|
|
2198
|
+
for (const ret of returns) {
|
|
2199
|
+
const info = context.state.return_flags.get(ret);
|
|
2200
|
+
if (info) {
|
|
2201
|
+
if (info.tracked) {
|
|
2202
|
+
callback_body.push(b.stmt(b.call('_$_.set', b.id(info.name), b.false)));
|
|
2203
|
+
} else {
|
|
2204
|
+
callback_body.push(b.stmt(b.assignment('=', b.id(info.name), b.false)));
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
callback_body.push(
|
|
2211
|
+
b.if(
|
|
2212
|
+
/** @type {AST.Expression} */ (context.visit(node.test)),
|
|
2213
|
+
b.stmt(b.call(b.id('__render'), b.id(consequent_id))),
|
|
2214
|
+
alternate_id
|
|
2215
|
+
? b.stmt(
|
|
2216
|
+
b.call(
|
|
2217
|
+
b.id('__render'),
|
|
2218
|
+
b.id(alternate_id),
|
|
2219
|
+
node.alternate ? b.literal(false) : undefined,
|
|
2160
2220
|
),
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
),
|
|
2221
|
+
)
|
|
2222
|
+
: undefined,
|
|
2164
2223
|
),
|
|
2165
2224
|
);
|
|
2166
2225
|
|
|
2226
|
+
statements.push(
|
|
2227
|
+
b.stmt(b.call('_$_.if', id, b.arrow([b.id('__render')], b.block(callback_body)))),
|
|
2228
|
+
);
|
|
2229
|
+
|
|
2167
2230
|
context.state.init?.push(b.block(statements));
|
|
2168
2231
|
},
|
|
2169
2232
|
|
|
2233
|
+
ReturnStatement(node, context) {
|
|
2234
|
+
if (!is_inside_component(context)) {
|
|
2235
|
+
return context.next();
|
|
2236
|
+
}
|
|
2237
|
+
if (context.state.to_ts) {
|
|
2238
|
+
return context.next();
|
|
2239
|
+
}
|
|
2240
|
+
const info = context.state.return_flags?.get(node);
|
|
2241
|
+
if (info) {
|
|
2242
|
+
if (info.tracked) {
|
|
2243
|
+
return b.stmt(b.call('_$_.set', b.id(info.name), b.true));
|
|
2244
|
+
} else {
|
|
2245
|
+
return b.stmt(b.assignment('=', b.id(info.name), b.true));
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
return context.next();
|
|
2249
|
+
},
|
|
2250
|
+
|
|
2170
2251
|
TSAsExpression(node, context) {
|
|
2171
2252
|
if (!context.state.to_ts) {
|
|
2172
2253
|
return context.visit(/** @type {AST.Expression} */ (node.expression));
|
|
@@ -2525,26 +2606,30 @@ function transform_ts_child(node, context) {
|
|
|
2525
2606
|
|
|
2526
2607
|
const jsx_attr = b.jsx_attribute(
|
|
2527
2608
|
jsx_name,
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
/** @type {AST.
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2609
|
+
// match the source code usage of expressions for literals
|
|
2610
|
+
// for proper source mapping to avoid turning strings into expressions
|
|
2611
|
+
attr_value?.type === 'Literal' && !attr_value.was_expression
|
|
2612
|
+
? /** @type {AST.Literal} */ (value)
|
|
2613
|
+
: b.jsx_expression_container(
|
|
2614
|
+
/** @type {AST.Expression} */ (value),
|
|
2615
|
+
attr_value === null
|
|
2616
|
+
? /** @type {AST.NodeWithLocation} */ (value)
|
|
2617
|
+
: // account location for opening and closing braces around the expression
|
|
2618
|
+
/** @type {AST.NodeWithLocation} */ ({
|
|
2619
|
+
start: attr_value.start - 1,
|
|
2620
|
+
end: attr_value.end + 1,
|
|
2621
|
+
loc: {
|
|
2622
|
+
start: {
|
|
2623
|
+
line: attr_value.loc.start.line,
|
|
2624
|
+
column: attr_value.loc.start.column - 1,
|
|
2625
|
+
},
|
|
2626
|
+
end: {
|
|
2627
|
+
line: attr_value.loc.end.line,
|
|
2628
|
+
column: attr_value.loc.end.column + 1,
|
|
2629
|
+
},
|
|
2630
|
+
},
|
|
2631
|
+
}),
|
|
2632
|
+
),
|
|
2548
2633
|
attr.shorthand ?? false,
|
|
2549
2634
|
/** @type {AST.NodeWithLocation} */ (attr),
|
|
2550
2635
|
);
|
|
@@ -2589,6 +2674,7 @@ function transform_ts_child(node, context) {
|
|
|
2589
2674
|
/** @type {AST.Identifier} */ (node.id).name === 'head'
|
|
2590
2675
|
? true
|
|
2591
2676
|
: state.inside_head,
|
|
2677
|
+
skip_children_traversal: is_dom_element,
|
|
2592
2678
|
},
|
|
2593
2679
|
}),
|
|
2594
2680
|
),
|
|
@@ -2848,6 +2934,71 @@ function transform_ts_child(node, context) {
|
|
|
2848
2934
|
}
|
|
2849
2935
|
}
|
|
2850
2936
|
|
|
2937
|
+
/**
|
|
2938
|
+
* Checks if a node is template or control-flow content
|
|
2939
|
+
* @param {AST.Node} node
|
|
2940
|
+
* @returns {boolean}
|
|
2941
|
+
*/
|
|
2942
|
+
function is_template_or_control_flow(node) {
|
|
2943
|
+
return (
|
|
2944
|
+
node.type === 'Element' ||
|
|
2945
|
+
node.type === 'Text' ||
|
|
2946
|
+
node.type === 'Html' ||
|
|
2947
|
+
node.type === 'TsxCompat' ||
|
|
2948
|
+
node.type === 'IfStatement' ||
|
|
2949
|
+
node.type === 'ForOfStatement' ||
|
|
2950
|
+
node.type === 'TryStatement' ||
|
|
2951
|
+
node.type === 'SwitchStatement'
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
/**
|
|
2956
|
+
* Builds a negated AND condition from return flag info: !flag1 && !flag2 && ...
|
|
2957
|
+
* Uses _$_.get() for tracked flags and direct reference for plain booleans.
|
|
2958
|
+
* @param {{ name: string, tracked: boolean }[]} flags
|
|
2959
|
+
* @returns {AST.Expression}
|
|
2960
|
+
*/
|
|
2961
|
+
function build_return_guard(flags) {
|
|
2962
|
+
/** @param {{ name: string, tracked: boolean }} flag */
|
|
2963
|
+
const negate_flag = (flag) =>
|
|
2964
|
+
flag.tracked ? b.unary('!', b.call('_$_.get', b.id(flag.name))) : b.unary('!', b.id(flag.name));
|
|
2965
|
+
|
|
2966
|
+
/** @type {AST.Expression} */
|
|
2967
|
+
let condition = negate_flag(flags[0]);
|
|
2968
|
+
for (let i = 1; i < flags.length; i++) {
|
|
2969
|
+
condition = b.logical('&&', condition, negate_flag(flags[i]));
|
|
2970
|
+
}
|
|
2971
|
+
return condition;
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
/**
|
|
2975
|
+
* Collects all unique return statements from direct children
|
|
2976
|
+
* @param {AST.Node[]} children
|
|
2977
|
+
* @returns {AST.ReturnStatement[]}
|
|
2978
|
+
*/
|
|
2979
|
+
function collect_returns_from_children(children) {
|
|
2980
|
+
/** @type {AST.ReturnStatement[]} */
|
|
2981
|
+
const returns = [];
|
|
2982
|
+
const seen = new Set();
|
|
2983
|
+
for (const node of children) {
|
|
2984
|
+
if (node.type === 'ReturnStatement') {
|
|
2985
|
+
if (!seen.has(node)) {
|
|
2986
|
+
seen.add(node);
|
|
2987
|
+
returns.push(node);
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
if (node.metadata?.returns) {
|
|
2991
|
+
for (const ret of node.metadata.returns) {
|
|
2992
|
+
if (!seen.has(ret)) {
|
|
2993
|
+
seen.add(ret);
|
|
2994
|
+
returns.push(ret);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return returns;
|
|
3000
|
+
}
|
|
3001
|
+
|
|
2851
3002
|
/**
|
|
2852
3003
|
*
|
|
2853
3004
|
* @param {AST.Node[]} children
|
|
@@ -2866,6 +3017,36 @@ function transform_children(children, context) {
|
|
|
2866
3017
|
)
|
|
2867
3018
|
);
|
|
2868
3019
|
|
|
3020
|
+
const all_returns = collect_returns_from_children(normalized);
|
|
3021
|
+
/** @type {Map<AST.ReturnStatement, { name: string, tracked: boolean }>} */
|
|
3022
|
+
const return_flags = new Map([...(state.return_flags || [])]);
|
|
3023
|
+
/** @type {AST.ReturnStatement[]} */
|
|
3024
|
+
const new_returns = [];
|
|
3025
|
+
for (const ret of all_returns) {
|
|
3026
|
+
if (!return_flags.has(ret)) {
|
|
3027
|
+
return_flags.set(ret, {
|
|
3028
|
+
name: state.scope.generate('__r'),
|
|
3029
|
+
tracked: ret.metadata?.is_reactive ?? false,
|
|
3030
|
+
});
|
|
3031
|
+
new_returns.push(ret);
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
if (!state.to_ts) {
|
|
3036
|
+
for (const ret of new_returns) {
|
|
3037
|
+
const info = /** @type {{ name: string, tracked: boolean }} */ (return_flags.get(ret));
|
|
3038
|
+
if (info.tracked) {
|
|
3039
|
+
state.init?.unshift(b.var(b.id(info.name), b.call('_$_.tracked', b.false)));
|
|
3040
|
+
} else {
|
|
3041
|
+
state.init?.unshift(b.var(b.id(info.name), b.false));
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
/** @type {{ name: string, tracked: boolean }[]} */
|
|
3047
|
+
const accumulated_return_flags = [];
|
|
3048
|
+
const has_returns = all_returns.length > 0;
|
|
3049
|
+
|
|
2869
3050
|
const is_fragment =
|
|
2870
3051
|
normalized.some(
|
|
2871
3052
|
(node) =>
|
|
@@ -2883,6 +3064,7 @@ function transform_children(children, context) {
|
|
|
2883
3064
|
).length > 1;
|
|
2884
3065
|
/** @type {AST.Identifier | null} */
|
|
2885
3066
|
let initial = null;
|
|
3067
|
+
/** @type {(() => AST.Identifier) | null} */
|
|
2886
3068
|
let prev = null;
|
|
2887
3069
|
let template_id = null;
|
|
2888
3070
|
|
|
@@ -2913,7 +3095,97 @@ function transform_children(children, context) {
|
|
|
2913
3095
|
state.init?.push(b.var(id, b.call(template_id)));
|
|
2914
3096
|
};
|
|
2915
3097
|
|
|
2916
|
-
|
|
3098
|
+
/** @type {AST.Node[]} */
|
|
3099
|
+
let pending_group = [];
|
|
3100
|
+
/** @type {{ name: string, tracked: boolean }[]} */
|
|
3101
|
+
let pending_guard_flags = [];
|
|
3102
|
+
|
|
3103
|
+
let skipped = 0;
|
|
3104
|
+
|
|
3105
|
+
const flush_pending_group = () => {
|
|
3106
|
+
if (pending_group.length === 0) return;
|
|
3107
|
+
|
|
3108
|
+
const guard_flags = pending_guard_flags;
|
|
3109
|
+
const group_nodes = pending_group;
|
|
3110
|
+
pending_group = [];
|
|
3111
|
+
pending_guard_flags = [];
|
|
3112
|
+
|
|
3113
|
+
// Push <!> placeholder for the _$_.if anchor
|
|
3114
|
+
state.template?.push('<!>');
|
|
3115
|
+
|
|
3116
|
+
if (initial === null && root) {
|
|
3117
|
+
create_initial(group_nodes[0]);
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
const current_prev = prev;
|
|
3121
|
+
/** @type {AST.Identifier | null} */
|
|
3122
|
+
let cached_anchor = null;
|
|
3123
|
+
const group_flush_node = () => {
|
|
3124
|
+
if (cached_anchor) return cached_anchor;
|
|
3125
|
+
const id = b.id(state.scope.generate('node'));
|
|
3126
|
+
if (current_prev !== null) {
|
|
3127
|
+
state.init?.push(b.var(id, b.call('_$_.sibling', current_prev())));
|
|
3128
|
+
} else if (initial !== null) {
|
|
3129
|
+
if (is_fragment) {
|
|
3130
|
+
state.init?.push(b.var(id, b.call('_$_.first_child_frag', initial)));
|
|
3131
|
+
} else {
|
|
3132
|
+
cached_anchor = initial;
|
|
3133
|
+
return initial;
|
|
3134
|
+
}
|
|
3135
|
+
} else if (state.flush_node !== null) {
|
|
3136
|
+
state.init?.push(b.var(id, b.call('_$_.child', state.flush_node?.())));
|
|
3137
|
+
}
|
|
3138
|
+
cached_anchor = id;
|
|
3139
|
+
return id;
|
|
3140
|
+
};
|
|
3141
|
+
|
|
3142
|
+
prev = group_flush_node;
|
|
3143
|
+
|
|
3144
|
+
const anchor = group_flush_node();
|
|
3145
|
+
|
|
3146
|
+
// Process group nodes through transform_body
|
|
3147
|
+
const body = transform_body(group_nodes, {
|
|
3148
|
+
...context,
|
|
3149
|
+
state: { ...context.state, flush_node: null, return_flags },
|
|
3150
|
+
});
|
|
3151
|
+
|
|
3152
|
+
const content_id = state.scope.generate('content');
|
|
3153
|
+
const guard_condition = build_return_guard(guard_flags);
|
|
3154
|
+
|
|
3155
|
+
/** @type {AST.Statement[]} */
|
|
3156
|
+
const callback_body = [
|
|
3157
|
+
b.if(guard_condition, b.stmt(b.call(b.id('__render'), b.id(content_id)))),
|
|
3158
|
+
];
|
|
3159
|
+
|
|
3160
|
+
state.init?.push(b.var(b.id(content_id), b.arrow([b.id('__anchor')], b.block(body))));
|
|
3161
|
+
state.init?.push(
|
|
3162
|
+
b.stmt(b.call('_$_.if', anchor, b.arrow([b.id('__render')], b.block(callback_body)))),
|
|
3163
|
+
);
|
|
3164
|
+
};
|
|
3165
|
+
|
|
3166
|
+
for (let node_idx = 0; node_idx < normalized.length; node_idx++) {
|
|
3167
|
+
const node = normalized[node_idx];
|
|
3168
|
+
|
|
3169
|
+
if (accumulated_return_flags.length > 0 && is_template_or_control_flow(node) && !state.to_ts) {
|
|
3170
|
+
if (pending_group.length === 0) {
|
|
3171
|
+
pending_guard_flags = [...accumulated_return_flags];
|
|
3172
|
+
}
|
|
3173
|
+
pending_group.push(node);
|
|
3174
|
+
|
|
3175
|
+
if (node.metadata?.has_return && node.metadata.returns) {
|
|
3176
|
+
flush_pending_group();
|
|
3177
|
+
for (const ret of node.metadata.returns) {
|
|
3178
|
+
const info = return_flags.get(ret);
|
|
3179
|
+
if (info && !accumulated_return_flags.some((f) => f.name === info.name)) {
|
|
3180
|
+
accumulated_return_flags.push(info);
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
continue;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
flush_pending_group();
|
|
3188
|
+
|
|
2917
3189
|
if (
|
|
2918
3190
|
node.type === 'VariableDeclaration' ||
|
|
2919
3191
|
node.type === 'ExpressionStatement' ||
|
|
@@ -2923,16 +3195,25 @@ function transform_children(children, context) {
|
|
|
2923
3195
|
node.type === 'ClassDeclaration' ||
|
|
2924
3196
|
node.type === 'TSTypeAliasDeclaration' ||
|
|
2925
3197
|
node.type === 'TSInterfaceDeclaration' ||
|
|
3198
|
+
node.type === 'ReturnStatement' ||
|
|
2926
3199
|
node.type === 'Component'
|
|
2927
3200
|
) {
|
|
2928
3201
|
const metadata = { await: false };
|
|
2929
|
-
state.init?.push(
|
|
3202
|
+
state.init?.push(
|
|
3203
|
+
/** @type {AST.Statement} */ (visit(node, { ...state, return_flags, metadata })),
|
|
3204
|
+
);
|
|
2930
3205
|
if (metadata.await) {
|
|
2931
3206
|
state.init?.push(b.if(b.call('_$_.aborted'), b.return(null)));
|
|
2932
3207
|
if (state.metadata?.await === false) {
|
|
2933
3208
|
state.metadata.await = true;
|
|
2934
3209
|
}
|
|
2935
3210
|
}
|
|
3211
|
+
if (!state.to_ts && node.type === 'ReturnStatement') {
|
|
3212
|
+
const info = return_flags.get(node);
|
|
3213
|
+
if (info && !accumulated_return_flags.some((f) => f.name === info.name)) {
|
|
3214
|
+
accumulated_return_flags.push(info);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
2936
3217
|
} else if (state.to_ts) {
|
|
2937
3218
|
transform_ts_child(node, /** @type {VisitorClientContext} */ ({ visit, state }));
|
|
2938
3219
|
} else {
|
|
@@ -2993,19 +3274,30 @@ function transform_children(children, context) {
|
|
|
2993
3274
|
const is_controlled = normalized.length === 1 && !root;
|
|
2994
3275
|
|
|
2995
3276
|
if (node.type === 'Element') {
|
|
3277
|
+
if (is_element_dom_element(node)) {
|
|
3278
|
+
skipped++;
|
|
3279
|
+
} else {
|
|
3280
|
+
skipped = 0;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
2996
3283
|
visit(node, {
|
|
2997
3284
|
...state,
|
|
3285
|
+
return_flags,
|
|
2998
3286
|
flush_node: /** @type {TransformClientState['flush_node']} */ (flush_node),
|
|
2999
3287
|
namespace: state.namespace,
|
|
3000
3288
|
});
|
|
3001
3289
|
} else if (node.type === 'TsxCompat') {
|
|
3290
|
+
skipped = 0;
|
|
3291
|
+
|
|
3002
3292
|
visit(node, {
|
|
3003
3293
|
...state,
|
|
3294
|
+
return_flags,
|
|
3004
3295
|
flush_node: /** @type {TransformClientState['flush_node']} */ (flush_node),
|
|
3005
3296
|
namespace: state.namespace,
|
|
3006
3297
|
});
|
|
3007
3298
|
} else if (node.type === 'Html') {
|
|
3008
3299
|
context.state.template?.push('<!>');
|
|
3300
|
+
skipped = 0;
|
|
3009
3301
|
|
|
3010
3302
|
const id = flush_node(false);
|
|
3011
3303
|
state.update?.push({
|
|
@@ -3022,6 +3314,7 @@ function transform_children(children, context) {
|
|
|
3022
3314
|
});
|
|
3023
3315
|
} else if (node.type === 'Text') {
|
|
3024
3316
|
if (metadata?.tracking) {
|
|
3317
|
+
skipped = 0;
|
|
3025
3318
|
state.template?.push(' ');
|
|
3026
3319
|
const id = flush_node(true);
|
|
3027
3320
|
state.update?.push({
|
|
@@ -3034,6 +3327,7 @@ function transform_children(children, context) {
|
|
|
3034
3327
|
/** @type {NonNullable<TransformClientState['update']>} */ (state.update).async = true;
|
|
3035
3328
|
}
|
|
3036
3329
|
} else if (normalized.length === 1) {
|
|
3330
|
+
skipped++;
|
|
3037
3331
|
const expr = /** @type {AST.Expression} */ (expression);
|
|
3038
3332
|
if (expr.type === 'Literal') {
|
|
3039
3333
|
if (
|
|
@@ -3061,6 +3355,7 @@ function transform_children(children, context) {
|
|
|
3061
3355
|
);
|
|
3062
3356
|
}
|
|
3063
3357
|
} else {
|
|
3358
|
+
skipped++;
|
|
3064
3359
|
// Handle Text nodes in fragments
|
|
3065
3360
|
const expr = /** @type {AST.Expression} */ (expression);
|
|
3066
3361
|
if (expr.type === 'Literal') {
|
|
@@ -3081,6 +3376,7 @@ function transform_children(children, context) {
|
|
|
3081
3376
|
}
|
|
3082
3377
|
}
|
|
3083
3378
|
} else if (node.type === 'ForOfStatement') {
|
|
3379
|
+
skipped = 0;
|
|
3084
3380
|
node.is_controlled = is_controlled;
|
|
3085
3381
|
visit(node, {
|
|
3086
3382
|
...state,
|
|
@@ -3088,13 +3384,16 @@ function transform_children(children, context) {
|
|
|
3088
3384
|
namespace: state.namespace,
|
|
3089
3385
|
});
|
|
3090
3386
|
} else if (node.type === 'IfStatement') {
|
|
3387
|
+
skipped = 0;
|
|
3091
3388
|
node.is_controlled = is_controlled;
|
|
3092
3389
|
visit(node, {
|
|
3093
3390
|
...state,
|
|
3391
|
+
return_flags,
|
|
3094
3392
|
flush_node: /** @type {TransformClientState['flush_node']} */ (flush_node),
|
|
3095
3393
|
namespace: state.namespace,
|
|
3096
3394
|
});
|
|
3097
3395
|
} else if (node.type === 'TryStatement') {
|
|
3396
|
+
skipped = 0;
|
|
3098
3397
|
node.is_controlled = is_controlled;
|
|
3099
3398
|
visit(node, {
|
|
3100
3399
|
...state,
|
|
@@ -3102,6 +3401,7 @@ function transform_children(children, context) {
|
|
|
3102
3401
|
namespace: state.namespace,
|
|
3103
3402
|
});
|
|
3104
3403
|
} else if (node.type === 'SwitchStatement') {
|
|
3404
|
+
skipped = 0;
|
|
3105
3405
|
node.is_controlled = is_controlled;
|
|
3106
3406
|
visit(node, {
|
|
3107
3407
|
...state,
|
|
@@ -3114,13 +3414,25 @@ function transform_children(children, context) {
|
|
|
3114
3414
|
debugger;
|
|
3115
3415
|
}
|
|
3116
3416
|
}
|
|
3417
|
+
|
|
3418
|
+
if (has_returns && node.metadata?.has_return && node.metadata.returns) {
|
|
3419
|
+
for (const ret of node.metadata.returns) {
|
|
3420
|
+
const info = return_flags.get(ret);
|
|
3421
|
+
if (info && !accumulated_return_flags.some((f) => f.name === info.name)) {
|
|
3422
|
+
accumulated_return_flags.push(info);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3117
3426
|
}
|
|
3118
3427
|
|
|
3119
|
-
|
|
3428
|
+
flush_pending_group();
|
|
3429
|
+
|
|
3430
|
+
for (let i = 0; i < head_elements.length; i++) {
|
|
3431
|
+
const head_element = head_elements[i];
|
|
3120
3432
|
if (state.to_ts) {
|
|
3121
3433
|
transform_ts_child(head_element, /** @type {VisitorClientContext} */ ({ visit, state }));
|
|
3122
3434
|
} else {
|
|
3123
|
-
visit_head_element(head_element, context);
|
|
3435
|
+
visit_head_element(head_element, i, context);
|
|
3124
3436
|
}
|
|
3125
3437
|
}
|
|
3126
3438
|
|
|
@@ -3137,6 +3449,13 @@ function transform_children(children, context) {
|
|
|
3137
3449
|
}
|
|
3138
3450
|
}
|
|
3139
3451
|
|
|
3452
|
+
let emitted_next = false;
|
|
3453
|
+
if (is_fragment && skipped > 1 && !state.skip_children_traversal) {
|
|
3454
|
+
skipped--;
|
|
3455
|
+
state.init?.push(b.stmt(b.call('_$_.next', skipped !== 1 && b.literal(skipped))));
|
|
3456
|
+
emitted_next = true;
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3140
3459
|
const template_namespace = state.namespace || 'html';
|
|
3141
3460
|
|
|
3142
3461
|
if (root && initial !== null && template_id !== null) {
|
|
@@ -3146,7 +3465,9 @@ function transform_children(children, context) {
|
|
|
3146
3465
|
} else if (template_namespace === 'mathml') {
|
|
3147
3466
|
flags |= TEMPLATE_MATHML_NAMESPACE;
|
|
3148
3467
|
}
|
|
3149
|
-
state.final?.push(
|
|
3468
|
+
state.final?.push(
|
|
3469
|
+
b.stmt(b.call('_$_.append', b.id('__anchor'), initial, emitted_next && b.true)),
|
|
3470
|
+
);
|
|
3150
3471
|
state.hoisted.push(
|
|
3151
3472
|
b.var(
|
|
3152
3473
|
template_id,
|
|
@@ -3466,6 +3787,18 @@ function create_tsx_with_typescript_support(comments) {
|
|
|
3466
3787
|
// cover the end
|
|
3467
3788
|
context.location(loc.end.line, loc.end.column);
|
|
3468
3789
|
},
|
|
3790
|
+
ReturnStatement(node, context) {
|
|
3791
|
+
if (!node.loc) {
|
|
3792
|
+
base_tsx.ReturnStatement?.(node, context);
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
const { start, end } = node.loc;
|
|
3797
|
+
|
|
3798
|
+
context.location(start.line, start.column);
|
|
3799
|
+
base_tsx.ReturnStatement?.(node, context);
|
|
3800
|
+
context.location(end.line, end.column);
|
|
3801
|
+
},
|
|
3469
3802
|
AwaitExpression(node, context) {
|
|
3470
3803
|
const loc = /** @type {AST.SourceLocation} */ (node.loc);
|
|
3471
3804
|
// the start needs to be covered as we don't cover it in visitors
|
|
@@ -3597,6 +3930,10 @@ function create_tsx_with_typescript_support(comments) {
|
|
|
3597
3930
|
}
|
|
3598
3931
|
context.write('>');
|
|
3599
3932
|
}
|
|
3933
|
+
|
|
3934
|
+
if (node.loc) {
|
|
3935
|
+
context.location(node.loc.end.line, node.loc.end.column);
|
|
3936
|
+
}
|
|
3600
3937
|
},
|
|
3601
3938
|
JSXClosingElement(node, context) {
|
|
3602
3939
|
const loc = /** @type {AST.SourceLocation} */ (node.loc);
|
|
@@ -4115,6 +4452,7 @@ export function transform_client(filename, source, analysis, to_ts, minify_css)
|
|
|
4115
4452
|
namespace: 'html',
|
|
4116
4453
|
metadata: {},
|
|
4117
4454
|
errors: analysis.errors,
|
|
4455
|
+
skip_children_traversal: false,
|
|
4118
4456
|
};
|
|
4119
4457
|
|
|
4120
4458
|
// Add ripple internal import once for the entire module
|