From d0f42035c2ee521846a97e983686f14bf49eb446 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 7 Mar 2024 10:32:33 -0800 Subject: [PATCH 1/2] fix crash in MapRowProxyHandler.ownKeys --- js/src/row/map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/row/map.ts b/js/src/row/map.ts index d0ccb872ec3..436eb397370 100644 --- a/js/src/row/map.ts +++ b/js/src/row/map.ts @@ -107,7 +107,7 @@ class MapRowProxyHandler imp deleteProperty() { return false; } preventExtensions() { return true; } ownKeys(row: MapRow) { - return row[kKeys].toArray().map(String); + return Array.from(row[kKeys].toArray(), String); } has(row: MapRow, key: string | symbol) { return row[kKeys].includes(key); From 89b3de1345d8f4db39f48d242abf4f5fd083cd2f Mon Sep 17 00:00:00 2001 From: ptaylor Date: Tue, 16 Apr 2024 13:48:26 -0700 Subject: [PATCH 2/2] create getter for keys as strings, use getter for all key ops --- js/src/row/map.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/js/src/row/map.ts b/js/src/row/map.ts index 436eb397370..9f826f083b3 100644 --- a/js/src/row/map.ts +++ b/js/src/row/map.ts @@ -24,6 +24,8 @@ import { instance as setVisitor } from '../visitor/set.js'; /** @ignore */ export const kKeys = Symbol.for('keys'); /** @ignore */ export const kVals = Symbol.for('vals'); +/** @ignore */ export const kKeysAsStrings = Symbol.for('kKeysAsStrings'); +/** @ignore */ export const _kKeysAsStrings = Symbol.for('_kKeysAsStrings'); export class MapRow { @@ -31,6 +33,7 @@ export class MapRow { declare private [kKeys]: Vector; declare private [kVals]: Data; + declare private [_kKeysAsStrings]: string[]; constructor(slice: Data>) { this[kKeys] = new Vector([slice.children[0]]).memoize() as Vector; @@ -38,6 +41,11 @@ export class MapRow { return new Proxy(this, new MapRowProxyHandler()); } + /** @ignore */ + get [kKeysAsStrings]() { + return this[_kKeysAsStrings] || (this[_kKeysAsStrings] = Array.from(this[kKeys].toArray(), String)); + } + [Symbol.iterator]() { return new MapRowIterator(this[kKeys], this[kVals]); } @@ -107,13 +115,13 @@ class MapRowProxyHandler imp deleteProperty() { return false; } preventExtensions() { return true; } ownKeys(row: MapRow) { - return Array.from(row[kKeys].toArray(), String); + return row[kKeysAsStrings]; } has(row: MapRow, key: string | symbol) { - return row[kKeys].includes(key); + return row[kKeysAsStrings].includes(key as string); } getOwnPropertyDescriptor(row: MapRow, key: string | symbol) { - const idx = row[kKeys].indexOf(key); + const idx = row[kKeysAsStrings].indexOf(key as string); if (idx !== -1) { return { writable: true, enumerable: true, configurable: true }; } @@ -124,7 +132,7 @@ class MapRowProxyHandler imp if (Reflect.has(row, key)) { return (row as any)[key]; } - const idx = row[kKeys].indexOf(key); + const idx = row[kKeysAsStrings].indexOf(key as string); if (idx !== -1) { const val = getVisitor.visit(Reflect.get(row, kVals), idx); // Cache key/val lookups @@ -133,7 +141,7 @@ class MapRowProxyHandler imp } } set(row: MapRow, key: string | symbol, val: V) { - const idx = row[kKeys].indexOf(key); + const idx = row[kKeysAsStrings].indexOf(key as string); if (idx !== -1) { setVisitor.visit(Reflect.get(row, kVals), idx, val); // Cache key/val lookups @@ -149,4 +157,5 @@ Object.defineProperties(MapRow.prototype, { [Symbol.toStringTag]: { enumerable: false, configurable: false, value: 'Row' }, [kKeys]: { writable: true, enumerable: false, configurable: false, value: null }, [kVals]: { writable: true, enumerable: false, configurable: false, value: null }, + [_kKeysAsStrings]: { writable: true, enumerable: false, configurable: false, value: null }, });