agentic-mermaid 0.1.0 → 0.1.2
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.
- package/CHANGELOG.md +149 -4
- package/LICENSES/Apache-2.0.txt +202 -0
- package/README.md +25 -32
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/assets/fonts/FONT-LICENSES.md +9 -5
- package/assets/fonts/Inter-Bold.ttf +0 -0
- package/assets/fonts/Inter-Medium.ttf +0 -0
- package/assets/fonts/Inter-Regular.ttf +0 -0
- package/assets/fonts/Inter-SemiBold.ttf +0 -0
- package/dist/agent-core.d.ts +463 -0
- package/dist/agent-core.js +397 -0
- package/dist/agent.d.ts +81 -1822
- package/dist/agent.js +336 -36839
- package/dist/agentic-mermaid-mcp.js +7 -37908
- package/dist/am.js +33638 -36261
- package/dist/chunk-4QECACIA.js +4702 -0
- package/dist/chunk-CDPKJ2BQ.js +37 -0
- package/dist/chunk-QKDLMOJJ.js +3487 -0
- package/dist/chunk-WI35L7IR.js +615 -0
- package/dist/chunk-WN3YDOBG.js +149 -0
- package/dist/chunk-ZYMMKQ3I.js +62637 -0
- package/dist/index-D54dqSdC.d.ts +6777 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +310 -32836
- package/dist/mcp-cli-SBQSTJFC.js +17 -0
- package/docs/README.md +14 -6
- package/docs/schemas/style-spec.schema.json +1221 -30
- package/examples/styles/catalog.json +54 -0
- package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
- package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
- package/examples/styles/cupertino-prototype.mmd +10 -0
- package/examples/styles/cupertino-prototype.style.json +63 -0
- package/examples/styles/mid-century-report.style.json +2 -2
- package/examples/styles/star-chart-atlas.style.json +2 -1
- package/examples/styles/transit-route-map.style.json +2 -2
- package/examples/styles/vercel-inspired-prototype.mmd +6 -0
- package/examples/styles/vercel-inspired-prototype.style.json +87 -0
- package/package.json +70 -43
- package/server.json +41 -0
- package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
- package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
- package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
- package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
- package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
- package/AGENT_NATIVE.md +0 -602
- package/Instructions_for_agents.md +0 -83
- package/TODO.md +0 -662
- package/assets/hero.png +0 -0
- package/dist/index-x2Cj1dVv.d.ts +0 -1089
- package/docs/agent-api-cookbook.md +0 -308
- package/docs/agent-mutation-policy.md +0 -104
- package/docs/agent-workflow-examples.md +0 -46
- package/docs/api.md +0 -203
- package/docs/ascii.md +0 -103
- package/docs/assets/improvements/box-start-connector.png +0 -0
- package/docs/assets/improvements/comment-dropped-lint.png +0 -0
- package/docs/assets/improvements/er-content-loss.png +0 -0
- package/docs/assets/improvements/fan-in-trunks.png +0 -0
- package/docs/assets/improvements/gantt-family.png +0 -0
- package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
- package/docs/assets/improvements/gantt-verify-seam.png +0 -0
- package/docs/assets/improvements/subgraph-container-edges.png +0 -0
- package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
- package/docs/assets/improvements/wrapper-init-directive.png +0 -0
- package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
- package/docs/assets/style-cookbook/mid-century-report.png +0 -0
- package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
- package/docs/assets/style-cookbook/transit-route-map.png +0 -0
- package/docs/comparison.md +0 -94
- package/docs/config.md +0 -105
- package/docs/contributing/adding-diagram-types.md +0 -144
- package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
- package/docs/contributing/diagram-family-citizenship.md +0 -82
- package/docs/contributing/harvesting-upstream-tests.md +0 -126
- package/docs/contributing/lessons-learned.md +0 -276
- package/docs/contributing/releasing.md +0 -71
- package/docs/contributing/visual-review-evidence.md +0 -53
- package/docs/custom-style-cookbook.md +0 -154
- package/docs/design/families/README.md +0 -26
- package/docs/design/families/architecture-beta.md +0 -48
- package/docs/design/families/flowchart-parser-conformance.md +0 -22
- package/docs/design/families/gantt-research.md +0 -137
- package/docs/design/families/gantt.md +0 -329
- package/docs/design/families/journey-agentic-cards-before.png +0 -0
- package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
- package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
- package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
- package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
- package/docs/design/families/journey-migration-parity.md +0 -433
- package/docs/design/families/journey-usage-research.md +0 -423
- package/docs/design/families/journey.md +0 -125
- package/docs/design/families/xychart.md +0 -85
- package/docs/design/system/README.md +0 -45
- package/docs/design/system/abstraction-audit.md +0 -224
- package/docs/design/system/abstraction-recommendations.md +0 -655
- package/docs/design/system/architecture.mmd +0 -29
- package/docs/design/system/architecture.svg +0 -137
- package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
- package/docs/design/system/layout-rubric.md +0 -138
- package/docs/design/system/route-contracts.md +0 -848
- package/docs/design/system/source-preservation-ladder.md +0 -52
- package/docs/design/system/styles-rollout.md +0 -216
- package/docs/design/system/ugly-layouts.md +0 -119
- package/docs/diagram-families.md +0 -193
- package/docs/features.md +0 -147
- package/docs/fork-differences.md +0 -130
- package/docs/getting-started.md +0 -175
- package/docs/issue-derived-test-cases.md +0 -156
- package/docs/layout-characterization/README.md +0 -245
- package/docs/layout-characterization/contact-sheet-families.md +0 -496
- package/docs/layout-characterization/contact-sheet.md +0 -638
- package/docs/layout-characterization/properties.md +0 -281
- package/docs/layout-characterization/visual-quality.md +0 -160
- package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
- package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
- package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
- package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
- package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
- package/docs/layout-characterization/visual-snapshots/journey.svg +0 -118
- package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
- package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
- package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
- package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
- package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
- package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
- package/docs/mcp-code-mode-rationale.md +0 -101
- package/docs/mcp-http-transport.md +0 -223
- package/docs/mermaid-layout-complaints.md +0 -837
- package/docs/mutation-testing.md +0 -206
- package/docs/project/divergences.md +0 -98
- package/docs/project/dogfooding-docs-strategy.md +0 -66
- package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
- package/docs/project/lessons-learned.md +0 -1019
- package/docs/project/remove-role-styling-plan.md +0 -176
- package/docs/quality.md +0 -212
- package/docs/react.md +0 -97
- package/docs/style-authoring.md +0 -133
- package/docs/testing-strategy.md +0 -335
- package/docs/theming.md +0 -162
- package/examples/agent-improve-auth-flow.ts +0 -206
- package/examples/agent-loop.ts +0 -53
- package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
- package/llms.txt +0 -104
- package/skill-evals/README.md +0 -77
- package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
- package/skill-evals/fixtures/class-payment/input.mmd +0 -4
- package/skill-evals/fixtures/er-orders/input.mmd +0 -10
- package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
- package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
- package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
- package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
- package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
- package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
- package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
- package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
- package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
- package/skill-evals/shared-benchmark.json +0 -510
- package/src/agent/analyze.ts +0 -157
- package/src/agent/apply.ts +0 -146
- package/src/agent/architecture-body.ts +0 -458
- package/src/agent/certificates.ts +0 -110
- package/src/agent/class-body.ts +0 -319
- package/src/agent/core.ts +0 -207
- package/src/agent/create.ts +0 -106
- package/src/agent/describe.ts +0 -364
- package/src/agent/er-body.ts +0 -224
- package/src/agent/facts.ts +0 -337
- package/src/agent/families-builtin.ts +0 -934
- package/src/agent/families.ts +0 -232
- package/src/agent/family-layouts.ts +0 -826
- package/src/agent/flowchart-body.ts +0 -372
- package/src/agent/flowchart-unsupported.ts +0 -243
- package/src/agent/gantt-body.ts +0 -495
- package/src/agent/index.ts +0 -10
- package/src/agent/journey-body.ts +0 -414
- package/src/agent/label-metrics.ts +0 -28
- package/src/agent/layout-to-rendered.ts +0 -63
- package/src/agent/mutate.ts +0 -97
- package/src/agent/mutation-ops.ts +0 -51
- package/src/agent/op-schema.ts +0 -439
- package/src/agent/parse.ts +0 -223
- package/src/agent/pie-body.ts +0 -270
- package/src/agent/png.ts +0 -117
- package/src/agent/quadrant-body.ts +0 -336
- package/src/agent/quality.ts +0 -363
- package/src/agent/readability-audit.ts +0 -92
- package/src/agent/rendered-route-audit.ts +0 -61
- package/src/agent/sequence-body.ts +0 -345
- package/src/agent/serialize.ts +0 -214
- package/src/agent/state-body.ts +0 -589
- package/src/agent/structural-count.ts +0 -150
- package/src/agent/timeline-body.ts +0 -280
- package/src/agent/trace-log.ts +0 -43
- package/src/agent/types.ts +0 -979
- package/src/agent/verify.ts +0 -571
- package/src/agent/xychart-body.ts +0 -472
- package/src/architecture/config.ts +0 -282
- package/src/architecture/layout.ts +0 -496
- package/src/architecture/parser.ts +0 -375
- package/src/architecture/renderer.ts +0 -611
- package/src/architecture/types.ts +0 -113
- package/src/ascii/ansi.ts +0 -423
- package/src/ascii/architecture.ts +0 -210
- package/src/ascii/canvas.ts +0 -443
- package/src/ascii/class-diagram.ts +0 -697
- package/src/ascii/converter.ts +0 -475
- package/src/ascii/draw.ts +0 -1693
- package/src/ascii/edge-bundling.ts +0 -328
- package/src/ascii/edge-routing.ts +0 -330
- package/src/ascii/er-diagram.ts +0 -439
- package/src/ascii/gantt.ts +0 -276
- package/src/ascii/grid.ts +0 -747
- package/src/ascii/index.ts +0 -196
- package/src/ascii/journey.ts +0 -189
- package/src/ascii/meta.ts +0 -244
- package/src/ascii/multiline-utils.ts +0 -80
- package/src/ascii/pathfinder.ts +0 -301
- package/src/ascii/pie.ts +0 -67
- package/src/ascii/quadrant.ts +0 -158
- package/src/ascii/reverse.ts +0 -216
- package/src/ascii/sequence.ts +0 -499
- package/src/ascii/shapes/circle.ts +0 -27
- package/src/ascii/shapes/corners.ts +0 -143
- package/src/ascii/shapes/diamond.ts +0 -27
- package/src/ascii/shapes/hexagon.ts +0 -27
- package/src/ascii/shapes/index.ts +0 -106
- package/src/ascii/shapes/rectangle.ts +0 -168
- package/src/ascii/shapes/rounded.ts +0 -27
- package/src/ascii/shapes/special.ts +0 -332
- package/src/ascii/shapes/stadium.ts +0 -110
- package/src/ascii/shapes/state.ts +0 -192
- package/src/ascii/shapes/types.ts +0 -73
- package/src/ascii/timeline.ts +0 -128
- package/src/ascii/types.ts +0 -312
- package/src/ascii/validate.ts +0 -120
- package/src/ascii/width.ts +0 -81
- package/src/ascii/xychart.ts +0 -919
- package/src/browser.ts +0 -29
- package/src/class/layout.ts +0 -240
- package/src/class/parser.ts +0 -332
- package/src/class/renderer.ts +0 -638
- package/src/class/types.ts +0 -129
- package/src/cli/agent-instructions.ts +0 -1
- package/src/cli/am-bin.ts +0 -6
- package/src/cli/exit-codes.ts +0 -18
- package/src/cli/index.ts +0 -1117
- package/src/cli/init-agent.ts +0 -147
- package/src/color-resolver.ts +0 -152
- package/src/elk-instance.ts +0 -114
- package/src/er/layout.ts +0 -187
- package/src/er/parser.ts +0 -226
- package/src/er/renderer.ts +0 -792
- package/src/er/types.ts +0 -99
- package/src/font-manifest.ts +0 -27
- package/src/gantt/layout.ts +0 -365
- package/src/gantt/parser.ts +0 -282
- package/src/gantt/pipeline.ts +0 -27
- package/src/gantt/renderer.ts +0 -414
- package/src/gantt/schedule.ts +0 -513
- package/src/gantt/types.ts +0 -255
- package/src/index.ts +0 -368
- package/src/journey/layout.ts +0 -520
- package/src/journey/parser.ts +0 -218
- package/src/journey/renderer.ts +0 -811
- package/src/journey/types.ts +0 -144
- package/src/layout/geometry.ts +0 -182
- package/src/layout/pass.ts +0 -142
- package/src/layout/passes/index.ts +0 -3916
- package/src/layout-engine.ts +0 -1565
- package/src/layout-rubric.ts +0 -659
- package/src/mcp/artifacts.ts +0 -137
- package/src/mcp/dynamic-harness.ts +0 -31
- package/src/mcp/dynamic-modules.d.ts +0 -7
- package/src/mcp/facade.ts +0 -608
- package/src/mcp/harness-runtime.ts +0 -203
- package/src/mcp/hosted-server.ts +0 -468
- package/src/mcp/mcp-bin.ts +0 -3
- package/src/mcp/mcp-cli.ts +0 -82
- package/src/mcp/protocol.ts +0 -13
- package/src/mcp/sandbox.ts +0 -195
- package/src/mcp/sdk-decl.ts +0 -387
- package/src/mcp/server.ts +0 -362
- package/src/mcp/tool-surface.ts +0 -146
- package/src/mermaid-source.ts +0 -655
- package/src/multiline-utils.ts +0 -228
- package/src/parser.ts +0 -1031
- package/src/pie/layout.ts +0 -168
- package/src/pie/parser.ts +0 -136
- package/src/pie/renderer.ts +0 -234
- package/src/pie/types.ts +0 -82
- package/src/quadrant/layout.ts +0 -191
- package/src/quadrant/parser.ts +0 -183
- package/src/quadrant/renderer.ts +0 -322
- package/src/quadrant/types.ts +0 -113
- package/src/render-family-hooks.ts +0 -244
- package/src/renderer.ts +0 -1099
- package/src/route-contracts.ts +0 -2723
- package/src/scene/backend.ts +0 -76
- package/src/scene/fidelity.ts +0 -183
- package/src/scene/hybrid-backend.ts +0 -174
- package/src/scene/ir.ts +0 -181
- package/src/scene/marks.ts +0 -127
- package/src/scene/rough-backend.ts +0 -378
- package/src/scene/seed.ts +0 -46
- package/src/scene/style-registry.ts +0 -556
- package/src/sequence/layout.ts +0 -456
- package/src/sequence/parser.ts +0 -255
- package/src/sequence/renderer.ts +0 -604
- package/src/sequence/types.ts +0 -154
- package/src/shape-clipping.ts +0 -351
- package/src/shared/accessibility-directives.ts +0 -22
- package/src/shared/batched.ts +0 -61
- package/src/shared/color-math.ts +0 -72
- package/src/shared/svg-a11y.ts +0 -29
- package/src/shared/syntax-error.ts +0 -17
- package/src/shared/unicode-ranges.ts +0 -135
- package/src/styles.ts +0 -318
- package/src/svg-paths.ts +0 -28
- package/src/text-metrics.ts +0 -248
- package/src/theme.ts +0 -639
- package/src/timeline/layout.ts +0 -381
- package/src/timeline/parser.ts +0 -215
- package/src/timeline/renderer.ts +0 -538
- package/src/timeline/types.ts +0 -105
- package/src/types.ts +0 -454
- package/src/website-worker-modules.d.ts +0 -18
- package/src/xychart/axis-utils.ts +0 -109
- package/src/xychart/colors.ts +0 -124
- package/src/xychart/config.ts +0 -88
- package/src/xychart/layout.ts +0 -656
- package/src/xychart/parser.ts +0 -504
- package/src/xychart/renderer.ts +0 -640
- package/src/xychart/types.ts +0 -282
package/src/ascii/reverse.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Reverse ASCII → Mermaid (Loop 10 M5, raiscui-inspired).
|
|
3
|
-
//
|
|
4
|
-
// BEST-EFFORT, FLOWCHART-ONLY, LOSSY BY NATURE. The ASCII render only carries
|
|
5
|
-
// node LABELS (the text inside boxes), not the original node IDs — so this
|
|
6
|
-
// reconstructs structure with SYNTHESIZED ids (N0, N1, …). It recovers:
|
|
7
|
-
// - boxes (┌─┐ / └─┘ rectangles, and their ASCII +,-,| equivalents) → nodes
|
|
8
|
-
// - arrows (──►, ◄──, ▼, ▲, and ASCII >,<,v,^) → directed edges, by
|
|
9
|
-
// spatial adjacency of an arrowhead to a box border
|
|
10
|
-
//
|
|
11
|
-
// What it does NOT recover: original ids, edge labels, node shapes (everything
|
|
12
|
-
// becomes a rectangle), subgraphs, styling. Round-trip is STRUCTURAL
|
|
13
|
-
// (same node-label set + same edge count), never byte-identical source.
|
|
14
|
-
//
|
|
15
|
-
// Honest contract (see docs/quality.md): reliable for simple linear chains and
|
|
16
|
-
// simple fan-outs. Dense/overlapping routes may miss or mis-attribute edges.
|
|
17
|
-
// ============================================================================
|
|
18
|
-
|
|
19
|
-
import type { Result, ParseError } from '../agent/types.ts'
|
|
20
|
-
import { ok, err } from '../agent/types.ts'
|
|
21
|
-
|
|
22
|
-
interface Box { id: string; label: string; top: number; left: number; bottom: number; right: number }
|
|
23
|
-
|
|
24
|
-
const TL = new Set(['┌', '╭'])
|
|
25
|
-
const TR = new Set(['┐', '╮'])
|
|
26
|
-
const ARROW_R = new Set(['►', '▶', '>'])
|
|
27
|
-
const ARROW_L = new Set(['◄', '◀', '<'])
|
|
28
|
-
const ARROW_D = new Set(['▼', 'v'])
|
|
29
|
-
const ARROW_U = new Set(['▲', '^'])
|
|
30
|
-
|
|
31
|
-
/** Detect rectangular boxes in the ASCII canvas. Returns boxes with their label text. */
|
|
32
|
-
function detectBoxes(rows: string[]): Box[] {
|
|
33
|
-
const boxes: Box[] = []
|
|
34
|
-
let counter = 0
|
|
35
|
-
for (let y = 0; y < rows.length; y++) {
|
|
36
|
-
const row = rows[y]!
|
|
37
|
-
for (let x = 0; x < row.length; x++) {
|
|
38
|
-
const ch = row[x]!
|
|
39
|
-
// A top-left corner (Unicode ┌/╭ or ASCII '+').
|
|
40
|
-
const isCorner = TL.has(ch) || (ch === '+' && isAsciiTopLeft(rows, x, y))
|
|
41
|
-
if (!isCorner) continue
|
|
42
|
-
const box = traceBox(rows, x, y)
|
|
43
|
-
if (box) { box.id = `N${counter++}`; boxes.push(box) }
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return boxes
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function isAsciiTopLeft(rows: string[], x: number, y: number): boolean {
|
|
50
|
-
// '+' is a corner if a '-' is to its right and a '|' below.
|
|
51
|
-
const right = rows[y]?.[x + 1]
|
|
52
|
-
const below = rows[y + 1]?.[x]
|
|
53
|
-
return right === '-' && below === '|'
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Given a top-left corner, scan right for the top edge and down for the left edge. */
|
|
57
|
-
function traceBox(rows: string[], x0: number, y0: number): Box | null {
|
|
58
|
-
const topRow = rows[y0]!
|
|
59
|
-
let x1 = -1
|
|
60
|
-
for (let x = x0 + 1; x < topRow.length; x++) {
|
|
61
|
-
const ch = topRow[x]!
|
|
62
|
-
if (TR.has(ch) || ch === '+') { x1 = x; break }
|
|
63
|
-
if (ch !== '─' && ch !== '-') break
|
|
64
|
-
}
|
|
65
|
-
if (x1 < 0) return null
|
|
66
|
-
let y1 = -1
|
|
67
|
-
for (let y = y0 + 1; y < rows.length; y++) {
|
|
68
|
-
const ch = rows[y]?.[x0]
|
|
69
|
-
if (ch === '└' || ch === '╰' || ch === '+') { y1 = y; break }
|
|
70
|
-
if (ch !== '│' && ch !== '|') break
|
|
71
|
-
}
|
|
72
|
-
if (y1 < 0) return null
|
|
73
|
-
// Extract label: non-border text inside the box, joined.
|
|
74
|
-
const labelParts: string[] = []
|
|
75
|
-
for (let y = y0 + 1; y < y1; y++) {
|
|
76
|
-
const seg = (rows[y] ?? '').slice(x0 + 1, x1).replace(/[│|]/g, ' ').trim()
|
|
77
|
-
if (seg) labelParts.push(seg)
|
|
78
|
-
}
|
|
79
|
-
return { id: '', label: labelParts.join(' ').trim(), top: y0, left: x0, bottom: y1, right: x1 }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Which box border is the cell (x,y) adjacent to / inside? */
|
|
83
|
-
function boxAt(boxes: Box[], x: number, y: number, slack = 1): Box | null {
|
|
84
|
-
for (const b of boxes) {
|
|
85
|
-
if (x >= b.left - slack && x <= b.right + slack && y >= b.top - slack && y <= b.bottom + slack) return b
|
|
86
|
-
}
|
|
87
|
-
return null
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Detect directed edges by finding arrowheads and walking back along the
|
|
92
|
-
* connector to the originating box. Best-effort: handles the common
|
|
93
|
-
* horizontal (──►) and vertical (▼) cases.
|
|
94
|
-
*/
|
|
95
|
-
function detectEdges(rows: string[], boxes: Box[]): Array<[string, string]> {
|
|
96
|
-
const edges: Array<[string, string]> = []
|
|
97
|
-
const seen = new Set<string>()
|
|
98
|
-
for (let y = 0; y < rows.length; y++) {
|
|
99
|
-
const row = rows[y]!
|
|
100
|
-
for (let x = 0; x < row.length; x++) {
|
|
101
|
-
const ch = row[x]!
|
|
102
|
-
let target: Box | null = null
|
|
103
|
-
let source: Box | null = null
|
|
104
|
-
if (ARROW_R.has(ch)) { target = boxAt(boxes, x + 1, y); source = walkLeft(rows, boxes, x, y) }
|
|
105
|
-
else if (ARROW_L.has(ch)) { target = boxAt(boxes, x - 1, y); source = walkRight(rows, boxes, x, y) }
|
|
106
|
-
else if (ARROW_D.has(ch)) { target = boxAt(boxes, x, y + 1); source = walkUp(rows, boxes, x, y) }
|
|
107
|
-
else if (ARROW_U.has(ch)) { target = boxAt(boxes, x, y - 1); source = walkDown(rows, boxes, x, y) }
|
|
108
|
-
if (source && target && source.id !== target.id) {
|
|
109
|
-
const key = `${source.id}->${target.id}`
|
|
110
|
-
if (!seen.has(key)) { seen.add(key); edges.push([source.id, target.id]) }
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return edges
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const HLINE = new Set(['─', '-', '┬', '┴', '┼', '├', '┤', '+'])
|
|
118
|
-
const VLINE = new Set(['│', '|', '┬', '┴', '┼', '├', '┤', '+'])
|
|
119
|
-
|
|
120
|
-
function walkLeft(rows: string[], boxes: Box[], x: number, y: number): Box | null {
|
|
121
|
-
for (let cx = x - 1; cx >= 0; cx--) {
|
|
122
|
-
const b = boxAt(boxes, cx, y); if (b) return b
|
|
123
|
-
if (!HLINE.has(rows[y]?.[cx] ?? '')) { // allow turning up/down at a junction
|
|
124
|
-
const up = boxAt(boxes, cx, y - 1), dn = boxAt(boxes, cx, y + 1)
|
|
125
|
-
return up ?? dn ?? null
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return null
|
|
129
|
-
}
|
|
130
|
-
function walkRight(rows: string[], boxes: Box[], x: number, y: number): Box | null {
|
|
131
|
-
for (let cx = x + 1; cx < (rows[y]?.length ?? 0); cx++) {
|
|
132
|
-
const b = boxAt(boxes, cx, y); if (b) return b
|
|
133
|
-
if (!HLINE.has(rows[y]?.[cx] ?? '')) break
|
|
134
|
-
}
|
|
135
|
-
return null
|
|
136
|
-
}
|
|
137
|
-
function walkUp(rows: string[], boxes: Box[], x: number, y: number): Box | null {
|
|
138
|
-
let cx = x
|
|
139
|
-
for (let cy = y - 1; cy >= 0; cy--) {
|
|
140
|
-
const b = boxAt(boxes, cx, cy); if (b) return b
|
|
141
|
-
const ch = rows[cy]?.[cx] ?? ''
|
|
142
|
-
// Junction/fork glyphs (┬┴┼├┤ and corners): the trunk may bend
|
|
143
|
-
// horizontally here (fan-out connectors like `├───┬───┐`). If the cell
|
|
144
|
-
// directly above is NOT a vertical line, hop along the horizontal run to
|
|
145
|
-
// the column that continues upward (the trunk root), then resume.
|
|
146
|
-
const isJunction = '┬┴┼├┤┐┌╮╭'.includes(ch)
|
|
147
|
-
if (isJunction && !VLINE.has(rows[cy - 1]?.[cx] ?? '')) {
|
|
148
|
-
const hop = hopToTrunk(rows, cx, cy)
|
|
149
|
-
if (hop === null) {
|
|
150
|
-
const left = boxAt(boxes, cx - 1, cy), right = boxAt(boxes, cx + 1, cy)
|
|
151
|
-
return left ?? right ?? null
|
|
152
|
-
}
|
|
153
|
-
cx = hop
|
|
154
|
-
continue
|
|
155
|
-
}
|
|
156
|
-
if (VLINE.has(ch)) continue
|
|
157
|
-
if (HLINE.has(ch)) {
|
|
158
|
-
const hop = hopToTrunk(rows, cx, cy)
|
|
159
|
-
if (hop !== null) { cx = hop; continue }
|
|
160
|
-
const left = boxAt(boxes, cx - 1, cy), right = boxAt(boxes, cx + 1, cy)
|
|
161
|
-
return left ?? right ?? null
|
|
162
|
-
}
|
|
163
|
-
// Dead air — give up.
|
|
164
|
-
const left = boxAt(boxes, cx - 1, cy), right = boxAt(boxes, cx + 1, cy)
|
|
165
|
-
return left ?? right ?? null
|
|
166
|
-
}
|
|
167
|
-
return null
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** On a horizontal junction row, scan left then right for a column whose cell
|
|
171
|
-
* above is a vertical line (the trunk continuing up). Returns that column or null. */
|
|
172
|
-
function hopToTrunk(rows: string[], x: number, y: number): number | null {
|
|
173
|
-
const above = (cx: number) => rows[y - 1]?.[cx] ?? ''
|
|
174
|
-
// Prefer the nearest column (left then right) that has a vertical above it.
|
|
175
|
-
for (let d = 0; d < 200; d++) {
|
|
176
|
-
for (const cx of [x - d, x + d]) {
|
|
177
|
-
const here = rows[y]?.[cx] ?? ''
|
|
178
|
-
if (!HLINE.has(here) && !'┐┌╮╭'.includes(here)) continue
|
|
179
|
-
if (VLINE.has(above(cx))) return cx
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return null
|
|
183
|
-
}
|
|
184
|
-
function walkDown(rows: string[], boxes: Box[], x: number, y: number): Box | null {
|
|
185
|
-
for (let cy = y + 1; cy < rows.length; cy++) {
|
|
186
|
-
const b = boxAt(boxes, x, cy); if (b) return b
|
|
187
|
-
if (!VLINE.has(rows[cy]?.[x] ?? '')) break
|
|
188
|
-
}
|
|
189
|
-
return null
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function escapeLabel(label: string): string {
|
|
193
|
-
// If the label has spaces or special chars, the [..] form handles it; quote
|
|
194
|
-
// only when it contains brackets that would break the shape.
|
|
195
|
-
return /["[\]{}()]/.test(label) ? `["${label.replace(/"/g, '"')}"]` : `[${label}]`
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Reverse an ASCII flowchart render back to (best-effort) Mermaid source.
|
|
200
|
-
* Returns synthesized ids (N0, N1, …) with recovered labels and edges.
|
|
201
|
-
*/
|
|
202
|
-
export function asciiToMermaid(ascii: string, opts: { direction?: 'TD' | 'LR' } = {}): Result<string, ParseError[]> {
|
|
203
|
-
if (!ascii.trim()) return err([{ code: 'EMPTY', message: 'empty ASCII input' }])
|
|
204
|
-
const rows = ascii.replace(/\[[0-9;]*m/g, '').split(/\r?\n/) // strip ANSI
|
|
205
|
-
const boxes = detectBoxes(rows)
|
|
206
|
-
if (boxes.length === 0) return err([{ code: 'NO_BOXES', message: 'no boxes detected in ASCII; not a recognized flowchart render' }])
|
|
207
|
-
|
|
208
|
-
const edges = detectEdges(rows, boxes)
|
|
209
|
-
const dir = opts.direction ?? 'LR'
|
|
210
|
-
const lines: string[] = [`flowchart ${dir}`]
|
|
211
|
-
// Emit node declarations (id + recovered label).
|
|
212
|
-
for (const b of boxes) lines.push(` ${b.id}${escapeLabel(b.label || b.id)}`)
|
|
213
|
-
// Emit edges.
|
|
214
|
-
for (const [from, to] of edges) lines.push(` ${from} --> ${to}`)
|
|
215
|
-
return ok(lines.join('\n'))
|
|
216
|
-
}
|