@hugobatist/smartcode 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +292 -0
- package/dist/cli.js +4324 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +1167 -0
- package/dist/index.js.map +1 -0
- package/dist/static/annotations-panel.js +133 -0
- package/dist/static/annotations-svg.js +108 -0
- package/dist/static/annotations.css +367 -0
- package/dist/static/annotations.js +367 -0
- package/dist/static/app-init.js +497 -0
- package/dist/static/breakpoints.css +69 -0
- package/dist/static/breakpoints.js +197 -0
- package/dist/static/clipboard.js +94 -0
- package/dist/static/collapse-ui.js +325 -0
- package/dist/static/command-history.js +89 -0
- package/dist/static/context-menu.js +334 -0
- package/dist/static/custom-renderer.js +201 -0
- package/dist/static/dagre-layout.js +291 -0
- package/dist/static/diagram-dom.js +241 -0
- package/dist/static/diagram-editor.js +368 -0
- package/dist/static/editor-panel.js +107 -0
- package/dist/static/editor-popovers.js +187 -0
- package/dist/static/event-bus.js +57 -0
- package/dist/static/export.js +181 -0
- package/dist/static/file-tree.js +470 -0
- package/dist/static/ghost-paths.js +397 -0
- package/dist/static/heatmap.css +116 -0
- package/dist/static/heatmap.js +308 -0
- package/dist/static/icons.js +66 -0
- package/dist/static/inline-edit.js +294 -0
- package/dist/static/interaction-state.js +155 -0
- package/dist/static/interaction-tracker.js +93 -0
- package/dist/static/live.html +239 -0
- package/dist/static/main-layout.css +220 -0
- package/dist/static/main.css +334 -0
- package/dist/static/mcp-sessions.js +202 -0
- package/dist/static/modal.css +109 -0
- package/dist/static/modal.js +171 -0
- package/dist/static/node-drag.js +293 -0
- package/dist/static/pan-zoom.js +199 -0
- package/dist/static/renderer.js +280 -0
- package/dist/static/search.css +103 -0
- package/dist/static/search.js +304 -0
- package/dist/static/selection.js +353 -0
- package/dist/static/session-player.css +137 -0
- package/dist/static/session-player.js +411 -0
- package/dist/static/sidebar.css +248 -0
- package/dist/static/svg-renderer.js +313 -0
- package/dist/static/svg-shapes.js +218 -0
- package/dist/static/tokens.css +76 -0
- package/dist/static/vendor/dagre-bundle.js +43 -0
- package/dist/static/vendor/dagre.min.js +3 -0
- package/dist/static/vendor/graphlib.min.js +2 -0
- package/dist/static/viewport-transform.js +107 -0
- package/dist/static/workspace-switcher.js +202 -0
- package/dist/static/ws-client.js +71 -0
- package/dist/static/ws-handler.js +125 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/diagram/service.ts","../src/utils/logger.ts","../src/diagram/annotations.ts","../src/diagram/constants.ts","../src/diagram/parser.ts","../src/diagram/validator.ts","../src/diagram/graph-types.ts","../src/diagram/graph-edge-parser.ts","../src/diagram/graph-parser.ts","../src/utils/paths.ts","../src/project/discovery.ts","../src/diagram/graph-serializer.ts","../src/project/manager.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { DiagramContent, Flag, GhostPathAnnotation, NodeStatus, RiskAnnotation, RiskLevel, ValidationResult } from './types.js';\nimport type { GraphModel } from './graph-types.js';\nimport { parseDiagramContent } from './parser.js';\nimport { injectAnnotations, parseAllAnnotations } from './annotations.js';\nimport { validateMermaidSyntax } from './validator.js';\nimport { parseMermaidToGraph } from './graph-parser.js';\nimport { resolveProjectPath } from '../utils/paths.js';\nimport { discoverMmdFiles } from '../project/discovery.js';\n\n/** All parsed annotation data from a .mmd file */\ninterface AnnotationData {\n raw: string;\n mermaidContent: string;\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n breakpoints: Set<string>;\n risks: Map<string, RiskAnnotation>;\n ghosts: GhostPathAnnotation[];\n}\n\n/**\n * DiagramService -- single entry point for all .mmd file operations.\n * Each instance is bound to a project root for path security.\n */\nexport class DiagramService {\n /** Per-file write locks to serialize concurrent write operations */\n private writeLocks = new Map<string, Promise<void>>();\n\n /**\n * Serialize write operations on a given file path.\n * Each call waits for the previous write on the same file to finish before running.\n * Cleans up lock entry when no further writes are queued.\n */\n private async withWriteLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const prev = this.writeLocks.get(filePath) ?? Promise.resolve();\n const current = prev.then(fn, fn); // run fn after previous completes (even if it failed)\n const settled = current.then(() => {}, () => {}); // swallow errors for the lock chain\n this.writeLocks.set(filePath, settled);\n const result = await current;\n // Clean up lock entry if no subsequent write has been queued\n if (this.writeLocks.get(filePath) === settled) {\n this.writeLocks.delete(filePath);\n }\n return result;\n }\n\n constructor(private readonly projectRoot: string) {}\n\n /**\n * Read a .mmd file and parse all annotations + mermaid content in one pass.\n */\n private async readAllAnnotations(filePath: string): Promise<AnnotationData> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n const { mermaidContent } = parseDiagramContent(raw);\n const { flags, statuses, breakpoints, risks, ghosts } = parseAllAnnotations(raw);\n return { raw, mermaidContent, flags, statuses, breakpoints, risks, ghosts };\n }\n\n /**\n * Read-modify-write cycle for annotation mutations.\n * Acquires the write lock, reads all annotations, calls modifyFn to mutate them,\n * then writes the result back.\n */\n private async modifyAnnotation(\n filePath: string,\n modifyFn: (data: AnnotationData) => void,\n ): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n const data = await this.readAllAnnotations(filePath);\n modifyFn(data);\n await this._writeDiagramInternal(\n filePath, data.mermaidContent, data.flags, data.statuses, data.breakpoints, data.risks, data.ghosts,\n );\n });\n }\n\n /**\n * Read and parse a .mmd file.\n * Resolves path with traversal protection, parses content, and validates syntax.\n */\n async readDiagram(filePath: string): Promise<DiagramContent> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n const { mermaidContent, diagramType } = parseDiagramContent(raw);\n const { flags, statuses, breakpoints, risks, ghosts } = parseAllAnnotations(raw);\n const validation = validateMermaidSyntax(mermaidContent);\n\n // Ensure diagramType from parser is reflected in validation result\n if (diagramType && !validation.diagramType) {\n validation.diagramType = diagramType;\n }\n\n return { raw, mermaidContent, flags, statuses, breakpoints, risks, ghosts, validation, filePath };\n }\n\n /**\n * Read a .mmd file and parse it into a structured GraphModel.\n */\n async readGraph(filePath: string): Promise<GraphModel> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseMermaidToGraph(raw, filePath);\n }\n\n /**\n * Write a .mmd file. If flags or statuses are provided, injects annotation block.\n * Creates parent directories if they don't exist.\n */\n async writeDiagram(\n filePath: string,\n content: string,\n flags?: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n return this.withWriteLock(filePath, () =>\n this._writeDiagramInternal(filePath, content, flags, statuses, breakpoints, risks, ghosts),\n );\n }\n\n /**\n * Write diagram content while preserving existing developer-owned annotations (flags, breakpoints).\n * Reads existing annotations first, merges caller-provided statuses/risks/ghosts on top, preserves flags\n * and breakpoints unconditionally, then writes the merged result atomically under the write lock.\n *\n * Merge semantics:\n * - `content`: always replaces the Mermaid diagram body\n * - `statuses`: if provided, replaces all statuses; if undefined, preserves existing\n * - `risks`: if provided, replaces all risks; if undefined, preserves existing\n * - `ghosts`: if provided, replaces all ghosts; if undefined, preserves existing\n * - `flags`: always preserved from the file (developer-owned, never touched by MCP)\n * - `breakpoints`: always preserved from the file (developer-owned, never touched by MCP)\n */\n async writeDiagramPreserving(\n filePath: string,\n content: string,\n statuses?: Map<string, NodeStatus>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n // Read existing annotations (if file exists)\n let existingFlags = new Map<string, Flag>();\n let existingBreakpoints = new Set<string>();\n let existingStatuses = new Map<string, NodeStatus>();\n let existingRisks = new Map<string, RiskAnnotation>();\n let existingGhosts: GhostPathAnnotation[] = [];\n try {\n const data = await this.readAllAnnotations(filePath);\n existingFlags = data.flags;\n existingBreakpoints = data.breakpoints;\n existingStatuses = data.statuses;\n existingRisks = data.risks;\n existingGhosts = data.ghosts;\n } catch {\n // File doesn't exist yet -- empty defaults are fine\n }\n\n await this._writeDiagramInternal(\n filePath,\n content,\n existingFlags, // always preserve\n statuses ?? existingStatuses, // replace if provided, else preserve\n existingBreakpoints, // always preserve\n risks ?? existingRisks, // replace if provided, else preserve\n ghosts ?? existingGhosts, // replace if provided, else preserve\n );\n });\n }\n\n /**\n * Write raw content to a .mmd file under the write lock.\n * Does NOT process annotations -- writes content as-is.\n * Used by /save endpoint which receives pre-formatted content from the editor.\n */\n async writeRaw(filePath: string, content: string): Promise<void> {\n return this.withWriteLock(filePath, async () => {\n const resolved = this.resolvePath(filePath);\n await mkdir(dirname(resolved), { recursive: true });\n await writeFile(resolved, content, 'utf-8');\n });\n }\n\n /**\n * Internal write without acquiring the lock.\n * Used by methods that already hold the write lock for the same file.\n */\n private async _writeDiagramInternal(\n filePath: string,\n content: string,\n flags?: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n ): Promise<void> {\n const resolved = this.resolvePath(filePath);\n let output = content;\n\n if (flags || statuses || breakpoints || risks || (ghosts && ghosts.length > 0)) {\n output = injectAnnotations(content, flags ?? new Map(), statuses, breakpoints, risks, ghosts);\n }\n\n await mkdir(dirname(resolved), { recursive: true });\n await writeFile(resolved, output, 'utf-8');\n }\n\n /** Get all flags from a .mmd file as an array. */\n async getFlags(filePath: string): Promise<Flag[]> {\n const diagram = await this.readDiagram(filePath);\n return Array.from(diagram.flags.values());\n }\n\n /** Set (add or update) a flag on a specific node. */\n async setFlag(filePath: string, nodeId: string, message: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.flags.set(nodeId, { nodeId, message });\n });\n }\n\n /** Remove a flag from a specific node. */\n async removeFlag(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.flags.delete(nodeId);\n });\n }\n\n /** Get all statuses from a .mmd file. */\n async getStatuses(filePath: string): Promise<Map<string, NodeStatus>> {\n const diagram = await this.readDiagram(filePath);\n return diagram.statuses;\n }\n\n /** Set (add or update) a status on a specific node. */\n async setStatus(filePath: string, nodeId: string, status: NodeStatus): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.statuses.set(nodeId, status);\n });\n }\n\n /** Remove a status from a specific node. */\n async removeStatus(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.statuses.delete(nodeId);\n });\n }\n\n /** Get all breakpoints from a .mmd file. */\n async getBreakpoints(filePath: string): Promise<Set<string>> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).breakpoints;\n }\n\n /** Set (add) a breakpoint on a specific node. */\n async setBreakpoint(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.breakpoints.add(nodeId);\n });\n }\n\n /** Remove a breakpoint from a specific node. */\n async removeBreakpoint(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.breakpoints.delete(nodeId);\n });\n }\n\n /** Get all risk annotations from a .mmd file. */\n async getRisks(filePath: string): Promise<Map<string, RiskAnnotation>> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).risks;\n }\n\n /** Set (add or update) a risk annotation on a specific node. */\n async setRisk(filePath: string, nodeId: string, level: RiskLevel, reason: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.risks.set(nodeId, { nodeId, level, reason });\n });\n }\n\n /** Remove a risk annotation from a specific node. */\n async removeRisk(filePath: string, nodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.risks.delete(nodeId);\n });\n }\n\n /** Get all ghost path annotations from a .mmd file. */\n async getGhosts(filePath: string): Promise<GhostPathAnnotation[]> {\n const resolved = this.resolvePath(filePath);\n const raw = await readFile(resolved, 'utf-8');\n return parseAllAnnotations(raw).ghosts;\n }\n\n /** Add a ghost path annotation to a .mmd file. */\n async addGhost(filePath: string, fromNodeId: string, toNodeId: string, label: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts.push({ fromNodeId, toNodeId, label });\n });\n }\n\n /** Remove a specific ghost path annotation (by from+to+label exact match). */\n async removeGhost(filePath: string, fromNodeId: string, toNodeId: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts = data.ghosts.filter(\n (g) => !(g.fromNodeId === fromNodeId && g.toNodeId === toNodeId),\n );\n });\n }\n\n /** Clear all ghost path annotations from a .mmd file. */\n async clearGhosts(filePath: string): Promise<void> {\n return this.modifyAnnotation(filePath, (data) => {\n data.ghosts = [];\n });\n }\n\n /** Validate the Mermaid syntax of a .mmd file. */\n async validate(filePath: string): Promise<ValidationResult> {\n const diagram = await this.readDiagram(filePath);\n return diagram.validation;\n }\n\n /** List all .mmd files in the project root. */\n async listFiles(): Promise<string[]> {\n return discoverMmdFiles(this.projectRoot);\n }\n\n /**\n * Resolve a relative file path against the project root.\n * Single chokepoint for path security -- rejects path traversal.\n */\n private resolvePath(filePath: string): string {\n return resolveProjectPath(this.projectRoot, filePath);\n }\n}\n","import pc from 'picocolors';\n\nexport const log = {\n info: (...args: unknown[]) => console.error(pc.blue('[smartcode]'), ...args),\n warn: (...args: unknown[]) => console.error(pc.yellow('[smartcode]'), ...args),\n error: (...args: unknown[]) => console.error(pc.red('[smartcode]'), ...args),\n debug: (...args: unknown[]) => {\n if (process.env['DEBUG']) console.error(pc.dim('[smartcode]'), ...args);\n },\n};\n","import type { Flag, GhostPathAnnotation, NodeStatus, RiskAnnotation, RiskLevel } from './types.js';\nimport { log } from '../utils/logger.js';\n\nexport const ANNOTATION_START = '%% --- ANNOTATIONS (auto-managed by SmartCode) ---';\n/** Legacy start marker for backward compat with existing .mmd files */\nconst ANNOTATION_START_LEGACY = '%% --- ANNOTATIONS (auto-managed by SmartB Diagrams) ---';\nexport const ANNOTATION_END = '%% --- END ANNOTATIONS ---';\n\n/** Check if a line matches either the current or legacy annotation start marker */\nfunction isAnnotationStart(line: string): boolean {\n return line === ANNOTATION_START || line === ANNOTATION_START_LEGACY;\n}\nconst FLAG_REGEX = /^%%\\s*@flag\\s+(\\S+)\\s+\"([^\"]*)\"$/;\nconst STATUS_REGEX = /^%%\\s*@status\\s+(\\S+)\\s+(\\S+)$/;\nexport const BREAKPOINT_REGEX = /^%%\\s*@breakpoint\\s+(\\S+)$/;\nexport const RISK_REGEX = /^%%\\s*@risk\\s+(\\S+)\\s+(high|medium|low)\\s+\"([^\"]*)\"$/;\nexport const GHOST_REGEX = /^%%\\s*@ghost\\s+(\\S+)\\s+(\\S+)\\s+\"([^\"]*)\"$/;\n\nconst VALID_STATUSES: readonly string[] = ['ok', 'problem', 'in-progress', 'discarded'];\n\n/** Result of parsing all annotation types in a single pass */\nexport interface AllAnnotations {\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n breakpoints: Set<string>;\n risks: Map<string, RiskAnnotation>;\n ghosts: GhostPathAnnotation[];\n}\n\n/**\n * Parse all annotation types (flags, statuses, breakpoints, risks) in a single pass.\n * Iterates through lines once, matching each annotation regex.\n * Unrecognized lines inside the annotation block are logged as debug warnings.\n */\nexport function parseAllAnnotations(content: string): AllAnnotations {\n const flags = new Map<string, Flag>();\n const statuses = new Map<string, NodeStatus>();\n const breakpoints = new Set<string>();\n const risks = new Map<string, RiskAnnotation>();\n const ghosts: GhostPathAnnotation[] = [];\n const lines = content.split('\\n');\n\n let inBlock = false;\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (isAnnotationStart(trimmed)) {\n inBlock = true;\n continue;\n }\n\n if (trimmed === ANNOTATION_END) {\n inBlock = false;\n continue;\n }\n\n if (!inBlock || trimmed === '') continue;\n\n let match = FLAG_REGEX.exec(trimmed);\n if (match) {\n flags.set(match[1]!, { nodeId: match[1]!, message: match[2]! });\n continue;\n }\n\n match = STATUS_REGEX.exec(trimmed);\n if (match) {\n const statusValue = match[2]!;\n if (VALID_STATUSES.includes(statusValue)) {\n statuses.set(match[1]!, statusValue as NodeStatus);\n } else {\n log.debug(`Skipping invalid status value: ${statusValue}`);\n }\n continue;\n }\n\n match = BREAKPOINT_REGEX.exec(trimmed);\n if (match) {\n breakpoints.add(match[1]!);\n continue;\n }\n\n match = RISK_REGEX.exec(trimmed);\n if (match) {\n risks.set(match[1]!, { nodeId: match[1]!, level: match[2]! as RiskLevel, reason: match[3]! });\n continue;\n }\n\n match = GHOST_REGEX.exec(trimmed);\n if (match) {\n ghosts.push({ fromNodeId: match[1]!, toNodeId: match[2]!, label: match[3]! });\n continue;\n }\n\n log.debug(`Skipping unrecognized annotation line: ${trimmed}`);\n }\n\n return { flags, statuses, breakpoints, risks, ghosts };\n}\n\n/** Parse all `%% @flag` lines. Delegates to parseAllAnnotations. */\nexport function parseFlags(content: string): Map<string, Flag> {\n return parseAllAnnotations(content).flags;\n}\n\n/** Parse all `%% @status` lines. Delegates to parseAllAnnotations. */\nexport function parseStatuses(content: string): Map<string, NodeStatus> {\n return parseAllAnnotations(content).statuses;\n}\n\n/** Parse all `%% @breakpoint` lines. Delegates to parseAllAnnotations. */\nexport function parseBreakpoints(content: string): Set<string> {\n return parseAllAnnotations(content).breakpoints;\n}\n\n/** Parse all `%% @risk` lines. Delegates to parseAllAnnotations. */\nexport function parseRisks(content: string): Map<string, RiskAnnotation> {\n return parseAllAnnotations(content).risks;\n}\n\n/** Parse all `%% @ghost` lines. Delegates to parseAllAnnotations. */\nexport function parseGhosts(content: string): GhostPathAnnotation[] {\n return parseAllAnnotations(content).ghosts;\n}\n\n/**\n * Remove the entire annotation block (from ANNOTATION_START to ANNOTATION_END inclusive)\n * and any trailing blank lines. Returns pure Mermaid content.\n */\nexport function stripAnnotations(content: string): string {\n const lines = content.split('\\n');\n const result: string[] = [];\n\n let inBlock = false;\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (isAnnotationStart(trimmed)) {\n inBlock = true;\n continue;\n }\n\n if (trimmed === ANNOTATION_END) {\n inBlock = false;\n continue;\n }\n\n if (!inBlock) {\n result.push(line);\n }\n }\n\n // Remove trailing blank lines\n while (result.length > 0 && result[result.length - 1]!.trim() === '') {\n result.pop();\n }\n\n // Ensure single trailing newline\n return result.join('\\n') + '\\n';\n}\n\n/**\n * Strip existing annotations, then append a new annotation block at the end.\n * If both flags and statuses maps are empty, returns content with no annotation block.\n * Escapes double quotes in flag messages by replacing \" with ''.\n */\nexport function injectAnnotations(\n content: string,\n flags: Map<string, Flag>,\n statuses?: Map<string, NodeStatus>,\n breakpoints?: Set<string>,\n risks?: Map<string, RiskAnnotation>,\n ghosts?: GhostPathAnnotation[],\n): string {\n const clean = stripAnnotations(content);\n\n const hasFlags = flags.size > 0;\n const hasStatuses = statuses !== undefined && statuses.size > 0;\n const hasBreakpoints = breakpoints !== undefined && breakpoints.size > 0;\n const hasRisks = risks !== undefined && risks.size > 0;\n const hasGhosts = ghosts !== undefined && ghosts.length > 0;\n\n if (!hasFlags && !hasStatuses && !hasBreakpoints && !hasRisks && !hasGhosts) {\n return clean;\n }\n\n const lines: string[] = [\n '',\n ANNOTATION_START,\n ];\n\n for (const [nodeId, flag] of flags) {\n const escapedMessage = flag.message.replace(/\"/g, \"''\");\n lines.push(`%% @flag ${nodeId} \"${escapedMessage}\"`);\n }\n\n if (hasStatuses) {\n for (const [nodeId, status] of statuses!) {\n lines.push(`%% @status ${nodeId} ${status}`);\n }\n }\n\n if (hasBreakpoints) {\n for (const nodeId of breakpoints!) {\n lines.push(`%% @breakpoint ${nodeId}`);\n }\n }\n\n if (hasRisks) {\n for (const [nodeId, risk] of risks!) {\n const escapedReason = risk.reason.replace(/\"/g, \"''\");\n lines.push(`%% @risk ${nodeId} ${risk.level} \"${escapedReason}\"`);\n }\n }\n\n if (hasGhosts) {\n for (const ghost of ghosts!) {\n const escapedLabel = ghost.label.replace(/\"/g, \"''\");\n lines.push(`%% @ghost ${ghost.fromNodeId} ${ghost.toNodeId} \"${escapedLabel}\"`);\n }\n }\n\n lines.push(ANNOTATION_END);\n lines.push('');\n\n return clean.trimEnd() + '\\n' + lines.join('\\n');\n}\n","/** Known Mermaid diagram type keywords */\nexport const KNOWN_DIAGRAM_TYPES = [\n 'flowchart',\n 'graph',\n 'sequenceDiagram',\n 'classDiagram',\n 'stateDiagram',\n 'erDiagram',\n 'gantt',\n 'pie',\n 'gitgraph',\n 'mindmap',\n 'timeline',\n] as const;\n\n/** Regex to match the start of a Mermaid subgraph definition */\nexport const SUBGRAPH_START = /^\\s*subgraph\\s+([^\\s\\[]+)(?:\\s*\\[\"([^\"]+)\"\\])?/;\n\n/** Regex to match the end of a Mermaid subgraph definition */\nexport const SUBGRAPH_END = /^\\s*end\\s*$/;\n","import type { Flag } from './types.js';\nimport { stripAnnotations, parseFlags } from './annotations.js';\nimport { KNOWN_DIAGRAM_TYPES } from './constants.js';\n\n/**\n * Extract the diagram type from the first non-empty, non-comment line.\n * Returns the matched type string or undefined if no match.\n */\nexport function parseDiagramType(content: string): string | undefined {\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and Mermaid comments\n if (trimmed === '' || trimmed.startsWith('%%')) continue;\n\n // Check if the line starts with a known diagram type keyword\n for (const diagramType of KNOWN_DIAGRAM_TYPES) {\n if (trimmed === diagramType || trimmed.startsWith(diagramType + ' ')) {\n return diagramType;\n }\n }\n\n // First non-empty, non-comment line didn't match any known type\n return undefined;\n }\n\n return undefined;\n}\n\n/**\n * Convenience function that strips annotations, parses flags, and detects diagram type.\n * Returns all three results together.\n */\nexport function parseDiagramContent(rawContent: string): {\n mermaidContent: string;\n flags: Map<string, Flag>;\n diagramType?: string;\n} {\n const mermaidContent = stripAnnotations(rawContent);\n const flags = parseFlags(rawContent);\n const diagramType = parseDiagramType(mermaidContent);\n\n return { mermaidContent, flags, diagramType };\n}\n","import type { ValidationResult } from './types.js';\nimport { parseDiagramType } from './parser.js';\nimport { KNOWN_DIAGRAM_TYPES } from './constants.js';\n\n/**\n * Validate Mermaid syntax using a regex-based heuristic approach.\n *\n * The @mermaid-js/parser package (v0.6) only supports a limited set of diagram types\n * (info, packet, pie, architecture, gitGraph, radar) and does NOT support flowchart,\n * which is the primary diagram type for SmartCode. We use a heuristic validator that\n * catches obvious syntax errors. Browser-side Mermaid.js catches the rest at render time.\n */\nexport function validateMermaidSyntax(content: string): ValidationResult {\n const errors: ValidationResult['errors'] = [];\n const trimmedContent = content.trim();\n\n if (trimmedContent === '') {\n return { valid: false, errors: [{ message: 'Empty diagram content' }] };\n }\n\n // Detect diagram type from first meaningful line\n const diagramType = parseDiagramType(content);\n\n if (!diagramType) {\n const firstLine = trimmedContent.split('\\n')[0]?.trim() ?? '';\n errors.push({\n message: `Unknown diagram type. First line: \"${firstLine}\". Expected one of: ${KNOWN_DIAGRAM_TYPES.join(', ')}`,\n line: 1,\n });\n return { valid: false, errors, diagramType: undefined };\n }\n\n // Check bracket matching\n const bracketErrors = checkBracketMatching(content);\n errors.push(...bracketErrors);\n\n // Check for dangling arrows (lines ending with --> with nothing after)\n const danglingErrors = checkDanglingArrows(content);\n errors.push(...danglingErrors);\n\n return {\n valid: errors.length === 0,\n errors,\n diagramType,\n };\n}\n\n/**\n * Check for unmatched brackets in the content.\n */\nfunction checkBracketMatching(content: string): ValidationResult['errors'] {\n const errors: ValidationResult['errors'] = [];\n const lines = content.split('\\n');\n\n const pairs: Array<[string, string]> = [['[', ']'], ['(', ')'], ['{', '}']];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineNum = i + 1;\n\n // Skip comment lines\n if (line.trim().startsWith('%%')) continue;\n\n for (const [open, close] of pairs) {\n let depth = 0;\n for (const char of line) {\n if (char === open) depth++;\n if (char === close) depth--;\n if (depth < 0) {\n errors.push({\n message: `Unexpected closing '${close}' without matching '${open}'`,\n line: lineNum,\n });\n break;\n }\n }\n if (depth > 0) {\n errors.push({\n message: `Unclosed '${open}' -- missing '${close}'`,\n line: lineNum,\n });\n }\n }\n }\n\n return errors;\n}\n\n/**\n * Check for dangling arrows (lines ending with an arrow operator and nothing after).\n */\nfunction checkDanglingArrows(content: string): ValidationResult['errors'] {\n const errors: ValidationResult['errors'] = [];\n const lines = content.split('\\n');\n\n const danglingArrowPattern = /-->\\s*$/;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const lineNum = i + 1;\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (trimmed === '' || trimmed.startsWith('%%')) continue;\n\n if (danglingArrowPattern.test(trimmed)) {\n errors.push({\n message: `Dangling arrow -- line ends with '-->' but no target node`,\n line: lineNum,\n });\n }\n }\n\n return errors;\n}\n","import type { Flag, NodeStatus, ValidationResult } from './types.js';\n\nexport type NodeShape =\n | 'rect' | 'rounded' | 'stadium' | 'subroutine' | 'cylinder'\n | 'circle' | 'asymmetric' | 'diamond' | 'hexagon'\n | 'parallelogram' | 'parallelogram-alt' | 'trapezoid' | 'trapezoid-alt';\n\nexport type EdgeType = 'arrow' | 'open' | 'dotted' | 'thick' | 'invisible';\n\nexport type FlowDirection = 'TB' | 'LR' | 'BT' | 'RL';\n\nexport interface GraphNode {\n id: string;\n label: string;\n shape: NodeShape;\n status?: NodeStatus;\n flag?: Flag;\n subgraphId?: string;\n cssClass?: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n}\n\nexport interface GraphEdge {\n id: string;\n from: string;\n to: string;\n label?: string;\n type: EdgeType;\n bidirectional?: boolean;\n}\n\nexport interface GraphSubgraph {\n id: string;\n label: string;\n parentId: string | null;\n nodeIds: string[];\n childSubgraphIds: string[];\n}\n\nexport interface GraphModel {\n diagramType: 'flowchart' | 'graph';\n direction: FlowDirection;\n nodes: Map<string, GraphNode>;\n edges: GraphEdge[];\n subgraphs: Map<string, GraphSubgraph>;\n classDefs: Map<string, string>;\n nodeStyles: Map<string, string>;\n linkStyles: Map<number, string>;\n classAssignments: Map<string, string>;\n filePath: string;\n flags: Map<string, Flag>;\n statuses: Map<string, NodeStatus>;\n validation: ValidationResult;\n}\n\n/** Shape bracket patterns — ordered longest-first for correct parsing precedence */\nexport const SHAPE_PATTERNS: Array<{ open: string; close: string; shape: NodeShape }> = [\n { open: '([', close: '])', shape: 'stadium' },\n { open: '[[', close: ']]', shape: 'subroutine' },\n { open: '[(', close: ')]', shape: 'cylinder' },\n { open: '((', close: '))', shape: 'circle' },\n { open: '{{', close: '}}', shape: 'hexagon' },\n { open: '[/', close: '\\\\]', shape: 'trapezoid' },\n { open: '[\\\\', close: '/]', shape: 'trapezoid-alt' },\n { open: '[/', close: '/]', shape: 'parallelogram' },\n { open: '[\\\\', close: '\\\\]', shape: 'parallelogram-alt' },\n { open: '>', close: ']', shape: 'asymmetric' },\n { open: '{', close: '}', shape: 'diamond' },\n { open: '(', close: ')', shape: 'rounded' },\n { open: '[', close: ']', shape: 'rect' },\n];\n\n/** Edge type to serialization syntax mapping */\nexport const EDGE_SYNTAX: Record<EdgeType, string> = {\n arrow: '-->',\n open: '---',\n dotted: '-.->',\n thick: '==>',\n invisible: '~~~',\n};\n","/**\n * SmartCode - Graph Edge Parser Helpers\n * Extracts edge definitions and node ID references from Mermaid lines.\n * Used by graph-parser.ts as part of the multi-pass pipeline.\n */\n\nimport type { NodeShape, EdgeType } from './graph-types.js';\nimport { SHAPE_PATTERNS } from './graph-types.js';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface SimpleEdge {\n from: string;\n to: string;\n type: EdgeType;\n label?: string;\n bidirectional: boolean;\n}\n\n// ─── Edge parsing patterns ──────────────────────────────────────────────────\n\n/**\n * All edge operator patterns, ordered by specificity (longest first).\n */\nexport const EDGE_OPS: Array<{\n pattern: RegExp;\n type: EdgeType;\n bidirectional: boolean;\n}> = [\n // Bidirectional variants (must come before unidirectional)\n { pattern: /\\s*<==>\\s*/, type: 'thick', bidirectional: true },\n { pattern: /\\s*<-\\.->\\s*/, type: 'dotted', bidirectional: true },\n { pattern: /\\s*<-->\\s*/, type: 'arrow', bidirectional: true },\n // Labeled edges: pipe syntax -->|\"label\"| or -->|label|\n { pattern: /\\s*-->\\|\"([^\"]*)\"\\|\\s*/, type: 'arrow', bidirectional: false },\n { pattern: /\\s*-->\\|([^|]*)\\|\\s*/, type: 'arrow', bidirectional: false },\n // Labeled edges: inline syntax -- \"label\" -->\n { pattern: /\\s*--\\s*\"([^\"]*)\"\\s*-->\\s*/, type: 'arrow', bidirectional: false },\n // Unlabeled operators (order: longest first)\n { pattern: /\\s*~~~\\s*/, type: 'invisible', bidirectional: false },\n { pattern: /\\s*==>\\s*/, type: 'thick', bidirectional: false },\n { pattern: /\\s*-\\.->\\s*/, type: 'dotted', bidirectional: false },\n { pattern: /\\s*---\\s*/, type: 'open', bidirectional: false },\n { pattern: /\\s*-->\\s*/, type: 'arrow', bidirectional: false },\n];\n\n// ─── Inline class stripping ─────────────────────────────────────────────────\n\nexport function stripInlineClass(ref: string): { id: string; className?: string } {\n const classIdx = ref.indexOf(':::');\n if (classIdx === -1) return { id: ref };\n return {\n id: ref.substring(0, classIdx),\n className: ref.substring(classIdx + 3),\n };\n}\n\n// ─── Node shape parsing ─────────────────────────────────────────────────────\n\nexport function parseNodeShape(definition: string): {\n id: string;\n label: string;\n shape: NodeShape;\n className?: string;\n} | null {\n const trimmed = definition.trim();\n if (!trimmed) return null;\n\n const { id: withShape, className } = stripInlineClass(trimmed);\n\n for (const sp of SHAPE_PATTERNS) {\n const openIdx = withShape.indexOf(sp.open);\n if (openIdx === -1) continue;\n\n const nodeId = withShape.substring(0, openIdx).trim();\n if (!nodeId || !/^[\\w][\\w\\d_-]*$/.test(nodeId)) continue;\n\n const afterOpen = withShape.substring(openIdx + sp.open.length);\n if (!afterOpen.endsWith(sp.close)) continue;\n\n const labelRaw = afterOpen.substring(0, afterOpen.length - sp.close.length);\n\n let label = labelRaw;\n if (label.startsWith('\"') && label.endsWith('\"')) {\n label = label.substring(1, label.length - 1);\n }\n\n return { id: nodeId, label, shape: sp.shape, className };\n }\n\n return null;\n}\n\n// ─── Node segment extraction ────────────────────────────────────────────────\n\n/**\n * Split a line into segments around edge operators.\n * E.g., `A[\"Start\"] --> B[\"End\"]` yields `['A[\"Start\"]', 'B[\"End\"]']`\n */\nexport function extractNodeSegments(line: string): string[] {\n let work = line;\n\n for (const op of EDGE_OPS) {\n work = work.replace(op.pattern, ' \\x00 ');\n }\n\n return work.split('\\x00').map(s => s.trim()).filter(Boolean);\n}\n\n// ─── Edge parsing ───────────────────────────────────────────────────────────\n\n/**\n * Parse all edges from a line, handling chained edges like A-->B-->C.\n */\nexport function parseEdgesFromLine(line: string): SimpleEdge[] {\n const result: SimpleEdge[] = [];\n let remaining = line;\n let lastNode: string | null = null;\n\n while (remaining.trim()) {\n let earliest: {\n index: number;\n matchLen: number;\n type: EdgeType;\n bidirectional: boolean;\n label?: string;\n } | null = null;\n\n for (const op of EDGE_OPS) {\n const match = op.pattern.exec(remaining);\n if (match && (earliest === null || match.index < earliest.index)) {\n earliest = {\n index: match.index,\n matchLen: match[0].length,\n type: op.type,\n bidirectional: op.bidirectional,\n label: match[1],\n };\n }\n }\n\n if (!earliest) break;\n\n const beforeOp = remaining.substring(0, earliest.index).trim();\n remaining = remaining.substring(earliest.index + earliest.matchLen);\n\n if (lastNode === null) {\n lastNode = extractNodeId(beforeOp);\n if (!lastNode) break;\n }\n\n const afterTrimmed = remaining.trim();\n const nextNodeId = extractNodeId(afterTrimmed, 'left');\n if (!nextNodeId) break;\n\n result.push({\n from: lastNode,\n to: nextNodeId,\n type: earliest.type,\n label: earliest.label,\n bidirectional: earliest.bidirectional,\n });\n\n lastNode = nextNodeId;\n remaining = advancePastNode(remaining.trim(), nextNodeId);\n }\n\n return result;\n}\n\n// ─── Internal helpers ───────────────────────────────────────────────────────\n\n/**\n * Extract a node ID from text.\n */\nfunction extractNodeId(\n text: string,\n direction: 'right' | 'left' = 'right',\n): string | null {\n if (!text.trim()) return null;\n\n const { id } = stripInlineClass(text.trim());\n\n const shaped = parseNodeShape(text.trim());\n if (shaped) return shaped.id;\n\n if (direction === 'left') {\n const match = /^([\\w][\\w\\d_-]*)/.exec(id);\n return match ? match[1]! : null;\n }\n\n const match = /([\\w][\\w\\d_-]*)$/.exec(id);\n return match ? match[1]! : null;\n}\n\n/**\n * Advance past a node definition in text (including any shape brackets).\n */\nfunction advancePastNode(text: string, nodeId: string): string {\n const { id: cleanText } = stripInlineClass(text);\n\n for (const sp of SHAPE_PATTERNS) {\n const expectedStart = nodeId + sp.open;\n if (cleanText.startsWith(expectedStart)) {\n const closeIdx = cleanText.indexOf(sp.close, expectedStart.length);\n if (closeIdx !== -1) {\n const afterClose = closeIdx + sp.close.length;\n const afterWithClass = text.substring(afterClose);\n const classMatch = /^:::\\S+/.exec(afterWithClass);\n return classMatch\n ? afterWithClass.substring(classMatch[0].length)\n : afterWithClass;\n }\n }\n }\n\n const safeId = regexSafe(nodeId);\n const simplePattern = new RegExp(`^${safeId}(?::::\\\\S+)?`);\n const simpleMatch = simplePattern.exec(text);\n if (simpleMatch) {\n return text.substring(simpleMatch[0].length);\n }\n\n return text.substring(nodeId.length);\n}\n\n/** Escape special regex characters in a string */\nfunction regexSafe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * SmartCode - Mermaid to GraphModel Parser\n * Multi-pass parser that converts raw .mmd content into a structured GraphModel.\n */\n\nimport type { ValidationResult } from './types.js';\nimport type {\n GraphModel, GraphNode, GraphEdge, GraphSubgraph, FlowDirection,\n} from './graph-types.js';\nimport { parseFlags, parseStatuses, stripAnnotations } from './annotations.js';\nimport { validateMermaidSyntax } from './validator.js';\nimport { SUBGRAPH_START, SUBGRAPH_END } from './constants.js';\nimport {\n stripInlineClass, parseNodeShape, extractNodeSegments, parseEdgesFromLine,\n} from './graph-edge-parser.js';\n\n// ─── Main Parser ─────────────────────────────────────────────────────────────\n\n/**\n * Parse raw .mmd content into a structured GraphModel.\n * Uses a multi-pass pipeline: preprocessing, direction, styles,\n * subgraphs, nodes, edges, annotations merge, validation.\n */\nexport function parseMermaidToGraph(rawContent: string, filePath: string): GraphModel {\n // ── Pre-processing ──────────────────────────────────────────────────────\n const flags = parseFlags(rawContent);\n const statuses = parseStatuses(rawContent);\n const mermaidContent = stripAnnotations(rawContent);\n const lines = mermaidContent.split('\\n');\n\n // ── Pass 1: Parse direction line ────────────────────────────────────────\n let diagramType: 'flowchart' | 'graph' = 'flowchart';\n let direction: FlowDirection = 'TB';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('%%')) continue;\n\n const dirMatch = /^(flowchart|graph)\\s+(TB|TD|BT|LR|RL)/.exec(trimmed);\n if (dirMatch) {\n diagramType = dirMatch[1] as 'flowchart' | 'graph';\n const rawDir = dirMatch[2]!;\n direction = rawDir === 'TD' ? 'TB' : rawDir as FlowDirection;\n }\n break; // Only check the first non-empty, non-comment line\n }\n\n // ── Pass 2: Extract style directives ────────────────────────────────────\n const classDefs = new Map<string, string>();\n const nodeStyles = new Map<string, string>();\n const linkStyles = new Map<number, string>();\n const classAssignments = new Map<string, string>();\n const directiveLineIndices = new Set<number>();\n\n parseStyleDirectives(\n lines, classDefs, nodeStyles, linkStyles, classAssignments, directiveLineIndices,\n );\n\n // ── Pass 3: Parse subgraph structure ────────────────────────────────────\n const subgraphs = new Map<string, GraphSubgraph>();\n const lineToSubgraph = new Map<number, string>();\n const subgraphLineIndices = new Set<number>();\n\n parseSubgraphStructure(lines, subgraphs, lineToSubgraph, subgraphLineIndices);\n\n // ── Pass 4: Parse node definitions ──────────────────────────────────────\n const nodes = new Map<string, GraphNode>();\n\n parseNodeDefinitions(\n lines, nodes, classAssignments, lineToSubgraph,\n directiveLineIndices, subgraphLineIndices,\n );\n\n // ── Pass 5: Parse edge definitions ──────────────────────────────────────\n const edges: GraphEdge[] = [];\n\n parseEdgeDefinitions(\n lines, edges, nodes, subgraphs, lineToSubgraph,\n directiveLineIndices, subgraphLineIndices,\n );\n\n // ── Pass 6: Merge annotations into nodes ────────────────────────────────\n for (const [nodeId, flag] of flags) {\n const node = nodes.get(nodeId);\n if (node) node.flag = flag;\n }\n\n for (const [nodeId, status] of statuses) {\n const node = nodes.get(nodeId);\n if (node) node.status = status;\n }\n\n // ── Pass 7: Validate ───────────────────────────────────────────────────\n const validation: ValidationResult = validateMermaidSyntax(mermaidContent);\n\n // ── Assemble and return ─────────────────────────────────────────────────\n return {\n diagramType,\n direction,\n nodes,\n edges,\n subgraphs,\n classDefs,\n nodeStyles,\n linkStyles,\n classAssignments,\n filePath,\n flags,\n statuses,\n validation,\n };\n}\n\n// ─── Pass 2: Style directives ───────────────────────────────────────────────\n\nfunction parseStyleDirectives(\n lines: string[],\n classDefs: Map<string, string>,\n nodeStyles: Map<string, string>,\n linkStyles: Map<number, string>,\n classAssignments: Map<string, string>,\n directiveLineIndices: Set<number>,\n): void {\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n\n const classDefMatch = /^classDef\\s+(\\S+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (classDefMatch) {\n const name = classDefMatch[1]!;\n classDefs.set(name, classDefMatch[2]!.replace(/;\\s*$/, ''));\n directiveLineIndices.add(i);\n continue;\n }\n\n const styleMatch = /^style\\s+(\\S+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (styleMatch) {\n nodeStyles.set(styleMatch[1]!, styleMatch[2]!.replace(/;\\s*$/, ''));\n directiveLineIndices.add(i);\n continue;\n }\n\n const linkStyleMatch = /^linkStyle\\s+(\\d+)\\s+(.+);?\\s*$/.exec(trimmed);\n if (linkStyleMatch) {\n linkStyles.set(\n parseInt(linkStyleMatch[1]!, 10),\n linkStyleMatch[2]!.replace(/;\\s*$/, ''),\n );\n directiveLineIndices.add(i);\n continue;\n }\n\n const classDirectiveMatch = /^class\\s+(.+?)\\s+(\\S+);?\\s*$/.exec(trimmed);\n if (classDirectiveMatch) {\n const className = classDirectiveMatch[2]!.replace(/;\\s*$/, '');\n const nodeIds = classDirectiveMatch[1]!.split(',').map(s => s.trim());\n for (const nid of nodeIds) {\n classAssignments.set(nid, className);\n }\n directiveLineIndices.add(i);\n continue;\n }\n }\n}\n\n// ─── Pass 3: Subgraph structure ─────────────────────────────────────────────\n\nfunction parseSubgraphStructure(\n lines: string[],\n subgraphs: Map<string, GraphSubgraph>,\n lineToSubgraph: Map<number, string>,\n subgraphLineIndices: Set<number>,\n): void {\n const subgraphStack: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const startMatch = SUBGRAPH_START.exec(line);\n\n if (startMatch) {\n const id = startMatch[1]!;\n const label = startMatch[2] || id;\n const parentId = subgraphStack.length > 0\n ? subgraphStack[subgraphStack.length - 1]!\n : null;\n\n const sg: GraphSubgraph = {\n id, label, parentId, nodeIds: [], childSubgraphIds: [],\n };\n\n subgraphs.set(id, sg);\n if (parentId) {\n const parent = subgraphs.get(parentId);\n if (parent) parent.childSubgraphIds.push(id);\n }\n\n subgraphStack.push(id);\n subgraphLineIndices.add(i);\n continue;\n }\n\n if (SUBGRAPH_END.test(line) && subgraphStack.length > 0) {\n subgraphStack.pop();\n subgraphLineIndices.add(i);\n continue;\n }\n\n if (subgraphStack.length > 0) {\n lineToSubgraph.set(i, subgraphStack[subgraphStack.length - 1]!);\n }\n }\n}\n\n// ─── Pass 4: Node definitions ───────────────────────────────────────────────\n\nconst DIRECTION_LINE = /^(flowchart|graph)\\s+(TB|TD|BT|LR|RL)/;\n\nfunction isSkippableLine(\n trimmed: string,\n lineIdx: number,\n directiveIndices: Set<number>,\n subgraphIndices: Set<number>,\n): boolean {\n if (directiveIndices.has(lineIdx)) return true;\n if (subgraphIndices.has(lineIdx)) return true;\n if (!trimmed || trimmed.startsWith('%%')) return true;\n if (DIRECTION_LINE.test(trimmed)) return true;\n return false;\n}\n\nfunction parseNodeDefinitions(\n lines: string[],\n nodes: Map<string, GraphNode>,\n classAssignments: Map<string, string>,\n lineToSubgraph: Map<number, string>,\n directiveLineIndices: Set<number>,\n subgraphLineIndices: Set<number>,\n): void {\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (isSkippableLine(trimmed, i, directiveLineIndices, subgraphLineIndices)) continue;\n\n const nodeSegments = extractNodeSegments(trimmed);\n\n for (const segment of nodeSegments) {\n const parsed = parseNodeShape(segment);\n if (parsed && !nodes.has(parsed.id)) {\n const subgraphId = lineToSubgraph.get(i);\n const cssClass = parsed.className || classAssignments.get(parsed.id);\n\n nodes.set(parsed.id, {\n id: parsed.id,\n label: parsed.label,\n shape: parsed.shape,\n subgraphId,\n cssClass,\n });\n\n if (parsed.className) {\n classAssignments.set(parsed.id, parsed.className);\n }\n } else if (!parsed) {\n // Handle bare ID:::className (no shape brackets)\n const { id: bareId, className } = stripInlineClass(segment.trim());\n if (className && /^[\\w][\\w\\d_-]*$/.test(bareId)) {\n classAssignments.set(bareId, className);\n if (!nodes.has(bareId)) {\n nodes.set(bareId, {\n id: bareId,\n label: bareId,\n shape: 'rect',\n subgraphId: lineToSubgraph.get(i),\n cssClass: className,\n });\n } else {\n nodes.get(bareId)!.cssClass = className;\n }\n }\n }\n }\n }\n}\n\n// ─── Pass 5: Edge definitions ───────────────────────────────────────────────\n\nfunction parseEdgeDefinitions(\n lines: string[],\n edges: GraphEdge[],\n nodes: Map<string, GraphNode>,\n subgraphs: Map<string, GraphSubgraph>,\n lineToSubgraph: Map<number, string>,\n directiveLineIndices: Set<number>,\n subgraphLineIndices: Set<number>,\n): void {\n const edgeIdCounts = new Map<string, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (isSkippableLine(trimmed, i, directiveLineIndices, subgraphLineIndices)) continue;\n\n const lineEdges = parseEdgesFromLine(trimmed);\n\n for (const edgeInfo of lineEdges) {\n const { id: fromId } = stripInlineClass(edgeInfo.from);\n const { id: toId } = stripInlineClass(edgeInfo.to);\n\n ensureNode(nodes, fromId, lineToSubgraph.get(i));\n ensureNode(nodes, toId, lineToSubgraph.get(i));\n\n // Track nodes inside subgraphs\n const sgId = lineToSubgraph.get(i);\n if (sgId) {\n const sg = subgraphs.get(sgId);\n if (sg) {\n if (!sg.nodeIds.includes(fromId) && !subgraphs.has(fromId)) {\n sg.nodeIds.push(fromId);\n }\n if (!sg.nodeIds.includes(toId) && !subgraphs.has(toId)) {\n sg.nodeIds.push(toId);\n }\n }\n }\n\n const baseId = `${fromId}->${toId}`;\n const count = edgeIdCounts.get(baseId) || 0;\n const edgeId = count === 0 ? baseId : `${baseId}#${count}`;\n edgeIdCounts.set(baseId, count + 1);\n\n edges.push({\n id: edgeId,\n from: fromId,\n to: toId,\n type: edgeInfo.type,\n label: edgeInfo.label,\n bidirectional: edgeInfo.bidirectional || undefined,\n });\n }\n }\n}\n\n// ─── Helper: ensure a node exists in the map ────────────────────────────────\n\nfunction ensureNode(\n nodes: Map<string, GraphNode>,\n id: string,\n subgraphId?: string,\n): void {\n if (nodes.has(id)) return;\n nodes.set(id, { id, label: id, shape: 'rect', subgraphId });\n}\n","import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve path to static assets bundled with the package.\n * Works regardless of global/local install location.\n *\n * In production (built): __dirname points to dist/\n * -> static assets at dist/static/ (../static from dist/)\n * In development/test: __dirname points to src/utils/\n * -> static assets at <root>/static/ (../../static from src/utils/)\n */\nexport function getStaticDir(): string {\n // Production path: dist/ -> dist/static/\n const prodPath = path.join(__dirname, '..', 'static');\n if (existsSync(prodPath)) return prodPath;\n\n // Development path: src/utils/ -> <root>/static/\n const devPath = path.join(__dirname, '..', '..', 'static');\n if (existsSync(devPath)) return devPath;\n\n // Fallback to original behavior\n return prodPath;\n}\n\nexport function getStaticFile(filename: string): string {\n return path.join(getStaticDir(), filename);\n}\n\n/**\n * Resolve a relative file path against a project root.\n * Throws if the resolved path escapes the project root (path traversal protection).\n */\nexport function resolveProjectPath(projectRoot: string, filePath: string): string {\n const resolvedRoot = path.resolve(projectRoot);\n const resolved = path.resolve(resolvedRoot, filePath);\n if (!resolved.startsWith(resolvedRoot + path.sep) && resolved !== resolvedRoot) {\n throw new Error(`Path traversal detected: ${filePath}`);\n }\n return resolved;\n}\n","import { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/** Directories excluded from .mmd file discovery */\nconst EXCLUDED_DIRS = new Set([\n 'node_modules', '.git', 'test', 'dist', '.planning', '.smartcode',\n]);\n\n/**\n * Discover all .mmd files recursively under the given directory.\n * Returns relative paths (relative to the directory).\n * Excludes node_modules, .git, test, dist, .planning, and .smartcode directories.\n * Results are sorted alphabetically for deterministic output.\n *\n * Uses recursive readdir (Node 18.17+) with post-filtering to avoid\n * external CJS dependency bundling issues with tsup ESM output.\n */\nexport async function discoverMmdFiles(directory: string): Promise<string[]> {\n const entries = await readdir(directory, { recursive: true, withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.mmd')) continue;\n\n // Build relative path from parentPath (available since Node 18.17)\n const parentPath = (entry as { parentPath?: string }).parentPath ?? '';\n const relativePath = parentPath\n ? join(parentPath, entry.name).slice(directory.length + 1)\n : entry.name;\n\n // Check if any path segment is in the excluded set\n const segments = relativePath.split('/');\n const excluded = segments.some((seg) => EXCLUDED_DIRS.has(seg));\n if (!excluded) {\n files.push(relativePath);\n }\n }\n\n return files.sort();\n}\n","/**\n * SmartCode - GraphModel to Mermaid Serializer\n * Converts a structured GraphModel back into valid Mermaid flowchart text.\n * Counterpart to graph-parser.ts — together they enable round-trip fidelity.\n */\n\nimport type { GraphModel, GraphSubgraph, NodeShape } from './graph-types.js';\nimport { SHAPE_PATTERNS, EDGE_SYNTAX } from './graph-types.js';\n\n// ─── Shape reverse lookup ───────────────────────────────────────────────────\n\n/** Map from shape name to bracket pair { open, close } */\nconst SHAPE_BRACKETS = new Map<NodeShape, { open: string; close: string }>();\n\nfor (const sp of SHAPE_PATTERNS) {\n // Only set the first match per shape (SHAPE_PATTERNS is ordered longest-first)\n if (!SHAPE_BRACKETS.has(sp.shape)) {\n SHAPE_BRACKETS.set(sp.shape, { open: sp.open, close: sp.close });\n }\n}\n\n// ─── Main serializer ────────────────────────────────────────────────────────\n\n/**\n * Serialize a GraphModel to valid Mermaid flowchart text.\n *\n * Output order (canonical):\n * 1. Direction line: `flowchart LR`\n * 2. classDef directives\n * 3. Subgraph blocks (recursive, with nodes inside)\n * 4. Root-level nodes (not inside any subgraph)\n * 5. Edges\n * 6. style directives\n * 7. linkStyle directives\n * 8. class assignments\n */\nexport function serializeGraphToMermaid(graph: GraphModel): string {\n const lines: string[] = [];\n\n // 1. Direction line\n lines.push(`${graph.diagramType} ${graph.direction}`);\n\n // 2. classDef directives\n for (const [name, styles] of graph.classDefs) {\n lines.push(` classDef ${name} ${styles}`);\n }\n\n // 3. Subgraph blocks (recursive) — track which nodes are emitted inside subgraphs\n const emittedNodes = new Set<string>();\n\n // Find root-level subgraphs (parentId === null)\n const rootSubgraphs: GraphSubgraph[] = [];\n for (const sg of graph.subgraphs.values()) {\n if (sg.parentId === null) {\n rootSubgraphs.push(sg);\n }\n }\n\n for (const sg of rootSubgraphs) {\n emitSubgraph(graph, sg, lines, emittedNodes, 1);\n }\n\n // 4. Root-level nodes (not emitted inside any subgraph)\n for (const [id, node] of graph.nodes) {\n if (emittedNodes.has(id)) continue;\n lines.push(` ${serializeNode(id, node.label, node.shape)}`);\n }\n\n // 5. Edges\n for (const edge of graph.edges) {\n const arrow = serializeEdgeOperator(edge.type, edge.bidirectional, edge.label);\n lines.push(` ${edge.from} ${arrow} ${edge.to}`);\n }\n\n // 6. style directives\n for (const [nodeId, styles] of graph.nodeStyles) {\n lines.push(` style ${nodeId} ${styles}`);\n }\n\n // 7. linkStyle directives\n const sortedLinkStyles = [...graph.linkStyles.entries()].sort((a, b) => a[0] - b[0]);\n for (const [idx, styles] of sortedLinkStyles) {\n lines.push(` linkStyle ${idx} ${styles}`);\n }\n\n // 8. class assignments — group by class name\n const classGroups = new Map<string, string[]>();\n for (const [nodeId, className] of graph.classAssignments) {\n if (!classGroups.has(className)) {\n classGroups.set(className, []);\n }\n classGroups.get(className)!.push(nodeId);\n }\n for (const [className, nodeIds] of classGroups) {\n lines.push(` class ${nodeIds.join(',')} ${className}`);\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n// ─── Subgraph emitter (recursive) ───────────────────────────────────────────\n\nfunction emitSubgraph(\n graph: GraphModel,\n sg: GraphSubgraph,\n lines: string[],\n emittedNodes: Set<string>,\n depth: number,\n): void {\n const indent = ' '.repeat(depth);\n\n // Subgraph header\n if (sg.label !== sg.id) {\n lines.push(`${indent}subgraph ${sg.id}[\"${sg.label}\"]`);\n } else {\n lines.push(`${indent}subgraph ${sg.id}`);\n }\n\n // Child subgraphs first\n for (const childId of sg.childSubgraphIds) {\n const child = graph.subgraphs.get(childId);\n if (child) {\n emitSubgraph(graph, child, lines, emittedNodes, depth + 1);\n }\n }\n\n // Nodes inside this subgraph\n for (const nodeId of sg.nodeIds) {\n const node = graph.nodes.get(nodeId);\n if (node) {\n lines.push(`${indent} ${serializeNode(nodeId, node.label, node.shape)}`);\n emittedNodes.add(nodeId);\n }\n }\n\n // Also emit nodes that have subgraphId matching this subgraph but aren't in nodeIds\n for (const [id, node] of graph.nodes) {\n if (node.subgraphId === sg.id && !emittedNodes.has(id)) {\n lines.push(`${indent} ${serializeNode(id, node.label, node.shape)}`);\n emittedNodes.add(id);\n }\n }\n\n lines.push(`${indent}end`);\n}\n\n// ─── Node serializer ────────────────────────────────────────────────────────\n\n/**\n * Serialize a single node definition.\n * - If label === id AND shape === 'rect', emit bare id\n * - Otherwise emit id + shape brackets + quoted label\n */\nfunction serializeNode(id: string, label: string, shape: NodeShape): string {\n if (label === id && shape === 'rect') {\n return id;\n }\n\n const brackets = SHAPE_BRACKETS.get(shape);\n if (!brackets) {\n // Fallback to rect brackets\n return `${id}[\"${label}\"]`;\n }\n\n return `${id}${brackets.open}\"${label}\"${brackets.close}`;\n}\n\n// ─── Edge operator serializer ───────────────────────────────────────────────\n\nfunction serializeEdgeOperator(\n type: string,\n bidirectional?: boolean,\n label?: string,\n): string {\n const baseSyntax = EDGE_SYNTAX[type as keyof typeof EDGE_SYNTAX] ?? '-->';\n\n if (bidirectional) {\n // Prepend '<' to make bidirectional: --> becomes <-->, -.-> becomes <-.->\n return `<${baseSyntax}`;\n }\n\n if (label) {\n // Insert label in pipe syntax: -->|\"label\"|\n return `${baseSyntax}|\"${label}\"|`;\n }\n\n return baseSyntax;\n}\n\n// ─── JSON serializer (for WebSocket / REST) ─────────────────────────────────\n\n/**\n * Serialize a GraphModel to a plain JSON-safe object.\n * Converts all Map fields to plain objects for transmission over WebSocket or REST.\n */\nexport function serializeGraphModel(graph: GraphModel): Record<string, unknown> {\n return {\n diagramType: graph.diagramType,\n direction: graph.direction,\n nodes: Object.fromEntries(graph.nodes),\n edges: graph.edges,\n subgraphs: Object.fromEntries(graph.subgraphs),\n classDefs: Object.fromEntries(graph.classDefs),\n nodeStyles: Object.fromEntries(graph.nodeStyles),\n linkStyles: Object.fromEntries(graph.linkStyles),\n classAssignments: Object.fromEntries(graph.classAssignments),\n filePath: graph.filePath,\n flags: Object.fromEntries(graph.flags),\n statuses: Object.fromEntries(graph.statuses),\n };\n}\n","import { statSync } from 'node:fs';\nimport { DiagramService } from '../diagram/service.js';\n\n/**\n * ProjectManager managing multiple project directories.\n * Each project gets its own DiagramService with independent path security.\n */\nexport class ProjectManager {\n private projects = new Map<string, DiagramService>();\n\n /**\n * Register a project directory and return its DiagramService.\n * If the directory is already registered, returns the existing service.\n * Throws if the directory does not exist.\n */\n addProject(rootDir: string): DiagramService {\n const existing = this.projects.get(rootDir);\n if (existing) {\n return existing;\n }\n\n // Validate that the directory exists\n const stat = statSync(rootDir);\n if (!stat.isDirectory()) {\n throw new Error(`Not a directory: ${rootDir}`);\n }\n\n const service = new DiagramService(rootDir);\n this.projects.set(rootDir, service);\n return service;\n }\n\n /**\n * Remove a project from management.\n * Returns true if it was registered, false otherwise.\n */\n removeProject(rootDir: string): boolean {\n return this.projects.delete(rootDir);\n }\n\n /**\n * Get the DiagramService for a registered project directory.\n * Returns undefined if the directory is not registered.\n */\n getProject(rootDir: string): DiagramService | undefined {\n return this.projects.get(rootDir);\n }\n\n /**\n * List all registered project root directories.\n */\n listProjects(): string[] {\n return Array.from(this.projects.keys());\n }\n\n /**\n * Discover .mmd files across all registered projects.\n * Returns a map of rootDir to file lists.\n */\n async discoverAll(): Promise<Map<string, string[]>> {\n const results = new Map<string, string[]>();\n\n for (const [rootDir, service] of this.projects) {\n const files = await service.listFiles();\n results.set(rootDir, files);\n }\n\n return results;\n }\n}\n"],"mappings":"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","names":["match"]}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Annotations Panel -- Panel rendering and navigation for flags.
|
|
3
|
+
* Extracted from annotations.js. Exposed as window.SmartCodeAnnotationsPanel.
|
|
4
|
+
* Dependencies: diagram-dom.js, pan-zoom.js
|
|
5
|
+
*/
|
|
6
|
+
(function () {
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
function renderPanel(state, hooks, removeFlagFn) {
|
|
10
|
+
var list = document.getElementById('flagPanelList');
|
|
11
|
+
if (!list) return;
|
|
12
|
+
var count = document.getElementById('flagPanelCount');
|
|
13
|
+
if (count) {
|
|
14
|
+
count.textContent = state.flags.size;
|
|
15
|
+
count.dataset.count = state.flags.size;
|
|
16
|
+
count.style.display = state.flags.size > 0 ? '' : 'none';
|
|
17
|
+
}
|
|
18
|
+
if (state.flags.size === 0) {
|
|
19
|
+
var emptyDiv = document.createElement('div');
|
|
20
|
+
emptyDiv.className = 'flag-panel-empty';
|
|
21
|
+
emptyDiv.textContent = 'No active flags. Enable Flag Mode (F) and click on a node to flag.';
|
|
22
|
+
list.textContent = '';
|
|
23
|
+
list.appendChild(emptyDiv);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
list.textContent = '';
|
|
27
|
+
|
|
28
|
+
// Show current file name as context
|
|
29
|
+
var currentFile = hooks.getCurrentFile();
|
|
30
|
+
if (currentFile) {
|
|
31
|
+
var fileDiv = document.createElement('div');
|
|
32
|
+
fileDiv.className = 'flag-panel-file';
|
|
33
|
+
fileDiv.textContent = currentFile;
|
|
34
|
+
list.appendChild(fileDiv);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (var entry of state.flags) {
|
|
38
|
+
var nodeId = entry[0];
|
|
39
|
+
var message = entry[1].message;
|
|
40
|
+
var item = document.createElement('div');
|
|
41
|
+
item.className = 'flag-panel-item';
|
|
42
|
+
item.dataset.nodeId = nodeId;
|
|
43
|
+
|
|
44
|
+
var topRow = document.createElement('div');
|
|
45
|
+
topRow.className = 'flag-panel-item-top';
|
|
46
|
+
|
|
47
|
+
var idDiv = document.createElement('div');
|
|
48
|
+
idDiv.className = 'flag-panel-item-id';
|
|
49
|
+
idDiv.textContent = nodeId;
|
|
50
|
+
topRow.appendChild(idDiv);
|
|
51
|
+
|
|
52
|
+
var btnDelete = document.createElement('button');
|
|
53
|
+
btnDelete.className = 'flag-panel-item-delete';
|
|
54
|
+
btnDelete.title = 'Remove flag';
|
|
55
|
+
/* safe: SmartCodeIcons contains static trusted SVG strings */
|
|
56
|
+
btnDelete.innerHTML = SmartCodeIcons.close;
|
|
57
|
+
btnDelete.addEventListener('click', (function(nid) {
|
|
58
|
+
return function(e) {
|
|
59
|
+
e.stopPropagation();
|
|
60
|
+
removeFlagFn(nid);
|
|
61
|
+
};
|
|
62
|
+
})(nodeId));
|
|
63
|
+
topRow.appendChild(btnDelete);
|
|
64
|
+
|
|
65
|
+
item.appendChild(topRow);
|
|
66
|
+
|
|
67
|
+
var msgDiv = document.createElement('div');
|
|
68
|
+
msgDiv.className = 'flag-panel-item-msg';
|
|
69
|
+
if (message) {
|
|
70
|
+
msgDiv.textContent = message;
|
|
71
|
+
} else {
|
|
72
|
+
msgDiv.style.fontStyle = 'italic';
|
|
73
|
+
msgDiv.textContent = '(no note)';
|
|
74
|
+
}
|
|
75
|
+
item.appendChild(msgDiv);
|
|
76
|
+
item.addEventListener('click', (function(nid) {
|
|
77
|
+
return function() { scrollToNode(nid); };
|
|
78
|
+
})(nodeId));
|
|
79
|
+
list.appendChild(item);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function scrollToNode(nodeId) {
|
|
84
|
+
var el = DiagramDOM.findNodeElement(nodeId) || DiagramDOM.findSubgraphElement(nodeId);
|
|
85
|
+
if (!el) { var svg = DiagramDOM.getSVG(); if (svg) el = svg.querySelector('[id="' + CSS.escape(nodeId) + '"]'); }
|
|
86
|
+
if (!el) return;
|
|
87
|
+
// Pan to center the node in the viewport
|
|
88
|
+
if (window.SmartCodePanZoom) {
|
|
89
|
+
var container = document.getElementById('preview-container');
|
|
90
|
+
if (container) {
|
|
91
|
+
var rect = el.getBoundingClientRect();
|
|
92
|
+
var containerRect = container.getBoundingClientRect();
|
|
93
|
+
var pan = SmartCodePanZoom.getPan();
|
|
94
|
+
var centerX = containerRect.width / 2;
|
|
95
|
+
var centerY = containerRect.height / 2;
|
|
96
|
+
var elCenterX = rect.left + rect.width / 2 - containerRect.left;
|
|
97
|
+
var elCenterY = rect.top + rect.height / 2 - containerRect.top;
|
|
98
|
+
SmartCodePanZoom.setPan(pan.panX + (centerX - elCenterX), pan.panY + (centerY - elCenterY));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
flashElement(el);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function flashElement(el) {
|
|
105
|
+
el.style.transition = 'opacity 0.15s'; el.style.opacity = '0.3';
|
|
106
|
+
setTimeout(function() { el.style.opacity = '1'; }, 150);
|
|
107
|
+
setTimeout(function() { el.style.opacity = '0.3'; }, 300);
|
|
108
|
+
setTimeout(function() { el.style.opacity = '1'; el.style.transition = ''; }, 450);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function updateBadge(flagCount) {
|
|
112
|
+
var badge = document.getElementById('flagCountBadge');
|
|
113
|
+
if (badge) {
|
|
114
|
+
badge.textContent = flagCount || '';
|
|
115
|
+
badge.dataset.count = flagCount;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function togglePanel(state) {
|
|
120
|
+
state.panelOpen = !state.panelOpen;
|
|
121
|
+
var panel = document.getElementById('flagPanel');
|
|
122
|
+
if (panel) panel.classList.toggle('hidden', !state.panelOpen);
|
|
123
|
+
if (window.zoomFit) setTimeout(window.zoomFit, 100);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
window.SmartCodeAnnotationsPanel = {
|
|
127
|
+
renderPanel: renderPanel,
|
|
128
|
+
scrollToNode: scrollToNode,
|
|
129
|
+
flashElement: flashElement,
|
|
130
|
+
updateBadge: updateBadge,
|
|
131
|
+
togglePanel: togglePanel,
|
|
132
|
+
};
|
|
133
|
+
})();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartCode Annotations SVG -- SVG overlay rendering for flags.
|
|
3
|
+
* Extracted from annotations.js. Exposed as window.SmartCodeAnnotationsSVG.
|
|
4
|
+
* Dependencies: diagram-dom.js
|
|
5
|
+
*/
|
|
6
|
+
(function () {
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
function svgEl(ns, tag, attrs) {
|
|
10
|
+
var el = document.createElementNS(ns, tag);
|
|
11
|
+
Object.entries(attrs).forEach(function(p) { el.setAttribute(p[0], p[1]); });
|
|
12
|
+
return el;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function addBadge(svg, element, nodeId, flagsMap) {
|
|
16
|
+
var bbox = element.getBBox ? element.getBBox() : null;
|
|
17
|
+
if (!bbox) return;
|
|
18
|
+
var ns = 'http://www.w3.org/2000/svg';
|
|
19
|
+
|
|
20
|
+
// Account for transform="translate(x,y)" on custom renderer nodes
|
|
21
|
+
var tx = 0, ty = 0;
|
|
22
|
+
var transform = element.getAttribute('transform');
|
|
23
|
+
if (transform) {
|
|
24
|
+
var m = transform.match(/translate\(\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)/);
|
|
25
|
+
if (m) { tx = parseFloat(m[1]); ty = parseFloat(m[2]); }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var g = svgEl(ns, 'g', { 'class': 'flag-badge' });
|
|
29
|
+
var cx = tx + bbox.x + bbox.width - 2, cy = ty + bbox.y + 2;
|
|
30
|
+
|
|
31
|
+
g.appendChild(svgEl(ns, 'circle', { cx: cx, cy: cy, r: 12, fill: '#ef4444', stroke: '#fff', 'stroke-width': 2 }));
|
|
32
|
+
var bang = svgEl(ns, 'text', { x: cx, y: cy + 1, 'text-anchor': 'middle', 'dominant-baseline': 'central', fill: '#fff', 'font-size': 13, 'font-weight': 700, 'font-family': 'Inter, sans-serif' });
|
|
33
|
+
bang.textContent = '!';
|
|
34
|
+
g.appendChild(bang);
|
|
35
|
+
|
|
36
|
+
// Flag message label with measured background
|
|
37
|
+
var flagData = nodeId ? flagsMap.get(nodeId) : null;
|
|
38
|
+
if (flagData && flagData.message) {
|
|
39
|
+
var msg = flagData.message.length > 35 ? flagData.message.substring(0, 34) + '\u2026' : flagData.message;
|
|
40
|
+
var label = svgEl(ns, 'text', { x: cx, y: cy + 24, 'text-anchor': 'middle', 'dominant-baseline': 'central', fill: '#fff', 'font-size': 10, 'font-weight': 600, 'font-family': "'JetBrains Mono', Inter, sans-serif" });
|
|
41
|
+
label.textContent = msg;
|
|
42
|
+
// Measure text by temporarily appending
|
|
43
|
+
g.appendChild(label);
|
|
44
|
+
svg.appendChild(g);
|
|
45
|
+
var tBox = label.getBBox();
|
|
46
|
+
svg.removeChild(g);
|
|
47
|
+
g.removeChild(label);
|
|
48
|
+
// Background pill
|
|
49
|
+
var padX = 8, padY = 3;
|
|
50
|
+
g.appendChild(svgEl(ns, 'rect', { x: tBox.x - padX, y: tBox.y - padY, width: tBox.width + padX * 2, height: tBox.height + padY * 2, rx: 8, fill: '#ef4444', opacity: '0.95' }));
|
|
51
|
+
g.appendChild(label);
|
|
52
|
+
var title = document.createElementNS(ns, 'title');
|
|
53
|
+
title.textContent = 'Flag: ' + flagData.message;
|
|
54
|
+
g.appendChild(title);
|
|
55
|
+
}
|
|
56
|
+
svg.appendChild(g);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function applyFlagsToSVG(flagsMap) {
|
|
60
|
+
var svg = DiagramDOM.getSVG();
|
|
61
|
+
if (!svg) return;
|
|
62
|
+
svg.querySelectorAll('.flag-badge').forEach(function(b) { b.remove(); });
|
|
63
|
+
svg.querySelectorAll('.flagged, .flagged-edge').forEach(function(el) {
|
|
64
|
+
el.classList.remove('flagged', 'flagged-edge');
|
|
65
|
+
});
|
|
66
|
+
if (flagsMap.size === 0) return;
|
|
67
|
+
|
|
68
|
+
flagsMap.forEach(function(flagVal, nodeId) {
|
|
69
|
+
// Use DiagramDOM to find node and subgraph elements
|
|
70
|
+
var nodeEl = DiagramDOM.findNodeElement(nodeId);
|
|
71
|
+
if (nodeEl) {
|
|
72
|
+
nodeEl.classList.add('flagged');
|
|
73
|
+
addBadge(svg, nodeEl, nodeId, flagsMap);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
var subEl = DiagramDOM.findSubgraphElement(nodeId);
|
|
77
|
+
if (subEl) {
|
|
78
|
+
subEl.classList.add('flagged');
|
|
79
|
+
addBadge(svg, subEl, nodeId, flagsMap);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Edge flags: check if ID starts with L- (Mermaid) or direct data-edge-id (custom)
|
|
83
|
+
if (nodeId.startsWith('L-')) {
|
|
84
|
+
var edgeEl = svg.querySelector('[id="' + nodeId + '"]');
|
|
85
|
+
if (!edgeEl) {
|
|
86
|
+
var bareEdgeId = nodeId.substring(2);
|
|
87
|
+
edgeEl = svg.querySelector('[data-edge-id="' + bareEdgeId + '"]');
|
|
88
|
+
}
|
|
89
|
+
if (edgeEl) {
|
|
90
|
+
edgeEl.classList.add('flagged-edge');
|
|
91
|
+
addBadge(svg, edgeEl, nodeId, flagsMap);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
var directEdge = svg.querySelector('[data-edge-id="' + nodeId + '"]');
|
|
95
|
+
if (directEdge) {
|
|
96
|
+
directEdge.classList.add('flagged-edge');
|
|
97
|
+
addBadge(svg, directEdge, nodeId, flagsMap);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
window.SmartCodeAnnotationsSVG = {
|
|
104
|
+
applyFlagsToSVG: applyFlagsToSVG,
|
|
105
|
+
addBadge: addBadge,
|
|
106
|
+
svgEl: svgEl,
|
|
107
|
+
};
|
|
108
|
+
})();
|