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