ripple 0.3.10 → 0.3.11
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 +31 -0
- package/package.json +2 -2
- package/src/compiler/errors.js +1 -1
- package/src/compiler/index.d.ts +3 -1
- package/src/compiler/phases/1-parse/index.js +170 -8
- package/src/compiler/phases/2-analyze/index.js +231 -20
- package/src/compiler/phases/3-transform/client/index.js +169 -77
- package/src/compiler/phases/3-transform/server/index.js +46 -3
- package/src/compiler/types/index.d.ts +19 -2
- package/src/compiler/types/parse.d.ts +1 -1
- package/src/compiler/utils.js +174 -0
- package/src/runtime/index-client.js +14 -4
- package/src/runtime/internal/client/composite.js +2 -2
- package/src/runtime/internal/client/expression.js +64 -2
- package/src/runtime/internal/client/portal.js +1 -1
- package/src/utils/builders.js +30 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.ripple.snap +1 -0
- package/tests/client/basic/basic.rendering.test.ripple +4 -2
- package/tests/client/composite/composite.render.test.ripple +46 -0
- package/tests/client/return.test.ripple +101 -0
- package/tests/client/tsx.test.ripple +486 -0
- package/tests/hydration/compiled/client/basic.js +8 -24
- package/tests/hydration/compiled/client/composite.js +6 -24
- package/tests/hydration/compiled/client/events.js +9 -54
- package/tests/hydration/compiled/client/for.js +59 -152
- package/tests/hydration/compiled/client/head.js +5 -20
- package/tests/hydration/compiled/client/hmr.js +2 -8
- package/tests/hydration/compiled/client/html.js +59 -226
- package/tests/hydration/compiled/client/if-children.js +6 -22
- package/tests/hydration/compiled/client/mixed-control-flow.js +18 -66
- package/tests/hydration/compiled/client/nested-control-flow.js +92 -368
- package/tests/hydration/compiled/client/portal.js +4 -16
- package/tests/hydration/compiled/client/reactivity.js +7 -40
- package/tests/hydration/compiled/client/return.js +1 -4
- package/tests/hydration/compiled/client/try.js +2 -2
- package/tests/utils/compiler-compat-config.test.js +38 -0
- package/tests/utils/vite-plugin-config.test.js +113 -0
- package/tsconfig.typecheck.json +2 -1
- package/types/index.d.ts +2 -12
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
is_ripple_import,
|
|
62
62
|
replace_lazy_param_pattern,
|
|
63
63
|
ripple_import_requires_block,
|
|
64
|
+
jsx_to_ripple_node,
|
|
64
65
|
} from '../../../utils.js';
|
|
65
66
|
import {
|
|
66
67
|
CSS_HASH_IDENTIFIER,
|
|
@@ -858,6 +859,8 @@ const visitors = {
|
|
|
858
859
|
// Handle standalone lazy destructuring: &[data] = track(0); → const lazy0 = track(0);
|
|
859
860
|
if (
|
|
860
861
|
node.expression.type === 'AssignmentExpression' &&
|
|
862
|
+
(node.expression.left.type === 'ObjectPattern' ||
|
|
863
|
+
node.expression.left.type === 'ArrayPattern') &&
|
|
861
864
|
node.expression.left.lazy &&
|
|
862
865
|
node.expression.left.metadata?.lazy_id
|
|
863
866
|
) {
|
|
@@ -1140,6 +1143,16 @@ const visitors = {
|
|
|
1140
1143
|
TsxCompat(node, context) {
|
|
1141
1144
|
const { state, visit } = context;
|
|
1142
1145
|
|
|
1146
|
+
// to_ts mode: produce a JSX fragment
|
|
1147
|
+
if (state.to_ts) {
|
|
1148
|
+
const children = /** @type {AST.TsxCompat['children']} */ (
|
|
1149
|
+
node.children
|
|
1150
|
+
.map((child) => visit(/** @type {AST.Node} */ (child), state))
|
|
1151
|
+
.filter((child) => child.type !== 'JSXText' || child.value.trim() !== '')
|
|
1152
|
+
);
|
|
1153
|
+
return b.jsx_fragment(children);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1143
1156
|
state.template?.push('<!>');
|
|
1144
1157
|
|
|
1145
1158
|
const normalized_children = node.children.filter((child) => {
|
|
@@ -1177,6 +1190,58 @@ const visitors = {
|
|
|
1177
1190
|
);
|
|
1178
1191
|
},
|
|
1179
1192
|
|
|
1193
|
+
Tsx(node, context) {
|
|
1194
|
+
const { state, visit } = context;
|
|
1195
|
+
|
|
1196
|
+
// to_ts mode: produce a JSX fragment
|
|
1197
|
+
if (state.to_ts) {
|
|
1198
|
+
const children = /** @type {AST.Tsx['children']} */ (
|
|
1199
|
+
node.children
|
|
1200
|
+
.map((child) => visit(/** @type {AST.Node} */ (child), state))
|
|
1201
|
+
.filter((child) => child.type !== 'JSXText' || child.value.trim() !== '')
|
|
1202
|
+
);
|
|
1203
|
+
return b.jsx_fragment(children);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
const children_filtered = node.children
|
|
1207
|
+
.map((child) => jsx_to_ripple_node(/** @type {AST.Node} */ (child)))
|
|
1208
|
+
.flat()
|
|
1209
|
+
.filter(
|
|
1210
|
+
(child) => child != null && child.type !== 'EmptyStatement' && child.type !== 'Component',
|
|
1211
|
+
);
|
|
1212
|
+
|
|
1213
|
+
const children_component = b.component(b.id('render_children'), [], children_filtered);
|
|
1214
|
+
|
|
1215
|
+
const element = b.call(
|
|
1216
|
+
'_$_.ripple_element',
|
|
1217
|
+
/** @type {AST.Expression} */ (
|
|
1218
|
+
visit(children_component, {
|
|
1219
|
+
...state,
|
|
1220
|
+
namespace: state.namespace,
|
|
1221
|
+
is_ripple_element: true,
|
|
1222
|
+
})
|
|
1223
|
+
),
|
|
1224
|
+
);
|
|
1225
|
+
|
|
1226
|
+
// Template body context: push to template and schedule init
|
|
1227
|
+
if (state.flush_node) {
|
|
1228
|
+
state.template?.push('<!>');
|
|
1229
|
+
|
|
1230
|
+
const id = state.flush_node(false);
|
|
1231
|
+
|
|
1232
|
+
const call = b.call('_$_.expression', id, b.thunk(element));
|
|
1233
|
+
state.init?.push(
|
|
1234
|
+
state.namespace !== DEFAULT_NAMESPACE
|
|
1235
|
+
? b.stmt(b.call('_$_.with_ns', b.literal(state.namespace), b.thunk(call)))
|
|
1236
|
+
: b.stmt(call),
|
|
1237
|
+
);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Expression context: return the ripple_element directly as an expression value
|
|
1242
|
+
return element;
|
|
1243
|
+
},
|
|
1244
|
+
|
|
1180
1245
|
Element(node, context) {
|
|
1181
1246
|
const { state, visit } = context;
|
|
1182
1247
|
|
|
@@ -1574,6 +1639,7 @@ const visitors = {
|
|
|
1574
1639
|
child.type === 'TryStatement' ||
|
|
1575
1640
|
child.type === 'ForOfStatement' ||
|
|
1576
1641
|
child.type === 'SwitchStatement' ||
|
|
1642
|
+
child.type === 'Tsx' ||
|
|
1577
1643
|
child.type === 'TsxCompat' ||
|
|
1578
1644
|
child.type === 'Html' ||
|
|
1579
1645
|
(child.type === 'Element' &&
|
|
@@ -1623,7 +1689,9 @@ const visitors = {
|
|
|
1623
1689
|
let property =
|
|
1624
1690
|
attr.value === null
|
|
1625
1691
|
? b.literal(true)
|
|
1626
|
-
: /** @type {AST.Expression} */ (
|
|
1692
|
+
: /** @type {AST.Expression} */ (
|
|
1693
|
+
visit(attr.value, { ...state, flush_node: null, metadata })
|
|
1694
|
+
);
|
|
1627
1695
|
|
|
1628
1696
|
if (attr.name.name === 'class' && node.metadata.scoped && state.component?.css) {
|
|
1629
1697
|
if (property.type === 'Literal') {
|
|
@@ -1671,7 +1739,9 @@ const visitors = {
|
|
|
1671
1739
|
b.prop(
|
|
1672
1740
|
'init',
|
|
1673
1741
|
b.key(attr.name.name),
|
|
1674
|
-
/** @type {AST.Expression} */ (
|
|
1742
|
+
/** @type {AST.Expression} */ (
|
|
1743
|
+
visit(/** @type {AST.Node} */ (attr.value), { ...state, flush_node: null })
|
|
1744
|
+
),
|
|
1675
1745
|
),
|
|
1676
1746
|
);
|
|
1677
1747
|
}
|
|
@@ -1679,7 +1749,13 @@ const visitors = {
|
|
|
1679
1749
|
props.push(
|
|
1680
1750
|
b.spread(
|
|
1681
1751
|
/** @type {AST.Expression} */
|
|
1682
|
-
(
|
|
1752
|
+
(
|
|
1753
|
+
visit(attr.argument, {
|
|
1754
|
+
...state,
|
|
1755
|
+
flush_node: null,
|
|
1756
|
+
metadata: { ...state.metadata },
|
|
1757
|
+
})
|
|
1758
|
+
),
|
|
1683
1759
|
),
|
|
1684
1760
|
);
|
|
1685
1761
|
} else if (attr.type === 'RefAttribute') {
|
|
@@ -1690,7 +1766,9 @@ const visitors = {
|
|
|
1690
1766
|
b.prop(
|
|
1691
1767
|
'init',
|
|
1692
1768
|
b.id(ref_id),
|
|
1693
|
-
/** @type {AST.Expression} */ (
|
|
1769
|
+
/** @type {AST.Expression} */ (
|
|
1770
|
+
visit(attr.argument, { ...state, flush_node: null, metadata })
|
|
1771
|
+
),
|
|
1694
1772
|
true,
|
|
1695
1773
|
),
|
|
1696
1774
|
);
|
|
@@ -1736,6 +1814,7 @@ const visitors = {
|
|
|
1736
1814
|
: {}),
|
|
1737
1815
|
scope: /** @type {ScopeInterface} */ (component_scope),
|
|
1738
1816
|
namespace: child_namespace,
|
|
1817
|
+
is_ripple_element: true,
|
|
1739
1818
|
})
|
|
1740
1819
|
),
|
|
1741
1820
|
);
|
|
@@ -1953,30 +2032,46 @@ const visitors = {
|
|
|
1953
2032
|
}
|
|
1954
2033
|
|
|
1955
2034
|
const component_scope = context.state.scopes.get(node) || context.state.scope;
|
|
1956
|
-
const
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2035
|
+
const is_ripple_element = context.state.is_ripple_element;
|
|
2036
|
+
const is_synthetic_children = node.id?.name === 'render_children';
|
|
2037
|
+
const transformed_body = transform_body(node.body, {
|
|
2038
|
+
...context,
|
|
2039
|
+
state: {
|
|
2040
|
+
...context.state,
|
|
2041
|
+
flush_node: null,
|
|
2042
|
+
component: node,
|
|
2043
|
+
metadata,
|
|
2044
|
+
scope: component_scope,
|
|
2045
|
+
is_ripple_element: false,
|
|
2046
|
+
applyParentCssScope: is_synthetic_children ? context.state.applyParentCssScope : undefined,
|
|
2047
|
+
},
|
|
2048
|
+
});
|
|
2049
|
+
|
|
2050
|
+
// RippleElement render functions don't need push/pop component context
|
|
2051
|
+
// since they inherit context from where they're used
|
|
2052
|
+
const body_statements = is_ripple_element
|
|
2053
|
+
? transformed_body
|
|
2054
|
+
: [
|
|
2055
|
+
b.stmt(b.call('_$_.push_component')),
|
|
2056
|
+
...transformed_body,
|
|
2057
|
+
b.stmt(b.call('_$_.pop_component')),
|
|
2058
|
+
];
|
|
1970
2059
|
|
|
1971
2060
|
if (node.css !== null && node.css) {
|
|
1972
2061
|
context.state.stylesheets.push(node.css);
|
|
1973
2062
|
}
|
|
1974
2063
|
|
|
2064
|
+
// RippleElement render functions use simpler params: [__anchor, __block]
|
|
2065
|
+
// Regular components use: [__anchor, props, __block] or [__anchor, _, __block]
|
|
2066
|
+
const params = is_ripple_element
|
|
2067
|
+
? [b.id('__anchor'), b.id('__block')]
|
|
2068
|
+
: node.params.length > 0
|
|
2069
|
+
? [b.id('__anchor'), props, b.id('__block')]
|
|
2070
|
+
: [b.id('__anchor'), b.id('_'), b.id('__block')];
|
|
2071
|
+
|
|
1975
2072
|
const func = b.function(
|
|
1976
2073
|
node.id,
|
|
1977
|
-
|
|
1978
|
-
? [b.id('__anchor'), props, b.id('__block')]
|
|
1979
|
-
: [b.id('__anchor'), b.id('_'), b.id('__block')],
|
|
2074
|
+
params,
|
|
1980
2075
|
b.block([
|
|
1981
2076
|
...style_statements,
|
|
1982
2077
|
...(prop_statements ?? []),
|
|
@@ -2821,7 +2916,10 @@ function transform_ts_child(node, context) {
|
|
|
2821
2916
|
}
|
|
2822
2917
|
}
|
|
2823
2918
|
|
|
2824
|
-
if (
|
|
2919
|
+
if (
|
|
2920
|
+
/** @type {AST.Node} */ (node.id).type !== 'MemberExpression' &&
|
|
2921
|
+
/** @type {AST.Identifier} */ (node.id).tracked
|
|
2922
|
+
) {
|
|
2825
2923
|
// This is just temporary until we remove capitalization
|
|
2826
2924
|
// The `is_capitalized` was never handled for MemberExpression
|
|
2827
2925
|
// but it should've been for the `object` part because it starts the tag
|
|
@@ -3064,6 +3162,18 @@ function transform_ts_child(node, context) {
|
|
|
3064
3162
|
);
|
|
3065
3163
|
|
|
3066
3164
|
state.init?.push(b.stmt(b.jsx_fragment(children)));
|
|
3165
|
+
} else if (node.type === 'Tsx') {
|
|
3166
|
+
const children = /** @type {AST.Tsx['children']} */ (
|
|
3167
|
+
node.children
|
|
3168
|
+
.map((child) => visit(/** @type {AST.Node} */ (child), state))
|
|
3169
|
+
.filter((child) => child.type !== 'JSXText' || child.value.trim() !== '')
|
|
3170
|
+
);
|
|
3171
|
+
|
|
3172
|
+
const result = b.jsx_fragment(children);
|
|
3173
|
+
if (!state.init) {
|
|
3174
|
+
return result;
|
|
3175
|
+
}
|
|
3176
|
+
state.init.push(b.stmt(result));
|
|
3067
3177
|
} else if (node.type === 'JSXExpressionContainer') {
|
|
3068
3178
|
// JSX comments {/* ... */} are JSXExpressionContainer with JSXEmptyExpression
|
|
3069
3179
|
// These should be preserved in the output as-is for prettier to handle
|
|
@@ -3105,6 +3215,7 @@ function is_template_or_control_flow(node) {
|
|
|
3105
3215
|
node.type === 'RippleExpression' ||
|
|
3106
3216
|
node.type === 'Text' ||
|
|
3107
3217
|
node.type === 'Html' ||
|
|
3218
|
+
node.type === 'Tsx' ||
|
|
3108
3219
|
node.type === 'TsxCompat' ||
|
|
3109
3220
|
node.type === 'IfStatement' ||
|
|
3110
3221
|
node.type === 'ForOfStatement' ||
|
|
@@ -3196,6 +3307,7 @@ function element_has_dynamic_content(element) {
|
|
|
3196
3307
|
child.type === 'TryStatement' ||
|
|
3197
3308
|
child.type === 'ForOfStatement' ||
|
|
3198
3309
|
child.type === 'SwitchStatement' ||
|
|
3310
|
+
child.type === 'Tsx' ||
|
|
3199
3311
|
child.type === 'TsxCompat' ||
|
|
3200
3312
|
child.type === 'Html'
|
|
3201
3313
|
) {
|
|
@@ -3371,6 +3483,7 @@ function transform_children(children, context) {
|
|
|
3371
3483
|
node.type === 'TryStatement' ||
|
|
3372
3484
|
node.type === 'ForOfStatement' ||
|
|
3373
3485
|
node.type === 'SwitchStatement' ||
|
|
3486
|
+
node.type === 'Tsx' ||
|
|
3374
3487
|
node.type === 'TsxCompat' ||
|
|
3375
3488
|
node.type === 'Html' ||
|
|
3376
3489
|
(node.type === 'Element' &&
|
|
@@ -3384,6 +3497,15 @@ function transform_children(children, context) {
|
|
|
3384
3497
|
node.type === 'RippleExpression' &&
|
|
3385
3498
|
is_children_template_expression(node.expression, state.scope),
|
|
3386
3499
|
)) ||
|
|
3500
|
+
// At root level, non-literal expressions need a fragment template so the
|
|
3501
|
+
// anchor has a parent node. Without a parent, expression()'s .before() call
|
|
3502
|
+
// is a no-op when the value is a RippleElement.
|
|
3503
|
+
(root &&
|
|
3504
|
+
normalized.some(
|
|
3505
|
+
(node) =>
|
|
3506
|
+
node.type === 'RippleExpression' &&
|
|
3507
|
+
/** @type {AST.RippleExpression} */ (node).expression.type !== 'Literal',
|
|
3508
|
+
)) ||
|
|
3387
3509
|
normalized.filter(
|
|
3388
3510
|
(node) => node.type !== 'VariableDeclaration' && node.type !== 'EmptyStatement',
|
|
3389
3511
|
).length > 1;
|
|
@@ -3652,6 +3774,7 @@ function transform_children(children, context) {
|
|
|
3652
3774
|
child.type === 'TryStatement' ||
|
|
3653
3775
|
child.type === 'ForOfStatement' ||
|
|
3654
3776
|
child.type === 'SwitchStatement' ||
|
|
3777
|
+
child.type === 'Tsx' ||
|
|
3655
3778
|
child.type === 'TsxCompat' ||
|
|
3656
3779
|
child.type === 'Html' ||
|
|
3657
3780
|
(child.type === 'Element' &&
|
|
@@ -3682,6 +3805,7 @@ function transform_children(children, context) {
|
|
|
3682
3805
|
next_node.type === 'TryStatement' ||
|
|
3683
3806
|
next_node.type === 'ForOfStatement' ||
|
|
3684
3807
|
next_node.type === 'SwitchStatement' ||
|
|
3808
|
+
next_node.type === 'Tsx' ||
|
|
3685
3809
|
next_node.type === 'TsxCompat'
|
|
3686
3810
|
) {
|
|
3687
3811
|
needs_sibling_call = true;
|
|
@@ -3693,7 +3817,7 @@ function transform_children(children, context) {
|
|
|
3693
3817
|
}
|
|
3694
3818
|
}
|
|
3695
3819
|
}
|
|
3696
|
-
} else if (node.type === 'TsxCompat') {
|
|
3820
|
+
} else if (node.type === 'TsxCompat' || node.type === 'Tsx') {
|
|
3697
3821
|
skipped = 0;
|
|
3698
3822
|
|
|
3699
3823
|
visit(node, {
|
|
@@ -3721,10 +3845,6 @@ function transform_children(children, context) {
|
|
|
3721
3845
|
});
|
|
3722
3846
|
} else if (node.type === 'RippleExpression') {
|
|
3723
3847
|
const expr = /** @type {AST.Expression} */ (expression);
|
|
3724
|
-
const is_children_expression = is_children_template_expression(
|
|
3725
|
-
node.expression,
|
|
3726
|
-
state.scope,
|
|
3727
|
-
);
|
|
3728
3848
|
|
|
3729
3849
|
if (expr.type === 'Literal') {
|
|
3730
3850
|
if (normalized.length === 1) {
|
|
@@ -3743,60 +3863,29 @@ function transform_children(children, context) {
|
|
|
3743
3863
|
skipped++;
|
|
3744
3864
|
state.template?.push(escape_html(expr.value));
|
|
3745
3865
|
}
|
|
3746
|
-
} else if (
|
|
3747
|
-
|
|
3748
|
-
state.
|
|
3749
|
-
|
|
3750
|
-
state.update?.push({
|
|
3751
|
-
operation: () => {
|
|
3752
|
-
const call = b.call('_$_.expression', id, b.thunk(expr));
|
|
3753
|
-
return state.namespace !== DEFAULT_NAMESPACE
|
|
3754
|
-
? b.stmt(b.call('_$_.with_ns', b.literal(state.namespace), b.thunk(call)))
|
|
3755
|
-
: b.stmt(call);
|
|
3756
|
-
},
|
|
3757
|
-
});
|
|
3758
|
-
if (metadata?.await) {
|
|
3759
|
-
/** @type {NonNullable<TransformClientState['update']>} */ (state.update).async = true;
|
|
3760
|
-
}
|
|
3761
|
-
} else if (metadata?.tracking) {
|
|
3762
|
-
skipped = 0;
|
|
3763
|
-
state.template?.push(' ');
|
|
3764
|
-
const id = flush_node(true);
|
|
3765
|
-
state.update?.push({
|
|
3766
|
-
operation: (key) => b.stmt(b.call('_$_.set_text', id, key)),
|
|
3767
|
-
expression: expr,
|
|
3768
|
-
identity: node.expression,
|
|
3769
|
-
initial: b.literal(' '),
|
|
3770
|
-
});
|
|
3771
|
-
if (metadata.await) {
|
|
3772
|
-
/** @type {NonNullable<TransformClientState['update']>} */ (state.update).async = true;
|
|
3773
|
-
}
|
|
3774
|
-
} else if (normalized.length === 1) {
|
|
3866
|
+
} else if (
|
|
3867
|
+
normalized.length === 1 &&
|
|
3868
|
+
!is_children_template_expression(node.expression, state.scope)
|
|
3869
|
+
) {
|
|
3775
3870
|
skipped++;
|
|
3776
|
-
const id = flush_node(true);
|
|
3777
3871
|
state.template?.push(' ');
|
|
3872
|
+
const id = flush_node(true);
|
|
3873
|
+
const call = b.call('_$_.expression', id, b.thunk(expr));
|
|
3778
3874
|
state.init?.push(
|
|
3779
|
-
|
|
3780
|
-
b.
|
|
3781
|
-
|
|
3782
|
-
b.member(/** @type {AST.Identifier} */ (id), b.id('nodeValue')),
|
|
3783
|
-
expr,
|
|
3784
|
-
),
|
|
3785
|
-
),
|
|
3875
|
+
state.namespace !== DEFAULT_NAMESPACE
|
|
3876
|
+
? b.stmt(b.call('_$_.with_ns', b.literal(state.namespace), b.thunk(call)))
|
|
3877
|
+
: b.stmt(call),
|
|
3786
3878
|
);
|
|
3787
3879
|
} else {
|
|
3788
|
-
skipped
|
|
3789
|
-
state.template?.push('
|
|
3790
|
-
const id = flush_node(
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
if (metadata?.await) {
|
|
3798
|
-
/** @type {NonNullable<TransformClientState['update']>} */ (state.update).async = true;
|
|
3799
|
-
}
|
|
3880
|
+
skipped = 0;
|
|
3881
|
+
state.template?.push('<!>');
|
|
3882
|
+
const id = flush_node(false);
|
|
3883
|
+
const call = b.call('_$_.expression', id, b.thunk(expr));
|
|
3884
|
+
state.init?.push(
|
|
3885
|
+
state.namespace !== DEFAULT_NAMESPACE
|
|
3886
|
+
? b.stmt(b.call('_$_.with_ns', b.literal(state.namespace), b.thunk(call)))
|
|
3887
|
+
: b.stmt(call),
|
|
3888
|
+
);
|
|
3800
3889
|
}
|
|
3801
3890
|
} else if (node.type === 'Text') {
|
|
3802
3891
|
if (metadata?.tracking) {
|
|
@@ -4399,7 +4488,10 @@ function create_tsx_with_typescript_support(comments) {
|
|
|
4399
4488
|
// Shorthand object properties require an Identifier value. When the
|
|
4400
4489
|
// transformed value is a tracked MemberExpression (for example
|
|
4401
4490
|
// @value), emit longhand to keep valid output.
|
|
4402
|
-
if (
|
|
4491
|
+
if (
|
|
4492
|
+
node.value.type === 'MemberExpression' &&
|
|
4493
|
+
/** @type {AST.MemberExpression & { tracked?: boolean }} */ (node.value).tracked
|
|
4494
|
+
) {
|
|
4403
4495
|
context.visit(node.key);
|
|
4404
4496
|
context.write(': ');
|
|
4405
4497
|
context.visit(node.value);
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
hash,
|
|
33
33
|
flatten_switch_consequent,
|
|
34
34
|
get_ripple_namespace_call_name,
|
|
35
|
+
jsx_to_ripple_node,
|
|
35
36
|
} from '../../../utils.js';
|
|
36
37
|
import { escape } from '../../../../utils/escaping.js';
|
|
37
38
|
import { is_event_attribute } from '../../../../utils/events.js';
|
|
@@ -55,6 +56,7 @@ function is_template_or_control_flow(node) {
|
|
|
55
56
|
node.type === 'RippleExpression' ||
|
|
56
57
|
node.type === 'Text' ||
|
|
57
58
|
node.type === 'Html' ||
|
|
59
|
+
node.type === 'Tsx' ||
|
|
58
60
|
node.type === 'TsxCompat' ||
|
|
59
61
|
node.type === 'IfStatement' ||
|
|
60
62
|
node.type === 'ForOfStatement' ||
|
|
@@ -199,7 +201,7 @@ function transform_children(children, context) {
|
|
|
199
201
|
}
|
|
200
202
|
}
|
|
201
203
|
} else {
|
|
202
|
-
visit(node, { ...state, return_flags });
|
|
204
|
+
visit(node, { ...state, return_flags, template_child: true });
|
|
203
205
|
}
|
|
204
206
|
};
|
|
205
207
|
|
|
@@ -402,14 +404,22 @@ const visitors = {
|
|
|
402
404
|
b.stmt(b.call('_$_.push_component')),
|
|
403
405
|
...transform_body(node.body, {
|
|
404
406
|
...context,
|
|
405
|
-
state: {
|
|
407
|
+
state: {
|
|
408
|
+
...context.state,
|
|
409
|
+
component: node,
|
|
410
|
+
metadata,
|
|
411
|
+
applyParentCssScope:
|
|
412
|
+
node.id?.name === 'render_children' ? context.state.applyParentCssScope : undefined,
|
|
413
|
+
},
|
|
406
414
|
}),
|
|
407
415
|
b.stmt(b.call('_$_.pop_component')),
|
|
408
416
|
);
|
|
409
417
|
|
|
410
418
|
let component_fn = b.function(
|
|
411
419
|
node.id,
|
|
412
|
-
node.params.length > 0
|
|
420
|
+
node.params.length > 0
|
|
421
|
+
? [b.id('__output'), /** @type {AST.Pattern} */ (props_param_output)]
|
|
422
|
+
: [b.id('__output')],
|
|
413
423
|
b.block([
|
|
414
424
|
...(metadata.await
|
|
415
425
|
? [b.return(b.call('_$_.async', b.thunk(b.block(body_statements), true)))]
|
|
@@ -807,6 +817,8 @@ const visitors = {
|
|
|
807
817
|
// Handle standalone lazy destructuring: &[data] = track(0); → const lazy0 = track(0);
|
|
808
818
|
if (
|
|
809
819
|
node.expression.type === 'AssignmentExpression' &&
|
|
820
|
+
(node.expression.left.type === 'ObjectPattern' ||
|
|
821
|
+
node.expression.left.type === 'ArrayPattern') &&
|
|
810
822
|
node.expression.left.lazy &&
|
|
811
823
|
node.expression.left.metadata?.lazy_id
|
|
812
824
|
) {
|
|
@@ -1654,6 +1666,37 @@ const visitors = {
|
|
|
1654
1666
|
}
|
|
1655
1667
|
},
|
|
1656
1668
|
|
|
1669
|
+
Tsx(node, { visit, state }) {
|
|
1670
|
+
const converted_children = node.children
|
|
1671
|
+
.map((child) => jsx_to_ripple_node(/** @type {AST.Node} */ (child)))
|
|
1672
|
+
.flat()
|
|
1673
|
+
.filter((child) => child != null);
|
|
1674
|
+
|
|
1675
|
+
/** @type {AST.Statement[]} */
|
|
1676
|
+
const init = [];
|
|
1677
|
+
transform_children(
|
|
1678
|
+
converted_children,
|
|
1679
|
+
/** @type {TransformServerContext} */ ({
|
|
1680
|
+
visit,
|
|
1681
|
+
state: {
|
|
1682
|
+
...state,
|
|
1683
|
+
init,
|
|
1684
|
+
},
|
|
1685
|
+
}),
|
|
1686
|
+
);
|
|
1687
|
+
|
|
1688
|
+
if (state.template_child) {
|
|
1689
|
+
// Template body: push children statements inline
|
|
1690
|
+
if (init.length > 0) {
|
|
1691
|
+
state.init?.push(b.block(init));
|
|
1692
|
+
}
|
|
1693
|
+
} else {
|
|
1694
|
+
// Expression context: return ripple_element(render_fn)
|
|
1695
|
+
const render_fn = b.function(b.id('render_children'), [b.id('__output')], b.block(init));
|
|
1696
|
+
return b.call('_$_.ripple_element', render_fn);
|
|
1697
|
+
}
|
|
1698
|
+
},
|
|
1699
|
+
|
|
1657
1700
|
Html(node, { visit, state }) {
|
|
1658
1701
|
const metadata = { await: false };
|
|
1659
1702
|
const expression = /** @type {AST.Expression} */ (
|
|
@@ -22,6 +22,7 @@ interface BaseNodeMetaData {
|
|
|
22
22
|
inside_component_top_level?: boolean;
|
|
23
23
|
returns?: AST.ReturnStatement[];
|
|
24
24
|
has_return?: boolean;
|
|
25
|
+
has_throw?: boolean;
|
|
25
26
|
is_reactive?: boolean;
|
|
26
27
|
lone_return?: boolean;
|
|
27
28
|
forceMapping?: boolean;
|
|
@@ -116,7 +117,9 @@ declare module 'estree' {
|
|
|
116
117
|
|
|
117
118
|
// We mark the whole node as marked when member is @[expression]
|
|
118
119
|
// Otherwise, we only mark Identifier nodes
|
|
119
|
-
interface MemberExpression {
|
|
120
|
+
interface MemberExpression {
|
|
121
|
+
tracked?: boolean;
|
|
122
|
+
}
|
|
120
123
|
|
|
121
124
|
interface SimpleLiteral extends AST.LiteralNode {}
|
|
122
125
|
interface RegExpLiteral extends AST.LiteralNode {}
|
|
@@ -133,6 +136,7 @@ declare module 'estree' {
|
|
|
133
136
|
// Include TypeScript node types and Ripple-specific nodes in NodeMap
|
|
134
137
|
interface NodeMap {
|
|
135
138
|
Component: Component;
|
|
139
|
+
Tsx: Tsx;
|
|
136
140
|
TsxCompat: TsxCompat;
|
|
137
141
|
RippleExpression: RippleExpression;
|
|
138
142
|
Html: Html;
|
|
@@ -270,6 +274,16 @@ declare module 'estree' {
|
|
|
270
274
|
typeParameters?: AST.TSTypeParameterDeclaration;
|
|
271
275
|
}
|
|
272
276
|
|
|
277
|
+
interface Tsx extends AST.BaseNode {
|
|
278
|
+
type: 'Tsx';
|
|
279
|
+
attributes: Array<any>;
|
|
280
|
+
children: ESTreeJSX.JSXElement['children'];
|
|
281
|
+
selfClosing?: boolean;
|
|
282
|
+
unclosed?: boolean;
|
|
283
|
+
openingElement: ESTreeJSX.JSXOpeningElement;
|
|
284
|
+
closingElement: ESTreeJSX.JSXClosingElement;
|
|
285
|
+
}
|
|
286
|
+
|
|
273
287
|
interface TsxCompat extends AST.BaseNode {
|
|
274
288
|
type: 'TsxCompat';
|
|
275
289
|
kind: string;
|
|
@@ -406,7 +420,7 @@ declare module 'estree' {
|
|
|
406
420
|
|
|
407
421
|
export type RippleStatement = AST.Statement | TSESTree.Statement;
|
|
408
422
|
|
|
409
|
-
export type NodeWithChildren = AST.Element | AST.TsxCompat;
|
|
423
|
+
export type NodeWithChildren = AST.Element | AST.Tsx | AST.TsxCompat;
|
|
410
424
|
|
|
411
425
|
export namespace CSS {
|
|
412
426
|
export interface BaseNode extends AST.NodeWithMaybeComments {
|
|
@@ -1270,6 +1284,7 @@ export interface AnalysisState extends BaseState {
|
|
|
1270
1284
|
elements?: AST.Element[];
|
|
1271
1285
|
function_depth?: number;
|
|
1272
1286
|
loose?: boolean;
|
|
1287
|
+
configured_compat_kinds?: Set<string>;
|
|
1273
1288
|
metadata: BaseStateMetaData & {
|
|
1274
1289
|
styleClasses?: StyleClasses;
|
|
1275
1290
|
};
|
|
@@ -1290,6 +1305,7 @@ export interface TransformServerState extends BaseState {
|
|
|
1290
1305
|
applyParentCssScope?: AST.CSS.StyleSheet['hash'];
|
|
1291
1306
|
dev?: boolean;
|
|
1292
1307
|
return_flags?: Map<AST.ReturnStatement, { name: string; tracked: boolean }>;
|
|
1308
|
+
template_child?: boolean;
|
|
1293
1309
|
}
|
|
1294
1310
|
|
|
1295
1311
|
type UpdateList = Array<
|
|
@@ -1323,6 +1339,7 @@ export interface TransformClientState extends BaseState {
|
|
|
1323
1339
|
applyParentCssScope?: AST.CSS.StyleSheet['hash'];
|
|
1324
1340
|
skip_children_traversal: boolean;
|
|
1325
1341
|
return_flags?: Map<AST.ReturnStatement, { name: string; tracked: boolean }>;
|
|
1342
|
+
is_ripple_element?: boolean;
|
|
1326
1343
|
}
|
|
1327
1344
|
|
|
1328
1345
|
/** Override zimmerframe types and provide our own */
|
|
@@ -1166,7 +1166,7 @@ export namespace Parse {
|
|
|
1166
1166
|
|
|
1167
1167
|
parseServerBlock(): AST.ServerBlock;
|
|
1168
1168
|
|
|
1169
|
-
parseElement(): AST.Element | AST.TsxCompat;
|
|
1169
|
+
parseElement(): AST.Element | AST.Tsx | AST.TsxCompat;
|
|
1170
1170
|
|
|
1171
1171
|
parseTemplateBody(
|
|
1172
1172
|
body: (AST.Statement | AST.Node | ESTreeJSX.JSXText | ESTreeJSX.JSXElement['children'])[],
|