ripple 0.2.133 → 0.2.135
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/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +286 -55
- package/src/compiler/phases/2-analyze/index.js +35 -1
- package/src/compiler/phases/3-transform/client/index.js +224 -60
- package/src/runtime/index-client.js +3 -3
- package/src/runtime/internal/client/blocks.js +26 -4
- package/src/runtime/internal/client/compat.js +37 -5
- package/src/runtime/internal/client/types.d.ts +10 -0
- package/src/utils/builders.js +17 -0
- package/tests/client/basic/basic.components.test.ripple +30 -20
- package/tests/client/compiler/compiler.basic.test.ripple +93 -64
- package/tests/client/compiler/compiler.tracked-access.test.ripple +108 -0
- package/tests/client/dynamic-elements.test.ripple +120 -1
|
@@ -317,21 +317,21 @@ const visitors = {
|
|
|
317
317
|
if (!context.state.to_ts) {
|
|
318
318
|
return b.empty;
|
|
319
319
|
}
|
|
320
|
-
context.next();
|
|
320
|
+
return context.next();
|
|
321
321
|
},
|
|
322
322
|
|
|
323
323
|
TSInterfaceDeclaration(_, context) {
|
|
324
324
|
if (!context.state.to_ts) {
|
|
325
325
|
return b.empty;
|
|
326
326
|
}
|
|
327
|
-
context.next();
|
|
327
|
+
return context.next();
|
|
328
328
|
},
|
|
329
329
|
|
|
330
330
|
TSMappedType(_, context) {
|
|
331
331
|
if (!context.state.to_ts) {
|
|
332
332
|
return b.empty;
|
|
333
333
|
}
|
|
334
|
-
context.next();
|
|
334
|
+
return context.next();
|
|
335
335
|
},
|
|
336
336
|
|
|
337
337
|
NewExpression(node, context) {
|
|
@@ -384,7 +384,7 @@ const visitors = {
|
|
|
384
384
|
|
|
385
385
|
TrackedArrayExpression(node, context) {
|
|
386
386
|
if (context.state.to_ts) {
|
|
387
|
-
const arrayAlias = import_from_ripple_if_needed(
|
|
387
|
+
const arrayAlias = import_from_ripple_if_needed('TrackedArray', context);
|
|
388
388
|
|
|
389
389
|
return b.call(
|
|
390
390
|
b.member(b.id(arrayAlias), b.id('from')),
|
|
@@ -401,12 +401,9 @@ const visitors = {
|
|
|
401
401
|
|
|
402
402
|
TrackedObjectExpression(node, context) {
|
|
403
403
|
if (context.state.to_ts) {
|
|
404
|
-
const objectAlias = import_from_ripple_if_needed(
|
|
404
|
+
const objectAlias = import_from_ripple_if_needed('TrackedObject', context);
|
|
405
405
|
|
|
406
|
-
return b.new(
|
|
407
|
-
b.id(objectAlias),
|
|
408
|
-
b.object(node.properties.map((prop) => context.visit(prop))),
|
|
409
|
-
);
|
|
406
|
+
return b.new(b.id(objectAlias), b.object(node.properties.map((prop) => context.visit(prop))));
|
|
410
407
|
}
|
|
411
408
|
|
|
412
409
|
return b.call(
|
|
@@ -466,14 +463,17 @@ const visitors = {
|
|
|
466
463
|
}
|
|
467
464
|
|
|
468
465
|
if (node.tracked || (node.property.type === 'Identifier' && node.property.tracked)) {
|
|
466
|
+
// In TypeScript mode, skip the transformation and let transform_ts_child handle it
|
|
469
467
|
add_ripple_internal_import(context);
|
|
470
468
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
469
|
+
if (!context.state.to_ts) {
|
|
470
|
+
return b.call(
|
|
471
|
+
'_$_.get_property',
|
|
472
|
+
context.visit(node.object),
|
|
473
|
+
node.computed ? context.visit(node.property) : b.literal(node.property.name),
|
|
474
|
+
node.optional ? b.true : undefined,
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
if (node.object.type === 'MemberExpression' && node.object.optional) {
|
|
@@ -499,7 +499,7 @@ const visitors = {
|
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
501
|
} else {
|
|
502
|
-
context.next();
|
|
502
|
+
return context.next();
|
|
503
503
|
}
|
|
504
504
|
},
|
|
505
505
|
|
|
@@ -549,14 +549,68 @@ const visitors = {
|
|
|
549
549
|
},
|
|
550
550
|
|
|
551
551
|
JSXText(node, context) {
|
|
552
|
+
if (context.state.to_ts) {
|
|
553
|
+
return context.next();
|
|
554
|
+
}
|
|
552
555
|
return b.literal(node.value + '');
|
|
553
556
|
},
|
|
554
557
|
|
|
555
558
|
JSXIdentifier(node, context) {
|
|
559
|
+
if (context.state.to_ts) {
|
|
560
|
+
return context.next();
|
|
561
|
+
}
|
|
556
562
|
return b.id(node.name);
|
|
557
563
|
},
|
|
558
564
|
|
|
565
|
+
JSXExpressionContainer(node, context) {
|
|
566
|
+
if (context.state.to_ts) {
|
|
567
|
+
return context.next();
|
|
568
|
+
}
|
|
569
|
+
return context.visit(node.expression);
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
JSXFragment(node, context) {
|
|
573
|
+
if (context.state.to_ts) {
|
|
574
|
+
return context.next();
|
|
575
|
+
}
|
|
576
|
+
const attributes = node.openingFragment.attributes;
|
|
577
|
+
const normalized_children = node.children.filter((child) => {
|
|
578
|
+
return child.type !== 'JSXText' || child.value.trim() !== '';
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
const props = b.object(
|
|
582
|
+
attributes.map((attr) => {
|
|
583
|
+
if (attr.type === 'JSXAttribute') {
|
|
584
|
+
return b.prop('init', context.visit(attr.name), context.visit(attr.value));
|
|
585
|
+
} else if (attr.type === 'JSXSpreadAttribute') {
|
|
586
|
+
return b.spread(context.visit(attr.argument));
|
|
587
|
+
}
|
|
588
|
+
}),
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
if (normalized_children.length > 0) {
|
|
592
|
+
props.properties.push(
|
|
593
|
+
b.prop(
|
|
594
|
+
'init',
|
|
595
|
+
b.id('children'),
|
|
596
|
+
normalized_children.length === 1
|
|
597
|
+
? context.visit(normalized_children[0])
|
|
598
|
+
: b.array(normalized_children.map((child) => context.visit(child))),
|
|
599
|
+
),
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return b.call(
|
|
604
|
+
normalized_children.length > 1 ? '__compat.jsxs' : '__compat.jsx',
|
|
605
|
+
b.id('__compat.Fragment'),
|
|
606
|
+
props,
|
|
607
|
+
);
|
|
608
|
+
},
|
|
609
|
+
|
|
559
610
|
JSXElement(node, context) {
|
|
611
|
+
if (context.state.to_ts) {
|
|
612
|
+
return context.next();
|
|
613
|
+
}
|
|
560
614
|
const name = node.openingElement.name;
|
|
561
615
|
const attributes = node.openingElement.attributes;
|
|
562
616
|
const normalized_children = node.children.filter((child) => {
|
|
@@ -573,7 +627,7 @@ const visitors = {
|
|
|
573
627
|
}),
|
|
574
628
|
);
|
|
575
629
|
|
|
576
|
-
if (
|
|
630
|
+
if (normalized_children.length > 0) {
|
|
577
631
|
props.properties.push(
|
|
578
632
|
b.prop(
|
|
579
633
|
'init',
|
|
@@ -586,7 +640,7 @@ const visitors = {
|
|
|
586
640
|
}
|
|
587
641
|
|
|
588
642
|
return b.call(
|
|
589
|
-
'
|
|
643
|
+
normalized_children.length > 1 ? '__compat.jsxs' : '__compat.jsx',
|
|
590
644
|
name.type === 'JSXIdentifier' && name.name[0].toLowerCase() === name.name[0]
|
|
591
645
|
? b.literal(name.name)
|
|
592
646
|
: context.visit(name),
|
|
@@ -678,6 +732,29 @@ const visitors = {
|
|
|
678
732
|
const local_updates = [];
|
|
679
733
|
const is_void = is_void_element(node.id.name);
|
|
680
734
|
|
|
735
|
+
let scoping_hash = null;
|
|
736
|
+
if (node.metadata.scoped && state.component.css) {
|
|
737
|
+
scoping_hash = state.component.css.hash;
|
|
738
|
+
} else {
|
|
739
|
+
let inside_dynamic_children = false;
|
|
740
|
+
for (let i = context.path.length - 1; i >= 0; i--) {
|
|
741
|
+
const anc = context.path[i];
|
|
742
|
+
if (anc && anc.type === 'Component' && anc.metadata && anc.metadata.inherited_css) {
|
|
743
|
+
inside_dynamic_children = true;
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (inside_dynamic_children) {
|
|
748
|
+
for (let i = context.path.length - 1; i >= 0; i--) {
|
|
749
|
+
const anc = context.path[i];
|
|
750
|
+
if (anc && anc.type === 'Component' && anc.css) {
|
|
751
|
+
scoping_hash = anc.css.hash;
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
681
758
|
state.template.push(`<${node.id.name}`);
|
|
682
759
|
|
|
683
760
|
for (const attr of node.attributes) {
|
|
@@ -847,8 +924,8 @@ const visitors = {
|
|
|
847
924
|
if (class_attribute.value.type === 'Literal') {
|
|
848
925
|
let value = class_attribute.value.value;
|
|
849
926
|
|
|
850
|
-
if (
|
|
851
|
-
value = `${
|
|
927
|
+
if (scoping_hash) {
|
|
928
|
+
value = `${scoping_hash} ${value}`;
|
|
852
929
|
}
|
|
853
930
|
|
|
854
931
|
handle_static_attr(class_attribute.name.name, value);
|
|
@@ -857,10 +934,7 @@ const visitors = {
|
|
|
857
934
|
const metadata = { tracking: false, await: false };
|
|
858
935
|
let expression = visit(class_attribute.value, { ...state, metadata });
|
|
859
936
|
|
|
860
|
-
const hash_arg =
|
|
861
|
-
node.metadata.scoped && state.component.css
|
|
862
|
-
? b.literal(state.component.css.hash)
|
|
863
|
-
: undefined;
|
|
937
|
+
const hash_arg = scoping_hash ? b.literal(scoping_hash) : undefined;
|
|
864
938
|
const is_html = context.state.metadata.namespace === 'html' && node.id.name !== 'svg';
|
|
865
939
|
|
|
866
940
|
if (metadata.tracking) {
|
|
@@ -873,10 +947,8 @@ const visitors = {
|
|
|
873
947
|
);
|
|
874
948
|
}
|
|
875
949
|
}
|
|
876
|
-
} else if (
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
handle_static_attr(is_spreading ? '#class' : 'class', value);
|
|
950
|
+
} else if (scoping_hash) {
|
|
951
|
+
handle_static_attr(is_spreading ? '#class' : 'class', scoping_hash);
|
|
880
952
|
}
|
|
881
953
|
|
|
882
954
|
if (style_attribute !== null) {
|
|
@@ -1015,7 +1087,14 @@ const visitors = {
|
|
|
1015
1087
|
|
|
1016
1088
|
if (children_filtered.length > 0) {
|
|
1017
1089
|
const component_scope = context.state.scopes.get(node);
|
|
1018
|
-
const
|
|
1090
|
+
const children_component = b.component(b.id('children'), [], children_filtered);
|
|
1091
|
+
|
|
1092
|
+
children_component.metadata = {
|
|
1093
|
+
...(children_component.metadata || {}),
|
|
1094
|
+
inherited_css: true,
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
const children = visit(children_component, {
|
|
1019
1098
|
...context.state,
|
|
1020
1099
|
scope: component_scope,
|
|
1021
1100
|
namespace: child_namespace,
|
|
@@ -1139,7 +1218,7 @@ const visitors = {
|
|
|
1139
1218
|
const operator = node.operator;
|
|
1140
1219
|
const right = node.right;
|
|
1141
1220
|
|
|
1142
|
-
if (operator !== '=') {
|
|
1221
|
+
if (operator !== '=' && context.state.metadata?.tracking === false) {
|
|
1143
1222
|
context.state.metadata.tracking = true;
|
|
1144
1223
|
}
|
|
1145
1224
|
|
|
@@ -1193,7 +1272,9 @@ const visitors = {
|
|
|
1193
1272
|
(argument.tracked || (argument.property.type === 'Identifier' && argument.property.tracked))
|
|
1194
1273
|
) {
|
|
1195
1274
|
add_ripple_internal_import(context);
|
|
1196
|
-
context.state.metadata
|
|
1275
|
+
if (context.state.metadata?.tracking === false) {
|
|
1276
|
+
context.state.metadata.tracking = true;
|
|
1277
|
+
}
|
|
1197
1278
|
|
|
1198
1279
|
return b.call(
|
|
1199
1280
|
node.prefix ? '_$_.update_pre_property' : '_$_.update_property',
|
|
@@ -1609,7 +1690,17 @@ function transform_ts_child(node, context) {
|
|
|
1609
1690
|
state.init.push(b.stmt(visit(node.expression, { ...state })));
|
|
1610
1691
|
} else if (node.type === 'Element') {
|
|
1611
1692
|
// Use capitalized name for dynamic components/elements in TypeScript output
|
|
1612
|
-
|
|
1693
|
+
// If node.id is not an Identifier (e.g., MemberExpression like props.children),
|
|
1694
|
+
// we need to visit it to get the proper expression
|
|
1695
|
+
let type_expression;
|
|
1696
|
+
let type_is_expression = false;
|
|
1697
|
+
if (node.id.type === 'MemberExpression') {
|
|
1698
|
+
// For MemberExpressions, we need to create a JSXExpression, not a JSXIdentifier
|
|
1699
|
+
type_expression = visit(node.id, state);
|
|
1700
|
+
type_is_expression = true;
|
|
1701
|
+
} else {
|
|
1702
|
+
type_expression = node.metadata?.ts_name || node.id.name;
|
|
1703
|
+
}
|
|
1613
1704
|
const children = [];
|
|
1614
1705
|
let has_children_props = false;
|
|
1615
1706
|
|
|
@@ -1647,9 +1738,7 @@ function transform_ts_child(node, context) {
|
|
|
1647
1738
|
const createRefKeyAlias = import_from_ripple_if_needed('createRefKey', context);
|
|
1648
1739
|
const metadata = { await: false };
|
|
1649
1740
|
const argument = visit(attr.argument, { ...state, metadata });
|
|
1650
|
-
const wrapper = b.object(
|
|
1651
|
-
[b.prop('init', b.call(createRefKeyAlias), argument, true)]
|
|
1652
|
-
);
|
|
1741
|
+
const wrapper = b.object([b.prop('init', b.call(createRefKeyAlias), argument, true)]);
|
|
1653
1742
|
return b.jsx_spread_attribute(wrapper);
|
|
1654
1743
|
}
|
|
1655
1744
|
});
|
|
@@ -1674,33 +1763,40 @@ function transform_ts_child(node, context) {
|
|
|
1674
1763
|
}
|
|
1675
1764
|
}
|
|
1676
1765
|
|
|
1677
|
-
|
|
1678
|
-
// Use node.id.loc if available, otherwise create a loc based on the element's position
|
|
1679
|
-
opening_type.loc = node.id.loc || {
|
|
1680
|
-
start: {
|
|
1681
|
-
line: node.loc.start.line,
|
|
1682
|
-
column: node.loc.start.column + 2, // After "<@"
|
|
1683
|
-
},
|
|
1684
|
-
end: {
|
|
1685
|
-
line: node.loc.start.line,
|
|
1686
|
-
column: node.loc.start.column + 2 + type.length,
|
|
1687
|
-
},
|
|
1688
|
-
};
|
|
1689
|
-
|
|
1690
|
-
let closing_type = undefined;
|
|
1766
|
+
let opening_type, closing_type;
|
|
1691
1767
|
|
|
1692
|
-
if (
|
|
1693
|
-
|
|
1694
|
-
|
|
1768
|
+
if (type_is_expression) {
|
|
1769
|
+
// For dynamic/expression-based components (e.g., props.children),
|
|
1770
|
+
// use JSX expression instead of identifier
|
|
1771
|
+
opening_type = type_expression;
|
|
1772
|
+
closing_type = node.selfClosing ? undefined : type_expression;
|
|
1773
|
+
} else {
|
|
1774
|
+
opening_type = b.jsx_id(type_expression);
|
|
1775
|
+
// Use node.id.loc if available, otherwise create a loc based on the element's position
|
|
1776
|
+
opening_type.loc = node.id.loc || {
|
|
1695
1777
|
start: {
|
|
1696
|
-
line: node.loc.
|
|
1697
|
-
column: node.loc.
|
|
1778
|
+
line: node.loc.start.line,
|
|
1779
|
+
column: node.loc.start.column + 2, // After "<@"
|
|
1698
1780
|
},
|
|
1699
1781
|
end: {
|
|
1700
|
-
line: node.loc.
|
|
1701
|
-
column: node.loc.
|
|
1782
|
+
line: node.loc.start.line,
|
|
1783
|
+
column: node.loc.start.column + 2 + type_expression.length,
|
|
1702
1784
|
},
|
|
1703
1785
|
};
|
|
1786
|
+
|
|
1787
|
+
if (!node.selfClosing) {
|
|
1788
|
+
closing_type = b.jsx_id(type_expression);
|
|
1789
|
+
closing_type.loc = {
|
|
1790
|
+
start: {
|
|
1791
|
+
line: node.loc.end.line,
|
|
1792
|
+
column: node.loc.end.column - type_expression.length - 1,
|
|
1793
|
+
},
|
|
1794
|
+
end: {
|
|
1795
|
+
line: node.loc.end.line,
|
|
1796
|
+
column: node.loc.end.column - 1,
|
|
1797
|
+
},
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1704
1800
|
}
|
|
1705
1801
|
|
|
1706
1802
|
const jsxElement = b.jsx_element(
|
|
@@ -1815,8 +1911,14 @@ function transform_ts_child(node, context) {
|
|
|
1815
1911
|
state.init.push(component);
|
|
1816
1912
|
} else if (node.type === 'BreakStatement') {
|
|
1817
1913
|
state.init.push(b.break);
|
|
1818
|
-
} else {
|
|
1914
|
+
} else if (node.type === 'TsxCompat') {
|
|
1915
|
+
const children = node.children
|
|
1916
|
+
.map((child) => visit(child, state))
|
|
1917
|
+
.filter((child) => child.type !== 'JSXText' || child.value.trim() !== '');
|
|
1918
|
+
|
|
1819
1919
|
debugger;
|
|
1920
|
+
state.init.push(b.stmt(b.jsx_fragment(children)));
|
|
1921
|
+
} else {
|
|
1820
1922
|
throw new Error('TODO');
|
|
1821
1923
|
}
|
|
1822
1924
|
}
|
|
@@ -2064,9 +2166,66 @@ function transform_body(body, { visit, state }) {
|
|
|
2064
2166
|
function create_tsx_with_typescript_support() {
|
|
2065
2167
|
const base_tsx = tsx();
|
|
2066
2168
|
|
|
2067
|
-
//
|
|
2169
|
+
// Add custom TypeScript node handlers that aren't in tsx
|
|
2068
2170
|
return {
|
|
2069
2171
|
...base_tsx,
|
|
2172
|
+
// Custom handler for TSParenthesizedType: (Type)
|
|
2173
|
+
TSParenthesizedType(node, context) {
|
|
2174
|
+
context.write('(');
|
|
2175
|
+
context.visit(node.typeAnnotation);
|
|
2176
|
+
context.write(')');
|
|
2177
|
+
},
|
|
2178
|
+
// Custom handler for TSMappedType: { [K in keyof T]: T[K] }
|
|
2179
|
+
TSMappedType(node, context) {
|
|
2180
|
+
context.write('{ ');
|
|
2181
|
+
if (node.readonly) {
|
|
2182
|
+
if (node.readonly === '+' || node.readonly === true) {
|
|
2183
|
+
context.write('readonly ');
|
|
2184
|
+
} else if (node.readonly === '-') {
|
|
2185
|
+
context.write('-readonly ');
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
context.write('[');
|
|
2189
|
+
// Visit the entire type parameter (TSTypeParameter node)
|
|
2190
|
+
if (node.typeParameter) {
|
|
2191
|
+
context.visit(node.typeParameter);
|
|
2192
|
+
}
|
|
2193
|
+
context.write(']');
|
|
2194
|
+
if (node.optional) {
|
|
2195
|
+
if (node.optional === '+' || node.optional === true) {
|
|
2196
|
+
context.write('?');
|
|
2197
|
+
} else if (node.optional === '-') {
|
|
2198
|
+
context.write('-?');
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
context.write(': ');
|
|
2202
|
+
// Visit the value type - could be either typeAnnotation or nameType
|
|
2203
|
+
if (node.typeAnnotation) {
|
|
2204
|
+
context.visit(node.typeAnnotation);
|
|
2205
|
+
} else if (node.nameType) {
|
|
2206
|
+
context.visit(node.nameType);
|
|
2207
|
+
}
|
|
2208
|
+
context.write(' }');
|
|
2209
|
+
},
|
|
2210
|
+
// Custom handler for TSTypeParameter: K in T (for mapped types)
|
|
2211
|
+
// acord ts has a bug where `in` is printed as `extends`, so we override it here
|
|
2212
|
+
TSTypeParameter(node, context) {
|
|
2213
|
+
// For mapped types, the name is just a string, not an Identifier node
|
|
2214
|
+
if (typeof node.name === 'string') {
|
|
2215
|
+
context.write(node.name);
|
|
2216
|
+
} else if (node.name && node.name.name) {
|
|
2217
|
+
context.write(node.name.name);
|
|
2218
|
+
}
|
|
2219
|
+
if (node.constraint) {
|
|
2220
|
+
context.write(' in ');
|
|
2221
|
+
context.visit(node.constraint);
|
|
2222
|
+
}
|
|
2223
|
+
if (node.default) {
|
|
2224
|
+
context.write(' = ');
|
|
2225
|
+
context.visit(node.default);
|
|
2226
|
+
}
|
|
2227
|
+
},
|
|
2228
|
+
// Override the ArrowFunctionExpression handler to support TypeScript return types
|
|
2070
2229
|
ArrowFunctionExpression(node, context) {
|
|
2071
2230
|
if (node.async) context.write('async ');
|
|
2072
2231
|
|
|
@@ -2097,7 +2256,7 @@ function create_tsx_with_typescript_support() {
|
|
|
2097
2256
|
} else {
|
|
2098
2257
|
context.visit(node.body);
|
|
2099
2258
|
}
|
|
2100
|
-
}
|
|
2259
|
+
},
|
|
2101
2260
|
};
|
|
2102
2261
|
}
|
|
2103
2262
|
|
|
@@ -2113,7 +2272,12 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
2113
2272
|
const ripple_user_imports = new Map(); // exported -> local
|
|
2114
2273
|
if (analysis && analysis.ast && Array.isArray(analysis.ast.body)) {
|
|
2115
2274
|
for (const stmt of analysis.ast.body) {
|
|
2116
|
-
if (
|
|
2275
|
+
if (
|
|
2276
|
+
stmt &&
|
|
2277
|
+
stmt.type === 'ImportDeclaration' &&
|
|
2278
|
+
stmt.source &&
|
|
2279
|
+
stmt.source.value === 'ripple'
|
|
2280
|
+
) {
|
|
2117
2281
|
for (const spec of stmt.specifiers || []) {
|
|
2118
2282
|
if (spec.type === 'ImportSpecifier' && spec.imported && spec.local) {
|
|
2119
2283
|
ripple_user_imports.set(spec.imported.name, spec.local.name);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { Block } from '#client' */
|
|
1
|
+
/** @import { Block, CompatOptions } from '#client' */
|
|
2
2
|
|
|
3
3
|
import { destroy_block, root } from './internal/client/blocks.js';
|
|
4
4
|
import { handle_root_events } from './internal/client/events.js';
|
|
@@ -12,7 +12,7 @@ export { jsx, jsxs, Fragment } from '../jsx-runtime.js';
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @param {(anchor: Node, props: Record<string, any>, active_block: Block | null) => void} component
|
|
15
|
-
* @param {{ props?: Record<string, any>, target: HTMLElement }} options
|
|
15
|
+
* @param {{ props?: Record<string, any>, target: HTMLElement, compat?: CompatOptions }} options
|
|
16
16
|
* @returns {() => void}
|
|
17
17
|
*/
|
|
18
18
|
export function mount(component, options) {
|
|
@@ -34,7 +34,7 @@ export function mount(component, options) {
|
|
|
34
34
|
|
|
35
35
|
const _root = root(() => {
|
|
36
36
|
component(anchor, props, active_block);
|
|
37
|
-
});
|
|
37
|
+
}, options.compat);
|
|
38
38
|
|
|
39
39
|
return () => {
|
|
40
40
|
cleanup_events();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { Block, Derived } from '#client' */
|
|
1
|
+
/** @import { Block, Derived, CompatOptions } from '#client' */
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
BLOCK_HAS_RUN,
|
|
@@ -124,11 +124,33 @@ export function ref(element, get_fn) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* @param {() => void} fn
|
|
127
|
+
* @param {() => (void | (() => void))} fn
|
|
128
|
+
* @param {CompatOptions} [compat]
|
|
128
129
|
* @returns {Block}
|
|
129
130
|
*/
|
|
130
|
-
export function root(fn) {
|
|
131
|
-
|
|
131
|
+
export function root(fn, compat) {
|
|
132
|
+
var target_fn = fn;
|
|
133
|
+
|
|
134
|
+
if (compat != null) {
|
|
135
|
+
/** @type {Array<void | (() => void)>} */
|
|
136
|
+
var unmounts = [];
|
|
137
|
+
for (var key in compat) {
|
|
138
|
+
var api = compat[key];
|
|
139
|
+
unmounts.push(api.createRoot());
|
|
140
|
+
}
|
|
141
|
+
target_fn = () => {
|
|
142
|
+
var component_unmount = fn();
|
|
143
|
+
|
|
144
|
+
return () => {
|
|
145
|
+
component_unmount?.();
|
|
146
|
+
for (var unmount of unmounts) {
|
|
147
|
+
unmount?.();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return block(ROOT_BLOCK, fn, { compat });
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
/**
|
|
@@ -1,8 +1,40 @@
|
|
|
1
|
+
/** @import { CompatApi } from '#client' */
|
|
2
|
+
|
|
3
|
+
import { ROOT_BLOCK } from "./constants";
|
|
4
|
+
import { active_block } from "./runtime";
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
|
-
* @param {string} kind
|
|
3
|
-
* @
|
|
4
|
-
|
|
7
|
+
* @param {string} kind
|
|
8
|
+
* @returns {CompatApi | null}
|
|
9
|
+
*/
|
|
10
|
+
function get_compat_from_root(kind) {
|
|
11
|
+
var current = active_block;
|
|
12
|
+
|
|
13
|
+
while (current !== null) {
|
|
14
|
+
if ((current.f & ROOT_BLOCK) !== 0) {
|
|
15
|
+
var api = current.s.compat[kind];
|
|
16
|
+
|
|
17
|
+
if (api != null) {
|
|
18
|
+
return api;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
current = current.p;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} kind
|
|
29
|
+
* @param {Node} node
|
|
30
|
+
* @param {() => JSX.Element[]} children_fn
|
|
5
31
|
*/
|
|
6
32
|
export function tsx_compat(kind, node, children_fn) {
|
|
7
|
-
|
|
8
|
-
|
|
33
|
+
var compat = get_compat_from_root(kind);
|
|
34
|
+
|
|
35
|
+
if (compat == null) {
|
|
36
|
+
throw new Error(`No compat API found for kind "${kind}"`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
compat.createComponent(node, children_fn);
|
|
40
|
+
}
|
|
@@ -53,3 +53,13 @@ export type Block = {
|
|
|
53
53
|
// teardown function
|
|
54
54
|
t: (() => {}) | null;
|
|
55
55
|
};
|
|
56
|
+
|
|
57
|
+
export type CompatApi = {
|
|
58
|
+
createRoot: () => void;
|
|
59
|
+
createComponent: (node: any, children_fn: () => any) => void;
|
|
60
|
+
jsx: (type: any, props: any) => any;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type CompatOptions = {
|
|
64
|
+
[key: string]: CompatApi;
|
|
65
|
+
}
|
package/src/utils/builders.js
CHANGED
|
@@ -753,6 +753,23 @@ export function jsx_element(
|
|
|
753
753
|
return element;
|
|
754
754
|
}
|
|
755
755
|
|
|
756
|
+
/**
|
|
757
|
+
* @param {Array<ESTree.JSXText | ESTree.JSXExpressionContainer | ESTree.JSXSpreadChild | ESTree.JSXElement | ESTree.JSXFragment>} children
|
|
758
|
+
* @returns {ESTree.JSXFragment}
|
|
759
|
+
*/
|
|
760
|
+
export function jsx_fragment(children = []) {
|
|
761
|
+
return {
|
|
762
|
+
type: 'JSXFragment',
|
|
763
|
+
openingFragment: {
|
|
764
|
+
type: 'JSXOpeningFragment',
|
|
765
|
+
},
|
|
766
|
+
closingFragment: {
|
|
767
|
+
type: 'JSXClosingFragment',
|
|
768
|
+
},
|
|
769
|
+
children,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
756
773
|
/**
|
|
757
774
|
* @param {ESTree.Expression | ESTree.JSXEmptyExpression} expression
|
|
758
775
|
* @returns {ESTree.JSXExpressionContainer}
|