diff --git a/.eslintrc.json b/.eslintrc.json
index d83222f3a..1d052e22b 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -21,7 +21,16 @@
"plugin:@cspell/recommended",
"prettier"
],
- "plugins": ["@typescript-eslint", "no-only-tests", "html", "jest", "jsdoc", "json", "@cspell"],
+ "plugins": [
+ "@typescript-eslint",
+ "no-only-tests",
+ "html",
+ "jest",
+ "jsdoc",
+ "json",
+ "@cspell",
+ "lodash"
+ ],
"rules": {
"curly": "error",
"no-console": "error",
@@ -53,7 +62,8 @@
"allowEmptyCatch": true
}
],
- "no-only-tests/no-only-tests": "error"
+ "no-only-tests/no-only-tests": "error",
+ "lodash/import-scope": ["error", "method"]
},
"overrides": [
{
diff --git a/.prettierignore b/.prettierignore
index fe2c55574..b66f97d1c 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -3,4 +3,5 @@ cypress/platform/xss3.html
.cache
coverage
# Autogenerated by PNPM
-pnpm-lock.yaml
\ No newline at end of file
+pnpm-lock.yaml
+stats
\ No newline at end of file
diff --git a/.vite/build.ts b/.vite/build.ts
index f2dd7db05..1be46ad5a 100644
--- a/.vite/build.ts
+++ b/.vite/build.ts
@@ -56,7 +56,7 @@ interface BuildOptions {
}
export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions): InlineConfig => {
- const external = ['require', 'fs', 'path'];
+ const external: (string | RegExp)[] = ['require', 'fs', 'path'];
console.log(entryName, packageOptions[entryName]);
const { name, file, packageName } = packageOptions[entryName];
let output: OutputOptions = [
@@ -80,7 +80,9 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
);
// Core build is used to generate file without bundled dependencies.
// This is used by downstream projects to bundle dependencies themselves.
- external.push(...Object.keys(dependencies));
+ // Ignore dependencies and any dependencies of dependencies
+ // Adapted from the RegEx used by `rollup-plugin-node`
+ external.push(new RegExp('^(?:' + Object.keys(dependencies).join('|') + ')(?:/.+)?$'));
// This needs to be an array. Otherwise vite will build esm & umd with same name and overwrite esm with umd.
output = [
{
diff --git a/package.json b/package.json
index 36846a313..628fcecd2 100644
--- a/package.json
+++ b/package.json
@@ -60,8 +60,8 @@
"@cspell/eslint-plugin": "^6.14.2",
"@types/eslint": "^8.4.10",
"@types/express": "^4.17.14",
- "@types/jsdom": "^20.0.1",
"@types/js-yaml": "^4.0.5",
+ "@types/jsdom": "^20.0.1",
"@types/lodash": "^4.14.188",
"@types/mdast": "^3.0.10",
"@types/node": "^18.11.9",
@@ -83,17 +83,19 @@
"eslint-plugin-jest": "^27.1.5",
"eslint-plugin-jsdoc": "^39.6.2",
"eslint-plugin-json": "^3.1.0",
+ "eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-markdown": "^3.0.0",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-tsdoc": "^0.2.17",
+ "eslint-plugin-unicorn": "^45.0.0",
"express": "^4.18.2",
"globby": "^13.1.2",
"husky": "^8.0.2",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.3.1",
"jison": "^0.4.18",
- "jsdom": "^20.0.2",
"js-yaml": "^4.1.0",
+ "jsdom": "^20.0.2",
"lint-staged": "^13.0.3",
"path-browserify": "^1.0.1",
"pnpm": "^7.15.0",
diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json
index 0b4c7aad1..26e846c20 100644
--- a/packages/mermaid/package.json
+++ b/packages/mermaid/package.json
@@ -54,12 +54,12 @@
"dependencies": {
"@braintree/sanitize-url": "^6.0.0",
"d3": "^7.0.0",
- "dagre-d3-es": "7.0.2",
+ "dagre-d3-es": "7.0.4",
"dompurify": "2.4.1",
"fast-clone": "^1.5.13",
"graphlib": "^2.1.8",
"khroma": "^2.0.0",
- "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
"moment-mini": "^2.24.0",
"non-layered-tidy-tree-layout": "^2.0.2",
"stylis": "^4.1.2",
@@ -69,7 +69,7 @@
"@types/d3": "^7.4.0",
"@types/dompurify": "^2.4.0",
"@types/jsdom": "^20.0.1",
- "@types/lodash": "^4.14.188",
+ "@types/lodash-es": "^4.17.6",
"@types/micromatch": "^4.0.2",
"@types/prettier": "^2.7.1",
"@types/stylis": "^4.0.2",
diff --git a/packages/mermaid/src/dagre-wrapper/index.js b/packages/mermaid/src/dagre-wrapper/index.js
index 43fe311b3..8b77c8520 100644
--- a/packages/mermaid/src/dagre-wrapper/index.js
+++ b/packages/mermaid/src/dagre-wrapper/index.js
@@ -1,5 +1,5 @@
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
-import graphlib from 'graphlib';
+import * as graphlibJson from 'dagre-d3-es/src/graphlib/json';
import insertMarkers from './markers';
import { updateNodeBounds } from './shapes/util';
import {
@@ -15,7 +15,7 @@ import { insertEdgeLabel, positionEdgeLabel, insertEdge, clear as clearEdges } f
import { log } from '../logger';
const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
- log.info('Graph in recursive render: XXX', graphlib.json.write(graph), parentCluster);
+ log.info('Graph in recursive render: XXX', graphlibJson.write(graph), parentCluster);
const dir = graph.graph().rankdir;
log.trace('Dir in recursive render - dir:', dir);
@@ -96,7 +96,7 @@ const recursiveRender = (_elem, graph, diagramtype, parentCluster) => {
log.info('#############################################');
log.info(graph);
dagreLayout(graph);
- log.info('Graph after layout:', graphlib.json.write(graph));
+ log.info('Graph after layout:', graphlibJson.write(graph));
// Move the nodes to the correct place
let diff = 0;
sortNodesByHierarchy(graph).forEach(function (v) {
@@ -153,10 +153,10 @@ export const render = (elem, graph, markers, diagramtype, id) => {
clearClusters();
clearGraphlib();
- log.warn('Graph at first:', graphlib.json.write(graph));
+ log.warn('Graph at first:', graphlibJson.write(graph));
adjustClustersAndEdges(graph);
- log.warn('Graph after:', graphlib.json.write(graph));
- // log.warn('Graph ever after:', graphlib.json.write(graph.node('A').graph));
+ log.warn('Graph after:', graphlibJson.write(graph));
+ // log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
recursiveRender(elem, graph, diagramtype);
};
diff --git a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.js b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.js
index 56f656430..15fadc940 100644
--- a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.js
+++ b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.js
@@ -1,6 +1,7 @@
/** Decorates with functions required by mermaids dagre-wrapper. */
import { log } from '../logger';
-import graphlib from 'graphlib';
+import * as graphlibJson from 'dagre-d3-es/src/graphlib/json';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
export let clusterDb = {};
let decendants = {};
@@ -322,7 +323,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
graph.setEdge(v, w, edge, e.name);
}
});
- log.warn('Adjusted Graph', graphlib.json.write(graph));
+ log.warn('Adjusted Graph', graphlibJson.write(graph));
extractor(graph, 0);
log.trace(clusterDb);
@@ -336,7 +337,7 @@ export const adjustClustersAndEdges = (graph, depth) => {
};
export const extractor = (graph, depth) => {
- log.warn('extractor - ', depth, graphlib.json.write(graph), graph.children('D'));
+ log.warn('extractor - ', depth, graphlibJson.write(graph), graph.children('D'));
if (depth > 10) {
log.error('Bailing out');
return;
@@ -415,7 +416,7 @@ export const extractor = (graph, depth) => {
return {};
});
- log.warn('Old graph before copy', graphlib.json.write(graph));
+ log.warn('Old graph before copy', graphlibJson.write(graph));
copy(node, graph, clusterGraph, node);
graph.setNode(node, {
clusterNode: true,
@@ -424,8 +425,8 @@ export const extractor = (graph, depth) => {
labelText: clusterDb[node].labelText,
graph: clusterGraph,
});
- log.warn('New graph after copy node: (', node, ')', graphlib.json.write(clusterGraph));
- log.debug('Old graph after copy', graphlib.json.write(graph));
+ log.warn('New graph after copy node: (', node, ')', graphlibJson.write(clusterGraph));
+ log.debug('Old graph after copy', graphlibJson.write(graph));
} else {
log.warn(
'Cluster ** ',
diff --git a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
index a09e17f02..49b022f4d 100644
--- a/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
+++ b/packages/mermaid/src/dagre-wrapper/mermaid-graphlib.spec.js
@@ -1,4 +1,5 @@
-import graphlib from 'graphlib';
+import * as graphlibJson from 'dagre-d3-es/src/graphlib/json';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import {
validate,
adjustClustersAndEdges,
@@ -232,9 +233,9 @@ describe('Graphlib decorations', () => {
g.setParent('D', 'C');
// log.info('Graph before', g.node('D'))
- // log.info('Graph before', graphlib.json.write(g))
+ // log.info('Graph before', graphlibJson.write(g))
adjustClustersAndEdges(g);
- // log.info('Graph after', graphlib.json.write(g), g.node('C').graph)
+ // log.info('Graph after', graphlibJson.write(g), g.node('C').graph)
const CGraph = g.node('C').graph;
const DGraph = CGraph.node('D').graph;
@@ -278,9 +279,9 @@ describe('Graphlib decorations', () => {
g.setEdge('A', 'C', { data: 'link2' }, '2');
log.info('Graph before', g.node('D'));
- log.info('Graph before', graphlib.json.write(g));
+ log.info('Graph before', graphlibJson.write(g));
adjustClustersAndEdges(g);
- log.trace('Graph after', graphlib.json.write(g));
+ log.trace('Graph after', graphlibJson.write(g));
expect(g.nodes()).toEqual(['C', 'B', 'A']);
expect(g.nodes().length).toBe(3);
expect(g.edges().length).toBe(2);
@@ -333,11 +334,11 @@ describe('Graphlib decorations', () => {
g.setEdge('c', 'd', { data: 'link2' }, '2');
g.setEdge('d', 'e', { data: 'link2' }, '2');
- log.info('Graph before', graphlib.json.write(g));
+ log.info('Graph before', graphlibJson.write(g));
adjustClustersAndEdges(g);
const bGraph = g.node('b').graph;
- // log.trace('Graph after', graphlib.json.write(g))
- log.info('Graph after', graphlib.json.write(bGraph));
+ // log.trace('Graph after', graphlibJson.write(g))
+ log.info('Graph after', graphlibJson.write(bGraph));
expect(bGraph.nodes().length).toBe(3);
expect(bGraph.edges().length).toBe(2);
});
@@ -359,13 +360,13 @@ describe('Graphlib decorations', () => {
g.setParent('c', 'b');
g.setParent('e', 'c');
- log.info('Graph before', graphlib.json.write(g));
+ log.info('Graph before', graphlibJson.write(g));
adjustClustersAndEdges(g);
const aGraph = g.node('a').graph;
const bGraph = aGraph.node('b').graph;
- log.info('Graph after', graphlib.json.write(aGraph));
+ log.info('Graph after', graphlibJson.write(aGraph));
const cGraph = bGraph.node('c').graph;
- // log.trace('Graph after', graphlib.json.write(g))
+ // log.trace('Graph after', graphlibJson.write(g))
expect(aGraph.nodes().length).toBe(1);
expect(bGraph.nodes().length).toBe(1);
expect(cGraph.nodes().length).toBe(1);
@@ -387,14 +388,14 @@ flowchart TB
const exportedGraph = JSON.parse(
'{"options":{"directed":true,"multigraph":true,"compound":true},"nodes":[{"v":"A","value":{"labelStyle":"","shape":"rect","labelText":"A","rx":0,"ry":0,"class":"default","style":"","id":"A","width":500,"type":"group","padding":15}},{"v":"B","value":{"labelStyle":"","shape":"rect","labelText":"B","rx":0,"ry":0,"class":"default","style":"","id":"B","width":500,"type":"group","padding":15},"parent":"A"},{"v":"b","value":{"labelStyle":"","shape":"rect","labelText":"b","rx":0,"ry":0,"class":"default","style":"","id":"b","padding":15},"parent":"A"},{"v":"c","value":{"labelStyle":"","shape":"rect","labelText":"c","rx":0,"ry":0,"class":"default","style":"","id":"c","padding":15},"parent":"B"},{"v":"a","value":{"labelStyle":"","shape":"rect","labelText":"a","rx":0,"ry":0,"class":"default","style":"","id":"a","padding":15},"parent":"A"}],"edges":[{"v":"b","w":"B","name":"1","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-b-B","classes":"flowchart-link LS-b LE-B"}},{"v":"a","w":"c","name":"2","value":{"minlen":1,"arrowhead":"normal","arrowTypeStart":"arrow_open","arrowTypeEnd":"arrow_point","thickness":"normal","pattern":"solid","style":"fill:none","labelStyle":"","arrowheadStyle":"fill: #333","labelpos":"c","labelType":"text","label":"","id":"L-a-c","classes":"flowchart-link LS-a LE-c"}}],"value":{"rankdir":"TB","nodesep":50,"ranksep":50,"marginx":8,"marginy":8}}'
);
- const gr = graphlib.json.read(exportedGraph);
+ const gr = graphlibJson.read(exportedGraph);
- log.info('Graph before', graphlib.json.write(gr));
+ log.info('Graph before', graphlibJson.write(gr));
adjustClustersAndEdges(gr);
const aGraph = gr.node('A').graph;
const bGraph = aGraph.node('B').graph;
- log.info('Graph after', graphlib.json.write(aGraph));
- // log.trace('Graph after', graphlib.json.write(g))
+ log.info('Graph after', graphlibJson.write(aGraph));
+ // log.trace('Graph after', graphlibJson.write(g))
expect(aGraph.parent('c')).toBe('B');
expect(aGraph.parent('B')).toBe(undefined);
});
diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.js b/packages/mermaid/src/diagrams/class/classRenderer-v2.js
index bca3c01c8..905e6ee2f 100644
--- a/packages/mermaid/src/diagrams/class/classRenderer-v2.js
+++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.js
@@ -1,5 +1,5 @@
import { select } from 'd3';
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import { log } from '../../logger';
import { getConfig } from '../../config';
import { render } from '../../dagre-wrapper/index.js';
diff --git a/packages/mermaid/src/diagrams/class/classRenderer.js b/packages/mermaid/src/diagrams/class/classRenderer.js
index 357647427..74e2a48c2 100644
--- a/packages/mermaid/src/diagrams/class/classRenderer.js
+++ b/packages/mermaid/src/diagrams/class/classRenderer.js
@@ -1,6 +1,6 @@
import { select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger';
import svgDraw from './svgDraw';
import { configureSvgSize } from '../../setupGraphViewbox';
diff --git a/packages/mermaid/src/diagrams/er/erRenderer.js b/packages/mermaid/src/diagrams/er/erRenderer.js
index d0771fe39..36267f415 100644
--- a/packages/mermaid/src/diagrams/er/erRenderer.js
+++ b/packages/mermaid/src/diagrams/er/erRenderer.js
@@ -1,4 +1,4 @@
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import { line, curveBasis, select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
import { getConfig } from '../../config';
diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
index 0a736b22b..fa1b692cf 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js
@@ -1,4 +1,4 @@
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import { select, curveLinear, selectAll } from 'd3';
import flowDb from './flowDb';
diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
index 0fcbce545..7febc4034 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
+++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js
@@ -1,4 +1,4 @@
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import { select, curveLinear, selectAll } from 'd3';
import { getConfig } from '../../config';
import { render as Render } from 'dagre-d3-es';
diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow-direction.spec.js b/packages/mermaid/src/diagrams/flowchart/parser/flow-direction.spec.js
index 6b741fc12..6cba33f88 100644
--- a/packages/mermaid/src/diagrams/flowchart/parser/flow-direction.spec.js
+++ b/packages/mermaid/src/diagrams/flowchart/parser/flow-direction.spec.js
@@ -1,6 +1,6 @@
import flowDb from '../flowDb';
import flow from './flow';
-import filter from 'lodash/filter';
+import filter from 'lodash-es/filter';
import { setConfig } from '../../../config';
setConfig({
diff --git a/packages/mermaid/src/diagrams/flowchart/parser/subgraph.spec.js b/packages/mermaid/src/diagrams/flowchart/parser/subgraph.spec.js
index aa8e9217f..6fec233e7 100644
--- a/packages/mermaid/src/diagrams/flowchart/parser/subgraph.spec.js
+++ b/packages/mermaid/src/diagrams/flowchart/parser/subgraph.spec.js
@@ -1,6 +1,6 @@
import flowDb from '../flowDb';
import flow from './flow';
-import filter from 'lodash/filter';
+import filter from 'lodash-es/filter';
import { setConfig } from '../../../config';
setConfig({
diff --git a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
index 0338ec50c..10469d50d 100644
--- a/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
+++ b/packages/mermaid/src/diagrams/requirement/requirementRenderer.js
@@ -1,6 +1,6 @@
import { line, select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger';
import { configureSvgSize } from '../../setupGraphViewbox';
import common from '../common/common';
diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js b/packages/mermaid/src/diagrams/state/stateRenderer-v2.js
index 03c678789..6fdeb723e 100644
--- a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js
+++ b/packages/mermaid/src/diagrams/state/stateRenderer-v2.js
@@ -1,4 +1,4 @@
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib';
import { select } from 'd3';
import { getConfig } from '../../config';
import { render } from '../../dagre-wrapper/index.js';
diff --git a/packages/mermaid/src/diagrams/state/stateRenderer.js b/packages/mermaid/src/diagrams/state/stateRenderer.js
index 783460cc6..57b1d1665 100644
--- a/packages/mermaid/src/diagrams/state/stateRenderer.js
+++ b/packages/mermaid/src/diagrams/state/stateRenderer.js
@@ -1,6 +1,6 @@
import { select } from 'd3';
import { layout as dagreLayout } from 'dagre-d3-es/src/dagre/index.js';
-import graphlib from 'graphlib';
+import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
import { log } from '../../logger';
import common from '../common/common';
import { drawState, addTitleAndBox, drawEdge } from './shapes';
diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts
index 75e6ae2fe..0b2e85cd6 100644
--- a/packages/mermaid/src/mermaidAPI.ts
+++ b/packages/mermaid/src/mermaidAPI.ts
@@ -29,7 +29,7 @@ import utils, { directiveSanitizer } from './utils';
import DOMPurify from 'dompurify';
import { MermaidConfig } from './config.type';
import { evaluate } from './diagrams/common/common';
-import isEmpty from 'lodash/isEmpty';
+import isEmpty from 'lodash-es/isEmpty';
// diagram names that support classDef statements
const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram', 'stateDiagram-v2'];
diff --git a/packages/mermaid/src/utils.spec.js b/packages/mermaid/src/utils.spec.js
index 4d3e07e6b..54262f10e 100644
--- a/packages/mermaid/src/utils.spec.js
+++ b/packages/mermaid/src/utils.spec.js
@@ -3,7 +3,7 @@ import utils from './utils';
import assignWithDepth from './assignWithDepth';
import { detectType } from './diagram-api/detectType';
import { addDiagrams } from './diagram-api/diagram-orchestration';
-import memoize from 'lodash/memoize';
+import memoize from 'lodash-es/memoize';
import { MockD3 } from 'd3';
addDiagrams();
diff --git a/packages/mermaid/src/utils.ts b/packages/mermaid/src/utils.ts
index 82f89d61a..3689a01a1 100644
--- a/packages/mermaid/src/utils.ts
+++ b/packages/mermaid/src/utils.ts
@@ -21,7 +21,7 @@ import { log } from './logger';
import { detectType } from './diagram-api/detectType';
import assignWithDepth from './assignWithDepth';
import { MermaidConfig } from './config.type';
-import memoize from 'lodash/memoize';
+import memoize from 'lodash-es/memoize';
// Effectively an enum of the supported curve types, accessible by name
const d3CurveTypes = {
@@ -561,54 +561,77 @@ export const drawSimpleText = function (
return textElem;
};
-export const wrapLabel = memoize(
- (label, maxWidth, config) => {
- if (!label) {
- return label;
- }
- config = Object.assign(
- { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', joinWith: '
' },
- config
- );
- if (common.lineBreakRegex.test(label)) {
- return label;
- }
- const words = label.split(' ');
- const completedLines = [];
- let nextLine = '';
- words.forEach((word, index) => {
- const wordLength = calculateTextWidth(`${word} `, config);
- const nextLineLength = calculateTextWidth(nextLine, config);
- if (wordLength > maxWidth) {
- const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, '-', config);
- completedLines.push(nextLine, ...hyphenatedStrings);
- nextLine = remainingWord;
- } else if (nextLineLength + wordLength >= maxWidth) {
- completedLines.push(nextLine);
- nextLine = word;
- } else {
- nextLine = [nextLine, word].filter(Boolean).join(' ');
- }
- const currentWord = index + 1;
- const isLastWord = currentWord === words.length;
- if (isLastWord) {
- completedLines.push(nextLine);
- }
- });
- return completedLines.filter((line) => line !== '').join(config.joinWith);
- },
- (label, maxWidth, config) =>
- `${label}${maxWidth}${config.fontSize}${config.fontWeight}${config.fontFamily}${config.joinWith}`
-);
+interface WrapLabelConfig {
+ fontSize: number;
+ fontFamily: string;
+ fontWeight: number;
+ joinWith: string;
+}
-const breakString = memoize(
- (word, maxWidth, hyphenCharacter = '-', config) => {
+export const wrapLabel: (label: string, maxWidth: string, config: WrapLabelConfig) => string =
+ memoize(
+ (label: string, maxWidth: string, config: WrapLabelConfig): string => {
+ if (!label) {
+ return label;
+ }
+ config = Object.assign(
+ { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', joinWith: '
' },
+ config
+ );
+ if (common.lineBreakRegex.test(label)) {
+ return label;
+ }
+ const words = label.split(' ');
+ const completedLines = [];
+ let nextLine = '';
+ words.forEach((word, index) => {
+ const wordLength = calculateTextWidth(`${word} `, config);
+ const nextLineLength = calculateTextWidth(nextLine, config);
+ if (wordLength > maxWidth) {
+ const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, '-', config);
+ completedLines.push(nextLine, ...hyphenatedStrings);
+ nextLine = remainingWord;
+ } else if (nextLineLength + wordLength >= maxWidth) {
+ completedLines.push(nextLine);
+ nextLine = word;
+ } else {
+ nextLine = [nextLine, word].filter(Boolean).join(' ');
+ }
+ const currentWord = index + 1;
+ const isLastWord = currentWord === words.length;
+ if (isLastWord) {
+ completedLines.push(nextLine);
+ }
+ });
+ return completedLines.filter((line) => line !== '').join(config.joinWith);
+ },
+ (label, maxWidth, config) =>
+ `${label}${maxWidth}${config.fontSize}${config.fontWeight}${config.fontFamily}${config.joinWith}`
+ );
+
+interface BreakStringOutput {
+ hyphenatedStrings: string[];
+ remainingWord: string;
+}
+
+const breakString: (
+ word: string,
+ maxWidth: number,
+ hyphenCharacter: string,
+ config: WrapLabelConfig
+) => BreakStringOutput = memoize(
+ (
+ word: string,
+ maxWidth: number,
+ hyphenCharacter = '-',
+ config: WrapLabelConfig
+ ): BreakStringOutput => {
config = Object.assign(
{ fontSize: 12, fontWeight: 400, fontFamily: 'Arial', margin: 0 },
config
);
const characters = word.split('');
- const lines = [];
+ const lines: string[] = [];
let currentLine = '';
characters.forEach((character, index) => {
const nextLine = `${currentLine}${character}`;
@@ -667,6 +690,16 @@ export function calculateTextWidth(
return calculateTextDimensions(text, config).width;
}
+interface TextDimensionConfig {
+ fontSize?: number;
+ fontWeight?: number;
+ fontFamily?: string;
+}
+interface TextDimensions {
+ width: number;
+ height: number;
+ lineHeight?: number;
+}
/**
* This calculates the dimensions of the given text, font size, font family, font weight, and
* margins.
@@ -676,15 +709,11 @@ export function calculateTextWidth(
* the resulting size
* @returns The dimensions for the given text
*/
-export const calculateTextDimensions = memoize(
- function (
- text: string,
- config: {
- fontSize?: number;
- fontWeight?: number;
- fontFamily?: string;
- }
- ) {
+export const calculateTextDimensions: (
+ text: string,
+ config: TextDimensionConfig
+) => TextDimensions = memoize(
+ (text: string, config: TextDimensionConfig): TextDimensions => {
config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config);
const { fontSize, fontFamily, fontWeight } = config;
if (!text) {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7bd96ee8f..91e22e019 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -91,6 +91,9 @@ importers:
eslint-plugin-json:
specifier: ^3.1.0
version: 3.1.0
+ eslint-plugin-lodash:
+ specifier: ^7.4.0
+ version: 7.4.0_eslint@8.27.0
eslint-plugin-markdown:
specifier: ^3.0.0
version: 3.0.0_eslint@8.27.0
@@ -100,6 +103,9 @@ importers:
eslint-plugin-tsdoc:
specifier: ^0.2.17
version: 0.2.17
+ eslint-plugin-unicorn:
+ specifier: ^45.0.0
+ version: 45.0.0_eslint@8.27.0
express:
specifier: ^4.18.2
version: 4.18.2
@@ -179,8 +185,8 @@ importers:
specifier: ^7.0.0
version: 7.6.1
dagre-d3-es:
- specifier: 7.0.2
- version: 7.0.2
+ specifier: 7.0.4
+ version: 7.0.4
dompurify:
specifier: 2.4.1
version: 2.4.1
@@ -193,7 +199,7 @@ importers:
khroma:
specifier: ^2.0.0
version: 2.0.0
- lodash:
+ lodash-es:
specifier: ^4.17.21
version: 4.17.21
moment-mini:
@@ -218,9 +224,9 @@ importers:
'@types/jsdom':
specifier: ^20.0.1
version: 20.0.1
- '@types/lodash':
- specifier: ^4.14.188
- version: 4.14.188
+ '@types/lodash-es':
+ specifier: ^4.17.6
+ version: 4.17.6
'@types/micromatch':
specifier: ^4.0.2
version: 4.0.2
@@ -1766,7 +1772,7 @@ packages:
'@types/node': 18.11.9
ansi-escapes: 4.3.2
chalk: 4.1.2
- ci-info: 3.4.0
+ ci-info: 3.6.2
exit: 0.1.2
graceful-fs: 4.2.10
jest-changed-files: 29.2.0
@@ -2498,6 +2504,12 @@ packages:
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
dev: true
+ /@types/lodash-es/4.17.6:
+ resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==}
+ dependencies:
+ '@types/lodash': 4.14.188
+ dev: true
+
/@types/lodash/4.14.188:
resolution: {integrity: sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w==}
dev: true
@@ -3779,6 +3791,11 @@ packages:
ieee754: 1.2.1
dev: true
+ /builtin-modules/3.3.0:
+ resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
+ engines: {node: '>=6'}
+ dev: true
+
/bytes/3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
@@ -3969,8 +3986,9 @@ packages:
engines: {node: '>=6.0'}
dev: true
- /ci-info/3.4.0:
- resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==}
+ /ci-info/3.6.2:
+ resolution: {integrity: sha512-lVZdhvbEudris15CLytp2u6Y0p5EKfztae9Fqa189MfNmln9F33XuH69v5fvNfiRN5/0eAUz2yJL3mo+nhaRKg==}
+ engines: {node: '>=8'}
dev: true
/cjs-module-lexer/1.2.2:
@@ -3984,6 +4002,13 @@ packages:
jsonlint: 1.6.0
dev: true
+ /clean-regexp/1.0.0:
+ resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
+ engines: {node: '>=4'}
+ dependencies:
+ escape-string-regexp: 1.0.5
+ dev: true
+
/clean-stack/2.2.0:
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
@@ -4814,8 +4839,8 @@ packages:
d3-zoom: 3.0.0
dev: false
- /dagre-d3-es/7.0.2:
- resolution: {integrity: sha512-m9+5yhzkf9gyklDMdWlQC/8bayGVlTF8GspmN6XC6nnZjas6kAmffvh0c/EcyFhQ+fp4QIl0fMpNdv76AJGlVQ==}
+ /dagre-d3-es/7.0.4:
+ resolution: {integrity: sha512-fQL8ldFR9UYpecz48d1smrXNJ9zGUK38Vl5OzX6Fhn9LR+oQh0GzHRPQylP5kWawmMTKm1QtqcHMVySMJ5CYaQ==}
dependencies:
d3: 7.6.1
lodash-es: 4.17.21
@@ -5554,6 +5579,16 @@ packages:
vscode-json-languageservice: 4.2.1
dev: true
+ /eslint-plugin-lodash/7.4.0_eslint@8.27.0:
+ resolution: {integrity: sha512-Tl83UwVXqe1OVeBRKUeWcfg6/pCW1GTRObbdnbEJgYwjxp5Q92MEWQaH9+dmzbRt6kvYU1Mp893E79nJiCSM8A==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: '>=2'
+ dependencies:
+ eslint: 8.27.0
+ lodash: 4.17.21
+ dev: true
+
/eslint-plugin-markdown/3.0.0_eslint@8.27.0:
resolution: {integrity: sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -5578,6 +5613,31 @@ packages:
'@microsoft/tsdoc-config': 0.16.2
dev: true
+ /eslint-plugin-unicorn/45.0.0_eslint@8.27.0:
+ resolution: {integrity: sha512-iP8cMRxXKHonKioOhnCoCcqVhoqhAp6rB+nsoLjXFDxTHz3btWMAp8xwzjHA0B1K6YV/U/Yvqn1bUXZt8sJPuQ==}
+ engines: {node: '>=14.18'}
+ peerDependencies:
+ eslint: '>=8.28.0'
+ dependencies:
+ '@babel/helper-validator-identifier': 7.19.1
+ ci-info: 3.6.2
+ clean-regexp: 1.0.0
+ eslint: 8.27.0
+ eslint-utils: 3.0.0_eslint@8.27.0
+ esquery: 1.4.0
+ indent-string: 4.0.0
+ is-builtin-module: 3.2.0
+ jsesc: 3.0.2
+ lodash: 4.17.21
+ pluralize: 8.0.0
+ read-pkg-up: 7.0.1
+ regexp-tree: 0.1.24
+ regjsparser: 0.9.1
+ safe-regex: 2.1.1
+ semver: 7.3.8
+ strip-indent: 3.0.0
+ dev: true
+
/eslint-scope/5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
@@ -6052,16 +6112,6 @@ packages:
resolution: {integrity: sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA==}
dev: true
- /follow-redirects/1.15.2:
- resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
- engines: {node: '>=4.0'}
- peerDependencies:
- debug: '*'
- peerDependenciesMeta:
- debug:
- optional: true
- dev: true
-
/follow-redirects/1.15.2_debug@4.3.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
@@ -6648,7 +6698,7 @@ packages:
engines: {node: '>=8.0.0'}
dependencies:
eventemitter3: 4.0.7
- follow-redirects: 1.15.2
+ follow-redirects: 1.15.2_debug@4.3.2
requires-port: 1.0.0
transitivePeerDependencies:
- debug
@@ -6871,11 +6921,18 @@ packages:
engines: {node: '>=4'}
dev: true
+ /is-builtin-module/3.2.0:
+ resolution: {integrity: sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==}
+ engines: {node: '>=6'}
+ dependencies:
+ builtin-modules: 3.3.0
+ dev: true
+
/is-ci/3.0.1:
resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
hasBin: true
dependencies:
- ci-info: 3.4.0
+ ci-info: 3.6.2
dev: true
/is-core-module/2.10.0:
@@ -7173,7 +7230,7 @@ packages:
'@types/node': 18.11.9
babel-jest: 29.3.1_@babel+core@7.12.3
chalk: 4.1.2
- ci-info: 3.4.0
+ ci-info: 3.6.2
deepmerge: 4.2.2
glob: 7.2.3
graceful-fs: 4.2.10
@@ -7459,7 +7516,7 @@ packages:
'@jest/types': 29.3.1
'@types/node': 18.11.9
chalk: 4.1.2
- ci-info: 3.4.0
+ ci-info: 3.6.2
graceful-fs: 4.2.10
picomatch: 2.3.1
dev: true
@@ -7648,12 +7705,23 @@ packages:
- utf-8-validate
dev: true
+ /jsesc/0.5.0:
+ resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
+ hasBin: true
+ dev: true
+
/jsesc/2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'}
hasBin: true
dev: true
+ /jsesc/3.0.2:
+ resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dev: true
+
/json-buffer/3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: true
@@ -8969,6 +9037,11 @@ packages:
xmlbuilder: 15.1.1
dev: true
+ /pluralize/8.0.0:
+ resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
+ engines: {node: '>=4'}
+ dev: true
+
/png-async/0.9.4:
resolution: {integrity: sha512-B//AXX9TkneKfgtOpT1mdUnnhk2BImGD+a98vImsMU8uo1dBeHyW/kM2erWZ/CsYteTPU/xKG+t6T62heHkC3A==}
dev: true
@@ -9255,11 +9328,23 @@ packages:
strip-indent: 3.0.0
dev: true
+ /regexp-tree/0.1.24:
+ resolution: {integrity: sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==}
+ hasBin: true
+ dev: true
+
/regexpp/3.2.0:
resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==}
engines: {node: '>=8'}
dev: true
+ /regjsparser/0.9.1:
+ resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==}
+ hasBin: true
+ dependencies:
+ jsesc: 0.5.0
+ dev: true
+
/remark-parse/10.0.1:
resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==}
dependencies:
@@ -9491,6 +9576,12 @@ packages:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
+ /safe-regex/2.1.1:
+ resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==}
+ dependencies:
+ regexp-tree: 0.1.24
+ dev: true
+
/safer-buffer/2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}