Skip to content

Commit a5b4daf

Browse files
committed
fix(data-table): guard resolvePath pathCache.delete and segments
- guard resolvePath pathCache.delete key - guard resolvePath segments before reduce
1 parent ff700e3 commit a5b4daf

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

src/DataTable/data-table-utils.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,13 @@ const RE_IGNORE_ROW_CLICK = /^bx--(overflow-menu|checkbox|radio-button)/;
141141
/**
142142
* Returns true if the element's class list indicates the click target
143143
* is an overflow menu, checkbox, or radio button (row click should be ignored).
144-
* @param {EventTarget} target - The event target (e.g., from a click event)
144+
* @param {EventTarget | null} target - The event target (e.g., from a click event)
145145
* @returns {boolean}
146146
*/
147147
export function shouldIgnoreRowClick(target) {
148148
if (!target || !("classList" in target)) return false;
149-
return [...target.classList].some((name) => RE_IGNORE_ROW_CLICK.test(name));
149+
const el = /** @type {HTMLElement} */ (target);
150+
return [...el.classList].some((name) => RE_IGNORE_ROW_CLICK.test(name));
150151
}
151152

152153
const PATH_SPLIT_REGEX = /[.[\]'"]/;
@@ -171,16 +172,25 @@ export function resolvePath(object, path) {
171172
if (segments.length > 1) {
172173
if (pathCache.size >= MAX_PATH_CACHE_SIZE) {
173174
const firstKey = pathCache.keys().next().value;
174-
pathCache.delete(firstKey);
175+
if (firstKey !== undefined) {
176+
pathCache.delete(firstKey);
177+
}
175178
}
176179
pathCache.set(path, segments);
177180
}
178181
}
179182

180-
return segments.reduce(
181-
/** @type {(acc: unknown, prop: string) => unknown} */
182-
(o, p) => (o && typeof o === "object" ? o[p] : o),
183-
/** @type {unknown} */ (object),
183+
return (segments ?? []).reduce(
184+
/**
185+
* @param {unknown} acc
186+
* @param {string} p
187+
* @returns {unknown}
188+
*/
189+
(acc, p) =>
190+
acc && typeof acc === "object"
191+
? /** @type {Record<string, unknown>} */ (acc)[p]
192+
: acc,
193+
object,
184194
);
185195
}
186196

tests/DataTable/data-table-utils.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ describe("resolvePath", () => {
624624
expect(resolvePath(obj, "contact.company")).toBeUndefined();
625625
});
626626

627+
it("returns undefined for single-segment path not in object (segments reduce guard)", () => {
628+
const obj = { a: 1 };
629+
expect(resolvePath(obj, "b")).toBeUndefined();
630+
});
631+
627632
it("handles null and undefined in path resolution", () => {
628633
const obj = {
629634
contact: null,
@@ -681,7 +686,7 @@ describe("resolvePath", () => {
681686
expect(result3).toBe("Other Corp");
682687
});
683688

684-
it("handles cache size limit to prevent memory leaks", () => {
689+
it("handles cache size limit to prevent memory leaks (also guards pathCache.delete key)", () => {
685690
const paths = Array.from(
686691
{ length: 1000 + 1 },
687692
(_, i) => `level${i}.nested.value`,

0 commit comments

Comments
 (0)