@farm.js/react 0.1.0-beta.2 → 0.1.0-beta.4
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 +148 -42
- package/dist/compiler-runtime.cjs +2087 -134
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +94 -1
- package/dist/compiler-runtime.d.ts +94 -1
- package/dist/compiler-runtime.mjs +2087 -134
- 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 +1321 -75
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +1321 -75
- package/dist/vite.mjs.map +1 -1
- package/package.json +4 -3
package/dist/vite.mjs
CHANGED
|
@@ -4,6 +4,62 @@ 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
|
+
}
|
|
7
63
|
var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set(["Boolean", "Number", "String"]);
|
|
8
64
|
var SAFE_MATH_CALLS = /* @__PURE__ */ new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc"]);
|
|
9
65
|
function isComponentName(name) {
|
|
@@ -88,6 +144,37 @@ function rewriteDestructuredPropAccess(expression, names, propsParameter) {
|
|
|
88
144
|
});
|
|
89
145
|
return file.program.body[0].expression;
|
|
90
146
|
}
|
|
147
|
+
function collectDestructuredPropNames(expression, names, propsParameter) {
|
|
148
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
149
|
+
if (names.size === 0) return referenced;
|
|
150
|
+
traverse(expressionFile(cloneExpression(expression)), {
|
|
151
|
+
MemberExpression(path) {
|
|
152
|
+
const { object, property, computed } = path.node;
|
|
153
|
+
if (computed || !types.isIdentifier(object, { name: propsParameter.name }) || !types.isIdentifier(property) || !names.has(property.name)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
referenced.add(property.name);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return referenced;
|
|
160
|
+
}
|
|
161
|
+
function rewriteTrackedPropAccess(expression, propsParameter, bindingsByName) {
|
|
162
|
+
if (bindingsByName.size === 0) return cloneExpression(expression);
|
|
163
|
+
const file = expressionFile(cloneExpression(expression));
|
|
164
|
+
traverse(file, {
|
|
165
|
+
MemberExpression(path) {
|
|
166
|
+
const { object, property, computed } = path.node;
|
|
167
|
+
if (computed || !types.isIdentifier(object, { name: propsParameter.name }) || !types.isIdentifier(property)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const binding = bindingsByName.get(property.name);
|
|
171
|
+
if (!binding) return;
|
|
172
|
+
path.replaceWith(types.identifier(binding.valueName));
|
|
173
|
+
path.skip();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return file.program.body[0].expression;
|
|
177
|
+
}
|
|
91
178
|
function rewriteHandlerAccess(root, handlersByName) {
|
|
92
179
|
if (handlersByName.size === 0) return { root: types.cloneNode(root, true) };
|
|
93
180
|
const file = expressionFile(types.cloneNode(root, true));
|
|
@@ -767,7 +854,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
767
854
|
const reason = visit(row, []);
|
|
768
855
|
return reason ? { reason } : { bindings, events, conditionals };
|
|
769
856
|
}
|
|
770
|
-
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
|
|
857
|
+
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
|
|
771
858
|
let collection;
|
|
772
859
|
let keyCallback;
|
|
773
860
|
let renderCallback;
|
|
@@ -822,17 +909,29 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
|
|
|
822
909
|
safeGlobals,
|
|
823
910
|
new Set([...statesByValue.values()].map((state) => state.setterName))
|
|
824
911
|
);
|
|
825
|
-
if (rowAnalysis.reason) return void 0;
|
|
912
|
+
if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
|
|
913
|
+
const keyExpression = returnedExpression(keyCallback);
|
|
914
|
+
const structureDependencies = new Set(collectStateDependencies(collection, statesByValue));
|
|
915
|
+
if (keyExpression) {
|
|
916
|
+
for (const dependency of collectStateDependencies(keyExpression, statesByValue)) {
|
|
917
|
+
structureDependencies.add(dependency);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
826
920
|
return {
|
|
827
921
|
source,
|
|
828
922
|
collection,
|
|
923
|
+
structureDependencies: [...structureDependencies].sort((left, right) => left - right),
|
|
829
924
|
keyCallback,
|
|
830
925
|
renderCallback,
|
|
831
926
|
row,
|
|
832
927
|
dependencies,
|
|
833
|
-
bindings: rowAnalysis.bindings || []
|
|
928
|
+
bindings: (rowAnalysis.bindings || []).map((binding) => ({
|
|
929
|
+
...binding,
|
|
930
|
+
dependencies: collectStateDependencies(binding.value, statesByValue)
|
|
931
|
+
})),
|
|
834
932
|
events: rowAnalysis.events || [],
|
|
835
933
|
conditionals: rowAnalysis.conditionals || [],
|
|
934
|
+
rowReason: rowAnalysis.reason,
|
|
836
935
|
syntax
|
|
837
936
|
};
|
|
838
937
|
}
|
|
@@ -849,22 +948,7 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
849
948
|
}
|
|
850
949
|
const children = meaningfulJsxChildren(container);
|
|
851
950
|
if (children.length !== 1) return void 0;
|
|
852
|
-
return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames);
|
|
853
|
-
}
|
|
854
|
-
function isStaticKeyedRangeSibling(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) || !isStaticKeyedRangeSibling(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;
|
|
951
|
+
return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames, true);
|
|
868
952
|
}
|
|
869
953
|
function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
|
|
870
954
|
if (container.openingElement.attributes.some(
|
|
@@ -876,6 +960,7 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
876
960
|
if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
|
|
877
961
|
const ranges = [];
|
|
878
962
|
const dependencies = /* @__PURE__ */ new Set();
|
|
963
|
+
const staticBindings = [];
|
|
879
964
|
let staticBefore = 0;
|
|
880
965
|
for (const child of children) {
|
|
881
966
|
const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames);
|
|
@@ -896,18 +981,31 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
896
981
|
continue;
|
|
897
982
|
}
|
|
898
983
|
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
899
|
-
|
|
984
|
+
const analysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
|
|
985
|
+
if (analysis.reason) return void 0;
|
|
986
|
+
for (const binding of analysis.bindings || []) {
|
|
987
|
+
staticBindings.push({
|
|
988
|
+
...binding,
|
|
989
|
+
segment: ranges.length,
|
|
990
|
+
sibling: staticBefore
|
|
991
|
+
});
|
|
992
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
993
|
+
dependencies.add(dependency);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
900
996
|
staticBefore += 1;
|
|
901
997
|
}
|
|
902
998
|
if (ranges.length === 0) return void 0;
|
|
903
999
|
return {
|
|
904
1000
|
ranges,
|
|
905
1001
|
trailing: staticBefore,
|
|
906
|
-
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
1002
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1003
|
+
staticBindings
|
|
907
1004
|
};
|
|
908
1005
|
}
|
|
909
|
-
function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
1006
|
+
function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = false, statefulOnly) {
|
|
910
1007
|
const bindings = [];
|
|
1008
|
+
const needsStaticBinding = (expression) => !statefulOnly || collectStateDependencies(expression, statefulOnly).length > 0;
|
|
911
1009
|
const visit = (element, path) => {
|
|
912
1010
|
const tag = element.openingElement.name;
|
|
913
1011
|
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
@@ -916,20 +1014,26 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
916
1014
|
if (tag.name === "svg") return "compiler-owned conditionals do not support SVG yet";
|
|
917
1015
|
for (const attribute of element.openingElement.attributes) {
|
|
918
1016
|
if (types.isJSXSpreadAttribute(attribute)) {
|
|
1017
|
+
if (statefulOnly && !needsStaticBinding(attribute.argument)) continue;
|
|
919
1018
|
return "compiler-owned conditionals do not support JSX attribute spreads";
|
|
920
1019
|
}
|
|
921
1020
|
const name = jsxAttributeName(attribute);
|
|
922
1021
|
if (!name) return "compiler-owned conditionals do not support namespaced JSX attributes";
|
|
923
1022
|
if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
|
|
1023
|
+
if (statefulOnly && (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression) || !needsStaticBinding(attribute.value.expression))) {
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
924
1026
|
return `compiler-owned conditional ${name} requires React ownership`;
|
|
925
1027
|
}
|
|
926
1028
|
if (/^on[A-Z]/.test(name)) {
|
|
1029
|
+
if (allowStaticEvents) continue;
|
|
927
1030
|
return "compiler-owned conditional events require React ownership";
|
|
928
1031
|
}
|
|
929
1032
|
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
930
1033
|
continue;
|
|
931
1034
|
}
|
|
932
1035
|
const expression = attribute.value.expression;
|
|
1036
|
+
if (!needsStaticBinding(expression)) continue;
|
|
933
1037
|
if (name === "style") {
|
|
934
1038
|
if (!types.isObjectExpression(expression)) {
|
|
935
1039
|
return "compiler-owned conditional styles must use one inline object literal";
|
|
@@ -942,6 +1046,7 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
942
1046
|
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
943
1047
|
return "compiler-owned conditional style names must use camelCase or a CSS custom property";
|
|
944
1048
|
}
|
|
1049
|
+
if (!needsStaticBinding(property.value)) continue;
|
|
945
1050
|
const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
|
|
946
1051
|
if (unsupported2) {
|
|
947
1052
|
return `compiler-owned conditional style ${propertyName} cannot use ${unsupported2}`;
|
|
@@ -976,14 +1081,20 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
976
1081
|
const expressions = element.children.filter(
|
|
977
1082
|
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
978
1083
|
);
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1084
|
+
const boundExpressions = statefulOnly ? expressions.filter((child) => needsStaticBinding(child.expression)) : expressions;
|
|
1085
|
+
if (boundExpressions.length > 0) {
|
|
1086
|
+
for (const child of expressions) {
|
|
1087
|
+
const unsupported = validateDerivedExpression(
|
|
1088
|
+
child.expression,
|
|
1089
|
+
safeGlobals
|
|
1090
|
+
);
|
|
1091
|
+
if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
|
|
1092
|
+
}
|
|
982
1093
|
}
|
|
983
|
-
if (nestedElements.length > 0 &&
|
|
1094
|
+
if (nestedElements.length > 0 && boundExpressions.length > 0) {
|
|
984
1095
|
return "compiler-owned conditionals do not support dynamic text beside nested elements yet";
|
|
985
1096
|
}
|
|
986
|
-
if (nestedElements.length === 0 &&
|
|
1097
|
+
if (nestedElements.length === 0 && boundExpressions.length > 0) {
|
|
987
1098
|
const parts = [];
|
|
988
1099
|
for (const child of element.children) {
|
|
989
1100
|
if (types.isJSXText(child)) {
|
|
@@ -1007,7 +1118,369 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
|
1007
1118
|
const reason = visit(branch, []);
|
|
1008
1119
|
return reason ? { reason } : { bindings };
|
|
1009
1120
|
}
|
|
1010
|
-
function
|
|
1121
|
+
function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1122
|
+
const bindings = [];
|
|
1123
|
+
const plans = [];
|
|
1124
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
1125
|
+
const visit = (element, path, owner) => {
|
|
1126
|
+
const tag = element.openingElement.name;
|
|
1127
|
+
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
1128
|
+
return "recursive compiler-owned blocks support host elements only";
|
|
1129
|
+
}
|
|
1130
|
+
if (tag.name === "svg") return "recursive compiler-owned blocks do not support SVG yet";
|
|
1131
|
+
for (const attribute of element.openingElement.attributes) {
|
|
1132
|
+
if (types.isJSXSpreadAttribute(attribute)) {
|
|
1133
|
+
return "recursive compiler-owned blocks do not support JSX attribute spreads";
|
|
1134
|
+
}
|
|
1135
|
+
const name = jsxAttributeName(attribute);
|
|
1136
|
+
if (!name) return "recursive compiler-owned blocks do not support namespaced attributes";
|
|
1137
|
+
if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
|
|
1138
|
+
return `recursive compiler-owned block ${name} requires React ownership`;
|
|
1139
|
+
}
|
|
1140
|
+
if (/^on[A-Z]/.test(name)) {
|
|
1141
|
+
return "recursive compiler-owned block events require React ownership";
|
|
1142
|
+
}
|
|
1143
|
+
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
const expression = attribute.value.expression;
|
|
1147
|
+
if (name === "style") {
|
|
1148
|
+
if (!types.isObjectExpression(expression)) {
|
|
1149
|
+
return "recursive compiler-owned styles must use one inline object literal";
|
|
1150
|
+
}
|
|
1151
|
+
for (const property of expression.properties) {
|
|
1152
|
+
if (!types.isObjectProperty(property) || property.computed || !types.isExpression(property.value)) {
|
|
1153
|
+
return "recursive compiler-owned styles do not support spreads, methods, or computed properties";
|
|
1154
|
+
}
|
|
1155
|
+
const propertyName = types.isIdentifier(property.key) ? property.key.name : types.isStringLiteral(property.key) ? property.key.value : void 0;
|
|
1156
|
+
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
1157
|
+
return "recursive compiler-owned style names must use camelCase or a CSS custom property";
|
|
1158
|
+
}
|
|
1159
|
+
const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
|
|
1160
|
+
if (unsupported2) {
|
|
1161
|
+
return `recursive compiler-owned style ${propertyName} cannot use ${unsupported2}`;
|
|
1162
|
+
}
|
|
1163
|
+
bindings.push({
|
|
1164
|
+
kind: "style",
|
|
1165
|
+
path: [...path],
|
|
1166
|
+
name: propertyName,
|
|
1167
|
+
value: cloneExpression(property.value)
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
if (name === "children") {
|
|
1173
|
+
return "recursive compiler-owned children props are not supported yet";
|
|
1174
|
+
}
|
|
1175
|
+
const unsupported = validateDerivedExpression(expression, safeGlobals);
|
|
1176
|
+
if (unsupported) return `recursive compiler-owned ${name} cannot use ${unsupported}`;
|
|
1177
|
+
bindings.push({
|
|
1178
|
+
kind: "attribute",
|
|
1179
|
+
path: [...path],
|
|
1180
|
+
name,
|
|
1181
|
+
value: cloneExpression(expression)
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const children = meaningfulJsxChildren(element);
|
|
1185
|
+
const hasConditionalRange = children.some(
|
|
1186
|
+
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression) && conditionalBlockShape(child.expression) !== null
|
|
1187
|
+
);
|
|
1188
|
+
const hasKeyedRange = children.some(
|
|
1189
|
+
(child) => analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true) !== void 0
|
|
1190
|
+
);
|
|
1191
|
+
if (hasConditionalRange && hasKeyedRange) {
|
|
1192
|
+
const id = allocateId();
|
|
1193
|
+
const mixed = analyzeMixedRangesContainer(
|
|
1194
|
+
element,
|
|
1195
|
+
statesByValue,
|
|
1196
|
+
safeGlobals,
|
|
1197
|
+
listNames,
|
|
1198
|
+
id,
|
|
1199
|
+
allocateId
|
|
1200
|
+
);
|
|
1201
|
+
if (mixed) {
|
|
1202
|
+
plans.push(...mixed.nestedPlans);
|
|
1203
|
+
for (const [nestedElement, plan2] of mixed.descriptorBlocks) {
|
|
1204
|
+
blocks.set(nestedElement, plan2);
|
|
1205
|
+
}
|
|
1206
|
+
const plan = {
|
|
1207
|
+
kind: "nested-host-mixed-ranges",
|
|
1208
|
+
id,
|
|
1209
|
+
parent: owner,
|
|
1210
|
+
dependencies: mixed.dependencies,
|
|
1211
|
+
source: element,
|
|
1212
|
+
ranges: mixed.ranges,
|
|
1213
|
+
trailing: mixed.trailing,
|
|
1214
|
+
staticBindings: mixed.staticBindings
|
|
1215
|
+
};
|
|
1216
|
+
plans.push(plan);
|
|
1217
|
+
blocks.set(element, plan);
|
|
1218
|
+
return void 0;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
const conditionalChildren = /* @__PURE__ */ new Map();
|
|
1222
|
+
let conditionalContainer = children.length > 0;
|
|
1223
|
+
for (const child of children) {
|
|
1224
|
+
if (types.isJSXElement(child) && isHostElement(child)) continue;
|
|
1225
|
+
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1226
|
+
const shape = conditionalBlockShape(child.expression);
|
|
1227
|
+
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1228
|
+
conditionalChildren.set(child.expression, shape);
|
|
1229
|
+
continue;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
conditionalContainer = false;
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
if (conditionalContainer && conditionalChildren.size > 0) {
|
|
1236
|
+
const id = allocateId();
|
|
1237
|
+
const ranges = [];
|
|
1238
|
+
const staticBindings = [];
|
|
1239
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1240
|
+
let staticBefore2 = 0;
|
|
1241
|
+
for (const child of children) {
|
|
1242
|
+
if (types.isJSXElement(child)) {
|
|
1243
|
+
const nested = analyzeRecursiveHostTree(
|
|
1244
|
+
child,
|
|
1245
|
+
statesByValue,
|
|
1246
|
+
safeGlobals,
|
|
1247
|
+
listNames,
|
|
1248
|
+
owner,
|
|
1249
|
+
allocateId
|
|
1250
|
+
);
|
|
1251
|
+
if (nested.reason) return nested.reason;
|
|
1252
|
+
plans.push(...nested.plans);
|
|
1253
|
+
for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
|
|
1254
|
+
for (const binding of nested.bindings) {
|
|
1255
|
+
staticBindings.push({
|
|
1256
|
+
...binding,
|
|
1257
|
+
segment: ranges.length,
|
|
1258
|
+
sibling: staticBefore2
|
|
1259
|
+
});
|
|
1260
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1261
|
+
dependencies.add(dependency);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
staticBefore2 += 1;
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
if (!types.isJSXExpressionContainer(child) || types.isJSXEmptyExpression(child.expression)) {
|
|
1268
|
+
return "recursive conditional ranges contain an unsupported child";
|
|
1269
|
+
}
|
|
1270
|
+
const expression = child.expression;
|
|
1271
|
+
const shape = conditionalChildren.get(expression);
|
|
1272
|
+
const truthy = shape.truthy ? analyzeRecursiveHostTree(
|
|
1273
|
+
shape.truthy,
|
|
1274
|
+
statesByValue,
|
|
1275
|
+
safeGlobals,
|
|
1276
|
+
listNames,
|
|
1277
|
+
id,
|
|
1278
|
+
allocateId
|
|
1279
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1280
|
+
const falsy = shape.falsy ? analyzeRecursiveHostTree(
|
|
1281
|
+
shape.falsy,
|
|
1282
|
+
statesByValue,
|
|
1283
|
+
safeGlobals,
|
|
1284
|
+
listNames,
|
|
1285
|
+
id,
|
|
1286
|
+
allocateId
|
|
1287
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1288
|
+
if (truthy.reason) return truthy.reason;
|
|
1289
|
+
if (falsy.reason) return falsy.reason;
|
|
1290
|
+
plans.push(...truthy.plans, ...falsy.plans);
|
|
1291
|
+
for (const [nestedElement, plan2] of truthy.blocks) blocks.set(nestedElement, plan2);
|
|
1292
|
+
for (const [nestedElement, plan2] of falsy.blocks) blocks.set(nestedElement, plan2);
|
|
1293
|
+
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1294
|
+
dependencies.add(dependency);
|
|
1295
|
+
}
|
|
1296
|
+
for (const binding of [...truthy.bindings, ...falsy.bindings]) {
|
|
1297
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1298
|
+
dependencies.add(dependency);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
ranges.push({
|
|
1302
|
+
before: staticBefore2,
|
|
1303
|
+
source: expression,
|
|
1304
|
+
test: cloneExpression(shape.test),
|
|
1305
|
+
logical: shape.logical,
|
|
1306
|
+
truthy: shape.truthy,
|
|
1307
|
+
falsy: shape.falsy,
|
|
1308
|
+
truthyBindings: truthy.bindings,
|
|
1309
|
+
falsyBindings: falsy.bindings
|
|
1310
|
+
});
|
|
1311
|
+
staticBefore2 = 0;
|
|
1312
|
+
}
|
|
1313
|
+
const plan = {
|
|
1314
|
+
kind: "nested-host-conditional-ranges",
|
|
1315
|
+
id,
|
|
1316
|
+
parent: owner,
|
|
1317
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1318
|
+
source: element,
|
|
1319
|
+
ranges,
|
|
1320
|
+
trailing: staticBefore2,
|
|
1321
|
+
staticBindings
|
|
1322
|
+
};
|
|
1323
|
+
plans.push(plan);
|
|
1324
|
+
blocks.set(element, plan);
|
|
1325
|
+
return void 0;
|
|
1326
|
+
}
|
|
1327
|
+
const keyedRows = [];
|
|
1328
|
+
let keyedContainer = children.length > 0;
|
|
1329
|
+
let staticBefore = 0;
|
|
1330
|
+
const staticChildren = [];
|
|
1331
|
+
for (const child of children) {
|
|
1332
|
+
const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
|
|
1333
|
+
if (range) {
|
|
1334
|
+
keyedRows.push({ before: staticBefore, range });
|
|
1335
|
+
staticBefore = 0;
|
|
1336
|
+
} else if (types.isJSXElement(child) && isHostElement(child)) {
|
|
1337
|
+
staticChildren.push({
|
|
1338
|
+
element: child,
|
|
1339
|
+
segment: keyedRows.length,
|
|
1340
|
+
sibling: staticBefore
|
|
1341
|
+
});
|
|
1342
|
+
staticBefore += 1;
|
|
1343
|
+
} else {
|
|
1344
|
+
keyedContainer = false;
|
|
1345
|
+
break;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (keyedContainer && keyedRows.length > 0) {
|
|
1349
|
+
const id = allocateId();
|
|
1350
|
+
const keyedRanges = [];
|
|
1351
|
+
const staticBindings = [];
|
|
1352
|
+
const keyedDependencies = /* @__PURE__ */ new Set();
|
|
1353
|
+
for (const { before, range } of keyedRows) {
|
|
1354
|
+
if (range.events.length > 0) {
|
|
1355
|
+
return "recursive compiler-owned keyed rows cannot contain events";
|
|
1356
|
+
}
|
|
1357
|
+
const row = types.cloneNode(range.row, true);
|
|
1358
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1359
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1360
|
+
);
|
|
1361
|
+
const rowAnalysis = analyzeRecursiveHostTree(
|
|
1362
|
+
row,
|
|
1363
|
+
statesByValue,
|
|
1364
|
+
safeGlobals,
|
|
1365
|
+
listNames,
|
|
1366
|
+
id,
|
|
1367
|
+
allocateId
|
|
1368
|
+
);
|
|
1369
|
+
if (rowAnalysis.reason) return rowAnalysis.reason;
|
|
1370
|
+
plans.push(...rowAnalysis.plans);
|
|
1371
|
+
for (const [nestedElement, nestedPlan] of rowAnalysis.blocks) {
|
|
1372
|
+
blocks.set(nestedElement, nestedPlan);
|
|
1373
|
+
}
|
|
1374
|
+
keyedRanges.push({
|
|
1375
|
+
before,
|
|
1376
|
+
source: range.source,
|
|
1377
|
+
collection: range.collection,
|
|
1378
|
+
keyCallback: range.keyCallback,
|
|
1379
|
+
renderCallback: range.renderCallback,
|
|
1380
|
+
row,
|
|
1381
|
+
bindings: rowAnalysis.bindings,
|
|
1382
|
+
syntax: range.syntax
|
|
1383
|
+
});
|
|
1384
|
+
for (const dependency of range.dependencies) keyedDependencies.add(dependency);
|
|
1385
|
+
}
|
|
1386
|
+
for (const { element: child, segment, sibling } of staticChildren) {
|
|
1387
|
+
const nested = analyzeRecursiveHostTree(
|
|
1388
|
+
child,
|
|
1389
|
+
statesByValue,
|
|
1390
|
+
safeGlobals,
|
|
1391
|
+
listNames,
|
|
1392
|
+
owner,
|
|
1393
|
+
allocateId
|
|
1394
|
+
);
|
|
1395
|
+
if (nested.reason) return nested.reason;
|
|
1396
|
+
plans.push(...nested.plans);
|
|
1397
|
+
for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
|
|
1398
|
+
for (const binding of nested.bindings) {
|
|
1399
|
+
staticBindings.push({ ...binding, segment, sibling });
|
|
1400
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1401
|
+
keyedDependencies.add(dependency);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
const plan = {
|
|
1406
|
+
kind: "nested-host-keyed-ranges",
|
|
1407
|
+
id,
|
|
1408
|
+
parent: owner,
|
|
1409
|
+
dependencies: [...keyedDependencies].sort((left, right) => left - right),
|
|
1410
|
+
source: element,
|
|
1411
|
+
ranges: keyedRanges,
|
|
1412
|
+
trailing: staticBefore,
|
|
1413
|
+
staticBindings
|
|
1414
|
+
};
|
|
1415
|
+
plans.push(plan);
|
|
1416
|
+
blocks.set(element, plan);
|
|
1417
|
+
return void 0;
|
|
1418
|
+
}
|
|
1419
|
+
if (element.children.some((child) => types.isJSXFragment(child))) {
|
|
1420
|
+
return "recursive compiler-owned blocks do not support fragments yet";
|
|
1421
|
+
}
|
|
1422
|
+
const nestedElements = element.children.filter(
|
|
1423
|
+
(child) => types.isJSXElement(child)
|
|
1424
|
+
);
|
|
1425
|
+
const expressions = element.children.filter(
|
|
1426
|
+
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
1427
|
+
);
|
|
1428
|
+
for (const child of expressions) {
|
|
1429
|
+
const unsupported = validateDerivedExpression(child.expression, safeGlobals);
|
|
1430
|
+
if (unsupported) return `recursive compiler-owned text cannot use ${unsupported}`;
|
|
1431
|
+
}
|
|
1432
|
+
if (nestedElements.length > 0 && expressions.length > 0) {
|
|
1433
|
+
return "recursive compiler-owned blocks do not support dynamic text beside nested elements";
|
|
1434
|
+
}
|
|
1435
|
+
if (nestedElements.length === 0 && expressions.length > 0) {
|
|
1436
|
+
const parts = [];
|
|
1437
|
+
for (const child of element.children) {
|
|
1438
|
+
if (types.isJSXText(child)) {
|
|
1439
|
+
const text = cleanJsxText(child.value);
|
|
1440
|
+
if (text) parts.push(types.stringLiteral(text));
|
|
1441
|
+
} else if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1442
|
+
parts.push(cloneExpression(child.expression));
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
bindings.push({ kind: "text", path: [...path], value: types.arrayExpression(parts) });
|
|
1446
|
+
}
|
|
1447
|
+
let elementIndex = 0;
|
|
1448
|
+
for (const child of element.children) {
|
|
1449
|
+
if (!types.isJSXElement(child)) continue;
|
|
1450
|
+
const reason2 = visit(child, [...path, elementIndex], owner);
|
|
1451
|
+
if (reason2) return reason2;
|
|
1452
|
+
elementIndex += 1;
|
|
1453
|
+
}
|
|
1454
|
+
return void 0;
|
|
1455
|
+
};
|
|
1456
|
+
const reason = visit(branch, [], parent);
|
|
1457
|
+
return { bindings, plans, blocks, reason };
|
|
1458
|
+
}
|
|
1459
|
+
function analyzeCompilerOwnedKeyedRowHostBlocks(shape, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1460
|
+
if (shape.events.length > 0) return void 0;
|
|
1461
|
+
const row = types.cloneNode(shape.row, true);
|
|
1462
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1463
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1464
|
+
);
|
|
1465
|
+
const analysis = analyzeRecursiveHostTree(
|
|
1466
|
+
row,
|
|
1467
|
+
statesByValue,
|
|
1468
|
+
safeGlobals,
|
|
1469
|
+
listNames,
|
|
1470
|
+
parent,
|
|
1471
|
+
allocateId
|
|
1472
|
+
);
|
|
1473
|
+
if (analysis.reason || analysis.plans.length === 0) {
|
|
1474
|
+
return void 0;
|
|
1475
|
+
}
|
|
1476
|
+
return {
|
|
1477
|
+
row,
|
|
1478
|
+
bindings: analysis.bindings,
|
|
1479
|
+
descriptorBlocks: analysis.blocks,
|
|
1480
|
+
nestedPlans: analysis.plans
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function analyzeHostConditionalContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1011
1484
|
const containerName = container.openingElement.name;
|
|
1012
1485
|
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg") {
|
|
1013
1486
|
return void 0;
|
|
@@ -1029,8 +1502,22 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
|
|
|
1029
1502
|
}
|
|
1030
1503
|
const shape = conditionalBlockShape(children[0].expression);
|
|
1031
1504
|
if (!shape || validateDerivedExpression(shape.test, safeGlobals)) return void 0;
|
|
1032
|
-
const truthyAnalysis = shape.truthy ?
|
|
1033
|
-
|
|
1505
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1506
|
+
shape.truthy,
|
|
1507
|
+
statesByValue,
|
|
1508
|
+
safeGlobals,
|
|
1509
|
+
listNames,
|
|
1510
|
+
parent,
|
|
1511
|
+
allocateId
|
|
1512
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1513
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1514
|
+
shape.falsy,
|
|
1515
|
+
statesByValue,
|
|
1516
|
+
safeGlobals,
|
|
1517
|
+
listNames,
|
|
1518
|
+
parent,
|
|
1519
|
+
allocateId
|
|
1520
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1034
1521
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1035
1522
|
const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1036
1523
|
for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
|
|
@@ -1040,12 +1527,232 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
|
|
|
1040
1527
|
}
|
|
1041
1528
|
return {
|
|
1042
1529
|
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1043
|
-
test: cloneExpression(shape.test),
|
|
1044
|
-
logical: shape.logical,
|
|
1045
|
-
truthy: shape.truthy,
|
|
1046
|
-
falsy: shape.falsy,
|
|
1047
|
-
truthyBindings: truthyAnalysis.bindings || [],
|
|
1048
|
-
falsyBindings: falsyAnalysis.bindings || []
|
|
1530
|
+
test: cloneExpression(shape.test),
|
|
1531
|
+
logical: shape.logical,
|
|
1532
|
+
truthy: shape.truthy,
|
|
1533
|
+
falsy: shape.falsy,
|
|
1534
|
+
truthyBindings: truthyAnalysis.bindings || [],
|
|
1535
|
+
falsyBindings: falsyAnalysis.bindings || [],
|
|
1536
|
+
descriptorBlocks: new Map([...truthyAnalysis.blocks, ...falsyAnalysis.blocks]),
|
|
1537
|
+
nestedPlans: [...truthyAnalysis.plans, ...falsyAnalysis.plans]
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange, listNames, parent, allocateId) {
|
|
1541
|
+
const containerName = container.openingElement.name;
|
|
1542
|
+
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
|
|
1543
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
1544
|
+
)) {
|
|
1545
|
+
return void 0;
|
|
1546
|
+
}
|
|
1547
|
+
const children = meaningfulJsxChildren(container);
|
|
1548
|
+
if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
|
|
1549
|
+
const ranges = [];
|
|
1550
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1551
|
+
const descriptorBlocks = /* @__PURE__ */ new Map();
|
|
1552
|
+
const nestedPlans = [];
|
|
1553
|
+
const staticBindings = [];
|
|
1554
|
+
let staticBefore = 0;
|
|
1555
|
+
for (const child of children) {
|
|
1556
|
+
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1557
|
+
const shape = conditionalBlockShape(child.expression);
|
|
1558
|
+
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1559
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1560
|
+
shape.truthy,
|
|
1561
|
+
statesByValue,
|
|
1562
|
+
safeGlobals,
|
|
1563
|
+
listNames,
|
|
1564
|
+
parent,
|
|
1565
|
+
allocateId
|
|
1566
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1567
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1568
|
+
shape.falsy,
|
|
1569
|
+
statesByValue,
|
|
1570
|
+
safeGlobals,
|
|
1571
|
+
listNames,
|
|
1572
|
+
parent,
|
|
1573
|
+
allocateId
|
|
1574
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1575
|
+
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1576
|
+
nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
|
|
1577
|
+
for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
1578
|
+
for (const [element, plan] of falsyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
1579
|
+
const rangeDependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1580
|
+
for (const binding of [
|
|
1581
|
+
...truthyAnalysis.bindings || [],
|
|
1582
|
+
...falsyAnalysis.bindings || []
|
|
1583
|
+
]) {
|
|
1584
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1585
|
+
rangeDependencies.add(dependency);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
for (const dependency of rangeDependencies) dependencies.add(dependency);
|
|
1589
|
+
ranges.push({
|
|
1590
|
+
before: staticBefore,
|
|
1591
|
+
source: child.expression,
|
|
1592
|
+
test: cloneExpression(shape.test),
|
|
1593
|
+
logical: shape.logical,
|
|
1594
|
+
truthy: shape.truthy,
|
|
1595
|
+
falsy: shape.falsy,
|
|
1596
|
+
truthyBindings: truthyAnalysis.bindings || [],
|
|
1597
|
+
falsyBindings: falsyAnalysis.bindings || []
|
|
1598
|
+
});
|
|
1599
|
+
staticBefore = 0;
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
1604
|
+
const staticAnalysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
|
|
1605
|
+
if (staticAnalysis.reason) return void 0;
|
|
1606
|
+
for (const binding of staticAnalysis.bindings || []) {
|
|
1607
|
+
staticBindings.push({
|
|
1608
|
+
...binding,
|
|
1609
|
+
segment: ranges.length,
|
|
1610
|
+
sibling: staticBefore
|
|
1611
|
+
});
|
|
1612
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1613
|
+
dependencies.add(dependency);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
staticBefore += 1;
|
|
1617
|
+
}
|
|
1618
|
+
if (ranges.length === 0) return void 0;
|
|
1619
|
+
return {
|
|
1620
|
+
ranges,
|
|
1621
|
+
trailing: staticBefore,
|
|
1622
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1623
|
+
staticBindings,
|
|
1624
|
+
descriptorBlocks,
|
|
1625
|
+
nestedPlans
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
|
|
1629
|
+
const containerName = container.openingElement.name;
|
|
1630
|
+
if (!types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
|
|
1631
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
1632
|
+
)) {
|
|
1633
|
+
return void 0;
|
|
1634
|
+
}
|
|
1635
|
+
const children = meaningfulJsxChildren(container);
|
|
1636
|
+
if (children.length < 2) return void 0;
|
|
1637
|
+
const ranges = [];
|
|
1638
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1639
|
+
const descriptorBlocks = /* @__PURE__ */ new Map();
|
|
1640
|
+
const nestedPlans = [];
|
|
1641
|
+
const staticBindings = [];
|
|
1642
|
+
let conditionalCount = 0;
|
|
1643
|
+
let keyedCount = 0;
|
|
1644
|
+
let staticBefore = 0;
|
|
1645
|
+
const mergeAnalysis = (analysis) => {
|
|
1646
|
+
if (analysis.reason) return false;
|
|
1647
|
+
nestedPlans.push(...analysis.plans);
|
|
1648
|
+
for (const [element, plan] of analysis.blocks) descriptorBlocks.set(element, plan);
|
|
1649
|
+
for (const binding of analysis.bindings) {
|
|
1650
|
+
for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
|
|
1651
|
+
dependencies.add(dependency);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return true;
|
|
1655
|
+
};
|
|
1656
|
+
for (const child of children) {
|
|
1657
|
+
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1658
|
+
const shape = conditionalBlockShape(child.expression);
|
|
1659
|
+
if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
|
|
1660
|
+
const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
|
|
1661
|
+
shape.truthy,
|
|
1662
|
+
statesByValue,
|
|
1663
|
+
safeGlobals,
|
|
1664
|
+
listNames,
|
|
1665
|
+
parent,
|
|
1666
|
+
allocateId
|
|
1667
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1668
|
+
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1669
|
+
shape.falsy,
|
|
1670
|
+
statesByValue,
|
|
1671
|
+
safeGlobals,
|
|
1672
|
+
listNames,
|
|
1673
|
+
parent,
|
|
1674
|
+
allocateId
|
|
1675
|
+
) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
|
|
1676
|
+
if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
|
|
1677
|
+
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1678
|
+
dependencies.add(dependency);
|
|
1679
|
+
}
|
|
1680
|
+
ranges.push({
|
|
1681
|
+
rangeKind: "conditional",
|
|
1682
|
+
before: staticBefore,
|
|
1683
|
+
source: child.expression,
|
|
1684
|
+
test: cloneExpression(shape.test),
|
|
1685
|
+
logical: shape.logical,
|
|
1686
|
+
truthy: shape.truthy,
|
|
1687
|
+
falsy: shape.falsy,
|
|
1688
|
+
truthyBindings: truthyAnalysis.bindings,
|
|
1689
|
+
falsyBindings: falsyAnalysis.bindings
|
|
1690
|
+
});
|
|
1691
|
+
conditionalCount += 1;
|
|
1692
|
+
staticBefore = 0;
|
|
1693
|
+
continue;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
const keyed = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
|
|
1697
|
+
if (keyed) {
|
|
1698
|
+
if (keyed.events.length > 0) return void 0;
|
|
1699
|
+
const row = types.cloneNode(keyed.row, true);
|
|
1700
|
+
row.openingElement.attributes = row.openingElement.attributes.filter(
|
|
1701
|
+
(attribute) => !types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
|
|
1702
|
+
);
|
|
1703
|
+
const rowAnalysis = analyzeRecursiveHostTree(
|
|
1704
|
+
row,
|
|
1705
|
+
statesByValue,
|
|
1706
|
+
safeGlobals,
|
|
1707
|
+
listNames,
|
|
1708
|
+
parent,
|
|
1709
|
+
allocateId
|
|
1710
|
+
);
|
|
1711
|
+
if (!mergeAnalysis(rowAnalysis)) return void 0;
|
|
1712
|
+
for (const dependency of keyed.dependencies) dependencies.add(dependency);
|
|
1713
|
+
ranges.push({
|
|
1714
|
+
rangeKind: "keyed",
|
|
1715
|
+
before: staticBefore,
|
|
1716
|
+
source: keyed.source,
|
|
1717
|
+
collection: keyed.collection,
|
|
1718
|
+
keyCallback: keyed.keyCallback,
|
|
1719
|
+
renderCallback: keyed.renderCallback,
|
|
1720
|
+
row,
|
|
1721
|
+
bindings: rowAnalysis.bindings,
|
|
1722
|
+
syntax: keyed.syntax
|
|
1723
|
+
});
|
|
1724
|
+
keyedCount += 1;
|
|
1725
|
+
staticBefore = 0;
|
|
1726
|
+
continue;
|
|
1727
|
+
}
|
|
1728
|
+
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
1729
|
+
const staticAnalysis = analyzeRecursiveHostTree(
|
|
1730
|
+
child,
|
|
1731
|
+
statesByValue,
|
|
1732
|
+
safeGlobals,
|
|
1733
|
+
listNames,
|
|
1734
|
+
parent,
|
|
1735
|
+
allocateId
|
|
1736
|
+
);
|
|
1737
|
+
if (staticAnalysis.reason) return void 0;
|
|
1738
|
+
for (const binding of staticAnalysis.bindings) {
|
|
1739
|
+
staticBindings.push({
|
|
1740
|
+
...binding,
|
|
1741
|
+
segment: ranges.length,
|
|
1742
|
+
sibling: staticBefore
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
if (!mergeAnalysis(staticAnalysis)) return void 0;
|
|
1746
|
+
staticBefore += 1;
|
|
1747
|
+
}
|
|
1748
|
+
if (conditionalCount === 0 || keyedCount === 0) return void 0;
|
|
1749
|
+
return {
|
|
1750
|
+
ranges,
|
|
1751
|
+
trailing: staticBefore,
|
|
1752
|
+
dependencies: [...dependencies].sort((left, right) => left - right),
|
|
1753
|
+
staticBindings,
|
|
1754
|
+
descriptorBlocks,
|
|
1755
|
+
nestedPlans
|
|
1049
1756
|
};
|
|
1050
1757
|
}
|
|
1051
1758
|
function keyedListBoundary(blockRuntime, plan, source) {
|
|
@@ -1070,14 +1777,14 @@ function keyedListBoundary(blockRuntime, plan, source) {
|
|
|
1070
1777
|
true
|
|
1071
1778
|
);
|
|
1072
1779
|
}
|
|
1073
|
-
function hostElementDescriptor(element) {
|
|
1780
|
+
function hostElementDescriptor(element, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1074
1781
|
const tag = element.openingElement.name;
|
|
1075
1782
|
const attributes = [];
|
|
1076
1783
|
const styles = [];
|
|
1077
1784
|
for (const attribute of element.openingElement.attributes) {
|
|
1078
1785
|
if (!types.isJSXAttribute(attribute)) continue;
|
|
1079
1786
|
const name = jsxAttributeName(attribute);
|
|
1080
|
-
if (!name || name === "key" || /^on[A-Z]/.test(name)) continue;
|
|
1787
|
+
if (!name || name === "key" || name === "ref" || /^on[A-Z]/.test(name)) continue;
|
|
1081
1788
|
if (name === "style") {
|
|
1082
1789
|
if (types.isJSXExpressionContainer(attribute.value) && types.isObjectExpression(attribute.value.expression)) {
|
|
1083
1790
|
for (const property of attribute.value.expression.properties) {
|
|
@@ -1101,24 +1808,93 @@ function hostElementDescriptor(element) {
|
|
|
1101
1808
|
])
|
|
1102
1809
|
);
|
|
1103
1810
|
}
|
|
1811
|
+
const block = descriptorBlocks.get(element);
|
|
1812
|
+
const conditionalBySource = /* @__PURE__ */ new Map();
|
|
1813
|
+
const keyedBySource = /* @__PURE__ */ new Map();
|
|
1814
|
+
if (block?.kind === "nested-host-conditional-ranges") {
|
|
1815
|
+
for (const range of block.ranges) conditionalBySource.set(range.source, range);
|
|
1816
|
+
} else if (block?.kind === "nested-host-keyed-ranges") {
|
|
1817
|
+
for (const range of block.ranges) keyedBySource.set(range.source, range);
|
|
1818
|
+
} else if (block?.kind === "nested-host-mixed-ranges") {
|
|
1819
|
+
for (const range of block.ranges) {
|
|
1820
|
+
if (range.rangeKind === "conditional") conditionalBySource.set(range.source, range);
|
|
1821
|
+
else keyedBySource.set(range.source, range);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1104
1824
|
const children = [];
|
|
1105
1825
|
for (const child of element.children) {
|
|
1106
1826
|
if (types.isJSXText(child)) {
|
|
1107
1827
|
const text = cleanJsxText(child.value);
|
|
1108
1828
|
if (text) children.push(types.stringLiteral(text));
|
|
1109
1829
|
} else if (types.isJSXElement(child)) {
|
|
1110
|
-
|
|
1830
|
+
const keyedRange = keyedBySource.get(child);
|
|
1831
|
+
if (keyedRange) {
|
|
1832
|
+
if (block?.kind !== "nested-host-keyed-ranges") {
|
|
1833
|
+
children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
|
|
1834
|
+
}
|
|
1835
|
+
} else {
|
|
1836
|
+
children.push(hostElementDescriptor(child, descriptorBlocks));
|
|
1837
|
+
}
|
|
1111
1838
|
} else if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)) {
|
|
1112
|
-
|
|
1839
|
+
const conditionalRange = conditionalBySource.get(child.expression);
|
|
1840
|
+
const keyedRange = keyedBySource.get(child.expression);
|
|
1841
|
+
if (conditionalRange) {
|
|
1842
|
+
children.push(conditionalRangeDescriptorChild(conditionalRange, descriptorBlocks));
|
|
1843
|
+
} else if (keyedRange) {
|
|
1844
|
+
if (block?.kind !== "nested-host-keyed-ranges") {
|
|
1845
|
+
children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
|
|
1846
|
+
}
|
|
1847
|
+
} else {
|
|
1848
|
+
children.push(cloneExpression(child.expression));
|
|
1849
|
+
}
|
|
1113
1850
|
}
|
|
1114
1851
|
}
|
|
1115
|
-
|
|
1852
|
+
const properties = [
|
|
1116
1853
|
types.objectProperty(types.identifier("kind"), types.stringLiteral("element")),
|
|
1117
1854
|
types.objectProperty(types.identifier("tag"), types.stringLiteral(tag.name)),
|
|
1118
1855
|
types.objectProperty(types.identifier("attributes"), types.arrayExpression(attributes)),
|
|
1119
1856
|
types.objectProperty(types.identifier("styles"), types.arrayExpression(styles)),
|
|
1120
1857
|
types.objectProperty(types.identifier("children"), types.arrayExpression(children))
|
|
1121
|
-
]
|
|
1858
|
+
];
|
|
1859
|
+
if (block) {
|
|
1860
|
+
properties.push(
|
|
1861
|
+
types.objectProperty(types.identifier("block"), nestedHostBlockObject(block, descriptorBlocks))
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
return types.objectExpression(properties);
|
|
1865
|
+
}
|
|
1866
|
+
function conditionalRangeDescriptorChild(range, descriptorBlocks) {
|
|
1867
|
+
const truthy = range.truthy ? hostElementDescriptor(range.truthy, descriptorBlocks) : types.nullLiteral();
|
|
1868
|
+
if (range.logical) {
|
|
1869
|
+
return types.logicalExpression("&&", cloneExpression(range.test), truthy);
|
|
1870
|
+
}
|
|
1871
|
+
return types.conditionalExpression(
|
|
1872
|
+
cloneExpression(range.test),
|
|
1873
|
+
truthy,
|
|
1874
|
+
range.falsy ? hostElementDescriptor(range.falsy, descriptorBlocks) : types.nullLiteral()
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
function keyedRangeDescriptorChildren(range, descriptorBlocks) {
|
|
1878
|
+
const parameters = range.renderCallback.params.map(
|
|
1879
|
+
(parameter) => types.cloneNode(parameter, true)
|
|
1880
|
+
);
|
|
1881
|
+
const callback = types.arrowFunctionExpression(
|
|
1882
|
+
parameters,
|
|
1883
|
+
hostElementDescriptor(range.row, descriptorBlocks)
|
|
1884
|
+
);
|
|
1885
|
+
const collection = cloneExpression(range.collection);
|
|
1886
|
+
if (range.syntax === "map") {
|
|
1887
|
+
return types.callExpression(types.memberExpression(collection, types.identifier("map")), [callback]);
|
|
1888
|
+
}
|
|
1889
|
+
return types.callExpression(
|
|
1890
|
+
types.memberExpression(
|
|
1891
|
+
types.callExpression(types.memberExpression(types.identifier("Array"), types.identifier("from")), [
|
|
1892
|
+
types.logicalExpression("||", collection, types.arrayExpression([]))
|
|
1893
|
+
]),
|
|
1894
|
+
types.identifier("map")
|
|
1895
|
+
),
|
|
1896
|
+
[callback]
|
|
1897
|
+
);
|
|
1122
1898
|
}
|
|
1123
1899
|
function keyedRowBindingObject(binding, parameters) {
|
|
1124
1900
|
const properties = [
|
|
@@ -1126,6 +1902,12 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1126
1902
|
types.objectProperty(
|
|
1127
1903
|
types.identifier("path"),
|
|
1128
1904
|
types.arrayExpression(binding.path.map((part) => types.numericLiteral(part)))
|
|
1905
|
+
),
|
|
1906
|
+
types.objectProperty(
|
|
1907
|
+
types.identifier("dependencies"),
|
|
1908
|
+
types.arrayExpression(
|
|
1909
|
+
(binding.dependencies || []).map((dependency) => types.numericLiteral(dependency))
|
|
1910
|
+
)
|
|
1129
1911
|
)
|
|
1130
1912
|
];
|
|
1131
1913
|
if (binding.name) {
|
|
@@ -1142,6 +1924,16 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1142
1924
|
);
|
|
1143
1925
|
return types.objectExpression(properties);
|
|
1144
1926
|
}
|
|
1927
|
+
function staticRangeBindingObject(binding) {
|
|
1928
|
+
const value = keyedRowBindingObject(binding, []);
|
|
1929
|
+
value.properties.splice(
|
|
1930
|
+
1,
|
|
1931
|
+
0,
|
|
1932
|
+
types.objectProperty(types.identifier("segment"), types.numericLiteral(binding.segment)),
|
|
1933
|
+
types.objectProperty(types.identifier("sibling"), types.numericLiteral(binding.sibling))
|
|
1934
|
+
);
|
|
1935
|
+
return value;
|
|
1936
|
+
}
|
|
1145
1937
|
function uniqueLocalIdentifier(base, nodes) {
|
|
1146
1938
|
const names = /* @__PURE__ */ new Set();
|
|
1147
1939
|
for (const node of nodes) {
|
|
@@ -1258,6 +2050,10 @@ function keyedRowEventObject(event, renderParameters) {
|
|
|
1258
2050
|
const parameters = [types.cloneNode(renderParameters[0], true), index, syntheticEvent];
|
|
1259
2051
|
return types.objectExpression([
|
|
1260
2052
|
types.objectProperty(types.identifier("name"), types.stringLiteral(event.name)),
|
|
2053
|
+
types.objectProperty(
|
|
2054
|
+
types.identifier("path"),
|
|
2055
|
+
types.arrayExpression(event.path.map((part) => types.numericLiteral(part)))
|
|
2056
|
+
),
|
|
1261
2057
|
types.objectProperty(
|
|
1262
2058
|
types.identifier("invoke"),
|
|
1263
2059
|
types.arrowFunctionExpression(
|
|
@@ -1327,6 +2123,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1327
2123
|
plan.source,
|
|
1328
2124
|
...plan.conditionals.map((conditional) => conditional.test)
|
|
1329
2125
|
]);
|
|
2126
|
+
const delegatedEvents = canDelegateKeyedRowEvents(plan);
|
|
1330
2127
|
const renderSource = keyedRowsRenderSource(plan, eventFactory, conditionalFactory);
|
|
1331
2128
|
const renderFactoryParameters = plan.conditionals.length > 0 ? [types.cloneNode(eventFactory), types.cloneNode(conditionalFactory)] : plan.events.length > 0 ? [types.cloneNode(eventFactory)] : [];
|
|
1332
2129
|
return types.jsxElement(
|
|
@@ -1344,6 +2141,14 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1344
2141
|
types.jsxIdentifier("items"),
|
|
1345
2142
|
types.jsxExpressionContainer(types.arrowFunctionExpression([], cloneExpression(plan.collection)))
|
|
1346
2143
|
),
|
|
2144
|
+
types.jsxAttribute(
|
|
2145
|
+
types.jsxIdentifier("structureDependencies"),
|
|
2146
|
+
types.jsxExpressionContainer(
|
|
2147
|
+
types.arrayExpression(
|
|
2148
|
+
plan.structureDependencies.map((dependency) => types.numericLiteral(dependency))
|
|
2149
|
+
)
|
|
2150
|
+
)
|
|
2151
|
+
),
|
|
1347
2152
|
types.jsxAttribute(
|
|
1348
2153
|
types.jsxIdentifier("rowKey"),
|
|
1349
2154
|
types.jsxExpressionContainer(types.cloneNode(plan.keyCallback, true))
|
|
@@ -1353,7 +2158,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1353
2158
|
types.jsxExpressionContainer(
|
|
1354
2159
|
types.arrowFunctionExpression(
|
|
1355
2160
|
parameters.map((parameter) => types.cloneNode(parameter, true)),
|
|
1356
|
-
hostElementDescriptor(plan.row)
|
|
2161
|
+
hostElementDescriptor(plan.row, plan.descriptorBlocks)
|
|
1357
2162
|
)
|
|
1358
2163
|
)
|
|
1359
2164
|
),
|
|
@@ -1373,7 +2178,13 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1373
2178
|
plan.events.map((event) => keyedRowEventObject(event, parameters))
|
|
1374
2179
|
)
|
|
1375
2180
|
)
|
|
1376
|
-
)
|
|
2181
|
+
),
|
|
2182
|
+
...delegatedEvents ? [
|
|
2183
|
+
types.jsxAttribute(
|
|
2184
|
+
types.jsxIdentifier("delegateEvents"),
|
|
2185
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
2186
|
+
)
|
|
2187
|
+
] : []
|
|
1377
2188
|
] : [],
|
|
1378
2189
|
...plan.conditionals.length > 0 ? [
|
|
1379
2190
|
types.jsxAttribute(
|
|
@@ -1386,6 +2197,12 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1386
2197
|
)
|
|
1387
2198
|
)
|
|
1388
2199
|
)
|
|
2200
|
+
] : [],
|
|
2201
|
+
...plan.descriptorBlocks?.size ? [
|
|
2202
|
+
types.jsxAttribute(
|
|
2203
|
+
types.jsxIdentifier("hostBlocks"),
|
|
2204
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
2205
|
+
)
|
|
1389
2206
|
] : []
|
|
1390
2207
|
],
|
|
1391
2208
|
true
|
|
@@ -1395,7 +2212,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1395
2212
|
true
|
|
1396
2213
|
);
|
|
1397
2214
|
}
|
|
1398
|
-
function keyedRangeObject(range) {
|
|
2215
|
+
function keyedRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1399
2216
|
const parameters = range.renderCallback.params.map(
|
|
1400
2217
|
(parameter) => types.cloneNode(parameter, true)
|
|
1401
2218
|
);
|
|
@@ -1410,7 +2227,7 @@ function keyedRangeObject(range) {
|
|
|
1410
2227
|
types.identifier("create"),
|
|
1411
2228
|
types.arrowFunctionExpression(
|
|
1412
2229
|
parameters.map((parameter) => types.cloneNode(parameter, true)),
|
|
1413
|
-
hostElementDescriptor(range.row)
|
|
2230
|
+
hostElementDescriptor(range.row, descriptorBlocks)
|
|
1414
2231
|
)
|
|
1415
2232
|
),
|
|
1416
2233
|
types.objectProperty(
|
|
@@ -1454,6 +2271,12 @@ function keyedRangesBoundary(blockRuntime, plan) {
|
|
|
1454
2271
|
types.jsxAttribute(
|
|
1455
2272
|
types.jsxIdentifier("trailing"),
|
|
1456
2273
|
types.jsxExpressionContainer(types.numericLiteral(plan.trailing))
|
|
2274
|
+
),
|
|
2275
|
+
types.jsxAttribute(
|
|
2276
|
+
types.jsxIdentifier("bindings"),
|
|
2277
|
+
types.jsxExpressionContainer(
|
|
2278
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2279
|
+
)
|
|
1457
2280
|
)
|
|
1458
2281
|
],
|
|
1459
2282
|
true
|
|
@@ -1463,11 +2286,11 @@ function keyedRangesBoundary(blockRuntime, plan) {
|
|
|
1463
2286
|
true
|
|
1464
2287
|
);
|
|
1465
2288
|
}
|
|
1466
|
-
function hostConditionalBranchObject(branch, bindings) {
|
|
2289
|
+
function hostConditionalBranchObject(branch, bindings, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
1467
2290
|
return types.objectExpression([
|
|
1468
2291
|
types.objectProperty(
|
|
1469
2292
|
types.identifier("create"),
|
|
1470
|
-
types.arrowFunctionExpression([], hostElementDescriptor(branch))
|
|
2293
|
+
types.arrowFunctionExpression([], hostElementDescriptor(branch, descriptorBlocks))
|
|
1471
2294
|
),
|
|
1472
2295
|
types.objectProperty(
|
|
1473
2296
|
types.identifier("bindings"),
|
|
@@ -1496,7 +2319,9 @@ function hostConditionalBoundary(blockRuntime, plan) {
|
|
|
1496
2319
|
attributes.push(
|
|
1497
2320
|
types.jsxAttribute(
|
|
1498
2321
|
types.jsxIdentifier("truthy"),
|
|
1499
|
-
types.jsxExpressionContainer(
|
|
2322
|
+
types.jsxExpressionContainer(
|
|
2323
|
+
hostConditionalBranchObject(plan.truthy, plan.truthyBindings, plan.descriptorBlocks)
|
|
2324
|
+
)
|
|
1500
2325
|
)
|
|
1501
2326
|
);
|
|
1502
2327
|
}
|
|
@@ -1504,10 +2329,147 @@ function hostConditionalBoundary(blockRuntime, plan) {
|
|
|
1504
2329
|
attributes.push(
|
|
1505
2330
|
types.jsxAttribute(
|
|
1506
2331
|
types.jsxIdentifier("falsy"),
|
|
1507
|
-
types.jsxExpressionContainer(
|
|
2332
|
+
types.jsxExpressionContainer(
|
|
2333
|
+
hostConditionalBranchObject(plan.falsy, plan.falsyBindings, plan.descriptorBlocks)
|
|
2334
|
+
)
|
|
2335
|
+
)
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
2339
|
+
}
|
|
2340
|
+
function conditionalRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
|
|
2341
|
+
const properties = [
|
|
2342
|
+
types.objectProperty(types.identifier("before"), types.numericLiteral(range.before)),
|
|
2343
|
+
types.objectProperty(
|
|
2344
|
+
types.identifier("test"),
|
|
2345
|
+
types.arrowFunctionExpression([], cloneExpression(range.test))
|
|
2346
|
+
)
|
|
2347
|
+
];
|
|
2348
|
+
if (range.logical) {
|
|
2349
|
+
properties.push(types.objectProperty(types.identifier("logical"), types.booleanLiteral(true)));
|
|
2350
|
+
}
|
|
2351
|
+
if (range.truthy) {
|
|
2352
|
+
properties.push(
|
|
2353
|
+
types.objectProperty(
|
|
2354
|
+
types.identifier("truthy"),
|
|
2355
|
+
hostConditionalBranchObject(range.truthy, range.truthyBindings, descriptorBlocks)
|
|
2356
|
+
)
|
|
2357
|
+
);
|
|
2358
|
+
}
|
|
2359
|
+
if (range.falsy) {
|
|
2360
|
+
properties.push(
|
|
2361
|
+
types.objectProperty(
|
|
2362
|
+
types.identifier("falsy"),
|
|
2363
|
+
hostConditionalBranchObject(range.falsy, range.falsyBindings, descriptorBlocks)
|
|
1508
2364
|
)
|
|
1509
2365
|
);
|
|
1510
2366
|
}
|
|
2367
|
+
return types.objectExpression(properties);
|
|
2368
|
+
}
|
|
2369
|
+
function nestedHostBlockObject(plan, descriptorBlocks) {
|
|
2370
|
+
const kind = plan.kind === "nested-host-conditional-ranges" ? "conditional-ranges" : plan.kind === "nested-host-keyed-ranges" ? "keyed-ranges" : "mixed-ranges";
|
|
2371
|
+
return types.objectExpression([
|
|
2372
|
+
types.objectProperty(types.identifier("kind"), types.stringLiteral(kind)),
|
|
2373
|
+
types.objectProperty(types.identifier("id"), types.numericLiteral(plan.id)),
|
|
2374
|
+
types.objectProperty(
|
|
2375
|
+
types.identifier("ranges"),
|
|
2376
|
+
types.arrayExpression(
|
|
2377
|
+
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))
|
|
2378
|
+
)
|
|
2379
|
+
),
|
|
2380
|
+
types.objectProperty(types.identifier("trailing"), types.numericLiteral(plan.trailing)),
|
|
2381
|
+
types.objectProperty(
|
|
2382
|
+
types.identifier("bindings"),
|
|
2383
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2384
|
+
),
|
|
2385
|
+
...plan.kind === "nested-host-keyed-ranges" ? [types.objectProperty(types.identifier("staticChildrenOnly"), types.booleanLiteral(true))] : []
|
|
2386
|
+
]);
|
|
2387
|
+
}
|
|
2388
|
+
function mixedRangeObject(range, descriptorBlocks) {
|
|
2389
|
+
const value = range.rangeKind === "conditional" ? conditionalRangeObject(range, descriptorBlocks) : keyedRangeObject(range, descriptorBlocks);
|
|
2390
|
+
value.properties.unshift(
|
|
2391
|
+
types.objectProperty(types.identifier("kind"), types.stringLiteral(range.rangeKind))
|
|
2392
|
+
);
|
|
2393
|
+
return value;
|
|
2394
|
+
}
|
|
2395
|
+
function mixedRangesBoundary(blockRuntime, plan) {
|
|
2396
|
+
const name = types.jsxMemberExpression(
|
|
2397
|
+
types.jsxIdentifier(blockRuntime.name),
|
|
2398
|
+
types.jsxIdentifier("MixedRanges")
|
|
2399
|
+
);
|
|
2400
|
+
const source = types.cloneNode(plan.source, true);
|
|
2401
|
+
const rootRefIndex = source.openingElement.attributes.findIndex(
|
|
2402
|
+
(attribute) => types.isJSXAttribute(attribute) && jsxAttributeName(attribute) === "ref"
|
|
2403
|
+
);
|
|
2404
|
+
const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
|
|
2405
|
+
const nestedPlan = {
|
|
2406
|
+
kind: "nested-host-mixed-ranges",
|
|
2407
|
+
id: plan.id,
|
|
2408
|
+
parent: plan.parent,
|
|
2409
|
+
dependencies: plan.dependencies,
|
|
2410
|
+
source: plan.source,
|
|
2411
|
+
ranges: plan.ranges,
|
|
2412
|
+
trailing: plan.trailing,
|
|
2413
|
+
staticBindings: plan.staticBindings
|
|
2414
|
+
};
|
|
2415
|
+
const descriptorBlocks = new Map(plan.descriptorBlocks);
|
|
2416
|
+
descriptorBlocks.set(plan.source, nestedPlan);
|
|
2417
|
+
const attributes = [
|
|
2418
|
+
types.jsxAttribute(types.jsxIdentifier("id"), types.jsxExpressionContainer(types.numericLiteral(plan.id))),
|
|
2419
|
+
types.jsxAttribute(
|
|
2420
|
+
types.jsxIdentifier("render"),
|
|
2421
|
+
types.jsxExpressionContainer(types.arrowFunctionExpression([], source))
|
|
2422
|
+
),
|
|
2423
|
+
types.jsxAttribute(
|
|
2424
|
+
types.jsxIdentifier("create"),
|
|
2425
|
+
types.jsxExpressionContainer(
|
|
2426
|
+
types.arrowFunctionExpression([], hostElementDescriptor(plan.source, descriptorBlocks))
|
|
2427
|
+
)
|
|
2428
|
+
)
|
|
2429
|
+
];
|
|
2430
|
+
if (rootRef?.value) {
|
|
2431
|
+
attributes.push(types.jsxAttribute(types.jsxIdentifier("rootRef"), types.cloneNode(rootRef.value, true)));
|
|
2432
|
+
}
|
|
2433
|
+
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
2434
|
+
}
|
|
2435
|
+
function conditionalRangesBoundary(blockRuntime, plan) {
|
|
2436
|
+
const name = types.jsxMemberExpression(
|
|
2437
|
+
types.jsxIdentifier(blockRuntime.name),
|
|
2438
|
+
types.jsxIdentifier("ConditionalRanges")
|
|
2439
|
+
);
|
|
2440
|
+
const source = types.cloneNode(plan.source, true);
|
|
2441
|
+
const rootRefIndex = source.openingElement.attributes.findIndex(
|
|
2442
|
+
(attribute) => types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && attribute.name.name === "ref"
|
|
2443
|
+
);
|
|
2444
|
+
const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
|
|
2445
|
+
const attributes = [
|
|
2446
|
+
types.jsxAttribute(types.jsxIdentifier("id"), types.jsxExpressionContainer(types.numericLiteral(plan.id))),
|
|
2447
|
+
types.jsxAttribute(
|
|
2448
|
+
types.jsxIdentifier("render"),
|
|
2449
|
+
types.jsxExpressionContainer(types.arrowFunctionExpression([], source))
|
|
2450
|
+
),
|
|
2451
|
+
types.jsxAttribute(
|
|
2452
|
+
types.jsxIdentifier("ranges"),
|
|
2453
|
+
types.jsxExpressionContainer(
|
|
2454
|
+
types.arrayExpression(
|
|
2455
|
+
plan.ranges.map((range) => conditionalRangeObject(range, plan.descriptorBlocks))
|
|
2456
|
+
)
|
|
2457
|
+
)
|
|
2458
|
+
),
|
|
2459
|
+
types.jsxAttribute(
|
|
2460
|
+
types.jsxIdentifier("trailing"),
|
|
2461
|
+
types.jsxExpressionContainer(types.numericLiteral(plan.trailing))
|
|
2462
|
+
),
|
|
2463
|
+
types.jsxAttribute(
|
|
2464
|
+
types.jsxIdentifier("bindings"),
|
|
2465
|
+
types.jsxExpressionContainer(
|
|
2466
|
+
types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
|
|
2467
|
+
)
|
|
2468
|
+
)
|
|
2469
|
+
];
|
|
2470
|
+
if (rootRef?.value) {
|
|
2471
|
+
attributes.push(types.jsxAttribute(types.jsxIdentifier("rootRef"), types.cloneNode(rootRef.value, true)));
|
|
2472
|
+
}
|
|
1511
2473
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
1512
2474
|
}
|
|
1513
2475
|
function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allowedComponentNames) {
|
|
@@ -1675,6 +2637,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1675
2637
|
}
|
|
1676
2638
|
if (types.isJSXElement(child)) {
|
|
1677
2639
|
if (isHostElement(child)) {
|
|
2640
|
+
const mixedRangeStart = nextId;
|
|
2641
|
+
const mixedRangeId = nextId++;
|
|
2642
|
+
const mixedRanges = insideConditional ? void 0 : analyzeMixedRangesContainer(
|
|
2643
|
+
child,
|
|
2644
|
+
statesByValue,
|
|
2645
|
+
safeGlobals,
|
|
2646
|
+
listNames,
|
|
2647
|
+
mixedRangeId,
|
|
2648
|
+
() => nextId++
|
|
2649
|
+
);
|
|
2650
|
+
if (mixedRanges) {
|
|
2651
|
+
plans.push({
|
|
2652
|
+
kind: "mixed-ranges",
|
|
2653
|
+
id: mixedRangeId,
|
|
2654
|
+
parent,
|
|
2655
|
+
dependencies: mixedRanges.dependencies,
|
|
2656
|
+
source: child,
|
|
2657
|
+
ranges: mixedRanges.ranges,
|
|
2658
|
+
trailing: mixedRanges.trailing,
|
|
2659
|
+
staticBindings: mixedRanges.staticBindings,
|
|
2660
|
+
descriptorBlocks: mixedRanges.descriptorBlocks
|
|
2661
|
+
});
|
|
2662
|
+
plans.push(...mixedRanges.nestedPlans);
|
|
2663
|
+
for (const range of mixedRanges.ranges) {
|
|
2664
|
+
if (range.rangeKind === "conditional") {
|
|
2665
|
+
conditionalExpressions.add(range.source);
|
|
2666
|
+
} else if (types.isJSXElement(range.source)) {
|
|
2667
|
+
ownedElements.add(range.source);
|
|
2668
|
+
} else {
|
|
2669
|
+
keyedExpressions.add(range.source);
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
nextId = mixedRangeStart;
|
|
1678
2675
|
const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
|
|
1679
2676
|
if (keyedRanges) {
|
|
1680
2677
|
plans.push({
|
|
@@ -1684,7 +2681,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1684
2681
|
dependencies: keyedRanges.dependencies,
|
|
1685
2682
|
source: child,
|
|
1686
2683
|
ranges: keyedRanges.ranges,
|
|
1687
|
-
trailing: keyedRanges.trailing
|
|
2684
|
+
trailing: keyedRanges.trailing,
|
|
2685
|
+
staticBindings: keyedRanges.staticBindings
|
|
1688
2686
|
});
|
|
1689
2687
|
for (const range of keyedRanges.ranges) {
|
|
1690
2688
|
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
@@ -1692,42 +2690,102 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1692
2690
|
}
|
|
1693
2691
|
continue;
|
|
1694
2692
|
}
|
|
2693
|
+
const conditionalRangeStart = nextId;
|
|
2694
|
+
const conditionalRangeId = nextId++;
|
|
2695
|
+
const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(
|
|
2696
|
+
child,
|
|
2697
|
+
statesByValue,
|
|
2698
|
+
safeGlobals,
|
|
2699
|
+
false,
|
|
2700
|
+
listNames,
|
|
2701
|
+
conditionalRangeId,
|
|
2702
|
+
() => nextId++
|
|
2703
|
+
);
|
|
2704
|
+
if (conditionalRanges) {
|
|
2705
|
+
plans.push({
|
|
2706
|
+
kind: "conditional-ranges",
|
|
2707
|
+
id: conditionalRangeId,
|
|
2708
|
+
parent,
|
|
2709
|
+
dependencies: conditionalRanges.dependencies,
|
|
2710
|
+
source: child,
|
|
2711
|
+
ranges: conditionalRanges.ranges,
|
|
2712
|
+
trailing: conditionalRanges.trailing,
|
|
2713
|
+
staticBindings: conditionalRanges.staticBindings,
|
|
2714
|
+
descriptorBlocks: conditionalRanges.descriptorBlocks
|
|
2715
|
+
});
|
|
2716
|
+
plans.push(...conditionalRanges.nestedPlans || []);
|
|
2717
|
+
for (const range of conditionalRanges.ranges) {
|
|
2718
|
+
conditionalExpressions.add(range.source);
|
|
2719
|
+
}
|
|
2720
|
+
continue;
|
|
2721
|
+
}
|
|
2722
|
+
nextId = conditionalRangeStart;
|
|
2723
|
+
const hostConditionalStart = nextId;
|
|
2724
|
+
const hostConditionalId = nextId++;
|
|
1695
2725
|
const hostConditional = analyzeHostConditionalContainer(
|
|
1696
2726
|
child,
|
|
1697
2727
|
statesByValue,
|
|
1698
|
-
safeGlobals
|
|
2728
|
+
safeGlobals,
|
|
2729
|
+
listNames,
|
|
2730
|
+
hostConditionalId,
|
|
2731
|
+
() => nextId++
|
|
1699
2732
|
);
|
|
1700
2733
|
if (hostConditional) {
|
|
1701
2734
|
plans.push({
|
|
1702
2735
|
kind: "host-conditional",
|
|
1703
|
-
id:
|
|
2736
|
+
id: hostConditionalId,
|
|
1704
2737
|
parent,
|
|
1705
2738
|
source: child,
|
|
1706
2739
|
...hostConditional
|
|
1707
2740
|
});
|
|
2741
|
+
plans.push(...hostConditional.nestedPlans || []);
|
|
1708
2742
|
ownedElements.add(child);
|
|
1709
2743
|
continue;
|
|
1710
2744
|
}
|
|
2745
|
+
nextId = hostConditionalStart;
|
|
2746
|
+
const keyedRowsStart = nextId;
|
|
2747
|
+
const keyedRowsId = nextId++;
|
|
1711
2748
|
const keyedRows = analyzeKeyedRowsContainer(child, statesByValue, safeGlobals, listNames);
|
|
1712
2749
|
if (keyedRows) {
|
|
2750
|
+
const nestedStart = nextId;
|
|
2751
|
+
const hostBlocks = analyzeCompilerOwnedKeyedRowHostBlocks(
|
|
2752
|
+
keyedRows,
|
|
2753
|
+
statesByValue,
|
|
2754
|
+
safeGlobals,
|
|
2755
|
+
listNames,
|
|
2756
|
+
keyedRowsId,
|
|
2757
|
+
() => nextId++
|
|
2758
|
+
);
|
|
2759
|
+
if (!hostBlocks) nextId = nestedStart;
|
|
2760
|
+
if (keyedRows.rowReason && !hostBlocks) {
|
|
2761
|
+
nextId = keyedRowsStart;
|
|
2762
|
+
const nested2 = visitHost(child, parent, insideConditional);
|
|
2763
|
+
if (nested2.reason) return { dependencies, reason: nested2.reason };
|
|
2764
|
+
mergeDependencies(dependencies, nested2.dependencies);
|
|
2765
|
+
continue;
|
|
2766
|
+
}
|
|
1713
2767
|
plans.push({
|
|
1714
2768
|
kind: "keyed-rows",
|
|
1715
|
-
id:
|
|
2769
|
+
id: keyedRowsId,
|
|
1716
2770
|
parent,
|
|
1717
2771
|
dependencies: keyedRows.dependencies,
|
|
1718
2772
|
source: child,
|
|
1719
2773
|
collection: keyedRows.collection,
|
|
2774
|
+
structureDependencies: keyedRows.structureDependencies,
|
|
1720
2775
|
keyCallback: keyedRows.keyCallback,
|
|
1721
2776
|
renderCallback: keyedRows.renderCallback,
|
|
1722
|
-
row: keyedRows.row,
|
|
1723
|
-
bindings: keyedRows.bindings,
|
|
2777
|
+
row: hostBlocks?.row || keyedRows.row,
|
|
2778
|
+
bindings: hostBlocks?.bindings || keyedRows.bindings,
|
|
1724
2779
|
events: keyedRows.events,
|
|
1725
|
-
conditionals: keyedRows.conditionals,
|
|
2780
|
+
conditionals: hostBlocks ? [] : keyedRows.conditionals,
|
|
2781
|
+
descriptorBlocks: hostBlocks?.descriptorBlocks,
|
|
1726
2782
|
syntax: keyedRows.syntax
|
|
1727
2783
|
});
|
|
2784
|
+
plans.push(...hostBlocks?.nestedPlans || []);
|
|
1728
2785
|
ownedElements.add(child);
|
|
1729
2786
|
continue;
|
|
1730
2787
|
}
|
|
2788
|
+
nextId = keyedRowsStart;
|
|
1731
2789
|
const nested = visitHost(child, parent, insideConditional);
|
|
1732
2790
|
if (nested.reason) return { dependencies, reason: nested.reason };
|
|
1733
2791
|
mergeDependencies(dependencies, nested.dependencies);
|
|
@@ -1824,6 +2882,46 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1824
2882
|
}
|
|
1825
2883
|
return { dependencies };
|
|
1826
2884
|
};
|
|
2885
|
+
const rootMixedRangeStart = nextId;
|
|
2886
|
+
const rootMixedRangeId = nextId++;
|
|
2887
|
+
const rootMixedRanges = analyzeMixedRangesContainer(
|
|
2888
|
+
root,
|
|
2889
|
+
statesByValue,
|
|
2890
|
+
safeGlobals,
|
|
2891
|
+
listNames,
|
|
2892
|
+
rootMixedRangeId,
|
|
2893
|
+
() => nextId++
|
|
2894
|
+
);
|
|
2895
|
+
if (rootMixedRanges) {
|
|
2896
|
+
plans.push({
|
|
2897
|
+
kind: "mixed-ranges",
|
|
2898
|
+
id: rootMixedRangeId,
|
|
2899
|
+
dependencies: rootMixedRanges.dependencies,
|
|
2900
|
+
source: root,
|
|
2901
|
+
ranges: rootMixedRanges.ranges,
|
|
2902
|
+
trailing: rootMixedRanges.trailing,
|
|
2903
|
+
staticBindings: rootMixedRanges.staticBindings,
|
|
2904
|
+
descriptorBlocks: rootMixedRanges.descriptorBlocks
|
|
2905
|
+
});
|
|
2906
|
+
plans.push(...rootMixedRanges.nestedPlans);
|
|
2907
|
+
for (const range of rootMixedRanges.ranges) {
|
|
2908
|
+
if (range.rangeKind === "conditional") {
|
|
2909
|
+
conditionalExpressions.add(range.source);
|
|
2910
|
+
} else if (types.isJSXElement(range.source)) {
|
|
2911
|
+
ownedElements.add(range.source);
|
|
2912
|
+
} else {
|
|
2913
|
+
keyedExpressions.add(range.source);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
return {
|
|
2917
|
+
plans,
|
|
2918
|
+
componentElements,
|
|
2919
|
+
conditionalExpressions,
|
|
2920
|
+
ownedElements,
|
|
2921
|
+
keyedExpressions
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
nextId = rootMixedRangeStart;
|
|
1827
2925
|
const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
|
|
1828
2926
|
if (rootRanges) {
|
|
1829
2927
|
plans.push({
|
|
@@ -1832,7 +2930,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1832
2930
|
dependencies: rootRanges.dependencies,
|
|
1833
2931
|
source: root,
|
|
1834
2932
|
ranges: rootRanges.ranges,
|
|
1835
|
-
trailing: rootRanges.trailing
|
|
2933
|
+
trailing: rootRanges.trailing,
|
|
2934
|
+
staticBindings: rootRanges.staticBindings
|
|
1836
2935
|
});
|
|
1837
2936
|
for (const range of rootRanges.ranges) {
|
|
1838
2937
|
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
@@ -1846,6 +2945,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1846
2945
|
keyedExpressions
|
|
1847
2946
|
};
|
|
1848
2947
|
}
|
|
2948
|
+
const rootConditionalRangeStart = nextId;
|
|
2949
|
+
const rootConditionalRangeId = nextId++;
|
|
2950
|
+
const rootConditionalRanges = analyzeConditionalRangesContainer(
|
|
2951
|
+
root,
|
|
2952
|
+
statesByValue,
|
|
2953
|
+
safeGlobals,
|
|
2954
|
+
true,
|
|
2955
|
+
listNames,
|
|
2956
|
+
rootConditionalRangeId,
|
|
2957
|
+
() => nextId++
|
|
2958
|
+
);
|
|
2959
|
+
if (rootConditionalRanges) {
|
|
2960
|
+
plans.push({
|
|
2961
|
+
kind: "conditional-ranges",
|
|
2962
|
+
id: rootConditionalRangeId,
|
|
2963
|
+
dependencies: rootConditionalRanges.dependencies,
|
|
2964
|
+
source: root,
|
|
2965
|
+
ranges: rootConditionalRanges.ranges,
|
|
2966
|
+
trailing: rootConditionalRanges.trailing,
|
|
2967
|
+
staticBindings: rootConditionalRanges.staticBindings,
|
|
2968
|
+
descriptorBlocks: rootConditionalRanges.descriptorBlocks
|
|
2969
|
+
});
|
|
2970
|
+
plans.push(...rootConditionalRanges.nestedPlans || []);
|
|
2971
|
+
for (const range of rootConditionalRanges.ranges) {
|
|
2972
|
+
conditionalExpressions.add(range.source);
|
|
2973
|
+
}
|
|
2974
|
+
return {
|
|
2975
|
+
plans,
|
|
2976
|
+
componentElements,
|
|
2977
|
+
conditionalExpressions,
|
|
2978
|
+
ownedElements,
|
|
2979
|
+
keyedExpressions
|
|
2980
|
+
};
|
|
2981
|
+
}
|
|
2982
|
+
nextId = rootConditionalRangeStart;
|
|
1849
2983
|
const result = visitHost(root, void 0, false);
|
|
1850
2984
|
if (result.reason) return { reason: result.reason };
|
|
1851
2985
|
return {
|
|
@@ -1883,9 +3017,15 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
1883
3017
|
plans.map((plan) => [plan.source, plan])
|
|
1884
3018
|
);
|
|
1885
3019
|
const rootPlan = planBySource.get(root);
|
|
3020
|
+
if (rootPlan?.kind === "mixed-ranges") {
|
|
3021
|
+
return mixedRangesBoundary(blockRuntime, rootPlan);
|
|
3022
|
+
}
|
|
1886
3023
|
if (rootPlan?.kind === "keyed-ranges") {
|
|
1887
3024
|
return keyedRangesBoundary(blockRuntime, rootPlan);
|
|
1888
3025
|
}
|
|
3026
|
+
if (rootPlan?.kind === "conditional-ranges") {
|
|
3027
|
+
return conditionalRangesBoundary(blockRuntime, rootPlan);
|
|
3028
|
+
}
|
|
1889
3029
|
const visit = (element) => {
|
|
1890
3030
|
element.children = element.children.map((child) => {
|
|
1891
3031
|
if (types.isJSXElement(child)) {
|
|
@@ -1893,12 +3033,18 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
1893
3033
|
if (plan2?.kind === "host-conditional") {
|
|
1894
3034
|
return hostConditionalBoundary(blockRuntime, plan2);
|
|
1895
3035
|
}
|
|
3036
|
+
if (plan2?.kind === "mixed-ranges") {
|
|
3037
|
+
return mixedRangesBoundary(blockRuntime, plan2);
|
|
3038
|
+
}
|
|
1896
3039
|
if (plan2?.kind === "keyed-rows") {
|
|
1897
3040
|
return keyedRowsBoundary(blockRuntime, plan2);
|
|
1898
3041
|
}
|
|
1899
3042
|
if (plan2?.kind === "keyed-ranges") {
|
|
1900
3043
|
return keyedRangesBoundary(blockRuntime, plan2);
|
|
1901
3044
|
}
|
|
3045
|
+
if (plan2?.kind === "conditional-ranges") {
|
|
3046
|
+
return conditionalRangesBoundary(blockRuntime, plan2);
|
|
3047
|
+
}
|
|
1902
3048
|
if (plan2?.kind === "component") {
|
|
1903
3049
|
return componentIslandBoundary(blockRuntime, plan2, child);
|
|
1904
3050
|
}
|
|
@@ -1939,6 +3085,31 @@ function assignStableBindingTargets(bindings) {
|
|
|
1939
3085
|
binding.target = target;
|
|
1940
3086
|
}
|
|
1941
3087
|
}
|
|
3088
|
+
function markShortCircuitBindings(bindings) {
|
|
3089
|
+
for (const binding of bindings) {
|
|
3090
|
+
if (binding.kind === "block" || binding.dependencies.length < 2) continue;
|
|
3091
|
+
let shortCircuits = false;
|
|
3092
|
+
traverse(expressionFile(types.cloneNode(binding.value, true)), {
|
|
3093
|
+
ConditionalExpression(path) {
|
|
3094
|
+
shortCircuits = true;
|
|
3095
|
+
path.stop();
|
|
3096
|
+
},
|
|
3097
|
+
LogicalExpression(path) {
|
|
3098
|
+
shortCircuits = true;
|
|
3099
|
+
path.stop();
|
|
3100
|
+
},
|
|
3101
|
+
OptionalCallExpression(path) {
|
|
3102
|
+
shortCircuits = true;
|
|
3103
|
+
path.stop();
|
|
3104
|
+
},
|
|
3105
|
+
OptionalMemberExpression(path) {
|
|
3106
|
+
shortCircuits = true;
|
|
3107
|
+
path.stop();
|
|
3108
|
+
}
|
|
3109
|
+
});
|
|
3110
|
+
if (shortCircuits) binding.tracking = "dynamic";
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
1942
3113
|
function lowerStableBindingTargets(root, bindings, blockRuntime, ownedElements) {
|
|
1943
3114
|
const targetByPath = /* @__PURE__ */ new Map();
|
|
1944
3115
|
for (const binding of bindings) {
|
|
@@ -2208,6 +3379,9 @@ function bindingObject(binding, propsParameter, stateParameter, statesByValue, s
|
|
|
2208
3379
|
types.objectProperty(types.identifier("target"), types.numericLiteral(binding.target))
|
|
2209
3380
|
);
|
|
2210
3381
|
}
|
|
3382
|
+
if (binding.tracking) {
|
|
3383
|
+
properties.push(types.objectProperty(types.identifier("tracking"), types.stringLiteral(binding.tracking)));
|
|
3384
|
+
}
|
|
2211
3385
|
if (binding.name)
|
|
2212
3386
|
properties.push(types.objectProperty(types.identifier("name"), types.stringLiteral(binding.name)));
|
|
2213
3387
|
properties.push(
|
|
@@ -2226,7 +3400,7 @@ function wrapperElement(definitionIdentifier, props) {
|
|
|
2226
3400
|
const attributes = props ? [types.jsxSpreadAttribute(types.cloneNode(props))] : [];
|
|
2227
3401
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
2228
3402
|
}
|
|
2229
|
-
function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId) {
|
|
3403
|
+
function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId, reactivity) {
|
|
2230
3404
|
const { path, name, statementPath } = candidate;
|
|
2231
3405
|
if (path.node.async || path.node.generator)
|
|
2232
3406
|
return "async and generator components are not supported";
|
|
@@ -2343,8 +3517,34 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2343
3517
|
);
|
|
2344
3518
|
const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
|
|
2345
3519
|
if (setterReason) return setterReason;
|
|
3520
|
+
const referencedPropNames = collectDestructuredPropNames(
|
|
3521
|
+
expandedRoot,
|
|
3522
|
+
propsPlan.destructuredNames,
|
|
3523
|
+
propsPlan.definitionParameter
|
|
3524
|
+
);
|
|
3525
|
+
let propBindings = referencedPropNames.has("children") ? [] : [...propsPlan.destructuredNames].filter((propName) => referencedPropNames.has(propName)).map(
|
|
3526
|
+
(localName, propIndex) => ({
|
|
3527
|
+
localName,
|
|
3528
|
+
valueName: path.scope.generateUidIdentifier(`farmProp${propIndex}`).name,
|
|
3529
|
+
index: states.length + propIndex
|
|
3530
|
+
})
|
|
3531
|
+
);
|
|
3532
|
+
const propBindingsByName = new Map(propBindings.map((binding) => [binding.localName, binding]));
|
|
3533
|
+
let reactiveByValue = new Map(statesByValue);
|
|
3534
|
+
for (const binding of propBindings) {
|
|
3535
|
+
reactiveByValue.set(binding.valueName, {
|
|
3536
|
+
valueName: binding.valueName,
|
|
3537
|
+
setterName: "",
|
|
3538
|
+
index: binding.index
|
|
3539
|
+
});
|
|
3540
|
+
}
|
|
3541
|
+
let expandedReactiveRoot = rewriteTrackedPropAccess(
|
|
3542
|
+
expandedRoot,
|
|
3543
|
+
propsPlan.definitionParameter,
|
|
3544
|
+
propBindingsByName
|
|
3545
|
+
);
|
|
2346
3546
|
const referencedComponentNames = /* @__PURE__ */ new Set();
|
|
2347
|
-
traverse(expressionFile(types.cloneNode(
|
|
3547
|
+
traverse(expressionFile(types.cloneNode(expandedReactiveRoot, true)), {
|
|
2348
3548
|
JSXOpeningElement(componentPath) {
|
|
2349
3549
|
const componentName = componentPath.node.name;
|
|
2350
3550
|
if (types.isJSXIdentifier(componentName) && isComponentName(componentName.name)) {
|
|
@@ -2361,32 +3561,54 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2361
3561
|
);
|
|
2362
3562
|
})
|
|
2363
3563
|
);
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
3564
|
+
let blockAnalysis = analyzeComposableBlocks(
|
|
3565
|
+
expandedReactiveRoot,
|
|
3566
|
+
reactiveByValue,
|
|
2367
3567
|
safeGlobals,
|
|
2368
3568
|
listNames,
|
|
2369
3569
|
allowedComponentNames
|
|
2370
3570
|
);
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
expandedRoot,
|
|
2375
|
-
statesByValue,
|
|
3571
|
+
let analysis = analyzeHostTree(
|
|
3572
|
+
expandedReactiveRoot,
|
|
3573
|
+
reactiveByValue,
|
|
2376
3574
|
safeGlobals,
|
|
2377
3575
|
blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
2378
3576
|
blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
2379
3577
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
2380
3578
|
blockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
2381
3579
|
);
|
|
3580
|
+
if (propBindings.length > 0 && (blockAnalysis.reason || analysis.reason)) {
|
|
3581
|
+
propBindings = [];
|
|
3582
|
+
reactiveByValue = new Map(statesByValue);
|
|
3583
|
+
expandedReactiveRoot = types.cloneNode(expandedRoot, true);
|
|
3584
|
+
blockAnalysis = analyzeComposableBlocks(
|
|
3585
|
+
expandedReactiveRoot,
|
|
3586
|
+
reactiveByValue,
|
|
3587
|
+
safeGlobals,
|
|
3588
|
+
listNames,
|
|
3589
|
+
allowedComponentNames
|
|
3590
|
+
);
|
|
3591
|
+
analysis = analyzeHostTree(
|
|
3592
|
+
expandedReactiveRoot,
|
|
3593
|
+
reactiveByValue,
|
|
3594
|
+
safeGlobals,
|
|
3595
|
+
blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
3596
|
+
blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
3597
|
+
blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
3598
|
+
blockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
3599
|
+
);
|
|
3600
|
+
}
|
|
3601
|
+
if (blockAnalysis.reason) return blockAnalysis.reason;
|
|
2382
3602
|
if (analysis.reason) return analysis.reason;
|
|
3603
|
+
const blockPlans = blockAnalysis.plans || [];
|
|
3604
|
+
markShortCircuitBindings(analysis.bindings || []);
|
|
2383
3605
|
assignStableBindingTargets(analysis.bindings || []);
|
|
2384
3606
|
const stateParameter = path.scope.generateUidIdentifier("farmState");
|
|
2385
3607
|
const blockParameter = path.scope.generateUidIdentifier("farmBlocks");
|
|
2386
3608
|
const definitionIdentifier = path.scope.generateUidIdentifier(`${name}Compiled`);
|
|
2387
3609
|
const propsParameter = propsPlan.definitionParameter;
|
|
2388
3610
|
const rootWithTargets = lowerStableBindingTargets(
|
|
2389
|
-
|
|
3611
|
+
expandedReactiveRoot,
|
|
2390
3612
|
analysis.bindings || [],
|
|
2391
3613
|
blockParameter,
|
|
2392
3614
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
|
|
@@ -2400,12 +3622,13 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2400
3622
|
const rewrittenRoot = rewriteStateAccess(
|
|
2401
3623
|
rootWithBlocks,
|
|
2402
3624
|
stateParameter,
|
|
2403
|
-
|
|
3625
|
+
reactiveByValue,
|
|
2404
3626
|
statesBySetter
|
|
2405
3627
|
);
|
|
2406
3628
|
const definition = types.callExpression(types.cloneNode(createComponentIdentifier), [
|
|
2407
3629
|
types.objectExpression([
|
|
2408
3630
|
types.objectProperty(types.identifier("displayName"), types.stringLiteral(name)),
|
|
3631
|
+
types.objectProperty(types.identifier("reactivity"), types.stringLiteral(reactivity)),
|
|
2409
3632
|
types.spreadElement(
|
|
2410
3633
|
types.conditionalExpression(
|
|
2411
3634
|
types.memberExpression(
|
|
@@ -2416,7 +3639,9 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2416
3639
|
types.objectProperty(types.identifier("hmrId"), types.stringLiteral(`${moduleId}#${name}`)),
|
|
2417
3640
|
types.objectProperty(
|
|
2418
3641
|
types.identifier("stateSignature"),
|
|
2419
|
-
types.stringLiteral(
|
|
3642
|
+
types.stringLiteral(
|
|
3643
|
+
propBindings.length === 0 ? String(states.length) : `${states.length}:${propBindings.map((binding) => binding.localName).join(",")}`
|
|
3644
|
+
)
|
|
2420
3645
|
)
|
|
2421
3646
|
]),
|
|
2422
3647
|
types.objectExpression([])
|
|
@@ -2439,6 +3664,22 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2439
3664
|
)
|
|
2440
3665
|
)
|
|
2441
3666
|
),
|
|
3667
|
+
...propBindings.length > 0 ? [
|
|
3668
|
+
types.objectProperty(
|
|
3669
|
+
types.identifier("readProps"),
|
|
3670
|
+
types.arrowFunctionExpression(
|
|
3671
|
+
[types.cloneNode(propsParameter)],
|
|
3672
|
+
types.arrayExpression(
|
|
3673
|
+
propBindings.map(
|
|
3674
|
+
(binding) => types.memberExpression(
|
|
3675
|
+
types.cloneNode(propsParameter),
|
|
3676
|
+
types.identifier(binding.localName)
|
|
3677
|
+
)
|
|
3678
|
+
)
|
|
3679
|
+
)
|
|
3680
|
+
)
|
|
3681
|
+
)
|
|
3682
|
+
] : [],
|
|
2442
3683
|
types.objectProperty(
|
|
2443
3684
|
types.identifier("render"),
|
|
2444
3685
|
types.arrowFunctionExpression(
|
|
@@ -2458,7 +3699,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2458
3699
|
dependencies: block.dependencies
|
|
2459
3700
|
}))
|
|
2460
3701
|
].map(
|
|
2461
|
-
(binding) => bindingObject(binding, propsParameter, stateParameter,
|
|
3702
|
+
(binding) => bindingObject(binding, propsParameter, stateParameter, reactiveByValue, statesBySetter)
|
|
2462
3703
|
)
|
|
2463
3704
|
)
|
|
2464
3705
|
)
|
|
@@ -2552,7 +3793,8 @@ async function compileReactModule(code, id, options) {
|
|
|
2552
3793
|
useStateNames,
|
|
2553
3794
|
reactNames,
|
|
2554
3795
|
listNames,
|
|
2555
|
-
id
|
|
3796
|
+
id,
|
|
3797
|
+
options.reactivity
|
|
2556
3798
|
);
|
|
2557
3799
|
if (reason) {
|
|
2558
3800
|
diagnostics.push({
|
|
@@ -2679,6 +3921,10 @@ function normalizeReactCompilerOptions(value) {
|
|
|
2679
3921
|
if (!["fallback", "warn", "error"].includes(onUnsupported)) {
|
|
2680
3922
|
throw new TypeError(`Unknown unsupported-component behavior: ${String(onUnsupported)}`);
|
|
2681
3923
|
}
|
|
3924
|
+
const reactivity = options.reactivity || "hybrid";
|
|
3925
|
+
if (reactivity !== "static" && reactivity !== "hybrid") {
|
|
3926
|
+
throw new TypeError(`Unknown React compiler reactivity mode: ${String(reactivity)}`);
|
|
3927
|
+
}
|
|
2682
3928
|
if (options.report !== void 0 && typeof options.report !== "boolean") {
|
|
2683
3929
|
throw new TypeError("The React compiler report option must be a boolean.");
|
|
2684
3930
|
}
|
|
@@ -2689,7 +3935,7 @@ function normalizeReactCompilerOptions(value) {
|
|
|
2689
3935
|
}
|
|
2690
3936
|
const reportFile = normalizeCompilerReportFile(options.reportFile);
|
|
2691
3937
|
const report = options.report === true || options.reportFile !== void 0;
|
|
2692
|
-
return { mode, directive, onUnsupported, report, reportFile };
|
|
3938
|
+
return { mode, directive, onUnsupported, reactivity, report, reportFile };
|
|
2693
3939
|
}
|
|
2694
3940
|
|
|
2695
3941
|
// src/vite.ts
|
|
@@ -2705,7 +3951,7 @@ function readCompilerOptions(rendererOptions) {
|
|
|
2705
3951
|
);
|
|
2706
3952
|
}
|
|
2707
3953
|
const normalized = compiler;
|
|
2708
|
-
if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
|
|
3954
|
+
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")) {
|
|
2709
3955
|
return normalized;
|
|
2710
3956
|
}
|
|
2711
3957
|
return normalizeReactCompilerOptions(compiler);
|