feat(cli,playground,generators): Export LikeC4 views to Draw.io + Uncle Bob refactors#10
Merged
feat(cli,playground,generators): Export LikeC4 views to Draw.io + Uncle Bob refactors#10
Conversation
- Docs: Export DrawIO option --output,-o -> --outdir,-o - generate-drawio: pageScale="1" for well-formed XML, mxUserObject after mxGeometry - generate-drawio: flattenMarkdownOrString and isEmptyish for description/technology - parse-drawio: infer system only for swimlane not shape=rectangle+rounded - parse-drawio: toId remove dot from allowed chars to avoid invalid FQN - Playground: DrawioContextMenu refactor with hook and presentational component Co-authored-by: Cursor <[email protected]>
…PR drafts Co-authored-by: Cursor <[email protected]>
…d export/import - Export: view title/description (diagram name + likec4ViewTitle/Description), summary, links, border, opacity, relationship kind/notation, likec4ColorName - Import: diagram name as view id, view title/description from root cell, edge strokeColor to style color, opacity, shape (cylinder/document), summary/links/border/relationshipKind/notation - Add CONVERSION-MAPPING.md documenting mapped and unmapped items - Add pako.d.ts for typecheck; export DiagramInfo from parse-drawio Co-authored-by: Cursor <[email protected]>
…pport - IMPLEMENTATION-PLAN.md: phased plan for full conversion coverage - parseDrawioToLikeC4Multi(xml): merge multiple diagrams into one model, one view per tab with include list - getAllDiagrams(xml): extract all diagram name/id/content from mxfile - First diagram without name attribute still yields view 'index' for backward compatibility - Test: two-tab drawio produces view overview (include A, B) and view detail (include A, C) Co-authored-by: Cursor <[email protected]>
…and single English doc
- Import: emit layout as comment block (likec4.layout.drawio) for round-trip
- Import: emit vertex strokeColor as comment block (DSL has no element strokeColor)
- Import: parse likec4Metadata on edges, emit metadata { } block
- Import: parse Draw.io native style 'link', emit element link when no likec4Links
- Export: add likec4StrokeColor on vertex, likec4Metadata on edge
- Docs: single Draw.io integration page (tooling/drawio.mdx) in English; link from CLI
- Remove CONVERSION-MAPPING.md and IMPLEMENTATION-PLAN.md; add changeset
Co-authored-by: Cursor <[email protected]>
…on, size/padding/textSize/iconPosition - 2.1: Import emit vertex strokeWidth as comment block (likec4.strokeWidth.vertices) - 2.4: Export likec4ViewNotation on root cell when view has notation - 2.5: Export/import element size, padding, textSize, iconPosition (likec4Size etc.) - Export likec4StrokeWidth on vertex for round-trip - Docs: drawio.mdx updated with new mappings Co-authored-by: Cursor <[email protected]>
…ustomData comment Co-authored-by: Cursor <[email protected]>
- Export: GenerateDrawioOptions with layoutOverride, strokeColorByNodeId, strokeWidthByNodeId, edgeWaypoints; view notation string; customData and waypoints in XML. - Import: view notation and edge waypoints comment blocks (single + multi); parseDrawioRoundtripComments() to read comment blocks for re-export. - Playground: getSourceContent from workspace files; export applies round-trip options when comment blocks present. - Playground generate: use PowerShell on Windows (usePowerShell + quotePowerShell) so generate runs without bash. - Generators: export getAllDiagrams, DrawioRoundtripData, parseDrawioRoundtripComments; @types/pako; fix view.notation type and layoutByView possibly undefined. - Docs: drawio.mdx updated with options, waypoints, re-export note. - Tests: parseDrawioRoundtripComments; generate snapshots updated. - Changeset: drawio-roundtrip-options.md. Co-authored-by: Cursor <[email protected]>
- CLI: likec4 export drawio --roundtrip reads .c4 source, parses comment blocks (layout, stroke, waypoints), applies options per view. - Generators: export generateDrawioMulti, parseDrawioRoundtripComments, parseDrawioToLikeC4Multi from main index for CLI/consumers. - Playground: DrawioContextMenu accepts optional getSourceContent for round-trip export when used with explicit props. - Docs: cli.mdx documents --roundtrip and --all-in-one for Export to DrawIO. - E2E: playwright.playground.config.ts and drawio-playground.spec.ts; test:playground script; e2e/.gitignore allows drawio-playground.spec.ts. - Changeset: drawio-cli-roundtrip-e2e.md (likec4, e2e patch). Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
… correctly Co-authored-by: Cursor <[email protected]>
- Use BBox, ThemeColorValues, RelationshipColorValues from @likec4/core - Add getEffectiveStyles(viewmodel) and resolveThemeColor for DRY - JSDoc for public and key internal helpers - Docs: drawio.mdx export behavior (theme colors, containers behind, edge anchors, layoutOverride BBox) Co-authored-by: Cursor <[email protected]>
…ut fallbacks - useDrawioContextMenuActions: build viewModels from likec4model.views() then fill via getLayoutedModel, viewStates, layoutViews so all tabs export - DrawioContextMenuDropdown: minor copy/tooltip tweaks - README and schema updates Co-authored-by: Cursor <[email protected]>
Export: - Container: keep rounded=0 (no rounded corners) - Elements: rounded=1 + arcSize=0.12 (subtle curve) - UserObject with link for navigateTo; style link=data:page/id,likec4-<viewId> - Docs: navigability and link format Import: - Parse UserObject wrapping mxCell: use id and link from UserObject - navigateTo from link attribute (data:page/id,likec4-<viewId>) for round-trip - Refactor: buildCellFromMxCell for reuse; skip duplicate id from UserObject Playground: - DrawIO context menu font size 10px Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
- Parse: container=1 -> system, child of container -> component; fillOpacity/likec4Opacity; view title/description/notation from root cell - Merge container title cells (text shape) into container element; exclude from vertex list - inferKind(style, parentCell); single and multi-diagram use containerIdToTitle and byId - generate-drawio.spec: ProcessedView type for viewWithNav; drawio-demo: expected nodes include container title count - CLI: likec4 import drawio described as experimental (import not yet fully validated) Co-authored-by: Cursor <[email protected]>
…r oxlint Co-authored-by: Cursor <[email protected]>
- Add devops/commands/postpack.ts: copy packed tgz to package.tgz (Node fs) - Replace cp ... || true in all 14 packages and styled-system with likec4ops postpack - Enables pnpm lint:package and validate on Windows Co-authored-by: Cursor <[email protected]>
- CI: single check-validate job runs pnpm validate (same as local); e2e/docs/playground depend on it - Root: pnpm validate script (generate -> typecheck -> core type tests -> lint -> build -> lint:package -> test) - Husky: pre-push runs validate when pushing to main - AGENTS.md: document pnpm validate - Changeset: drawio import alignment, CLI experimental, postpack, validate pipeline Co-authored-by: Cursor <[email protected]>
…hangeset" This reverts commit bdc881e.
…changes) Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
- Export: preserve node parent links (parentId from view hierarchy); container title cell parent = container id - Docs: mention --all-in-one early in Export section - Playground: use layouted diagram for single-view export when available; forEach -> for...of - generate-drawio: hex regex 3/4/6/8 only; remove sourcePoint/targetPoint from Array points; container margins: horizontal = xl, vertical = xl+md (vertical slightly larger) - Remove pako.d.ts, use @types/pako - parse-drawio: likec4LineType only 1 1 / 2 2 = dotted; getAllDiagrams guard empty/invalid content; DRY: stripHtml, stripHtmlForTitle, emitElementToLines, emitEdgesToLines, emitRoundtripComments(Single|Multi) - worker: errToString guard JSON.stringify circular refs - drawio-demo spec: assert reimportViews.length > 0; fix NodeId type in containerCount - Snapshots updated for parent/container changes Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
- generate-drawio: use view.bounds for page, zero offset when content fits - drawio-demo spec: increase timeout to 15s for vice versa test - handler: use loggable(err) instead of String(err) for error logging - worker: avoid String(err) on object in errToString (return literal) Co-authored-by: Cursor <[email protected]>
…iew LSP request, MonacoEditor props Co-authored-by: Cursor <[email protected]>
…etry Co-authored-by: Cursor <[email protected]>
- Wait for .react-flow.initialized (20s) like export snapshot tests - Increase test timeout to 35s for CI layout delay - Remove arbitrary sleep and fragile canvas wait Co-authored-by: Cursor <[email protected]>
- Remove CLI import drawio command and handlers - Playground: DrawIO menu export only (no Import item, no Monaco import action) - Docs: export-only sections in drawio.mdx and cli.mdx - Tests: skip import/round-trip specs (to re-enable in import PR) - E2E: assert Export to DrawIO and Export all only - Add DRAWIO-PR-SPLIT.md and .pr-description-export.md / .pr-description-import.md Co-authored-by: Cursor <[email protected]>
…s sibling data tags Co-authored-by: Cursor <[email protected]>
- buildNavLinkStyle, toExportString, linksToStyleJson, metadataToStyleJson - Unify buildNodeCellXml cellXml (single styleStr/geometryLine + optional UserObject wrap) - Single stripHtml in parse-drawio (remove stripHtmlForTitle/stripHtmlFromValue) - Move LIKEC4_FONT_FAMILY, CONTAINER_TITLE_COLOR to constants.ts - Add REFACTOR-VALIDATION-DRAWIO.md with checklist Co-authored-by: Cursor <[email protected]>
…derência Generators drawio: - getThemeColorValues + refactor getElementColors/getEdgeStrokeColor/getEdgeLabelColors (DRY 8.1.1, SOLID 8.2.1) - toNonEmptyString, getContainerDashedStyle, getDefaultStrokeWidth, applyStrokeColorOverride (8.1.3, 8.3.1, 8.3.2) - formatLinkLines partilhado em pushElementLinks e emitEdgesToLines (DRY 8.1.2) - elementHasBody + pushElementBody em emitElementToLines (Clean Code 8.5.1) - xml-utils.ts com escapeXml/decodeXmlEntities (8.5.2) - buildCellOptionalFields + buildCellFromMxCell simplificado (SOLID 8.2.2) Playground: - DRAWIO_DOWNLOAD_REVOKE_MS para revoke delay (8.5.3) REFACTOR-VALIDATION-DRAWIO: secção 9 (8.2.2 concluído), secção 10 (aderência ao system design) Co-authored-by: Cursor <[email protected]>
…er names, audit doc - NodeLikec4StyleParams type for buildLikec4StyleForNode params - getElementColors: el -> elementColors; toNonEmptyString: x/s -> value/str - parse-drawio: parseNum(s/n) -> parseNum(str/num), add JSDoc - REFACTOR-VALIDATION-DRAWIO: fix conclusion, add section 12 (high-end audit) Co-authored-by: Cursor <[email protected]>
…tors): constant and cast - docs: CLI DrawIO section — add --uncompressed option - docs: drawio.mdx — document generateDrawio, generateDrawioMulti, GenerateDrawioOptions in API - Remove REFACTOR-VALIDATION-DRAWIO.md, PR-DESCRIPTION-DRAWIO-EXPORT.md, DRAFT-PR-DRAWIO-EXPORT.md - generators: DEFAULT_CONTAINER_OPACITY in constants; remove redundant edges cast Co-authored-by: Cursor <[email protected]>
…lint) Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
…o spec Co-authored-by: Cursor <[email protected]>
…asErrorLogged - generators: add buildDrawioExportOptionsForViews(viewIds, sourceContent, overrides), use in CLI handler and playground - parse-drawio: export toErrorMessage(err), use in decompressDrawioDiagram - logger: hasErrorLogged(error: Error | RollupError) return false, ViteLogger compatible - e2e: remove refs to ERROR-MODEL and LEVANTAMENTO docs from E2E-COVERAGE Co-authored-by: Cursor <[email protected]>
…ent, getLayoutedViewmodels - CLI drawio: joinNonEmptyFiles(chunks, separator) for round-trip source assembly - parse-drawio: emitElement.toLines grouping for element emit - generate-drawio.spec: getLayoutedViewmodels(views) helper for multi-view tests Co-authored-by: Cursor <[email protected]>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Co-authored-by: Cursor <[email protected]>
…e, refactor - Use --project e2e for multi-project workspace - Add test: empty workspace exits with code 1 - Extract isDrawioFile, mkdirSync, sort output; align naming Co-authored-by: Cursor <[email protected]>
…riables - Playground: pass onExportError to export options only when non-null - e2e: extract sourceDir/outDir in likec4-cli-build.spec for readability Co-authored-by: Cursor <[email protected]>
- filenames.ts only used basename(); node:path is sufficient - Remove pathe dependency from @likec4/config Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
…build spec Co-authored-by: Cursor <[email protected]>
…ode like build Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
…ace load is fixed Co-authored-by: Cursor <[email protected]>
…slash; re-enable e2e drawio export test Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
This was referenced Feb 13, 2026
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.
feat(cli,playground,generators): Export LikeC4 views to Draw.io + Uncle Bob refactors
Summary
This PR adds export of LikeC4 views to Draw.io (
.drawio) format from the CLI (likec4 export drawio) and the Playground (right-click → DrawIO → Export view / Export all). It also includes a code-quality refactor pass (Uncle Bob / Clean Code) across the DrawIO-related code (generators, CLI, playground, E2E) to improve maintainability, single responsibility, and consistency. Import from Draw.io is out of scope and will be proposed in a separate PR.What's in this PR
1. Feature: Export to Draw.io
@likec4/generators):generateDrawio,generateDrawioMulti, round-trip comment parsing,parseDrawioToLikeC4/parseDrawioToLikeC4Multi. Options: layout override, stroke/waypoints, compressed/uncompressed.likec4 export drawiowith--outdir,--all-in-one,--roundtrip,--uncompressed,--project,--use-dot.apps/docs/.../tooling/drawio.mdxand CLI section for export only (no import).2. Code quality refactors (Uncle Bob sweep)
Refactors were driven by a structured sweep over DrawIO/CLI/Playground/Generators and applied in priority order (P2 → P1 → P0). Below is the detailed breakdown.
2.1 Generators —
packages/generators/src/drawio/computeNodeCellExportDatasplit intocomputeNodeGeometry,computeNodeStylePartsAndValue; orchestrator buildsNodeCellExportData. P1:nodeOptionalFields/edgeOptionalFieldsgroup optional getters (getNotes, getSummary, getTags, …);buildEdgeCellXmlsplit intobuildEdgeLabelValue,buildEdgeGeometryXml,buildEdgeStyleString. P2: Phase comments incomputeDiagramLayout; use ofMXGRAPH_DEFAULT_DX/DYfrom constants. API: Exported typeDrawioViewModelLike;generateDrawio/generateDrawioMultiuse it; playground usesas DrawioViewModelLikeinstead ofParameters<...>[0].verticesAndEdgesFromCells,buildSingleDiagramState,emitLikeC4SourceFromSingleState;parseDrawioToLikeC4delegates to them. P2:emitElement = { toLines: emitElementToLines }; all call sites useemitElement.toLines. JSDoc andDIAGRAM_TAG_OPEN_LENas in sweep.MXGRAPH_DEFAULT_DX,MXGRAPH_DEFAULT_DY(and existing DrawIO constants).getLayoutedViewmodels(views); multi-view tests use it. Import ofDrawioViewModelLikefor typings.2.2 CLI —
packages/likec4/src/cli/joinNonEmptyFiles(chunks, separator);readWorkspaceSourceContentuses it.getDrawioEpilog(); phase comments inrunExportDrawio(1–4). Handler uses!!args.allInOneetc.ERR_PROJECT_NOT_FOUND,ERR_NO_PROJECTS;runExportJson(args, logger); typeJsonExportArgs; handler delegates.PngExportArgs;runExportPng(args, logger);pngHandler(args)creates logger and callsrunExportPng(aligned with drawio/json).applyLoggerConfig.2.3 Playground —
apps/playground/src/components/drawio/fillFromLayoutedModel,fillFromViewStates,fillFromLayoutViews,fillFromModelView;collectViewModelsForExportAllcalls them.canExportAllViewsas named variable. Import and use ofDrawioViewModelLike.EMPTY_DRAWIO_SNAPSHOTconstant.2.4 E2E —
e2e/CANVAS_SELECTOR,EDITOR_SELECTOR,MENU_SELECTOR,canvas(page),editor(page)shared by drawio-playground and static-navigation.2.5 Other packages
error().What's not in this PR
likec4 import drawiocommand or Playground "Import from DrawIO".Checklist (contribution guidelines)
mainbefore creating this PR.feat:,refactor:).pnpm build(filter!./apps/*),pnpm typecheck, andpnpm test --no-typecheck -- packages/generators packages/likec4; all pass.Verification (local)
pnpm build— OK (turbo, excludes apps).pnpm typecheck— OK.pnpm test --no-typecheck -- packages/generators packages/likec4— 13 test files, 68 tests (4 skipped), pass.Notes for reviewers
DrawioViewModelLikeis the public type for view models passed togenerateDrawio/generateDrawioMulti; playground and CLI stay compatible.runExport*(args, logger)+ thin handler that creates logger and delegates.e2e/helpers/so specs stay DRY and timeouts are tuned in one place.Reference
e2e/UNCLE-BOB-PLAN-EXECUTED.md(optional read; not part of the PR diff if excluded from commit).