symbiote-ui 0.3.0-alpha.4

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 (322) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +21 -0
  3. package/README.md +76 -0
  4. package/canvas/AutoLayout.js +731 -0
  5. package/canvas/Breadcrumb/Breadcrumb.css.js +75 -0
  6. package/canvas/Breadcrumb/Breadcrumb.js +96 -0
  7. package/canvas/Breadcrumb/Breadcrumb.tpl.js +7 -0
  8. package/canvas/CanvasConnectionRenderer.js +971 -0
  9. package/canvas/CanvasGraph/CanvasGraph.css.js +29 -0
  10. package/canvas/CanvasGraph/CanvasGraph.js +1697 -0
  11. package/canvas/CanvasGraph/CanvasGraphDrawState.js +280 -0
  12. package/canvas/CanvasGraph/CanvasGraphGeometry.js +194 -0
  13. package/canvas/CanvasViewport.js +550 -0
  14. package/canvas/ConnectionRenderer.js +1283 -0
  15. package/canvas/FlowSimulator.js +326 -0
  16. package/canvas/ForceLayout.js +226 -0
  17. package/canvas/ForceWorker.js +1303 -0
  18. package/canvas/FrameManager.js +223 -0
  19. package/canvas/GraphExplorerShell/GraphExplorerShell.css.js +136 -0
  20. package/canvas/GraphExplorerShell/GraphExplorerShell.js +129 -0
  21. package/canvas/GraphExplorerShell/GraphExplorerShell.tpl.js +12 -0
  22. package/canvas/GraphTabs/GraphTabs.css.js +101 -0
  23. package/canvas/GraphTabs/GraphTabs.js +189 -0
  24. package/canvas/GraphTabs/GraphTabs.tpl.js +12 -0
  25. package/canvas/LODManager.js +88 -0
  26. package/canvas/Minimap/Minimap.css.js +73 -0
  27. package/canvas/Minimap/Minimap.js +210 -0
  28. package/canvas/Minimap/Minimap.tpl.js +7 -0
  29. package/canvas/NodeCanvas/NodeCanvas.css.js +398 -0
  30. package/canvas/NodeCanvas/NodeCanvas.js +1499 -0
  31. package/canvas/NodeCanvas/NodeCanvas.tpl.js +22 -0
  32. package/canvas/NodeSearch/NodeSearch.css.js +97 -0
  33. package/canvas/NodeSearch/NodeSearch.js +140 -0
  34. package/canvas/NodeSearch/NodeSearch.tpl.js +25 -0
  35. package/canvas/NodeViewManager.js +748 -0
  36. package/canvas/PcbRouteDiagnostics.js +463 -0
  37. package/canvas/PcbRouter.js +1127 -0
  38. package/canvas/PinExpansion.js +134 -0
  39. package/canvas/PseudoConnection.js +84 -0
  40. package/canvas/SelectionSync.js +163 -0
  41. package/canvas/SubgraphManager.js +203 -0
  42. package/canvas/SubgraphRouter.js +452 -0
  43. package/canvas/ViewportActions.js +473 -0
  44. package/canvas/graph-explorer.js +339 -0
  45. package/canvas/graph-layout.js +148 -0
  46. package/canvas/graph-model.js +68 -0
  47. package/canvas/html-in-canvas.js +202 -0
  48. package/canvas/project-graph-builder.js +440 -0
  49. package/canvas/project-graph-model.js +183 -0
  50. package/chat/ChatComposer/ChatComposer.css.js +652 -0
  51. package/chat/ChatComposer/ChatComposer.js +304 -0
  52. package/chat/ChatList/ChatList.css.js +102 -0
  53. package/chat/ChatList/ChatList.js +99 -0
  54. package/chat/ChatList/ChatList.tpl.js +20 -0
  55. package/chat/ChatListItem/ChatListItem.css.js +117 -0
  56. package/chat/ChatListItem/ChatListItem.js +32 -0
  57. package/chat/ChatListItem/ChatListItem.tpl.js +17 -0
  58. package/chat/ChatMessageItem/ChatMessageItem.css.js +628 -0
  59. package/chat/ChatMessageItem/ChatMessageItem.js +156 -0
  60. package/chat/ChatSidebar/ChatSidebar.css.js +150 -0
  61. package/chat/ChatSidebar/ChatSidebar.js +230 -0
  62. package/chat/ChatSidebar/ChatSidebar.tpl.js +18 -0
  63. package/chat/ChatSidebar/constants.js +11 -0
  64. package/chat/ChatSidebarItem/ChatSidebarItem.css.js +445 -0
  65. package/chat/ChatSidebarItem/ChatSidebarItem.js +304 -0
  66. package/chat/ChatTranscript/ChatTranscript.css.js +90 -0
  67. package/chat/ChatTranscript/ChatTranscript.js +244 -0
  68. package/chat/chat-context.js +123 -0
  69. package/chat/message-model.js +156 -0
  70. package/cli.js +20 -0
  71. package/control/Button/Button.css.js +93 -0
  72. package/control/Button/Button.js +78 -0
  73. package/control/Button/Button.tpl.js +3 -0
  74. package/control/Field/Field.css.js +91 -0
  75. package/control/Field/Field.js +17 -0
  76. package/control/Field/Field.tpl.js +3 -0
  77. package/core/Connection.js +47 -0
  78. package/core/Editor.js +449 -0
  79. package/core/Frame.js +33 -0
  80. package/core/GraphMermaid.js +348 -0
  81. package/core/GraphText.js +228 -0
  82. package/core/Node.js +145 -0
  83. package/core/Portal.js +106 -0
  84. package/core/Socket.js +187 -0
  85. package/core/SubgraphNode.js +121 -0
  86. package/core/base-path.js +55 -0
  87. package/core/dom-utils.js +14 -0
  88. package/core/index.js +18 -0
  89. package/core/local-cache.js +26 -0
  90. package/core/state-sync.js +227 -0
  91. package/custom-elements.json +6380 -0
  92. package/discover.js +240 -0
  93. package/display/Badge/Badge.css.js +44 -0
  94. package/display/Badge/Badge.js +17 -0
  95. package/display/Badge/Badge.tpl.js +3 -0
  96. package/display/Banner/Banner.css.js +61 -0
  97. package/display/Banner/Banner.js +17 -0
  98. package/display/Banner/Banner.tpl.js +3 -0
  99. package/display/CodeBlock/CodeBlock.css.js +194 -0
  100. package/display/CodeBlock/CodeBlock.js +220 -0
  101. package/display/CodeBlock/CodeBlock.tpl.js +11 -0
  102. package/display/DataTable/DataTable.css.js +101 -0
  103. package/display/DataTable/DataTable.js +136 -0
  104. package/display/DataTable/DataTable.tpl.js +13 -0
  105. package/display/EmptyState/EmptyState.css.js +33 -0
  106. package/display/EmptyState/EmptyState.js +17 -0
  107. package/display/EmptyState/EmptyState.tpl.js +3 -0
  108. package/display/EventFeed/EventFeed.css.js +145 -0
  109. package/display/EventFeed/EventFeed.js +64 -0
  110. package/display/EventFeed/EventFeed.tpl.js +14 -0
  111. package/display/EventFeed/EventFeedItem.js +116 -0
  112. package/display/EventFeed/EventFeedItem.tpl.js +22 -0
  113. package/display/LoadingOverlay/LoadingOverlay.css.js +91 -0
  114. package/display/LoadingOverlay/LoadingOverlay.js +48 -0
  115. package/display/LoadingOverlay/LoadingOverlay.tpl.js +12 -0
  116. package/display/Metric/Metric.css.js +60 -0
  117. package/display/Metric/Metric.js +17 -0
  118. package/display/Metric/Metric.tpl.js +6 -0
  119. package/display/OutputGraphPreview/OutputGraphPreview.css.js +122 -0
  120. package/display/OutputGraphPreview/OutputGraphPreview.js +89 -0
  121. package/display/OutputGraphPreview/OutputGraphPreview.tpl.js +13 -0
  122. package/display/OutputListPreview/OutputListPreview.css.js +109 -0
  123. package/display/OutputListPreview/OutputListPreview.js +77 -0
  124. package/display/OutputListPreview/OutputListPreview.tpl.js +13 -0
  125. package/display/SourceEditor/SourceEditor.css.js +39 -0
  126. package/display/SourceEditor/SourceEditor.js +129 -0
  127. package/display/SourceEditor/SourceEditor.tpl.js +10 -0
  128. package/display/SourceViewer/SourceViewer.css.js +80 -0
  129. package/display/SourceViewer/SourceViewer.js +418 -0
  130. package/display/SourceViewer/SourceViewer.tpl.js +17 -0
  131. package/display/StatusRibbon/StatusRibbon.css.js +73 -0
  132. package/display/StatusRibbon/StatusRibbon.js +87 -0
  133. package/display/StatusRibbon/StatusRibbon.tpl.js +7 -0
  134. package/display/event-feed-adapter.js +72 -0
  135. package/display/format-utils.js +29 -0
  136. package/display/highlight.js +659 -0
  137. package/display/icons.js +37 -0
  138. package/display/markdown-formatter.js +60 -0
  139. package/display/network-approval-page.js +487 -0
  140. package/display/output-preview.js +261 -0
  141. package/effects/CellBg/CellBg.css.js +33 -0
  142. package/effects/CellBg/CellBg.js +410 -0
  143. package/effects/CellBg/CellBg.tpl.js +5 -0
  144. package/graph/canvas-adapter.js +223 -0
  145. package/graph/graph-algorithms.js +31 -0
  146. package/graph/index.js +46 -0
  147. package/graph/model.js +176 -0
  148. package/graph/project-graph-build.js +66 -0
  149. package/graph/project-graph-metadata.js +253 -0
  150. package/graph/project-package.js +128 -0
  151. package/graph/project-runtime.js +116 -0
  152. package/graph/project-transaction.js +284 -0
  153. package/graph/skeleton-utils.js +84 -0
  154. package/graph/theme-contract.js +36 -0
  155. package/graph/transaction-parser.js +56 -0
  156. package/icons/MaterialSymbols.js +69 -0
  157. package/icons/material-symbols-outlined-400.ttf +0 -0
  158. package/icons/material-symbols.css +24 -0
  159. package/index.js +95 -0
  160. package/inspector/InspectorPanel/InspectorPanel.css.js +375 -0
  161. package/inspector/InspectorPanel/InspectorPanel.js +368 -0
  162. package/inspector/InspectorPanel/InspectorPanel.tpl.js +96 -0
  163. package/inspector/TemplatePreview/TemplatePreview.css.js +104 -0
  164. package/inspector/TemplatePreview/TemplatePreview.js +145 -0
  165. package/inspector/TemplatePreview/TemplatePreview.tpl.js +33 -0
  166. package/interactions/ConnectFlow.js +304 -0
  167. package/interactions/Drag.js +104 -0
  168. package/interactions/Selector.js +133 -0
  169. package/interactions/SnapGrid.js +66 -0
  170. package/interactions/Zoom.js +139 -0
  171. package/layout/ActionZone/ActionZone.css.js +88 -0
  172. package/layout/ActionZone/ActionZone.js +261 -0
  173. package/layout/ActionZone/ActionZone.tpl.js +11 -0
  174. package/layout/CrossLayoutPortalBridge/CrossLayoutPortalBridge.js +255 -0
  175. package/layout/Layout/Layout.css.js +91 -0
  176. package/layout/Layout/Layout.js +637 -0
  177. package/layout/Layout/Layout.tpl.js +27 -0
  178. package/layout/LayoutNode/LayoutNode.css.js +302 -0
  179. package/layout/LayoutNode/LayoutNode.js +509 -0
  180. package/layout/LayoutNode/LayoutNode.tpl.js +39 -0
  181. package/layout/LayoutPreview/LayoutPreview.css.js +46 -0
  182. package/layout/LayoutPreview/LayoutPreview.js +102 -0
  183. package/layout/LayoutPreview/LayoutPreview.tpl.js +6 -0
  184. package/layout/LayoutRouter/LayoutRouter.js +274 -0
  185. package/layout/LayoutRouter/SectionRegistry.js +135 -0
  186. package/layout/LayoutRouter/routerSync.js +250 -0
  187. package/layout/LayoutSidebar/LayoutSidebar.css.js +411 -0
  188. package/layout/LayoutSidebar/LayoutSidebar.js +368 -0
  189. package/layout/LayoutSidebar/LayoutSidebar.tpl.js +26 -0
  190. package/layout/LayoutSidebar/SidebarSection.css.js +20 -0
  191. package/layout/LayoutSidebar/SidebarSection.js +184 -0
  192. package/layout/LayoutSidebar/SidebarSection.tpl.js +22 -0
  193. package/layout/LayoutTree.js +373 -0
  194. package/layout/PanelMenu/PanelMenu.css.js +43 -0
  195. package/layout/PanelMenu/PanelMenu.js +95 -0
  196. package/layout/PanelMenu/PanelMenu.tpl.js +17 -0
  197. package/layout/ProjectTabs/ProjectTabs.css.js +188 -0
  198. package/layout/ProjectTabs/ProjectTabs.js +77 -0
  199. package/layout/ProjectTabs/ProjectTabs.tpl.js +15 -0
  200. package/layout/index.js +40 -0
  201. package/list/ListDetailShell/ListDetailShell.css.js +128 -0
  202. package/list/ListDetailShell/ListDetailShell.js +72 -0
  203. package/list/ListDetailShell/ListDetailShell.tpl.js +36 -0
  204. package/list/ListItem/ListItem.css.js +111 -0
  205. package/list/ListItem/ListItem.js +66 -0
  206. package/list/ListItem/ListItem.tpl.js +18 -0
  207. package/locale/index.js +503 -0
  208. package/manifest/component-registry.js +2446 -0
  209. package/manifest/graph-schema.js +285 -0
  210. package/manifest/index.js +6 -0
  211. package/manifest/project-schema-catalog.js +246 -0
  212. package/manifest/rule-catalog.js +201 -0
  213. package/manifest/theme-catalog.js +2149 -0
  214. package/manifest/ui-schema-catalog.js +334 -0
  215. package/menu/ContextMenu/ContextMenu.css.js +61 -0
  216. package/menu/ContextMenu/ContextMenu.js +82 -0
  217. package/menu/ContextMenu/ContextMenu.tpl.js +19 -0
  218. package/navigation/QuickOpen/QuickOpen.css.js +92 -0
  219. package/navigation/QuickOpen/QuickOpen.js +185 -0
  220. package/navigation/QuickOpen/QuickOpen.tpl.js +15 -0
  221. package/navigation/quick-open-utils.js +101 -0
  222. package/node/CtrlItem/CtrlItem.css.js +41 -0
  223. package/node/CtrlItem/CtrlItem.js +24 -0
  224. package/node/CtrlItem/CtrlItem.tpl.js +17 -0
  225. package/node/GraphFrame/GraphFrame.css.js +66 -0
  226. package/node/GraphFrame/GraphFrame.js +32 -0
  227. package/node/GraphFrame/GraphFrame.tpl.js +13 -0
  228. package/node/GraphNode/GraphNode.css.js +815 -0
  229. package/node/GraphNode/GraphNode.js +173 -0
  230. package/node/GraphNode/GraphNode.tpl.js +33 -0
  231. package/node/NodeCallout/NodeCallout.css.js +91 -0
  232. package/node/NodeCallout/NodeCallout.js +281 -0
  233. package/node/NodeCallout/NodeCallout.tpl.js +8 -0
  234. package/node/NodeSocket/NodeSocket.css.js +68 -0
  235. package/node/NodeSocket/NodeSocket.js +26 -0
  236. package/node/NodeSocket/NodeSocket.tpl.js +7 -0
  237. package/node/PortItem/PortItem.css.js +93 -0
  238. package/node/PortItem/PortItem.js +87 -0
  239. package/node/PortItem/PortItem.tpl.js +10 -0
  240. package/package.json +165 -0
  241. package/palette/PaletteBrowser/PaletteBrowser.css.js +143 -0
  242. package/palette/PaletteBrowser/PaletteBrowser.js +152 -0
  243. package/palette/PaletteBrowser/PaletteBrowser.tpl.js +23 -0
  244. package/plugins/History.js +408 -0
  245. package/plugins/Readonly.js +60 -0
  246. package/rules/symbiote-3x.json +170 -0
  247. package/schemas/component-descriptor-v1.json +91 -0
  248. package/schemas/component-descriptor-v2.json +145 -0
  249. package/schemas/graph-model-v1.json +179 -0
  250. package/schemas/graph-v1.json +91 -0
  251. package/schemas/project-package-v1.json +102 -0
  252. package/schemas/project-transaction-v1.json +114 -0
  253. package/schemas/runtime-ui-v1.json +80 -0
  254. package/schemas/theme-rule-block-v1.json +73 -0
  255. package/shapes/CircleShape.js +79 -0
  256. package/shapes/CommentShape.js +35 -0
  257. package/shapes/DiamondShape.js +130 -0
  258. package/shapes/NodeShape.js +79 -0
  259. package/shapes/PillShape.js +91 -0
  260. package/shapes/RectShape.js +84 -0
  261. package/shapes/SVGShape.js +525 -0
  262. package/shapes/index.js +63 -0
  263. package/surface/Card/Card.css.js +57 -0
  264. package/surface/Card/Card.js +17 -0
  265. package/surface/Card/Card.tpl.js +3 -0
  266. package/themes/Palette.js +30 -0
  267. package/themes/Skin.js +113 -0
  268. package/themes/Theme.js +82 -0
  269. package/themes/carbon.js +135 -0
  270. package/themes/dark.js +140 -0
  271. package/themes/default-dark.js +714 -0
  272. package/themes/default-provider.css +635 -0
  273. package/themes/default-provider.js +718 -0
  274. package/themes/ebook.js +136 -0
  275. package/themes/grey.js +137 -0
  276. package/themes/light.js +139 -0
  277. package/themes/neon.js +138 -0
  278. package/themes/pcb.js +273 -0
  279. package/themes/synthwave.js +138 -0
  280. package/tokens/base.json +29 -0
  281. package/tokens/themes/carbon.json +11 -0
  282. package/tokens/themes/dark.json +12 -0
  283. package/tokens/themes/default-dark.json +1543 -0
  284. package/tokens/themes/default-provider.json +1543 -0
  285. package/tokens/themes/ebook.json +11 -0
  286. package/tokens/themes/grey.json +11 -0
  287. package/tokens/themes/light.json +12 -0
  288. package/tokens/themes/neon.json +11 -0
  289. package/tokens/themes/pcb.json +11 -0
  290. package/tokens/themes/synthwave.json +11 -0
  291. package/toolbar/QuickToolbar/QuickToolbar.css.js +152 -0
  292. package/toolbar/QuickToolbar/QuickToolbar.js +529 -0
  293. package/toolbar/QuickToolbar/QuickToolbar.tpl.js +34 -0
  294. package/tree/TreePanel/TreePanel.css.js +112 -0
  295. package/tree/TreePanel/TreePanel.js +147 -0
  296. package/tree/TreePanel/TreePanel.tpl.js +18 -0
  297. package/tree/TreeView/TreeView.css.js +122 -0
  298. package/tree/TreeView/TreeView.js +365 -0
  299. package/tree/TreeView/TreeView.tpl.js +10 -0
  300. package/ui/dialogs.js +221 -0
  301. package/ui/host-adapters.js +114 -0
  302. package/ui/index.js +660 -0
  303. package/ui/locale.js +50 -0
  304. package/ui/overlay-stack.js +89 -0
  305. package/ui/shared-styles.js +26 -0
  306. package/webmcp.js +37 -0
  307. package/xr/deep-graph.js +646 -0
  308. package/xr/emulation.js +198 -0
  309. package/xr/gesture.js +228 -0
  310. package/xr/html-canvas-renderer.js +472 -0
  311. package/xr/index.js +15 -0
  312. package/xr/layout-projection.js +1046 -0
  313. package/xr/panel-frame.js +128 -0
  314. package/xr/panel-host.js +267 -0
  315. package/xr/pointer.js +258 -0
  316. package/xr/scene-controller.js +242 -0
  317. package/xr/spatial-scene.js +212 -0
  318. package/xr/theme-bridge.js +105 -0
  319. package/xr/three-webxr-adapter.js +3439 -0
  320. package/xr/webgl-layer-renderer.js +419 -0
  321. package/xr/webxr.js +679 -0
  322. package/xr/workbench.js +516 -0
@@ -0,0 +1,659 @@
1
+ const t=new Set(["async","await","break","case","catch","class","const","continue","debugger","default","delete","do","else","export","extends","finally","for","from","function","if","import","in","instanceof","let","new","of","return","super","switch","this","throw","try","typeof","var","void","while","with","yield","static","get","set"]),n=new Set(["true","false","null","undefined","NaN","Infinity"]),s=new Set(["console","document","window","global","process","module","require","Promise","Array","Object","String","Number","Boolean","Map","Set","WeakMap","WeakSet","Symbol","RegExp","Error","JSON","Math","Date","parseInt","parseFloat","setTimeout","setInterval","clearTimeout","clearInterval","fetch","URL","Buffer","EventTarget","CustomEvent","HTMLElement","requestAnimationFrame","queueMicrotask"]);function e(t){return"&"===t?"&amp;":"<"===t?"&lt;":">"===t?"&gt;":t}
2
+ export function highlight(i){const l=[],f=i.length;
3
+ let h=0;for(;h<f;){const g=i[h];if("/"===g&&"/"===i[h+1]){const t=h;for(;h<f&&"\n"!==i[h];)h++;l.push(`<span class="t-cm">${a(i,t,h)}</span>`);continue}if("/"===g&&"*"===i[h+1]){const t=h;for(h+=2;h<f&&("*"!==i[h]||"/"!==i[h+1]);)h++;if(h<f-1)h+=2;else h=f;
4
+ const n=i.substring(t,h);n.startsWith("/**")?l.push(u(n)):l.push(`<span class="t-cm">${a(i,t,h)}</span>`);continue}if("/"===g&&h+1<f&&"*"!==i[h+1]&&"/"!==i[h+1]){
5
+ let isRegex = false;
6
+ let prev = h - 1;
7
+ while(prev >= 0 && (i[prev]===" "||i[prev]==="\t"||i[prev]==="\n")) prev--;
8
+ if (prev < 0 || "=([{;:,!?&|<>+-*%~/^".includes(i[prev])) isRegex = true;
9
+ if (isRegex) {
10
+ const t=h;
11
+ for(h++;h<f&&"\n"!==i[h]&&"/"!==i[h];){
12
+ "\\"===i[h]&&h++;
13
+ h++;
14
+ }
15
+ if(h<f&&"/"===i[h]){
16
+ h++;
17
+ while(h<f&&c(i[h])) h++;
18
+ }
19
+ l.push(`<span class="t-str">${a(i,t,h)}</span>`);
20
+ continue;
21
+ }
22
+ }
23
+ if("'"===g||'"'===g){const t=h;for(h++;h<f&&i[h]!==g;)"\\"===i[h]&&h++,h++;if(h<f)h++;l.push(`<span class="t-str">${a(i,t,h)}</span>`);continue}if("`"===g){const t=h;for(h++;h<f&&"`"!==i[h];)"\\"===i[h]&&h++,h++;if(h<f)h++;l.push(highlightTemplateLiteral(i.substring(t,h)));continue}if(r(g)||"."===g&&h+1<f&&r(i[h+1])){const t=h;if("0"!==g||"x"!==i[h+1]&&"X"!==i[h+1])for(;h<f&&(r(i[h])||"."===i[h]||"e"===i[h]||"E"===i[h]||"_"===i[h]);)h++;else for(h+=2;h<f&&o(i[h]);)h++;h<f&&"n"===i[h]&&h++,l.push(`<span class="t-num">${a(i,t,h)}</span>`);continue}if(c(g)){const g=h;for(;h<f&&p(i[h]);)h++;
24
+ const m=i.substring(g,h);
25
+ let d=h;for(;d<f&&" "===i[d];)d++;t.has(m)?l.push(`<span class="t-kw">${m}</span>`):n.has(m)?l.push(`<span class="t-lit">${m}</span>`):s.has(m)?l.push(`<span class="t-bi">${m}</span>`):"("===i[d]?l.push(`<span class="t-fn">${m}</span>`):g>0&&"."===i[g-1]?l.push(`<span class="t-prop">${m}</span>`):l.push(m);continue}l.push(e(g)),h++}return l.join("")}
26
+ function a(t,n,s){let i="";for(let l=n;l<s;l++)i+=e(t[l]);return i}
27
+ function r(t){return t>="0"&&t<="9"}
28
+ function o(t){return r(t)||t>="a"&&t<="f"||t>="A"&&t<="F"}
29
+ function c(t){return t>="a"&&t<="z"||t>="A"&&t<="Z"||"_"===t||"$"===t}
30
+ function p(t){return c(t)||r(t)}
31
+ function u(t){return'<span class="t-jd">'+t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/(@\w+)/g,'<span class="t-jd-tag">$1</span>').replace(/\{([^}]+)\}/g,'<span class="t-jd-type">{$1}</span>')+"</span>"}
32
+
33
+ /**
34
+ * @param {string} raw
35
+ * @returns {string}
36
+ */
37
+ function highlightTemplateLiteral(raw) {
38
+ const inner = raw.slice(1, -1); // strip backticks
39
+ const escaped = inner.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
40
+
41
+ const hasHtmlTags = /<[a-zA-Z]/.test(inner);
42
+ const hasCssProps = /[{;]\s*[\w-]+\s*:/.test(inner) || /^\s*[\w.#&:\[\]>~+*-]+\s*\{/m.test(inner);
43
+
44
+ let highlighted;
45
+ if (hasHtmlTags) {
46
+ highlighted = highlightTemplateHtml(escaped);
47
+ } else if (hasCssProps) {
48
+ highlighted = highlightTemplateCss(escaped);
49
+ } else {
50
+ // Fallback: plain string with ${} interpolation highlighting
51
+ highlighted = escaped.replace(/\$\{([^}]*)\}/g, '<span class="t-tl-interp">${$1}</span>');
52
+ }
53
+
54
+ return '<span class="t-tl">`' + highlighted + '`</span>';
55
+ }
56
+
57
+ /**
58
+ * @param {string} html
59
+ * @returns {string}
60
+ */
61
+ function highlightTemplateHtml(html) {
62
+ return html
63
+ // ${...} interpolations
64
+ .replace(/\$\{([^}]*)\}/g, '<span class="t-tl-interp">${$1}</span>')
65
+ // HTML tags with attributes
66
+ .replace(/(&lt;\/?)([\w-]*)((?:\s+[^&]*?)?)(\/?\s*&gt;)/g, (_, open, tag, attrs, close) => {
67
+ let attrHtml = attrs;
68
+ if (attrs) {
69
+ // Highlight attribute names and values
70
+ attrHtml = attrs
71
+ .replace(/([\w-]+)(=)(&quot;[^&]*?&quot;|&#39;[^&]*?&#39;|"[^"]*"|'[^']*')/g,
72
+ '<span class="t-tl-attr">$1</span>$2<span class="t-str">$3</span>')
73
+ .replace(/\s([\w-]+)(?=[\s\/&]|$)/g, ' <span class="t-tl-attr">$1</span>');
74
+ }
75
+ return `<span class="t-tl-bracket">${open}</span><span class="t-tl-tag">${tag}</span>${attrHtml}<span class="t-tl-bracket">${close}</span>`;
76
+ })
77
+ // HTML comments
78
+ .replace(/(&lt;!--[\s\S]*?--&gt;)/g, '<span class="t-cm">$1</span>');
79
+ }
80
+
81
+ /**
82
+ * @param {string} css
83
+ * @returns {string}
84
+ */
85
+ function highlightTemplateCss(css) {
86
+ return css
87
+ // ${...} interpolations
88
+ .replace(/\$\{([^}]*)\}/g, '<span class="t-tl-interp">${$1}</span>')
89
+ // CSS comments
90
+ .replace(/(\/\*[\s\S]*?\*\/)/g, '<span class="t-cm">$1</span>')
91
+ // CSS selectors (lines ending with {)
92
+ .replace(/^(\s*)([\w.#&:\[\]>~+*\s,-]+?)(\s*\{)/gm, '$1<span class="t-tl-sel">$2</span>$3')
93
+ // CSS property: value pairs
94
+ .replace(/([\w-]+)(\s*:\s*)([^;{}]+)(;)/g,
95
+ '<span class="t-tl-prop">$1</span>$2<span class="t-tl-val">$3</span>$4')
96
+ // CSS @-rules
97
+ .replace(/@([\w-]+)/g, '<span class="t-kw">@$1</span>');
98
+ }
99
+
100
+ /**
101
+ * @param {string} src
102
+ * @param {Object|string} [options]
103
+ * @returns {string}
104
+ */
105
+ export function renderMarkdown(src, options = {}) {
106
+ const { basePath = '', resolveImageSrc } = typeof options === 'string'
107
+ ? { basePath: options }
108
+ : (options || {});
109
+ const esc = s => String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
110
+ const escAttr = s => esc(s).replace(/"/g,'&quot;').replace(/'/g,'&#39;');
111
+ const lines = src.split('\n');
112
+ const out = [];
113
+ let inCode = false, codeLang = '', codeLines = [];
114
+ let inList = false, listType = '';
115
+ let paragraph = [];
116
+
117
+ function flushP() {
118
+ if (paragraph.length > 0) {
119
+ out.push(`<p class="md-p">${paragraph.map(inline).join('<br>')}</p>`);
120
+ paragraph = [];
121
+ }
122
+ }
123
+
124
+ function closeList() {
125
+ flushP();
126
+ if (inList) { out.push(listType === 'ul' ? '</ul>' : '</ol>'); inList = false; }
127
+ }
128
+
129
+ for (let i = 0; i < lines.length; i++) {
130
+ const raw = lines[i];
131
+
132
+ // Fenced code blocks
133
+ if (raw.trimStart().startsWith('```')) {
134
+ flushP();
135
+ if (inCode) {
136
+ out.push(`<pre class="md-code-block"><code>${esc(codeLines.join('\n'))}</code></pre>`);
137
+ inCode = false; codeLines = [];
138
+ } else {
139
+ closeList();
140
+ inCode = true;
141
+ codeLang = raw.trim().slice(3).trim();
142
+ codeLines = [];
143
+ }
144
+ continue;
145
+ }
146
+ if (inCode) { codeLines.push(raw); continue; }
147
+
148
+ const trimmed = raw.trim();
149
+ if (!trimmed) { flushP(); closeList(); continue; }
150
+
151
+ // Headings
152
+ const hm = trimmed.match(/^(#{1,6})\s+(.+)/);
153
+ if (hm) {
154
+ flushP();
155
+ closeList();
156
+ const level = hm[1].length;
157
+ out.push(`<h${level} class="md-h">${inline(hm[2])}</h${level}>`);
158
+ continue;
159
+ }
160
+
161
+ // Horizontal rule
162
+ if (/^[-*_]{3,}\s*$/.test(trimmed)) {
163
+ flushP();
164
+ closeList();
165
+ out.push('<hr class="md-hr">');
166
+ continue;
167
+ }
168
+
169
+ // Blockquote
170
+ if (trimmed.startsWith('> ')) {
171
+ flushP();
172
+ closeList();
173
+ out.push(`<blockquote class="md-quote">${inline(trimmed.slice(2))}</blockquote>`);
174
+ continue;
175
+ }
176
+
177
+ // Unordered list
178
+ const ulm = trimmed.match(/^[-*+]\s+(.+)/);
179
+ if (ulm) {
180
+ flushP();
181
+ if (!inList || listType !== 'ul') { closeList(); out.push('<ul class="md-list">'); inList = true; listType = 'ul'; }
182
+ out.push(`<li>${inline(ulm[1])}</li>`);
183
+ continue;
184
+ }
185
+
186
+ // Ordered list
187
+ const olm = trimmed.match(/^\d+[.)]\s+(.+)/);
188
+ if (olm) {
189
+ flushP();
190
+ if (!inList || listType !== 'ol') { closeList(); out.push('<ol class="md-list">'); inList = true; listType = 'ol'; }
191
+ out.push(`<li>${inline(olm[1])}</li>`);
192
+ continue;
193
+ }
194
+
195
+ // Table detection
196
+ if (trimmed.includes('|') && i + 1 < lines.length && /^\|?\s*[-:]+/.test(lines[i+1].trim())) {
197
+ flushP();
198
+ closeList();
199
+ const headers = trimmed.split('|').map(c => c.trim()).filter(Boolean);
200
+ i++; // skip separator
201
+ out.push('<table class="md-table"><thead><tr>');
202
+ headers.forEach(h => out.push(`<th>${inline(h)}</th>`));
203
+ out.push('</tr></thead><tbody>');
204
+ while (i + 1 < lines.length && lines[i+1].trim().includes('|')) {
205
+ i++;
206
+ const cells = lines[i].trim().split('|').map(c => c.trim()).filter(Boolean);
207
+ out.push('<tr>');
208
+ cells.forEach(c => out.push(`<td>${inline(c)}</td>`));
209
+ out.push('</tr>');
210
+ }
211
+ out.push('</tbody></table>');
212
+ continue;
213
+ }
214
+
215
+ // Paragraph
216
+ paragraph.push(trimmed);
217
+ }
218
+
219
+ flushP();
220
+ // Close any open code block
221
+ if (inCode) {
222
+ out.push(`<pre class="md-code-block"><code>${esc(codeLines.join('\n'))}</code></pre>`);
223
+ }
224
+ closeList();
225
+
226
+ return out.join('\n');
227
+
228
+ function inline(text) {
229
+ let escaped = esc(text);
230
+
231
+ // Unescape safe HTML tags commonly used in markdown
232
+ escaped = escaped.replace(/&lt;(\/?)(details|summary|kbd|br|hr|sub|sup)(.*?)&gt;/gi, (m, slash, tag, rest) => {
233
+ const safeRest = safeMarkdownHtmlAttributes(tag, slash, rest);
234
+ if (safeRest === null) return m;
235
+ return `<${slash}${tag}${safeRest}>`;
236
+ });
237
+
238
+ return escaped
239
+ // Images: ![alt](src)
240
+ .replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => {
241
+ const resolved = resolveImagePath(src, { basePath, resolveImageSrc });
242
+ if (!resolved) return '';
243
+ return `<img class="md-img" src="${escAttr(resolved)}" alt="${escAttr(alt)}" loading="lazy">`;
244
+ })
245
+ // Links: [text](url)
246
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) => {
247
+ const href = sanitizeMarkdownUrl(url);
248
+ if (!href) return label;
249
+ return `<a class="md-link" href="${escAttr(href)}" target="_blank" rel="noopener noreferrer">${label}</a>`;
250
+ })
251
+ // Bold: **text** or __text__
252
+ .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
253
+ .replace(/__(.+?)__/g, '<strong>$1</strong>')
254
+ // Italic: *text* or _text_
255
+ .replace(/\*(.+?)\*/g, '<em>$1</em>')
256
+ .replace(/_(.+?)_/g, '<em>$1</em>')
257
+ // Inline code: `code`
258
+ .replace(/`([^`]+)`/g, '<code class="md-inline-code">$1</code>')
259
+ // Strikethrough: ~~text~~
260
+ .replace(/~~(.+?)~~/g, '<del>$1</del>');
261
+ }
262
+
263
+ function resolveImagePath(src, options = {}) {
264
+ src = String(src || '').trim();
265
+ const safe = sanitizeMarkdownUrl(src, { allowDataImage: true });
266
+ if (!safe) return '';
267
+ if (safe.startsWith('http://') || safe.startsWith('https://') || safe.startsWith('data:image/')) return safe;
268
+ const { basePath = '', resolveImageSrc } = options;
269
+ if (typeof resolveImageSrc === 'function') {
270
+ const resolved = sanitizeMarkdownUrl(resolveImageSrc(safe, { basePath, originalSrc: src }), { allowDataImage: true });
271
+ if (resolved) return resolved;
272
+ }
273
+ const dir = basePath ? basePath.substring(0, basePath.lastIndexOf('/') + 1) : '';
274
+ const full = dir + safe;
275
+ return full;
276
+ }
277
+
278
+ function sanitizeMarkdownUrl(url, options = {}) {
279
+ const value = String(url || '').trim();
280
+ if (!value) return '';
281
+ const normalized = value.replace(/[\u0000-\u001F\u007F\s]+/g, '');
282
+ const lower = normalized.toLowerCase();
283
+ if (lower.startsWith('http://') || lower.startsWith('https://') || lower.startsWith('mailto:')) return value;
284
+ if (options.allowDataImage && /^data:image\/(?:png|gif|jpe?g|webp|svg\+xml);/i.test(value)) return value;
285
+ if (/^[a-z][a-z0-9+.-]*:/i.test(normalized)) return '';
286
+ return value;
287
+ }
288
+
289
+ function safeMarkdownHtmlAttributes(tag, slash, rest) {
290
+ const name = String(tag || '').toLowerCase();
291
+ const trimmed = String(rest || '').trim();
292
+ if (slash || !trimmed) return '';
293
+ if (name === 'details' && /^open$/i.test(trimmed)) return ' open';
294
+ return null;
295
+ }
296
+ }
297
+
298
+ /**
299
+ * @param {string} src
300
+ * @returns {string}
301
+ */
302
+ export function highlightSQL(src) {
303
+ const kw = new Set(['SELECT','FROM','WHERE','INSERT','INTO','VALUES','UPDATE','SET','DELETE','CREATE','ALTER','DROP','TABLE','INDEX','IF','NOT','EXISTS','PRIMARY','KEY','REFERENCES','DEFAULT','NULL','ON','AND','OR','IN','AS','JOIN','LEFT','RIGHT','INNER','OUTER','GROUP','BY','ORDER','HAVING','LIMIT','OFFSET','UNION','ALL','DISTINCT','CASE','WHEN','THEN','ELSE','END','CASCADE','SERIAL','CONSTRAINT','UNIQUE','CHECK','FOREIGN','INTEGER','INT','VARCHAR','TEXT','BOOLEAN','TIMESTAMP','JSONB','JSON','BIGINT','SMALLINT','NUMERIC','FLOAT','DOUBLE','DECIMAL','DATE','TIME','NOW','WITH','RECURSIVE','RETURNING']);
304
+ return src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
305
+ .replace(/--.*/g, m => `<span class="t-cm">${m}</span>`)
306
+ .replace(/'[^']*'/g, m => `<span class="t-str">${m}</span>`)
307
+ .replace(/\b\d+\b/g, m => `<span class="t-num">${m}</span>`)
308
+ .replace(/\b[A-Z_]{2,}\b/g, m => kw.has(m) ? `<span class="t-kw">${m}</span>` : m);
309
+ }
310
+
311
+ /**
312
+ * @param {string} src
313
+ * @returns {string}
314
+ */
315
+ export function highlightJSON(src) {
316
+ return src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
317
+ // Strings (keys and values)
318
+ .replace(/("(?:[^"\\]|\\.)*")\s*:/g, '<span class="t-tl-prop">$1</span>:')
319
+ .replace(/:(\s*)("(?:[^"\\]|\\.)*")/g, ':$1<span class="t-str">$2</span>')
320
+ // Remaining standalone strings (in arrays etc.)
321
+ .replace(/(?<=[\[,\s])("(?:[^"\\]|\\.)*")(?=[\],\s])/g, '<span class="t-str">$1</span>')
322
+ // Numbers
323
+ .replace(/:\s*(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g, (m, n) => m.replace(n, `<span class="t-num">${n}</span>`))
324
+ // Booleans and null
325
+ .replace(/\b(true|false|null)\b/g, '<span class="t-lit">$1</span>');
326
+ }
327
+
328
+ /**
329
+ * @param {string} src
330
+ * @returns {string}
331
+ */
332
+ export function highlightCSS(src) {
333
+ let html = src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
334
+ // Extract comments and strings as placeholders to avoid regex conflicts
335
+ const placeholders = [];
336
+ const ph = (s) => { placeholders.push(s); return `\x00PH${placeholders.length - 1}\x00`; };
337
+ html = html.replace(/(\/\*[\s\S]*?\*\/)/g, (m) => ph(`<span class="t-cm">${m}</span>`));
338
+ html = html.replace(/(["'])(?:(?!\1).)*?\1/g, (m) => ph(`<span class="t-str">${m}</span>`));
339
+ // @-rules
340
+ html = html.replace(/@([\w-]+)/g, '<span class="t-kw">@$1</span>');
341
+ // Selectors (lines ending with {)
342
+ html = html.replace(/^(\s*)([\w.#&:\[\]>~+*\s,-]+?)(\s*\{)/gm, '$1<span class="t-tl-sel">$2</span>$3');
343
+ // Property: value pairs
344
+ html = html.replace(/([\w-]+)(\s*:\s*)([^;{}]+)(;)/g,
345
+ '<span class="t-tl-prop">$1</span>$2<span class="t-tl-val">$3</span>$4');
346
+ // Restore placeholders
347
+ html = html.replace(/\x00PH(\d+)\x00/g, (_, i) => placeholders[i]);
348
+ return html;
349
+ }
350
+
351
+ /**
352
+ * @param {string} src
353
+ * @returns {string}
354
+ */
355
+ export function highlightHTML(src) {
356
+ return src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')
357
+ // Comments
358
+ .replace(/(&lt;!--[\s\S]*?--&gt;)/g, '<span class="t-cm">$1</span>')
359
+ // DOCTYPE / processing instructions
360
+ .replace(/(&lt;![A-Z]+[^&]*?&gt;)/g, '<span class="t-cm">$1</span>')
361
+ // Tags with attributes
362
+ .replace(/(&lt;\/?)(\w[\w-]*)((?:\s+[^&]*?)?)(\/?\s*&gt;)/g, (_, open, tag, attrs, close) => {
363
+ let attrHtml = attrs;
364
+ if (attrs) {
365
+ attrHtml = attrs
366
+ .replace(/([\w-]+)(=)(&quot;[^&]*?&quot;|&#39;[^&]*?&#39;|"[^"]*"|'[^']*')/g,
367
+ '<span class="t-tl-attr">$1</span>$2<span class="t-str">$3</span>')
368
+ .replace(/\s([\w-]+)(?=[\s\/&]|$)/g, ' <span class="t-tl-attr">$1</span>');
369
+ }
370
+ return `<span class="t-tl-bracket">${open}</span><span class="t-tl-tag">${tag}</span>${attrHtml}<span class="t-tl-bracket">${close}</span>`;
371
+ })
372
+ // Entities
373
+ .replace(/(&amp;\w+;)/g, '<span class="t-num">$1</span>');
374
+ }
375
+
376
+ /**
377
+ * @param {string} src
378
+ * @returns {string}
379
+ */
380
+ export function highlightYAML(src) {
381
+ let html = src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
382
+ const placeholders = [];
383
+ const ph = (s) => { placeholders.push(s); return `\x00PH${placeholders.length - 1}\x00`; };
384
+ // Comments
385
+ html = html.replace(/(#.*)/g, (m) => ph(`<span class="t-cm">${m}</span>`));
386
+ // Quoted strings
387
+ html = html.replace(/(["'])(?:(?!\1).)*?\1/g, (m) => ph(`<span class="t-str">${m}</span>`));
388
+ // Keys (word: )
389
+ html = html.replace(/^(\s*)([\w][\w.-]*)(\s*:)/gm, '$1<span class="t-tl-prop">$2</span>$3');
390
+ // Booleans and null
391
+ html = html.replace(/:\s*(true|false|null|yes|no|on|off)\b/gi, (m, v) => m.replace(v, `<span class="t-lit">${v}</span>`));
392
+ // Numbers
393
+ html = html.replace(/:\s*(-?\d+\.?\d*)\b/g, (m, n) => m.replace(n, `<span class="t-num">${n}</span>`));
394
+ // Anchors and aliases
395
+ html = html.replace(/([&*]\w+)/g, '<span class="t-fn">$1</span>');
396
+ // Document markers
397
+ html = html.replace(/^(---|\.\.\.)\s*$/gm, '<span class="t-kw">$1</span>');
398
+ // Restore placeholders
399
+ html = html.replace(/\x00PH(\d+)\x00/g, (_, i) => placeholders[i]);
400
+ return html;
401
+ }
402
+
403
+ /**
404
+ * @param {string} src
405
+ * @returns {string}
406
+ */
407
+ export function highlightShell(src) {
408
+ const kw = new Set(['if','then','else','elif','fi','for','while','do','done','case','esac','in','function','return','exit','export','local','readonly','declare','source','alias','unalias','set','unset','shift','trap','eval','exec','test']);
409
+ let html = src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
410
+ const placeholders = [];
411
+ const ph = (s) => { placeholders.push(s); return `\x00PH${placeholders.length - 1}\x00`; };
412
+ // Comments
413
+ html = html.replace(/(#.*)/g, (m) => ph(`<span class="t-cm">${m}</span>`));
414
+ // Double-quoted strings
415
+ html = html.replace(/"(?:[^"\\]|\\.)*"/g, (m) => ph(`<span class="t-str">${m}</span>`));
416
+ // Single-quoted strings
417
+ html = html.replace(/'[^']*'/g, (m) => ph(`<span class="t-str">${m}</span>`));
418
+ // Variables
419
+ html = html.replace(/(\$\{?\w+\}?)/g, '<span class="t-fn">$1</span>');
420
+ // Numbers
421
+ html = html.replace(/\b(\d+)\b/g, '<span class="t-num">$1</span>');
422
+ // Keywords
423
+ html = html.replace(/\b(\w+)\b/g, (m, w) => kw.has(w) ? `<span class="t-kw">${w}</span>` : m);
424
+ // Restore placeholders
425
+ html = html.replace(/\x00PH(\d+)\x00/g, (_, i) => placeholders[i]);
426
+ return html;
427
+ }
428
+
429
+ /**
430
+ * @param {string} src
431
+ * @returns {string}
432
+ */
433
+ export function highlightINI(src) {
434
+ let html = src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
435
+ const placeholders = [];
436
+ const ph = (s) => { placeholders.push(s); return `\x00PH${placeholders.length - 1}\x00`; };
437
+ // Comments
438
+ html = html.replace(/(#.*|;.*)/g, (m) => ph(`<span class="t-cm">${m}</span>`));
439
+ // Quoted values
440
+ html = html.replace(/(["'])(?:(?!\1).)*?\1/g, (m) => ph(`<span class="t-str">${m}</span>`));
441
+ // Section headers [section]
442
+ html = html.replace(/^(\s*\[[\w. -]+\]\s*)$/gm, '<span class="t-kw">$1</span>');
443
+ // Key=value
444
+ html = html.replace(/^(\s*)([\w][\w.-]*)(\s*=\s*)(.*)/gm, (_, indent, key, eq, val) => {
445
+ let vHtml = val;
446
+ if (/^\x00PH/.test(val)) vHtml = val; // already a placeholder
447
+ else if (/^(true|false|yes|no|on|off)$/i.test(val)) vHtml = `<span class="t-lit">${val}</span>`;
448
+ else if (/^-?\d+\.?\d*$/.test(val)) vHtml = `<span class="t-num">${val}</span>`;
449
+ else vHtml = `<span class="t-tl-val">${val}</span>`;
450
+ return `${indent}<span class="t-tl-prop">${key}</span>${eq}${vHtml}`;
451
+ });
452
+ // Restore placeholders
453
+ html = html.replace(/\x00PH(\d+)\x00/g, (_, i) => placeholders[i]);
454
+ return html;
455
+ }
456
+
457
+ /** Language keyword/builtin/literal definitions for the universal highlighter */
458
+ const LANG_DEFS = {
459
+ python: {
460
+ kw: new Set(['and','as','assert','async','await','break','class','continue','def','del','elif','else','except','finally','for','from','global','if','import','in','is','lambda','nonlocal','not','or','pass','raise','return','try','while','with','yield']),
461
+ bi: new Set(['print','len','range','type','int','str','float','list','dict','tuple','set','bool','None','True','False','super','self','open','map','filter','zip','enumerate','sorted','reversed','isinstance','issubclass','hasattr','getattr','setattr','input','abs','max','min','sum','round','any','all','iter','next','format','repr','id','hash','dir','vars','globals','locals','staticmethod','classmethod','property']),
462
+ lit: new Set(['True','False','None']),
463
+ hashComment: true, tripleStr: true,
464
+ },
465
+ ruby: {
466
+ kw: new Set(['alias','and','begin','break','case','class','def','defined?','do','else','elsif','end','ensure','for','if','in','module','next','nil','not','or','redo','rescue','retry','return','self','super','then','undef','unless','until','when','while','yield','require','include','extend','attr_accessor','attr_reader','attr_writer','raise','puts','print']),
467
+ bi: new Set(['Array','Hash','String','Integer','Float','Symbol','Proc','Lambda','IO','File','Dir','Regexp','Range','Enumerable','Comparable','Kernel','Object','Class','Module','NilClass','TrueClass','FalseClass']),
468
+ lit: new Set(['true','false','nil']),
469
+ hashComment: true,
470
+ },
471
+ go: {
472
+ kw: new Set(['break','case','chan','const','continue','default','defer','else','fallthrough','for','func','go','goto','if','import','interface','map','package','range','return','select','struct','switch','type','var']),
473
+ bi: new Set(['append','cap','close','complex','copy','delete','imag','len','make','new','panic','print','println','real','recover','error','string','bool','byte','rune','int','int8','int16','int32','int64','uint','uint8','uint16','uint32','uint64','float32','float64','complex64','complex128','uintptr','fmt','os','io','net','http','context','sync','time','strings','strconv','errors','log']),
474
+ lit: new Set(['true','false','nil','iota']),
475
+ },
476
+ rust: {
477
+ kw: new Set(['as','async','await','break','const','continue','crate','dyn','else','enum','extern','fn','for','if','impl','in','let','loop','match','mod','move','mut','pub','ref','return','self','Self','static','struct','super','trait','type','unsafe','use','where','while','macro_rules']),
478
+ bi: new Set(['Vec','String','Option','Result','Box','Rc','Arc','Cell','RefCell','HashMap','HashSet','BTreeMap','BTreeSet','Iterator','IntoIterator','From','Into','Display','Debug','Clone','Copy','Default','Eq','PartialEq','Ord','PartialOrd','Hash','Send','Sync','Sized','Drop','Fn','FnMut','FnOnce','Some','None','Ok','Err','println','eprintln','format','write','writeln','todo','unimplemented','unreachable','assert','assert_eq','assert_ne','dbg','vec','panic']),
479
+ lit: new Set(['true','false']),
480
+ },
481
+ java: {
482
+ kw: new Set(['abstract','assert','boolean','break','byte','case','catch','char','class','const','continue','default','do','double','else','enum','extends','final','finally','float','for','goto','if','implements','import','instanceof','int','interface','long','native','new','package','private','protected','public','return','short','static','strictfp','super','switch','synchronized','this','throw','throws','transient','try','void','volatile','while','var','record','sealed','permits','yield']),
483
+ bi: new Set(['System','String','Integer','Long','Double','Float','Boolean','Character','Byte','Short','Object','Class','Math','Arrays','Collections','List','ArrayList','Map','HashMap','Set','HashSet','Queue','Stack','Optional','Stream','Thread','Runnable','Exception','RuntimeException','IOException','StringBuilder','Scanner','File','Path','Paths','Files']),
484
+ lit: new Set(['true','false','null']),
485
+ },
486
+ kotlin: {
487
+ kw: new Set(['abstract','annotation','as','break','by','catch','class','companion','const','constructor','continue','crossinline','data','do','else','enum','external','final','finally','for','fun','get','if','import','in','infix','init','inline','inner','interface','internal','is','lateinit','noinline','object','open','operator','out','override','package','private','protected','public','reified','return','sealed','set','super','suspend','tailrec','this','throw','try','typealias','val','var','vararg','when','where','while']),
488
+ bi: new Set(['Any','Boolean','Byte','Char','Double','Float','Int','Long','Nothing','Short','String','Unit','Array','List','Map','Set','MutableList','MutableMap','MutableSet','Pair','Triple','Sequence','Comparable','Iterable','println','print','readLine','listOf','mapOf','setOf','arrayOf','mutableListOf','mutableMapOf','mutableSetOf']),
489
+ lit: new Set(['true','false','null']),
490
+ },
491
+ swift: {
492
+ kw: new Set(['associatedtype','break','case','catch','class','continue','default','defer','deinit','do','else','enum','extension','fallthrough','fileprivate','for','func','guard','if','import','in','init','inout','internal','is','let','open','operator','private','protocol','public','repeat','rethrows','return','self','Self','static','struct','subscript','super','switch','throw','throws','try','typealias','var','where','while','async','await','actor']),
493
+ bi: new Set(['Array','Bool','Character','Dictionary','Double','Float','Int','Optional','Set','String','UInt','Any','AnyObject','Error','Codable','Decodable','Encodable','Equatable','Hashable','Comparable','CustomStringConvertible','DispatchQueue','URLSession','Data','URL','print','debugPrint','fatalError','precondition','assert']),
494
+ lit: new Set(['true','false','nil']),
495
+ },
496
+ c: {
497
+ kw: new Set(['auto','break','case','char','const','continue','default','do','double','else','enum','extern','float','for','goto','if','inline','int','long','register','restrict','return','short','signed','sizeof','static','struct','switch','typedef','union','unsigned','void','volatile','while','_Alignas','_Alignof','_Atomic','_Bool','_Complex','_Generic','_Imaginary','_Noreturn','_Static_assert','_Thread_local','#include','#define','#ifdef','#ifndef','#endif','#if','#else','#elif','#pragma','#error','#undef']),
498
+ bi: new Set(['printf','scanf','malloc','calloc','realloc','free','memcpy','memset','memmove','strcmp','strlen','strcpy','strcat','strncpy','strncat','fprintf','sprintf','snprintf','fopen','fclose','fread','fwrite','fgets','fputs','stdin','stdout','stderr','NULL','EOF','size_t','ptrdiff_t','FILE','EXIT_SUCCESS','EXIT_FAILURE','assert','abort','exit']),
499
+ lit: new Set(['true','false','NULL','TRUE','FALSE']),
500
+ },
501
+ csharp: {
502
+ kw: new Set(['abstract','as','base','bool','break','byte','case','catch','char','checked','class','const','continue','decimal','default','delegate','do','double','else','enum','event','explicit','extern','finally','fixed','float','for','foreach','goto','if','implicit','in','int','interface','internal','is','lock','long','namespace','new','object','operator','out','override','params','private','protected','public','readonly','ref','return','sbyte','sealed','short','sizeof','stackalloc','static','string','struct','switch','this','throw','try','typeof','uint','ulong','unchecked','unsafe','ushort','using','var','virtual','void','volatile','while','async','await','dynamic','nameof','record','init','required','yield']),
503
+ bi: new Set(['Console','String','Int32','Boolean','Object','Array','List','Dictionary','Task','Action','Func','Exception','DateTime','TimeSpan','Math','File','Path','Directory','Stream','StringBuilder','Enumerable','Linq','IEnumerable','IList','IDictionary','IDisposable','EventHandler','Attribute','Type','Convert','Guid','Nullable','Tuple','ValueTuple']),
504
+ lit: new Set(['true','false','null']),
505
+ },
506
+ php: {
507
+ kw: new Set(['abstract','and','array','as','break','callable','case','catch','class','clone','const','continue','declare','default','do','echo','else','elseif','empty','enddeclare','endfor','endforeach','endif','endswitch','endwhile','eval','extends','final','finally','fn','for','foreach','function','global','goto','if','implements','include','include_once','instanceof','insteadof','interface','isset','list','match','namespace','new','or','print','private','protected','public','readonly','require','require_once','return','static','switch','throw','trait','try','unset','use','var','while','xor','yield','from']),
508
+ bi: new Set(['array_map','array_filter','array_push','array_pop','array_shift','array_merge','array_keys','array_values','count','strlen','strpos','substr','str_replace','explode','implode','trim','strtolower','strtoupper','is_array','is_string','is_int','is_null','isset','empty','var_dump','print_r','json_encode','json_decode','date','time','file_get_contents','file_put_contents','preg_match','preg_replace','sprintf','intval','floatval','boolval']),
509
+ lit: new Set(['true','false','null','TRUE','FALSE','NULL']),
510
+ hashComment: true,
511
+ },
512
+ dart: {
513
+ kw: new Set(['abstract','as','assert','async','await','break','case','catch','class','const','continue','covariant','default','deferred','do','dynamic','else','enum','export','extends','extension','external','factory','final','finally','for','Function','get','hide','if','implements','import','in','interface','is','late','library','mixin','new','on','operator','part','required','rethrow','return','set','show','static','super','switch','sync','this','throw','try','typedef','var','void','while','with','yield']),
514
+ bi: new Set(['print','int','double','String','bool','List','Map','Set','Future','Stream','Duration','DateTime','RegExp','Object','Type','Iterable','Iterator','Null','Symbol','Function','dynamic','num','Comparable','Pattern','StringBuffer','Uri','Error','Exception','StateError','ArgumentError','RangeError','TypeError','FormatException']),
515
+ lit: new Set(['true','false','null']),
516
+ },
517
+ lua: {
518
+ kw: new Set(['and','break','do','else','elseif','end','for','function','goto','if','in','local','not','or','repeat','return','then','until','while']),
519
+ bi: new Set(['print','type','tostring','tonumber','error','assert','pcall','xpcall','require','select','pairs','ipairs','next','rawget','rawset','rawequal','setmetatable','getmetatable','unpack','table','string','math','io','os','coroutine','debug']),
520
+ lit: new Set(['true','false','nil']),
521
+ lineComment: '--', blockCommentOpen: '--[[', blockCommentClose: ']]',
522
+ },
523
+ dockerfile: {
524
+ kw: new Set(['FROM','RUN','CMD','LABEL','MAINTAINER','EXPOSE','ENV','ADD','COPY','ENTRYPOINT','VOLUME','USER','WORKDIR','ARG','ONBUILD','STOPSIGNAL','HEALTHCHECK','SHELL','AS']),
525
+ bi: new Set(['apt-get','apk','yum','npm','pip','curl','wget','chmod','chown','mkdir','rm','cp','mv','cat','echo','bash','sh']),
526
+ lit: new Set(['true','false']),
527
+ hashComment: true,
528
+ },
529
+ };
530
+
531
+ /**
532
+ * Universal C-like syntax highlighter.
533
+ * Works for Python, Go, Rust, Java, C/C++, C#, PHP, Ruby, Kotlin, Swift, Dart, Lua, Dockerfile.
534
+ * Uses the same tokenizer logic as the JS highlighter but with configurable keyword sets.
535
+ * @param {string} src - Source code
536
+ * @param {string} lang - Language key (must exist in LANG_DEFS)
537
+ * @returns {string}
538
+ */
539
+ export function highlightLang(src, lang) {
540
+ const def = LANG_DEFS[lang];
541
+ if (!def) return highlightPlain(src);
542
+ const { kw, bi, lit, hashComment, tripleStr, lineComment, blockCommentOpen, blockCommentClose } = def;
543
+ const lc = lineComment || '//';
544
+ const bco = blockCommentOpen || '/*';
545
+ const bcc = blockCommentClose || '*/';
546
+ const out = [];
547
+ const len = src.length;
548
+ let i = 0;
549
+ while (i < len) {
550
+ const ch = src[i];
551
+ // Line comments (// or # or --)
552
+ if ((hashComment && ch === '#') ||
553
+ (src.substring(i, i + lc.length) === lc && !hashComment)) {
554
+ const s = i;
555
+ while (i < len && src[i] !== '\n') i++;
556
+ out.push(`<span class="t-cm">${esc(src, s, i)}</span>`);
557
+ continue;
558
+ }
559
+ // Block comments (/* */ or --[[ ]])
560
+ if (src.substring(i, i + bco.length) === bco) {
561
+ const s = i;
562
+ i += bco.length;
563
+ while (i < len && src.substring(i, i + bcc.length) !== bcc) i++;
564
+ i += bcc.length;
565
+ out.push(`<span class="t-cm">${esc(src, s, i)}</span>`);
566
+ continue;
567
+ }
568
+ // Triple-quoted strings (Python)
569
+ if (tripleStr && (src.substring(i, i+3) === '"""' || src.substring(i, i+3) === "'''")) {
570
+ const q = src.substring(i, i+3);
571
+ const s = i;
572
+ i += 3;
573
+ while (i < len && src.substring(i, i+3) !== q) { if (src[i] === '\\') i++; i++; }
574
+ i += 3;
575
+ out.push(`<span class="t-str">${esc(src, s, i)}</span>`);
576
+ continue;
577
+ }
578
+ // Strings
579
+ if (ch === "'" || ch === '"') {
580
+ const s = i; i++;
581
+ while (i < len && src[i] !== ch) { if (src[i] === '\\') i++; i++; }
582
+ i++;
583
+ out.push(`<span class="t-str">${esc(src, s, i)}</span>`);
584
+ continue;
585
+ }
586
+ // Backtick strings (Go raw strings, etc.)
587
+ if (ch === '`') {
588
+ const s = i; i++;
589
+ while (i < len && src[i] !== '`') i++;
590
+ i++;
591
+ out.push(`<span class="t-str">${esc(src, s, i)}</span>`);
592
+ continue;
593
+ }
594
+ // Numbers
595
+ if (isDigit(ch) || (ch === '.' && i+1 < len && isDigit(src[i+1]))) {
596
+ const s = i;
597
+ if (ch === '0' && (src[i+1] === 'x' || src[i+1] === 'X')) {
598
+ i += 2; while (i < len && isHex(src[i])) i++;
599
+ } else if (ch === '0' && (src[i+1] === 'b' || src[i+1] === 'B')) {
600
+ i += 2; while (i < len && (src[i] === '0' || src[i] === '1')) i++;
601
+ } else if (ch === '0' && (src[i+1] === 'o' || src[i+1] === 'O')) {
602
+ i += 2; while (i < len && src[i] >= '0' && src[i] <= '7') i++;
603
+ } else {
604
+ while (i < len && (isDigit(src[i]) || src[i] === '.' || src[i] === 'e' || src[i] === 'E' || src[i] === '_')) i++;
605
+ }
606
+ // Numeric suffixes (f, u, l, i32, etc.)
607
+ while (i < len && isIdent(src[i])) i++;
608
+ out.push(`<span class="t-num">${esc(src, s, i)}</span>`);
609
+ continue;
610
+ }
611
+ // Identifiers and keywords
612
+ if (isIdentStart(ch)) {
613
+ const s = i;
614
+ while (i < len && isIdent(src[i])) i++;
615
+ const word = src.substring(s, i);
616
+ let d = i; while (d < len && src[d] === ' ') d++;
617
+ if (kw.has(word)) out.push(`<span class="t-kw">${word}</span>`);
618
+ else if (lit.has(word)) out.push(`<span class="t-lit">${word}</span>`);
619
+ else if (bi.has(word)) out.push(`<span class="t-bi">${word}</span>`);
620
+ else if (src[d] === '(') out.push(`<span class="t-fn">${word}</span>`);
621
+ else if (s > 0 && src[s-1] === '.') out.push(`<span class="t-prop">${word}</span>`);
622
+ else out.push(escChar(word));
623
+ continue;
624
+ }
625
+ // PHP variables
626
+ if (ch === '$' && i+1 < len && isIdentStart(src[i+1])) {
627
+ const s = i; i++;
628
+ while (i < len && isIdent(src[i])) i++;
629
+ out.push(`<span class="t-fn">${esc(src, s, i)}</span>`);
630
+ continue;
631
+ }
632
+ // Decorators / Attributes (@)
633
+ if (ch === '@' && i+1 < len && isIdentStart(src[i+1])) {
634
+ const s = i; i++;
635
+ while (i < len && isIdent(src[i])) i++;
636
+ out.push(`<span class="t-jd-tag">${esc(src, s, i)}</span>`);
637
+ continue;
638
+ }
639
+ out.push(escSingle(ch));
640
+ i++;
641
+ }
642
+ return out.join('');
643
+ }
644
+
645
+ function esc(src, from, to) { let r = ''; for (let i = from; i < to; i++) r += escSingle(src[i]); return r; }
646
+ function escSingle(ch) { return ch === '&' ? '&amp;' : ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : ch; }
647
+ function escChar(s) { return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
648
+ function isDigit(ch) { return ch >= '0' && ch <= '9'; }
649
+ function isHex(ch) { return isDigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); }
650
+ function isIdentStart(ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '_' || ch === '$'; }
651
+ function isIdent(ch) { return isIdentStart(ch) || isDigit(ch); }
652
+
653
+ /**
654
+ * @param {string} src
655
+ * @returns {string}
656
+ */
657
+ export function highlightPlain(src) {
658
+ return src.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
659
+ }