From fd76e0e27095997c2ac21902c0629cd6600e30d9 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Thu, 17 Nov 2022 23:54:25 +0000 Subject: [PATCH] chore: replace dagre/dagre-d3 with dagre-d3-es Replace the dagre and dagre-d3 libraries with dagre-d3-es. Both dagre and dagre-d3 are deprecated and unmaintained, and haven't been updated for more than 3 years. Since dagre-d3 still requires an old version of d3, this causes a bunch of security warnings, e.g. https://github.com/advisories/GHSA-36jr-mh4h-2g58 The [dagre-d3-es](https://github.com/tbo47/dagre-es) package is a fork that contains support for `"d3": "^7.6.1"`. Also, it's ESM, so we will hopefully get smaller bundle sizes too. The only issue is that this fork isn't very well used (only has 3000 weekly downloads), compared to `dagre-d3`'s 250,000 weekly downloads. (although to be fair, a large proportion of dagre-d3's downloads probably come from mermaid) Since it's is a less popular package, **I've pinned `dagre-d3-es` to `"7.0.2"` instead of `"^7.0.2"`**. This does mean if there is a bug in `dagre-d3-es`, we will have to manually bump it ourselves, but it also means we won't accidentally be sending a buggy version of `dagre-d3-es` out to users in cases something changes (it might be worth disabling renovate for this if we're feeling paranoid!) --- package.json | 3 -- packages/mermaid/package.json | 6 +--- packages/mermaid/src/dagre-wrapper/index.js | 4 +-- .../dagre-wrapper/mermaid-graphlib.spec.js | 1 - .../src/diagrams/class/classRenderer.js | 4 +-- .../mermaid/src/diagrams/er/erRenderer.js | 4 +-- .../src/diagrams/flowchart/flowChartShapes.js | 25 ++++++------- .../src/diagrams/flowchart/flowRenderer-v2.js | 2 +- .../src/diagrams/flowchart/flowRenderer.js | 8 ++--- .../requirement/requirementRenderer.js | 4 +-- .../src/diagrams/state/stateRenderer.js | 4 +-- packages/mermaid/src/tests/setup.ts | 2 +- pnpm-lock.yaml | 35 +++++++------------ 13 files changed, 42 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 7bd648877..70fac0ea9 100644 --- a/package.json +++ b/package.json @@ -105,9 +105,6 @@ "vitepress-plugin-search": "^1.0.4-alpha.15", "vitest": "^0.25.1" }, - "resolutions": { - "d3": "^7.6.1" - }, "sideEffects": [ "**/*.css", "**/*.scss" diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index 842e9ba9a..f79ffe6f3 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -54,8 +54,7 @@ "dependencies": { "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", - "dagre": "^0.8.5", - "dagre-d3": "^0.6.4", + "dagre-d3-es": "7.0.2", "dompurify": "2.4.1", "fast-clone": "^1.5.13", "graphlib": "^2.1.8", @@ -98,9 +97,6 @@ "typescript": "^4.8.4", "unist-util-flatmap": "^1.0.0" }, - "resolutions": { - "d3": "^7.0.0" - }, "files": [ "dist", "README.md" diff --git a/packages/mermaid/src/dagre-wrapper/index.js b/packages/mermaid/src/dagre-wrapper/index.js index 72652ff8c..43fe311b3 100644 --- a/packages/mermaid/src/dagre-wrapper/index.js +++ b/packages/mermaid/src/dagre-wrapper/index.js @@ -1,4 +1,4 @@ -import dagre from 'dagre'; +import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import graphlib from 'graphlib'; import insertMarkers from './markers'; import { updateNodeBounds } from './shapes/util'; @@ -95,7 +95,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => { log.info('### Layout ###'); log.info('#############################################'); log.info(graph); - dagre.layout(graph); + dagreLayout(graph); log.info('Graph after layout:', graphlib.json.write(graph)); // Move the nodes to the correct place let diff = 0; diff --git a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js index 8155bbf70..a09e17f02 100644 --- a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js +++ b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js @@ -1,5 +1,4 @@ import graphlib from 'graphlib'; -import dagre from 'dagre'; import { validate, adjustClustersAndEdges, diff --git a/packages/mermaid/src/diagrams/class/classRenderer.js b/packages/mermaid/src/diagrams/class/classRenderer.js index 23b586192..357647427 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer.js +++ b/packages/mermaid/src/diagrams/class/classRenderer.js @@ -1,5 +1,5 @@ import { select } from 'd3'; -import dagre from 'dagre'; +import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import graphlib from 'graphlib'; import { log } from '../../logger'; import svgDraw from './svgDraw'; @@ -238,7 +238,7 @@ export const draw = function (text, id, _version, diagObj) { } }); - dagre.layout(g); + dagreLayout(g); g.nodes().forEach(function (v) { if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') { log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v))); diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js index 323bb4607..57aa737ab 100644 --- a/packages/mermaid/src/diagrams/er/erRenderer.js +++ b/packages/mermaid/src/diagrams/er/erRenderer.js @@ -1,6 +1,6 @@ import graphlib from 'graphlib'; import { line, curveBasis, select } from 'd3'; -import dagre from 'dagre'; +import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import { getConfig } from '../../config'; import { log } from '../../logger'; import erMarkers from './erMarkers'; @@ -637,7 +637,7 @@ export const draw = function (text, id, _version, diagObj) { // Add all the relationships to the graph const relationships = addRelationships(diagObj.db.getRelationships(), g); - dagre.layout(g); // Node and edge positions will be updated + dagreLayout(g); // Node and edge positions will be updated // Adjust the positions of the entities so that they adhere to the layout adjustEntities(svg, g); diff --git a/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js b/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js index b66bfe730..d02d484c4 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js +++ b/packages/mermaid/src/diagrams/flowchart/flowChartShapes.js @@ -1,4 +1,5 @@ -import dagreD3 from 'dagre-d3'; +import { intersectPolygon } from 'dagre-d3-es/src/dagre-js/intersect/intersect-polygon.js'; +import { intersectRect } from 'dagre-d3-es/src/dagre-js/intersect/intersect-rect.js'; /** * @param parent @@ -17,7 +18,7 @@ function question(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, s, s, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -42,7 +43,7 @@ function hexagon(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -64,7 +65,7 @@ function rect_left_inv_arrow(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -85,7 +86,7 @@ function lean_right(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -106,7 +107,7 @@ function lean_left(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -127,7 +128,7 @@ function trapezoid(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -148,7 +149,7 @@ function inv_trapezoid(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -170,7 +171,7 @@ function rect_right_inv_arrow(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -194,7 +195,7 @@ function stadium(parent, bbox, node) { .attr('height', h); node.intersect = function (point) { - return dagreD3.intersect.rect(node, point); + return intersectRect(node, point); }; return shapeSvg; } @@ -221,7 +222,7 @@ function subroutine(parent, bbox, node) { ]; const shapeSvg = insertPolygonShape(parent, w, h, points); node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point); + return intersectPolygon(node, points, point); }; return shapeSvg; } @@ -270,7 +271,7 @@ function cylinder(parent, bbox, node) { .attr('transform', 'translate(' + -w / 2 + ',' + -(h / 2 + ry) + ')'); node.intersect = function (point) { - const pos = dagreD3.intersect.rect(node, point); + const pos = intersectRect(node, point); const x = pos.x - node.x; if ( diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js index 6b7c4c1bf..86eb52504 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js @@ -5,7 +5,7 @@ import flowDb from './flowDb'; import { getConfig } from '../../config'; import { render } from '../../dagre-wrapper/index.js'; -import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js'; +import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; import { log } from '../../logger'; import common, { evaluate } from '../common/common'; import { interpolateToCurve, getStylesFromArray } from '../../utils'; diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js index c403b7fe3..0fcbce545 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js @@ -1,8 +1,9 @@ import graphlib from 'graphlib'; import { select, curveLinear, selectAll } from 'd3'; import { getConfig } from '../../config'; -import dagreD3 from 'dagre-d3'; -import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js'; +import { render as Render } from 'dagre-d3-es'; +import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js'; +import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; import { log } from '../../logger'; import common, { evaluate } from '../common/common'; import { interpolateToCurve, getStylesFromArray } from '../../utils'; @@ -370,7 +371,6 @@ export const draw = function (text, id, _version, diagObj) { addEdges(edges, g, diagObj); // Create the renderer - const Render = dagreD3.render; const render = new Render(); // Add custom shapes @@ -390,7 +390,7 @@ export const draw = function (text, id, _version, diagObj) { .attr('orient', 'auto'); const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z'); - dagreD3.util.applyStyle(path, edge[type + 'Style']); + applyStyle(path, edge[type + 'Style']); }; // Override normal arrowhead defined in d3. Remove style & add class to allow css styling. diff --git a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js index 79d67e76e..0338ec50c 100644 --- a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js +++ b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js @@ -1,5 +1,5 @@ import { line, select } from 'd3'; -import dagre from 'dagre'; +import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import graphlib from 'graphlib'; import { log } from '../../logger'; import { configureSvgSize } from '../../setupGraphViewbox'; @@ -348,7 +348,7 @@ export const draw = (text, id, _version, diagObj) => { drawReqs(requirements, g, svg); drawElements(elements, g, svg); addRelationships(relationships, g); - dagre.layout(g); + dagreLayout(g); adjustEntities(svg, g); relationships.forEach(function (rel) { diff --git a/packages/mermaid/src/diagrams/state/stateRenderer.js b/packages/mermaid/src/diagrams/state/stateRenderer.js index 73717a645..783460cc6 100644 --- a/packages/mermaid/src/diagrams/state/stateRenderer.js +++ b/packages/mermaid/src/diagrams/state/stateRenderer.js @@ -1,5 +1,5 @@ import { select } from 'd3'; -import dagre from 'dagre'; +import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js'; import graphlib from 'graphlib'; import { log } from '../../logger'; import common from '../common/common'; @@ -239,7 +239,7 @@ const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument, diagObj) = ); }); - dagre.layout(graph); + dagreLayout(graph); log.debug('Graph after layout', graph.nodes()); const svgElem = diagram.node(); diff --git a/packages/mermaid/src/tests/setup.ts b/packages/mermaid/src/tests/setup.ts index e8058c517..b3330787c 100644 --- a/packages/mermaid/src/tests/setup.ts +++ b/packages/mermaid/src/tests/setup.ts @@ -1,3 +1,3 @@ import { vi } from 'vitest'; vi.mock('d3'); -vi.mock('dagre-d3'); +vi.mock('dagre-d3-es'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11703bd03..0a04f741e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,8 +1,5 @@ lockfileVersion: 5.4-inlineSpecifiers -overrides: - d3: ^7.6.1 - importers: .: @@ -167,14 +164,11 @@ importers: specifier: ^6.0.0 version: 6.0.0 d3: - specifier: ^7.6.1 + specifier: ^7.0.0 version: 7.6.1 - dagre: - specifier: ^0.8.5 - version: 0.8.5 - dagre-d3: - specifier: ^0.6.4 - version: 0.6.4 + dagre-d3-es: + specifier: 7.0.2 + version: 7.0.2 dompurify: specifier: 2.4.1 version: 2.4.1 @@ -318,7 +312,7 @@ importers: specifier: ^2.1.0 version: 2.1.0_cytoscape@3.23.0 d3: - specifier: ^7.6.1 + specifier: ^7.0.0 version: 7.6.1 khroma: specifier: ^2.0.0 @@ -4800,20 +4794,11 @@ packages: d3-zoom: 3.0.0 dev: false - /dagre-d3/0.6.4: - resolution: {integrity: sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==} + /dagre-d3-es/7.0.2: + resolution: {integrity: sha512-m9+5yhzkf9gyklDMdWlQC/8bayGVlTF8GspmN6XC6nnZjas6kAmffvh0c/EcyFhQ+fp4QIl0fMpNdv76AJGlVQ==} dependencies: d3: 7.6.1 - dagre: 0.8.5 - graphlib: 2.1.8 - lodash: 4.17.21 - dev: false - - /dagre/0.8.5: - resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} - dependencies: - graphlib: 2.1.8 - lodash: 4.17.21 + lodash-es: 4.17.21 dev: false /dargs/7.0.0: @@ -7905,6 +7890,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash-es/4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: false + /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true