@shumoku/core 0.1.1 → 0.2.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 (193) hide show
  1. package/dist/constants.d.ts +23 -0
  2. package/dist/constants.d.ts.map +1 -0
  3. package/dist/constants.js +25 -0
  4. package/dist/constants.js.map +1 -0
  5. package/dist/icons/build-icons.js +3 -3
  6. package/dist/icons/build-icons.js.map +1 -1
  7. package/dist/icons/generated-icons.js +10 -10
  8. package/dist/icons/generated-icons.js.map +1 -1
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +6 -6
  12. package/dist/index.js.map +1 -1
  13. package/dist/layout/hierarchical.d.ts +13 -40
  14. package/dist/layout/hierarchical.d.ts.map +1 -1
  15. package/dist/layout/hierarchical.js +726 -1028
  16. package/dist/layout/hierarchical.js.map +1 -1
  17. package/dist/layout/index.d.ts +1 -1
  18. package/dist/layout/index.d.ts.map +1 -1
  19. package/dist/layout/index.js.map +1 -1
  20. package/dist/models/types.d.ts +30 -0
  21. package/dist/models/types.d.ts.map +1 -1
  22. package/dist/models/types.js +13 -13
  23. package/dist/models/types.js.map +1 -1
  24. package/dist/themes/dark.d.ts.map +1 -1
  25. package/dist/themes/dark.js +1 -1
  26. package/dist/themes/dark.js.map +1 -1
  27. package/dist/themes/index.d.ts +3 -3
  28. package/dist/themes/index.d.ts.map +1 -1
  29. package/dist/themes/index.js +4 -4
  30. package/dist/themes/index.js.map +1 -1
  31. package/dist/themes/modern.d.ts.map +1 -1
  32. package/dist/themes/modern.js.map +1 -1
  33. package/dist/themes/types.d.ts.map +1 -1
  34. package/dist/themes/utils.d.ts +1 -1
  35. package/dist/themes/utils.d.ts.map +1 -1
  36. package/dist/themes/utils.js +5 -4
  37. package/dist/themes/utils.js.map +1 -1
  38. package/package.json +88 -92
  39. package/src/constants.ts +35 -0
  40. package/src/icons/build-icons.ts +12 -6
  41. package/src/icons/generated-icons.ts +12 -12
  42. package/src/index.test.ts +66 -0
  43. package/src/index.ts +6 -10
  44. package/src/layout/hierarchical.ts +1251 -1543
  45. package/src/layout/index.ts +1 -1
  46. package/src/models/types.ts +84 -37
  47. package/src/themes/dark.ts +15 -15
  48. package/src/themes/index.ts +7 -7
  49. package/src/themes/modern.ts +22 -22
  50. package/src/themes/types.ts +26 -26
  51. package/src/themes/utils.ts +25 -24
  52. package/dist/renderer/components/index.d.ts +0 -8
  53. package/dist/renderer/components/index.d.ts.map +0 -1
  54. package/dist/renderer/components/index.js +0 -8
  55. package/dist/renderer/components/index.js.map +0 -1
  56. package/dist/renderer/components/link-renderer.d.ts +0 -11
  57. package/dist/renderer/components/link-renderer.d.ts.map +0 -1
  58. package/dist/renderer/components/link-renderer.js +0 -340
  59. package/dist/renderer/components/link-renderer.js.map +0 -1
  60. package/dist/renderer/components/node-renderer.d.ts +0 -14
  61. package/dist/renderer/components/node-renderer.d.ts.map +0 -1
  62. package/dist/renderer/components/node-renderer.js +0 -242
  63. package/dist/renderer/components/node-renderer.js.map +0 -1
  64. package/dist/renderer/components/port-renderer.d.ts +0 -8
  65. package/dist/renderer/components/port-renderer.d.ts.map +0 -1
  66. package/dist/renderer/components/port-renderer.js +0 -85
  67. package/dist/renderer/components/port-renderer.js.map +0 -1
  68. package/dist/renderer/components/subgraph-renderer.d.ts +0 -13
  69. package/dist/renderer/components/subgraph-renderer.d.ts.map +0 -1
  70. package/dist/renderer/components/subgraph-renderer.js +0 -85
  71. package/dist/renderer/components/subgraph-renderer.js.map +0 -1
  72. package/dist/renderer/icon-registry/index.d.ts +0 -6
  73. package/dist/renderer/icon-registry/index.d.ts.map +0 -1
  74. package/dist/renderer/icon-registry/index.js +0 -5
  75. package/dist/renderer/icon-registry/index.js.map +0 -1
  76. package/dist/renderer/icon-registry/registry.d.ts +0 -25
  77. package/dist/renderer/icon-registry/registry.d.ts.map +0 -1
  78. package/dist/renderer/icon-registry/registry.js +0 -85
  79. package/dist/renderer/icon-registry/registry.js.map +0 -1
  80. package/dist/renderer/icon-registry/types.d.ts +0 -44
  81. package/dist/renderer/icon-registry/types.d.ts.map +0 -1
  82. package/dist/renderer/icon-registry/types.js +0 -5
  83. package/dist/renderer/icon-registry/types.js.map +0 -1
  84. package/dist/renderer/index.d.ts +0 -6
  85. package/dist/renderer/index.d.ts.map +0 -1
  86. package/dist/renderer/index.js +0 -5
  87. package/dist/renderer/index.js.map +0 -1
  88. package/dist/renderer/render-model/builder.d.ts +0 -43
  89. package/dist/renderer/render-model/builder.d.ts.map +0 -1
  90. package/dist/renderer/render-model/builder.js +0 -646
  91. package/dist/renderer/render-model/builder.js.map +0 -1
  92. package/dist/renderer/render-model/index.d.ts +0 -6
  93. package/dist/renderer/render-model/index.d.ts.map +0 -1
  94. package/dist/renderer/render-model/index.js +0 -5
  95. package/dist/renderer/render-model/index.js.map +0 -1
  96. package/dist/renderer/render-model/types.d.ts +0 -216
  97. package/dist/renderer/render-model/types.d.ts.map +0 -1
  98. package/dist/renderer/render-model/types.js +0 -6
  99. package/dist/renderer/render-model/types.js.map +0 -1
  100. package/dist/renderer/renderer-types.d.ts +0 -55
  101. package/dist/renderer/renderer-types.d.ts.map +0 -1
  102. package/dist/renderer/renderer-types.js +0 -5
  103. package/dist/renderer/renderer-types.js.map +0 -1
  104. package/dist/renderer/svg-builder.d.ts +0 -152
  105. package/dist/renderer/svg-builder.d.ts.map +0 -1
  106. package/dist/renderer/svg-builder.js +0 -176
  107. package/dist/renderer/svg-builder.js.map +0 -1
  108. package/dist/renderer/svg-dom/builders/defs.d.ts +0 -10
  109. package/dist/renderer/svg-dom/builders/defs.d.ts.map +0 -1
  110. package/dist/renderer/svg-dom/builders/defs.js +0 -82
  111. package/dist/renderer/svg-dom/builders/defs.js.map +0 -1
  112. package/dist/renderer/svg-dom/builders/index.d.ts +0 -9
  113. package/dist/renderer/svg-dom/builders/index.d.ts.map +0 -1
  114. package/dist/renderer/svg-dom/builders/index.js +0 -9
  115. package/dist/renderer/svg-dom/builders/index.js.map +0 -1
  116. package/dist/renderer/svg-dom/builders/link.d.ts +0 -18
  117. package/dist/renderer/svg-dom/builders/link.d.ts.map +0 -1
  118. package/dist/renderer/svg-dom/builders/link.js +0 -188
  119. package/dist/renderer/svg-dom/builders/link.js.map +0 -1
  120. package/dist/renderer/svg-dom/builders/node.d.ts +0 -15
  121. package/dist/renderer/svg-dom/builders/node.d.ts.map +0 -1
  122. package/dist/renderer/svg-dom/builders/node.js +0 -262
  123. package/dist/renderer/svg-dom/builders/node.js.map +0 -1
  124. package/dist/renderer/svg-dom/builders/subgraph.d.ts +0 -14
  125. package/dist/renderer/svg-dom/builders/subgraph.d.ts.map +0 -1
  126. package/dist/renderer/svg-dom/builders/subgraph.js +0 -63
  127. package/dist/renderer/svg-dom/builders/subgraph.js.map +0 -1
  128. package/dist/renderer/svg-dom/builders/utils.d.ts +0 -40
  129. package/dist/renderer/svg-dom/builders/utils.d.ts.map +0 -1
  130. package/dist/renderer/svg-dom/builders/utils.js +0 -79
  131. package/dist/renderer/svg-dom/builders/utils.js.map +0 -1
  132. package/dist/renderer/svg-dom/index.d.ts +0 -9
  133. package/dist/renderer/svg-dom/index.d.ts.map +0 -1
  134. package/dist/renderer/svg-dom/index.js +0 -7
  135. package/dist/renderer/svg-dom/index.js.map +0 -1
  136. package/dist/renderer/svg-dom/interaction.d.ts +0 -69
  137. package/dist/renderer/svg-dom/interaction.d.ts.map +0 -1
  138. package/dist/renderer/svg-dom/interaction.js +0 -296
  139. package/dist/renderer/svg-dom/interaction.js.map +0 -1
  140. package/dist/renderer/svg-dom/renderer.d.ts +0 -47
  141. package/dist/renderer/svg-dom/renderer.d.ts.map +0 -1
  142. package/dist/renderer/svg-dom/renderer.js +0 -188
  143. package/dist/renderer/svg-dom/renderer.js.map +0 -1
  144. package/dist/renderer/svg-string/builders/defs.d.ts +0 -10
  145. package/dist/renderer/svg-string/builders/defs.d.ts.map +0 -1
  146. package/dist/renderer/svg-string/builders/defs.js +0 -43
  147. package/dist/renderer/svg-string/builders/defs.js.map +0 -1
  148. package/dist/renderer/svg-string/builders/link.d.ts +0 -10
  149. package/dist/renderer/svg-string/builders/link.d.ts.map +0 -1
  150. package/dist/renderer/svg-string/builders/link.js +0 -149
  151. package/dist/renderer/svg-string/builders/link.js.map +0 -1
  152. package/dist/renderer/svg-string/builders/node.d.ts +0 -10
  153. package/dist/renderer/svg-string/builders/node.d.ts.map +0 -1
  154. package/dist/renderer/svg-string/builders/node.js +0 -134
  155. package/dist/renderer/svg-string/builders/node.js.map +0 -1
  156. package/dist/renderer/svg-string/builders/subgraph.d.ts +0 -10
  157. package/dist/renderer/svg-string/builders/subgraph.d.ts.map +0 -1
  158. package/dist/renderer/svg-string/builders/subgraph.js +0 -59
  159. package/dist/renderer/svg-string/builders/subgraph.js.map +0 -1
  160. package/dist/renderer/svg-string/index.d.ts +0 -5
  161. package/dist/renderer/svg-string/index.d.ts.map +0 -1
  162. package/dist/renderer/svg-string/index.js +0 -5
  163. package/dist/renderer/svg-string/index.js.map +0 -1
  164. package/dist/renderer/svg-string/renderer.d.ts +0 -17
  165. package/dist/renderer/svg-string/renderer.d.ts.map +0 -1
  166. package/dist/renderer/svg-string/renderer.js +0 -53
  167. package/dist/renderer/svg-string/renderer.js.map +0 -1
  168. package/dist/renderer/svg.d.ts +0 -105
  169. package/dist/renderer/svg.d.ts.map +0 -1
  170. package/dist/renderer/svg.js +0 -804
  171. package/dist/renderer/svg.js.map +0 -1
  172. package/dist/renderer/text-measurer/browser-measurer.d.ts +0 -25
  173. package/dist/renderer/text-measurer/browser-measurer.d.ts.map +0 -1
  174. package/dist/renderer/text-measurer/browser-measurer.js +0 -85
  175. package/dist/renderer/text-measurer/browser-measurer.js.map +0 -1
  176. package/dist/renderer/text-measurer/fallback-measurer.d.ts +0 -22
  177. package/dist/renderer/text-measurer/fallback-measurer.d.ts.map +0 -1
  178. package/dist/renderer/text-measurer/fallback-measurer.js +0 -113
  179. package/dist/renderer/text-measurer/fallback-measurer.js.map +0 -1
  180. package/dist/renderer/text-measurer/index.d.ts +0 -13
  181. package/dist/renderer/text-measurer/index.d.ts.map +0 -1
  182. package/dist/renderer/text-measurer/index.js +0 -35
  183. package/dist/renderer/text-measurer/index.js.map +0 -1
  184. package/dist/renderer/text-measurer/types.d.ts +0 -30
  185. package/dist/renderer/text-measurer/types.d.ts.map +0 -1
  186. package/dist/renderer/text-measurer/types.js +0 -5
  187. package/dist/renderer/text-measurer/types.js.map +0 -1
  188. package/dist/renderer/theme.d.ts +0 -29
  189. package/dist/renderer/theme.d.ts.map +0 -1
  190. package/dist/renderer/theme.js +0 -80
  191. package/dist/renderer/theme.js.map +0 -1
  192. package/src/renderer/index.ts +0 -6
  193. package/src/renderer/svg.ts +0 -997
package/package.json CHANGED
@@ -1,92 +1,88 @@
1
- {
2
- "name": "@shumoku/core",
3
- "version": "0.1.1",
4
- "description": "Core library for shumoku network topology visualization",
5
- "license": "MIT",
6
- "author": "konoe-akitoshi",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/konoe-akitoshi/shumoku.git",
10
- "directory": "packages/@shumoku/core"
11
- },
12
- "homepage": "https://shumoku.packof.me/",
13
- "bugs": {
14
- "url": "https://github.com/konoe-akitoshi/shumoku/issues"
15
- },
16
- "keywords": [
17
- "network",
18
- "topology",
19
- "diagram",
20
- "visualization",
21
- "svg"
22
- ],
23
- "type": "module",
24
- "main": "./dist/index.js",
25
- "module": "./dist/index.js",
26
- "types": "./dist/index.d.ts",
27
- "exports": {
28
- ".": {
29
- "types": "./dist/index.d.ts",
30
- "import": "./dist/index.js"
31
- },
32
- "./models": {
33
- "types": "./dist/models/index.d.ts",
34
- "import": "./dist/models/index.js"
35
- },
36
- "./parser": {
37
- "types": "./dist/parser/index.d.ts",
38
- "import": "./dist/parser/index.js"
39
- },
40
- "./layout": {
41
- "types": "./dist/layout/index.d.ts",
42
- "import": "./dist/layout/index.js"
43
- },
44
- "./renderer": {
45
- "types": "./dist/renderer/index.d.ts",
46
- "import": "./dist/renderer/index.js"
47
- },
48
- "./themes": {
49
- "types": "./dist/themes/index.d.ts",
50
- "import": "./dist/themes/index.js"
51
- },
52
- "./icons": {
53
- "types": "./dist/icons/index.d.ts",
54
- "import": "./dist/icons/index.js"
55
- }
56
- },
57
- "files": [
58
- "dist",
59
- "src"
60
- ],
61
- "scripts": {
62
- "build": "tsc",
63
- "dev": "tsc --watch",
64
- "test": "vitest",
65
- "typecheck": "tsc --noEmit",
66
- "lint": "biome check ."
67
- },
68
- "dependencies": {
69
- "elkjs": "^0.11.0",
70
- "pixi.js": "^8.5.2"
71
- },
72
- "devDependencies": {
73
- "@types/node": "^20.11.0",
74
- "typescript": "^5.6.3",
75
- "vitest": "^2.1.5"
76
- },
77
- "peerDependencies": {
78
- "@pixi/react": "^8.0.0",
79
- "react": "^18.0.0 || ^19.0.0"
80
- },
81
- "peerDependenciesMeta": {
82
- "@pixi/react": {
83
- "optional": true
84
- },
85
- "react": {
86
- "optional": true
87
- }
88
- },
89
- "publishConfig": {
90
- "access": "public"
91
- }
92
- }
1
+ {
2
+ "name": "@shumoku/core",
3
+ "version": "0.2.1",
4
+ "description": "Core library for shumoku network topology visualization",
5
+ "license": "MIT",
6
+ "author": "konoe-akitoshi",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/konoe-akitoshi/shumoku.git",
10
+ "directory": "packages/@shumoku/core"
11
+ },
12
+ "homepage": "https://shumoku.packof.me/",
13
+ "bugs": {
14
+ "url": "https://github.com/konoe-akitoshi/shumoku/issues"
15
+ },
16
+ "keywords": [
17
+ "network",
18
+ "topology",
19
+ "diagram",
20
+ "visualization",
21
+ "svg"
22
+ ],
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./models": {
33
+ "types": "./dist/models/index.d.ts",
34
+ "import": "./dist/models/index.js"
35
+ },
36
+ "./parser": {
37
+ "types": "./dist/parser/index.d.ts",
38
+ "import": "./dist/parser/index.js"
39
+ },
40
+ "./layout": {
41
+ "types": "./dist/layout/index.d.ts",
42
+ "import": "./dist/layout/index.js"
43
+ },
44
+ "./themes": {
45
+ "types": "./dist/themes/index.d.ts",
46
+ "import": "./dist/themes/index.js"
47
+ },
48
+ "./icons": {
49
+ "types": "./dist/icons/index.d.ts",
50
+ "import": "./dist/icons/index.js"
51
+ }
52
+ },
53
+ "files": [
54
+ "dist",
55
+ "src"
56
+ ],
57
+ "scripts": {
58
+ "build": "tsc",
59
+ "dev": "tsc --watch",
60
+ "test": "vitest --passWithNoTests",
61
+ "typecheck": "tsc --noEmit",
62
+ "lint": "biome check ."
63
+ },
64
+ "dependencies": {
65
+ "elkjs": "^0.11.0",
66
+ "pixi.js": "^8.5.2"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^25.0.7",
70
+ "typescript": "^5.6.3",
71
+ "vitest": "^4.0.17"
72
+ },
73
+ "peerDependencies": {
74
+ "@pixi/react": "^8.0.0",
75
+ "react": "^18.0.0 || ^19.0.0"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "@pixi/react": {
79
+ "optional": true
80
+ },
81
+ "react": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "publishConfig": {
86
+ "access": "public"
87
+ }
88
+ }
@@ -0,0 +1,35 @@
1
+ // Layout and rendering constants
2
+ // These values are shared between layout engines and renderers to ensure consistency
3
+
4
+ /** Default icon size in pixels (both width and height for square icons) */
5
+ export const DEFAULT_ICON_SIZE = 40
6
+
7
+ /** Gap between icon and label in pixels */
8
+ export const ICON_LABEL_GAP = 8
9
+
10
+ /** Line height for node labels in pixels */
11
+ export const LABEL_LINE_HEIGHT = 16
12
+
13
+ /** Vertical padding inside node box in pixels */
14
+ export const NODE_VERTICAL_PADDING = 16
15
+
16
+ /** Horizontal padding inside node box in pixels */
17
+ export const NODE_HORIZONTAL_PADDING = 16
18
+
19
+ /** Minimum spacing between ports in pixels (fallback when no labels) */
20
+ export const MIN_PORT_SPACING = 48
21
+
22
+ /** Port label font size in pixels */
23
+ export const PORT_LABEL_FONT_SIZE = 9
24
+
25
+ /** Character width ratio relative to font size (for proportional fonts ~0.55, monospace ~0.6) */
26
+ export const CHAR_WIDTH_RATIO = 0.55
27
+
28
+ /** Padding around port label for spacing calculation */
29
+ export const PORT_LABEL_PADDING = 16
30
+
31
+ /** Maximum icon width as percentage of node width (0.0 - 1.0) */
32
+ export const MAX_ICON_WIDTH_RATIO = 0.6
33
+
34
+ /** Estimated character width for node label width calculation (larger font) */
35
+ export const ESTIMATED_CHAR_WIDTH = 7
@@ -3,9 +3,9 @@
3
3
  * Run with: bun src/icons/build-icons.ts
4
4
  */
5
5
 
6
- import * as fs from 'fs'
7
- import * as path from 'path'
8
- import { fileURLToPath } from 'url'
6
+ import * as fs from 'node:fs'
7
+ import * as path from 'node:path'
8
+ import { fileURLToPath } from 'node:url'
9
9
 
10
10
  const __filename = fileURLToPath(import.meta.url)
11
11
  const __dirname = path.dirname(__filename)
@@ -111,7 +111,9 @@ function generateTypeScript(icons: Record<string, string>): string {
111
111
  lines.push('/**')
112
112
  lines.push(' * Register vendor icons (called by @shumoku/icons)')
113
113
  lines.push(' */')
114
- lines.push('export function registerVendorIcons(vendor: string, icons: Record<string, IconEntry>): void {')
114
+ lines.push(
115
+ 'export function registerVendorIcons(vendor: string, icons: Record<string, IconEntry>): void {',
116
+ )
115
117
  lines.push(' vendorIconRegistry[vendor] = icons')
116
118
  lines.push('}')
117
119
  lines.push('')
@@ -125,7 +127,9 @@ function generateTypeScript(icons: Record<string, string>): string {
125
127
  lines.push(' resource?: string')
126
128
  lines.push('): IconEntry | undefined {')
127
129
  lines.push(" if (vendor === 'default' || !vendor) {")
128
- lines.push(' const content = defaultIcons[service] || (resource ? defaultIcons[resource] : undefined)')
130
+ lines.push(
131
+ ' const content = defaultIcons[service] || (resource ? defaultIcons[resource] : undefined)',
132
+ )
129
133
  lines.push(' return content ? { default: content } : undefined')
130
134
  lines.push(' }')
131
135
  lines.push('')
@@ -135,7 +139,9 @@ function generateTypeScript(icons: Record<string, string>): string {
135
139
  lines.push(' const key = resource ? `${service}/${resource}` : service')
136
140
  lines.push(' const entry = vendorIcons[key]')
137
141
  lines.push(' if (!entry) {')
138
- lines.push(" const serviceKey = Object.keys(vendorIcons).find(k => k.startsWith(service + '/'))")
142
+ lines.push(
143
+ " const serviceKey = Object.keys(vendorIcons).find(k => k.startsWith(service + '/'))",
144
+ )
139
145
  lines.push(' if (serviceKey) return vendorIcons[serviceKey]')
140
146
  lines.push(' return undefined')
141
147
  lines.push(' }')
@@ -17,17 +17,17 @@ export interface IconEntry {
17
17
  // Default network device icons
18
18
  const defaultIcons: Record<string, string> = {
19
19
  'access-point': `<path d="M12 10a2 2 0 100 4 2 2 0 000-4zm-4.5-2.5a6.5 6.5 0 019 0l-1.4 1.4a4.5 4.5 0 00-6.2 0l-1.4-1.4zm-2.8-2.8a10 10 0 0114.6 0l-1.4 1.4a8 8 0 00-11.8 0L4.7 4.7z"/>`,
20
- 'cloud': `<path d="M19.4 10.6A7 7 0 006 12a5 5 0 00.7 9.9h11.8a4.5 4.5 0 00.9-8.9z"/>`,
21
- 'database': `<path d="M12 4c-4.4 0-8 1.3-8 3v10c0 1.7 3.6 3 8 3s8-1.3 8-3V7c0-1.7-3.6-3-8-3zm0 2c3.3 0 6 .9 6 2s-2.7 2-6 2-6-.9-6-2 2.7-2 6-2zM6 10.5c1.4.7 3.5 1 6 1s4.6-.3 6-1V12c0 1.1-2.7 2-6 2s-6-.9-6-2v-1.5zm0 4c1.4.7 3.5 1 6 1s4.6-.3 6-1V16c0 1.1-2.7 2-6 2s-6-.9-6-2v-1.5z"/>`,
22
- 'firewall': `<path d="M12 2L4 6v6c0 5.5 3.4 10.3 8 12 4.6-1.7 8-6.5 8-12V6l-8-4zm0 2.2l6 3v5.3c0 4.3-2.6 8.1-6 9.5-3.4-1.4-6-5.2-6-9.5V7.2l6-3z"/> <path d="M11 8h2v5h-2V8zm0 6h2v2h-2v-2z"/>`,
23
- 'generic': `<path d="M4 4h16v16H4V4zm2 2v12h12V6H6zm2 2h8v2H8V8zm0 4h8v2H8v-2z"/>`,
24
- 'internet': `<path d="M12 2a10 10 0 100 20 10 10 0 000-20zm0 2c.6 0 1.3.8 1.8 2H10.2c.5-1.2 1.2-2 1.8-2zm-3.2.7A8 8 0 005 10h2.5c.1-2 .5-3.7 1.3-5.3zm6.4 0c.8 1.6 1.2 3.3 1.3 5.3H19a8 8 0 00-3.8-5.3zM5 12h2.5c.1 2 .5 3.7 1.3 5.3A8 8 0 015 12zm4.5 0h5c0 1.5-.3 3-1 4h-3c-.7-1-1-2.5-1-4zm7 0H19a8 8 0 01-3.8 5.3c.8-1.6 1.2-3.3 1.3-5.3zM10.2 18h3.6c-.5 1.2-1.2 2-1.8 2s-1.3-.8-1.8-2z"/>`,
20
+ cloud: `<path d="M19.4 10.6A7 7 0 006 12a5 5 0 00.7 9.9h11.8a4.5 4.5 0 00.9-8.9z"/>`,
21
+ database: `<path d="M12 4c-4.4 0-8 1.3-8 3v10c0 1.7 3.6 3 8 3s8-1.3 8-3V7c0-1.7-3.6-3-8-3zm0 2c3.3 0 6 .9 6 2s-2.7 2-6 2-6-.9-6-2 2.7-2 6-2zM6 10.5c1.4.7 3.5 1 6 1s4.6-.3 6-1V12c0 1.1-2.7 2-6 2s-6-.9-6-2v-1.5zm0 4c1.4.7 3.5 1 6 1s4.6-.3 6-1V16c0 1.1-2.7 2-6 2s-6-.9-6-2v-1.5z"/>`,
22
+ firewall: `<path d="M12 2L4 6v6c0 5.5 3.4 10.3 8 12 4.6-1.7 8-6.5 8-12V6l-8-4zm0 2.2l6 3v5.3c0 4.3-2.6 8.1-6 9.5-3.4-1.4-6-5.2-6-9.5V7.2l6-3z"/> <path d="M11 8h2v5h-2V8zm0 6h2v2h-2v-2z"/>`,
23
+ generic: `<path d="M4 4h16v16H4V4zm2 2v12h12V6H6zm2 2h8v2H8V8zm0 4h8v2H8v-2z"/>`,
24
+ internet: `<path d="M12 2a10 10 0 100 20 10 10 0 000-20zm0 2c.6 0 1.3.8 1.8 2H10.2c.5-1.2 1.2-2 1.8-2zm-3.2.7A8 8 0 005 10h2.5c.1-2 .5-3.7 1.3-5.3zm6.4 0c.8 1.6 1.2 3.3 1.3 5.3H19a8 8 0 00-3.8-5.3zM5 12h2.5c.1 2 .5 3.7 1.3 5.3A8 8 0 015 12zm4.5 0h5c0 1.5-.3 3-1 4h-3c-.7-1-1-2.5-1-4zm7 0H19a8 8 0 01-3.8 5.3c.8-1.6 1.2-3.3 1.3-5.3zM10.2 18h3.6c-.5 1.2-1.2 2-1.8 2s-1.3-.8-1.8-2z"/>`,
25
25
  'l2-switch': `<path d="M3 8h18v8H3V8zm2 2v4h14v-4H5zm2 1h2v2H7v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2z"/>`,
26
26
  'l3-switch': `<path d="M3 6h18v12H3V6zm2 2v8h14V8H5zm2 2h4v1H7v-1zm6 0h4v1h-4v-1zm-6 3h4v1H7v-1zm6 0h4v1h-4v-1z"/>`,
27
27
  'load-balancer': `<path d="M12 4L4 8l8 4 8-4-8-4zm0 2.5L16 8l-4 2-4-2 4-1.5zM4 12l8 4 8-4v2l-8 4-8-4v-2zm0 4l8 4 8-4v2l-8 4-8-4v-2z"/>`,
28
- 'router': `<path d="M4 8h16v8H4V8zm2 2v4h12v-4H6zm1 1h2v2H7v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2z"/>`,
29
- 'server': `<path d="M4 4h16v4H4V4zm0 6h16v4H4v-4zm0 6h16v4H4v-4zm2-10v2h2V6H6zm0 6v2h2v-2H6zm0 6v2h2v-2H6zm10-12v2h2V6h-2zm0 6v2h2v-2h-2zm0 6v2h2v-2h-2z"/>`,
30
- 'vpn': `<path d="M12 2L4 5v6.5c0 5.3 3.4 10 8 11.5 4.6-1.5 8-6.2 8-11.5V5l-8-3zm0 4a3 3 0 110 6 3 3 0 010-6zm-4 8h8v1c0 2-1.8 3-4 3s-4-1-4-3v-1z"/>`,
28
+ router: `<path d="M4 8h16v8H4V8zm2 2v4h12v-4H6zm1 1h2v2H7v-2zm4 0h2v2h-2v-2zm4 0h2v2h-2v-2z"/>`,
29
+ server: `<path d="M4 4h16v4H4V4zm0 6h16v4H4v-4zm0 6h16v4H4v-4zm2-10v2h2V6H6zm0 6v2h2v-2H6zm0 6v2h2v-2H6zm10-12v2h2V6h-2zm0 6v2h2v-2h-2zm0 6v2h2v-2h-2z"/>`,
30
+ vpn: `<path d="M12 2L4 5v6.5c0 5.3 3.4 10 8 11.5 4.6-1.5 8-6.2 8-11.5V5l-8-3zm0 4a3 3 0 110 6 3 3 0 010-6zm-4 8h8v1c0 2-1.8 3-4 3s-4-1-4-3v-1z"/>`,
31
31
  }
32
32
 
33
33
  // Map DeviceType to icon key
@@ -57,7 +57,7 @@ export function getDeviceIcon(type?: DeviceType): string | undefined {
57
57
  }
58
58
 
59
59
  // Vendor icon registry (populated by @shumoku/icons if installed)
60
- let vendorIconRegistry: Record<string, Record<string, IconEntry>> = {}
60
+ const vendorIconRegistry: Record<string, Record<string, IconEntry>> = {}
61
61
 
62
62
  /**
63
63
  * Register vendor icons (called by @shumoku/icons)
@@ -72,7 +72,7 @@ export function registerVendorIcons(vendor: string, icons: Record<string, IconEn
72
72
  export function getVendorIconEntry(
73
73
  vendor: string,
74
74
  service: string,
75
- resource?: string
75
+ resource?: string,
76
76
  ): IconEntry | undefined {
77
77
  if (vendor === 'default' || !vendor) {
78
78
  const content = defaultIcons[service] || (resource ? defaultIcons[resource] : undefined)
@@ -85,7 +85,7 @@ export function getVendorIconEntry(
85
85
  const key = resource ? `${service}/${resource}` : service
86
86
  const entry = vendorIcons[key]
87
87
  if (!entry) {
88
- const serviceKey = Object.keys(vendorIcons).find(k => k.startsWith(service + '/'))
88
+ const serviceKey = Object.keys(vendorIcons).find((k) => k.startsWith(`${service}/`))
89
89
  if (serviceKey) return vendorIcons[serviceKey]
90
90
  return undefined
91
91
  }
@@ -99,7 +99,7 @@ export function getVendorIcon(
99
99
  vendor: string,
100
100
  service: string,
101
101
  resource?: string,
102
- theme: IconThemeVariant = 'default'
102
+ theme: IconThemeVariant = 'default',
103
103
  ): string | undefined {
104
104
  const entry = getVendorIconEntry(vendor, service, resource)
105
105
  if (!entry) return undefined
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { darkTheme, HierarchicalLayout, modernTheme, version } from './index.js'
3
+ import type { NetworkGraph } from './models/index.js'
4
+
5
+ describe('@shumoku/core', () => {
6
+ describe('exports', () => {
7
+ it('should export version', () => {
8
+ expect(version).toBeDefined()
9
+ })
10
+
11
+ it('should export HierarchicalLayout', () => {
12
+ expect(HierarchicalLayout).toBeDefined()
13
+ })
14
+
15
+ it('should export themes', () => {
16
+ expect(modernTheme).toBeDefined()
17
+ expect(darkTheme).toBeDefined()
18
+ })
19
+ })
20
+
21
+ describe('HierarchicalLayout', () => {
22
+ it('should create instance', () => {
23
+ const engine = new HierarchicalLayout()
24
+ expect(engine).toBeInstanceOf(HierarchicalLayout)
25
+ })
26
+
27
+ it('should layout empty graph', async () => {
28
+ const engine = new HierarchicalLayout()
29
+ const graph: NetworkGraph = {
30
+ nodes: [],
31
+ links: [],
32
+ }
33
+ const result = await engine.layout(graph)
34
+ expect(result).toBeDefined()
35
+ expect(result.nodes).toBeDefined()
36
+ expect(result.links).toBeDefined()
37
+ })
38
+
39
+ it('should layout graph with nodes only', async () => {
40
+ const engine = new HierarchicalLayout()
41
+ const graph: NetworkGraph = {
42
+ nodes: [
43
+ { id: 'router1', label: 'Router 1', type: 'router' },
44
+ { id: 'switch1', label: 'Switch 1', type: 'l2-switch' },
45
+ ],
46
+ links: [],
47
+ }
48
+ const result = await engine.layout(graph)
49
+ expect(result.nodes.size).toBe(2)
50
+ })
51
+ })
52
+
53
+ describe('themes', () => {
54
+ it('should have modernTheme with required properties', () => {
55
+ expect(modernTheme.name).toBeDefined()
56
+ expect(modernTheme.colors).toBeDefined()
57
+ expect(modernTheme.colors.background).toBeDefined()
58
+ })
59
+
60
+ it('should have darkTheme with required properties', () => {
61
+ expect(darkTheme.name).toBeDefined()
62
+ expect(darkTheme.colors).toBeDefined()
63
+ expect(darkTheme.colors.background).toBeDefined()
64
+ })
65
+ })
66
+ })
package/src/index.ts CHANGED
@@ -2,20 +2,16 @@
2
2
  * @shumoku/core - Network topology visualization core library
3
3
  */
4
4
 
5
- // Models
6
- export * from './models/index.js'
7
-
5
+ // Constants
6
+ export * from './constants.js'
7
+ // Icons
8
+ export * from './icons/index.js'
8
9
  // Layout
9
10
  export * from './layout/index.js'
10
-
11
+ // Models
12
+ export * from './models/index.js'
11
13
  // Themes
12
14
  export * from './themes/index.js'
13
15
 
14
- // Icons
15
- export * from './icons/index.js'
16
-
17
- // Renderer
18
- export * from './renderer/index.js'
19
-
20
16
  // Version
21
17
  export const version = '0.0.0'