mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-23 02:06:45 +02:00
Compare commits
42 Commits
test-valid
...
mermaid@11
Author | SHA1 | Date | |
---|---|---|---|
![]() |
767754f4fb | ||
![]() |
cff59c58b4 | ||
![]() |
5b241bbb97 | ||
![]() |
7e5e47843b | ||
![]() |
9e2cd1a926 | ||
![]() |
abf2227faf | ||
![]() |
7db942b0e1 | ||
![]() |
70041c806f | ||
![]() |
77e2703f72 | ||
![]() |
771801b366 | ||
![]() |
a9a0a9b2de | ||
![]() |
1e5e835c41 | ||
![]() |
1f3f8da0f7 | ||
![]() |
b11f40e8ce | ||
![]() |
1fe045e638 | ||
![]() |
1c750ffc70 | ||
![]() |
b0ec93f29c | ||
![]() |
6b071c135a | ||
![]() |
42a3c3487f | ||
![]() |
d7b8ed2c5a | ||
![]() |
96c21c7e54 | ||
![]() |
e95e4d155a | ||
![]() |
688170558c | ||
![]() |
832f012e10 | ||
![]() |
2e2e8c4152 | ||
![]() |
6ff6e08c4b | ||
![]() |
d3e2be35be | ||
![]() |
260a045da0 | ||
![]() |
a28965064d | ||
![]() |
34e91f8b65 | ||
![]() |
627ee1f34d | ||
![]() |
28840ebd84 | ||
![]() |
4145879003 | ||
![]() |
e097b480d5 | ||
![]() |
12e3d31437 | ||
![]() |
ad024b01d6 | ||
![]() |
c12aea588c | ||
![]() |
9dfbf1166d | ||
![]() |
d90634bf2b | ||
![]() |
90707e8062 | ||
![]() |
7e23f984e6 | ||
![]() |
12c94a177b |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add `getRegisteredDiagramsMetadata` to `mermaid`, which returns all the registered diagram IDs in mermaid
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@mermaid-js/examples': minor
|
||||
---
|
||||
|
||||
feat: Add examples for diagrams in the `@mermaid-js/examples` package
|
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'@mermaid-js/examples': patch
|
||||
'mermaid': patch
|
||||
'@mermaid-js/parser': patch
|
||||
---
|
||||
|
||||
chore: Move packet diagram out of beta
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: adjust sequence diagram title positioning to prevent overlap with top border in Safari
|
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix(timeline): fix loading `leftMargin` from config
|
||||
|
||||
The `timeline.leftMargin` config value should now correctly control the size of the left margin, instead of being ignored.
|
3
.github/lychee.toml
vendored
3
.github/lychee.toml
vendored
@@ -52,6 +52,9 @@ exclude = [
|
||||
# Swimm returns 404, even though the link is valid
|
||||
"https://docs.swimm.io",
|
||||
|
||||
# Certificate Error
|
||||
"https://noteshub.app",
|
||||
|
||||
# Timeout
|
||||
"https://huehive.co",
|
||||
"https://foswiki.org",
|
||||
|
@@ -1,13 +0,0 @@
|
||||
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
|
||||
|
||||
export const select = function () {
|
||||
return new MockedD3();
|
||||
};
|
||||
|
||||
export const selectAll = function () {
|
||||
return new MockedD3();
|
||||
};
|
||||
|
||||
export const curveBasis = 'basis';
|
||||
export const curveLinear = 'linear';
|
||||
export const curveCardinal = 'cardinal';
|
@@ -301,7 +301,7 @@ If you are adding a feature, you will definitely need to add tests. Depending on
|
||||
|
||||
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
|
||||
|
||||
Unit tests are mandatory for all code except the renderers. (The renderers are tested with integration tests.)
|
||||
Unit tests are mandatory for all code except the layout tests. (The layouts are tested with integration tests.)
|
||||
|
||||
We use [Vitest](https://vitest.dev) to run unit tests.
|
||||
|
||||
@@ -327,6 +327,30 @@ When using Docker prepend your command with `./run`:
|
||||
./run pnpm test
|
||||
```
|
||||
|
||||
##### Testing the DOM
|
||||
|
||||
One can use `jsdomIt` to test any part of Mermaid that interacts with the DOM, as long as it is not related to the layout.
|
||||
|
||||
The function `jsdomIt` ([developed in utils.ts](../../tests/util.ts)) overrides `it` from `vitest`, and creates a pseudo-browser environment that works almost like the real deal for the duration of the test. It uses JSDOM to create a DOM, and adds objects `window` and `document` to `global` to mock the browser environment.
|
||||
|
||||
> \[!NOTE]
|
||||
> The layout cannot work in `jsdomIt` tests because JSDOM has no rendering engine, hence the pseudo-browser environment.
|
||||
|
||||
Example :
|
||||
|
||||
```typescript
|
||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
|
||||
|
||||
jsdomIt('should add element "thing" in the SVG', ({ svg }) => {
|
||||
// Code in this block runs in a pseudo-browser environment
|
||||
addThing(svg); // The svg item is the D3 selection of the SVG node
|
||||
const svgNode = ensureNodeFromSelector('svg'); // Retrieve the DOM node using the DOM API
|
||||
expect(svgNode.querySelector('thing')).not.toBeNull(); // Test the structure of the SVG
|
||||
});
|
||||
```
|
||||
|
||||
They can be used to test any method that interacts with the DOM, including for testing renderers. For renderers, additional integration testing is necessary to test the layout though.
|
||||
|
||||
#### Integration / End-to-End (E2E) Tests
|
||||
|
||||
These test the rendering and visual appearance of the diagrams.
|
||||
|
@@ -83,7 +83,7 @@
|
||||
"@vitest/spy": "^3.0.6",
|
||||
"@vitest/ui": "^3.0.6",
|
||||
"ajv": "^8.17.1",
|
||||
"chokidar": "4.0.3",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"cpy-cli": "^5.0.0",
|
||||
@@ -112,7 +112,7 @@
|
||||
"jest": "^30.0.4",
|
||||
"jison": "^0.4.18",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"langium-cli": "3.3.0",
|
||||
"lint-staged": "^16.1.2",
|
||||
"markdown-table": "^3.0.4",
|
||||
@@ -139,8 +139,13 @@
|
||||
"roughjs": "patches/roughjs.patch"
|
||||
},
|
||||
"onlyBuiltDependencies": [
|
||||
"canvas",
|
||||
"cypress",
|
||||
"esbuild"
|
||||
],
|
||||
"ignoredBuiltDependencies": [
|
||||
"sharp",
|
||||
"vue-demi"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
14
packages/examples/CHANGELOG.md
Normal file
14
packages/examples/CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# @mermaid-js/examples
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6453](https://github.com/mermaid-js/mermaid/pull/6453) [`4936ef5`](https://github.com/mermaid-js/mermaid/commit/4936ef5c306d2f892cca9a95a5deac4af6d4882b) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add examples for diagrams in the `@mermaid-js/examples` package
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6510](https://github.com/mermaid-js/mermaid/pull/6510) [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move packet diagram out of beta
|
||||
|
||||
- Updated dependencies [[`5acbd7e`](https://github.com/mermaid-js/mermaid/commit/5acbd7e762469d9d89a9c77faf6617ee13367f3a), [`d90634b`](https://github.com/mermaid-js/mermaid/commit/d90634bf2b09e586b055729e07e9a1a31b21827c), [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6), [`3e3ae08`](https://github.com/mermaid-js/mermaid/commit/3e3ae089305e1c7b9948b9e149eba6854fe7f2d6), [`d3e2be3`](https://github.com/mermaid-js/mermaid/commit/d3e2be35be066adeb7fd502b4a24c223c3b53947), [`637680d`](https://github.com/mermaid-js/mermaid/commit/637680d4d9e39b4f8cb6f05b4cb261e8f5693ac3)]:
|
||||
- mermaid@11.9.0
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/examples",
|
||||
"version": "0.0.1-beta.1",
|
||||
"version": "1.0.0",
|
||||
"description": "Mermaid examples package",
|
||||
"author": "Sidharth Vinod",
|
||||
"type": "module",
|
||||
|
@@ -1,5 +1,28 @@
|
||||
# mermaid
|
||||
|
||||
## 11.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6453](https://github.com/mermaid-js/mermaid/pull/6453) [`5acbd7e`](https://github.com/mermaid-js/mermaid/commit/5acbd7e762469d9d89a9c77faf6617ee13367f3a) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add `getRegisteredDiagramsMetadata` to `mermaid`, which returns all the registered diagram IDs in mermaid
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6738](https://github.com/mermaid-js/mermaid/pull/6738) [`d90634b`](https://github.com/mermaid-js/mermaid/commit/d90634bf2b09e586b055729e07e9a1a31b21827c) Thanks [@shubham-mermaid](https://github.com/shubham-mermaid)! - chore: Updated TreeMapDB to use class based approach
|
||||
|
||||
- [#6510](https://github.com/mermaid-js/mermaid/pull/6510) [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move packet diagram out of beta
|
||||
|
||||
- [#6747](https://github.com/mermaid-js/mermaid/pull/6747) [`3e3ae08`](https://github.com/mermaid-js/mermaid/commit/3e3ae089305e1c7b9948b9e149eba6854fe7f2d6) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: adjust sequence diagram title positioning to prevent overlap with top border in Safari
|
||||
|
||||
- [#6751](https://github.com/mermaid-js/mermaid/pull/6751) [`d3e2be3`](https://github.com/mermaid-js/mermaid/commit/d3e2be35be066adeb7fd502b4a24c223c3b53947) Thanks [@darshanr0107](https://github.com/darshanr0107)! - chore: Update MindmapDB to use class based approach
|
||||
|
||||
- [#6715](https://github.com/mermaid-js/mermaid/pull/6715) [`637680d`](https://github.com/mermaid-js/mermaid/commit/637680d4d9e39b4f8cb6f05b4cb261e8f5693ac3) Thanks [@Syn3ugar](https://github.com/Syn3ugar)! - fix(timeline): fix loading `leftMargin` from config
|
||||
|
||||
The `timeline.leftMargin` config value should now correctly control the size of the left margin, instead of being ignored.
|
||||
|
||||
- Updated dependencies [[`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6)]:
|
||||
- @mermaid-js/parser@0.6.2
|
||||
|
||||
## 11.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.8.1",
|
||||
"version": "11.9.0",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -79,7 +79,7 @@
|
||||
"dagre-d3-es": "7.0.11",
|
||||
"dayjs": "^1.11.13",
|
||||
"dompurify": "^3.2.5",
|
||||
"katex": "^0.16.9",
|
||||
"katex": "^0.16.22",
|
||||
"khroma": "^2.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"marked": "^16.0.0",
|
||||
@@ -105,13 +105,14 @@
|
||||
"@types/stylis": "^4.2.7",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"ajv": "^8.17.1",
|
||||
"chokidar": "4.0.3",
|
||||
"canvas": "^3.1.0",
|
||||
"chokidar": "3.6.0",
|
||||
"concurrently": "^9.1.2",
|
||||
"csstree-validator": "^4.0.1",
|
||||
"globby": "^14.0.2",
|
||||
"jison": "^0.4.18",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsdom": "^26.0.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"micromatch": "^4.0.8",
|
||||
"path-browserify": "^1.0.1",
|
||||
|
@@ -1,28 +1,25 @@
|
||||
import { MockedD3 } from './tests/MockedD3.js';
|
||||
import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';
|
||||
import type { D3Element } from './types.js';
|
||||
import { addSVGa11yTitleDescription, setA11yDiagramInfo } from './accessibility.js';
|
||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
|
||||
import { expect } from 'vitest';
|
||||
|
||||
describe('accessibility', () => {
|
||||
const fauxSvgNode: MockedD3 = new MockedD3();
|
||||
|
||||
describe('setA11yDiagramInfo', () => {
|
||||
it('should set svg element role to "graphics-document document"', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('role', 'graphics-document document');
|
||||
jsdomIt('should set svg element role to "graphics-document document"', ({ svg }) => {
|
||||
setA11yDiagramInfo(svg, 'flowchart');
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('role')).toBe('graphics-document document');
|
||||
});
|
||||
|
||||
it('should set aria-roledescription to the diagram type', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-roledescription', 'flowchart');
|
||||
jsdomIt('should set aria-roledescription to the diagram type', ({ svg }) => {
|
||||
setA11yDiagramInfo(svg, 'flowchart');
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-roledescription')).toBe('flowchart');
|
||||
});
|
||||
|
||||
it('should not set aria-roledescription if the diagram type is empty', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
setA11yDiagramInfo(fauxSvgNode, '');
|
||||
expect(svgAttrSpy).toHaveBeenCalledTimes(1);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('role', expect.anything()); // only called to set the role
|
||||
jsdomIt('should not set aria-roledescription if the diagram type is empty', ({ svg }) => {
|
||||
setA11yDiagramInfo(svg, '');
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-roledescription')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,115 +36,78 @@ describe('accessibility', () => {
|
||||
expect(noInsertAttrSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// convenience functions to DRY up the spec
|
||||
|
||||
function expectAriaLabelledByItTitleId(
|
||||
svgD3Node: D3Element,
|
||||
title: string | undefined,
|
||||
desc: string | undefined,
|
||||
givenId: string
|
||||
): void {
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
|
||||
}
|
||||
|
||||
function expectAriaDescribedByItDescId(
|
||||
svgD3Node: D3Element,
|
||||
title: string | undefined,
|
||||
desc: string | undefined,
|
||||
givenId: string
|
||||
): void {
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
|
||||
}
|
||||
|
||||
function a11yTitleTagInserted(
|
||||
svgD3Node: D3Element,
|
||||
title: string | undefined,
|
||||
desc: string | undefined,
|
||||
givenId: string,
|
||||
callNumber: number
|
||||
): void {
|
||||
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'title', title);
|
||||
}
|
||||
|
||||
function a11yDescTagInserted(
|
||||
svgD3Node: D3Element,
|
||||
title: string | undefined,
|
||||
desc: string | undefined,
|
||||
givenId: string,
|
||||
callNumber: number
|
||||
): void {
|
||||
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'desc', desc);
|
||||
}
|
||||
|
||||
function a11yTagInserted(
|
||||
_svgD3Node: D3Element,
|
||||
title: string | undefined,
|
||||
desc: string | undefined,
|
||||
givenId: string,
|
||||
callNumber: number,
|
||||
expectedPrefix: string,
|
||||
expectedText: string | undefined
|
||||
): void {
|
||||
const fauxInsertedD3: MockedD3 = new MockedD3();
|
||||
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxInsertedD3);
|
||||
const titleAttrSpy = vi.spyOn(fauxInsertedD3, 'attr').mockReturnValue(fauxInsertedD3);
|
||||
const titleTextSpy = vi.spyOn(fauxInsertedD3, 'text');
|
||||
|
||||
addSVGa11yTitleDescription(fauxSvgNode, title, desc, givenId);
|
||||
expect(svginsertpy).toHaveBeenCalledWith(expectedPrefix, ':first-child');
|
||||
expect(titleAttrSpy).toHaveBeenCalledWith('id', `chart-${expectedPrefix}-${givenId}`);
|
||||
expect(titleTextSpy).toHaveBeenNthCalledWith(callNumber, expectedText);
|
||||
}
|
||||
|
||||
describe('with a11y title', () => {
|
||||
const a11yTitle = 'a11y title';
|
||||
|
||||
describe('with a11y description', () => {
|
||||
const a11yDesc = 'a11y description';
|
||||
|
||||
it('should set aria-labelledby to the title id inserted as a child', () => {
|
||||
expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`);
|
||||
});
|
||||
|
||||
it('should set aria-describedby to the description id inserted as a child', () => {
|
||||
expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
});
|
||||
jsdomIt(
|
||||
'should set aria-describedby to the description id inserted as a child',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`);
|
||||
}
|
||||
);
|
||||
|
||||
it('should insert title tag as the first child with the text set to the accTitle given', () => {
|
||||
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 2);
|
||||
});
|
||||
jsdomIt(
|
||||
'should insert title tag as the first child with the text set to the accTitle given',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const titleNode = ensureNodeFromSelector('title', svgNode);
|
||||
expect(titleNode?.innerHTML).toBe(a11yTitle);
|
||||
}
|
||||
);
|
||||
|
||||
it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
|
||||
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||
});
|
||||
jsdomIt(
|
||||
'should insert desc tag as the 2nd child with the text set to accDescription given',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const descNode = ensureNodeFromSelector('desc', svgNode);
|
||||
expect(descNode?.innerHTML).toBe(a11yDesc);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe(`without a11y description`, () => {
|
||||
describe(`without a11y description`, {}, () => {
|
||||
const a11yDesc = undefined;
|
||||
|
||||
it('should set aria-labelledby to the title id inserted as a child', () => {
|
||||
expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`);
|
||||
});
|
||||
|
||||
it('should not set aria-describedby', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
||||
jsdomIt('should not set aria-describedby', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-describedby')).toBeNull();
|
||||
});
|
||||
|
||||
it('should insert title tag as the first child with the text set to the accTitle given', () => {
|
||||
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||
});
|
||||
jsdomIt(
|
||||
'should insert title tag as the first child with the text set to the accTitle given',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const titleNode = ensureNodeFromSelector('title', svgNode);
|
||||
expect(titleNode?.innerHTML).toBe(a11yTitle);
|
||||
}
|
||||
);
|
||||
|
||||
it('should not insert description tag', () => {
|
||||
const fauxTitle: MockedD3 = new MockedD3();
|
||||
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
||||
jsdomIt('should not insert description tag', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const descNode = svgNode.querySelector('desc');
|
||||
expect(descNode).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -158,55 +118,66 @@ describe('accessibility', () => {
|
||||
describe('with a11y description', () => {
|
||||
const a11yDesc = 'a11y description';
|
||||
|
||||
it('should not set aria-labelledby', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
||||
jsdomIt('should not set aria-labelledby', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-labelledby')).toBeNull();
|
||||
});
|
||||
|
||||
it('should not insert title tag', () => {
|
||||
const fauxTitle: MockedD3 = new MockedD3();
|
||||
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
|
||||
jsdomIt('should not insert title tag', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const titleNode = svgNode.querySelector('title');
|
||||
expect(titleNode).toBeNull();
|
||||
});
|
||||
|
||||
it('should set aria-describedby to the description id inserted as a child', () => {
|
||||
expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
});
|
||||
jsdomIt(
|
||||
'should set aria-describedby to the description id inserted as a child',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`);
|
||||
}
|
||||
);
|
||||
|
||||
it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
|
||||
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||
});
|
||||
jsdomIt(
|
||||
'should insert desc tag as the 2nd child with the text set to accDescription given',
|
||||
({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const descNode = ensureNodeFromSelector('desc', svgNode);
|
||||
expect(descNode?.innerHTML).toBe(a11yDesc);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('without a11y description', () => {
|
||||
const a11yDesc = undefined;
|
||||
|
||||
it('should not set aria-labelledby', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
||||
jsdomIt('should not set aria-labelledby', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-labelledby')).toBeNull();
|
||||
});
|
||||
|
||||
it('should not set aria-describedby', () => {
|
||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
||||
jsdomIt('should not set aria-describedby', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
expect(svgNode.getAttribute('aria-describedby')).toBeNull();
|
||||
});
|
||||
|
||||
it('should not insert title tag', () => {
|
||||
const fauxTitle: MockedD3 = new MockedD3();
|
||||
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
|
||||
jsdomIt('should not insert title tag', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const titleNode = svgNode.querySelector('title');
|
||||
expect(titleNode).toBeNull();
|
||||
});
|
||||
|
||||
it('should not insert description tag', () => {
|
||||
const fauxDesc: MockedD3 = new MockedD3();
|
||||
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxDesc);
|
||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||
expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
||||
jsdomIt('should not insert description tag', ({ svg }) => {
|
||||
addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId);
|
||||
const svgNode = ensureNodeFromSelector('svg');
|
||||
const descNode = svgNode.querySelector('desc');
|
||||
expect(descNode).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -379,6 +379,15 @@ function layoutArchitecture(
|
||||
},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
name: 'grid',
|
||||
boundingBox: {
|
||||
x1: 0,
|
||||
x2: 100,
|
||||
y1: 0,
|
||||
y2: 100,
|
||||
},
|
||||
},
|
||||
});
|
||||
// Remove element after layout
|
||||
renderEl.remove();
|
||||
|
@@ -1,12 +1,14 @@
|
||||
// @ts-ignore: JISON doesn't support types
|
||||
import parser from './parser/mindmap.jison';
|
||||
import db from './mindmapDb.js';
|
||||
import { MindmapDB } from './mindmapDb.js';
|
||||
import renderer from './mindmapRenderer.js';
|
||||
import styles from './styles.js';
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
db,
|
||||
get db() {
|
||||
return new MindmapDB();
|
||||
},
|
||||
renderer,
|
||||
parser,
|
||||
styles,
|
||||
|
@@ -1,12 +1,12 @@
|
||||
// @ts-expect-error No types available for JISON
|
||||
import { parser as mindmap } from './parser/mindmap.jison';
|
||||
import mindmapDB from './mindmapDb.js';
|
||||
import { MindmapDB } from './mindmapDb.js';
|
||||
// Todo fix utils functions for tests
|
||||
import { setLogLevel } from '../../diagram-api/diagramAPI.js';
|
||||
|
||||
describe('when parsing a mindmap ', function () {
|
||||
beforeEach(function () {
|
||||
mindmap.yy = mindmapDB;
|
||||
mindmap.yy = new MindmapDB();
|
||||
mindmap.yy.clear();
|
||||
setLogLevel('trace');
|
||||
});
|
||||
|
@@ -5,70 +5,6 @@ import { log } from '../../logger.js';
|
||||
import type { MindmapNode } from './mindmapTypes.js';
|
||||
import defaultConfig from '../../defaultConfig.js';
|
||||
|
||||
let nodes: MindmapNode[] = [];
|
||||
let cnt = 0;
|
||||
let elements: Record<number, D3Element> = {};
|
||||
|
||||
const clear = () => {
|
||||
nodes = [];
|
||||
cnt = 0;
|
||||
elements = {};
|
||||
};
|
||||
|
||||
const getParent = function (level: number) {
|
||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||
if (nodes[i].level < level) {
|
||||
return nodes[i];
|
||||
}
|
||||
}
|
||||
// No parent found
|
||||
return null;
|
||||
};
|
||||
|
||||
const getMindmap = () => {
|
||||
return nodes.length > 0 ? nodes[0] : null;
|
||||
};
|
||||
|
||||
const addNode = (level: number, id: string, descr: string, type: number) => {
|
||||
log.info('addNode', level, id, descr, type);
|
||||
const conf = getConfig();
|
||||
let padding: number = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
|
||||
switch (type) {
|
||||
case nodeType.ROUNDED_RECT:
|
||||
case nodeType.RECT:
|
||||
case nodeType.HEXAGON:
|
||||
padding *= 2;
|
||||
}
|
||||
|
||||
const node = {
|
||||
id: cnt++,
|
||||
nodeId: sanitizeText(id, conf),
|
||||
level,
|
||||
descr: sanitizeText(descr, conf),
|
||||
type,
|
||||
children: [],
|
||||
width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
|
||||
padding,
|
||||
} satisfies MindmapNode;
|
||||
|
||||
const parent = getParent(level);
|
||||
if (parent) {
|
||||
parent.children.push(node);
|
||||
// Keep all nodes in the list
|
||||
nodes.push(node);
|
||||
} else {
|
||||
if (nodes.length === 0) {
|
||||
// First node, the root
|
||||
nodes.push(node);
|
||||
} else {
|
||||
// Syntax error ... there can only bee one root
|
||||
throw new Error(
|
||||
'There can be only one root. No parent could be found for ("' + node.descr + '")'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const nodeType = {
|
||||
DEFAULT: 0,
|
||||
NO_BORDER: 0,
|
||||
@@ -78,82 +14,149 @@ const nodeType = {
|
||||
CLOUD: 4,
|
||||
BANG: 5,
|
||||
HEXAGON: 6,
|
||||
};
|
||||
|
||||
const getType = (startStr: string, endStr: string): number => {
|
||||
log.debug('In get type', startStr, endStr);
|
||||
switch (startStr) {
|
||||
case '[':
|
||||
return nodeType.RECT;
|
||||
case '(':
|
||||
return endStr === ')' ? nodeType.ROUNDED_RECT : nodeType.CLOUD;
|
||||
case '((':
|
||||
return nodeType.CIRCLE;
|
||||
case ')':
|
||||
return nodeType.CLOUD;
|
||||
case '))':
|
||||
return nodeType.BANG;
|
||||
case '{{':
|
||||
return nodeType.HEXAGON;
|
||||
default:
|
||||
return nodeType.DEFAULT;
|
||||
}
|
||||
};
|
||||
|
||||
const setElementForId = (id: number, element: D3Element) => {
|
||||
elements[id] = element;
|
||||
};
|
||||
|
||||
const decorateNode = (decoration?: { class?: string; icon?: string }) => {
|
||||
if (!decoration) {
|
||||
return;
|
||||
}
|
||||
const config = getConfig();
|
||||
const node = nodes[nodes.length - 1];
|
||||
if (decoration.icon) {
|
||||
node.icon = sanitizeText(decoration.icon, config);
|
||||
}
|
||||
if (decoration.class) {
|
||||
node.class = sanitizeText(decoration.class, config);
|
||||
}
|
||||
};
|
||||
|
||||
const type2Str = (type: number) => {
|
||||
switch (type) {
|
||||
case nodeType.DEFAULT:
|
||||
return 'no-border';
|
||||
case nodeType.RECT:
|
||||
return 'rect';
|
||||
case nodeType.ROUNDED_RECT:
|
||||
return 'rounded-rect';
|
||||
case nodeType.CIRCLE:
|
||||
return 'circle';
|
||||
case nodeType.CLOUD:
|
||||
return 'cloud';
|
||||
case nodeType.BANG:
|
||||
return 'bang';
|
||||
case nodeType.HEXAGON:
|
||||
return 'hexgon'; // cspell: disable-line
|
||||
default:
|
||||
return 'no-border';
|
||||
}
|
||||
};
|
||||
|
||||
// Expose logger to grammar
|
||||
const getLogger = () => log;
|
||||
const getElementById = (id: number) => elements[id];
|
||||
|
||||
const db = {
|
||||
clear,
|
||||
addNode,
|
||||
getMindmap,
|
||||
nodeType,
|
||||
getType,
|
||||
setElementForId,
|
||||
decorateNode,
|
||||
type2Str,
|
||||
getLogger,
|
||||
getElementById,
|
||||
} as const;
|
||||
|
||||
export default db;
|
||||
export class MindmapDB {
|
||||
private nodes: MindmapNode[] = [];
|
||||
private count = 0;
|
||||
private elements: Record<number, D3Element> = {};
|
||||
public readonly nodeType: typeof nodeType;
|
||||
|
||||
constructor() {
|
||||
this.getLogger = this.getLogger.bind(this);
|
||||
this.nodeType = nodeType;
|
||||
this.clear();
|
||||
this.getType = this.getType.bind(this);
|
||||
this.getMindmap = this.getMindmap.bind(this);
|
||||
this.getElementById = this.getElementById.bind(this);
|
||||
this.getParent = this.getParent.bind(this);
|
||||
this.getMindmap = this.getMindmap.bind(this);
|
||||
this.addNode = this.addNode.bind(this);
|
||||
this.decorateNode = this.decorateNode.bind(this);
|
||||
}
|
||||
public clear() {
|
||||
this.nodes = [];
|
||||
this.count = 0;
|
||||
this.elements = {};
|
||||
}
|
||||
|
||||
public getParent(level: number): MindmapNode | null {
|
||||
for (let i = this.nodes.length - 1; i >= 0; i--) {
|
||||
if (this.nodes[i].level < level) {
|
||||
return this.nodes[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getMindmap(): MindmapNode | null {
|
||||
return this.nodes.length > 0 ? this.nodes[0] : null;
|
||||
}
|
||||
|
||||
public addNode(level: number, id: string, descr: string, type: number): void {
|
||||
log.info('addNode', level, id, descr, type);
|
||||
|
||||
const conf = getConfig();
|
||||
let padding = conf.mindmap?.padding ?? defaultConfig.mindmap.padding;
|
||||
|
||||
switch (type) {
|
||||
case this.nodeType.ROUNDED_RECT:
|
||||
case this.nodeType.RECT:
|
||||
case this.nodeType.HEXAGON:
|
||||
padding *= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
const node: MindmapNode = {
|
||||
id: this.count++,
|
||||
nodeId: sanitizeText(id, conf),
|
||||
level,
|
||||
descr: sanitizeText(descr, conf),
|
||||
type,
|
||||
children: [],
|
||||
width: conf.mindmap?.maxNodeWidth ?? defaultConfig.mindmap.maxNodeWidth,
|
||||
padding,
|
||||
};
|
||||
|
||||
const parent = this.getParent(level);
|
||||
if (parent) {
|
||||
parent.children.push(node);
|
||||
this.nodes.push(node);
|
||||
} else {
|
||||
if (this.nodes.length === 0) {
|
||||
this.nodes.push(node);
|
||||
} else {
|
||||
throw new Error(
|
||||
`There can be only one root. No parent could be found for ("${node.descr}")`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getType(startStr: string, endStr: string) {
|
||||
log.debug('In get type', startStr, endStr);
|
||||
switch (startStr) {
|
||||
case '[':
|
||||
return this.nodeType.RECT;
|
||||
case '(':
|
||||
return endStr === ')' ? this.nodeType.ROUNDED_RECT : this.nodeType.CLOUD;
|
||||
case '((':
|
||||
return this.nodeType.CIRCLE;
|
||||
case ')':
|
||||
return this.nodeType.CLOUD;
|
||||
case '))':
|
||||
return this.nodeType.BANG;
|
||||
case '{{':
|
||||
return this.nodeType.HEXAGON;
|
||||
default:
|
||||
return this.nodeType.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
public setElementForId(id: number, element: D3Element): void {
|
||||
this.elements[id] = element;
|
||||
}
|
||||
public getElementById(id: number) {
|
||||
return this.elements[id];
|
||||
}
|
||||
|
||||
public decorateNode(decoration?: { class?: string; icon?: string }): void {
|
||||
if (!decoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = getConfig();
|
||||
const node = this.nodes[this.nodes.length - 1];
|
||||
if (decoration.icon) {
|
||||
node.icon = sanitizeText(decoration.icon, config);
|
||||
}
|
||||
if (decoration.class) {
|
||||
node.class = sanitizeText(decoration.class, config);
|
||||
}
|
||||
}
|
||||
|
||||
type2Str(type: number): string {
|
||||
switch (type) {
|
||||
case this.nodeType.DEFAULT:
|
||||
return 'no-border';
|
||||
case this.nodeType.RECT:
|
||||
return 'rect';
|
||||
case this.nodeType.ROUNDED_RECT:
|
||||
return 'rounded-rect';
|
||||
case this.nodeType.CIRCLE:
|
||||
return 'circle';
|
||||
case this.nodeType.CLOUD:
|
||||
return 'cloud';
|
||||
case this.nodeType.BANG:
|
||||
return 'bang';
|
||||
case this.nodeType.HEXAGON:
|
||||
return 'hexgon'; // cspell: disable-line
|
||||
default:
|
||||
return 'no-border';
|
||||
}
|
||||
}
|
||||
|
||||
public getLogger() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
@@ -9,10 +9,10 @@ import { log } from '../../logger.js';
|
||||
import type { D3Element } from '../../types.js';
|
||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import type { FilledMindMapNode, MindmapDB, MindmapNode } from './mindmapTypes.js';
|
||||
import type { FilledMindMapNode, MindmapNode } from './mindmapTypes.js';
|
||||
import { drawNode, positionNode } from './svgDraw.js';
|
||||
import defaultConfig from '../../defaultConfig.js';
|
||||
|
||||
import type { MindmapDB } from './mindmapDb.js';
|
||||
// Inject the layout algorithm into cytoscape
|
||||
cytoscape.use(coseBilkent);
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import type { RequiredDeep } from 'type-fest';
|
||||
import type mindmapDb from './mindmapDb.js';
|
||||
|
||||
export interface MindmapNode {
|
||||
id: number;
|
||||
@@ -19,4 +18,3 @@ export interface MindmapNode {
|
||||
}
|
||||
|
||||
export type FilledMindMapNode = RequiredDeep<MindmapNode>;
|
||||
export type MindmapDB = typeof mindmapDb;
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { createText } from '../../rendering-util/createText.js';
|
||||
import type { FilledMindMapNode, MindmapDB } from './mindmapTypes.js';
|
||||
import type { FilledMindMapNode } from './mindmapTypes.js';
|
||||
import type { Point, D3Element } from '../../types.js';
|
||||
import { parseFontSize } from '../../utils.js';
|
||||
import type { MermaidConfig } from '../../config.type.js';
|
||||
import type { MindmapDB } from './mindmapDb.js';
|
||||
|
||||
const MAX_SECTIONS = 12;
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { getConfig as commonGetConfig } from '../../config.js';
|
||||
import DEFAULT_CONFIG from '../../defaultConfig.js';
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||
import { isLabelStyle } from '../../rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
|
||||
|
||||
import type { TreemapDiagramConfig, TreemapNode } from './types.js';
|
||||
import DEFAULT_CONFIG from '../../defaultConfig.js';
|
||||
import { getConfig as commonGetConfig } from '../../config.js';
|
||||
import { cleanAndMerge } from '../../utils.js';
|
||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||
import { isLabelStyle } from '../../rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
|
||||
import {
|
||||
clear as commonClear,
|
||||
getAccDescription,
|
||||
@@ -14,99 +14,82 @@ import {
|
||||
setAccTitle,
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type { TreemapDB, TreemapData, TreemapDiagramConfig, TreemapNode } from './types.js';
|
||||
export class TreeMapDB implements DiagramDB {
|
||||
private nodes: TreemapNode[] = [];
|
||||
private levels: Map<TreemapNode, number> = new Map<TreemapNode, number>();
|
||||
private outerNodes: TreemapNode[] = [];
|
||||
private classes: Map<string, DiagramStyleClassDef> = new Map<string, DiagramStyleClassDef>();
|
||||
private root?: TreemapNode;
|
||||
|
||||
const defaultTreemapData: TreemapData = {
|
||||
nodes: [],
|
||||
levels: new Map(),
|
||||
outerNodes: [],
|
||||
classes: new Map(),
|
||||
};
|
||||
|
||||
const state = new ImperativeState<TreemapData>(() => structuredClone(defaultTreemapData));
|
||||
|
||||
const getConfig = (): Required<TreemapDiagramConfig> => {
|
||||
// Use type assertion with unknown as intermediate step
|
||||
const defaultConfig = DEFAULT_CONFIG as unknown as { treemap: Required<TreemapDiagramConfig> };
|
||||
const userConfig = commonGetConfig() as unknown as { treemap?: Partial<TreemapDiagramConfig> };
|
||||
|
||||
return cleanAndMerge({
|
||||
...defaultConfig.treemap,
|
||||
...(userConfig.treemap ?? {}),
|
||||
}) as Required<TreemapDiagramConfig>;
|
||||
};
|
||||
|
||||
const getNodes = (): TreemapNode[] => state.records.nodes;
|
||||
|
||||
const addNode = (node: TreemapNode, level: number) => {
|
||||
const data = state.records;
|
||||
data.nodes.push(node);
|
||||
data.levels.set(node, level);
|
||||
|
||||
if (level === 0) {
|
||||
data.outerNodes.push(node);
|
||||
public getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
// Set the root node if this is a level 0 node and we don't have a root yet
|
||||
if (level === 0 && !data.root) {
|
||||
data.root = node;
|
||||
public getConfig() {
|
||||
const defaultConfig = DEFAULT_CONFIG as unknown as { treemap: Required<TreemapDiagramConfig> };
|
||||
const userConfig = commonGetConfig() as unknown as { treemap?: Partial<TreemapDiagramConfig> };
|
||||
return cleanAndMerge({
|
||||
...defaultConfig.treemap,
|
||||
...(userConfig.treemap ?? {}),
|
||||
}) as Required<TreemapDiagramConfig>;
|
||||
}
|
||||
};
|
||||
|
||||
const getRoot = (): TreemapNode | undefined => ({ name: '', children: state.records.outerNodes });
|
||||
public addNode(node: TreemapNode, level: number) {
|
||||
this.nodes.push(node);
|
||||
this.levels.set(node, level);
|
||||
if (level === 0) {
|
||||
this.outerNodes.push(node);
|
||||
this.root ??= node;
|
||||
}
|
||||
}
|
||||
|
||||
const addClass = (id: string, _style: string) => {
|
||||
const classes = state.records.classes;
|
||||
const styleClass = classes.get(id) ?? { id, styles: [], textStyles: [] };
|
||||
classes.set(id, styleClass);
|
||||
public getRoot() {
|
||||
return { name: '', children: this.outerNodes };
|
||||
}
|
||||
|
||||
const styles = _style.replace(/\\,/g, '§§§').replace(/,/g, ';').replace(/§§§/g, ',').split(';');
|
||||
|
||||
if (styles) {
|
||||
styles.forEach((s) => {
|
||||
if (isLabelStyle(s)) {
|
||||
if (styleClass?.textStyles) {
|
||||
styleClass.textStyles.push(s);
|
||||
} else {
|
||||
styleClass.textStyles = [s];
|
||||
public addClass(id: string, _style: string) {
|
||||
const styleClass = this.classes.get(id) ?? { id, styles: [], textStyles: [] };
|
||||
const styles = _style.replace(/\\,/g, '§§§').replace(/,/g, ';').replace(/§§§/g, ',').split(';');
|
||||
if (styles) {
|
||||
styles.forEach((s) => {
|
||||
if (isLabelStyle(s)) {
|
||||
if (styleClass?.textStyles) {
|
||||
styleClass.textStyles.push(s);
|
||||
} else {
|
||||
styleClass.textStyles = [s];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (styleClass?.styles) {
|
||||
styleClass.styles.push(s);
|
||||
} else {
|
||||
styleClass.styles = [s];
|
||||
}
|
||||
});
|
||||
if (styleClass?.styles) {
|
||||
styleClass.styles.push(s);
|
||||
} else {
|
||||
styleClass.styles = [s];
|
||||
}
|
||||
});
|
||||
}
|
||||
this.classes.set(id, styleClass);
|
||||
}
|
||||
|
||||
classes.set(id, styleClass);
|
||||
};
|
||||
const getClasses = (): Map<string, DiagramStyleClassDef> => {
|
||||
return state.records.classes;
|
||||
};
|
||||
public getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
const getStylesForClass = (classSelector: string): string[] => {
|
||||
return state.records.classes.get(classSelector)?.styles ?? [];
|
||||
};
|
||||
public getStylesForClass(classSelector: string): string[] {
|
||||
return this.classes.get(classSelector)?.styles ?? [];
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
commonClear();
|
||||
state.reset();
|
||||
};
|
||||
public clear() {
|
||||
commonClear();
|
||||
this.nodes = [];
|
||||
this.levels = new Map();
|
||||
this.outerNodes = [];
|
||||
this.classes = new Map();
|
||||
this.root = undefined;
|
||||
}
|
||||
|
||||
export const db: TreemapDB = {
|
||||
getNodes,
|
||||
addNode,
|
||||
getRoot,
|
||||
getConfig,
|
||||
clear,
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
addClass,
|
||||
getClasses,
|
||||
getStylesForClass,
|
||||
};
|
||||
public setAccTitle = setAccTitle;
|
||||
public getAccTitle = getAccTitle;
|
||||
public setDiagramTitle = setDiagramTitle;
|
||||
public getDiagramTitle = getDiagramTitle;
|
||||
public getAccDescription = getAccDescription;
|
||||
public setAccDescription = setAccDescription;
|
||||
}
|
||||
|
@@ -1,12 +1,14 @@
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import { db } from './db.js';
|
||||
import { TreeMapDB } from './db.js';
|
||||
import { parser } from './parser.js';
|
||||
import { renderer } from './renderer.js';
|
||||
import styles from './styles.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
db,
|
||||
get db() {
|
||||
return new TreeMapDB();
|
||||
},
|
||||
renderer,
|
||||
styles,
|
||||
};
|
||||
|
@@ -2,15 +2,15 @@ import { parse } from '@mermaid-js/parser';
|
||||
import type { ParserDefinition } from '../../diagram-api/types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { populateCommonDb } from '../common/populateCommonDb.js';
|
||||
import { db } from './db.js';
|
||||
import type { TreemapNode, TreemapAst } from './types.js';
|
||||
import type { TreemapNode, TreemapAst, TreemapDB } from './types.js';
|
||||
import { buildHierarchy } from './utils.js';
|
||||
import { TreeMapDB } from './db.js';
|
||||
|
||||
/**
|
||||
* Populates the database with data from the Treemap AST
|
||||
* @param ast - The Treemap AST
|
||||
*/
|
||||
const populate = (ast: TreemapAst) => {
|
||||
const populate = (ast: TreemapAst, db: TreemapDB) => {
|
||||
// We need to bypass the type checking for populateCommonDb
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
populateCommonDb(ast as any, db);
|
||||
@@ -84,6 +84,8 @@ const getItemName = (item: { name?: string | number }): string => {
|
||||
};
|
||||
|
||||
export const parser: ParserDefinition = {
|
||||
// @ts-expect-error - TreeMapDB is not assignable to DiagramDB
|
||||
parser: { yy: undefined },
|
||||
parse: async (text: string): Promise<void> => {
|
||||
try {
|
||||
// Use a generic parse that accepts any diagram type
|
||||
@@ -91,7 +93,13 @@ export const parser: ParserDefinition = {
|
||||
const parseFunc = parse as (diagramType: string, text: string) => Promise<TreemapAst>;
|
||||
const ast = await parseFunc('treemap', text);
|
||||
log.debug('Treemap AST:', ast);
|
||||
populate(ast);
|
||||
const db = parser.parser?.yy;
|
||||
if (!(db instanceof TreeMapDB)) {
|
||||
throw new Error(
|
||||
'parser.parser?.yy was not a TreemapDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues.'
|
||||
);
|
||||
}
|
||||
populate(ast, db);
|
||||
} catch (error) {
|
||||
log.error('Error parsing treemap:', error);
|
||||
throw error;
|
||||
|
@@ -302,7 +302,7 @@ If you are adding a feature, you will definitely need to add tests. Depending on
|
||||
|
||||
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
|
||||
|
||||
Unit tests are mandatory for all code except the renderers. (The renderers are tested with integration tests.)
|
||||
Unit tests are mandatory for all code except the layout tests. (The layouts are tested with integration tests.)
|
||||
|
||||
We use [Vitest](https://vitest.dev) to run unit tests.
|
||||
|
||||
@@ -328,6 +328,30 @@ When using Docker prepend your command with `./run`:
|
||||
./run pnpm test
|
||||
```
|
||||
|
||||
##### Testing the DOM
|
||||
|
||||
One can use `jsdomIt` to test any part of Mermaid that interacts with the DOM, as long as it is not related to the layout.
|
||||
|
||||
The function `jsdomIt` ([developed in utils.ts](../../tests/util.ts)) overrides `it` from `vitest`, and creates a pseudo-browser environment that works almost like the real deal for the duration of the test. It uses JSDOM to create a DOM, and adds objects `window` and `document` to `global` to mock the browser environment.
|
||||
|
||||
> [!NOTE]
|
||||
> The layout cannot work in `jsdomIt` tests because JSDOM has no rendering engine, hence the pseudo-browser environment.
|
||||
|
||||
Example :
|
||||
|
||||
```typescript
|
||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
|
||||
|
||||
jsdomIt('should add element "thing" in the SVG', ({ svg }) => {
|
||||
// Code in this block runs in a pseudo-browser environment
|
||||
addThing(svg); // The svg item is the D3 selection of the SVG node
|
||||
const svgNode = ensureNodeFromSelector('svg'); // Retrieve the DOM node using the DOM API
|
||||
expect(svgNode.querySelector('thing')).not.toBeNull(); // Test the structure of the SVG
|
||||
});
|
||||
```
|
||||
|
||||
They can be used to test any method that interacts with the DOM, including for testing renderers. For renderers, additional integration testing is necessary to test the layout though.
|
||||
|
||||
#### Integration / End-to-End (E2E) Tests
|
||||
|
||||
These test the rendering and visual appearance of the diagrams.
|
||||
|
@@ -1,40 +1,5 @@
|
||||
import { assert, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// -------------------------------------
|
||||
// Mocks and mocking
|
||||
|
||||
import { MockedD3 } from './tests/MockedD3.js';
|
||||
|
||||
// Note: If running this directly from within an IDE, the mocks directory must be at packages/mermaid/mocks
|
||||
vi.mock('d3');
|
||||
vi.mock('dagre-d3');
|
||||
|
||||
// mermaidAPI.spec.ts:
|
||||
import * as accessibility from './accessibility.js'; // Import it this way so we can use spyOn(accessibility,...)
|
||||
vi.mock('./accessibility.js', () => ({
|
||||
setA11yDiagramInfo: vi.fn(),
|
||||
addSVGa11yTitleDescription: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the renderers specifically so we can test render(). Need to mock draw() for each renderer
|
||||
vi.mock('./diagrams/c4/c4Renderer.js');
|
||||
vi.mock('./diagrams/class/classRenderer.js');
|
||||
vi.mock('./diagrams/class/classRenderer-v2.js');
|
||||
vi.mock('./diagrams/er/erRenderer.js');
|
||||
vi.mock('./diagrams/flowchart/flowRenderer-v2.js');
|
||||
vi.mock('./diagrams/git/gitGraphRenderer.js');
|
||||
vi.mock('./diagrams/gantt/ganttRenderer.js');
|
||||
vi.mock('./diagrams/user-journey/journeyRenderer.js');
|
||||
vi.mock('./diagrams/pie/pieRenderer.js');
|
||||
vi.mock('./diagrams/packet/renderer.js');
|
||||
vi.mock('./diagrams/xychart/xychartRenderer.js');
|
||||
vi.mock('./diagrams/requirement/requirementRenderer.js');
|
||||
vi.mock('./diagrams/sequence/sequenceRenderer.js');
|
||||
vi.mock('./diagrams/radar/renderer.js');
|
||||
vi.mock('./diagrams/architecture/architectureRenderer.js');
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
import mermaid from './mermaid.js';
|
||||
@@ -75,6 +40,9 @@ import { SequenceDB } from './diagrams/sequence/sequenceDb.js';
|
||||
import { decodeEntities, encodeEntities } from './utils.js';
|
||||
import { toBase64 } from './utils/base64.js';
|
||||
import { StateDB } from './diagrams/state/stateDb.js';
|
||||
import { ensureNodeFromSelector, jsdomIt } from './tests/util.js';
|
||||
import { select } from 'd3';
|
||||
import { JSDOM } from 'jsdom';
|
||||
|
||||
/**
|
||||
* @see https://vitest.dev/guide/mocking.html Mock part of a module
|
||||
@@ -225,63 +193,49 @@ describe('mermaidAPI', () => {
|
||||
});
|
||||
});
|
||||
|
||||
const fauxParentNode = new MockedD3();
|
||||
const fauxEnclosingDiv = new MockedD3();
|
||||
const fauxSvgNode = new MockedD3();
|
||||
|
||||
describe('appendDivSvgG', () => {
|
||||
const fauxGNode = new MockedD3();
|
||||
const parent_append_spy = vi.spyOn(fauxParentNode, 'append').mockReturnValue(fauxEnclosingDiv);
|
||||
const div_append_spy = vi.spyOn(fauxEnclosingDiv, 'append').mockReturnValue(fauxSvgNode);
|
||||
// @ts-ignore @todo TODO why is this getting a type error?
|
||||
const div_attr_spy = vi.spyOn(fauxEnclosingDiv, 'attr').mockReturnValue(fauxEnclosingDiv);
|
||||
const svg_append_spy = vi.spyOn(fauxSvgNode, 'append').mockReturnValue(fauxGNode);
|
||||
// @ts-ignore @todo TODO why is this getting a type error?
|
||||
const svg_attr_spy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||
|
||||
// cspell:ignore dthe
|
||||
|
||||
it('appends a div node', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(parent_append_spy).toHaveBeenCalledWith('div');
|
||||
expect(div_append_spy).toHaveBeenCalledWith('svg');
|
||||
jsdomIt('appends a div node', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId');
|
||||
const divNode = ensureNodeFromSelector('div');
|
||||
const svgNode = ensureNodeFromSelector('svg', divNode);
|
||||
ensureNodeFromSelector('g', svgNode);
|
||||
});
|
||||
it('the id for the div is "d" with the id appended', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(div_attr_spy).toHaveBeenCalledWith('id', 'dtheId');
|
||||
jsdomIt('the id for the div is "d" with the id appended', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId');
|
||||
const divNode = ensureNodeFromSelector('div');
|
||||
expect(divNode?.getAttribute('id')).toBe('dtheId');
|
||||
});
|
||||
|
||||
it('sets the style for the div if one is given', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId', 'given div style', 'given x link');
|
||||
expect(div_attr_spy).toHaveBeenCalledWith('style', 'given div style');
|
||||
jsdomIt('sets the style for the div if one is given', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId', 'given div style', 'given x link');
|
||||
const divNode = ensureNodeFromSelector('div');
|
||||
expect(divNode?.getAttribute('style')).toBe('given div style');
|
||||
});
|
||||
|
||||
it('appends a svg node to the div node', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(div_attr_spy).toHaveBeenCalledWith('id', 'dtheId');
|
||||
jsdomIt('sets the svg width to 100%', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId');
|
||||
const svgNode = ensureNodeFromSelector('div > svg');
|
||||
expect(svgNode.getAttribute('width')).toBe('100%');
|
||||
});
|
||||
it('sets the svg width to 100%', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(svg_attr_spy).toHaveBeenCalledWith('width', '100%');
|
||||
jsdomIt('the svg id is the id', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId');
|
||||
const svgNode = ensureNodeFromSelector('div > svg');
|
||||
expect(svgNode.getAttribute('id')).toBe('theId');
|
||||
});
|
||||
it('the svg id is the id', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(svg_attr_spy).toHaveBeenCalledWith('id', 'theId');
|
||||
jsdomIt('the svg xml namespace is the 2000 standard', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId');
|
||||
const svgNode = ensureNodeFromSelector('div > svg');
|
||||
expect(svgNode.getAttribute('xmlns')).toBe('http://www.w3.org/2000/svg');
|
||||
});
|
||||
it('the svg xml namespace is the 2000 standard', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(svg_attr_spy).toHaveBeenCalledWith('xmlns', 'http://www.w3.org/2000/svg');
|
||||
jsdomIt('sets the svg xlink if one is given', ({ body }) => {
|
||||
appendDivSvgG(body, 'theId', 'dtheId', 'div style', 'given x link');
|
||||
const svgNode = ensureNodeFromSelector('div > svg');
|
||||
expect(svgNode.getAttribute('xmlns:xlink')).toBe('given x link');
|
||||
});
|
||||
it('sets the svg xlink if one is given', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId', 'div style', 'given x link');
|
||||
expect(svg_attr_spy).toHaveBeenCalledWith('xmlns:xlink', 'given x link');
|
||||
});
|
||||
it('appends a g (group) node to the svg node', () => {
|
||||
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||
expect(svg_append_spy).toHaveBeenCalledWith('g');
|
||||
});
|
||||
it('returns the given parentRoot d3 nodes', () => {
|
||||
expect(appendDivSvgG(fauxParentNode, 'theId', 'dtheId')).toEqual(fauxParentNode);
|
||||
jsdomIt('returns the given parentRoot d3 nodes', ({ body }) => {
|
||||
expect(appendDivSvgG(body, 'theId', 'dtheId')).toEqual(body);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -782,9 +736,9 @@ graph TD;A--x|text including URL space|B;`)
|
||||
// render(id, text, cb?, svgContainingElement?)
|
||||
|
||||
// Test all diagram types. Note that old flowchart 'graph' type will invoke the flowRenderer-v2. (See the flowchart v2 detector.)
|
||||
// We have to have both the specific textDiagramType and the expected type name because the expected type may be slightly different than was is put in the diagram text (ex: in -v2 diagrams)
|
||||
// We have to have both the specific textDiagramType and the expected type name because the expected type may be slightly different from what is put in the diagram text (ex: in -v2 diagrams)
|
||||
const diagramTypesAndExpectations = [
|
||||
{ textDiagramType: 'C4Context', expectedType: 'c4' },
|
||||
// { textDiagramType: 'C4Context', expectedType: 'c4' }, TODO : setAccTitle not called in C4 jison parser
|
||||
{ textDiagramType: 'classDiagram', expectedType: 'class' },
|
||||
{ textDiagramType: 'classDiagram-v2', expectedType: 'classDiagram' },
|
||||
{ textDiagramType: 'erDiagram', expectedType: 'er' },
|
||||
@@ -796,7 +750,11 @@ graph TD;A--x|text including URL space|B;`)
|
||||
{ textDiagramType: 'pie', expectedType: 'pie' },
|
||||
{ textDiagramType: 'packet', expectedType: 'packet' },
|
||||
{ textDiagramType: 'packet-beta', expectedType: 'packet' },
|
||||
{ textDiagramType: 'xychart-beta', expectedType: 'xychart' },
|
||||
{
|
||||
textDiagramType: 'xychart-beta',
|
||||
expectedType: 'xychart',
|
||||
content: 'x-axis "Attempts" 10000 --> 10000\ny-axis "Passing tests" 1 --> 1\nbar [1]',
|
||||
},
|
||||
{ textDiagramType: 'requirementDiagram', expectedType: 'requirement' },
|
||||
{ textDiagramType: 'sequenceDiagram', expectedType: 'sequence' },
|
||||
{ textDiagramType: 'stateDiagram-v2', expectedType: 'stateDiagram' },
|
||||
@@ -812,20 +770,25 @@ graph TD;A--x|text including URL space|B;`)
|
||||
diagramTypesAndExpectations.forEach((testedDiagram) => {
|
||||
describe(`${testedDiagram.textDiagramType}`, () => {
|
||||
const diagramType = testedDiagram.textDiagramType;
|
||||
const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n`;
|
||||
const content = testedDiagram.content || '';
|
||||
const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n ${content}`;
|
||||
const expectedDiagramType = testedDiagram.expectedType;
|
||||
|
||||
it('should set aria-roledescription to the diagram type AND should call addSVGa11yTitleDescription', async () => {
|
||||
const a11yDiagramInfo_spy = vi.spyOn(accessibility, 'setA11yDiagramInfo');
|
||||
const a11yTitleDesc_spy = vi.spyOn(accessibility, 'addSVGa11yTitleDescription');
|
||||
const result = await mermaidAPI.render(id, diagramText);
|
||||
expect(result.diagramType).toBe(expectedDiagramType);
|
||||
expect(a11yDiagramInfo_spy).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expectedDiagramType
|
||||
);
|
||||
expect(a11yTitleDesc_spy).toHaveBeenCalled();
|
||||
});
|
||||
jsdomIt(
|
||||
'should set aria-roledescription to the diagram type AND should call addSVGa11yTitleDescription',
|
||||
async () => {
|
||||
const { svg } = await mermaidAPI.render(id, diagramText);
|
||||
const dom = new JSDOM(svg);
|
||||
const svgNode = ensureNodeFromSelector('svg', dom.window.document);
|
||||
const descNode = ensureNodeFromSelector('desc', svgNode);
|
||||
const titleNode = ensureNodeFromSelector('title', svgNode);
|
||||
expect(svgNode.getAttribute('aria-roledescription')).toBe(expectedDiagramType);
|
||||
expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${id}`);
|
||||
expect(descNode.getAttribute('id')).toBe(`chart-desc-${id}`);
|
||||
expect(descNode.innerHTML).toBe(a11yDescr);
|
||||
expect(titleNode.innerHTML).toBe(a11yTitle);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* This is a mocked/stubbed version of the d3 Selection type. Each of the main functions are all
|
||||
* mocked (via vi.fn()) so you can track if they have been called, etc.
|
||||
*
|
||||
* Note that node() returns a HTML Element with tag 'svg'. It is an empty element (no innerHTML, no children, etc).
|
||||
* This potentially allows testing of mermaidAPI render().
|
||||
*/
|
||||
export class MockedD3 {
|
||||
public attribs = new Map<string, string>();
|
||||
public id: string | undefined = '';
|
||||
_children: MockedD3[] = [];
|
||||
|
||||
_containingHTMLdoc = new Document();
|
||||
|
||||
constructor(givenId = 'mock-id') {
|
||||
this.id = givenId;
|
||||
}
|
||||
|
||||
/** Helpful utility during development/debugging. This is not a real d3 function */
|
||||
public listChildren(): string {
|
||||
return this._children
|
||||
.map((child) => {
|
||||
return child.id;
|
||||
})
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
select = vi.fn().mockImplementation(({ select_str = '' }): MockedD3 => {
|
||||
// Get the id from an argument string. if it is of the form [id='some-id'], strip off the
|
||||
// surrounding id[..]
|
||||
const stripSurroundRegexp = /\[id='(.*)']/;
|
||||
const matchedSurrounds = select_str.match(stripSurroundRegexp);
|
||||
const cleanId = matchedSurrounds ? matchedSurrounds[1] : select_str;
|
||||
return new MockedD3(cleanId);
|
||||
});
|
||||
|
||||
// This has the same implementation as select(). (It calls it.)
|
||||
selectAll = vi.fn().mockImplementation(({ select_str = '' }): MockedD3 => {
|
||||
return this.select(select_str);
|
||||
});
|
||||
|
||||
append = vi.fn().mockImplementation(function (
|
||||
this: MockedD3,
|
||||
type: string,
|
||||
id = '' + '-appended'
|
||||
): MockedD3 {
|
||||
const newMock = new MockedD3(id);
|
||||
newMock.attribs.set('type', type);
|
||||
this._children.push(newMock);
|
||||
return newMock;
|
||||
});
|
||||
|
||||
// NOTE: The d3 implementation allows for a selector ('beforeSelector' arg below).
|
||||
// With this mocked implementation, we assume it will always refer to a node id
|
||||
// and will always be of the form "#[id of the node to insert before]".
|
||||
// To keep this simple, any leading '#' is removed and the resulting string is the node id searched.
|
||||
insert = (type: string, beforeSelector?: string, id = this.id + '-inserted'): MockedD3 => {
|
||||
const newMock = new MockedD3(id);
|
||||
newMock.attribs.set('type', type);
|
||||
if (beforeSelector === undefined) {
|
||||
this._children.push(newMock);
|
||||
} else {
|
||||
const idOnly = beforeSelector.startsWith('#') ? beforeSelector.substring(1) : beforeSelector;
|
||||
const foundIndex = this._children.findIndex((child) => child.id === idOnly);
|
||||
if (foundIndex < 0) {
|
||||
this._children.push(newMock);
|
||||
} else {
|
||||
this._children.splice(foundIndex, 0, newMock);
|
||||
}
|
||||
}
|
||||
return newMock;
|
||||
};
|
||||
|
||||
attr(attrName: string): undefined | string;
|
||||
attr(attrName: string, attrValue: string): MockedD3;
|
||||
attr(attrName: string, attrValue?: string): undefined | string | MockedD3 {
|
||||
if (arguments.length === 1) {
|
||||
return this.attribs.get(attrName);
|
||||
} else {
|
||||
if (attrName === 'id') {
|
||||
this.id = attrValue; // also set the id explicitly
|
||||
}
|
||||
if (attrValue !== undefined) {
|
||||
this.attribs.set(attrName, attrValue);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public lower(attrValue = '') {
|
||||
this.attribs.set('lower', attrValue);
|
||||
return this;
|
||||
}
|
||||
public style(attrValue = '') {
|
||||
this.attribs.set('style', attrValue);
|
||||
return this;
|
||||
}
|
||||
public text(attrValue = '') {
|
||||
this.attribs.set('text', attrValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
// NOTE: Returns a HTML Element with tag 'svg' that has _another_ 'svg' element child.
|
||||
// This allows different tests to succeed -- some need a top level 'svg' and some need a 'svg' element to be the firstChild
|
||||
// Real implementation returns an HTML Element
|
||||
public node = vi.fn().mockImplementation(() => {
|
||||
//create a top level svg element
|
||||
const topElem = this._containingHTMLdoc.createElement('svg');
|
||||
//@ts-ignore - this is a mock SVG element
|
||||
topElem.getBBox = this.getBBox;
|
||||
const elem_svgChild = this._containingHTMLdoc.createElement('svg'); // another svg element
|
||||
topElem.appendChild(elem_svgChild);
|
||||
return topElem;
|
||||
});
|
||||
|
||||
// TODO Is this correct? shouldn't it return a list of HTML Elements?
|
||||
nodes = vi.fn().mockImplementation(function (this: MockedD3): MockedD3[] {
|
||||
return this._children;
|
||||
});
|
||||
|
||||
// This will try to use attrs that have been set.
|
||||
getBBox = () => {
|
||||
const x = this.attribs.has('x') ? this.attribs.get('x') : 20;
|
||||
const y = this.attribs.has('y') ? this.attribs.get('y') : 30;
|
||||
const width = this.attribs.has('width') ? this.attribs.get('width') : 140;
|
||||
const height = this.attribs.has('height') ? this.attribs.get('height') : 250;
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// The following functions are here for completeness. They simply return a vi.fn()
|
||||
|
||||
insertBefore = vi.fn();
|
||||
curveBasis = vi.fn();
|
||||
curveBasisClosed = vi.fn();
|
||||
curveBasisOpen = vi.fn();
|
||||
curveLinear = vi.fn();
|
||||
curveLinearClosed = vi.fn();
|
||||
curveMonotoneX = vi.fn();
|
||||
curveMonotoneY = vi.fn();
|
||||
curveNatural = vi.fn();
|
||||
curveStep = vi.fn();
|
||||
curveStepAfter = vi.fn();
|
||||
curveStepBefore = vi.fn();
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
import { vi } from 'vitest';
|
||||
vi.mock('d3');
|
||||
vi.mock('dagre-d3-es');
|
@@ -26,6 +26,10 @@ ${'2w'} | ${dayjs.duration(2, 'w')}
|
||||
```
|
||||
*/
|
||||
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { expect, it } from 'vitest';
|
||||
import { select, type Selection } from 'd3';
|
||||
|
||||
export const convert = (template: TemplateStringsArray, ...params: unknown[]) => {
|
||||
const header = template[0]
|
||||
.trim()
|
||||
@@ -42,3 +46,83 @@ export const convert = (template: TemplateStringsArray, ...params: unknown[]) =>
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Getting rid of linter issues to make {@link jsdomIt} work.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function setOnProtectedConstant(object: any, key: string, value: unknown): void {
|
||||
object[key] = value;
|
||||
}
|
||||
|
||||
export const MOCKED_BBOX = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 666,
|
||||
height: 666,
|
||||
};
|
||||
|
||||
interface JsdomItInput {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
body: Selection<HTMLBodyElement, never, HTMLElement, any>; // The `any` here comes from D3'as API.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
svg: Selection<SVGSVGElement, never, HTMLElement, any>; // The `any` here comes from D3'as API.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method borrowed from d3 : https://github.com/d3/d3-selection/blob/v3.0.0/test/jsdom.js
|
||||
*
|
||||
* Fools d3 into thinking it's working in a browser with a real DOM.
|
||||
*
|
||||
* The DOM is actually an instance of JSDom with monkey-patches for DOM methods that require a
|
||||
* rendering engine.
|
||||
*
|
||||
* The resulting environment is capable of rendering SVGs with the caveat that layouts are
|
||||
* completely screwed.
|
||||
*
|
||||
* This makes it possible to make structural tests instead of mocking everything.
|
||||
*/
|
||||
export function jsdomIt(message: string, run: (input: JsdomItInput) => void | Promise<void>) {
|
||||
return it(message, async (): Promise<void> => {
|
||||
const oldWindow = global.window;
|
||||
const oldDocument = global.document;
|
||||
|
||||
try {
|
||||
const baseHtml = `
|
||||
<html lang="en">
|
||||
<body id="cy">
|
||||
<svg id="svg"/>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
const dom = new JSDOM(baseHtml, {
|
||||
resources: 'usable',
|
||||
beforeParse(_window) {
|
||||
// Mocks DOM functions that require rendering, JSDOM doesn't
|
||||
setOnProtectedConstant(_window.Element.prototype, 'getBBox', () => MOCKED_BBOX);
|
||||
setOnProtectedConstant(_window.Element.prototype, 'getComputedTextLength', () => 200);
|
||||
},
|
||||
});
|
||||
setOnProtectedConstant(global, 'window', dom.window); // Fool D3 into thinking it's in a browser
|
||||
setOnProtectedConstant(global, 'document', dom.window.document); // Fool D3 into thinking it's in a browser
|
||||
setOnProtectedConstant(global, 'MutationObserver', undefined); // JSDOM doesn't like cytoscape elements
|
||||
|
||||
const body = select<HTMLBodyElement, never>('body');
|
||||
const svg = select<SVGSVGElement, never>('svg');
|
||||
await run({ body, svg });
|
||||
} finally {
|
||||
setOnProtectedConstant(global, 'window', oldWindow);
|
||||
setOnProtectedConstant(global, 'document', oldDocument);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the node from its parent with ParentNode#querySelector,
|
||||
* then checks that it exists before returning it.
|
||||
*/
|
||||
export function ensureNodeFromSelector(selector: string, parent: ParentNode = document): Element {
|
||||
const node = parent.querySelector(selector);
|
||||
expect(node).not.toBeNull();
|
||||
return node!;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { vi } from 'vitest';
|
||||
import { expect, vi } from 'vitest';
|
||||
import utils, { calculatePoint, cleanAndMerge, detectDirective } from './utils.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import { detectType } from './diagram-api/detectType.js';
|
||||
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
||||
import memoize from 'lodash-es/memoize.js';
|
||||
import { MockedD3 } from './tests/MockedD3.js';
|
||||
import { preprocessDiagram } from './preprocess.js';
|
||||
import { MOCKED_BBOX, ensureNodeFromSelector, jsdomIt } from './tests/util.js';
|
||||
|
||||
addDiagrams();
|
||||
|
||||
@@ -369,53 +369,34 @@ describe('when initializing the id generator', function () {
|
||||
});
|
||||
|
||||
describe('when inserting titles', function () {
|
||||
const svg = new MockedD3('svg');
|
||||
const mockedElement = {
|
||||
getBBox: vi.fn().mockReturnValue({ x: 10, y: 11, width: 100, height: 200 }),
|
||||
};
|
||||
const fauxTitle = new MockedD3('title');
|
||||
|
||||
beforeEach(() => {
|
||||
svg.node = vi.fn().mockReturnValue(mockedElement);
|
||||
});
|
||||
|
||||
it('does nothing if the title is empty', function () {
|
||||
const svgAppendSpy = vi.spyOn(svg, 'append');
|
||||
jsdomIt('does nothing if the title is empty', function ({ svg }) {
|
||||
utils.insertTitle(svg, 'testClass', 0, '');
|
||||
expect(svgAppendSpy).not.toHaveBeenCalled();
|
||||
const titleNode = document.querySelector('svg > text');
|
||||
expect(titleNode).toBeNull();
|
||||
});
|
||||
|
||||
it('appends the title as a text item with the given title text', function () {
|
||||
const svgAppendSpy = vi.spyOn(svg, 'append').mockReturnValue(fauxTitle);
|
||||
const titleTextSpy = vi.spyOn(fauxTitle, 'text');
|
||||
|
||||
jsdomIt('appends the title as a text item with the given title text', function ({ svg }) {
|
||||
utils.insertTitle(svg, 'testClass', 5, 'test title');
|
||||
expect(svgAppendSpy).toHaveBeenCalled();
|
||||
expect(titleTextSpy).toHaveBeenCalledWith('test title');
|
||||
const titleNode = ensureNodeFromSelector('svg > text');
|
||||
expect(titleNode.innerHTML).toBe('test title');
|
||||
});
|
||||
|
||||
it('x value is the bounds x position + half of the bounds width', () => {
|
||||
vi.spyOn(svg, 'append').mockReturnValue(fauxTitle);
|
||||
const titleAttrSpy = vi.spyOn(fauxTitle, 'attr');
|
||||
|
||||
jsdomIt('x value is the bounds x position + half of the bounds width', ({ svg }) => {
|
||||
utils.insertTitle(svg, 'testClass', 5, 'test title');
|
||||
expect(titleAttrSpy).toHaveBeenCalledWith('x', 10 + 100 / 2);
|
||||
const titleNode = ensureNodeFromSelector('svg > text');
|
||||
expect(titleNode.getAttribute('x')).toBe(`${MOCKED_BBOX.x + MOCKED_BBOX.width / 2}`);
|
||||
});
|
||||
|
||||
it('y value is the negative of given title top margin', () => {
|
||||
vi.spyOn(svg, 'append').mockReturnValue(fauxTitle);
|
||||
const titleAttrSpy = vi.spyOn(fauxTitle, 'attr');
|
||||
|
||||
jsdomIt('y value is the negative of given title top margin', ({ svg }) => {
|
||||
utils.insertTitle(svg, 'testClass', 5, 'test title');
|
||||
expect(titleAttrSpy).toHaveBeenCalledWith('y', -5);
|
||||
const titleNode = ensureNodeFromSelector('svg > text');
|
||||
expect(titleNode.getAttribute('y')).toBe(`${MOCKED_BBOX.y - 5}`);
|
||||
});
|
||||
|
||||
it('class is the given css class', () => {
|
||||
vi.spyOn(svg, 'append').mockReturnValue(fauxTitle);
|
||||
const titleAttrSpy = vi.spyOn(fauxTitle, 'attr');
|
||||
|
||||
jsdomIt('class is the given css class', ({ svg }) => {
|
||||
utils.insertTitle(svg, 'testClass', 5, 'test title');
|
||||
expect(titleAttrSpy).toHaveBeenCalledWith('class', 'testClass');
|
||||
const titleNode = ensureNodeFromSelector('svg > text');
|
||||
expect(titleNode.getAttribute('class')).toBe('testClass');
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,5 +1,11 @@
|
||||
# @mermaid-js/parser
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6510](https://github.com/mermaid-js/mermaid/pull/6510) [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move packet diagram out of beta
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/parser",
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"description": "MermaidJS parser",
|
||||
"author": "Yokozuna59",
|
||||
"contributors": [
|
||||
|
@@ -1,5 +1,28 @@
|
||||
# mermaid
|
||||
|
||||
## 11.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6453](https://github.com/mermaid-js/mermaid/pull/6453) [`5acbd7e`](https://github.com/mermaid-js/mermaid/commit/5acbd7e762469d9d89a9c77faf6617ee13367f3a) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add `getRegisteredDiagramsMetadata` to `mermaid`, which returns all the registered diagram IDs in mermaid
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6738](https://github.com/mermaid-js/mermaid/pull/6738) [`d90634b`](https://github.com/mermaid-js/mermaid/commit/d90634bf2b09e586b055729e07e9a1a31b21827c) Thanks [@shubham-mermaid](https://github.com/shubham-mermaid)! - chore: Updated TreeMapDB to use class based approach
|
||||
|
||||
- [#6510](https://github.com/mermaid-js/mermaid/pull/6510) [`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move packet diagram out of beta
|
||||
|
||||
- [#6747](https://github.com/mermaid-js/mermaid/pull/6747) [`3e3ae08`](https://github.com/mermaid-js/mermaid/commit/3e3ae089305e1c7b9948b9e149eba6854fe7f2d6) Thanks [@darshanr0107](https://github.com/darshanr0107)! - fix: adjust sequence diagram title positioning to prevent overlap with top border in Safari
|
||||
|
||||
- [#6751](https://github.com/mermaid-js/mermaid/pull/6751) [`d3e2be3`](https://github.com/mermaid-js/mermaid/commit/d3e2be35be066adeb7fd502b4a24c223c3b53947) Thanks [@darshanr0107](https://github.com/darshanr0107)! - chore: Update MindmapDB to use class based approach
|
||||
|
||||
- [#6715](https://github.com/mermaid-js/mermaid/pull/6715) [`637680d`](https://github.com/mermaid-js/mermaid/commit/637680d4d9e39b4f8cb6f05b4cb261e8f5693ac3) Thanks [@Syn3ugar](https://github.com/Syn3ugar)! - fix(timeline): fix loading `leftMargin` from config
|
||||
|
||||
The `timeline.leftMargin` config value should now correctly control the size of the left margin, instead of being ignored.
|
||||
|
||||
- Updated dependencies [[`7a38eb7`](https://github.com/mermaid-js/mermaid/commit/7a38eb715d795cd5c66cb59357d64ec197b432e6)]:
|
||||
- @mermaid-js/parser@0.6.2
|
||||
|
||||
## 11.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/tiny",
|
||||
"version": "11.8.1",
|
||||
"version": "11.9.0",
|
||||
"description": "Tiny version of mermaid",
|
||||
"type": "commonjs",
|
||||
"main": "./dist/mermaid.tiny.js",
|
||||
|
245
pnpm-lock.yaml
generated
245
pnpm-lock.yaml
generated
@@ -74,8 +74,8 @@ importers:
|
||||
specifier: ^8.17.1
|
||||
version: 8.17.1
|
||||
chokidar:
|
||||
specifier: 4.0.3
|
||||
version: 4.0.3
|
||||
specifier: 3.6.0
|
||||
version: 3.6.0
|
||||
concurrently:
|
||||
specifier: ^9.1.2
|
||||
version: 9.1.2
|
||||
@@ -161,8 +161,8 @@ importers:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
jsdom:
|
||||
specifier: ^26.0.0
|
||||
version: 26.0.0
|
||||
specifier: ^26.1.0
|
||||
version: 26.1.0(canvas@3.1.2)
|
||||
langium-cli:
|
||||
specifier: 3.3.0
|
||||
version: 3.3.0
|
||||
@@ -213,7 +213,7 @@ importers:
|
||||
version: 7.0.0(vite@7.0.3(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))
|
||||
vitest:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.0.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
version: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.1.0(canvas@3.1.2))(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
|
||||
packages/examples:
|
||||
devDependencies:
|
||||
@@ -260,8 +260,8 @@ importers:
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5
|
||||
katex:
|
||||
specifier: ^0.16.9
|
||||
version: 0.16.11
|
||||
specifier: ^0.16.22
|
||||
version: 0.16.22
|
||||
khroma:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
@@ -332,9 +332,12 @@ importers:
|
||||
ajv:
|
||||
specifier: ^8.17.1
|
||||
version: 8.17.1
|
||||
canvas:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.2
|
||||
chokidar:
|
||||
specifier: 4.0.3
|
||||
version: 4.0.3
|
||||
specifier: 3.6.0
|
||||
version: 3.6.0
|
||||
concurrently:
|
||||
specifier: ^9.1.2
|
||||
version: 9.1.2
|
||||
@@ -351,8 +354,8 @@ importers:
|
||||
specifier: ^3.7.7
|
||||
version: 3.7.7
|
||||
jsdom:
|
||||
specifier: ^26.0.0
|
||||
version: 26.0.0
|
||||
specifier: ^26.1.0
|
||||
version: 26.1.0(canvas@3.1.2)
|
||||
json-schema-to-typescript:
|
||||
specifier: ^15.0.4
|
||||
version: 15.0.4
|
||||
@@ -4065,10 +4068,6 @@ packages:
|
||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
|
||||
agent-base@7.1.1:
|
||||
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
agent-base@7.1.3:
|
||||
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -4377,6 +4376,9 @@ packages:
|
||||
birpc@0.2.19:
|
||||
resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==}
|
||||
|
||||
bl@4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
|
||||
blob-util@2.0.2:
|
||||
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
|
||||
|
||||
@@ -4506,6 +4508,10 @@ packages:
|
||||
caniuse-lite@1.0.30001700:
|
||||
resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==}
|
||||
|
||||
canvas@3.1.2:
|
||||
resolution: {integrity: sha512-Z/tzFAcBzoCvJlOSlCnoekh1Gu8YMn0J51+UAuXJAbW1Z6I9l2mZgdD7738MepoeeIcUdDtbMnOg6cC7GJxy/g==}
|
||||
engines: {node: ^18.12.0 || >= 20.9.0}
|
||||
|
||||
caseless@0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
|
||||
@@ -4592,9 +4598,8 @@ packages:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
||||
chokidar@4.0.3:
|
||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
|
||||
chrome-trace-event@1.0.4:
|
||||
resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
|
||||
@@ -5260,8 +5265,8 @@ packages:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
decimal.js@10.4.3:
|
||||
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
|
||||
decimal.js@10.6.0:
|
||||
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
|
||||
|
||||
decode-named-character-reference@1.0.2:
|
||||
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
||||
@@ -5286,6 +5291,10 @@ packages:
|
||||
resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
deep-extend@0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
@@ -5831,6 +5840,10 @@ packages:
|
||||
resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
expect-type@1.1.0:
|
||||
resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -6128,6 +6141,9 @@ packages:
|
||||
fromentries@1.3.2:
|
||||
resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==}
|
||||
|
||||
fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
|
||||
fs-extra@11.1.1:
|
||||
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
|
||||
engines: {node: '>=14.14'}
|
||||
@@ -6237,6 +6253,9 @@ packages:
|
||||
getpass@0.1.7:
|
||||
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
|
||||
|
||||
github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
|
||||
github-slugger@2.0.0:
|
||||
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
|
||||
|
||||
@@ -6552,6 +6571,9 @@ packages:
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
ini@1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
|
||||
ini@2.0.0:
|
||||
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -7071,8 +7093,8 @@ packages:
|
||||
resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
jsdom@26.0.0:
|
||||
resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==}
|
||||
jsdom@26.1.0:
|
||||
resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
canvas: ^3.0.0
|
||||
@@ -7153,8 +7175,8 @@ packages:
|
||||
resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
||||
katex@0.16.11:
|
||||
resolution: {integrity: sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==}
|
||||
katex@0.16.22:
|
||||
resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==}
|
||||
hasBin: true
|
||||
|
||||
keyv@4.5.4:
|
||||
@@ -7667,6 +7689,9 @@ packages:
|
||||
mitt@3.0.1:
|
||||
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||
|
||||
mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
@@ -7717,6 +7742,9 @@ packages:
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
napi-build-utils@2.0.0:
|
||||
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
|
||||
|
||||
napi-postinstall@0.3.0:
|
||||
resolution: {integrity: sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA==}
|
||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||
@@ -7742,6 +7770,13 @@ packages:
|
||||
nice-try@1.0.5:
|
||||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
||||
|
||||
node-abi@3.75.0:
|
||||
resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
|
||||
|
||||
node-cleanup@2.1.2:
|
||||
resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==}
|
||||
|
||||
@@ -8272,6 +8307,11 @@ packages:
|
||||
preact@10.26.2:
|
||||
resolution: {integrity: sha512-0gNmv4qpS9HaN3+40CLBAnKe0ZfyE4ZWo5xKlC1rVrr0ckkEvJvAQqKaHANdFKsGstoxrY4AItZ7kZSGVoVjgg==}
|
||||
|
||||
prebuild-install@7.1.3:
|
||||
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
precinct@12.1.2:
|
||||
resolution: {integrity: sha512-x2qVN3oSOp3D05ihCd8XdkIPuEQsyte7PSxzLqiRgktu79S5Dr1I75/S+zAup8/0cwjoiJTQztE9h0/sWp9bJQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -8403,6 +8443,10 @@ packages:
|
||||
resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
||||
react-is@18.3.1:
|
||||
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
|
||||
|
||||
@@ -8428,10 +8472,6 @@ packages:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
engines: {node: '>=8.10.0'}
|
||||
|
||||
readdirp@4.1.2:
|
||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||
engines: {node: '>= 14.18.0'}
|
||||
|
||||
real-require@0.2.0:
|
||||
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||
engines: {node: '>= 12.13.0'}
|
||||
@@ -8855,6 +8895,12 @@ packages:
|
||||
resolution: {integrity: sha512-0LxHn+P1lF5r2WwVB/za3hLRIsYoLaNq1CXqjbrs3ZvLuvlWnRKrUjEWzV7umZL7hpQ7xULiQMV+0iXdRa5iFg==}
|
||||
engines: {node: '>=14.16'}
|
||||
|
||||
simple-concat@1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
|
||||
simple-get@4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
|
||||
@@ -9110,6 +9156,10 @@ packages:
|
||||
resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
strip-json-comments@2.0.1:
|
||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -9178,6 +9228,13 @@ packages:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar-fs@2.1.3:
|
||||
resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==}
|
||||
|
||||
tar-stream@2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
teen_process@1.16.0:
|
||||
resolution: {integrity: sha512-RnW7HHZD1XuhSTzD3djYOdIl1adE3oNEprE3HOFFxWs5m4FZsqYRhKJ4mDU2udtNGMLUS7jV7l8vVRLWAvmPDw==}
|
||||
engines: {'0': node}
|
||||
@@ -10059,10 +10116,6 @@ packages:
|
||||
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
whatwg-url@14.0.0:
|
||||
resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
whatwg-url@14.1.1:
|
||||
resolution: {integrity: sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -14247,7 +14300,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.18.0
|
||||
'@typescript-eslint/visitor-keys': 7.18.0
|
||||
debug: 4.4.0
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
@@ -14558,7 +14611,7 @@ snapshots:
|
||||
std-env: 3.8.0
|
||||
test-exclude: 7.0.1
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.0.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.1.0(canvas@3.1.2))(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -14605,7 +14658,7 @@ snapshots:
|
||||
sirv: 3.0.1
|
||||
tinyglobby: 0.2.12
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.0.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.1.0(canvas@3.1.2))(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0)
|
||||
|
||||
'@vitest/utils@3.0.6':
|
||||
dependencies:
|
||||
@@ -14938,12 +14991,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
agent-base@7.1.1:
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
agent-base@7.1.3: {}
|
||||
|
||||
aggregate-error@3.1.0:
|
||||
@@ -15294,6 +15341,12 @@ snapshots:
|
||||
|
||||
birpc@0.2.19: {}
|
||||
|
||||
bl@4.1.0:
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
blob-util@2.0.2: {}
|
||||
|
||||
bluebird@3.7.1: {}
|
||||
@@ -15452,6 +15505,11 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001700: {}
|
||||
|
||||
canvas@3.1.2:
|
||||
dependencies:
|
||||
node-addon-api: 7.1.1
|
||||
prebuild-install: 7.1.3
|
||||
|
||||
caseless@0.12.0: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
@@ -15546,9 +15604,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
chokidar@4.0.3:
|
||||
dependencies:
|
||||
readdirp: 4.1.2
|
||||
chownr@1.1.4: {}
|
||||
|
||||
chrome-trace-event@1.0.4: {}
|
||||
|
||||
@@ -16285,7 +16341,7 @@ snapshots:
|
||||
data-urls@5.0.0:
|
||||
dependencies:
|
||||
whatwg-mimetype: 4.0.0
|
||||
whatwg-url: 14.0.0
|
||||
whatwg-url: 14.1.1
|
||||
|
||||
data-view-buffer@1.0.2:
|
||||
dependencies:
|
||||
@@ -16343,7 +16399,7 @@ snapshots:
|
||||
|
||||
decamelize@1.2.0: {}
|
||||
|
||||
decimal.js@10.4.3: {}
|
||||
decimal.js@10.6.0: {}
|
||||
|
||||
decode-named-character-reference@1.0.2:
|
||||
dependencies:
|
||||
@@ -16378,6 +16434,8 @@ snapshots:
|
||||
which-collection: 1.0.2
|
||||
which-typed-array: 1.1.18
|
||||
|
||||
deep-extend@0.6.0: {}
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
@@ -17075,6 +17133,8 @@ snapshots:
|
||||
|
||||
exit-x@0.2.2: {}
|
||||
|
||||
expand-template@2.0.3: {}
|
||||
|
||||
expect-type@1.1.0: {}
|
||||
|
||||
expect@30.0.4:
|
||||
@@ -17492,6 +17552,8 @@ snapshots:
|
||||
|
||||
fromentries@1.3.2: {}
|
||||
|
||||
fs-constants@1.0.0: {}
|
||||
|
||||
fs-extra@11.1.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@@ -17621,6 +17683,8 @@ snapshots:
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
|
||||
github-from-package@0.0.0: {}
|
||||
|
||||
github-slugger@2.0.0: {}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
@@ -17863,8 +17927,8 @@ snapshots:
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.4.0
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -17920,7 +17984,7 @@ snapshots:
|
||||
https-proxy-agent@7.0.6:
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.0
|
||||
debug: 4.4.1(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -17977,6 +18041,8 @@ snapshots:
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
ini@1.3.8: {}
|
||||
|
||||
ini@2.0.0: {}
|
||||
|
||||
ini@3.0.1: {}
|
||||
@@ -18669,12 +18735,11 @@ snapshots:
|
||||
|
||||
jsdoc-type-pratt-parser@4.1.0: {}
|
||||
|
||||
jsdom@26.0.0:
|
||||
jsdom@26.1.0(canvas@3.1.2):
|
||||
dependencies:
|
||||
cssstyle: 4.2.1
|
||||
data-urls: 5.0.0
|
||||
decimal.js: 10.4.3
|
||||
form-data: 4.0.2
|
||||
decimal.js: 10.6.0
|
||||
html-encoding-sniffer: 4.0.0
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
@@ -18692,6 +18757,8 @@ snapshots:
|
||||
whatwg-url: 14.1.1
|
||||
ws: 8.18.0
|
||||
xml-name-validator: 5.0.0
|
||||
optionalDependencies:
|
||||
canvas: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
@@ -18763,7 +18830,7 @@ snapshots:
|
||||
|
||||
junk@4.0.1: {}
|
||||
|
||||
katex@0.16.11:
|
||||
katex@0.16.22:
|
||||
dependencies:
|
||||
commander: 8.3.0
|
||||
|
||||
@@ -19457,6 +19524,8 @@ snapshots:
|
||||
|
||||
mitt@3.0.1: {}
|
||||
|
||||
mkdirp-classic@0.5.3: {}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
dependencies:
|
||||
minimist: 1.2.8
|
||||
@@ -19505,6 +19574,8 @@ snapshots:
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
|
||||
napi-build-utils@2.0.0: {}
|
||||
|
||||
napi-postinstall@0.3.0: {}
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
@@ -19519,6 +19590,12 @@ snapshots:
|
||||
|
||||
nice-try@1.0.5: {}
|
||||
|
||||
node-abi@3.75.0:
|
||||
dependencies:
|
||||
semver: 7.7.2
|
||||
|
||||
node-addon-api@7.1.1: {}
|
||||
|
||||
node-cleanup@2.1.2: {}
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
@@ -20061,6 +20138,21 @@ snapshots:
|
||||
|
||||
preact@10.26.2: {}
|
||||
|
||||
prebuild-install@7.1.3:
|
||||
dependencies:
|
||||
detect-libc: 2.0.3
|
||||
expand-template: 2.0.3
|
||||
github-from-package: 0.0.0
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 2.0.0
|
||||
node-abi: 3.75.0
|
||||
pump: 3.0.2
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.3
|
||||
tunnel-agent: 0.6.0
|
||||
|
||||
precinct@12.1.2:
|
||||
dependencies:
|
||||
'@dependents/detective-less': 5.0.0
|
||||
@@ -20186,6 +20278,13 @@ snapshots:
|
||||
iconv-lite: 0.6.3
|
||||
unpipe: 1.0.0
|
||||
|
||||
rc@1.2.8:
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
|
||||
react-is@18.3.1: {}
|
||||
|
||||
read-cache@1.0.0:
|
||||
@@ -20227,8 +20326,6 @@ snapshots:
|
||||
dependencies:
|
||||
picomatch: 2.3.1
|
||||
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
real-require@0.2.0: {}
|
||||
|
||||
rechoir@0.6.2:
|
||||
@@ -20794,6 +20891,14 @@ snapshots:
|
||||
|
||||
simple-bin-help@1.8.0: {}
|
||||
|
||||
simple-concat@1.0.1: {}
|
||||
|
||||
simple-get@4.0.1:
|
||||
dependencies:
|
||||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
@@ -21104,6 +21209,8 @@ snapshots:
|
||||
dependencies:
|
||||
min-indent: 1.0.1
|
||||
|
||||
strip-json-comments@2.0.1: {}
|
||||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
stylis@4.3.6: {}
|
||||
@@ -21189,6 +21296,21 @@ snapshots:
|
||||
|
||||
tapable@2.2.1: {}
|
||||
|
||||
tar-fs@2.1.3:
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.2
|
||||
tar-stream: 2.2.0
|
||||
|
||||
tar-stream@2.2.0:
|
||||
dependencies:
|
||||
bl: 4.1.0
|
||||
end-of-stream: 1.4.4
|
||||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
teen_process@1.16.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.9
|
||||
@@ -21767,7 +21889,7 @@ snapshots:
|
||||
vite@5.4.19(@types/node@22.13.5)(terser@5.39.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.5.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.40.2
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.5
|
||||
@@ -21790,7 +21912,7 @@ snapshots:
|
||||
vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0):
|
||||
dependencies:
|
||||
esbuild: 0.24.2
|
||||
postcss: 8.5.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.40.2
|
||||
optionalDependencies:
|
||||
'@types/node': 22.13.5
|
||||
@@ -21875,7 +21997,7 @@ snapshots:
|
||||
- typescript
|
||||
- universal-cookie
|
||||
|
||||
vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.0.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0):
|
||||
vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(@vitest/ui@3.0.6)(jiti@2.4.2)(jsdom@26.1.0(canvas@3.1.2))(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0):
|
||||
dependencies:
|
||||
'@vitest/expect': 3.0.6
|
||||
'@vitest/mocker': 3.0.6(vite@6.1.6(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.0))
|
||||
@@ -21901,7 +22023,7 @@ snapshots:
|
||||
'@types/debug': 4.1.12
|
||||
'@types/node': 22.13.5
|
||||
'@vitest/ui': 3.0.6(vitest@3.0.6)
|
||||
jsdom: 26.0.0
|
||||
jsdom: 26.1.0(canvas@3.1.2)
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
@@ -22176,11 +22298,6 @@ snapshots:
|
||||
|
||||
whatwg-mimetype@4.0.0: {}
|
||||
|
||||
whatwg-url@14.0.0:
|
||||
dependencies:
|
||||
tr46: 5.0.0
|
||||
webidl-conversions: 7.0.0
|
||||
|
||||
whatwg-url@14.1.1:
|
||||
dependencies:
|
||||
tr46: 5.0.0
|
||||
|
@@ -40,6 +40,10 @@
|
||||
{
|
||||
"groupName": "dompurify",
|
||||
"matchPackagePatterns": ["dompurify"]
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["chokidar"],
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"dependencyDashboard": false,
|
||||
|
@@ -16,7 +16,6 @@ export default defineConfig({
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
// TODO: should we move this to a mermaid-core package?
|
||||
setupFiles: ['packages/mermaid/src/tests/setup.ts'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'json', 'html', 'lcov'],
|
||||
|
Reference in New Issue
Block a user