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.
- package/AGENT_NATIVE.md +155 -91
- package/CHANGELOG.md +163 -4
- package/Instructions_for_agents.md +10 -10
- package/LICENSES/Apache-2.0.txt +202 -0
- package/README.md +31 -38
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/assets/hero.png +0 -0
- package/dist/agent-core.d.ts +463 -0
- package/dist/agent-core.js +397 -0
- package/dist/agent.d.ts +73 -1868
- package/dist/agent.js +336 -37325
- package/dist/agentic-mermaid-mcp.js +7 -38399
- package/dist/am.js +33626 -40446
- package/dist/chunk-2P5FKUQC.js +3485 -0
- package/dist/chunk-2S3VSS6I.js +149 -0
- package/dist/chunk-2SILJDW2.js +37 -0
- package/dist/chunk-BJYMBT4I.js +61963 -0
- package/dist/chunk-FDM43XU7.js +615 -0
- package/dist/chunk-MYPDVZCO.js +4702 -0
- package/dist/index-DWPa2MJs.d.ts +6780 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +310 -33014
- package/dist/mcp-cli-5J47WEY3.js +17 -0
- package/docs/README.md +39 -31
- package/docs/agent-api-cookbook.md +44 -35
- package/docs/agent-mutation-policy.md +1 -1
- package/docs/agent-workflow-examples.md +2 -2
- package/docs/api.md +284 -77
- package/docs/ascii.md +26 -16
- package/docs/code-mode-impact.md +214 -0
- package/docs/comparison.md +23 -11
- package/docs/computational-aesthetics-prototype-plan.md +252 -0
- package/docs/config.md +26 -10
- package/docs/custom-fonts.md +265 -0
- package/docs/custom-style-cookbook.md +130 -9
- package/docs/diagram-families.md +48 -23
- package/docs/features.md +59 -52
- package/docs/fork-differences.md +6 -3
- package/docs/getting-started.md +23 -16
- package/docs/issue-derived-test-cases.md +29 -22
- package/docs/mcp-code-mode-rationale.md +13 -6
- package/docs/mcp-http-transport.md +20 -13
- package/docs/mermaid-layout-complaints.md +66 -52
- package/docs/mutation-testing.md +145 -66
- package/docs/quality.md +23 -14
- package/docs/react.md +2 -2
- package/docs/schemas/style-spec.schema.json +1221 -30
- package/docs/style-authoring.md +241 -38
- package/docs/svg-semantic-contract.md +49 -0
- package/docs/testing-strategy.md +166 -58
- package/docs/theming.md +19 -32
- 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 +85 -45
- package/server.json +2 -2
- 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/TODO.md +0 -684
- package/dist/index-wjRjbsP-.d.ts +0 -1102
- 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/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 -82
- package/docs/contributing/visual-review-evidence.md +0 -53
- 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-experience-curve-implementation.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 -439
- package/docs/design/families/journey-section-overlap-after.png +0 -0
- package/docs/design/families/journey-section-overlap-before.png +0 -0
- package/docs/design/families/journey-usage-research.md +0 -423
- package/docs/design/families/journey.md +0 -153
- 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/layout-characterization/README.md +0 -245
- package/docs/layout-characterization/contact-sheet-families.md +0 -498
- 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 -98
- 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/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/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 -368
- package/src/agent/er-body.ts +0 -224
- package/src/agent/facts.ts +0 -360
- package/src/agent/families-builtin.ts +0 -920
- package/src/agent/families.ts +0 -232
- package/src/agent/family-layouts.ts +0 -832
- package/src/agent/flowchart-body.ts +0 -372
- package/src/agent/flowchart-unsupported.ts +0 -243
- package/src/agent/font-coverage.ts +0 -288
- package/src/agent/gantt-body.ts +0 -495
- package/src/agent/index.ts +0 -10
- package/src/agent/journey-body.ts +0 -374
- 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 -443
- package/src/agent/parse.ts +0 -223
- package/src/agent/pie-body.ts +0 -270
- package/src/agent/png.ts +0 -171
- 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 -995
- package/src/agent/verify.ts +0 -603
- 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 -169
- 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 -141
- package/src/ascii/types.ts +0 -312
- package/src/ascii/validate.ts +0 -120
- package/src/ascii/width.ts +0 -81
- package/src/ascii/wrap.ts +0 -131
- 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 -1132
- package/src/cli/init-agent.ts +0 -147
- package/src/cli/run-entrypoint.ts +0 -10
- 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/family-rubric.ts +0 -425
- package/src/font-manifest.ts +0 -31
- 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 -554
- package/src/journey/parse-core.ts +0 -251
- package/src/journey/parser.ts +0 -101
- package/src/journey/renderer.ts +0 -917
- 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 -391
- 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 -93
- 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 -710
- 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 -462
- 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/agent/class-body.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Class diagram structured body: parse, serialize, mutate, verify.
|
|
3
|
-
//
|
|
4
|
-
// Structured-or-opaque: returns a typed body when every line maps cleanly
|
|
5
|
-
// into the model, else returns null so the caller falls back to an opaque
|
|
6
|
-
// body (lossless round-trip via canonicalSource).
|
|
7
|
-
//
|
|
8
|
-
// Supported:
|
|
9
|
-
// class A
|
|
10
|
-
// class A { +member ... } (multi-line braces)
|
|
11
|
-
// class A["Display label"]
|
|
12
|
-
// class A as "Display label"
|
|
13
|
-
// A : +member (separate-decl member)
|
|
14
|
-
// A <|-- B / *-- / o-- / --> / ..> / ..|> / -- / .. (relations)
|
|
15
|
-
// A "card" <|-- "card" B : label (cardinalities + label)
|
|
16
|
-
// note for A "text"
|
|
17
|
-
// note "text"
|
|
18
|
-
// title T
|
|
19
|
-
//
|
|
20
|
-
// Unmodeled (forces opaque):
|
|
21
|
-
// - direction TB / namespaces / generic types / annotations like <<enum>>
|
|
22
|
-
// embedded after `class X` (we DO accept them as `members` of X via the
|
|
23
|
-
// `class X { <<interface>> }` form). The standalone `class X <<...>>`
|
|
24
|
-
// form falls back to opaque.
|
|
25
|
-
// - cssClass / link / callback / click handlers
|
|
26
|
-
// - styled / classDef
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
|
-
import { unknownOpMessage } from './mutation-ops.ts'
|
|
30
|
-
import type {
|
|
31
|
-
ClassBody, ClassNode, ClassRelation, ClassRelationKind, ClassNote,
|
|
32
|
-
ClassMutationOp, MutationError, Result, LayoutWarning, VerifyOptions,
|
|
33
|
-
} from './types.ts'
|
|
34
|
-
import { ok, err, DEFAULT_LABEL_CHAR_CAP } from './types.ts'
|
|
35
|
-
import { labelOverflowWarning } from './label-metrics.ts'
|
|
36
|
-
|
|
37
|
-
// ---- Parser ---------------------------------------------------------------
|
|
38
|
-
|
|
39
|
-
const RELATION_TOKENS: Array<{ pat: RegExp; kind: ClassRelationKind }> = [
|
|
40
|
-
// Order matters: more specific (4+ char) before shorter ones.
|
|
41
|
-
{ pat: /<\|--/, kind: 'inheritance' },
|
|
42
|
-
{ pat: /--\|>/, kind: 'inheritance' },
|
|
43
|
-
{ pat: /\.\.\|>/, kind: 'realization' },
|
|
44
|
-
{ pat: /\*--/, kind: 'composition' },
|
|
45
|
-
{ pat: /--\*/, kind: 'composition' },
|
|
46
|
-
{ pat: /o--/, kind: 'aggregation' },
|
|
47
|
-
{ pat: /--o/, kind: 'aggregation' },
|
|
48
|
-
{ pat: /-->/, kind: 'association' },
|
|
49
|
-
{ pat: /<--/, kind: 'association' },
|
|
50
|
-
{ pat: /\.\.>/, kind: 'dependency' },
|
|
51
|
-
{ pat: /<\.\./, kind: 'dependency' },
|
|
52
|
-
{ pat: /--/, kind: 'link-solid' },
|
|
53
|
-
{ pat: /\.\./, kind: 'link-dashed' },
|
|
54
|
-
]
|
|
55
|
-
|
|
56
|
-
// `class X`, `class X { ... }`, `class X["label"]`, `class X as "label"`
|
|
57
|
-
const CLASS_DECL_RE = /^class\s+(`[^`]+`|[\w$]+)(?:\s*\[\s*"([^"]*)"\s*\])?(?:\s+as\s+"([^"]+)")?\s*(\{)?\s*$/
|
|
58
|
-
const MEMBER_DECL_RE = /^(`[^`]+`|[\w$]+)\s*:\s*(.+)$/
|
|
59
|
-
const NOTE_RE = /^note(?:\s+for\s+(`[^`]+`|[\w$]+))?\s+"([^"]+)"\s*$/
|
|
60
|
-
const TITLE_RE = /^title\s+(.+)$/i
|
|
61
|
-
|
|
62
|
-
function stripBackticks(s: string): string {
|
|
63
|
-
return s.startsWith('`') && s.endsWith('`') ? s.slice(1, -1) : s
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function parseRelation(line: string): ClassRelation | null {
|
|
67
|
-
for (const { pat, kind } of RELATION_TOKENS) {
|
|
68
|
-
const m = line.match(new RegExp(`^(\\S+?)(?:\\s+"([^"]+)")?\\s*${pat.source}\\s*(?:"([^"]+)"\\s+)?(\\S+?)(?:\\s*:\\s*(.+))?$`))
|
|
69
|
-
if (!m) continue
|
|
70
|
-
const from = stripBackticks(m[1]!)
|
|
71
|
-
const fromCardinality = m[2]
|
|
72
|
-
const toCardinality = m[3]
|
|
73
|
-
const to = stripBackticks(m[4]!)
|
|
74
|
-
const label = m[5]?.trim()
|
|
75
|
-
// Reject if from/to don't look like class names
|
|
76
|
-
if (!/^[\w$]+$/.test(from) || !/^[\w$]+$/.test(to)) return null
|
|
77
|
-
return { from, to, kind, label, fromCardinality, toCardinality }
|
|
78
|
-
}
|
|
79
|
-
return null
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function parseClassBody(lines: string[]): ClassBody | null {
|
|
83
|
-
const body: ClassBody = { kind: 'class', classes: [], relations: [], notes: [] }
|
|
84
|
-
const classMap = new Map<string, ClassNode>()
|
|
85
|
-
const upsert = (id: string, label?: string): ClassNode => {
|
|
86
|
-
let c = classMap.get(id)
|
|
87
|
-
if (!c) { c = { id, label, members: [] }; classMap.set(id, c); body.classes.push(c) }
|
|
88
|
-
else if (label !== undefined && !c.label) c.label = label
|
|
89
|
-
return c
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let i = 0
|
|
93
|
-
while (i < lines.length) {
|
|
94
|
-
const raw = lines[i]!.trim()
|
|
95
|
-
i++
|
|
96
|
-
if (!raw || raw.startsWith('%%')) continue
|
|
97
|
-
|
|
98
|
-
// Title
|
|
99
|
-
const tm = raw.match(TITLE_RE)
|
|
100
|
-
if (tm) { body.title = tm[1]!.trim(); continue }
|
|
101
|
-
|
|
102
|
-
// Class declaration (with or without open brace)
|
|
103
|
-
const cm = raw.match(CLASS_DECL_RE)
|
|
104
|
-
if (cm) {
|
|
105
|
-
const id = stripBackticks(cm[1]!)
|
|
106
|
-
const label = cm[2] ?? cm[3]
|
|
107
|
-
const node = upsert(id, label)
|
|
108
|
-
if (cm[4] === '{') {
|
|
109
|
-
// Consume members until closing brace
|
|
110
|
-
while (i < lines.length) {
|
|
111
|
-
const ml = lines[i]!.trim()
|
|
112
|
-
i++
|
|
113
|
-
if (!ml || ml.startsWith('%%')) continue
|
|
114
|
-
if (ml === '}') break
|
|
115
|
-
node.members.push(ml)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
continue
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Note (with or without target)
|
|
122
|
-
const nm = raw.match(NOTE_RE)
|
|
123
|
-
if (nm) {
|
|
124
|
-
body.notes.push({ text: nm[2]!, for: nm[1] ? stripBackticks(nm[1]) : undefined })
|
|
125
|
-
continue
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Relation — try this before member because relations may have `:` too
|
|
129
|
-
const rel = parseRelation(raw)
|
|
130
|
-
if (rel) { body.relations.push(rel); upsert(rel.from); upsert(rel.to); continue }
|
|
131
|
-
|
|
132
|
-
// Member declaration (X : member)
|
|
133
|
-
const mm = raw.match(MEMBER_DECL_RE)
|
|
134
|
-
if (mm) {
|
|
135
|
-
const id = stripBackticks(mm[1]!)
|
|
136
|
-
const text = mm[2]!.trim()
|
|
137
|
-
upsert(id).members.push(text)
|
|
138
|
-
continue
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Unmodeled line — bail to opaque.
|
|
142
|
-
return null
|
|
143
|
-
}
|
|
144
|
-
return body
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ---- Serializer -----------------------------------------------------------
|
|
148
|
-
|
|
149
|
-
const ARROW_FOR: Record<ClassRelationKind, string> = {
|
|
150
|
-
inheritance: '<|--',
|
|
151
|
-
composition: '*--',
|
|
152
|
-
aggregation: 'o--',
|
|
153
|
-
association: '-->',
|
|
154
|
-
dependency: '..>',
|
|
155
|
-
realization: '..|>',
|
|
156
|
-
'link-solid': '--',
|
|
157
|
-
'link-dashed': '..',
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function quoteIfNeeded(id: string): string {
|
|
161
|
-
return /^[\w$]+$/.test(id) ? id : `\`${id}\``
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function renderClass(body: ClassBody): string {
|
|
165
|
-
const lines: string[] = ['classDiagram']
|
|
166
|
-
if (body.title) lines.push(` title ${body.title}`)
|
|
167
|
-
for (const n of body.notes) {
|
|
168
|
-
if (n.for) lines.push(` note for ${quoteIfNeeded(n.for)} "${n.text}"`)
|
|
169
|
-
else lines.push(` note "${n.text}"`)
|
|
170
|
-
}
|
|
171
|
-
for (const c of body.classes) {
|
|
172
|
-
const head = `class ${quoteIfNeeded(c.id)}${c.label ? `["${c.label}"]` : ''}`
|
|
173
|
-
if (c.members.length === 0) {
|
|
174
|
-
lines.push(` ${head}`)
|
|
175
|
-
} else {
|
|
176
|
-
lines.push(` ${head} {`)
|
|
177
|
-
for (const m of c.members) lines.push(` ${m}`)
|
|
178
|
-
lines.push(` }`)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
for (const r of body.relations) {
|
|
182
|
-
const arrow = ARROW_FOR[r.kind]
|
|
183
|
-
const left = r.fromCardinality ? `${quoteIfNeeded(r.from)} "${r.fromCardinality}"` : quoteIfNeeded(r.from)
|
|
184
|
-
const right = r.toCardinality ? `"${r.toCardinality}" ${quoteIfNeeded(r.to)}` : quoteIfNeeded(r.to)
|
|
185
|
-
const label = r.label ? ` : ${r.label}` : ''
|
|
186
|
-
lines.push(` ${left} ${arrow} ${right}${label}`)
|
|
187
|
-
}
|
|
188
|
-
return lines.join('\n') + '\n'
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// ---- Mutator --------------------------------------------------------------
|
|
192
|
-
|
|
193
|
-
function cloneClass(body: ClassBody): ClassBody {
|
|
194
|
-
return {
|
|
195
|
-
kind: 'class',
|
|
196
|
-
title: body.title,
|
|
197
|
-
classes: body.classes.map(c => ({ id: c.id, label: c.label, members: [...c.members] })),
|
|
198
|
-
relations: body.relations.map(r => ({ ...r })),
|
|
199
|
-
notes: body.notes.map(n => ({ ...n })),
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function mutateClass(body: ClassBody, op: ClassMutationOp): Result<ClassBody, MutationError> {
|
|
204
|
-
const b = cloneClass(body)
|
|
205
|
-
const findClass = (id: string) => b.classes.find(c => c.id === id)
|
|
206
|
-
|
|
207
|
-
switch (op.kind) {
|
|
208
|
-
case 'set_title': {
|
|
209
|
-
b.title = op.title ?? undefined
|
|
210
|
-
return ok(b)
|
|
211
|
-
}
|
|
212
|
-
case 'add_class': {
|
|
213
|
-
if (findClass(op.id)) return err({ code: 'DUPLICATE_CLASS', message: `class ${op.id} already exists` })
|
|
214
|
-
b.classes.push({ id: op.id, label: op.label, members: op.members ?? [] })
|
|
215
|
-
return ok(b)
|
|
216
|
-
}
|
|
217
|
-
case 'remove_class': {
|
|
218
|
-
const i = b.classes.findIndex(c => c.id === op.id)
|
|
219
|
-
if (i < 0) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.id} not found` })
|
|
220
|
-
b.classes.splice(i, 1)
|
|
221
|
-
b.relations = b.relations.filter(r => r.from !== op.id && r.to !== op.id)
|
|
222
|
-
b.notes = b.notes.filter(n => n.for !== op.id)
|
|
223
|
-
return ok(b)
|
|
224
|
-
}
|
|
225
|
-
case 'rename_class': {
|
|
226
|
-
const c = findClass(op.from)
|
|
227
|
-
if (!c) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.from} not found` })
|
|
228
|
-
if (findClass(op.to)) return err({ code: 'DUPLICATE_CLASS', message: `class ${op.to} already exists` })
|
|
229
|
-
c.id = op.to
|
|
230
|
-
for (const r of b.relations) {
|
|
231
|
-
if (r.from === op.from) r.from = op.to
|
|
232
|
-
if (r.to === op.from) r.to = op.to
|
|
233
|
-
}
|
|
234
|
-
for (const n of b.notes) if (n.for === op.from) n.for = op.to
|
|
235
|
-
return ok(b)
|
|
236
|
-
}
|
|
237
|
-
case 'add_member': {
|
|
238
|
-
const c = findClass(op.class)
|
|
239
|
-
if (!c) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.class} not found` })
|
|
240
|
-
c.members.push(op.text)
|
|
241
|
-
return ok(b)
|
|
242
|
-
}
|
|
243
|
-
case 'remove_member': {
|
|
244
|
-
const c = findClass(op.class)
|
|
245
|
-
if (!c) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.class} not found` })
|
|
246
|
-
if (op.index < 0 || op.index >= c.members.length) return err({ code: 'MEMBER_NOT_FOUND', message: `member index ${op.index} out of range` })
|
|
247
|
-
c.members.splice(op.index, 1)
|
|
248
|
-
return ok(b)
|
|
249
|
-
}
|
|
250
|
-
case 'add_relation': {
|
|
251
|
-
if (!findClass(op.from)) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.from} not found` })
|
|
252
|
-
if (!findClass(op.to)) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.to} not found` })
|
|
253
|
-
b.relations.push({ from: op.from, to: op.to, kind: op.relKind, label: op.label })
|
|
254
|
-
return ok(b)
|
|
255
|
-
}
|
|
256
|
-
case 'remove_relation': {
|
|
257
|
-
if (op.index < 0 || op.index >= b.relations.length) return err({ code: 'RELATION_NOT_FOUND', message: `relation index ${op.index} out of range` })
|
|
258
|
-
b.relations.splice(op.index, 1)
|
|
259
|
-
return ok(b)
|
|
260
|
-
}
|
|
261
|
-
case 'add_note': {
|
|
262
|
-
if (op.for && !findClass(op.for)) return err({ code: 'CLASS_NOT_FOUND', message: `class ${op.for} not found` })
|
|
263
|
-
b.notes.push({ text: op.text, for: op.for })
|
|
264
|
-
return ok(b)
|
|
265
|
-
}
|
|
266
|
-
case 'remove_note': {
|
|
267
|
-
if (op.index < 0 || op.index >= b.notes.length) return err({ code: 'NOTE_NOT_FOUND', message: `note index ${op.index} out of range` })
|
|
268
|
-
b.notes.splice(op.index, 1)
|
|
269
|
-
return ok(b)
|
|
270
|
-
}
|
|
271
|
-
default:
|
|
272
|
-
return err({ code: 'INVALID_OP', message: unknownOpMessage('class', op) })
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// ---- Verifier -------------------------------------------------------------
|
|
277
|
-
|
|
278
|
-
export function verifyClass(body: ClassBody, opts: VerifyOptions): LayoutWarning[] {
|
|
279
|
-
const warnings: LayoutWarning[] = []
|
|
280
|
-
const cap = opts.labelCharCap ?? DEFAULT_LABEL_CHAR_CAP
|
|
281
|
-
|
|
282
|
-
if (body.classes.length === 0 && body.title === undefined) {
|
|
283
|
-
warnings.push({ code: 'EMPTY_DIAGRAM' })
|
|
284
|
-
return warnings
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const overflow = (target: string, text: string) => {
|
|
288
|
-
const w = labelOverflowWarning(target, text, cap)
|
|
289
|
-
if (w) warnings.push(w)
|
|
290
|
-
}
|
|
291
|
-
if (body.title) overflow('title', body.title)
|
|
292
|
-
|
|
293
|
-
const ids = new Set(body.classes.map(c => c.id))
|
|
294
|
-
for (const c of body.classes) {
|
|
295
|
-
if (c.label) overflow(c.id, c.label)
|
|
296
|
-
for (let i = 0; i < c.members.length; i++) {
|
|
297
|
-
overflow(`${c.id}#m${i}`, c.members[i]!)
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
for (let i = 0; i < body.relations.length; i++) {
|
|
301
|
-
const r = body.relations[i]!
|
|
302
|
-
if (!ids.has(r.from) || !ids.has(r.to)) {
|
|
303
|
-
warnings.push({
|
|
304
|
-
code: 'EDGE_MISANCHORED', edge: `rel#${i}:${r.from}->${r.to}`,
|
|
305
|
-
from: ids.has(r.from) ? r.from : undefined, to: ids.has(r.to) ? r.to : undefined,
|
|
306
|
-
})
|
|
307
|
-
}
|
|
308
|
-
if (r.label) overflow(`rel#${i}`, r.label)
|
|
309
|
-
}
|
|
310
|
-
for (let i = 0; i < body.notes.length; i++) {
|
|
311
|
-
const n = body.notes[i]!
|
|
312
|
-
overflow(`note#${i}`, n.text)
|
|
313
|
-
if (n.for && !ids.has(n.for)) {
|
|
314
|
-
warnings.push({ code: 'EDGE_MISANCHORED', edge: `note#${i}->${n.for}`, from: undefined, to: undefined })
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return warnings
|
|
319
|
-
}
|
package/src/agent/core.ts
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// agentic-mermaid — runtime-neutral agent surface (v4).
|
|
3
|
-
// Everything here is pure JS/TS (elkjs bundled build included) and safe to
|
|
4
|
-
// bundle for workerd/browser targets. The public barrel (`./index.ts`)
|
|
5
|
-
// re-exports this plus the Node-native `renderMermaidPNG`; import this module
|
|
6
|
-
// from code that must not drag in the napi resvg addon.
|
|
7
|
-
// No LayoutContext / SeededRNG / Clock / font-metrics: that apparatus did
|
|
8
|
-
// nothing (ELK is deterministic on its own). See AGENT_NATIVE.md § (1).
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
export type {
|
|
12
|
-
Result, ValidDiagram, FlowchartValidDiagram, StateValidDiagram, SequenceValidDiagram, TimelineValidDiagram,
|
|
13
|
-
ClassValidDiagram, ErValidDiagram, JourneyValidDiagram, ArchitectureValidDiagram, XyChartValidDiagram, PieValidDiagram, QuadrantValidDiagram, GanttValidDiagram, MutableValidDiagram,
|
|
14
|
-
ValidDiagramMeta, ValidDiagramPayload, SerializedFlowchartGraph, DiagramBody, DiagramKind,
|
|
15
|
-
StateBody, StateNode, StateTransition,
|
|
16
|
-
SequenceBody, SequenceParticipant, SequenceMessage, SequenceMessageStyle,
|
|
17
|
-
TimelineBody, TimelineSection, TimelinePeriod, TimelineEvent,
|
|
18
|
-
ClassBody, ClassNode, ClassRelation, ClassRelationKind, ClassNote,
|
|
19
|
-
ErBody, ErEntity, ErRelation, ErAttribute, ErCardinality,
|
|
20
|
-
JourneyBody, JourneySection, JourneyTask,
|
|
21
|
-
ArchitectureBody, ArchitectureGroup, ArchitectureService, ArchitectureJunction, ArchitectureEdge, ArchitectureEndpoint, ArchitectureSide,
|
|
22
|
-
XyChartBody, XyChartAxis, XyChartSeries, XyChartAxisSpec,
|
|
23
|
-
PieBody, PieSlice, QuadrantBody, QuadrantAxis, QuadrantPoint,
|
|
24
|
-
GanttBody, GanttBodySection, GanttBodyTask, GanttBodyTaskTag, GanttStatement,
|
|
25
|
-
SourceMap, SourceComment, InitDirective, Accessibility,
|
|
26
|
-
ParseError, MutationError, MutationOp, FlowchartMutationOp, StateMutationOp, SequenceMutationOp, TimelineMutationOp,
|
|
27
|
-
ClassMutationOp, ErMutationOp, JourneyMutationOp, ArchitectureMutationOp, XyChartMutationOp, PieMutationOp, QuadrantMutationOp, GanttMutationOp, AnyMutationOp,
|
|
28
|
-
NodeId, EdgeId, GroupId, ParticipantId,
|
|
29
|
-
LayoutWarning, WarningCode, Tier1WarningCode, Tier2WarningCode, WarningSeverity, WarningTier,
|
|
30
|
-
VerifyOptions, VerifyResult, RenderedLayout, RenderedLayoutNode, RenderedLayoutEdge, RenderedLayoutGroup, RenderedRegion, RenderedRegionKind,
|
|
31
|
-
DiagramAnalysis, DiagramActionRecord, DiagramActionKind, DiagramActionSecurity, FeedbackEdgeAnalysis, GanttScheduleAnalysisSummary,
|
|
32
|
-
Finite,
|
|
33
|
-
} from './types.ts'
|
|
34
|
-
export type { MermaidFact, CheckMermaidSpec, CheckMermaidObjectSpec, CheckMermaidResult } from './facts.ts'
|
|
35
|
-
|
|
36
|
-
export { WARNING_SEVERITY, WARNING_TIER, DEFAULT_LABEL_CHAR_CAP, ok, err, toFinite, asFlowchart, asState, asSequence, asTimeline, asClass, asEr, asJourney, asArchitecture, asXyChart, asPie, asQuadrant, asGantt } from './types.ts'
|
|
37
|
-
export { parseMermaid } from './parse.ts'
|
|
38
|
-
export { serializeMermaid, synthesizeFromGraph } from './serialize.ts'
|
|
39
|
-
export { createMermaid, buildMermaid } from './create.ts'
|
|
40
|
-
export type { CreateMermaidOptions, BuildError } from './create.ts'
|
|
41
|
-
export { mutate, mutateChecked, edgeIdOf } from './mutate.ts'
|
|
42
|
-
export { applyOps, buildChecked, verifySummary } from './apply.ts'
|
|
43
|
-
export type { OpEnvelope, VerifySummary, CheckedBuildError, ApplyOpsInput } from './apply.ts'
|
|
44
|
-
export { validateOp, hasOpSchema, opMenu, describeOps, opSignatures } from './op-schema.ts'
|
|
45
|
-
export type { OpFamily, OpValidationError, OpFieldDoc } from './op-schema.ts'
|
|
46
|
-
export { verifyMermaid } from './verify.ts'
|
|
47
|
-
export { measureQuality, checkQuality, DEFAULT_BOUNDS, BOUND_PROVENANCE } from './quality.ts'
|
|
48
|
-
export type { QualityMetrics, QualityBounds, QualityVerdict, RankedViolation, BoundProvenance, BoundBasis, ViolationSeverity } from './quality.ts'
|
|
49
|
-
export { layoutCertificateProof } from './certificates.ts'
|
|
50
|
-
export type { LayoutCertificateProof } from './certificates.ts'
|
|
51
|
-
export type { RouteCertificate, EdgeRouteCertificate, FamilyEdgeRouteCertificate, RegionContainmentCertificate, FamilyRouteCertificate, LayoutRouteCertificate, LayoutRouteClass, RouteClass, RouteBlocker, RoutePortAssignment, PortSemanticRole, AnyPort, PortSide, DiamondFacet } from '../types.ts'
|
|
52
|
-
export { registerFamily, getFamily, knownFamilies, BUILTIN_FAMILY_METADATA, BUILTIN_FAMILY_METADATA_COVERS_DIAGRAM_KIND, builtinFamilyMetadata } from './families.ts'
|
|
53
|
-
export type { FamilyPlugin, ExtractedLabel, BuiltinFamilyMetadata, BuiltinFamilyId } from './families.ts'
|
|
54
|
-
export { renderMermaidASCIIWithMeta, ASCII_ROUTE_PARITY_CONTRACT } from '../ascii/meta.ts'
|
|
55
|
-
export type { AsciiRegion, AsciiWithMeta, RegionKind, AsciiWarning, AsciiWarningCode } from '../ascii/meta.ts'
|
|
56
|
-
export { describeMermaid, describeMermaidSource, describeMermaidTree } from './describe.ts'
|
|
57
|
-
export { describeMermaidFacts, describeMermaidFactsSource, checkMermaid, checkMermaidSource } from './facts.ts'
|
|
58
|
-
export { analyzeMermaid, analyzeMermaidSource, collectActionRecords } from './analyze.ts'
|
|
59
|
-
export { TEXT_MEASUREMENT_CONTRACT, measureText, measureTextWidth } from '../text-metrics.ts'
|
|
60
|
-
export type { TextMeasurementContract, TextMeasurementInput, TextMeasurementResult } from '../text-metrics.ts'
|
|
61
|
-
export type { DescribeTree } from './describe.ts'
|
|
62
|
-
export type { DescribeOptions } from './describe.ts'
|
|
63
|
-
export { asciiToMermaid } from '../ascii/reverse.ts'
|
|
64
|
-
|
|
65
|
-
import { renderMermaidSVG as _svg } from '../index.ts'
|
|
66
|
-
export { verifyNoExternalRefs } from '../index.ts'
|
|
67
|
-
// Style system — agents reach the library through this entry, so the style
|
|
68
|
-
// registry must be importable here too, not only from the main entry.
|
|
69
|
-
export { registerStyle, getStyle, knownStyles, validateStyleSpec, resolveStyleStack, inferBackend } from '../scene/style-registry.ts'
|
|
70
|
-
export type { StyleSpec, StyleInput } from '../scene/style-registry.ts'
|
|
71
|
-
import { renderMermaidASCII as _ascii } from '../ascii/index.ts'
|
|
72
|
-
import { layoutGraphSync } from '../layout-engine.ts'
|
|
73
|
-
import { parseMermaid as parseFlowchartLegacy } from '../parser.ts'
|
|
74
|
-
import { stateBodyToGraph } from './state-body.ts'
|
|
75
|
-
import { serializeMermaid as _serialize } from './serialize.ts'
|
|
76
|
-
import type { ValidDiagram, RenderedLayout, RenderedRegion } from './types.ts'
|
|
77
|
-
import { positionedToRenderedLayout, emptyRenderedLayout } from './layout-to-rendered.ts'
|
|
78
|
-
import { layoutFamilyToRendered } from './family-layouts.ts'
|
|
79
|
-
import { collectActionRecords as collectRenderedActionRecords } from './analyze.ts'
|
|
80
|
-
import { toFinite } from './types.ts'
|
|
81
|
-
|
|
82
|
-
export function renderMermaidSVG(input: ValidDiagram | string, opts: Parameters<typeof _svg>[1] = {}): string {
|
|
83
|
-
return _svg(typeof input === 'string' ? input : _serialize(input), opts)
|
|
84
|
-
}
|
|
85
|
-
export function renderMermaidASCII(input: ValidDiagram | string, opts: Parameters<typeof _ascii>[1] = {}): string {
|
|
86
|
-
return _ascii(typeof input === 'string' ? input : _serialize(input), opts)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface LayoutMermaidOptions { debug?: boolean; regions?: boolean; actions?: boolean }
|
|
90
|
-
|
|
91
|
-
export function layoutMermaid(d: ValidDiagram, opts: LayoutMermaidOptions = {}): RenderedLayout {
|
|
92
|
-
if (d.body.kind === 'flowchart') {
|
|
93
|
-
return enrichRenderedLayout(d, positionedToRenderedLayout(layoutGraphSync(d.body.graph, {}), d.kind, opts), opts)
|
|
94
|
-
}
|
|
95
|
-
// State diagrams (BUILD-19) project to a MermaidGraph via the legacy parser,
|
|
96
|
-
// so layout reuses the flowchart geometric path.
|
|
97
|
-
if (d.body.kind === 'state') {
|
|
98
|
-
return enrichRenderedLayout(d, positionedToRenderedLayout(layoutGraphSync(stateBodyToGraph(d.body), {}), d.kind, opts), opts)
|
|
99
|
-
}
|
|
100
|
-
if (d.body.kind === 'opaque' && d.kind === 'flowchart') {
|
|
101
|
-
try {
|
|
102
|
-
return enrichRenderedLayout(d, positionedToRenderedLayout(layoutGraphSync(parseFlowchartLegacy(d.canonicalSource), {}), d.kind, opts), opts)
|
|
103
|
-
} catch {
|
|
104
|
-
return emptyRenderedLayout(d.kind)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// QUAL-1: renderable non-graph families project their real positioned
|
|
108
|
-
// layout (parsed from d.canonicalSource — works for both structured and
|
|
109
|
-
// opaque bodies) so the perceptual-quality metrics see them. Debug mode
|
|
110
|
-
// includes family-specific route/layout certificates where available.
|
|
111
|
-
const familyLayout = layoutFamilyToRendered(d, opts)
|
|
112
|
-
if (familyLayout) return enrichRenderedLayout(d, familyLayout, opts)
|
|
113
|
-
return enrichRenderedLayout(d, emptyRenderedLayout(d.kind), opts)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function enrichRenderedLayout(d: ValidDiagram, layout: RenderedLayout, opts: LayoutMermaidOptions): RenderedLayout {
|
|
117
|
-
const wantRegions = opts.debug || opts.regions
|
|
118
|
-
const wantActions = opts.debug || opts.actions
|
|
119
|
-
if (!wantRegions && !wantActions) return layout
|
|
120
|
-
const next: RenderedLayout = { ...layout }
|
|
121
|
-
if (wantRegions) next.regions = buildRenderedRegions(d, layout)
|
|
122
|
-
if (wantActions) {
|
|
123
|
-
const nodeIds = new Set<string>(layout.nodes.map(n => n.id))
|
|
124
|
-
next.actions = collectRenderedActionRecords(d)
|
|
125
|
-
.filter(a => nodeIds.has(a.target))
|
|
126
|
-
.map(a => ({ ...a, regionId: a.regionId ?? `node:${a.target}` }))
|
|
127
|
-
}
|
|
128
|
-
return next
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function buildRenderedRegions(d: ValidDiagram, layout: RenderedLayout): RenderedRegion[] {
|
|
132
|
-
const regions: RenderedRegion[] = [{
|
|
133
|
-
id: 'canvas',
|
|
134
|
-
kind: 'canvas',
|
|
135
|
-
bounds: { x: toFinite(0), y: toFinite(0), w: layout.bounds.w, h: layout.bounds.h },
|
|
136
|
-
}]
|
|
137
|
-
const groupByMember = new Map<string, string>()
|
|
138
|
-
for (const group of layout.groups) for (const member of group.members) groupByMember.set(member, group.id)
|
|
139
|
-
const sourceLines = sourceLineHints(d)
|
|
140
|
-
for (const group of layout.groups) {
|
|
141
|
-
regions.push({
|
|
142
|
-
id: `group:${group.id}`,
|
|
143
|
-
kind: 'group',
|
|
144
|
-
elementId: group.id,
|
|
145
|
-
parentId: group.parentId ? `group:${group.parentId}` : 'canvas',
|
|
146
|
-
bounds: { x: group.x, y: group.y, w: group.w, h: group.h },
|
|
147
|
-
sourceLine: d.source.groups.get(group.id)?.line ?? sourceLines.groups.get(group.id),
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
for (const node of layout.nodes) {
|
|
151
|
-
regions.push({
|
|
152
|
-
id: `node:${node.id}`,
|
|
153
|
-
kind: 'node',
|
|
154
|
-
elementId: node.id,
|
|
155
|
-
parentId: groupByMember.has(node.id) ? `group:${groupByMember.get(node.id)!}` : 'canvas',
|
|
156
|
-
bounds: { x: node.x, y: node.y, w: node.w, h: node.h },
|
|
157
|
-
sourceLine: d.source.nodes.get(node.id)?.line ?? sourceLines.nodes.get(node.id),
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
for (const edge of layout.edges) {
|
|
161
|
-
const xs = edge.path.map(p => p[0])
|
|
162
|
-
const ys = edge.path.map(p => p[1])
|
|
163
|
-
if (xs.length > 0 && ys.length > 0) {
|
|
164
|
-
const minX = Math.min(...xs), maxX = Math.max(...xs), minY = Math.min(...ys), maxY = Math.max(...ys)
|
|
165
|
-
regions.push({
|
|
166
|
-
id: `edge:${edge.id}`,
|
|
167
|
-
kind: 'edge',
|
|
168
|
-
elementId: edge.id,
|
|
169
|
-
parentId: 'canvas',
|
|
170
|
-
bounds: { x: toFinite(minX), y: toFinite(minY), w: toFinite(Math.max(1, maxX - minX)), h: toFinite(Math.max(1, maxY - minY)) },
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
if (edge.label) {
|
|
174
|
-
const w = Math.max(1, edge.label.text.length * 7)
|
|
175
|
-
const h = 14
|
|
176
|
-
const labelX = d.kind === 'sequence' && edge.from === edge.to
|
|
177
|
-
? edge.label.x // sequence self-message labels render with text-anchor="start"
|
|
178
|
-
: edge.label.x - w / 2
|
|
179
|
-
regions.push({
|
|
180
|
-
id: `label:${edge.id}`,
|
|
181
|
-
kind: 'label',
|
|
182
|
-
elementId: edge.id,
|
|
183
|
-
parentId: `edge:${edge.id}`,
|
|
184
|
-
bounds: { x: toFinite(labelX), y: toFinite(edge.label.y - h / 2), w: toFinite(w), h: toFinite(h) },
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return regions
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function sourceLineHints(d: ValidDiagram): { nodes: Map<string, number>; groups: Map<string, number> } {
|
|
192
|
-
const nodes = new Map<string, number>()
|
|
193
|
-
const groups = new Map<string, number>()
|
|
194
|
-
const source = d.body.kind === 'opaque' ? d.body.source : d.canonicalSource
|
|
195
|
-
const lines = source.split(/\r?\n/)
|
|
196
|
-
for (let i = 0; i < lines.length; i++) {
|
|
197
|
-
const text = lines[i]!
|
|
198
|
-
const group = text.match(/^\s*subgraph\s+([A-Za-z0-9_:-]+)/)
|
|
199
|
-
if (group?.[1] && !groups.has(group[1])) groups.set(group[1], i + 1)
|
|
200
|
-
for (const node of text.matchAll(/(?:^|[\s&;])([A-Za-z][A-Za-z0-9_:-]*)(?=\s*(?:\[|\(|\{|--|==|-.|$))/g)) {
|
|
201
|
-
const id = node[1]!
|
|
202
|
-
if (id === 'subgraph' || id === 'end' || id === d.kind) continue
|
|
203
|
-
if (!nodes.has(id)) nodes.set(id, i + 1)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return { nodes, groups }
|
|
207
|
-
}
|
package/src/agent/create.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// createMermaid / buildMermaid: blank-slate authoring through the typed
|
|
3
|
-
// surface. Editing an existing diagram already goes parse → narrow → mutate;
|
|
4
|
-
// creating one previously meant hand-writing Mermaid source — the fragile
|
|
5
|
-
// path the typed ops exist to replace. createMermaid returns an empty
|
|
6
|
-
// structured diagram for any built-in family; buildMermaid folds a mutation
|
|
7
|
-
// list over that empty diagram so a whole new diagram is one typed call.
|
|
8
|
-
// ============================================================================
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
ValidDiagram, MutableValidDiagram, DiagramKind, DiagramBody,
|
|
12
|
-
FlowchartValidDiagram, StateValidDiagram, SequenceValidDiagram, TimelineValidDiagram,
|
|
13
|
-
ClassValidDiagram, ErValidDiagram, JourneyValidDiagram, ArchitectureValidDiagram,
|
|
14
|
-
XyChartValidDiagram, PieValidDiagram, QuadrantValidDiagram, GanttValidDiagram,
|
|
15
|
-
FlowchartMutationOp, StateMutationOp, SequenceMutationOp, TimelineMutationOp,
|
|
16
|
-
ClassMutationOp, ErMutationOp, JourneyMutationOp, ArchitectureMutationOp,
|
|
17
|
-
XyChartMutationOp, PieMutationOp, QuadrantMutationOp, GanttMutationOp, AnyMutationOp,
|
|
18
|
-
MutationError, Result,
|
|
19
|
-
} from './types.ts'
|
|
20
|
-
import { ok, err } from './types.ts'
|
|
21
|
-
import { serializeMermaid } from './serialize.ts'
|
|
22
|
-
import { logToolInvocation } from './trace-log.ts'
|
|
23
|
-
import { mutate } from './mutate.ts'
|
|
24
|
-
import type { Direction } from '../types.ts'
|
|
25
|
-
|
|
26
|
-
export interface CreateMermaidOptions {
|
|
27
|
-
/** Layout direction for flowchart/state diagrams (default TD). Ignored elsewhere. */
|
|
28
|
-
direction?: Direction
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** A mutation failure annotated with which op in the build list failed. */
|
|
32
|
-
export type BuildError = MutationError & { opIndex: number }
|
|
33
|
-
|
|
34
|
-
function emptyBody(kind: DiagramKind, opts: CreateMermaidOptions): Exclude<DiagramBody, { kind: 'opaque' }> {
|
|
35
|
-
switch (kind) {
|
|
36
|
-
case 'flowchart': return {
|
|
37
|
-
kind: 'flowchart',
|
|
38
|
-
graph: {
|
|
39
|
-
direction: opts.direction ?? 'TD', nodes: new Map(), edges: [], subgraphs: [],
|
|
40
|
-
classDefs: new Map(), classAssignments: new Map(), nodeStyles: new Map(), linkStyles: new Map(),
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
case 'state': return { kind: 'state', states: [], transitions: [], direction: opts.direction }
|
|
44
|
-
case 'sequence': return { kind: 'sequence', participants: [], messages: [], statements: [] }
|
|
45
|
-
case 'timeline': return { kind: 'timeline', sections: [] }
|
|
46
|
-
case 'class': return { kind: 'class', classes: [], relations: [], notes: [] }
|
|
47
|
-
case 'er': return { kind: 'er', entities: [], relations: [] }
|
|
48
|
-
case 'journey': return { kind: 'journey', sections: [] }
|
|
49
|
-
case 'architecture': return { kind: 'architecture', groups: [], services: [], junctions: [], edges: [] }
|
|
50
|
-
case 'xychart': return { kind: 'xychart', series: [] }
|
|
51
|
-
case 'pie': return { kind: 'pie', showData: false, slices: [] }
|
|
52
|
-
case 'quadrant': return { kind: 'quadrant', quadrants: [undefined, undefined, undefined, undefined], points: [] }
|
|
53
|
-
case 'gantt': return { kind: 'gantt', sections: [], statements: [] }
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function createMermaid(kind: 'flowchart', opts?: CreateMermaidOptions): FlowchartValidDiagram
|
|
58
|
-
export function createMermaid(kind: 'state', opts?: CreateMermaidOptions): StateValidDiagram
|
|
59
|
-
export function createMermaid(kind: 'sequence', opts?: CreateMermaidOptions): SequenceValidDiagram
|
|
60
|
-
export function createMermaid(kind: 'timeline', opts?: CreateMermaidOptions): TimelineValidDiagram
|
|
61
|
-
export function createMermaid(kind: 'class', opts?: CreateMermaidOptions): ClassValidDiagram
|
|
62
|
-
export function createMermaid(kind: 'er', opts?: CreateMermaidOptions): ErValidDiagram
|
|
63
|
-
export function createMermaid(kind: 'journey', opts?: CreateMermaidOptions): JourneyValidDiagram
|
|
64
|
-
export function createMermaid(kind: 'architecture', opts?: CreateMermaidOptions): ArchitectureValidDiagram
|
|
65
|
-
export function createMermaid(kind: 'xychart', opts?: CreateMermaidOptions): XyChartValidDiagram
|
|
66
|
-
export function createMermaid(kind: 'pie', opts?: CreateMermaidOptions): PieValidDiagram
|
|
67
|
-
export function createMermaid(kind: 'quadrant', opts?: CreateMermaidOptions): QuadrantValidDiagram
|
|
68
|
-
export function createMermaid(kind: 'gantt', opts?: CreateMermaidOptions): GanttValidDiagram
|
|
69
|
-
export function createMermaid(kind: DiagramKind, opts?: CreateMermaidOptions): MutableValidDiagram
|
|
70
|
-
export function createMermaid(kind: DiagramKind, opts: CreateMermaidOptions = {}): MutableValidDiagram {
|
|
71
|
-
logToolInvocation('build') // also covers buildMermaid/buildChecked, which route through here
|
|
72
|
-
const body = emptyBody(kind, opts) as ReturnType<typeof emptyBody> | undefined
|
|
73
|
-
// The switch is TS-exhaustive but callers reach this from untyped surfaces
|
|
74
|
-
// (Code Mode, CLI), so fail loudly on an unknown kind.
|
|
75
|
-
if (!body) throw new Error(`createMermaid: unknown diagram kind "${String(kind)}"`)
|
|
76
|
-
const draft: ValidDiagram = {
|
|
77
|
-
kind, body,
|
|
78
|
-
meta: { initDirectives: [], comments: [], accessibility: {} },
|
|
79
|
-
source: { nodes: new Map(), edges: new Map(), groups: new Map(), labels: new Map() },
|
|
80
|
-
canonicalSource: '',
|
|
81
|
-
}
|
|
82
|
-
return { ...draft, canonicalSource: serializeMermaid(draft) } as MutableValidDiagram
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function buildMermaid(kind: 'flowchart', ops: FlowchartMutationOp[], opts?: CreateMermaidOptions): Result<FlowchartValidDiagram, BuildError>
|
|
86
|
-
export function buildMermaid(kind: 'state', ops: StateMutationOp[], opts?: CreateMermaidOptions): Result<StateValidDiagram, BuildError>
|
|
87
|
-
export function buildMermaid(kind: 'sequence', ops: SequenceMutationOp[], opts?: CreateMermaidOptions): Result<SequenceValidDiagram, BuildError>
|
|
88
|
-
export function buildMermaid(kind: 'timeline', ops: TimelineMutationOp[], opts?: CreateMermaidOptions): Result<TimelineValidDiagram, BuildError>
|
|
89
|
-
export function buildMermaid(kind: 'class', ops: ClassMutationOp[], opts?: CreateMermaidOptions): Result<ClassValidDiagram, BuildError>
|
|
90
|
-
export function buildMermaid(kind: 'er', ops: ErMutationOp[], opts?: CreateMermaidOptions): Result<ErValidDiagram, BuildError>
|
|
91
|
-
export function buildMermaid(kind: 'journey', ops: JourneyMutationOp[], opts?: CreateMermaidOptions): Result<JourneyValidDiagram, BuildError>
|
|
92
|
-
export function buildMermaid(kind: 'architecture', ops: ArchitectureMutationOp[], opts?: CreateMermaidOptions): Result<ArchitectureValidDiagram, BuildError>
|
|
93
|
-
export function buildMermaid(kind: 'xychart', ops: XyChartMutationOp[], opts?: CreateMermaidOptions): Result<XyChartValidDiagram, BuildError>
|
|
94
|
-
export function buildMermaid(kind: 'pie', ops: PieMutationOp[], opts?: CreateMermaidOptions): Result<PieValidDiagram, BuildError>
|
|
95
|
-
export function buildMermaid(kind: 'quadrant', ops: QuadrantMutationOp[], opts?: CreateMermaidOptions): Result<QuadrantValidDiagram, BuildError>
|
|
96
|
-
export function buildMermaid(kind: 'gantt', ops: GanttMutationOp[], opts?: CreateMermaidOptions): Result<GanttValidDiagram, BuildError>
|
|
97
|
-
export function buildMermaid(kind: DiagramKind, ops: AnyMutationOp[], opts?: CreateMermaidOptions): Result<MutableValidDiagram, BuildError>
|
|
98
|
-
export function buildMermaid(kind: DiagramKind, ops: AnyMutationOp[], opts: CreateMermaidOptions = {}): Result<MutableValidDiagram, BuildError> {
|
|
99
|
-
let d = createMermaid(kind, opts)
|
|
100
|
-
for (let i = 0; i < ops.length; i++) {
|
|
101
|
-
const r = mutate(d, ops[i]!)
|
|
102
|
-
if (!r.ok) return err({ ...r.error, opIndex: i, message: `op[${i}] (${ops[i]!.kind}): ${r.error.message}` })
|
|
103
|
-
d = r.value
|
|
104
|
-
}
|
|
105
|
-
return ok(d)
|
|
106
|
-
}
|