libpetri 2.0.0 → 2.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/dist/{chunk-4L6JVKH4.js → chunk-B2CV5M3L.js} +64 -2
- package/dist/chunk-B2CV5M3L.js.map +1 -0
- package/dist/chunk-RNWTYK5B.js +419 -0
- package/dist/chunk-RNWTYK5B.js.map +1 -0
- package/dist/debug/index.js +1 -1
- package/dist/doclet/index.js +2 -2
- package/dist/doclet/resources/petrinet-diagrams.css +256 -0
- package/dist/doclet/resources/petrinet-diagrams.js +30 -6
- package/dist/dot-exporter-WJMCJEFK.js +8 -0
- package/dist/export/index.d.ts +2 -2
- package/dist/export/index.js +1 -1
- package/dist/render-QK57X4TP.js +73 -0
- package/dist/render-QK57X4TP.js.map +1 -0
- package/dist/viewer/index.d.ts +32 -1
- package/dist/viewer/index.js +510 -75
- package/dist/viewer/index.js.map +1 -1
- package/dist/viewer/layout/index.d.ts +200 -0
- package/dist/viewer/layout/index.js +15 -0
- package/dist/viewer/layout/index.js.map +1 -0
- package/dist/viewer/viewer-static.iife.js +2 -2
- package/dist/viewer/viewer.css +256 -0
- package/dist/viewer/viewer.iife.js +30 -6
- package/package.json +12 -1
- package/dist/chunk-4L6JVKH4.js.map +0 -1
- package/dist/dot-exporter-PMHOQHZ3.js +0 -8
- package/dist/render-P6GROU7J.js +0 -16
- package/dist/render-P6GROU7J.js.map +0 -1
- /package/dist/{dot-exporter-PMHOQHZ3.js.map → dot-exporter-WJMCJEFK.js.map} +0 -0
package/dist/export/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { P as PetriNet } from '../petri-net-BDrj4XZE.js';
|
|
|
13
13
|
*/
|
|
14
14
|
type RankDir = 'TB' | 'BT' | 'LR' | 'RL';
|
|
15
15
|
type NodeShape = 'circle' | 'doublecircle' | 'box' | 'diamond' | 'ellipse' | 'record';
|
|
16
|
-
type EdgeLineStyle = 'solid' | 'dashed' | 'bold';
|
|
16
|
+
type EdgeLineStyle = 'solid' | 'dashed' | 'bold' | 'invis';
|
|
17
17
|
type ArrowHead = 'normal' | 'odot' | 'none' | 'diamond' | 'dot';
|
|
18
18
|
interface GraphNode {
|
|
19
19
|
readonly id: string;
|
|
@@ -38,7 +38,7 @@ interface GraphEdge {
|
|
|
38
38
|
readonly arrowhead: ArrowHead;
|
|
39
39
|
readonly penwidth?: number;
|
|
40
40
|
/** The arc type that produced this edge (for semantic queries). */
|
|
41
|
-
readonly arcType: 'input' | 'output' | 'inhibitor' | 'read' | 'reset' | 'reset-output';
|
|
41
|
+
readonly arcType: 'input' | 'output' | 'inhibitor' | 'read' | 'reset' | 'reset-output' | 'ghost';
|
|
42
42
|
readonly attrs?: Readonly<Record<string, string>>;
|
|
43
43
|
}
|
|
44
44
|
/**
|
package/dist/export/index.js
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
elkLayout,
|
|
3
|
+
foldOrphans,
|
|
4
|
+
parseLibpetriDot,
|
|
5
|
+
replicateShared,
|
|
6
|
+
writeBack
|
|
7
|
+
} from "./chunk-RNWTYK5B.js";
|
|
8
|
+
|
|
9
|
+
// src/viewer/render.ts
|
|
10
|
+
import { instance as vizInstance } from "@viz-js/viz";
|
|
11
|
+
var vizPromise = null;
|
|
12
|
+
function getViz() {
|
|
13
|
+
if (!vizPromise) vizPromise = vizInstance();
|
|
14
|
+
return vizPromise;
|
|
15
|
+
}
|
|
16
|
+
async function renderDotToSvg(dotSource) {
|
|
17
|
+
const viz = await getViz();
|
|
18
|
+
return viz.renderSVGElement(dotSource, { engine: "dot" });
|
|
19
|
+
}
|
|
20
|
+
function fnv1a(input) {
|
|
21
|
+
let h = 2166136261;
|
|
22
|
+
for (let i = 0; i < input.length; i++) {
|
|
23
|
+
h ^= input.charCodeAt(i);
|
|
24
|
+
h = Math.imul(h, 16777619);
|
|
25
|
+
}
|
|
26
|
+
return (h >>> 0).toString(16);
|
|
27
|
+
}
|
|
28
|
+
var PINNED_DOT_CACHE_CAP = 16;
|
|
29
|
+
var pinnedDotCache = /* @__PURE__ */ new Map();
|
|
30
|
+
function getCachedPinnedDot(key) {
|
|
31
|
+
const hit = pinnedDotCache.get(key);
|
|
32
|
+
if (hit !== void 0) {
|
|
33
|
+
pinnedDotCache.delete(key);
|
|
34
|
+
pinnedDotCache.set(key, hit);
|
|
35
|
+
}
|
|
36
|
+
return hit;
|
|
37
|
+
}
|
|
38
|
+
function setCachedPinnedDot(key, value) {
|
|
39
|
+
pinnedDotCache.set(key, value);
|
|
40
|
+
while (pinnedDotCache.size > PINNED_DOT_CACHE_CAP) {
|
|
41
|
+
const oldest = pinnedDotCache.keys().next().value;
|
|
42
|
+
if (oldest === void 0) break;
|
|
43
|
+
pinnedDotCache.delete(oldest);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function _clearElkLayoutCache() {
|
|
47
|
+
pinnedDotCache.clear();
|
|
48
|
+
}
|
|
49
|
+
async function renderDotToSvgWithElkLayout(dotSource) {
|
|
50
|
+
const key = fnv1a(dotSource);
|
|
51
|
+
let pinnedDot = getCachedPinnedDot(key);
|
|
52
|
+
if (pinnedDot === void 0) {
|
|
53
|
+
const graph = replicateShared(
|
|
54
|
+
foldOrphans(parseLibpetriDot(dotSource), 0.7),
|
|
55
|
+
{ max: Infinity }
|
|
56
|
+
);
|
|
57
|
+
const layout = await elkLayout(graph);
|
|
58
|
+
pinnedDot = writeBack(graph, layout);
|
|
59
|
+
setCachedPinnedDot(key, pinnedDot);
|
|
60
|
+
}
|
|
61
|
+
const viz = await getViz();
|
|
62
|
+
return viz.renderSVGElement(pinnedDot, {
|
|
63
|
+
engine: "nop",
|
|
64
|
+
yInvert: true
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
_clearElkLayoutCache,
|
|
69
|
+
getViz,
|
|
70
|
+
renderDotToSvg,
|
|
71
|
+
renderDotToSvgWithElkLayout
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=render-QK57X4TP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/viewer/render.ts"],"sourcesContent":["/**\n * DOT → SVG rendering for the canonical libpetri viewer.\n *\n * Two render paths:\n *\n * renderDotToSvg(dot) — plain Graphviz `dot` engine.\n * renderDotToSvgWithElkLayout(dot) — C0 pipeline: parse → fold →\n * replicate → ELK → writeBack →\n * Graphviz `neato` with `nop=1`\n * (pin mode). Cached by DOT hash.\n *\n * The ELK path is the default for {@link mount}; the plain-Graphviz path\n * remains as a fallback for callers that want stock layout (or for\n * environments where elkjs isn't installed).\n *\n * @module viewer/render\n */\n\nimport { instance as vizInstance } from '@viz-js/viz';\nimport {\n foldOrphans,\n parseLibpetriDot,\n replicateShared,\n} from './layout/preprocess.js';\nimport { elkLayout, writeBack } from './layout/elk-place.js';\n\ntype Viz = Awaited<ReturnType<typeof vizInstance>>;\n\nlet vizPromise: Promise<Viz> | null = null;\n\n/** Memoize the viz.js instance so the wasm loads only once per page. */\nexport function getViz(): Promise<Viz> {\n if (!vizPromise) vizPromise = vizInstance();\n return vizPromise;\n}\n\n/**\n * Render a DOT source string to an SVGSVGElement using the plain `dot`\n * engine. Deterministic across runs; libpetri exporters emit byte-stable\n * DOT per spec EXP-014 so the same DOT yields the same SVG.\n */\nexport async function renderDotToSvg(dotSource: string): Promise<SVGSVGElement> {\n const viz = await getViz();\n return viz.renderSVGElement(dotSource, { engine: 'dot' });\n}\n\n// ---- C0 / ELK pin-mode cache ---------------------------------------------\n\n/** FNV-1a 32-bit hash. Fast enough that a SHA isn't worth the import. */\nfunction fnv1a(input: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return (h >>> 0).toString(16);\n}\n\nconst PINNED_DOT_CACHE_CAP = 16;\nconst pinnedDotCache = new Map<string, string>();\n\nfunction getCachedPinnedDot(key: string): string | undefined {\n const hit = pinnedDotCache.get(key);\n if (hit !== undefined) {\n // LRU touch: re-insert moves to most-recent position in Map ordering.\n pinnedDotCache.delete(key);\n pinnedDotCache.set(key, hit);\n }\n return hit;\n}\n\nfunction setCachedPinnedDot(key: string, value: string): void {\n pinnedDotCache.set(key, value);\n while (pinnedDotCache.size > PINNED_DOT_CACHE_CAP) {\n const oldest = pinnedDotCache.keys().next().value;\n if (oldest === undefined) break;\n pinnedDotCache.delete(oldest);\n }\n}\n\n/** Test helper — clears the pinned-DOT LRU cache between mounts. */\nexport function _clearElkLayoutCache(): void {\n pinnedDotCache.clear();\n}\n\n/**\n * Run the C0 layout pipeline against a libpetri DOT source and return the\n * rendered SVG. The expensive steps (preprocess + ELK layout + DOT rewrite)\n * are cached keyed on the input DOT's hash, so re-mounts on the same net\n * structure skip everything except the Graphviz pin-mode draw.\n *\n * Per-tick marking updates do NOT call this — they toggle classes on the\n * already-mounted SVG. ELK only runs when the net structure changes.\n */\nexport async function renderDotToSvgWithElkLayout(\n dotSource: string,\n): Promise<SVGSVGElement> {\n const key = fnv1a(dotSource);\n let pinnedDot = getCachedPinnedDot(key);\n if (pinnedDot === undefined) {\n const graph = replicateShared(\n foldOrphans(parseLibpetriDot(dotSource), 0.7),\n { max: Infinity },\n );\n const layout = await elkLayout(graph);\n pinnedDot = writeBack(graph, layout);\n setCachedPinnedDot(key, pinnedDot);\n }\n const viz = await getViz();\n return viz.renderSVGElement(pinnedDot, {\n engine: 'nop',\n yInvert: true,\n });\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAS,YAAY,mBAAmB;AAUxC,IAAI,aAAkC;AAG/B,SAAS,SAAuB;AACrC,MAAI,CAAC,WAAY,cAAa,YAAY;AAC1C,SAAO;AACT;AAOA,eAAsB,eAAe,WAA2C;AAC9E,QAAM,MAAM,MAAM,OAAO;AACzB,SAAO,IAAI,iBAAiB,WAAW,EAAE,QAAQ,MAAM,CAAC;AAC1D;AAKA,SAAS,MAAM,OAAuB;AACpC,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,SAAK,MAAM,WAAW,CAAC;AACvB,QAAI,KAAK,KAAK,GAAG,QAAU;AAAA,EAC7B;AACA,UAAQ,MAAM,GAAG,SAAS,EAAE;AAC9B;AAEA,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB,oBAAI,IAAoB;AAE/C,SAAS,mBAAmB,KAAiC;AAC3D,QAAM,MAAM,eAAe,IAAI,GAAG;AAClC,MAAI,QAAQ,QAAW;AAErB,mBAAe,OAAO,GAAG;AACzB,mBAAe,IAAI,KAAK,GAAG;AAAA,EAC7B;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAa,OAAqB;AAC5D,iBAAe,IAAI,KAAK,KAAK;AAC7B,SAAO,eAAe,OAAO,sBAAsB;AACjD,UAAM,SAAS,eAAe,KAAK,EAAE,KAAK,EAAE;AAC5C,QAAI,WAAW,OAAW;AAC1B,mBAAe,OAAO,MAAM;AAAA,EAC9B;AACF;AAGO,SAAS,uBAA6B;AAC3C,iBAAe,MAAM;AACvB;AAWA,eAAsB,4BACpB,WACwB;AACxB,QAAM,MAAM,MAAM,SAAS;AAC3B,MAAI,YAAY,mBAAmB,GAAG;AACtC,MAAI,cAAc,QAAW;AAC3B,UAAM,QAAQ;AAAA,MACZ,YAAY,iBAAiB,SAAS,GAAG,GAAG;AAAA,MAC5C,EAAE,KAAK,SAAS;AAAA,IAClB;AACA,UAAM,SAAS,MAAM,UAAU,KAAK;AACpC,gBAAY,UAAU,OAAO,MAAM;AACnC,uBAAmB,KAAK,SAAS;AAAA,EACnC;AACA,QAAM,MAAM,MAAM,OAAO;AACzB,SAAO,IAAI,iBAAiB,WAAW;AAAA,IACrC,QAAQ;AAAA,IACR,SAAS;AAAA,EACX,CAAC;AACH;","names":[]}
|
package/dist/viewer/index.d.ts
CHANGED
|
@@ -82,6 +82,17 @@ declare function discoverClusters(svg: SVGSVGElement): Map<string, ClusterDescri
|
|
|
82
82
|
*/
|
|
83
83
|
declare function colorForPrefix(prefix: string): string;
|
|
84
84
|
|
|
85
|
+
interface VisibilityState {
|
|
86
|
+
/** Cluster short names currently visible. */
|
|
87
|
+
readonly visibleClusters: ReadonlySet<string>;
|
|
88
|
+
/**
|
|
89
|
+
* When false, hide every replica/shared place (`g.node.petri-replica`)
|
|
90
|
+
* regardless of which cluster it belongs to. The corresponding sidebar
|
|
91
|
+
* checkbox is labelled "Shared places".
|
|
92
|
+
*/
|
|
93
|
+
readonly includeSharedPlaces: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
/**
|
|
86
97
|
* CSS custom properties exposed by the canonical viewer stylesheet.
|
|
87
98
|
*
|
|
@@ -96,7 +107,7 @@ declare function colorForPrefix(prefix: string): string;
|
|
|
96
107
|
* @module viewer/styles
|
|
97
108
|
*/
|
|
98
109
|
/** CSS custom property names that the canonical stylesheet honours. */
|
|
99
|
-
declare const VIEWER_CSS_VARIABLES: readonly ["--lpv-bg", "--lpv-header-bg", "--lpv-border", "--lpv-text", "--lpv-muted", "--lpv-cluster-bg", "--lpv-cluster-bg-collapsed", "--lpv-cluster-stroke-width", "--lpv-cluster-stroke-dash", "--lpv-cluster-fill-tint", "--lpv-dim-opacity", "--lpv-active-filter-outline", "--lpv-legend-bg", "--lpv-chip-bg", "--lpv-chip-active-bg"];
|
|
110
|
+
declare const VIEWER_CSS_VARIABLES: readonly ["--lpv-bg", "--lpv-header-bg", "--lpv-border", "--lpv-text", "--lpv-muted", "--lpv-cluster-bg", "--lpv-cluster-bg-collapsed", "--lpv-cluster-stroke-width", "--lpv-cluster-stroke-dash", "--lpv-cluster-fill-tint", "--lpv-dim-opacity", "--lpv-active-filter-outline", "--lpv-legend-bg", "--lpv-chip-bg", "--lpv-chip-active-bg", "--lpv-sidebar-bg", "--lpv-sidebar-border", "--lpv-sidebar-text", "--lpv-sidebar-muted", "--lpv-sidebar-chip-bg", "--lpv-sidebar-chip-hover-bg", "--lpv-sidebar-chip-off-opacity", "--lpv-shared-glyph-color", "--lpv-replica-fill", "--lpv-replica-stroke", "--lpv-highlight-stroke", "--lpv-highlight-glow", "--lpv-neighbor-stroke", "--lpv-faded-node-opacity", "--lpv-faded-edge-opacity", "--lpv-faded-cluster-opacity"];
|
|
100
111
|
|
|
101
112
|
/**
|
|
102
113
|
* Canonical libpetri Petri-net diagram viewer.
|
|
@@ -152,6 +163,18 @@ interface ViewerHandle {
|
|
|
152
163
|
fit(): void;
|
|
153
164
|
/** Reports whether `graphId` is inside a currently-collapsed cluster. */
|
|
154
165
|
isInsideCollapsedCluster(graphId: string): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Highlight a node and every DOM copy of the same logical place; walk
|
|
168
|
+
* junctions to surface real neighbors. Pass `null` to clear. C0-only.
|
|
169
|
+
*/
|
|
170
|
+
highlight(nodeId: string | null): void;
|
|
171
|
+
/** The node id currently highlighted, or `null`. */
|
|
172
|
+
readonly highlightedNodeId: string | null;
|
|
173
|
+
/**
|
|
174
|
+
* Set the cluster-visibility state: which clusters render, and whether
|
|
175
|
+
* directed-reachable orphans render. C0-only.
|
|
176
|
+
*/
|
|
177
|
+
setVisibility(state: VisibilityState): void;
|
|
155
178
|
/** Tear down: dispose panzoom and detach listeners. */
|
|
156
179
|
dispose(): void;
|
|
157
180
|
}
|
|
@@ -172,6 +195,14 @@ interface MountOptions {
|
|
|
172
195
|
readonly onClusterFilter?: (prefix: string | null) => void;
|
|
173
196
|
/** When true, append a legend sidebar + filter chip strip inside `container`. */
|
|
174
197
|
readonly chrome?: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* Layout strategy. `'elk'` (default) runs the C0 pipeline — parse → fold
|
|
200
|
+
* → replicate → ELK → Graphviz `neato` pin mode — and tags replica
|
|
201
|
+
* nodes for the click-all-copies + ⇄ overlay. `'graphviz'` runs the
|
|
202
|
+
* plain Graphviz `dot` engine and skips replica tagging. The result is
|
|
203
|
+
* cached on the DOT hash; re-mounts on identical DOT skip the pipeline.
|
|
204
|
+
*/
|
|
205
|
+
readonly layout?: 'elk' | 'graphviz';
|
|
175
206
|
}
|
|
176
207
|
/**
|
|
177
208
|
* Render a DOT source, mount the resulting SVG into `container`, wire pan/zoom,
|