diff --git a/src/flowchart/flowchart-shapes.js b/src/flowchart/flowchart-shapes.js new file mode 100644 index 0000000..b6a5142 --- /dev/null +++ b/src/flowchart/flowchart-shapes.js @@ -0,0 +1,65 @@ +/** + * SVG shape templates for the 5 supported Mermaid flowchart node kinds. + * Each `shapeSvg` returns ONE SVG element string — the canvas wraps it in a + * alongside a label. + * + * Pure module: no DOM, no globals, no side effects. + * + * @module flowchart-shapes + */ + +'use strict'; + +const SHAPE_KINDS = ['process', 'decision', 'terminator', 'subroutine', 'document']; +const DEFAULT_WIDTH = 140; +const DEFAULT_HEIGHT = 60; +const LABEL_PADDING_X = 16; +const LABEL_PADDING_Y = 12; + +function shapeSvg(kind, x, y, width, height) { + if (!SHAPE_KINDS.includes(kind)) { + throw new Error(`flowchart-shapes: unknown shape kind "${kind}"`); + } + switch (kind) { + case 'process': + return ``; + case 'terminator': + return ``; + case 'subroutine': { + const inset = 4; + return ( + `` + + `` + ); + } + case 'decision': { + const cx = x + width / 2; + const cy = y + height / 2; + const left = `${x},${cy}`; + const top = `${cx},${y}`; + const right = `${x + width},${cy}`; + const bottom = `${cx},${y + height}`; + return ``; + } + case 'document': { + // Parallelogram: top-right and bottom-right indented by ~20% of height. + const skew = Math.max(10, Math.round(height * 0.25)); + const tl = `${x + skew},${y}`; + const tr = `${x + width},${y}`; + const br = `${x + width - skew},${y + height}`; + const bl = `${x},${y + height}`; + return ``; + } + default: + throw new Error(`flowchart-shapes: unknown shape kind "${kind}"`); + } +} + +module.exports = { + shapeSvg, + SHAPE_KINDS, + DEFAULT_WIDTH, + DEFAULT_HEIGHT, + LABEL_PADDING_X, + LABEL_PADDING_Y, +}; diff --git a/tests/flowchart-shapes.test.js b/tests/flowchart-shapes.test.js new file mode 100644 index 0000000..204b936 --- /dev/null +++ b/tests/flowchart-shapes.test.js @@ -0,0 +1,67 @@ +/** + * @jest-environment node + */ +const { + shapeSvg, + SHAPE_KINDS, + DEFAULT_WIDTH, + DEFAULT_HEIGHT, +} = require('../src/flowchart/flowchart-shapes'); + +describe('flowchart-shapes: shapeSvg', () => { + test('process emits a at the given coordinates', () => { + const svg = shapeSvg('process', 10, 20, 100, 50); + expect(svg).toMatch(/ diamond', () => { + const svg = shapeSvg('decision', 0, 0, 100, 60); + expect(svg).toMatch(/ with rx (stadium)', () => { + const svg = shapeSvg('terminator', 0, 0, 120, 40); + expect(svg).toMatch(/ { + expect(() => shapeSvg('hexagon', 0, 0, 100, 50)).toThrow(/hexagon/); + }); + + test('SHAPE_KINDS lists all 5 shapes', () => { + expect(SHAPE_KINDS.sort()).toEqual([ + 'decision', + 'document', + 'process', + 'subroutine', + 'terminator', + ]); + }); + + test('DEFAULT_WIDTH and DEFAULT_HEIGHT are positive numbers', () => { + expect(DEFAULT_WIDTH).toBeGreaterThan(0); + expect(DEFAULT_HEIGHT).toBeGreaterThan(0); + }); +});