zombie-mermaid 2.2.3 → 2.2.6
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/README.md +4 -4
- package/dist/ascii.cjs +1 -11
- package/dist/ascii.d.cts +1 -167
- package/dist/ascii.d.ts +1 -167
- package/dist/ascii.js +1 -6591
- package/dist/cli.js +836 -10946
- package/dist/index.cjs +2 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -680
- package/dist/index.d.ts +42 -680
- package/dist/index.js +408 -10002
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +1 -17909
- package/dist/mcp.d.cts +1 -11
- package/dist/mcp.d.ts +1 -11
- package/dist/mcp.js +1 -17884
- package/package.json +29 -29
- package/src/__tests__/workspace-package-boundaries.test.ts +15 -16
- package/src/__tests__/xychart-parser-categories.test.ts +78 -0
- package/src/ascii-entry.ts +14 -0
- package/src/cli/html-viewer.ts +5 -0
- package/src/mcp-entry.ts +21 -0
- package/dist/ascii.cjs.map +0 -1
- package/dist/ascii.js.map +0 -1
- package/dist/mcp.cjs.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/packages/ascii-renderer/LICENSE +0 -22
- package/packages/ascii-renderer/src/ansi.ts +0 -490
- package/packages/ascii-renderer/src/canvas.ts +0 -658
- package/packages/ascii-renderer/src/class-diagram.ts +0 -2001
- package/packages/ascii-renderer/src/converter.ts +0 -446
- package/packages/ascii-renderer/src/coords.ts +0 -58
- package/packages/ascii-renderer/src/display-width.ts +0 -151
- package/packages/ascii-renderer/src/draw-arrows.ts +0 -549
- package/packages/ascii-renderer/src/draw-boxes.ts +0 -267
- package/packages/ascii-renderer/src/draw-bundles.ts +0 -611
- package/packages/ascii-renderer/src/draw-lines.ts +0 -174
- package/packages/ascii-renderer/src/draw-subgraphs.ts +0 -108
- package/packages/ascii-renderer/src/draw.ts +0 -337
- package/packages/ascii-renderer/src/edge-bundling.ts +0 -435
- package/packages/ascii-renderer/src/edge-cell-styles.ts +0 -81
- package/packages/ascii-renderer/src/edge-routing.ts +0 -1049
- package/packages/ascii-renderer/src/er-diagram.ts +0 -1488
- package/packages/ascii-renderer/src/flowchart.ts +0 -94
- package/packages/ascii-renderer/src/grid-occupancy.ts +0 -234
- package/packages/ascii-renderer/src/grid.ts +0 -1267
- package/packages/ascii-renderer/src/hyperlinks.ts +0 -248
- package/packages/ascii-renderer/src/index.ts +0 -163
- package/packages/ascii-renderer/src/lane-search.ts +0 -68
- package/packages/ascii-renderer/src/multiline-utils.ts +0 -82
- package/packages/ascii-renderer/src/pathfinder.ts +0 -448
- package/packages/ascii-renderer/src/registry.ts +0 -88
- package/packages/ascii-renderer/src/sequence.ts +0 -1318
- package/packages/ascii-renderer/src/shapes/circle.ts +0 -31
- package/packages/ascii-renderer/src/shapes/corners.ts +0 -273
- package/packages/ascii-renderer/src/shapes/diamond.ts +0 -31
- package/packages/ascii-renderer/src/shapes/hexagon.ts +0 -31
- package/packages/ascii-renderer/src/shapes/index.ts +0 -123
- package/packages/ascii-renderer/src/shapes/rectangle.ts +0 -199
- package/packages/ascii-renderer/src/shapes/rounded.ts +0 -31
- package/packages/ascii-renderer/src/shapes/special.ts +0 -352
- package/packages/ascii-renderer/src/shapes/stadium.ts +0 -122
- package/packages/ascii-renderer/src/shapes/state.ts +0 -204
- package/packages/ascii-renderer/src/shapes/types.ts +0 -78
- package/packages/ascii-renderer/src/territory.ts +0 -136
- package/packages/ascii-renderer/src/types.ts +0 -454
- package/packages/ascii-renderer/src/validate.ts +0 -189
- package/packages/ascii-renderer/src/xychart.ts +0 -1085
- package/packages/core/LICENSE +0 -22
- package/packages/core/src/click-directive.ts +0 -106
- package/packages/core/src/color-utils.ts +0 -205
- package/packages/core/src/diagram-type.ts +0 -35
- package/packages/core/src/direction-override.ts +0 -46
- package/packages/core/src/direction.ts +0 -56
- package/packages/core/src/index.ts +0 -34
- package/packages/core/src/init-directive.ts +0 -248
- package/packages/core/src/multiline-utils.ts +0 -275
- package/packages/core/src/statements.ts +0 -197
- package/packages/core/src/style-directives.ts +0 -214
- package/packages/core/src/text-metrics.ts +0 -498
- package/packages/core/src/theme.ts +0 -696
- package/packages/core/src/types.ts +0 -670
- package/packages/mcp/LICENSE +0 -22
- package/packages/mcp/src/index.ts +0 -17
- package/packages/mcp/src/server.ts +0 -135
- package/packages/mcp/src/tools/check-sequence-activations.ts +0 -91
- package/packages/mcp/src/tools/fix-sequence-activations.ts +0 -77
- package/packages/mcp/src/tools/render-ascii.ts +0 -99
- package/packages/mcp/src/tools/render-svg.ts +0 -95
- package/packages/mermaid-parser/LICENSE +0 -22
- package/packages/mermaid-parser/src/class/format.ts +0 -15
- package/packages/mermaid-parser/src/class/parser.ts +0 -593
- package/packages/mermaid-parser/src/class/types.ts +0 -166
- package/packages/mermaid-parser/src/er/parser.ts +0 -286
- package/packages/mermaid-parser/src/er/types.ts +0 -99
- package/packages/mermaid-parser/src/expanded-shapes.ts +0 -376
- package/packages/mermaid-parser/src/index.ts +0 -48
- package/packages/mermaid-parser/src/sequence/activation-check.ts +0 -149
- package/packages/mermaid-parser/src/sequence/activation-fix.ts +0 -112
- package/packages/mermaid-parser/src/sequence/box-color.ts +0 -85
- package/packages/mermaid-parser/src/sequence/parser.ts +0 -613
- package/packages/mermaid-parser/src/sequence/types.ts +0 -242
- package/packages/mermaid-parser/src/xychart/colors.ts +0 -177
- package/packages/mermaid-parser/src/xychart/parser.ts +0 -203
- package/packages/mermaid-parser/src/xychart/types.ts +0 -150
- package/packages/svg-renderer/LICENSE +0 -22
- package/packages/svg-renderer/src/class/layout.ts +0 -360
- package/packages/svg-renderer/src/class/renderer.ts +0 -636
- package/packages/svg-renderer/src/edge-curves.ts +0 -204
- package/packages/svg-renderer/src/elk-instance.ts +0 -292
- package/packages/svg-renderer/src/er/layout.ts +0 -200
- package/packages/svg-renderer/src/er/renderer.ts +0 -493
- package/packages/svg-renderer/src/index.ts +0 -58
- package/packages/svg-renderer/src/layout-engine/constants.ts +0 -19
- package/packages/svg-renderer/src/layout-engine/edge-bundling.ts +0 -379
- package/packages/svg-renderer/src/layout-engine/elk-adapter-utils.ts +0 -81
- package/packages/svg-renderer/src/layout-engine/elk-graph-builder.ts +0 -240
- package/packages/svg-renderer/src/layout-engine/from-elk.ts +0 -685
- package/packages/svg-renderer/src/layout-engine/layer-alignment.ts +0 -174
- package/packages/svg-renderer/src/layout-engine/to-elk.ts +0 -695
- package/packages/svg-renderer/src/layout-engine.ts +0 -74
- package/packages/svg-renderer/src/layout.ts +0 -8
- package/packages/svg-renderer/src/renderer.ts +0 -1485
- package/packages/svg-renderer/src/resolve-colors.ts +0 -339
- package/packages/svg-renderer/src/sequence/layout.ts +0 -698
- package/packages/svg-renderer/src/sequence/renderer.ts +0 -546
- package/packages/svg-renderer/src/shape-clipping.ts +0 -197
- package/packages/svg-renderer/src/styles.ts +0 -118
- package/packages/svg-renderer/src/xychart/layout.ts +0 -682
- package/packages/svg-renderer/src/xychart/renderer.ts +0 -684
- package/src/__tests__/ascii-canvas-write.test.ts +0 -137
- package/src/__tests__/ascii-charset-border-junctions.test.ts +0 -63
- package/src/__tests__/ascii-cjk-width.test.ts +0 -150
- package/src/__tests__/ascii-class-box-occupancy.test.ts +0 -462
- package/src/__tests__/ascii-class-column-width-488-489.test.ts +0 -639
- package/src/__tests__/ascii-class-cross-level-jog-corruption.test.ts +0 -187
- package/src/__tests__/ascii-class-detour-label-routing-487.test.ts +0 -114
- package/src/__tests__/ascii-class-diagram-compartments.test.ts +0 -70
- package/src/__tests__/ascii-class-label-box-collision.test.ts +0 -60
- package/src/__tests__/ascii-class-label-row-collision-531.test.ts +0 -135
- package/src/__tests__/ascii-class-label-territory-row-awareness.test.ts +0 -57
- package/src/__tests__/ascii-class-padding.test.ts +0 -104
- package/src/__tests__/ascii-class-parent-alignment-971.test.ts +0 -139
- package/src/__tests__/ascii-class-parent-alignment-972.test.ts +0 -208
- package/src/__tests__/ascii-class-reciprocal-relationships-448.test.ts +0 -169
- package/src/__tests__/ascii-combining-mark-width.test.ts +0 -70
- package/src/__tests__/ascii-coords-overlay.test.ts +0 -64
- package/src/__tests__/ascii-decision-lr-box-start.test.ts +0 -106
- package/src/__tests__/ascii-display-width-unit.test.ts +0 -154
- package/src/__tests__/ascii-draw-arrows-coverage.test.ts +0 -171
- package/src/__tests__/ascii-draw-arrows-single-point-path.test.ts +0 -112
- package/src/__tests__/ascii-edge-bundling-rank-violation-454.test.ts +0 -72
- package/src/__tests__/ascii-edge-ending-glyphs.test.ts +0 -206
- package/src/__tests__/ascii-edge-label-diagonal-fallback-418.test.ts +0 -95
- package/src/__tests__/ascii-edge-routing-fixes.test.ts +0 -178
- package/src/__tests__/ascii-edge-routing-single-point-path.test.ts +0 -107
- package/src/__tests__/ascii-edge-styles.test.ts +0 -149
- package/src/__tests__/ascii-emoji-cluster-width.test.ts +0 -101
- package/src/__tests__/ascii-er-box-occupancy.test.ts +0 -251
- package/src/__tests__/ascii-er-cardinality.test.ts +0 -40
- package/src/__tests__/ascii-er-corner-glyphs.test.ts +0 -249
- package/src/__tests__/ascii-er-jog-stray-line.test.ts +0 -111
- package/src/__tests__/ascii-er-label-padding.test.ts +0 -118
- package/src/__tests__/ascii-er-padding.test.ts +0 -114
- package/src/__tests__/ascii-er-relationship-label-corruption-350.test.ts +0 -458
- package/src/__tests__/ascii-er-relationship-overwrite.test.ts +0 -325
- package/src/__tests__/ascii-er-stray-connectors.test.ts +0 -347
- package/src/__tests__/ascii-er-unrelated-stem-separation-411.test.ts +0 -98
- package/src/__tests__/ascii-er-vertical-one-marker.test.ts +0 -110
- package/src/__tests__/ascii-label-line-terminal-fallback.test.ts +0 -172
- package/src/__tests__/ascii-lane-search.test.ts +0 -207
- package/src/__tests__/ascii-multibox-cjk-width.test.ts +0 -184
- package/src/__tests__/ascii-multiline.test.ts +0 -291
- package/src/__tests__/ascii-padding-edge-cases.test.ts +0 -154
- package/src/__tests__/ascii-pathfinder-route-edge.test.ts +0 -194
- package/src/__tests__/ascii-sequence-alt-else-label.test.ts +0 -236
- package/src/__tests__/ascii-sequence-block-wall-clearance.test.ts +0 -217
- package/src/__tests__/ascii-sequence-box-group.test.ts +0 -159
- package/src/__tests__/ascii-sequence-cjk-width.test.ts +0 -235
- package/src/__tests__/ascii-sequence-create-destroy.test.ts +0 -114
- package/src/__tests__/ascii-sequence-form-invariants.test.ts +0 -432
- package/src/__tests__/ascii-sequence-mermaid-parity.test.ts +0 -219
- package/src/__tests__/ascii-sequence-notes.test.ts +0 -61
- package/src/__tests__/ascii-sequence-padding.test.ts +0 -119
- package/src/__tests__/ascii-sequence-self-arrow.test.ts +0 -206
- package/src/__tests__/ascii-shape-diamond.test.ts +0 -38
- package/src/__tests__/ascii-shape-rectangle.test.ts +0 -258
- package/src/__tests__/ascii-shape-rounded.test.ts +0 -36
- package/src/__tests__/ascii-shapes-circle.test.ts +0 -41
- package/src/__tests__/ascii-shapes-hexagon.test.ts +0 -42
- package/src/__tests__/ascii-shapes-special.test.ts +0 -349
- package/src/__tests__/ascii-shapes-stadium.test.ts +0 -217
- package/src/__tests__/ascii-shapes-state.test.ts +0 -234
- package/src/__tests__/ascii-state-bidirectional-label-swap-530.test.ts +0 -130
- package/src/__tests__/ascii-subgraph-direction-honored-445.test.ts +0 -90
- package/src/__tests__/ascii-subgraph-label-border-clip.test.ts +0 -152
- package/src/__tests__/ascii-subgraph-title-padding.test.ts +0 -77
- package/src/__tests__/ascii-territory-unit.test.ts +0 -219
- package/src/__tests__/ascii-validate.test.ts +0 -220
- package/src/__tests__/ascii.test.ts +0 -328
- package/src/__tests__/box-color.test.ts +0 -80
- package/src/__tests__/class-arrow-directions.test.ts +0 -505
- package/src/__tests__/click-directive.test.ts +0 -63
- package/src/__tests__/color-utils.test.ts +0 -186
- package/src/__tests__/diagram-type.test.ts +0 -28
- package/src/__tests__/draw-lines.test.ts +0 -93
- package/src/__tests__/edge-cell-styles.test.ts +0 -180
- package/src/__tests__/elk-adapter-utils.test.ts +0 -166
- package/src/__tests__/grid-occupancy.test.ts +0 -240
- package/src/__tests__/helpers/ascii-form.ts +0 -142
- package/src/__tests__/helpers/terminal-display-width.ts +0 -74
- package/src/__tests__/mcp-check-sequence-activations-tool.test.ts +0 -85
- package/src/__tests__/mcp-fix-sequence-activations-tool.test.ts +0 -134
- package/src/__tests__/mcp-server.test.ts +0 -163
- package/src/__tests__/pathfinder.test.ts +0 -246
- package/src/__tests__/sequence-activation-fix.test.ts +0 -91
- package/src/__tests__/testdata/ascii/ampersand_lhs.txt +0 -18
- package/src/__tests__/testdata/ascii/ampersand_lhs_and_rhs.txt +0 -18
- package/src/__tests__/testdata/ascii/ampersand_rhs.txt +0 -18
- package/src/__tests__/testdata/ascii/ampersand_td_fanin.txt +0 -18
- package/src/__tests__/testdata/ascii/ampersand_td_fanout.txt +0 -18
- package/src/__tests__/testdata/ascii/ampersand_without_edge.txt +0 -18
- package/src/__tests__/testdata/ascii/back_reference_from_child.txt +0 -10
- package/src/__tests__/testdata/ascii/backlink_from_bottom.txt +0 -22
- package/src/__tests__/testdata/ascii/backlink_from_top.txt +0 -22
- package/src/__tests__/testdata/ascii/backlink_with_short_y_padding.txt +0 -20
- package/src/__tests__/testdata/ascii/cls_all_relationships.txt +0 -19
- package/src/__tests__/testdata/ascii/cls_annotation.txt +0 -29
- package/src/__tests__/testdata/ascii/cls_association.txt +0 -14
- package/src/__tests__/testdata/ascii/cls_basic.txt +0 -15
- package/src/__tests__/testdata/ascii/cls_dependency.txt +0 -14
- package/src/__tests__/testdata/ascii/cls_inheritance.txt +0 -20
- package/src/__tests__/testdata/ascii/cls_methods.txt +0 -21
- package/src/__tests__/testdata/ascii/comments.txt +0 -23
- package/src/__tests__/testdata/ascii/custom_padding.txt +0 -10
- package/src/__tests__/testdata/ascii/duplicate_labels.txt +0 -19
- package/src/__tests__/testdata/ascii/er_attributes.txt +0 -21
- package/src/__tests__/testdata/ascii/er_basic.txt +0 -8
- package/src/__tests__/testdata/ascii/er_identifying.txt +0 -18
- package/src/__tests__/testdata/ascii/flowchart_tb_simple.txt +0 -29
- package/src/__tests__/testdata/ascii/graph_bt_direction.txt +0 -28
- package/src/__tests__/testdata/ascii/graph_tb_direction.txt +0 -26
- package/src/__tests__/testdata/ascii/nested_subgraphs_with_labels.txt +0 -36
- package/src/__tests__/testdata/ascii/preserve_order_of_definition.txt +0 -23
- package/src/__tests__/testdata/ascii/self_reference.txt +0 -10
- package/src/__tests__/testdata/ascii/self_reference_with_edge.txt +0 -10
- package/src/__tests__/testdata/ascii/seq_basic.txt +0 -17
- package/src/__tests__/testdata/ascii/seq_multiple_messages.txt +0 -25
- package/src/__tests__/testdata/ascii/seq_self_message.txt +0 -18
- package/src/__tests__/testdata/ascii/single_node.txt +0 -8
- package/src/__tests__/testdata/ascii/single_node_longer_name.txt +0 -8
- package/src/__tests__/testdata/ascii/subgraph_complex_mixed.txt +0 -38
- package/src/__tests__/testdata/ascii/subgraph_complex_nested.txt +0 -49
- package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +0 -47
- package/src/__tests__/testdata/ascii/subgraph_empty.txt +0 -10
- package/src/__tests__/testdata/ascii/subgraph_mixed_nodes.txt +0 -20
- package/src/__tests__/testdata/ascii/subgraph_mixed_nodes_td.txt +0 -48
- package/src/__tests__/testdata/ascii/subgraph_multiple_edges.txt +0 -32
- package/src/__tests__/testdata/ascii/subgraph_multiple_nodes.txt +0 -16
- package/src/__tests__/testdata/ascii/subgraph_nested.txt +0 -24
- package/src/__tests__/testdata/ascii/subgraph_nested_with_external.txt +0 -30
- package/src/__tests__/testdata/ascii/subgraph_node_outside_lr.txt +0 -17
- package/src/__tests__/testdata/ascii/subgraph_single_node.txt +0 -16
- package/src/__tests__/testdata/ascii/subgraph_td_direction.txt +0 -26
- package/src/__tests__/testdata/ascii/subgraph_td_multiple.txt +0 -44
- package/src/__tests__/testdata/ascii/subgraph_td_multiple_paddingy.txt +0 -42
- package/src/__tests__/testdata/ascii/subgraph_three_levels_nested.txt +0 -32
- package/src/__tests__/testdata/ascii/subgraph_three_separate.txt +0 -24
- package/src/__tests__/testdata/ascii/subgraph_two_separate.txt +0 -20
- package/src/__tests__/testdata/ascii/subgraph_with_labels.txt +0 -20
- package/src/__tests__/testdata/ascii/three_nodes.txt +0 -9
- package/src/__tests__/testdata/ascii/three_nodes_single_line.txt +0 -8
- package/src/__tests__/testdata/ascii/two_layer_single_graph.txt +0 -19
- package/src/__tests__/testdata/ascii/two_layer_single_graph_longer_names.txt +0 -19
- package/src/__tests__/testdata/ascii/two_nodes_linked.txt +0 -8
- package/src/__tests__/testdata/ascii/two_nodes_longer_names.txt +0 -8
- package/src/__tests__/testdata/ascii/two_root_nodes.txt +0 -19
- package/src/__tests__/testdata/ascii/two_root_nodes_longer_names.txt +0 -19
- package/src/__tests__/testdata/ascii/two_single_root_nodes.txt +0 -19
- package/src/__tests__/testdata/unicode/ampersand_lhs.txt +0 -18
- package/src/__tests__/testdata/unicode/ampersand_lhs_and_rhs.txt +0 -18
- package/src/__tests__/testdata/unicode/ampersand_rhs.txt +0 -18
- package/src/__tests__/testdata/unicode/ampersand_without_edge.txt +0 -18
- package/src/__tests__/testdata/unicode/back_reference_from_child.txt +0 -10
- package/src/__tests__/testdata/unicode/backlink_from_bottom.txt +0 -22
- package/src/__tests__/testdata/unicode/backlink_from_top.txt +0 -22
- package/src/__tests__/testdata/unicode/cls_all_relationships.txt +0 -19
- package/src/__tests__/testdata/unicode/cls_annotation.txt +0 -29
- package/src/__tests__/testdata/unicode/cls_association.txt +0 -14
- package/src/__tests__/testdata/unicode/cls_basic.txt +0 -15
- package/src/__tests__/testdata/unicode/cls_dependency.txt +0 -14
- package/src/__tests__/testdata/unicode/cls_inheritance.txt +0 -20
- package/src/__tests__/testdata/unicode/cls_methods.txt +0 -21
- package/src/__tests__/testdata/unicode/comments.txt +0 -23
- package/src/__tests__/testdata/unicode/duplicate_labels.txt +0 -19
- package/src/__tests__/testdata/unicode/er_attributes.txt +0 -21
- package/src/__tests__/testdata/unicode/er_basic.txt +0 -8
- package/src/__tests__/testdata/unicode/er_identifying.txt +0 -18
- package/src/__tests__/testdata/unicode/graph_bt_direction.txt +0 -28
- package/src/__tests__/testdata/unicode/preserve_order_of_definition.txt +0 -23
- package/src/__tests__/testdata/unicode/self_reference.txt +0 -10
- package/src/__tests__/testdata/unicode/self_reference_with_edge.txt +0 -10
- package/src/__tests__/testdata/unicode/seq_basic.txt +0 -17
- package/src/__tests__/testdata/unicode/seq_multiple_messages.txt +0 -25
- package/src/__tests__/testdata/unicode/seq_self_message.txt +0 -18
- package/src/__tests__/testdata/unicode/single_node.txt +0 -8
- package/src/__tests__/testdata/unicode/single_node_longer_name.txt +0 -8
- package/src/__tests__/testdata/unicode/three_nodes.txt +0 -9
- package/src/__tests__/testdata/unicode/three_nodes_single_line.txt +0 -8
- package/src/__tests__/testdata/unicode/two_layer_single_graph.txt +0 -19
- package/src/__tests__/testdata/unicode/two_layer_single_graph_longer_names.txt +0 -19
- package/src/__tests__/testdata/unicode/two_nodes_linked.txt +0 -8
- package/src/__tests__/testdata/unicode/two_nodes_longer_names.txt +0 -8
- package/src/__tests__/testdata/unicode/two_root_nodes.txt +0 -19
- package/src/__tests__/testdata/unicode/two_root_nodes_longer_names.txt +0 -19
- package/src/__tests__/testdata/unicode/two_single_root_nodes.txt +0 -19
- package/src/__tests__/text-metrics.test.ts +0 -473
- package/src/__tests__/theme-palette-contrast.test.ts +0 -84
- package/src/__tests__/theme.test.ts +0 -132
- package/src/__tests__/xychart-ascii.test.ts +0 -376
- package/src/__tests__/xychart-colors.test.ts +0 -149
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
parseCssColor,
|
|
4
|
-
parseHexColor,
|
|
5
|
-
mixSrgb,
|
|
6
|
-
mixHexColors,
|
|
7
|
-
formatCssColor,
|
|
8
|
-
} from '@zombie-mermaid/core'
|
|
9
|
-
|
|
10
|
-
describe('parseCssColor', () => {
|
|
11
|
-
it('parses 3/4/6/8-digit hex, expanding shorthand and reading alpha', () => {
|
|
12
|
-
expect(parseCssColor('#fff')).toEqual({ r: 255, g: 255, b: 255, a: 1 })
|
|
13
|
-
expect(parseCssColor('#f008')).toEqual({
|
|
14
|
-
r: 255,
|
|
15
|
-
g: 0,
|
|
16
|
-
b: 0,
|
|
17
|
-
a: 0x88 / 255,
|
|
18
|
-
})
|
|
19
|
-
expect(parseCssColor('#27272A')).toEqual({ r: 39, g: 39, b: 42, a: 1 })
|
|
20
|
-
expect(parseCssColor('#00000080')).toEqual({
|
|
21
|
-
r: 0,
|
|
22
|
-
g: 0,
|
|
23
|
-
b: 0,
|
|
24
|
-
a: 0x80 / 255,
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('parses rgb()/rgba() in legacy comma and modern space syntax', () => {
|
|
29
|
-
expect(parseCssColor('rgb(1, 2, 3)')).toEqual({ r: 1, g: 2, b: 3, a: 1 })
|
|
30
|
-
expect(parseCssColor('rgba(1, 2, 3, 0.5)')).toEqual({
|
|
31
|
-
r: 1,
|
|
32
|
-
g: 2,
|
|
33
|
-
b: 3,
|
|
34
|
-
a: 0.5,
|
|
35
|
-
})
|
|
36
|
-
expect(parseCssColor('rgb(10 20 30 / 50%)')).toEqual({
|
|
37
|
-
r: 10,
|
|
38
|
-
g: 20,
|
|
39
|
-
b: 30,
|
|
40
|
-
a: 0.5,
|
|
41
|
-
})
|
|
42
|
-
expect(parseCssColor('rgb(100%, 0%, 50%)')).toEqual({
|
|
43
|
-
r: 255,
|
|
44
|
-
g: 0,
|
|
45
|
-
b: 127.5,
|
|
46
|
-
a: 1,
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('parses the transparent keyword', () => {
|
|
51
|
-
expect(parseCssColor('transparent')).toEqual({ r: 0, g: 0, b: 0, a: 0 })
|
|
52
|
-
expect(parseCssColor(' Transparent ')).toEqual({ r: 0, g: 0, b: 0, a: 0 })
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('returns null for anything it cannot evaluate rather than guessing', () => {
|
|
56
|
-
expect(parseCssColor('var(--fg)')).toBeNull()
|
|
57
|
-
expect(parseCssColor('red')).toBeNull()
|
|
58
|
-
expect(parseCssColor('hsl(0 100% 50%)')).toBeNull()
|
|
59
|
-
expect(parseCssColor('#ggg')).toBeNull()
|
|
60
|
-
expect(parseCssColor('color-mix(in srgb, #000, #fff)')).toBeNull()
|
|
61
|
-
expect(parseCssColor('')).toBeNull()
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('returns null when a channel matches the token pattern but is not a valid number', () => {
|
|
65
|
-
// RGB_FUNC_RE's channel class (`[\d.]+%?`) accepts any run of digits
|
|
66
|
-
// and dots, including a malformed one like "1.2.3" — it isn't trying
|
|
67
|
-
// to fully validate number syntax, just to find the token boundaries.
|
|
68
|
-
// Number("1.2.3") is NaN, so this must be rejected downstream rather
|
|
69
|
-
// than producing a color with a NaN channel.
|
|
70
|
-
expect(parseCssColor('rgb(1.2.3, 0, 0)')).toBeNull()
|
|
71
|
-
expect(parseCssColor('rgba(0, 0, 0, 1.2.3)')).toBeNull()
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
describe('parseHexColor', () => {
|
|
76
|
-
it('returns RGB tuple for hex literals and null otherwise', () => {
|
|
77
|
-
expect(parseHexColor('#abc')).toEqual([170, 187, 204])
|
|
78
|
-
expect(parseHexColor('#aabbccdd')).toEqual([170, 187, 204])
|
|
79
|
-
expect(parseHexColor('rgb(1,2,3)')).toBeNull()
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
describe('mixSrgb', () => {
|
|
84
|
-
const black = { r: 0, g: 0, b: 0, a: 1 }
|
|
85
|
-
const white = { r: 255, g: 255, b: 255, a: 1 }
|
|
86
|
-
const transparent = { r: 0, g: 0, b: 0, a: 0 }
|
|
87
|
-
|
|
88
|
-
it('defaults to 50/50 when both percentages are omitted', () => {
|
|
89
|
-
expect(mixSrgb(black, white)).toEqual({
|
|
90
|
-
r: 127.5,
|
|
91
|
-
g: 127.5,
|
|
92
|
-
b: 127.5,
|
|
93
|
-
a: 1,
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('infers the omitted percentage as 100 minus the given one', () => {
|
|
98
|
-
expect(mixSrgb(black, white, 25)).toEqual({
|
|
99
|
-
r: 191.25,
|
|
100
|
-
g: 191.25,
|
|
101
|
-
b: 191.25,
|
|
102
|
-
a: 1,
|
|
103
|
-
})
|
|
104
|
-
expect(mixSrgb(black, white, undefined, 25)).toEqual({
|
|
105
|
-
r: 63.75,
|
|
106
|
-
g: 63.75,
|
|
107
|
-
b: 63.75,
|
|
108
|
-
a: 1,
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('normalizes percentages that sum to more than 100', () => {
|
|
113
|
-
// 150 + 50 → 75% / 25%
|
|
114
|
-
expect(mixSrgb(black, white, 150, 50)).toEqual({
|
|
115
|
-
r: 63.75,
|
|
116
|
-
g: 63.75,
|
|
117
|
-
b: 63.75,
|
|
118
|
-
a: 1,
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('scales alpha by the sum when percentages sum to less than 100', () => {
|
|
123
|
-
// 25 + 25 → 50/50 blend at alpha 0.5
|
|
124
|
-
expect(mixSrgb(black, white, 25, 25)).toEqual({
|
|
125
|
-
r: 127.5,
|
|
126
|
-
g: 127.5,
|
|
127
|
-
b: 127.5,
|
|
128
|
-
a: 0.5,
|
|
129
|
-
})
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('interpolates in premultiplied alpha, so fading toward transparent keeps the hue', () => {
|
|
133
|
-
const red = { r: 255, g: 0, b: 0, a: 1 }
|
|
134
|
-
const mixed = mixSrgb(red, transparent, 20)
|
|
135
|
-
expect(mixed).toEqual({ r: 255, g: 0, b: 0, a: 0.2 })
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('returns null when both percentages are zero (invalid per spec)', () => {
|
|
139
|
-
expect(mixSrgb(black, white, 0, 0)).toBeNull()
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('mixes two fully-transparent colors without dividing by zero alpha', () => {
|
|
143
|
-
// Both inputs have alpha 0, so the result's premultiplied alpha is also
|
|
144
|
-
// 0 — premul's `alpha === 0 ? 0 : …` guard must short-circuit rather
|
|
145
|
-
// than compute `0/0` (NaN) for each channel.
|
|
146
|
-
const transparentRed = { r: 255, g: 0, b: 0, a: 0 }
|
|
147
|
-
const transparentBlue = { r: 0, g: 0, b: 255, a: 0 }
|
|
148
|
-
expect(mixSrgb(transparentRed, transparentBlue, 50, 50)).toEqual({
|
|
149
|
-
r: 0,
|
|
150
|
-
g: 0,
|
|
151
|
-
b: 0,
|
|
152
|
-
a: 0,
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
describe('mixHexColors', () => {
|
|
158
|
-
it('mixes fg into bg at the given percentage, matching the ASCII bridge’s historical math', () => {
|
|
159
|
-
// 0*.5 + 255*.5 = 127.5 → rounds to 128 = 0x80
|
|
160
|
-
expect(mixHexColors('#000000', '#ffffff', 50)).toBe('#808080')
|
|
161
|
-
// 0*.85 + 255*.15 = 38.25 → 38 = 0x26
|
|
162
|
-
expect(mixHexColors('#000000', '#ffffff', 85)).toBe('#262626')
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
it('returns fg unchanged when either side is not a concrete color', () => {
|
|
166
|
-
expect(mixHexColors('var(--fg)', '#fff', 50)).toBe('var(--fg)')
|
|
167
|
-
expect(mixHexColors('#000', 'var(--bg)', 50)).toBe('#000')
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
describe('formatCssColor', () => {
|
|
172
|
-
it('emits #rrggbb for opaque colors and rgba() otherwise', () => {
|
|
173
|
-
expect(formatCssColor({ r: 255, g: 0, b: 128, a: 1 })).toBe('#ff0080')
|
|
174
|
-
expect(formatCssColor({ r: 39, g: 39, b: 42, a: 0.2 })).toBe(
|
|
175
|
-
'rgba(39, 39, 42, 0.2)',
|
|
176
|
-
)
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('rounds channels and clamps out-of-range values', () => {
|
|
180
|
-
expect(formatCssColor({ r: 127.5, g: -3, b: 300, a: 1 })).toBe('#8000ff')
|
|
181
|
-
expect(formatCssColor({ r: 0, g: 0, b: 0, a: 1.5 })).toBe('#000000')
|
|
182
|
-
expect(formatCssColor({ r: 0, g: 0, b: 0, a: 0.33333 })).toBe(
|
|
183
|
-
'rgba(0, 0, 0, 0.333)',
|
|
184
|
-
)
|
|
185
|
-
})
|
|
186
|
-
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { detectDiagramType } from '@zombie-mermaid/core'
|
|
3
|
-
|
|
4
|
-
describe('detectDiagramType', () => {
|
|
5
|
-
it('detects each diagram type from its header keyword', () => {
|
|
6
|
-
expect(detectDiagramType('flowchart TD\nA-->B')).toBe('flowchart')
|
|
7
|
-
expect(detectDiagramType('sequenceDiagram\nA->>B: Hi')).toBe('sequence')
|
|
8
|
-
expect(detectDiagramType('classDiagram\nclass Foo')).toBe('class')
|
|
9
|
-
expect(detectDiagramType('erDiagram\nFOO ||--o{ BAR : has')).toBe('er')
|
|
10
|
-
expect(detectDiagramType('xychart-beta\nx-axis [a, b]')).toBe('xychart')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('isolates the header on a semicolon-separated single line', () => {
|
|
14
|
-
expect(detectDiagramType('sequenceDiagram;A->>B: Hi')).toBe('sequence')
|
|
15
|
-
expect(detectDiagramType('classDiagram;class Foo')).toBe('class')
|
|
16
|
-
expect(detectDiagramType('erDiagram;FOO ||--o{ BAR : has')).toBe('er')
|
|
17
|
-
expect(detectDiagramType('flowchart TD;A-->B')).toBe('flowchart')
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('does not match an xychart header with an unsupported suffix', () => {
|
|
21
|
-
expect(detectDiagramType('xychart-foo\nx-axis [a, b]')).toBe('flowchart')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('falls back to flowchart for unrecognized input', () => {
|
|
25
|
-
expect(detectDiagramType('')).toBe('flowchart')
|
|
26
|
-
expect(detectDiagramType('not a real header')).toBe('flowchart')
|
|
27
|
-
})
|
|
28
|
-
})
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Direct unit tests for drawLine's diagonal routing branches
|
|
3
|
-
* (UpperLeft/UpperRight/LowerLeft/LowerRight in src/ascii/draw-lines.ts).
|
|
4
|
-
*
|
|
5
|
-
* These branches only fire when `from` and `to` differ on both axes.
|
|
6
|
-
* Every real call site (draw-arrows.ts's drawPath, draw-bundles.ts) feeds
|
|
7
|
-
* drawLine coordinates derived from an A* grid path — and the pathfinder
|
|
8
|
-
* only ever moves 4-directionally (see pathfinder.ts's MOVE_DIRS) — so no
|
|
9
|
-
* Mermaid diagram through the renderer can actually produce a diagonal
|
|
10
|
-
* `from`/`to` pair here; the pure-vertical/horizontal branches are already
|
|
11
|
-
* covered that way. Testing this diagonal routing therefore has to call
|
|
12
|
-
* drawLine directly, the same way pathfinder.test.ts unit-tests getPath
|
|
13
|
-
* directly with hand-built inputs rather than through a full render.
|
|
14
|
-
*/
|
|
15
|
-
import { describe, it, expect } from 'vitest'
|
|
16
|
-
import { drawLine } from '../../packages/ascii-renderer/src/draw-lines.ts'
|
|
17
|
-
import { mkCanvas } from '../../packages/ascii-renderer/src/canvas.ts'
|
|
18
|
-
|
|
19
|
-
describe('drawLine diagonal routing', () => {
|
|
20
|
-
it('routes UpperLeft as a horizontal-then-vertical bend', () => {
|
|
21
|
-
const canvas = mkCanvas(10, 10)
|
|
22
|
-
const drawn = drawLine(canvas, { x: 8, y: 8 }, { x: 2, y: 2 }, 1, -1, false)
|
|
23
|
-
expect(canvas[7]![8]).toBe('─')
|
|
24
|
-
expect(canvas[2]![8]).toBe('─')
|
|
25
|
-
expect(canvas[2]![7]).toBe('│')
|
|
26
|
-
expect(canvas[2]![3]).toBe('│')
|
|
27
|
-
expect(drawn.length).toBe(6 + 5)
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('routes UpperRight as a horizontal-then-vertical bend', () => {
|
|
31
|
-
const canvas = mkCanvas(10, 10)
|
|
32
|
-
const drawn = drawLine(canvas, { x: 2, y: 8 }, { x: 8, y: 2 }, 1, -1, false)
|
|
33
|
-
expect(canvas[3]![8]).toBe('─')
|
|
34
|
-
expect(canvas[8]![8]).toBe('─')
|
|
35
|
-
expect(canvas[8]![7]).toBe('│')
|
|
36
|
-
expect(canvas[8]![3]).toBe('│')
|
|
37
|
-
expect(drawn.length).toBe(6 + 5)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('routes LowerLeft as a horizontal-then-vertical bend', () => {
|
|
41
|
-
const canvas = mkCanvas(10, 10)
|
|
42
|
-
const drawn = drawLine(canvas, { x: 8, y: 2 }, { x: 2, y: 8 }, 1, -1, false)
|
|
43
|
-
expect(canvas[7]![2]).toBe('─')
|
|
44
|
-
expect(canvas[2]![2]).toBe('─')
|
|
45
|
-
expect(canvas[2]![3]).toBe('│')
|
|
46
|
-
expect(canvas[2]![7]).toBe('│')
|
|
47
|
-
expect(drawn.length).toBe(6 + 5)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('LowerRight', () => {
|
|
51
|
-
it('draws a straight vertical line when x delta is 1 (source-aligned)', () => {
|
|
52
|
-
const canvas = mkCanvas(10, 10)
|
|
53
|
-
const drawn = drawLine(
|
|
54
|
-
canvas,
|
|
55
|
-
{ x: 5, y: 2 },
|
|
56
|
-
{ x: 6, y: 8 },
|
|
57
|
-
1,
|
|
58
|
-
-1,
|
|
59
|
-
false,
|
|
60
|
-
)
|
|
61
|
-
for (let y = 3; y <= 7; y++) {
|
|
62
|
-
expect(canvas[5]![y]).toBe('│')
|
|
63
|
-
}
|
|
64
|
-
expect(canvas[6]![8]).toBe(' ')
|
|
65
|
-
expect(drawn.every((c) => c.x === 5)).toBe(true)
|
|
66
|
-
expect(drawn.length).toBe(5)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('routes as a horizontal-then-vertical bend when x delta is greater than 1', () => {
|
|
70
|
-
const canvas = mkCanvas(10, 10)
|
|
71
|
-
const drawn = drawLine(
|
|
72
|
-
canvas,
|
|
73
|
-
{ x: 2, y: 2 },
|
|
74
|
-
{ x: 8, y: 8 },
|
|
75
|
-
1,
|
|
76
|
-
-1,
|
|
77
|
-
false,
|
|
78
|
-
)
|
|
79
|
-
expect(canvas[3]![2]).toBe('─')
|
|
80
|
-
expect(canvas[8]![2]).toBe('─')
|
|
81
|
-
expect(canvas[8]![3]).toBe('│')
|
|
82
|
-
expect(canvas[8]![7]).toBe('│')
|
|
83
|
-
expect(drawn.length).toBe(6 + 5)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('uses ASCII characters in ASCII mode', () => {
|
|
87
|
-
const canvas = mkCanvas(10, 10)
|
|
88
|
-
drawLine(canvas, { x: 2, y: 2 }, { x: 8, y: 8 }, 1, -1, true)
|
|
89
|
-
expect(canvas[3]![2]).toBe('-')
|
|
90
|
-
expect(canvas[8]![3]).toBe('|')
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
})
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
createEdgeCellStyles,
|
|
4
|
-
findStyleConflict,
|
|
5
|
-
claimPathCells,
|
|
6
|
-
} from '../../packages/ascii-renderer/src/edge-cell-styles.ts'
|
|
7
|
-
import {
|
|
8
|
-
createGrid,
|
|
9
|
-
placeBlock,
|
|
10
|
-
} from '../../packages/ascii-renderer/src/grid-occupancy.ts'
|
|
11
|
-
|
|
12
|
-
describe('edge-cell-styles', () => {
|
|
13
|
-
it('reports no conflict against an empty map', () => {
|
|
14
|
-
const grid = createGrid()
|
|
15
|
-
const cellStyles = createEdgeCellStyles()
|
|
16
|
-
const path = [
|
|
17
|
-
{ x: 0, y: 0 },
|
|
18
|
-
{ x: 3, y: 0 },
|
|
19
|
-
]
|
|
20
|
-
expect(findStyleConflict(grid, cellStyles, path, 'solid')).toBeNull()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('does not flag a second same-style edge through claimed cells', () => {
|
|
24
|
-
const grid = createGrid()
|
|
25
|
-
const cellStyles = createEdgeCellStyles()
|
|
26
|
-
const path = [
|
|
27
|
-
{ x: 0, y: 0 },
|
|
28
|
-
{ x: 3, y: 0 },
|
|
29
|
-
]
|
|
30
|
-
claimPathCells(grid, cellStyles, path, 'solid')
|
|
31
|
-
// A second solid edge reusing the same cells is exactly the "sibling
|
|
32
|
-
// edges share a trunk" / "LR routing merges naturally at corners"
|
|
33
|
-
// behavior other tests rely on — must stay unflagged.
|
|
34
|
-
expect(findStyleConflict(grid, cellStyles, path, 'solid')).toBeNull()
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('flags a different-style edge crossing already-claimed cells', () => {
|
|
38
|
-
const grid = createGrid()
|
|
39
|
-
const cellStyles = createEdgeCellStyles()
|
|
40
|
-
const path = [
|
|
41
|
-
{ x: 0, y: 0 },
|
|
42
|
-
{ x: 3, y: 0 },
|
|
43
|
-
]
|
|
44
|
-
claimPathCells(grid, cellStyles, path, 'solid')
|
|
45
|
-
expect(findStyleConflict(grid, cellStyles, path, 'dotted')).toEqual({
|
|
46
|
-
x: 0,
|
|
47
|
-
y: 0,
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('reports the first conflicting cell in path order', () => {
|
|
52
|
-
const grid = createGrid()
|
|
53
|
-
const cellStyles = createEdgeCellStyles()
|
|
54
|
-
claimPathCells(
|
|
55
|
-
grid,
|
|
56
|
-
cellStyles,
|
|
57
|
-
[
|
|
58
|
-
{ x: 5, y: 0 },
|
|
59
|
-
{ x: 8, y: 0 },
|
|
60
|
-
],
|
|
61
|
-
'thick',
|
|
62
|
-
)
|
|
63
|
-
const crossing = [
|
|
64
|
-
{ x: 0, y: 0 },
|
|
65
|
-
{ x: 10, y: 0 },
|
|
66
|
-
]
|
|
67
|
-
expect(findStyleConflict(grid, cellStyles, crossing, 'solid')).toEqual({
|
|
68
|
-
x: 5,
|
|
69
|
-
y: 0,
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('first claim wins — claiming a cell twice with different styles keeps the original', () => {
|
|
74
|
-
const grid = createGrid()
|
|
75
|
-
const cellStyles = createEdgeCellStyles()
|
|
76
|
-
const cell = [{ x: 1, y: 1 }]
|
|
77
|
-
claimPathCells(grid, cellStyles, cell, 'solid')
|
|
78
|
-
claimPathCells(grid, cellStyles, cell, 'dotted')
|
|
79
|
-
// Still solid from the first claim, so a *third* dotted edge is still
|
|
80
|
-
// reported as a conflict rather than silently "winning" the cell.
|
|
81
|
-
expect(findStyleConflict(grid, cellStyles, cell, 'dotted')).toEqual({
|
|
82
|
-
x: 1,
|
|
83
|
-
y: 1,
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('does not flag cells the path never touches', () => {
|
|
88
|
-
const grid = createGrid()
|
|
89
|
-
const cellStyles = createEdgeCellStyles()
|
|
90
|
-
claimPathCells(
|
|
91
|
-
grid,
|
|
92
|
-
cellStyles,
|
|
93
|
-
[
|
|
94
|
-
{ x: 0, y: 0 },
|
|
95
|
-
{ x: 0, y: 5 },
|
|
96
|
-
],
|
|
97
|
-
'solid',
|
|
98
|
-
)
|
|
99
|
-
const unrelated = [
|
|
100
|
-
{ x: 10, y: 10 },
|
|
101
|
-
{ x: 12, y: 10 },
|
|
102
|
-
]
|
|
103
|
-
expect(findStyleConflict(grid, cellStyles, unrelated, 'dotted')).toBeNull()
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Regression: an edge's path always includes its own source/target
|
|
108
|
-
* node's border cell — that's how it connects to the box at all — so
|
|
109
|
-
* two edges sharing a node (one incoming, one outgoing, as in a retry
|
|
110
|
-
* loop's `B -->|No| D; D -.-> A`) legitimately share that exact port
|
|
111
|
-
* cell. An earlier version tracked *every* path cell including
|
|
112
|
-
* node-owned ones, which flagged this as a conflict — and since an edge
|
|
113
|
-
* always returns to its own node's fixed attachment point regardless of
|
|
114
|
-
* grid occupancy, "blocking" a node cell and re-routing found the
|
|
115
|
-
* identical cell again every time, so the fix never actually converged.
|
|
116
|
-
*/
|
|
117
|
-
it('does not flag a shared node-border cell as a conflict', () => {
|
|
118
|
-
const grid = createGrid()
|
|
119
|
-
placeBlock(grid, { x: 4, y: 8 }) // node D's reserved 3x3 block
|
|
120
|
-
const cellStyles = createEdgeCellStyles()
|
|
121
|
-
|
|
122
|
-
// Incoming solid edge terminating at D's top-center port, (5, 8).
|
|
123
|
-
claimPathCells(
|
|
124
|
-
grid,
|
|
125
|
-
cellStyles,
|
|
126
|
-
[
|
|
127
|
-
{ x: 2, y: 5 },
|
|
128
|
-
{ x: 5, y: 5 },
|
|
129
|
-
{ x: 5, y: 8 },
|
|
130
|
-
],
|
|
131
|
-
'solid',
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
// Outgoing dotted edge leaving from D's right-side port, (6, 9) —
|
|
135
|
-
// inside the same reserved block, so still node-owned — then diverging
|
|
136
|
-
// into its own open column (7) rather than reusing (5, *).
|
|
137
|
-
const conflict = findStyleConflict(
|
|
138
|
-
grid,
|
|
139
|
-
cellStyles,
|
|
140
|
-
[
|
|
141
|
-
{ x: 6, y: 9 },
|
|
142
|
-
{ x: 7, y: 9 },
|
|
143
|
-
{ x: 7, y: 1 },
|
|
144
|
-
],
|
|
145
|
-
'dotted',
|
|
146
|
-
)
|
|
147
|
-
expect(conflict).toBeNull()
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('still flags a genuine open-space conflict alongside a shared node border', () => {
|
|
151
|
-
const grid = createGrid()
|
|
152
|
-
placeBlock(grid, { x: 4, y: 8 }) // node D's reserved 3x3 block
|
|
153
|
-
const cellStyles = createEdgeCellStyles()
|
|
154
|
-
|
|
155
|
-
claimPathCells(
|
|
156
|
-
grid,
|
|
157
|
-
cellStyles,
|
|
158
|
-
[
|
|
159
|
-
{ x: 2, y: 5 },
|
|
160
|
-
{ x: 5, y: 5 },
|
|
161
|
-
{ x: 5, y: 8 },
|
|
162
|
-
],
|
|
163
|
-
'solid',
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
// A different-style edge that reaches D via the *same open-space*
|
|
167
|
-
// column (5, 5)-(5, 8), not just the shared port cell, is still a
|
|
168
|
-
// real conflict — reported at the first open cell it crosses.
|
|
169
|
-
const conflict = findStyleConflict(
|
|
170
|
-
grid,
|
|
171
|
-
cellStyles,
|
|
172
|
-
[
|
|
173
|
-
{ x: 5, y: 1 },
|
|
174
|
-
{ x: 5, y: 8 },
|
|
175
|
-
],
|
|
176
|
-
'dotted',
|
|
177
|
-
)
|
|
178
|
-
expect(conflict).toEqual({ x: 5, y: 5 })
|
|
179
|
-
})
|
|
180
|
-
})
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the shared ELK edge-geometry extraction helpers
|
|
3
|
-
* (`extractEdgePoints` / `extractEdgeLabelPosition`).
|
|
4
|
-
*
|
|
5
|
-
* `from-elk.ts`, `class/layout.ts`, and `er/layout.ts` all exercise this
|
|
6
|
-
* module indirectly through full-diagram integration tests, but those
|
|
7
|
-
* only ever hit the "happy path" (an edge with sections and, sometimes,
|
|
8
|
-
* a placed label). These tests cover the defensive branches directly —
|
|
9
|
-
* missing/empty sections, missing/empty labels, an unplaced label, and
|
|
10
|
-
* missing bend points/label dimensions — so every branch has direct
|
|
11
|
-
* coverage rather than relying on an integration test to happen to hit it.
|
|
12
|
-
*/
|
|
13
|
-
import { describe, it, expect } from 'vitest'
|
|
14
|
-
import type { ElkExtendedEdge } from 'elkjs'
|
|
15
|
-
import {
|
|
16
|
-
extractEdgePoints,
|
|
17
|
-
extractEdgeLabelPosition,
|
|
18
|
-
} from '@zombie-mermaid/svg-renderer'
|
|
19
|
-
|
|
20
|
-
function edge(partial: Partial<ElkExtendedEdge>): ElkExtendedEdge {
|
|
21
|
-
return { id: 'e0', sources: ['a'], targets: ['b'], ...partial }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe('extractEdgePoints', () => {
|
|
25
|
-
it('returns an empty array when the edge has no sections property', () => {
|
|
26
|
-
expect(extractEdgePoints(edge({}))).toEqual([])
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('returns an empty array when sections is an empty array', () => {
|
|
30
|
-
expect(extractEdgePoints(edge({ sections: [] }))).toEqual([])
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('walks start -> end with no bend points', () => {
|
|
34
|
-
const e = edge({
|
|
35
|
-
sections: [
|
|
36
|
-
{
|
|
37
|
-
id: 's0',
|
|
38
|
-
startPoint: { x: 10, y: 20 },
|
|
39
|
-
endPoint: { x: 30, y: 40 },
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
})
|
|
43
|
-
expect(extractEdgePoints(e)).toEqual([
|
|
44
|
-
{ x: 10, y: 20 },
|
|
45
|
-
{ x: 30, y: 40 },
|
|
46
|
-
])
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('walks start -> bendPoints -> end when bend points are present', () => {
|
|
50
|
-
const e = edge({
|
|
51
|
-
sections: [
|
|
52
|
-
{
|
|
53
|
-
id: 's0',
|
|
54
|
-
startPoint: { x: 0, y: 0 },
|
|
55
|
-
endPoint: { x: 100, y: 0 },
|
|
56
|
-
bendPoints: [
|
|
57
|
-
{ x: 25, y: 50 },
|
|
58
|
-
{ x: 75, y: 50 },
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
})
|
|
63
|
-
expect(extractEdgePoints(e)).toEqual([
|
|
64
|
-
{ x: 0, y: 0 },
|
|
65
|
-
{ x: 25, y: 50 },
|
|
66
|
-
{ x: 75, y: 50 },
|
|
67
|
-
{ x: 100, y: 0 },
|
|
68
|
-
])
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('translates every point by offsetX/offsetY when provided', () => {
|
|
72
|
-
const e = edge({
|
|
73
|
-
sections: [
|
|
74
|
-
{
|
|
75
|
-
id: 's0',
|
|
76
|
-
startPoint: { x: 0, y: 0 },
|
|
77
|
-
endPoint: { x: 10, y: 10 },
|
|
78
|
-
bendPoints: [{ x: 5, y: 5 }],
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
})
|
|
82
|
-
expect(extractEdgePoints(e, 100, 200)).toEqual([
|
|
83
|
-
{ x: 100, y: 200 },
|
|
84
|
-
{ x: 105, y: 205 },
|
|
85
|
-
{ x: 110, y: 210 },
|
|
86
|
-
])
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('only reads the first section when multiple are present', () => {
|
|
90
|
-
const e = edge({
|
|
91
|
-
sections: [
|
|
92
|
-
{ id: 's0', startPoint: { x: 0, y: 0 }, endPoint: { x: 1, y: 1 } },
|
|
93
|
-
{ id: 's1', startPoint: { x: 9, y: 9 }, endPoint: { x: 8, y: 8 } },
|
|
94
|
-
],
|
|
95
|
-
})
|
|
96
|
-
expect(extractEdgePoints(e)).toEqual([
|
|
97
|
-
{ x: 0, y: 0 },
|
|
98
|
-
{ x: 1, y: 1 },
|
|
99
|
-
])
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
describe('extractEdgeLabelPosition', () => {
|
|
104
|
-
it('returns undefined when the edge has no labels property', () => {
|
|
105
|
-
expect(extractEdgeLabelPosition(edge({}))).toBeUndefined()
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('returns undefined when labels is an empty array', () => {
|
|
109
|
-
expect(extractEdgeLabelPosition(edge({ labels: [] }))).toBeUndefined()
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('returns undefined when the label has no x/y (ELK left it unplaced)', () => {
|
|
113
|
-
expect(
|
|
114
|
-
extractEdgeLabelPosition(edge({ labels: [{ text: 'foo' }] })),
|
|
115
|
-
).toBeUndefined()
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('returns undefined when only x is set (y still unplaced)', () => {
|
|
119
|
-
expect(
|
|
120
|
-
extractEdgeLabelPosition(edge({ labels: [{ text: 'foo', x: 5 }] })),
|
|
121
|
-
).toBeUndefined()
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('computes the label center, defaulting missing width/height to 0', () => {
|
|
125
|
-
expect(
|
|
126
|
-
extractEdgeLabelPosition(
|
|
127
|
-
edge({ labels: [{ text: 'foo', x: 10, y: 20 }] }),
|
|
128
|
-
),
|
|
129
|
-
).toEqual({ x: 10, y: 20 })
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('computes the label center from x/y/width/height', () => {
|
|
133
|
-
expect(
|
|
134
|
-
extractEdgeLabelPosition(
|
|
135
|
-
edge({
|
|
136
|
-
labels: [{ text: 'foo', x: 10, y: 20, width: 40, height: 10 }],
|
|
137
|
-
}),
|
|
138
|
-
),
|
|
139
|
-
).toEqual({ x: 30, y: 25 })
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('translates the computed center by offsetX/offsetY when provided', () => {
|
|
143
|
-
expect(
|
|
144
|
-
extractEdgeLabelPosition(
|
|
145
|
-
edge({
|
|
146
|
-
labels: [{ text: 'foo', x: 10, y: 20, width: 40, height: 10 }],
|
|
147
|
-
}),
|
|
148
|
-
100,
|
|
149
|
-
200,
|
|
150
|
-
),
|
|
151
|
-
).toEqual({ x: 130, y: 225 })
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('only reads the first label when multiple are present', () => {
|
|
155
|
-
expect(
|
|
156
|
-
extractEdgeLabelPosition(
|
|
157
|
-
edge({
|
|
158
|
-
labels: [
|
|
159
|
-
{ text: 'first', x: 0, y: 0 },
|
|
160
|
-
{ text: 'second', x: 100, y: 100 },
|
|
161
|
-
],
|
|
162
|
-
}),
|
|
163
|
-
),
|
|
164
|
-
).toEqual({ x: 0, y: 0 })
|
|
165
|
-
})
|
|
166
|
-
})
|