From 446df7b37ba8689385c2e173ba03c70b1d3c6eb6 Mon Sep 17 00:00:00 2001 From: Aravind Date: Fri, 18 Sep 2026 15:28:01 +0530 Subject: [PATCH] =?UTF-8?q?refactor(ts-migration):=20Phase=2011=20batch=20?= =?UTF-8?q?5=20=E2=80=94=20ui-tree=20and=20ui-editor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The eleven files that render and edit the node tree: six in `src/components/ui-tree/`, five in `src/components/ui-editor/`. The first `.jsx` -> `.tsx` of this phase. Renaming raised six errors, all in one file, and one annotation cleared all six. `UiNodeBoundary` is a class component declared `extends React.Component` with no type arguments, so both its props and its state are `{}` — which is why reading `this.props.node` and `this.state.failed` looked wrong. `UiNodeBoundaryProps` and `UiNodeBoundaryState` write down what the class already uses: `node` and `children`, and `failed` plus `forNode`. `forNode` is what stops the boundary staying latched after a broken node is hidden, so it is part of the contract rather than an implementation detail. Nothing else needed anything. That is the earlier batches paying off: these files consume `lib/ui`, which was typed in batch 1, so the tree and node values arriving here are already described. The `.jsx` -> `.tsx` move is the one that can change emitted output — esbuild's `tsx` loader elides unused imports where the `jsx` loader does not, which cost a 942-byte bundle change in Phase 10. It did not happen here: all eleven erase byte-identically, and the bundle hash is unchanged. ESLint now reports all eleven under their new extensions, checked by name rather than by count. That is the failure Phase 0 existed to prevent — `.tsx` outside the globs would have dropped them silently while `eslint .` went on exiting 0. Measured against `55ddaa1`: typecheck 9 errors, unchanged; no new error anywhere lint exit 0, 0 errors, 289 warnings, 11/11 linted by name npm test 1684/1691, the same 7 failures verbatim build exit 0, identical bundle hash 74d17e2d… type erasure 57/57 byte-identical across Phase 11 so far No baseline artifact touched. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8 --- .../{NodeInspector.jsx => NodeInspector.tsx} | 0 .../{NodePicker.jsx => NodePicker.tsx} | 0 .../{TreePanel.jsx => TreePanel.tsx} | 0 .../ui-editor/{UiEditor.jsx => UiEditor.tsx} | 0 src/components/ui-editor/{ops.js => ops.ts} | 0 ...tingProvider.jsx => UiEditingProvider.tsx} | 0 ...{UiNodeBoundary.jsx => UiNodeBoundary.tsx} | 22 ++++++++++++++++++- ...{UiTreeRenderer.jsx => UiTreeRenderer.tsx} | 0 ...{chartNodeTypes.jsx => chartNodeTypes.tsx} | 0 .../ui-tree/{nodeTypes.jsx => nodeTypes.tsx} | 0 ...tionNodeTypes.jsx => sectionNodeTypes.tsx} | 0 11 files changed, 21 insertions(+), 1 deletion(-) rename src/components/ui-editor/{NodeInspector.jsx => NodeInspector.tsx} (100%) rename src/components/ui-editor/{NodePicker.jsx => NodePicker.tsx} (100%) rename src/components/ui-editor/{TreePanel.jsx => TreePanel.tsx} (100%) rename src/components/ui-editor/{UiEditor.jsx => UiEditor.tsx} (100%) rename src/components/ui-editor/{ops.js => ops.ts} (100%) rename src/components/ui-tree/{UiEditingProvider.jsx => UiEditingProvider.tsx} (100%) rename src/components/ui-tree/{UiNodeBoundary.jsx => UiNodeBoundary.tsx} (81%) rename src/components/ui-tree/{UiTreeRenderer.jsx => UiTreeRenderer.tsx} (100%) rename src/components/ui-tree/{chartNodeTypes.jsx => chartNodeTypes.tsx} (100%) rename src/components/ui-tree/{nodeTypes.jsx => nodeTypes.tsx} (100%) rename src/components/ui-tree/{sectionNodeTypes.jsx => sectionNodeTypes.tsx} (100%) diff --git a/src/components/ui-editor/NodeInspector.jsx b/src/components/ui-editor/NodeInspector.tsx similarity index 100% rename from src/components/ui-editor/NodeInspector.jsx rename to src/components/ui-editor/NodeInspector.tsx diff --git a/src/components/ui-editor/NodePicker.jsx b/src/components/ui-editor/NodePicker.tsx similarity index 100% rename from src/components/ui-editor/NodePicker.jsx rename to src/components/ui-editor/NodePicker.tsx diff --git a/src/components/ui-editor/TreePanel.jsx b/src/components/ui-editor/TreePanel.tsx similarity index 100% rename from src/components/ui-editor/TreePanel.jsx rename to src/components/ui-editor/TreePanel.tsx diff --git a/src/components/ui-editor/UiEditor.jsx b/src/components/ui-editor/UiEditor.tsx similarity index 100% rename from src/components/ui-editor/UiEditor.jsx rename to src/components/ui-editor/UiEditor.tsx diff --git a/src/components/ui-editor/ops.js b/src/components/ui-editor/ops.ts similarity index 100% rename from src/components/ui-editor/ops.js rename to src/components/ui-editor/ops.ts diff --git a/src/components/ui-tree/UiEditingProvider.jsx b/src/components/ui-tree/UiEditingProvider.tsx similarity index 100% rename from src/components/ui-tree/UiEditingProvider.jsx rename to src/components/ui-tree/UiEditingProvider.tsx diff --git a/src/components/ui-tree/UiNodeBoundary.jsx b/src/components/ui-tree/UiNodeBoundary.tsx similarity index 81% rename from src/components/ui-tree/UiNodeBoundary.jsx rename to src/components/ui-tree/UiNodeBoundary.tsx index e959ec5..681554b 100644 --- a/src/components/ui-tree/UiNodeBoundary.jsx +++ b/src/components/ui-tree/UiNodeBoundary.tsx @@ -25,7 +25,27 @@ import React from 'react'; * the node it is holding changes, which is what makes removing the broken node * put the page right without a reload. */ -export class UiNodeBoundary extends React.Component { +/** + * `node` is the one this boundary holds; `children` is what it renders while + * that node is fine. Both optional, because the placeholder path reads them + * with `?.` and has always tolerated their absence. + */ +interface UiNodeBoundaryProps { + node?: any; + children?: React.ReactNode; +} + +/** + * `forNode` is how the reset works: it records which node the current `failed` + * belongs to, so a boundary does not stay latched after the broken node is + * hidden or removed. It is absent until the first `getDerivedStateFromProps`. + */ +interface UiNodeBoundaryState { + failed: boolean; + forNode?: any; +} + +export class UiNodeBoundary extends React.Component { constructor(props) { super(props); this.state = { failed: false }; diff --git a/src/components/ui-tree/UiTreeRenderer.jsx b/src/components/ui-tree/UiTreeRenderer.tsx similarity index 100% rename from src/components/ui-tree/UiTreeRenderer.jsx rename to src/components/ui-tree/UiTreeRenderer.tsx diff --git a/src/components/ui-tree/chartNodeTypes.jsx b/src/components/ui-tree/chartNodeTypes.tsx similarity index 100% rename from src/components/ui-tree/chartNodeTypes.jsx rename to src/components/ui-tree/chartNodeTypes.tsx diff --git a/src/components/ui-tree/nodeTypes.jsx b/src/components/ui-tree/nodeTypes.tsx similarity index 100% rename from src/components/ui-tree/nodeTypes.jsx rename to src/components/ui-tree/nodeTypes.tsx diff --git a/src/components/ui-tree/sectionNodeTypes.jsx b/src/components/ui-tree/sectionNodeTypes.tsx similarity index 100% rename from src/components/ui-tree/sectionNodeTypes.jsx rename to src/components/ui-tree/sectionNodeTypes.tsx