Publishes `tableExtension: WordsExtension` in `extensions/table/table-extension.ts` with the three static facets we can ship without touching the engine: - `nodeTypes`: ['table', 'table-row', 'table-cell'] - `factories`: typed constructors for the three node types - `commandNames`: the 12 public table commands (insertTable, deleteTableRow, toggleTableHeaderRow, setTableCellTone, …) mapped to internal operation types (1:1 today). The dynamic hooks (`render`, `normalize`, `serialize`, `path`, `keyboard`, `commands`, `events`) are intentionally absent — F2.3f-h port each one incrementally. The engine does NOT yet consume the registry; the stub publishes the shape the engine will respect once F2.3i full lands. 6 smoke tests verify the public shape (nodeTypes, factories produce valid nodes, registry registers cleanly + finds by every nodeType, all 12 command names exposed, hooks intentionally absent, default 1×1 table). 102/102 in extensions + engine scope, 149/149 in full words soma scope. CONTINUE.md updated to reflect F2.3i-stub done + next-session order (F2.3h first, then F2.3f/g — F2.3i full wire-up follows F2.3h). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>active-uix
parent
54cd1744c7
commit
bde6728590
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Table extension — entrypoint that materialises the `WordsExtension`
|
||||||
|
* contract for the table node tree (`table` → `table-row` → `table-cell`).
|
||||||
|
*
|
||||||
|
* **F2.3i stub stage**: this file currently declares only the three
|
||||||
|
* static facets of the extension that we can publish without touching
|
||||||
|
* the engine's hardcoded branches:
|
||||||
|
*
|
||||||
|
* 1. `nodeTypes` — the three node `type` strings owned by the extension.
|
||||||
|
* 2. `factories` — typed constructors so callers can build empty
|
||||||
|
* `table` / `table-row` / `table-cell` nodes without importing
|
||||||
|
* the engine internals.
|
||||||
|
* 3. `commandNames` — the public command-name registry. Every
|
||||||
|
* table-related command in `engine/commands.ts` is mirrored here
|
||||||
|
* so the registry knows which public command belongs to this
|
||||||
|
* extension. The internal operation type matches the public name
|
||||||
|
* 1:1 today (no renames pending).
|
||||||
|
*
|
||||||
|
* The dynamic hooks (`render`, `normalize`, `serialize`, `path`,
|
||||||
|
* `keyboard`, `commands`) are intentionally absent. F2.3f-h port each
|
||||||
|
* one of those incrementally, at which point this object grows new
|
||||||
|
* fields; the public shape (this file) stays stable.
|
||||||
|
*
|
||||||
|
* The engine does NOT yet consult the registry at runtime — render /
|
||||||
|
* normalize / serialize / path / commands still hardcode the `table`
|
||||||
|
* branch. The extension is published so consumers (tests, future
|
||||||
|
* tooling, the eventual engine boot wire-up) can already see the shape
|
||||||
|
* the engine will respect once F2.3i full lands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { WordsExtension, WordsExtensionNode } from '../extension-types';
|
||||||
|
import {
|
||||||
|
createTable,
|
||||||
|
createTableCell,
|
||||||
|
createTableRow
|
||||||
|
} from './factories';
|
||||||
|
|
||||||
|
// Erase the typed factories to the registry's uniform shape. The factory
|
||||||
|
// functions remain individually typed for callers that import them
|
||||||
|
// directly; this adapter is only the contract-boundary view.
|
||||||
|
type ErasedFactory = (...args: ReadonlyArray<unknown>) => WordsExtensionNode;
|
||||||
|
|
||||||
|
const tableFactory = ((...args: ReadonlyArray<unknown>) =>
|
||||||
|
createTable(...(args as Parameters<typeof createTable>))) as ErasedFactory;
|
||||||
|
|
||||||
|
const tableRowFactory = ((...args: ReadonlyArray<unknown>) =>
|
||||||
|
createTableRow(...(args as Parameters<typeof createTableRow>))) as ErasedFactory;
|
||||||
|
|
||||||
|
const tableCellFactory = ((...args: ReadonlyArray<unknown>) =>
|
||||||
|
createTableCell(...(args as Parameters<typeof createTableCell>))) as ErasedFactory;
|
||||||
|
|
||||||
|
export const tableExtension: WordsExtension = {
|
||||||
|
name: 'table',
|
||||||
|
version: '1.0.0',
|
||||||
|
nodeTypes: ['table', 'table-row', 'table-cell'],
|
||||||
|
factories: {
|
||||||
|
table: tableFactory,
|
||||||
|
'table-row': tableRowFactory,
|
||||||
|
'table-cell': tableCellFactory
|
||||||
|
},
|
||||||
|
commandNames: {
|
||||||
|
// Public command name → internal operation type. They match 1:1
|
||||||
|
// today; the indirection lets us rename one side without breaking
|
||||||
|
// the other when needed.
|
||||||
|
insertTable: 'insertTable',
|
||||||
|
insertTableRow: 'insertTableRow',
|
||||||
|
insertTableColumn: 'insertTableColumn',
|
||||||
|
deleteTableRow: 'deleteTableRow',
|
||||||
|
deleteTableColumn: 'deleteTableColumn',
|
||||||
|
moveTableCell: 'moveTableCell',
|
||||||
|
toggleTableHeaderRow: 'toggleTableHeaderRow',
|
||||||
|
toggleTableHeaderColumn: 'toggleTableHeaderColumn',
|
||||||
|
toggleTableStriped: 'toggleTableStriped',
|
||||||
|
toggleTableCompact: 'toggleTableCompact',
|
||||||
|
setTableCellTone: 'setTableCellTone',
|
||||||
|
setTableCellVerticalAlign: 'setTableCellVerticalAlign'
|
||||||
|
}
|
||||||
|
// render / normalize / serialize / path / keyboard / commands /
|
||||||
|
// events / dispose intentionally absent — see file header.
|
||||||
|
} satisfies WordsExtension;
|
||||||
Loading…
Reference in new issue