dsh-model-everything 0.5.0 → 0.5.1

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.
Files changed (62) hide show
  1. package/README.en-US.md +12 -0
  2. package/README.md +4 -0
  3. package/lib/client.js +2437 -216
  4. package/lib/render/channels.js +243 -0
  5. package/lib/render/collapse.js +12 -20
  6. package/lib/render/components.js +99 -0
  7. package/lib/render/coords.js +288 -0
  8. package/lib/render/cycle-break.js +147 -0
  9. package/lib/render/dummy.js +43 -0
  10. package/lib/render/from-mermaid.js +34 -10
  11. package/lib/render/from-plantuml.js +318 -46
  12. package/lib/render/layer.js +91 -0
  13. package/lib/render/layout.js +27 -11
  14. package/lib/render/network-simplex.js +272 -0
  15. package/lib/render/order.js +122 -0
  16. package/lib/render/paint.js +764 -67
  17. package/lib/render/place.js +393 -121
  18. package/lib/render/route.js +225 -0
  19. package/lib/render/svg.js +143 -21
  20. package/lib/render/symbol.js +108 -0
  21. package/lib/render/text.js +74 -0
  22. package/lib/render/wrap.js +87 -0
  23. package/lib/types/render/channels.d.ts +63 -0
  24. package/lib/types/render/components.d.ts +57 -0
  25. package/lib/types/render/coords.d.ts +64 -0
  26. package/lib/types/render/cycle-break.d.ts +45 -0
  27. package/lib/types/render/dummy.d.ts +32 -0
  28. package/lib/types/render/from-plantuml.d.ts +12 -6
  29. package/lib/types/render/layer.d.ts +28 -0
  30. package/lib/types/render/layout.d.ts +43 -11
  31. package/lib/types/render/model.d.ts +17 -0
  32. package/lib/types/render/network-simplex.d.ts +54 -0
  33. package/lib/types/render/order.d.ts +27 -0
  34. package/lib/types/render/paint.d.ts +42 -9
  35. package/lib/types/render/place.d.ts +35 -19
  36. package/lib/types/render/route.d.ts +77 -0
  37. package/lib/types/render/svg.d.ts +1 -1
  38. package/lib/types/render/symbol.d.ts +73 -0
  39. package/lib/types/render/text.d.ts +38 -0
  40. package/lib/types/render/wrap.d.ts +27 -0
  41. package/package.json +148 -148
  42. package/skills/model-everything-diagram/SKILL.md +84 -82
  43. package/src/render/channels.ts +309 -0
  44. package/src/render/collapse.ts +150 -155
  45. package/src/render/components.ts +126 -0
  46. package/src/render/coords.ts +328 -0
  47. package/src/render/cycle-break.ts +164 -0
  48. package/src/render/dummy.ts +65 -0
  49. package/src/render/from-mermaid.ts +261 -236
  50. package/src/render/from-plantuml.ts +469 -178
  51. package/src/render/layer.ts +98 -0
  52. package/src/render/layout.ts +101 -62
  53. package/src/render/model.ts +86 -67
  54. package/src/render/network-simplex.ts +290 -0
  55. package/src/render/order.ts +139 -0
  56. package/src/render/paint.ts +1006 -290
  57. package/src/render/place.ts +527 -234
  58. package/src/render/route.ts +269 -0
  59. package/src/render/svg.ts +270 -127
  60. package/src/render/symbol.ts +137 -0
  61. package/src/render/text.ts +86 -0
  62. package/src/render/wrap.ts +103 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Wrapping: turning one endless column into a page.
3
+ *
4
+ * A chain of twelve boxes has twelve layers, and layering alone draws it as a single column taller than anything a
5
+ * reader can take in - a strip, not a drawing. Graphviz and ELK both answer this with a wrapping pass: cut the layer
6
+ * sequence into bands and stand the bands side by side, so reading order becomes "down the page, then the next
7
+ * column", the way text wraps.
8
+ *
9
+ * The cut is chosen, not guessed: each candidate number of bands is scored by how close the packed page gets to the
10
+ * aspect ratio a page and a landscape screen share, and the best one wins. A drawing that is already close to that
11
+ * shape is left alone - wrapping exists for the strip, not for every tall drawing.
12
+ *
13
+ * Pure: layer sizes in, band ranges and offsets out. The caller applies them.
14
+ */
15
+
16
+ /** The aspect ratio a page and a landscape screen share. */
17
+ const PAGE_ASPECT = 1.6
18
+
19
+ /** A drawing shorter than this many layers is read better stacked, whatever its proportions. */
20
+ const MIN_LAYERS_TO_WRAP = 4
21
+
22
+ /** A drawing that is not this tall relative to its width is not a strip. */
23
+ const STRIP_RATIO = 2
24
+
25
+ export interface BandRange {
26
+ /** The first and last layer the band holds, inclusive. */
27
+ first: number
28
+ last: number
29
+ /** How far right the band stands, relative to the first one. */
30
+ offsetX: number
31
+ }
32
+
33
+ export interface BandPlan {
34
+ bands: BandRange[]
35
+ width: number
36
+ height: number
37
+ }
38
+
39
+ /** The height of a run of layers with the gap between them. */
40
+ function runHeight(layerHeight: number[], first: number, last: number, gap: number): number {
41
+ let total = 0
42
+ for (let index = first; index <= last; index += 1) {
43
+ total += layerHeight[index]
44
+ if (index < last) total += gap
45
+ }
46
+ return total
47
+ }
48
+
49
+ /** The width of a run of layers: the widest layer sets it. */
50
+ function runWidth(layerWidth: number[], first: number, last: number): number {
51
+ let widest = 0
52
+ for (let index = first; index <= last; index += 1) widest = Math.max(widest, layerWidth[index])
53
+ return widest
54
+ }
55
+
56
+ /** How far the packed page is from the target shape, in log space so half and double count the same. */
57
+ function shapeError(width: number, height: number, aspect: number): number {
58
+ if (width <= 0 || height <= 0) return Infinity
59
+ const ratio = Math.max(width, height) / Math.min(width, height)
60
+ return Math.abs(Math.log(ratio / aspect))
61
+ }
62
+
63
+ export function planBands(layerWidth: number[], layerHeight: number[], gap: number, aspect: number = PAGE_ASPECT): BandPlan {
64
+ const count = layerWidth.length
65
+ if (count === 0) return { bands: [], width: 0, height: 0 }
66
+ const single: BandPlan = {
67
+ bands: [{ first: 0, last: count - 1, offsetX: 0 }],
68
+ width: runWidth(layerWidth, 0, count - 1),
69
+ height: runHeight(layerHeight, 0, count - 1, gap),
70
+ }
71
+ if (count < MIN_LAYERS_TO_WRAP || single.height <= single.width * STRIP_RATIO) return single
72
+
73
+ const columnGap = gap * 2
74
+ let best = single
75
+ let bestError = shapeError(single.width, single.height, aspect)
76
+ for (let bands = 2; bands < count; bands += 1) {
77
+ const base = Math.floor(count / bands)
78
+ const extra = count % bands
79
+ const ranges: Array<{ first: number; last: number }> = []
80
+ let cursor = 0
81
+ for (let band = 0; band < bands; band += 1) {
82
+ const size = base + (band < extra ? 1 : 0)
83
+ ranges.push({ first: cursor, last: cursor + size - 1 })
84
+ cursor += size
85
+ }
86
+ let width = columnGap * (bands - 1)
87
+ let height = 0
88
+ for (const range of ranges) {
89
+ width += runWidth(layerWidth, range.first, range.last)
90
+ height = Math.max(height, runHeight(layerHeight, range.first, range.last, gap))
91
+ }
92
+ if (shapeError(width, height, aspect) >= bestError) continue
93
+ const planned: BandRange[] = []
94
+ let offsetX = 0
95
+ for (const range of ranges) {
96
+ planned.push({ first: range.first, last: range.last, offsetX })
97
+ offsetX += runWidth(layerWidth, range.first, range.last) + columnGap
98
+ }
99
+ best = { bands: planned, width, height }
100
+ bestError = shapeError(width, height, aspect)
101
+ }
102
+ return best
103
+ }