agentic-mermaid 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/AGENT_NATIVE.md +155 -91
  2. package/CHANGELOG.md +163 -4
  3. package/Instructions_for_agents.md +10 -10
  4. package/LICENSES/Apache-2.0.txt +202 -0
  5. package/README.md +31 -38
  6. package/THIRD_PARTY_NOTICES.md +29 -0
  7. package/assets/hero.png +0 -0
  8. package/dist/agent-core.d.ts +463 -0
  9. package/dist/agent-core.js +397 -0
  10. package/dist/agent.d.ts +73 -1868
  11. package/dist/agent.js +336 -37325
  12. package/dist/agentic-mermaid-mcp.js +7 -38399
  13. package/dist/am.js +33626 -40446
  14. package/dist/chunk-2P5FKUQC.js +3485 -0
  15. package/dist/chunk-2S3VSS6I.js +149 -0
  16. package/dist/chunk-2SILJDW2.js +37 -0
  17. package/dist/chunk-BJYMBT4I.js +61963 -0
  18. package/dist/chunk-FDM43XU7.js +615 -0
  19. package/dist/chunk-MYPDVZCO.js +4702 -0
  20. package/dist/index-DWPa2MJs.d.ts +6780 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +310 -33014
  23. package/dist/mcp-cli-5J47WEY3.js +17 -0
  24. package/docs/README.md +39 -31
  25. package/docs/agent-api-cookbook.md +44 -35
  26. package/docs/agent-mutation-policy.md +1 -1
  27. package/docs/agent-workflow-examples.md +2 -2
  28. package/docs/api.md +284 -77
  29. package/docs/ascii.md +26 -16
  30. package/docs/code-mode-impact.md +214 -0
  31. package/docs/comparison.md +23 -11
  32. package/docs/computational-aesthetics-prototype-plan.md +252 -0
  33. package/docs/config.md +26 -10
  34. package/docs/custom-fonts.md +265 -0
  35. package/docs/custom-style-cookbook.md +130 -9
  36. package/docs/diagram-families.md +48 -23
  37. package/docs/features.md +59 -52
  38. package/docs/fork-differences.md +6 -3
  39. package/docs/getting-started.md +23 -16
  40. package/docs/issue-derived-test-cases.md +29 -22
  41. package/docs/mcp-code-mode-rationale.md +13 -6
  42. package/docs/mcp-http-transport.md +20 -13
  43. package/docs/mermaid-layout-complaints.md +66 -52
  44. package/docs/mutation-testing.md +145 -66
  45. package/docs/quality.md +23 -14
  46. package/docs/react.md +2 -2
  47. package/docs/schemas/style-spec.schema.json +1221 -30
  48. package/docs/style-authoring.md +241 -38
  49. package/docs/svg-semantic-contract.md +49 -0
  50. package/docs/testing-strategy.md +166 -58
  51. package/docs/theming.md +19 -32
  52. package/examples/styles/catalog.json +54 -0
  53. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  54. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  55. package/examples/styles/cupertino-prototype.mmd +10 -0
  56. package/examples/styles/cupertino-prototype.style.json +63 -0
  57. package/examples/styles/mid-century-report.style.json +2 -2
  58. package/examples/styles/star-chart-atlas.style.json +2 -1
  59. package/examples/styles/transit-route-map.style.json +2 -2
  60. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  61. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  62. package/package.json +85 -45
  63. package/server.json +2 -2
  64. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  65. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  66. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  67. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  68. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  69. package/TODO.md +0 -684
  70. package/dist/index-wjRjbsP-.d.ts +0 -1102
  71. package/docs/assets/improvements/box-start-connector.png +0 -0
  72. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  73. package/docs/assets/improvements/er-content-loss.png +0 -0
  74. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  75. package/docs/assets/improvements/gantt-family.png +0 -0
  76. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  77. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  78. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  79. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  80. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  81. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  82. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  83. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  84. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  85. package/docs/contributing/adding-diagram-types.md +0 -144
  86. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  87. package/docs/contributing/diagram-family-citizenship.md +0 -82
  88. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  89. package/docs/contributing/lessons-learned.md +0 -276
  90. package/docs/contributing/releasing.md +0 -82
  91. package/docs/contributing/visual-review-evidence.md +0 -53
  92. package/docs/design/families/README.md +0 -26
  93. package/docs/design/families/architecture-beta.md +0 -48
  94. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  95. package/docs/design/families/gantt-research.md +0 -137
  96. package/docs/design/families/gantt.md +0 -329
  97. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  98. package/docs/design/families/journey-experience-curve-implementation.png +0 -0
  99. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  100. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  101. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  102. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  103. package/docs/design/families/journey-migration-parity.md +0 -439
  104. package/docs/design/families/journey-section-overlap-after.png +0 -0
  105. package/docs/design/families/journey-section-overlap-before.png +0 -0
  106. package/docs/design/families/journey-usage-research.md +0 -423
  107. package/docs/design/families/journey.md +0 -153
  108. package/docs/design/families/xychart.md +0 -85
  109. package/docs/design/system/README.md +0 -45
  110. package/docs/design/system/abstraction-audit.md +0 -224
  111. package/docs/design/system/abstraction-recommendations.md +0 -655
  112. package/docs/design/system/architecture.mmd +0 -29
  113. package/docs/design/system/architecture.svg +0 -137
  114. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  115. package/docs/design/system/layout-rubric.md +0 -138
  116. package/docs/design/system/route-contracts.md +0 -848
  117. package/docs/design/system/source-preservation-ladder.md +0 -52
  118. package/docs/design/system/styles-rollout.md +0 -216
  119. package/docs/design/system/ugly-layouts.md +0 -119
  120. package/docs/layout-characterization/README.md +0 -245
  121. package/docs/layout-characterization/contact-sheet-families.md +0 -498
  122. package/docs/layout-characterization/contact-sheet.md +0 -638
  123. package/docs/layout-characterization/properties.md +0 -281
  124. package/docs/layout-characterization/visual-quality.md +0 -160
  125. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  126. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  127. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  128. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  129. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  130. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -98
  131. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  132. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  133. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  134. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  135. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  136. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  137. package/docs/project/divergences.md +0 -98
  138. package/docs/project/dogfooding-docs-strategy.md +0 -66
  139. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  140. package/docs/project/lessons-learned.md +0 -1019
  141. package/docs/project/remove-role-styling-plan.md +0 -176
  142. package/examples/agent-improve-auth-flow.ts +0 -206
  143. package/examples/agent-loop.ts +0 -53
  144. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  145. package/llms.txt +0 -104
  146. package/skill-evals/README.md +0 -77
  147. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  148. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  149. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  150. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  151. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  152. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  153. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  154. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  155. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  156. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  157. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  158. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  159. package/skill-evals/shared-benchmark.json +0 -510
  160. package/src/agent/analyze.ts +0 -157
  161. package/src/agent/apply.ts +0 -146
  162. package/src/agent/architecture-body.ts +0 -458
  163. package/src/agent/certificates.ts +0 -110
  164. package/src/agent/class-body.ts +0 -319
  165. package/src/agent/core.ts +0 -207
  166. package/src/agent/create.ts +0 -106
  167. package/src/agent/describe.ts +0 -368
  168. package/src/agent/er-body.ts +0 -224
  169. package/src/agent/facts.ts +0 -360
  170. package/src/agent/families-builtin.ts +0 -920
  171. package/src/agent/families.ts +0 -232
  172. package/src/agent/family-layouts.ts +0 -832
  173. package/src/agent/flowchart-body.ts +0 -372
  174. package/src/agent/flowchart-unsupported.ts +0 -243
  175. package/src/agent/font-coverage.ts +0 -288
  176. package/src/agent/gantt-body.ts +0 -495
  177. package/src/agent/index.ts +0 -10
  178. package/src/agent/journey-body.ts +0 -374
  179. package/src/agent/label-metrics.ts +0 -28
  180. package/src/agent/layout-to-rendered.ts +0 -63
  181. package/src/agent/mutate.ts +0 -97
  182. package/src/agent/mutation-ops.ts +0 -51
  183. package/src/agent/op-schema.ts +0 -443
  184. package/src/agent/parse.ts +0 -223
  185. package/src/agent/pie-body.ts +0 -270
  186. package/src/agent/png.ts +0 -171
  187. package/src/agent/quadrant-body.ts +0 -336
  188. package/src/agent/quality.ts +0 -363
  189. package/src/agent/readability-audit.ts +0 -92
  190. package/src/agent/rendered-route-audit.ts +0 -61
  191. package/src/agent/sequence-body.ts +0 -345
  192. package/src/agent/serialize.ts +0 -214
  193. package/src/agent/state-body.ts +0 -589
  194. package/src/agent/structural-count.ts +0 -150
  195. package/src/agent/timeline-body.ts +0 -280
  196. package/src/agent/trace-log.ts +0 -43
  197. package/src/agent/types.ts +0 -995
  198. package/src/agent/verify.ts +0 -603
  199. package/src/agent/xychart-body.ts +0 -472
  200. package/src/architecture/config.ts +0 -282
  201. package/src/architecture/layout.ts +0 -496
  202. package/src/architecture/parser.ts +0 -375
  203. package/src/architecture/renderer.ts +0 -611
  204. package/src/architecture/types.ts +0 -113
  205. package/src/ascii/ansi.ts +0 -423
  206. package/src/ascii/architecture.ts +0 -210
  207. package/src/ascii/canvas.ts +0 -443
  208. package/src/ascii/class-diagram.ts +0 -697
  209. package/src/ascii/converter.ts +0 -475
  210. package/src/ascii/draw.ts +0 -1693
  211. package/src/ascii/edge-bundling.ts +0 -328
  212. package/src/ascii/edge-routing.ts +0 -330
  213. package/src/ascii/er-diagram.ts +0 -439
  214. package/src/ascii/gantt.ts +0 -276
  215. package/src/ascii/grid.ts +0 -747
  216. package/src/ascii/index.ts +0 -196
  217. package/src/ascii/journey.ts +0 -169
  218. package/src/ascii/meta.ts +0 -244
  219. package/src/ascii/multiline-utils.ts +0 -80
  220. package/src/ascii/pathfinder.ts +0 -301
  221. package/src/ascii/pie.ts +0 -67
  222. package/src/ascii/quadrant.ts +0 -158
  223. package/src/ascii/reverse.ts +0 -216
  224. package/src/ascii/sequence.ts +0 -499
  225. package/src/ascii/shapes/circle.ts +0 -27
  226. package/src/ascii/shapes/corners.ts +0 -143
  227. package/src/ascii/shapes/diamond.ts +0 -27
  228. package/src/ascii/shapes/hexagon.ts +0 -27
  229. package/src/ascii/shapes/index.ts +0 -106
  230. package/src/ascii/shapes/rectangle.ts +0 -168
  231. package/src/ascii/shapes/rounded.ts +0 -27
  232. package/src/ascii/shapes/special.ts +0 -332
  233. package/src/ascii/shapes/stadium.ts +0 -110
  234. package/src/ascii/shapes/state.ts +0 -192
  235. package/src/ascii/shapes/types.ts +0 -73
  236. package/src/ascii/timeline.ts +0 -141
  237. package/src/ascii/types.ts +0 -312
  238. package/src/ascii/validate.ts +0 -120
  239. package/src/ascii/width.ts +0 -81
  240. package/src/ascii/wrap.ts +0 -131
  241. package/src/ascii/xychart.ts +0 -919
  242. package/src/browser.ts +0 -29
  243. package/src/class/layout.ts +0 -240
  244. package/src/class/parser.ts +0 -332
  245. package/src/class/renderer.ts +0 -638
  246. package/src/class/types.ts +0 -129
  247. package/src/cli/agent-instructions.ts +0 -1
  248. package/src/cli/am-bin.ts +0 -6
  249. package/src/cli/exit-codes.ts +0 -18
  250. package/src/cli/index.ts +0 -1132
  251. package/src/cli/init-agent.ts +0 -147
  252. package/src/cli/run-entrypoint.ts +0 -10
  253. package/src/color-resolver.ts +0 -152
  254. package/src/elk-instance.ts +0 -114
  255. package/src/er/layout.ts +0 -187
  256. package/src/er/parser.ts +0 -226
  257. package/src/er/renderer.ts +0 -792
  258. package/src/er/types.ts +0 -99
  259. package/src/family-rubric.ts +0 -425
  260. package/src/font-manifest.ts +0 -31
  261. package/src/gantt/layout.ts +0 -365
  262. package/src/gantt/parser.ts +0 -282
  263. package/src/gantt/pipeline.ts +0 -27
  264. package/src/gantt/renderer.ts +0 -414
  265. package/src/gantt/schedule.ts +0 -513
  266. package/src/gantt/types.ts +0 -255
  267. package/src/index.ts +0 -368
  268. package/src/journey/layout.ts +0 -554
  269. package/src/journey/parse-core.ts +0 -251
  270. package/src/journey/parser.ts +0 -101
  271. package/src/journey/renderer.ts +0 -917
  272. package/src/journey/types.ts +0 -144
  273. package/src/layout/geometry.ts +0 -182
  274. package/src/layout/pass.ts +0 -142
  275. package/src/layout/passes/index.ts +0 -3916
  276. package/src/layout-engine.ts +0 -1565
  277. package/src/layout-rubric.ts +0 -659
  278. package/src/mcp/artifacts.ts +0 -137
  279. package/src/mcp/dynamic-harness.ts +0 -31
  280. package/src/mcp/dynamic-modules.d.ts +0 -7
  281. package/src/mcp/facade.ts +0 -608
  282. package/src/mcp/harness-runtime.ts +0 -203
  283. package/src/mcp/hosted-server.ts +0 -468
  284. package/src/mcp/mcp-bin.ts +0 -3
  285. package/src/mcp/mcp-cli.ts +0 -82
  286. package/src/mcp/protocol.ts +0 -13
  287. package/src/mcp/sandbox.ts +0 -195
  288. package/src/mcp/sdk-decl.ts +0 -391
  289. package/src/mcp/server.ts +0 -362
  290. package/src/mcp/tool-surface.ts +0 -146
  291. package/src/mermaid-source.ts +0 -655
  292. package/src/multiline-utils.ts +0 -228
  293. package/src/parser.ts +0 -1031
  294. package/src/pie/layout.ts +0 -168
  295. package/src/pie/parser.ts +0 -136
  296. package/src/pie/renderer.ts +0 -234
  297. package/src/pie/types.ts +0 -82
  298. package/src/quadrant/layout.ts +0 -191
  299. package/src/quadrant/parser.ts +0 -183
  300. package/src/quadrant/renderer.ts +0 -322
  301. package/src/quadrant/types.ts +0 -113
  302. package/src/render-family-hooks.ts +0 -244
  303. package/src/renderer.ts +0 -1099
  304. package/src/route-contracts.ts +0 -2723
  305. package/src/scene/backend.ts +0 -76
  306. package/src/scene/fidelity.ts +0 -183
  307. package/src/scene/hybrid-backend.ts +0 -174
  308. package/src/scene/ir.ts +0 -181
  309. package/src/scene/marks.ts +0 -127
  310. package/src/scene/rough-backend.ts +0 -378
  311. package/src/scene/seed.ts +0 -46
  312. package/src/scene/style-registry.ts +0 -556
  313. package/src/sequence/layout.ts +0 -456
  314. package/src/sequence/parser.ts +0 -255
  315. package/src/sequence/renderer.ts +0 -604
  316. package/src/sequence/types.ts +0 -154
  317. package/src/shape-clipping.ts +0 -351
  318. package/src/shared/accessibility-directives.ts +0 -22
  319. package/src/shared/batched.ts +0 -61
  320. package/src/shared/color-math.ts +0 -93
  321. package/src/shared/svg-a11y.ts +0 -29
  322. package/src/shared/syntax-error.ts +0 -17
  323. package/src/shared/unicode-ranges.ts +0 -135
  324. package/src/styles.ts +0 -318
  325. package/src/svg-paths.ts +0 -28
  326. package/src/text-metrics.ts +0 -248
  327. package/src/theme.ts +0 -710
  328. package/src/timeline/layout.ts +0 -381
  329. package/src/timeline/parser.ts +0 -215
  330. package/src/timeline/renderer.ts +0 -538
  331. package/src/timeline/types.ts +0 -105
  332. package/src/types.ts +0 -462
  333. package/src/website-worker-modules.d.ts +0 -18
  334. package/src/xychart/axis-utils.ts +0 -109
  335. package/src/xychart/colors.ts +0 -124
  336. package/src/xychart/config.ts +0 -88
  337. package/src/xychart/layout.ts +0 -656
  338. package/src/xychart/parser.ts +0 -504
  339. package/src/xychart/renderer.ts +0 -640
  340. package/src/xychart/types.ts +0 -282
@@ -1,312 +0,0 @@
1
- // ============================================================================
2
- // ASCII renderer — type definitions
3
- //
4
- // Ported from AlexanderGrooff/mermaid-ascii (Go).
5
- // These types model the grid-based coordinate system, 2D text canvas,
6
- // and graph structures used by the ASCII/Unicode renderer.
7
- // ============================================================================
8
-
9
- import type { NodeShape, EdgeMarker, RouteClass } from '../types.ts'
10
-
11
- // Re-export shared graph types for convenience
12
- export type { NodeShape, EdgeMarker }
13
-
14
- /**
15
- * Shape type for ASCII rendering — maps parser shapes to ASCII renderers.
16
- * Most shapes from the parser are supported, with fallback to 'rectangle'.
17
- */
18
- export type AsciiNodeShape = NodeShape
19
-
20
- /** Logical grid coordinate — nodes occupy 3x3 blocks on this grid. */
21
- export interface GridCoord {
22
- x: number
23
- y: number
24
- }
25
-
26
- /** Character-level coordinate on the 2D text canvas. */
27
- export interface DrawingCoord {
28
- x: number
29
- y: number
30
- }
31
-
32
- /**
33
- * Direction constants model positions on a node's 3x3 grid block.
34
- * Each node occupies grid cells [x..x+2, y..y+2].
35
- * Directions are offsets into that block, used for edge attachment points.
36
- *
37
- * (0,0) UL (1,0) Up (2,0) UR
38
- * (0,1) Left (1,1) Mid (2,1) Right
39
- * (0,2) LL (1,2) Down (2,2) LR
40
- */
41
- export interface Direction {
42
- readonly x: number
43
- readonly y: number
44
- }
45
-
46
- export const Up: Direction = { x: 1, y: 0 }
47
- export const Down: Direction = { x: 1, y: 2 }
48
- export const Left: Direction = { x: 0, y: 1 }
49
- export const Right: Direction = { x: 2, y: 1 }
50
- export const UpperRight: Direction = { x: 2, y: 0 }
51
- export const UpperLeft: Direction = { x: 0, y: 0 }
52
- export const LowerRight: Direction = { x: 2, y: 2 }
53
- export const LowerLeft: Direction = { x: 0, y: 2 }
54
- export const Middle: Direction = { x: 1, y: 1 }
55
-
56
- /** All named directions for iteration. */
57
- export const ALL_DIRECTIONS: readonly Direction[] = [
58
- Up, Down, Left, Right, UpperRight, UpperLeft, LowerRight, LowerLeft, Middle,
59
- ]
60
-
61
- /**
62
- * 2D text canvas — column-major (canvas[x][y]).
63
- * Each cell holds a single character (or space).
64
- */
65
- export type Canvas = string[][]
66
-
67
- /** A node in the ASCII graph, positioned on the grid. */
68
- export interface AsciiNode {
69
- /** Unique identity key — the original node ID from the parser (e.g. "A", "B"). */
70
- name: string
71
- /** Human-readable label for rendering inside the box (e.g. "Web Server"). */
72
- displayLabel: string
73
- /** Node shape from the parser (e.g. "rectangle", "diamond", "circle"). */
74
- shape: AsciiNodeShape
75
- index: number
76
- gridCoord: GridCoord | null
77
- drawingCoord: DrawingCoord | null
78
- drawing: Canvas | null
79
- drawn: boolean
80
- styleClassName: string
81
- styleClass: AsciiStyleClass
82
- }
83
-
84
- /** Style class for colored node text (ported from Go's classDef). */
85
- export interface AsciiStyleClass {
86
- name: string
87
- styles: Record<string, string>
88
- }
89
-
90
- /** Edge line style for ASCII rendering. */
91
- export type AsciiEdgeStyle = 'solid' | 'dotted' | 'thick' | 'invisible'
92
-
93
- /** An edge in the ASCII graph, with a routed path. */
94
- export interface AsciiEdge {
95
- from: AsciiNode
96
- to: AsciiNode
97
- /**
98
- * Source container when the Mermaid edge targets a subgraph id.
99
- * Consumed by the converter/grid (grid.ts attachment-point selection) and by
100
- * draw.ts's getSubgraphAttachmentPoint to choose WHERE on the container the
101
- * edge anchors. NOT the same as attachFromSubgraph (see below), which only
102
- * drives border clipping.
103
- */
104
- fromSubgraph?: AsciiSubgraph
105
- /**
106
- * Target container when the Mermaid edge targets a subgraph id.
107
- * Mirror of fromSubgraph for the edge target. Consumed by grid.ts and
108
- * draw.ts's getSubgraphAttachmentPoint for attachment-point selection.
109
- */
110
- toSubgraph?: AsciiSubgraph
111
- text: string
112
- path: GridCoord[]
113
- labelLine: GridCoord[]
114
- startDir: Direction
115
- endDir: Direction
116
- /** Shared semantic route intent from classifyRoutes(); consumed by grid placement/routing parity. */
117
- routeClass?: RouteClass
118
- /** Line style: solid (default), dotted (-.->) or thick (==>) */
119
- style: AsciiEdgeStyle
120
- /** Whether to render a marker at the start (source end) of the edge */
121
- hasArrowStart: boolean
122
- /** Whether to render a marker at the end (target end) of the edge */
123
- hasArrowEnd: boolean
124
- /** Marker shape at start when hasArrowStart=true. Defaults to 'arrow' if undefined. */
125
- startMarker?: EdgeMarker
126
- /** Marker shape at end when hasArrowEnd=true. Defaults to 'arrow' if undefined. */
127
- endMarker?: EdgeMarker
128
- /** Bundle this edge belongs to (if any). Set during bundling analysis. */
129
- bundle?: EdgeBundle
130
- /**
131
- * For bundled edges: path from source/target to the junction point.
132
- * The full visual path is: pathToJunction + bundle.sharedPath (for fan-in)
133
- * or bundle.sharedPath + pathToJunction (for fan-out).
134
- */
135
- pathToJunction?: GridCoord[]
136
- /**
137
- * BUILD-14: when an edge endpoint is a subgraph id (rather than a real node),
138
- * the edge attaches to the subgraph container, not a phantom node. For
139
- * layout/routing we anchor the edge on a representative member of the
140
- * container, but the visible terminus is clipped to the container's border.
141
- * - attachFromSubgraph: the SOURCE of the edge is a subgraph container.
142
- * - attachToSubgraph: the TARGET of the edge is a subgraph container.
143
- *
144
- * Consumed ONLY by draw.ts's drawContainerEdge, which clips the routed
145
- * polyline at the container border (clipPolylineAtBorder). Distinct from
146
- * fromSubgraph/toSubgraph above: those pick the attachment point; these pick
147
- * where to clip. Both pairs can be set, and they are not interchangeable.
148
- */
149
- attachFromSubgraph?: AsciiSubgraph
150
- attachToSubgraph?: AsciiSubgraph
151
- }
152
-
153
- /** A subgraph container with bounding box for rendering. */
154
- export interface AsciiSubgraph {
155
- /** Mermaid subgraph id (distinct from the display label); used for container-edge references. */
156
- id: string
157
- name: string
158
- nodes: AsciiNode[]
159
- parent: AsciiSubgraph | null
160
- children: AsciiSubgraph[]
161
- minX: number
162
- minY: number
163
- maxX: number
164
- maxY: number
165
- /** Optional direction override for layout within this subgraph (LR or TD). */
166
- direction?: 'LR' | 'TD'
167
- }
168
-
169
- /** Configuration for ASCII rendering. */
170
- export interface AsciiConfig {
171
- /** true = ASCII chars (+,-,|), false = Unicode box-drawing (┌,─,│). Default: false */
172
- useAscii: boolean
173
- /** Horizontal spacing between nodes. Default: 5 */
174
- paddingX: number
175
- /** Vertical spacing between nodes. Default: 5 */
176
- paddingY: number
177
- /** Padding inside node boxes. Default: 1 */
178
- boxBorderPadding: number
179
- /** Graph direction: "LR" or "TD". */
180
- graphDirection: 'LR' | 'TD'
181
- }
182
-
183
- /** Full ASCII graph state used during layout and rendering. */
184
- export interface AsciiGraph {
185
- nodes: AsciiNode[]
186
- edges: AsciiEdge[]
187
- canvas: Canvas
188
- /** Role canvas — tracks the role of each character for colored output. */
189
- roleCanvas: RoleCanvas
190
- /** Grid occupancy map — maps "x,y" keys to node references. */
191
- grid: Map<string, AsciiNode>
192
- columnWidth: Map<number, number>
193
- rowHeight: Map<number, number>
194
- subgraphs: AsciiSubgraph[]
195
- config: AsciiConfig
196
- /** Offset applied to all drawing coords to accommodate subgraph borders. */
197
- offsetX: number
198
- offsetY: number
199
- /** Edge bundles for parallel link visualization. Set during bundling analysis. */
200
- bundles: EdgeBundle[]
201
- /** Grid coordinates where sibling-edge trunk branches need explicit T-junctions. */
202
- trunkJunctions: GridCoord[]
203
- }
204
-
205
- // ============================================================================
206
- // Coordinate helpers
207
- // ============================================================================
208
-
209
- export function gridCoordEquals(a: GridCoord, b: GridCoord): boolean {
210
- return a.x === b.x && a.y === b.y
211
- }
212
-
213
- export function drawingCoordEquals(a: DrawingCoord, b: DrawingCoord): boolean {
214
- return a.x === b.x && a.y === b.y
215
- }
216
-
217
- /** Apply a direction offset to a grid coordinate (move into the 3x3 block). */
218
- export function gridCoordDirection(c: GridCoord, dir: Direction): GridCoord {
219
- return { x: c.x + dir.x, y: c.y + dir.y }
220
- }
221
-
222
- /** Key for storing GridCoord in a Map. */
223
- export function gridKey(c: GridCoord): string {
224
- return `${c.x},${c.y}`
225
- }
226
-
227
- /** Default empty style class. */
228
- export const EMPTY_STYLE: AsciiStyleClass = { name: '', styles: {} }
229
-
230
- // ============================================================================
231
- // Character role types for colored output
232
- // ============================================================================
233
-
234
- /**
235
- * Role of a character in the ASCII diagram, used for theming.
236
- * Each role maps to a different color when colors are enabled.
237
- */
238
- export type CharRole =
239
- | 'text' // Node labels, edge labels
240
- | 'border' // Node box borders, subgraph borders
241
- | 'line' // Edge lines (paths between nodes)
242
- | 'arrow' // Arrowheads (▲▼◄► or ^v<>)
243
- | 'corner' // Corner characters at path bends
244
- | 'junction' // Junction characters (┬┴├┤ where edges meet boxes)
245
-
246
- /**
247
- * Role canvas — parallel to Canvas, tracks the role of each character.
248
- * Same column-major structure: roleCanvas[x][y] gives the role at (x, y).
249
- * null means the character has no role (whitespace).
250
- */
251
- export type RoleCanvas = (CharRole | null)[][]
252
-
253
- /**
254
- * Theme colors for ASCII output — hex color strings.
255
- * Derived from the SVG theme system for visual consistency.
256
- */
257
- export interface AsciiTheme {
258
- /** Text color (node labels, edge labels) */
259
- fg: string
260
- /** Box border color (node borders, subgraph borders) */
261
- border: string
262
- /** Edge line color (paths between nodes) */
263
- line: string
264
- /** Arrowhead color (▲▼◄► or ^v<>) */
265
- arrow: string
266
- /** Theme accent color (optional, used by xycharts for series 0) */
267
- accent?: string
268
- /** Background color (optional, used by xycharts for dark-mode-aware shading) */
269
- bg?: string
270
- /** Corner character color (optional, defaults to line) */
271
- corner?: string
272
- /** Junction character color (optional, defaults to border) */
273
- junction?: string
274
- }
275
-
276
- /** Color mode for output. */
277
- export type ColorMode =
278
- | 'none' // No colors (plain text)
279
- | 'ansi16' // 16-color ANSI (basic terminals)
280
- | 'ansi256' // 256-color ANSI (xterm)
281
- | 'truecolor' // 24-bit RGB (modern terminals)
282
- | 'html' // HTML <span> tags with inline color styles (browsers)
283
-
284
- // ============================================================================
285
- // Edge bundling types
286
- // ============================================================================
287
-
288
- /**
289
- * Edge bundle — groups edges that share a common source or target.
290
- * Used to visually merge parallel links before they reach the shared node.
291
- *
292
- * For fan-in (A & B --> C): multiple sources converge to one target.
293
- * For fan-out (A --> B & C): one source diverges to multiple targets.
294
- */
295
- export interface EdgeBundle {
296
- /** Bundle type: fan-in = many→one, fan-out = one→many */
297
- type: 'fan-in' | 'fan-out'
298
- /** Edges in this bundle */
299
- edges: AsciiEdge[]
300
- /** The common node (target for fan-in, source for fan-out) */
301
- sharedNode: AsciiNode
302
- /** The non-shared nodes (sources for fan-in, targets for fan-out) */
303
- otherNodes: AsciiNode[]
304
- /** Junction point where edges merge/split — set during routing */
305
- junctionPoint: GridCoord | null
306
- /** Path from junction to shared node (drawn once for all edges) */
307
- sharedPath: GridCoord[]
308
- /** Direction when entering/exiting the junction */
309
- junctionDir: Direction
310
- /** Direction when entering/exiting the shared node */
311
- sharedNodeDir: Direction
312
- }
@@ -1,120 +0,0 @@
1
- /**
2
- * ASCII Rendering Validation Utilities
3
- *
4
- * Provides validation functions for ASCII diagram output,
5
- * including diagonal line detection to ensure orthogonal-only routing.
6
- */
7
-
8
- /**
9
- * Characters that represent diagonal lines in ASCII and Unicode modes.
10
- * These should never appear in properly rendered diagrams.
11
- */
12
- export const DIAGONAL_CHARS = {
13
- ascii: ['/', '\\'],
14
- unicode: ['\u2571', '\u2572'], // ╱ ╲
15
- all: ['/', '\\', '\u2571', '\u2572'],
16
- } as const
17
-
18
- /**
19
- * Position of a diagonal character in ASCII output.
20
- */
21
- export interface DiagonalPosition {
22
- line: number
23
- col: number
24
- char: string
25
- }
26
-
27
- /**
28
- * Check if ASCII output contains any diagonal line characters.
29
- * Returns true if diagonals are found (which is an error condition).
30
- *
31
- * @param asciiOutput - The rendered ASCII diagram string
32
- * @returns true if diagonal characters are present, false otherwise
33
- */
34
- export function hasDiagonalLines(asciiOutput: string): boolean {
35
- return DIAGONAL_CHARS.all.some((char) => asciiOutput.includes(char))
36
- }
37
-
38
- /**
39
- * Find all diagonal line character positions in ASCII output.
40
- * Useful for debugging when diagonals are detected.
41
- *
42
- * Skips diagonal characters that appear inside node labels (between box borders).
43
- * This prevents false positives from labels like "feature/auth" or "release/1.0".
44
- *
45
- * @param asciiOutput - The rendered ASCII diagram string
46
- * @returns Array of positions where diagonal characters were found
47
- */
48
- export function findDiagonalLines(asciiOutput: string): DiagonalPosition[] {
49
- const positions: DiagonalPosition[] = []
50
- const lines = asciiOutput.split('\n')
51
-
52
- // Box-drawing characters that indicate node boundaries
53
- const boxBorders = new Set(['│', '┤', '├', '║', '┃', '|'])
54
-
55
- for (let lineNum = 0; lineNum < lines.length; lineNum++) {
56
- const line = lines[lineNum]!
57
-
58
- // Find all box border positions in this line
59
- const borderPositions: number[] = []
60
- for (let col = 0; col < line.length; col++) {
61
- if (boxBorders.has(line[col]!)) {
62
- borderPositions.push(col)
63
- }
64
- }
65
-
66
- for (let col = 0; col < line.length; col++) {
67
- const char = line[col]!
68
- if (DIAGONAL_CHARS.all.includes(char as '/' | '\\' | '╱' | '╲')) {
69
- // Check if this position is inside a node (between two box borders)
70
- // Find the nearest borders before and after this position
71
- let insideNode = false
72
- for (let i = 0; i < borderPositions.length - 1; i++) {
73
- const leftBorder = borderPositions[i]!
74
- const rightBorder = borderPositions[i + 1]!
75
- if (col > leftBorder && col < rightBorder) {
76
- // This diagonal char is between two borders - likely inside a node label
77
- insideNode = true
78
- break
79
- }
80
- }
81
-
82
- if (!insideNode) {
83
- positions.push({
84
- line: lineNum + 1, // 1-indexed for human readability
85
- col: col + 1,
86
- char,
87
- })
88
- }
89
- }
90
- }
91
- }
92
-
93
- return positions
94
- }
95
-
96
- /**
97
- * Assert that ASCII output contains no diagonal lines.
98
- * Throws an error with detailed position information if diagonals are found.
99
- *
100
- * @param asciiOutput - The rendered ASCII diagram string
101
- * @param context - Optional context string for error message (e.g., diagram name)
102
- * @throws Error if diagonal characters are present
103
- */
104
- export function assertNoDiagonals(asciiOutput: string, context?: string): void {
105
- if (!hasDiagonalLines(asciiOutput)) {
106
- return
107
- }
108
-
109
- const positions = findDiagonalLines(asciiOutput)
110
- const contextStr = context ? ` in "${context}"` : ''
111
- const positionStr = positions
112
- .map((p) => ` Line ${p.line}, Col ${p.col}: '${p.char}'`)
113
- .join('\n')
114
-
115
- throw new Error(
116
- `Diagonal lines detected${contextStr}. ` +
117
- `Edges must use orthogonal Manhattan routing (90° bends only).\n` +
118
- `Found ${positions.length} diagonal character(s):\n${positionStr}`
119
- )
120
- }
@@ -1,81 +0,0 @@
1
- // ============================================================================
2
- // Terminal display width helpers for ASCII/Unicode rendering.
3
- //
4
- // Range tables live in src/shared/unicode-ranges.ts so the SVG metrics
5
- // module can share them without the ascii/ → core import that the
6
- // substrate lint forbids.
7
- //
8
- // Variation selectors (U+FE0E / U+FE0F) modify the WIDTH of the preceding
9
- // base codepoint, so `visualWidth` does a two-pass tally rather than a
10
- // per-codepoint sum: it remembers the last-emitted width and rewrites it
11
- // when a selector arrives. ZWJ (U+200D) and FE0E both have width 0; FE0F
12
- // forces the previous base to width 2.
13
- // ============================================================================
14
-
15
- import { isWideRange, isZeroWidth, VS_TEXT, VS_EMOJI, ZWJ } from '../shared/unicode-ranges.ts'
16
-
17
- /** Sentinel stored in the canvas cell following a fullwidth character. */
18
- export const WIDE_CHAR_CONTINUATION = '\x00'
19
-
20
- /**
21
- * Width of a single codepoint, with no knowledge of neighbours.
22
- * Variation selectors are reported as zero-width here; the per-string
23
- * `visualWidth` applies the selector's retroactive width override.
24
- */
25
- export function charVisualWidth(ch: string): number {
26
- const code = ch.codePointAt(0) ?? 0
27
- if (code === VS_TEXT || code === VS_EMOJI || code === ZWJ) return 0
28
- if (isZeroWidth(code)) return 0
29
- if (isWideRange(code)) return 2
30
- return 1
31
- }
32
-
33
- /**
34
- * Terminal display width of a string, in cells.
35
- *
36
- * Iterates codepoints and applies these post-process rules:
37
- * - FE0F (emoji-presentation selector): force the preceding base to width 2
38
- * - FE0E (text-presentation selector): force the preceding base to width 1
39
- * - 200D (ZWJ): zero width; binds the next base
40
- * into an emoji ZWJ sequence — the next base is also forced to 0
41
- * so a man-with-laptop (👨‍💻) totals 2 cells, not 4.
42
- */
43
- export function visualWidth(text: string): number {
44
- let total = 0
45
- let lastBaseWidth = 0
46
- let zwjPending = false
47
- for (const ch of text) {
48
- const code = ch.codePointAt(0) ?? 0
49
- if (code === VS_EMOJI) {
50
- if (lastBaseWidth === 1) {
51
- total += 1
52
- lastBaseWidth = 2
53
- }
54
- continue
55
- }
56
- if (code === VS_TEXT) {
57
- if (lastBaseWidth === 2) {
58
- total -= 1
59
- lastBaseWidth = 1
60
- }
61
- continue
62
- }
63
- if (code === ZWJ) {
64
- zwjPending = true
65
- lastBaseWidth = 0
66
- continue
67
- }
68
- if (isZeroWidth(code)) {
69
- lastBaseWidth = 0
70
- continue
71
- }
72
- let w = isWideRange(code) ? 2 : 1
73
- if (zwjPending) {
74
- w = 0
75
- zwjPending = false
76
- }
77
- total += w
78
- lastBaseWidth = w
79
- }
80
- return total
81
- }
package/src/ascii/wrap.ts DELETED
@@ -1,131 +0,0 @@
1
- // ============================================================================
2
- // ASCII renderer — width-aware text wrapping.
3
- //
4
- // Shared by the journey and timeline ASCII renderers. Wrapping iterates
5
- // grapheme clusters (Intl.Segmenter) rather than codepoints and measures
6
- // candidates with the whole-string `visualWidth`, so FE0F emoji count their
7
- // display width (a per-codepoint sum sees ❤️ as 1 cell; it renders as 2)
8
- // and ZWJ sequences (👩‍🔬) are never split mid-grapheme.
9
- //
10
- // Mid-word breaks follow the SVG layout's breakWordToWidth convention
11
- // (src/journey/layout.ts): the continuing chunk takes a trailing '-',
12
- // except when the break falls between two double-width clusters — CJK and
13
- // fullwidth text wraps at any character without hyphenation.
14
- // ============================================================================
15
-
16
- import { visualWidth } from './width.ts'
17
-
18
- /** Options for wrapText/wrapParagraph/breakWord. */
19
- export interface WrapOptions {
20
- /**
21
- * Append '-' where a word is broken mid-line (suppressed between
22
- * double-width clusters, and when the hyphen itself would not fit).
23
- * Default: true. Glyph strips (e.g. the journey score strip) disable it.
24
- */
25
- hyphenate?: boolean
26
- }
27
-
28
- /** Grapheme segmentation is locale-independent (UAX #29), so this is deterministic. */
29
- const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })
30
-
31
- /** Split a string into grapheme clusters (emoji ZWJ sequences stay whole). */
32
- export function graphemes(text: string): string[] {
33
- return Array.from(segmenter.segment(text), s => s.segment)
34
- }
35
-
36
- /**
37
- * Wrap text to at most `maxWidth` display cells per line. Embedded '\n' are
38
- * hard breaks. Without a positive finite maxWidth, only splits on '\n'.
39
- */
40
- export function wrapText(text: string, maxWidth: number | undefined, options?: WrapOptions): string[] {
41
- if (!maxWidth || !Number.isFinite(maxWidth) || maxWidth <= 0) return text.split('\n')
42
- const limit = Math.max(1, Math.floor(maxWidth))
43
- const lines: string[] = []
44
- for (const paragraph of text.split('\n')) {
45
- lines.push(...wrapParagraph(paragraph, limit, options))
46
- }
47
- return lines.length > 0 ? lines : ['']
48
- }
49
-
50
- /**
51
- * Wrap a single paragraph (no '\n') at word boundaries by display width.
52
- * Words wider than maxWidth are broken by `breakWord`.
53
- */
54
- export function wrapParagraph(text: string, maxWidth: number, options?: WrapOptions): string[] {
55
- if (visualWidth(text) <= maxWidth) return [text]
56
- const words = text.split(/\s+/).filter(Boolean)
57
- if (words.length === 0) return ['']
58
-
59
- const lines: string[] = []
60
- let current = ''
61
- for (const word of words) {
62
- if (!current) {
63
- const chunks = breakWord(word, maxWidth, options)
64
- lines.push(...chunks.slice(0, -1))
65
- current = chunks[chunks.length - 1] ?? ''
66
- continue
67
- }
68
-
69
- const candidate = `${current} ${word}`
70
- if (visualWidth(candidate) <= maxWidth) {
71
- current = candidate
72
- continue
73
- }
74
-
75
- lines.push(current)
76
- const chunks = breakWord(word, maxWidth, options)
77
- lines.push(...chunks.slice(0, -1))
78
- current = chunks[chunks.length - 1] ?? ''
79
- }
80
- if (current) lines.push(current)
81
- return lines
82
- }
83
-
84
- /**
85
- * Break a single word into chunks of at most maxWidth cells. Greedy over
86
- * grapheme clusters: each line takes as many whole clusters as fit,
87
- * reserving one cell for the trailing hyphen when its break needs one.
88
- * A cluster wider than maxWidth still gets emitted alone (nothing narrower
89
- * exists to emit), matching the pre-grapheme behavior.
90
- */
91
- export function breakWord(word: string, maxWidth: number, options?: WrapOptions): string[] {
92
- if (visualWidth(word) <= maxWidth) return [word]
93
- const hyphenate = options?.hyphenate ?? true
94
- const clusters = graphemes(word)
95
- const lines: string[] = []
96
- let start = 0
97
- while (start < clusters.length) {
98
- let end = start + 1 // always consume at least one cluster per line
99
- while (end < clusters.length && fitsWithBreak(clusters, start, end + 1, maxWidth, hyphenate)) end++
100
- const chunk = clusters.slice(start, end).join('')
101
- const hyphen = end < clusters.length
102
- && breakNeedsHyphen(clusters[end - 1]!, clusters[end]!, hyphenate)
103
- && visualWidth(chunk) + 1 <= maxWidth
104
- lines.push(hyphen ? `${chunk}-` : chunk)
105
- start = end
106
- }
107
- return lines
108
- }
109
-
110
- /** Would clusters[start..end) fit in maxWidth, counting the hyphen its break would need? */
111
- function fitsWithBreak(
112
- clusters: string[],
113
- start: number,
114
- end: number,
115
- maxWidth: number,
116
- hyphenate: boolean,
117
- ): boolean {
118
- const width = visualWidth(clusters.slice(start, end).join(''))
119
- const hyphen = end < clusters.length && breakNeedsHyphen(clusters[end - 1]!, clusters[end]!, hyphenate) ? 1 : 0
120
- return width + hyphen <= maxWidth
121
- }
122
-
123
- /**
124
- * A mid-word break takes a hyphen unless it falls between two double-width
125
- * clusters (CJK, fullwidth forms, emoji), where hyphenation is not a text
126
- * convention.
127
- */
128
- function breakNeedsHyphen(before: string, after: string, hyphenate: boolean): boolean {
129
- if (!hyphenate) return false
130
- return !(visualWidth(before) === 2 && visualWidth(after) === 2)
131
- }