@farm.js/react 0.1.0-beta.6 → 0.1.0-beta.7
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 +40 -13
- package/dist/compiler-runtime.cjs +82 -3
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +5 -3
- package/dist/compiler-runtime.d.ts +5 -3
- package/dist/compiler-runtime.mjs +82 -4
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +120 -9
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +120 -9
- package/dist/vite.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -300,19 +300,25 @@ expose the site count as `keyedArrayRollingWindowHints`.
|
|
|
300
300
|
Native known-position updates can avoid a complete keyed scan too:
|
|
301
301
|
|
|
302
302
|
```tsx
|
|
303
|
-
setItems((current) => current.toSpliced(
|
|
304
|
-
setItems((current) => current.
|
|
303
|
+
setItems((current) => current.toSpliced(selectedIndex, 0, nextItem));
|
|
304
|
+
setItems((current) => current.toSpliced(selectedIndex, 1));
|
|
305
|
+
setItems((current) => current.with(selectedIndex, replacement));
|
|
305
306
|
```
|
|
306
307
|
|
|
307
|
-
The compiler recognizes only a concise functional setter
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
The compiler recognizes only a concise functional setter and either a safe-integer literal or a
|
|
309
|
+
compiler-safe runtime position expression, such as an identifier, property read, arithmetic,
|
|
310
|
+
conditional, or safe `Math` call. The update must insert one item with zero removals, remove one
|
|
311
|
+
item, or directly replace one item. Farm preserves method lookup, evaluates the position and
|
|
312
|
+
remaining arguments once in their original order, executes the ordinary native call, and records
|
|
313
|
+
metadata only after validating the committed native source, result, and actual safe-integer
|
|
314
|
+
position. The runtime creates one inserted row, removes one known row, or patches/replaces one row
|
|
315
|
+
at that position without rereading every existing key, descriptor, and binding. Surviving rows keep
|
|
316
|
+
their DOM identity. Index-aware or collection-reading rows, custom methods, position expressions
|
|
317
|
+
with user calls or mutations, runtime positions that are not safe integers, other `toSpliced()`
|
|
318
|
+
forms, block-bodied updaters, unsafe incoming expressions, queued uncommitted updates, reused keys,
|
|
319
|
+
nested or React-owned rows, and failed checks use complete keyed reconciliation. Reports expose the
|
|
320
|
+
site count as `keyedArrayPositionHints`; the capability is tree-shaken from modules that do not emit
|
|
321
|
+
it.
|
|
316
322
|
|
|
317
323
|
A direct native reverse can carry its complete permutation to a separate optional runtime:
|
|
318
324
|
|
|
@@ -330,6 +336,26 @@ React-owned rows, and failed checks keep complete keyed reconciliation. Reports
|
|
|
330
336
|
count as `keyedArrayReorderHints`, and modules without one omit the reorder runtime. Farm does not
|
|
331
337
|
polyfill `Array.prototype.toReversed`.
|
|
332
338
|
|
|
339
|
+
A direct native immutable sort can use the same optional reorder runtime:
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
setItems((current) => current.toSorted((left, right) => left.rank - right.rank));
|
|
343
|
+
setLabels((current) => current.toSorted());
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Farm recognizes a concise functional setter with no comparator or an inline synchronous comparator
|
|
347
|
+
from the compiler-safe expression subset. It preserves the original method lookup, comparator,
|
|
348
|
+
stable native result, and errors. After the native sort runs, the runtime validates a committed
|
|
349
|
+
ordinary dense array, equal lengths, and a unique one-to-one item-identity permutation. It then
|
|
350
|
+
uses LIS to move only `n - LIS` keyed DOM nodes without rereading row keys, descriptors, or
|
|
351
|
+
bindings. The native sorting work itself is unchanged.
|
|
352
|
+
|
|
353
|
+
Index-aware or collection-reading rows, referenced comparators, block-bodied updaters, computed or
|
|
354
|
+
chained calls, custom methods, sparse or subclassed arrays, duplicate item identities, queued
|
|
355
|
+
uncommitted sorts, nested or React-owned rows, and failed checks keep complete keyed
|
|
356
|
+
reconciliation. Reports expose the site count as `keyedArraySortHints`; sort shares the optional
|
|
357
|
+
reorder runtime, and Farm does not polyfill `Array.prototype.toSorted`.
|
|
358
|
+
|
|
333
359
|
Concise immutable filters on a direct keyed array can carry removal positions into the same
|
|
334
360
|
optional runtime:
|
|
335
361
|
|
|
@@ -631,9 +657,10 @@ reasons aggregated by count. Its summary and per-module `optimizations` also rep
|
|
|
631
657
|
`keyedArrayAppendHints`, the number of compiler-proven direct keyed-array append sites; and
|
|
632
658
|
`keyedArrayFilterHints`, the number of compiler-proven direct keyed-array filter sites; and
|
|
633
659
|
`keyedArrayPrependHints`, the number of compiler-proven direct keyed-array prepend sites; and
|
|
634
|
-
`keyedArrayPositionHints`, the number of compiler-proven native
|
|
635
|
-
replacement sites; and
|
|
660
|
+
`keyedArrayPositionHints`, the number of compiler-proven native exact-position insertion, removal,
|
|
661
|
+
or replacement sites, including guarded compiler-safe runtime positions; and
|
|
636
662
|
`keyedArrayReorderHints`, the number of compiler-proven direct native keyed-array reverse sites; and
|
|
663
|
+
`keyedArraySortHints`, the number of compiler-proven direct native keyed-array sort sites; and
|
|
637
664
|
`keyedArrayRollingWindowHints`, the number of compiler-proven retained-tail plus incoming-suffix
|
|
638
665
|
sites; and
|
|
639
666
|
`keyedArraySliceHints`, the number of compiler-proven direct keyed-array slice sites. A custom
|
|
@@ -43,6 +43,7 @@ var NATIVE_ARRAY_SLICE = Array.prototype.slice;
|
|
|
43
43
|
var NATIVE_ARRAY_TO_SPLICED = Array.prototype.toSpliced;
|
|
44
44
|
var NATIVE_ARRAY_WITH = Array.prototype.with;
|
|
45
45
|
var NATIVE_ARRAY_TO_REVERSED = Array.prototype.toReversed;
|
|
46
|
+
var NATIVE_ARRAY_TO_SORTED = Array.prototype.toSorted;
|
|
46
47
|
var NATIVE_REFLECT_APPLY = Reflect.apply;
|
|
47
48
|
function compilerObject(value) {
|
|
48
49
|
return typeof value === "object" && value !== null || typeof value === "function" ? value : void 0;
|
|
@@ -163,7 +164,7 @@ function compilerKeyedArrayPosition(value, sourceToken, expectedLength) {
|
|
|
163
164
|
const target = compilerObject(value);
|
|
164
165
|
if (!target || !sourceToken || !Array.isArray(value)) return void 0;
|
|
165
166
|
const update = COMPILER_KEYED_ARRAY_POSITIONS.get(target);
|
|
166
|
-
if (!update || update.sourceToken !== sourceToken || update.sourceLength !== expectedLength || update.resultLength !== value.length || update.position < 0 || update.position > expectedLength || update.kind === "insert" && update.resultLength !== expectedLength + 1 || update.kind === "replace" && (update.position >= expectedLength || update.resultLength !== expectedLength)) {
|
|
167
|
+
if (!update || update.sourceToken !== sourceToken || update.sourceLength !== expectedLength || update.resultLength !== value.length || update.position < 0 || update.position > expectedLength || update.kind === "insert" && update.resultLength !== expectedLength + 1 || update.kind === "remove" && (update.position >= expectedLength || update.resultLength !== expectedLength - 1) || update.kind === "replace" && (update.position >= expectedLength || update.resultLength !== expectedLength)) {
|
|
167
168
|
return void 0;
|
|
168
169
|
}
|
|
169
170
|
return update;
|
|
@@ -380,8 +381,9 @@ function createCompilerKeyedArrayPositionUpdate(previous, method, kind, position
|
|
|
380
381
|
const sourceLength = previous.length;
|
|
381
382
|
const normalizedPosition = position < 0 ? Math.max(sourceLength + position, 0) : Math.min(position, sourceLength);
|
|
382
383
|
const validInsert = kind === "insert" && method === NATIVE_ARRAY_TO_SPLICED && args.length === 2 && Object.is(args[0], 0) && value.length === sourceLength + 1;
|
|
384
|
+
const validRemove = kind === "remove" && method === NATIVE_ARRAY_TO_SPLICED && args.length === 1 && Object.is(args[0], 1) && normalizedPosition < sourceLength && value.length === sourceLength - 1;
|
|
383
385
|
const validReplace = kind === "replace" && method === NATIVE_ARRAY_WITH && args.length === 1 && position >= -sourceLength && position < sourceLength && value.length === sourceLength;
|
|
384
|
-
if (!validInsert && !validReplace) return value;
|
|
386
|
+
if (!validInsert && !validRemove && !validReplace) return value;
|
|
385
387
|
const sourceToken = compilerKeyedCollectionToken(previousTarget);
|
|
386
388
|
if (!sourceToken) return value;
|
|
387
389
|
COMPILER_KEYED_ARRAY_POSITIONS.set(valueTarget, {
|
|
@@ -419,6 +421,33 @@ function createCompilerKeyedArrayReorder(previous, method) {
|
|
|
419
421
|
}
|
|
420
422
|
return value;
|
|
421
423
|
}
|
|
424
|
+
function createCompilerKeyedArraySort(previous, method, ...args) {
|
|
425
|
+
const value = NATIVE_REFLECT_APPLY(
|
|
426
|
+
method,
|
|
427
|
+
previous,
|
|
428
|
+
args
|
|
429
|
+
);
|
|
430
|
+
try {
|
|
431
|
+
const previousTarget = compilerObject(previous);
|
|
432
|
+
const valueTarget = compilerObject(value);
|
|
433
|
+
if (!previousTarget || !valueTarget || !COMPILER_KEYED_COMMITTED_COLLECTIONS.has(previousTarget) || !Array.isArray(previous) || !Array.isArray(value) || Object.getPrototypeOf(previous) !== NATIVE_ARRAY_PROTOTYPE || Object.getPrototypeOf(value) !== NATIVE_ARRAY_PROTOTYPE || method !== NATIVE_ARRAY_TO_SORTED || args.length > 1 || args.length === 1 && args[0] !== void 0 && typeof args[0] !== "function" || value.length !== previous.length) {
|
|
434
|
+
return value;
|
|
435
|
+
}
|
|
436
|
+
for (let index = 0; index < previous.length; index += 1) {
|
|
437
|
+
if (!(index in previous)) return value;
|
|
438
|
+
}
|
|
439
|
+
const sourceToken = compilerKeyedCollectionToken(previousTarget);
|
|
440
|
+
if (!sourceToken) return value;
|
|
441
|
+
COMPILER_KEYED_ARRAY_REORDERS.set(valueTarget, {
|
|
442
|
+
kind: "sort",
|
|
443
|
+
sourceToken,
|
|
444
|
+
sourceLength: previous.length,
|
|
445
|
+
resultLength: value.length
|
|
446
|
+
});
|
|
447
|
+
} catch {
|
|
448
|
+
}
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
422
451
|
function applyCompilerKeyedCollectionMutation(collection, method, operation, key, value) {
|
|
423
452
|
const args = operation === "map-set" ? [key, value] : [key];
|
|
424
453
|
const result = NATIVE_REFLECT_APPLY(method, collection, args);
|
|
@@ -2758,6 +2787,16 @@ function reconcileCompilerKeyedArrayPosition(props, dirtyState, collectionToken,
|
|
|
2758
2787
|
if (!update || !Array.isArray(finalValue)) return void 0;
|
|
2759
2788
|
const previousInstances = [...instances.values()];
|
|
2760
2789
|
const previous = previousInstances[update.position];
|
|
2790
|
+
if (update.kind === "remove") {
|
|
2791
|
+
if (!previous || previous.index !== update.position) return void 0;
|
|
2792
|
+
previous.scope?.cleanup();
|
|
2793
|
+
previous.element.remove();
|
|
2794
|
+
previousInstances.splice(update.position, 1);
|
|
2795
|
+
for (let index = update.position; index < previousInstances.length; index += 1) {
|
|
2796
|
+
previousInstances[index].index = index;
|
|
2797
|
+
}
|
|
2798
|
+
return new Map(previousInstances.map((instance) => [instance.key, instance]));
|
|
2799
|
+
}
|
|
2761
2800
|
let item;
|
|
2762
2801
|
let key;
|
|
2763
2802
|
try {
|
|
@@ -2834,8 +2873,47 @@ function reconcileCompilerKeyedArrayReorder(props, dirtyState, collectionToken,
|
|
|
2834
2873
|
}
|
|
2835
2874
|
const finalValue = props.items();
|
|
2836
2875
|
const update = compilerKeyedArrayReorder(finalValue, collectionToken, instances.size);
|
|
2837
|
-
if (!update ||
|
|
2876
|
+
if (!update || !Array.isArray(finalValue)) return void 0;
|
|
2838
2877
|
const previousInstances = [...instances.values()];
|
|
2878
|
+
if (update.kind === "sort") {
|
|
2879
|
+
const instancesByItem = /* @__PURE__ */ new Map();
|
|
2880
|
+
try {
|
|
2881
|
+
for (let sourceIndex = 0; sourceIndex < previousInstances.length; sourceIndex += 1) {
|
|
2882
|
+
const instance = previousInstances[sourceIndex];
|
|
2883
|
+
if (instance.index !== sourceIndex || instancesByItem.has(instance.item)) return void 0;
|
|
2884
|
+
instancesByItem.set(instance.item, instance);
|
|
2885
|
+
}
|
|
2886
|
+
const nextInstances = [];
|
|
2887
|
+
const sequence = [];
|
|
2888
|
+
for (let targetIndex = 0; targetIndex < finalValue.length; targetIndex += 1) {
|
|
2889
|
+
const item = finalValue[targetIndex];
|
|
2890
|
+
const instance = instancesByItem.get(item);
|
|
2891
|
+
if (!instance || !Object.is(instance.item, item)) return void 0;
|
|
2892
|
+
instancesByItem.delete(item);
|
|
2893
|
+
nextInstances.push(instance);
|
|
2894
|
+
sequence.push(instance.index);
|
|
2895
|
+
}
|
|
2896
|
+
if (instancesByItem.size > 0) return void 0;
|
|
2897
|
+
const activeElement2 = root.ownerDocument.activeElement;
|
|
2898
|
+
const restoreFocus2 = Boolean(activeElement2 && root.contains(activeElement2));
|
|
2899
|
+
const stablePositions = longestIncreasingSubsequencePositions(sequence);
|
|
2900
|
+
let anchor2 = null;
|
|
2901
|
+
for (let index = nextInstances.length - 1; index >= 0; index -= 1) {
|
|
2902
|
+
const instance = nextInstances[index];
|
|
2903
|
+
if (!stablePositions.has(index) && instance.element.nextSibling !== anchor2) {
|
|
2904
|
+
root.insertBefore(instance.element, anchor2);
|
|
2905
|
+
}
|
|
2906
|
+
anchor2 = instance.element;
|
|
2907
|
+
instance.index = index;
|
|
2908
|
+
}
|
|
2909
|
+
if (restoreFocus2 && activeElement2?.isConnected && activeElement2.ownerDocument.activeElement !== activeElement2 && "focus" in activeElement2) {
|
|
2910
|
+
activeElement2.focus({ preventScroll: true });
|
|
2911
|
+
}
|
|
2912
|
+
return new Map(nextInstances.map((instance) => [instance.key, instance]));
|
|
2913
|
+
} catch {
|
|
2914
|
+
return void 0;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2839
2917
|
try {
|
|
2840
2918
|
for (let sourceIndex = 0; sourceIndex < previousInstances.length; sourceIndex += 1) {
|
|
2841
2919
|
const instance = previousInstances[sourceIndex];
|
|
@@ -5147,6 +5225,7 @@ exports.createCompilerKeyedArrayPrepend = createCompilerKeyedArrayPrepend;
|
|
|
5147
5225
|
exports.createCompilerKeyedArrayReorder = createCompilerKeyedArrayReorder;
|
|
5148
5226
|
exports.createCompilerKeyedArrayRollingWindow = createCompilerKeyedArrayRollingWindow;
|
|
5149
5227
|
exports.createCompilerKeyedArraySlice = createCompilerKeyedArraySlice;
|
|
5228
|
+
exports.createCompilerKeyedArraySort = createCompilerKeyedArraySort;
|
|
5150
5229
|
exports.createCompilerKeyedCollectionUpdate = createCompilerKeyedCollectionUpdate;
|
|
5151
5230
|
exports.createCompilerKeyedMapUpdate = createCompilerKeyedMapUpdate;
|
|
5152
5231
|
exports.hostConditionalRuntimeFeature = hostConditionalRuntimeFeature;
|