diff --git a/.changeset/crazy-jobs-see.md b/.changeset/crazy-jobs-see.md new file mode 100644 index 00000000000..fb56d3f0877 --- /dev/null +++ b/.changeset/crazy-jobs-see.md @@ -0,0 +1,5 @@ +--- +'@mermaid-js/mermaid-local-editor': patch +--- + +feat: add local editor package for Mermaid diagrams diff --git a/package.json b/package.json index b307db8f11a..a64c75bf385 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,15 @@ "git graph" ], "scripts": { + "clean": "rimraf packages/mermaid/dist", + "copy:dompurify": "cpy node_modules/.pnpm/dompurify@*/node_modules/dompurify/dist/purify.min.js packages/mermaid/dist/mermaid-local-editor/vendor/ --flat", + "copy:mermaid": "cpy packages/mermaid/dist/mermaid.min.js packages/mermaid/dist/mermaid-local-editor/vendor/ --flat", + "copy:editor": "cpy \"packages/mermaid-local-editor/static/**/*\" packages/mermaid/dist/mermaid-local-editor", + "serve:dist": "sirv packages/mermaid/dist/mermaid-local-editor --port 8081 --dev --no-clear", "build": "pnpm build:esbuild && pnpm build:types", "build:esbuild": "pnpm run -r clean && tsx .esbuild/build.ts", "build:mermaid": "pnpm build:esbuild --mermaid", + "build:mermaid:full": "pnpm clean && pnpm build:mermaid && pnpm copy:editor && pnpm copy:mermaid && pnpm copy:dompurify && pnpm serve:dist", "build:viz": "pnpm build:esbuild --visualize", "build:types": "pnpm --filter mermaid types:build-config && tsx .build/types.ts", "build:types:watch": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly --watch", @@ -133,6 +139,7 @@ "prettier-plugin-jsdoc": "^1.3.3", "rimraf": "^6.0.1", "rollup-plugin-visualizer": "^6.0.5", + "sirv-cli": "^3.0.1", "start-server-and-test": "^2.1.3", "tslib": "^2.8.1", "tsx": "^4.20.6", diff --git a/packages/mermaid-local-editor/README.md b/packages/mermaid-local-editor/README.md new file mode 100644 index 00000000000..31943ec3468 --- /dev/null +++ b/packages/mermaid-local-editor/README.md @@ -0,0 +1,74 @@ +# Mermaid Local Editor + +Standalone local editor for Mermaid diagrams. +Runs entirely from `dist/` with no external dependencies. + +--- + +## Usage + +```sh +pnpm build:mermaid:full +``` + +--- + +## Build Pipeline + +The `build:mermaid:full` command performs the following steps: + +1. **Clean** + + Removes the existing build output: + + ```sh + pnpm clean + ``` + +2. **Build Mermaid** + + Compiles Mermaid using the repository build pipeline: + + ```sh + pnpm build:mermaid + ``` + +3. **Copy Editor** + + Copies the local editor sources into the distribution directory: + + ```sh + pnpm copy:editor + ``` + +4. **Bundle Dependencies** + + Copies required runtime dependencies into the editor bundle: + + ```sh + pnpm copy:mermaid + pnpm copy:dompurify + ``` + +5. **Serve** + + Starts a local static server: + + ```sh + pnpm serve:dist + ``` + +--- + +## Output + +After build, the editor is available at [`packages/mermaid/dist/mermaid-local-editor/`](../mermaid/dist/mermaid-local-editor): + +--- + +## Notes + +- No external CDN dependencies are used +- DOMPurify is bundled locally +- The editor is fully offline-capable +- Designed to run directly from the `dist/` directory diff --git a/packages/mermaid-local-editor/package.json b/packages/mermaid-local-editor/package.json new file mode 100644 index 00000000000..b7c18bbbc1b --- /dev/null +++ b/packages/mermaid-local-editor/package.json @@ -0,0 +1,6 @@ +{ + "name": "@mermaid-js/mermaid-local-editor", + "private": true, + "version": "0.0.0", + "type": "module" +} diff --git a/packages/mermaid-local-editor/static/app.js b/packages/mermaid-local-editor/static/app.js new file mode 100644 index 00000000000..7d448d8414c --- /dev/null +++ b/packages/mermaid-local-editor/static/app.js @@ -0,0 +1,80 @@ +import { initMermaid, state, IS_E2E } from './js/config.js'; +import { createStorage } from './js/storage.js'; +import { renderDiagram } from './js/renderer.js'; +import { setupUI, refreshList } from './js/ui.js'; +import { createNavigation } from './js/navigation.js'; + +initMermaid(); + +const srcPanel = document.getElementById('srcPanel'); +const preview = document.getElementById('preview'); +const diagramsSelect = document.getElementById('diagrams'); +const nameInput = document.getElementById('name'); +const storage = createStorage(); +const navigation = createNavigation({ + state, + preview, + srcPanel, + applyTransform, +}); + +function render() { + void renderDiagram({ + srcValue: srcPanel.value, + preview, + state, + IS_E2E, + applyTransform, + rebuildNavNodes: navigation.rebuildNavNodes, + }); +} + +function load(name) { + storage.setCurrent(name); + const d = storage.diagrams[name]; + + srcPanel.value = d.src; + + // restore the view + state.scale = d.view?.scale ?? 1; + state.panX = d.view?.panX ?? 0; + state.panY = d.view?.panY ?? 0; + + refreshList({ diagramsSelect, nameInput, storage }); + render(); + requestAnimationFrame(applyTransform); +} + +function applyTransform() { + if (!state.iframeRef) { + return; + } + + const svg = state.iframeRef.contentDocument?.querySelector('svg'); + if (!svg) { + return; + } + + state.panY = Math.max(-20000, Math.min(20000, state.panY)); + state.panX = Math.max(-20000, Math.min(20000, state.panX)); + + svg.style.transform = `translate(${state.panX}px, ${state.panY}px) scale(${state.scale})`; + + storage.updateCurrent({ + view: { scale: state.scale, panX: state.panX, panY: state.panY }, + }); +} + +setupUI({ + src: srcPanel, + diagramsSelect, + nameInput, + storage, + state, + render, + load, + applyTransform, +}); + +navigation.setupKeyboardNav(); +load(storage.current); diff --git a/packages/mermaid-local-editor/static/index.html b/packages/mermaid-local-editor/static/index.html new file mode 100644 index 00000000000..7018d92707c --- /dev/null +++ b/packages/mermaid-local-editor/static/index.html @@ -0,0 +1,31 @@ + + + + + Mermaid Local Editor + + + + + + + + + +
+ + + + + + + + +
+ +
+ +
+
+ + diff --git a/packages/mermaid-local-editor/static/js/config.js b/packages/mermaid-local-editor/static/js/config.js new file mode 100644 index 00000000000..ed71337d365 --- /dev/null +++ b/packages/mermaid-local-editor/static/js/config.js @@ -0,0 +1,24 @@ +/* global mermaid */ + +export const IS_E2E = navigator.webdriver || location.search.includes('graph='); + +export function initMermaid() { + mermaid.initialize({ + startOnLoad: false, + theme: 'dark', + securityLevel: 'strict', + deterministicIds: true, + fontFamily: 'Arial', + htmlLabels: false, + flowchart: { + useMaxWidth: false, + }, + }); +} + +export let state = { + scale: 1, + panX: 0, + panY: 0, + iframeRef: null, +}; diff --git a/packages/mermaid-local-editor/static/js/navigation.js b/packages/mermaid-local-editor/static/js/navigation.js new file mode 100644 index 00000000000..254f33ad5e4 --- /dev/null +++ b/packages/mermaid-local-editor/static/js/navigation.js @@ -0,0 +1,96 @@ +export function createNavigation({ state, preview, srcPanel, applyTransform }) { + let navNodes = []; + let navIndex = 0; + + function rebuildNavNodes() { + navNodes = []; + navIndex = 0; + + const svg = state.iframeRef?.contentDocument?.querySelector('svg'); + if (!svg) { + return; + } + + navNodes = [...svg.querySelectorAll('g.node')]; + navIndex = 0; + + if (navNodes.length) { + highlightCurrentNode(); + centerCurrentNode(); + } + } + + function highlightCurrentNode() { + const svg = state.iframeRef?.contentDocument?.querySelector('svg'); + if (!svg) { + return; + } + + svg + .querySelectorAll('g.node.selected-node') + .forEach((n) => n.classList.remove('selected-node')); + + const node = navNodes[navIndex]; + if (node) { + node.classList.add('selected-node'); + } + } + + function centerCurrentNode() { + const node = navNodes[navIndex]; + if (!node) { + return; + } + + const nodeRect = node.getBoundingClientRect(); + const contRect = preview.getBoundingClientRect(); + + const nodeCenterY = nodeRect.top + nodeRect.height / 6; + const contCenterY = contRect.top + contRect.height / 6; + const deltaY = contCenterY - nodeCenterY; + + // Intentionally biased to upper-left instead of strict center, + // so forward nodes remain visible in LR / TD diagrams. + const nodeCenterX = nodeRect.left + nodeRect.width / 6; + const contCenterX = contRect.left + contRect.width / 6; + const deltaX = contCenterX - nodeCenterX; + + state.panX += deltaX; + state.panY += deltaY; + + applyTransform(); + } + + function setupKeyboardNav() { + window.addEventListener('keydown', (e) => { + if (document.activeElement === srcPanel) { + return; + } + + if (e.key === 'ArrowDown') { + e.preventDefault(); + if (!navNodes.length) { + rebuildNavNodes(); + } + navIndex = Math.min(navIndex + 1, navNodes.length - 1); + highlightCurrentNode(); + centerCurrentNode(); + } + + if (e.key === 'ArrowUp') { + e.preventDefault(); + if (!navNodes.length) { + rebuildNavNodes(); + } + navIndex = Math.max(navIndex - 1, 0); + highlightCurrentNode(); + centerCurrentNode(); + } + }); + } + + return { + rebuildNavNodes, + setupKeyboardNav, + }; +} diff --git a/packages/mermaid-local-editor/static/js/renderer.js b/packages/mermaid-local-editor/static/js/renderer.js new file mode 100644 index 00000000000..f4c1b67df54 --- /dev/null +++ b/packages/mermaid-local-editor/static/js/renderer.js @@ -0,0 +1,157 @@ +/* global mermaid, DOMPurify */ + +export async function renderDiagram({ + srcValue, + preview, + state, + IS_E2E, + applyTransform, + rebuildNavNodes, +}) { + try { + const { svg } = await mermaid.render(IS_E2E ? 'm1' : 'm' + Date.now(), srcValue); + + preview.replaceChildren(); + + if (IS_E2E) { + const cleanSvg = DOMPurify.sanitize(svg, { + ADD_TAGS: ['foreignObject'], + ADD_ATTR: ['xmlns'], + }); + + const doc = new DOMParser().parseFromString(cleanSvg, 'image/svg+xml'); + preview.replaceChildren(doc.documentElement); + return; + } + + const iframe = document.createElement('iframe'); + iframe.sandbox = 'allow-same-origin'; + iframe.style.width = '100%'; + iframe.style.height = '100%'; + iframe.style.border = 'none'; + + preview.appendChild(iframe); + state.iframeRef = iframe; + + const cleanSvg = DOMPurify.sanitize(svg, { + ADD_TAGS: ['foreignObject'], + ADD_ATTR: ['xmlns'], + }); + + const parsed = new DOMParser().parseFromString(cleanSvg, 'image/svg+xml'); + const svgEl = parsed.documentElement; + + svgEl.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + + svgEl.querySelectorAll('*').forEach((el) => { + [...el.attributes].forEach((attr) => { + if (attr.name.startsWith('on')) { + el.removeAttribute(attr.name); + } + }); + }); + + const doc = iframe.contentDocument; + doc.open(); + doc.close(); + doc.body.appendChild(doc.importNode(svgEl, true)); + + setTimeout(() => { + rebuildNavNodes(); + }, 0); + + requestAnimationFrame(() => { + const svgEl = iframe.contentDocument?.querySelector('svg'); + if (!svgEl) { + return; + } + + svgEl.style.transformOrigin = '0 0'; + svgEl.style.display = 'block'; + }); + + const style = doc.createElement('style'); + style.textContent = ` + text { fill: #e6e6e6 !important; } + .node rect, .node polygon, .node path { + transition: fill 120ms ease, filter 120ms ease; + } + + .node:hover rect, + .node:hover polygon, + .node:hover path { + fill: rgba(0, 170, 255, 0.25); + filter: drop-shadow(0 0 11px rgba(0, 170, 255, 0.6)); + } + + g.node.selected-node rect, + g.node.selected-node polygon, + g.node.selected-node path { + fill: rgba(0, 170, 255, 0.35) !important; + stroke: #00aaff !important; + stroke-width: 2px !important; + filter: drop-shadow(0 0 16px rgba(0, 170, 255, 1)) !important; + } + + g.node.selected-node text { + fill: #ffffff !important; + font-weight: bold !important; + } + + body { + margin: 0; + overflow: hidden; + } + `; + doc.head.appendChild(style); + + iframe.addEventListener('load', () => { + window.focus(); + }); + + doc.onwheel = null; + doc.onmousedown = null; + doc.onmouseup = null; + doc.onmousemove = null; + + let isPanningLocal = false; + let startXLocal = 0; + let startYLocal = 0; + + doc.onwheel = (e) => { + e.preventDefault(); + state.scale += e.deltaY * -0.0015; + state.scale = Math.min(Math.max(0.2, state.scale), 4); + applyTransform(); + }; + + doc.onmousedown = (e) => { + isPanningLocal = true; + startXLocal = e.clientX - state.panX; + startYLocal = e.clientY - state.panY; + doc.body.style.cursor = 'grabbing'; + }; + + doc.onmouseup = () => { + isPanningLocal = false; + doc.body.style.cursor = 'default'; + }; + + doc.onmousemove = (e) => { + if (!isPanningLocal) { + return; + } + state.panX = e.clientX - startXLocal; + state.panY = e.clientY - startYLocal; + applyTransform(); + }; + } catch (e) { + preview.replaceChildren(); + + const pre = document.createElement('pre'); + pre.style.color = '#ff6b6b'; + pre.textContent = e.message; + + preview.appendChild(pre); + } +} diff --git a/packages/mermaid-local-editor/static/js/storage.js b/packages/mermaid-local-editor/static/js/storage.js new file mode 100644 index 00000000000..5cf4668432e --- /dev/null +++ b/packages/mermaid-local-editor/static/js/storage.js @@ -0,0 +1,50 @@ +export function createStorage() { + let diagrams = JSON.parse(localStorage.getItem('mermaid-diagrams') || '{}'); + let current = localStorage.getItem('mermaid-current') || 'main'; + + if (!diagrams[current]) { + diagrams[current] = { + src: `flowchart LR\n UI --> RuntimeBus --> Orchestrator --> Agents`, + view: { scale: 1, panX: 0, panY: 0 }, + }; + } + + function save() { + localStorage.setItem('mermaid-diagrams', JSON.stringify(diagrams)); + localStorage.setItem('mermaid-current', current); + } + + return { + get diagrams() { + return diagrams; + }, + get current() { + return current; + }, + + setCurrent(name) { + current = name; + save(); + }, + + updateCurrent(data) { + diagrams[current] = { ...diagrams[current], ...data }; + save(); + }, + + deleteCurrent() { + delete diagrams[current]; + current = Object.keys(diagrams)[0] || 'main'; + save(); + }, + + create(name) { + diagrams[name] = { + src: 'flowchart LR\n A --> B', + view: { scale: 1, panX: 0, panY: 0 }, + }; + current = name; + save(); + }, + }; +} diff --git a/packages/mermaid-local-editor/static/js/ui.js b/packages/mermaid-local-editor/static/js/ui.js new file mode 100644 index 00000000000..6d5c03228a9 --- /dev/null +++ b/packages/mermaid-local-editor/static/js/ui.js @@ -0,0 +1,117 @@ +export function refreshList({ diagramsSelect, nameInput, storage }) { + diagramsSelect.innerHTML = ''; + Object.keys(storage.diagrams).forEach((k) => { + const opt = document.createElement('option'); + opt.value = k; + opt.textContent = k; + diagramsSelect.appendChild(opt); + }); + diagramsSelect.value = storage.current; + nameInput.value = storage.current; +} + +export function setupUI({ + src, + diagramsSelect, + nameInput, + storage, + state, + render, + load, + applyTransform, +}) { + document.getElementById('save').onclick = () => { + const name = nameInput.value.trim(); + if (!name) { + return; + } + + storage.setCurrent(name); + storage.updateCurrent({ + src: src.value, + view: { scale: state.scale, panX: state.panX, panY: state.panY }, + }); + refreshList({ diagramsSelect, nameInput, storage }); + }; + + document.getElementById('new').onclick = () => { + const name = prompt('Enter diagram name'); + if (!name) { + return; + } + + storage.create(name); + load(name); + }; + + document.getElementById('del').onclick = () => { + if (!confirm(`Delete diagram "${storage.current}"?`)) { + return; + } + + storage.deleteCurrent(); + load(storage.current); + }; + + document.getElementById('resetView').onclick = () => { + state.scale = 1; + state.panX = 0; + state.panY = 0; + applyTransform(); // this will save the reset to storage.diagrams[storage.current].view + }; + + document.getElementById('exportSvg').onclick = () => { + if (!state.iframeRef) { + return; + } + + const svg = state.iframeRef.contentDocument?.querySelector('svg'); + if (!svg) { + return; + } + + const blob = new Blob([svg.outerHTML], { type: 'image/svg+xml' }); + const url = URL.createObjectURL(blob); + + const a = document.createElement('a'); + a.href = url; + a.download = `${storage.current}.svg`; + a.click(); + + URL.revokeObjectURL(url); + }; + + diagramsSelect.onchange = () => load(diagramsSelect.value); + + let saveTimer; + src.addEventListener('input', () => { + render(); + + clearTimeout(saveTimer); + saveTimer = setTimeout(() => { + if (storage.diagrams[storage.current]) { + storage.updateCurrent({ src: src.value }); + } + }, 300); + }); + + const toolbar = document.getElementById('srcPanel'); + const toggleToolbarBtn = document.getElementById('toggleToolbar'); + + let toolbarCollapsed = localStorage.getItem('toolbar-collapsed') === '1'; + + function applyToolbarState() { + toolbar.classList.toggle('collapsed', toolbarCollapsed); + toggleToolbarBtn.textContent = toolbarCollapsed ? '☰' : '✕'; + toggleToolbarBtn.title = toolbarCollapsed ? 'Show toolbar' : 'Hide toolbar'; + } + + toggleToolbarBtn.onclick = () => { + toolbarCollapsed = !toolbarCollapsed; + localStorage.setItem('toolbar-collapsed', toolbarCollapsed ? '1' : '0'); + applyToolbarState(); + }; + + applyToolbarState(); + refreshList({ diagramsSelect, nameInput, storage }); +} diff --git a/packages/mermaid-local-editor/static/styles.css b/packages/mermaid-local-editor/static/styles.css new file mode 100644 index 00000000000..1559f434586 --- /dev/null +++ b/packages/mermaid-local-editor/static/styles.css @@ -0,0 +1,111 @@ +body { + margin: 0; + display: grid; + grid-template-rows: 40px 1fr; + height: 100vh; + background: #0f1115; + color: #ddd; +} +#toolbar { + position: relative; + display: flex; + gap: 8px; + padding: 6px 10px; + background: #0b0d12; + border-bottom: 1px solid #222; + transition: + transform 0.25s ease, + opacity 0.2s ease, + height 0.25s ease; + will-change: transform, opacity, height; +} +#toolbar input, +#toolbar select, +#toolbar button { + background: #111; + color: #ddd; + border: 1px solid #333; + padding: 4px 8px; +} +#srcPanel { + z-index: 1000; +} +#srcPanel.collapsed { + transform: translateY(-100%); + opacity: 0; + height: 0; + padding: 0 8px; + overflow: hidden; +} + +/* Node highlight styling */ +svg .node rect, +svg .node polygon, +svg .node path { + transition: + fill 120ms ease, + filter 120ms ease; +} + +svg .node:hover rect, +svg .node:hover polygon, +svg .node:hover path { + fill: rgba(0, 170, 255, 0.25); /* fon */ + filter: drop-shadow(0 0 11px rgba(0, 170, 255, 0.6)); /* glow */ +} + +/* Keyboard-selected node styling */ +svg g.node.selected-node rect, +svg g.node.selected-node polygon, +svg g.node.selected-node path { + fill: rgba(0, 170, 255, 0.28); + filter: drop-shadow(0 0 14px rgba(0, 170, 255, 0.9)); + transition: + fill 120ms ease, + filter 120ms ease; +} + +p, +div, +div > * { + user-select: none; +} + +#toggleToolbar { + cursor: pointer; + background: #1f2020; + color: #ccc; + border: 1px solid #2a2a2a; + border-radius: 6px; + padding: 4px 8px; +} + +#preview svg { + width: 100%; + height: auto; + padding: 12px; + position: relative; + overflow: visible; + display: block; /* removes inline centering */ + margin: 0; /* removes auto-indents */ + transform-origin: 0 0; /* transformation anchor */ +} +#preview svg g { + transform-origin: 0 0; +} +#main { + display: grid; + grid-template-columns: 0.5fr 1fr; + height: calc(100vh - 40px); + overflow: hidden; +} +textarea { + width: 100%; + height: 100%; + background: #0b0d12; + color: #e6e6e6; + border: none; + padding: 12px; + font-family: monospace; + font-size: 14px; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index edc7575b012..afcc5230ec1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -199,6 +199,9 @@ importers: rollup-plugin-visualizer: specifier: ^6.0.5 version: 6.0.5(rollup@4.60.1) + sirv-cli: + specifier: ^3.0.1 + version: 3.0.1 start-server-and-test: specifier: ^2.1.3 version: 2.1.3 @@ -468,6 +471,8 @@ importers: specifier: ^2.0.2 version: 2.0.2 + packages/mermaid-local-editor: {} + packages/mermaid-zenuml: dependencies: '@zenuml/core': @@ -4874,6 +4879,10 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + console-clear@1.1.1: + resolution: {integrity: sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==} + engines: {node: '>=4'} + console.table@0.10.0: resolution: {integrity: sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==} engines: {node: '> 0.10'} @@ -6224,6 +6233,10 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-port@5.1.1: + resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} + engines: {node: '>=8'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -7224,6 +7237,10 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} @@ -7309,6 +7326,10 @@ packages: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} + local-access@1.1.0: + resolution: {integrity: sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==} + engines: {node: '>=6'} + local-pkg@1.1.2: resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} @@ -8748,6 +8769,10 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -8805,6 +8830,10 @@ packages: resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} engines: {node: '>=10'} + semiver@1.1.0: + resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==} + engines: {node: '>=6'} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -8946,6 +8975,11 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + sirv-cli@3.0.1: + resolution: {integrity: sha512-ICXaF2u6IQhLZ0EXF6nqUF4YODfSQSt+mGykt4qqO5rY+oIiwdg7B8w2PVDBJlQulaS2a3J8666CUoDoAuCGvg==} + engines: {node: '>=18'} + hasBin: true + sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -9356,6 +9390,10 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinydate@1.3.0: + resolution: {integrity: sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==} + engines: {node: '>=4'} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} @@ -15242,6 +15280,8 @@ snapshots: consola@3.4.2: {} + console-clear@1.1.1: {} + console.table@0.10.0: dependencies: easy-table: 1.1.0 @@ -16990,6 +17030,8 @@ snapshots: get-package-type@0.1.0: {} + get-port@5.1.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -18208,6 +18250,8 @@ snapshots: kind-of@6.0.3: {} + kleur@4.1.5: {} + kolorist@1.8.0: {} ky@0.30.0: {} @@ -18314,6 +18358,8 @@ snapshots: loader-runner@4.3.0: {} + local-access@1.1.0: {} + local-pkg@1.1.2: dependencies: mlly: 1.8.0 @@ -19982,6 +20028,10 @@ snapshots: dependencies: tslib: 2.8.1 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.9 @@ -20042,6 +20092,8 @@ snapshots: '@types/node-forge': 1.3.14 node-forge: 1.3.1 + semiver@1.1.0: {} + semver@5.7.2: {} semver@6.3.1: {} @@ -20259,6 +20311,17 @@ snapshots: once: 1.4.0 simple-concat: 1.0.1 + sirv-cli@3.0.1: + dependencies: + console-clear: 1.1.1 + get-port: 5.1.1 + kleur: 4.1.5 + local-access: 1.1.0 + sade: 1.8.1 + semiver: 1.1.0 + sirv: 3.0.2 + tinydate: 1.3.0 + sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -20759,6 +20822,8 @@ snapshots: tinybench@2.9.0: {} + tinydate@1.3.0: {} + tinyexec@0.3.2: {} tinyexec@1.0.1: {} diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 7b7934881a3..d030d903688 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -18,6 +18,9 @@ "./demos/dev", "./vite.config.ts", "./vitest.workspace.js", - "eslint.config.js" + "eslint.config.js", + "packages/mermaid-local-editor/static/js/**/*.js", + "packages/mermaid-local-editor/**/*.js", + "packages/mermaid-local-editor/**/*.html" ] }