Refactor to pure functions: remove state registries from core API#3
Open
gerchowl wants to merge 14 commits into
Open
Refactor to pure functions: remove state registries from core API#3gerchowl wants to merge 14 commits into
gerchowl wants to merge 14 commits into
Conversation
- Streamline CLAUDE.md with @path imports for PRD and test README - Add .claude/settings.json with project permissions (just, typst, tt) - Add .claude/rules/ with path-scoped rules for source, tests, examples - Add .claude/skills/ for test, build, docs, and new-test workflows https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- PostToolUse hook: verify src/lib.typ compiles after .typ file edits - Notification hook: cross-platform desktop alert when Claude needs input https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- Add typst-explorer subagent (read-only, Haiku) for codebase exploration - Add PreToolUse hook to protect test reference images from direct edits - Add SessionStart compact hook to re-inject key project context - Update .gitignore for Claude Code local files (settings.local, worktrees) https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
…e, example, review - /add-primitive: scaffold a new primitive type following the unified model - /add-component: create a reusable component with connectors - /debug-state: diagnose state registry / context expression issues - /example: create a new example file with the correct template - /review: code review against Blueprint conventions (runs in typst-explorer subagent) https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
…ones Analyzes current code against v0.2.0 milestone checklist from PRD.md, identifies blockers, and suggests implementation order. https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
The 4 component tests (component-borders-rect, component-borders-circle, component-borders-ellipse, nested-components) were duplicated in both tests/ and tests/_component-tests-disabled/ with identical content. The active copies can't pass because place-component() uses state().get() which requires context expressions. Remove the active copies; the canonical versions remain in _component-tests-disabled/. Also clarifies that no reference images have been generated yet (ref/ directories don't exist), and that the disabled tests are still relevant to the current API. https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
…ests Major architectural change: all factory functions are now pure (return plain dicts, no state() usage). This eliminates the context expression requirement that blocked component tests and removes the return-discards-content warning. Fixes: - Remove all state() registries from factory functions (component, connector, style, canvas, edge-style) — everything is now pure data flow - Implement calculate-bounds() in utils.typ (was placeholder returning zeros) - Implement arrow mark rendering in edge.typ with proper arrowhead triangles - Fix length*length arithmetic in arrowhead math (convert to pt floats) - Fix relative-with-anchor() to account for target object bounds - Replace error() calls with panic() (correct Typst function) New features: - Arrow marks: ->, <-, <->, -, with colored arrowheads matching stroke - Dashed edge support via dash parameter - Style inheritance via base parameter - Component inheritance via component-extend() (fully working) - Three render modes (detailed/collapsed/high-level) all functional Tests (13 total, all passing): - Re-enabled 4 previously disabled component tests - Added 5 new tests: edge-routing, component-connectors, component-inheritance, render-modes, styles-and-themes - Generated reference images for all 13 tests https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
Fix two-layer rendering (draw-item/draw-content) to properly translate nested placed components using CeTZ scope+translate. Fix calculate-content-bounds to offset item bounds by placement position. Add computer-architecture test (CPU with nested cache hierarchy, memory controller, PCIe subsystem, edges in single canvas) and datacenter-architecture test (rack with ToR switch, servers, storage, network edges, collapsed/high-level views). All 15 tests passing. https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
…ring - Primitives: add optional `label` parameter that renders text at center - Components: auto-render name above border (detailed) or centered (collapsed) - Connectors: add `side`/`offset` parameters for border-relative positioning (e.g., side: "bottom", offset: 0.3 places connector at 30% along bottom edge) - Rewrite computer-architecture and datacenter-architecture tests with: - Labels on all primitives (ALU, Regs, L1$, CPU, RAM, NIC, Disk 1-4, etc.) - Border-relative connectors that sit exactly on component edges - Edges connecting to actual connector positions via conn-abs helper - Internal cache hierarchy edges within CPU package - Update all 15 test reference images for name label rendering https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- Fix anchor-to-offset to use Y-up semantics (top=1.0, bottom=0.0) - Fix relative() and relative-with-anchor() to include bounds.x/y offset - Fix primitive anchor dicts for Y-up consistency - Add relative-positioning test: datacenter rack built with relative-with-anchor() instead of hardcoded absolute coordinates (16 tests, all passing) https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- route-manhattan now accepts from-side/to-side parameters for connector border awareness. Edges leave/arrive perpendicular to their border. - Algorithm uses stub segments for clean departure/arrival, then connects with minimal turns: L-shape (1 turn) for adjacent sides, bridge (2 turns) for opposite/same sides. Collinear points are cleaned up. - connect-points accepts from-side/to-side hints; connect() auto-detects side from connector dicts. - Edge-routing test rewritten with labeled sections demonstrating all routing modes, side combinations, and component integration. https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- tools/sql_to_blueprint.py: Python script that queries a SQLite database (datacenters → racks → switches/servers → NICs/disks → links) and generates Blueprint Typst code with relative positioning and Manhattan routing. - Complex schema: 10 tables (datacenters, racks, switches, servers, nics, disks, links, vlans, vlan_assignments), populated with 2 DCs, 4 racks, 4 switches, 8 servers, 15 NICs, 16 disks, 10 network links. - Generated diagrams are color-coded by role (compute=blue, storage=orange, gpu=pink), with cable-type colored edges (copper=green, DAC=orange, fiber=red). - New test: sql-generated (17 tests, all passing). https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
- Edge labels: `label:` parameter on `edge-style()` and `connect-points()`, rendered at midpoint of longest segment - Layout combinators: `stack()` for vertical/horizontal placement, `grid()` for row-major grid layout with configurable columns and gaps - Instance badges: `render-name-label()` shows "×N" when component has `instance-count > 1` - SQL generator: updated to use `stack()` combinator and edge labels showing link speeds (10G, 25G, 100G) with cable-type coloring All 17 tests pass. https://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K
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
This PR refactors Blueprint's core API from a state-based architecture to pure functions, eliminating global registries and making components, connectors, edges, and styles plain data structures. This improves composability, testability, and eliminates context-dependent errors.
Key Changes
Core API Refactoring:
component()now returns a plain dictionary instead of registering tocomponent-registrycomponent-extend()takes a component object directly (not a name string) and returns a new componentplace-component()now takes a component object and returns an updated component with new positionconnector()returns a plain dictionary; removedconnector-registrystateedge-style()returns a plain dictionary; removededge-style-registrystatestyle()function andstyle-registrystate (styles are now inline dictionaries)canvas-registryandobject-registrystatescreate-canvas()is now a pure function returning canvas info without state updatesLayout & Positioning:
relative()now takes a reference object dictionary directly instead of looking up by nameregister-object()andget-object()functionsEdge Rendering:
edge-style()is now a pure functionget-edge-style()lookup functionroute-direct,route-rectangular,route-manhattan) remain pureTest Updates:
place-component()instead of component namescomponent-connectors,component-inheritance,edge-routing,render-modes,styles-and-themes,computer-architecture,datacenter-architectureDocumentation & Tooling:
CLAUDE.mdwith project overview and development commands.claude/directory with Claude Code settings, skills, rules, and agents for development workflowtests/README.mdwith current test structureexamples/simple.typto demonstrate new API.gitignoreto protect test reference imagesImplementation Details
positionparameter was added tocomponent()to support initial positioningcomponent-extend()now recalculates bounds after merging propertieshttps://claude.ai/code/session_01LDjYnYKJGMSvxVt7dTEu2K