refactor(core): scaffold node-registry + split styles.ts into per-theme files#77
Merged
refactor(core): scaffold node-registry + split styles.ts into per-theme files#77
Conversation
…me files
PR 1 of the monolith split. Lays the foundation for migrating each node
type into a self-contained module under packages/core/src/nodes/<type>/
and splits the 3,900-line styles.ts into one file per visual theme.
Scaffold:
- nodes/_contract.ts — NodeDefinition<K> contract with per-target
render functions (HTML / React / Tailwind have genuinely different
context shapes; modeling them as one would force a bad union).
TransformContext exposes peekNext / consumeNext / parseAttributes
for parser-side migrations.
- nodes/_registry.ts — empty static registry + getNodeDefinition lookup.
- nodes/_helpers.ts — re-exports for shared helpers used by node modules.
- Registry-first dispatch hooks added to html-renderer, react-renderer,
tailwind-renderer. With the registry empty, behavior is unchanged —
all paths fall through to the existing switches.
Styles split:
- renderer/styles/{sketch,clean,wireframe,none,tailwind,material,brutal}.ts
— one file per theme, ~135–730 lines each.
- renderer/styles/_structural.ts — shared structural CSS for tabs, rows,
comments, demo blocks (previously inline in getStyleCSS).
- renderer/styles/index.ts — dispatcher; exports getStyleCSS unchanged.
- renderer/styles.ts — thin re-export shim for the legacy import path.
Verification:
- pnpm typecheck: clean
- pnpm test: 1,153 / 1,153 passing
- pnpm review:refresh: zero snapshot drift ("log unchanged")
- 17 KNOWN_FAILURES still .fails (refactor neither fixes nor breaks them)
Public API (packages/core/src/index.ts) unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pin the invariants that the strangler-fig migration relies on so any
future PR that breaks them fails loudly:
- tests/registry.test.ts (8 tests): registry empty by default,
getNodeDefinition returns undefined for unknown types, dispatchers
prefer registry.render.{html,react,tailwind} over the legacy switch,
per-target fall-through is independent (registering only html does
not affect react/tailwind paths).
- tests/styles-split.test.ts (19 tests): each theme getter emits
non-empty prefix-aware CSS, structural module is non-empty,
getStyleCSS = structural + theme in that order, unknown style name
falls back to sketch (legacy behavior preserved).
Suite goes 1153 → 1180 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
teezeit
added a commit
that referenced
this pull request
May 1, 2026
## Summary Final PR of the monolith split. All node types with renderable output now live in self-contained modules under `packages/core/src/nodes/<type>/`. The three legacy renderer files shrink from 2,214 lines to 383 lines (83% reduction) — each is now a thin registry-first dispatcher with a fall-through "Unknown node" comment for types whose fixtures expect that path. **Adding a new component is now: drop a folder, register it, write fixtures.** ## What's migrated (this PR + earlier squash-merged PRs #77 #78) - **Container family**: container (11 subtypes incl. sidebar-main extractor as recursion validator) - **Layout** (6): nav, nav-item, brand, grid, grid-item, row - **Content** (14): heading, paragraph, text, image, icon, link, list, list-item, table, table-header, table-row, table-cell, blockquote, code - **Forms** (6): input, textarea, select, checkbox, radio, radio-group - **UI** (7): badge, separator, comment, breadcrumbs (HTML-only), tabs (HTML-only), tab (HTML-only), demo (HTML-only) - Plus: button (PR #78), styles split (PR #77) **Skipped intentionally**: alert, accordion, accordion-item, breadcrumb-item, loading-state, empty-state, error-state, form, option — these had no dedicated renderers in the legacy code (fall through to default), so there's nothing to migrate. ## Contract change `NodeDefinition.render.{html,react,tailwind}` are now **optional**. Many node types historically had no React/Tailwind renderer — instead of forcing every module to implement no-op stubs, the dispatcher falls through to the "Unknown node" comment, preserving snapshot bytes exactly. ## Stats | | Before | After | |---|---|---| | html-renderer.ts | 953 | 200 | | react-renderer.ts | 638 | 112 | | tailwind-renderer.ts | 623 | 71 | | **total legacy** | **2,214** | **383** (-83%) | | nodes/ files | 0 | 136 | | node folders | 0 | ~30 | Plus: 1 small chore commit fixing the CRLF fixture's gitattributes rule (was showing as modified on every branch due to autocrlf interaction). ## Test plan - [x] `pnpm typecheck` clean - [x] `pnpm test` — 1,180 / 1,180 passing - [x] `pnpm review:refresh` — zero snapshot drift ("log unchanged"). Byte-equivalence with the legacy switches is proven. - [x] 17 `KNOWN_FAILURES` still `.fails` — refactor neither fixes nor breaks parser bugs. - [x] Public API unchanged. - [ ] CI green - [ ] Smoke test: render a complex fixture in the editor; eyeball each style. ## What's next (separate PRs, not this one) - **CONTRIBUTING.md** update: replace the 13-step Feature Development Checklist with "drop a `nodes/<type>/` folder, register it, add fixtures." - **Knock out parser bug clusters** now that the parser still in `transformer.ts` can be tackled with a clean slate. The 17 `KNOWN_FAILURES` are in scope for a future cleanup pass. - Optional: parser-side migration (split `transformer.ts` per node type). The renderer split is the hard half; the parser is mostly mechanical from here. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
teezeit
added a commit
that referenced
this pull request
May 1, 2026
…ecture (#80) ## Summary Both files still described the pre-split flow ("add a case to html-renderer.ts, react-renderer.ts, tailwind-renderer.ts") even though those switches were deleted in #77 / #78 / #79. New contributors following the old checklist would land in the wrong place. **No code change** — pure docs. ### CLAUDE.md - Architecture tree shows the new `nodes/<type>/` layout, the registry + contract files, and the per-theme styles split. - New "Render flow (Strategy + Registry)" paragraph explains the dispatcher → registry → node module flow and the intentional "Unknown node" fall-through for nodes without per-target renderers. - New "Adding a new component" pointer to the CONTRIBUTING checklist. - Classic tests list adds `registry.test.ts` and `styles-split.test.ts` (added in #77). ### CONTRIBUTING.md "Feature Development Checklist" - Replaced the three "add a case" bullets with one **Node module** bullet pointing at `src/nodes/<your-type>/`. - Notes that React and Tailwind targets are **optional** — many UI nodes (tabs, breadcrumbs, demo) ship HTML-only and the dispatcher falls through cleanly. - CSS bullet points at `renderer/styles/_structural.ts` and the per-theme files instead of the old monolithic `styles.ts`. - Removed the "Renderer index" bullet — `renderer/index.ts` no longer needs per-component plumbing. ## Test plan - [x] No code touched; nothing to test. - [ ] Skim both files for accuracy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
teezeit
added a commit
that referenced
this pull request
May 1, 2026
## Summary Self-contained brief for the next architectural beat after the renderer split. **No code change** — just the planning doc at `.github/dev-docs/parser-contract-plan.md`. The renderer monolith is split (#77 #78 #79 #80). The next high-leverage move is **not** splitting `parser/transformer.ts` per file — it's fixing the contract: explicit `TransformContext` with `peekNext`/`consumeNext`, plus isolated per-node parse tests that don't go through the full markdown→AST→render pipeline. The doc explains why (the file split is cosmetic; the leverage is the contract), what to build (`_context.ts` + test helpers + per-node tests), and what NOT to do (no file split in this PR, no syntax change, no bug fix). It also captures the user's pending syntax direction (`((pill))` over `|pill|`, `:::columns` over `:::grid`, etc.) so the next session has the destination clear before starting work. Two syntax ideas got pushed back during discussion and are flagged for design calls before any code: - Free-floating `{.right}/{.center}/{.left}` "applies until resolved" — stateful-parsing trap; counter-proposed "applies to nearest element only." - Navbar `[[ a | b | c ]]` `|` separators — collides with table syntax, new escape rules; counter-proposed alignment classes on items. ## Test plan - [x] No code touched. - [ ] Skim the doc for accuracy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR 1 of the monolith split. Foundation for the node-centric architecture:
NodeDefinition<K>contract + static registry underpackages/core/src/nodes/. Empty for now — wired into the three renderers as registry-first dispatch with fall-through to the legacy switches. Behavior is unchanged.styles.ts(3,900 lines) into one file per theme underpackages/core/src/renderer/styles/: sketch, clean, wireframe, none, tailwind, material, brutal, plus shared structural CSS.The plan: each subsequent PR migrates one or more node types into
nodes/<type>/{parse,html,react,tailwind}.ts, deleting their case arms from the legacy files. Adding a new component eventually becomes "drop in a folder."See
.github/dev-docs/monolith-split-plan.mdfor the full arc; this PR matches its "Phase 1 — styles" plus the registry scaffold.What this PR does NOT change
KNOWN_FAILURESstill.fails(refactor neither fixes nor breaks them).Test plan
pnpm typecheckcleanpnpm test— 1,153 / 1,153 passingpnpm review:refresh— zero snapshot drift ("log unchanged")🤖 Generated with Claude Code