@torpor/view 1.1.1 → 1.1.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/dist/index.cjs +75 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +75 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -992,6 +992,22 @@ function getElementFragment(document, array, index, html, ns) {
|
|
|
992
992
|
return array[index].cloneNode(true);
|
|
993
993
|
}
|
|
994
994
|
//#endregion
|
|
995
|
+
//#region src/render/isServerComponent.ts
|
|
996
|
+
/**
|
|
997
|
+
* Whether a component function was compiled for SSR
|
|
998
|
+
*
|
|
999
|
+
* Server components are emitted as `async function`s taking
|
|
1000
|
+
* `(props, context, slots)` and returning a `{ body, head }` pair, while
|
|
1001
|
+
* client components are plain functions taking
|
|
1002
|
+
* `(parent, anchor, props, context, slots)`. Checking the function's
|
|
1003
|
+
* constructor distinguishes the two without calling it (which would start
|
|
1004
|
+
* the render). The name lives on the intrinsic `AsyncFunction` object, so
|
|
1005
|
+
* it survives minification.
|
|
1006
|
+
*/
|
|
1007
|
+
function isServerComponent(component) {
|
|
1008
|
+
return component.constructor?.name === "AsyncFunction";
|
|
1009
|
+
}
|
|
1010
|
+
//#endregion
|
|
995
1011
|
//#region src/render/hydrate.ts
|
|
996
1012
|
/**
|
|
997
1013
|
* Hydrates a component into an existing DOM tree
|
|
@@ -1000,6 +1016,7 @@ function getElementFragment(document, array, index, html, ns) {
|
|
|
1000
1016
|
* @param props An object containing component props
|
|
1001
1017
|
*/
|
|
1002
1018
|
function hydrate(parent, component, props, slots) {
|
|
1019
|
+
if (isServerComponent(component)) throw new Error("The component was compiled for SSR (it renders to an HTML string) and cannot be hydrated in the browser. Import the client build instead, e.g. with the '?client' import query");
|
|
1003
1020
|
context.hydrationNode = parent.firstChild;
|
|
1004
1021
|
context.rootRegion = newRegion(require_devContext.devContext.enabled ? "Root" : void 0);
|
|
1005
1022
|
context.previousRegion = context.rootRegion;
|
|
@@ -1018,6 +1035,7 @@ function hydrate(parent, component, props, slots) {
|
|
|
1018
1035
|
* @param props An object containing component props
|
|
1019
1036
|
*/
|
|
1020
1037
|
function mount(parent, component, props, slots) {
|
|
1038
|
+
if (isServerComponent(component)) throw new Error("The component was compiled for SSR (it renders to an HTML string) and cannot be mounted in the browser. Import the client build instead, e.g. with the '?client' import query");
|
|
1021
1039
|
if (parent.childElementCount > 0) throw new Error("The parent node must have no child elements");
|
|
1022
1040
|
while (parent.firstChild !== null) parent.firstChild.remove();
|
|
1023
1041
|
if (context.rootRegion === null) {
|
|
@@ -1139,8 +1157,14 @@ function nodeAnchor(node) {
|
|
|
1139
1157
|
if (isCommentNode(node) && node.data === "[") {
|
|
1140
1158
|
const startParent = node.parentNode;
|
|
1141
1159
|
let currentNode = nodeNext(node);
|
|
1142
|
-
const firstInside = currentNode;
|
|
1143
1160
|
node.remove();
|
|
1161
|
+
while (currentNode !== null && isCommentNode(currentNode) && currentNode.data === "^") {
|
|
1162
|
+
const next = currentNode.nextSibling;
|
|
1163
|
+
currentNode.remove();
|
|
1164
|
+
currentNode = next;
|
|
1165
|
+
context.hydrationNode = currentNode;
|
|
1166
|
+
}
|
|
1167
|
+
const firstInside = currentNode;
|
|
1144
1168
|
let level = 1;
|
|
1145
1169
|
while (currentNode !== null) {
|
|
1146
1170
|
if (isCommentNode(currentNode)) {
|
|
@@ -1151,9 +1175,10 @@ function nodeAnchor(node) {
|
|
|
1151
1175
|
const endNode = currentNode.nextSibling;
|
|
1152
1176
|
currentNode.remove();
|
|
1153
1177
|
if (context.hydrationNode === currentNode) context.hydrationNode = endNode;
|
|
1178
|
+
const firstContent = firstInside === currentNode ? null : firstInside;
|
|
1154
1179
|
const region = context.activeRegion;
|
|
1155
|
-
if (region.startNode === null
|
|
1156
|
-
setFirstInsideNode(endNode,
|
|
1180
|
+
if (region.startNode === null) region.startNode = firstContent ?? endNode;
|
|
1181
|
+
setFirstInsideNode(endNode, firstContent);
|
|
1157
1182
|
return endNode;
|
|
1158
1183
|
}
|
|
1159
1184
|
}
|
|
@@ -1433,6 +1458,52 @@ function runControlBranch(region, oldIndex, index) {
|
|
|
1433
1458
|
return true;
|
|
1434
1459
|
}
|
|
1435
1460
|
//#endregion
|
|
1461
|
+
//#region src/render/checkListKeys.ts
|
|
1462
|
+
const warnedByRegion = /* @__PURE__ */ new WeakMap();
|
|
1463
|
+
/**
|
|
1464
|
+
* DEV-ONLY: warns when a keyed `@for` list contains duplicate `@key` values.
|
|
1465
|
+
*
|
|
1466
|
+
* `runListItems` matches old and new rows by key (first match wins), so
|
|
1467
|
+
* duplicate keys make updates and removals hit the wrong rows, desyncing the
|
|
1468
|
+
* DOM from the data. Called from `runList` only when `devContext.enabled`, so
|
|
1469
|
+
* it never runs in a production build.
|
|
1470
|
+
*
|
|
1471
|
+
* `undefined`/`null` keys are the "unkeyed" case (rows are matched
|
|
1472
|
+
* positionally) and are ignored.
|
|
1473
|
+
*
|
|
1474
|
+
* @param region The `@for` list's region, used to dedupe warnings per list.
|
|
1475
|
+
* @param specs The new row specs, in order.
|
|
1476
|
+
*/
|
|
1477
|
+
function checkListKeys(region, specs) {
|
|
1478
|
+
let seen;
|
|
1479
|
+
for (let i = 0; i < specs.length; i++) {
|
|
1480
|
+
const key = specs[i].key;
|
|
1481
|
+
if (key === void 0 || key === null) continue;
|
|
1482
|
+
if (seen === void 0) seen = /* @__PURE__ */ new Set();
|
|
1483
|
+
if (!seen.has(key)) {
|
|
1484
|
+
seen.add(key);
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
let warned = warnedByRegion.get(region);
|
|
1488
|
+
if (warned === void 0) {
|
|
1489
|
+
warned = /* @__PURE__ */ new Set();
|
|
1490
|
+
warnedByRegion.set(region, warned);
|
|
1491
|
+
}
|
|
1492
|
+
if (!warned.has(key)) {
|
|
1493
|
+
warned.add(key);
|
|
1494
|
+
console.warn(`[torpor] Duplicate @key value ${formatKey(key)} in a keyed @for list. Keys must be unique, or updates and removals will affect the wrong rows.`);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
function formatKey(key) {
|
|
1499
|
+
try {
|
|
1500
|
+
const json = JSON.stringify(key);
|
|
1501
|
+
return json === void 0 ? String(key) : json;
|
|
1502
|
+
} catch {
|
|
1503
|
+
return String(key);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
//#endregion
|
|
1436
1507
|
//#region src/watch/deepWrap.ts
|
|
1437
1508
|
/**
|
|
1438
1509
|
* Wraps a value with `$watch` if it is a plain object (or Date/Map/Set) that
|
|
@@ -2250,6 +2321,7 @@ function runList(region, parent, anchor, buildItems, create, update, noWatch) {
|
|
|
2250
2321
|
const oldRegion = pushRegion(region, first);
|
|
2251
2322
|
first = false;
|
|
2252
2323
|
const newSpecs = buildItems();
|
|
2324
|
+
if (require_devContext.devContext.enabled) checkListKeys(region, newSpecs);
|
|
2253
2325
|
context.activeTarget = null;
|
|
2254
2326
|
listItems = runListItems(region, parent, anchor, listItems, newSpecs, create, update, noWatch);
|
|
2255
2327
|
popRegion(oldRegion);
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/Animation.ts","../src/render/addAnimation.ts","../src/render/addEvent.ts","../src/render/addElement.ts","../src/render/addFragment.ts","../src/render/applyProps.ts","../src/render/clearLayoutSlot.ts","../src/render/fillLayoutSlot.ts","../src/render/formatText.ts","../src/render/firstInsideNode.ts","../src/render/getFragment.ts","../src/render/getElementFragment.ts","../src/render/hydrate.ts","../src/render/mount.ts","../src/render/unmount.ts","../src/types/ListItemSpec.ts","../src/types/ListItem.ts","../src/render/newListItem.ts","../src/render/newRegion.ts","../src/render/nodeAnchor.ts","../src/render/nodeChild.ts","../src/render/nodeNext.ts","../src/render/nodeRootElement.ts","../src/render/nodeRoot.ts","../src/render/nodeSkip.ts","../src/render/popRegion.ts","../src/render/pushRegion.ts","../src/render/rerunRegionEffects.ts","../src/render/restoreHydration.ts","../src/render/runControl.ts","../src/render/runControlBranch.ts","../src/render/runList.ts","../src/render/runAwait.ts","../src/render/runTry.ts","../src/render/saveHydration.ts","../src/render/headElement.ts","../src/render/setAttribute.ts","../src/render/setDynamicElement.ts","../src/types/Bindable.ts","../src/watch/$batch.ts","../src/watch/$async.ts","../src/watch/$bind.ts","../src/watch/$cache.ts","../src/watch/$onmount.ts","../src/watch/$peek.ts","../src/watch/$pending.ts","../src/watch/$refresh.ts","../src/watch/$run.ts","../src/watch/$stream.ts","../src/watch/$unwrap.ts","../src/types/WatchOptions.ts","../src/watch/$watch.ts"],"mappings":";;;;;UAAyB;EACxB,WAAW,aAAa;EACxB,mBAAmB;;;;iBCCI,aAAa,IAAI,aAAa,QAAQ,WAAW,OAAO;;;iBCDxD,SACvB,IAAI,SACJ,cACA,YAAA,MAAkB,SAAS;;;;;;;;;;;;;;;;;;;;;;iBCiBJ,WAAW,MAAM,SAAS,QAAQ,YAAY,QAAQ;;;iBCnBtD,YACvB,UAAU,kBACV,QAAQ,YACR,QAAQ,aACR,UAAU,WACV,YAAY;;;iBCLW,WACvB,IAAI,SACJ,OAAO,iCACP;;;;;;;;;;iBCKuB,gBAAgB,QAAQ;;;;;;;;;;;;;;;;;;iBCYxB,eACvB,WAAW,WACX,MAAM,YACN,QAAQ,YACR,QAAQ,aACR,SAAS,OAAO,mBAChB,WAAW,OAAO,oBAChB;;;iBC5BqB,WAAW;;;;;;;;iBCiBX,gBAAgB,QAAQ,YAAY;;;iBCnBpC,YACvB,UAAU,UACV,OAAO,oBACP,eACA,cACA,eACE;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCkBqB,mBACvB,UAAU,UACV,OAAO,WACP,eACA,cACA,eACE;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/Animation.ts","../src/render/addAnimation.ts","../src/render/addEvent.ts","../src/render/addElement.ts","../src/render/addFragment.ts","../src/render/applyProps.ts","../src/render/clearLayoutSlot.ts","../src/render/fillLayoutSlot.ts","../src/render/formatText.ts","../src/render/firstInsideNode.ts","../src/render/getFragment.ts","../src/render/getElementFragment.ts","../src/render/hydrate.ts","../src/render/mount.ts","../src/render/unmount.ts","../src/types/ListItemSpec.ts","../src/types/ListItem.ts","../src/render/newListItem.ts","../src/render/newRegion.ts","../src/render/nodeAnchor.ts","../src/render/nodeChild.ts","../src/render/nodeNext.ts","../src/render/nodeRootElement.ts","../src/render/nodeRoot.ts","../src/render/nodeSkip.ts","../src/render/popRegion.ts","../src/render/pushRegion.ts","../src/render/rerunRegionEffects.ts","../src/render/restoreHydration.ts","../src/render/runControl.ts","../src/render/runControlBranch.ts","../src/render/runList.ts","../src/render/runAwait.ts","../src/render/runTry.ts","../src/render/saveHydration.ts","../src/render/headElement.ts","../src/render/setAttribute.ts","../src/render/setDynamicElement.ts","../src/types/Bindable.ts","../src/watch/$batch.ts","../src/watch/$async.ts","../src/watch/$bind.ts","../src/watch/$cache.ts","../src/watch/$onmount.ts","../src/watch/$peek.ts","../src/watch/$pending.ts","../src/watch/$refresh.ts","../src/watch/$run.ts","../src/watch/$stream.ts","../src/watch/$unwrap.ts","../src/types/WatchOptions.ts","../src/watch/$watch.ts"],"mappings":"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"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/Animation.ts","../src/render/addAnimation.ts","../src/render/addEvent.ts","../src/render/addElement.ts","../src/render/addFragment.ts","../src/render/applyProps.ts","../src/render/clearLayoutSlot.ts","../src/render/fillLayoutSlot.ts","../src/render/formatText.ts","../src/render/firstInsideNode.ts","../src/render/getFragment.ts","../src/render/getElementFragment.ts","../src/render/hydrate.ts","../src/render/mount.ts","../src/render/unmount.ts","../src/types/ListItemSpec.ts","../src/types/ListItem.ts","../src/render/newListItem.ts","../src/render/newRegion.ts","../src/render/nodeAnchor.ts","../src/render/nodeChild.ts","../src/render/nodeNext.ts","../src/render/nodeRootElement.ts","../src/render/nodeRoot.ts","../src/render/nodeSkip.ts","../src/render/popRegion.ts","../src/render/pushRegion.ts","../src/render/rerunRegionEffects.ts","../src/render/restoreHydration.ts","../src/render/runControl.ts","../src/render/runControlBranch.ts","../src/render/runList.ts","../src/render/runAwait.ts","../src/render/runTry.ts","../src/render/saveHydration.ts","../src/render/headElement.ts","../src/render/setAttribute.ts","../src/render/setDynamicElement.ts","../src/types/Bindable.ts","../src/watch/$batch.ts","../src/watch/$async.ts","../src/watch/$bind.ts","../src/watch/$cache.ts","../src/watch/$onmount.ts","../src/watch/$peek.ts","../src/watch/$pending.ts","../src/watch/$refresh.ts","../src/watch/$run.ts","../src/watch/$stream.ts","../src/watch/$unwrap.ts","../src/types/WatchOptions.ts","../src/watch/$watch.ts"],"mappings":";;;;;UAAyB;EACxB,WAAW,aAAa;EACxB,mBAAmB;;;;iBCCI,aAAa,IAAI,aAAa,QAAQ,WAAW,OAAO;;;iBCDxD,SACvB,IAAI,SACJ,cACA,YAAA,MAAkB,SAAS;;;;;;;;;;;;;;;;;;;;;;iBCiBJ,WAAW,MAAM,SAAS,QAAQ,YAAY,QAAQ;;;iBCnBtD,YACvB,UAAU,kBACV,QAAQ,YACR,QAAQ,aACR,UAAU,WACV,YAAY;;;iBCLW,WACvB,IAAI,SACJ,OAAO,iCACP;;;;;;;;;;iBCKuB,gBAAgB,QAAQ;;;;;;;;;;;;;;;;;;iBCYxB,eACvB,WAAW,WACX,MAAM,YACN,QAAQ,YACR,QAAQ,aACR,SAAS,OAAO,mBAChB,WAAW,OAAO,oBAChB;;;iBC5BqB,WAAW;;;;;;;;iBCiBX,gBAAgB,QAAQ,YAAY;;;iBCnBpC,YACvB,UAAU,UACV,OAAO,oBACP,eACA,cACA,eACE;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCkBqB,mBACvB,UAAU,UACV,OAAO,WACP,eACA,cACA,eACE;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/Animation.ts","../src/render/addAnimation.ts","../src/render/addEvent.ts","../src/render/addElement.ts","../src/render/addFragment.ts","../src/render/applyProps.ts","../src/render/clearLayoutSlot.ts","../src/render/fillLayoutSlot.ts","../src/render/formatText.ts","../src/render/firstInsideNode.ts","../src/render/getFragment.ts","../src/render/getElementFragment.ts","../src/render/hydrate.ts","../src/render/mount.ts","../src/render/unmount.ts","../src/types/ListItemSpec.ts","../src/types/ListItem.ts","../src/render/newListItem.ts","../src/render/newRegion.ts","../src/render/nodeAnchor.ts","../src/render/nodeChild.ts","../src/render/nodeNext.ts","../src/render/nodeRootElement.ts","../src/render/nodeRoot.ts","../src/render/nodeSkip.ts","../src/render/popRegion.ts","../src/render/pushRegion.ts","../src/render/rerunRegionEffects.ts","../src/render/restoreHydration.ts","../src/render/runControl.ts","../src/render/runControlBranch.ts","../src/render/runList.ts","../src/render/runAwait.ts","../src/render/runTry.ts","../src/render/saveHydration.ts","../src/render/headElement.ts","../src/render/setAttribute.ts","../src/render/setDynamicElement.ts","../src/types/Bindable.ts","../src/watch/$batch.ts","../src/watch/$async.ts","../src/watch/$bind.ts","../src/watch/$cache.ts","../src/watch/$onmount.ts","../src/watch/$peek.ts","../src/watch/$pending.ts","../src/watch/$refresh.ts","../src/watch/$run.ts","../src/watch/$stream.ts","../src/watch/$unwrap.ts","../src/types/WatchOptions.ts","../src/watch/$watch.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -991,6 +991,22 @@ function getElementFragment(document, array, index, html, ns) {
|
|
|
991
991
|
return array[index].cloneNode(true);
|
|
992
992
|
}
|
|
993
993
|
//#endregion
|
|
994
|
+
//#region src/render/isServerComponent.ts
|
|
995
|
+
/**
|
|
996
|
+
* Whether a component function was compiled for SSR
|
|
997
|
+
*
|
|
998
|
+
* Server components are emitted as `async function`s taking
|
|
999
|
+
* `(props, context, slots)` and returning a `{ body, head }` pair, while
|
|
1000
|
+
* client components are plain functions taking
|
|
1001
|
+
* `(parent, anchor, props, context, slots)`. Checking the function's
|
|
1002
|
+
* constructor distinguishes the two without calling it (which would start
|
|
1003
|
+
* the render). The name lives on the intrinsic `AsyncFunction` object, so
|
|
1004
|
+
* it survives minification.
|
|
1005
|
+
*/
|
|
1006
|
+
function isServerComponent(component) {
|
|
1007
|
+
return component.constructor?.name === "AsyncFunction";
|
|
1008
|
+
}
|
|
1009
|
+
//#endregion
|
|
994
1010
|
//#region src/render/hydrate.ts
|
|
995
1011
|
/**
|
|
996
1012
|
* Hydrates a component into an existing DOM tree
|
|
@@ -999,6 +1015,7 @@ function getElementFragment(document, array, index, html, ns) {
|
|
|
999
1015
|
* @param props An object containing component props
|
|
1000
1016
|
*/
|
|
1001
1017
|
function hydrate(parent, component, props, slots) {
|
|
1018
|
+
if (isServerComponent(component)) throw new Error("The component was compiled for SSR (it renders to an HTML string) and cannot be hydrated in the browser. Import the client build instead, e.g. with the '?client' import query");
|
|
1002
1019
|
context.hydrationNode = parent.firstChild;
|
|
1003
1020
|
context.rootRegion = newRegion(devContext.enabled ? "Root" : void 0);
|
|
1004
1021
|
context.previousRegion = context.rootRegion;
|
|
@@ -1017,6 +1034,7 @@ function hydrate(parent, component, props, slots) {
|
|
|
1017
1034
|
* @param props An object containing component props
|
|
1018
1035
|
*/
|
|
1019
1036
|
function mount(parent, component, props, slots) {
|
|
1037
|
+
if (isServerComponent(component)) throw new Error("The component was compiled for SSR (it renders to an HTML string) and cannot be mounted in the browser. Import the client build instead, e.g. with the '?client' import query");
|
|
1020
1038
|
if (parent.childElementCount > 0) throw new Error("The parent node must have no child elements");
|
|
1021
1039
|
while (parent.firstChild !== null) parent.firstChild.remove();
|
|
1022
1040
|
if (context.rootRegion === null) {
|
|
@@ -1138,8 +1156,14 @@ function nodeAnchor(node) {
|
|
|
1138
1156
|
if (isCommentNode(node) && node.data === "[") {
|
|
1139
1157
|
const startParent = node.parentNode;
|
|
1140
1158
|
let currentNode = nodeNext(node);
|
|
1141
|
-
const firstInside = currentNode;
|
|
1142
1159
|
node.remove();
|
|
1160
|
+
while (currentNode !== null && isCommentNode(currentNode) && currentNode.data === "^") {
|
|
1161
|
+
const next = currentNode.nextSibling;
|
|
1162
|
+
currentNode.remove();
|
|
1163
|
+
currentNode = next;
|
|
1164
|
+
context.hydrationNode = currentNode;
|
|
1165
|
+
}
|
|
1166
|
+
const firstInside = currentNode;
|
|
1143
1167
|
let level = 1;
|
|
1144
1168
|
while (currentNode !== null) {
|
|
1145
1169
|
if (isCommentNode(currentNode)) {
|
|
@@ -1150,9 +1174,10 @@ function nodeAnchor(node) {
|
|
|
1150
1174
|
const endNode = currentNode.nextSibling;
|
|
1151
1175
|
currentNode.remove();
|
|
1152
1176
|
if (context.hydrationNode === currentNode) context.hydrationNode = endNode;
|
|
1177
|
+
const firstContent = firstInside === currentNode ? null : firstInside;
|
|
1153
1178
|
const region = context.activeRegion;
|
|
1154
|
-
if (region.startNode === null
|
|
1155
|
-
setFirstInsideNode(endNode,
|
|
1179
|
+
if (region.startNode === null) region.startNode = firstContent ?? endNode;
|
|
1180
|
+
setFirstInsideNode(endNode, firstContent);
|
|
1156
1181
|
return endNode;
|
|
1157
1182
|
}
|
|
1158
1183
|
}
|
|
@@ -1432,6 +1457,52 @@ function runControlBranch(region, oldIndex, index) {
|
|
|
1432
1457
|
return true;
|
|
1433
1458
|
}
|
|
1434
1459
|
//#endregion
|
|
1460
|
+
//#region src/render/checkListKeys.ts
|
|
1461
|
+
const warnedByRegion = /* @__PURE__ */ new WeakMap();
|
|
1462
|
+
/**
|
|
1463
|
+
* DEV-ONLY: warns when a keyed `@for` list contains duplicate `@key` values.
|
|
1464
|
+
*
|
|
1465
|
+
* `runListItems` matches old and new rows by key (first match wins), so
|
|
1466
|
+
* duplicate keys make updates and removals hit the wrong rows, desyncing the
|
|
1467
|
+
* DOM from the data. Called from `runList` only when `devContext.enabled`, so
|
|
1468
|
+
* it never runs in a production build.
|
|
1469
|
+
*
|
|
1470
|
+
* `undefined`/`null` keys are the "unkeyed" case (rows are matched
|
|
1471
|
+
* positionally) and are ignored.
|
|
1472
|
+
*
|
|
1473
|
+
* @param region The `@for` list's region, used to dedupe warnings per list.
|
|
1474
|
+
* @param specs The new row specs, in order.
|
|
1475
|
+
*/
|
|
1476
|
+
function checkListKeys(region, specs) {
|
|
1477
|
+
let seen;
|
|
1478
|
+
for (let i = 0; i < specs.length; i++) {
|
|
1479
|
+
const key = specs[i].key;
|
|
1480
|
+
if (key === void 0 || key === null) continue;
|
|
1481
|
+
if (seen === void 0) seen = /* @__PURE__ */ new Set();
|
|
1482
|
+
if (!seen.has(key)) {
|
|
1483
|
+
seen.add(key);
|
|
1484
|
+
continue;
|
|
1485
|
+
}
|
|
1486
|
+
let warned = warnedByRegion.get(region);
|
|
1487
|
+
if (warned === void 0) {
|
|
1488
|
+
warned = /* @__PURE__ */ new Set();
|
|
1489
|
+
warnedByRegion.set(region, warned);
|
|
1490
|
+
}
|
|
1491
|
+
if (!warned.has(key)) {
|
|
1492
|
+
warned.add(key);
|
|
1493
|
+
console.warn(`[torpor] Duplicate @key value ${formatKey(key)} in a keyed @for list. Keys must be unique, or updates and removals will affect the wrong rows.`);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
function formatKey(key) {
|
|
1498
|
+
try {
|
|
1499
|
+
const json = JSON.stringify(key);
|
|
1500
|
+
return json === void 0 ? String(key) : json;
|
|
1501
|
+
} catch {
|
|
1502
|
+
return String(key);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
//#endregion
|
|
1435
1506
|
//#region src/watch/deepWrap.ts
|
|
1436
1507
|
/**
|
|
1437
1508
|
* Wraps a value with `$watch` if it is a plain object (or Date/Map/Set) that
|
|
@@ -2249,6 +2320,7 @@ function runList(region, parent, anchor, buildItems, create, update, noWatch) {
|
|
|
2249
2320
|
const oldRegion = pushRegion(region, first);
|
|
2250
2321
|
first = false;
|
|
2251
2322
|
const newSpecs = buildItems();
|
|
2323
|
+
if (devContext.enabled) checkListKeys(region, newSpecs);
|
|
2252
2324
|
context.activeTarget = null;
|
|
2253
2325
|
listItems = runListItems(region, parent, anchor, listItems, newSpecs, create, update, noWatch);
|
|
2254
2326
|
popRegion(oldRegion);
|