Use when developing or modifying the @handsontable/angular-wrapper package - Angular components with decorators, NgZone performance optimization, and ng-packagr build system
日本語の概要は準備中です。原文の説明を表示しています。
Use for ANY work touching the `handsontable/` core package: fixing bugs, adding features, modifying TypeScript types, removing as-casts, writing or debugging plugins, editors, renderers, validators, cell types, hooks, shortcuts, selection, helpers, index translations, or i18n. Also use for how-to questions about core internals (plugin lifecycle, coordinate systems, hook registration, TypeScript conventions). Triggers on file paths under `handsontable/src/` (excluding `3rdparty/walkontable/` which has its own skill), or when the user describes a symptom in the core grid without naming a file. This is the primary entry point for all core Handsontable development, when in doubt, load it.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Load handsontable-code-review (architecture dimension) first for every change, then the task-specific specialist. It is the design lens (SOLID, Law of Demeter, plugin decoupling, breaking changes); the task skill is the implementation guide.
| Task | Skill |
|---|---|
| Create / modify a plugin | handsontable-plugin-dev |
| Create / modify an editor | handsontable-editor-dev |
| Create / modify a renderer | handsontable-renderer-dev |
| Create / modify a validator | handsontable-validator-dev |
| Create / modify a cell type | handsontable-celltype-dev |
| Write a new E2E test | handsontable-playwright-e2e (Playwright, tests/e2e/) |
Maintain a legacy E2E test (*.spec.js, frozen) | handsontable-e2e-testing |
Write / modify unit tests (*.unit.js or *.unit.ts) | handsontable-unit-testing |
| Make a test actually prove behavior | test-writing-discipline |
| Build a demo / test page | handsontable-demo-page |
| Work on CSS / themes | handsontable-css-dev |
| Walkontable rendering engine | walkontable-dev / walkontable-testing |
| A rendering-engine geometry change needs a spec (viewport, overlays, sizing, scroll sync) | engine tier: edit an existing walkontable Jasmine spec, or add new coverage in tests/e2e/walkontable/*.spec.ts (walkontable-dev, Testing) |
| Lint violations | handsontable/AGENTS.md (Lint) + handsontable/.ai/CONVENTIONS.md |
| Coordinate translation (physical/visual/renderable) | coordinate-systems |
| i18n / translations | i18n-translations |
| Visual regression tests | visual-testing |
| Docs pages | writing-docs-pages |
handsontable-code-reviewFull checklist: its references/architecture.md.
hot.getPlugin('Name'). No circular plugin dependencies.registerConflict() from src/plugins/base/conflictRegistry.ts at module load time.TableView or Core for Walkontable data, not this.hot.view.wt.wtTable chains.BasePlugin contract (lifecycle methods + static properties).cell → column → global where applicable; document table-level-only options (like data) in JSDoc.src/plugins/pagination/pagination.ts (plugin structure, settings validation, conflict registration, focus management).src/plugins/{pluginName}/ index.ts, {pluginName}.ts, types.ts?, __tests__/,
AGENTS.md + CLAUDE.md->AGENTS.md (required)
src/editors/{editorName}/ index.ts, {editorName}.ts
src/renderers/{rendererName}/ index.ts, {rendererName}.ts
src/validators/{validatorName}/ index.ts, {validatorName}.ts
src/cellTypes/{typeName}/ index.ts, {typeName}.ts
Unit tests are *.unit.js or *.unit.ts. New E2E is Playwright (tests/e2e/*.spec.ts); the Jasmine *.spec.js suite is frozen (edit existing specs, migrate broken ones to Playwright). .d.ts files are generated by npm run build:types into handsontable/tmp/.
as castsNew code adds no as casts (as SomeType, <SomeType>value). Treat the urge to write one as a wrong type upstream. Exhaust these in order: (1) make the function/method signature generic; (2) make the shared entity generic; (3) narrow with a type guard; (4) use unknown only at a true I/O boundary. A cast is acceptable only when none apply (external/normalization boundary, known TS generic-inference gap) and carries a comment saying why. as unknown as T (double cast) is banned. Use unknown instead of any at boundaries, then narrow. After removing casts, rerun npm run test:types; some are load-bearing.
// ✗ function getFirst(items: unknown[]): SomeRow { return items[0] as SomeRow; }
// ✓ function getFirst<T>(items: T[]): T { return items[0]; }
Fix the type at its source. When the same cast repeats across consumers, make the shared structure generic with a permissive default so existing callers compile unchanged:
class TreeNode<T extends object = Record<string, unknown>> {
data: T;
walkDown(cb: (node: TreeNode<T>) => unknown) { /* ... */ }
}
Example: src/utils/dataStructures/tree.ts TreeNode<T>, consumed by nestedHeaders as TreeNode<HeaderNodeData>.
Use isHTMLElement from src/helpers/dom/element.ts (for a Node | Element | null value) instead of x as HTMLElement, x instanceof HTMLElement, or a nodeType === Node.ELEMENT_NODE guard.
.d.ts filesDeclarations are generated from source into handsontable/tmp/ only: hand-write no .d.ts anywhere (there is no separate types/ mirror) and edit nothing under tmp/. If a type is missing from the public API, fix the JSDoc/export in the .ts source and rerun npm run build:types.
import type for typesimport type { HotInstance } from '../../core/types';
core/| Type | Location |
|---|---|
GridSettings, Events, HookKey | src/core/settings.ts |
HotInstance | src/core/types.ts |
| Plugin-local types | the plugin's own types.ts |
Import these types; never paste a partial copy of GridSettings/HotInstance into the file you are editing (a local copy drifts from the real signature). When the existing type is too wide, narrow it with a generic parameter or type guard at the boundary. Consumers import the same types from the package (import type { GridSettings } from 'handsontable'); see docs/content/guides/tools-and-building/typescript-types/typescript-types.md.
Adding a new hook:
GridSettings in src/core/settings.ts.src/core/hooks/constants.ts / src/core/hooks/index.ts.Hooks.getSingleton().register('myHook') at module level in the plugin file.#, callbacks are arrow-function class fieldsclass MyPlugin extends BasePlugin {
#map: HidingMap | null = null;
#onAfterRender = (): void => { /* `this` is bound */ };
}
@private JSDoc tags and .bind(this) are forbidden.
Extract a helper to fix a violation.
| Rule | What to do |
|---|---|
No throw new Error() | throwWithCause('...', cause) from src/helpers/errors.ts |
No window / document / console globals | this.hot.rootWindow, this.hot.rootDocument, helpers from src/helpers/console.ts |
No raw setTimeout / setInterval | this.hot._registerTimeout(fn, delay) (auto-clears on hot.destroy()) |
| No barrel imports | Import from the specific submodule path (plugins/index, editors/index, renderers/index, validators/index, cellTypes/index, i18n/index are off limits). Only src/registry.ts may use barrels. |
| No direct cross-plugin imports | Hooks or this.hot.getPlugin('Name') |
it() in *.spec.js must be async | async with await when calling HOT rendering APIs |
No native toLocaleLowerCase(locale) | localeLowerCase(value, locale) from helpers/string (enforced by no-restricted-syntax) |
jsdoc/require-jsdoc is error for src/**/*.ts and scripts/**/*.mjs: every class, method, function declaration, and class field needs a block. Test and type files (*.unit.ts, *.spec.ts, *.types.ts, *.d.ts) are exempt.
AGENTS.md), with a blank line before /** and after */.{Type} in every @param and @returns, public or private. docs:api (jsdoc-to-markdown) reads compiled handsontable/tmp/ and prints these types in the API reference. Keep them in sync with the TS signature ({number|object} for number | { from: number; to: number }). The TS [80004] warning is suppressed for .ts source.{Type} must parse as JSDoc (catharsis), not TypeScript. A tuple breaks docs:api with Invalid type expression. Write @type {Array<number> | null} and keep the tuple on the TS annotation (#pastePlan: [number, number, number, number] | null). No PR check catches this: the docs path filter in .github/workflows/checks.yml covers docs/** and handsontable/package.json, not handsontable/src/**, so the break surfaces as a failing Docs Staging Deployment on the next unrelated push touching docs/**. After a JSDoc type change, build the package and run npm --prefix docs run docs:api.# fields: a description block, no @private.colspan/rowspan from hot.getCellMeta(row, col), not td.colSpan / td.rowSpan. MergeCells sets cellProperties.colspan via afterGetCellMeta; the DOM attribute may be missing outside the viewport and ignores custom afterGetCellMeta overrides.hot.rowIndexMapper / hot.columnIndexMapper (coordinate-systems skill).src/i18n/constants.ts and translations to every file in src/i18n/languages/.| Component | Wire into |
|---|---|
| Plugin | src/plugins/index.ts |
| Editor | src/editors/index.ts + src/editors/factory.ts |
| Renderer | src/renderers/index.ts + src/renderers/factory.ts |
| Validator | src/validators/index.ts |
| Cell type | src/cellTypes/index.ts |
| Any new option / hook | src/dataMap/metaManager/metaSchema.ts + src/core/settings.ts |
npm run build:types # step 1: tsc emits tmp/**/*.d.ts
npm run downlevel:types # step 2: rewrites post-TS-5.1 lib types to TS 5.1 equivalents
npm run build runs both. Run after any change to the public type surface (new export, changed parameter type, new GridSettings option). Wrappers consume handsontable/tmp/.
The dev compiler is TS 6, which infers ArrayIterator, IteratorObject (TS 5.6+) and WeakKey (TS 5.2+), absent from TS 5.1. scripts/downlevel-dts.mjs swaps them for IterableIterator<T> / object. CI job verify-emitted-types runs tsc@5.1.6 --noEmit against tmp/ and reports the leaked identifier as TS2304: Cannot find name '...'. Fix by either annotating the source with the TS 5.1 type (: IterableIterator<T>, WeakMap<object, V>) or adding a row to REPLACEMENTS in scripts/downlevel-dts.mjs.
.tsas / any casts introduced.d.ts files hand-edited*.unit.js or *.unit.ts), pure logic, no mockstests/e2e/ (new); legacy *.spec.js suite is frozennpm run build (or build:types + downlevel:types) run if public types changedmetaSchema.ts if a new option was introduced{Type} in every @param/@returns, in sync with the TS signature; no @private on # fields)bin/changelog entry)まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when developing or modifying the @handsontable/angular-wrapper package - Angular components with decorators, NgZone performance optimization, and ng-packagr build system
日本語の概要は準備中です。原文の説明を表示しています。
Use when testing a local or public URL on a real device via BrowserStack, opening a live browser session on Android, iOS, or desktop browsers, or when the user mentions BrowserStack, real device testing, mobile testing, cross-browser testing, touch testing, or wants to verify behavior on a specific phone, tablet, or browser version. Also trigger when the user says "test this on Android/iPhone/Safari/Chrome mobile", asks to open a live session, or mentions demo-mobile.html, even if they don't mention BrowserStack by name.
日本語の概要は準備中です。原文の説明を表示しています。
Use when a source code change needs a changelog entry, or before committing and pushing any bug fix, feature, or behavior change to source code - detecting when entries are required, categorizing changes correctly (added/changed/fixed/deprecated/removed/security), writing user-facing titles, and creating the JSON entry in .changelogs/
日本語の概要は準備中です。原文の説明を表示しています。
Query the pre-built code-review-graph knowledge graph (Tree-sitter, whole monorepo) instead of walking call chains with Grep+Read – 2-6x cheaper, and it catches dynamic dispatch that grep misses. Use for ANY task that spans multiple files, even when the user never mentions a graph or asks for it - fixing or tracing a bug ("fix this bug", "why does X happen", "trace this"), exploring unfamiliar code ("how does X work", "who calls X", "what imports Y", "where is X used or handled"), planning or doing a refactor ("rename X", "is it safe to change or remove X", "what would break", "blast radius", "find dead code"), or reviewing changes ("review this PR", "review this branch or diff"). When you are about to Grep for a symbol's callers, callees, or importers, use this skill.
日本語の概要は準備中です。原文の説明を表示しています。
Use when working with row or column indexes in Handsontable - translating between physical, visual, and renderable coordinates, using IndexMapper, or debugging index-related bugs where rows or columns appear in wrong positions
日本語の概要は準備中です。原文の説明を表示しています。
Use when creating code examples for documentation pages - JavaScript, TypeScript, React, Angular, and Vue variants with proper imports, registration, and license key
日本語の概要は準備中です。原文の説明を表示しています。