@camstack/types 1.2.241 → 1.2.242

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.
@@ -90,10 +90,4 @@ export interface ContainerChildRef {
90
90
  * they are deliberately absent and fall through to type priority.
91
91
  */
92
92
  export declare const CONTAINER_CHILD_ROLE_PRIORITY: readonly string[];
93
- /**
94
- * The child a container stands for: the operator's pick when it still exists,
95
- * else the highest-priority type. `null` for a childless container — a caller
96
- * must decide what an empty container means for it, rather than being handed a
97
- * child that is not there.
98
- */
99
93
  export declare function resolveContainerPrimaryChild(children: readonly ContainerChildRef[], overrideEntityId: string | null | undefined, containerName?: string): ContainerChildRef | null;
package/dist/index.js CHANGED
@@ -42717,12 +42717,39 @@ function rank(type) {
42717
42717
  * must decide what an empty container means for it, rather than being handed a
42718
42718
  * child that is not there.
42719
42719
  */
42720
+ /**
42721
+ * Two names for the same thing, compared the way an integration writes them.
42722
+ *
42723
+ * An exact case-insensitive match was not enough, and the failure was total
42724
+ * rather than marginal. An ESPHome shutter arrives as a container named
42725
+ * `Tapparella-Cucina` whose children include the COVER, named `Tapparella
42726
+ * cucina`, and a device-presence entity carrying the slug verbatim,
42727
+ * `tapparella-cucina`. The slug matched the container exactly and the cover
42728
+ * did not, so the namesake tie-break handed the container to a connectivity
42729
+ * indicator — and the viewer's accessory panel, which correctly shows only
42730
+ * children with an actuating control, then rendered NOTHING. The operator saw
42731
+ * no shutters at all on cucina, studio and both veranda cameras (2026-09-22).
42732
+ *
42733
+ * `Markise` was the control case that proved the mechanism: there the cover
42734
+ * really is called exactly like its container, so it won and appeared.
42735
+ *
42736
+ * Separators are therefore normalised — `-`, `_` and whitespace are the same
42737
+ * character for this comparison, and runs of them collapse. The two candidates
42738
+ * then tie on the namesake and the decision falls through to `rank(type)`,
42739
+ * where `cover` is eighth and a `presence` entity is not listed at all. The
42740
+ * criterion keeps doing its job for a container whose child IS the namesake;
42741
+ * it stops being decided by which integration used a hyphen.
42742
+ */
42743
+ function sameName(childName, containerName) {
42744
+ const flatten = (v) => v.toLowerCase().replace(/[-_\s]+/g, " ").trim();
42745
+ return flatten(childName) === flatten(containerName);
42746
+ }
42720
42747
  function resolveContainerPrimaryChild(children, overrideEntityId, containerName) {
42721
42748
  if (overrideEntityId !== void 0 && overrideEntityId !== null) {
42722
42749
  const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
42723
42750
  if (picked !== void 0) return picked;
42724
42751
  }
42725
- const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && c.name.toLowerCase() === containerName.toLowerCase() ? 0 : 1;
42752
+ const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && sameName(c.name, containerName) ? 0 : 1;
42726
42753
  return [...children].toSorted((a, b) => roleRank(a.role) - roleRank(b.role) || namesake(a) - namesake(b) || rank(a.type) - rank(b.type))[0] ?? null;
42727
42754
  }
42728
42755
  //#endregion
package/dist/index.mjs CHANGED
@@ -42716,12 +42716,39 @@ function rank(type) {
42716
42716
  * must decide what an empty container means for it, rather than being handed a
42717
42717
  * child that is not there.
42718
42718
  */
42719
+ /**
42720
+ * Two names for the same thing, compared the way an integration writes them.
42721
+ *
42722
+ * An exact case-insensitive match was not enough, and the failure was total
42723
+ * rather than marginal. An ESPHome shutter arrives as a container named
42724
+ * `Tapparella-Cucina` whose children include the COVER, named `Tapparella
42725
+ * cucina`, and a device-presence entity carrying the slug verbatim,
42726
+ * `tapparella-cucina`. The slug matched the container exactly and the cover
42727
+ * did not, so the namesake tie-break handed the container to a connectivity
42728
+ * indicator — and the viewer's accessory panel, which correctly shows only
42729
+ * children with an actuating control, then rendered NOTHING. The operator saw
42730
+ * no shutters at all on cucina, studio and both veranda cameras (2026-09-22).
42731
+ *
42732
+ * `Markise` was the control case that proved the mechanism: there the cover
42733
+ * really is called exactly like its container, so it won and appeared.
42734
+ *
42735
+ * Separators are therefore normalised — `-`, `_` and whitespace are the same
42736
+ * character for this comparison, and runs of them collapse. The two candidates
42737
+ * then tie on the namesake and the decision falls through to `rank(type)`,
42738
+ * where `cover` is eighth and a `presence` entity is not listed at all. The
42739
+ * criterion keeps doing its job for a container whose child IS the namesake;
42740
+ * it stops being decided by which integration used a hyphen.
42741
+ */
42742
+ function sameName(childName, containerName) {
42743
+ const flatten = (v) => v.toLowerCase().replace(/[-_\s]+/g, " ").trim();
42744
+ return flatten(childName) === flatten(containerName);
42745
+ }
42719
42746
  function resolveContainerPrimaryChild(children, overrideEntityId, containerName) {
42720
42747
  if (overrideEntityId !== void 0 && overrideEntityId !== null) {
42721
42748
  const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
42722
42749
  if (picked !== void 0) return picked;
42723
42750
  }
42724
- const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && c.name.toLowerCase() === containerName.toLowerCase() ? 0 : 1;
42751
+ const namesake = (c) => containerName !== void 0 && containerName.length > 0 && c.name !== void 0 && sameName(c.name, containerName) ? 0 : 1;
42725
42752
  return [...children].toSorted((a, b) => roleRank(a.role) - roleRank(b.role) || namesake(a) - namesake(b) || rank(a.type) - rank(b.type))[0] ?? null;
42726
42753
  }
42727
42754
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.241",
3
+ "version": "1.2.242",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",