Compare commits

..

4 Commits

Author SHA1 Message Date
Sidharth Vinod
3e92b463d9 Add remove in mockedD3 2023-06-04 12:35:50 +05:30
Sidharth Vinod
509798c03d Fix imports in utils 2023-06-04 12:35:28 +05:30
Sidharth Vinod
7dc7ecb8f1 Fix type issues in utils test 2023-06-04 12:12:41 +05:30
Sidharth Vinod
1d5b7702b4 Rename utils.spec to ts 2023-06-04 12:10:57 +05:30
30 changed files with 2286 additions and 259 deletions

View File

@@ -84,7 +84,6 @@
"mkdocs",
"mmorel",
"mult",
"nextra",
"orlandoni",
"pathe",
"pbrolin",

View File

@@ -60,7 +60,7 @@ export const renderGraph = (graphStr, options, api) => {
openURLAndVerifyRendering(url, options);
};
export const openURLAndVerifyRendering = (url, options, validation = undefined) => {
const openURLAndVerifyRendering = (url, options, validation = undefined) => {
const useAppli = Cypress.env('useAppli');
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');

View File

@@ -1,4 +1,4 @@
import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.js';
import { urlSnapshotTest } from '../../helpers/util.js';
describe('CSS injections', () => {
it('should not allow CSS injections outside of the diagram', () => {
@@ -13,11 +13,4 @@ describe('CSS injections', () => {
flowchart: { htmlLabels: false },
});
});
it('should not allow manipulating styletags using arrowheads', () => {
openURLAndVerifyRendering('http://localhost:9000/xss23-css.html', {
logLevel: 1,
arrowMarkerAbsolute: false,
flowchart: { htmlLabels: true },
});
});
});

View File

@@ -52,17 +52,6 @@ root[A root with a long text that wraps to keep the node size in check]
);
});
it('a root with wrapping text and long words that exceed width', () => {
imgSnapshotTest(
`mindmap
root[A few smaller words but then averylongsetofcharacterswithoutwhitespacetoseparate that we expect to wrapontonextlinesandnotexceedwidthparameters]
`,
{},
undefined,
shouldHaveRoot
);
});
it('a root with an icon', () => {
imgSnapshotTest(
`mindmap

View File

@@ -88,16 +88,6 @@ context('Sequence diagram', () => {
{}
);
});
it('should handle empty lines', () => {
imgSnapshotTest(
`
sequenceDiagram
Alice->>John: Hello John<br/>
John-->>Alice: Great<br/><br/>day!
`,
{}
);
});
it('should handle line breaks and wrap annotations', () => {
imgSnapshotTest(
`

View File

@@ -1,85 +0,0 @@
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
rel="stylesheet"
/>
<style>
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
/* font-size: 18px !important; */
}
h1 {
color: grey;
}
.mermaid2 {
display: none;
}
.mermaid svg {
/* font-size: 18px !important; */
}
.malware {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 150px;
background: red;
color: black;
display: flex;
display: flex;
justify-content: center;
align-items: center;
font-family: monospace;
font-size: 72px;
}
</style>
</head>
<body>
<div>Security check</div>
<div class="flex">
<div id="diagram" class="mermaid"></div>
<div id="graph-div"></div>
<div id="res" class=""></div>
</div>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'base',
startOnLoad: false,
flowcharts: { htmlLabels: true },
});
function callback() {
alert('It worked');
}
function xssAttack() {
const div = document.createElement('div');
div.id = 'the-malware';
div.className = 'malware';
div.innerHTML = 'XSS Succeeded';
document.getElementsByTagName('body')[0].appendChild(div);
throw new Error('XSS Succeeded');
}
let diagram = `graph TD
A[["a marker-end=#quot;url(<s title='#<style>*{background:red}</style>'>b"]]
`;
const el = document.querySelector('#graph-div');
console.log(diagram);
const { svg } = await mermaid.render('graph-div', diagram);
document.querySelector('#res').innerHTML = svg;
window.rendered = true;
</script>
</body>
</html>

1054
docs/CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -96,7 +96,7 @@ mermaid.initialize(config);
#### Defined in
[mermaidAPI.ts:670](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L670)
[mermaidAPI.ts:667](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L667)
## Functions
@@ -127,7 +127,7 @@ Return the last node appended
#### Defined in
[mermaidAPI.ts:309](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L309)
[mermaidAPI.ts:306](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L306)
---
@@ -295,7 +295,7 @@ Put the svgCode into an iFrame. Return the iFrame code
#### Defined in
[mermaidAPI.ts:288](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L288)
[mermaidAPI.ts:285](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L285)
---
@@ -320,4 +320,4 @@ Remove any existing elements from the given document
#### Defined in
[mermaidAPI.ts:359](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L359)
[mermaidAPI.ts:356](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L356)

View File

@@ -59,8 +59,6 @@ They also serve as proof of concept, for the variety of things that can be built
- [hexo-filter-mermaid-diagrams](https://github.com/webappdevelp/hexo-filter-mermaid-diagrams)
- [hexo-tag-mermaid](https://github.com/JameChou/hexo-tag-mermaid)
- [hexo-mermaid-diagrams](https://github.com/mslxl/hexo-mermaid-diagrams)
- [Nextra](https://nextra.site/)
- [Mermaid](https://nextra.site/docs/guide/mermaid)
## CMS

View File

@@ -46,6 +46,9 @@ quadrantChart
## Syntax
> **Note**
> In place of `<text>` you can use text like `this is a sample text` or inside **double quotes** like `"This type of text may contain unicode like ❤"`.
> **Note**
> If there is no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant.
> If there are points **x-axis** labels will rendered from left of the respective quadrant also they will be displayed in bottom of the chart, and **y-axis** lables will be rendered in bottom of the respective quadrant, the quadrant text will render at top of the respective quadrant.
@@ -149,7 +152,7 @@ Points are used to plot a circle inside the quadrantChart. The syntax is `<text>
%%{init: {"quadrantChart": {"chartWidth": 400, "chartHeight": 400}, "themeVariables": {"quadrant1TextFill": "#ff0000"} }}%%
quadrantChart
x-axis Urgent --> Not Urgent
y-axis Not Important --> "Important ❤"
y-axis Not Important --> important
quadrant-1 Plan
quadrant-2 Do
quadrant-3 Deligate
@@ -160,7 +163,7 @@ quadrantChart
%%{init: {"quadrantChart": {"chartWidth": 400, "chartHeight": 400}, "themeVariables": {"quadrant1TextFill": "#ff0000"} }}%%
quadrantChart
x-axis Urgent --> Not Urgent
y-axis Not Important --> "Important ❤"
y-axis Not Important --> important
quadrant-1 Plan
quadrant-2 Do
quadrant-3 Deligate

View File

@@ -1,7 +1,7 @@
{
"name": "mermaid-monorepo",
"private": true,
"version": "10.2.3",
"version": "10.2.0",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"packageManager": "pnpm@8.5.1",

View File

@@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "10.2.3",
"version": "10.2.0",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"module": "./dist/mermaid.core.mjs",
@@ -28,7 +28,7 @@
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && ts-node-esm src/docs.mts",
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && ts-node-esm src/docs.mts --verify",
"docs:pre:vitepress": "rimraf src/vitepress && pnpm docs:code && ts-node-esm src/docs.mts --vitepress",
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm --filter ./ install --no-frozen-lockfile --ignore-scripts && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm --filter ./ install --no-frozen-lockfile && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./ src/vitepress dev\" \"ts-node-esm src/docs.mts --watch --vitepress\"",
"docs:serve": "pnpm docs:build:vitepress && vitepress serve src/vitepress",
"docs:spellcheck": "cspell --config ../../cSpell.json \"src/docs/**/*.md\"",

View File

@@ -20,7 +20,7 @@
* of src to dst in order.
* @param {any} dst - The destination of the merge
* @param {any} src - The source object(s) to merge into destination
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
* @param {{ depth?: number; clobber?: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
* @returns {any}

View File

@@ -1,8 +1,8 @@
import { sanitizeUrl } from '@braintree/sanitize-url';
import dayjs from 'dayjs';
import dayjsIsoWeek from 'dayjs/plugin/isoWeek.js';
import dayjsCustomParseFormat from 'dayjs/plugin/customParseFormat.js';
import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat.js';
import dayjs from 'dayjs/esm/index.js';
import dayjsIsoWeek from 'dayjs/esm/plugin/isoWeek/index.js';
import dayjsCustomParseFormat from 'dayjs/esm/plugin/customParseFormat/index.js';
import dayjsAdvancedFormat from 'dayjs/esm/plugin/advancedFormat/index.js';
import { log } from '../../logger.js';
import * as configApi from '../../config.js';
import utils from '../../utils.js';

View File

@@ -1,5 +1,5 @@
// @ts-nocheck TODO: Fix TS
import dayjs from 'dayjs';
import dayjs from 'dayjs/esm/index.js';
import ganttDb from './ganttDb.js';
import { convert } from '../../tests/util.js';

View File

@@ -1,4 +1,4 @@
import dayjs from 'dayjs';
import dayjs from 'dayjs/esm/index.js';
import { log } from '../../logger.js';
import {
select,

View File

@@ -1,7 +1,7 @@
import common from '../common/common.js';
import * as svgDrawCommon from '../common/svgDrawCommon';
import { addFunction } from '../../interactionDb.js';
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
import { parseFontSize } from '../../utils.js';
import { sanitizeUrl } from '@braintree/sanitize-url';
export const drawRect = function (elem, rectData) {
@@ -224,16 +224,15 @@ export const drawText = function (elem, textData) {
textElem.attr('dy', dy);
}
const text = line || ZERO_WIDTH_SPACE;
if (textData.tspan) {
const span = textElem.append('tspan');
span.attr('x', textData.x);
if (textData.fill !== undefined) {
span.attr('fill', textData.fill);
}
span.text(text);
span.text(line);
} else {
textElem.text(text);
textElem.text(line);
}
if (
textData.valign !== undefined &&

View File

@@ -5,12 +5,12 @@ import { contributors } from '../contributors';
<template>
<div flex="~ wrap gap2" justify-center>
<a
v-for="{ username, avatar } of contributors"
:key="username"
:href="`https://github.com/${username}`"
v-for="{ name, avatar } of contributors"
:key="name"
:href="`https://github.com/${name}`"
m-0
rel="noopener noreferrer"
:aria-label="`${username} on GitHub`"
:aria-label="`${name} on GitHub`"
>
<img
loading="lazy"
@@ -20,7 +20,7 @@ import { contributors } from '../contributors';
rounded-full
h-12
w-12
:alt="`${username}'s avatar`"
:alt="`${name}'s avatar`"
/>
</a>
</div>

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-console */
import { mkdir, writeFile, readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { fileURLToPath } from 'url';
@@ -13,23 +12,22 @@ async function download(url: string, fileName: URL) {
if (existsSync(fileName)) {
return;
}
console.log('downloading', url);
// eslint-disable-next-line no-console
console.log('downloading', fileName);
try {
const image = await fetch(url);
await writeFile(fileName, Buffer.from(await image.arrayBuffer()));
} catch (error) {
console.error(error);
}
} catch {}
}
async function fetchAvatars() {
await mkdir(fileURLToPath(new URL(getAvatarPath('none'))).replace('none.png', ''), {
recursive: true,
});
await mkdir(fileURLToPath(new URL('..', getAvatarPath('none'))), { recursive: true });
contributors = JSON.parse(await readFile(pathContributors, { encoding: 'utf-8' }));
for (const name of contributors) {
await download(`https://github.com/${name}.png?size=100`, getAvatarPath(name));
}
await Promise.allSettled(
contributors.map((name) =>
download(`https://github.com/${name}.png?size=100`, getAvatarPath(name))
)
);
}
fetchAvatars();

View File

@@ -23,8 +23,9 @@ async function fetchContributors() {
}
);
data = await response.json();
console.log(response.status, response.statusText);
console.log(data);
collaborators.push(...data.map((i) => i.login));
console.log(`Fetched page ${page}`);
page++;
} while (data.length === 100);
return collaborators.filter((name) => !name.includes('[bot]'));

File diff suppressed because it is too large Load Diff

View File

@@ -53,8 +53,6 @@ They also serve as proof of concept, for the variety of things that can be built
- [hexo-filter-mermaid-diagrams](https://github.com/webappdevelp/hexo-filter-mermaid-diagrams)
- [hexo-tag-mermaid](https://github.com/JameChou/hexo-tag-mermaid)
- [hexo-mermaid-diagrams](https://github.com/mslxl/hexo-mermaid-diagrams)
- [Nextra](https://nextra.site/)
- [Mermaid](https://nextra.site/docs/guide/mermaid)
## CMS

View File

@@ -23,6 +23,10 @@ quadrantChart
## Syntax
```note
In place of `<text>` you can use text like `this is a sample text` or inside **double quotes** like `"This type of text may contain unicode like ❤"`.
```
```note
If there is no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant.
If there are points **x-axis** labels will rendered from left of the respective quadrant also they will be displayed in bottom of the chart, and **y-axis** lables will be rendered in bottom of the respective quadrant, the quadrant text will render at top of the respective quadrant.
@@ -130,7 +134,7 @@ Points are used to plot a circle inside the quadrantChart. The syntax is `<text>
%%{init: {"quadrantChart": {"chartWidth": 400, "chartHeight": 400}, "themeVariables": {"quadrant1TextFill": "#ff0000"} }}%%
quadrantChart
x-axis Urgent --> Not Urgent
y-axis Not Important --> "Important ❤"
y-axis Not Important --> important
quadrant-1 Plan
quadrant-2 Do
quadrant-3 Deligate

View File

@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable no-console */
import dayjs from 'dayjs';
import dayjs from 'dayjs/esm/index.js';
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';

View File

@@ -263,10 +263,7 @@ export const cleanUpSvgCode = (
// Replace marker-end urls with just the # anchor (remove the preceding part of the URL)
if (!useArrowMarkerUrls && !inSandboxMode) {
cleanedUpSvg = cleanedUpSvg.replace(
/marker-end="url\([\d+./:=?A-Za-z-]*?#/g,
'marker-end="url(#'
);
cleanedUpSvg = cleanedUpSvg.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#');
}
cleanedUpSvg = decodeEntities(cleanedUpSvg);

View File

@@ -78,22 +78,6 @@ function createTspan(textElement, lineIndex, lineHeight) {
.attr('dy', lineHeight + 'em');
}
/**
* Compute the width of rendered text
* @param {object} parentNode
* @param {number} lineHeight
* @param {string} text
* @returns {number}
*/
function computeWidthOfText(parentNode, lineHeight, text) {
const testElement = parentNode.append('text');
const testSpan = createTspan(testElement, 1, lineHeight);
updateTextContentAndStyles(testSpan, [{ content: text, type: 'normal' }]);
const textLength = testSpan.node().getComputedTextLength();
testElement.remove();
return textLength;
}
/**
* Creates a formatted text element by breaking lines and applying styles based on
* the given structuredText.
@@ -111,44 +95,31 @@ function createFormattedText(width, g, structuredText, addBackground = false) {
// .attr('dominant-baseline', 'middle')
// .attr('text-anchor', 'middle');
// .attr('text-anchor', 'middle');
let lineIndex = 0;
let lineIndex = -1;
structuredText.forEach((line) => {
/**
* Preprocess raw string content of line data
* Creating an array of strings pre-split to satisfy width limit
*/
let fullStr = line.map((data) => data.content).join(' ');
let tempStr = '';
let linesUnderWidth = [];
let prevIndex = 0;
if (computeWidthOfText(labelGroup, lineHeight, fullStr) <= width) {
linesUnderWidth.push(fullStr);
} else {
for (let i = 0; i <= fullStr.length; i++) {
tempStr = fullStr.slice(prevIndex, i);
log.info(tempStr, prevIndex, i);
if (computeWidthOfText(labelGroup, lineHeight, tempStr) > width) {
const subStr = fullStr.slice(prevIndex, i);
// Break at space if any
const lastSpaceIndex = subStr.lastIndexOf(' ');
if (lastSpaceIndex > -1) {
i = prevIndex + lastSpaceIndex + 1;
}
linesUnderWidth.push(fullStr.slice(prevIndex, i).trim());
prevIndex = i;
tempStr = null;
}
lineIndex++;
let tspan = createTspan(textElement, lineIndex, lineHeight);
let words = [...line].reverse();
let currentWord;
let wrappedLine = [];
while (words.length) {
currentWord = words.pop();
wrappedLine.push(currentWord);
updateTextContentAndStyles(tspan, wrappedLine);
if (tspan.node().getComputedTextLength() > width) {
wrappedLine.pop();
words.push(currentWord);
updateTextContentAndStyles(tspan, wrappedLine);
wrappedLine = [];
lineIndex++;
tspan = createTspan(textElement, lineIndex, lineHeight);
}
if (tempStr != null) {
linesUnderWidth.push(tempStr);
}
}
/** Add each prepared line as a tspan to the parent node */
const preparedLines = linesUnderWidth.map((w) => ({ content: w, type: line.type }));
for (const preparedLine of preparedLines) {
let tspan = createTspan(textElement, lineIndex, lineHeight);
updateTextContentAndStyles(tspan, [preparedLine]);
lineIndex++;
}
});
if (addBackground) {

View File

@@ -133,6 +133,7 @@ export class MockedD3 {
// --------------------------------------------------------------------------------
// The following functions are here for completeness. They simply return a vi.fn()
remove = vi.fn();
insertBefore = vi.fn();
curveBasis = vi.fn();
curveBasisClosed = vi.fn();

View File

@@ -1,4 +1,4 @@
import { vi } from 'vitest';
import { vi, describe, it, expect } from 'vitest';
import utils from './utils.js';
import assignWithDepth from './assignWithDepth.js';
import { detectType } from './diagram-api/detectType.js';
@@ -10,51 +10,51 @@ addDiagrams();
describe('when assignWithDepth: should merge objects within objects', function () {
it('should handle simple, depth:1 types (identity)', function () {
let config_0 = { foo: 'bar', bar: 0 };
let config_1 = { foo: 'bar', bar: 0 };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: 0 };
const config_1 = { foo: 'bar', bar: 0 };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual(config_1);
});
it('should handle simple, depth:1 types (dst: undefined)', function () {
let config_0 = undefined;
let config_1 = { foo: 'bar', bar: 0 };
let result = assignWithDepth(config_0, config_1);
const config_0 = undefined;
const config_1 = { foo: 'bar', bar: 0 };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual(config_1);
});
it('should handle simple, depth:1 types (src: undefined)', function () {
let config_0 = { foo: 'bar', bar: 0 };
let config_1 = undefined;
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: 0 };
const config_1 = undefined;
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual(config_0);
});
it('should handle simple, depth:1 types (merge)', function () {
let config_0 = { foo: 'bar', bar: 0 };
let config_1 = { foo: 'foo' };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: 0 };
const config_1 = { foo: 'foo' };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual({ foo: 'foo', bar: 0 });
});
it('should handle depth:2 types (dst: orphan)', function () {
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
let config_1 = { foo: 'bar' };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: { foo: 'bar' } };
const config_1 = { foo: 'bar' };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual(config_0);
});
it('should handle depth:2 types (dst: object, src: simple type)', function () {
let config_0 = { foo: 'bar', bar: { foo: 'bar' } };
let config_1 = { foo: 'foo', bar: 'should NOT clobber' };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: { foo: 'bar' } };
const config_1 = { foo: 'foo', bar: 'should NOT clobber' };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual({ foo: 'foo', bar: { foo: 'bar' } });
});
it('should handle depth:2 types (src: orphan)', function () {
let config_0 = { foo: 'bar' };
let config_1 = { foo: 'bar', bar: { foo: 'bar' } };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar' };
const config_1 = { foo: 'bar', bar: { foo: 'bar' } };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual(config_1);
});
it('should handle depth:2 types (merge)', function () {
let config_0 = { foo: 'bar', bar: { foo: 'bar' }, boofar: 1 };
let config_1 = { foo: 'foo', bar: { bar: 0 }, foobar: 'foobar' };
let result = assignWithDepth(config_0, config_1);
const config_0 = { foo: 'bar', bar: { foo: 'bar' }, boofar: 1 };
const config_1 = { foo: 'foo', bar: { bar: 0 }, foobar: 'foobar' };
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual({
foo: 'foo',
bar: { foo: 'bar', bar: 0 },
@@ -63,17 +63,17 @@ describe('when assignWithDepth: should merge objects within objects', function (
});
});
it('should handle depth:3 types (merge with clobber because assignWithDepth::depth == 2)', function () {
let config_0 = {
const config_0 = {
foo: 'bar',
bar: { foo: 'bar', bar: { foo: { message: 'this', willbe: 'clobbered' } } },
boofar: 1,
};
let config_1 = {
const config_1 = {
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
foobar: 'foobar',
};
let result = assignWithDepth(config_0, config_1);
const result = assignWithDepth(config_0, config_1);
expect(result).toEqual({
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'clobbered other foo' } } },
@@ -82,7 +82,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
});
});
it('should handle depth:3 types (merge with clobber because assignWithDepth::depth == 1)', function () {
let config_0 = {
const config_0 = {
foo: 'bar',
bar: {
foo: 'bar',
@@ -90,12 +90,12 @@ describe('when assignWithDepth: should merge objects within objects', function (
},
boofar: 1,
};
let config_1 = {
const config_1 = {
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
foobar: 'foobar',
};
let result = assignWithDepth(config_0, config_1, { depth: 1 });
const result = assignWithDepth(config_0, config_1, { depth: 1 });
expect(result).toEqual({
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
@@ -104,17 +104,17 @@ describe('when assignWithDepth: should merge objects within objects', function (
});
});
it('should handle depth:3 types (merge with no clobber because assignWithDepth::depth == 3)', function () {
let config_0 = {
const config_0 = {
foo: 'bar',
bar: { foo: 'bar', bar: { foo: { message: '', willbe: 'present' } } },
boofar: 1,
};
let config_1 = {
const config_1 = {
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'this' } } },
foobar: 'foobar',
};
let result = assignWithDepth(config_0, config_1, { depth: 3 });
const result = assignWithDepth(config_0, config_1, { depth: 3 });
expect(result).toEqual({
foo: 'foo',
bar: { foo: 'foo', bar: { foo: { message: 'this', willbe: 'present' } } },
@@ -125,7 +125,7 @@ describe('when assignWithDepth: should merge objects within objects', function (
});
describe('when memoizing', function () {
it('should return the same value', function () {
const fib = memoize(
const fib: (n: number, x: unknown, canary: { flag: boolean }) => number = memoize(
function (n, x, canary) {
canary.flag = true;
if (n < 2) {
@@ -260,7 +260,7 @@ describe('when formatting urls', function () {
it('should handle links', function () {
const url = 'https://mermaid-js.github.io/mermaid/#/';
let config = { securityLevel: 'loose' };
const config = { securityLevel: 'loose' };
let result = utils.formatUrl(url, config);
expect(result).toEqual(url);
@@ -271,7 +271,7 @@ describe('when formatting urls', function () {
it('should handle anchors', function () {
const url = '#interaction';
let config = { securityLevel: 'loose' };
const config = { securityLevel: 'loose' };
let result = utils.formatUrl(url, config);
expect(result).toEqual(url);
@@ -282,7 +282,7 @@ describe('when formatting urls', function () {
it('should handle mailto', function () {
const url = 'mailto:user@user.user';
let config = { securityLevel: 'loose' };
const config = { securityLevel: 'loose' };
let result = utils.formatUrl(url, config);
expect(result).toEqual(url);
@@ -293,7 +293,7 @@ describe('when formatting urls', function () {
it('should handle other protocols', function () {
const url = 'notes://do-your-thing/id';
let config = { securityLevel: 'loose' };
const config = { securityLevel: 'loose' };
let result = utils.formatUrl(url, config);
expect(result).toEqual(url);
@@ -304,7 +304,7 @@ describe('when formatting urls', function () {
it('should handle scripts', function () {
const url = 'javascript:alert("test")';
let config = { securityLevel: 'loose' };
const config = { securityLevel: 'loose' };
let result = utils.formatUrl(url, config);
expect(result).toEqual(url);
@@ -425,6 +425,7 @@ describe('when parsing font sizes', function () {
});
it('handles unparseable input', function () {
// @ts-expect-error This is testing an invalid case
expect(utils.parseFontSize({ fontSize: 14 })).toEqual([undefined, undefined]);
});
});

View File

@@ -32,8 +32,6 @@ import assignWithDepth from './assignWithDepth.js';
import { MermaidConfig } from './config.type.js';
import memoize from 'lodash-es/memoize.js';
export const ZERO_WIDTH_SPACE = '\u200b';
// Effectively an enum of the supported curve types, accessible by name
const d3CurveTypes = {
curveBasis: curveBasis,
@@ -767,7 +765,7 @@ export const calculateTextDimensions: (
const dim = { width: 0, height: 0, lineHeight: 0 };
for (const line of lines) {
const textObj = getTextObj();
textObj.text = line || ZERO_WIDTH_SPACE;
textObj.text = line;
const textElem = drawSimpleText(g, textObj)
.style('font-size', _fontSizePx)
.style('font-weight', fontWeight)
@@ -802,7 +800,7 @@ export const calculateTextDimensions: (
);
export const initIdGenerator = class iterator {
constructor(deterministic, seed) {
constructor(deterministic: boolean, seed?: string) {
this.deterministic = deterministic;
// TODO: Seed is only used for length?
this.seed = seed;

94
pnpm-lock.yaml generated
View File

@@ -435,6 +435,58 @@ importers:
specifier: ^6.5.4
version: 6.5.4
packages/mermaid/src/vitepress:
dependencies:
'@vueuse/core':
specifier: ^10.1.0
version: 10.1.0(vue@3.2.47)
jiti:
specifier: ^1.18.2
version: 1.18.2
vue:
specifier: ^3.2.47
version: 3.2.47
devDependencies:
'@iconify-json/carbon':
specifier: ^1.1.16
version: 1.1.16
'@unocss/reset':
specifier: ^0.52.0
version: 0.52.0
'@vite-pwa/vitepress':
specifier: ^0.0.5
version: 0.0.5(vite-plugin-pwa@0.15.0)
'@vitejs/plugin-vue':
specifier: ^4.2.1
version: 4.2.1(vite@4.3.3)(vue@3.2.47)
fast-glob:
specifier: ^3.2.12
version: 3.2.12
https-localhost:
specifier: ^4.7.1
version: 4.7.1
pathe:
specifier: ^1.1.0
version: 1.1.0
unocss:
specifier: ^0.52.0
version: 0.52.0(postcss@8.4.23)(rollup@2.79.1)(vite@4.3.3)
unplugin-vue-components:
specifier: ^0.24.1
version: 0.24.1(rollup@2.79.1)(vue@3.2.47)
vite:
specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.0)
vite-plugin-pwa:
specifier: ^0.15.0
version: 0.15.0(vite@4.3.3)(workbox-build@6.5.4)(workbox-window@6.5.4)
vitepress:
specifier: 1.0.0-alpha.76
version: 1.0.0-alpha.76(@algolia/client-search@4.14.2)(@types/node@18.16.0)
workbox-window:
specifier: ^6.5.4
version: 6.5.4
tests/webpack:
dependencies:
'@mermaid-js/mermaid-example-diagram':
@@ -14605,6 +14657,48 @@ packages:
- terser
dev: true
/vitepress@1.0.0-alpha.76(@algolia/client-search@4.14.2)(@types/node@18.16.0):
resolution: {integrity: sha512-fzR1pDpGnSMeCJ+AnDdMe/ETD2G0Go+g6mTxDv9ps7Hmr1JjVqw97nasCyZg3jgfQxi2nt78EJ/bw7hY5n/rlw==}
hasBin: true
dependencies:
'@docsearch/css': 3.3.5
'@docsearch/js': 3.3.5(@algolia/client-search@4.14.2)
'@vitejs/plugin-vue': 4.2.3(vite@4.3.8)(vue@3.3.4)
'@vue/devtools-api': 6.5.0
'@vueuse/core': 10.1.2(vue@3.3.4)
'@vueuse/integrations': 10.1.2(focus-trap@7.4.3)(vue@3.3.4)
body-scroll-lock: 4.0.0-beta.0
focus-trap: 7.4.3
mark.js: 8.11.1
minisearch: 6.1.0
shiki: 0.14.2
vite: 4.3.8(@types/node@18.16.0)
vue: 3.3.4
transitivePeerDependencies:
- '@algolia/client-search'
- '@types/node'
- '@types/react'
- '@vue/composition-api'
- async-validator
- axios
- change-case
- drauu
- fuse.js
- idb-keyval
- jwt-decode
- less
- nprogress
- qrcode
- react
- react-dom
- sass
- sortablejs
- stylus
- sugarss
- terser
- universal-cookie
dev: true
/vitepress@1.0.0-beta.1(@algolia/client-search@4.14.2)(@types/node@18.16.0):
resolution: {integrity: sha512-V2yyCwQ+v9fh7rbnGDLp8M7vHa9sLElexXf/JHtBOsOwv7ed9wt1QI4WUagYgKR3TeoJT9v2s6f0UaQSne0EvQ==}
hasBin: true