@farm.js/react 0.1.0-beta.1 → 0.1.0-beta.2
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 +67 -9
- package/dist/compiler-runtime.cjs +227 -1
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +18 -1
- package/dist/compiler-runtime.d.ts +18 -1
- package/dist/compiler-runtime.mjs +227 -1
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +326 -20
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +326 -20
- package/dist/vite.mjs.map +1 -1
- package/package.json +3 -3
package/dist/vite.mjs
CHANGED
|
@@ -258,6 +258,31 @@ function isTextExpression(expression, statesByValue, safeGlobals) {
|
|
|
258
258
|
function jsxAttributeName(attribute) {
|
|
259
259
|
return types.isJSXIdentifier(attribute.name) ? attribute.name.name : void 0;
|
|
260
260
|
}
|
|
261
|
+
function jsxAttribute(element, name) {
|
|
262
|
+
return element.openingElement.attributes.find(
|
|
263
|
+
(attribute) => types.isJSXAttribute(attribute) && jsxAttributeName(attribute) === name
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
function staticJsxAttributeString(attribute) {
|
|
267
|
+
if (!attribute?.value) return attribute ? "" : void 0;
|
|
268
|
+
if (types.isStringLiteral(attribute.value)) return attribute.value.value;
|
|
269
|
+
if (types.isJSXExpressionContainer(attribute.value) && types.isStringLiteral(attribute.value.expression)) {
|
|
270
|
+
return attribute.value.expression.value;
|
|
271
|
+
}
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
function controlledSelectHasDynamicOptions(element) {
|
|
275
|
+
let dynamic = false;
|
|
276
|
+
types.traverseFast(element, (node) => {
|
|
277
|
+
if (dynamic || !types.isJSXElement(node)) return;
|
|
278
|
+
const tag = node.openingElement.name;
|
|
279
|
+
if (!types.isJSXIdentifier(tag) || tag.name !== "option" && tag.name !== "optgroup") return;
|
|
280
|
+
dynamic = node.openingElement.attributes.some(
|
|
281
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXExpressionContainer(attribute.value) && !types.isJSXEmptyExpression(attribute.value.expression)
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
return dynamic;
|
|
285
|
+
}
|
|
261
286
|
function isEmptyConditionalBranch(expression) {
|
|
262
287
|
return types.isNullLiteral(expression) || types.isBooleanLiteral(expression, { value: false });
|
|
263
288
|
}
|
|
@@ -483,7 +508,87 @@ function validateKeyedRowEventHandler(handler) {
|
|
|
483
508
|
});
|
|
484
509
|
return reason;
|
|
485
510
|
}
|
|
486
|
-
function
|
|
511
|
+
function stabilizeDeferredEventCurrentTarget(handler, compilerSetters) {
|
|
512
|
+
const cloned = types.cloneNode(handler, true);
|
|
513
|
+
const eventParameter = cloned.params[0];
|
|
514
|
+
if (!types.isIdentifier(eventParameter) || compilerSetters.size === 0) return cloned;
|
|
515
|
+
const file = expressionFile(cloned);
|
|
516
|
+
const expression = file.program.body[0].expression;
|
|
517
|
+
if (!types.isArrowFunctionExpression(expression) && !types.isFunctionExpression(expression)) {
|
|
518
|
+
return cloned;
|
|
519
|
+
}
|
|
520
|
+
const rootBindingIdentifier = expression.params[0];
|
|
521
|
+
const snapshots = [];
|
|
522
|
+
const snapshotsByProperty = /* @__PURE__ */ new Map();
|
|
523
|
+
const replaceCurrentTarget = (path) => {
|
|
524
|
+
const property = path.node.property;
|
|
525
|
+
const isCurrentTarget = path.node.computed ? types.isStringLiteral(property, { value: "currentTarget" }) : types.isIdentifier(property, { name: "currentTarget" });
|
|
526
|
+
if (!isCurrentTarget || !types.isIdentifier(path.node.object, { name: eventParameter.name }))
|
|
527
|
+
return;
|
|
528
|
+
const binding = path.scope.getBinding(eventParameter.name);
|
|
529
|
+
if (!binding || binding.identifier !== rootBindingIdentifier) return;
|
|
530
|
+
const setterCall = path.findParent(
|
|
531
|
+
(parent2) => parent2.isCallExpression() && types.isIdentifier(parent2.node.callee) && compilerSetters.has(parent2.node.callee.name)
|
|
532
|
+
);
|
|
533
|
+
if (!setterCall) return;
|
|
534
|
+
const deferredFunction = path.findParent(
|
|
535
|
+
(parent2) => parent2.isFunction() && parent2.node !== expression
|
|
536
|
+
);
|
|
537
|
+
if (!deferredFunction || !deferredFunction.findParent((parent2) => parent2 === setterCall))
|
|
538
|
+
return;
|
|
539
|
+
const parent = path.parentPath;
|
|
540
|
+
const propertyRead = (parent?.isMemberExpression() || parent?.isOptionalMemberExpression()) && parent.node.object === path.node ? parent : path;
|
|
541
|
+
const snapshotProperty = propertyRead === path ? "element" : propertyRead.node.computed ? types.isStringLiteral(propertyRead.node.property) ? propertyRead.node.property.value : `computed${snapshots.length}` : types.isIdentifier(propertyRead.node.property) ? propertyRead.node.property.name : `property${snapshots.length}`;
|
|
542
|
+
let snapshot = snapshotsByProperty.get(snapshotProperty);
|
|
543
|
+
if (!snapshot) {
|
|
544
|
+
const suffix = snapshotProperty.replace(/[^A-Za-z0-9_$]/g, " ").replace(
|
|
545
|
+
/(?:^|\s+)([A-Za-z0-9_$])/g,
|
|
546
|
+
(_match, character) => character.toUpperCase()
|
|
547
|
+
).replace(/\s/g, "");
|
|
548
|
+
snapshot = uniqueLocalIdentifier(`_farmCurrentTarget${suffix}`, [
|
|
549
|
+
expression,
|
|
550
|
+
...snapshots.map((entry) => entry.identifier)
|
|
551
|
+
]);
|
|
552
|
+
snapshotsByProperty.set(snapshotProperty, snapshot);
|
|
553
|
+
snapshots.push({
|
|
554
|
+
identifier: snapshot,
|
|
555
|
+
value: types.cloneNode(propertyRead.node, true)
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
propertyRead.replaceWith(types.cloneNode(snapshot));
|
|
559
|
+
propertyRead.skip();
|
|
560
|
+
};
|
|
561
|
+
traverse(file, {
|
|
562
|
+
MemberExpression: replaceCurrentTarget,
|
|
563
|
+
OptionalMemberExpression: replaceCurrentTarget
|
|
564
|
+
});
|
|
565
|
+
if (snapshots.length === 0) return expression;
|
|
566
|
+
const declarations = snapshots.map(
|
|
567
|
+
({ identifier, value }) => types.variableDeclaration("const", [types.variableDeclarator(types.cloneNode(identifier), value)])
|
|
568
|
+
);
|
|
569
|
+
if (types.isBlockStatement(expression.body)) {
|
|
570
|
+
expression.body.body.unshift(...declarations);
|
|
571
|
+
} else {
|
|
572
|
+
expression.body = types.blockStatement([...declarations, types.returnStatement(expression.body)]);
|
|
573
|
+
}
|
|
574
|
+
return expression;
|
|
575
|
+
}
|
|
576
|
+
function stabilizeDeferredEventCurrentTargets(root, compilerSetters) {
|
|
577
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
578
|
+
traverse(file, {
|
|
579
|
+
JSXAttribute(path) {
|
|
580
|
+
if (!types.isJSXIdentifier(path.node.name) || !/^on[A-Z]/.test(path.node.name.name)) return;
|
|
581
|
+
const value = path.node.value;
|
|
582
|
+
if (!types.isJSXExpressionContainer(value) || !types.isArrowFunctionExpression(value.expression) && !types.isFunctionExpression(value.expression)) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
value.expression = stabilizeDeferredEventCurrentTarget(value.expression, compilerSetters);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
const expression = file.program.body[0].expression;
|
|
589
|
+
return types.isJSXElement(expression) ? expression : types.cloneNode(root, true);
|
|
590
|
+
}
|
|
591
|
+
function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters) {
|
|
487
592
|
if (renderCallback.async || renderCallback.generator || renderCallback.params.length < 1 || renderCallback.params.length > 2 || !types.isIdentifier(renderCallback.params[0]) || renderCallback.params[1] !== void 0 && !types.isIdentifier(renderCallback.params[1])) {
|
|
488
593
|
return { reason: "compiled keyed rows require item and optional index identifiers" };
|
|
489
594
|
}
|
|
@@ -499,8 +604,25 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals) {
|
|
|
499
604
|
const attributeNames = new Set(
|
|
500
605
|
element.openingElement.attributes.filter((attribute) => types.isJSXAttribute(attribute)).map(jsxAttributeName).filter((name) => name !== void 0)
|
|
501
606
|
);
|
|
502
|
-
|
|
503
|
-
|
|
607
|
+
const controlled = attributeNames.has("value") || attributeNames.has("checked");
|
|
608
|
+
if (attributeNames.has("contentEditable")) {
|
|
609
|
+
return "content-editable keyed rows require React ownership";
|
|
610
|
+
}
|
|
611
|
+
if (tag.name === "input" && controlled) {
|
|
612
|
+
const type = jsxAttribute(element, "type");
|
|
613
|
+
const staticType = staticJsxAttributeString(type);
|
|
614
|
+
if (type && staticType === void 0) {
|
|
615
|
+
return "controlled keyed row inputs require a static type";
|
|
616
|
+
}
|
|
617
|
+
if (attributeNames.has("value") && staticType?.toLowerCase() === "file") {
|
|
618
|
+
return "file inputs require React ownership";
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (tag.name === "textarea" && controlled && meaningfulJsxChildren(element).length > 0) {
|
|
622
|
+
return "controlled keyed row textareas cannot also use children";
|
|
623
|
+
}
|
|
624
|
+
if (tag.name === "select" && controlled && controlledSelectHasDynamicOptions(element)) {
|
|
625
|
+
return "controlled keyed row selects require static options";
|
|
504
626
|
}
|
|
505
627
|
for (const attribute of element.openingElement.attributes) {
|
|
506
628
|
if (types.isJSXSpreadAttribute(attribute)) {
|
|
@@ -531,7 +653,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals) {
|
|
|
531
653
|
id: events.length,
|
|
532
654
|
path: [...path],
|
|
533
655
|
name,
|
|
534
|
-
value:
|
|
656
|
+
value: stabilizeDeferredEventCurrentTarget(handler, compilerSetters)
|
|
535
657
|
});
|
|
536
658
|
continue;
|
|
537
659
|
}
|
|
@@ -645,26 +767,14 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals) {
|
|
|
645
767
|
const reason = visit(row, []);
|
|
646
768
|
return reason ? { reason } : { bindings, events, conditionals };
|
|
647
769
|
}
|
|
648
|
-
function
|
|
649
|
-
if (container.openingElement.attributes.some(
|
|
650
|
-
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
651
|
-
)) {
|
|
652
|
-
return void 0;
|
|
653
|
-
}
|
|
654
|
-
for (const attribute of container.openingElement.attributes) {
|
|
655
|
-
if (types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && types.isJSXExpressionContainer(attribute.value) && !types.isJSXEmptyExpression(attribute.value.expression) && !/^on[A-Z]/.test(attribute.name.name) && collectStateDependencies(attribute.value.expression, statesByValue).length > 0) {
|
|
656
|
-
return void 0;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
const children = meaningfulJsxChildren(container);
|
|
660
|
-
if (children.length !== 1) return void 0;
|
|
770
|
+
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
|
|
661
771
|
let collection;
|
|
662
772
|
let keyCallback;
|
|
663
773
|
let renderCallback;
|
|
664
774
|
let row;
|
|
665
775
|
let dependencies;
|
|
666
776
|
let syntax;
|
|
667
|
-
|
|
777
|
+
let source;
|
|
668
778
|
if (types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression) && isMapCall(child.expression)) {
|
|
669
779
|
const result = analyzeMapList(child.expression, statesByValue, safeGlobals);
|
|
670
780
|
if (result.reason) return void 0;
|
|
@@ -684,6 +794,7 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
684
794
|
row = returned;
|
|
685
795
|
dependencies = result.dependencies || [];
|
|
686
796
|
syntax = "map";
|
|
797
|
+
source = child.expression;
|
|
687
798
|
} else if (types.isJSXElement(child) && isPublicListElement(child, listNames)) {
|
|
688
799
|
const result = analyzePublicList(child, statesByValue, safeGlobals);
|
|
689
800
|
if (result.reason) return void 0;
|
|
@@ -701,12 +812,19 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
701
812
|
row = returned;
|
|
702
813
|
dependencies = result.dependencies || [];
|
|
703
814
|
syntax = "list";
|
|
815
|
+
source = child;
|
|
704
816
|
} else {
|
|
705
817
|
return void 0;
|
|
706
818
|
}
|
|
707
|
-
const rowAnalysis = analyzeKeyedRowTree(
|
|
819
|
+
const rowAnalysis = analyzeKeyedRowTree(
|
|
820
|
+
row,
|
|
821
|
+
renderCallback,
|
|
822
|
+
safeGlobals,
|
|
823
|
+
new Set([...statesByValue.values()].map((state) => state.setterName))
|
|
824
|
+
);
|
|
708
825
|
if (rowAnalysis.reason) return void 0;
|
|
709
826
|
return {
|
|
827
|
+
source,
|
|
710
828
|
collection,
|
|
711
829
|
keyCallback,
|
|
712
830
|
renderCallback,
|
|
@@ -718,6 +836,76 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
718
836
|
syntax
|
|
719
837
|
};
|
|
720
838
|
}
|
|
839
|
+
function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNames) {
|
|
840
|
+
if (container.openingElement.attributes.some(
|
|
841
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
842
|
+
)) {
|
|
843
|
+
return void 0;
|
|
844
|
+
}
|
|
845
|
+
for (const attribute of container.openingElement.attributes) {
|
|
846
|
+
if (types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && types.isJSXExpressionContainer(attribute.value) && !types.isJSXEmptyExpression(attribute.value.expression) && !/^on[A-Z]/.test(attribute.name.name) && collectStateDependencies(attribute.value.expression, statesByValue).length > 0) {
|
|
847
|
+
return void 0;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const children = meaningfulJsxChildren(container);
|
|
851
|
+
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;
|
|
868
|
+
}
|
|
869
|
+
function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
|
|
870
|
+
if (container.openingElement.attributes.some(
|
|
871
|
+
(attribute) => types.isJSXSpreadAttribute(attribute) || types.isJSXAttribute(attribute) && types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
|
|
872
|
+
)) {
|
|
873
|
+
return void 0;
|
|
874
|
+
}
|
|
875
|
+
const children = meaningfulJsxChildren(container);
|
|
876
|
+
if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
|
|
877
|
+
const ranges = [];
|
|
878
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
879
|
+
let staticBefore = 0;
|
|
880
|
+
for (const child of children) {
|
|
881
|
+
const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames);
|
|
882
|
+
if (range) {
|
|
883
|
+
if (range.events.length > 0 || range.conditionals.length > 0) return void 0;
|
|
884
|
+
ranges.push({
|
|
885
|
+
before: staticBefore,
|
|
886
|
+
source: range.source,
|
|
887
|
+
collection: range.collection,
|
|
888
|
+
keyCallback: range.keyCallback,
|
|
889
|
+
renderCallback: range.renderCallback,
|
|
890
|
+
row: range.row,
|
|
891
|
+
bindings: range.bindings,
|
|
892
|
+
syntax: range.syntax
|
|
893
|
+
});
|
|
894
|
+
for (const dependency of range.dependencies) dependencies.add(dependency);
|
|
895
|
+
staticBefore = 0;
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
if (!types.isJSXElement(child) || !isHostElement(child)) return void 0;
|
|
899
|
+
if (!isStaticKeyedRangeSibling(child, statesByValue, safeGlobals)) return void 0;
|
|
900
|
+
staticBefore += 1;
|
|
901
|
+
}
|
|
902
|
+
if (ranges.length === 0) return void 0;
|
|
903
|
+
return {
|
|
904
|
+
ranges,
|
|
905
|
+
trailing: staticBefore,
|
|
906
|
+
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
907
|
+
};
|
|
908
|
+
}
|
|
721
909
|
function analyzeHostConditionalTree(branch, safeGlobals) {
|
|
722
910
|
const bindings = [];
|
|
723
911
|
const visit = (element, path) => {
|
|
@@ -1207,6 +1395,74 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
1207
1395
|
true
|
|
1208
1396
|
);
|
|
1209
1397
|
}
|
|
1398
|
+
function keyedRangeObject(range) {
|
|
1399
|
+
const parameters = range.renderCallback.params.map(
|
|
1400
|
+
(parameter) => types.cloneNode(parameter, true)
|
|
1401
|
+
);
|
|
1402
|
+
return types.objectExpression([
|
|
1403
|
+
types.objectProperty(types.identifier("before"), types.numericLiteral(range.before)),
|
|
1404
|
+
types.objectProperty(
|
|
1405
|
+
types.identifier("items"),
|
|
1406
|
+
types.arrowFunctionExpression([], cloneExpression(range.collection))
|
|
1407
|
+
),
|
|
1408
|
+
types.objectProperty(types.identifier("rowKey"), types.cloneNode(range.keyCallback, true)),
|
|
1409
|
+
types.objectProperty(
|
|
1410
|
+
types.identifier("create"),
|
|
1411
|
+
types.arrowFunctionExpression(
|
|
1412
|
+
parameters.map((parameter) => types.cloneNode(parameter, true)),
|
|
1413
|
+
hostElementDescriptor(range.row)
|
|
1414
|
+
)
|
|
1415
|
+
),
|
|
1416
|
+
types.objectProperty(
|
|
1417
|
+
types.identifier("bindings"),
|
|
1418
|
+
types.arrayExpression(
|
|
1419
|
+
range.bindings.map((binding) => keyedRowBindingObject(binding, parameters))
|
|
1420
|
+
)
|
|
1421
|
+
)
|
|
1422
|
+
]);
|
|
1423
|
+
}
|
|
1424
|
+
function keyedRangesBoundary(blockRuntime, plan) {
|
|
1425
|
+
const name = types.jsxMemberExpression(
|
|
1426
|
+
types.jsxIdentifier(blockRuntime.name),
|
|
1427
|
+
types.jsxIdentifier("KeyedRanges")
|
|
1428
|
+
);
|
|
1429
|
+
const source = types.cloneNode(plan.source, true);
|
|
1430
|
+
let rootRef;
|
|
1431
|
+
source.openingElement.attributes = source.openingElement.attributes.filter((attribute) => {
|
|
1432
|
+
if (!types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "ref" || !types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
1433
|
+
return true;
|
|
1434
|
+
}
|
|
1435
|
+
rootRef = cloneExpression(attribute.value.expression);
|
|
1436
|
+
return false;
|
|
1437
|
+
});
|
|
1438
|
+
return types.jsxElement(
|
|
1439
|
+
types.jsxOpeningElement(
|
|
1440
|
+
name,
|
|
1441
|
+
[
|
|
1442
|
+
types.jsxAttribute(types.jsxIdentifier("id"), types.jsxExpressionContainer(types.numericLiteral(plan.id))),
|
|
1443
|
+
types.jsxAttribute(
|
|
1444
|
+
types.jsxIdentifier("render"),
|
|
1445
|
+
types.jsxExpressionContainer(types.arrowFunctionExpression([], source))
|
|
1446
|
+
),
|
|
1447
|
+
...rootRef ? [types.jsxAttribute(types.jsxIdentifier("rootRef"), types.jsxExpressionContainer(rootRef))] : [],
|
|
1448
|
+
types.jsxAttribute(
|
|
1449
|
+
types.jsxIdentifier("ranges"),
|
|
1450
|
+
types.jsxExpressionContainer(
|
|
1451
|
+
types.arrayExpression(plan.ranges.map((range) => keyedRangeObject(range)))
|
|
1452
|
+
)
|
|
1453
|
+
),
|
|
1454
|
+
types.jsxAttribute(
|
|
1455
|
+
types.jsxIdentifier("trailing"),
|
|
1456
|
+
types.jsxExpressionContainer(types.numericLiteral(plan.trailing))
|
|
1457
|
+
)
|
|
1458
|
+
],
|
|
1459
|
+
true
|
|
1460
|
+
),
|
|
1461
|
+
null,
|
|
1462
|
+
[],
|
|
1463
|
+
true
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1210
1466
|
function hostConditionalBranchObject(branch, bindings) {
|
|
1211
1467
|
return types.objectExpression([
|
|
1212
1468
|
types.objectProperty(
|
|
@@ -1419,6 +1675,23 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1419
1675
|
}
|
|
1420
1676
|
if (types.isJSXElement(child)) {
|
|
1421
1677
|
if (isHostElement(child)) {
|
|
1678
|
+
const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
|
|
1679
|
+
if (keyedRanges) {
|
|
1680
|
+
plans.push({
|
|
1681
|
+
kind: "keyed-ranges",
|
|
1682
|
+
id: nextId++,
|
|
1683
|
+
parent,
|
|
1684
|
+
dependencies: keyedRanges.dependencies,
|
|
1685
|
+
source: child,
|
|
1686
|
+
ranges: keyedRanges.ranges,
|
|
1687
|
+
trailing: keyedRanges.trailing
|
|
1688
|
+
});
|
|
1689
|
+
for (const range of keyedRanges.ranges) {
|
|
1690
|
+
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
1691
|
+
else keyedExpressions.add(range.source);
|
|
1692
|
+
}
|
|
1693
|
+
continue;
|
|
1694
|
+
}
|
|
1422
1695
|
const hostConditional = analyzeHostConditionalContainer(
|
|
1423
1696
|
child,
|
|
1424
1697
|
statesByValue,
|
|
@@ -1551,6 +1824,28 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
1551
1824
|
}
|
|
1552
1825
|
return { dependencies };
|
|
1553
1826
|
};
|
|
1827
|
+
const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
|
|
1828
|
+
if (rootRanges) {
|
|
1829
|
+
plans.push({
|
|
1830
|
+
kind: "keyed-ranges",
|
|
1831
|
+
id: nextId++,
|
|
1832
|
+
dependencies: rootRanges.dependencies,
|
|
1833
|
+
source: root,
|
|
1834
|
+
ranges: rootRanges.ranges,
|
|
1835
|
+
trailing: rootRanges.trailing
|
|
1836
|
+
});
|
|
1837
|
+
for (const range of rootRanges.ranges) {
|
|
1838
|
+
if (types.isJSXElement(range.source)) ownedElements.add(range.source);
|
|
1839
|
+
else keyedExpressions.add(range.source);
|
|
1840
|
+
}
|
|
1841
|
+
return {
|
|
1842
|
+
plans,
|
|
1843
|
+
componentElements,
|
|
1844
|
+
conditionalExpressions,
|
|
1845
|
+
ownedElements,
|
|
1846
|
+
keyedExpressions
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1554
1849
|
const result = visitHost(root, void 0, false);
|
|
1555
1850
|
if (result.reason) return { reason: result.reason };
|
|
1556
1851
|
return {
|
|
@@ -1587,6 +1882,10 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
1587
1882
|
const planBySource = new Map(
|
|
1588
1883
|
plans.map((plan) => [plan.source, plan])
|
|
1589
1884
|
);
|
|
1885
|
+
const rootPlan = planBySource.get(root);
|
|
1886
|
+
if (rootPlan?.kind === "keyed-ranges") {
|
|
1887
|
+
return keyedRangesBoundary(blockRuntime, rootPlan);
|
|
1888
|
+
}
|
|
1590
1889
|
const visit = (element) => {
|
|
1591
1890
|
element.children = element.children.map((child) => {
|
|
1592
1891
|
if (types.isJSXElement(child)) {
|
|
@@ -1597,6 +1896,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
1597
1896
|
if (plan2?.kind === "keyed-rows") {
|
|
1598
1897
|
return keyedRowsBoundary(blockRuntime, plan2);
|
|
1599
1898
|
}
|
|
1899
|
+
if (plan2?.kind === "keyed-ranges") {
|
|
1900
|
+
return keyedRangesBoundary(blockRuntime, plan2);
|
|
1901
|
+
}
|
|
1600
1902
|
if (plan2?.kind === "component") {
|
|
1601
1903
|
return componentIslandBoundary(blockRuntime, plan2, child);
|
|
1602
1904
|
}
|
|
@@ -2030,11 +2332,15 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
2030
2332
|
const handlerRewrite = rewriteHandlerAccess(rootWithDerived, handlersByName);
|
|
2031
2333
|
if (handlerRewrite.reason) return handlerRewrite.reason;
|
|
2032
2334
|
if (!handlerRewrite.root) return "event handlers could not be prepared safely";
|
|
2033
|
-
const
|
|
2335
|
+
const expandedRootWithDeferredEvents = rewriteDestructuredPropAccess(
|
|
2034
2336
|
handlerRewrite.root,
|
|
2035
2337
|
propsPlan.destructuredNames,
|
|
2036
2338
|
propsPlan.definitionParameter
|
|
2037
2339
|
);
|
|
2340
|
+
const expandedRoot = stabilizeDeferredEventCurrentTargets(
|
|
2341
|
+
expandedRootWithDeferredEvents,
|
|
2342
|
+
new Set(states.map((state) => state.setterName))
|
|
2343
|
+
);
|
|
2038
2344
|
const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
|
|
2039
2345
|
if (setterReason) return setterReason;
|
|
2040
2346
|
const referencedComponentNames = /* @__PURE__ */ new Set();
|