@farm.js/react 0.1.0-beta.3 → 0.1.0-beta.5
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/README.md +133 -37
- package/dist/compiler-runtime.cjs +2052 -188
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +106 -4
- package/dist/compiler-runtime.d.ts +106 -4
- package/dist/compiler-runtime.mjs +2041 -189
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/index.cjs +5 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.mjs +5 -1
- package/dist/index.mjs.map +1 -1
- package/dist/list.cjs +18 -1
- package/dist/list.cjs.map +1 -1
- package/dist/list.mjs +18 -1
- package/dist/list.mjs.map +1 -1
- package/dist/vite.cjs +1224 -87
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +1224 -87
- package/dist/vite.mjs.map +1 -1
- package/package.json +6 -3
package/dist/vite.mjs
CHANGED
|
@@ -4,6 +4,96 @@ import { mkdir, writeFile } from 'fs/promises';
|
|
|
4
4
|
import { resolve, dirname, relative } from 'path';
|
|
5
5
|
|
|
6
6
|
// src/vite.ts
|
|
7
|
+
var DELEGATABLE_KEYED_ROW_EVENTS = /* @__PURE__ */ new Set([
|
|
8
|
+
"onBeforeInput",
|
|
9
|
+
"onBlur",
|
|
10
|
+
"onChange",
|
|
11
|
+
"onClick",
|
|
12
|
+
"onCompositionEnd",
|
|
13
|
+
"onCompositionStart",
|
|
14
|
+
"onCompositionUpdate",
|
|
15
|
+
"onContextMenu",
|
|
16
|
+
"onCopy",
|
|
17
|
+
"onCut",
|
|
18
|
+
"onDoubleClick",
|
|
19
|
+
"onDrag",
|
|
20
|
+
"onDragEnd",
|
|
21
|
+
"onDragEnter",
|
|
22
|
+
"onDragExit",
|
|
23
|
+
"onDragLeave",
|
|
24
|
+
"onDragOver",
|
|
25
|
+
"onDragStart",
|
|
26
|
+
"onDrop",
|
|
27
|
+
"onFocus",
|
|
28
|
+
"onInput",
|
|
29
|
+
"onKeyDown",
|
|
30
|
+
"onKeyPress",
|
|
31
|
+
"onKeyUp",
|
|
32
|
+
"onMouseDown",
|
|
33
|
+
"onMouseMove",
|
|
34
|
+
"onMouseOut",
|
|
35
|
+
"onMouseOver",
|
|
36
|
+
"onMouseUp",
|
|
37
|
+
"onPaste",
|
|
38
|
+
"onPointerCancel",
|
|
39
|
+
"onPointerDown",
|
|
40
|
+
"onPointerMove",
|
|
41
|
+
"onPointerOut",
|
|
42
|
+
"onPointerOver",
|
|
43
|
+
"onPointerUp",
|
|
44
|
+
"onReset",
|
|
45
|
+
"onSubmit",
|
|
46
|
+
"onTouchCancel",
|
|
47
|
+
"onTouchEnd",
|
|
48
|
+
"onTouchMove",
|
|
49
|
+
"onTouchStart",
|
|
50
|
+
"onWheel"
|
|
51
|
+
]);
|
|
52
|
+
function canDelegateKeyedRowEvents(plan) {
|
|
53
|
+
if (plan.events.length === 0 || plan.conditionals.length > 0) return false;
|
|
54
|
+
if (plan.source.openingElement.attributes.some(
|
|
55
|
+
(attribute) => types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && /^on[A-Z]/.test(attribute.name.name)
|
|
56
|
+
)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return plan.events.every(
|
|
60
|
+
(event) => DELEGATABLE_KEYED_ROW_EVENTS.has(event.name.replace(/Capture$/, ""))
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
var COMPILER_RUNTIME_FEATURE_EXPORTS = {
|
|
64
|
+
conditional: "conditionalRuntimeFeature",
|
|
65
|
+
"host-conditional": "hostConditionalRuntimeFeature",
|
|
66
|
+
"conditional-ranges": "conditionalRangesRuntimeFeature",
|
|
67
|
+
"keyed-list": "keyedListRuntimeFeature",
|
|
68
|
+
"keyed-rows": "keyedRowsRuntimeFeature",
|
|
69
|
+
"keyed-rows-conditional": "keyedRowsConditionalRuntimeFeature",
|
|
70
|
+
"keyed-rows-host": "keyedRowsHostRuntimeFeature",
|
|
71
|
+
"keyed-rows-complete": "keyedRowsCompleteRuntimeFeature",
|
|
72
|
+
"keyed-ranges": "keyedRangesRuntimeFeature",
|
|
73
|
+
"mixed-ranges": "mixedRangesRuntimeFeature",
|
|
74
|
+
component: "componentRuntimeFeature"
|
|
75
|
+
};
|
|
76
|
+
function runtimeFeaturesForPlans(plans) {
|
|
77
|
+
const features = /* @__PURE__ */ new Set();
|
|
78
|
+
let keyedRowsHaveConditionals = false;
|
|
79
|
+
let keyedRowsHaveHostBlocks = false;
|
|
80
|
+
for (const plan of plans) {
|
|
81
|
+
if (plan.kind === "keyed-rows") {
|
|
82
|
+
keyedRowsHaveConditionals || (keyedRowsHaveConditionals = plan.conditionals.length > 0);
|
|
83
|
+
keyedRowsHaveHostBlocks || (keyedRowsHaveHostBlocks = Boolean(plan.descriptorBlocks?.size));
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (plan.kind in COMPILER_RUNTIME_FEATURE_EXPORTS) {
|
|
87
|
+
features.add(plan.kind);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (plans.some((plan) => plan.kind === "keyed-rows")) {
|
|
91
|
+
features.add(
|
|
92
|
+
keyedRowsHaveConditionals && keyedRowsHaveHostBlocks ? "keyed-rows-complete" : keyedRowsHaveConditionals ? "keyed-rows-conditional" : keyedRowsHaveHostBlocks ? "keyed-rows-host" : "keyed-rows"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return [...features].sort();
|
|
96
|
+
}
|
|
7
97
|
var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set(["Boolean", "Number", "String"]);
|
|
8
98
|
var SAFE_MATH_CALLS = /* @__PURE__ */ new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc"]);
|
|
9
99
|
function isComponentName(name) {
|
|
@@ -88,6 +178,37 @@ function rewriteDestructuredPropAccess(expression, names, propsParameter) {
|
|
|
88
178
|
});
|
|
89
179
|
return file.program.body[0].expression;
|
|
90
180
|
}
|
|
181
|
+
function collectDestructuredPropNames(expression, names, propsParameter) {
|
|
182
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
183
|
+
if (names.size === 0) return referenced;
|
|
184
|
+
traverse(expressionFile(cloneExpression(expression)), {
|
|
185
|
+
MemberExpression(path) {
|
|
186
|
+
const { object, property, computed } = path.node;
|
|
187
|
+
if (computed || !types.isIdentifier(object, { name: propsParameter.name }) || !types.isIdentifier(property) || !names.has(property.name)) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
referenced.add(property.name);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return referenced;
|
|
194
|
+
}
|
|
195
|
+
function rewriteTrackedPropAccess(expression, propsParameter, bindingsByName) {
|
|
196
|
+
if (bindingsByName.size === 0) return cloneExpression(expression);
|
|
197
|
+
const file = expressionFile(cloneExpression(expression));
|
|
198
|
+
traverse(file, {
|
|
199
|
+
MemberExpression(path) {
|
|
200
|
+
const { object, property, computed } = path.node;
|
|
201
|
+
if (computed || !types.isIdentifier(object, { name: propsParameter.name }) || !types.isIdentifier(property)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const binding = bindingsByName.get(property.name);
|
|
205
|
+
if (!binding) return;
|
|
206
|
+
path.replaceWith(types.identifier(binding.valueName));
|
|
207
|
+
path.skip();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
return file.program.body[0].expression;
|
|
211
|
+
}
|
|
91
212
|
function rewriteHandlerAccess(root, handlersByName) {
|
|
92
213
|
if (handlersByName.size === 0) return { root: types.cloneNode(root, true) };
|
|
93
214
|
const file = expressionFile(types.cloneNode(root, true));
|
|
@@ -767,7 +888,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
767
888
|
const reason = visit(row, []);
|
|
768
889
|
return reason ? { reason } : { bindings, events, conditionals };
|
|
769
890
|
}
|
|
770
|
-
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
|
|
891
|
+
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
|
|
771
892
|
let collection;
|
|
772
893
|
let keyCallback;
|
|
773
894
|
let renderCallback;
|
|
@@ -822,17 +943,29 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
|
|
|
822
943
|
safeGlobals,
|
|
823
944
|
new Set([...statesByValue.values()].map((state) => state.setterName))
|
|
824
945
|
);
|
|
825
|
-
if (rowAnalysis.reason) return void 0;
|
|
946
|
+
if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
|
|
947
|
+
const keyExpression = returnedExpression(keyCallback);
|
|
948
|
+
const structureDependencies = new Set(collectStateDependencies(collection, statesByValue));
|
|
949
|
+
if (keyExpression) {
|
|
950
|
+
for (const dependency of collectStateDependencies(keyExpression, statesByValue)) {
|
|
951
|
+
structureDependencies.add(dependency);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
826
954
|
return {
|
|
827
955
|
source,
|
|
828
956
|
collection,
|
|
957
|
+
structureDependencies: [...structureDependencies].sort((left, right) => left - right),
|
|
829
958
|
keyCallback,
|
|
830
959
|
renderCallback,
|
|
831
960
|
row,
|
|
832
961
|
dependencies,
|
|
833
|
-
bindings: rowAnalysis.bindings || []
|
|
962
|
+
bindings: (rowAnalysis.bindings || []).map((binding) => ({
|
|
963
|
+
...binding,
|
|
964
|
+
dependencies: collectStateDependencies(binding.value, statesByValue)
|
|
965
|
+
})),
|
|
834
966
|
events: rowAnalysis.events || [],
|
|
835
967
|
conditionals: rowAnalysis.conditionals || [],
|
|
968
|
+
rowReason: rowAnalysis.reason,
|
|
836
969
|
syntax
|
|
837
970
|
};
|
|
838
971
|
}
|
|
@@ -849,22 +982,7 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
849
982
|
}
|
|
850
983
|
const children = meaningfulJsxChildren(container);
|
|
851
984
|
if (children.length !== 1) return void 0;
|
|
852
|
-
return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames);
|
|
853
|
-
}
|
|
854
|
-
function isStaticRangeSibling(element, statesByValue, safeGlobals) {
|
|
855
|
-
for (const child of meaningfulJsxChildren(element)) {
|
|
856
|
-
if (types.isJSXFragment(child)) return false;
|
|
857
|
-
if (types.isJSXElement(child)) {
|
|
858
|
-
if (!isHostElement(child) || !isStaticRangeSibling(child, statesByValue, safeGlobals)) {
|
|
859
|
-
return false;
|
|
860
|
-
}
|
|
861
|
-
continue;
|
|
862
|
-
}
|
|
863
|
-
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression) && !isTextExpression(child.expression, statesByValue, safeGlobals)) {
|
|
864
|
-
return false;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
return true;
|
|
985
|
+
return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames, true);
|
|
868
986
|
}
|
|
869
987
|
function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
|
|
870
988
|
if (container.openingElement.attributes.some(
|
|
@@ -876,6 +994,7 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
876
994
|
if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
|
|
877
995
|
const ranges = [];
|
|
878
996
|
const dependencies = /* @__PURE__ */ new Set();
|
|
997
|
+
const staticBindings = [];
|
|
879
998
|
let staticBefore = 0;
|
|
880
999
|
for (const child of children) {
|
|
881
1000
|
const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames);
|
|
@@ -896,18 +1015,31 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
896
1015
|
continue;
|
|
897
1016
|
}
|
|
898
1017
|
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
899
|
-
|
|
1018
|
+
const analysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
|
|
1019
|
+
if (analysis.reason) return void 0;
|
|
1020
|
+
for (const binding of analysis.bindings || []) {
|
|
1021
|
+
staticBindings.push({
|
|
1022
|
+
...binding,
|
|
1023
|
+
segment: ranges.length,
|
|
1024
|
+
sibling: staticBefore
|
|
1025
|
+
});
|
|
1026
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1027
|
+
dependencies.add(dependency);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
900
1030
|
staticBefore += 1;
|
|
901
1031
|
}
|
|
902
1032
|
if (ranges.length === 0) return void 0;
|
|
903
1033
|
return {
|
|
904
1034
|
ranges,
|
|
905
1035
|
trailing: staticBefore,
|
|
906
|
-
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
1036
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1037
|
+
staticBindings
|
|
907
1038
|
};
|
|
908
1039
|
}
|
|
909
|
-
function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
1040
|
+
function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = false, statefulOnly) {
|
|
910
1041
|
const bindings = [];
|
|
1042
|
+
const needsStaticBinding = (expression) => !statefulOnly || collectStateDependencies(expression, statefulOnly).length > 0;
|
|
911
1043
|
const visit = (element, path) => {
|
|
912
1044
|
const tag = element.openingElement.name;
|
|
913
1045
|
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
@@ -916,20 +1048,26 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
916
1048
|
if (tag.name === "svg") return "compiler-owned conditionals do not support SVG yet";
|
|
917
1049
|
for (const attribute of element.openingElement.attributes) {
|
|
918
1050
|
if (types.isJSXSpreadAttribute(attribute)) {
|
|
1051
|
+
if (statefulOnly && !needsStaticBinding(attribute.argument)) continue;
|
|
919
1052
|
return "compiler-owned conditionals do not support JSX attribute spreads";
|
|
920
1053
|
}
|
|
921
1054
|
const name = jsxAttributeName(attribute);
|
|
922
1055
|
if (!name) return "compiler-owned conditionals do not support namespaced JSX attributes";
|
|
923
1056
|
if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
|
|
1057
|
+
if (statefulOnly && (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression) || !needsStaticBinding(attribute.value.expression))) {
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
924
1060
|
return `compiler-owned conditional ${name} requires React ownership`;
|
|
925
1061
|
}
|
|
926
1062
|
if (/^on[A-Z]/.test(name)) {
|
|
1063
|
+
if (allowStaticEvents) continue;
|
|
927
1064
|
return "compiler-owned conditional events require React ownership";
|
|
928
1065
|
}
|
|
929
1066
|
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
930
1067
|
continue;
|
|
931
1068
|
}
|
|
932
1069
|
const expression = attribute.value.expression;
|
|
1070
|
+
if (!needsStaticBinding(expression)) continue;
|
|
933
1071
|
if (name === "style") {
|
|
934
1072
|
if (!types.isObjectExpression(expression)) {
|
|
935
1073
|
return "compiler-owned conditional styles must use one inline object literal";
|
|
@@ -942,6 +1080,7 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
942
1080
|
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
943
1081
|
return "compiler-owned conditional style names must use camelCase or a CSS custom property";
|
|
944
1082
|
}
|
|
1083
|
+
if (!needsStaticBinding(property.value)) continue;
|
|
945
1084
|
const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
|
|
946
1085
|
if (unsupported2) {
|
|
947
1086
|
return `compiler-owned conditional style ${propertyName} cannot use ${unsupported2}`;
|
|
@@ -976,14 +1115,20 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
976
1115
|
const expressions = element.children.filter(
|
|
977
1116
|
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
978
1117
|
);
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1118
|
+
const boundExpressions = statefulOnly ? expressions.filter((child) => needsStaticBinding(child.expression)) : expressions;
|
|
1119
|
+
if (boundExpressions.length > 0) {
|
|
1120
|
+
for (const child of expressions) {
|
|
1121
|
+
const unsupported = validateDerivedExpression(
|
|
1122
|
+
child.expression,
|
|
1123
|
+
safeGlobals
|
|
1124
|
+
);
|
|
1125
|
+
if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
|
|
1126
|
+
}
|
|
982
1127
|
}
|
|
983
|
-
if (nestedElements.length > 0 &&
|
|
1128
|
+
if (nestedElements.length > 0 && boundExpressions.length > 0) {
|
|
984
1129
|
return "compiler-owned conditionals do not support dynamic text beside nested elements yet";
|
|
985
1130
|
}
|
|
986
|
-
if (nestedElements.length === 0 &&
|
|
1131
|
+
if (nestedElements.length === 0 && boundExpressions.length > 0) {
|
|
987
1132
|
const parts = [];
|
|
988
1133
|
for (const child of element.children) {
|
|
989
1134
|
if (types.isJSXText(child)) {
|
|
@@ -1007,7 +1152,369 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
1007
1152
|
const reason = visit(branch, []);
|
|
1008
1153
|
return reason ? { reason } : { bindings };
|
|
1009
1154
|
}
|
|
1010
|
-
function
|
|
1155
|
+
function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1156
|
+
const bindings = [];
|
|
1157
|
+
const plans = [];
|
|
1158
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
1159
|
+
const visit = (element, path, owner) => {
|
|
1160
|
+
const tag = element.openingElement.name;
|
|
1161
|
+
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
1162
|
+
return "recursive compiler-owned blocks support host elements only";
|
|
1163
|
+
}
|
|
1164
|
+
if (tag.name === "svg") return "recursive compiler-owned blocks do not support SVG yet";
|
|
1165
|
+
for (const attribute of element.openingElement.attributes) {
|
|
1166
|
+
if (types.isJSXSpreadAttribute(attribute)) {
|
|
1167
|
+
return "recursive compiler-owned blocks do not support JSX attribute spreads";
|
|
1168
|
+
}
|
|
1169
|
+
const name = jsxAttributeName(attribute);
|
|
1170
|
+
if (!name) return "recursive compiler-owned blocks do not support namespaced attributes";
|
|
1171
|
+
if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
|
|
1172
|
+
return `recursive compiler-owned block ${name} requires React ownership`;
|
|
1173
|
+
}
|
|
1174
|
+
if (/^on[A-Z]/.test(name)) {
|
|
1175
|
+
return "recursive compiler-owned block events require React ownership";
|
|
1176
|
+
}
|
|
1177
|
+
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
const expression = attribute.value.expression;
|
|
1181
|
+
if (name === "style") {
|
|
1182
|
+
if (!types.isObjectExpression(expression)) {
|
|
1183
|
+
return "recursive compiler-owned styles must use one inline object literal";
|
|
1184
|
+
}
|
|
1185
|
+
for (const property of expression.properties) {
|
|
1186
|
+
if (!types.isObjectProperty(property) || property.computed || !types.isExpression(property.value)) {
|
|
1187
|
+
return "recursive compiler-owned styles do not support spreads, methods, or computed properties";
|
|
1188
|
+
}
|
|
1189
|
+
const propertyName = types.isIdentifier(property.key) ? property.key.name : types.isStringLiteral(property.key) ? property.key.value : void 0;
|
|
1190
|
+
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
1191
|
+
return "recursive compiler-owned style names must use camelCase or a CSS custom property";
|
|
1192
|
+
}
|
|
1193
|
+
const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
|
|
1194
|
+
if (unsupported2) {
|
|
1195
|
+
return `recursive compiler-owned style ${propertyName} cannot use ${unsupported2}`;
|
|
1196
|
+
}
|
|
1197
|
+
bindings.push({
|
|
1198
|
+
kind: "style",
|
|
1199
|
+
path: [...path],
|
|
1200
|
+
name: propertyName,
|
|
1201
|
+
value: cloneExpression(property.value)
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
if (name === "children") {
|
|
1207
|
+
return "recursive compiler-owned children props are not supported yet";
|
|
1208
|
+
}
|
|
1209
|
+
const unsupported = validateDerivedExpression(expression, safeGlobals);
|
|
1210
|
+
if (unsupported) return `recursive compiler-owned ${name} cannot use ${unsupported}`;
|
|
1211
|
+
bindings.push({
|
|
1212
|
+
kind: "attribute",
|
|
1213
|
+
path: [...path],
|
|
1214
|
+
name,
|
|
1215
|
+
value: cloneExpression(expression)
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
const children = meaningfulJsxChildren(element);
|
|
1219
|
+
const hasConditionalRange = children.some(
|
|
1220
|
+
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression) && conditionalBlockShape(child.expression) !== null
|
|
1221
|
+
);
|
|
1222
|
+
const hasKeyedRange = children.some(
|
|
1223
|
+
(child) => analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true) !== void 0
|
|
1224
|
+
);
|
|
1225
|
+
if (hasConditionalRange && hasKeyedRange) {
|
|
1226
|
+
const id = allocateId();
|
|
1227
|
+
const mixed = analyzeMixedRangesContainer(
|
|
1228
|
+
element,
|
|
1229
|
+
statesByValue,
|
|
1230
|
+
safeGlobals,
|
|
1231
|
+
listNames,
|
|
1232
|
+
id,
|
|
1233
|
+
allocateId
|
|
1234
|
+
);
|
|
1235
|
+
if (mixed) {
|
|
1236
|
+
plans.push(...mixed.nestedPlans);
|
|
1237
|
+
for (const [nestedElement, plan2] of mixed.descriptorBlocks) {
|
|
1238
|
+
blocks.set(nestedElement, plan2);
|
|
1239
|
+
}
|
|
1240
|
+
const plan = {
|
|
1241
|
+
kind: "nested-host-mixed-ranges",
|
|
1242
|
+
id,
|
|
1243
|
+
parent: owner,
|
|
1244
|
+
dependencies: mixed.dependencies,
|
|
1245
|
+
source: element,
|
|
1246
|
+
ranges: mixed.ranges,
|
|
1247
|
+
trailing: mixed.trailing,
|
|
1248
|
+
staticBindings: mixed.staticBindings
|
|
1249
|
+
};
|
|
1250
|
+
plans.push(plan);
|
|
1251
|
+
blocks.set(element, plan);
|
|
1252
|
+
return void 0;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
const conditionalChildren = /* @__PURE__ */ new Map();
|
|
1256
|
+
let conditionalContainer = children.length > 0;
|
|
1257
|
+
for (const child of children) {
|
|
1258
|
+
if (types.isJSXElement(child) && isHostElement(child)) continue;
|
|
1259
|
+
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1260
|
+
const shape = conditionalBlockShape(child.expression);
|
|
1261
|
+
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1262
|
+
conditionalChildren.set(child.expression, shape);
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
conditionalContainer = false;
|
|
1267
|
+
break;
|
|
1268
|
+
}
|
|
1269
|
+
if (conditionalContainer && conditionalChildren.size > 0) {
|
|
1270
|
+
const id = allocateId();
|
|
1271
|
+
const ranges = [];
|
|
1272
|
+
const staticBindings = [];
|
|
1273
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1274
|
+
let staticBefore2 = 0;
|
|
1275
|
+
for (const child of children) {
|
|
1276
|
+
if (types.isJSXElement(child)) {
|
|
1277
|
+
const nested = analyzeRecursiveHostTree(
|
|
1278
|
+
child,
|
|
1279
|
+
statesByValue,
|
|
1280
|
+
safeGlobals,
|
|
1281
|
+
listNames,
|
|
1282
|
+
owner,
|
|
1283
|
+
allocateId
|
|
1284
|
+
);
|
|
1285
|
+
if (nested.reason) return nested.reason;
|
|
1286
|
+
plans.push(...nested.plans);
|
|
1287
|
+
for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
|
|
1288
|
+
for (const binding of nested.bindings) {
|
|
1289
|
+
staticBindings.push({
|
|
1290
|
+
...binding,
|
|
1291
|
+
segment: ranges.length,
|
|
1292
|
+
sibling: staticBefore2
|
|
1293
|
+
});
|
|
1294
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1295
|
+
dependencies.add(dependency);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
staticBefore2 += 1;
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
if (!types.isJSXExpressionContainer(child) || types.isJSXEmptyExpression(child.expression)) {
|
|
1302
|
+
return "recursive conditional ranges contain an unsupported child";
|
|
1303
|
+
}
|
|
1304
|
+
const expression = child.expression;
|
|
1305
|
+
const shape = conditionalChildren.get(expression);
|
|
1306
|
+
const truthy = shape.truthy ? analyzeRecursiveHostTree(
|
|
1307
|
+
shape.truthy,
|
|
1308
|
+
statesByValue,
|
|
1309
|
+
safeGlobals,
|
|
1310
|
+
listNames,
|
|
1311
|
+
id,
|
|
1312
|
+
allocateId
|
|
1313
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1314
|
+
const falsy = shape.falsy ? analyzeRecursiveHostTree(
|
|
1315
|
+
shape.falsy,
|
|
1316
|
+
statesByValue,
|
|
1317
|
+
safeGlobals,
|
|
1318
|
+
listNames,
|
|
1319
|
+
id,
|
|
1320
|
+
allocateId
|
|
1321
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1322
|
+
if (truthy.reason) return truthy.reason;
|
|
1323
|
+
if (falsy.reason) return falsy.reason;
|
|
1324
|
+
plans.push(...truthy.plans, ...falsy.plans);
|
|
1325
|
+
for (const [nestedElement, plan2] of truthy.blocks) blocks.set(nestedElement, plan2);
|
|
1326
|
+
for (const [nestedElement, plan2] of falsy.blocks) blocks.set(nestedElement, plan2);
|
|
1327
|
+
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1328
|
+
dependencies.add(dependency);
|
|
1329
|
+
}
|
|
1330
|
+
for (const binding of [...truthy.bindings, ...falsy.bindings]) {
|
|
1331
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1332
|
+
dependencies.add(dependency);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
ranges.push({
|
|
1336
|
+
before: staticBefore2,
|
|
1337
|
+
source: expression,
|
|
1338
|
+
test: cloneExpression(shape.test),
|
|
1339
|
+
logical: shape.logical,
|
|
1340
|
+
truthy: shape.truthy,
|
|
1341
|
+
falsy: shape.falsy,
|
|
1342
|
+
truthyBindings: truthy.bindings,
|
|
1343
|
+
falsyBindings: falsy.bindings
|
|
1344
|
+
});
|
|
1345
|
+
staticBefore2 = 0;
|
|
1346
|
+
}
|
|
1347
|
+
const plan = {
|
|
1348
|
+
kind: "nested-host-conditional-ranges",
|
|
1349
|
+
id,
|
|
1350
|
+
parent: owner,
|
|
1351
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1352
|
+
source: element,
|
|
1353
|
+
ranges,
|
|
1354
|
+
trailing: staticBefore2,
|
|
1355
|
+
staticBindings
|
|
1356
|
+
};
|
|
1357
|
+
plans.push(plan);
|
|
1358
|
+
blocks.set(element, plan);
|
|
1359
|
+
return void 0;
|
|
1360
|
+
}
|
|
1361
|
+
const keyedRows = [];
|
|
1362
|
+
let keyedContainer = children.length > 0;
|
|
1363
|
+
let staticBefore = 0;
|
|
1364
|
+
const staticChildren = [];
|
|
1365
|
+
for (const child of children) {
|
|
1366
|
+
const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
|
|
1367
|
+
if (range) {
|
|
1368
|
+
keyedRows.push({ before: staticBefore, range });
|
|
1369
|
+
staticBefore = 0;
|
|
1370
|
+
} else if (types.isJSXElement(child) && isHostElement(child)) {
|
|
1371
|
+
staticChildren.push({
|
|
1372
|
+
element: child,
|
|
1373
|
+
segment: keyedRows.length,
|
|
1374
|
+
sibling: staticBefore
|
|
1375
|
+
});
|
|
1376
|
+
staticBefore += 1;
|
|
1377
|
+
} else {
|
|
1378
|
+
keyedContainer = false;
|
|
1379
|
+
break;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
if (keyedContainer && keyedRows.length > 0) {
|
|
1383
|
+
const id = allocateId();
|
|
1384
|
+
const keyedRanges = [];
|
|
1385
|
+
const staticBindings = [];
|
|
1386
|
+
const keyedDependencies = /* @__PURE__ */ new Set();
|
|
1387
|
+
for (const { before, range } of keyedRows) {
|
|
1388
|
+
if (range.events.length > 0) {
|
|
1389
|
+
return "recursive compiler-owned keyed rows cannot contain events";
|
|
1390
|
+
}
|
|
1391
|
+
const row = types.cloneNode(range.row, true);
|
|
1392
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1393
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1394
|
+
);
|
|
1395
|
+
const rowAnalysis = analyzeRecursiveHostTree(
|
|
1396
|
+
row,
|
|
1397
|
+
statesByValue,
|
|
1398
|
+
safeGlobals,
|
|
1399
|
+
listNames,
|
|
1400
|
+
id,
|
|
1401
|
+
allocateId
|
|
1402
|
+
);
|
|
1403
|
+
if (rowAnalysis.reason) return rowAnalysis.reason;
|
|
1404
|
+
plans.push(...rowAnalysis.plans);
|
|
1405
|
+
for (const [nestedElement, nestedPlan] of rowAnalysis.blocks) {
|
|
1406
|
+
blocks.set(nestedElement, nestedPlan);
|
|
1407
|
+
}
|
|
1408
|
+
keyedRanges.push({
|
|
1409
|
+
before,
|
|
1410
|
+
source: range.source,
|
|
1411
|
+
collection: range.collection,
|
|
1412
|
+
keyCallback: range.keyCallback,
|
|
1413
|
+
renderCallback: range.renderCallback,
|
|
1414
|
+
row,
|
|
1415
|
+
bindings: rowAnalysis.bindings,
|
|
1416
|
+
syntax: range.syntax
|
|
1417
|
+
});
|
|
1418
|
+
for (const dependency of range.dependencies) keyedDependencies.add(dependency);
|
|
1419
|
+
}
|
|
1420
|
+
for (const { element: child, segment, sibling } of staticChildren) {
|
|
1421
|
+
const nested = analyzeRecursiveHostTree(
|
|
1422
|
+
child,
|
|
1423
|
+
statesByValue,
|
|
1424
|
+
safeGlobals,
|
|
1425
|
+
listNames,
|
|
1426
|
+
owner,
|
|
1427
|
+
allocateId
|
|
1428
|
+
);
|
|
1429
|
+
if (nested.reason) return nested.reason;
|
|
1430
|
+
plans.push(...nested.plans);
|
|
1431
|
+
for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
|
|
1432
|
+
for (const binding of nested.bindings) {
|
|
1433
|
+
staticBindings.push({ ...binding, segment, sibling });
|
|
1434
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1435
|
+
keyedDependencies.add(dependency);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
const plan = {
|
|
1440
|
+
kind: "nested-host-keyed-ranges",
|
|
1441
|
+
id,
|
|
1442
|
+
parent: owner,
|
|
1443
|
+
dependencies: [...keyedDependencies].sort((left, right) => left - right),
|
|
1444
|
+
source: element,
|
|
1445
|
+
ranges: keyedRanges,
|
|
1446
|
+
trailing: staticBefore,
|
|
1447
|
+
staticBindings
|
|
1448
|
+
};
|
|
1449
|
+
plans.push(plan);
|
|
1450
|
+
blocks.set(element, plan);
|
|
1451
|
+
return void 0;
|
|
1452
|
+
}
|
|
1453
|
+
if (element.children.some((child) => types.isJSXFragment(child))) {
|
|
1454
|
+
return "recursive compiler-owned blocks do not support fragments yet";
|
|
1455
|
+
}
|
|
1456
|
+
const nestedElements = element.children.filter(
|
|
1457
|
+
(child) => types.isJSXElement(child)
|
|
1458
|
+
);
|
|
1459
|
+
const expressions = element.children.filter(
|
|
1460
|
+
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
1461
|
+
);
|
|
1462
|
+
for (const child of expressions) {
|
|
1463
|
+
const unsupported = validateDerivedExpression(child.expression, safeGlobals);
|
|
1464
|
+
if (unsupported) return `recursive compiler-owned text cannot use ${unsupported}`;
|
|
1465
|
+
}
|
|
1466
|
+
if (nestedElements.length > 0 && expressions.length > 0) {
|
|
1467
|
+
return "recursive compiler-owned blocks do not support dynamic text beside nested elements";
|
|
1468
|
+
}
|
|
1469
|
+
if (nestedElements.length === 0 && expressions.length > 0) {
|
|
1470
|
+
const parts = [];
|
|
1471
|
+
for (const child of element.children) {
|
|
1472
|
+
if (types.isJSXText(child)) {
|
|
1473
|
+
const text = cleanJsxText(child.value);
|
|
1474
|
+
if (text) parts.push(types.stringLiteral(text));
|
|
1475
|
+
} else if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1476
|
+
parts.push(cloneExpression(child.expression));
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
bindings.push({ kind: "text", path: [...path], value: types.arrayExpression(parts) });
|
|
1480
|
+
}
|
|
1481
|
+
let elementIndex = 0;
|
|
1482
|
+
for (const child of element.children) {
|
|
1483
|
+
if (!types.isJSXElement(child)) continue;
|
|
1484
|
+
const reason2 = visit(child, [...path, elementIndex], owner);
|
|
1485
|
+
if (reason2) return reason2;
|
|
1486
|
+
elementIndex += 1;
|
|
1487
|
+
}
|
|
1488
|
+
return void 0;
|
|
1489
|
+
};
|
|
1490
|
+
const reason = visit(branch, [], parent);
|
|
1491
|
+
return { bindings, plans, blocks, reason };
|
|
1492
|
+
}
|
|
1493
|
+
function analyzeCompilerOwnedKeyedRowHostBlocks(shape, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1494
|
+
if (shape.events.length > 0) return void 0;
|
|
1495
|
+
const row = types.cloneNode(shape.row, true);
|
|
1496
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1497
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1498
|
+
);
|
|
1499
|
+
const analysis = analyzeRecursiveHostTree(
|
|
1500
|
+
row,
|
|
1501
|
+
statesByValue,
|
|
1502
|
+
safeGlobals,
|
|
1503
|
+
listNames,
|
|
1504
|
+
parent,
|
|
1505
|
+
allocateId
|
|
1506
|
+
);
|
|
1507
|
+
if (analysis.reason || analysis.plans.length === 0) {
|
|
1508
|
+
return void 0;
|
|
1509
|
+
}
|
|
1510
|
+
return {
|
|
1511
|
+
row,
|
|
1512
|
+
bindings: analysis.bindings,
|
|
1513
|
+
descriptorBlocks: analysis.blocks,
|
|
1514
|
+
nestedPlans: analysis.plans
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
function analyzeHostConditionalContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1011
1518
|
const containerName = container.openingElement.name;
|
|
1012
1519
|
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg") {
|
|
1013
1520
|
return void 0;
|
|
@@ -1029,8 +1536,22 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
|
|
|
1029
1536
|
}
|
|
1030
1537
|
const shape = conditionalBlockShape(children[0].expression);
|
|
1031
1538
|
if (!shape || validateDerivedExpression(shape.test, safeGlobals)) return void 0;
|
|
1032
|
-
const truthyAnalysis = shape.truthy ?
|
|
1033
|
-
|
|
1539
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1540
|
+
shape.truthy,
|
|
1541
|
+
statesByValue,
|
|
1542
|
+
safeGlobals,
|
|
1543
|
+
listNames,
|
|
1544
|
+
parent,
|
|
1545
|
+
allocateId
|
|
1546
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1547
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1548
|
+
shape.falsy,
|
|
1549
|
+
statesByValue,
|
|
1550
|
+
safeGlobals,
|
|
1551
|
+
listNames,
|
|
1552
|
+
parent,
|
|
1553
|
+
allocateId
|
|
1554
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1034
1555
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1035
1556
|
const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1036
1557
|
for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
|
|
@@ -1045,10 +1566,12 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
|
|
|
1045
1566
|
truthy: shape.truthy,
|
|
1046
1567
|
falsy: shape.falsy,
|
|
1047
1568
|
truthyBindings: truthyAnalysis.bindings || [],
|
|
1048
|
-
falsyBindings: falsyAnalysis.bindings || []
|
|
1569
|
+
falsyBindings: falsyAnalysis.bindings || [],
|
|
1570
|
+
descriptorBlocks: new Map([...truthyAnalysis.blocks, ...falsyAnalysis.blocks]),
|
|
1571
|
+
nestedPlans: [...truthyAnalysis.plans, ...falsyAnalysis.plans]
|
|
1049
1572
|
};
|
|
1050
1573
|
}
|
|
1051
|
-
function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange
|
|
1574
|
+
function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange, listNames, parent, allocateId) {
|
|
1052
1575
|
const containerName = container.openingElement.name;
|
|
1053
1576
|
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
|
|
1054
1577
|
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
@@ -1059,14 +1582,34 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1059
1582
|
if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
|
|
1060
1583
|
const ranges = [];
|
|
1061
1584
|
const dependencies = /* @__PURE__ */ new Set();
|
|
1585
|
+
const descriptorBlocks = /* @__PURE__ */ new Map();
|
|
1586
|
+
const nestedPlans = [];
|
|
1587
|
+
const staticBindings = [];
|
|
1062
1588
|
let staticBefore = 0;
|
|
1063
1589
|
for (const child of children) {
|
|
1064
1590
|
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1065
1591
|
const shape = conditionalBlockShape(child.expression);
|
|
1066
1592
|
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1067
|
-
const truthyAnalysis = shape.truthy ?
|
|
1068
|
-
|
|
1593
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1594
|
+
shape.truthy,
|
|
1595
|
+
statesByValue,
|
|
1596
|
+
safeGlobals,
|
|
1597
|
+
listNames,
|
|
1598
|
+
parent,
|
|
1599
|
+
allocateId
|
|
1600
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1601
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1602
|
+
shape.falsy,
|
|
1603
|
+
statesByValue,
|
|
1604
|
+
safeGlobals,
|
|
1605
|
+
listNames,
|
|
1606
|
+
parent,
|
|
1607
|
+
allocateId
|
|
1608
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1069
1609
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1610
|
+
nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
|
|
1611
|
+
for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
1612
|
+
for (const [element, plan] of falsyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
1070
1613
|
const rangeDependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1071
1614
|
for (const binding of [
|
|
1072
1615
|
...truthyAnalysis.bindings || [],
|
|
@@ -1092,14 +1635,158 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1092
1635
|
}
|
|
1093
1636
|
}
|
|
1094
1637
|
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
1095
|
-
|
|
1638
|
+
const staticAnalysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
|
|
1639
|
+
if (staticAnalysis.reason) return void 0;
|
|
1640
|
+
for (const binding of staticAnalysis.bindings || []) {
|
|
1641
|
+
staticBindings.push({
|
|
1642
|
+
...binding,
|
|
1643
|
+
segment: ranges.length,
|
|
1644
|
+
sibling: staticBefore
|
|
1645
|
+
});
|
|
1646
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1647
|
+
dependencies.add(dependency);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1096
1650
|
staticBefore += 1;
|
|
1097
1651
|
}
|
|
1098
1652
|
if (ranges.length === 0) return void 0;
|
|
1099
1653
|
return {
|
|
1100
1654
|
ranges,
|
|
1101
1655
|
trailing: staticBefore,
|
|
1102
|
-
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
1656
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1657
|
+
staticBindings,
|
|
1658
|
+
descriptorBlocks,
|
|
1659
|
+
nestedPlans
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1663
|
+
const containerName = container.openingElement.name;
|
|
1664
|
+
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
|
|
1665
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
1666
|
+
)) {
|
|
1667
|
+
return void 0;
|
|
1668
|
+
}
|
|
1669
|
+
const children = meaningfulJsxChildren(container);
|
|
1670
|
+
if (children.length < 2) return void 0;
|
|
1671
|
+
const ranges = [];
|
|
1672
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1673
|
+
const descriptorBlocks = /* @__PURE__ */ new Map();
|
|
1674
|
+
const nestedPlans = [];
|
|
1675
|
+
const staticBindings = [];
|
|
1676
|
+
let conditionalCount = 0;
|
|
1677
|
+
let keyedCount = 0;
|
|
1678
|
+
let staticBefore = 0;
|
|
1679
|
+
const mergeAnalysis = (analysis) => {
|
|
1680
|
+
if (analysis.reason) return false;
|
|
1681
|
+
nestedPlans.push(...analysis.plans);
|
|
1682
|
+
for (const [element, plan] of analysis.blocks) descriptorBlocks.set(element, plan);
|
|
1683
|
+
for (const binding of analysis.bindings) {
|
|
1684
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1685
|
+
dependencies.add(dependency);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
return true;
|
|
1689
|
+
};
|
|
1690
|
+
for (const child of children) {
|
|
1691
|
+
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1692
|
+
const shape = conditionalBlockShape(child.expression);
|
|
1693
|
+
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1694
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1695
|
+
shape.truthy,
|
|
1696
|
+
statesByValue,
|
|
1697
|
+
safeGlobals,
|
|
1698
|
+
listNames,
|
|
1699
|
+
parent,
|
|
1700
|
+
allocateId
|
|
1701
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1702
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1703
|
+
shape.falsy,
|
|
1704
|
+
statesByValue,
|
|
1705
|
+
safeGlobals,
|
|
1706
|
+
listNames,
|
|
1707
|
+
parent,
|
|
1708
|
+
allocateId
|
|
1709
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1710
|
+
if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
|
|
1711
|
+
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1712
|
+
dependencies.add(dependency);
|
|
1713
|
+
}
|
|
1714
|
+
ranges.push({
|
|
1715
|
+
rangeKind: "conditional",
|
|
1716
|
+
before: staticBefore,
|
|
1717
|
+
source: child.expression,
|
|
1718
|
+
test: cloneExpression(shape.test),
|
|
1719
|
+
logical: shape.logical,
|
|
1720
|
+
truthy: shape.truthy,
|
|
1721
|
+
falsy: shape.falsy,
|
|
1722
|
+
truthyBindings: truthyAnalysis.bindings,
|
|
1723
|
+
falsyBindings: falsyAnalysis.bindings
|
|
1724
|
+
});
|
|
1725
|
+
conditionalCount += 1;
|
|
1726
|
+
staticBefore = 0;
|
|
1727
|
+
continue;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
const keyed = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
|
|
1731
|
+
if (keyed) {
|
|
1732
|
+
if (keyed.events.length > 0) return void 0;
|
|
1733
|
+
const row = types.cloneNode(keyed.row, true);
|
|
1734
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1735
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1736
|
+
);
|
|
1737
|
+
const rowAnalysis = analyzeRecursiveHostTree(
|
|
1738
|
+
row,
|
|
1739
|
+
statesByValue,
|
|
1740
|
+
safeGlobals,
|
|
1741
|
+
listNames,
|
|
1742
|
+
parent,
|
|
1743
|
+
allocateId
|
|
1744
|
+
);
|
|
1745
|
+
if (!mergeAnalysis(rowAnalysis)) return void 0;
|
|
1746
|
+
for (const dependency of keyed.dependencies) dependencies.add(dependency);
|
|
1747
|
+
ranges.push({
|
|
1748
|
+
rangeKind: "keyed",
|
|
1749
|
+
before: staticBefore,
|
|
1750
|
+
source: keyed.source,
|
|
1751
|
+
collection: keyed.collection,
|
|
1752
|
+
keyCallback: keyed.keyCallback,
|
|
1753
|
+
renderCallback: keyed.renderCallback,
|
|
1754
|
+
row,
|
|
1755
|
+
bindings: rowAnalysis.bindings,
|
|
1756
|
+
syntax: keyed.syntax
|
|
1757
|
+
});
|
|
1758
|
+
keyedCount += 1;
|
|
1759
|
+
staticBefore = 0;
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
1763
|
+
const staticAnalysis = analyzeRecursiveHostTree(
|
|
1764
|
+
child,
|
|
1765
|
+
statesByValue,
|
|
1766
|
+
safeGlobals,
|
|
1767
|
+
listNames,
|
|
1768
|
+
parent,
|
|
1769
|
+
allocateId
|
|
1770
|
+
);
|
|
1771
|
+
if (staticAnalysis.reason) return void 0;
|
|
1772
|
+
for (const binding of staticAnalysis.bindings) {
|
|
1773
|
+
staticBindings.push({
|
|
1774
|
+
...binding,
|
|
1775
|
+
segment: ranges.length,
|
|
1776
|
+
sibling: staticBefore
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
if (!mergeAnalysis(staticAnalysis)) return void 0;
|
|
1780
|
+
staticBefore += 1;
|
|
1781
|
+
}
|
|
1782
|
+
if (conditionalCount === 0 || keyedCount === 0) return void 0;
|
|
1783
|
+
return {
|
|
1784
|
+
ranges,
|
|
1785
|
+
trailing: staticBefore,
|
|
1786
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1787
|
+
staticBindings,
|
|
1788
|
+
descriptorBlocks,
|
|
1789
|
+
nestedPlans
|
|
1103
1790
|
};
|
|
1104
1791
|
}
|
|
1105
1792
|
function keyedListBoundary(blockRuntime, plan, source) {
|
|
@@ -1124,14 +1811,14 @@ function keyedListBoundary(blockRuntime, plan, source) {
|
|
|
1124
1811
|
true
|
|
1125
1812
|
);
|
|
1126
1813
|
}
|
|
1127
|
-
function hostElementDescriptor(element) {
|
|
1814
|
+
function hostElementDescriptor(element, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1128
1815
|
const tag = element.openingElement.name;
|
|
1129
1816
|
const attributes = [];
|
|
1130
1817
|
const styles = [];
|
|
1131
1818
|
for (const attribute of element.openingElement.attributes) {
|
|
1132
1819
|
if (!types.isJSXAttribute(attribute)) continue;
|
|
1133
1820
|
const name = jsxAttributeName(attribute);
|
|
1134
|
-
if (!name || name === "key" || /^on[A-Z]/.test(name)) continue;
|
|
1821
|
+
if (!name || name === "key" || name === "ref" || /^on[A-Z]/.test(name)) continue;
|
|
1135
1822
|
if (name === "style") {
|
|
1136
1823
|
if (types.isJSXExpressionContainer(attribute.value) && types.isObjectExpression(attribute.value.expression)) {
|
|
1137
1824
|
for (const property of attribute.value.expression.properties) {
|
|
@@ -1155,24 +1842,93 @@ function hostElementDescriptor(element) {
|
|
|
1155
1842
|
])
|
|
1156
1843
|
);
|
|
1157
1844
|
}
|
|
1845
|
+
const block = descriptorBlocks.get(element);
|
|
1846
|
+
const conditionalBySource = /* @__PURE__ */ new Map();
|
|
1847
|
+
const keyedBySource = /* @__PURE__ */ new Map();
|
|
1848
|
+
if (block?.kind === "nested-host-conditional-ranges") {
|
|
1849
|
+
for (const range of block.ranges) conditionalBySource.set(range.source, range);
|
|
1850
|
+
} else if (block?.kind === "nested-host-keyed-ranges") {
|
|
1851
|
+
for (const range of block.ranges) keyedBySource.set(range.source, range);
|
|
1852
|
+
} else if (block?.kind === "nested-host-mixed-ranges") {
|
|
1853
|
+
for (const range of block.ranges) {
|
|
1854
|
+
if (range.rangeKind === "conditional") conditionalBySource.set(range.source, range);
|
|
1855
|
+
else keyedBySource.set(range.source, range);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1158
1858
|
const children = [];
|
|
1159
1859
|
for (const child of element.children) {
|
|
1160
1860
|
if (types.isJSXText(child)) {
|
|
1161
1861
|
const text = cleanJsxText(child.value);
|
|
1162
1862
|
if (text) children.push(types.stringLiteral(text));
|
|
1163
1863
|
} else if (types.isJSXElement(child)) {
|
|
1164
|
-
|
|
1864
|
+
const keyedRange = keyedBySource.get(child);
|
|
1865
|
+
if (keyedRange) {
|
|
1866
|
+
if (block?.kind !== "nested-host-keyed-ranges") {
|
|
1867
|
+
children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
|
|
1868
|
+
}
|
|
1869
|
+
} else {
|
|
1870
|
+
children.push(hostElementDescriptor(child, descriptorBlocks));
|
|
1871
|
+
}
|
|
1165
1872
|
} else if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1166
|
-
|
|
1873
|
+
const conditionalRange = conditionalBySource.get(child.expression);
|
|
1874
|
+
const keyedRange = keyedBySource.get(child.expression);
|
|
1875
|
+
if (conditionalRange) {
|
|
1876
|
+
children.push(conditionalRangeDescriptorChild(conditionalRange, descriptorBlocks));
|
|
1877
|
+
} else if (keyedRange) {
|
|
1878
|
+
if (block?.kind !== "nested-host-keyed-ranges") {
|
|
1879
|
+
children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
|
|
1880
|
+
}
|
|
1881
|
+
} else {
|
|
1882
|
+
children.push(cloneExpression(child.expression));
|
|
1883
|
+
}
|
|
1167
1884
|
}
|
|
1168
1885
|
}
|
|
1169
|
-
|
|
1886
|
+
const properties = [
|
|
1170
1887
|
types.objectProperty(types.identifier("kind"), types.stringLiteral("element")),
|
|
1171
1888
|
types.objectProperty(types.identifier("tag"), types.stringLiteral(tag.name)),
|
|
1172
1889
|
types.objectProperty(types.identifier("attributes"), types.arrayExpression(attributes)),
|
|
1173
1890
|
types.objectProperty(types.identifier("styles"), types.arrayExpression(styles)),
|
|
1174
1891
|
types.objectProperty(types.identifier("children"), types.arrayExpression(children))
|
|
1175
|
-
]
|
|
1892
|
+
];
|
|
1893
|
+
if (block) {
|
|
1894
|
+
properties.push(
|
|
1895
|
+
types.objectProperty(types.identifier("block"), nestedHostBlockObject(block, descriptorBlocks))
|
|
1896
|
+
);
|
|
1897
|
+
}
|
|
1898
|
+
return types.objectExpression(properties);
|
|
1899
|
+
}
|
|
1900
|
+
function conditionalRangeDescriptorChild(range, descriptorBlocks) {
|
|
1901
|
+
const truthy = range.truthy ? hostElementDescriptor(range.truthy, descriptorBlocks) : types.nullLiteral();
|
|
1902
|
+
if (range.logical) {
|
|
1903
|
+
return types.logicalExpression("&&", cloneExpression(range.test), truthy);
|
|
1904
|
+
}
|
|
1905
|
+
return types.conditionalExpression(
|
|
1906
|
+
cloneExpression(range.test),
|
|
1907
|
+
truthy,
|
|
1908
|
+
range.falsy ? hostElementDescriptor(range.falsy, descriptorBlocks) : types.nullLiteral()
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
function keyedRangeDescriptorChildren(range, descriptorBlocks) {
|
|
1912
|
+
const parameters = range.renderCallback.params.map(
|
|
1913
|
+
(parameter) => types.cloneNode(parameter, true)
|
|
1914
|
+
);
|
|
1915
|
+
const callback = types.arrowFunctionExpression(
|
|
1916
|
+
parameters,
|
|
1917
|
+
hostElementDescriptor(range.row, descriptorBlocks)
|
|
1918
|
+
);
|
|
1919
|
+
const collection = cloneExpression(range.collection);
|
|
1920
|
+
if (range.syntax === "map") {
|
|
1921
|
+
return types.callExpression(types.memberExpression(collection, types.identifier("map")), [callback]);
|
|
1922
|
+
}
|
|
1923
|
+
return types.callExpression(
|
|
1924
|
+
types.memberExpression(
|
|
1925
|
+
types.callExpression(types.memberExpression(types.identifier("Array"), types.identifier("from")), [
|
|
1926
|
+
types.logicalExpression("||", collection, types.arrayExpression([]))
|
|
1927
|
+
]),
|
|
1928
|
+
types.identifier("map")
|
|
1929
|
+
),
|
|
1930
|
+
[callback]
|
|
1931
|
+
);
|
|
1176
1932
|
}
|
|
1177
1933
|
function keyedRowBindingObject(binding, parameters) {
|
|
1178
1934
|
const properties = [
|
|
@@ -1180,6 +1936,12 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1180
1936
|
types.objectProperty(
|
|
1181
1937
|
types.identifier("path"),
|
|
1182
1938
|
types.arrayExpression(binding.path.map((part) => types.numericLiteral(part)))
|
|
1939
|
+
),
|
|
1940
|
+
types.objectProperty(
|
|
1941
|
+
types.identifier("dependencies"),
|
|
1942
|
+
types.arrayExpression(
|
|
1943
|
+
(binding.dependencies || []).map((dependency) => types.numericLiteral(dependency))
|
|
1944
|
+
)
|
|
1183
1945
|
)
|
|
1184
1946
|
];
|
|
1185
1947
|
if (binding.name) {
|
|
@@ -1196,6 +1958,16 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1196
1958
|
);
|
|
1197
1959
|
return types.objectExpression(properties);
|
|
1198
1960
|
}
|
|
1961
|
+
function staticRangeBindingObject(binding) {
|
|
1962
|
+
const value = keyedRowBindingObject(binding, []);
|
|
1963
|
+
value.properties.splice(
|
|
1964
|
+
1,
|
|
1965
|
+
0,
|
|
1966
|
+
types.objectProperty(types.identifier("segment"), types.numericLiteral(binding.segment)),
|
|
1967
|
+
types.objectProperty(types.identifier("sibling"), types.numericLiteral(binding.sibling))
|
|
1968
|
+
);
|
|
1969
|
+
return value;
|
|
1970
|
+
}
|
|
1199
1971
|
function uniqueLocalIdentifier(base, nodes) {
|
|
1200
1972
|
const names = /* @__PURE__ */ new Set();
|
|
1201
1973
|
for (const node of nodes) {
|
|
@@ -1312,6 +2084,10 @@ function keyedRowEventObject(event, renderParameters) {
|
|
|
1312
2084
|
const parameters = [types.cloneNode(renderParameters[0], true), index, syntheticEvent];
|
|
1313
2085
|
return types.objectExpression([
|
|
1314
2086
|
types.objectProperty(types.identifier("name"), types.stringLiteral(event.name)),
|
|
2087
|
+
types.objectProperty(
|
|
2088
|
+
types.identifier("path"),
|
|
2089
|
+
types.arrayExpression(event.path.map((part) => types.numericLiteral(part)))
|
|
2090
|
+
),
|
|
1315
2091
|
types.objectProperty(
|
|
1316
2092
|
types.identifier("invoke"),
|
|
1317
2093
|
types.arrowFunctionExpression(
|
|
@@ -1381,6 +2157,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1381
2157
|
plan.source,
|
|
1382
2158
|
...plan.conditionals.map((conditional) => conditional.test)
|
|
1383
2159
|
]);
|
|
2160
|
+
const delegatedEvents = canDelegateKeyedRowEvents(plan);
|
|
1384
2161
|
const renderSource = keyedRowsRenderSource(plan, eventFactory, conditionalFactory);
|
|
1385
2162
|
const renderFactoryParameters = plan.conditionals.length > 0 ? [types.cloneNode(eventFactory), types.cloneNode(conditionalFactory)] : plan.events.length > 0 ? [types.cloneNode(eventFactory)] : [];
|
|
1386
2163
|
return types.jsxElement(
|
|
@@ -1398,6 +2175,14 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1398
2175
|
types.jsxIdentifier("items"),
|
|
1399
2176
|
types.jsxExpressionContainer(types.arrowFunctionExpression([], cloneExpression(plan.collection)))
|
|
1400
2177
|
),
|
|
2178
|
+
types.jsxAttribute(
|
|
2179
|
+
types.jsxIdentifier("structureDependencies"),
|
|
2180
|
+
types.jsxExpressionContainer(
|
|
2181
|
+
types.arrayExpression(
|
|
2182
|
+
plan.structureDependencies.map((dependency) => types.numericLiteral(dependency))
|
|
2183
|
+
)
|
|
2184
|
+
)
|
|
2185
|
+
),
|
|
1401
2186
|
types.jsxAttribute(
|
|
1402
2187
|
types.jsxIdentifier("rowKey"),
|
|
1403
2188
|
types.jsxExpressionContainer(types.cloneNode(plan.keyCallback, true))
|
|
@@ -1407,7 +2192,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1407
2192
|
types.jsxExpressionContainer(
|
|
1408
2193
|
types.arrowFunctionExpression(
|
|
1409
2194
|
parameters.map((parameter) => types.cloneNode(parameter, true)),
|
|
1410
|
-
hostElementDescriptor(plan.row)
|
|
2195
|
+
hostElementDescriptor(plan.row, plan.descriptorBlocks)
|
|
1411
2196
|
)
|
|
1412
2197
|
)
|
|
1413
2198
|
),
|
|
@@ -1427,7 +2212,13 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1427
2212
|
plan.events.map((event) => keyedRowEventObject(event, parameters))
|
|
1428
2213
|
)
|
|
1429
2214
|
)
|
|
1430
|
-
)
|
|
2215
|
+
),
|
|
2216
|
+
...delegatedEvents ? [
|
|
2217
|
+
types.jsxAttribute(
|
|
2218
|
+
types.jsxIdentifier("delegateEvents"),
|
|
2219
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
2220
|
+
)
|
|
2221
|
+
] : []
|
|
1431
2222
|
] : [],
|
|
1432
2223
|
...plan.conditionals.length > 0 ? [
|
|
1433
2224
|
types.jsxAttribute(
|
|
@@ -1440,6 +2231,12 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1440
2231
|
)
|
|
1441
2232
|
)
|
|
1442
2233
|
)
|
|
2234
|
+
] : [],
|
|
2235
|
+
...plan.descriptorBlocks?.size ? [
|
|
2236
|
+
types.jsxAttribute(
|
|
2237
|
+
types.jsxIdentifier("hostBlocks"),
|
|
2238
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
2239
|
+
)
|
|
1443
2240
|
] : []
|
|
1444
2241
|
],
|
|
1445
2242
|
true
|
|
@@ -1449,7 +2246,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1449
2246
|
true
|
|
1450
2247
|
);
|
|
1451
2248
|
}
|
|
1452
|
-
function keyedRangeObject(range) {
|
|
2249
|
+
function keyedRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1453
2250
|
const parameters = range.renderCallback.params.map(
|
|
1454
2251
|
(parameter) => types.cloneNode(parameter, true)
|
|
1455
2252
|
);
|
|
@@ -1464,7 +2261,7 @@ function keyedRangeObject(range) {
|
|
|
1464
2261
|
types.identifier("create"),
|
|
1465
2262
|
types.arrowFunctionExpression(
|
|
1466
2263
|
parameters.map((parameter) => types.cloneNode(parameter, true)),
|
|
1467
|
-
hostElementDescriptor(range.row)
|
|
2264
|
+
hostElementDescriptor(range.row, descriptorBlocks)
|
|
1468
2265
|
)
|
|
1469
2266
|
),
|
|
1470
2267
|
types.objectProperty(
|
|
@@ -1508,6 +2305,12 @@ function keyedRangesBoundary(blockRuntime, plan) {
|
|
|
1508
2305
|
types.jsxAttribute(
|
|
1509
2306
|
types.jsxIdentifier("trailing"),
|
|
1510
2307
|
types.jsxExpressionContainer(types.numericLiteral(plan.trailing))
|
|
2308
|
+
),
|
|
2309
|
+
types.jsxAttribute(
|
|
2310
|
+
types.jsxIdentifier("bindings"),
|
|
2311
|
+
types.jsxExpressionContainer(
|
|
2312
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2313
|
+
)
|
|
1511
2314
|
)
|
|
1512
2315
|
],
|
|
1513
2316
|
true
|
|
@@ -1517,11 +2320,11 @@ function keyedRangesBoundary(blockRuntime, plan) {
|
|
|
1517
2320
|
true
|
|
1518
2321
|
);
|
|
1519
2322
|
}
|
|
1520
|
-
function hostConditionalBranchObject(branch, bindings) {
|
|
2323
|
+
function hostConditionalBranchObject(branch, bindings, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1521
2324
|
return types.objectExpression([
|
|
1522
2325
|
types.objectProperty(
|
|
1523
2326
|
types.identifier("create"),
|
|
1524
|
-
types.arrowFunctionExpression([], hostElementDescriptor(branch))
|
|
2327
|
+
types.arrowFunctionExpression([], hostElementDescriptor(branch, descriptorBlocks))
|
|
1525
2328
|
),
|
|
1526
2329
|
types.objectProperty(
|
|
1527
2330
|
types.identifier("bindings"),
|
|
@@ -1550,7 +2353,9 @@ function hostConditionalBoundary(blockRuntime, plan) {
|
|
|
1550
2353
|
attributes.push(
|
|
1551
2354
|
types.jsxAttribute(
|
|
1552
2355
|
types.jsxIdentifier("truthy"),
|
|
1553
|
-
types.jsxExpressionContainer(
|
|
2356
|
+
types.jsxExpressionContainer(
|
|
2357
|
+
hostConditionalBranchObject(plan.truthy, plan.truthyBindings, plan.descriptorBlocks)
|
|
2358
|
+
)
|
|
1554
2359
|
)
|
|
1555
2360
|
);
|
|
1556
2361
|
}
|
|
@@ -1558,13 +2363,15 @@ function hostConditionalBoundary(blockRuntime, plan) {
|
|
|
1558
2363
|
attributes.push(
|
|
1559
2364
|
types.jsxAttribute(
|
|
1560
2365
|
types.jsxIdentifier("falsy"),
|
|
1561
|
-
types.jsxExpressionContainer(
|
|
2366
|
+
types.jsxExpressionContainer(
|
|
2367
|
+
hostConditionalBranchObject(plan.falsy, plan.falsyBindings, plan.descriptorBlocks)
|
|
2368
|
+
)
|
|
1562
2369
|
)
|
|
1563
2370
|
);
|
|
1564
2371
|
}
|
|
1565
2372
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
1566
2373
|
}
|
|
1567
|
-
function conditionalRangeObject(range) {
|
|
2374
|
+
function conditionalRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1568
2375
|
const properties = [
|
|
1569
2376
|
types.objectProperty(types.identifier("before"), types.numericLiteral(range.before)),
|
|
1570
2377
|
types.objectProperty(
|
|
@@ -1579,7 +2386,7 @@ function conditionalRangeObject(range) {
|
|
|
1579
2386
|
properties.push(
|
|
1580
2387
|
types.objectProperty(
|
|
1581
2388
|
types.identifier("truthy"),
|
|
1582
|
-
hostConditionalBranchObject(range.truthy, range.truthyBindings)
|
|
2389
|
+
hostConditionalBranchObject(range.truthy, range.truthyBindings, descriptorBlocks)
|
|
1583
2390
|
)
|
|
1584
2391
|
);
|
|
1585
2392
|
}
|
|
@@ -1587,12 +2394,78 @@ function conditionalRangeObject(range) {
|
|
|
1587
2394
|
properties.push(
|
|
1588
2395
|
types.objectProperty(
|
|
1589
2396
|
types.identifier("falsy"),
|
|
1590
|
-
hostConditionalBranchObject(range.falsy, range.falsyBindings)
|
|
2397
|
+
hostConditionalBranchObject(range.falsy, range.falsyBindings, descriptorBlocks)
|
|
1591
2398
|
)
|
|
1592
2399
|
);
|
|
1593
2400
|
}
|
|
1594
2401
|
return types.objectExpression(properties);
|
|
1595
2402
|
}
|
|
2403
|
+
function nestedHostBlockObject(plan, descriptorBlocks) {
|
|
2404
|
+
const kind = plan.kind === "nested-host-conditional-ranges" ? "conditional-ranges" : plan.kind === "nested-host-keyed-ranges" ? "keyed-ranges" : "mixed-ranges";
|
|
2405
|
+
return types.objectExpression([
|
|
2406
|
+
types.objectProperty(types.identifier("kind"), types.stringLiteral(kind)),
|
|
2407
|
+
types.objectProperty(types.identifier("id"), types.numericLiteral(plan.id)),
|
|
2408
|
+
types.objectProperty(
|
|
2409
|
+
types.identifier("ranges"),
|
|
2410
|
+
types.arrayExpression(
|
|
2411
|
+
plan.kind === "nested-host-conditional-ranges" ? plan.ranges.map((range) => conditionalRangeObject(range, descriptorBlocks)) : plan.kind === "nested-host-keyed-ranges" ? plan.ranges.map((range) => keyedRangeObject(range, descriptorBlocks)) : plan.ranges.map((range) => mixedRangeObject(range, descriptorBlocks))
|
|
2412
|
+
)
|
|
2413
|
+
),
|
|
2414
|
+
types.objectProperty(types.identifier("trailing"), types.numericLiteral(plan.trailing)),
|
|
2415
|
+
types.objectProperty(
|
|
2416
|
+
types.identifier("bindings"),
|
|
2417
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2418
|
+
),
|
|
2419
|
+
...plan.kind === "nested-host-keyed-ranges" ? [types.objectProperty(types.identifier("staticChildrenOnly"), types.booleanLiteral(true))] : []
|
|
2420
|
+
]);
|
|
2421
|
+
}
|
|
2422
|
+
function mixedRangeObject(range, descriptorBlocks) {
|
|
2423
|
+
const value = range.rangeKind === "conditional" ? conditionalRangeObject(range, descriptorBlocks) : keyedRangeObject(range, descriptorBlocks);
|
|
2424
|
+
value.properties.unshift(
|
|
2425
|
+
types.objectProperty(types.identifier("kind"), types.stringLiteral(range.rangeKind))
|
|
2426
|
+
);
|
|
2427
|
+
return value;
|
|
2428
|
+
}
|
|
2429
|
+
function mixedRangesBoundary(blockRuntime, plan) {
|
|
2430
|
+
const name = types.jsxMemberExpression(
|
|
2431
|
+
types.jsxIdentifier(blockRuntime.name),
|
|
2432
|
+
types.jsxIdentifier("MixedRanges")
|
|
2433
|
+
);
|
|
2434
|
+
const source = types.cloneNode(plan.source, true);
|
|
2435
|
+
const rootRefIndex = source.openingElement.attributes.findIndex(
|
|
2436
|
+
(attribute) => types.isJSXAttribute(attribute) && jsxAttributeName(attribute) === "ref"
|
|
2437
|
+
);
|
|
2438
|
+
const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
|
|
2439
|
+
const nestedPlan = {
|
|
2440
|
+
kind: "nested-host-mixed-ranges",
|
|
2441
|
+
id: plan.id,
|
|
2442
|
+
parent: plan.parent,
|
|
2443
|
+
dependencies: plan.dependencies,
|
|
2444
|
+
source: plan.source,
|
|
2445
|
+
ranges: plan.ranges,
|
|
2446
|
+
trailing: plan.trailing,
|
|
2447
|
+
staticBindings: plan.staticBindings
|
|
2448
|
+
};
|
|
2449
|
+
const descriptorBlocks = new Map(plan.descriptorBlocks);
|
|
2450
|
+
descriptorBlocks.set(plan.source, nestedPlan);
|
|
2451
|
+
const attributes = [
|
|
2452
|
+
types.jsxAttribute(types.jsxIdentifier("id"), types.jsxExpressionContainer(types.numericLiteral(plan.id))),
|
|
2453
|
+
types.jsxAttribute(
|
|
2454
|
+
types.jsxIdentifier("render"),
|
|
2455
|
+
types.jsxExpressionContainer(types.arrowFunctionExpression([], source))
|
|
2456
|
+
),
|
|
2457
|
+
types.jsxAttribute(
|
|
2458
|
+
types.jsxIdentifier("create"),
|
|
2459
|
+
types.jsxExpressionContainer(
|
|
2460
|
+
types.arrowFunctionExpression([], hostElementDescriptor(plan.source, descriptorBlocks))
|
|
2461
|
+
)
|
|
2462
|
+
)
|
|
2463
|
+
];
|
|
2464
|
+
if (rootRef?.value) {
|
|
2465
|
+
attributes.push(types.jsxAttribute(types.jsxIdentifier("rootRef"), types.cloneNode(rootRef.value, true)));
|
|
2466
|
+
}
|
|
2467
|
+
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
2468
|
+
}
|
|
1596
2469
|
function conditionalRangesBoundary(blockRuntime, plan) {
|
|
1597
2470
|
const name = types.jsxMemberExpression(
|
|
1598
2471
|
types.jsxIdentifier(blockRuntime.name),
|
|
@@ -1612,12 +2485,20 @@ function conditionalRangesBoundary(blockRuntime, plan) {
|
|
|
1612
2485
|
types.jsxAttribute(
|
|
1613
2486
|
types.jsxIdentifier("ranges"),
|
|
1614
2487
|
types.jsxExpressionContainer(
|
|
1615
|
-
types.arrayExpression(
|
|
2488
|
+
types.arrayExpression(
|
|
2489
|
+
plan.ranges.map((range) => conditionalRangeObject(range, plan.descriptorBlocks))
|
|
2490
|
+
)
|
|
1616
2491
|
)
|
|
1617
2492
|
),
|
|
1618
2493
|
types.jsxAttribute(
|
|
1619
2494
|
types.jsxIdentifier("trailing"),
|
|
1620
2495
|
types.jsxExpressionContainer(types.numericLiteral(plan.trailing))
|
|
2496
|
+
),
|
|
2497
|
+
types.jsxAttribute(
|
|
2498
|
+
types.jsxIdentifier("bindings"),
|
|
2499
|
+
types.jsxExpressionContainer(
|
|
2500
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2501
|
+
)
|
|
1621
2502
|
)
|
|
1622
2503
|
];
|
|
1623
2504
|
if (rootRef?.value) {
|
|
@@ -1790,6 +2671,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1790
2671
|
}
|
|
1791
2672
|
if (types.isJSXElement(child)) {
|
|
1792
2673
|
if (isHostElement(child)) {
|
|
2674
|
+
const mixedRangeStart = nextId;
|
|
2675
|
+
const mixedRangeId = nextId++;
|
|
2676
|
+
const mixedRanges = insideConditional ? void 0 : analyzeMixedRangesContainer(
|
|
2677
|
+
child,
|
|
2678
|
+
statesByValue,
|
|
2679
|
+
safeGlobals,
|
|
2680
|
+
listNames,
|
|
2681
|
+
mixedRangeId,
|
|
2682
|
+
() => nextId++
|
|
2683
|
+
);
|
|
2684
|
+
if (mixedRanges) {
|
|
2685
|
+
plans.push({
|
|
2686
|
+
kind: "mixed-ranges",
|
|
2687
|
+
id: mixedRangeId,
|
|
2688
|
+
parent,
|
|
2689
|
+
dependencies: mixedRanges.dependencies,
|
|
2690
|
+
source: child,
|
|
2691
|
+
ranges: mixedRanges.ranges,
|
|
2692
|
+
trailing: mixedRanges.trailing,
|
|
2693
|
+
staticBindings: mixedRanges.staticBindings,
|
|
2694
|
+
descriptorBlocks: mixedRanges.descriptorBlocks
|
|
2695
|
+
});
|
|
2696
|
+
plans.push(...mixedRanges.nestedPlans);
|
|
2697
|
+
for (const range of mixedRanges.ranges) {
|
|
2698
|
+
if (range.rangeKind === "conditional") {
|
|
2699
|
+
conditionalExpressions.add(range.source);
|
|
2700
|
+
} else if (types.isJSXElement(range.source)) {
|
|
2701
|
+
ownedElements.add(range.source);
|
|
2702
|
+
} else {
|
|
2703
|
+
keyedExpressions.add(range.source);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
continue;
|
|
2707
|
+
}
|
|
2708
|
+
nextId = mixedRangeStart;
|
|
1793
2709
|
const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
|
|
1794
2710
|
if (keyedRanges) {
|
|
1795
2711
|
plans.push({
|
|
@@ -1799,7 +2715,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1799
2715
|
dependencies: keyedRanges.dependencies,
|
|
1800
2716
|
source: child,
|
|
1801
2717
|
ranges: keyedRanges.ranges,
|
|
1802
|
-
trailing: keyedRanges.trailing
|
|
2718
|
+
trailing: keyedRanges.trailing,
|
|
2719
|
+
staticBindings: keyedRanges.staticBindings
|
|
1803
2720
|
});
|
|
1804
2721
|
for (const range of keyedRanges.ranges) {
|
|
1805
2722
|
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
@@ -1807,58 +2724,102 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1807
2724
|
}
|
|
1808
2725
|
continue;
|
|
1809
2726
|
}
|
|
1810
|
-
const
|
|
2727
|
+
const conditionalRangeStart = nextId;
|
|
2728
|
+
const conditionalRangeId = nextId++;
|
|
2729
|
+
const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(
|
|
2730
|
+
child,
|
|
2731
|
+
statesByValue,
|
|
2732
|
+
safeGlobals,
|
|
2733
|
+
false,
|
|
2734
|
+
listNames,
|
|
2735
|
+
conditionalRangeId,
|
|
2736
|
+
() => nextId++
|
|
2737
|
+
);
|
|
1811
2738
|
if (conditionalRanges) {
|
|
1812
2739
|
plans.push({
|
|
1813
2740
|
kind: "conditional-ranges",
|
|
1814
|
-
id:
|
|
2741
|
+
id: conditionalRangeId,
|
|
1815
2742
|
parent,
|
|
1816
2743
|
dependencies: conditionalRanges.dependencies,
|
|
1817
2744
|
source: child,
|
|
1818
2745
|
ranges: conditionalRanges.ranges,
|
|
1819
|
-
trailing: conditionalRanges.trailing
|
|
2746
|
+
trailing: conditionalRanges.trailing,
|
|
2747
|
+
staticBindings: conditionalRanges.staticBindings,
|
|
2748
|
+
descriptorBlocks: conditionalRanges.descriptorBlocks
|
|
1820
2749
|
});
|
|
2750
|
+
plans.push(...conditionalRanges.nestedPlans || []);
|
|
1821
2751
|
for (const range of conditionalRanges.ranges) {
|
|
1822
2752
|
conditionalExpressions.add(range.source);
|
|
1823
2753
|
}
|
|
1824
2754
|
continue;
|
|
1825
2755
|
}
|
|
2756
|
+
nextId = conditionalRangeStart;
|
|
2757
|
+
const hostConditionalStart = nextId;
|
|
2758
|
+
const hostConditionalId = nextId++;
|
|
1826
2759
|
const hostConditional = analyzeHostConditionalContainer(
|
|
1827
2760
|
child,
|
|
1828
2761
|
statesByValue,
|
|
1829
|
-
safeGlobals
|
|
2762
|
+
safeGlobals,
|
|
2763
|
+
listNames,
|
|
2764
|
+
hostConditionalId,
|
|
2765
|
+
() => nextId++
|
|
1830
2766
|
);
|
|
1831
2767
|
if (hostConditional) {
|
|
1832
2768
|
plans.push({
|
|
1833
2769
|
kind: "host-conditional",
|
|
1834
|
-
id:
|
|
2770
|
+
id: hostConditionalId,
|
|
1835
2771
|
parent,
|
|
1836
2772
|
source: child,
|
|
1837
2773
|
...hostConditional
|
|
1838
2774
|
});
|
|
2775
|
+
plans.push(...hostConditional.nestedPlans || []);
|
|
1839
2776
|
ownedElements.add(child);
|
|
1840
2777
|
continue;
|
|
1841
2778
|
}
|
|
2779
|
+
nextId = hostConditionalStart;
|
|
2780
|
+
const keyedRowsStart = nextId;
|
|
2781
|
+
const keyedRowsId = nextId++;
|
|
1842
2782
|
const keyedRows = analyzeKeyedRowsContainer(child, statesByValue, safeGlobals, listNames);
|
|
1843
2783
|
if (keyedRows) {
|
|
2784
|
+
const nestedStart = nextId;
|
|
2785
|
+
const hostBlocks = analyzeCompilerOwnedKeyedRowHostBlocks(
|
|
2786
|
+
keyedRows,
|
|
2787
|
+
statesByValue,
|
|
2788
|
+
safeGlobals,
|
|
2789
|
+
listNames,
|
|
2790
|
+
keyedRowsId,
|
|
2791
|
+
() => nextId++
|
|
2792
|
+
);
|
|
2793
|
+
if (!hostBlocks) nextId = nestedStart;
|
|
2794
|
+
if (keyedRows.rowReason && !hostBlocks) {
|
|
2795
|
+
nextId = keyedRowsStart;
|
|
2796
|
+
const nested2 = visitHost(child, parent, insideConditional);
|
|
2797
|
+
if (nested2.reason) return { dependencies, reason: nested2.reason };
|
|
2798
|
+
mergeDependencies(dependencies, nested2.dependencies);
|
|
2799
|
+
continue;
|
|
2800
|
+
}
|
|
1844
2801
|
plans.push({
|
|
1845
2802
|
kind: "keyed-rows",
|
|
1846
|
-
id:
|
|
2803
|
+
id: keyedRowsId,
|
|
1847
2804
|
parent,
|
|
1848
2805
|
dependencies: keyedRows.dependencies,
|
|
1849
2806
|
source: child,
|
|
1850
2807
|
collection: keyedRows.collection,
|
|
2808
|
+
structureDependencies: keyedRows.structureDependencies,
|
|
1851
2809
|
keyCallback: keyedRows.keyCallback,
|
|
1852
2810
|
renderCallback: keyedRows.renderCallback,
|
|
1853
|
-
row: keyedRows.row,
|
|
1854
|
-
bindings: keyedRows.bindings,
|
|
2811
|
+
row: hostBlocks?.row || keyedRows.row,
|
|
2812
|
+
bindings: hostBlocks?.bindings || keyedRows.bindings,
|
|
1855
2813
|
events: keyedRows.events,
|
|
1856
|
-
conditionals: keyedRows.conditionals,
|
|
2814
|
+
conditionals: hostBlocks ? [] : keyedRows.conditionals,
|
|
2815
|
+
descriptorBlocks: hostBlocks?.descriptorBlocks,
|
|
1857
2816
|
syntax: keyedRows.syntax
|
|
1858
2817
|
});
|
|
2818
|
+
plans.push(...hostBlocks?.nestedPlans || []);
|
|
1859
2819
|
ownedElements.add(child);
|
|
1860
2820
|
continue;
|
|
1861
2821
|
}
|
|
2822
|
+
nextId = keyedRowsStart;
|
|
1862
2823
|
const nested = visitHost(child, parent, insideConditional);
|
|
1863
2824
|
if (nested.reason) return { dependencies, reason: nested.reason };
|
|
1864
2825
|
mergeDependencies(dependencies, nested.dependencies);
|
|
@@ -1955,6 +2916,46 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1955
2916
|
}
|
|
1956
2917
|
return { dependencies };
|
|
1957
2918
|
};
|
|
2919
|
+
const rootMixedRangeStart = nextId;
|
|
2920
|
+
const rootMixedRangeId = nextId++;
|
|
2921
|
+
const rootMixedRanges = analyzeMixedRangesContainer(
|
|
2922
|
+
root,
|
|
2923
|
+
statesByValue,
|
|
2924
|
+
safeGlobals,
|
|
2925
|
+
listNames,
|
|
2926
|
+
rootMixedRangeId,
|
|
2927
|
+
() => nextId++
|
|
2928
|
+
);
|
|
2929
|
+
if (rootMixedRanges) {
|
|
2930
|
+
plans.push({
|
|
2931
|
+
kind: "mixed-ranges",
|
|
2932
|
+
id: rootMixedRangeId,
|
|
2933
|
+
dependencies: rootMixedRanges.dependencies,
|
|
2934
|
+
source: root,
|
|
2935
|
+
ranges: rootMixedRanges.ranges,
|
|
2936
|
+
trailing: rootMixedRanges.trailing,
|
|
2937
|
+
staticBindings: rootMixedRanges.staticBindings,
|
|
2938
|
+
descriptorBlocks: rootMixedRanges.descriptorBlocks
|
|
2939
|
+
});
|
|
2940
|
+
plans.push(...rootMixedRanges.nestedPlans);
|
|
2941
|
+
for (const range of rootMixedRanges.ranges) {
|
|
2942
|
+
if (range.rangeKind === "conditional") {
|
|
2943
|
+
conditionalExpressions.add(range.source);
|
|
2944
|
+
} else if (types.isJSXElement(range.source)) {
|
|
2945
|
+
ownedElements.add(range.source);
|
|
2946
|
+
} else {
|
|
2947
|
+
keyedExpressions.add(range.source);
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
return {
|
|
2951
|
+
plans,
|
|
2952
|
+
componentElements,
|
|
2953
|
+
conditionalExpressions,
|
|
2954
|
+
ownedElements,
|
|
2955
|
+
keyedExpressions
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2958
|
+
nextId = rootMixedRangeStart;
|
|
1958
2959
|
const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
|
|
1959
2960
|
if (rootRanges) {
|
|
1960
2961
|
plans.push({
|
|
@@ -1963,7 +2964,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1963
2964
|
dependencies: rootRanges.dependencies,
|
|
1964
2965
|
source: root,
|
|
1965
2966
|
ranges: rootRanges.ranges,
|
|
1966
|
-
trailing: rootRanges.trailing
|
|
2967
|
+
trailing: rootRanges.trailing,
|
|
2968
|
+
staticBindings: rootRanges.staticBindings
|
|
1967
2969
|
});
|
|
1968
2970
|
for (const range of rootRanges.ranges) {
|
|
1969
2971
|
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
@@ -1977,21 +2979,29 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1977
2979
|
keyedExpressions
|
|
1978
2980
|
};
|
|
1979
2981
|
}
|
|
2982
|
+
const rootConditionalRangeStart = nextId;
|
|
2983
|
+
const rootConditionalRangeId = nextId++;
|
|
1980
2984
|
const rootConditionalRanges = analyzeConditionalRangesContainer(
|
|
1981
2985
|
root,
|
|
1982
2986
|
statesByValue,
|
|
1983
2987
|
safeGlobals,
|
|
1984
|
-
true
|
|
2988
|
+
true,
|
|
2989
|
+
listNames,
|
|
2990
|
+
rootConditionalRangeId,
|
|
2991
|
+
() => nextId++
|
|
1985
2992
|
);
|
|
1986
2993
|
if (rootConditionalRanges) {
|
|
1987
2994
|
plans.push({
|
|
1988
2995
|
kind: "conditional-ranges",
|
|
1989
|
-
id:
|
|
2996
|
+
id: rootConditionalRangeId,
|
|
1990
2997
|
dependencies: rootConditionalRanges.dependencies,
|
|
1991
2998
|
source: root,
|
|
1992
2999
|
ranges: rootConditionalRanges.ranges,
|
|
1993
|
-
trailing: rootConditionalRanges.trailing
|
|
3000
|
+
trailing: rootConditionalRanges.trailing,
|
|
3001
|
+
staticBindings: rootConditionalRanges.staticBindings,
|
|
3002
|
+
descriptorBlocks: rootConditionalRanges.descriptorBlocks
|
|
1994
3003
|
});
|
|
3004
|
+
plans.push(...rootConditionalRanges.nestedPlans || []);
|
|
1995
3005
|
for (const range of rootConditionalRanges.ranges) {
|
|
1996
3006
|
conditionalExpressions.add(range.source);
|
|
1997
3007
|
}
|
|
@@ -2003,6 +3013,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
2003
3013
|
keyedExpressions
|
|
2004
3014
|
};
|
|
2005
3015
|
}
|
|
3016
|
+
nextId = rootConditionalRangeStart;
|
|
2006
3017
|
const result = visitHost(root, void 0, false);
|
|
2007
3018
|
if (result.reason) return { reason: result.reason };
|
|
2008
3019
|
return {
|
|
@@ -2040,6 +3051,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
2040
3051
|
plans.map((plan) => [plan.source, plan])
|
|
2041
3052
|
);
|
|
2042
3053
|
const rootPlan = planBySource.get(root);
|
|
3054
|
+
if (rootPlan?.kind === "mixed-ranges") {
|
|
3055
|
+
return mixedRangesBoundary(blockRuntime, rootPlan);
|
|
3056
|
+
}
|
|
2043
3057
|
if (rootPlan?.kind === "keyed-ranges") {
|
|
2044
3058
|
return keyedRangesBoundary(blockRuntime, rootPlan);
|
|
2045
3059
|
}
|
|
@@ -2053,6 +3067,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
2053
3067
|
if (plan2?.kind === "host-conditional") {
|
|
2054
3068
|
return hostConditionalBoundary(blockRuntime, plan2);
|
|
2055
3069
|
}
|
|
3070
|
+
if (plan2?.kind === "mixed-ranges") {
|
|
3071
|
+
return mixedRangesBoundary(blockRuntime, plan2);
|
|
3072
|
+
}
|
|
2056
3073
|
if (plan2?.kind === "keyed-rows") {
|
|
2057
3074
|
return keyedRowsBoundary(blockRuntime, plan2);
|
|
2058
3075
|
}
|
|
@@ -2102,6 +3119,31 @@ function assignStableBindingTargets(bindings) {
|
|
|
2102
3119
|
binding.target = target;
|
|
2103
3120
|
}
|
|
2104
3121
|
}
|
|
3122
|
+
function markShortCircuitBindings(bindings) {
|
|
3123
|
+
for (const binding of bindings) {
|
|
3124
|
+
if (binding.kind === "block" || binding.dependencies.length < 2) continue;
|
|
3125
|
+
let shortCircuits = false;
|
|
3126
|
+
traverse(expressionFile(types.cloneNode(binding.value, true)), {
|
|
3127
|
+
ConditionalExpression(path) {
|
|
3128
|
+
shortCircuits = true;
|
|
3129
|
+
path.stop();
|
|
3130
|
+
},
|
|
3131
|
+
LogicalExpression(path) {
|
|
3132
|
+
shortCircuits = true;
|
|
3133
|
+
path.stop();
|
|
3134
|
+
},
|
|
3135
|
+
OptionalCallExpression(path) {
|
|
3136
|
+
shortCircuits = true;
|
|
3137
|
+
path.stop();
|
|
3138
|
+
},
|
|
3139
|
+
OptionalMemberExpression(path) {
|
|
3140
|
+
shortCircuits = true;
|
|
3141
|
+
path.stop();
|
|
3142
|
+
}
|
|
3143
|
+
});
|
|
3144
|
+
if (shortCircuits) binding.tracking = "dynamic";
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
2105
3147
|
function lowerStableBindingTargets(root, bindings, blockRuntime, ownedElements) {
|
|
2106
3148
|
const targetByPath = /* @__PURE__ */ new Map();
|
|
2107
3149
|
for (const binding of bindings) {
|
|
@@ -2371,6 +3413,9 @@ function bindingObject(binding, propsParameter, stateParameter, statesByValue, s
|
|
|
2371
3413
|
types.objectProperty(types.identifier("target"), types.numericLiteral(binding.target))
|
|
2372
3414
|
);
|
|
2373
3415
|
}
|
|
3416
|
+
if (binding.tracking) {
|
|
3417
|
+
properties.push(types.objectProperty(types.identifier("tracking"), types.stringLiteral(binding.tracking)));
|
|
3418
|
+
}
|
|
2374
3419
|
if (binding.name)
|
|
2375
3420
|
properties.push(types.objectProperty(types.identifier("name"), types.stringLiteral(binding.name)));
|
|
2376
3421
|
properties.push(
|
|
@@ -2389,7 +3434,7 @@ function wrapperElement(definitionIdentifier, props) {
|
|
|
2389
3434
|
const attributes = props ? [types.jsxSpreadAttribute(types.cloneNode(props))] : [];
|
|
2390
3435
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
2391
3436
|
}
|
|
2392
|
-
function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId) {
|
|
3437
|
+
function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, useStateNames, reactNames, listNames, moduleId, reactivity) {
|
|
2393
3438
|
const { path, name, statementPath } = candidate;
|
|
2394
3439
|
if (path.node.async || path.node.generator)
|
|
2395
3440
|
return "async and generator components are not supported";
|
|
@@ -2506,8 +3551,34 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2506
3551
|
);
|
|
2507
3552
|
const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
|
|
2508
3553
|
if (setterReason) return setterReason;
|
|
3554
|
+
const referencedPropNames = collectDestructuredPropNames(
|
|
3555
|
+
expandedRoot,
|
|
3556
|
+
propsPlan.destructuredNames,
|
|
3557
|
+
propsPlan.definitionParameter
|
|
3558
|
+
);
|
|
3559
|
+
let propBindings = referencedPropNames.has("children") ? [] : [...propsPlan.destructuredNames].filter((propName) => referencedPropNames.has(propName)).map(
|
|
3560
|
+
(localName, propIndex) => ({
|
|
3561
|
+
localName,
|
|
3562
|
+
valueName: path.scope.generateUidIdentifier(`farmProp${propIndex}`).name,
|
|
3563
|
+
index: states.length + propIndex
|
|
3564
|
+
})
|
|
3565
|
+
);
|
|
3566
|
+
const propBindingsByName = new Map(propBindings.map((binding) => [binding.localName, binding]));
|
|
3567
|
+
let reactiveByValue = new Map(statesByValue);
|
|
3568
|
+
for (const binding of propBindings) {
|
|
3569
|
+
reactiveByValue.set(binding.valueName, {
|
|
3570
|
+
valueName: binding.valueName,
|
|
3571
|
+
setterName: "",
|
|
3572
|
+
index: binding.index
|
|
3573
|
+
});
|
|
3574
|
+
}
|
|
3575
|
+
let expandedReactiveRoot = rewriteTrackedPropAccess(
|
|
3576
|
+
expandedRoot,
|
|
3577
|
+
propsPlan.definitionParameter,
|
|
3578
|
+
propBindingsByName
|
|
3579
|
+
);
|
|
2509
3580
|
const referencedComponentNames = /* @__PURE__ */ new Set();
|
|
2510
|
-
traverse(expressionFile(types.cloneNode(
|
|
3581
|
+
traverse(expressionFile(types.cloneNode(expandedReactiveRoot, true)), {
|
|
2511
3582
|
JSXOpeningElement(componentPath) {
|
|
2512
3583
|
const componentName = componentPath.node.name;
|
|
2513
3584
|
if (types.isJSXIdentifier(componentName) && isComponentName(componentName.name)) {
|
|
@@ -2524,32 +3595,55 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2524
3595
|
);
|
|
2525
3596
|
})
|
|
2526
3597
|
);
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
3598
|
+
let blockAnalysis = analyzeComposableBlocks(
|
|
3599
|
+
expandedReactiveRoot,
|
|
3600
|
+
reactiveByValue,
|
|
2530
3601
|
safeGlobals,
|
|
2531
3602
|
listNames,
|
|
2532
3603
|
allowedComponentNames
|
|
2533
3604
|
);
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
expandedRoot,
|
|
2538
|
-
statesByValue,
|
|
3605
|
+
let analysis = analyzeHostTree(
|
|
3606
|
+
expandedReactiveRoot,
|
|
3607
|
+
reactiveByValue,
|
|
2539
3608
|
safeGlobals,
|
|
2540
3609
|
blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
2541
3610
|
blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
2542
3611
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
2543
3612
|
blockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
2544
3613
|
);
|
|
3614
|
+
if (propBindings.length > 0 && (blockAnalysis.reason || analysis.reason)) {
|
|
3615
|
+
propBindings = [];
|
|
3616
|
+
reactiveByValue = new Map(statesByValue);
|
|
3617
|
+
expandedReactiveRoot = types.cloneNode(expandedRoot, true);
|
|
3618
|
+
blockAnalysis = analyzeComposableBlocks(
|
|
3619
|
+
expandedReactiveRoot,
|
|
3620
|
+
reactiveByValue,
|
|
3621
|
+
safeGlobals,
|
|
3622
|
+
listNames,
|
|
3623
|
+
allowedComponentNames
|
|
3624
|
+
);
|
|
3625
|
+
analysis = analyzeHostTree(
|
|
3626
|
+
expandedReactiveRoot,
|
|
3627
|
+
reactiveByValue,
|
|
3628
|
+
safeGlobals,
|
|
3629
|
+
blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
3630
|
+
blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
3631
|
+
blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
3632
|
+
blockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
3633
|
+
);
|
|
3634
|
+
}
|
|
3635
|
+
if (blockAnalysis.reason) return blockAnalysis.reason;
|
|
2545
3636
|
if (analysis.reason) return analysis.reason;
|
|
3637
|
+
const blockPlans = blockAnalysis.plans || [];
|
|
3638
|
+
const runtimeFeatures = runtimeFeaturesForPlans(blockPlans);
|
|
3639
|
+
markShortCircuitBindings(analysis.bindings || []);
|
|
2546
3640
|
assignStableBindingTargets(analysis.bindings || []);
|
|
2547
3641
|
const stateParameter = path.scope.generateUidIdentifier("farmState");
|
|
2548
3642
|
const blockParameter = path.scope.generateUidIdentifier("farmBlocks");
|
|
2549
3643
|
const definitionIdentifier = path.scope.generateUidIdentifier(`${name}Compiled`);
|
|
2550
3644
|
const propsParameter = propsPlan.definitionParameter;
|
|
2551
3645
|
const rootWithTargets = lowerStableBindingTargets(
|
|
2552
|
-
|
|
3646
|
+
expandedReactiveRoot,
|
|
2553
3647
|
analysis.bindings || [],
|
|
2554
3648
|
blockParameter,
|
|
2555
3649
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
|
|
@@ -2563,12 +3657,13 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2563
3657
|
const rewrittenRoot = rewriteStateAccess(
|
|
2564
3658
|
rootWithBlocks,
|
|
2565
3659
|
stateParameter,
|
|
2566
|
-
|
|
3660
|
+
reactiveByValue,
|
|
2567
3661
|
statesBySetter
|
|
2568
3662
|
);
|
|
2569
3663
|
const definition = types.callExpression(types.cloneNode(createComponentIdentifier), [
|
|
2570
3664
|
types.objectExpression([
|
|
2571
3665
|
types.objectProperty(types.identifier("displayName"), types.stringLiteral(name)),
|
|
3666
|
+
types.objectProperty(types.identifier("reactivity"), types.stringLiteral(reactivity)),
|
|
2572
3667
|
types.spreadElement(
|
|
2573
3668
|
types.conditionalExpression(
|
|
2574
3669
|
types.memberExpression(
|
|
@@ -2579,7 +3674,9 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2579
3674
|
types.objectProperty(types.identifier("hmrId"), types.stringLiteral(`${moduleId}#${name}`)),
|
|
2580
3675
|
types.objectProperty(
|
|
2581
3676
|
types.identifier("stateSignature"),
|
|
2582
|
-
types.stringLiteral(
|
|
3677
|
+
types.stringLiteral(
|
|
3678
|
+
propBindings.length === 0 ? String(states.length) : `${states.length}:${propBindings.map((binding) => binding.localName).join(",")}`
|
|
3679
|
+
)
|
|
2583
3680
|
)
|
|
2584
3681
|
]),
|
|
2585
3682
|
types.objectExpression([])
|
|
@@ -2602,6 +3699,22 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2602
3699
|
)
|
|
2603
3700
|
)
|
|
2604
3701
|
),
|
|
3702
|
+
...propBindings.length > 0 ? [
|
|
3703
|
+
types.objectProperty(
|
|
3704
|
+
types.identifier("readProps"),
|
|
3705
|
+
types.arrowFunctionExpression(
|
|
3706
|
+
[types.cloneNode(propsParameter)],
|
|
3707
|
+
types.arrayExpression(
|
|
3708
|
+
propBindings.map(
|
|
3709
|
+
(binding) => types.memberExpression(
|
|
3710
|
+
types.cloneNode(propsParameter),
|
|
3711
|
+
types.identifier(binding.localName)
|
|
3712
|
+
)
|
|
3713
|
+
)
|
|
3714
|
+
)
|
|
3715
|
+
)
|
|
3716
|
+
)
|
|
3717
|
+
] : [],
|
|
2605
3718
|
types.objectProperty(
|
|
2606
3719
|
types.identifier("render"),
|
|
2607
3720
|
types.arrowFunctionExpression(
|
|
@@ -2621,11 +3734,14 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2621
3734
|
dependencies: block.dependencies
|
|
2622
3735
|
}))
|
|
2623
3736
|
].map(
|
|
2624
|
-
(binding) => bindingObject(binding, propsParameter, stateParameter,
|
|
3737
|
+
(binding) => bindingObject(binding, propsParameter, stateParameter, reactiveByValue, statesBySetter)
|
|
2625
3738
|
)
|
|
2626
3739
|
)
|
|
2627
3740
|
)
|
|
2628
|
-
])
|
|
3741
|
+
]),
|
|
3742
|
+
types.arrayExpression(
|
|
3743
|
+
runtimeFeatures.map((feature) => types.cloneNode(runtimeFeatureIdentifiers.get(feature)))
|
|
3744
|
+
)
|
|
2629
3745
|
]);
|
|
2630
3746
|
path.get("body").replaceWith(
|
|
2631
3747
|
types.blockStatement([
|
|
@@ -2635,6 +3751,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2635
3751
|
statementPath.insertAfter(
|
|
2636
3752
|
types.variableDeclaration("const", [types.variableDeclarator(definitionIdentifier, definition)])
|
|
2637
3753
|
);
|
|
3754
|
+
for (const feature of runtimeFeatures) usedRuntimeFeatures.add(feature);
|
|
2638
3755
|
return void 0;
|
|
2639
3756
|
}
|
|
2640
3757
|
function collectCandidates(programPath) {
|
|
@@ -2702,6 +3819,13 @@ async function compileReactModule(code, id, options) {
|
|
|
2702
3819
|
}
|
|
2703
3820
|
const candidates = collectCandidates(programPath);
|
|
2704
3821
|
const createComponentIdentifier = programPath.scope.generateUidIdentifier("createCompiledComponent");
|
|
3822
|
+
const runtimeFeatureIdentifiers = new Map(
|
|
3823
|
+
Object.entries(COMPILER_RUNTIME_FEATURE_EXPORTS).map(([feature, exportName]) => [
|
|
3824
|
+
feature,
|
|
3825
|
+
programPath.scope.generateUidIdentifier(exportName)
|
|
3826
|
+
])
|
|
3827
|
+
);
|
|
3828
|
+
const usedRuntimeFeatures = /* @__PURE__ */ new Set();
|
|
2705
3829
|
for (const candidate of candidates) {
|
|
2706
3830
|
const functionDirectives = new Set(
|
|
2707
3831
|
types.isBlockStatement(candidate.path.node.body) ? directiveValues(candidate.path.node.body) : []
|
|
@@ -2712,10 +3836,13 @@ async function compileReactModule(code, id, options) {
|
|
|
2712
3836
|
const reason = compileCandidate(
|
|
2713
3837
|
candidate,
|
|
2714
3838
|
createComponentIdentifier,
|
|
3839
|
+
runtimeFeatureIdentifiers,
|
|
3840
|
+
usedRuntimeFeatures,
|
|
2715
3841
|
useStateNames,
|
|
2716
3842
|
reactNames,
|
|
2717
3843
|
listNames,
|
|
2718
|
-
id
|
|
3844
|
+
id,
|
|
3845
|
+
options.reactivity
|
|
2719
3846
|
);
|
|
2720
3847
|
if (reason) {
|
|
2721
3848
|
diagnostics.push({
|
|
@@ -2734,7 +3861,13 @@ async function compileReactModule(code, id, options) {
|
|
|
2734
3861
|
[
|
|
2735
3862
|
types.importSpecifier(
|
|
2736
3863
|
createComponentIdentifier,
|
|
2737
|
-
types.identifier("
|
|
3864
|
+
types.identifier("createCompiledComponentWithFeatures")
|
|
3865
|
+
),
|
|
3866
|
+
...[...usedRuntimeFeatures].sort().map(
|
|
3867
|
+
(feature) => types.importSpecifier(
|
|
3868
|
+
types.cloneNode(runtimeFeatureIdentifiers.get(feature)),
|
|
3869
|
+
types.identifier(COMPILER_RUNTIME_FEATURE_EXPORTS[feature])
|
|
3870
|
+
)
|
|
2738
3871
|
)
|
|
2739
3872
|
],
|
|
2740
3873
|
types.stringLiteral("@farm.js/react/compiler-runtime")
|
|
@@ -2842,6 +3975,10 @@ function normalizeReactCompilerOptions(value) {
|
|
|
2842
3975
|
if (!["fallback", "warn", "error"].includes(onUnsupported)) {
|
|
2843
3976
|
throw new TypeError(`Unknown unsupported-component behavior: ${String(onUnsupported)}`);
|
|
2844
3977
|
}
|
|
3978
|
+
const reactivity = options.reactivity || "hybrid";
|
|
3979
|
+
if (reactivity !== "static" && reactivity !== "hybrid") {
|
|
3980
|
+
throw new TypeError(`Unknown React compiler reactivity mode: ${String(reactivity)}`);
|
|
3981
|
+
}
|
|
2845
3982
|
if (options.report !== void 0 && typeof options.report !== "boolean") {
|
|
2846
3983
|
throw new TypeError("The React compiler report option must be a boolean.");
|
|
2847
3984
|
}
|
|
@@ -2852,7 +3989,7 @@ function normalizeReactCompilerOptions(value) {
|
|
|
2852
3989
|
}
|
|
2853
3990
|
const reportFile = normalizeCompilerReportFile(options.reportFile);
|
|
2854
3991
|
const report = options.report === true || options.reportFile !== void 0;
|
|
2855
|
-
return { mode, directive, onUnsupported, report, reportFile };
|
|
3992
|
+
return { mode, directive, onUnsupported, reactivity, report, reportFile };
|
|
2856
3993
|
}
|
|
2857
3994
|
|
|
2858
3995
|
// src/vite.ts
|
|
@@ -2868,7 +4005,7 @@ function readCompilerOptions(rendererOptions) {
|
|
|
2868
4005
|
);
|
|
2869
4006
|
}
|
|
2870
4007
|
const normalized = compiler;
|
|
2871
|
-
if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
|
|
4008
|
+
if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.reactivity === "static" || normalized.reactivity === "hybrid") && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
|
|
2872
4009
|
return normalized;
|
|
2873
4010
|
}
|
|
2874
4011
|
return normalizeReactCompilerOptions(compiler);
|