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