.ai/CONCERNS.md
Walkontable DAO Layer (Data Access Objects):
handsontable/src/3rdparty/walkontable/src/core/_base.js, handsontable/src/3rdparty/walkontable/src/core/core.js, handsontable/src/3rdparty/walkontable/src/table.jscreateScrollDao() and getTableDao() in _base.js.Broken Plugin Initialization Abstraction (#6806):
!this.hot.view) and force updatePlugin() calls during enablePlugin().handsontable/src/plugins/nestedHeaders/nestedHeaders.js, handsontable/src/plugins/collapsibleColumns/collapsibleColumns.jshandsontable/src/plugins/base/base.js and the core plugin registry to guarantee that this.hot.view is available before enablePlugin() is called. Remove all #6806 workarounds once fixed.EventManager Shared Listener Array:
EventManager mutates an external object's eventListeners array, and all EventManager instances sharing the same context share the same listener list.handsontable/src/eventManager.jsEventManager instance should maintain its own listener list. Provide a central registry only for debugging/leak detection purposes.Redundant Render Cycle Calls:
handsontable/src/plugins/hiddenColumns/hiddenColumns.js, handsontable/src/plugins/autoColumnSize/autoColumnSize.js, handsontable/src/plugins/autoRowSize/autoRowSize.jsbatchRender() / suspendRender() / resumeRender() infrastructure to coalesce these calls.core.js Monolith:
core.js is covering initialization, data manipulation, rendering coordination, selection management, and the entire public API surface. Functions use this binding via closure (constructor function pattern), not class syntax.handsontable/src/core.jshandsontable/src/core/ directory already contains some extractions (hooks/, coordsMapper/); continue this pattern.NestedRows ManualRowMove Reimplementation:
rowMoveController.js in nestedRows contains three TODO comments about "mocking real work" of the ManualRowMove plugin and reimplementing its internal function.handsontable/src/plugins/nestedRows/utils/rowMoveController.jsNestedRows and ManualRowMove plugins. Bugs fixed in one may not be fixed in the other.ManualRowMove as a proper API.CustomBorders Plugin Bugs:
handsontable/src/plugins/customBorders/__tests__/customBorders.spec.js, handsontable/src/plugins/customBorders/__tests__/hidingColumns.spec.jsDOMPurify Deprecation In Progress:
sanitizer option exists but the old path is still the default.handsontable/src/helpers/dom/element.js, handsontable/src/helpers/string.jsdompurify remains a runtime dependency (listed in package.json dependencies). Until removal, bundle size includes DOMPurify even when users provide a custom sanitizer.dompurify from dependencies. Make sanitizer option required or provide a lightweight built-in default.CustomBorders Enable/Disable State Mismatch:
getPlugin('customBorders').isEnabled() returns true when it should be false (and vice versa) after certain updateSettings() calls.handsontable/src/plugins/customBorders/__tests__/customBorders.spec.jscustomBorders: true, then call updateSettings({ customBorders: false }).CustomBorders Border Count Incorrect:
countVisibleCustomBorders() and countCustomBorders() return values that do not match expected counts. For a 5x5 selection, the test expects 10 * 5 borders and notes "I think this should be 5 * 5."handsontable/src/plugins/customBorders/__tests__/customBorders.spec.jsFlaky CustomBorders Test:
getCellMeta(0, 0).borders is sometimes undefined, causing Cannot read property 'hasOwnProperty' of undefined.handsontable/src/plugins/customBorders/__tests__/customBorders.spec.jsHTML Sanitization Transition Period:
innerHTML is sanitized by default using DOMPurify. If a user passes sanitizer: false or a weak custom sanitizer, XSS is possible in cell content.handsontable/src/helpers/dom/element.js, handsontable/src/helpers/string.jsfastInnerHTML function checks for HTML characters before applying innerHTML.sanitizer: false disables XSS protection. Add a console warning when sanitizer is set to a non-function falsy value. Consider keeping a lightweight built-in sanitizer after DOMPurify removal.innerHTML Usage in Template Literal Tag:
templateLiteralTag.js helper uses template.innerHTML to parse tagged template literals. If user-supplied data flows into the template, it could introduce XSS.handsontable/src/helpers/templateLiteralTag.jsDOMParser or textContent where possible.innerHTML in Mixed Helper:
helpers/mixed.js uses messageNode.innerHTML to render domain-specific messages.handsontable/src/helpers/mixed.jstextContent or DOM API construction to eliminate the innerHTML call entirely.Spread Operator with Potentially Large Arrays:
array.push(...otherArray) exist in production source code. With arrays of 10k+ elements, this causes stack overflow due to argument count limits.handsontable/src/dataMap/metaManager/metaLayers/cellMeta.js, handsontable/src/plugins/nestedRows/nestedRows.js, handsontable/src/plugins/nestedRows/ui/collapsing.js, handsontable/src/plugins/collapsibleColumns/collapsibleColumns.js, handsontable/src/plugins/hiddenRows/contextMenuItem/showRow.js, handsontable/src/plugins/hiddenColumns/contextMenuItem/showColumn.js, handsontable/src/core.jsFunction.prototype.apply (which spread desugars to) has a maximum argument count (~65k in V8, lower in other engines).arr.push(...largeArr) with for or forEach loops in all code paths that may handle large datasets. Priority: cellMeta.js handles per-cell metadata and scales with table size.Walkontable Filter Object Recreation:
rowFilter and columnFilter are set to null and recreated on every render pass instead of updating state in place. Two TODO comments acknowledge this.handsontable/src/3rdparty/walkontable/src/table.jsLimited requestAnimationFrame Batching:
requestAnimationFrame is used in only 7 source files, primarily in autoRowSize, autoColumnSize, and the overlay system. Scroll events and resize operations in other areas may not be batched.handsontable/src/helpers/feature.js, handsontable/src/utils/interval.js, handsontable/src/3rdparty/walkontable/src/overlays.js, handsontable/src/plugins/autoRowSize/autoRowSize.js, handsontable/src/plugins/autoColumnSize/autoColumnSize.jsrequestAnimationFrame.Selection + MergeCells Interaction:
handsontable/src/selection/highlight/visualSelection.js, handsontable/src/selection/selection.js, handsontable/src/plugins/mergeCells/mergeCells.jsselection.clear() method has a TODO noting that selectedByColumnHeader and selectedByRowHeader collections should be cleared but are not.selectAll and selectCells spec suites.NestedHeaders + CollapsibleColumns:
handsontable/src/plugins/nestedHeaders/nestedHeaders.js, handsontable/src/plugins/collapsibleColumns/collapsibleColumns.jsNestedHeaders has 4 workaround sites, CollapsibleColumns has 3. These workarounds involve conditional state checks and forced updatePlugin() calls that mask timing issues.collapsibleColumns.spec.js and hidingColumns.spec.js in nested headers.Overlay System (Walkontable):
handsontable/src/3rdparty/walkontable/src/overlays.js, handsontable/src/3rdparty/walkontable/src/overlay/top.js, handsontable/src/3rdparty/walkontable/src/overlay/inlineStart.js, handsontable/src/3rdparty/walkontable/src/overlay/bottom.jsinnerBorderTop that is documented to be clearable only after SVG borders are merged. Lazy creation of corner overlays adds initialization complexity.fixedRowsTop, fixedRowsBottom, fixedColumnsStart. Test RTL layout. Verify no visual artifacts at overlay boundaries.npm run test:walkontable), separate from the main E2E tests.Cell Metadata Storage:
cellMeta.js layer uses push(...values()) to collect metadata, which risks stack overflow at large scales (50k+ rows with many columns).moment.js (pinned at 2.30.1):
dateFormat string options (using moment format patterns) is already underway.numbro (pinned at 2.5.0):
numericFormat.pattern and numericFormat.culture options using numbro are deprecated.handsontable/src/dataMap/metaManager/metaSchema.js (line 4098). Complete migration to native Intl.NumberFormat.TypeScript 3.8.2:
.d.ts type definitions in handsontable/types/ are limited to TS 3.8 features.@typescript-eslint/parser and plugin (^4.33.0):
ESLint ^7.25.0:
@typescript-eslint packages simultaneously.Jest ^27.5.1 and jasmine-core ^3.4.0:
babel-jest and potentially test configuration). Evaluate Jasmine upgrade separately due to API changes.@handsontable/pikaday (^1.0.0):
dateEditor is being deprecated (string-based dateFormat with Pikaday). Only 6 source files reference it.No Centralized Render Scheduler:
batchRender()/suspendRender()/resumeRender() API exists but is opt-in and used in only 4 source files.No Plugin Integration Testing Framework:
MergeCells + HiddenColumns + NestedHeaders) are tested via E2E specs but lack a structured integration test approach. Each combination must be manually tested.TouchScroll Plugin:
touchScroll plugin has 2 source files and 0 test files. Touch-specific scrolling behavior is entirely untested.handsontable/src/plugins/touchScroll/Walkontable DAO Layer:
_base.js are not unit tested. They are exercised only indirectly through higher-level integration tests.handsontable/src/3rdparty/walkontable/src/core/_base.jsVisual Selection Highlight Internals:
visualSelection.js with MergeCells interaction has TODO comments but no dedicated unit tests.handsontable/src/selection/highlight/visualSelection.jsEvent Manager Scope Filtering:
handsontable/src/eventManager.js