Merge branch 'develop' into UpdateClasstoMatchUmlSpecs

* develop: (56 commits)
  chore: Fix unit tests
  chore(deps): update all patch dependencies
  chore: Update docs
  Update docs
  New Mermaid Live Editor for Confluence Cloud (#4814)
  Update link to Discourse theme component (#4811)
  Update flowchart.md (#4810)
  chore: remove unneeded `CommomDB`
  chore: Update docs
  "CSS" instead of "css" in flowchart.md (#4797)
  Update CONTRIBUTING.md
  Update CONTRIBUTING.md
  fix: typos (#4801)
  chore: Align with convention
  chore: Add JSDoc to apply in sequenceDB
  refactor: Tidy up direction handling
  chore: Fix flowchart arrow
  chore: Add test to verify activate
  chore: Update tests snapshot
  fix: #4691 Align arrowheads properly in sequenceDiagram
  ...
This commit is contained in:
Sidharth Vinod 2023-09-05 23:36:06 +05:30
commit f1a6ef11f0
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
77 changed files with 1686 additions and 941 deletions

View File

@ -71,6 +71,8 @@ Documentation is necessary for all non bugfix/refactoring changes.
Only make changes to files that are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs) Only make changes to files that are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
**_DO NOT CHANGE FILES IN `/docs`_** **_DO NOT CHANGE FILES IN `/docs` MANUALLY_**
The `/docs` folder will be rebuilt and committed as part of a pre-commit hook.
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)

View File

@ -38,7 +38,10 @@
"docsy", "docsy",
"doku", "doku",
"dompurify", "dompurify",
"dont",
"doublecircle",
"edgechromium", "edgechromium",
"elems",
"elkjs", "elkjs",
"elle", "elle",
"faber", "faber",

View File

@ -386,30 +386,6 @@ describe('Class diagram V2', () => {
{ logLevel: 1, flowchart: { htmlLabels: false } } { logLevel: 1, flowchart: { htmlLabels: false } }
); );
}); });
it('18: should handle the direction statement with LR', () => {
imgSnapshotTest(
`
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
it('17a: should handle the direction statement with BT', () => { it('17a: should handle the direction statement with BT', () => {
imgSnapshotTest( imgSnapshotTest(
` `
@ -457,7 +433,31 @@ describe('Class diagram V2', () => {
); );
}); });
it('18: should render a simple class diagram with notes', () => { it('18a: should handle the direction statement with LR', () => {
imgSnapshotTest(
`
classDiagram
direction LR
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
it('18b: should render a simple class diagram with notes', () => {
imgSnapshotTest( imgSnapshotTest(
` `
classDiagram-v2 classDiagram-v2
@ -562,4 +562,13 @@ class C13["With Città foreign language"]
` `
); );
}); });
it('should render a simple class diagram with no members', () => {
imgSnapshotTest(
`
classDiagram-v2
class Class10
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
}); });

View File

@ -38,12 +38,14 @@
+quack() +quack()
} }
class Fish{ class Fish{
-int sizeInFeet -Listint sizeInFeet
-canEat() -canEat()
} }
class Zebra{ class Zebra{
+bool is_wild +bool is_wild
+run() +run(List~T~, List~OT~)
%% +run-composite(List~T, K~)
+run-nested(List~List~OT~~)
} }
</pre> </pre>
@ -80,6 +82,7 @@
Class01 : #size() Class01 : #size()
Class01 : -int chimp Class01 : -int chimp
Class01 : +int gorilla Class01 : +int gorilla
Class01 : +abstractAttribute string*
class Class10~T~ { class Class10~T~ {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
@ -122,6 +125,8 @@
classDiagram classDiagram
direction LR direction LR
Animal ()-- Dog Animal ()-- Dog
Animal ()-- Cat
note for Cat "should have no members area"
Dog : bark() Dog : bark()
Dog : species() Dog : species()
</pre> </pre>
@ -151,6 +156,7 @@
~InternalProperty : string ~InternalProperty : string
~AnotherInternalProperty : List~List~string~~ ~AnotherInternalProperty : List~List~string~~
} }
class People List~List~Person~~
</pre> </pre>
<hr /> <hr />

View File

@ -125,6 +125,21 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
erDiagram
_customer_order {
bigint id PK
bigint customer_id FK
text shipping_address
text delivery_method
timestamp_with_time_zone ordered_at
numeric total_tax_amount
numeric total_price
text payment_method
}
</pre>
<hr />
<script type="module"> <script type="module">
import mermaid from './mermaid.esm.mjs'; import mermaid from './mermaid.esm.mjs';
mermaid.initialize({ mermaid.initialize({

View File

@ -42,7 +42,7 @@ Once the release happens we add a tag to the `release` branch and merge it with
2. Check out the `develop` branch 2. Check out the `develop` branch
3. Create a new branch for your work. Please name the branch following our naming convention below. 3. Create a new branch for your work. Please name the branch following our naming convention below.
We use the follow naming convention for branches: We use the following naming convention for branches:
```txt ```txt
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces] [feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]

View File

@ -22,7 +22,7 @@ In GitHub, you first **fork** a repository when you are going to make changes an
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with. Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentaion, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories). [Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo) [Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)

View File

@ -22,7 +22,7 @@ In GitHub, you first **fork** a repository when you are going to make changes an
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with. Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentaion, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories). [Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo) [Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)

View File

@ -19,7 +19,7 @@ For instance:
#### Store data found during parsing #### Store data found during parsing
There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call a object provided to the parser by the user of the parser. This object can be called during parsing for storing data. There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call an object provided to the parser by the user of the parser. This object can be called during parsing for storing data.
```jison ```jison
statement statement
@ -35,7 +35,7 @@ In the extract of the grammar above, it is defined that a call to the setTitle m
> **Note** > **Note**
> Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user. > Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
For more info look in the example diagram type: For more info look at the example diagram type:
The `yy` object has the following function: The `yy` object has the following function:
@ -54,7 +54,7 @@ parser.yy = db;
### Step 2: Rendering ### Step 2: Rendering
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather then the flowchart renderer as this is a more generic example. Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather than the flowchart renderer as this is a more generic example.
Place the renderer in the diagram folder. Place the renderer in the diagram folder.
@ -62,7 +62,7 @@ Place the renderer in the diagram folder.
The second thing to do is to add the capability to detect the new diagram to type to the detectType in `diagram-api/detectType.ts`. The detection should return a key for the new diagram type. The second thing to do is to add the capability to detect the new diagram to type to the detectType in `diagram-api/detectType.ts`. The detection should return a key for the new diagram type.
[This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type. [This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type.
For example, if your new diagram use a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader For example, if your new diagram uses a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader
would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram. would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram.
Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same. Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same.
@ -122,7 +122,7 @@ There are a few features that are common between the different types of diagrams
- Themes, there is a common way to modify the styling of diagrams in Mermaid. - Themes, there is a common way to modify the styling of diagrams in Mermaid.
- Comments should follow mermaid standards - Comments should follow mermaid standards
Here some pointers on how to handle these different areas. Here are some pointers on how to handle these different areas.
## Accessibility ## Accessibility
@ -140,7 +140,7 @@ See [the definition of aria-roledescription](https://www.w3.org/TR/wai-aria-1.1/
### accessible title and description ### accessible title and description
The syntax for accessible titles and descriptions is described in [the Accessibility documenation section.](../config/accessibility.md) The syntax for accessible titles and descriptions is described in [the Accessibility documentation section.](../config/accessibility.md)
As a design goal, the jison syntax should be similar between the diagrams. As a design goal, the jison syntax should be similar between the diagrams.

View File

@ -126,7 +126,7 @@ The following code snippet changes `theme` to `forest`:
`%%{init: { "theme": "forest" } }%%` `%%{init: { "theme": "forest" } }%%`
Possible theme values are: `default`,`base`, `dark`, `forest` and `neutral`. Possible theme values are: `default`, `base`, `dark`, `forest` and `neutral`.
Default Value is `default`. Default Value is `default`.
Example: Example:
@ -291,7 +291,7 @@ Let us see an example:
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```
@ -300,7 +300,7 @@ Bob->Alice: Cool
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```
@ -317,7 +317,7 @@ By applying that snippet to the diagram above, `wrap` will be enabled:
%%{init: { "sequence": { "wrap": true, "width":300 } } }%% %%{init: { "sequence": { "wrap": true, "width":300 } } }%%
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```
@ -326,7 +326,7 @@ Bob->Alice: Cool
%%{init: { "sequence": { "wrap": true, "width":300 } } }%% %%{init: { "sequence": { "wrap": true, "width":300 } } }%%
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```

View File

@ -41,7 +41,7 @@ pnpm add mermaid
**Hosting mermaid on a web page:** **Hosting mermaid on a web page:**
> Note:This topic explored in greater depth in the [User Guide for Beginners](../intro/getting-started.md) > Note: This topic is explored in greater depth in the [User Guide for Beginners](../intro/getting-started.md)
The easiest way to integrate mermaid on a web page requires two elements: The easiest way to integrate mermaid on a web page requires two elements:
@ -100,7 +100,7 @@ Mermaid can load multiple diagrams, in the same page.
## Enabling Click Event and Tags in Nodes ## Enabling Click Event and Tags in Nodes
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduced in version 8.2 as a security improvement, aimed at preventing malicious use.
**It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.** **It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.**
@ -115,13 +115,13 @@ Values:
- **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled. - **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled.
- **antiscript**: HTML tags in text are allowed (only script elements are removed) and click functionality is enabled. - **antiscript**: HTML tags in text are allowed (only script elements are removed) and click functionality is enabled.
- **loose**: HTML tags in text are allowed and click functionality is enabled. - **loose**: HTML tags in text are allowed and click functionality is enabled.
- **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This prevent any JavaScript from running in the context. This may hinder interactive functionality of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc. - **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This prevents any JavaScript from running in the context. This may hinder interactive functionality of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc.
> **Note** > **Note**
> This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled. > This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
> **sandbox** security level is still in the beta version. > **sandbox** security level is still in the beta version.
**If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.** **If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing. This allows clicks and tags are allowed.**
**To change `securityLevel`, you have to call `mermaid.initialize`:** **To change `securityLevel`, you have to call `mermaid.initialize`:**

View File

@ -49,6 +49,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) (**Native support**) - [LiveBook](https://livebook.dev) (**Native support**)
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview) - [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) - [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid) - [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)

View File

@ -103,7 +103,7 @@ When writing the .html file, we give two instructions inside the html code to th
a. The mermaid code for the diagram we want to create. a. The mermaid code for the diagram we want to create.
b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process.
**a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:** **a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
@ -221,4 +221,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file,
**Comments from Knut Sveidqvist, creator of mermaid:** **Comments from Knut Sveidqvist, creator of mermaid:**
- In early versions of mermaid, the `<script>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works. - In early versions of mermaid, the `<script>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflect the previous way which still works.

View File

@ -90,7 +90,7 @@ Mermaid syntax for ER diagrams is compatible with PlantUML, with an extension to
Where: Where:
- `first-entity` is the name of an entity. Names must begin with an alphabetic character and may also contain digits, hyphens, and underscores. - `first-entity` is the name of an entity. Names must begin with an alphabetic character or an underscore (from v\<MERMAID_RELEASE_VERSION>+), and may also contain digits and hyphens.
- `relationship` describes the way that both entities inter-relate. See below. - `relationship` describes the way that both entities inter-relate. See below.
- `second-entity` is the name of the other entity. - `second-entity` is the name of the other entity.
- `relationship-label` describes the relationship from the perspective of the first entity. - `relationship-label` describes the relationship from the perspective of the first entity.

View File

@ -1051,9 +1051,9 @@ flowchart LR
classDef foobar stroke:#00f classDef foobar stroke:#00f
``` ```
### Css classes ### CSS classes
It is also possible to predefine classes in css styles that can be applied from the graph definition as in the example It is also possible to predefine classes in CSS styles that can be applied from the graph definition as in the example
below: below:
**Example style** **Example style**

View File

@ -58,7 +58,7 @@ mindmap
The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy. The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
In the following example you can see how there are 3 different levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further then the previous lines defining the nodes B and C. In the following example you can see how there are 3 different levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further than the previous lines defining the nodes B and C.
mindmap mindmap
Root Root
@ -66,7 +66,7 @@ In the following example you can see how there are 3 different levels. One with
B B
C C
In summary is a simple text outline where there are one node at the root level called `Root` which has one child `A`. `A` in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap. In summary is a simple text outline where there is one node at the root level called `Root` which has one child `A`. `A` in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap.
```mermaid-example ```mermaid-example
mindmap mindmap
@ -228,7 +228,7 @@ _These classes need to be supplied by the site administrator._
## Unclear indentation ## Unclear indentation
The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can se how the calculations are performed. Let us start with placing C with a smaller indentation than `B`but larger then `A`. The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can see how the calculations are performed. Let us start with placing C with a smaller indentation than `B` but larger then `A`.
mindmap mindmap
Root Root

View File

@ -47,8 +47,8 @@ quadrantChart
## Syntax ## Syntax
> **Note** > **Note**
> If there is no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant. > If there are no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant.
> If there are points **x-axis** labels will rendered from left of the respective quadrant also they will be displayed in bottom of the chart, and **y-axis** lables will be rendered in bottom of the respective quadrant, the quadrant text will render at top of the respective quadrant. > If there are points **x-axis** labels will rendered from the left of the respective quadrant also they will be displayed at the bottom of the chart, and **y-axis** labels will be rendered at the bottom of the respective quadrant, the quadrant text will render at the top of the respective quadrant.
> **Note** > **Note**
> For points x and y value min value is 0 and max value is 1. > For points x and y value min value is 0 and max value is 1.
@ -64,7 +64,7 @@ The title is a short description of the chart and it will always render on top o
### x-axis ### x-axis
The x-axis determine what text would be displayed in the x-axis. In x-axis there is two part **left** and **right** you can pass **both** or you can pass only **left**. The statement should start with `x-axis` then the `left axis text` followed by the delimiter `-->` then `right axis text`. The x-axis determines what text would be displayed in the x-axis. In x-axis there is two part **left** and **right** you can pass **both** or you can pass only **left**. The statement should start with `x-axis` then the `left axis text` followed by the delimiter `-->` then `right axis text`.
#### Example #### Example
@ -73,7 +73,7 @@ The x-axis determine what text would be displayed in the x-axis. In x-axis there
### y-axis ### y-axis
The y-axis determine what text would be displayed in the y-axis. In y-axis there is two part **top** and **bottom** you can pass **both** or you can pass only **bottom**. The statement should start with `y-axis` then the `bottom axis text` followed by the delimiter `-->` then `top axis text`. The y-axis determines what text would be displayed in the y-axis. In y-axis there is two part **top** and **bottom** you can pass **both** or you can pass only **bottom**. The statement should start with `y-axis` then the `bottom axis text` followed by the delimiter `-->` then `top axis text`.
#### Example #### Example

View File

@ -197,7 +197,7 @@ Electricity grid,H2 conversion,27.14
### Empty Lines ### Empty Lines
CSV does not support empty lines without comma delimeters by default. But you can add them if needed: CSV does not support empty lines without comma delimiters by default. But you can add them if needed:
```mermaid-example ```mermaid-example
sankey-beta sankey-beta

View File

@ -164,7 +164,7 @@ The actor(s) can be grouped in vertical boxes. You can define a color (if not, i
end end
A->>J: Hello John, how are you? A->>J: Hello John, how are you?
J->>A: Great! J->>A: Great!
A->>B: Hello Bob, how is Charly ? A->>B: Hello Bob, how is Charly?
B->>C: Hello Charly, how are you? B->>C: Hello Charly, how are you?
``` ```
@ -180,7 +180,7 @@ The actor(s) can be grouped in vertical boxes. You can define a color (if not, i
end end
A->>J: Hello John, how are you? A->>J: Hello John, how are you?
J->>A: Great! J->>A: Great!
A->>B: Hello Bob, how is Charly ? A->>B: Hello Bob, how is Charly?
B->>C: Hello Charly, how are you? B->>C: Hello Charly, how are you?
``` ```

View File

@ -4,7 +4,7 @@
"version": "10.2.4", "version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module", "type": "module",
"packageManager": "pnpm@8.6.12", "packageManager": "pnpm@8.7.1",
"keywords": [ "keywords": [
"diagram", "diagram",
"markdown", "markdown",

View File

@ -117,7 +117,7 @@
"rimraf": "^5.0.0", "rimraf": "^5.0.0",
"start-server-and-test": "^2.0.0", "start-server-and-test": "^2.0.0",
"type-fest": "^4.1.0", "type-fest": "^4.1.0",
"typedoc": "^0.24.5", "typedoc": "^0.25.0",
"typedoc-plugin-markdown": "^3.15.2", "typedoc-plugin-markdown": "^3.15.2",
"typescript": "^5.0.4", "typescript": "^5.0.4",
"unist-util-flatmap": "^1.0.0", "unist-util-flatmap": "^1.0.0",

View File

@ -1,47 +0,0 @@
import { sanitizeText as _sanitizeText } from './diagrams/common/common.js';
import { getConfig } from './config.js';
let title = '';
let diagramTitle = '';
let description = '';
const sanitizeText = (txt: string): string => _sanitizeText(txt, getConfig());
export const clear = function (): void {
title = '';
description = '';
diagramTitle = '';
};
export const setAccTitle = function (txt: string): void {
title = sanitizeText(txt).replace(/^\s+/g, '');
};
export const getAccTitle = function (): string {
return title || diagramTitle;
};
export const setAccDescription = function (txt: string): void {
description = sanitizeText(txt).replace(/\n\s+/g, '\n');
};
export const getAccDescription = function (): string {
return description;
};
export const setDiagramTitle = function (txt: string): void {
diagramTitle = sanitizeText(txt);
};
export const getDiagramTitle = function (): string {
return diagramTitle;
};
export default {
getAccTitle,
setAccTitle,
getDiagramTitle,
setDiagramTitle,
getAccDescription,
setAccDescription,
clear,
};

View File

@ -368,7 +368,20 @@ const cutPathAtIntersect = (_points, boundryNode) => {
return points; return points;
}; };
//(edgePaths, e, edge, clusterDb, diagramtype, graph) /**
* Calculate the deltas and angle between two points
* @param {{x: number, y:number}} point1
* @param {{x: number, y:number}} point2
* @returns {{angle: number, deltaX: number, deltaY: number}}
*/
function calculateDeltaAndAngle(point1, point2) {
const [x1, y1] = [point1.x, point1.y];
const [x2, y2] = [point2.x, point2.y];
const deltaX = x2 - x1;
const deltaY = y2 - y1;
return { angle: Math.atan(deltaY / deltaX), deltaX, deltaY };
}
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph) { export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph) {
let points = edge.points; let points = edge.points;
let pointsHasChanged = false; let pointsHasChanged = false;
@ -435,22 +448,62 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
const lineData = points.filter((p) => !Number.isNaN(p.y)); const lineData = points.filter((p) => !Number.isNaN(p.y));
// This is the accessor function we talked about above // This is the accessor function we talked about above
let curve; let curve = curveBasis;
// Currently only flowcharts get the curve from the settings, perhaps this should // Currently only flowcharts get the curve from the settings, perhaps this should
// be expanded to a common setting? Restricting it for now in order not to cause side-effects that // be expanded to a common setting? Restricting it for now in order not to cause side-effects that
// have not been thought through // have not been thought through
if (diagramType === 'graph' || diagramType === 'flowchart') { if (edge.curve && (diagramType === 'graph' || diagramType === 'flowchart')) {
curve = edge.curve || curveBasis; curve = edge.curve;
} else {
curve = curveBasis;
} }
// curve = curveLinear;
// We need to draw the lines a bit shorter to avoid drawing
// under any transparent markers.
// The offsets are calculated from the markers' dimensions.
const markerOffsets = {
aggregation: 18,
extension: 18,
composition: 18,
dependency: 6,
lollipop: 13.5,
arrow_point: 5.3,
};
const lineFunction = line() const lineFunction = line()
.x(function (d) { .x(function (d, i, data) {
return d.x; let offset = 0;
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
// Handle first point
// Calculate the angle and delta between the first two points
const { angle, deltaX } = calculateDeltaAndAngle(data[0], data[1]);
// Calculate the offset based on the angle and the marker's dimensions
offset = markerOffsets[edge.arrowTypeStart] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1) || 0;
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
// Handle last point
// Calculate the angle and delta between the last two points
const { angle, deltaX } = calculateDeltaAndAngle(
data[data.length - 1],
data[data.length - 2]
);
offset = markerOffsets[edge.arrowTypeEnd] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1) || 0;
}
return d.x + offset;
}) })
.y(function (d) { .y(function (d, i, data) {
return d.y; // Same handling as X above
let offset = 0;
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
const { angle, deltaY } = calculateDeltaAndAngle(data[0], data[1]);
offset =
markerOffsets[edge.arrowTypeStart] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
const { angle, deltaY } = calculateDeltaAndAngle(
data[data.length - 1],
data[data.length - 2]
);
offset =
markerOffsets[edge.arrowTypeEnd] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
}
return d.y + offset;
}) })
.curve(curve); .curve(curve);

View File

@ -155,9 +155,9 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
clearClusters(); clearClusters();
clearGraphlib(); clearGraphlib();
log.warn('Graph at first:', graphlibJson.write(graph)); log.warn('Graph at first:', JSON.stringify(graphlibJson.write(graph)));
adjustClustersAndEdges(graph); adjustClustersAndEdges(graph);
log.warn('Graph after:', graphlibJson.write(graph)); log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph)); // log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
await recursiveRender(elem, graph, diagramtype); await recursiveRender(elem, graph, diagramtype);
}; };

View File

@ -71,7 +71,7 @@ const extension = (elem, type, id) => {
.append('marker') .append('marker')
.attr('id', type + '-extensionStart') .attr('id', type + '-extensionStart')
.attr('class', 'marker extension ' + type) .attr('class', 'marker extension ' + type)
.attr('refX', 0) .attr('refX', 18)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 190) .attr('markerWidth', 190)
.attr('markerHeight', 240) .attr('markerHeight', 240)
@ -85,7 +85,7 @@ const extension = (elem, type, id) => {
.append('marker') .append('marker')
.attr('id', type + '-extensionEnd') .attr('id', type + '-extensionEnd')
.attr('class', 'marker extension ' + type) .attr('class', 'marker extension ' + type)
.attr('refX', 19) .attr('refX', 1)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 20) .attr('markerWidth', 20)
.attr('markerHeight', 28) .attr('markerHeight', 28)
@ -134,7 +134,7 @@ const composition = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-compositionStart') .attr('id', type + '-compositionStart')
.attr('class', 'marker composition ' + type) .attr('class', 'marker composition ' + type)
.attr('refX', 0) .attr('refX', 18)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 190) .attr('markerWidth', 190)
.attr('markerHeight', 240) .attr('markerHeight', 240)
@ -147,7 +147,7 @@ const composition = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-compositionEnd') .attr('id', type + '-compositionEnd')
.attr('class', 'marker composition ' + type) .attr('class', 'marker composition ' + type)
.attr('refX', 19) .attr('refX', 1)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 20) .attr('markerWidth', 20)
.attr('markerHeight', 28) .attr('markerHeight', 28)
@ -161,7 +161,7 @@ const aggregation = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-aggregationStart') .attr('id', type + '-aggregationStart')
.attr('class', 'marker aggregation ' + type) .attr('class', 'marker aggregation ' + type)
.attr('refX', 0) .attr('refX', 18)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 190) .attr('markerWidth', 190)
.attr('markerHeight', 240) .attr('markerHeight', 240)
@ -174,7 +174,7 @@ const aggregation = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-aggregationEnd') .attr('id', type + '-aggregationEnd')
.attr('class', 'marker aggregation ' + type) .attr('class', 'marker aggregation ' + type)
.attr('refX', 19) .attr('refX', 1)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 20) .attr('markerWidth', 20)
.attr('markerHeight', 28) .attr('markerHeight', 28)
@ -188,7 +188,7 @@ const dependency = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-dependencyStart') .attr('id', type + '-dependencyStart')
.attr('class', 'marker dependency ' + type) .attr('class', 'marker dependency ' + type)
.attr('refX', 0) .attr('refX', 6)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 190) .attr('markerWidth', 190)
.attr('markerHeight', 240) .attr('markerHeight', 240)
@ -201,7 +201,7 @@ const dependency = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-dependencyEnd') .attr('id', type + '-dependencyEnd')
.attr('class', 'marker dependency ' + type) .attr('class', 'marker dependency ' + type)
.attr('refX', 19) .attr('refX', 13)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 20) .attr('markerWidth', 20)
.attr('markerHeight', 28) .attr('markerHeight', 28)
@ -215,15 +215,32 @@ const lollipop = (elem, type) => {
.append('marker') .append('marker')
.attr('id', type + '-lollipopStart') .attr('id', type + '-lollipopStart')
.attr('class', 'marker lollipop ' + type) .attr('class', 'marker lollipop ' + type)
.attr('refX', 0) .attr('refX', 13)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 190) .attr('markerWidth', 190)
.attr('markerHeight', 240) .attr('markerHeight', 240)
.attr('orient', 'auto') .attr('orient', 'auto')
.append('circle') .append('circle')
.attr('stroke', 'black') .attr('stroke', 'black')
.attr('fill', 'white') .attr('fill', 'transparent')
.attr('cx', 6) .attr('cx', 7)
.attr('cy', 7)
.attr('r', 6);
elem
.append('defs')
.append('marker')
.attr('id', type + '-lollipopEnd')
.attr('class', 'marker lollipop ' + type)
.attr('refX', 1)
.attr('refY', 7)
.attr('markerWidth', 190)
.attr('markerHeight', 240)
.attr('orient', 'auto')
.append('circle')
.attr('stroke', 'black')
.attr('fill', 'transparent')
.attr('cx', 7)
.attr('cy', 7) .attr('cy', 7)
.attr('r', 6); .attr('r', 6);
}; };
@ -233,7 +250,7 @@ const point = (elem, type) => {
.attr('id', type + '-pointEnd') .attr('id', type + '-pointEnd')
.attr('class', 'marker ' + type) .attr('class', 'marker ' + type)
.attr('viewBox', '0 0 10 10') .attr('viewBox', '0 0 10 10')
.attr('refX', 10) .attr('refX', 6)
.attr('refY', 5) .attr('refY', 5)
.attr('markerUnits', 'userSpaceOnUse') .attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 12) .attr('markerWidth', 12)

View File

@ -291,8 +291,8 @@ export const adjustClustersAndEdges = (graph, depth) => {
shape: 'labelRect', shape: 'labelRect',
style: '', style: '',
}); });
const edge1 = JSON.parse(JSON.stringify(edge)); const edge1 = structuredClone(edge);
const edge2 = JSON.parse(JSON.stringify(edge)); const edge2 = structuredClone(edge);
edge1.label = ''; edge1.label = '';
edge1.arrowTypeEnd = 'none'; edge1.arrowTypeEnd = 'none';
edge2.label = ''; edge2.label = '';

View File

@ -5,7 +5,6 @@ import { getConfig } from '../config.js';
import intersect from './intersect/index.js'; import intersect from './intersect/index.js';
import createLabel from './createLabel.js'; import createLabel from './createLabel.js';
import note from './shapes/note.js'; import note from './shapes/note.js';
import { parseMember } from '../diagrams/class/svgDraw.js';
import { evaluate } from '../diagrams/common/common.js'; import { evaluate } from '../diagrams/common/common.js';
const formatClass = (str) => { const formatClass = (str) => {
@ -880,8 +879,8 @@ const class_box = (parent, node) => {
maxWidth = classTitleBBox.width; maxWidth = classTitleBBox.width;
} }
const classAttributes = []; const classAttributes = [];
node.classData.members.forEach((str) => { node.classData.members.forEach((member) => {
const parsedInfo = parseMember(str); const parsedInfo = member.getDisplayDetails();
let parsedText = parsedInfo.displayText; let parsedText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) { if (getConfig().flowchart.htmlLabels) {
parsedText = parsedText.replace(/</g, '&lt;').replace(/>/g, '&gt;'); parsedText = parsedText.replace(/</g, '&lt;').replace(/>/g, '&gt;');
@ -914,8 +913,8 @@ const class_box = (parent, node) => {
maxHeight += lineHeight; maxHeight += lineHeight;
const classMethods = []; const classMethods = [];
node.classData.methods.forEach((str) => { node.classData.methods.forEach((member) => {
const parsedInfo = parseMember(str); const parsedInfo = member.getDisplayDetails();
let displayText = parsedInfo.displayText; let displayText = parsedInfo.displayText;
if (getConfig().flowchart.htmlLabels) { if (getConfig().flowchart.htmlLabels) {
displayText = displayText.replace(/</g, '&lt;').replace(/>/g, '&gt;'); displayText = displayText.replace(/</g, '&lt;').replace(/>/g, '&gt;');

View File

@ -5,7 +5,7 @@ import { sanitizeText as _sanitizeText } from '../diagrams/common/common.js';
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js'; import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js';
import { addStylesForDiagram } from '../styles.js'; import { addStylesForDiagram } from '../styles.js';
import type { DiagramDefinition, DiagramDetector } from './types.js'; import type { DiagramDefinition, DiagramDetector } from './types.js';
import * as _commonDb from '../commonDb.js'; import * as _commonDb from '../diagrams/common/commonDb.js';
import { parseDirective as _parseDirective } from '../directiveUtils.js'; import { parseDirective as _parseDirective } from '../directiveUtils.js';
/* /*

View File

@ -1,7 +1,12 @@
import mermaidAPI from '../../mermaidAPI.js'; import mermaidAPI from '../../mermaidAPI.js';
import * as configApi from '../../config.js'; import * as configApi from '../../config.js';
import { sanitizeText } from '../common/common.js'; import { sanitizeText } from '../common/common.js';
import { setAccTitle, getAccTitle, getAccDescription, setAccDescription } from '../../commonDb.js'; import {
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
} from '../common/commonDb.js';
let c4ShapeArray = []; let c4ShapeArray = [];
let boundaryParseStack = ['']; let boundaryParseStack = [''];

View File

@ -1,4 +1,3 @@
// @ts-nocheck - don't check until handle it
import type { Selection } from 'd3'; import type { Selection } from 'd3';
import { select } from 'd3'; import { select } from 'd3';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
@ -14,7 +13,8 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
import { ClassMember } from './classTypes.js';
import type { import type {
ClassRelation, ClassRelation,
ClassNode, ClassNode,
@ -71,21 +71,21 @@ export const setClassLabel = function (id: string, label: string) {
* @public * @public
*/ */
export const addClass = function (id: string) { export const addClass = function (id: string) {
const classId = splitClassNameAndType(id); const { className, type } = splitClassNameAndType(id);
// Only add class if not exists // Only add class if not exists
if (classes[classId.className] !== undefined) { if (Object.hasOwn(classes, className)) {
return; return;
} }
classes[classId.className] = { classes[className] = {
id: classId.className, id: className,
type: classId.type, type: type,
label: classId.className, label: className,
cssClasses: [], cssClasses: [],
methods: [], methods: [],
members: [], members: [],
annotations: [], annotations: [],
domId: MERMAID_DOM_ID_PREFIX + classId.className + '-' + classCounter, domId: MERMAID_DOM_ID_PREFIX + className + '-' + classCounter,
} as ClassNode; } as ClassNode;
classCounter++; classCounter++;
@ -115,11 +115,11 @@ export const clear = function () {
commonClear(); commonClear();
}; };
export const getClass = function (id: string) { export const getClass = function (id: string): ClassNode {
return classes[id]; return classes[id];
}; };
export const getClasses = function () { export const getClasses = function (): ClassMap {
return classes; return classes;
}; };
@ -175,6 +175,8 @@ export const addAnnotation = function (className: string, annotation: string) {
* @public * @public
*/ */
export const addMember = function (className: string, member: string) { export const addMember = function (className: string, member: string) {
addClass(className);
const validatedClassName = splitClassNameAndType(className).className; const validatedClassName = splitClassNameAndType(className).className;
const theClass = classes[validatedClassName]; const theClass = classes[validatedClassName];
@ -187,9 +189,9 @@ export const addMember = function (className: string, member: string) {
theClass.annotations.push(sanitizeText(memberString.substring(2, memberString.length - 2))); theClass.annotations.push(sanitizeText(memberString.substring(2, memberString.length - 2)));
} else if (memberString.indexOf(')') > 0) { } else if (memberString.indexOf(')') > 0) {
//its a method //its a method
theClass.methods.push(sanitizeText(memberString)); theClass.methods.push(new ClassMember(memberString, 'method'));
} else if (memberString) { } else if (memberString) {
theClass.members.push(sanitizeText(memberString)); theClass.members.push(new ClassMember(memberString, 'attribute'));
} }
} }
}; };
@ -256,6 +258,7 @@ export const getTooltip = function (id: string, namespace?: string) {
return classes[id].tooltip; return classes[id].tooltip;
}; };
/** /**
* Called by parser when a link is found. Adds the URL to the vertex data. * Called by parser when a link is found. Adds the URL to the vertex data.
* *
@ -369,6 +372,7 @@ export const relationType = {
const setupToolTips = function (element: Element) { const setupToolTips = function (element: Element) {
let tooltipElem: Selection<HTMLDivElement, unknown, HTMLElement, unknown> = let tooltipElem: Selection<HTMLDivElement, unknown, HTMLElement, unknown> =
select('.mermaidTooltip'); select('.mermaidTooltip');
// @ts-expect-error - Incorrect types
if ((tooltipElem._groups || tooltipElem)[0][0] === null) { if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
tooltipElem = select('body').append('div').attr('class', 'mermaidTooltip').style('opacity', 0); tooltipElem = select('body').append('div').attr('class', 'mermaidTooltip').style('opacity', 0);
} }
@ -378,7 +382,6 @@ const setupToolTips = function (element: Element) {
const nodes = svg.selectAll('g.node'); const nodes = svg.selectAll('g.node');
nodes nodes
.on('mouseover', function () { .on('mouseover', function () {
// @ts-expect-error - select is not part of the d3 type definition
const el = select(this); const el = select(this);
const title = el.attr('title'); const title = el.attr('title');
// Don't try to draw a tooltip if no data is provided // Don't try to draw a tooltip if no data is provided
@ -388,6 +391,7 @@ const setupToolTips = function (element: Element) {
// @ts-ignore - getBoundingClientRect is not part of the d3 type definition // @ts-ignore - getBoundingClientRect is not part of the d3 type definition
const rect = this.getBoundingClientRect(); const rect = this.getBoundingClientRect();
// @ts-expect-error - Incorrect types
tooltipElem.transition().duration(200).style('opacity', '.9'); tooltipElem.transition().duration(200).style('opacity', '.9');
tooltipElem tooltipElem
.text(el.attr('title')) .text(el.attr('title'))
@ -397,8 +401,8 @@ const setupToolTips = function (element: Element) {
el.classed('hover', true); el.classed('hover', true);
}) })
.on('mouseout', function () { .on('mouseout', function () {
// @ts-expect-error - Incorrect types
tooltipElem.transition().duration(500).style('opacity', 0); tooltipElem.transition().duration(500).style('opacity', 0);
// @ts-expect-error - select is not part of the d3 type definition
const el = select(this); const el = select(this);
el.classed('hover', false); el.classed('hover', false);
}); });

View File

@ -4,6 +4,9 @@ import classDb from './classDb.js';
import { vi, describe, it, expect } from 'vitest'; import { vi, describe, it, expect } from 'vitest';
const spyOn = vi.spyOn; const spyOn = vi.spyOn;
const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
describe('given a basic class diagram, ', function () { describe('given a basic class diagram, ', function () {
describe('when parsing class definition', function () { describe('when parsing class definition', function () {
beforeEach(function () { beforeEach(function () {
@ -127,7 +130,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('member1'); expect(c1.members[0].getDisplayDetails().displayText).toBe('member1');
}); });
it('should parse a class with a text label, member and annotation', () => { it('should parse a class with a text label, member and annotation', () => {
@ -142,7 +145,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('int member1'); expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
expect(c1.annotations.length).toBe(1); expect(c1.annotations.length).toBe(1);
expect(c1.annotations[0]).toBe('interface'); expect(c1.annotations[0]).toBe('interface');
}); });
@ -168,7 +171,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members[0]).toBe('int member1'); expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
expect(c1.cssClasses[0]).toBe('styleClass'); expect(c1.cssClasses[0]).toBe('styleClass');
}); });
@ -371,6 +374,74 @@ class C13["With Città foreign language"]
note ${keyword}`; note ${keyword}`;
expect(() => parser.parse(str)).toThrowError(/(Expecting\s'STR'|Unrecognized\stext)/); expect(() => parser.parse(str)).toThrowError(/(Expecting\s'STR'|Unrecognized\stext)/);
}); });
it('should parse diagram with direction', () => {
parser.parse(`classDiagram
direction TB
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides`);
expect(Object.keys(classDb.getClasses()).length).toBe(3);
expect(classDb.getClasses().Student).toMatchInlineSnapshot(`
{
"annotations": [],
"cssClasses": [],
"domId": "classId-Student-134",
"id": "Student",
"label": "Student",
"members": [
ClassMember {
"classifier": "",
"id": "idCard : IdCard",
"memberType": "attribute",
"visibility": "-",
},
],
"methods": [],
"type": "",
}
`);
expect(classDb.getRelations().length).toBe(2);
expect(classDb.getRelations()).toMatchInlineSnapshot(`
[
{
"id1": "Student",
"id2": "IdCard",
"relation": {
"lineType": 0,
"type1": "none",
"type2": 0,
},
"relationTitle1": "1",
"relationTitle2": "1",
"title": "carries",
},
{
"id1": "Student",
"id2": "Bike",
"relation": {
"lineType": 0,
"type1": "none",
"type2": 0,
},
"relationTitle1": "1",
"relationTitle2": "1",
"title": "rides",
},
]
`);
});
}); });
describe('when parsing class defined in brackets', function () { describe('when parsing class defined in brackets', function () {
@ -422,8 +493,8 @@ class C13["With Città foreign language"]
'classDiagram\n' + 'classDiagram\n' +
'class Class1 {\n' + 'class Class1 {\n' +
'int testMember\n' + 'int testMember\n' +
'string fooMember\n' +
'test()\n' + 'test()\n' +
'string fooMember\n' +
'foo()\n' + 'foo()\n' +
'}'; '}';
parser.parse(str); parser.parse(str);
@ -431,10 +502,10 @@ class C13["With Città foreign language"]
const actual = parser.yy.getClass('Class1'); const actual = parser.yy.getClass('Class1');
expect(actual.members.length).toBe(2); expect(actual.members.length).toBe(2);
expect(actual.methods.length).toBe(2); expect(actual.methods.length).toBe(2);
expect(actual.members[0]).toBe('int testMember'); expect(actual.members[0].getDisplayDetails().displayText).toBe('int testMember');
expect(actual.members[1]).toBe('string fooMember'); expect(actual.members[1].getDisplayDetails().displayText).toBe('string fooMember');
expect(actual.methods[0]).toBe('test()'); expect(actual.methods[0].getDisplayDetails().displayText).toBe('test()');
expect(actual.methods[1]).toBe('foo()'); expect(actual.methods[1].getDisplayDetails().displayText).toBe('foo()');
}); });
it('should parse a class with a text label and members', () => { it('should parse a class with a text label and members', () => {
@ -444,7 +515,7 @@ class C13["With Città foreign language"]
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('+member1'); expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
}); });
it('should parse a class with a text label, members and annotation', () => { it('should parse a class with a text label, members and annotation', () => {
@ -459,7 +530,7 @@ class C13["With Città foreign language"]
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('+member1'); expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
expect(c1.annotations.length).toBe(1); expect(c1.annotations.length).toBe(1);
expect(c1.annotations[0]).toBe('interface'); expect(c1.annotations[0]).toBe('interface');
}); });
@ -742,6 +813,20 @@ describe('given a class diagram with members and methods ', function () {
parser.parse(str); parser.parse(str);
}); });
it('should handle direct member declaration', function () {
parser.parse('classDiagram\n' + 'Car : wheels');
const car = classDb.getClass('Car');
expect(car.members.length).toBe(1);
expect(car.members[0].id).toBe('wheels');
});
it('should handle direct member declaration with type', function () {
parser.parse('classDiagram\n' + 'Car : int wheels');
const car = classDb.getClass('Car');
expect(car.members.length).toBe(1);
expect(car.members[0].id).toBe('int wheels');
});
it('should handle simple member declaration with type', function () { it('should handle simple member declaration with type', function () {
const str = 'classDiagram\n' + 'class Car\n' + 'Car : int wheels'; const str = 'classDiagram\n' + 'class Car\n' + 'Car : int wheels';
@ -762,10 +847,10 @@ describe('given a class diagram with members and methods ', function () {
const actual = parser.yy.getClass('actual'); const actual = parser.yy.getClass('actual');
expect(actual.members.length).toBe(4); expect(actual.members.length).toBe(4);
expect(actual.methods.length).toBe(0); expect(actual.methods.length).toBe(0);
expect(actual.members[0]).toBe('-int privateMember'); expect(actual.members[0].getDisplayDetails().displayText).toBe('-int privateMember');
expect(actual.members[1]).toBe('+int publicMember'); expect(actual.members[1].getDisplayDetails().displayText).toBe('+int publicMember');
expect(actual.members[2]).toBe('#int protectedMember'); expect(actual.members[2].getDisplayDetails().displayText).toBe('#int protectedMember');
expect(actual.members[3]).toBe('~int privatePackage'); expect(actual.members[3].getDisplayDetails().displayText).toBe('~int privatePackage');
}); });
it('should handle generic types', function () { it('should handle generic types', function () {
@ -818,7 +903,9 @@ describe('given a class diagram with members and methods ', function () {
expect(actual.annotations.length).toBe(0); expect(actual.annotations.length).toBe(0);
expect(actual.members.length).toBe(0); expect(actual.members.length).toBe(0);
expect(actual.methods.length).toBe(1); expect(actual.methods.length).toBe(1);
expect(actual.methods[0]).toBe('someMethod()*'); const method = actual.methods[0];
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
expect(method.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
}); });
it('should handle static methods', function () { it('should handle static methods', function () {
@ -829,7 +916,9 @@ describe('given a class diagram with members and methods ', function () {
expect(actual.annotations.length).toBe(0); expect(actual.annotations.length).toBe(0);
expect(actual.members.length).toBe(0); expect(actual.members.length).toBe(0);
expect(actual.methods.length).toBe(1); expect(actual.methods.length).toBe(1);
expect(actual.methods[0]).toBe('someMethod()$'); const method = actual.methods[0];
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
expect(method.getDisplayDetails().cssStyle).toBe(staticCssStyle);
}); });
it('should handle generic types in arguments', function () { it('should handle generic types in arguments', function () {
@ -955,53 +1044,6 @@ foo()
parser.parse(str); parser.parse(str);
}); });
}); });
describe('when parsing invalid generic classes', function () {
beforeEach(function () {
classDb.clear();
parser.yy = classDb;
});
it('should break when another `{`is encountered before closing the first one while defining generic class with brackets', function () {
const str =
'classDiagram\n' +
'class Dummy_Class~T~ {\n' +
'String data\n' +
' void methods()\n' +
'}\n' +
'\n' +
'class Dummy_Class {\n' +
'class Flight {\n' +
' flightNumber : Integer\n' +
' departureTime : Date\n' +
'}';
let testPassed = false;
try {
parser.parse(str);
} catch (error) {
testPassed = true;
}
expect(testPassed).toBe(true);
});
it('should break when EOF is encountered before closing the first `{` while defining generic class with brackets', function () {
const str =
'classDiagram\n' +
'class Dummy_Class~T~ {\n' +
'String data\n' +
' void methods()\n' +
'}\n' +
'\n' +
'class Dummy_Class {\n';
let testPassed = false;
try {
parser.parse(str);
} catch (error) {
testPassed = true;
}
expect(testPassed).toBe(true);
});
});
}); });
describe('given a class diagram with relationships, ', function () { describe('given a class diagram with relationships, ', function () {
@ -1276,10 +1318,10 @@ describe('given a class diagram with relationships, ', function () {
const testClass = parser.yy.getClass('Class1'); const testClass = parser.yy.getClass('Class1');
expect(testClass.members.length).toBe(2); expect(testClass.members.length).toBe(2);
expect(testClass.methods.length).toBe(2); expect(testClass.methods.length).toBe(2);
expect(testClass.members[0]).toBe('int : test'); expect(testClass.members[0].getDisplayDetails().displayText).toBe('int : test');
expect(testClass.members[1]).toBe('string : foo'); expect(testClass.members[1].getDisplayDetails().displayText).toBe('string : foo');
expect(testClass.methods[0]).toBe('test()'); expect(testClass.methods[0].getDisplayDetails().displayText).toBe('test()');
expect(testClass.methods[1]).toBe('foo()'); expect(testClass.methods[1].getDisplayDetails().displayText).toBe('foo()');
}); });
it('should handle abstract methods', function () { it('should handle abstract methods', function () {
@ -1290,7 +1332,9 @@ describe('given a class diagram with relationships, ', function () {
expect(testClass.annotations.length).toBe(0); expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0); expect(testClass.members.length).toBe(0);
expect(testClass.methods.length).toBe(1); expect(testClass.methods.length).toBe(1);
expect(testClass.methods[0]).toBe('someMethod()*'); const method = testClass.methods[0];
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
expect(method.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
}); });
it('should handle static methods', function () { it('should handle static methods', function () {
@ -1301,7 +1345,9 @@ describe('given a class diagram with relationships, ', function () {
expect(testClass.annotations.length).toBe(0); expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0); expect(testClass.members.length).toBe(0);
expect(testClass.methods.length).toBe(1); expect(testClass.methods.length).toBe(1);
expect(testClass.methods[0]).toBe('someMethod()$'); const method = testClass.methods[0];
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
expect(method.getDisplayDetails().cssStyle).toBe(staticCssStyle);
}); });
it('should associate link and css appropriately', function () { it('should associate link and css appropriately', function () {
@ -1516,11 +1562,19 @@ class Class2
const testClasses = parser.yy.getClasses(); const testClasses = parser.yy.getClasses();
const testRelations = parser.yy.getRelations(); const testRelations = parser.yy.getRelations();
expect(Object.keys(testNamespaceA.classes).length).toBe(2); expect(Object.keys(testNamespaceA.classes).length).toBe(2);
expect(testNamespaceA.classes['A1'].members[0]).toBe('+foo : string'); expect(testNamespaceA.classes['A1'].members[0].getDisplayDetails().displayText).toBe(
expect(testNamespaceA.classes['A2'].members[0]).toBe('+bar : int'); '+foo : string'
);
expect(testNamespaceA.classes['A2'].members[0].getDisplayDetails().displayText).toBe(
'+bar : int'
);
expect(Object.keys(testNamespaceB.classes).length).toBe(2); expect(Object.keys(testNamespaceB.classes).length).toBe(2);
expect(testNamespaceB.classes['B1'].members[0]).toBe('+foo : bool'); expect(testNamespaceB.classes['B1'].members[0].getDisplayDetails().displayText).toBe(
expect(testNamespaceB.classes['B2'].members[0]).toBe('+bar : float'); '+foo : bool'
);
expect(testNamespaceB.classes['B2'].members[0].getDisplayDetails().displayText).toBe(
'+bar : float'
);
expect(Object.keys(testClasses).length).toBe(4); expect(Object.keys(testClasses).length).toBe(4);
expect(testClasses['A1'].parent).toBe('A'); expect(testClasses['A1'].parent).toBe('A');
expect(testClasses['A2'].parent).toBe('A'); expect(testClasses['A2'].parent).toBe('A');
@ -1572,8 +1626,8 @@ class Class2
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('+member1'); const member = c1.members[0];
expect(member.getDisplayDetails().displayText).toBe('+member1');
const c2 = classDb.getClass('C2'); const c2 = classDb.getClass('C2');
expect(c2.label).toBe('C2'); expect(c2.label).toBe('C2');
}); });
@ -1589,9 +1643,10 @@ class Class2
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1); expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
expect(c1.annotations.length).toBe(1); expect(c1.annotations.length).toBe(1);
expect(c1.annotations[0]).toBe('interface'); expect(c1.annotations[0]).toBe('interface');
const member = c1.members[0];
expect(member.getDisplayDetails().displayText).toBe('+member1');
const c2 = classDb.getClass('C2'); const c2 = classDb.getClass('C2');
expect(c2.label).toBe('C2'); expect(c2.label).toBe('C2');
@ -1608,8 +1663,9 @@ C1 --> C2
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.cssClasses.length).toBe(1); expect(c1.cssClasses.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
expect(c1.cssClasses[0]).toBe('styleClass'); expect(c1.cssClasses[0]).toBe('styleClass');
const member = c1.members[0];
expect(member.getDisplayDetails().displayText).toBe('+member1');
}); });
it('should parse a class with text label and css class', () => { it('should parse a class with text label and css class', () => {
@ -1624,8 +1680,9 @@ cssClass "C1" styleClass
const c1 = classDb.getClass('C1'); const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label'); expect(c1.label).toBe('Class 1 with text label');
expect(c1.cssClasses.length).toBe(1); expect(c1.cssClasses.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
expect(c1.cssClasses[0]).toBe('styleClass'); expect(c1.cssClasses[0]).toBe('styleClass');
const member = c1.members[0];
expect(member.getDisplayDetails().displayText).toBe('+member1');
}); });
it('should parse two classes with text labels and css classes', () => { it('should parse two classes with text labels and css classes', () => {

View File

@ -1,78 +0,0 @@
import { setConfig } from '../../config.js';
import classDB from './classDb.js';
// @ts-ignore - no types in jison
import classDiagram from './parser/classDiagram.jison';
setConfig({
securityLevel: 'strict',
});
describe('when parsing class diagram', function () {
beforeEach(function () {
classDiagram.parser.yy = classDB;
classDiagram.parser.yy.clear();
});
it('should parse diagram with direction', () => {
classDiagram.parser.parse(`classDiagram
direction TB
class Student {
-idCard : IdCard
}
class IdCard{
-id : int
-name : string
}
class Bike{
-id : int
-name : string
}
Student "1" --o "1" IdCard : carries
Student "1" --o "1" Bike : rides`);
expect(Object.keys(classDB.getClasses()).length).toBe(3);
expect(classDB.getClasses().Student).toMatchInlineSnapshot(`
{
"annotations": [],
"cssClasses": [],
"domId": "classId-Student-0",
"id": "Student",
"label": "Student",
"members": [
"-idCard : IdCard",
],
"methods": [],
"type": "",
}
`);
expect(classDB.getRelations().length).toBe(2);
expect(classDB.getRelations()).toMatchInlineSnapshot(`
[
{
"id1": "Student",
"id2": "IdCard",
"relation": {
"lineType": 0,
"type1": "none",
"type2": 0,
},
"relationTitle1": "1",
"relationTitle2": "1",
"title": "carries",
},
{
"id1": "Student",
"id2": "Bike",
"relation": {
"lineType": 0,
"type1": "none",
"type2": 0,
},
"relationTitle1": "1",
"relationTitle2": "1",
"title": "rides",
},
]
`);
});
});

View File

@ -156,24 +156,17 @@ export const addNotes = function (
) { ) {
log.info(notes); log.info(notes);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
notes.forEach(function (note, i) { notes.forEach(function (note, i) {
const vertex = note; const vertex = note;
/**
* Variable for storing the classes for the vertex
*
*/
const cssNoteStr = ''; const cssNoteStr = '';
const styles = { labelStyle: '', style: '' }; const styles = { labelStyle: '', style: '' };
// Use vertex id as text in the box if no text is provided by the graph definition
const vertexText = vertex.text; const vertexText = vertex.text;
const radius = 0; const radius = 0;
const shape = 'note'; const shape = 'note';
// Add the node
const node = { const node = {
labelStyle: styles.labelStyle, labelStyle: styles.labelStyle,
shape: shape, shape: shape,
@ -301,7 +294,7 @@ export const setConf = function (cnf: any) {
}; };
/** /**
* Draws a flowchart in the tag with id: id based on the graph definition in text. * Draws a class diagram in the tag with id: id based on the definition in text.
* *
* @param text - * @param text -
* @param id - * @param id -

View File

@ -0,0 +1,683 @@
import { ClassMember } from './classTypes.js';
import { vi, describe, it, expect } from 'vitest';
const spyOn = vi.spyOn;
const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
describe('given text representing a method, ', function () {
describe('when method has no parameters', function () {
it('should parse correctly', function () {
const str = `getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime()');
});
it('should handle private visibility', function () {
const str = `-getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime()');
});
it('should handle protected visibility', function () {
const str = `#getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime()');
});
it('should handle internal visibility', function () {
const str = `~getTime()`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime()');
});
it('should return correct css for static classifier', function () {
const str = `getTime()$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime()*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime()');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has single parameter value', function () {
it('should parse correctly', function () {
const str = `getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(int)');
});
it('should handle private visibility', function () {
const str = `-getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(int)');
});
it('should handle protected visibility', function () {
const str = `#getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(int)');
});
it('should handle internal visibility', function () {
const str = `~getTime(int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(int)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(int)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has single parameter type and name (type first)', function () {
it('should parse correctly', function () {
const str = `getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(int count)');
});
it('should handle private visibility', function () {
const str = `-getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(int count)');
});
it('should handle protected visibility', function () {
const str = `#getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(int count)');
});
it('should handle internal visibility', function () {
const str = `~getTime(int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(int count)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(int count)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(int count)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has single parameter type and name (name first)', function () {
it('should parse correctly', function () {
const str = `getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime(count int)');
});
it('should handle private visibility', function () {
const str = `-getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime(count int)');
});
it('should handle protected visibility', function () {
const str = `#getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime(count int)');
});
it('should handle internal visibility', function () {
const str = `~getTime(count int)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime(count int)');
});
it('should return correct css for static classifier', function () {
const str = `getTime(count int)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(count int)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(count int)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has multiple parameters', function () {
it('should parse correctly', function () {
const str = `getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle public visibility', function () {
const str = `+getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle private visibility', function () {
const str = `-getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle protected visibility', function () {
const str = `#getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should handle internal visibility', function () {
const str = `~getTime(string text, int count)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(str);
});
it('should return correct css for static classifier', function () {
const str = `getTime(string text, int count)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime(string text, int count)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime(string text, int count)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method has return type', function () {
it('should parse correctly', function () {
const str = `getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
});
it('should handle public visibility', function () {
const str = `+getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTime() : DateTime');
});
it('should handle private visibility', function () {
const str = `-getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTime() : DateTime');
});
it('should handle protected visibility', function () {
const str = `#getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTime() : DateTime');
});
it('should handle internal visibility', function () {
const str = `~getTime() DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTime() : DateTime');
});
it('should return correct css for static classifier', function () {
const str = `getTime() DateTime$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTime() DateTime*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTime() : DateTime');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is generic', function () {
it('should parse correctly', function () {
const str = `getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
});
it('should handle public visibility', function () {
const str = `+getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimes(List<T>)');
});
it('should handle private visibility', function () {
const str = `-getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimes(List<T>)');
});
it('should handle protected visibility', function () {
const str = `#getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimes(List<T>)');
});
it('should handle internal visibility', function () {
const str = `~getTimes(List~T~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimes(List<T>)');
});
it('should return correct css for static classifier', function () {
const str = `getTimes(List~T~)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimes(List~T~)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter contains two generic', function () {
it('should parse correctly', function () {
const str = `getTimes(List~T~, List~OT~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
});
it('should handle public visibility', function () {
const str = `+getTimes(List~T~, List~OT~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimes(List<T>, List<OT>)');
});
it('should handle private visibility', function () {
const str = `-getTimes(List~T~, List~OT~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimes(List<T>, List<OT>)');
});
it('should handle protected visibility', function () {
const str = `#getTimes(List~T~, List~OT~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimes(List<T>, List<OT>)');
});
it('should handle internal visibility', function () {
const str = `~getTimes(List~T~, List~OT~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimes(List<T>, List<OT>)');
});
it('should return correct css for static classifier', function () {
const str = `getTimes(List~T~, List~OT~)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimes(List~T~, List~OT~)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes(List<T>, List<OT>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is a nested generic', function () {
it('should parse correctly', function () {
const str = `getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
});
it('should handle public visibility', function () {
const str = `+getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimetableList(List<List<T>>)');
});
it('should handle private visibility', function () {
const str = `-getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimetableList(List<List<T>>)');
});
it('should handle protected visibility', function () {
const str = `#getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimetableList(List<List<T>>)');
});
it('should handle internal visibility', function () {
const str = `~getTimetableList(List~List~T~~)`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimetableList(List<List<T>>)');
});
it('should return correct css for static classifier', function () {
const str = `getTimetableList(List~List~T~~)$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimetableList(List~List~T~~)*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimetableList(List<List<T>>)');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method parameter is a composite generic', function () {
const methodNameAndParameters = 'getTimes(List~K, V~)';
const expectedMethodNameAndParameters = 'getTimes(List<K, V>)';
it('should parse correctly', function () {
const str = methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
});
it('should handle public visibility', function () {
const str = '+' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'+' + expectedMethodNameAndParameters
);
});
it('should handle private visibility', function () {
const str = '-' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'-' + expectedMethodNameAndParameters
);
});
it('should handle protected visibility', function () {
const str = '#' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'#' + expectedMethodNameAndParameters
);
});
it('should handle internal visibility', function () {
const str = '~' + methodNameAndParameters;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'~' + expectedMethodNameAndParameters
);
});
it('should return correct css for static classifier', function () {
const str = methodNameAndParameters + '$';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = methodNameAndParameters + '*';
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(expectedMethodNameAndParameters);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method return type is generic', function () {
it('should parse correctly', function () {
const str = `getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
});
it('should handle public visibility', function () {
const str = `+getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('+getTimes() : List<T>');
});
it('should handle private visibility', function () {
const str = `-getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('-getTimes() : List<T>');
});
it('should handle protected visibility', function () {
const str = `#getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('#getTimes() : List<T>');
});
it('should handle internal visibility', function () {
const str = `~getTimes() List~T~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('~getTimes() : List<T>');
});
it('should return correct css for static classifier', function () {
const str = `getTimes() List~T~$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimes() List~T~*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe('getTimes() : List<T>');
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('when method return type is a nested generic', function () {
it('should parse correctly', function () {
const str = `getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
});
it('should handle public visibility', function () {
const str = `+getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'+getTimetableList() : List<List<T>>'
);
});
it('should handle private visibility', function () {
const str = `-getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'-getTimetableList() : List<List<T>>'
);
});
it('should handle protected visibility', function () {
const str = `#getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'#getTimetableList() : List<List<T>>'
);
});
it('should handle internal visibility', function () {
const str = `~getTimetableList() List~List~T~~`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'~getTimetableList() : List<List<T>>'
);
});
it('should return correct css for static classifier', function () {
const str = `getTimetableList() List~List~T~~$`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
it('should return correct css for abstract classifier', function () {
const str = `getTimetableList() List~List~T~~*`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTimetableList() : List<List<T>>'
);
expect(classMember.getDisplayDetails().cssStyle).toBe(abstractCssStyle);
});
});
describe('--uncategorized tests--', function () {
it('member name should handle double colons', function () {
const str = `std::map ~int,string~ pMap;`;
const classMember = new ClassMember(str, 'attribute');
expect(classMember.getDisplayDetails().displayText).toBe('std::map <int,string> pMap;');
});
it('member name should handle generic type', function () {
const str = `getTime~T~(this T, int seconds)$ DateTime`;
const classMember = new ClassMember(str, 'method');
expect(classMember.getDisplayDetails().displayText).toBe(
'getTime<T>(this T, int seconds) : DateTime'
);
expect(classMember.getDisplayDetails().cssStyle).toBe(staticCssStyle);
});
});
});

View File

@ -1,10 +1,13 @@
import { getConfig } from '../../config.js';
import { parseGenericTypes, sanitizeText } from '../common/common.js';
export interface ClassNode { export interface ClassNode {
id: string; id: string;
type: string; type: string;
label: string; label: string;
cssClasses: string[]; cssClasses: string[];
methods: string[]; methods: ClassMember[];
members: string[]; members: ClassMember[];
annotations: string[]; annotations: string[];
domId: string; domId: string;
parent?: string; parent?: string;
@ -14,6 +17,120 @@ export interface ClassNode {
tooltip?: string; tooltip?: string;
} }
export type Visibility = '#' | '+' | '~' | '-' | '';
export const visibilityValues = ['#', '+', '~', '-', ''];
/**
* Parses and stores class diagram member variables/methods.
*
*/
export class ClassMember {
id!: string;
cssStyle!: string;
memberType!: 'method' | 'attribute';
visibility!: Visibility;
/**
* denote if static or to determine which css class to apply to the node
* @defaultValue ''
*/
classifier!: string;
/**
* parameters for method
* @defaultValue ''
*/
parameters!: string;
/**
* return type for method
* @defaultValue ''
*/
returnType!: string;
constructor(input: string, memberType: 'method' | 'attribute') {
this.memberType = memberType;
this.visibility = '';
this.classifier = '';
const sanitizedInput = sanitizeText(input, getConfig());
this.parseMember(sanitizedInput);
}
getDisplayDetails() {
let displayText = this.visibility + parseGenericTypes(this.id);
if (this.memberType === 'method') {
displayText += `(${parseGenericTypes(this.parameters.trim())})`;
if (this.returnType) {
displayText += ' : ' + parseGenericTypes(this.returnType);
}
}
displayText = displayText.trim();
const cssStyle = this.parseClassifier();
return {
displayText,
cssStyle,
};
}
parseMember(input: string) {
let potentialClassifier = '';
if (this.memberType === 'method') {
const methodRegEx = /([#+~-])?(.+)\((.*)\)([\s$*])?(.*)([$*])?/;
const match = input.match(methodRegEx);
if (match) {
const detectedVisibility = match[1] ? match[1].trim() : '';
if (visibilityValues.includes(detectedVisibility)) {
this.visibility = detectedVisibility as Visibility;
}
this.id = match[2].trim();
this.parameters = match[3] ? match[3].trim() : '';
potentialClassifier = match[4] ? match[4].trim() : '';
this.returnType = match[5] ? match[5].trim() : '';
if (potentialClassifier === '') {
const lastChar = this.returnType.substring(this.returnType.length - 1);
if (lastChar.match(/[$*]/)) {
potentialClassifier = lastChar;
this.returnType = this.returnType.substring(0, this.returnType.length - 1);
}
}
}
} else {
const length = input.length;
const firstChar = input.substring(0, 1);
const lastChar = input.substring(length - 1);
if (visibilityValues.includes(firstChar)) {
this.visibility = firstChar as Visibility;
}
if (lastChar.match(/[*?]/)) {
potentialClassifier = lastChar;
}
this.id = input.substring(
this.visibility === '' ? 0 : 1,
potentialClassifier === '' ? length : length - 1
);
}
this.classifier = potentialClassifier;
}
parseClassifier() {
switch (this.classifier) {
case '*':
return 'font-style:italic;';
case '$':
return 'text-decoration:underline;';
default:
return '';
}
}
}
export interface ClassNote { export interface ClassNote {
id: string; id: string;
class: string; class: string;

View File

@ -233,21 +233,14 @@ start
| statements | statements
; ;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
mermaidDoc mermaidDoc
: graphConfig : graphConfig
; ;
graphConfig
: CLASS_DIAGRAM NEWLINE statements EOF
;
directive directive
: openDirective typeDirective closeDirective NEWLINE : openDirective typeDirective closeDirective NEWLINE
| openDirective typeDirective ':' argDirective closeDirective NEWLINE | openDirective typeDirective ':' argDirective closeDirective NEWLINE
@ -269,10 +262,6 @@ closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'class'); } : close_directive { yy.parseDirective('}%%', 'close_directive', 'class'); }
; ;
graphConfig
: CLASS_DIAGRAM NEWLINE statements EOF
;
statements statements
: statement : statement
| statement NEWLINE | statement NEWLINE
@ -301,7 +290,7 @@ statement
| relationStatement LABEL { $1.title = yy.cleanupLabel($2); yy.addRelation($1); } | relationStatement LABEL { $1.title = yy.cleanupLabel($2); yy.addRelation($1); }
| namespaceStatement | namespaceStatement
| classStatement | classStatement
| methodStatement | memberStatement
| annotationStatement | annotationStatement
| clickStatement | clickStatement
| cssClassStatement | cssClassStatement
@ -348,7 +337,7 @@ members
| MEMBER members { $2.push($1);$$=$2;} | MEMBER members { $2.push($1);$$=$2;}
; ;
methodStatement memberStatement
: className {/*console.log('Rel found',$1);*/} : className {/*console.log('Rel found',$1);*/}
| className LABEL {yy.addMember($1,yy.cleanupLabel($2));} | className LABEL {yy.addMember($1,yy.cleanupLabel($2));}
| MEMBER {/*console.warn('Member',$1);*/} | MEMBER {/*console.warn('Member',$1);*/}
@ -367,6 +356,17 @@ noteStatement
| NOTE noteText { yy.addNote($2); } | NOTE noteText { yy.addNote($2); }
; ;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
relation relation
: relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; } : relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; }
| lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; } | lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; }

View File

@ -109,25 +109,25 @@ g.classGroup line {
} }
#extensionStart, .extension { #extensionStart, .extension {
fill: ${options.mainBkg} !important; fill: transparent !important;
stroke: ${options.lineColor} !important; stroke: ${options.lineColor} !important;
stroke-width: 1; stroke-width: 1;
} }
#extensionEnd, .extension { #extensionEnd, .extension {
fill: ${options.mainBkg} !important; fill: transparent !important;
stroke: ${options.lineColor} !important; stroke: ${options.lineColor} !important;
stroke-width: 1; stroke-width: 1;
} }
#aggregationStart, .aggregation { #aggregationStart, .aggregation {
fill: ${options.mainBkg} !important; fill: transparent !important;
stroke: ${options.lineColor} !important; stroke: ${options.lineColor} !important;
stroke-width: 1; stroke-width: 1;
} }
#aggregationEnd, .aggregation { #aggregationEnd, .aggregation {
fill: ${options.mainBkg} !important; fill: transparent !important;
stroke: ${options.lineColor} !important; stroke: ${options.lineColor} !important;
stroke-width: 1; stroke-width: 1;
} }

View File

@ -174,7 +174,6 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
// add class group // add class group
const g = elem.append('g').attr('id', diagObj.db.lookUpDomId(id)).attr('class', 'classGroup'); const g = elem.append('g').attr('id', diagObj.db.lookUpDomId(id)).attr('class', 'classGroup');
// add title
let title; let title;
if (classDef.link) { if (classDef.link) {
title = g title = g
@ -211,47 +210,56 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
} }
const titleHeight = title.node().getBBox().height; const titleHeight = title.node().getBBox().height;
let membersLine;
let membersBox;
let methodsLine;
const membersLine = g // don't draw box if no members
.append('line') // text label for the x axis if (classDef.members.length > 0) {
.attr('x1', 0) membersLine = g
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2) .append('line') // text label for the x axis
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2); .attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2);
const members = g const members = g
.append('text') // text label for the x axis .append('text') // text label for the x axis
.attr('x', conf.padding) .attr('x', conf.padding)
.attr('y', titleHeight + conf.dividerMargin + conf.textHeight) .attr('y', titleHeight + conf.dividerMargin + conf.textHeight)
.attr('fill', 'white') .attr('fill', 'white')
.attr('class', 'classText'); .attr('class', 'classText');
isFirst = true; isFirst = true;
classDef.members.forEach(function (member) { classDef.members.forEach(function (member) {
addTspan(members, member, isFirst, conf); addTspan(members, member, isFirst, conf);
isFirst = false; isFirst = false;
}); });
const membersBox = members.node().getBBox(); membersBox = members.node().getBBox();
}
const methodsLine = g // don't draw box if no methods
.append('line') // text label for the x axis if (classDef.methods.length > 0) {
.attr('x1', 0) methodsLine = g
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height) .append('line') // text label for the x axis
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height); .attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height);
const methods = g const methods = g
.append('text') // text label for the x axis .append('text') // text label for the x axis
.attr('x', conf.padding) .attr('x', conf.padding)
.attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight) .attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight)
.attr('fill', 'white') .attr('fill', 'white')
.attr('class', 'classText'); .attr('class', 'classText');
isFirst = true; isFirst = true;
classDef.methods.forEach(function (method) { classDef.methods.forEach(function (method) {
addTspan(methods, method, isFirst, conf); addTspan(methods, method, isFirst, conf);
isFirst = false; isFirst = false;
}); });
}
const classBox = g.node().getBBox(); const classBox = g.node().getBBox();
var cssClassStr = ' '; var cssClassStr = ' ';
@ -280,8 +288,12 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
title.insert('title').text(classDef.tooltip); title.insert('title').text(classDef.tooltip);
} }
membersLine.attr('x2', rectWidth); if (membersLine) {
methodsLine.attr('x2', rectWidth); membersLine.attr('x2', rectWidth);
}
if (methodsLine) {
methodsLine.attr('x2', rectWidth);
}
classInfo.width = rectWidth; classInfo.width = rectWidth;
classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin; classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin;
@ -293,7 +305,7 @@ export const getClassTitleString = function (classDef) {
let classTitleString = classDef.id; let classTitleString = classDef.id;
if (classDef.type) { if (classDef.type) {
classTitleString += '<' + classDef.type + '>'; classTitleString += '<' + parseGenericTypes(classDef.type) + '>';
} }
return classTitleString; return classTitleString;
@ -362,82 +374,19 @@ export const drawNote = function (elem, note, conf, diagObj) {
return noteInfo; return noteInfo;
}; };
export const parseMember = function (text) {
let displayText = '';
let cssStyle = '';
let returnType = '';
let visibility = '';
let firstChar = text.substring(0, 1);
let lastChar = text.substring(text.length - 1, text.length);
if (firstChar.match(/[#+~-]/)) {
visibility = firstChar;
}
let noClassifierRe = /[\s\w)~]/;
if (!lastChar.match(noClassifierRe)) {
cssStyle = parseClassifier(lastChar);
}
const startIndex = visibility === '' ? 0 : 1;
let endIndex = cssStyle === '' ? text.length : text.length - 1;
text = text.substring(startIndex, endIndex);
const methodStart = text.indexOf('(');
const methodEnd = text.indexOf(')');
const isMethod = methodStart > 1 && methodEnd > methodStart && methodEnd <= text.length;
if (isMethod) {
let methodName = text.substring(0, methodStart).trim();
const parameters = text.substring(methodStart + 1, methodEnd);
displayText = visibility + methodName + '(' + parseGenericTypes(parameters.trim()) + ')';
if (methodEnd < text.length) {
// special case: classifier after the closing parenthesis
let potentialClassifier = text.substring(methodEnd + 1, methodEnd + 2);
if (cssStyle === '' && !potentialClassifier.match(noClassifierRe)) {
cssStyle = parseClassifier(potentialClassifier);
returnType = text.substring(methodEnd + 2).trim();
} else {
returnType = text.substring(methodEnd + 1).trim();
}
if (returnType !== '') {
if (returnType.charAt(0) === ':') {
returnType = returnType.substring(1).trim();
}
returnType = ' : ' + parseGenericTypes(returnType);
displayText += returnType;
}
}
} else {
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
displayText = visibility + parseGenericTypes(text);
}
return {
displayText,
cssStyle,
};
};
/** /**
* Adds a <tspan> for a member in a diagram * Adds a <tspan> for a member in a diagram
* *
* @param {SVGElement} textEl The element to append to * @param {SVGElement} textEl The element to append to
* @param {string} txt The member * @param {string} member The member
* @param {boolean} isFirst * @param {boolean} isFirst
* @param {{ padding: string; textHeight: string }} conf The configuration for the member * @param {{ padding: string; textHeight: string }} conf The configuration for the member
*/ */
const addTspan = function (textEl, txt, isFirst, conf) { const addTspan = function (textEl, member, isFirst, conf) {
let member = parseMember(txt); const { displayText, cssStyle } = member.getDisplayDetails();
const tSpan = textEl.append('tspan').attr('x', conf.padding).text(displayText);
const tSpan = textEl.append('tspan').attr('x', conf.padding).text(member.displayText); if (cssStyle !== '') {
if (member.cssStyle !== '') {
tSpan.attr('style', member.cssStyle); tSpan.attr('style', member.cssStyle);
} }
@ -446,27 +395,9 @@ const addTspan = function (textEl, txt, isFirst, conf) {
} }
}; };
/**
* Gives the styles for a classifier
*
* @param {'+' | '-' | '#' | '~' | '*' | '$'} classifier The classifier string
* @returns {string} Styling for the classifier
*/
const parseClassifier = function (classifier) {
switch (classifier) {
case '*':
return 'font-style:italic;';
case '$':
return 'text-decoration:underline;';
default:
return '';
}
};
export default { export default {
getClassTitleString, getClassTitleString,
drawClass, drawClass,
drawEdge, drawEdge,
drawNote, drawNote,
parseMember,
}; };

View File

@ -1,330 +1,27 @@
import svgDraw from './svgDraw.js'; import svgDraw from './svgDraw.js';
import { JSDOM } from 'jsdom';
describe('given a string representing class method, ', function () { describe('given a string representing a class, ', function () {
it('should handle class names with generics', function () { describe('when class name includes generic, ', function () {
const classDef = { it('should return correct text for generic', function () {
id: 'Car', const classDef = {
type: 'T', id: 'Car',
label: 'Car', type: 'T',
}; label: 'Car',
};
let actual = svgDraw.getClassTitleString(classDef); let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T>'); expect(actual).toBe('Car<T>');
});
describe('when parsing base method declaration', function () {
it('should handle simple declaration', function () {
const str = 'foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('');
}); });
it('should return correct text for nested generics', function () {
const classDef = {
id: 'Car',
type: 'T~T~',
label: 'Car',
};
it('should handle declaration with parameters', function () { let actual = svgDraw.getClassTitleString(classDef);
const str = 'foo(int id)'; expect(actual).toBe('Car<T<T>>');
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int id)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with multiple parameters', function () {
const str = 'foo(int id, object thing)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int id, object thing)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with single item in parameters', function () {
const str = 'foo(id)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with single item in parameters with extra spaces', function () {
const str = ' foo ( id) ';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id)');
expect(actual.cssStyle).toBe('');
});
it('should handle method declaration with generic parameter', function () {
const str = 'foo(List~int~)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(List<int>)');
expect(actual.cssStyle).toBe('');
});
it('should handle method declaration with normal and generic parameter', function () {
const str = 'foo(int, List~int~)';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(int, List<int>)');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with return value', function () {
const str = 'foo(id) int';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id) : int');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with colon return value', function () {
const str = 'foo(id) : int';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id) : int');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with generic return value', function () {
const str = 'foo(id) List~int~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id) : List<int>');
expect(actual.cssStyle).toBe('');
});
it('should handle declaration with colon generic return value', function () {
const str = 'foo(id) : List~int~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(id) : List<int>');
expect(actual.cssStyle).toBe('');
});
it('should handle method declaration with all possible markup', function () {
const str = '+foo ( List~int~ ids )* List~Item~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('+foo(List<int> ids) : List<Item>');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle method declaration with nested generics', function () {
const str = '+foo ( List~List~int~~ ids )* List~List~Item~~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('+foo(List<List<int>> ids) : List<List<Item>>');
expect(actual.cssStyle).toBe('font-style:italic;');
});
});
describe('when parsing method visibility', function () {
it('should correctly handle public', function () {
const str = '+foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('+foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle private', function () {
const str = '-foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('-foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle protected', function () {
const str = '#foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('#foo()');
expect(actual.cssStyle).toBe('');
});
it('should correctly handle package/internal', function () {
const str = '~foo()';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('~foo()');
expect(actual.cssStyle).toBe('');
});
});
describe('when parsing method classifier', function () {
it('should handle abstract method', function () {
const str = 'foo()*';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle abstract method with return type', function () {
const str = 'foo(name: String) int*';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(name: String) : int');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle abstract method classifier after parenthesis with return type', function () {
const str = 'foo(name: String)* int';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(name: String) : int');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle static method classifier', function () {
const str = 'foo()$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static method classifier with return type', function () {
const str = 'foo(name: String) int$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(name: String) : int');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static method classifier with colon and return type', function () {
const str = 'foo(name: String): int$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(name: String) : int');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static method classifier after parenthesis with return type', function () {
const str = 'foo(name: String)$ int';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo(name: String) : int');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should ignore unknown character for classifier', function () {
const str = 'foo()!';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo()');
expect(actual.cssStyle).toBe('');
});
});
});
describe('given a string representing class member, ', function () {
describe('when parsing member declaration', function () {
it('should handle simple field', function () {
const str = 'id';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('id');
expect(actual.cssStyle).toBe('');
});
it('should handle field with type', function () {
const str = 'int id';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('int id');
expect(actual.cssStyle).toBe('');
});
it('should handle field with type (name first)', function () {
const str = 'id: int';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('id: int');
expect(actual.cssStyle).toBe('');
});
it('should handle array field', function () {
const str = 'int[] ids';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('int[] ids');
expect(actual.cssStyle).toBe('');
});
it('should handle array field (name first)', function () {
const str = 'ids: int[]';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('ids: int[]');
expect(actual.cssStyle).toBe('');
});
it('should handle field with generic type', function () {
const str = 'List~int~ ids';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('List<int> ids');
expect(actual.cssStyle).toBe('');
});
it('should handle field with generic type (name first)', function () {
const str = 'ids: List~int~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('ids: List<int>');
expect(actual.cssStyle).toBe('');
});
});
describe('when parsing classifiers', function () {
it('should handle static field', function () {
const str = 'String foo$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('String foo');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static field (name first)', function () {
const str = 'foo: String$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo: String');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static field with generic type', function () {
const str = 'List~String~ foo$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('List<String> foo');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle static field with generic type (name first)', function () {
const str = 'foo: List~String~$';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('foo: List<String>');
expect(actual.cssStyle).toBe('text-decoration:underline;');
});
it('should handle field with nested generic type', function () {
const str = 'List~List~int~~ idLists';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('List<List<int>> idLists');
expect(actual.cssStyle).toBe('');
});
it('should handle field with nested generic type (name first)', function () {
const str = 'idLists: List~List~int~~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('idLists: List<List<int>>');
expect(actual.cssStyle).toBe('');
}); });
}); });
}); });

View File

@ -69,6 +69,5 @@ describe('generic parser', () => {
'test <Array<Array<string[]>>>' 'test <Array<Array<string[]>>>'
); );
expect(parseGenericTypes('~test')).toEqual('~test'); expect(parseGenericTypes('~test')).toEqual('~test');
expect(parseGenericTypes('~test Array~string~')).toEqual('~test Array<string>');
}); });
}); });

View File

@ -178,23 +178,63 @@ export const getMin = function (...values: number[]): number {
* @param text - The text to convert * @param text - The text to convert
* @returns The converted string * @returns The converted string
*/ */
export const parseGenericTypes = function (text: string): string { export const parseGenericTypes = function (input: string): string {
let cleanedText = text; const inputSets = input.split(/(,)/);
const output = [];
if (text.split('~').length - 1 >= 2) { for (let i = 0; i < inputSets.length; i++) {
let newCleanedText = cleanedText; let thisSet = inputSets[i];
// use a do...while loop instead of replaceAll to detect recursion // if the original input included a value such as "~K, V~"", these will be split into
// e.g. Array~Array~T~~ // an array of ["~K",","," V~"].
do { // This means that on each call of processSet, there will only be 1 ~ present
cleanedText = newCleanedText; // To account for this, if we encounter a ",", we are checking the previous and next sets in the array
newCleanedText = cleanedText.replace(/~([^\s,:;]+)~/, '<$1>'); // to see if they contain matching ~'s
} while (newCleanedText != cleanedText); // in which case we are assuming that they should be rejoined and sent to be processed
if (thisSet === ',' && i > 0 && i + 1 < inputSets.length) {
const previousSet = inputSets[i - 1];
const nextSet = inputSets[i + 1];
return parseGenericTypes(newCleanedText); if (shouldCombineSets(previousSet, nextSet)) {
} else { thisSet = previousSet + ',' + nextSet;
return cleanedText; i++; // Move the index forward to skip the next iteration since we're combining sets
output.pop();
}
}
output.push(processSet(thisSet));
} }
return output.join('');
};
const shouldCombineSets = (previousSet: string, nextSet: string): boolean => {
const prevCount = [...previousSet].reduce((count, char) => (char === '~' ? count + 1 : count), 0);
const nextCount = [...nextSet].reduce((count, char) => (char === '~' ? count + 1 : count), 0);
return prevCount === 1 && nextCount === 1;
};
const processSet = (input: string): string => {
const chars = [...input];
const tildeCount = chars.reduce((count, char) => (char === '~' ? count + 1 : count), 0);
if (tildeCount <= 1) {
return input;
}
let first = chars.indexOf('~');
let last = chars.lastIndexOf('~');
while (first !== -1 && last !== -1 && first !== last) {
chars[first] = '<';
chars[last] = '>';
first = chars.indexOf('~');
last = chars.lastIndexOf('~');
}
return chars.join('');
}; };
export default { export default {

View File

@ -0,0 +1,32 @@
import { sanitizeText as _sanitizeText } from './common.js';
import { getConfig } from '../../config.js';
let accTitle = '';
let diagramTitle = '';
let accDescription = '';
const sanitizeText = (txt: string): string => _sanitizeText(txt, getConfig());
export const clear = (): void => {
accTitle = '';
accDescription = '';
diagramTitle = '';
};
export const setAccTitle = (txt: string): void => {
accTitle = sanitizeText(txt).replace(/^\s+/g, '');
};
export const getAccTitle = (): string => accTitle;
export const setAccDescription = (txt: string): void => {
accDescription = sanitizeText(txt).replace(/\n\s+/g, '\n');
};
export const getAccDescription = (): string => accDescription;
export const setDiagramTitle = (txt: string): void => {
diagramTitle = sanitizeText(txt);
};
export const getDiagramTitle = (): string => diagramTitle;

View File

@ -10,7 +10,7 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
let entities = {}; let entities = {};
let relationships = []; let relationships = [];

View File

@ -66,7 +66,7 @@ o\{ return 'ZERO_OR_MORE';
"optionally to" return 'NON_IDENTIFYING'; "optionally to" return 'NON_IDENTIFYING';
\.\- return 'NON_IDENTIFYING'; \.\- return 'NON_IDENTIFYING';
\-\. return 'NON_IDENTIFYING'; \-\. return 'NON_IDENTIFYING';
[A-Za-z][A-Za-z0-9\-_]* return 'ALPHANUM'; [A-Za-z_][A-Za-z0-9\-_]* return 'ALPHANUM';
. return yytext[0]; . return yytext[0];
<<EOF>> return 'EOF'; <<EOF>> return 'EOF';

View File

@ -33,7 +33,7 @@ describe('when parsing ER diagram it...', function () {
describe('has non A-Za-z0-9_- chars', function () { describe('has non A-Za-z0-9_- chars', function () {
// these were entered using the Mac keyboard utility. // these were entered using the Mac keyboard utility.
const chars = const chars =
"~ ` ! @ # $ ^ & * ( ) - _ = + [ ] { } | / ; : ' . ? ¡ ™ € £ ¢ ∞ fi § ‡ • ° ª · º ≠ ± œ Œ ∑ „ ® † ˇ ¥ Á ¨ ˆ ˆ Ø π ∏ “ « » å Å ß Í ∂ Î ƒ Ï © ˙ Ó ∆ Ô ˚  ¬ Ò … Ú æ Æ Ω ¸ ≈ π ˛ ç Ç √ ◊ ∫ ı ˜ µ  ≤ ¯ ≥ ˘ ÷ ¿"; "~ ` ! @ # $ ^ & * ( ) - = + [ ] { } | / ; : ' . ? ¡ ™ € £ ¢ ∞ fi § ‡ • ° ª · º ≠ ± œ Œ ∑ „ ® † ˇ ¥ Á ¨ ˆ ˆ Ø π ∏ “ « » å Å ß Í ∂ Î ƒ Ï © ˙ Ó ∆ Ô ˚  ¬ Ò … Ú æ Æ Ω ¸ ≈ π ˛ ç Ç √ ◊ ∫ ı ˜ µ  ≤ ¯ ≥ ˘ ÷ ¿";
const allowed = chars.split(' '); const allowed = chars.split(' ');
allowed.forEach((allowedChar) => { allowed.forEach((allowedChar) => {
@ -170,6 +170,13 @@ describe('when parsing ER diagram it...', function () {
expect(entities[firstEntity].alias).toBe(alias); expect(entities[firstEntity].alias).toBe(alias);
expect(entities[secondEntity].alias).toBeUndefined(); expect(entities[secondEntity].alias).toBeUndefined();
}); });
it('can start with an underscore', function () {
const entity = '_foo';
erDiagram.parser.parse(`erDiagram\n${entity}\n`);
const entities = erDb.getEntities();
expect(entities.hasOwnProperty(entity)).toBe(true);
});
}); });
describe('attribute name', () => { describe('attribute name', () => {

View File

@ -12,7 +12,7 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
const MERMAID_DOM_ID_PREFIX = 'flowchart-'; const MERMAID_DOM_ID_PREFIX = 'flowchart-';
let vertexCounter = 0; let vertexCounter = 0;

View File

@ -16,7 +16,7 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
dayjs.extend(dayjsIsoWeek); dayjs.extend(dayjsIsoWeek);
dayjs.extend(dayjsCustomParseFormat); dayjs.extend(dayjsCustomParseFormat);

View File

@ -12,7 +12,7 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
let mainBranchName = getConfig().gitGraph.mainBranchName; let mainBranchName = getConfig().gitGraph.mainBranchName;
let mainBranchOrder = getConfig().gitGraph.mainBranchOrder; let mainBranchOrder = getConfig().gitGraph.mainBranchOrder;

View File

@ -10,7 +10,7 @@ import {
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
import type { ParseDirectiveDefinition } from '../../diagram-api/types.js'; import type { ParseDirectiveDefinition } from '../../diagram-api/types.js';
import type { PieFields, PieDB, Sections } from './pieTypes.js'; import type { PieFields, PieDB, Sections } from './pieTypes.js';
import type { RequiredDeep } from 'type-fest'; import type { RequiredDeep } from 'type-fest';

View File

@ -10,7 +10,7 @@ import {
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
import { QuadrantBuilder } from './quadrantBuilder.js'; import { QuadrantBuilder } from './quadrantBuilder.js';
const config = configApi.getConfig(); const config = configApi.getConfig();

View File

@ -8,7 +8,7 @@ import {
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
let relations = []; let relations = [];
let latestRequirement = {}; let latestRequirement = {};

View File

@ -8,7 +8,7 @@ import {
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
// Sankey diagram represented by nodes and links between those nodes // Sankey diagram represented by nodes and links between those nodes
let links: SankeyLink[] = []; let links: SankeyLink[] = [];

View File

@ -301,7 +301,7 @@ placement
signal signal
: actor signaltype '+' actor text2 : actor signaltype '+' actor text2
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5}, { $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true},
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4} {type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4}
]} ]}
| actor signaltype '-' actor text2 | actor signaltype '-' actor text2

View File

@ -10,7 +10,7 @@ import {
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
let prevActor = undefined; let prevActor = undefined;
let actors = {}; let actors = {};
@ -124,7 +124,8 @@ export const addSignal = function (
idFrom, idFrom,
idTo, idTo,
message = { text: undefined, wrap: undefined }, message = { text: undefined, wrap: undefined },
messageType messageType,
activate = false
) { ) {
if (messageType === LINETYPE.ACTIVE_END) { if (messageType === LINETYPE.ACTIVE_END) {
const cnt = activationCount(idFrom.actor); const cnt = activationCount(idFrom.actor);
@ -147,6 +148,7 @@ export const addSignal = function (
message: message.text, message: message.text,
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap, wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
type: messageType, type: messageType,
activate,
}); });
return true; return true;
}; };
@ -450,6 +452,19 @@ export const getActorProperty = function (actor, key) {
return undefined; return undefined;
}; };
/**
* @typedef {object} AddMessageParams A message from one actor to another.
* @property {string} from - The id of the actor sending the message.
* @property {string} to - The id of the actor receiving the message.
* @property {string} msg - The message text.
* @property {number} signalType - The type of signal.
* @property {"addMessage"} type - Set to `"addMessage"` if this is an `AddMessageParams`.
* @property {boolean} [activate] - If `true`, this signal starts an activation.
*/
/**
* @param {object | object[] | AddMessageParams} param - Object of parameters.
*/
export const apply = function (param) { export const apply = function (param) {
if (Array.isArray(param)) { if (Array.isArray(param)) {
param.forEach(function (item) { param.forEach(function (item) {
@ -530,7 +545,7 @@ export const apply = function (param) {
lastDestroyed = undefined; lastDestroyed = undefined;
} }
} }
addSignal(param.from, param.to, param.msg, param.signalType); addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
break; break;
case 'boxStart': case 'boxStart':
addBox(param.boxData); addBox(param.boxData);

View File

@ -104,6 +104,7 @@ describe('more than one sequence diagram', () => {
expect(diagram1.db.getMessages()).toMatchInlineSnapshot(` expect(diagram1.db.getMessages()).toMatchInlineSnapshot(`
[ [
{ {
"activate": false,
"from": "Alice", "from": "Alice",
"message": "Hello Bob, how are you?", "message": "Hello Bob, how are you?",
"to": "Bob", "to": "Bob",
@ -111,6 +112,7 @@ describe('more than one sequence diagram', () => {
"wrap": false, "wrap": false,
}, },
{ {
"activate": false,
"from": "Bob", "from": "Bob",
"message": "I am good thanks!", "message": "I am good thanks!",
"to": "Alice", "to": "Alice",
@ -127,6 +129,7 @@ describe('more than one sequence diagram', () => {
expect(diagram2.db.getMessages()).toMatchInlineSnapshot(` expect(diagram2.db.getMessages()).toMatchInlineSnapshot(`
[ [
{ {
"activate": false,
"from": "Alice", "from": "Alice",
"message": "Hello Bob, how are you?", "message": "Hello Bob, how are you?",
"to": "Bob", "to": "Bob",
@ -134,6 +137,7 @@ describe('more than one sequence diagram', () => {
"wrap": false, "wrap": false,
}, },
{ {
"activate": false,
"from": "Bob", "from": "Bob",
"message": "I am good thanks!", "message": "I am good thanks!",
"to": "Alice", "to": "Alice",
@ -152,6 +156,7 @@ describe('more than one sequence diagram', () => {
expect(diagram3.db.getMessages()).toMatchInlineSnapshot(` expect(diagram3.db.getMessages()).toMatchInlineSnapshot(`
[ [
{ {
"activate": false,
"from": "Alice", "from": "Alice",
"message": "Hello John, how are you?", "message": "Hello John, how are you?",
"to": "John", "to": "John",
@ -159,6 +164,7 @@ describe('more than one sequence diagram', () => {
"wrap": false, "wrap": false,
}, },
{ {
"activate": false,
"from": "John", "from": "John",
"message": "I am good thanks!", "message": "I am good thanks!",
"to": "Alice", "to": "Alice",
@ -548,6 +554,7 @@ deactivate Bob`;
expect(messages.length).toBe(4); expect(messages.length).toBe(4);
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED); expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
expect(messages[0].activate).toBeTruthy();
expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START); expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
expect(messages[1].from.actor).toBe('Bob'); expect(messages[1].from.actor).toBe('Bob');
expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED); expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED);

View File

@ -1,5 +1,5 @@
// @ts-nocheck TODO: fix file // @ts-nocheck TODO: fix file
import { select, selectAll } from 'd3'; import { select } from 'd3';
import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js'; import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
import { log } from '../../logger.js'; import { log } from '../../logger.js';
import common from '../common/common.js'; import common from '../common/common.js';
@ -622,10 +622,10 @@ const activationBounds = function (actor, actors) {
const left = activations.reduce(function (acc, activation) { const left = activations.reduce(function (acc, activation) {
return common.getMin(acc, activation.startx); return common.getMin(acc, activation.startx);
}, actorObj.x + actorObj.width / 2); }, actorObj.x + actorObj.width / 2 - 1);
const right = activations.reduce(function (acc, activation) { const right = activations.reduce(function (acc, activation) {
return common.getMax(acc, activation.stopx); return common.getMax(acc, activation.stopx);
}, actorObj.x + actorObj.width / 2); }, actorObj.x + actorObj.width / 2 + 1);
return [left, right]; return [left, right];
}; };
@ -1389,9 +1389,8 @@ const buildNoteModel = function (msg, actors, diagObj) {
}; };
const buildMessageModel = function (msg, actors, diagObj) { const buildMessageModel = function (msg, actors, diagObj) {
let process = false;
if ( if (
[ ![
diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.SOLID_OPEN,
diagObj.db.LINETYPE.DOTTED_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN,
diagObj.db.LINETYPE.SOLID, diagObj.db.LINETYPE.SOLID,
@ -1402,17 +1401,47 @@ const buildMessageModel = function (msg, actors, diagObj) {
diagObj.db.LINETYPE.DOTTED_POINT, diagObj.db.LINETYPE.DOTTED_POINT,
].includes(msg.type) ].includes(msg.type)
) { ) {
process = true;
}
if (!process) {
return {}; return {};
} }
const fromBounds = activationBounds(msg.from, actors); const [fromLeft, fromRight] = activationBounds(msg.from, actors);
const toBounds = activationBounds(msg.to, actors); const [toLeft, toRight] = activationBounds(msg.to, actors);
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0; const isArrowToRight = fromLeft <= toLeft;
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1; const startx = isArrowToRight ? fromRight : fromLeft;
const allBounds = [...fromBounds, ...toBounds]; let stopx = isArrowToRight ? toLeft : toRight;
const boundedWidth = Math.abs(toBounds[toIdx] - fromBounds[fromIdx]);
// As the line width is considered, the left and right values will be off by 2.
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
/**
* Adjust the value based on the arrow direction
* @param value - The value to adjust
* @returns The adjustment with correct sign to be added to the actual value.
*/
const adjustValue = (value: number) => {
return isArrowToRight ? -value : value;
};
/**
* This is an edge case for the first activation.
* Proper fix would require significant changes.
* So, we set an activate flag in the message, and cross check that with isToActivation
* In cases where the message is to an activation that was properly detected, we don't want to move the arrow head
* The activation will not be detected on the first message, so we need to move the arrow head
*/
if (msg.activate && !isArrowToActivation) {
stopx += adjustValue(conf.activationWidth / 2 - 1);
}
/**
* Shorten the length of arrow at the end and move the marker forward (using refX) to have a clean arrowhead
* This is not required for open arrows that don't have arrowheads
*/
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
stopx += adjustValue(3);
}
const allBounds = [fromLeft, fromRight, toLeft, toRight];
const boundedWidth = Math.abs(startx - stopx);
if (msg.wrap && msg.message) { if (msg.wrap && msg.message) {
msg.message = utils.wrapLabel( msg.message = utils.wrapLabel(
msg.message, msg.message,
@ -1429,8 +1458,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
conf.width conf.width
), ),
height: 0, height: 0,
startx: fromBounds[fromIdx], startx,
stopx: toBounds[toIdx], stopx,
starty: 0, starty: 0,
stopy: 0, stopy: 0,
message: msg.message, message: msg.message,

View File

@ -703,7 +703,7 @@ export const insertArrowHead = function (elem) {
.append('defs') .append('defs')
.append('marker') .append('marker')
.attr('id', 'arrowhead') .attr('id', 'arrowhead')
.attr('refX', 9) .attr('refX', 7.9)
.attr('refY', 5) .attr('refY', 5)
.attr('markerUnits', 'userSpaceOnUse') .attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 12) .attr('markerWidth', 12)
@ -723,7 +723,7 @@ export const insertArrowFilledHead = function (elem) {
.append('defs') .append('defs')
.append('marker') .append('marker')
.attr('id', 'filled-head') .attr('id', 'filled-head')
.attr('refX', 18) .attr('refX', 15.5)
.attr('refY', 7) .attr('refY', 7)
.attr('markerWidth', 20) .attr('markerWidth', 20)
.attr('markerHeight', 28) .attr('markerHeight', 28)
@ -768,7 +768,7 @@ export const insertArrowCrossHead = function (elem) {
.attr('markerHeight', 8) .attr('markerHeight', 8)
.attr('orient', 'auto') .attr('orient', 'auto')
.attr('refX', 4) .attr('refX', 4)
.attr('refY', 5); .attr('refY', 4.5);
// The cross // The cross
marker marker
.append('path') .append('path')

View File

@ -11,7 +11,7 @@ import {
clear as commonClear, clear as commonClear,
setDiagramTitle, setDiagramTitle,
getDiagramTitle, getDiagramTitle,
} from '../../commonDb.js'; } from '../common/commonDb.js';
import { import {
DEFAULT_DIAGRAM_DIRECTION, DEFAULT_DIAGRAM_DIRECTION,

View File

@ -1,7 +1,6 @@
import { parser as timeline } from './parser/timeline.jison'; import { parser as timeline } from './parser/timeline.jison';
import * as timelineDB from './timelineDb.js'; import * as timelineDB from './timelineDb.js';
// import { injectUtils } from './mermaidUtils.js'; // import { injectUtils } from './mermaidUtils.js';
import * as _commonDb from '../../commonDb.js';
import { parseDirective as _parseDirective } from '../../directiveUtils.js'; import { parseDirective as _parseDirective } from '../../directiveUtils.js';
import { import {
@ -18,7 +17,6 @@ import {
// getConfig, // getConfig,
// sanitizeText, // sanitizeText,
// setupGraphViewBox, // setupGraphViewBox,
// _commonDb,
// _parseDirective // _parseDirective
// ); // );

View File

@ -1,5 +1,5 @@
import { parseDirective as _parseDirective } from '../../directiveUtils.js'; import { parseDirective as _parseDirective } from '../../directiveUtils.js';
import * as commonDb from '../../commonDb.js'; import * as commonDb from '../common/commonDb.js';
let currentSection = ''; let currentSection = '';
let currentTaskId = 0; let currentTaskId = 0;

View File

@ -8,7 +8,7 @@ import {
getAccDescription, getAccDescription,
setAccDescription, setAccDescription,
clear as commonClear, clear as commonClear,
} from '../../commonDb.js'; } from '../common/commonDb.js';
let currentSection = ''; let currentSection = '';

View File

@ -31,7 +31,7 @@ Once the release happens we add a tag to the `release` branch and merge it with
2. Check out the `develop` branch 2. Check out the `develop` branch
3. Create a new branch for your work. Please name the branch following our naming convention below. 3. Create a new branch for your work. Please name the branch following our naming convention below.
We use the follow naming convention for branches: We use the following naming convention for branches:
```txt ```txt
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces] [feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]

View File

@ -16,7 +16,7 @@ In GitHub, you first **fork** a repository when you are going to make changes an
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with. Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentaion, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories). [Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo) [Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)

View File

@ -16,7 +16,7 @@ In GitHub, you first **fork** a repository when you are going to make changes an
Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with. Then you **clone** a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
[Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentaion, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories). [Fork mermaid](https://github.com/mermaid-js/mermaid/fork) to start contributing to the main project and its documentation, or [search for other repositories](https://github.com/orgs/mermaid-js/repositories).
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo) [Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)

View File

@ -13,7 +13,7 @@ For instance:
#### Store data found during parsing #### Store data found during parsing
There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call a object provided to the parser by the user of the parser. This object can be called during parsing for storing data. There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call an object provided to the parser by the user of the parser. This object can be called during parsing for storing data.
```jison ```jison
statement statement
@ -30,7 +30,7 @@ In the extract of the grammar above, it is defined that a call to the setTitle m
Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user. Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
``` ```
For more info look in the example diagram type: For more info look at the example diagram type:
The `yy` object has the following function: The `yy` object has the following function:
@ -49,7 +49,7 @@ parser.yy = db;
### Step 2: Rendering ### Step 2: Rendering
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather then the flowchart renderer as this is a more generic example. Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather than the flowchart renderer as this is a more generic example.
Place the renderer in the diagram folder. Place the renderer in the diagram folder.
@ -57,7 +57,7 @@ Place the renderer in the diagram folder.
The second thing to do is to add the capability to detect the new diagram to type to the detectType in `diagram-api/detectType.ts`. The detection should return a key for the new diagram type. The second thing to do is to add the capability to detect the new diagram to type to the detectType in `diagram-api/detectType.ts`. The detection should return a key for the new diagram type.
[This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type. [This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type.
For example, if your new diagram use a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader For example, if your new diagram uses a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader
would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram. would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram.
Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same. Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same.
@ -117,7 +117,7 @@ There are a few features that are common between the different types of diagrams
- Themes, there is a common way to modify the styling of diagrams in Mermaid. - Themes, there is a common way to modify the styling of diagrams in Mermaid.
- Comments should follow mermaid standards - Comments should follow mermaid standards
Here some pointers on how to handle these different areas. Here are some pointers on how to handle these different areas.
## Accessibility ## Accessibility
@ -135,7 +135,7 @@ See [the definition of aria-roledescription](https://www.w3.org/TR/wai-aria-1.1/
### accessible title and description ### accessible title and description
The syntax for accessible titles and descriptions is described in [the Accessibility documenation section.](../config/accessibility.md) The syntax for accessible titles and descriptions is described in [the Accessibility documentation section.](../config/accessibility.md)
As a design goal, the jison syntax should be similar between the diagrams. As a design goal, the jison syntax should be similar between the diagrams.

View File

@ -116,7 +116,7 @@ The following code snippet changes `theme` to `forest`:
`%%{init: { "theme": "forest" } }%%` `%%{init: { "theme": "forest" } }%%`
Possible theme values are: `default`,`base`, `dark`, `forest` and `neutral`. Possible theme values are: `default`, `base`, `dark`, `forest` and `neutral`.
Default Value is `default`. Default Value is `default`.
Example: Example:
@ -235,7 +235,7 @@ Let us see an example:
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```
@ -252,7 +252,7 @@ By applying that snippet to the diagram above, `wrap` will be enabled:
%%{init: { "sequence": { "wrap": true, "width":300 } } }%% %%{init: { "sequence": { "wrap": true, "width":300 } } }%%
sequenceDiagram sequenceDiagram
Alice->Bob: Hello Bob, how are you? Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion? Bob->Alice: Fine, how did your mother like the book I suggested? And did you catch the new book about alien invasion?
Alice->Bob: Good. Alice->Bob: Good.
Bob->Alice: Cool Bob->Alice: Cool
``` ```

View File

@ -35,7 +35,7 @@ pnpm add mermaid
**Hosting mermaid on a web page:** **Hosting mermaid on a web page:**
> Note:This topic explored in greater depth in the [User Guide for Beginners](../intro/getting-started.md) > Note: This topic is explored in greater depth in the [User Guide for Beginners](../intro/getting-started.md)
The easiest way to integrate mermaid on a web page requires two elements: The easiest way to integrate mermaid on a web page requires two elements:
@ -94,7 +94,7 @@ Mermaid can load multiple diagrams, in the same page.
## Enabling Click Event and Tags in Nodes ## Enabling Click Event and Tags in Nodes
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduced in version 8.2 as a security improvement, aimed at preventing malicious use.
**It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.** **It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.**
@ -109,14 +109,14 @@ Values:
- **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled. - **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled.
- **antiscript**: HTML tags in text are allowed (only script elements are removed) and click functionality is enabled. - **antiscript**: HTML tags in text are allowed (only script elements are removed) and click functionality is enabled.
- **loose**: HTML tags in text are allowed and click functionality is enabled. - **loose**: HTML tags in text are allowed and click functionality is enabled.
- **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This prevent any JavaScript from running in the context. This may hinder interactive functionality of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc. - **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This prevents any JavaScript from running in the context. This may hinder interactive functionality of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc.
```note ```note
This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled. This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
**sandbox** security level is still in the beta version. **sandbox** security level is still in the beta version.
``` ```
**If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.** **If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing. This allows clicks and tags are allowed.**
**To change `securityLevel`, you have to call `mermaid.initialize`:** **To change `securityLevel`, you have to call `mermaid.initialize`:**

View File

@ -43,6 +43,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [LiveBook](https://livebook.dev) (**Native support**) - [LiveBook](https://livebook.dev) (**Native support**)
- [Atlassian Products](https://www.atlassian.com) - [Atlassian Products](https://www.atlassian.com)
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview) - [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) - [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid) - [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)

View File

@ -86,7 +86,7 @@ When writing the .html file, we give two instructions inside the html code to th
a. The mermaid code for the diagram we want to create. a. The mermaid code for the diagram we want to create.
b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process.
**a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:** **a. The embedded mermaid diagram definition inside a `<pre class="mermaid">`:**
@ -204,4 +204,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file,
**Comments from Knut Sveidqvist, creator of mermaid:** **Comments from Knut Sveidqvist, creator of mermaid:**
- In early versions of mermaid, the `<script>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflects the previous way which still works. - In early versions of mermaid, the `<script>` tag was invoked in the `<head>` part of the web page. Nowadays we can place it in the `<body>` as seen above. Older parts of the documentation frequently reflect the previous way which still works.

View File

@ -32,7 +32,7 @@
"unplugin-vue-components": "^0.25.0", "unplugin-vue-components": "^0.25.0",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-pwa": "^0.16.0", "vite-plugin-pwa": "^0.16.0",
"vitepress": "1.0.0-rc.4", "vitepress": "1.0.0-rc.10",
"workbox-window": "^7.0.0" "workbox-window": "^7.0.0"
} }
} }

View File

@ -56,7 +56,7 @@ Mermaid syntax for ER diagrams is compatible with PlantUML, with an extension to
Where: Where:
- `first-entity` is the name of an entity. Names must begin with an alphabetic character and may also contain digits, hyphens, and underscores. - `first-entity` is the name of an entity. Names must begin with an alphabetic character or an underscore (from v<MERMAID_RELEASE_VERSION>+), and may also contain digits and hyphens.
- `relationship` describes the way that both entities inter-relate. See below. - `relationship` describes the way that both entities inter-relate. See below.
- `second-entity` is the name of the other entity. - `second-entity` is the name of the other entity.
- `relationship-label` describes the relationship from the perspective of the first entity. - `relationship-label` describes the relationship from the perspective of the first entity.

View File

@ -709,9 +709,9 @@ flowchart LR
classDef foobar stroke:#00f classDef foobar stroke:#00f
``` ```
### Css classes ### CSS classes
It is also possible to predefine classes in css styles that can be applied from the graph definition as in the example It is also possible to predefine classes in CSS styles that can be applied from the graph definition as in the example
below: below:
**Example style** **Example style**

View File

@ -31,7 +31,7 @@ mindmap
The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy. The syntax for creating Mindmaps is simple and relies on indentation for setting the levels in the hierarchy.
In the following example you can see how there are 3 different levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further then the previous lines defining the nodes B and C. In the following example you can see how there are 3 different levels. One with starting at the left of the text and another level with two rows starting at the same column, defining the node A. At the end there is one more level where the text is indented further than the previous lines defining the nodes B and C.
``` ```
mindmap mindmap
@ -41,7 +41,7 @@ mindmap
C C
``` ```
In summary is a simple text outline where there are one node at the root level called `Root` which has one child `A`. `A` in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap. In summary is a simple text outline where there is one node at the root level called `Root` which has one child `A`. `A` in turn has two children `B`and `C`. In the diagram below we can see this rendered as a mindmap.
```mermaid ```mermaid
mindmap mindmap
@ -142,7 +142,7 @@ _These classes need to be supplied by the site administrator._
## Unclear indentation ## Unclear indentation
The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can se how the calculations are performed. Let us start with placing C with a smaller indentation than `B`but larger then `A`. The actual indentation does not really matter only compared with the previous rows. If we take the previous example and disrupt it a little we can see how the calculations are performed. Let us start with placing C with a smaller indentation than `B` but larger then `A`.
``` ```
mindmap mindmap

View File

@ -24,8 +24,8 @@ quadrantChart
## Syntax ## Syntax
```note ```note
If there is no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant. If there are no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant.
If there are points **x-axis** labels will rendered from left of the respective quadrant also they will be displayed in bottom of the chart, and **y-axis** lables will be rendered in bottom of the respective quadrant, the quadrant text will render at top of the respective quadrant. If there are points **x-axis** labels will rendered from the left of the respective quadrant also they will be displayed at the bottom of the chart, and **y-axis** labels will be rendered at the bottom of the respective quadrant, the quadrant text will render at the top of the respective quadrant.
``` ```
```note ```note
@ -45,7 +45,7 @@ quadrantChart
### x-axis ### x-axis
The x-axis determine what text would be displayed in the x-axis. In x-axis there is two part **left** and **right** you can pass **both** or you can pass only **left**. The statement should start with `x-axis` then the `left axis text` followed by the delimiter `-->` then `right axis text`. The x-axis determines what text would be displayed in the x-axis. In x-axis there is two part **left** and **right** you can pass **both** or you can pass only **left**. The statement should start with `x-axis` then the `left axis text` followed by the delimiter `-->` then `right axis text`.
#### Example #### Example
@ -54,7 +54,7 @@ The x-axis determine what text would be displayed in the x-axis. In x-axis there
### y-axis ### y-axis
The y-axis determine what text would be displayed in the y-axis. In y-axis there is two part **top** and **bottom** you can pass **both** or you can pass only **bottom**. The statement should start with `y-axis` then the `bottom axis text` followed by the delimiter `-->` then `top axis text`. The y-axis determines what text would be displayed in the y-axis. In y-axis there is two part **top** and **bottom** you can pass **both** or you can pass only **bottom**. The statement should start with `y-axis` then the `bottom axis text` followed by the delimiter `-->` then `top axis text`.
#### Example #### Example

View File

@ -109,7 +109,7 @@ Electricity grid,H2 conversion,27.14
### Empty Lines ### Empty Lines
CSV does not support empty lines without comma delimeters by default. But you can add them if needed: CSV does not support empty lines without comma delimiters by default. But you can add them if needed:
```mermaid-example ```mermaid-example
sankey-beta sankey-beta

View File

@ -121,7 +121,7 @@ end
end end
A->>J: Hello John, how are you? A->>J: Hello John, how are you?
J->>A: Great! J->>A: Great!
A->>B: Hello Bob, how is Charly ? A->>B: Hello Bob, how is Charly?
B->>C: Hello Charly, how are you? B->>C: Hello Charly, how are you?
``` ```

284
pnpm-lock.yaml generated
View File

@ -358,11 +358,11 @@ importers:
specifier: ^4.1.0 specifier: ^4.1.0
version: 4.1.0 version: 4.1.0
typedoc: typedoc:
specifier: ^0.24.5 specifier: ^0.25.0
version: 0.24.5(typescript@5.0.4) version: 0.25.0(typescript@5.0.4)
typedoc-plugin-markdown: typedoc-plugin-markdown:
specifier: ^3.15.2 specifier: ^3.15.2
version: 3.15.2(typedoc@0.24.5) version: 3.15.2(typedoc@0.25.0)
typescript: typescript:
specifier: ^5.0.4 specifier: ^5.0.4
version: 5.0.4 version: 5.0.4
@ -374,7 +374,7 @@ importers:
version: 4.1.2 version: 4.1.2
vitepress: vitepress:
specifier: ^1.0.0-alpha.72 specifier: ^1.0.0-alpha.72
version: 1.0.0-alpha.72(@algolia/client-search@4.14.2)(@types/node@18.16.0) version: 1.0.0-alpha.72(@algolia/client-search@4.19.1)(@types/node@18.16.0)
vitepress-plugin-search: vitepress-plugin-search:
specifier: ^1.0.4-alpha.20 specifier: ^1.0.4-alpha.20
version: 1.0.4-alpha.20(flexsearch@0.7.31)(vitepress@1.0.0-alpha.72)(vue@3.3.4) version: 1.0.4-alpha.20(flexsearch@0.7.31)(vitepress@1.0.0-alpha.72)(vue@3.3.4)
@ -475,8 +475,8 @@ importers:
specifier: ^0.16.0 specifier: ^0.16.0
version: 0.16.0(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0) version: 0.16.0(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0)
vitepress: vitepress:
specifier: 1.0.0-rc.4 specifier: 1.0.0-rc.10
version: 1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0) version: 1.0.0-rc.10(@algolia/client-search@4.19.1)(@types/node@18.16.0)(search-insights@2.6.0)
workbox-window: workbox-window:
specifier: ^7.0.0 specifier: ^7.0.0
version: 7.0.0 version: 7.0.0
@ -545,63 +545,63 @@ packages:
'@algolia/autocomplete-shared': 1.8.2 '@algolia/autocomplete-shared': 1.8.2
dev: true dev: true
/@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)(search-insights@2.6.0): /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==}
dependencies: dependencies:
'@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)(search-insights@2.6.0) '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)(search-insights@2.6.0)
'@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2) '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
- algoliasearch - algoliasearch
- search-insights - search-insights
dev: true dev: true
/@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)(search-insights@2.6.0): /@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==} resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==}
peerDependencies: peerDependencies:
search-insights: '>= 1 < 3' search-insights: '>= 1 < 3'
dependencies: dependencies:
'@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2) '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)
search-insights: 2.6.0 search-insights: 2.6.0
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
- algoliasearch - algoliasearch
dev: true dev: true
/@algolia/autocomplete-preset-algolia@1.8.2(@algolia/client-search@4.14.2)(algoliasearch@4.14.2): /@algolia/autocomplete-preset-algolia@1.8.2(@algolia/client-search@4.19.1)(algoliasearch@4.14.2):
resolution: {integrity: sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==} resolution: {integrity: sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==}
peerDependencies: peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6' '@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6'
dependencies: dependencies:
'@algolia/autocomplete-shared': 1.8.2 '@algolia/autocomplete-shared': 1.8.2
'@algolia/client-search': 4.14.2 '@algolia/client-search': 4.19.1
algoliasearch: 4.14.2 algoliasearch: 4.14.2
dev: true dev: true
/@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2): /@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1):
resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==} resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==}
peerDependencies: peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6' '@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6'
dependencies: dependencies:
'@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2) '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)
'@algolia/client-search': 4.14.2 '@algolia/client-search': 4.19.1
algoliasearch: 4.14.2 algoliasearch: 4.19.1
dev: true dev: true
/@algolia/autocomplete-shared@1.8.2: /@algolia/autocomplete-shared@1.8.2:
resolution: {integrity: sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==} resolution: {integrity: sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==}
dev: true dev: true
/@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2): /@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1):
resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==} resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==}
peerDependencies: peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6' '@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6'
dependencies: dependencies:
'@algolia/client-search': 4.14.2 '@algolia/client-search': 4.19.1
algoliasearch: 4.14.2 algoliasearch: 4.19.1
dev: true dev: true
/@algolia/cache-browser-local-storage@4.14.2: /@algolia/cache-browser-local-storage@4.14.2:
@ -610,16 +610,32 @@ packages:
'@algolia/cache-common': 4.14.2 '@algolia/cache-common': 4.14.2
dev: true dev: true
/@algolia/cache-browser-local-storage@4.19.1:
resolution: {integrity: sha512-FYAZWcGsFTTaSAwj9Std8UML3Bu8dyWDncM7Ls8g+58UOe4XYdlgzXWbrIgjaguP63pCCbMoExKr61B+ztK3tw==}
dependencies:
'@algolia/cache-common': 4.19.1
dev: true
/@algolia/cache-common@4.14.2: /@algolia/cache-common@4.14.2:
resolution: {integrity: sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==} resolution: {integrity: sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==}
dev: true dev: true
/@algolia/cache-common@4.19.1:
resolution: {integrity: sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg==}
dev: true
/@algolia/cache-in-memory@4.14.2: /@algolia/cache-in-memory@4.14.2:
resolution: {integrity: sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==} resolution: {integrity: sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==}
dependencies: dependencies:
'@algolia/cache-common': 4.14.2 '@algolia/cache-common': 4.14.2
dev: true dev: true
/@algolia/cache-in-memory@4.19.1:
resolution: {integrity: sha512-+PDWL+XALGvIginigzu8oU6eWw+o76Z8zHbBovWYcrtWOEtinbl7a7UTt3x3lthv+wNuFr/YD1Gf+B+A9V8n5w==}
dependencies:
'@algolia/cache-common': 4.19.1
dev: true
/@algolia/client-account@4.14.2: /@algolia/client-account@4.14.2:
resolution: {integrity: sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==} resolution: {integrity: sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==}
dependencies: dependencies:
@ -628,6 +644,14 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/@algolia/client-account@4.19.1:
resolution: {integrity: sha512-Oy0ritA2k7AMxQ2JwNpfaEcgXEDgeyKu0V7E7xt/ZJRdXfEpZcwp9TOg4TJHC7Ia62gIeT2Y/ynzsxccPw92GA==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/@algolia/client-analytics@4.14.2: /@algolia/client-analytics@4.14.2:
resolution: {integrity: sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==} resolution: {integrity: sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==}
dependencies: dependencies:
@ -637,6 +661,15 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/@algolia/client-analytics@4.19.1:
resolution: {integrity: sha512-5QCq2zmgdZLIQhHqwl55ZvKVpLM3DNWjFI4T+bHr3rGu23ew2bLO4YtyxaZeChmDb85jUdPDouDlCumGfk6wOg==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/@algolia/client-common@4.14.2: /@algolia/client-common@4.14.2:
resolution: {integrity: sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==} resolution: {integrity: sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==}
dependencies: dependencies:
@ -644,6 +677,13 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/@algolia/client-common@4.19.1:
resolution: {integrity: sha512-3kAIVqTcPrjfS389KQvKzliC559x+BDRxtWamVJt8IVp7LGnjq+aVAXg4Xogkur1MUrScTZ59/AaUd5EdpyXgA==}
dependencies:
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/@algolia/client-personalization@4.14.2: /@algolia/client-personalization@4.14.2:
resolution: {integrity: sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==} resolution: {integrity: sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==}
dependencies: dependencies:
@ -652,6 +692,14 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/@algolia/client-personalization@4.19.1:
resolution: {integrity: sha512-8CWz4/H5FA+krm9HMw2HUQenizC/DxUtsI5oYC0Jxxyce1vsr8cb1aEiSJArQT6IzMynrERif1RVWLac1m36xw==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/@algolia/client-search@4.14.2: /@algolia/client-search@4.14.2:
resolution: {integrity: sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==} resolution: {integrity: sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==}
dependencies: dependencies:
@ -660,32 +708,66 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/@algolia/client-search@4.19.1:
resolution: {integrity: sha512-mBecfMFS4N+yK/p0ZbK53vrZbL6OtWMk8YmnOv1i0LXx4pelY8TFhqKoTit3NPVPwoSNN0vdSN9dTu1xr1XOVw==}
dependencies:
'@algolia/client-common': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/@algolia/logger-common@4.14.2: /@algolia/logger-common@4.14.2:
resolution: {integrity: sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==} resolution: {integrity: sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==}
dev: true dev: true
/@algolia/logger-common@4.19.1:
resolution: {integrity: sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw==}
dev: true
/@algolia/logger-console@4.14.2: /@algolia/logger-console@4.14.2:
resolution: {integrity: sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==} resolution: {integrity: sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==}
dependencies: dependencies:
'@algolia/logger-common': 4.14.2 '@algolia/logger-common': 4.14.2
dev: true dev: true
/@algolia/logger-console@4.19.1:
resolution: {integrity: sha512-jj72k9GKb9W0c7TyC3cuZtTr0CngLBLmc8trzZlXdfvQiigpUdvTi1KoWIb2ZMcRBG7Tl8hSb81zEY3zI2RlXg==}
dependencies:
'@algolia/logger-common': 4.19.1
dev: true
/@algolia/requester-browser-xhr@4.14.2: /@algolia/requester-browser-xhr@4.14.2:
resolution: {integrity: sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==} resolution: {integrity: sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==}
dependencies: dependencies:
'@algolia/requester-common': 4.14.2 '@algolia/requester-common': 4.14.2
dev: true dev: true
/@algolia/requester-browser-xhr@4.19.1:
resolution: {integrity: sha512-09K/+t7lptsweRTueHnSnmPqIxbHMowejAkn9XIcJMLdseS3zl8ObnS5GWea86mu3vy4+8H+ZBKkUN82Zsq/zg==}
dependencies:
'@algolia/requester-common': 4.19.1
dev: true
/@algolia/requester-common@4.14.2: /@algolia/requester-common@4.14.2:
resolution: {integrity: sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==} resolution: {integrity: sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==}
dev: true dev: true
/@algolia/requester-common@4.19.1:
resolution: {integrity: sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ==}
dev: true
/@algolia/requester-node-http@4.14.2: /@algolia/requester-node-http@4.14.2:
resolution: {integrity: sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==} resolution: {integrity: sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==}
dependencies: dependencies:
'@algolia/requester-common': 4.14.2 '@algolia/requester-common': 4.14.2
dev: true dev: true
/@algolia/requester-node-http@4.19.1:
resolution: {integrity: sha512-6DK52DHviBHTG2BK/Vv2GIlEw7i+vxm7ypZW0Z7vybGCNDeWzADx+/TmxjkES2h15+FZOqVf/Ja677gePsVItA==}
dependencies:
'@algolia/requester-common': 4.19.1
dev: true
/@algolia/transporter@4.14.2: /@algolia/transporter@4.14.2:
resolution: {integrity: sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==} resolution: {integrity: sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==}
dependencies: dependencies:
@ -694,6 +776,14 @@ packages:
'@algolia/requester-common': 4.14.2 '@algolia/requester-common': 4.14.2
dev: true dev: true
/@algolia/transporter@4.19.1:
resolution: {integrity: sha512-nkpvPWbpuzxo1flEYqNIbGz7xhfhGOKGAZS7tzC+TELgEmi7z99qRyTfNSUlW7LZmB3ACdnqAo+9A9KFBENviQ==}
dependencies:
'@algolia/cache-common': 4.19.1
'@algolia/logger-common': 4.19.1
'@algolia/requester-common': 4.19.1
dev: true
/@alloc/quick-lru@5.2.0: /@alloc/quick-lru@5.2.0:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1403,6 +1493,7 @@ packages:
/@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.12.3): /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.12.3):
resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1418,6 +1509,7 @@ packages:
/@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1431,6 +1523,7 @@ packages:
/@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.12.3): /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.12.3):
resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.12.0 '@babel/core': ^7.12.0
dependencies: dependencies:
@ -1445,6 +1538,7 @@ packages:
/@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1456,6 +1550,7 @@ packages:
/@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.12.3): /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.12.3):
resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1467,6 +1562,7 @@ packages:
/@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1478,6 +1574,7 @@ packages:
/@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.12.3): /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.12.3):
resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1489,6 +1586,7 @@ packages:
/@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1500,6 +1598,7 @@ packages:
/@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1511,6 +1610,7 @@ packages:
/@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.12.3): /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.12.3):
resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1525,6 +1625,7 @@ packages:
/@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1536,6 +1637,7 @@ packages:
/@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.12.3): /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.12.3):
resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1548,6 +1650,7 @@ packages:
/@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1561,6 +1664,7 @@ packages:
/@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.12.3): /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.12.3):
resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -1576,6 +1680,7 @@ packages:
/@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.12.3): /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.12.3):
resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
engines: {node: '>=4'} engines: {node: '>=4'}
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
@ -2827,14 +2932,14 @@ packages:
resolution: {integrity: sha512-NaXVp3I8LdmJ54fn038KHgG7HmbIzZlKS2FkVf6mKcW5bYMJovkx4947joQyZk5yubxOZ+ddHSh79y39Aevufg==} resolution: {integrity: sha512-NaXVp3I8LdmJ54fn038KHgG7HmbIzZlKS2FkVf6mKcW5bYMJovkx4947joQyZk5yubxOZ+ddHSh79y39Aevufg==}
dev: true dev: true
/@docsearch/css@3.5.1: /@docsearch/css@3.5.2:
resolution: {integrity: sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA==} resolution: {integrity: sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==}
dev: true dev: true
/@docsearch/js@3.3.5(@algolia/client-search@4.14.2): /@docsearch/js@3.3.5(@algolia/client-search@4.19.1):
resolution: {integrity: sha512-nZi074OCryZnzva2LNcbQkwBJIND6cvuFI4s1FIe6Ygf6n9g6B/IYUULXNx05rpoCZ+KEoEt3taROpsHBliuSw==} resolution: {integrity: sha512-nZi074OCryZnzva2LNcbQkwBJIND6cvuFI4s1FIe6Ygf6n9g6B/IYUULXNx05rpoCZ+KEoEt3taROpsHBliuSw==}
dependencies: dependencies:
'@docsearch/react': 3.3.5(@algolia/client-search@4.14.2) '@docsearch/react': 3.3.5(@algolia/client-search@4.19.1)
preact: 10.11.0 preact: 10.11.0
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
@ -2843,10 +2948,10 @@ packages:
- react-dom - react-dom
dev: true dev: true
/@docsearch/js@3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0): /@docsearch/js@3.5.2(@algolia/client-search@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-EXi8de5njxgP6TV3N9ytnGRLG9zmBNTEZjR4VzwPcpPLbZxxTLG2gaFyJyKiFVQxHW/DPlMrDJA3qoRRGEkgZw==} resolution: {integrity: sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==}
dependencies: dependencies:
'@docsearch/react': 3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0) '@docsearch/react': 3.5.2(@algolia/client-search@4.19.1)(search-insights@2.6.0)
preact: 10.11.0 preact: 10.11.0
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
@ -2856,7 +2961,7 @@ packages:
- search-insights - search-insights
dev: true dev: true
/@docsearch/react@3.3.5(@algolia/client-search@4.14.2): /@docsearch/react@3.3.5(@algolia/client-search@4.19.1):
resolution: {integrity: sha512-Zuxf4z5PZ9eIQkVCNu76v1H+KAztKItNn3rLzZa7kpBS+++TgNARITnZeUS7C1DKoAhJZFr6T/H+Lvc6h/iiYg==} resolution: {integrity: sha512-Zuxf4z5PZ9eIQkVCNu76v1H+KAztKItNn3rLzZa7kpBS+++TgNARITnZeUS7C1DKoAhJZFr6T/H+Lvc6h/iiYg==}
peerDependencies: peerDependencies:
'@types/react': '>= 16.8.0 < 19.0.0' '@types/react': '>= 16.8.0 < 19.0.0'
@ -2871,19 +2976,20 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@algolia/autocomplete-core': 1.8.2 '@algolia/autocomplete-core': 1.8.2
'@algolia/autocomplete-preset-algolia': 1.8.2(@algolia/client-search@4.14.2)(algoliasearch@4.14.2) '@algolia/autocomplete-preset-algolia': 1.8.2(@algolia/client-search@4.19.1)(algoliasearch@4.14.2)
'@docsearch/css': 3.3.5 '@docsearch/css': 3.3.5
algoliasearch: 4.14.2 algoliasearch: 4.14.2
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
dev: true dev: true
/@docsearch/react@3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0): /@docsearch/react@3.5.2(@algolia/client-search@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ==} resolution: {integrity: sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==}
peerDependencies: peerDependencies:
'@types/react': '>= 16.8.0 < 19.0.0' '@types/react': '>= 16.8.0 < 19.0.0'
react: '>= 16.8.0 < 19.0.0' react: '>= 16.8.0 < 19.0.0'
react-dom: '>= 16.8.0 < 19.0.0' react-dom: '>= 16.8.0 < 19.0.0'
search-insights: '>= 1 < 3'
peerDependenciesMeta: peerDependenciesMeta:
'@types/react': '@types/react':
optional: true optional: true
@ -2891,14 +2997,16 @@ packages:
optional: true optional: true
react-dom: react-dom:
optional: true optional: true
search-insights:
optional: true
dependencies: dependencies:
'@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)(search-insights@2.6.0) '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)(search-insights@2.6.0)
'@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2) '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.19.1)(algoliasearch@4.19.1)
'@docsearch/css': 3.5.1 '@docsearch/css': 3.5.2
algoliasearch: 4.14.2 algoliasearch: 4.19.1
search-insights: 2.6.0
transitivePeerDependencies: transitivePeerDependencies:
- '@algolia/client-search' - '@algolia/client-search'
- search-insights
dev: true dev: true
/@es-joy/jsdoccomment@0.39.4: /@es-joy/jsdoccomment@0.39.4:
@ -5378,8 +5486,20 @@ packages:
- vue - vue
dev: true dev: true
/@vueuse/integrations@10.3.0(focus-trap@7.5.2)(vue@3.3.4): /@vueuse/core@10.4.1(vue@3.3.4):
resolution: {integrity: sha512-Jgiv7oFyIgC6BxmDtiyG/fxyGysIds00YaY7sefwbhCZ2/tjEx1W/1WcsISSJPNI30in28+HC2J4uuU8184ekg==} resolution: {integrity: sha512-DkHIfMIoSIBjMgRRvdIvxsyboRZQmImofLyOHADqiVbQVilP8VVHDhBX2ZqoItOgu7dWa8oXiNnScOdPLhdEXg==}
dependencies:
'@types/web-bluetooth': 0.0.17
'@vueuse/metadata': 10.4.1
'@vueuse/shared': 10.4.1(vue@3.3.4)
vue-demi: 0.14.5(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/@vueuse/integrations@10.4.1(focus-trap@7.5.2)(vue@3.3.4):
resolution: {integrity: sha512-uRBPyG5Lxoh1A/J+boiioPT3ELEAPEo4t8W6Mr4yTKIQBeW/FcbsotZNPr4k9uz+3QEksMmflWloS9wCnypM7g==}
peerDependencies: peerDependencies:
async-validator: '*' async-validator: '*'
axios: '*' axios: '*'
@ -5419,8 +5539,8 @@ packages:
universal-cookie: universal-cookie:
optional: true optional: true
dependencies: dependencies:
'@vueuse/core': 10.3.0(vue@3.3.4) '@vueuse/core': 10.4.1(vue@3.3.4)
'@vueuse/shared': 10.3.0(vue@3.3.4) '@vueuse/shared': 10.4.1(vue@3.3.4)
focus-trap: 7.5.2 focus-trap: 7.5.2
vue-demi: 0.14.5(vue@3.3.4) vue-demi: 0.14.5(vue@3.3.4)
transitivePeerDependencies: transitivePeerDependencies:
@ -5436,6 +5556,10 @@ packages:
resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==} resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==}
dev: true dev: true
/@vueuse/metadata@10.4.1:
resolution: {integrity: sha512-2Sc8X+iVzeuMGHr6O2j4gv/zxvQGGOYETYXEc41h0iZXIRnRbJZGmY/QP8dvzqUelf8vg0p/yEA5VpCEu+WpZg==}
dev: true
/@vueuse/shared@10.1.0(vue@3.3.4): /@vueuse/shared@10.1.0(vue@3.3.4):
resolution: {integrity: sha512-2X52ogu12i9DkKOQ01yeb/BKg9UO87RNnpm5sXkQvyORlbq8ONS5l39MYkjkeVWWjdT0teJru7a2S41dmHmqjQ==} resolution: {integrity: sha512-2X52ogu12i9DkKOQ01yeb/BKg9UO87RNnpm5sXkQvyORlbq8ONS5l39MYkjkeVWWjdT0teJru7a2S41dmHmqjQ==}
dependencies: dependencies:
@ -5454,6 +5578,15 @@ packages:
- vue - vue
dev: true dev: true
/@vueuse/shared@10.4.1(vue@3.3.4):
resolution: {integrity: sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg==}
dependencies:
vue-demi: 0.14.5(vue@3.3.4)
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: true
/@wdio/config@7.30.0(typescript@5.1.3): /@wdio/config@7.30.0(typescript@5.1.3):
resolution: {integrity: sha512-/38rol9WCfFTMtXyd/C856/aexxIZnfVvXg7Fw2WXpqZ9qadLA+R4N35S2703n/RByjK/5XAYtHoljtvh3727w==} resolution: {integrity: sha512-/38rol9WCfFTMtXyd/C856/aexxIZnfVvXg7Fw2WXpqZ9qadLA+R4N35S2703n/RByjK/5XAYtHoljtvh3727w==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@ -5856,6 +5989,25 @@ packages:
'@algolia/transporter': 4.14.2 '@algolia/transporter': 4.14.2
dev: true dev: true
/algoliasearch@4.19.1:
resolution: {integrity: sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g==}
dependencies:
'@algolia/cache-browser-local-storage': 4.19.1
'@algolia/cache-common': 4.19.1
'@algolia/cache-in-memory': 4.19.1
'@algolia/client-account': 4.19.1
'@algolia/client-analytics': 4.19.1
'@algolia/client-common': 4.19.1
'@algolia/client-personalization': 4.19.1
'@algolia/client-search': 4.19.1
'@algolia/logger-common': 4.19.1
'@algolia/logger-console': 4.19.1
'@algolia/requester-browser-xhr': 4.19.1
'@algolia/requester-common': 4.19.1
'@algolia/requester-node-http': 4.19.1
'@algolia/transporter': 4.19.1
dev: true
/amdefine@1.0.1: /amdefine@1.0.1:
resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==}
engines: {node: '>=0.4.2'} engines: {node: '>=0.4.2'}
@ -9350,7 +9502,7 @@ packages:
dependencies: dependencies:
foreground-child: 3.1.1 foreground-child: 3.1.1
jackspeak: 2.1.1 jackspeak: 2.1.1
minimatch: 9.0.0 minimatch: 9.0.1
minipass: 5.0.0 minipass: 5.0.0
path-scurry: 1.7.0 path-scurry: 1.7.0
dev: true dev: true
@ -11974,15 +12126,15 @@ packages:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
dev: true dev: true
/minimatch@9.0.0: /minimatch@9.0.1:
resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==} resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
dev: true dev: true
/minimatch@9.0.1: /minimatch@9.0.3:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
@ -14764,35 +14916,35 @@ packages:
is-typedarray: 1.0.0 is-typedarray: 1.0.0
dev: true dev: true
/typedoc-plugin-markdown@3.15.2(typedoc@0.24.5): /typedoc-plugin-markdown@3.15.2(typedoc@0.25.0):
resolution: {integrity: sha512-OPXAL9hhdoVJzH/UaKAz6CBS/s8KlYyLWwnxF7ap0fQCuaMMWShA1JBq4n1SXbiGjx+7DOhOfTKQ5OzwryN3Vw==} resolution: {integrity: sha512-OPXAL9hhdoVJzH/UaKAz6CBS/s8KlYyLWwnxF7ap0fQCuaMMWShA1JBq4n1SXbiGjx+7DOhOfTKQ5OzwryN3Vw==}
peerDependencies: peerDependencies:
typedoc: '>=0.24.0' typedoc: '>=0.24.0'
dependencies: dependencies:
handlebars: 4.7.7 handlebars: 4.7.7
typedoc: 0.24.5(typescript@5.0.4) typedoc: 0.25.0(typescript@5.0.4)
typedoc-plugin-mdn-links: 3.0.3(typedoc@0.24.5) typedoc-plugin-mdn-links: 3.0.3(typedoc@0.25.0)
dev: true dev: true
/typedoc-plugin-mdn-links@3.0.3(typedoc@0.24.5): /typedoc-plugin-mdn-links@3.0.3(typedoc@0.25.0):
resolution: {integrity: sha512-NXhIpwQnsg7BcyMCHVqj3tUK+DL4g3Bt96JbFl4APzTGFkA+iM6GfZ/fn3TAqJ8O0CXG5R9BfWxolw1m1omNuQ==} resolution: {integrity: sha512-NXhIpwQnsg7BcyMCHVqj3tUK+DL4g3Bt96JbFl4APzTGFkA+iM6GfZ/fn3TAqJ8O0CXG5R9BfWxolw1m1omNuQ==}
peerDependencies: peerDependencies:
typedoc: '>= 0.23.14 || 0.24.x' typedoc: '>= 0.23.14 || 0.24.x'
dependencies: dependencies:
typedoc: 0.24.5(typescript@5.0.4) typedoc: 0.25.0(typescript@5.0.4)
dev: true dev: true
/typedoc@0.24.5(typescript@5.0.4): /typedoc@0.25.0(typescript@5.0.4):
resolution: {integrity: sha512-tE1YDRxOTwJ33HltVazKiADqy/CasUmd2UVMnGOS2kX5Oj7q4rDVsIlcC0j03K1h3lEkGtvEyusBF7Psz4F4kA==} resolution: {integrity: sha512-FvCYWhO1n5jACE0C32qg6b3dSfQ8f2VzExnnRboowHtqUD6ARzM2r8YJeZFYXhcm2hI4C2oCRDgNPk/yaQUN9g==}
engines: {node: '>= 14.14'} engines: {node: '>= 16'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x
dependencies: dependencies:
lunr: 2.3.9 lunr: 2.3.9
marked: 4.3.0 marked: 4.3.0
minimatch: 9.0.0 minimatch: 9.0.3
shiki: 0.14.1 shiki: 0.14.3
typescript: 5.0.4 typescript: 5.0.4
dev: true dev: true
@ -15270,16 +15422,16 @@ packages:
flexsearch: 0.7.31 flexsearch: 0.7.31
glob-to-regexp: 0.4.1 glob-to-regexp: 0.4.1
markdown-it: 13.0.1 markdown-it: 13.0.1
vitepress: 1.0.0-alpha.72(@algolia/client-search@4.14.2)(@types/node@18.16.0) vitepress: 1.0.0-alpha.72(@algolia/client-search@4.19.1)(@types/node@18.16.0)
vue: 3.3.4 vue: 3.3.4
dev: true dev: true
/vitepress@1.0.0-alpha.72(@algolia/client-search@4.14.2)(@types/node@18.16.0): /vitepress@1.0.0-alpha.72(@algolia/client-search@4.19.1)(@types/node@18.16.0):
resolution: {integrity: sha512-Ou7fNE/OVYLrKGQMHSTVG6AcNsdv7tm4ACrdhx93SPMzEDj8UgIb4RFa5CTTowaYf3jeDGi2EAJlzXVC+IE3dg==} resolution: {integrity: sha512-Ou7fNE/OVYLrKGQMHSTVG6AcNsdv7tm4ACrdhx93SPMzEDj8UgIb4RFa5CTTowaYf3jeDGi2EAJlzXVC+IE3dg==}
hasBin: true hasBin: true
dependencies: dependencies:
'@docsearch/css': 3.3.3 '@docsearch/css': 3.3.3
'@docsearch/js': 3.3.5(@algolia/client-search@4.14.2) '@docsearch/js': 3.3.5(@algolia/client-search@4.19.1)
'@vitejs/plugin-vue': 4.2.3(vite@4.4.9)(vue@3.3.4) '@vitejs/plugin-vue': 4.2.3(vite@4.4.9)(vue@3.3.4)
'@vue/devtools-api': 6.5.0 '@vue/devtools-api': 6.5.0
'@vueuse/core': 10.3.0(vue@3.3.4) '@vueuse/core': 10.3.0(vue@3.3.4)
@ -15304,17 +15456,15 @@ packages:
- terser - terser
dev: true dev: true
/vitepress@1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0): /vitepress@1.0.0-rc.10(@algolia/client-search@4.19.1)(@types/node@18.16.0)(search-insights@2.6.0):
resolution: {integrity: sha512-JCQ89Bm6ECUTnyzyas3JENo00UDJeK8q1SUQyJYou+4Yz5BKEc/F3O21cu++DnUT2zXc0kvQ2Aj4BZCc/nioXQ==} resolution: {integrity: sha512-+MsahIWqq5WUEmj6MR4obcKYbT7im07jZPCQPdNJExkeOSbOAJ4xypSLx88x7rvtzWHhHc5aXbOhCRvGEGjFrw==}
hasBin: true hasBin: true
dependencies: dependencies:
'@docsearch/css': 3.5.1 '@docsearch/css': 3.5.2
'@docsearch/js': 3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0) '@docsearch/js': 3.5.2(@algolia/client-search@4.19.1)(search-insights@2.6.0)
'@vitejs/plugin-vue': 4.2.3(vite@4.4.9)(vue@3.3.4)
'@vue/devtools-api': 6.5.0 '@vue/devtools-api': 6.5.0
'@vueuse/core': 10.3.0(vue@3.3.4) '@vueuse/core': 10.4.1(vue@3.3.4)
'@vueuse/integrations': 10.3.0(focus-trap@7.5.2)(vue@3.3.4) '@vueuse/integrations': 10.4.1(focus-trap@7.5.2)(vue@3.3.4)
body-scroll-lock: 4.0.0-beta.0
focus-trap: 7.5.2 focus-trap: 7.5.2
mark.js: 8.11.1 mark.js: 8.11.1
minisearch: 6.1.0 minisearch: 6.1.0