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/sequence/types.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Sequence diagram types
|
|
3
|
-
//
|
|
4
|
-
// Models the parsed and positioned representations of a Mermaid sequence diagram.
|
|
5
|
-
// Sequence diagrams show actor interactions over time (vertical timeline).
|
|
6
|
-
// ============================================================================
|
|
7
|
-
|
|
8
|
-
import type { PositionedDiagram } from '../types.ts'
|
|
9
|
-
|
|
10
|
-
/** Parsed sequence diagram — logical structure from mermaid text */
|
|
11
|
-
export interface SequenceDiagram {
|
|
12
|
-
/** Optional accessibility title (Mermaid accTitle) */
|
|
13
|
-
accessibilityTitle?: string
|
|
14
|
-
/** Optional accessibility description (Mermaid accDescr) */
|
|
15
|
-
accessibilityDescription?: string
|
|
16
|
-
/** Ordered list of actors/participants */
|
|
17
|
-
actors: Actor[]
|
|
18
|
-
/** Messages between actors in chronological order */
|
|
19
|
-
messages: Message[]
|
|
20
|
-
/** Structural blocks (loop, alt, opt, par, critical) */
|
|
21
|
-
blocks: Block[]
|
|
22
|
-
/** Notes attached to actors */
|
|
23
|
-
notes: Note[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface Actor {
|
|
27
|
-
id: string
|
|
28
|
-
label: string
|
|
29
|
-
/** 'participant' renders as a box, 'actor' renders as a stick figure */
|
|
30
|
-
type: 'participant' | 'actor'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface Message {
|
|
34
|
-
from: string
|
|
35
|
-
to: string
|
|
36
|
-
label: string
|
|
37
|
-
/** Arrow style: solid line or dashed line */
|
|
38
|
-
lineStyle: 'solid' | 'dashed'
|
|
39
|
-
/** Arrow head: filled (closed) or open */
|
|
40
|
-
arrowHead: 'filled' | 'open'
|
|
41
|
-
/** Activate the target lifeline (+) */
|
|
42
|
-
activate?: boolean
|
|
43
|
-
/** Deactivate the source lifeline (-) */
|
|
44
|
-
deactivate?: boolean
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface Block {
|
|
48
|
-
/** Block type keyword */
|
|
49
|
-
type: 'loop' | 'alt' | 'opt' | 'par' | 'critical' | 'break' | 'rect'
|
|
50
|
-
/** Label for the block header */
|
|
51
|
-
label: string
|
|
52
|
-
/** Index of the first message inside this block */
|
|
53
|
-
startIndex: number
|
|
54
|
-
/** Index of the last message inside this block (inclusive) */
|
|
55
|
-
endIndex: number
|
|
56
|
-
/** For alt/par blocks: indices where "else"/"and" dividers appear (message indices) */
|
|
57
|
-
dividers: Array<{ index: number; label: string }>
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface Note {
|
|
61
|
-
/** Which actor(s) the note is attached to */
|
|
62
|
-
actorIds: string[]
|
|
63
|
-
/** Note text content */
|
|
64
|
-
text: string
|
|
65
|
-
/** Position relative to the actor(s) */
|
|
66
|
-
position: 'left' | 'right' | 'over'
|
|
67
|
-
/** Message index after which this note appears */
|
|
68
|
-
afterIndex: number
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ============================================================================
|
|
72
|
-
// Positioned sequence diagram — ready for SVG rendering
|
|
73
|
-
// ============================================================================
|
|
74
|
-
|
|
75
|
-
export interface PositionedSequenceDiagram extends PositionedDiagram {
|
|
76
|
-
width: number
|
|
77
|
-
height: number
|
|
78
|
-
accessibilityTitle?: string
|
|
79
|
-
accessibilityDescription?: string
|
|
80
|
-
actors: PositionedActor[]
|
|
81
|
-
lifelines: Lifeline[]
|
|
82
|
-
messages: PositionedMessage[]
|
|
83
|
-
activations: Activation[]
|
|
84
|
-
blocks: PositionedBlock[]
|
|
85
|
-
notes: PositionedNote[]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface PositionedActor {
|
|
89
|
-
id: string
|
|
90
|
-
label: string
|
|
91
|
-
type: 'participant' | 'actor'
|
|
92
|
-
/** Center x of the actor box */
|
|
93
|
-
x: number
|
|
94
|
-
/** Top y of the actor box */
|
|
95
|
-
y: number
|
|
96
|
-
width: number
|
|
97
|
-
height: number
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Vertical dashed line from actor to bottom of diagram */
|
|
101
|
-
export interface Lifeline {
|
|
102
|
-
actorId: string
|
|
103
|
-
x: number
|
|
104
|
-
topY: number
|
|
105
|
-
bottomY: number
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export interface PositionedMessage {
|
|
109
|
-
from: string
|
|
110
|
-
to: string
|
|
111
|
-
label: string
|
|
112
|
-
lineStyle: 'solid' | 'dashed'
|
|
113
|
-
arrowHead: 'filled' | 'open'
|
|
114
|
-
/** Start point (from actor's lifeline) */
|
|
115
|
-
x1: number
|
|
116
|
-
/** End point (to actor's lifeline) */
|
|
117
|
-
x2: number
|
|
118
|
-
/** Vertical position */
|
|
119
|
-
y: number
|
|
120
|
-
/** Whether this is a self-message (same actor) */
|
|
121
|
-
isSelf: boolean
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Narrow rectangle on a lifeline showing active processing */
|
|
125
|
-
export interface Activation {
|
|
126
|
-
actorId: string
|
|
127
|
-
x: number
|
|
128
|
-
topY: number
|
|
129
|
-
bottomY: number
|
|
130
|
-
width: number
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export interface PositionedBlock {
|
|
134
|
-
type: Block['type']
|
|
135
|
-
label: string
|
|
136
|
-
x: number
|
|
137
|
-
y: number
|
|
138
|
-
width: number
|
|
139
|
-
height: number
|
|
140
|
-
/** Divider lines within the block (for alt/par) */
|
|
141
|
-
dividers: Array<{ y: number; label: string }>
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export interface PositionedNote {
|
|
145
|
-
text: string
|
|
146
|
-
x: number
|
|
147
|
-
y: number
|
|
148
|
-
width: number
|
|
149
|
-
height: number
|
|
150
|
-
/** Actor IDs this note is attached to (for SVG attribution) */
|
|
151
|
-
actors?: string[]
|
|
152
|
-
/** Note position relative to actors (for SVG attribution) */
|
|
153
|
-
position?: 'left' | 'right' | 'over'
|
|
154
|
-
}
|
package/src/shape-clipping.ts
DELETED
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shape-aware edge clipping utilities.
|
|
3
|
-
*
|
|
4
|
-
* ELK.js treats all nodes as rectangles for edge routing. For non-rectangular
|
|
5
|
-
* shapes like diamonds, this causes edges to terminate at the bounding box
|
|
6
|
-
* boundary instead of the actual shape vertices.
|
|
7
|
-
*
|
|
8
|
-
* This module provides utilities to clip edge endpoints to actual shape
|
|
9
|
-
* boundaries after ELK layout is complete.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { Point, PositionedNode } from './types.ts'
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Clip an edge endpoint to the actual shape boundary of a node.
|
|
16
|
-
*
|
|
17
|
-
* @param points - The edge points array
|
|
18
|
-
* @param node - The node to clip to
|
|
19
|
-
* @param isStart - True if clipping the start point (source), false for end (target)
|
|
20
|
-
* @returns New points array with clipped endpoint
|
|
21
|
-
*/
|
|
22
|
-
export function clipEdgeToShape(
|
|
23
|
-
points: Point[],
|
|
24
|
-
node: PositionedNode,
|
|
25
|
-
isStart: boolean
|
|
26
|
-
): Point[] {
|
|
27
|
-
if (points.length < 2) return points
|
|
28
|
-
|
|
29
|
-
// Only clip non-rectangular shapes
|
|
30
|
-
if (node.shape === 'rectangle' || node.shape === 'service' || node.shape === 'rounded' || node.shape === 'subroutine') {
|
|
31
|
-
return points
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const result = [...points]
|
|
35
|
-
const clip = (endpoint: Point, adjacent: Point): Point => {
|
|
36
|
-
switch (node.shape) {
|
|
37
|
-
case 'diamond': return clipToDiamond(endpoint, adjacent, node)
|
|
38
|
-
case 'circle':
|
|
39
|
-
case 'doublecircle':
|
|
40
|
-
case 'state-start':
|
|
41
|
-
case 'state-end': return clipToEllipse(endpoint, adjacent, node)
|
|
42
|
-
case 'stadium': return clipToStadium(endpoint, adjacent, node)
|
|
43
|
-
case 'hexagon': return clipToHexagon(endpoint, adjacent, node)
|
|
44
|
-
case 'cylinder': return clipToCylinder(endpoint, adjacent, node)
|
|
45
|
-
case 'trapezoid':
|
|
46
|
-
case 'trapezoid-alt':
|
|
47
|
-
case 'lean-r':
|
|
48
|
-
case 'lean-l':
|
|
49
|
-
case 'asymmetric': return clipToConvexPolygon(endpoint, adjacent, slantedShapePolygon(node))
|
|
50
|
-
default: return endpoint
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (isStart) {
|
|
55
|
-
result[0] = clip(points[0]!, points[1]!)
|
|
56
|
-
} else {
|
|
57
|
-
const lastIdx = points.length - 1
|
|
58
|
-
result[lastIdx] = clip(points[lastIdx]!, points[lastIdx - 1]!)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return result
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Outline clippers for the symmetric shapes. Each extends the edge's final
|
|
66
|
-
// orthogonal segment as a ray and finds where it meets the rendered outline,
|
|
67
|
-
// preserving orthogonality — ELK only knows the bounding box, so an endpoint
|
|
68
|
-
// that is not at a side midpoint would otherwise float off the curve.
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
|
|
71
|
-
function rayInfo(endpoint: Point, adjacent: Point): { vertical: boolean; dir: 1 | -1 } {
|
|
72
|
-
const dx = endpoint.x - adjacent.x
|
|
73
|
-
const dy = endpoint.y - adjacent.y
|
|
74
|
-
const vertical = Math.abs(dx) < Math.abs(dy)
|
|
75
|
-
return { vertical, dir: (vertical ? dy : dx) >= 0 ? 1 : -1 }
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Ellipse inscribed in the bbox (circle when square). */
|
|
79
|
-
function clipToEllipse(endpoint: Point, adjacent: Point, node: PositionedNode): Point {
|
|
80
|
-
const cx = node.x + node.width / 2
|
|
81
|
-
const cy = node.y + node.height / 2
|
|
82
|
-
const rx = node.width / 2
|
|
83
|
-
const ry = node.height / 2
|
|
84
|
-
const { vertical, dir } = rayInfo(endpoint, adjacent)
|
|
85
|
-
if (vertical) {
|
|
86
|
-
const dx = (endpoint.x - cx) / rx
|
|
87
|
-
if (Math.abs(dx) > 1) return endpoint
|
|
88
|
-
const span = ry * Math.sqrt(1 - dx * dx)
|
|
89
|
-
// Entering downward hits the top half; upward hits the bottom half.
|
|
90
|
-
return { x: endpoint.x, y: cy - dir * span }
|
|
91
|
-
}
|
|
92
|
-
const dy = (endpoint.y - cy) / ry
|
|
93
|
-
if (Math.abs(dy) > 1) return endpoint
|
|
94
|
-
const span = rx * Math.sqrt(1 - dy * dy)
|
|
95
|
-
return { x: cx - dir * span, y: endpoint.y }
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Flat top/bottom, semicircular ends of radius h/2. */
|
|
99
|
-
function clipToStadium(endpoint: Point, adjacent: Point, node: PositionedNode): Point {
|
|
100
|
-
const cx = node.x + node.width / 2
|
|
101
|
-
const cy = node.y + node.height / 2
|
|
102
|
-
const hw = node.width / 2
|
|
103
|
-
const r = node.height / 2
|
|
104
|
-
const { vertical, dir } = rayInfo(endpoint, adjacent)
|
|
105
|
-
if (vertical) {
|
|
106
|
-
const dx = Math.abs(endpoint.x - cx)
|
|
107
|
-
if (dx <= hw - r) return { x: endpoint.x, y: cy - dir * r }
|
|
108
|
-
const ax = dx - (hw - r)
|
|
109
|
-
if (ax > r) return endpoint
|
|
110
|
-
return { x: endpoint.x, y: cy - dir * Math.sqrt(r * r - ax * ax) }
|
|
111
|
-
}
|
|
112
|
-
const dy = Math.abs(endpoint.y - cy)
|
|
113
|
-
if (dy > r) return endpoint
|
|
114
|
-
const span = (hw - r) + Math.sqrt(r * r - dy * dy)
|
|
115
|
-
return { x: cx - dir * span, y: endpoint.y }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** Six-gon: flat top/bottom inset by h/4, pointy E/W tips at mid-height. */
|
|
119
|
-
function clipToHexagon(endpoint: Point, adjacent: Point, node: PositionedNode): Point {
|
|
120
|
-
const cx = node.x + node.width / 2
|
|
121
|
-
const cy = node.y + node.height / 2
|
|
122
|
-
const hw = node.width / 2
|
|
123
|
-
const hh = node.height / 2
|
|
124
|
-
const inset = node.height / 4
|
|
125
|
-
const { vertical, dir } = rayInfo(endpoint, adjacent)
|
|
126
|
-
if (vertical) {
|
|
127
|
-
const dx = Math.abs(endpoint.x - cx)
|
|
128
|
-
if (dx <= hw - inset) return { x: endpoint.x, y: cy - dir * hh }
|
|
129
|
-
// Slanted corner: |dy| = hh * (1 - (dx - (hw - inset)) / inset)
|
|
130
|
-
const t = (dx - (hw - inset)) / inset
|
|
131
|
-
if (t > 1) return endpoint
|
|
132
|
-
return { x: endpoint.x, y: cy - dir * hh * (1 - t) }
|
|
133
|
-
}
|
|
134
|
-
const dy = Math.abs(endpoint.y - cy)
|
|
135
|
-
if (dy > hh) return endpoint
|
|
136
|
-
// |dx| at this height: flat region ends at hw - inset, tip at hw.
|
|
137
|
-
const span = dy >= 0 ? hw - inset * (dy / hh) : hw
|
|
138
|
-
return { x: cx - dir * span, y: endpoint.y }
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Vertical walls; elliptical caps of vertical radius 7 (renderer geometry). */
|
|
142
|
-
function clipToCylinder(endpoint: Point, adjacent: Point, node: PositionedNode): Point {
|
|
143
|
-
const RY = 7
|
|
144
|
-
const cx = node.x + node.width / 2
|
|
145
|
-
const hw = node.width / 2
|
|
146
|
-
const top = node.y + RY
|
|
147
|
-
const bottom = node.y + node.height - RY
|
|
148
|
-
const { vertical, dir } = rayInfo(endpoint, adjacent)
|
|
149
|
-
if (!vertical) {
|
|
150
|
-
if (endpoint.y >= top && endpoint.y <= bottom) {
|
|
151
|
-
return { x: cx - dir * hw, y: endpoint.y } // straight wall
|
|
152
|
-
}
|
|
153
|
-
// Above/below the walls the horizontal ray meets a cap ellipse; keep the
|
|
154
|
-
// ray's own y so the segment stays orthogonal.
|
|
155
|
-
const capCy = endpoint.y < top ? top : bottom
|
|
156
|
-
const dyCap = (endpoint.y - capCy) / RY
|
|
157
|
-
if (Math.abs(dyCap) > 1) return endpoint
|
|
158
|
-
const span = hw * Math.sqrt(1 - dyCap * dyCap)
|
|
159
|
-
return { x: cx - dir * span, y: endpoint.y }
|
|
160
|
-
}
|
|
161
|
-
const dx = (endpoint.x - cx) / hw
|
|
162
|
-
if (Math.abs(dx) > 1) return endpoint
|
|
163
|
-
const span = RY * Math.sqrt(1 - dx * dx)
|
|
164
|
-
return dir > 0
|
|
165
|
-
? { x: endpoint.x, y: top - span } // entering downward: top cap
|
|
166
|
-
: { x: endpoint.x, y: bottom + span } // entering upward: bottom cap
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Rendered polygon outlines of the slanted shapes (renderer geometry: the
|
|
171
|
-
* trapezoids and parallelograms shear by w * 0.15, the asymmetric flag
|
|
172
|
-
* indents its left point by 12px).
|
|
173
|
-
*/
|
|
174
|
-
function slantedShapePolygon(node: PositionedNode): Point[] {
|
|
175
|
-
const { x, y, width: w, height: h } = node
|
|
176
|
-
const inset = w * 0.15
|
|
177
|
-
switch (node.shape) {
|
|
178
|
-
case 'trapezoid': // wider bottom
|
|
179
|
-
return [{ x: x + inset, y }, { x: x + w - inset, y }, { x: x + w, y: y + h }, { x, y: y + h }]
|
|
180
|
-
case 'trapezoid-alt': // wider top
|
|
181
|
-
return [{ x, y }, { x: x + w, y }, { x: x + w - inset, y: y + h }, { x: x + inset, y: y + h }]
|
|
182
|
-
case 'lean-r': // parallelogram leaning right
|
|
183
|
-
return [{ x: x + inset, y }, { x: x + w, y }, { x: x + w - inset, y: y + h }, { x, y: y + h }]
|
|
184
|
-
case 'lean-l': // parallelogram leaning left
|
|
185
|
-
return [{ x, y }, { x: x + w - inset, y }, { x: x + w, y: y + h }, { x: x + inset, y: y + h }]
|
|
186
|
-
case 'asymmetric': // flag with a pointed left edge
|
|
187
|
-
return [{ x: x + 12, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x: x + 12, y: y + h }, { x, y: y + h / 2 }]
|
|
188
|
-
default:
|
|
189
|
-
return [{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h }]
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Generic convex-polygon clipper: extend the edge's final orthogonal segment
|
|
195
|
-
* as a ray and keep the polygon-boundary intersection nearest the OUTSIDE
|
|
196
|
-
* endpoint (`adjacent`) — the entry point into the shape. Like clipToDiamond
|
|
197
|
-
* this preserves orthogonality: the ray's own fixed coordinate is kept and
|
|
198
|
-
* only the coordinate along the ray moves onto the outline. Returns the
|
|
199
|
-
* endpoint unchanged when the ray misses the polygon.
|
|
200
|
-
*/
|
|
201
|
-
function clipToConvexPolygon(endpoint: Point, adjacent: Point, verts: Point[]): Point {
|
|
202
|
-
const { vertical } = rayInfo(endpoint, adjacent)
|
|
203
|
-
let best: Point | null = null
|
|
204
|
-
let bestDist = Infinity
|
|
205
|
-
for (let i = 0; i < verts.length; i++) {
|
|
206
|
-
const p1 = verts[i]!
|
|
207
|
-
const p2 = verts[(i + 1) % verts.length]!
|
|
208
|
-
const hit = vertical
|
|
209
|
-
? intersectVerticalRayWithEdge(endpoint.x, p1, p2)
|
|
210
|
-
: intersectHorizontalRayWithEdge(endpoint.y, p1, p2)
|
|
211
|
-
if (!hit) continue
|
|
212
|
-
const d = Math.hypot(hit.x - adjacent.x, hit.y - adjacent.y)
|
|
213
|
-
if (d < bestDist) {
|
|
214
|
-
bestDist = d
|
|
215
|
-
best = hit
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return best ?? endpoint
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Clip a point to the diamond shape boundary using ray-polygon intersection.
|
|
223
|
-
*
|
|
224
|
-
* Diamond vertices are at the midpoints of the bounding box sides:
|
|
225
|
-
* - Top: (cx, y)
|
|
226
|
-
* - Right: (x + w, cy)
|
|
227
|
-
* - Bottom: (cx, y + h)
|
|
228
|
-
* - Left: (x, cy)
|
|
229
|
-
*
|
|
230
|
-
* For orthogonal edges, we extend the final segment as a ray and find where
|
|
231
|
-
* it intersects the diamond boundary. This preserves orthogonality while
|
|
232
|
-
* ensuring the edge terminates at the actual diamond shape.
|
|
233
|
-
*
|
|
234
|
-
* @param endpoint - The edge endpoint to clip
|
|
235
|
-
* @param adjacent - The adjacent point (to determine ray direction)
|
|
236
|
-
* @param node - The diamond node
|
|
237
|
-
* @returns Clipped point on the diamond boundary
|
|
238
|
-
*/
|
|
239
|
-
function clipToDiamond(endpoint: Point, adjacent: Point, node: PositionedNode): Point {
|
|
240
|
-
const cx = node.x + node.width / 2
|
|
241
|
-
const cy = node.y + node.height / 2
|
|
242
|
-
const halfW = node.width / 2
|
|
243
|
-
const halfH = node.height / 2
|
|
244
|
-
|
|
245
|
-
// Diamond vertices
|
|
246
|
-
const top: Point = { x: cx, y: node.y }
|
|
247
|
-
const right: Point = { x: node.x + node.width, y: cy }
|
|
248
|
-
const bottom: Point = { x: cx, y: node.y + node.height }
|
|
249
|
-
const left: Point = { x: node.x, y: cy }
|
|
250
|
-
|
|
251
|
-
// Determine approach direction from adjacent point
|
|
252
|
-
const dx = endpoint.x - adjacent.x
|
|
253
|
-
const dy = endpoint.y - adjacent.y
|
|
254
|
-
|
|
255
|
-
// For orthogonal edges, one of dx or dy will be ~0
|
|
256
|
-
const isVertical = Math.abs(dx) < Math.abs(dy)
|
|
257
|
-
|
|
258
|
-
if (isVertical) {
|
|
259
|
-
// Vertical ray at x = endpoint.x
|
|
260
|
-
const rayX = endpoint.x
|
|
261
|
-
|
|
262
|
-
if (dy > 0) {
|
|
263
|
-
// Coming from above (moving down) → intersect with top half of diamond
|
|
264
|
-
// Top half edges: left-top (left → top) and top-right (top → right)
|
|
265
|
-
if (rayX <= cx) {
|
|
266
|
-
// Intersect with left-top edge (from left vertex to top vertex)
|
|
267
|
-
return intersectVerticalRayWithEdge(rayX, left, top) ?? top
|
|
268
|
-
} else {
|
|
269
|
-
// Intersect with top-right edge (from top vertex to right vertex)
|
|
270
|
-
return intersectVerticalRayWithEdge(rayX, top, right) ?? top
|
|
271
|
-
}
|
|
272
|
-
} else {
|
|
273
|
-
// Coming from below (moving up) → intersect with bottom half of diamond
|
|
274
|
-
// Bottom half edges: left-bottom (bottom → left) and bottom-right (right → bottom)
|
|
275
|
-
if (rayX <= cx) {
|
|
276
|
-
// Intersect with bottom-left edge (from bottom vertex to left vertex)
|
|
277
|
-
return intersectVerticalRayWithEdge(rayX, bottom, left) ?? bottom
|
|
278
|
-
} else {
|
|
279
|
-
// Intersect with bottom-right edge (from right vertex to bottom vertex)
|
|
280
|
-
return intersectVerticalRayWithEdge(rayX, right, bottom) ?? bottom
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
} else {
|
|
284
|
-
// Horizontal ray at y = endpoint.y
|
|
285
|
-
const rayY = endpoint.y
|
|
286
|
-
|
|
287
|
-
if (dx > 0) {
|
|
288
|
-
// Coming from left (moving right) → intersect with left half of diamond
|
|
289
|
-
// Left half edges: top-left (top → left) and left-bottom (left → bottom)
|
|
290
|
-
if (rayY <= cy) {
|
|
291
|
-
// Intersect with top-left edge (from top vertex to left vertex)
|
|
292
|
-
return intersectHorizontalRayWithEdge(rayY, top, left) ?? left
|
|
293
|
-
} else {
|
|
294
|
-
// Intersect with left-bottom edge (from left vertex to bottom vertex)
|
|
295
|
-
return intersectHorizontalRayWithEdge(rayY, left, bottom) ?? left
|
|
296
|
-
}
|
|
297
|
-
} else {
|
|
298
|
-
// Coming from right (moving left) → intersect with right half of diamond
|
|
299
|
-
// Right half edges: top-right (top → right) and right-bottom (right → bottom)
|
|
300
|
-
if (rayY <= cy) {
|
|
301
|
-
// Intersect with top-right edge (from top vertex to right vertex)
|
|
302
|
-
return intersectHorizontalRayWithEdge(rayY, top, right) ?? right
|
|
303
|
-
} else {
|
|
304
|
-
// Intersect with right-bottom edge (from right vertex to bottom vertex)
|
|
305
|
-
return intersectHorizontalRayWithEdge(rayY, right, bottom) ?? right
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Find intersection of a horizontal ray (y = rayY) with a line segment.
|
|
313
|
-
* Returns the intersection point or null if no intersection.
|
|
314
|
-
*/
|
|
315
|
-
function intersectHorizontalRayWithEdge(rayY: number, p1: Point, p2: Point): Point | null {
|
|
316
|
-
const dy = p2.y - p1.y
|
|
317
|
-
if (Math.abs(dy) < 0.001) {
|
|
318
|
-
// Edge is horizontal, no single intersection
|
|
319
|
-
return null
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
const t = (rayY - p1.y) / dy
|
|
323
|
-
if (t < 0 || t > 1) {
|
|
324
|
-
// Intersection outside the edge segment
|
|
325
|
-
return null
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
const x = p1.x + t * (p2.x - p1.x)
|
|
329
|
-
return { x, y: rayY }
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Find intersection of a vertical ray (x = rayX) with a line segment.
|
|
334
|
-
* Returns the intersection point or null if no intersection.
|
|
335
|
-
*/
|
|
336
|
-
function intersectVerticalRayWithEdge(rayX: number, p1: Point, p2: Point): Point | null {
|
|
337
|
-
const dx = p2.x - p1.x
|
|
338
|
-
if (Math.abs(dx) < 0.001) {
|
|
339
|
-
// Edge is vertical, no single intersection
|
|
340
|
-
return null
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const t = (rayX - p1.x) / dx
|
|
344
|
-
if (t < 0 || t > 1) {
|
|
345
|
-
// Intersection outside the edge segment
|
|
346
|
-
return null
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const y = p1.y + t * (p2.y - p1.y)
|
|
350
|
-
return { x: rayX, y }
|
|
351
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// Mermaid-universal accessibility directives — accTitle / accDescr single
|
|
2
|
-
// lines and accDescr { … } blocks — are legal in every diagram family.
|
|
3
|
-
// Families that MODEL them (sequence, timeline) parse them into fields; the
|
|
4
|
-
// rest accept-and-skip via this one helper so the tolerance can never drift
|
|
5
|
-
// per family again (pie and quadrant each carried a hand-rolled copy).
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* If `lines[i]` starts an accessibility directive, return the index of its
|
|
9
|
-
* LAST line (the caller's loop increment then steps past it); otherwise -1.
|
|
10
|
-
* Handles single-line `accTitle:`/`accDescr:` and multi-line `accDescr {`
|
|
11
|
-
* blocks terminated by a line containing `}`.
|
|
12
|
-
*/
|
|
13
|
-
export function accessibilityDirectiveEnd(lines: readonly string[], i: number): number {
|
|
14
|
-
const line = lines[i]!.trim()
|
|
15
|
-
if (/^acc(Title|Descr)\s*:/i.test(line)) return i
|
|
16
|
-
if (/^accDescr\s*\{/i.test(line)) {
|
|
17
|
-
let end = i
|
|
18
|
-
while (end < lines.length && !lines[end]!.includes('}')) end++
|
|
19
|
-
return end
|
|
20
|
-
}
|
|
21
|
-
return -1
|
|
22
|
-
}
|
package/src/shared/batched.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// runBatchedOperations — shared scaffold for "run a handler over each item
|
|
3
|
-
// in a list, never abort the batch on a single failure".
|
|
4
|
-
//
|
|
5
|
-
// Loop 9 M8. Both `cmdBatch` (CLI JSONL runner) and `runWithJudge`
|
|
6
|
-
// (LLM-judge fan-out) had near-identical loops: iterate items, try the
|
|
7
|
-
// handler, surface the error as a structured entry, keep going.
|
|
8
|
-
//
|
|
9
|
-
// Signature is sync-or-async — the handler returns O or Promise<O>; the
|
|
10
|
-
// result list is awaited as a whole.
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
export interface BatchSuccess<O> { ok: true; value: O }
|
|
14
|
-
export interface BatchFailure { ok: false; error: { code: string; message: string } }
|
|
15
|
-
export type BatchEntry<O> = BatchSuccess<O> | BatchFailure
|
|
16
|
-
|
|
17
|
-
export interface RunBatchedOptions {
|
|
18
|
-
/** Override the code field on caught errors (default 'HANDLER_ERROR'). */
|
|
19
|
-
errorCode?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function runBatchedOperations<I, O>(
|
|
23
|
-
items: I[],
|
|
24
|
-
handler: (item: I, index: number) => O | Promise<O>,
|
|
25
|
-
opts: RunBatchedOptions = {},
|
|
26
|
-
): Promise<BatchEntry<O>[]> {
|
|
27
|
-
const errorCode = opts.errorCode ?? 'HANDLER_ERROR'
|
|
28
|
-
const out: BatchEntry<O>[] = []
|
|
29
|
-
for (let i = 0; i < items.length; i++) {
|
|
30
|
-
try {
|
|
31
|
-
const value = await handler(items[i]!, i)
|
|
32
|
-
out.push({ ok: true, value })
|
|
33
|
-
} catch (e) {
|
|
34
|
-
const message = e instanceof Error ? e.message : String(e)
|
|
35
|
-
out.push({ ok: false, error: { code: errorCode, message } })
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return out
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Synchronous variant for callers whose handler is guaranteed sync.
|
|
43
|
-
* Identical semantics to runBatchedOperations sans the await — used by
|
|
44
|
-
* cmdBatch in the CLI where the dispatcher returns a number, not a promise.
|
|
45
|
-
*/
|
|
46
|
-
export function collectBatched<I, O>(
|
|
47
|
-
items: I[],
|
|
48
|
-
handler: (item: I, index: number) => O,
|
|
49
|
-
errorCode = 'HANDLER_ERROR',
|
|
50
|
-
): BatchEntry<O>[] {
|
|
51
|
-
const out: BatchEntry<O>[] = []
|
|
52
|
-
for (let i = 0; i < items.length; i++) {
|
|
53
|
-
try {
|
|
54
|
-
out.push({ ok: true, value: handler(items[i]!, i) })
|
|
55
|
-
} catch (e) {
|
|
56
|
-
const message = e instanceof Error ? e.message : String(e)
|
|
57
|
-
out.push({ ok: false, error: { code: errorCode, message } })
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return out
|
|
61
|
-
}
|
package/src/shared/color-math.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Shared hex color math.
|
|
3
|
-
//
|
|
4
|
-
// The single home for hex parsing, hex serialization, sRGB mixing, and the
|
|
5
|
-
// BT.601 luma used for dark/contrast decisions. Thresholds stay at the call
|
|
6
|
-
// sites (theme dark-detection, ANSI brightness, contrast text) — only the
|
|
7
|
-
// primitives live here, so the arithmetic cannot drift between the SVG,
|
|
8
|
-
// ASCII, and chart color paths.
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Parse a hex color to [r, g, b]. Accepts #RGB and #RRGGBB (a longer string
|
|
13
|
-
* such as #RRGGBBAA is read as its first six digits; alpha is ignored).
|
|
14
|
-
* Assumes a syntactically valid color — use tryParseHex when unsure.
|
|
15
|
-
*/
|
|
16
|
-
export function parseHex(hex: string): [number, number, number] {
|
|
17
|
-
const h = hex.replace('#', '')
|
|
18
|
-
const full = h.length === 3
|
|
19
|
-
? h[0]! + h[0]! + h[1]! + h[1]! + h[2]! + h[2]!
|
|
20
|
-
: h
|
|
21
|
-
return [
|
|
22
|
-
parseInt(full.slice(0, 2), 16),
|
|
23
|
-
parseInt(full.slice(2, 4), 16),
|
|
24
|
-
parseInt(full.slice(4, 6), 16),
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Validating parse: [r, g, b] for #RGB/#RRGGBB/#RRGGBBAA, else null. */
|
|
29
|
-
export function tryParseHex(hex: string): [number, number, number] | null {
|
|
30
|
-
if (!/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(hex)) return null
|
|
31
|
-
return parseHex(hex)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Serialize r/g/b (clamped and rounded) to #rrggbb. */
|
|
35
|
-
export function toHex(r: number, g: number, b: number): string {
|
|
36
|
-
return '#' + [r, g, b]
|
|
37
|
-
.map(c => Math.round(Math.max(0, Math.min(255, c))).toString(16).padStart(2, '0'))
|
|
38
|
-
.join('')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Mix `pct`% of `fg` over `bg` in sRGB — replicates CSS
|
|
43
|
-
* `color-mix(in srgb, fg pct%, bg)`.
|
|
44
|
-
*/
|
|
45
|
-
export function mixHex(fg: string, bg: string, pct: number): string {
|
|
46
|
-
const [r1, g1, b1] = parseHex(fg)
|
|
47
|
-
const [r2, g2, b2] = parseHex(bg)
|
|
48
|
-
const p = pct / 100
|
|
49
|
-
return toHex(
|
|
50
|
-
r1 * p + r2 * (1 - p),
|
|
51
|
-
g1 * p + g2 * (1 - p),
|
|
52
|
-
b1 * p + b2 * (1 - p),
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Loose CSS hex form: #RGB, #RGBA, #RRGGBB, or #RRGGBBAA. */
|
|
57
|
-
export function isHexColor(s: string): boolean {
|
|
58
|
-
return /^#[0-9a-fA-F]{3,8}$/.test(s)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Strict 6-digit hex form (#RRGGBB) — what the chart palettes require. */
|
|
62
|
-
export function isSixDigitHex(s: string): boolean {
|
|
63
|
-
return /^#[0-9a-fA-F]{6}$/.test(s)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Perceived brightness on a 0–255 scale (ITU-R BT.601 luma:
|
|
68
|
-
* `(r·299 + g·587 + b·114) / 1000`). Callers own their thresholds.
|
|
69
|
-
*/
|
|
70
|
-
export function luma255(r: number, g: number, b: number): number {
|
|
71
|
-
return (r * 299 + g * 587 + b * 114) / 1000
|
|
72
|
-
}
|
package/src/shared/svg-a11y.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared SVG accessibility root attributes.
|
|
3
|
-
*
|
|
4
|
-
* One implementation of the contract every family renderer that threads
|
|
5
|
-
* accessibility itself must follow: `role="img"` on the root,
|
|
6
|
-
* `aria-labelledby` referencing the `<title id>` and `aria-describedby`
|
|
7
|
-
* referencing the `<desc id>`. Renderers that do not thread accessibility get
|
|
8
|
-
* the same contract from the injectAccessibility post-pass in index.ts —
|
|
9
|
-
* which detects these root attributes to know when to leave output alone.
|
|
10
|
-
* (Conformance-gated across all families by svg-a11y-conformance.test.ts.)
|
|
11
|
-
*/
|
|
12
|
-
export function buildAccessibilityAttrs(
|
|
13
|
-
title: string | undefined,
|
|
14
|
-
description: string | undefined,
|
|
15
|
-
titleId: string,
|
|
16
|
-
descId: string,
|
|
17
|
-
roledescription?: string,
|
|
18
|
-
): Record<string, string> {
|
|
19
|
-
const attrs: Record<string, string> = {}
|
|
20
|
-
if (roledescription) {
|
|
21
|
-
attrs['role'] = 'img'
|
|
22
|
-
attrs['aria-roledescription'] = roledescription
|
|
23
|
-
} else if (title || description) {
|
|
24
|
-
attrs['role'] = 'img'
|
|
25
|
-
}
|
|
26
|
-
if (title) attrs['aria-labelledby'] = titleId
|
|
27
|
-
if (description) attrs['aria-describedby'] = descId
|
|
28
|
-
return attrs
|
|
29
|
-
}
|