@deck.gl-community/graph-layers 9.2.0-beta.2 → 9.2.0-beta.4
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/_deprecated/old-constants.d.ts +1 -0
- package/dist/_deprecated/old-constants.js +1 -0
- package/dist/core/cache.d.ts +1 -0
- package/dist/core/cache.js +1 -0
- package/dist/core/constants.d.ts +2 -1
- package/dist/core/constants.js +1 -0
- package/dist/core/graph-engine.d.ts +64 -21
- package/dist/core/graph-engine.d.ts.map +1 -1
- package/dist/core/graph-engine.js +158 -77
- package/dist/core/graph-engine.js.map +1 -1
- package/dist/core/graph-layout.d.ts +23 -18
- package/dist/core/graph-layout.d.ts.map +1 -1
- package/dist/core/graph-layout.js +35 -19
- package/dist/core/graph-layout.js.map +1 -1
- package/dist/core/interaction-manager.d.ts +5 -4
- package/dist/core/interaction-manager.d.ts.map +1 -1
- package/dist/core/interaction-manager.js +10 -7
- package/dist/core/interaction-manager.js.map +1 -1
- package/dist/graph/arrow-graph.d.ts +70 -0
- package/dist/graph/arrow-graph.d.ts.map +1 -0
- package/dist/graph/arrow-graph.js +514 -0
- package/dist/graph/arrow-graph.js.map +1 -0
- package/dist/graph/classic-graph.d.ts +170 -0
- package/dist/graph/classic-graph.d.ts.map +1 -0
- package/dist/graph/classic-graph.js +391 -0
- package/dist/graph/classic-graph.js.map +1 -0
- package/dist/graph/edge.d.ts +8 -7
- package/dist/graph/edge.d.ts.map +1 -1
- package/dist/graph/edge.js +1 -0
- package/dist/graph/edge.js.map +1 -1
- package/dist/graph/functions/arrow-utils.d.ts +7 -0
- package/dist/graph/functions/arrow-utils.d.ts.map +1 -0
- package/dist/graph/functions/arrow-utils.js +68 -0
- package/dist/graph/functions/arrow-utils.js.map +1 -0
- package/dist/graph/functions/create-graph-from-data.d.ts +4 -0
- package/dist/graph/functions/create-graph-from-data.d.ts.map +1 -0
- package/dist/graph/functions/create-graph-from-data.js +13 -0
- package/dist/graph/functions/create-graph-from-data.js.map +1 -0
- package/dist/graph/graph-normalization.d.ts +11 -0
- package/dist/graph/graph-normalization.d.ts.map +1 -0
- package/dist/graph/graph-normalization.js +66 -0
- package/dist/graph/graph-normalization.js.map +1 -0
- package/dist/graph/graph.d.ts +63 -155
- package/dist/graph/graph.d.ts.map +1 -1
- package/dist/graph/graph.js +12 -300
- package/dist/graph/graph.js.map +1 -1
- package/dist/graph/node.d.ts +8 -7
- package/dist/graph/node.d.ts.map +1 -1
- package/dist/graph/node.js +3 -2
- package/dist/graph/node.js.map +1 -1
- package/dist/graph-data/arrow-graph-data-builder.d.ts +22 -0
- package/dist/graph-data/arrow-graph-data-builder.d.ts.map +1 -0
- package/dist/graph-data/arrow-graph-data-builder.js +106 -0
- package/dist/graph-data/arrow-graph-data-builder.js.map +1 -0
- package/dist/graph-data/graph-data-builder.d.ts +7 -0
- package/dist/graph-data/graph-data-builder.d.ts.map +1 -0
- package/dist/graph-data/graph-data-builder.js +2 -0
- package/dist/graph-data/graph-data-builder.js.map +1 -0
- package/dist/graph-data/graph-data.d.ts +41 -0
- package/dist/graph-data/graph-data.d.ts.map +1 -0
- package/dist/graph-data/graph-data.js +12 -0
- package/dist/graph-data/graph-data.js.map +1 -0
- package/dist/graph-data/plain-graph-data-builder.d.ts +21 -0
- package/dist/graph-data/plain-graph-data-builder.d.ts.map +1 -0
- package/dist/graph-data/plain-graph-data-builder.js +106 -0
- package/dist/graph-data/plain-graph-data-builder.js.map +1 -0
- package/dist/graph-style-schema.cdn.js +1 -1
- package/dist/graph-style-schema.json +1 -1
- package/dist/index.cjs +6905 -4576
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +36 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -29
- package/dist/index.js.map +1 -1
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.d.ts +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-fragment.glsl.js +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.d.ts +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex-tf.glsl.js +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.d.ts +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer-vertex.glsl.js +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts +1 -0
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer.d.ts.map +1 -1
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js +2 -2
- package/dist/layers/common-layers/flow-path-layer/flow-path-layer.js.map +1 -1
- package/dist/layers/common-layers/grid-layer/grid-layer.d.ts +84 -0
- package/dist/layers/common-layers/grid-layer/grid-layer.d.ts.map +1 -0
- package/dist/layers/common-layers/grid-layer/grid-layer.js +134 -0
- package/dist/layers/common-layers/grid-layer/grid-layer.js.map +1 -0
- package/dist/layers/common-layers/marker-layer/atlas-data-url.d.ts +1 -0
- package/dist/layers/common-layers/marker-layer/atlas-data-url.js +1 -0
- package/dist/layers/common-layers/marker-layer/marker-layer.d.ts +1 -0
- package/dist/layers/common-layers/marker-layer/marker-layer.js +3 -2
- package/dist/layers/common-layers/marker-layer/marker-list.d.ts +1 -0
- package/dist/layers/common-layers/marker-layer/marker-list.js +1 -0
- package/dist/layers/common-layers/marker-layer/marker-mapping.d.ts +1 -0
- package/dist/layers/common-layers/marker-layer/marker-mapping.js +1 -0
- package/dist/layers/common-layers/spline-layer/spline-layer.d.ts +1 -0
- package/dist/layers/common-layers/spline-layer/spline-layer.js +1 -0
- package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.d.ts +1 -0
- package/dist/layers/common-layers/zoomable-text-layer/zoomable-text-layer.js +1 -0
- package/dist/layers/edge-attachment-helper.d.ts +4 -3
- package/dist/layers/edge-attachment-helper.d.ts.map +1 -1
- package/dist/layers/edge-attachment-helper.js +4 -4
- package/dist/layers/edge-attachment-helper.js.map +1 -1
- package/dist/layers/edge-layer.d.ts +1 -0
- package/dist/layers/edge-layer.js +4 -3
- package/dist/layers/edge-layers/arrow-2d-geometry.d.ts +1 -0
- package/dist/layers/edge-layers/arrow-2d-geometry.js +1 -0
- package/dist/layers/edge-layers/curved-edge-layer.d.ts +2 -1
- package/dist/layers/edge-layers/curved-edge-layer.js +2 -1
- package/dist/layers/edge-layers/edge-arrow-layer.d.ts +1 -0
- package/dist/layers/edge-layers/edge-arrow-layer.js +2 -1
- package/dist/layers/edge-layers/edge-label-layer.d.ts +2 -1
- package/dist/layers/edge-layers/edge-label-layer.js +2 -1
- package/dist/layers/edge-layers/flow-layer.d.ts +2 -1
- package/dist/layers/edge-layers/flow-layer.js +2 -1
- package/dist/layers/edge-layers/path-edge-layer.d.ts +1 -0
- package/dist/layers/edge-layers/path-edge-layer.js +1 -0
- package/dist/layers/edge-layers/straight-line-edge-layer.d.ts +1 -0
- package/dist/layers/edge-layers/straight-line-edge-layer.js +1 -0
- package/dist/layers/graph-layer.d.ts +75 -17
- package/dist/layers/graph-layer.d.ts.map +1 -1
- package/dist/layers/graph-layer.js +450 -64
- package/dist/layers/graph-layer.js.map +1 -1
- package/dist/layers/node-layers/circle-layer.d.ts +1 -0
- package/dist/layers/node-layers/circle-layer.js +1 -0
- package/dist/layers/node-layers/image-layer.d.ts +1 -0
- package/dist/layers/node-layers/image-layer.js +1 -0
- package/dist/layers/node-layers/label-layer.d.ts +2 -1
- package/dist/layers/node-layers/label-layer.js +2 -1
- package/dist/layers/node-layers/path-rounded-rectangle-layer.d.ts +1 -0
- package/dist/layers/node-layers/path-rounded-rectangle-layer.js +2 -1
- package/dist/layers/node-layers/rectangle-layer.d.ts +1 -0
- package/dist/layers/node-layers/rectangle-layer.js +1 -0
- package/dist/layers/node-layers/rounded-rectangle-layer-fragment.d.ts +1 -0
- package/dist/layers/node-layers/rounded-rectangle-layer-fragment.js +1 -0
- package/dist/layers/node-layers/rounded-rectangle-layer.d.ts +2 -1
- package/dist/layers/node-layers/rounded-rectangle-layer.js +3 -2
- package/dist/layers/node-layers/zoomable-marker-layer.d.ts +2 -1
- package/dist/layers/node-layers/zoomable-marker-layer.js +2 -1
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts +25 -0
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.d.ts.map +1 -0
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js +252 -0
- package/dist/layouts/d3-dag/collapsable-d3-dag-layout.js.map +1 -0
- package/dist/layouts/d3-dag/d3-dag-layout.d.ts +48 -62
- package/dist/layouts/d3-dag/d3-dag-layout.d.ts.map +1 -1
- package/dist/layouts/d3-dag/d3-dag-layout.js +89 -273
- package/dist/layouts/d3-dag/d3-dag-layout.js.map +1 -1
- package/dist/layouts/d3-force/d3-force-layout.d.ts +22 -9
- package/dist/layouts/d3-force/d3-force-layout.d.ts.map +1 -1
- package/dist/layouts/d3-force/d3-force-layout.js +42 -22
- package/dist/layouts/d3-force/d3-force-layout.js.map +1 -1
- package/dist/layouts/d3-force/worker.d.ts +1 -0
- package/dist/layouts/d3-force/worker.js +1 -0
- package/dist/layouts/experimental/force-multi-graph-layout.d.ts +21 -16
- package/dist/layouts/experimental/force-multi-graph-layout.d.ts.map +1 -1
- package/dist/layouts/experimental/force-multi-graph-layout.js +49 -39
- package/dist/layouts/experimental/force-multi-graph-layout.js.map +1 -1
- package/dist/layouts/experimental/hive-plot-layout.d.ts +20 -16
- package/dist/layouts/experimental/hive-plot-layout.d.ts.map +1 -1
- package/dist/layouts/experimental/hive-plot-layout.js +35 -35
- package/dist/layouts/experimental/hive-plot-layout.js.map +1 -1
- package/dist/layouts/experimental/radial-layout.d.ts +14 -8
- package/dist/layouts/experimental/radial-layout.d.ts.map +1 -1
- package/dist/layouts/experimental/radial-layout.js +33 -15
- package/dist/layouts/experimental/radial-layout.js.map +1 -1
- package/dist/layouts/gpu-force/gpu-force-layout.d.ts +13 -9
- package/dist/layouts/gpu-force/gpu-force-layout.d.ts.map +1 -1
- package/dist/layouts/gpu-force/gpu-force-layout.js +61 -57
- package/dist/layouts/gpu-force/gpu-force-layout.js.map +1 -1
- package/dist/layouts/gpu-force/worker.d.ts +1 -0
- package/dist/layouts/gpu-force/worker.js +1 -0
- package/dist/layouts/simple-layout.d.ts +10 -26
- package/dist/layouts/simple-layout.d.ts.map +1 -1
- package/dist/layouts/simple-layout.js +15 -18
- package/dist/layouts/simple-layout.js.map +1 -1
- package/dist/loaders/dot-graph-loader.d.ts +26 -0
- package/dist/loaders/dot-graph-loader.d.ts.map +1 -0
- package/dist/loaders/dot-graph-loader.js +669 -0
- package/dist/loaders/dot-graph-loader.js.map +1 -0
- package/dist/loaders/json-graph-loader.d.ts +7 -0
- package/dist/loaders/json-graph-loader.d.ts.map +1 -0
- package/dist/loaders/json-graph-loader.js +32 -0
- package/dist/loaders/json-graph-loader.js.map +1 -0
- package/dist/loaders/parsers/edge-parsers.d.ts +3 -0
- package/dist/loaders/parsers/edge-parsers.d.ts.map +1 -0
- package/dist/loaders/{edge-parsers.js → parsers/edge-parsers.js} +2 -1
- package/dist/loaders/parsers/edge-parsers.js.map +1 -0
- package/dist/loaders/parsers/node-parsers.d.ts +3 -0
- package/dist/loaders/parsers/node-parsers.d.ts.map +1 -0
- package/dist/loaders/{node-parsers.js → parsers/node-parsers.js} +2 -1
- package/dist/loaders/parsers/node-parsers.js.map +1 -0
- package/dist/loaders/parsers/parse-json-graph.d.ts +30 -0
- package/dist/loaders/parsers/parse-json-graph.d.ts.map +1 -0
- package/dist/loaders/parsers/parse-json-graph.js +79 -0
- package/dist/loaders/parsers/parse-json-graph.js.map +1 -0
- package/dist/style/graph-layer-stylesheet.d.ts +3 -2
- package/dist/style/graph-layer-stylesheet.js +1 -0
- package/dist/style/graph-style-accessor-map.d.ts +1 -0
- package/dist/style/graph-style-accessor-map.js +1 -0
- package/dist/style/graph-style-engine.d.ts +6 -3
- package/dist/style/graph-style-engine.d.ts.map +1 -1
- package/dist/style/graph-style-engine.js +7 -5
- package/dist/style/graph-style-engine.js.map +1 -1
- package/dist/style/graph-stylesheet.schema.d.ts +1 -0
- package/dist/style/graph-stylesheet.schema.js +1 -0
- package/dist/style/style-property.d.ts +1 -0
- package/dist/style/style-property.js +2 -1
- package/dist/style/{style-engine.d.ts → stylesheet-engine.d.ts} +5 -4
- package/dist/style/stylesheet-engine.d.ts.map +1 -0
- package/dist/style/{style-engine.js → stylesheet-engine.js} +4 -3
- package/dist/style/stylesheet-engine.js.map +1 -0
- package/dist/utils/collapsed-chains.d.ts +10 -9
- package/dist/utils/collapsed-chains.d.ts.map +1 -1
- package/dist/utils/collapsed-chains.js +2 -6
- package/dist/utils/collapsed-chains.js.map +1 -1
- package/dist/utils/layer-utils.d.ts +1 -0
- package/dist/utils/layer-utils.js +1 -0
- package/dist/utils/log.d.ts +1 -0
- package/dist/utils/log.js +1 -0
- package/dist/utils/node-boundary.d.ts +1 -0
- package/dist/utils/node-boundary.js +1 -0
- package/dist/utils/polygon-calculations.d.ts +1 -0
- package/dist/utils/polygon-calculations.js +1 -0
- package/dist/utils/rank-grid.d.ts +31 -0
- package/dist/utils/rank-grid.d.ts.map +1 -0
- package/dist/utils/rank-grid.js +307 -0
- package/dist/utils/rank-grid.js.map +1 -0
- package/package.json +7 -11
- package/src/_disabled/arrow-graph-data.ts.disabled +18 -0
- package/src/_disabled/columnar-graph-data-builder.ts.disabled +250 -0
- package/src/_disabled/graph-runtime-layout.ts.disabled +29 -0
- package/src/core/graph-engine.ts +201 -84
- package/src/core/graph-layout.ts +52 -29
- package/src/core/interaction-manager.ts +20 -20
- package/src/graph/arrow-graph.ts +648 -0
- package/src/graph/classic-graph.ts +447 -0
- package/src/graph/edge.ts +7 -7
- package/src/graph/functions/arrow-utils.ts +72 -0
- package/src/graph/functions/convert-arrow-graph-to-classic-graph.ts.disabled +47 -0
- package/src/graph/functions/convert-plain-graph-to-arrow-graph.ts.disabled +119 -0
- package/src/graph/functions/create-graph-from-data.ts +16 -0
- package/src/graph/functions/create-plain-graph-from-data.ts.disabled +176 -0
- package/src/graph/graph-normalization.ts +87 -0
- package/src/graph/graph.ts +68 -339
- package/src/graph/node.ts +9 -9
- package/src/graph/tabular-graph.ts.disabled +761 -0
- package/src/graph-data/arrow-graph-data-builder.ts +165 -0
- package/src/graph-data/graph-data-builder.ts +7 -0
- package/src/graph-data/graph-data.ts +57 -0
- package/src/graph-data/plain-graph-data-builder.ts +132 -0
- package/src/index.ts +53 -13
- package/src/layers/common-layers/flow-path-layer/flow-path-layer.ts +1 -2
- package/src/layers/common-layers/grid-layer/grid-layer.ts +237 -0
- package/src/layers/edge-attachment-helper.ts +22 -16
- package/src/layers/graph-layer.ts +642 -62
- package/src/layouts/d3-dag/collapsable-d3-dag-layout.ts +330 -0
- package/src/layouts/d3-dag/d3-dag-layout.ts +166 -396
- package/src/layouts/d3-force/d3-force-layout.ts +52 -30
- package/src/layouts/experimental/force-multi-graph-layout.ts +55 -49
- package/src/layouts/experimental/hive-plot-layout.ts +41 -42
- package/src/layouts/experimental/radial-layout.ts +39 -20
- package/src/layouts/gpu-force/gpu-force-layout.ts +72 -70
- package/src/layouts/simple-layout.ts +20 -44
- package/src/loaders/{create-graph.ts → deprecated/create-graph.ts.disabled} +6 -6
- package/src/loaders/deprecated/json-classic-graph-loader.ts.disabled +33 -0
- package/src/loaders/{simple-json-graph-loader.ts → deprecated/simple-json-graph-loader.ts.disabled} +3 -3
- package/src/loaders/{table-graph-loader.ts → deprecated/table-graph-loader.ts.disabled} +8 -8
- package/src/loaders/dot-graph-loader.ts +860 -0
- package/src/loaders/json-graph-loader.ts +48 -0
- package/src/loaders/parsers/create-graph-data.ts.disabled +45 -0
- package/src/loaders/{edge-parsers.ts → parsers/edge-parsers.ts} +2 -2
- package/src/loaders/{node-parsers.ts → parsers/node-parsers.ts} +2 -2
- package/src/loaders/parsers/parse-json-graph.ts +134 -0
- package/src/style/graph-style-engine.ts +5 -2
- package/src/style/{style-engine.ts → stylesheet-engine.ts} +3 -3
- package/src/utils/collapsed-chains.ts +11 -17
- package/src/utils/rank-grid.ts +426 -0
- package/dist/loaders/create-graph.d.ts +0 -12
- package/dist/loaders/create-graph.d.ts.map +0 -1
- package/dist/loaders/create-graph.js +0 -38
- package/dist/loaders/create-graph.js.map +0 -1
- package/dist/loaders/edge-parsers.d.ts +0 -2
- package/dist/loaders/edge-parsers.d.ts.map +0 -1
- package/dist/loaders/edge-parsers.js.map +0 -1
- package/dist/loaders/json-loader.d.ts +0 -7
- package/dist/loaders/json-loader.d.ts.map +0 -1
- package/dist/loaders/json-loader.js +0 -16
- package/dist/loaders/json-loader.js.map +0 -1
- package/dist/loaders/node-parsers.d.ts +0 -2
- package/dist/loaders/node-parsers.d.ts.map +0 -1
- package/dist/loaders/node-parsers.js.map +0 -1
- package/dist/loaders/simple-json-graph-loader.d.ts +0 -11
- package/dist/loaders/simple-json-graph-loader.d.ts.map +0 -1
- package/dist/loaders/simple-json-graph-loader.js +0 -20
- package/dist/loaders/simple-json-graph-loader.js.map +0 -1
- package/dist/loaders/table-graph-loader.d.ts +0 -16
- package/dist/loaders/table-graph-loader.d.ts.map +0 -1
- package/dist/loaders/table-graph-loader.js +0 -91
- package/dist/loaders/table-graph-loader.js.map +0 -1
- package/dist/style/style-engine.d.ts.map +0 -1
- package/dist/style/style-engine.js.map +0 -1
- package/dist/widgets/long-press-button.d.ts +0 -12
- package/dist/widgets/long-press-button.d.ts.map +0 -1
- package/dist/widgets/long-press-button.js +0 -31
- package/dist/widgets/long-press-button.js.map +0 -1
- package/dist/widgets/view-control-widget.d.ts +0 -77
- package/dist/widgets/view-control-widget.d.ts.map +0 -1
- package/dist/widgets/view-control-widget.js +0 -197
- package/dist/widgets/view-control-widget.js.map +0 -1
- package/src/loaders/json-loader.ts +0 -19
- package/src/widgets/long-press-button.tsx +0 -50
- package/src/widgets/view-control-widget.tsx +0 -339
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
// deck.gl-community
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
import { ArrowGraphDataBuilder } from "../graph-data/arrow-graph-data-builder.js";
|
|
5
|
+
// __VERSION__ is injected by babel-plugin-version-inline
|
|
6
|
+
// @ts-ignore TS2304: Cannot find name '__VERSION__'.
|
|
7
|
+
const VERSION = typeof "9.2.0-beta.4" !== 'undefined' ? "9.2.0-beta.4" : 'latest';
|
|
8
|
+
export const DOTGraphLoader = {
|
|
9
|
+
dataType: null,
|
|
10
|
+
batchType: null,
|
|
11
|
+
name: 'DOT Graph',
|
|
12
|
+
id: 'dot-graph',
|
|
13
|
+
module: 'graph-layers',
|
|
14
|
+
version: VERSION,
|
|
15
|
+
worker: false,
|
|
16
|
+
extensions: ['dot'],
|
|
17
|
+
mimeTypes: ['text/vnd.graphviz', 'text/x-graphviz', 'application/vnd.graphviz'],
|
|
18
|
+
text: true,
|
|
19
|
+
options: {
|
|
20
|
+
dot: {
|
|
21
|
+
version: 0
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
parse: (arrayBuffer, options) => {
|
|
25
|
+
const text = new TextDecoder().decode(arrayBuffer);
|
|
26
|
+
return Promise.resolve(DOTGraphLoader.parseTextSync(text, options));
|
|
27
|
+
},
|
|
28
|
+
parseTextSync: (text, options) => {
|
|
29
|
+
const parseOptions = { ...DOTGraphLoader.options.dot, ...options?.dot };
|
|
30
|
+
return loadDOTGraph(text, parseOptions);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
export function loadDOTGraph(dot, options = {}) {
|
|
34
|
+
const parsed = parseDOT(dot);
|
|
35
|
+
return buildArrowGraphData(parsed, options);
|
|
36
|
+
}
|
|
37
|
+
export function parseDOTToArrowGraphData(dot, options = {}) {
|
|
38
|
+
const parsed = parseDOT(dot);
|
|
39
|
+
return buildArrowGraphData(parsed, options);
|
|
40
|
+
}
|
|
41
|
+
function buildArrowGraphData(parsed, options) {
|
|
42
|
+
const builder = new ArrowGraphDataBuilder({ version: options.version });
|
|
43
|
+
const subgraphDescriptors = new Map();
|
|
44
|
+
for (const [id, subgraph] of parsed.subgraphs.entries()) {
|
|
45
|
+
subgraphDescriptors.set(id, {
|
|
46
|
+
id,
|
|
47
|
+
attributes: { ...subgraph.attributes },
|
|
48
|
+
parentId: subgraph.parentId
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const node of parsed.nodes.values()) {
|
|
52
|
+
const attributes = { ...node.attributes };
|
|
53
|
+
if (node.subgraphs.size > 0) {
|
|
54
|
+
attributes.subgraphs = Array.from(node.subgraphs, (id) => describeSubgraph(id, subgraphDescriptors));
|
|
55
|
+
}
|
|
56
|
+
builder.addNode({
|
|
57
|
+
id: node.id,
|
|
58
|
+
attributes
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
parsed.edges.forEach((edge) => {
|
|
62
|
+
const attributes = { ...edge.attributes };
|
|
63
|
+
if (edge.subgraphs.length > 0) {
|
|
64
|
+
attributes.subgraphs = edge.subgraphs.map((id) => describeSubgraph(id, subgraphDescriptors));
|
|
65
|
+
}
|
|
66
|
+
builder.addEdge({
|
|
67
|
+
id: edge.id,
|
|
68
|
+
sourceId: edge.sourceId,
|
|
69
|
+
targetId: edge.targetId,
|
|
70
|
+
directed: edge.directed,
|
|
71
|
+
attributes
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
const metadata = {
|
|
75
|
+
id: parsed.id,
|
|
76
|
+
directed: parsed.directed,
|
|
77
|
+
strict: parsed.strict,
|
|
78
|
+
attributes: { ...parsed.graphAttributes },
|
|
79
|
+
subgraphs: Array.from(parsed.subgraphs.values(), (subgraph) => ({
|
|
80
|
+
id: subgraph.id,
|
|
81
|
+
attributes: { ...subgraph.attributes },
|
|
82
|
+
parentId: subgraph.parentId
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
const data = builder.finish();
|
|
86
|
+
data.metadata = metadata;
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
function describeSubgraph(id, descriptors) {
|
|
90
|
+
const subgraph = descriptors.get(id);
|
|
91
|
+
if (!subgraph) {
|
|
92
|
+
return { id, attributes: {} };
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
id,
|
|
96
|
+
attributes: { ...subgraph.attributes },
|
|
97
|
+
parentId: subgraph.parentId
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
class DOTParser {
|
|
101
|
+
tokens;
|
|
102
|
+
position = 0;
|
|
103
|
+
result = {
|
|
104
|
+
directed: false,
|
|
105
|
+
strict: false,
|
|
106
|
+
graphAttributes: {},
|
|
107
|
+
nodes: new Map(),
|
|
108
|
+
edges: [],
|
|
109
|
+
subgraphs: new Map()
|
|
110
|
+
};
|
|
111
|
+
scopes = [
|
|
112
|
+
{ nodeDefaults: {}, edgeDefaults: {}, graphAttributes: {} }
|
|
113
|
+
];
|
|
114
|
+
subgraphCounter = 0;
|
|
115
|
+
edgeCounter = 0;
|
|
116
|
+
constructor(tokens) {
|
|
117
|
+
this.tokens = tokens;
|
|
118
|
+
}
|
|
119
|
+
parse() {
|
|
120
|
+
this.parseGraph();
|
|
121
|
+
return this.result;
|
|
122
|
+
}
|
|
123
|
+
parseGraph() {
|
|
124
|
+
const strictToken = this.peek();
|
|
125
|
+
if (strictToken && isKeyword(strictToken, 'strict')) {
|
|
126
|
+
this.consume();
|
|
127
|
+
this.result.strict = true;
|
|
128
|
+
}
|
|
129
|
+
const typeToken = this.peek();
|
|
130
|
+
if (!typeToken || !isGraphType(typeToken)) {
|
|
131
|
+
throw new Error('DOT graph must start with graph or digraph keyword.');
|
|
132
|
+
}
|
|
133
|
+
this.consume();
|
|
134
|
+
this.result.directed = isKeyword(typeToken, 'digraph');
|
|
135
|
+
const idToken = this.peek();
|
|
136
|
+
if (idToken && isIdentifierLike(idToken)) {
|
|
137
|
+
if (!isStructuralToken(idToken)) {
|
|
138
|
+
this.result.id = parseIdentifierValue(this.consume());
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
this.expect('lbrace');
|
|
142
|
+
while (!this.match('rbrace')) {
|
|
143
|
+
if (!this.parseStatement()) {
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
this.result.graphAttributes = { ...this.scopes[0].graphAttributes };
|
|
148
|
+
}
|
|
149
|
+
parseStatement() {
|
|
150
|
+
if (this.consumeSemicolonIfPresent()) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
const token = this.peek();
|
|
154
|
+
if (!token) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (this.tryParseSubgraphStatement(token)) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (this.tryParseKeywordStatement(token)) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (this.tryParseAssignmentStatement(token)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
if (isIdentifierLike(token)) {
|
|
167
|
+
this.parseNodeOrEdgeStatement();
|
|
168
|
+
this.consumeOptionalSemicolon();
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
throw new Error(`Unexpected token: ${token.value}`);
|
|
172
|
+
}
|
|
173
|
+
consumeSemicolonIfPresent() {
|
|
174
|
+
const next = this.peek();
|
|
175
|
+
if (next?.type === 'semicolon') {
|
|
176
|
+
this.consume();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
tryParseSubgraphStatement(token) {
|
|
182
|
+
if (token.type !== 'lbrace' && !isKeyword(token, 'subgraph')) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
this.parseSubgraph();
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
tryParseKeywordStatement(token) {
|
|
189
|
+
if (!(isKeyword(token, 'graph') || isKeyword(token, 'node') || isKeyword(token, 'edge'))) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
this.consume();
|
|
193
|
+
const attrs = this.parseAttributeList();
|
|
194
|
+
if (isKeyword(token, 'graph')) {
|
|
195
|
+
Object.assign(this.currentScope().graphAttributes, attrs);
|
|
196
|
+
}
|
|
197
|
+
else if (isKeyword(token, 'node')) {
|
|
198
|
+
Object.assign(this.currentScope().nodeDefaults, attrs);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
Object.assign(this.currentScope().edgeDefaults, attrs);
|
|
202
|
+
}
|
|
203
|
+
this.consumeOptionalSemicolon();
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
tryParseAssignmentStatement(token) {
|
|
207
|
+
if (!isIdentifierLike(token)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
const next = this.peek(1);
|
|
211
|
+
if (next?.type !== 'equals') {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
const key = parseIdentifierValue(this.consume());
|
|
215
|
+
this.consume();
|
|
216
|
+
const valueToken = this.consume();
|
|
217
|
+
const value = parseAttributeValue(valueToken);
|
|
218
|
+
this.currentScope().graphAttributes[key] = value;
|
|
219
|
+
this.consumeOptionalSemicolon();
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
parseNodeOrEdgeStatement() {
|
|
223
|
+
const first = parseIdentifierValue(this.consume());
|
|
224
|
+
const references = [first];
|
|
225
|
+
const operators = [];
|
|
226
|
+
let operatorToken = this.match('arrow');
|
|
227
|
+
while (operatorToken) {
|
|
228
|
+
operators.push(operatorToken.value);
|
|
229
|
+
const referenceToken = this.consume();
|
|
230
|
+
if (!isIdentifierLike(referenceToken)) {
|
|
231
|
+
throw new Error('Expected node identifier in edge statement.');
|
|
232
|
+
}
|
|
233
|
+
references.push(parseIdentifierValue(referenceToken));
|
|
234
|
+
operatorToken = this.match('arrow');
|
|
235
|
+
}
|
|
236
|
+
if (operators.length === 0) {
|
|
237
|
+
const attrs = this.parseAttributeList();
|
|
238
|
+
this.addNode(first, attrs);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const attrs = this.parseAttributeList();
|
|
242
|
+
this.addEdgeChain(references, operators, attrs);
|
|
243
|
+
}
|
|
244
|
+
addNode(id, attrs) {
|
|
245
|
+
const membership = this.getCurrentSubgraphChain();
|
|
246
|
+
const node = this.ensureNode(id, membership);
|
|
247
|
+
node.attributes = { ...node.attributes, ...attrs };
|
|
248
|
+
}
|
|
249
|
+
addEdgeChain(nodes, operators, attrs) {
|
|
250
|
+
const membership = this.getCurrentSubgraphChain();
|
|
251
|
+
const defaults = this.currentScope().edgeDefaults;
|
|
252
|
+
const attributes = { ...defaults, ...attrs };
|
|
253
|
+
for (let index = 0; index < nodes.length - 1; index++) {
|
|
254
|
+
const sourceId = nodes[index];
|
|
255
|
+
const targetId = nodes[index + 1];
|
|
256
|
+
const operator = operators[index];
|
|
257
|
+
const directed = operator === '->';
|
|
258
|
+
const edgeId = deriveEdgeId(attributes, sourceId, targetId, ++this.edgeCounter);
|
|
259
|
+
const edgeAttributes = { ...attributes };
|
|
260
|
+
this.ensureNode(sourceId, membership);
|
|
261
|
+
this.ensureNode(targetId, membership);
|
|
262
|
+
const directedOverride = deriveDirectedFlag(edgeAttributes, directed);
|
|
263
|
+
this.result.edges.push({
|
|
264
|
+
id: edgeId,
|
|
265
|
+
sourceId,
|
|
266
|
+
targetId,
|
|
267
|
+
directed: directedOverride,
|
|
268
|
+
attributes: edgeAttributes,
|
|
269
|
+
subgraphs: membership
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
parseSubgraph() {
|
|
274
|
+
let idToken = this.peek();
|
|
275
|
+
let subgraphId;
|
|
276
|
+
if (idToken && isKeyword(idToken, 'subgraph')) {
|
|
277
|
+
this.consume();
|
|
278
|
+
idToken = this.peek();
|
|
279
|
+
}
|
|
280
|
+
if (idToken && isIdentifierLike(idToken) && idToken.type !== 'lbrace') {
|
|
281
|
+
subgraphId = parseIdentifierValue(this.consume());
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
subgraphId = `subgraph_${++this.subgraphCounter}`;
|
|
285
|
+
}
|
|
286
|
+
this.expect('lbrace');
|
|
287
|
+
const parentId = this.findCurrentSubgraphId();
|
|
288
|
+
const context = {
|
|
289
|
+
id: subgraphId,
|
|
290
|
+
nodeDefaults: { ...this.currentScope().nodeDefaults },
|
|
291
|
+
edgeDefaults: { ...this.currentScope().edgeDefaults },
|
|
292
|
+
graphAttributes: {}
|
|
293
|
+
};
|
|
294
|
+
this.scopes.push(context);
|
|
295
|
+
this.result.subgraphs.set(subgraphId, { id: subgraphId, attributes: context.graphAttributes, parentId });
|
|
296
|
+
let shouldContinue = true;
|
|
297
|
+
while (shouldContinue) {
|
|
298
|
+
if (this.match('rbrace')) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
shouldContinue = this.parseStatement();
|
|
302
|
+
}
|
|
303
|
+
this.scopes.pop();
|
|
304
|
+
}
|
|
305
|
+
parseAttributeList() {
|
|
306
|
+
const attributes = {};
|
|
307
|
+
while (this.match('lbrack')) {
|
|
308
|
+
while (!this.match('rbrack')) {
|
|
309
|
+
const keyToken = this.consume();
|
|
310
|
+
if (!isIdentifierLike(keyToken)) {
|
|
311
|
+
throw new Error('Expected attribute name.');
|
|
312
|
+
}
|
|
313
|
+
const key = parseIdentifierValue(keyToken);
|
|
314
|
+
let value = true;
|
|
315
|
+
if (this.match('equals')) {
|
|
316
|
+
const valueToken = this.consume();
|
|
317
|
+
value = parseAttributeValue(valueToken);
|
|
318
|
+
}
|
|
319
|
+
attributes[key] = value;
|
|
320
|
+
if (this.peek()?.type === 'comma' || this.peek()?.type === 'semicolon') {
|
|
321
|
+
this.consume();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return attributes;
|
|
326
|
+
}
|
|
327
|
+
ensureNode(id, membership) {
|
|
328
|
+
let node = this.result.nodes.get(id);
|
|
329
|
+
if (!node) {
|
|
330
|
+
const defaults = this.currentScope().nodeDefaults;
|
|
331
|
+
node = { id, attributes: { ...defaults }, subgraphs: new Set() };
|
|
332
|
+
this.result.nodes.set(id, node);
|
|
333
|
+
}
|
|
334
|
+
if (node) {
|
|
335
|
+
membership.forEach((subgraphId) => node.subgraphs.add(subgraphId));
|
|
336
|
+
}
|
|
337
|
+
return node;
|
|
338
|
+
}
|
|
339
|
+
getCurrentSubgraphChain() {
|
|
340
|
+
const chain = [];
|
|
341
|
+
for (const scope of this.scopes) {
|
|
342
|
+
if (scope.id) {
|
|
343
|
+
chain.push(scope.id);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return chain;
|
|
347
|
+
}
|
|
348
|
+
findCurrentSubgraphId() {
|
|
349
|
+
for (let index = this.scopes.length - 1; index >= 0; index--) {
|
|
350
|
+
const scope = this.scopes[index];
|
|
351
|
+
if (scope.id) {
|
|
352
|
+
return scope.id;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
currentScope() {
|
|
358
|
+
return this.scopes[this.scopes.length - 1];
|
|
359
|
+
}
|
|
360
|
+
consumeOptionalSemicolon() {
|
|
361
|
+
const next = this.peek();
|
|
362
|
+
if (next?.type === 'semicolon') {
|
|
363
|
+
this.consume();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
expect(type) {
|
|
367
|
+
const token = this.consume();
|
|
368
|
+
if (!token || token.type !== type) {
|
|
369
|
+
throw new Error(`Expected token ${type}.`);
|
|
370
|
+
}
|
|
371
|
+
return token;
|
|
372
|
+
}
|
|
373
|
+
consume() {
|
|
374
|
+
const token = this.tokens[this.position];
|
|
375
|
+
if (!token) {
|
|
376
|
+
throw new Error('Unexpected end of DOT input.');
|
|
377
|
+
}
|
|
378
|
+
this.position++;
|
|
379
|
+
return token;
|
|
380
|
+
}
|
|
381
|
+
match(type) {
|
|
382
|
+
const token = this.peek();
|
|
383
|
+
if (token && token.type === type) {
|
|
384
|
+
this.position++;
|
|
385
|
+
return token;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
peek(offset = 0) {
|
|
390
|
+
return this.tokens[this.position + offset] ?? null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function parseDOT(input) {
|
|
394
|
+
const parser = new DOTParser(tokenize(input));
|
|
395
|
+
return parser.parse();
|
|
396
|
+
}
|
|
397
|
+
const IDENTIFIER_TERMINATORS = new Set(['{', '}', '[', ']', '=', ';', ',', '"', '<', '#']);
|
|
398
|
+
function tokenize(input) {
|
|
399
|
+
const tokens = [];
|
|
400
|
+
let index = 0;
|
|
401
|
+
while (index < input.length) {
|
|
402
|
+
const { token, nextIndex } = readNextToken(input, index);
|
|
403
|
+
if (nextIndex <= index) {
|
|
404
|
+
throw new Error(`Tokenizer did not advance at position ${index}.`);
|
|
405
|
+
}
|
|
406
|
+
if (token) {
|
|
407
|
+
tokens.push(token);
|
|
408
|
+
}
|
|
409
|
+
index = nextIndex;
|
|
410
|
+
}
|
|
411
|
+
return tokens;
|
|
412
|
+
}
|
|
413
|
+
function readNextToken(input, index) {
|
|
414
|
+
if (index >= input.length) {
|
|
415
|
+
return { token: null, nextIndex: input.length };
|
|
416
|
+
}
|
|
417
|
+
const char = input[index];
|
|
418
|
+
if (isWhitespace(char)) {
|
|
419
|
+
return { token: null, nextIndex: index + 1 };
|
|
420
|
+
}
|
|
421
|
+
const commentEnd = skipComment(input, index);
|
|
422
|
+
if (commentEnd !== null) {
|
|
423
|
+
return { token: null, nextIndex: commentEnd };
|
|
424
|
+
}
|
|
425
|
+
const arrowToken = readArrowToken(input, index);
|
|
426
|
+
if (arrowToken) {
|
|
427
|
+
return arrowToken;
|
|
428
|
+
}
|
|
429
|
+
const punctuation = readPunctuationToken(char);
|
|
430
|
+
if (punctuation) {
|
|
431
|
+
return { token: punctuation, nextIndex: index + 1 };
|
|
432
|
+
}
|
|
433
|
+
if (char === '"') {
|
|
434
|
+
const { value, nextIndex } = readQuotedString(input, index + 1);
|
|
435
|
+
return { token: { type: 'string', value }, nextIndex };
|
|
436
|
+
}
|
|
437
|
+
if (char === '<') {
|
|
438
|
+
const { value, nextIndex } = readHtmlString(input, index + 1);
|
|
439
|
+
return { token: { type: 'html', value }, nextIndex };
|
|
440
|
+
}
|
|
441
|
+
const identifier = readIdentifier(input, index);
|
|
442
|
+
if (identifier.value) {
|
|
443
|
+
return {
|
|
444
|
+
token: { type: 'identifier', value: identifier.value },
|
|
445
|
+
nextIndex: identifier.nextIndex
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
throw new Error(`Unexpected token at position ${index}.`);
|
|
449
|
+
}
|
|
450
|
+
function skipComment(input, index) {
|
|
451
|
+
const char = input[index];
|
|
452
|
+
if (char === '/') {
|
|
453
|
+
const next = input[index + 1];
|
|
454
|
+
if (next === '/') {
|
|
455
|
+
return skipLineComment(input, index + 2);
|
|
456
|
+
}
|
|
457
|
+
if (next === '*') {
|
|
458
|
+
return skipBlockComment(input, index + 2);
|
|
459
|
+
}
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
if (char === '#') {
|
|
463
|
+
return skipLineComment(input, index + 1);
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
function skipLineComment(input, startIndex) {
|
|
468
|
+
let cursor = startIndex;
|
|
469
|
+
while (cursor < input.length && !isLineBreak(input[cursor])) {
|
|
470
|
+
cursor++;
|
|
471
|
+
}
|
|
472
|
+
return cursor;
|
|
473
|
+
}
|
|
474
|
+
function skipBlockComment(input, startIndex) {
|
|
475
|
+
let cursor = startIndex;
|
|
476
|
+
while (cursor < input.length) {
|
|
477
|
+
if (input[cursor] === '*' && input[cursor + 1] === '/') {
|
|
478
|
+
return cursor + 2;
|
|
479
|
+
}
|
|
480
|
+
cursor++;
|
|
481
|
+
}
|
|
482
|
+
throw new Error('Unterminated block comment in DOT source.');
|
|
483
|
+
}
|
|
484
|
+
function readArrowToken(input, index) {
|
|
485
|
+
const next = input[index + 1];
|
|
486
|
+
if (input[index] === '-' && next === '-') {
|
|
487
|
+
return { token: { type: 'arrow', value: '--' }, nextIndex: index + 2 };
|
|
488
|
+
}
|
|
489
|
+
if (input[index] === '-' && next === '>') {
|
|
490
|
+
return { token: { type: 'arrow', value: '->' }, nextIndex: index + 2 };
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
function readPunctuationToken(char) {
|
|
495
|
+
switch (char) {
|
|
496
|
+
case '{':
|
|
497
|
+
return { type: 'lbrace', value: char };
|
|
498
|
+
case '}':
|
|
499
|
+
return { type: 'rbrace', value: char };
|
|
500
|
+
case '[':
|
|
501
|
+
return { type: 'lbrack', value: char };
|
|
502
|
+
case ']':
|
|
503
|
+
return { type: 'rbrack', value: char };
|
|
504
|
+
case '=':
|
|
505
|
+
return { type: 'equals', value: char };
|
|
506
|
+
case ',':
|
|
507
|
+
return { type: 'comma', value: char };
|
|
508
|
+
case ';':
|
|
509
|
+
return { type: 'semicolon', value: char };
|
|
510
|
+
default:
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
function readQuotedString(input, startIndex) {
|
|
515
|
+
let value = '';
|
|
516
|
+
let index = startIndex;
|
|
517
|
+
while (index < input.length) {
|
|
518
|
+
const char = input[index];
|
|
519
|
+
if (char === '"') {
|
|
520
|
+
return { value, nextIndex: index + 1 };
|
|
521
|
+
}
|
|
522
|
+
if (char === '\\') {
|
|
523
|
+
const escape = readEscapedCharacter(input, index + 1);
|
|
524
|
+
value += escape.value;
|
|
525
|
+
index = escape.nextIndex;
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
value += char;
|
|
529
|
+
index++;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
throw new Error('Unterminated string literal in DOT source.');
|
|
533
|
+
}
|
|
534
|
+
function readEscapedCharacter(input, startIndex) {
|
|
535
|
+
const next = input[startIndex];
|
|
536
|
+
switch (next) {
|
|
537
|
+
case 'n':
|
|
538
|
+
case 'l':
|
|
539
|
+
case 'L':
|
|
540
|
+
return { value: '\n', nextIndex: startIndex + 1 };
|
|
541
|
+
case 't':
|
|
542
|
+
return { value: '\t', nextIndex: startIndex + 1 };
|
|
543
|
+
case 'r':
|
|
544
|
+
return { value: '\r', nextIndex: startIndex + 1 };
|
|
545
|
+
case '"':
|
|
546
|
+
return { value: '"', nextIndex: startIndex + 1 };
|
|
547
|
+
case '\\':
|
|
548
|
+
return { value: '\\', nextIndex: startIndex + 1 };
|
|
549
|
+
default: {
|
|
550
|
+
if (typeof next === 'undefined') {
|
|
551
|
+
throw new Error('Unterminated escape sequence in DOT source.');
|
|
552
|
+
}
|
|
553
|
+
return { value: next, nextIndex: startIndex + 1 };
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function readHtmlString(input, startIndex) {
|
|
558
|
+
let value = '<';
|
|
559
|
+
let depth = 1;
|
|
560
|
+
let index = startIndex;
|
|
561
|
+
while (index < input.length) {
|
|
562
|
+
const char = input[index];
|
|
563
|
+
value += char;
|
|
564
|
+
if (char === '<') {
|
|
565
|
+
depth++;
|
|
566
|
+
}
|
|
567
|
+
else if (char === '>') {
|
|
568
|
+
depth--;
|
|
569
|
+
if (depth === 0) {
|
|
570
|
+
return { value, nextIndex: index + 1 };
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
index++;
|
|
574
|
+
}
|
|
575
|
+
throw new Error('Unterminated HTML-like string literal in DOT source.');
|
|
576
|
+
}
|
|
577
|
+
function readIdentifier(input, startIndex) {
|
|
578
|
+
let index = startIndex;
|
|
579
|
+
let value = '';
|
|
580
|
+
while (index < input.length && !isIdentifierTerminator(input, index)) {
|
|
581
|
+
value += input[index];
|
|
582
|
+
index++;
|
|
583
|
+
}
|
|
584
|
+
return { value, nextIndex: index };
|
|
585
|
+
}
|
|
586
|
+
function isIdentifierTerminator(input, index) {
|
|
587
|
+
const char = input[index];
|
|
588
|
+
if (isWhitespace(char) || IDENTIFIER_TERMINATORS.has(char)) {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
if (isArrowOperatorStart(input, index)) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
if (isCommentStart(input, index)) {
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
function isArrowOperatorStart(input, index) {
|
|
600
|
+
if (input[index] !== '-') {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
const next = input[index + 1];
|
|
604
|
+
return next === '-' || next === '>';
|
|
605
|
+
}
|
|
606
|
+
function isCommentStart(input, index) {
|
|
607
|
+
if (input[index] !== '/') {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
const next = input[index + 1];
|
|
611
|
+
return next === '/' || next === '*';
|
|
612
|
+
}
|
|
613
|
+
function isWhitespace(char) {
|
|
614
|
+
return char === ' ' || char === '\n' || char === '\r' || char === '\t' || char === '\f';
|
|
615
|
+
}
|
|
616
|
+
function isLineBreak(char) {
|
|
617
|
+
return char === '\n' || char === '\r';
|
|
618
|
+
}
|
|
619
|
+
function isKeyword(token, keyword) {
|
|
620
|
+
return token.type === 'identifier' && token.value.toLowerCase() === keyword.toLowerCase();
|
|
621
|
+
}
|
|
622
|
+
function isGraphType(token) {
|
|
623
|
+
return isKeyword(token, 'graph') || isKeyword(token, 'digraph');
|
|
624
|
+
}
|
|
625
|
+
function isIdentifierLike(token) {
|
|
626
|
+
return token.type === 'identifier' || token.type === 'string' || token.type === 'html';
|
|
627
|
+
}
|
|
628
|
+
function isStructuralToken(token) {
|
|
629
|
+
return token.type === 'lbrace' || token.type === 'rbrace' || token.type === 'lbrack' || token.type === 'rbrack';
|
|
630
|
+
}
|
|
631
|
+
function parseIdentifierValue(token) {
|
|
632
|
+
return token.value;
|
|
633
|
+
}
|
|
634
|
+
function parseAttributeValue(token) {
|
|
635
|
+
if (token.type === 'string' || token.type === 'html') {
|
|
636
|
+
return token.value;
|
|
637
|
+
}
|
|
638
|
+
if (token.type === 'identifier') {
|
|
639
|
+
const numeric = Number(token.value);
|
|
640
|
+
if (!Number.isNaN(numeric)) {
|
|
641
|
+
return numeric;
|
|
642
|
+
}
|
|
643
|
+
return token.value;
|
|
644
|
+
}
|
|
645
|
+
throw new Error('Invalid attribute value in DOT input.');
|
|
646
|
+
}
|
|
647
|
+
function deriveEdgeId(attributes, sourceId, targetId, counter) {
|
|
648
|
+
const candidate = attributes.id ?? attributes.Id ?? attributes.ID;
|
|
649
|
+
if (typeof candidate === 'string' || typeof candidate === 'number') {
|
|
650
|
+
return String(candidate);
|
|
651
|
+
}
|
|
652
|
+
return `${String(sourceId)}-${String(targetId)}-${counter}`;
|
|
653
|
+
}
|
|
654
|
+
function deriveDirectedFlag(attributes, defaultDirected) {
|
|
655
|
+
const candidate = attributes.directed;
|
|
656
|
+
if (typeof candidate === 'boolean') {
|
|
657
|
+
return candidate;
|
|
658
|
+
}
|
|
659
|
+
const dirAttr = attributes.dir;
|
|
660
|
+
if (typeof dirAttr === 'string') {
|
|
661
|
+
const normalized = dirAttr.toLowerCase();
|
|
662
|
+
if (normalized === 'none') {
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
return defaultDirected;
|
|
668
|
+
}
|
|
669
|
+
//# sourceMappingURL=dot-graph-loader.js.map
|