libpetri 0.3.5 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/debug/debug-command.ts","../../src/debug/marking-cache.ts","../../src/debug/net-event-converter.ts","../../src/debug/debug-protocol-handler.ts","../../src/debug/debug-event-store.ts","../../src/debug/place-analysis.ts","../../src/debug/debug-session-registry.ts","../../src/debug/debug-aware-event-store.ts","../../src/debug/index.ts"],"sourcesContent":["/**\n * Commands sent from debug UI client to server via WebSocket.\n * TypeScript port of Java's DebugCommand sealed interface.\n */\n\nexport type SubscriptionMode = 'live' | 'replay';\n\nexport type BreakpointType =\n | 'TRANSITION_ENABLED'\n | 'TRANSITION_START'\n | 'TRANSITION_COMPLETE'\n | 'TRANSITION_FAIL'\n | 'TOKEN_ADDED'\n | 'TOKEN_REMOVED';\n\nexport interface BreakpointConfig {\n readonly id: string;\n readonly type: BreakpointType;\n readonly target: string | null;\n readonly enabled: boolean;\n}\n\nexport interface EventFilter {\n readonly eventTypes: readonly string[] | null;\n readonly transitionNames: readonly string[] | null;\n readonly placeNames: readonly string[] | null;\n}\n\nexport type DebugCommand =\n | { readonly type: 'subscribe'; readonly sessionId: string; readonly mode: SubscriptionMode; readonly fromIndex?: number }\n | { readonly type: 'unsubscribe'; readonly sessionId: string }\n | { readonly type: 'listSessions'; readonly limit?: number; readonly activeOnly?: boolean }\n | { readonly type: 'seek'; readonly sessionId: string; readonly timestamp: string }\n | { readonly type: 'playbackSpeed'; readonly sessionId: string; readonly speed: number }\n | { readonly type: 'filter'; readonly sessionId: string; readonly filter: EventFilter }\n | { readonly type: 'pause'; readonly sessionId: string }\n | { readonly type: 'resume'; readonly sessionId: string }\n | { readonly type: 'stepForward'; readonly sessionId: string }\n | { readonly type: 'stepBackward'; readonly sessionId: string }\n | { readonly type: 'setBreakpoint'; readonly sessionId: string; readonly breakpoint: BreakpointConfig }\n | { readonly type: 'clearBreakpoint'; readonly sessionId: string; readonly breakpointId: string }\n | { readonly type: 'listBreakpoints'; readonly sessionId: string };\n\nexport function eventFilterAll(): EventFilter {\n return { eventTypes: null, transitionNames: null, placeNames: null };\n}\n","/**\n * Caches computed state snapshots at periodic intervals for efficient seek/step.\n * TypeScript port of Java's MarkingCache.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport type { TokenInfo } from './debug-response.js';\nimport { computeState, applyEvents, toImmutableState, type ComputedState } from './debug-protocol-handler.js';\n\n/** Number of events between cached snapshots. */\nexport const SNAPSHOT_INTERVAL = 256;\n\nexport class MarkingCache {\n private readonly _snapshots: ComputedState[] = [];\n\n /**\n * Computes the state at the given event index, using cached snapshots\n * to minimize the number of events that need to be replayed.\n *\n * @param events the full event list for the session\n * @param targetIndex event index to compute state at (exclusive upper bound)\n */\n computeAt(events: readonly NetEvent[], targetIndex: number): ComputedState {\n if (targetIndex <= 0) {\n return computeState([]);\n }\n\n this.ensureCachedUpTo(events, targetIndex);\n\n if (this._snapshots.length === 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n // Find highest snapshot <= targetIndex\n const snapshotSlot = Math.min(Math.floor(targetIndex / SNAPSHOT_INTERVAL), this._snapshots.length) - 1;\n\n if (snapshotSlot < 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n const snapshotEventIndex = (snapshotSlot + 1) * SNAPSHOT_INTERVAL;\n\n if (snapshotEventIndex === targetIndex) {\n return this._snapshots[snapshotSlot]!;\n }\n\n return replayDelta(this._snapshots[snapshotSlot]!, events.slice(snapshotEventIndex, targetIndex));\n }\n\n /** Invalidates the cache. */\n invalidate(): void {\n this._snapshots.length = 0;\n }\n\n /** Extends the snapshot cache to cover at least up to the given event index. */\n private ensureCachedUpTo(events: readonly NetEvent[], targetIndex: number): void {\n const neededSnapshots = Math.floor(targetIndex / SNAPSHOT_INTERVAL);\n\n while (this._snapshots.length < neededSnapshots) {\n const nextSnapshotIndex = (this._snapshots.length + 1) * SNAPSHOT_INTERVAL;\n if (nextSnapshotIndex > events.length) break;\n\n if (this._snapshots.length === 0) {\n this._snapshots.push(computeState(events.slice(0, nextSnapshotIndex)));\n } else {\n const prevSnapshotIndex = this._snapshots.length * SNAPSHOT_INTERVAL;\n const delta = events.slice(prevSnapshotIndex, nextSnapshotIndex);\n this._snapshots.push(replayDelta(this._snapshots[this._snapshots.length - 1]!, delta));\n }\n }\n }\n}\n\n/** Replays delta events on top of a base snapshot to produce a new state. */\nfunction replayDelta(base: ComputedState, delta: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n for (const [key, value] of base.marking) {\n marking.set(key, [...value]);\n }\n const enabled = new Set(base.enabledTransitions);\n const inFlight = new Set(base.inFlightTransitions);\n applyEvents(marking, enabled, inFlight, delta);\n return toImmutableState(marking, enabled, inFlight);\n}\n","/**\n * Converts CTPN NetEvent instances to serializable DebugResponse types.\n * TypeScript port of Java's NetEventConverter.\n */\n\nimport type { Token } from '../core/token.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { NetEventInfo, TokenInfo } from './debug-response.js';\n\n/** Converts a NetEvent to a serializable NetEventInfo. */\nexport function toEventInfo(event: NetEvent, compact = false): NetEventInfo {\n switch (event.type) {\n case 'execution-started':\n return {\n type: 'ExecutionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: { netName: event.netName, executionId: event.executionId },\n };\n\n case 'execution-completed':\n return {\n type: 'ExecutionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n netName: event.netName,\n executionId: event.executionId,\n totalDurationMs: event.totalDurationMs,\n },\n };\n\n case 'transition-enabled':\n return {\n type: 'TransitionEnabled',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-clock-restarted':\n return {\n type: 'TransitionClockRestarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-started':\n return {\n type: 'TransitionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n consumedTokens: event.consumedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n },\n };\n\n case 'transition-completed':\n return {\n type: 'TransitionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n producedTokens: event.producedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n durationMs: event.durationMs,\n },\n };\n\n case 'transition-failed':\n return {\n type: 'TransitionFailed',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n errorMessage: event.errorMessage,\n exceptionType: event.exceptionType,\n },\n };\n\n case 'transition-timed-out':\n return {\n type: 'TransitionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n deadlineMs: event.deadlineMs,\n actualDurationMs: event.actualDurationMs,\n },\n };\n\n case 'action-timed-out':\n return {\n type: 'ActionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: { timeoutMs: event.timeoutMs },\n };\n\n case 'token-added':\n return {\n type: 'TokenAdded',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'token-removed':\n return {\n type: 'TokenRemoved',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'marking-snapshot':\n return {\n type: 'MarkingSnapshot',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n marking: convertMarking(event.marking, compact),\n },\n };\n\n case 'log-message': {\n const details: Record<string, unknown> = {\n loggerName: event.logger,\n level: event.level,\n message: event.message,\n };\n if (event.error != null) details['throwable'] = event.error;\n if (event.errorMessage != null) details['throwableMessage'] = event.errorMessage;\n return {\n type: 'LogMessage',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details,\n };\n }\n }\n}\n\n/** Converts a Token to serializable TokenInfo with full value. */\nexport function tokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n const fullValue = value != null ? String(value) : 'null';\n return {\n id: null,\n type,\n value: fullValue,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n}\n\n/** Converts a Token to compact TokenInfo (type only, no value). */\nexport function compactTokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n return {\n id: null,\n type,\n value: null,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n}\n\n/** Converts a marking map to serializable form. */\nexport function convertMarking(\n marking: ReadonlyMap<string, readonly Token<unknown>[]>,\n compact = false,\n): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n const mapper = compact ? compactTokenInfo : tokenInfo;\n for (const [name, tokens] of marking) {\n result[name] = tokens.map(mapper);\n }\n return result;\n}\n","/**\n * Framework-agnostic handler for the Petri net debug protocol.\n * TypeScript port of Java's DebugProtocolHandler.\n *\n * Manages debug subscriptions, event filtering, breakpoints, and replay\n * for connected clients. Decoupled from any specific WebSocket framework\n * via the ResponseSink type.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport { sanitize } from '../export/petri-net-mapper.js';\nimport type { DebugCommand, EventFilter, BreakpointConfig } from './debug-command.js';\nimport type { DebugResponse, TokenInfo, NetEventInfo, NetStructure } from './debug-response.js';\nimport type { DebugSession } from './debug-session-registry.js';\nimport type { DebugSessionRegistry } from './debug-session-registry.js';\nimport type { Subscription } from './debug-event-store.js';\nimport { MarkingCache } from './marking-cache.js';\nimport { toEventInfo, tokenInfo, convertMarking } from './net-event-converter.js';\n\n/** Callback for sending responses to a connected client. */\nexport type ResponseSink = (response: DebugResponse) => void;\n\n/** Computed state from replaying events. */\nexport interface ComputedState {\n readonly marking: ReadonlyMap<string, readonly TokenInfo[]>;\n readonly enabledTransitions: readonly string[];\n readonly inFlightTransitions: readonly string[];\n}\n\n/** Maximum events per batch when sending historical events. */\nconst BATCH_SIZE = 500;\n\nexport class DebugProtocolHandler {\n private readonly _sessionRegistry: DebugSessionRegistry;\n private readonly _clients = new Map<string, ClientState>();\n\n constructor(sessionRegistry: DebugSessionRegistry) {\n this._sessionRegistry = sessionRegistry;\n }\n\n /** Registers a new client connection. */\n clientConnected(clientId: string, sink: ResponseSink): void {\n this._clients.set(clientId, new ClientState(sink));\n }\n\n /** Cleans up when a client disconnects. */\n clientDisconnected(clientId: string): void {\n const state = this._clients.get(clientId);\n this._clients.delete(clientId);\n if (state) state.subscriptions.cancelAll();\n }\n\n /** Handles a command from a connected client. */\n handleCommand(clientId: string, command: DebugCommand): void {\n const clientState = this._clients.get(clientId);\n if (!clientState) return;\n\n try {\n switch (command.type) {\n case 'listSessions': this.handleListSessions(clientState, command); break;\n case 'subscribe': this.handleSubscribe(clientState, command); break;\n case 'unsubscribe': this.handleUnsubscribe(clientState, command); break;\n case 'seek': this.handleSeek(clientState, command); break;\n case 'playbackSpeed': this.handlePlaybackSpeed(clientState, command); break;\n case 'filter': this.handleSetFilter(clientState, command); break;\n case 'pause': this.handlePause(clientState, command); break;\n case 'resume': this.handleResume(clientState, command); break;\n case 'stepForward': this.handleStepForward(clientState, command); break;\n case 'stepBackward': this.handleStepBackward(clientState, command); break;\n case 'setBreakpoint': this.handleSetBreakpoint(clientState, command); break;\n case 'clearBreakpoint': this.handleClearBreakpoint(clientState, command); break;\n case 'listBreakpoints': this.handleListBreakpoints(clientState, command); break;\n }\n } catch (e) {\n this.sendError(clientState, 'COMMAND_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n // ======================== Command Handlers ========================\n\n private handleListSessions(client: ClientState, cmd: Extract<DebugCommand, { type: 'listSessions' }>): void {\n const limit = cmd.limit ?? 50;\n const sessions = cmd.activeOnly\n ? this._sessionRegistry.listActiveSessions(limit)\n : this._sessionRegistry.listSessions(limit);\n\n const summaries = sessions.map(s => ({\n sessionId: s.sessionId,\n netName: s.netName,\n startTime: new Date(s.startTime).toISOString(),\n active: s.active,\n eventCount: s.eventStore.eventCount(),\n }));\n\n this.send(client, { type: 'sessionList', sessions: summaries });\n }\n\n private handleSubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'subscribe' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const eventStore = debugSession.eventStore;\n client.subscriptions.cancel(cmd.sessionId);\n\n const events = eventStore.events();\n const computed = computeState(events);\n const structure = buildNetStructure(debugSession);\n\n this.send(client, {\n type: 'subscribed',\n sessionId: cmd.sessionId,\n netName: debugSession.netName,\n dotDiagram: debugSession.dotDiagram,\n structure,\n currentMarking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n eventCount: eventStore.eventCount(),\n mode: cmd.mode,\n });\n\n const fromIndex = cmd.fromIndex ?? 0;\n if (cmd.mode === 'live') {\n this.subscribeLive(client, cmd.sessionId, debugSession, fromIndex);\n } else {\n this.subscribeReplay(client, cmd.sessionId, debugSession, fromIndex);\n }\n }\n\n private subscribeLive(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n let eventIndex = fromIndex;\n\n const historicalEvents = eventStore.eventsFrom(fromIndex);\n if (historicalEvents.length > 0) {\n const filtered = historicalEvents\n .filter(e => client.subscriptions.matchesFilter(sessionId, e))\n .map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, filtered);\n eventIndex = fromIndex + historicalEvents.length;\n }\n\n const subscription = eventStore.subscribe(event => {\n if (!client.subscriptions.isPaused(sessionId) && client.subscriptions.matchesFilter(sessionId, event)) {\n const eventInfo = toEventInfo(event);\n const idx = eventIndex++;\n\n const hitBreakpoint = client.subscriptions.checkBreakpoints(sessionId, event);\n if (hitBreakpoint) {\n client.subscriptions.setPaused(sessionId, true);\n this.send(client, {\n type: 'breakpointHit',\n sessionId,\n breakpointId: hitBreakpoint.id,\n event: eventInfo,\n eventIndex: idx,\n });\n }\n\n this.send(client, { type: 'event', sessionId, index: idx, event: eventInfo });\n }\n });\n\n client.subscriptions.addSubscription(sessionId, subscription, eventIndex);\n }\n\n private subscribeReplay(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n\n const events = eventStore.eventsFrom(fromIndex);\n const converted = events.map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, converted);\n\n const eventIndex = fromIndex + events.length;\n client.subscriptions.addSubscription(sessionId, null, eventIndex);\n client.subscriptions.setPaused(sessionId, true);\n }\n\n private handleUnsubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'unsubscribe' }>): void {\n client.subscriptions.cancel(cmd.sessionId);\n this.send(client, { type: 'unsubscribed', sessionId: cmd.sessionId });\n }\n\n private handleSeek(client: ClientState, cmd: Extract<DebugCommand, { type: 'seek' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', 'Session not found', cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const targetTs = new Date(cmd.timestamp).getTime();\n\n let targetIndex = 0;\n for (let i = 0; i < events.length; i++) {\n if (events[i]!.timestamp >= targetTs) {\n targetIndex = i;\n break;\n }\n targetIndex = i + 1;\n }\n\n client.subscriptions.setEventIndex(cmd.sessionId, targetIndex);\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, targetIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n\n private handlePlaybackSpeed(client: ClientState, cmd: Extract<DebugCommand, { type: 'playbackSpeed' }>): void {\n client.subscriptions.setSpeed(cmd.sessionId, cmd.speed);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: client.subscriptions.isPaused(cmd.sessionId),\n speed: cmd.speed,\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleSetFilter(client: ClientState, cmd: Extract<DebugCommand, { type: 'filter' }>): void {\n client.subscriptions.setFilter(cmd.sessionId, cmd.filter);\n this.send(client, { type: 'filterApplied', sessionId: cmd.sessionId, filter: cmd.filter });\n }\n\n private handlePause(client: ClientState, cmd: Extract<DebugCommand, { type: 'pause' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, true);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: true,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleResume(client: ClientState, cmd: Extract<DebugCommand, { type: 'resume' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, false);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: false,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleStepForward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepForward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n\n if (currentIndex < events.length) {\n const event = events[currentIndex]!;\n this.send(client, {\n type: 'event',\n sessionId: cmd.sessionId,\n index: currentIndex,\n event: toEventInfo(event),\n });\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex + 1);\n }\n }\n\n private handleStepBackward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepBackward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n let currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n if (currentIndex > 0) {\n currentIndex--;\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex);\n\n const events = debugSession.eventStore.events();\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, currentIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n }\n\n private handleSetBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'setBreakpoint' }>): void {\n client.subscriptions.addBreakpoint(cmd.sessionId, cmd.breakpoint);\n this.send(client, { type: 'breakpointSet', sessionId: cmd.sessionId, breakpoint: cmd.breakpoint });\n }\n\n private handleClearBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'clearBreakpoint' }>): void {\n client.subscriptions.removeBreakpoint(cmd.sessionId, cmd.breakpointId);\n this.send(client, { type: 'breakpointCleared', sessionId: cmd.sessionId, breakpointId: cmd.breakpointId });\n }\n\n private handleListBreakpoints(client: ClientState, cmd: Extract<DebugCommand, { type: 'listBreakpoints' }>): void {\n const breakpoints = client.subscriptions.getBreakpoints(cmd.sessionId);\n this.send(client, { type: 'breakpointList', sessionId: cmd.sessionId, breakpoints });\n }\n\n // ======================== Helper Methods ========================\n\n private send(client: ClientState, response: DebugResponse): void {\n client.sink(response);\n }\n\n private sendError(client: ClientState, code: string, message: string, sessionId: string | null): void {\n this.send(client, { type: 'error', code, message, sessionId });\n }\n\n private sendInBatches(client: ClientState, sessionId: string, startIndex: number, events: readonly NetEventInfo[]): void {\n if (events.length === 0) {\n this.send(client, { type: 'eventBatch', sessionId, startIndex, events: [], hasMore: false });\n return;\n }\n for (let i = 0; i < events.length; i += BATCH_SIZE) {\n const end = Math.min(i + BATCH_SIZE, events.length);\n const chunk = events.slice(i, end);\n const hasMore = end < events.length;\n this.send(client, { type: 'eventBatch', sessionId, startIndex: startIndex + i, events: chunk, hasMore });\n }\n }\n}\n\n// ======================== State Computation (exported for MarkingCache) ========================\n\n/** Computes marking, enabled transitions, and in-flight transitions from events. */\nexport function computeState(events: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n const enabled = new Set<string>();\n const inFlight = new Set<string>();\n applyEvents(marking, enabled, inFlight, events);\n return toImmutableState(marking, enabled, inFlight);\n}\n\n/** Applies events to mutable accumulator collections. */\nexport function applyEvents(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n events: readonly NetEvent[],\n): void {\n for (const event of events) {\n switch (event.type) {\n case 'token-added': {\n let tokens = marking.get(event.placeName);\n if (!tokens) {\n tokens = [];\n marking.set(event.placeName, tokens);\n }\n tokens.push(tokenInfo(event.token));\n break;\n }\n case 'token-removed': {\n const tokens = marking.get(event.placeName);\n if (tokens && tokens.length > 0) tokens.shift();\n break;\n }\n case 'marking-snapshot': {\n marking.clear();\n const converted = convertMarking(event.marking);\n for (const [key, value] of Object.entries(converted)) {\n marking.set(key, [...value]);\n }\n break;\n }\n case 'transition-enabled':\n enabled.add(event.transitionName);\n break;\n case 'transition-started':\n enabled.delete(event.transitionName);\n inFlight.add(event.transitionName);\n break;\n case 'transition-completed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-failed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-timed-out':\n inFlight.delete(event.transitionName);\n break;\n case 'action-timed-out':\n inFlight.delete(event.transitionName);\n break;\n default:\n break;\n }\n }\n}\n\n/** Converts mutable accumulator collections into an immutable ComputedState. */\nexport function toImmutableState(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n): ComputedState {\n const resultMarking = new Map<string, readonly TokenInfo[]>();\n for (const [key, value] of marking) {\n resultMarking.set(key, [...value]);\n }\n return {\n marking: resultMarking,\n enabledTransitions: [...enabled],\n inFlightTransitions: [...inFlight],\n };\n}\n\n/** Builds net structure from a debug session. */\nfunction buildNetStructure(debugSession: DebugSession): NetStructure {\n const places = debugSession.places;\n const transitions = debugSession.transitions;\n\n const placeInfos = [...places.data.entries()].map(([name, info]) => ({\n name,\n graphId: `p_${sanitize(name)}`,\n tokenType: info.tokenType,\n isStart: !info.hasIncoming,\n isEnd: !info.hasOutgoing,\n isEnvironment: false,\n }));\n\n const transitionInfos = [...transitions].map(t => ({\n name: t.name,\n graphId: `t_${sanitize(t.name)}`,\n }));\n\n return { places: placeInfos, transitions: transitionInfos };\n}\n\n/** Convert Map to Record for JSON serialization. */\nfunction mapToRecord(map: ReadonlyMap<string, readonly TokenInfo[]>): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n for (const [key, value] of map) {\n result[key] = value;\n }\n return result;\n}\n\n// ======================== Client State ========================\n\nclass ClientState {\n readonly sink: ResponseSink;\n readonly subscriptions = new SubscriptionState();\n\n constructor(sink: ResponseSink) {\n this.sink = sink;\n }\n}\n\n// ======================== Subscription State ========================\n\ninterface SessionSubscription {\n subscription: Subscription | null;\n eventIndex: number;\n markingCache: MarkingCache;\n breakpoints: Map<string, BreakpointConfig>;\n paused: boolean;\n speed: number;\n filter: EventFilter | null;\n}\n\nclass SubscriptionState {\n private readonly _sessionSubs = new Map<string, SessionSubscription>();\n\n addSubscription(sessionId: string, subscription: Subscription | null, eventIndex: number): void {\n this._sessionSubs.set(sessionId, {\n subscription,\n eventIndex,\n markingCache: new MarkingCache(),\n breakpoints: new Map(),\n paused: false,\n speed: 1.0,\n filter: null,\n });\n }\n\n cancel(sessionId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub?.subscription) sub.subscription.cancel();\n this._sessionSubs.delete(sessionId);\n }\n\n cancelAll(): void {\n for (const sub of this._sessionSubs.values()) {\n if (sub.subscription) sub.subscription.cancel();\n }\n this._sessionSubs.clear();\n }\n\n isPaused(sessionId: string): boolean {\n return this._sessionSubs.get(sessionId)?.paused ?? false;\n }\n\n setPaused(sessionId: string, paused: boolean): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.paused = paused;\n }\n\n getSpeed(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.speed ?? 1.0;\n }\n\n setSpeed(sessionId: string, speed: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.speed = speed;\n }\n\n getEventIndex(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.eventIndex ?? 0;\n }\n\n setEventIndex(sessionId: string, index: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.eventIndex = index;\n }\n\n computeStateAt(sessionId: string, events: readonly NetEvent[], targetIndex: number): ComputedState {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) return sub.markingCache.computeAt(events, targetIndex);\n return computeState(events.slice(0, targetIndex));\n }\n\n setFilter(sessionId: string, filter: EventFilter): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.filter = filter;\n }\n\n matchesFilter(sessionId: string, event: NetEvent): boolean {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub?.filter) return true;\n\n const filter = sub.filter;\n\n if (filter.eventTypes && filter.eventTypes.length > 0) {\n const eventType = eventTypeToName(event);\n if (!filter.eventTypes.includes(eventType)) return false;\n }\n\n if (filter.transitionNames && filter.transitionNames.length > 0) {\n const name = extractTransitionName(event);\n if (!name || !filter.transitionNames.includes(name)) return false;\n }\n\n if (filter.placeNames && filter.placeNames.length > 0) {\n const name = extractPlaceName(event);\n if (!name || !filter.placeNames.includes(name)) return false;\n }\n\n return true;\n }\n\n addBreakpoint(sessionId: string, breakpoint: BreakpointConfig): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.set(breakpoint.id, breakpoint);\n }\n\n removeBreakpoint(sessionId: string, breakpointId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.delete(breakpointId);\n }\n\n getBreakpoints(sessionId: string): readonly BreakpointConfig[] {\n const sub = this._sessionSubs.get(sessionId);\n return sub ? [...sub.breakpoints.values()] : [];\n }\n\n checkBreakpoints(sessionId: string, event: NetEvent): BreakpointConfig | null {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub || sub.breakpoints.size === 0) return null;\n\n for (const bp of sub.breakpoints.values()) {\n if (!bp.enabled) continue;\n if (matchesBreakpoint(bp, event)) return bp;\n }\n return null;\n }\n}\n\nfunction eventTypeToName(event: NetEvent): string {\n const map: Record<string, string> = {\n 'execution-started': 'ExecutionStarted',\n 'execution-completed': 'ExecutionCompleted',\n 'transition-enabled': 'TransitionEnabled',\n 'transition-clock-restarted': 'TransitionClockRestarted',\n 'transition-started': 'TransitionStarted',\n 'transition-completed': 'TransitionCompleted',\n 'transition-failed': 'TransitionFailed',\n 'transition-timed-out': 'TransitionTimedOut',\n 'action-timed-out': 'ActionTimedOut',\n 'token-added': 'TokenAdded',\n 'token-removed': 'TokenRemoved',\n 'marking-snapshot': 'MarkingSnapshot',\n 'log-message': 'LogMessage',\n };\n return map[event.type] ?? event.type;\n}\n\nfunction extractTransitionName(event: NetEvent): string | null {\n switch (event.type) {\n case 'transition-enabled':\n case 'transition-clock-restarted':\n case 'transition-started':\n case 'transition-completed':\n case 'transition-failed':\n case 'transition-timed-out':\n case 'action-timed-out':\n case 'log-message':\n return event.transitionName;\n default:\n return null;\n }\n}\n\nfunction extractPlaceName(event: NetEvent): string | null {\n switch (event.type) {\n case 'token-added':\n case 'token-removed':\n return event.placeName;\n default:\n return null;\n }\n}\n\nfunction matchesBreakpoint(bp: BreakpointConfig, event: NetEvent): boolean {\n switch (bp.type) {\n case 'TRANSITION_ENABLED':\n return event.type === 'transition-enabled' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_START':\n return event.type === 'transition-started' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_COMPLETE':\n return event.type === 'transition-completed' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_FAIL':\n return event.type === 'transition-failed' && (bp.target === null || bp.target === event.transitionName);\n case 'TOKEN_ADDED':\n return event.type === 'token-added' && (bp.target === null || bp.target === event.placeName);\n case 'TOKEN_REMOVED':\n return event.type === 'token-removed' && (bp.target === null || bp.target === event.placeName);\n default:\n return false;\n }\n}\n","/**\n * EventStore with live tailing and historical replay.\n * TypeScript port of Java's DebugEventStore.\n *\n * Node.js simplifications: single-threaded, no locks needed,\n * synchronous Set<Function> for subscribers, microtask broadcast.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\n\n/** Handle for managing a live event subscription. */\nexport interface Subscription {\n cancel(): void;\n isActive(): boolean;\n}\n\n/** Default maximum events to retain before evicting oldest. */\nexport const DEFAULT_MAX_EVENTS = 10_000;\n\nexport class DebugEventStore implements EventStore {\n private readonly _events: NetEvent[] = [];\n private readonly _subscribers = new Set<(event: NetEvent) => void>();\n private readonly _sessionId: string;\n private readonly _maxEvents: number;\n private _eventCount = 0;\n private _evictedCount = 0;\n\n constructor(sessionId: string, maxEvents = DEFAULT_MAX_EVENTS) {\n if (maxEvents <= 0) throw new Error(`maxEvents must be positive, got: ${maxEvents}`);\n this._sessionId = sessionId;\n this._maxEvents = maxEvents;\n }\n\n get sessionId(): string { return this._sessionId; }\n get maxEvents(): number { return this._maxEvents; }\n\n /** Total events appended (including evicted). */\n eventCount(): number { return this._eventCount; }\n\n /** Number of events evicted from the store. */\n evictedCount(): number { return this._evictedCount; }\n\n // ======================== EventStore Implementation ========================\n\n append(event: NetEvent): void {\n this._events.push(event);\n this._eventCount++;\n\n // Evict oldest when capacity exceeded\n while (this._events.length > this._maxEvents) {\n this._events.shift();\n this._evictedCount++;\n }\n\n // Broadcast to subscribers (microtask for async-like behavior)\n if (this._subscribers.size > 0) {\n // Use queueMicrotask instead of synchronous call to avoid blocking\n const subscribers = [...this._subscribers];\n queueMicrotask(() => {\n for (const sub of subscribers) {\n try {\n sub(event);\n } catch (e) {\n console.warn('Subscriber threw exception during event broadcast', e);\n }\n }\n });\n }\n }\n\n events(): readonly NetEvent[] {\n return this._events;\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._events.length;\n }\n\n isEmpty(): boolean {\n return this._events.length === 0;\n }\n\n // ======================== Live Tailing ========================\n\n /** Subscribe to receive events as they occur. */\n subscribe(listener: (event: NetEvent) => void): Subscription {\n this._subscribers.add(listener);\n return {\n cancel: () => { this._subscribers.delete(listener); },\n isActive: () => this._subscribers.has(listener),\n };\n }\n\n /** Number of active subscribers. */\n subscriberCount(): number {\n return this._subscribers.size;\n }\n\n // ======================== Historical Replay ========================\n\n /** Returns events starting from a specific index. */\n eventsFrom(fromIndex: number): readonly NetEvent[] {\n const adjustedSkip = Math.max(0, fromIndex - this._evictedCount);\n if (adjustedSkip <= 0) return this._events;\n return this._events.slice(adjustedSkip);\n }\n\n /** Returns all events since the specified timestamp. */\n eventsSince(from: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from);\n }\n\n /** Returns events within a time range. */\n eventsBetween(from: number, to: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from && e.timestamp < to);\n }\n\n // ======================== Lifecycle ========================\n\n /** Close the store (no-op in JS, but matches Java interface). */\n close(): void {\n this._subscribers.clear();\n }\n}\n","/**\n * Analyze places for start/end/environment classification.\n * TypeScript port of Java's PlaceAnalysis.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Place } from '../core/place.js';\n\nexport interface PlaceAnalysisInfo {\n readonly tokenType: string;\n readonly hasIncoming: boolean;\n readonly hasOutgoing: boolean;\n}\n\nexport class PlaceAnalysis {\n private readonly _data: ReadonlyMap<string, PlaceAnalysisInfo>;\n\n constructor(data: ReadonlyMap<string, PlaceAnalysisInfo>) {\n this._data = data;\n }\n\n get data(): ReadonlyMap<string, PlaceAnalysisInfo> {\n return this._data;\n }\n\n isStart(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasIncoming;\n }\n\n isEnd(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasOutgoing;\n }\n\n /** Build place analysis from a PetriNet. */\n static from(net: PetriNet): PlaceAnalysis {\n const data = new Map<string, { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean }>();\n\n function ensure(place: Place<unknown>): { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean } {\n let info = data.get(place.name);\n if (!info) {\n info = { tokenType: 'unknown', hasIncoming: false, hasOutgoing: false };\n data.set(place.name, info);\n }\n return info;\n }\n\n for (const transition of net.transitions) {\n // Input arcs: place → transition (place has outgoing)\n for (const input of transition.inputSpecs) {\n const info = ensure((input as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Output arcs: transition → place (place has incoming)\n if (transition.outputSpec) {\n const outputPlaces = collectOutputPlaces(transition.outputSpec);\n for (const place of outputPlaces) {\n const info = ensure(place);\n info.hasIncoming = true;\n }\n }\n\n // Inhibitor arcs: just ensure place exists\n for (const inh of transition.inhibitors) {\n ensure((inh as { place: Place<unknown> }).place);\n }\n\n // Read arcs: place has outgoing (read = test without consuming)\n for (const read of transition.reads) {\n const info = ensure((read as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Reset arcs: just ensure place exists\n for (const reset of transition.resets) {\n ensure((reset as { place: Place<unknown> }).place);\n }\n }\n\n return new PlaceAnalysis(data as ReadonlyMap<string, PlaceAnalysisInfo>);\n }\n}\n\n/** Recursively collect all output places from an Out spec. */\nfunction collectOutputPlaces(out: unknown): Place<unknown>[] {\n const spec = out as { type: string; place?: Place<unknown>; children?: unknown[]; child?: unknown; from?: Place<unknown>; to?: Place<unknown> };\n switch (spec.type) {\n case 'place':\n return spec.place ? [spec.place] : [];\n case 'and':\n case 'xor':\n return (spec.children ?? []).flatMap(c => collectOutputPlaces(c));\n case 'timeout':\n return spec.child ? collectOutputPlaces(spec.child) : [];\n case 'forward-input':\n return spec.to ? [spec.to] : [];\n default:\n return [];\n }\n}\n","/**\n * Registry for managing Petri net debug sessions.\n * TypeScript port of Java's DebugSessionRegistry.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Transition } from '../core/transition.js';\nimport { dotExport } from '../export/dot-exporter.js';\nimport { PlaceAnalysis } from './place-analysis.js';\nimport { DebugEventStore } from './debug-event-store.js';\n\nexport interface DebugSession {\n readonly sessionId: string;\n readonly netName: string;\n readonly dotDiagram: string;\n readonly places: PlaceAnalysis;\n readonly transitions: ReadonlySet<Transition>;\n readonly eventStore: DebugEventStore;\n readonly startTime: number;\n readonly active: boolean;\n}\n\nexport type EventStoreFactory = (sessionId: string) => DebugEventStore;\n\nexport class DebugSessionRegistry {\n private readonly _sessions = new Map<string, DebugSession>();\n private readonly _maxSessions: number;\n private readonly _eventStoreFactory: EventStoreFactory;\n\n constructor(maxSessions = 50, eventStoreFactory?: EventStoreFactory) {\n this._maxSessions = maxSessions;\n this._eventStoreFactory = eventStoreFactory ?? ((id: string) => new DebugEventStore(id));\n }\n\n /**\n * Registers a new debug session for the given Petri net.\n * Generates DOT diagram and extracts net structure.\n */\n register(sessionId: string, net: PetriNet): DebugSession {\n const dotDiagram = dotExport(net);\n const places = PlaceAnalysis.from(net);\n const eventStore = this._eventStoreFactory(sessionId);\n\n const session: DebugSession = {\n sessionId,\n netName: net.name,\n dotDiagram,\n places,\n transitions: net.transitions,\n eventStore,\n startTime: Date.now(),\n active: true,\n };\n\n this.evictIfNecessary();\n this._sessions.set(sessionId, session);\n return session;\n }\n\n /** Marks a session as completed (no longer active). */\n complete(sessionId: string): void {\n const session = this._sessions.get(sessionId);\n if (session) {\n this._sessions.set(sessionId, { ...session, active: false });\n }\n }\n\n /** Removes a session from the registry. */\n remove(sessionId: string): DebugSession | undefined {\n const removed = this._sessions.get(sessionId);\n if (removed) {\n this._sessions.delete(sessionId);\n removed.eventStore.close();\n }\n return removed;\n }\n\n /** Returns a session by ID. */\n getSession(sessionId: string): DebugSession | undefined {\n return this._sessions.get(sessionId);\n }\n\n /** Lists sessions, ordered by start time (most recent first). */\n listSessions(limit: number): readonly DebugSession[] {\n return [...this._sessions.values()]\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Lists only active sessions. */\n listActiveSessions(limit: number): readonly DebugSession[] {\n return [...this._sessions.values()]\n .filter(s => s.active)\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Total number of sessions. */\n get size(): number {\n return this._sessions.size;\n }\n\n /** Evicts oldest inactive sessions if at capacity. */\n private evictIfNecessary(): void {\n if (this._sessions.size < this._maxSessions) return;\n\n const candidates = [...this._sessions.values()]\n .sort((a, b) => {\n // Inactive first, then oldest\n if (a.active !== b.active) return a.active ? 1 : -1;\n return a.startTime - b.startTime;\n });\n\n for (const candidate of candidates) {\n if (this._sessions.size < this._maxSessions) break;\n const evicted = this._sessions.get(candidate.sessionId);\n if (evicted) {\n this._sessions.delete(candidate.sessionId);\n evicted.eventStore.close();\n }\n }\n }\n}\n","/**\n * EventStore that delegates to both a primary store and a debug store.\n * TypeScript port of Java's DebugAwareEventStore.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { DebugEventStore } from './debug-event-store.js';\n\nexport class DebugAwareEventStore implements EventStore {\n private readonly _primary: EventStore;\n private readonly _debugStore: DebugEventStore;\n\n constructor(primary: EventStore, debugStore: DebugEventStore) {\n this._primary = primary;\n this._debugStore = debugStore;\n }\n\n append(event: NetEvent): void {\n this._primary.append(event);\n try {\n this._debugStore.append(event);\n } catch {\n // Debug failures must not break production\n }\n }\n\n events(): readonly NetEvent[] {\n return this._primary.events();\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._primary.size();\n }\n\n isEmpty(): boolean {\n return this._primary.isEmpty();\n }\n\n /** Returns the underlying debug store for subscription management. */\n get debugStore(): DebugEventStore {\n return this._debugStore;\n }\n}\n","/**\n * Debug infrastructure for Petri net execution visualization.\n *\n * Provides a framework-agnostic debug protocol handler, event store with\n * live tailing, session registry, and marking cache for efficient replay.\n *\n * @module debug\n */\n\n// Protocol types\nexport type { DebugCommand, SubscriptionMode, BreakpointType, BreakpointConfig, EventFilter } from './debug-command.js';\nexport { eventFilterAll } from './debug-command.js';\nexport type {\n DebugResponse, SessionSummary, TokenInfo, NetEventInfo,\n PlaceInfo, TransitionInfo, NetStructure,\n} from './debug-response.js';\n\n// Core infrastructure\nexport { DebugProtocolHandler } from './debug-protocol-handler.js';\nexport type { ResponseSink, ComputedState } from './debug-protocol-handler.js';\nexport { DebugEventStore, DEFAULT_MAX_EVENTS } from './debug-event-store.js';\nexport type { Subscription } from './debug-event-store.js';\nexport { DebugSessionRegistry } from './debug-session-registry.js';\nexport type { DebugSession, EventStoreFactory } from './debug-session-registry.js';\nexport { MarkingCache, SNAPSHOT_INTERVAL } from './marking-cache.js';\n\n// Converters and analysis\nexport { toEventInfo, tokenInfo, compactTokenInfo, convertMarking } from './net-event-converter.js';\nexport { DebugAwareEventStore } from './debug-aware-event-store.js';\nexport { PlaceAnalysis } from './place-analysis.js';\nexport type { PlaceAnalysisInfo } from './place-analysis.js';\n\n/**\n * Returns the path to the bundled debug UI assets directory.\n * Requires Node.js — resolves relative to this module's location.\n */\nexport async function debugUiAssetPath(): Promise<string> {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const dynamicImport = Function('m', 'return import(m)') as (m: string) => Promise<Record<string, unknown>>;\n const nodeUrl = await dynamicImport('node:url') as { fileURLToPath(url: string | URL): string };\n const nodePath = await dynamicImport('node:path') as { dirname(p: string): string; join(...paths: string[]): string };\n const thisDir = nodePath.dirname(nodeUrl.fileURLToPath(import.meta.url));\n return nodePath.join(thisDir, '..', 'debug-ui');\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,108 @@
1
+ import { Application } from 'typedoc';
2
+ import { a as PetriNet } from '../petri-net-C3Jy5HCt.js';
3
+
4
+ /**
5
+ * TypeDoc plugin for `@petrinet` tag — auto-generates interactive SVG diagrams
6
+ * from PetriNet definitions and embeds them in TypeDoc output.
7
+ *
8
+ * Mirrors: `org.libpetri.doclet.PetriNetTaglet`
9
+ *
10
+ * Plugin lifecycle (TypeDoc hooks):
11
+ * 1. `bootstrapEnd` → register `@petrinet` as known block tag
12
+ * 2. `preRenderAsyncJobs` → walk reflections, resolve nets, generate SVGs, cache HTML
13
+ * 3. `comment.beforeTags` → inject cached HTML via JSX.Raw, skip default rendering
14
+ *
15
+ * @module doclet/petri-net-plugin
16
+ */
17
+
18
+ /**
19
+ * Loads the petri-net plugin into the TypeDoc application.
20
+ *
21
+ * @param app - the TypeDoc Application instance
22
+ */
23
+ declare function load(app: Application): void;
24
+
25
+ /**
26
+ * Shared HTML renderer for Petri Net diagrams in TypeDoc.
27
+ *
28
+ * Generates consistent HTML markup with interactive controls for zoom, pan,
29
+ * and fullscreen functionality. Accepts pre-rendered SVG from `@viz-js/viz`.
30
+ *
31
+ * CSS and JS are loaded from bundled resources and inlined into the generated
32
+ * HTML, making the plugin fully self-contained with no external file dependencies.
33
+ *
34
+ * Mirrors: `org.libpetri.doclet.DiagramRenderer`
35
+ *
36
+ * @module doclet/diagram-renderer
37
+ */
38
+ /**
39
+ * Escapes HTML special characters for safe embedding.
40
+ */
41
+ declare function escapeHtml(text: string): string;
42
+ /**
43
+ * Renders a pre-built SVG diagram with an optional title.
44
+ *
45
+ * Inlines CSS and JS from bundled resources. The JS is guarded by an
46
+ * idempotency check so it only executes once per page, even when multiple
47
+ * `@petrinet` tags appear.
48
+ *
49
+ * @param title - optional title (null/undefined for no title)
50
+ * @param svgContent - the SVG markup
51
+ * @param dotSource - the DOT source code for display in a collapsible block
52
+ * @returns HTML markup with diagram controls
53
+ */
54
+ declare function renderSvg(title: string | null | undefined, svgContent: string, dotSource: string): string;
55
+
56
+ /**
57
+ * SVG renderer using `@viz-js/viz` (Graphviz WASM).
58
+ *
59
+ * Pure WASM — zero external dependencies. No system `dot` binary required.
60
+ *
61
+ * Mirrors: Java's `PetriNetTaglet.dotToSvg()` (which uses `dot -Tsvg` subprocess)
62
+ *
63
+ * @module doclet/svg-renderer
64
+ */
65
+ /**
66
+ * Renders a DOT string to SVG using the `@viz-js/viz` WASM engine.
67
+ *
68
+ * Strips the XML prolog/DOCTYPE and explicit width/height attributes so the SVG
69
+ * scales via viewBox + CSS instead of overriding with fixed pt sizes.
70
+ *
71
+ * @param dot - the DOT source string
72
+ * @returns SVG markup string
73
+ * @throws if `@viz-js/viz` is not installed or DOT parsing fails
74
+ */
75
+ declare function dotToSvg(dot: string): Promise<string>;
76
+
77
+ /**
78
+ * Dynamic import-based PetriNet resolver for TypeDoc.
79
+ *
80
+ * TypeScript cannot use reflection like Java — modules must be importable
81
+ * at doc time (from `dist/` after `npm run build`).
82
+ *
83
+ * Tag format:
84
+ * ```
85
+ * @petrinet ./path/to/module#exportName — access a PetriNet constant
86
+ * @petrinet ./path/to/module#functionName() — call a function returning PetriNet
87
+ * @petrinet #localExport — resolve from same file
88
+ * ```
89
+ *
90
+ * Mirrors: `org.libpetri.doclet.PetriNetTaglet.resolvePetriNet()`
91
+ *
92
+ * @module doclet/net-resolver
93
+ */
94
+
95
+ interface ResolvedNet {
96
+ readonly net: PetriNet;
97
+ readonly title: string;
98
+ }
99
+ /**
100
+ * Parses a `@petrinet` reference and resolves the PetriNet via dynamic import.
101
+ *
102
+ * @param reference - the tag content, e.g. `./definition#buildDebugNet()`
103
+ * @param sourceFilePath - absolute path to the source file containing the tag
104
+ * @returns the resolved PetriNet with title, or null on failure
105
+ */
106
+ declare function resolveNet(reference: string, sourceFilePath: string): Promise<ResolvedNet | null>;
107
+
108
+ export { type ResolvedNet, dotToSvg, escapeHtml, load, renderSvg, resolveNet };
@@ -0,0 +1,215 @@
1
+ // src/doclet/petri-net-plugin.ts
2
+ import {
3
+ JSX
4
+ } from "typedoc";
5
+
6
+ // src/doclet/net-resolver.ts
7
+ import { resolve, dirname } from "path";
8
+ import { pathToFileURL } from "url";
9
+ async function resolveNet(reference, sourceFilePath) {
10
+ const trimmed = reference.trim().split(/\s+/)[0] ?? "";
11
+ if (!trimmed) return null;
12
+ const hashIndex = trimmed.indexOf("#");
13
+ if (hashIndex === -1) return null;
14
+ const modulePath = trimmed.substring(0, hashIndex);
15
+ const exportRef = trimmed.substring(hashIndex + 1);
16
+ if (!exportRef) return null;
17
+ const isCall = exportRef.endsWith("()");
18
+ const exportName = isCall ? exportRef.slice(0, -2) : exportRef;
19
+ let absolutePath;
20
+ if (modulePath) {
21
+ absolutePath = resolve(dirname(sourceFilePath), modulePath);
22
+ } else {
23
+ absolutePath = sourceFilePath;
24
+ }
25
+ const candidates = [
26
+ absolutePath,
27
+ absolutePath + ".js",
28
+ absolutePath + ".ts",
29
+ absolutePath.replace(/\.ts$/, ".js")
30
+ ];
31
+ let mod;
32
+ for (const candidate of candidates) {
33
+ try {
34
+ mod = await import(pathToFileURL(candidate).href);
35
+ break;
36
+ } catch {
37
+ }
38
+ }
39
+ if (!mod) return null;
40
+ const exported = mod[exportName];
41
+ if (exported == null) return null;
42
+ let net;
43
+ if (isCall) {
44
+ if (typeof exported !== "function") return null;
45
+ const result = exported();
46
+ net = "net" in result ? result.net : result;
47
+ } else {
48
+ net = exported;
49
+ }
50
+ if (typeof net?.name !== "string" || !(net?.transitions instanceof Set)) {
51
+ return null;
52
+ }
53
+ return { net, title: net.name };
54
+ }
55
+
56
+ // src/doclet/svg-renderer.ts
57
+ async function dotToSvg(dot) {
58
+ const { instance } = await import("@viz-js/viz");
59
+ const viz = await instance();
60
+ let svg = viz.renderString(dot, { format: "svg", engine: "dot" });
61
+ const svgStart = svg.indexOf("<svg");
62
+ if (svgStart > 0) svg = svg.substring(svgStart);
63
+ svg = svg.replace(/\s+(?:width|height)="[^"]*"/g, "");
64
+ return svg;
65
+ }
66
+
67
+ // src/doclet/diagram-renderer.ts
68
+ import { readFileSync } from "fs";
69
+ import { fileURLToPath } from "url";
70
+ import { dirname as dirname2, join } from "path";
71
+ var __dirname = dirname2(fileURLToPath(import.meta.url));
72
+ function loadResource(filename) {
73
+ return readFileSync(join(__dirname, "resources", filename), "utf-8");
74
+ }
75
+ var inlineCss;
76
+ var inlineJs;
77
+ function css() {
78
+ return inlineCss ??= loadResource("petrinet-diagrams.css");
79
+ }
80
+ function js() {
81
+ return inlineJs ??= loadResource("petrinet-diagrams.js");
82
+ }
83
+ function escapeHtml(text) {
84
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
85
+ }
86
+ function renderSvg(title, svgContent, dotSource) {
87
+ const titleHtml = title ? `<h4>${escapeHtml(title)}</h4>
88
+ ` : "";
89
+ const summaryText = title ? "View DOT Source" : "View Source";
90
+ return `<style>${css()}</style>
91
+ <script>if(!window._petriNetDiagramsInit){window._petriNetDiagramsInit=true;
92
+ ${js()}
93
+ }</script>
94
+ <div class="petrinet-diagram">
95
+ ${titleHtml}<div class="diagram-container">
96
+ <div class="diagram-controls">
97
+ <button class="diagram-btn btn-reset" title="Reset zoom">Reset</button>
98
+ <button class="diagram-btn btn-fullscreen" onclick="PetriNetDiagrams.toggleFullscreen(this)">Fullscreen</button>
99
+ </div>
100
+ ${svgContent}
101
+ </div>
102
+ <details>
103
+ <summary>${summaryText}</summary>
104
+ <pre><code>${escapeHtml(dotSource)}</code></pre>
105
+ </details>
106
+ </div>`;
107
+ }
108
+
109
+ // src/doclet/petri-net-plugin.ts
110
+ async function getDotExport() {
111
+ const mod = await import("../dot-exporter-U6BRCQNK.js");
112
+ return mod.dotExport;
113
+ }
114
+ var TAG_NAME = "@petrinet";
115
+ var htmlCache = /* @__PURE__ */ new Map();
116
+ function load(app) {
117
+ app.on("bootstrapEnd", () => {
118
+ const blockTags = app.options.getValue("blockTags");
119
+ if (!blockTags.includes(TAG_NAME)) {
120
+ app.options.setValue("blockTags", [...blockTags, TAG_NAME]);
121
+ }
122
+ });
123
+ app.renderer.preRenderAsyncJobs.push(async (output) => {
124
+ htmlCache.clear();
125
+ await processProject(app, output.project);
126
+ });
127
+ app.renderer.hooks.on("comment.beforeTags", (_context, comment, reflection) => {
128
+ const cached = htmlCache.get(reflection.id);
129
+ if (!cached) return JSX.createElement(JSX.Raw, { html: "" });
130
+ for (const tag of comment.blockTags) {
131
+ if (tag.tag === TAG_NAME) {
132
+ tag.skipRendering = true;
133
+ }
134
+ }
135
+ return JSX.createElement(JSX.Raw, { html: cached });
136
+ });
137
+ }
138
+ async function processProject(app, project) {
139
+ const reflections = Object.values(project.reflections);
140
+ for (const reflection of reflections) {
141
+ const comment = reflection.comment;
142
+ if (!comment) continue;
143
+ const petrinetTags = comment.blockTags.filter(
144
+ (tag) => tag.tag === TAG_NAME
145
+ );
146
+ if (petrinetTags.length === 0) continue;
147
+ for (const tag of petrinetTags) {
148
+ const reference = tagContent(tag);
149
+ try {
150
+ const html = await generateDiagram(reference, reflection, app);
151
+ const existing = htmlCache.get(reflection.id) ?? "";
152
+ htmlCache.set(reflection.id, existing + html);
153
+ } catch (e) {
154
+ const msg = e instanceof Error ? e.message : String(e);
155
+ app.logger.warn(`@petrinet error for ${reflection.getFriendlyFullName()}: ${msg}`);
156
+ const html = errorHtml(`Error generating diagram for '${reference}': ${msg}`);
157
+ const existing = htmlCache.get(reflection.id) ?? "";
158
+ htmlCache.set(reflection.id, existing + html);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ async function generateDiagram(reference, reflection, app) {
164
+ const trimmed = reference.trim();
165
+ if (!trimmed) {
166
+ return errorHtml(`Empty @petrinet reference on ${reflection.getFriendlyFullName()}`);
167
+ }
168
+ const sourceFile = getSourceFilePath(reflection);
169
+ if (!sourceFile) {
170
+ return errorHtml(`Cannot determine source file for ${reflection.getFriendlyFullName()}`);
171
+ }
172
+ const resolved = await resolveNet(trimmed, sourceFile);
173
+ if (!resolved) {
174
+ return errorHtml(`Cannot resolve PetriNet: ${trimmed}`);
175
+ }
176
+ const dotExport = await getDotExport();
177
+ const dot = dotExport(resolved.net);
178
+ try {
179
+ const svg = await dotToSvg(dot);
180
+ return renderSvg(resolved.title, svg, dot);
181
+ } catch (e) {
182
+ app.logger.warn(`SVG rendering failed, falling back to DOT source: ${e}`);
183
+ return renderSvg(
184
+ resolved.title,
185
+ `<pre><code>${escapeHtml(dot)}</code></pre>`,
186
+ dot
187
+ );
188
+ }
189
+ }
190
+ function tagContent(tag) {
191
+ return tag.content.map((part) => part.text).join("").trim();
192
+ }
193
+ function getSourceFilePath(reflection) {
194
+ const decl = reflection;
195
+ if (decl.sources && decl.sources.length > 0) {
196
+ return decl.sources[0].fullFileName;
197
+ }
198
+ if (reflection.parent) {
199
+ return getSourceFilePath(reflection.parent);
200
+ }
201
+ return null;
202
+ }
203
+ function errorHtml(message) {
204
+ return `<div class="petrinet-error" style="color: #dc3545; border: 1px solid #dc3545; padding: 10px; border-radius: 4px;">
205
+ <strong>@petrinet Error:</strong> ${escapeHtml(message)}
206
+ </div>`;
207
+ }
208
+ export {
209
+ dotToSvg,
210
+ escapeHtml,
211
+ load,
212
+ renderSvg,
213
+ resolveNet
214
+ };
215
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/doclet/petri-net-plugin.ts","../../src/doclet/net-resolver.ts","../../src/doclet/svg-renderer.ts","../../src/doclet/diagram-renderer.ts"],"sourcesContent":["/**\n * TypeDoc plugin for `@petrinet` tag — auto-generates interactive SVG diagrams\n * from PetriNet definitions and embeds them in TypeDoc output.\n *\n * Mirrors: `org.libpetri.doclet.PetriNetTaglet`\n *\n * Plugin lifecycle (TypeDoc hooks):\n * 1. `bootstrapEnd` → register `@petrinet` as known block tag\n * 2. `preRenderAsyncJobs` → walk reflections, resolve nets, generate SVGs, cache HTML\n * 3. `comment.beforeTags` → inject cached HTML via JSX.Raw, skip default rendering\n *\n * @module doclet/petri-net-plugin\n */\n\nimport {\n type Application,\n type CommentTag,\n type DeclarationReflection,\n type ProjectReflection,\n type Reflection,\n JSX,\n} from 'typedoc';\nimport { resolveNet } from './net-resolver.js';\nimport { dotToSvg } from './svg-renderer.js';\nimport { renderSvg, escapeHtml } from './diagram-renderer.js';\n\n// Lazy import to avoid requiring libpetri/export at module level\nasync function getDotExport(): Promise<typeof import('../export/dot-exporter.js').dotExport> {\n const mod = await import('../export/dot-exporter.js');\n return mod.dotExport;\n}\n\n/** Tag name including @ prefix. */\nconst TAG_NAME = '@petrinet' as `@${string}`;\n\n/** Cache: reflection ID → rendered HTML string */\nconst htmlCache = new Map<number, string>();\n\n/**\n * Loads the petri-net plugin into the TypeDoc application.\n *\n * @param app - the TypeDoc Application instance\n */\nexport function load(app: Application): void {\n // 1. Register @petrinet as a known block tag at bootstrap time\n app.on('bootstrapEnd', () => {\n const blockTags = app.options.getValue('blockTags') as string[];\n if (!blockTags.includes(TAG_NAME)) {\n app.options.setValue('blockTags', [...blockTags, TAG_NAME]);\n }\n });\n\n // 2. Resolve nets and generate SVG during pre-render async phase\n app.renderer.preRenderAsyncJobs.push(async (output) => {\n htmlCache.clear();\n await processProject(app, output.project);\n });\n\n // 3. Inject cached HTML into comment output, suppress default tag rendering\n app.renderer.hooks.on('comment.beforeTags', (_context, comment, reflection) => {\n const cached = htmlCache.get(reflection.id);\n if (!cached) return JSX.createElement(JSX.Raw, { html: '' });\n\n // Mark @petrinet tags as skip so TypeDoc doesn't render them as plain text\n for (const tag of comment.blockTags) {\n if (tag.tag === TAG_NAME) {\n tag.skipRendering = true;\n }\n }\n\n // Inject raw HTML using TypeDoc's JSX\n return JSX.createElement(JSX.Raw, { html: cached });\n });\n}\n\n/**\n * Walks all reflections in the project and processes `@petrinet` tags.\n */\nasync function processProject(app: Application, project: ProjectReflection): Promise<void> {\n const reflections = Object.values(project.reflections);\n\n for (const reflection of reflections) {\n const comment = reflection.comment;\n if (!comment) continue;\n\n const petrinetTags = comment.blockTags.filter(\n (tag: CommentTag) => tag.tag === TAG_NAME,\n );\n if (petrinetTags.length === 0) continue;\n\n for (const tag of petrinetTags) {\n const reference = tagContent(tag);\n try {\n const html = await generateDiagram(reference, reflection, app);\n const existing = htmlCache.get(reflection.id) ?? '';\n htmlCache.set(reflection.id, existing + html);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n app.logger.warn(`@petrinet error for ${reflection.getFriendlyFullName()}: ${msg}`);\n const html = errorHtml(`Error generating diagram for '${reference}': ${msg}`);\n const existing = htmlCache.get(reflection.id) ?? '';\n htmlCache.set(reflection.id, existing + html);\n }\n }\n }\n}\n\n/**\n * Generates a diagram HTML string for a single `@petrinet` reference.\n */\nasync function generateDiagram(\n reference: string,\n reflection: Reflection,\n app: Application,\n): Promise<string> {\n const trimmed = reference.trim();\n if (!trimmed) {\n return errorHtml(`Empty @petrinet reference on ${reflection.getFriendlyFullName()}`);\n }\n\n const sourceFile = getSourceFilePath(reflection);\n if (!sourceFile) {\n return errorHtml(`Cannot determine source file for ${reflection.getFriendlyFullName()}`);\n }\n\n const resolved = await resolveNet(trimmed, sourceFile);\n if (!resolved) {\n return errorHtml(`Cannot resolve PetriNet: ${trimmed}`);\n }\n\n const dotExport = await getDotExport();\n const dot = dotExport(resolved.net);\n\n try {\n const svg = await dotToSvg(dot);\n return renderSvg(resolved.title, svg, dot);\n } catch (e) {\n app.logger.warn(`SVG rendering failed, falling back to DOT source: ${e}`);\n return renderSvg(\n resolved.title,\n `<pre><code>${escapeHtml(dot)}</code></pre>`,\n dot,\n );\n }\n}\n\n/**\n * Extracts text content from a CommentTag.\n */\nfunction tagContent(tag: CommentTag): string {\n return tag.content\n .map((part) => part.text)\n .join('')\n .trim();\n}\n\n/**\n * Gets the source file path from a reflection.\n */\nfunction getSourceFilePath(reflection: Reflection): string | null {\n const decl = reflection as DeclarationReflection;\n if (decl.sources && decl.sources.length > 0) {\n return decl.sources[0]!.fullFileName;\n }\n if (reflection.parent) {\n return getSourceFilePath(reflection.parent);\n }\n return null;\n}\n\n/**\n * Renders an error message as styled HTML.\n */\nfunction errorHtml(message: string): string {\n return `<div class=\"petrinet-error\" style=\"color: #dc3545; border: 1px solid #dc3545; padding: 10px; border-radius: 4px;\">\n<strong>@petrinet Error:</strong> ${escapeHtml(message)}\n</div>`;\n}\n","/**\n * Dynamic import-based PetriNet resolver for TypeDoc.\n *\n * TypeScript cannot use reflection like Java — modules must be importable\n * at doc time (from `dist/` after `npm run build`).\n *\n * Tag format:\n * ```\n * @petrinet ./path/to/module#exportName — access a PetriNet constant\n * @petrinet ./path/to/module#functionName() — call a function returning PetriNet\n * @petrinet #localExport — resolve from same file\n * ```\n *\n * Mirrors: `org.libpetri.doclet.PetriNetTaglet.resolvePetriNet()`\n *\n * @module doclet/net-resolver\n */\n\nimport { resolve, dirname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { PetriNet } from '../core/petri-net.js';\n\nexport interface ResolvedNet {\n readonly net: PetriNet;\n readonly title: string;\n}\n\n/**\n * Parses a `@petrinet` reference and resolves the PetriNet via dynamic import.\n *\n * @param reference - the tag content, e.g. `./definition#buildDebugNet()`\n * @param sourceFilePath - absolute path to the source file containing the tag\n * @returns the resolved PetriNet with title, or null on failure\n */\nexport async function resolveNet(\n reference: string,\n sourceFilePath: string,\n): Promise<ResolvedNet | null> {\n const trimmed = reference.trim().split(/\\s+/)[0] ?? '';\n if (!trimmed) return null;\n\n const hashIndex = trimmed.indexOf('#');\n if (hashIndex === -1) return null;\n\n const modulePath = trimmed.substring(0, hashIndex);\n const exportRef = trimmed.substring(hashIndex + 1);\n if (!exportRef) return null;\n\n const isCall = exportRef.endsWith('()');\n const exportName = isCall ? exportRef.slice(0, -2) : exportRef;\n\n // Resolve module path relative to the source file\n let absolutePath: string;\n if (modulePath) {\n absolutePath = resolve(dirname(sourceFilePath), modulePath);\n } else {\n // #localExport — resolve from same file's compiled output\n absolutePath = sourceFilePath;\n }\n\n // Try .js extension for compiled output, then .ts for ts-node scenarios\n const candidates = [\n absolutePath,\n absolutePath + '.js',\n absolutePath + '.ts',\n absolutePath.replace(/\\.ts$/, '.js'),\n ];\n\n let mod: Record<string, unknown> | undefined;\n for (const candidate of candidates) {\n try {\n mod = await import(pathToFileURL(candidate).href) as Record<string, unknown>;\n break;\n } catch {\n // Try next candidate\n }\n }\n\n if (!mod) return null;\n\n const exported = mod[exportName];\n if (exported == null) return null;\n\n let net: PetriNet;\n if (isCall) {\n if (typeof exported !== 'function') return null;\n const result = exported() as PetriNet | { net: PetriNet };\n // Support functions that return { net: PetriNet, ... }\n net = 'net' in result ? result.net : result;\n } else {\n net = exported as PetriNet;\n }\n\n // Validate it looks like a PetriNet (has name and transitions)\n if (typeof net?.name !== 'string' || !(net?.transitions instanceof Set)) {\n return null;\n }\n\n return { net, title: net.name };\n}\n","/**\n * SVG renderer using `@viz-js/viz` (Graphviz WASM).\n *\n * Pure WASM — zero external dependencies. No system `dot` binary required.\n *\n * Mirrors: Java's `PetriNetTaglet.dotToSvg()` (which uses `dot -Tsvg` subprocess)\n *\n * @module doclet/svg-renderer\n */\n\n/**\n * Renders a DOT string to SVG using the `@viz-js/viz` WASM engine.\n *\n * Strips the XML prolog/DOCTYPE and explicit width/height attributes so the SVG\n * scales via viewBox + CSS instead of overriding with fixed pt sizes.\n *\n * @param dot - the DOT source string\n * @returns SVG markup string\n * @throws if `@viz-js/viz` is not installed or DOT parsing fails\n */\nexport async function dotToSvg(dot: string): Promise<string> {\n // Dynamic import — @viz-js/viz is an optional peer dependency\n const { instance } = await import('@viz-js/viz');\n const viz = await instance();\n let svg = viz.renderString(dot, { format: 'svg', engine: 'dot' });\n\n // Strip XML prolog and DOCTYPE — invalid inside HTML5\n const svgStart = svg.indexOf('<svg');\n if (svgStart > 0) svg = svg.substring(svgStart);\n\n // Strip explicit width/height attributes (e.g. \"1942pt\") so the SVG\n // scales via viewBox + CSS instead of overriding with fixed pt sizes\n svg = svg.replace(/\\s+(?:width|height)=\"[^\"]*\"/g, '');\n\n return svg;\n}\n","/**\n * Shared HTML renderer for Petri Net diagrams in TypeDoc.\n *\n * Generates consistent HTML markup with interactive controls for zoom, pan,\n * and fullscreen functionality. Accepts pre-rendered SVG from `@viz-js/viz`.\n *\n * CSS and JS are loaded from bundled resources and inlined into the generated\n * HTML, making the plugin fully self-contained with no external file dependencies.\n *\n * Mirrors: `org.libpetri.doclet.DiagramRenderer`\n *\n * @module doclet/diagram-renderer\n */\n\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction loadResource(filename: string): string {\n return readFileSync(join(__dirname, 'resources', filename), 'utf-8');\n}\n\nlet inlineCss: string | undefined;\nlet inlineJs: string | undefined;\n\nfunction css(): string {\n return (inlineCss ??= loadResource('petrinet-diagrams.css'));\n}\n\nfunction js(): string {\n return (inlineJs ??= loadResource('petrinet-diagrams.js'));\n}\n\n/**\n * Escapes HTML special characters for safe embedding.\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n/**\n * Renders a pre-built SVG diagram with an optional title.\n *\n * Inlines CSS and JS from bundled resources. The JS is guarded by an\n * idempotency check so it only executes once per page, even when multiple\n * `@petrinet` tags appear.\n *\n * @param title - optional title (null/undefined for no title)\n * @param svgContent - the SVG markup\n * @param dotSource - the DOT source code for display in a collapsible block\n * @returns HTML markup with diagram controls\n */\nexport function renderSvg(\n title: string | null | undefined,\n svgContent: string,\n dotSource: string,\n): string {\n const titleHtml = title ? `<h4>${escapeHtml(title)}</h4>\\n` : '';\n const summaryText = title ? 'View DOT Source' : 'View Source';\n\n return `<style>${css()}</style>\n<script>if(!window._petriNetDiagramsInit){window._petriNetDiagramsInit=true;\n${js()}\n}</script>\n<div class=\"petrinet-diagram\">\n${titleHtml}<div class=\"diagram-container\">\n<div class=\"diagram-controls\">\n<button class=\"diagram-btn btn-reset\" title=\"Reset zoom\">Reset</button>\n<button class=\"diagram-btn btn-fullscreen\" onclick=\"PetriNetDiagrams.toggleFullscreen(this)\">Fullscreen</button>\n</div>\n${svgContent}\n</div>\n<details>\n<summary>${summaryText}</summary>\n<pre><code>${escapeHtml(dotSource)}</code></pre>\n</details>\n</div>`;\n}\n"],"mappings":"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","names":["dirname"]}