@knowvah/dot-engine 2.2.0 → 2.3.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.
- package/dist/index.js +274 -257
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/edge-route.d.ts.map +1 -1
- package/dist/layout/dot/ortho-adapter.d.ts +1 -1
- package/dist/layout/dot/ortho-adapter.d.ts.map +1 -1
- package/dist/layout/dot/splines-flat-multi.d.ts +3 -1
- package/dist/layout/dot/splines-flat-multi.d.ts.map +1 -1
- package/dist/layout/dot/splines-flat.d.ts +3 -4
- package/dist/layout/dot/splines-flat.d.ts.map +1 -1
- package/dist/pathplan/route.d.ts.map +1 -1
- package/dist/pathplan/solvers.d.ts +15 -3
- package/dist/pathplan/solvers.d.ts.map +1 -1
- package/dist/render.js +274 -257
- package/dist/render.js.map +4 -4
- package/package.json +5 -3
- package/src/layout/dot/edge-route.ts +17 -7
- package/src/layout/dot/ortho-adapter.ts +4 -3
- package/src/layout/dot/splines-flat-multi.ts +17 -4
- package/src/layout/dot/splines-flat.ts +12 -12
- package/src/parser/dot.js +68 -94
- package/src/parser/dot.pegjs +7 -6
- package/src/pathplan/route.ts +79 -34
- package/src/pathplan/solvers.ts +78 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knowvah/dot-engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Faithful TypeScript port of Graphviz (dot, neato, fdp, sfdp, circo, twopi, osage, patchwork) — no C: no native binary, no WASM. Oracle-verified against the C implementation, runs in the browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphviz",
|
|
@@ -76,10 +76,12 @@
|
|
|
76
76
|
"docs:brand": "node docs-site/copy-brand-assets.mjs",
|
|
77
77
|
"docs:copy-reports": "node docs-site/copy-reports.mjs",
|
|
78
78
|
"docs:copy-goldens": "node docs-site/copy-goldens.mjs",
|
|
79
|
+
"docs:i18n-status": "node scripts/docs-i18n-status.mjs",
|
|
80
|
+
"docs:i18n-hashes": "node scripts/docs-i18n-status.mjs --write-hashes",
|
|
79
81
|
"docs:api": "typedoc",
|
|
80
|
-
"docs:dev": "npm run docs:brand && npm run docs:copy-reports && npm run docs:copy-goldens && npm run docs:api && vitepress dev docs-site",
|
|
82
|
+
"docs:dev": "npm run docs:brand && npm run docs:copy-reports && npm run docs:copy-goldens && npm run docs:i18n-hashes && npm run docs:api && vitepress dev docs-site",
|
|
81
83
|
"predocs:build": "npm run parser:regen",
|
|
82
|
-
"docs:build": "npm run docs:brand && npm run docs:copy-reports && npm run docs:copy-goldens && npm run docs:api && vitepress build docs-site",
|
|
84
|
+
"docs:build": "npm run docs:brand && npm run docs:copy-reports && npm run docs:copy-goldens && npm run docs:i18n-hashes && npm run docs:api && vitepress build docs-site",
|
|
83
85
|
"docs:preview": "vitepress preview docs-site",
|
|
84
86
|
"release": "semantic-release",
|
|
85
87
|
"publish:check": "npm run typecheck && npm run build && npm pack --dry-run",
|
|
@@ -33,8 +33,8 @@ import { ShapeKind, type ShapeDesc } from '../../common/types.js';
|
|
|
33
33
|
import {
|
|
34
34
|
collectNonAdjacentFlatGroup, routeFlatEdgeGroupFaithful,
|
|
35
35
|
} from './splines-flat-multi.js';
|
|
36
|
-
import { makeFlatLabeledEdge, makeAdjFlatNoPortEdge } from './splines-flat-labeled.js';
|
|
37
|
-
import {
|
|
36
|
+
import { makeFlatLabeledEdge, makeAdjFlatNoPortEdge, isAdjFlatCandidate } from './splines-flat-labeled.js';
|
|
37
|
+
import { edgeType, swapEndsP, swapEdgeSpline, getMainEdge } from './splines.js';
|
|
38
38
|
import { FLATORDER } from './fastgr.js';
|
|
39
39
|
import { IGNORED } from './rank.js';
|
|
40
40
|
import { buildDotSinfo } from './self-loop.js';
|
|
@@ -312,9 +312,18 @@ function isAdjacentPortFlat(e: GraphEdge, g: Graph): boolean {
|
|
|
312
312
|
&& isFlatAdjacent(g, e) && hasDefinedPort(e);
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
/** True when x is an unrouted adjacent same-rank flat edge
|
|
315
|
+
/** True when x is an unrouted adjacent same-rank flat edge (port or not): C
|
|
316
|
+
* groups by main edge only, so a port-less sibling joins the aux call. */
|
|
316
317
|
function isGroupableFlat(x: GraphEdge, g: Graph): boolean {
|
|
317
|
-
return x.info.spl === undefined &&
|
|
318
|
+
return x.info.spl === undefined && x.tail.info.rank !== undefined
|
|
319
|
+
&& x.tail.info.rank === x.head.info.rank && isFlatAdjacent(g, x);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** True when a port-less adjacent flat edge shares its group with a ported one:
|
|
323
|
+
* C's `ports` flag covers the whole group, so it routes via the aux graph. */
|
|
324
|
+
function joinsPortedFlatGroup(e: GraphEdge, g: Graph): boolean {
|
|
325
|
+
return isAdjFlatCandidate(e) && isGroupableFlat(e, g)
|
|
326
|
+
&& collectAdjacentFlatGroup(e, g).some(hasDefinedPort);
|
|
318
327
|
}
|
|
319
328
|
|
|
320
329
|
/**
|
|
@@ -362,7 +371,7 @@ function routeFaithfulSidePort(e: GraphEdge, g: Graph): boolean {
|
|
|
362
371
|
// @see lib/dotgen/dotsplines.c:dot_splines_ (ED_adjacent edge-group loop)
|
|
363
372
|
if (sameRank && isFlatAdjacent(g, e)) {
|
|
364
373
|
const group = collectAdjacentFlatGroup(e, g);
|
|
365
|
-
return makeFlatAdjEdges(g, group, group.length,
|
|
374
|
+
return makeFlatAdjEdges(g, group, group.length, edgeType(g)) === 0
|
|
366
375
|
&& e.info.spl !== undefined;
|
|
367
376
|
}
|
|
368
377
|
// Non-adjacent flats: C groups identical-port siblings into ONE make_flat_edge
|
|
@@ -372,7 +381,7 @@ function routeFaithfulSidePort(e: GraphEdge, g: Graph): boolean {
|
|
|
372
381
|
// @see lib/dotgen/dotsplines.c:make_flat_edge, make_flat_bottom_edges
|
|
373
382
|
if (sameRank) {
|
|
374
383
|
const group = collectNonAdjacentFlatGroup(e, g);
|
|
375
|
-
return routeFlatEdgeGroupFaithful(g, group, group.length) && e.info.spl !== undefined;
|
|
384
|
+
return routeFlatEdgeGroupFaithful(g, group, group.length, edgeType(g)) && e.info.spl !== undefined;
|
|
376
385
|
}
|
|
377
386
|
const pts = routeRegularEdgeFaithful(g, e);
|
|
378
387
|
if (pts === null) return false;
|
|
@@ -410,6 +419,7 @@ function routeFlatEdge(e: GraphEdge, g: Graph): boolean {
|
|
|
410
419
|
// above (make_flat_adj_edges → makeSimpleFlatLabels). Both decline for every
|
|
411
420
|
// other edge, so only labeled flats are diverted. @see dotsplines.c:1527-1533
|
|
412
421
|
if (makeFlatLabeledEdge(g, e)) return true;
|
|
422
|
+
if (joinsPortedFlatGroup(e, g) && routeFaithfulSidePort(e, g)) return true;
|
|
413
423
|
if (makeAdjFlatNoPortEdge(g, e)) return true;
|
|
414
424
|
if ((hasSidePort(e) || isAdjacentPortFlat(e, g)) && routeFaithfulSidePort(e, g)) return true;
|
|
415
425
|
// Non-adjacent unlabeled flat with no side port (e.g. a same-rank cross-cluster
|
|
@@ -419,7 +429,7 @@ function routeFlatEdge(e: GraphEdge, g: Graph): boolean {
|
|
|
419
429
|
&& e.info.label === undefined && !isFlatAdjacent(g, e)) {
|
|
420
430
|
const group = collectNonAdjacentFlatGroup(e, g);
|
|
421
431
|
if (group.length > 0
|
|
422
|
-
&& routeFlatEdgeGroupFaithful(g, group, group.length)
|
|
432
|
+
&& routeFlatEdgeGroupFaithful(g, group, group.length, edgeType(g))
|
|
423
433
|
&& e.info.spl !== undefined) return true;
|
|
424
434
|
}
|
|
425
435
|
return false;
|
|
@@ -58,7 +58,9 @@ function buildNodes(nodeArr: Node[]): OrthoNodeArr {
|
|
|
58
58
|
* parallel multi-edge) is skipped. This is ortho's own concentrate mechanism,
|
|
59
59
|
* distinct from class2's `edge_type == IGNORED` marking, and the keep-first
|
|
60
60
|
* decision depends on this iteration order matching C's.
|
|
61
|
-
* Self-loops (tail === head) are
|
|
61
|
+
* Self-loops (tail === head) are gathered like any other edge; orthoEdges
|
|
62
|
+
* routes them via addLoop. Only Concentrate dedup skips edges.
|
|
63
|
+
* @see lib/ortho/ortho.c:orthoEdges
|
|
62
64
|
* @see lib/ortho/ortho.c:1207-1228 (orthoEdges edge gather + Concentrate PS)
|
|
63
65
|
*/
|
|
64
66
|
function buildEdges(
|
|
@@ -74,7 +76,6 @@ function buildEdges(
|
|
|
74
76
|
const oes = outIndex.get(n);
|
|
75
77
|
if (oes === undefined) continue;
|
|
76
78
|
for (const e of oes) {
|
|
77
|
-
if (e.tail === e.head) continue;
|
|
78
79
|
if (concentrate) {
|
|
79
80
|
const ti = e.tail.id;
|
|
80
81
|
const hi = e.head.id;
|
|
@@ -103,7 +104,7 @@ function buildEdges(
|
|
|
103
104
|
return result;
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
/** Build an OrthoGraph from the dot Graph (
|
|
107
|
+
/** Build an OrthoGraph from the dot Graph (every out-edge, self-loops included). */
|
|
107
108
|
export function buildOrthoGraph(g: Graph): OrthoGraph {
|
|
108
109
|
const nodeArr = nodesInSeq(g);
|
|
109
110
|
const orthoNodes = buildNodes(nodeArr);
|
|
@@ -22,10 +22,12 @@ import type { Edge } from '../../model/edge.js';
|
|
|
22
22
|
import type { Node } from '../../model/node.js';
|
|
23
23
|
import type { Port, Box } from '../../model/geom.js';
|
|
24
24
|
import type { Path, PathendT } from '../../common/types.js';
|
|
25
|
-
import { routeSplines } from '../../common/splines-routespl.js';
|
|
25
|
+
import { routeSplines, routePolylines } from '../../common/splines-routespl.js';
|
|
26
26
|
import { clipAndInstall } from '../../common/splines-clip.js';
|
|
27
27
|
import { graphRanksep } from './position-aux.js';
|
|
28
28
|
import { buildDotSinfo } from './self-loop.js';
|
|
29
|
+
import { EDGETYPE_LINE, EDGETYPE_SPLINE } from './splines.js';
|
|
30
|
+
import { makeSimpleFlat } from './splines-flat-labeled.js';
|
|
29
31
|
import {
|
|
30
32
|
isFlatAdjacent, makeFlatEndBox, topBoxes, bottomBoxes, flatSide, flatVspace,
|
|
31
33
|
freshFlatPath, assembleFlatPath, flatBboxCtx,
|
|
@@ -41,6 +43,8 @@ interface GroupRouteCtx {
|
|
|
41
43
|
tlast: Box;
|
|
42
44
|
hlast: Box;
|
|
43
45
|
bottom: boolean;
|
|
46
|
+
/** Edge type: SPLINE routes with routesplines, anything else routepolylines. */
|
|
47
|
+
et: number;
|
|
44
48
|
stepx: number;
|
|
45
49
|
stepy: number;
|
|
46
50
|
/** Geometric left end node of the channel (lower order). routeSplines yields
|
|
@@ -132,7 +136,8 @@ function routeGroupEdge(e: Edge, i: number, c: GroupRouteCtx): boolean {
|
|
|
132
136
|
? bottomBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy)
|
|
133
137
|
: topBoxes(c.tlast, c.hlast, endStepX, endStepY, c.stepy);
|
|
134
138
|
assembleFlatPath(c.P, copyPathEnd(c.tend), copyPathEnd(c.hend), mid);
|
|
135
|
-
|
|
139
|
+
// @see lib/dotgen/dotsplines.c:1603-1607 (et == EDGETYPE_SPLINE ? routesplines : routepolylines)
|
|
140
|
+
const pts = c.et === EDGETYPE_SPLINE ? routeSplines(c.P) : routePolylines(c.P);
|
|
136
141
|
if (pts === null || pts.length === 0) return false;
|
|
137
142
|
// routeSplines returns points left→right (tend = leftNode). Reverse for an edge
|
|
138
143
|
// whose tail is the right node so the points run tail→head; pass ignoreSwap so
|
|
@@ -149,12 +154,20 @@ function routeGroupEdge(e: Edge, i: number, c: GroupRouteCtx): boolean {
|
|
|
149
154
|
* makeFlatEnd tail+head; for i in 0..cnt-1 route edge i nested by (i+1)*step.
|
|
150
155
|
* Installs spl on every edges[i]; returns true iff all installed. cnt=1 reduces
|
|
151
156
|
* to routeFlatEdgeFaithful (AD-1). `edges` must be group-ordered (collect...).
|
|
157
|
+
* `et == EDGETYPE_LINE` short-circuits to makeSimpleFlat (C 1535-1537); the
|
|
158
|
+
* corridor router is routesplines only for EDGETYPE_SPLINE, else routepolylines.
|
|
152
159
|
* @see lib/dotgen/dotsplines.c:make_flat_edge, make_flat_bottom_edges
|
|
153
160
|
*/
|
|
154
|
-
export function routeFlatEdgeGroupFaithful(
|
|
161
|
+
export function routeFlatEdgeGroupFaithful(
|
|
162
|
+
g: Graph, edges: Edge[], cnt: number, et: number,
|
|
163
|
+
): boolean {
|
|
155
164
|
const lead = edges[0];
|
|
156
165
|
if (g.info.rank === undefined || lead.tail.info.rank === undefined
|
|
157
166
|
|| lead.head.info.rank !== lead.tail.info.rank) return false;
|
|
167
|
+
if (et === EDGETYPE_LINE) {
|
|
168
|
+
makeSimpleFlat(edges, et);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
158
171
|
// C makefwdedge: build the channel left→right by node order, else the middle
|
|
159
172
|
// box inverts for a right-to-left (tail right of head) flat edge.
|
|
160
173
|
const tailIsLeft = (lead.tail.info.order ?? 0) <= (lead.head.info.order ?? 0);
|
|
@@ -179,7 +192,7 @@ export function routeFlatEdgeGroupFaithful(g: Graph, edges: Edge[], cnt: number)
|
|
|
179
192
|
const stepy = flatVspace(g, leftNode, !bottom) / (cnt + 1);
|
|
180
193
|
const rc: GroupRouteCtx = {
|
|
181
194
|
P, tend, hend, tlast: tend.boxes[tend.boxn - 1], hlast: hend.boxes[hend.boxn - 1],
|
|
182
|
-
bottom, stepx, stepy, leftNode,
|
|
195
|
+
bottom, et, stepx, stepy, leftNode,
|
|
183
196
|
};
|
|
184
197
|
for (let i = 0; i < cnt; i++) {
|
|
185
198
|
if (!routeGroupEdge(edges[i], i, rc)) return false;
|
|
@@ -21,11 +21,11 @@ import { dotRank } from './rank.js';
|
|
|
21
21
|
import { dotMincross } from './mincross.js';
|
|
22
22
|
import { dotPosition } from './position.js';
|
|
23
23
|
import { dotSameports } from './sameport.js';
|
|
24
|
-
import { dotSplines_, swapEndsP, swapEdgeSpline } from './splines.js';
|
|
24
|
+
import { dotSplines_, swapEndsP, swapEdgeSpline, EDGETYPE_SPLINE } from './splines.js';
|
|
25
25
|
import { makePort } from '../../model/edgeInfo.js';
|
|
26
26
|
import { beginPath } from '../../common/splines-path-begin.js';
|
|
27
27
|
import { endPath } from '../../common/splines-path-end.js';
|
|
28
|
-
import { routeSplines } from '../../common/splines-routespl.js';
|
|
28
|
+
import { routeSplines, routePolylines } from '../../common/splines-routespl.js';
|
|
29
29
|
import { addBox, resolvePort } from '../../common/splines-path-shared.js';
|
|
30
30
|
import { TOP, BOTTOM, FLATEDGE } from '../../common/splines-constants.js';
|
|
31
31
|
import {
|
|
@@ -363,8 +363,11 @@ function normalizeCopiedFlatSpline(orig: Edge, auxe: Edge): void {
|
|
|
363
363
|
* makeSimpleFlat branch are out of scope (callers gate on a side port).
|
|
364
364
|
* @see lib/dotgen/dotsplines.c:make_flat_adj_edges
|
|
365
365
|
*/
|
|
366
|
-
export function makeFlatAdjEdges(g: Graph, edges: Edge[], cnt: number,
|
|
366
|
+
export function makeFlatAdjEdges(g: Graph, edges: Edge[], cnt: number, et: number): number {
|
|
367
367
|
const aux = buildFlatAux(g, edges, cnt);
|
|
368
|
+
// C setEdgeType(auxg, et); inlined (index.ts's setEdgeType would be an import cycle).
|
|
369
|
+
// @see lib/dotgen/dotsplines.c:make_flat_adj_edges
|
|
370
|
+
aux.auxg.info.flags = (aux.auxg.info.flags & ~0xf) | (et & 0xf);
|
|
368
371
|
dotInitNodeEdge(aux.auxg);
|
|
369
372
|
dotRank(aux.auxg);
|
|
370
373
|
if (dotMincross(aux.auxg) !== 0) return 1;
|
|
@@ -571,12 +574,11 @@ export function assembleFlatPath(P: Path, tend: PathendT, hend: PathendT, mid: B
|
|
|
571
574
|
* faithful `beginPath → routeSplines → endPath → clipAndInstall` pipeline.
|
|
572
575
|
* Returns spline control points in graphviz-internal (y-up) coordinates, or
|
|
573
576
|
* null when the edge is not a same-rank edge. Does NOT clip or install — the
|
|
574
|
-
* caller (routeOneEdge) does that via clipAndInstall
|
|
575
|
-
* the regular faithful path.
|
|
577
|
+
* caller (routeOneEdge) does that via clipAndInstall (as the regular path).
|
|
576
578
|
*
|
|
577
579
|
* @see lib/dotgen/dotsplines.c:make_flat_edge (cnt=1, non-adjacent spline)
|
|
578
580
|
*/
|
|
579
|
-
export function routeFlatEdgeFaithful(g: Graph, e: Edge): Point[] | null {
|
|
581
|
+
export function routeFlatEdgeFaithful(g: Graph, e: Edge, et: number): Point[] | null {
|
|
580
582
|
const tn = e.tail;
|
|
581
583
|
const r = tn.info.rank;
|
|
582
584
|
if (g.info.rank === undefined || r === undefined || e.head.info.rank !== r) return null;
|
|
@@ -588,11 +590,9 @@ export function routeFlatEdgeFaithful(g: Graph, e: Edge): Point[] | null {
|
|
|
588
590
|
const hend = makeFlatEndBox({ ctx, P, e, n: e.head, side, ranksep, isBegin: false });
|
|
589
591
|
const stepx = (g.info.nodesep ?? 18) / 2;
|
|
590
592
|
const stepy = flatVspace(g, tn, !bottom) / 2;
|
|
591
|
-
const tlast = tend.boxes[tend.boxn - 1];
|
|
592
|
-
const
|
|
593
|
-
const mid = bottom
|
|
594
|
-
? bottomBoxes(tlast, hlast, stepx, stepy, stepy)
|
|
595
|
-
: topBoxes(tlast, hlast, stepx, stepy, stepy);
|
|
593
|
+
const [tlast, hlast] = [tend.boxes[tend.boxn - 1], hend.boxes[hend.boxn - 1]];
|
|
594
|
+
const mid = (bottom ? bottomBoxes : topBoxes)(tlast, hlast, stepx, stepy, stepy);
|
|
596
595
|
assembleFlatPath(P, tend, hend, mid);
|
|
597
|
-
|
|
596
|
+
// @see lib/dotgen/dotsplines.c:1603-1607
|
|
597
|
+
return et === EDGETYPE_SPLINE ? routeSplines(P) : routePolylines(P);
|
|
598
598
|
}
|
package/src/parser/dot.js
CHANGED
|
@@ -291,12 +291,11 @@ function peg$parse(input, options) {
|
|
|
291
291
|
function peg$f15() { return "node"; }
|
|
292
292
|
function peg$f16() { return "edge"; }
|
|
293
293
|
function peg$f17(defs, rest) { return defs.concat(rest); }
|
|
294
|
-
function peg$f18(
|
|
295
|
-
function peg$f19() { return
|
|
296
|
-
function peg$f20(
|
|
297
|
-
function peg$f21(
|
|
298
|
-
function peg$f22(
|
|
299
|
-
function peg$f23(head, chain, attrs) {
|
|
294
|
+
function peg$f18() { return []; }
|
|
295
|
+
function peg$f19(a) { return a; }
|
|
296
|
+
function peg$f20(pairs) { return pairs; }
|
|
297
|
+
function peg$f21(k, v) { return { key: k, value: v }; }
|
|
298
|
+
function peg$f22(head, chain, attrs) {
|
|
300
299
|
if (chain.length > 0) {
|
|
301
300
|
const nodes = [head].concat(chain);
|
|
302
301
|
return { type: "edge", nodes: nodes, attrs: attrs };
|
|
@@ -310,28 +309,28 @@ function peg$parse(input, options) {
|
|
|
310
309
|
return { type: "node", id: head, attrs: attrs };
|
|
311
310
|
}
|
|
312
311
|
}
|
|
313
|
-
function peg$
|
|
314
|
-
function peg$
|
|
315
|
-
function peg$
|
|
316
|
-
function peg$
|
|
317
|
-
function peg$
|
|
318
|
-
function peg$
|
|
319
|
-
function peg$
|
|
320
|
-
function peg$
|
|
312
|
+
function peg$f23(s) { return s; }
|
|
313
|
+
function peg$f24(n) { return n; }
|
|
314
|
+
function peg$f25(id, port, compass) { return { id: id, port: port, compass: compass }; }
|
|
315
|
+
function peg$f26(id, port) { return { id: id, port: port, compass: null }; }
|
|
316
|
+
function peg$f27(id) { return { id: id, port: null, compass: null }; }
|
|
317
|
+
function peg$f28(s, rest) { return [s].concat(rest); }
|
|
318
|
+
function peg$f29() { return []; }
|
|
319
|
+
function peg$f30(id, stmts) { return { type: "subgraph", id: id, stmts: stmts }; }
|
|
320
|
+
function peg$f31(stmts) { return { type: "subgraph", id: null, stmts: stmts }; }
|
|
321
321
|
function peg$f32(stmts) { return { type: "subgraph", id: null, stmts: stmts }; }
|
|
322
|
-
function peg$f33(
|
|
323
|
-
function peg$f34(first,
|
|
324
|
-
function peg$f35(
|
|
325
|
-
function peg$f36(
|
|
326
|
-
function peg$f37() { return '
|
|
327
|
-
function peg$f38() { return ''; }
|
|
328
|
-
function peg$f39(
|
|
329
|
-
function peg$f40(
|
|
330
|
-
function peg$f41(
|
|
331
|
-
function peg$f42(
|
|
332
|
-
function peg$f43(
|
|
333
|
-
function peg$f44(
|
|
334
|
-
function peg$f45(s) { return Array.isArray(s) ? s.flat(Infinity).filter(x => x !== null && x !== undefined).join("") : String(s); }
|
|
322
|
+
function peg$f33(first, s) { return s; }
|
|
323
|
+
function peg$f34(first, rest) { return rest.length > 0 ? first + rest.join("") : first; }
|
|
324
|
+
function peg$f35(chars) { return chars.join(""); }
|
|
325
|
+
function peg$f36() { return '"'; }
|
|
326
|
+
function peg$f37() { return ''; }
|
|
327
|
+
function peg$f38(c) { return '\\' + c; }
|
|
328
|
+
function peg$f39(content) { return "\u0001" + content; }
|
|
329
|
+
function peg$f40(chars) { return chars.join(""); }
|
|
330
|
+
function peg$f41(nested, content) { return "<" + content + ">"; }
|
|
331
|
+
function peg$f42(n) { return n; }
|
|
332
|
+
function peg$f43(first, rest) { return first + rest.join(""); }
|
|
333
|
+
function peg$f44(s) { return Array.isArray(s) ? s.flat(Infinity).filter(x => x !== null && x !== undefined).join("") : String(s); }
|
|
335
334
|
let peg$currPos = options.peg$currPos | 0;
|
|
336
335
|
let peg$savedPos = peg$currPos;
|
|
337
336
|
const peg$posDetailsCache = [{ line: 1, column: 1 }];
|
|
@@ -749,7 +748,7 @@ function peg$parse(input, options) {
|
|
|
749
748
|
s1 = peg$parseAttrType();
|
|
750
749
|
if (s1 !== peg$FAILED) {
|
|
751
750
|
s2 = peg$parse_();
|
|
752
|
-
s3 = peg$
|
|
751
|
+
s3 = peg$parseAttrListReq();
|
|
753
752
|
if (s3 !== peg$FAILED) {
|
|
754
753
|
peg$savedPos = s0;
|
|
755
754
|
s0 = peg$f12(s1, s3);
|
|
@@ -806,7 +805,7 @@ function peg$parse(input, options) {
|
|
|
806
805
|
return s0;
|
|
807
806
|
}
|
|
808
807
|
|
|
809
|
-
function peg$
|
|
808
|
+
function peg$parseAttrListReq() {
|
|
810
809
|
let s0, s1, s2, s3, s4, s5, s6, s7;
|
|
811
810
|
|
|
812
811
|
s0 = peg$currPos;
|
|
@@ -846,45 +845,20 @@ function peg$parse(input, options) {
|
|
|
846
845
|
peg$currPos = s0;
|
|
847
846
|
s0 = peg$FAILED;
|
|
848
847
|
}
|
|
848
|
+
|
|
849
|
+
return s0;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function peg$parseAttrList() {
|
|
853
|
+
let s0, s1;
|
|
854
|
+
|
|
855
|
+
s0 = peg$parseAttrListReq();
|
|
849
856
|
if (s0 === peg$FAILED) {
|
|
850
857
|
s0 = peg$currPos;
|
|
851
|
-
s1 =
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
} else {
|
|
856
|
-
s2 = peg$FAILED;
|
|
857
|
-
if (peg$silentFails === 0) { peg$fail(peg$e3); }
|
|
858
|
-
}
|
|
859
|
-
if (s2 !== peg$FAILED) {
|
|
860
|
-
s3 = peg$parse_();
|
|
861
|
-
s4 = peg$parseAttrDefs();
|
|
862
|
-
s5 = peg$parse_();
|
|
863
|
-
if (input.charCodeAt(peg$currPos) === 93) {
|
|
864
|
-
s6 = peg$c4;
|
|
865
|
-
peg$currPos++;
|
|
866
|
-
} else {
|
|
867
|
-
s6 = peg$FAILED;
|
|
868
|
-
if (peg$silentFails === 0) { peg$fail(peg$e4); }
|
|
869
|
-
}
|
|
870
|
-
if (s6 !== peg$FAILED) {
|
|
871
|
-
peg$savedPos = s0;
|
|
872
|
-
s0 = peg$f18(s4);
|
|
873
|
-
} else {
|
|
874
|
-
peg$currPos = s0;
|
|
875
|
-
s0 = peg$FAILED;
|
|
876
|
-
}
|
|
877
|
-
} else {
|
|
878
|
-
peg$currPos = s0;
|
|
879
|
-
s0 = peg$FAILED;
|
|
880
|
-
}
|
|
881
|
-
if (s0 === peg$FAILED) {
|
|
882
|
-
s0 = peg$currPos;
|
|
883
|
-
s1 = '';
|
|
884
|
-
peg$savedPos = s0;
|
|
885
|
-
s1 = peg$f19();
|
|
886
|
-
s0 = s1;
|
|
887
|
-
}
|
|
858
|
+
s1 = '';
|
|
859
|
+
peg$savedPos = s0;
|
|
860
|
+
s1 = peg$f18();
|
|
861
|
+
s0 = s1;
|
|
888
862
|
}
|
|
889
863
|
|
|
890
864
|
return s0;
|
|
@@ -919,7 +893,7 @@ function peg$parse(input, options) {
|
|
|
919
893
|
s5 = null;
|
|
920
894
|
}
|
|
921
895
|
peg$savedPos = s2;
|
|
922
|
-
s2 = peg$
|
|
896
|
+
s2 = peg$f19(s3);
|
|
923
897
|
} else {
|
|
924
898
|
peg$currPos = s2;
|
|
925
899
|
s2 = peg$FAILED;
|
|
@@ -950,14 +924,14 @@ function peg$parse(input, options) {
|
|
|
950
924
|
s5 = null;
|
|
951
925
|
}
|
|
952
926
|
peg$savedPos = s2;
|
|
953
|
-
s2 = peg$
|
|
927
|
+
s2 = peg$f19(s3);
|
|
954
928
|
} else {
|
|
955
929
|
peg$currPos = s2;
|
|
956
930
|
s2 = peg$FAILED;
|
|
957
931
|
}
|
|
958
932
|
}
|
|
959
933
|
peg$savedPos = s0;
|
|
960
|
-
s1 = peg$
|
|
934
|
+
s1 = peg$f20(s1);
|
|
961
935
|
s0 = s1;
|
|
962
936
|
|
|
963
937
|
return s0;
|
|
@@ -982,7 +956,7 @@ function peg$parse(input, options) {
|
|
|
982
956
|
s5 = peg$parseAtom();
|
|
983
957
|
if (s5 !== peg$FAILED) {
|
|
984
958
|
peg$savedPos = s0;
|
|
985
|
-
s0 = peg$
|
|
959
|
+
s0 = peg$f21(s1, s5);
|
|
986
960
|
} else {
|
|
987
961
|
peg$currPos = s0;
|
|
988
962
|
s0 = peg$FAILED;
|
|
@@ -1012,7 +986,7 @@ function peg$parse(input, options) {
|
|
|
1012
986
|
s5 = peg$parseAttrList();
|
|
1013
987
|
if (s5 !== peg$FAILED) {
|
|
1014
988
|
peg$savedPos = s0;
|
|
1015
|
-
s0 = peg$
|
|
989
|
+
s0 = peg$f22(s1, s3, s5);
|
|
1016
990
|
} else {
|
|
1017
991
|
peg$currPos = s0;
|
|
1018
992
|
s0 = peg$FAILED;
|
|
@@ -1036,7 +1010,7 @@ function peg$parse(input, options) {
|
|
|
1036
1010
|
s1 = peg$parseSubgraph();
|
|
1037
1011
|
if (s1 !== peg$FAILED) {
|
|
1038
1012
|
peg$savedPos = s0;
|
|
1039
|
-
s1 = peg$
|
|
1013
|
+
s1 = peg$f23(s1);
|
|
1040
1014
|
}
|
|
1041
1015
|
s0 = s1;
|
|
1042
1016
|
if (s0 === peg$FAILED) {
|
|
@@ -1044,7 +1018,7 @@ function peg$parse(input, options) {
|
|
|
1044
1018
|
s1 = peg$parseNode();
|
|
1045
1019
|
if (s1 !== peg$FAILED) {
|
|
1046
1020
|
peg$savedPos = s0;
|
|
1047
|
-
s1 = peg$
|
|
1021
|
+
s1 = peg$f24(s1);
|
|
1048
1022
|
}
|
|
1049
1023
|
s0 = s1;
|
|
1050
1024
|
}
|
|
@@ -1083,7 +1057,7 @@ function peg$parse(input, options) {
|
|
|
1083
1057
|
s9 = peg$parseAtom();
|
|
1084
1058
|
if (s9 !== peg$FAILED) {
|
|
1085
1059
|
peg$savedPos = s0;
|
|
1086
|
-
s0 = peg$
|
|
1060
|
+
s0 = peg$f25(s1, s5, s9);
|
|
1087
1061
|
} else {
|
|
1088
1062
|
peg$currPos = s0;
|
|
1089
1063
|
s0 = peg$FAILED;
|
|
@@ -1121,7 +1095,7 @@ function peg$parse(input, options) {
|
|
|
1121
1095
|
s5 = peg$parseAtom();
|
|
1122
1096
|
if (s5 !== peg$FAILED) {
|
|
1123
1097
|
peg$savedPos = s0;
|
|
1124
|
-
s0 = peg$
|
|
1098
|
+
s0 = peg$f26(s1, s5);
|
|
1125
1099
|
} else {
|
|
1126
1100
|
peg$currPos = s0;
|
|
1127
1101
|
s0 = peg$FAILED;
|
|
@@ -1139,7 +1113,7 @@ function peg$parse(input, options) {
|
|
|
1139
1113
|
s1 = peg$parseAtom();
|
|
1140
1114
|
if (s1 !== peg$FAILED) {
|
|
1141
1115
|
peg$savedPos = s0;
|
|
1142
|
-
s1 = peg$
|
|
1116
|
+
s1 = peg$f27(s1);
|
|
1143
1117
|
}
|
|
1144
1118
|
s0 = s1;
|
|
1145
1119
|
}
|
|
@@ -1161,7 +1135,7 @@ function peg$parse(input, options) {
|
|
|
1161
1135
|
s5 = peg$parseEdgeChain();
|
|
1162
1136
|
if (s5 !== peg$FAILED) {
|
|
1163
1137
|
peg$savedPos = s0;
|
|
1164
|
-
s0 = peg$
|
|
1138
|
+
s0 = peg$f28(s3, s5);
|
|
1165
1139
|
} else {
|
|
1166
1140
|
peg$currPos = s0;
|
|
1167
1141
|
s0 = peg$FAILED;
|
|
@@ -1178,7 +1152,7 @@ function peg$parse(input, options) {
|
|
|
1178
1152
|
s0 = peg$currPos;
|
|
1179
1153
|
s1 = '';
|
|
1180
1154
|
peg$savedPos = s0;
|
|
1181
|
-
s1 = peg$
|
|
1155
|
+
s1 = peg$f29();
|
|
1182
1156
|
s0 = s1;
|
|
1183
1157
|
}
|
|
1184
1158
|
|
|
@@ -1245,7 +1219,7 @@ function peg$parse(input, options) {
|
|
|
1245
1219
|
}
|
|
1246
1220
|
if (s9 !== peg$FAILED) {
|
|
1247
1221
|
peg$savedPos = s0;
|
|
1248
|
-
s0 = peg$
|
|
1222
|
+
s0 = peg$f30(s3, s7);
|
|
1249
1223
|
} else {
|
|
1250
1224
|
peg$currPos = s0;
|
|
1251
1225
|
s0 = peg$FAILED;
|
|
@@ -1292,7 +1266,7 @@ function peg$parse(input, options) {
|
|
|
1292
1266
|
}
|
|
1293
1267
|
if (s7 !== peg$FAILED) {
|
|
1294
1268
|
peg$savedPos = s0;
|
|
1295
|
-
s0 = peg$
|
|
1269
|
+
s0 = peg$f31(s5);
|
|
1296
1270
|
} else {
|
|
1297
1271
|
peg$currPos = s0;
|
|
1298
1272
|
s0 = peg$FAILED;
|
|
@@ -1332,7 +1306,7 @@ function peg$parse(input, options) {
|
|
|
1332
1306
|
}
|
|
1333
1307
|
if (s5 !== peg$FAILED) {
|
|
1334
1308
|
peg$savedPos = s0;
|
|
1335
|
-
s0 = peg$
|
|
1309
|
+
s0 = peg$f32(s3);
|
|
1336
1310
|
} else {
|
|
1337
1311
|
peg$currPos = s0;
|
|
1338
1312
|
s0 = peg$FAILED;
|
|
@@ -1372,7 +1346,7 @@ function peg$parse(input, options) {
|
|
|
1372
1346
|
s7 = peg$parseQAtom();
|
|
1373
1347
|
if (s7 !== peg$FAILED) {
|
|
1374
1348
|
peg$savedPos = s3;
|
|
1375
|
-
s3 = peg$
|
|
1349
|
+
s3 = peg$f33(s1, s7);
|
|
1376
1350
|
} else {
|
|
1377
1351
|
peg$currPos = s3;
|
|
1378
1352
|
s3 = peg$FAILED;
|
|
@@ -1397,7 +1371,7 @@ function peg$parse(input, options) {
|
|
|
1397
1371
|
s7 = peg$parseQAtom();
|
|
1398
1372
|
if (s7 !== peg$FAILED) {
|
|
1399
1373
|
peg$savedPos = s3;
|
|
1400
|
-
s3 = peg$
|
|
1374
|
+
s3 = peg$f33(s1, s7);
|
|
1401
1375
|
} else {
|
|
1402
1376
|
peg$currPos = s3;
|
|
1403
1377
|
s3 = peg$FAILED;
|
|
@@ -1408,7 +1382,7 @@ function peg$parse(input, options) {
|
|
|
1408
1382
|
}
|
|
1409
1383
|
}
|
|
1410
1384
|
peg$savedPos = s0;
|
|
1411
|
-
s0 = peg$
|
|
1385
|
+
s0 = peg$f34(s1, s2);
|
|
1412
1386
|
} else {
|
|
1413
1387
|
peg$currPos = s0;
|
|
1414
1388
|
s0 = peg$FAILED;
|
|
@@ -1458,7 +1432,7 @@ function peg$parse(input, options) {
|
|
|
1458
1432
|
}
|
|
1459
1433
|
if (s3 !== peg$FAILED) {
|
|
1460
1434
|
peg$savedPos = s0;
|
|
1461
|
-
s0 = peg$
|
|
1435
|
+
s0 = peg$f35(s2);
|
|
1462
1436
|
} else {
|
|
1463
1437
|
peg$currPos = s0;
|
|
1464
1438
|
s0 = peg$FAILED;
|
|
@@ -1484,7 +1458,7 @@ function peg$parse(input, options) {
|
|
|
1484
1458
|
}
|
|
1485
1459
|
if (s1 !== peg$FAILED) {
|
|
1486
1460
|
peg$savedPos = s0;
|
|
1487
|
-
s1 = peg$
|
|
1461
|
+
s1 = peg$f36();
|
|
1488
1462
|
}
|
|
1489
1463
|
s0 = s1;
|
|
1490
1464
|
if (s0 === peg$FAILED) {
|
|
@@ -1498,7 +1472,7 @@ function peg$parse(input, options) {
|
|
|
1498
1472
|
}
|
|
1499
1473
|
if (s1 !== peg$FAILED) {
|
|
1500
1474
|
peg$savedPos = s0;
|
|
1501
|
-
s1 = peg$
|
|
1475
|
+
s1 = peg$f37();
|
|
1502
1476
|
}
|
|
1503
1477
|
s0 = s1;
|
|
1504
1478
|
if (s0 === peg$FAILED) {
|
|
@@ -1520,7 +1494,7 @@ function peg$parse(input, options) {
|
|
|
1520
1494
|
}
|
|
1521
1495
|
if (s2 !== peg$FAILED) {
|
|
1522
1496
|
peg$savedPos = s0;
|
|
1523
|
-
s0 = peg$
|
|
1497
|
+
s0 = peg$f38(s2);
|
|
1524
1498
|
} else {
|
|
1525
1499
|
peg$currPos = s0;
|
|
1526
1500
|
s0 = peg$FAILED;
|
|
@@ -1566,7 +1540,7 @@ function peg$parse(input, options) {
|
|
|
1566
1540
|
}
|
|
1567
1541
|
if (s3 !== peg$FAILED) {
|
|
1568
1542
|
peg$savedPos = s0;
|
|
1569
|
-
s0 = peg$
|
|
1543
|
+
s0 = peg$f39(s2);
|
|
1570
1544
|
} else {
|
|
1571
1545
|
peg$currPos = s0;
|
|
1572
1546
|
s0 = peg$FAILED;
|
|
@@ -1590,7 +1564,7 @@ function peg$parse(input, options) {
|
|
|
1590
1564
|
s2 = peg$parseHtmlChar();
|
|
1591
1565
|
}
|
|
1592
1566
|
peg$savedPos = s0;
|
|
1593
|
-
s1 = peg$
|
|
1567
|
+
s1 = peg$f40(s1);
|
|
1594
1568
|
s0 = s1;
|
|
1595
1569
|
|
|
1596
1570
|
return s0;
|
|
@@ -1619,7 +1593,7 @@ function peg$parse(input, options) {
|
|
|
1619
1593
|
}
|
|
1620
1594
|
if (s3 !== peg$FAILED) {
|
|
1621
1595
|
peg$savedPos = s0;
|
|
1622
|
-
s0 = peg$
|
|
1596
|
+
s0 = peg$f41(s1, s2);
|
|
1623
1597
|
} else {
|
|
1624
1598
|
peg$currPos = s0;
|
|
1625
1599
|
s0 = peg$FAILED;
|
|
@@ -1665,7 +1639,7 @@ function peg$parse(input, options) {
|
|
|
1665
1639
|
s2 = peg$parseName();
|
|
1666
1640
|
if (s2 !== peg$FAILED) {
|
|
1667
1641
|
peg$savedPos = s0;
|
|
1668
|
-
s0 = peg$
|
|
1642
|
+
s0 = peg$f42(s2);
|
|
1669
1643
|
} else {
|
|
1670
1644
|
peg$currPos = s0;
|
|
1671
1645
|
s0 = peg$FAILED;
|
|
@@ -1710,7 +1684,7 @@ function peg$parse(input, options) {
|
|
|
1710
1684
|
}
|
|
1711
1685
|
}
|
|
1712
1686
|
peg$savedPos = s0;
|
|
1713
|
-
s0 = peg$
|
|
1687
|
+
s0 = peg$f43(s1, s2);
|
|
1714
1688
|
} else {
|
|
1715
1689
|
peg$currPos = s0;
|
|
1716
1690
|
s0 = peg$FAILED;
|
|
@@ -1908,7 +1882,7 @@ function peg$parse(input, options) {
|
|
|
1908
1882
|
}
|
|
1909
1883
|
if (s1 !== peg$FAILED) {
|
|
1910
1884
|
peg$savedPos = s0;
|
|
1911
|
-
s1 = peg$
|
|
1885
|
+
s1 = peg$f44(s1);
|
|
1912
1886
|
}
|
|
1913
1887
|
s0 = s1;
|
|
1914
1888
|
|
package/src/parser/dot.pegjs
CHANGED
|
@@ -57,7 +57,7 @@ Stmt
|
|
|
57
57
|
// grammar.y: attrtype : T_graph | T_node | T_edge
|
|
58
58
|
// grammar.y: graphattrdefs : attrassignment (bare key=value at graph level)
|
|
59
59
|
AttrStmt
|
|
60
|
-
= t:AttrType _ attrs:
|
|
60
|
+
= t:AttrType _ attrs:AttrListReq
|
|
61
61
|
{ return { type: "attr", target: t, attrs: attrs }; }
|
|
62
62
|
/ a:AttrAssignment
|
|
63
63
|
{ return { type: "assign", key: a.key, value: a.value }; }
|
|
@@ -68,13 +68,14 @@ AttrType
|
|
|
68
68
|
/ NodeKw { return "node"; }
|
|
69
69
|
/ EdgeKw { return "edge"; }
|
|
70
70
|
|
|
71
|
-
// grammar.y:
|
|
72
|
-
|
|
73
|
-
AttrList
|
|
71
|
+
// grammar.y: attrlist : optattr '[' optattrdefs ']' (one or more bracket groups)
|
|
72
|
+
AttrListReq
|
|
74
73
|
= _ "[" _ defs:AttrDefs _ "]" rest:AttrList
|
|
75
74
|
{ return defs.concat(rest); }
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
|
|
76
|
+
// grammar.y: optattr : attrlist | /* empty */
|
|
77
|
+
AttrList
|
|
78
|
+
= AttrListReq
|
|
78
79
|
/ "" { return []; }
|
|
79
80
|
|
|
80
81
|
// grammar.y: optattrdefs : optattrdefs attrdefs | /* empty */
|