Compare commits

..

78 Commits

Author SHA1 Message Date
Sidharth Vinod
49446940f5 Merge branch 'develop' into sidv/FixTilde
* develop:
  chore: Align with convention
  chore(deps): update all patch dependencies
  chore(deps): update all minor dependencies
2023-09-03 12:27:22 +05:30
Sidharth Vinod
69b4b48f62 Merge pull request #4534 from mermaid-js/UpdateClassMemberHandling
Update class member handling
2023-09-03 06:51:37 +00:00
Sidharth Vinod
05c2a11e3d chore: Align with convention 2023-09-03 12:00:32 +05:30
Sidharth Vinod
650d712bd8 fix: Add support for ~test Array~string~ 2023-09-03 11:55:32 +05:30
Justin Greywolf
5839e0de87 add additional test case 2023-08-28 06:13:30 -07:00
Sidharth Vinod
6e51f8fd98 Merge pull request #4782 from mermaid-js/renovate/patch-all-patch
chore(deps): update all patch dependencies (patch)
2023-08-28 07:37:22 +00:00
Sidharth Vinod
9823834a56 Merge pull request #4783 from mermaid-js/renovate/all-minor
chore(deps): update all minor dependencies (minor)
2023-08-28 07:37:09 +00:00
renovate[bot]
6b0e0e21ac chore(deps): update all patch dependencies 2023-08-28 05:09:59 +00:00
renovate[bot]
19aaf459a5 chore(deps): update all minor dependencies 2023-08-28 00:12:53 +00:00
Justin Greywolf
12f11c6721 added test case 2023-08-27 15:47:22 -07:00
Justin Greywolf
b513169f12 Merge branch 'develop' into UpdateClassMemberHandling 2023-08-26 14:01:42 -07:00
Justin Greywolf
87880fdf40 add sanitize text 2023-08-26 14:01:14 -07:00
Nikolay Rozhkov
ed819e96d5 Merge pull request #4758 from tomperr/feat/4746_add_er_alias
feat(er): add entity name alias
2023-08-26 11:02:15 +00:00
Justin Greywolf
5a2b3db14c Merge branch 'develop' into UpdateClassMemberHandling 2023-08-25 13:21:57 -07:00
jgreywolf
fa6198b4ce Update docs 2023-08-25 20:13:40 +00:00
Justin Greywolf
3678ad4e9d modifications to generic parser 2023-08-25 13:08:51 -07:00
Sidharth Vinod
979dcb073d Merge pull request #4774 from Yokozuna59/bug/4772_align-slices-and-legend-orders
fix(pie): align slices and legend orders
2023-08-25 19:58:52 +00:00
Sidharth Vinod
ecf14cd4e3 docs: Fix link 2023-08-26 01:33:15 +05:30
Sidharth Vinod
92d9f35f89 Update docs 2023-08-26 01:20:17 +05:30
Justin Greywolf
8e64995047 Merge branch 'develop' into UpdateClassMemberHandling 2023-08-25 10:58:49 -07:00
Justin Greywolf
8b96282c48 improvements to parseGenericTypes 2023-08-25 10:58:20 -07:00
Sidharth Vinod
15c7c37227 Merge pull request #4723 from GingerNinjaNicko/fix-fontawesome-class
Fix Twitter fontawesome class in flowchart.md
2023-08-25 13:51:02 +00:00
Reda Al Sulais
267935713c fix(pie): align slices and legend orders 2023-08-25 16:12:26 +03:00
Knut Sveidqvist
8ef5f38861 Merge remote-tracking branch 'origin/develop' into develop 2023-08-25 14:26:27 +02:00
Knut Sveidqvist
47af4760bc Merge branch 'master' into develop 2023-08-25 14:26:21 +02:00
Knut Sveidqvist
8e5275d844 Mermaid version v10.4.0 2023-08-25 14:19:00 +02:00
Knut Sveidqvist
c51afa4dd2 Merge branch 'release/10.4.0' 2023-08-25 14:16:18 +02:00
Knut Sveidqvist
671ad82ad3 unique batches every time, if not repeated tests end up in the same batch 2023-08-25 14:13:11 +02:00
Sidharth Vinod
1bfa1a8c88 Merge pull request #4767 from nirname/docs/2910_renaming-docs-and-fixes
Docs/2910 Remove n00b and fix some docs
2023-08-25 11:32:00 +00:00
Nikolay Rozhkov
ab140a0fc7 Added missed .md 2023-08-25 14:27:06 +03:00
Nikolay Rozhkov
7d395e176e Increase JS heap 2023-08-25 12:55:26 +03:00
Nikolay Rozhkov
3d35015ee9 More tests for redirects + prettier 2023-08-25 12:37:29 +03:00
Nikolay Rozhkov
2676130146 Fixed redirects inside vitepress, extended tests 2023-08-25 12:35:07 +03:00
Sidharth Vinod
fb3814bf85 chore: Explain redirect.ts clearly 2023-08-25 14:56:20 +05:30
Sidharth Vinod
2dd1415849 docs: Fix npmjs link 2023-08-25 12:43:31 +05:30
Sidharth Vinod
9fa6dc23ca Merge branch 'develop' into feat/4746_add_er_alias 2023-08-25 04:35:40 +00:00
Sidharth Vinod
9dccf4d9c9 chore: Update editor.bash to build latest version 2023-08-25 10:04:53 +05:30
Sidharth Vinod
f248a22c71 Merge branch 'develop' into feat/4746_add_er_alias 2023-08-25 04:14:24 +00:00
Sidharth Vinod
6563a6ea26 chore: Build after clone 2023-08-25 09:43:53 +05:30
Sidharth Vinod
87d2899e4e Merge branch 'develop' into feat/4746_add_er_alias 2023-08-25 04:07:38 +00:00
Sidharth Vinod
a3a6eb9bf5 chore: Force install npm to avoid cache. 2023-08-25 09:37:22 +05:30
Sidharth Vinod
c28c285711 Merge branch 'develop' into feat/4746_add_er_alias 2023-08-25 03:48:11 +00:00
Sidharth Vinod
a4ba192aad Merge branch 'develop' into feat/4746_add_er_alias 2023-08-25 03:06:47 +00:00
Nikolay Rozhkov
58afdd1baa Reverted docker compose to develop branch 2023-08-25 01:49:36 +03:00
Justin Greywolf
0881619fcb Merge branch 'UpdateClassMemberHandling' of https://github.com/mermaid-js/mermaid into UpdateClassMemberHandling 2023-08-24 14:05:19 -07:00
Nikolay Rozhkov
eba5fcca6b Run GA 2023-08-24 22:26:20 +03:00
nirname
52cbf9fd28 Update docs 2023-08-24 19:07:14 +00:00
nirname
fc19bf93aa Update docs
Fixed link to mermaid-js.github.io after review

Update docs

Fixed link again
2023-08-24 22:01:35 +03:00
Tom PERRILLAT-COLLOMB
56419f7459 fix(er): bug if relationship is declared first 2023-08-24 16:16:40 +02:00
Sidharth Vinod
2537152c7a Merge pull request #4768 from mermaid-js/latest-news
Docs: update Latest News section
2023-08-24 10:32:58 +00:00
Steph
14c1c1cc59 update latest news 2023-08-23 23:11:58 -07:00
Nikolay Rozhkov
108c25f19f Removed all n00b file names and added redirects 2023-08-23 23:32:33 +03:00
Justin Greywolf
3ec32521f8 Update packages/mermaid/src/diagrams/class/svgDraw.js
Co-authored-by: Sidharth Vinod <sidharthv96@gmail.com>
2023-08-23 05:22:23 -07:00
Knut Sveidqvist
72b4a74bee Merge branch 'master' of github.com:mermaid-js/mermaid 2023-08-23 10:24:56 +02:00
Tom PERRILLAT-COLLOMB
4a06bc1a68 test(er): add cypress test on entity name alias 2023-08-22 13:53:37 +02:00
Tom PERRILLAT-COLLOMB
a7ae1b6890 feat(er): use square brackets to add aliases 2023-08-22 11:05:09 +02:00
Tom PERRILLAT-COLLOMB
cc8b4572d5 docs(er): add release version for entity name aliases 2023-08-22 00:30:33 +02:00
Tom PERRILLAT-COLLOMB
e5315f2933 feat(er): add entity name alias 2023-08-21 23:33:42 +02:00
Justin Greywolf
3f327196fd return comment 2023-08-15 11:07:21 -07:00
Justin Greywolf
bbaab54ec9 add tsdoc comments 2023-08-15 11:02:06 -07:00
Justin Greywolf
9a9abac5b1 Merge branch 'develop' into UpdateClassMemberHandling 2023-08-15 10:08:42 -07:00
Justin Greywolf
6ed0c9bc36 update tests 2023-08-15 10:02:31 -07:00
Nicko J. Ruddock
65c93807d8 Fix Twitter fontawesome class in flowchart.md 2023-08-11 15:23:16 +01:00
Knut Sveidqvist
8ed9ddc7aa Merge branch 'release/10.3.1' 2023-08-11 14:21:10 +02:00
Justin Greywolf
02acf9d7d9 Merge branch 'UpdateClassMemberHandling' of https://github.com/mermaid-js/mermaid into UpdateClassMemberHandling 2023-07-03 09:40:52 -07:00
Justin Greywolf
e29d2b29a9 apply suggesitons 2023-07-03 09:40:25 -07:00
Justin Greywolf
c001520e54 Update packages/mermaid/src/diagrams/class/classTypes.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2023-07-02 18:11:25 -07:00
Justin Greywolf
8435330534 Update packages/mermaid/src/diagrams/class/classTypes.ts
Co-authored-by: Alois Klink <alois@aloisklink.com>
2023-07-02 18:10:53 -07:00
Justin Greywolf
1d391d9408 Merge branch 'develop' into UpdateClassMemberHandling 2023-07-02 17:45:30 -07:00
Justin Greywolf
6abf0f1d19 Merge branch 'develop' into UpdateClassMemberHandling 2023-06-29 08:55:37 -07:00
Justin Greywolf
7b2ef1110a update tests and db name 2023-06-28 12:37:32 -07:00
Justin Greywolf
3718274a1c Merge branch 'develop' into UpdateClassMemberHandling 2023-06-28 08:26:33 -07:00
Justin Greywolf
b32da2b1b1 Fix tests 2023-06-25 15:07:47 -07:00
Justin Greywolf
a9ee184551 spec changes 2023-06-12 14:23:36 -07:00
Justin Greywolf
164605b442 update classes to handle , in generic 2023-06-12 11:31:29 -07:00
Justin Greywolf
f4ffd5c965 Merge branch 'develop' into UpdateClassMemberHandling 2023-06-09 16:01:15 -07:00
Justin Greywolf
b0b3c7f410 Update and add tests 2023-06-02 03:08:53 -07:00
Justin Greywolf
0aa09bfca5 Create new type for member handling 2023-05-30 10:43:44 -07:00
55 changed files with 1624 additions and 887 deletions

View File

@@ -60,7 +60,7 @@ Use Mermaid with your favorite applications, check out the list of [Integrations
You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/n00b-gettingStarted.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/intro/getting-started.md), [Usage](./docs/config/usage.md) and [Tutorials](./docs/config/Tutorials.md).
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.

View File

@@ -55,7 +55,7 @@ Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。<br/>
你可以访问 [教程](./docs/config/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/n00b-gettingStarted.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md).
如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/config/Tutorials.md).
<!-- </Main description> -->

View File

@@ -38,7 +38,10 @@
"docsy",
"doku",
"dompurify",
"dont",
"doublecircle",
"edgechromium",
"elems",
"elkjs",
"elle",
"faber",
@@ -154,7 +157,8 @@
"xlink",
"yash",
"yokozuna",
"zenuml"
"zenuml",
"zune"
],
"patterns": [
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },

View File

@@ -18,7 +18,11 @@ const utf8ToB64 = (str: string): string => {
return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
};
const batchId: string = 'mermaid-batch-' + Cypress.env('CYPRESS_COMMIT') || Date.now().toString();
const batchId: string =
'mermaid-batch-' +
(Cypress.env('useAppli')
? Date.now().toString()
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
export const mermaidUrl = (
graphStr: string,

View File

@@ -386,30 +386,6 @@ describe('Class diagram V2', () => {
{ 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', () => {
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(
`
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

@@ -305,4 +305,21 @@ ORDER ||--|{ LINE-ITEM : contains
{}
);
});
it('should render entities with entity name aliases', () => {
imgSnapshotTest(
`
erDiagram
p[Person] {
varchar(64) firstName
varchar(64) lastName
}
c["Customer Account"] {
varchar(128) email
}
p ||--o| c : has
`,
{ logLevel: 1 }
);
});
});

View File

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

View File

@@ -110,6 +110,20 @@
}
MANUFACTURER only one to zero or more CAR : makes
</pre>
<hr />
<pre class="mermaid">
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
</pre>
<hr />
<script type="module">
import mermaid from './mermaid.esm.mjs';

View File

@@ -5,9 +5,9 @@ services:
stdin_open: true
tty: true
working_dir: /mermaid
mem_limit: '2G'
mem_limit: '4G'
environment:
- NODE_OPTIONS=--max_old_space_size=2048
- NODE_OPTIONS=--max_old_space_size=4096
volumes:
- ./:/mermaid
- root_cache:/root/.cache

View File

@@ -32,7 +32,7 @@ The definitions that can be generated the Live-Editor are also backwards-compati
## Mermaid with HTML
Examples are provided in [Getting Started](../intro/n00b-gettingStarted.md)
Examples are provided in [Getting Started](../intro/getting-started.md)
**CodePen Examples:**

View File

@@ -2,9 +2,9 @@
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/n00b-advanced.md](../../packages/mermaid/src/docs/config/n00b-advanced.md).
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/advanced.md](../../packages/mermaid/src/docs/config/advanced.md).
# Advanced n00b mermaid (Coming soon..)
# Advanced mermaid (Coming soon..)
## splitting mermaid code from html

View File

@@ -41,7 +41,7 @@ pnpm add mermaid
**Hosting mermaid on a web page:**
> Note:This topic explored in greater depth in the [User Guide for Beginners](../intro/n00b-gettingStarted.md)
> Note:This topic 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:

View File

@@ -2,13 +2,13 @@
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/intro/n00b-gettingStarted.md](../../packages/mermaid/src/docs/intro/n00b-gettingStarted.md).
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/intro/getting-started.md](../../packages/mermaid/src/docs/intro/getting-started.md).
# A Mermaid User-Guide for Beginners
Mermaid is composed of three parts: Deployment, Syntax and Configuration.
This section talks about the different ways to deploy Mermaid. Learning the [Syntax](n00b-syntaxReference.md) would be of great help to the beginner.
This section talks about the different ways to deploy Mermaid. Learning the [Syntax](syntax-reference.md) would be of great help to the beginner.
> Generally the live editor is enough for most general uses of mermaid, and is a good place to start learning.
@@ -53,7 +53,7 @@ graph TD
In the `Code` section one can write or edit raw mermaid code, and instantly `Preview` the rendered result on the panel beside it.
The `Configuration` Section is for changing the appearance and behavior of mermaid diagrams. An easy introduction to mermaid configuration is found in the [Advanced usage](../config/n00b-advanced.md) section. A complete configuration reference cataloging the default values can be found on the [mermaidAPI](../config/setup/README.md) page.
The `Configuration` Section is for changing the appearance and behavior of mermaid diagrams. An easy introduction to mermaid configuration is found in the [Advanced usage](../config/advanced.md) section. A complete configuration reference cataloging the default values can be found on the [mermaidAPI](../config/setup/README.md) page.
![Code,Config and Preview](./img/Code-Preview-Config.png)

View File

@@ -10,7 +10,7 @@
It is a JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
> If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](n00b-syntaxReference.md).
> If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](syntax-reference.md).
<img src="/header.png" alt="" />
@@ -44,7 +44,7 @@ Mermaid allows even non-programmers to easily create detailed and diagrams throu
[Tutorials](../config/Tutorials.md) has video tutorials.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](../ecosystem/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/n00b-gettingStarted.md) and [Usage](../config/usage.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/getting-started.md) and [Usage](../config/usage.md).
🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](../community/development.md) | 🔌 [Plug-Ins](../ecosystem/integrations.md)
@@ -284,9 +284,9 @@ quadrantChart
## Installation
**In depth guides and examples can be found at [Getting Started](./n00b-gettingStarted.md) and [Usage](../config/usage.md).**
**In depth guides and examples can be found at [Getting Started](./getting-started.md) and [Usage](../config/usage.md).**
**It would also be helpful to learn more about mermaid's [Syntax](./n00b-syntaxReference.md).**
**It would also be helpful to learn more about mermaid's [Syntax](./syntax-reference.md).**
### CDN
@@ -402,7 +402,7 @@ Update version number in `package.json`.
npm publish
```
The above command generates files into the `dist` folder and publishes them to [npmjs.org](npmjs.org).
The above command generates files into the `dist` folder and publishes them to [npmjs.com](https://www.npmjs.com/).
## Security and safe diagrams

View File

@@ -2,7 +2,7 @@
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/intro/n00b-syntaxReference.md](../../packages/mermaid/src/docs/intro/n00b-syntaxReference.md).
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/intro/syntax-reference.md](../../packages/mermaid/src/docs/intro/syntax-reference.md).
# Diagram Syntax
@@ -42,7 +42,7 @@ erDiagram
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
```
The [Getting Started](./n00b-gettingStarted.md) section can also provide some practical examples of mermaid syntax.
The [Getting Started](./getting-started.md) section can also provide some practical examples of mermaid syntax.
## Diagram Breaking
@@ -66,20 +66,20 @@ Configuration is the third part of Mermaid, after deployment and syntax. It deal
If you are interested in altering and customizing your Mermaid Diagrams, you will find the methods and values available for [Configuration](../config/setup/README.md) here. It includes themes.
This section will introduce the different methods of configuring the behaviors and appearances of Mermaid Diagrams.
The following are the most commonly used methods, and they are all tied to Mermaid [Deployment](./n00b-gettingStarted.md) methods.
The following are the most commonly used methods, and they are all tied to Mermaid [Deployment](./getting-started.md) methods.
### Configuration Section in the [Live Editor](https://mermaid.live).
Here you can edit certain values to change the behavior and appearance of the diagram.
### [The initialize() call](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted?id=_3-calling-the-javascript-api),
### [The initialize() call](./getting-started.md#_3-calling-the-javascript-api)
Used when Mermaid is called via an API, or through a `<script>` tag.
### [Directives](../config/directives.md),
### [Directives](../config/directives.md)
Allows for the limited reconfiguration of a diagram just before it is rendered. It can alter the font style, color and other aesthetic aspects of the diagram. You can pass a directive alongside your definition inside `%%{ }%%`. It can be done either above or below your diagram definition.
### [Theme Manipulation](../config/theming.md):
### [Theme Manipulation](../config/theming.md)
An application of using Directives to change [Themes](../config/theming.md). `Theme` is a value within Mermaid's configuration that dictates the color scheme for diagrams.

View File

@@ -6,8 +6,8 @@
# Announcements
## [From Chaos to Clarity: Exploring Mind Maps with MermaidJS](https://www.mermaidchart.com/blog/posts/from-chaos-to-clarity-exploring-mind-maps-with-mermaidjs)
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
24 July 2023 · 4 mins
23 August 2023 · 15 mins
Introducing the concept of mind mapping as a tool for organizing complex information, and highlights Mermaid as a user-friendly software that simplifies the creation and editing of mind maps for applications in IT solution design, business decision-making, and knowledge organization.
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.

View File

@@ -6,6 +6,24 @@
# Blog
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
23 August 2023 · 15 mins
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation/)
14 August 2023 · 4 mins
Introducing Mermaid Charts new AI chatbot, a diagramming assistant that simplifies text-based diagram creation for everyone, from developers to educators, offering features to start, edit, and fix diagrams, and embodying our vision to make diagramming accessible, user-friendly, and fun.
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/uml-diagram-tool/)
14 August 2023 · 8 mins
A UML diagram tool helps developers and other professionals quickly create and share UML diagrams that communicate information about complex software systems.
## [From Chaos to Clarity: Exploring Mind Maps with MermaidJS](https://www.mermaidchart.com/blog/posts/from-chaos-to-clarity-exploring-mind-maps-with-mermaidjs)
24 July 2023 · 4 mins

View File

@@ -198,6 +198,34 @@ erDiagram
The `type` values must begin with an alphabetic character and may contain digits, hyphens, underscores, parentheses and square brackets. The `name` values follow a similar format to `type`, but may start with an asterisk as another option to indicate an attribute is a primary key. Other than that, there are no restrictions, and there is no implicit set of valid data types.
### Entity Name Aliases (v\<MERMAID_RELEASE_VERSION>+)
An alias can be added to an entity using square brackets. If provided, the alias will be showed in the diagram instead of the entity name.
```mermaid-example
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
```
```mermaid
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
```
#### Attribute Keys and Comments
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.

View File

@@ -1098,7 +1098,7 @@ The icons are accessed via the syntax fa:#icon class name#.
```mermaid-example
flowchart TD
B["fab:fa-twitter for peace"]
B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner)
B-->E(A fa:fa-camera-retro perhaps?)
@@ -1106,7 +1106,7 @@ flowchart TD
```mermaid
flowchart TD
B["fab:fa-twitter for peace"]
B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner)
B-->E(A fa:fa-camera-retro perhaps?)

View File

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

View File

@@ -1 +1 @@
../mermaid/src/docs/syntax/zenuml.md
../mermaid/src/docs/syntax/zenuml.md

View File

@@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "10.3.1",
"version": "10.4.0",
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"module": "./dist/mermaid.core.mjs",
@@ -117,7 +117,7 @@
"rimraf": "^5.0.0",
"start-server-and-test": "^2.0.0",
"type-fest": "^4.1.0",
"typedoc": "^0.24.5",
"typedoc": "^0.25.0",
"typedoc-plugin-markdown": "^3.15.2",
"typescript": "^5.0.4",
"unist-util-flatmap": "^1.0.0",

View File

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

View File

@@ -15,6 +15,7 @@ import {
setDiagramTitle,
getDiagramTitle,
} from '../../commonDb.js';
import { ClassMember } from './classTypes.js';
import type {
ClassRelation,
ClassNode,
@@ -115,11 +116,11 @@ export const clear = function () {
commonClear();
};
export const getClass = function (id: string) {
export const getClass = function (id: string): ClassNode {
return classes[id];
};
export const getClasses = function () {
export const getClasses = function (): ClassMap {
return classes;
};
@@ -187,9 +188,9 @@ export const addMember = function (className: string, member: string) {
theClass.annotations.push(sanitizeText(memberString.substring(2, memberString.length - 2)));
} else if (memberString.indexOf(')') > 0) {
//its a method
theClass.methods.push(sanitizeText(memberString));
theClass.methods.push(new ClassMember(memberString, 'method'));
} else if (memberString) {
theClass.members.push(sanitizeText(memberString));
theClass.members.push(new ClassMember(memberString, 'attribute'));
}
}
};
@@ -256,6 +257,7 @@ export const getTooltip = function (id: string, namespace?: string) {
return classes[id].tooltip;
};
/**
* Called by parser when a link is found. Adds the URL to the vertex data.
*

View File

@@ -4,6 +4,9 @@ import classDb from './classDb.js';
import { vi, describe, it, expect } from 'vitest';
const spyOn = vi.spyOn;
const staticCssStyle = 'text-decoration:underline;';
const abstractCssStyle = 'font-style:italic;';
describe('given a basic class diagram, ', function () {
describe('when parsing class definition', function () {
beforeEach(function () {
@@ -127,7 +130,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
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', () => {
@@ -142,7 +145,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
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[0]).toBe('interface');
});
@@ -168,7 +171,7 @@ describe('given a basic class diagram, ', function () {
const c1 = classDb.getClass('C1');
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');
});
@@ -371,6 +374,74 @@ class C13["With Città foreign language"]
note ${keyword}`;
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 () {
@@ -422,8 +493,8 @@ class C13["With Città foreign language"]
'classDiagram\n' +
'class Class1 {\n' +
'int testMember\n' +
'string fooMember\n' +
'test()\n' +
'string fooMember\n' +
'foo()\n' +
'}';
parser.parse(str);
@@ -431,10 +502,10 @@ class C13["With Città foreign language"]
const actual = parser.yy.getClass('Class1');
expect(actual.members.length).toBe(2);
expect(actual.methods.length).toBe(2);
expect(actual.members[0]).toBe('int testMember');
expect(actual.members[1]).toBe('string fooMember');
expect(actual.methods[0]).toBe('test()');
expect(actual.methods[1]).toBe('foo()');
expect(actual.members[0].getDisplayDetails().displayText).toBe('int testMember');
expect(actual.members[1].getDisplayDetails().displayText).toBe('string fooMember');
expect(actual.methods[0].getDisplayDetails().displayText).toBe('test()');
expect(actual.methods[1].getDisplayDetails().displayText).toBe('foo()');
});
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');
expect(c1.label).toBe('Class 1 with text label');
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', () => {
@@ -459,7 +530,7 @@ class C13["With Città foreign language"]
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
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[0]).toBe('interface');
});
@@ -762,10 +833,10 @@ describe('given a class diagram with members and methods ', function () {
const actual = parser.yy.getClass('actual');
expect(actual.members.length).toBe(4);
expect(actual.methods.length).toBe(0);
expect(actual.members[0]).toBe('-int privateMember');
expect(actual.members[1]).toBe('+int publicMember');
expect(actual.members[2]).toBe('#int protectedMember');
expect(actual.members[3]).toBe('~int privatePackage');
expect(actual.members[0].getDisplayDetails().displayText).toBe('-int privateMember');
expect(actual.members[1].getDisplayDetails().displayText).toBe('+int publicMember');
expect(actual.members[2].getDisplayDetails().displayText).toBe('#int protectedMember');
expect(actual.members[3].getDisplayDetails().displayText).toBe('~int privatePackage');
});
it('should handle generic types', function () {
@@ -818,7 +889,9 @@ describe('given a class diagram with members and methods ', function () {
expect(actual.annotations.length).toBe(0);
expect(actual.members.length).toBe(0);
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 () {
@@ -829,7 +902,9 @@ describe('given a class diagram with members and methods ', function () {
expect(actual.annotations.length).toBe(0);
expect(actual.members.length).toBe(0);
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 () {
@@ -955,53 +1030,6 @@ foo()
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 () {
@@ -1274,10 +1302,10 @@ describe('given a class diagram with relationships, ', function () {
const testClass = parser.yy.getClass('Class1');
expect(testClass.members.length).toBe(2);
expect(testClass.methods.length).toBe(2);
expect(testClass.members[0]).toBe('int : test');
expect(testClass.members[1]).toBe('string : foo');
expect(testClass.methods[0]).toBe('test()');
expect(testClass.methods[1]).toBe('foo()');
expect(testClass.members[0].getDisplayDetails().displayText).toBe('int : test');
expect(testClass.members[1].getDisplayDetails().displayText).toBe('string : foo');
expect(testClass.methods[0].getDisplayDetails().displayText).toBe('test()');
expect(testClass.methods[1].getDisplayDetails().displayText).toBe('foo()');
});
it('should handle abstract methods', function () {
@@ -1288,7 +1316,9 @@ describe('given a class diagram with relationships, ', function () {
expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0);
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 () {
@@ -1299,7 +1329,9 @@ describe('given a class diagram with relationships, ', function () {
expect(testClass.annotations.length).toBe(0);
expect(testClass.members.length).toBe(0);
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 () {
@@ -1514,11 +1546,19 @@ class Class2
const testClasses = parser.yy.getClasses();
const testRelations = parser.yy.getRelations();
expect(Object.keys(testNamespaceA.classes).length).toBe(2);
expect(testNamespaceA.classes['A1'].members[0]).toBe('+foo : string');
expect(testNamespaceA.classes['A2'].members[0]).toBe('+bar : int');
expect(testNamespaceA.classes['A1'].members[0].getDisplayDetails().displayText).toBe(
'+foo : string'
);
expect(testNamespaceA.classes['A2'].members[0].getDisplayDetails().displayText).toBe(
'+bar : int'
);
expect(Object.keys(testNamespaceB.classes).length).toBe(2);
expect(testNamespaceB.classes['B1'].members[0]).toBe('+foo : bool');
expect(testNamespaceB.classes['B2'].members[0]).toBe('+bar : float');
expect(testNamespaceB.classes['B1'].members[0].getDisplayDetails().displayText).toBe(
'+foo : bool'
);
expect(testNamespaceB.classes['B2'].members[0].getDisplayDetails().displayText).toBe(
'+bar : float'
);
expect(Object.keys(testClasses).length).toBe(4);
expect(testClasses['A1'].parent).toBe('A');
expect(testClasses['A2'].parent).toBe('A');
@@ -1570,8 +1610,8 @@ class Class2
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
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');
expect(c2.label).toBe('C2');
});
@@ -1587,9 +1627,10 @@ class Class2
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
expect(c1.members.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
expect(c1.annotations.length).toBe(1);
expect(c1.annotations[0]).toBe('interface');
const member = c1.members[0];
expect(member.getDisplayDetails().displayText).toBe('+member1');
const c2 = classDb.getClass('C2');
expect(c2.label).toBe('C2');
@@ -1606,8 +1647,9 @@ C1 --> C2
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
expect(c1.cssClasses.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
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', () => {
@@ -1622,8 +1664,9 @@ cssClass "C1" styleClass
const c1 = classDb.getClass('C1');
expect(c1.label).toBe('Class 1 with text label');
expect(c1.cssClasses.length).toBe(1);
expect(c1.members[0]).toBe('+member1');
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', () => {

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);
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
notes.forEach(function (note, i) {
const vertex = note;
/**
* Variable for storing the classes for the vertex
*
*/
const cssNoteStr = '';
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 radius = 0;
const shape = 'note';
// Add the node
const node = {
labelStyle: styles.labelStyle,
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 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 {
id: string;
type: string;
label: string;
cssClasses: string[];
methods: string[];
members: string[];
methods: ClassMember[];
members: ClassMember[];
annotations: string[];
domId: string;
parent?: string;
@@ -14,6 +17,120 @@ export interface ClassNode {
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 {
id: string;
class: string;

View File

@@ -224,21 +224,14 @@ start
| statements
;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
mermaidDoc
: graphConfig
;
graphConfig
: CLASS_DIAGRAM NEWLINE statements EOF
;
directive
: openDirective typeDirective closeDirective NEWLINE
| openDirective typeDirective ':' argDirective closeDirective NEWLINE
@@ -260,10 +253,6 @@ closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'class'); }
;
graphConfig
: CLASS_DIAGRAM NEWLINE statements EOF
;
statements
: statement
| statement NEWLINE
@@ -292,7 +281,7 @@ statement
| relationStatement LABEL { $1.title = yy.cleanupLabel($2); yy.addRelation($1); }
| namespaceStatement
| classStatement
| methodStatement
| memberStatement
| annotationStatement
| clickStatement
| cssClassStatement
@@ -339,7 +328,7 @@ members
| MEMBER members { $2.push($1);$$=$2;}
;
methodStatement
memberStatement
: className {/*console.log('Rel found',$1);*/}
| className LABEL {yy.addMember($1,yy.cleanupLabel($2));}
| MEMBER {/*console.warn('Member',$1);*/}
@@ -358,6 +347,17 @@ noteStatement
| 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
: relationType lineType relationType { $$={type1:$1,type2:$3,lineType:$2}; }
| lineType relationType { $$={type1:'none',type2:$2,lineType:$1}; }

View File

@@ -172,7 +172,6 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
// add class group
const g = elem.append('g').attr('id', diagObj.db.lookUpDomId(id)).attr('class', 'classGroup');
// add title
let title;
if (classDef.link) {
title = g
@@ -209,47 +208,56 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
}
const titleHeight = title.node().getBBox().height;
let membersLine;
let membersBox;
let methodsLine;
const membersLine = g
.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2);
// don't draw box if no members
if (classDef.members.length > 0) {
membersLine = g
.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2);
const members = g
.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + conf.dividerMargin + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
const members = g
.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + conf.dividerMargin + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
isFirst = true;
classDef.members.forEach(function (member) {
addTspan(members, member, isFirst, conf);
isFirst = false;
});
isFirst = true;
classDef.members.forEach(function (member) {
addTspan(members, member, isFirst, conf);
isFirst = false;
});
const membersBox = members.node().getBBox();
membersBox = members.node().getBBox();
}
const methodsLine = g
.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height);
// don't draw box if no methods
if (classDef.methods.length > 0) {
methodsLine = g
.append('line') // text label for the x axis
.attr('x1', 0)
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height)
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height);
const methods = g
.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
const methods = g
.append('text') // text label for the x axis
.attr('x', conf.padding)
.attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight)
.attr('fill', 'white')
.attr('class', 'classText');
isFirst = true;
isFirst = true;
classDef.methods.forEach(function (method) {
addTspan(methods, method, isFirst, conf);
isFirst = false;
});
classDef.methods.forEach(function (method) {
addTspan(methods, method, isFirst, conf);
isFirst = false;
});
}
const classBox = g.node().getBBox();
var cssClassStr = ' ';
@@ -278,8 +286,12 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
title.insert('title').text(classDef.tooltip);
}
membersLine.attr('x2', rectWidth);
methodsLine.attr('x2', rectWidth);
if (membersLine) {
membersLine.attr('x2', rectWidth);
}
if (methodsLine) {
methodsLine.attr('x2', rectWidth);
}
classInfo.width = rectWidth;
classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin;
@@ -291,7 +303,7 @@ export const getClassTitleString = function (classDef) {
let classTitleString = classDef.id;
if (classDef.type) {
classTitleString += '<' + classDef.type + '>';
classTitleString += '<' + parseGenericTypes(classDef.type) + '>';
}
return classTitleString;
@@ -360,82 +372,19 @@ export const drawNote = function (elem, note, conf, diagObj) {
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
*
* @param {SVGElement} textEl The element to append to
* @param {string} txt The member
* @param {string} member The member
* @param {boolean} isFirst
* @param {{ padding: string; textHeight: string }} conf The configuration for the member
*/
const addTspan = function (textEl, txt, isFirst, conf) {
let member = parseMember(txt);
const addTspan = function (textEl, member, isFirst, conf) {
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 (member.cssStyle !== '') {
if (cssStyle !== '') {
tSpan.attr('style', member.cssStyle);
}
@@ -444,27 +393,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 {
getClassTitleString,
drawClass,
drawEdge,
drawNote,
parseMember,
};

View File

@@ -1,330 +1,27 @@
import svgDraw from './svgDraw.js';
import { JSDOM } from 'jsdom';
describe('given a string representing class method, ', function () {
it('should handle class names with generics', function () {
const classDef = {
id: 'Car',
type: 'T',
label: 'Car',
};
describe('given a string representing a class, ', function () {
describe('when class name includes generic, ', function () {
it('should return correct text for generic', function () {
const classDef = {
id: 'Car',
type: 'T',
label: 'Car',
};
let actual = svgDraw.getClassTitleString(classDef);
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('');
let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T>');
});
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 () {
const str = 'foo(int id)';
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('');
let actual = svgDraw.getClassTitleString(classDef);
expect(actual).toBe('Car<T<T>>');
});
});
});

View File

@@ -1,4 +1,4 @@
import { sanitizeText, removeScript, parseGenericTypes } from './common.js';
import { sanitizeText, removeScript, parseGenericTypes, countOccurrence } from './common.js';
describe('when securityLevel is antiscript, all script must be removed', () => {
/**
@@ -59,16 +59,29 @@ describe('Sanitize text', () => {
});
describe('generic parser', () => {
it('should parse generic types', () => {
expect(parseGenericTypes('test~T~')).toEqual('test<T>');
expect(parseGenericTypes('test~Array~Array~string~~~')).toEqual('test<Array<Array<string>>>');
expect(parseGenericTypes('test~Array~Array~string[]~~~')).toEqual(
'test<Array<Array<string[]>>>'
);
expect(parseGenericTypes('test ~Array~Array~string[]~~~')).toEqual(
'test <Array<Array<string[]>>>'
);
expect(parseGenericTypes('~test')).toEqual('~test');
expect(parseGenericTypes('~test Array~string~')).toEqual('~test Array<string>');
it.each([
['test~T~', 'test<T>'],
['test~Array~Array~string~~~', 'test<Array<Array<string>>>'],
['test~Array~Array~string[]~~~', 'test<Array<Array<string[]>>>'],
['test ~Array~Array~string[]~~~', 'test <Array<Array<string[]>>>'],
['~test', '~test'],
['~test~T~', '~test<T>'],
])('should parse generic types: %s to %s', (input: string, expected: string) => {
expect(parseGenericTypes(input)).toEqual(expected);
});
});
it.each([
['', '', 0],
['', 'x', 0],
['test', 'x', 0],
['test', 't', 2],
['test', 'te', 1],
['test~T~', '~', 2],
['test~Array~Array~string~~~', '~', 6],
])(
'should count `%s` to contain occurrences of `%s` to be `%i`',
(str: string, substring: string, count: number) => {
expect(countOccurrence(str, substring)).toEqual(count);
}
);

View File

@@ -178,23 +178,80 @@ export const getMin = function (...values: number[]): number {
* @param text - The text to convert
* @returns The converted string
*/
export const parseGenericTypes = function (text: string): string {
let cleanedText = text;
export const parseGenericTypes = function (input: string): string {
const inputSets = input.split(/(,)/);
const output = [];
if (text.split('~').length - 1 >= 2) {
let newCleanedText = cleanedText;
for (let i = 0; i < inputSets.length; i++) {
let thisSet = inputSets[i];
// use a do...while loop instead of replaceAll to detect recursion
// e.g. Array~Array~T~~
do {
cleanedText = newCleanedText;
newCleanedText = cleanedText.replace(/~([^\s,:;]+)~/, '<$1>');
} while (newCleanedText != cleanedText);
// if the original input included a value such as "~K, V~"", these will be split into
// an array of ["~K",","," V~"].
// This means that on each call of processSet, there will only be 1 ~ present
// To account for this, if we encounter a ",", we are checking the previous and next sets in the array
// to see if they contain matching ~'s
// 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);
} else {
return cleanedText;
if (shouldCombineSets(previousSet, nextSet)) {
thisSet = previousSet + ',' + nextSet;
i++; // Move the index forward to skip the next iteration since we're combining sets
output.pop();
}
}
output.push(processSet(thisSet));
}
return output.join('');
};
export const countOccurrence = (string: string, substring: string): number => {
return Math.max(0, string.split(substring).length - 1);
};
const shouldCombineSets = (previousSet: string, nextSet: string): boolean => {
const prevCount = countOccurrence(previousSet, '~');
const nextCount = countOccurrence(nextSet, '~');
return prevCount === 1 && nextCount === 1;
};
const processSet = (input: string): string => {
const tildeCount = countOccurrence(input, '~');
let hasStartingTilde = false;
if (tildeCount <= 1) {
return input;
}
// If there is an odd number of tildes, and the input starts with a tilde, we need to remove it and add it back in later
if (tildeCount % 2 !== 0 && input.startsWith('~')) {
input = input.substring(1);
hasStartingTilde = true;
}
const chars = [...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('~');
}
// Add the starting tilde back in if we removed it
if (hasStartingTilde) {
chars.unshift('~');
}
return chars.join('');
};
export default {

View File

@@ -32,10 +32,13 @@ export const parseDirective = function (statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
const addEntity = function (name) {
const addEntity = function (name, alias = undefined) {
if (entities[name] === undefined) {
entities[name] = { attributes: [] };
entities[name] = { attributes: [], alias: alias };
log.info('Added new entity :', name);
} else if (entities[name] && !entities[name].alias && alias) {
entities[name].alias = alias;
log.info(`Add alias '${alias}' to entity '${name}'`);
}
return entities[name];

View File

@@ -326,7 +326,7 @@ const drawEntities = function (svgNode, entities, graph) {
.style('text-anchor', 'middle')
.style('font-family', getConfig().fontFamily)
.style('font-size', conf.fontSize + 'px')
.text(entityName);
.text(entities[entityName].alias ?? entityName);
const { width: entityWidth, height: entityHeight } = drawAttributes(
groupNode,

View File

@@ -35,6 +35,8 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
<block>[\n]+ /* nothing */
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
<block>. return yytext[0];
"[" return 'SQS';
"]" return 'SQE';
"one or zero" return 'ZERO_OR_ONE';
"one or more" return 'ONE_OR_MORE';
@@ -102,17 +104,21 @@ statement
yy.addEntity($1);
yy.addEntity($3);
yy.addRelationship($1, $5, $3, $2);
/*console.log($1 + $2 + $3 + ':' + $5);*/
}
| entityName BLOCK_START attributes BLOCK_STOP
{
/* console.log('detected block'); */
yy.addEntity($1);
yy.addAttributes($1, $3);
/* console.log('handled block'); */
}
| entityName BLOCK_START BLOCK_STOP { yy.addEntity($1); }
| entityName { yy.addEntity($1); }
| entityName SQS entityName SQE BLOCK_START attributes BLOCK_STOP
{
yy.addEntity($1, $3);
yy.addAttributes($1, $6);
}
| entityName SQS entityName SQE BLOCK_START BLOCK_STOP { yy.addEntity($1, $3); }
| entityName SQS entityName SQE { yy.addEntity($1, $3); }
| title title_value { $$=$2.trim();yy.setAccTitle($$); }
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }

View File

@@ -133,6 +133,43 @@ describe('when parsing ER diagram it...', function () {
const entities = erDb.getEntities();
expect(entities.hasOwnProperty(hyphensUnderscore)).toBe(true);
});
it('can have an alias', function () {
const entity = 'foo';
const alias = 'bar';
erDiagram.parser.parse(`erDiagram\n${entity}["${alias}"]\n`);
const entities = erDb.getEntities();
expect(entities.hasOwnProperty(entity)).toBe(true);
expect(entities[entity].alias).toBe(alias);
});
it('can have an alias even if the relationship is defined before class', function () {
const firstEntity = 'foo';
const secondEntity = 'bar';
const alias = 'batman';
erDiagram.parser.parse(
`erDiagram\n${firstEntity} ||--o| ${secondEntity} : rel\nclass ${firstEntity}["${alias}"]\n`
);
const entities = erDb.getEntities();
expect(entities.hasOwnProperty(firstEntity)).toBe(true);
expect(entities.hasOwnProperty(secondEntity)).toBe(true);
expect(entities[firstEntity].alias).toBe(alias);
expect(entities[secondEntity].alias).toBeUndefined();
});
it('can have an alias even if the relationship is defined after class', function () {
const firstEntity = 'foo';
const secondEntity = 'bar';
const alias = 'batman';
erDiagram.parser.parse(
`erDiagram\nclass ${firstEntity}["${alias}"]\n${firstEntity} ||--o| ${secondEntity} : rel\n`
);
const entities = erDb.getEntities();
expect(entities.hasOwnProperty(firstEntity)).toBe(true);
expect(entities.hasOwnProperty(secondEntity)).toBe(true);
expect(entities[firstEntity].alias).toBe(alias);
expect(entities[secondEntity].alias).toBeUndefined();
});
});
describe('attribute name', () => {

View File

@@ -12,14 +12,16 @@ import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
const createPieArcs = (sections: Sections): d3.PieArcDatum<D3Sections>[] => {
// Compute the position of each group on the pie:
const pieData: D3Sections[] = Object.entries(sections).map(
(element: [string, number]): D3Sections => {
const pieData: D3Sections[] = Object.entries(sections)
.map((element: [string, number]): D3Sections => {
return {
label: element[0],
value: element[1],
};
}
);
})
.sort((a: D3Sections, b: D3Sections): number => {
return b.value - a.value;
});
const pie: d3.Pie<unknown, D3Sections> = d3pie<D3Sections>().value(
(d3Section: D3Sections): number => d3Section.value
);

View File

@@ -109,8 +109,8 @@ function sidebarAll() {
collapsed: false,
items: [
{ text: 'About Mermaid', link: '/intro/' },
{ text: 'Getting Started', link: '/intro/n00b-gettingStarted' },
{ text: 'Syntax and Configuration', link: '/intro/n00b-syntaxReference' },
{ text: 'Getting Started', link: '/intro/getting-started' },
{ text: 'Syntax and Configuration', link: '/intro/syntax-reference' },
],
},
...sidebarSyntax(),
@@ -167,7 +167,7 @@ function sidebarConfig() {
{ text: 'Theming', link: '/config/theming' },
{ text: 'Accessibility', link: '/config/accessibility' },
{ text: 'Mermaid CLI', link: '/config/mermaidCLI' },
{ text: 'Advanced usage', link: '/config/n00b-advanced' },
{ text: 'Advanced usage', link: '/config/advanced' },
{ text: 'FAQ', link: '/config/faq' },
],
},

View File

@@ -19,8 +19,17 @@ test.each([
'https://mermaid-js.github.io/mermaid/#/flowchart?another=test&id=my-id&one=more', // with multiple params
'syntax/flowchart.html#my-id',
],
['https://mermaid-js.github.io/mermaid/#/n00b-advanced', 'config/n00b-advanced.html'], // without .md
['https://mermaid-js.github.io/mermaid/#/n00b-advanced.md', 'config/n00b-advanced.html'], // with .md
['https://mermaid-js.github.io/mermaid/#/n00b-advanced', 'config/advanced.html'], // without .md
['https://mermaid-js.github.io/mermaid/#/n00b-advanced.md', 'config/advanced.html'], // with .md
['https://mermaid-js.github.io/mermaid/#/n00b-gettingstarted', 'intro/getting-started.html'],
['https://mermaid-js.github.io/mermaid/#/n00b-gettingstarted.md', 'intro/getting-started.html'],
['https://mermaid-js.github.io/mermaid/#/n00b-overview', 'intro/getting-started.html'],
['https://mermaid-js.github.io/mermaid/#/n00b-overview.md', 'intro/getting-started.html'],
['https://mermaid-js.github.io/mermaid/#/n00b-syntaxreference', 'intro/syntax-reference.html'],
['https://mermaid-js.github.io/mermaid/#/n00b-syntaxreference.md', 'intro/syntax-reference.html'],
['https://mermaid-js.github.io/mermaid/#/quickstart', 'intro/getting-started.html'],
['https://mermaid-js.github.io/mermaid/#/quickstart.md', 'intro/getting-started.html'],
[
'https://mermaid-js.github.io/mermaid/#/flowchart?id=a-node-in-the-form-of-a-circle', // with id, without .md
'syntax/flowchart.html#a-node-in-the-form-of-a-circle',

View File

@@ -25,9 +25,13 @@ const getBaseFile = (url: URL): Redirect => {
};
/**
* Used to redirect old documentation pages to corresponding new pages.
* Used to redirect old (pre-vitepress) documentation pages to corresponding new pages.
* The key is the old documentation ID, and the value is the new documentation path.
* No key should be added here as it already has all the old documentation IDs.
* If you are changing a documentation page, you should update the corresponding value here, and add an entry in the urlRedirectMap below.
*/
const idRedirectMap: Record<string, string> = {
// ID of the old documentation page: Path of the new documentation page
'8.6.0_docs': '',
accessibility: 'config/theming',
breakingchanges: '',
@@ -50,15 +54,14 @@ const idRedirectMap: Record<string, string> = {
mermaidcli: 'config/mermaidCLI',
mindmap: 'syntax/mindmap',
'more-pages': '',
'n00b-advanced': 'config/n00b-advanced',
'n00b-gettingstarted': 'intro/n00b-gettingStarted',
'n00b-overview': 'intro/n00b-gettingStarted',
'community/n00b-overview': 'intro/n00b-gettingStarted',
'n00b-syntaxreference': 'intro/n00b-syntaxReference',
'n00b-advanced': 'config/advanced',
'n00b-gettingstarted': 'intro/getting-started',
'n00b-overview': 'intro/getting-started',
'n00b-syntaxreference': 'intro/syntax-reference',
newdiagram: 'community/newDiagram',
pie: 'syntax/pie',
plugins: '',
quickstart: 'intro/n00b-gettingStarted',
quickstart: 'intro/getting-started',
requirementdiagram: 'syntax/requirementDiagram',
security: 'community/security',
sequencediagram: 'syntax/sequenceDiagram',
@@ -74,10 +77,19 @@ const idRedirectMap: Record<string, string> = {
/**
* Used to redirect pages that have been moved in the vitepress site.
* No keys should be deleted from here.
* If you are changing a documentation page, you should update the corresponding value here,
* and update the entry in the idRedirectMap above if it was present
* (No need to add new keys in idRedirectMap).
*/
const urlRedirectMap: Record<string, string> = {
// Old URL: New URL
'/misc/faq.html': 'configure/faq.html',
'/syntax/c4c.html': 'syntax/c4.html',
'/config/n00b-advanced.html': 'config/advanced',
'/intro/n00b-gettingStarted.html': 'intro/getting-started',
'/intro/n00b-syntaxReference.html': 'intro/syntax-reference',
'/community/n00b-overview.html': 'intro/getting-started',
};
/**

View File

@@ -26,7 +26,7 @@ The definitions that can be generated the Live-Editor are also backwards-compati
## Mermaid with HTML
Examples are provided in [Getting Started](../intro/n00b-gettingStarted.md)
Examples are provided in [Getting Started](../intro/getting-started.md)
**CodePen Examples:**

View File

@@ -1,4 +1,4 @@
# Advanced n00b mermaid (Coming soon..)
# Advanced mermaid (Coming soon..)
## splitting mermaid code from html

View File

@@ -35,7 +35,7 @@ pnpm add mermaid
**Hosting mermaid on a web page:**
> Note:This topic explored in greater depth in the [User Guide for Beginners](../intro/n00b-gettingStarted.md)
> Note:This topic 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:

View File

@@ -2,7 +2,7 @@
Mermaid is composed of three parts: Deployment, Syntax and Configuration.
This section talks about the different ways to deploy Mermaid. Learning the [Syntax](n00b-syntaxReference.md) would be of great help to the beginner.
This section talks about the different ways to deploy Mermaid. Learning the [Syntax](syntax-reference.md) would be of great help to the beginner.
> Generally the live editor is enough for most general uses of mermaid, and is a good place to start learning.
@@ -36,7 +36,7 @@ graph TD
In the `Code` section one can write or edit raw mermaid code, and instantly `Preview` the rendered result on the panel beside it.
The `Configuration` Section is for changing the appearance and behavior of mermaid diagrams. An easy introduction to mermaid configuration is found in the [Advanced usage](../config/n00b-advanced.md) section. A complete configuration reference cataloging the default values can be found on the [mermaidAPI](../config/setup/README.md) page.
The `Configuration` Section is for changing the appearance and behavior of mermaid diagrams. An easy introduction to mermaid configuration is found in the [Advanced usage](../config/advanced.md) section. A complete configuration reference cataloging the default values can be found on the [mermaidAPI](../config/setup/README.md) page.
![Code,Config and Preview](./img/Code-Preview-Config.png)

View File

@@ -4,7 +4,7 @@
It is a JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.
> If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](n00b-syntaxReference.md).
> If you are familiar with Markdown you should have no problem learning [Mermaid's Syntax](syntax-reference.md).
<img src="/header.png" alt="" />
@@ -39,7 +39,7 @@ Mermaid allows even non-programmers to easily create detailed and diagrams throu
[Tutorials](../config/Tutorials.md) has video tutorials.
Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](../ecosystem/integrations.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/n00b-gettingStarted.md) and [Usage](../config/usage.md).
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](../intro/getting-started.md) and [Usage](../config/usage.md).
🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](../community/development.md) | 🔌 [Plug-Ins](../ecosystem/integrations.md)
@@ -59,9 +59,9 @@ In our release process we rely heavily on visual regression tests using [applito
## Installation
**In depth guides and examples can be found at [Getting Started](./n00b-gettingStarted.md) and [Usage](../config/usage.md).**
**In depth guides and examples can be found at [Getting Started](./getting-started.md) and [Usage](../config/usage.md).**
**It would also be helpful to learn more about mermaid's [Syntax](./n00b-syntaxReference.md).**
**It would also be helpful to learn more about mermaid's [Syntax](./syntax-reference.md).**
### CDN
@@ -179,7 +179,7 @@ Update version number in `package.json`.
npm publish
```
The above command generates files into the `dist` folder and publishes them to [npmjs.org](npmjs.org).
The above command generates files into the `dist` folder and publishes them to [npmjs.com](https://www.npmjs.com/).
## Security and safe diagrams

View File

@@ -24,7 +24,7 @@ erDiagram
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
```
The [Getting Started](./n00b-gettingStarted.md) section can also provide some practical examples of mermaid syntax.
The [Getting Started](./getting-started.md) section can also provide some practical examples of mermaid syntax.
## Diagram Breaking
@@ -48,20 +48,20 @@ Configuration is the third part of Mermaid, after deployment and syntax. It deal
If you are interested in altering and customizing your Mermaid Diagrams, you will find the methods and values available for [Configuration](../config/setup/README.md) here. It includes themes.
This section will introduce the different methods of configuring the behaviors and appearances of Mermaid Diagrams.
The following are the most commonly used methods, and they are all tied to Mermaid [Deployment](./n00b-gettingStarted.md) methods.
The following are the most commonly used methods, and they are all tied to Mermaid [Deployment](./getting-started.md) methods.
### Configuration Section in the [Live Editor](https://mermaid.live).
Here you can edit certain values to change the behavior and appearance of the diagram.
### [The initialize() call](https://mermaid-js.github.io/mermaid/#/n00b-gettingStarted?id=_3-calling-the-javascript-api),
### [The initialize() call](./getting-started.md#_3-calling-the-javascript-api)
Used when Mermaid is called via an API, or through a `<script>` tag.
### [Directives](../config/directives.md),
### [Directives](../config/directives.md)
Allows for the limited reconfiguration of a diagram just before it is rendered. It can alter the font style, color and other aesthetic aspects of the diagram. You can pass a directive alongside your definition inside `%%{ }%%`. It can be done either above or below your diagram definition.
### [Theme Manipulation](../config/theming.md):
### [Theme Manipulation](../config/theming.md)
An application of using Directives to change [Themes](../config/theming.md). `Theme` is a value within Mermaid's configuration that dictates the color scheme for diagrams.

View File

@@ -1,7 +1,7 @@
# Announcements
## [From Chaos to Clarity: Exploring Mind Maps with MermaidJS](https://www.mermaidchart.com/blog/posts/from-chaos-to-clarity-exploring-mind-maps-with-mermaidjs)
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
24 July 2023 · 4 mins
23 August 2023 · 15 mins
Introducing the concept of mind mapping as a tool for organizing complex information, and highlights Mermaid as a user-friendly software that simplifies the creation and editing of mind maps for applications in IT solution design, business decision-making, and knowledge organization.
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.

View File

@@ -1,5 +1,23 @@
# Blog
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
23 August 2023 · 15 mins
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation/)
14 August 2023 · 4 mins
Introducing Mermaid Charts new AI chatbot, a diagramming assistant that simplifies text-based diagram creation for everyone, from developers to educators, offering features to start, edit, and fix diagrams, and embodying our vision to make diagramming accessible, user-friendly, and fun.
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/uml-diagram-tool/)
14 August 2023 · 8 mins
A UML diagram tool helps developers and other professionals quickly create and share UML diagrams that communicate information about complex software systems.
## [From Chaos to Clarity: Exploring Mind Maps with MermaidJS](https://www.mermaidchart.com/blog/posts/from-chaos-to-clarity-exploring-mind-maps-with-mermaidjs)
24 July 2023 · 4 mins

View File

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

View File

@@ -144,6 +144,22 @@ erDiagram
The `type` values must begin with an alphabetic character and may contain digits, hyphens, underscores, parentheses and square brackets. The `name` values follow a similar format to `type`, but may start with an asterisk as another option to indicate an attribute is a primary key. Other than that, there are no restrictions, and there is no implicit set of valid data types.
### Entity Name Aliases (v<MERMAID_RELEASE_VERSION>+)
An alias can be added to an entity using square brackets. If provided, the alias will be showed in the diagram instead of the entity name.
```mermaid-example
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
```
#### Attribute Keys and Comments
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.

View File

@@ -751,7 +751,7 @@ The icons are accessed via the syntax fa:#icon class name#.
```mermaid-example
flowchart TD
B["fab:fa-twitter for peace"]
B["fa:fa-twitter for peace"]
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner)
B-->E(A fa:fa-camera-retro perhaps?)

307
pnpm-lock.yaml generated
View File

@@ -358,11 +358,11 @@ importers:
specifier: ^4.1.0
version: 4.1.0
typedoc:
specifier: ^0.24.5
version: 0.24.5(typescript@5.0.4)
specifier: ^0.25.0
version: 0.25.0(typescript@5.0.4)
typedoc-plugin-markdown:
specifier: ^3.15.2
version: 3.15.2(typedoc@0.24.5)
version: 3.15.2(typedoc@0.25.0)
typescript:
specifier: ^5.0.4
version: 5.0.4
@@ -475,63 +475,8 @@ importers:
specifier: ^0.16.0
version: 0.16.0(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0)
vitepress:
specifier: 1.0.0-rc.4
version: 1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0)
workbox-window:
specifier: ^7.0.0
version: 7.0.0
packages/mermaid/src/vitepress:
dependencies:
'@vueuse/core':
specifier: ^10.1.0
version: 10.1.0(vue@3.3.4)
jiti:
specifier: ^1.18.2
version: 1.18.2
mermaid:
specifier: workspace:^
version: link:../..
vue:
specifier: ^3.3
version: 3.3.4
devDependencies:
'@iconify-json/carbon':
specifier: ^1.1.16
version: 1.1.16
'@unocss/reset':
specifier: ^0.55.2
version: 0.55.2
'@vite-pwa/vitepress':
specifier: ^0.2.0
version: 0.2.0(vite-plugin-pwa@0.16.0)
'@vitejs/plugin-vue':
specifier: ^4.2.1
version: 4.2.1(vite@4.3.9)(vue@3.3.4)
fast-glob:
specifier: ^3.2.12
version: 3.2.12
https-localhost:
specifier: ^4.7.1
version: 4.7.1
pathe:
specifier: ^1.1.0
version: 1.1.0
unocss:
specifier: ^0.55.2
version: 0.55.2(postcss@8.4.27)(rollup@2.79.1)(vite@4.3.9)
unplugin-vue-components:
specifier: ^0.25.0
version: 0.25.0(rollup@2.79.1)(vue@3.3.4)
vite:
specifier: ^4.3.9
version: 4.3.9(@types/node@18.16.0)
vite-plugin-pwa:
specifier: ^0.16.0
version: 0.16.0(vite@4.3.9)(workbox-build@7.0.0)(workbox-window@7.0.0)
vitepress:
specifier: 1.0.0-rc.4
version: 1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0)
specifier: 1.0.0-rc.8
version: 1.0.0-rc.8(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0)
workbox-window:
specifier: ^7.0.0
version: 7.0.0
@@ -600,23 +545,23 @@ packages:
'@algolia/autocomplete-shared': 1.8.2
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.14.2)(algoliasearch@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==}
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-shared': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)
'@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.19.1)(search-insights@2.6.0)
'@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.19.1)
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
- search-insights
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.14.2)(algoliasearch@4.19.1)(search-insights@2.6.0):
resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==}
peerDependencies:
search-insights: '>= 1 < 3'
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.14.2)(algoliasearch@4.19.1)
search-insights: 2.6.0
transitivePeerDependencies:
- '@algolia/client-search'
@@ -634,29 +579,29 @@ packages:
algoliasearch: 4.14.2
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.14.2)(algoliasearch@4.19.1):
resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==}
peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6'
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.14.2)(algoliasearch@4.19.1)
'@algolia/client-search': 4.14.2
algoliasearch: 4.14.2
algoliasearch: 4.19.1
dev: true
/@algolia/autocomplete-shared@1.8.2:
resolution: {integrity: sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==}
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.14.2)(algoliasearch@4.19.1):
resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==}
peerDependencies:
'@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6'
dependencies:
'@algolia/client-search': 4.14.2
algoliasearch: 4.14.2
algoliasearch: 4.19.1
dev: true
/@algolia/cache-browser-local-storage@4.14.2:
@@ -665,16 +610,32 @@ packages:
'@algolia/cache-common': 4.14.2
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:
resolution: {integrity: sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==}
dev: true
/@algolia/cache-common@4.19.1:
resolution: {integrity: sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg==}
dev: true
/@algolia/cache-in-memory@4.14.2:
resolution: {integrity: sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==}
dependencies:
'@algolia/cache-common': 4.14.2
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:
resolution: {integrity: sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==}
dependencies:
@@ -683,6 +644,14 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==}
dependencies:
@@ -692,6 +661,15 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==}
dependencies:
@@ -699,6 +677,13 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==}
dependencies:
@@ -707,6 +692,14 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==}
dependencies:
@@ -715,32 +708,66 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==}
dev: true
/@algolia/logger-common@4.19.1:
resolution: {integrity: sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw==}
dev: true
/@algolia/logger-console@4.14.2:
resolution: {integrity: sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==}
dependencies:
'@algolia/logger-common': 4.14.2
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:
resolution: {integrity: sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==}
dependencies:
'@algolia/requester-common': 4.14.2
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:
resolution: {integrity: sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==}
dev: true
/@algolia/requester-common@4.19.1:
resolution: {integrity: sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ==}
dev: true
/@algolia/requester-node-http@4.14.2:
resolution: {integrity: sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==}
dependencies:
'@algolia/requester-common': 4.14.2
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:
resolution: {integrity: sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==}
dependencies:
@@ -749,6 +776,14 @@ packages:
'@algolia/requester-common': 4.14.2
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:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -2882,8 +2917,8 @@ packages:
resolution: {integrity: sha512-NaXVp3I8LdmJ54fn038KHgG7HmbIzZlKS2FkVf6mKcW5bYMJovkx4947joQyZk5yubxOZ+ddHSh79y39Aevufg==}
dev: true
/@docsearch/css@3.5.1:
resolution: {integrity: sha512-2Pu9HDg/uP/IT10rbQ+4OrTQuxIWdKVUEdcw9/w7kZJv9NeHS6skJx1xuRiFyoGKwAzcHXnLp7csE99sj+O1YA==}
/@docsearch/css@3.5.2:
resolution: {integrity: sha512-SPiDHaWKQZpwR2siD0KQUwlStvIAnEyK6tAE2h2Wuoq8ue9skzhlyVQ1ddzOxX6khULnAALDiR/isSF3bnuciA==}
dev: true
/@docsearch/js@3.3.5(@algolia/client-search@4.14.2):
@@ -2898,10 +2933,10 @@ packages:
- react-dom
dev: true
/@docsearch/js@3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0):
resolution: {integrity: sha512-EXi8de5njxgP6TV3N9ytnGRLG9zmBNTEZjR4VzwPcpPLbZxxTLG2gaFyJyKiFVQxHW/DPlMrDJA3qoRRGEkgZw==}
/@docsearch/js@3.5.2(@algolia/client-search@4.14.2)(search-insights@2.6.0):
resolution: {integrity: sha512-p1YFTCDflk8ieHgFJYfmyHBki1D61+U9idwrLh+GQQMrBSP3DLGKpy0XUJtPjAOPltcVbqsTjiPFfH7JImjUNg==}
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.14.2)(search-insights@2.6.0)
preact: 10.11.0
transitivePeerDependencies:
- '@algolia/client-search'
@@ -2933,12 +2968,13 @@ packages:
- '@algolia/client-search'
dev: true
/@docsearch/react@3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0):
resolution: {integrity: sha512-t5mEODdLzZq4PTFAm/dvqcvZFdPDMdfPE5rJS5SC8OUq9mPzxEy6b+9THIqNM9P0ocCb4UC5jqBrxKclnuIbzQ==}
/@docsearch/react@3.5.2(@algolia/client-search@4.14.2)(search-insights@2.6.0):
resolution: {integrity: sha512-9Ahcrs5z2jq/DcAvYtvlqEBHImbm4YJI8M9y0x6Tqg598P40HTEkX7hsMcIuThI+hTFxRGZ9hll0Wygm2yEjng==}
peerDependencies:
'@types/react': '>= 16.8.0 < 19.0.0'
react: '>= 16.8.0 < 19.0.0'
react-dom: '>= 16.8.0 < 19.0.0'
search-insights: '>= 1 < 3'
peerDependenciesMeta:
'@types/react':
optional: true
@@ -2946,14 +2982,16 @@ packages:
optional: true
react-dom:
optional: true
search-insights:
optional: true
dependencies:
'@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)(search-insights@2.6.0)
'@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.14.2)
'@docsearch/css': 3.5.1
algoliasearch: 4.14.2
'@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.19.1)(search-insights@2.6.0)
'@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.14.2)(algoliasearch@4.19.1)
'@docsearch/css': 3.5.2
algoliasearch: 4.19.1
search-insights: 2.6.0
transitivePeerDependencies:
- '@algolia/client-search'
- search-insights
dev: true
/@es-joy/jsdoccomment@0.39.4:
@@ -4050,7 +4088,7 @@ packages:
tslib:
optional: true
dependencies:
'@rollup/pluginutils': 5.0.2(rollup@2.79.1)
'@rollup/pluginutils': 5.0.2
resolve: 1.22.2
typescript: 5.1.3
dev: true
@@ -4067,7 +4105,7 @@ packages:
rollup: 2.79.1
dev: true
/@rollup/pluginutils@5.0.2(rollup@2.79.1):
/@rollup/pluginutils@5.0.2:
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@@ -4079,7 +4117,6 @@ packages:
'@types/estree': 1.0.0
estree-walker: 2.0.2
picomatch: 2.3.1
rollup: 2.79.1
dev: true
/@rollup/pluginutils@5.0.3(rollup@2.79.1):
@@ -5434,8 +5471,20 @@ packages:
- vue
dev: true
/@vueuse/integrations@10.3.0(focus-trap@7.5.2)(vue@3.3.4):
resolution: {integrity: sha512-Jgiv7oFyIgC6BxmDtiyG/fxyGysIds00YaY7sefwbhCZ2/tjEx1W/1WcsISSJPNI30in28+HC2J4uuU8184ekg==}
/@vueuse/core@10.4.1(vue@3.3.4):
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:
async-validator: '*'
axios: '*'
@@ -5475,8 +5524,8 @@ packages:
universal-cookie:
optional: true
dependencies:
'@vueuse/core': 10.3.0(vue@3.3.4)
'@vueuse/shared': 10.3.0(vue@3.3.4)
'@vueuse/core': 10.4.1(vue@3.3.4)
'@vueuse/shared': 10.4.1(vue@3.3.4)
focus-trap: 7.5.2
vue-demi: 0.14.5(vue@3.3.4)
transitivePeerDependencies:
@@ -5492,6 +5541,10 @@ packages:
resolution: {integrity: sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==}
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):
resolution: {integrity: sha512-2X52ogu12i9DkKOQ01yeb/BKg9UO87RNnpm5sXkQvyORlbq8ONS5l39MYkjkeVWWjdT0teJru7a2S41dmHmqjQ==}
dependencies:
@@ -5510,6 +5563,15 @@ packages:
- vue
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):
resolution: {integrity: sha512-/38rol9WCfFTMtXyd/C856/aexxIZnfVvXg7Fw2WXpqZ9qadLA+R4N35S2703n/RByjK/5XAYtHoljtvh3727w==}
engines: {node: '>=12.0.0'}
@@ -5912,6 +5974,25 @@ packages:
'@algolia/transporter': 4.14.2
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:
resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==}
engines: {node: '>=0.4.2'}
@@ -9406,7 +9487,7 @@ packages:
dependencies:
foreground-child: 3.1.1
jackspeak: 2.1.1
minimatch: 9.0.0
minimatch: 9.0.1
minipass: 5.0.0
path-scurry: 1.7.0
dev: true
@@ -12030,15 +12111,15 @@ packages:
brace-expansion: 2.0.1
dev: true
/minimatch@9.0.0:
resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==}
/minimatch@9.0.1:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimatch@9.0.1:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
/minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
@@ -14820,35 +14901,35 @@ packages:
is-typedarray: 1.0.0
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==}
peerDependencies:
typedoc: '>=0.24.0'
dependencies:
handlebars: 4.7.7
typedoc: 0.24.5(typescript@5.0.4)
typedoc-plugin-mdn-links: 3.0.3(typedoc@0.24.5)
typedoc: 0.25.0(typescript@5.0.4)
typedoc-plugin-mdn-links: 3.0.3(typedoc@0.25.0)
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==}
peerDependencies:
typedoc: '>= 0.23.14 || 0.24.x'
dependencies:
typedoc: 0.24.5(typescript@5.0.4)
typedoc: 0.25.0(typescript@5.0.4)
dev: true
/typedoc@0.24.5(typescript@5.0.4):
resolution: {integrity: sha512-tE1YDRxOTwJ33HltVazKiADqy/CasUmd2UVMnGOS2kX5Oj7q4rDVsIlcC0j03K1h3lEkGtvEyusBF7Psz4F4kA==}
engines: {node: '>= 14.14'}
/typedoc@0.25.0(typescript@5.0.4):
resolution: {integrity: sha512-FvCYWhO1n5jACE0C32qg6b3dSfQ8f2VzExnnRboowHtqUD6ARzM2r8YJeZFYXhcm2hI4C2oCRDgNPk/yaQUN9g==}
engines: {node: '>= 16'}
hasBin: true
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:
lunr: 2.3.9
marked: 4.3.0
minimatch: 9.0.0
shiki: 0.14.1
minimatch: 9.0.3
shiki: 0.14.3
typescript: 5.0.4
dev: true
@@ -15055,7 +15136,7 @@ packages:
optional: true
dependencies:
'@antfu/utils': 0.7.5
'@rollup/pluginutils': 5.0.2(rollup@2.79.1)
'@rollup/pluginutils': 5.0.3(rollup@2.79.1)
chokidar: 3.5.3
debug: 4.3.4(supports-color@8.1.1)
fast-glob: 3.3.1
@@ -15360,17 +15441,15 @@ packages:
- terser
dev: true
/vitepress@1.0.0-rc.4(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0):
resolution: {integrity: sha512-JCQ89Bm6ECUTnyzyas3JENo00UDJeK8q1SUQyJYou+4Yz5BKEc/F3O21cu++DnUT2zXc0kvQ2Aj4BZCc/nioXQ==}
/vitepress@1.0.0-rc.8(@algolia/client-search@4.14.2)(@types/node@18.16.0)(search-insights@2.6.0):
resolution: {integrity: sha512-InoW3VdY0KDrFi/Nffy9hoL5wd7ScWaCiHx6im4TCCvNP01N7AF0Wq5MX+4b3HIZGS6I9b3ltbP1pGvqHP79Mg==}
hasBin: true
dependencies:
'@docsearch/css': 3.5.1
'@docsearch/js': 3.5.1(@algolia/client-search@4.14.2)(search-insights@2.6.0)
'@vitejs/plugin-vue': 4.2.3(vite@4.4.9)(vue@3.3.4)
'@docsearch/css': 3.5.2
'@docsearch/js': 3.5.2(@algolia/client-search@4.14.2)(search-insights@2.6.0)
'@vue/devtools-api': 6.5.0
'@vueuse/core': 10.3.0(vue@3.3.4)
'@vueuse/integrations': 10.3.0(focus-trap@7.5.2)(vue@3.3.4)
body-scroll-lock: 4.0.0-beta.0
'@vueuse/core': 10.4.1(vue@3.3.4)
'@vueuse/integrations': 10.4.1(focus-trap@7.5.2)(vue@3.3.4)
focus-trap: 7.5.2
mark.js: 8.11.1
minisearch: 6.1.0

View File

@@ -1,22 +1,20 @@
#!/usr/bin/env bash
set -euxo pipefail
# We have to use npm instead of yarn because it causes trouble in netlify
# Link local mermaid to npm
pushd packages/mermaid
npm link
popd
pnpm build
# Clone the Mermaid Live Editor repository
rm -rf mermaid-live-editor
git clone --single-branch https://github.com/mermaid-js/mermaid-live-editor.git
# Link local mermaid to live editor
npm link mermaid
cd mermaid-live-editor
# We have to use npm instead of yarn because it causes trouble in netlify
# Install dependencies
npm install --force
npm install
# Link local mermaid to live editor
npm link ../packages/mermaid
# Force Build the site
npm run build -- --force