├── codecov.yml
├── .gitmodules
├── DefaultSettings.php
├── i18n
├── zh-hant.json
├── qqq.json
├── ja.json
├── ko.json
├── zh-hans.json
├── he.json
├── sv.json
├── de.json
├── extra
│ └── Mermaid.magic.php
├── ce.json
├── nb.json
├── ar.json
├── en.json
├── li.json
├── sl.json
├── mk.json
├── uk.json
├── ia.json
├── krc.json
├── ast.json
├── roa-tara.json
├── eu.json
├── nl.json
├── be-tarask.json
├── fr.json
├── gl.json
├── pt.json
├── es.json
├── ru.json
├── pl.json
├── tr.json
└── pt-br.json
├── docs
├── PULL_REQUEST_TEMPLATE.md
├── ISSUE_TEMPLATE.md
├── USAGE.md
├── UPDATEMERMAID.md
├── INSTALL.md
└── RELEASE-NOTES.md
├── .gitignore
├── tsconfig.json
├── resources
├── utility
│ └── inject-nomin.cjs
├── ext.mermaid.js
└── styles
│ └── ext.mermaid.css
├── src
├── Config.php
├── ServiceWiring.php
├── Hooks.php
├── MermaidParserFunction.php
└── MermaidConfigExtractor.php
├── rollup.config.mjs
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── Makefile
├── tests
├── phpunit
│ ├── Unit
│ │ ├── MermaidConfigExtractorTest.php
│ │ ├── ConfigTest.php
│ │ ├── MermaidParserFunctionTest.php
│ │ └── TestingConsts.php
│ └── Integration
│ │ ├── JSONScript
│ │ ├── TestCases
│ │ │ ├── parser-graph.json
│ │ │ ├── parser-flowcharts-node.json
│ │ │ ├── parser-sankey-beta.json
│ │ │ ├── parser-flowcharts-direction.json
│ │ │ ├── parser-flowcharts-node-with-unicode-text.json
│ │ │ ├── parser-flowcharts-node-shapes-round-edges.json
│ │ │ ├── parser-flowcharts-node-with-text.json
│ │ │ ├── parser-flowcharts-node-shapes-stadium-shaped.json
│ │ │ ├── parser-git-graph-diagram.json
│ │ │ ├── parser-entity-relationship-diagram.json
│ │ │ ├── parser-timeline-diagram.json
│ │ │ ├── parser-user-journey-diagram.json
│ │ │ ├── parser-sequence-diagram-loops.json
│ │ │ ├── parser-sequence-diagram-actors.json
│ │ │ ├── parser-block-diagram.json
│ │ │ ├── parser-sequence-diagram-participans-aliases.json
│ │ │ ├── parser-gantt-milestones.json
│ │ │ ├── parser-class-with-multiplicity.json
│ │ │ ├── parser-pie-chart-show-data.json
│ │ │ ├── parser-class-define-members.json
│ │ │ ├── parser-state-diagram-choice-state.json
│ │ │ ├── parser-flowcharts-markdown-formatting.json
│ │ │ ├── parser-state-diagram-with-direction.json
│ │ │ ├── parser-sequence-diagram-line-breaks.json
│ │ │ ├── parser-sequence-diagram-notes.json
│ │ │ ├── parser-state-diagram-notes-on-states.json
│ │ │ ├── parser-gantt-title-exclusions.json
│ │ │ ├── parser-xychart-diagram.json
│ │ │ ├── parser-class-with-annotations.json
│ │ │ ├── parser-graph-links-tooltips.json
│ │ │ ├── parser-requirement-diagram.json
│ │ │ ├── parser-sequence-diagram-participans.json
│ │ │ ├── parser-class-with-generic-types.json
│ │ │ ├── parser-class-relations-with-labels.json
│ │ │ ├── parser-state-diagram-fork-join-state.json
│ │ │ ├── parser-graph-with-links.json
│ │ │ ├── parser-gantt-chart.json
│ │ │ ├── parser-sequence-diagram-nested-parallel-blocks.json
│ │ │ ├── parser-sequence-diagram-create-destroy-alias.json
│ │ │ ├── parser-quadrant-chart.json
│ │ │ ├── parser-subgraphs.json
│ │ │ ├── parser-sequence-diagram-popus-menus.json
│ │ │ ├── parser-wide-graph-horizontal-scroll.json
│ │ │ ├── parser-state-diagram-composite-states.json
│ │ │ └── parser-c4-context-diagram.json
│ │ └── JsonTestCaseScriptRunnerTest.php
│ │ └── I18nJsonFileIntegrityTest.php
└── bootstrap.php
├── phpunit.xml.dist
├── package.json
├── extension.json
├── composer.json
├── .phpcs.xml
├── README.md
├── scripts
└── generateConfigMap.ts
└── COPYING
/codecov.yml:
--------------------------------------------------------------------------------
1 | fixes:
2 | - "/var/www/html/extensions/Mermaid/::"
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "build"]
2 | path = build
3 | url = https://github.com/gesinn-it-pub/docker-compose-ci.git
4 |
--------------------------------------------------------------------------------
/DefaultSettings.php:
--------------------------------------------------------------------------------
1 | 'forest'
8 | ];
9 |
--------------------------------------------------------------------------------
/i18n/zh-hant.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Kly"
5 | ]
6 | },
7 | "mermaid-desc": "提供解析函式以協助產生使用 [https://mermaidjs.github.io/ mermaid] 腳本語言的圖表與流程圖"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/qqq.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Kghbln"
5 | ]
6 | },
7 | "mermaid-desc": "{{desc|name=Mermaid|url=https://www.mediawiki.org/wiki/Extension:Mermaid}}"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ja.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Yukkuri Shambis"
5 | ]
6 | },
7 | "mermaid-desc": "[https://mermaidjs.github.io/ mermaid]というスクリプト言語を使用して、図表やフローチャートを生成するのに役立つパーサー関数を提供します"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ko.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Jay94ks"
5 | ]
6 | },
7 | "mermaid-desc": "[https://mermaidjs.github.io/mermaid] 스크립트 언어를 사용하여 다이어그램 및 흐름도를 생성하기 위해 사용할 구문 분석기 함수를 제공하세요."
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/zh-hans.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "LittlePaw365",
5 | "Liuxinyu970226"
6 | ]
7 | },
8 | "mermaid-desc": "提供解析器函数,帮助使用[https://mermaidjs.github.io/ mermaid]脚本语言生成示意图和流程图"
9 | }
10 |
--------------------------------------------------------------------------------
/i18n/he.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Amire80"
5 | ]
6 | },
7 | "mermaid-desc": "אספקת פונקציית מפענח כדי לסייע ביצירת ותרשימי זרימה ותרשימים אחרים באמצעות שפת [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/sv.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Psl85"
5 | ]
6 | },
7 | "mermaid-desc": "Begär en parserfunksjon för att generera diagram och flödekort med skriptspråket [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Kghbln"
5 | ]
6 | },
7 | "mermaid-desc": "Ermöglicht das Erstellen von Grafiken und Diagrammen mithilfe der Skriptsprache [https://mermaidjs.github.io/ „mermaid“]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/extra/Mermaid.magic.php:
--------------------------------------------------------------------------------
1 | array( 0, 'mermaid' )
13 | );
14 |
--------------------------------------------------------------------------------
/i18n/ce.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Умар"
5 | ]
6 | },
7 | "mermaid-desc": "Парсеран функцеш гӀодо, скриптан мотт а лелош, диаграммашна а, блок-схемашна а генераци йан [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/nb.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Jon Harald Søby"
5 | ]
6 | },
7 | "mermaid-desc": "Gir en parserfunksjon for å generere diagrammer og flytkart med skriptspråket [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ar.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "ديفيد"
5 | ]
6 | },
7 | "mermaid-desc": "توفر وظيفة محلل للمساعدة في توليد الرسوم البيانية ومخططات الانسيابية باستخدام لغة البرنامج النصي [https://mermaidjs.github.io/ الحورية]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "mwjames"
5 | ]
6 | },
7 | "mermaid-desc": "Provides a parser function to help generate diagrams and flowcharts using the [https://mermaidjs.github.io/ mermaid] script language"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/li.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Ooswesthoesbes"
5 | ]
6 | },
7 | "mermaid-desc": "Bèdj 'n parserfunctie veur diagramme en vleujkaarte te make mit gebroek van 't [https://mermaidjs.github.io/ mermaid-sjrif]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/sl.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Eleassar"
5 | ]
6 | },
7 | "mermaid-desc": "Zagotavlja funkcijo razčlenjevalnika za ustvarjanje potekov in diagramov s skriptnim jezikom [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/docs/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | This PR is made in reference to: #
2 |
3 | This PR addresses or contains:
4 | - ...
5 | - ...
6 | - ...
7 |
8 | This PR includes:
9 | - [ ] Tests (unit/integration)
10 | - [ ] CI build passed
11 |
12 | Fixes #
13 |
--------------------------------------------------------------------------------
/i18n/mk.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Bjankuloski06"
5 | ]
6 | },
7 | "mermaid-desc": "Дава расчленувачка функција за создавање на дијаграми и блок-шеми користејќи го скриптниот јазик [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/uk.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Vlad5250"
5 | ]
6 | },
7 | "mermaid-desc": "Надає функції парсера для допомоги у генерації діаграм і блок-схем, з використанням скриптової мови [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ia.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "McDutchie"
5 | ]
6 | },
7 | "mermaid-desc": "Forni un function analysator pro adjutar a generar diagrammas e fluxogrammas usante le linguage de script [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/krc.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Къарачайлы"
5 | ]
6 | },
7 | "mermaid-desc": "[https://mermaidjs.github.io/ Mermaid] скрипт тилни хайырланыб диаграммала эмда блок-схемала болдурургъа болушур ючюн парсер функцияны береди"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ast.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Xuacu"
5 | ]
6 | },
7 | "mermaid-desc": "Ufre una función del analizador sintácticu p'ayudar a xenerar diagrames y organigrames usando'l llinguaxe de script [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/roa-tara.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Joetaras"
5 | ]
6 | },
7 | "mermaid-desc": "Dèje 'na funzione ca analizze pe aijutà a generà le diagramme e le flusse ausanne 'u lenguagge de script [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/eu.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Amaia"
5 | ]
6 | },
7 | "mermaid-desc": "Eman funtzio aztertzaile sintaktiko bat, diagramak eta organigramak sortzen laguntzeko, [https://mermaidjs.github.io/ mermaid] programazio hizkuntza erabiliz"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/nl.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Mainframe98"
5 | ]
6 | },
7 | "mermaid-desc": "Voegt een parserfunctie toe die helpt bij het genereren van (stroom)diagrammen die gebruik maken van de [https://mermaidjs.github.io/ mermaid] scripttaal"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/be-tarask.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Red Winged Duck"
5 | ]
6 | },
7 | "mermaid-desc": "Забясьпечвае функцыю парсэру для дапамогі ў стварэньні дыяграмаў і блёк-схемаў з выкарыстаньнем скрыптавай мовы [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Wladek92"
5 | ]
6 | },
7 | "mermaid-desc": "Fournit une fonction d'analyse pour aider à la génération des diagrammes et des organigrammes en utilisant le langage de script [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/gl.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Elisardojm"
5 | ]
6 | },
7 | "mermaid-desc": "Proporciona unha función do analizador sintáctico para axudar a xerar diagramas e organigramas mediante a linguaxe de comandos [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/pt.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Hamilton Abreu"
5 | ]
6 | },
7 | "mermaid-desc": "Fornece uma função do analisador sintático para ajudar a gerar diagramas e fluxogramas, utilizando a linguagem de comandos [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Fitoschido"
5 | ]
6 | },
7 | "mermaid-desc": "Proporciona una función del analizador sintáctico para ayudar a generar diagramas y organigramas mediante el lenguaje de programación [https://mermaidjs.github.io/ mermaid]"
8 | }
9 |
--------------------------------------------------------------------------------
/i18n/ru.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Kaganer",
5 | "Staspotanin2"
6 | ]
7 | },
8 | "mermaid-desc": "Предоставляет функции парсера, для помощи в генерации диаграмм и блок-схем, с использованием скриптового языка [https://mermaidjs.github.io/ mermaid]"
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *~
3 | *.kate-swp
4 |
5 | vendor/
6 | extensions/
7 |
8 | composer.phar
9 | composer.lock
10 |
11 | !.*
12 | .idea/
13 |
14 | node_modules/
15 | coverage/
16 |
17 | yarn-error.log
18 | .npmrc
19 | token
20 |
21 | package-lock.json
22 |
23 | .vscode/
24 |
25 | .env
--------------------------------------------------------------------------------
/i18n/pl.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Rail",
5 | "Railfail536"
6 | ]
7 | },
8 | "mermaid-desc": "Dostarcza funkcję parsera pomagającą w generowaniu diagramów i schematów blokowych przy wykorzystaniu języka skryptowego [https://mermaidjs.github.io/ mermaid]"
9 | }
10 |
--------------------------------------------------------------------------------
/i18n/tr.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Hedda",
5 | "MuratTheTurkish"
6 | ]
7 | },
8 | "mermaid-desc": "[https://mermaidjs.github.io/ Mermaid] betik dilini kullanarak diyagramlar ve akış çizelgeleri oluşturmaya yardımcı olmak için bir ayrıştırıcı işlevi sağlar"
9 | }
10 |
--------------------------------------------------------------------------------
/i18n/pt-br.json:
--------------------------------------------------------------------------------
1 | {
2 | "@metadata": {
3 | "authors": [
4 | "Eduardo Addad de Oliveira",
5 | "Eduardoaddad"
6 | ]
7 | },
8 | "mermaid-desc": "Fornece uma função do analisador sintático para ajudar a gerar diagramas e fluxogramas, utilizando a linguagem de comandos [https://mermaidjs.github.io/ mermaid]"
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "moduleResolution": "node",
6 | "strict": true,
7 | "esModuleInterop": true,
8 | "skipLibCheck": true,
9 | "forceConsistentCasingInFileNames": true
10 | },
11 | "include": [
12 | "scripts/**/*",
13 | "src/**/*"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/resources/utility/inject-nomin.cjs:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const targetFile = path.resolve(__dirname, '../../resources/mermaid.min.js');
5 | const comment = '/*@nomin*/\n';
6 |
7 | const content = fs.readFileSync(targetFile, 'utf8');
8 | fs.writeFileSync(targetFile, comment + content, 'utf8');
9 |
10 | console.log('Prepended /*@nomin*/ to mermaid.min.js');
--------------------------------------------------------------------------------
/docs/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Setup and configuration
2 |
3 | - Mermaid version:
4 | - MediaWiki version:
5 | - PHP version:
6 | - Database system (MySQL, PostgresQL, etc.) and version:
7 |
8 | ### Issue
9 |
10 | Produces a [stack trace](https://www.semantic-mediawiki.org/wiki/Help:Identifying_bugs) and outputs:
11 |
12 | ```
13 | ```
14 |
15 | Steps to reproduce the observation (recommendation is to use the [sandbox](http://www.sandbox.semantic-mediawiki.org)):
16 |
--------------------------------------------------------------------------------
/src/Config.php:
--------------------------------------------------------------------------------
1 | globalConfig = $globalConfig;
15 | }
16 |
17 | public function getDefaultTheme() {
18 | $key = "mermaidgDefaultTheme";
19 | if ( $this->globalConfig->has( $key ) ) {
20 | return $this->globalConfig->get( $key );
21 | }
22 | return 'forest';
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | import resolve from '@rollup/plugin-node-resolve';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import terserCjs from '@rollup/plugin-terser';
4 | const terser = terserCjs.default || terserCjs;
5 |
6 | export default {
7 | input: 'resources/ext.mermaid.js',
8 | output: {
9 | file: 'resources/mermaid.min.js',
10 | format: 'umd',
11 | name: 'mermaid',
12 | inlineDynamicImports: true
13 | },
14 | plugins: [
15 | resolve(),
16 | commonjs(),
17 | terser()
18 | ]
19 | };
20 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: smw
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ['https://www.semantic-mediawiki.org/wiki/Sponsorship']
13 |
--------------------------------------------------------------------------------
/src/ServiceWiring.php:
--------------------------------------------------------------------------------
1 | function ( MediaWikiServices $services ) {
22 | return new MermaidConfigExtractor();
23 | },
24 |
25 | /**
26 | * Mermaid.Config
27 | */
28 | 'Mermaid.Config' => function ( MediaWikiServices $services ) {
29 | $globalConfig = $services->getMainConfig();
30 | return new \Mermaid\Config( $globalConfig );
31 | }
32 | ];
33 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | -include .env
2 | export
3 |
4 | # setup for docker-compose-ci build directory
5 | # delete "build" directory to update docker-compose-ci
6 |
7 | ifeq (,$(wildcard ./build/))
8 | $(shell git submodule update --init --remote)
9 | endif
10 |
11 | EXTENSION=Mermaid
12 |
13 | # docker images
14 | MW_VERSION?=1.43
15 | PHP_VERSION?=8.3
16 | DB_TYPE?=mysql
17 | DB_IMAGE?="mariadb:11.2"
18 |
19 | # extensions
20 | # Enables JSONScript tests to be run
21 | SMW_VERSION?=6.0.1
22 |
23 | # composer
24 | # Enables "composer update" inside of extension
25 | COMPOSER_EXT?=true
26 |
27 | # nodejs
28 | # Enables node.js related tests and "npm install"
29 | # NODE_JS?=true
30 |
31 | # check for build dir and git submodule init if it does not exist
32 | include build/Makefile
33 |
34 |
--------------------------------------------------------------------------------
/tests/phpunit/Unit/MermaidConfigExtractorTest.php:
--------------------------------------------------------------------------------
1 | assertSame( $expected, $instance->extract( $input ), 'Extractor able to extract the configs' );
25 | }
26 |
27 | public function caseProvider() {
28 | return TestingConsts::EXTRACTOR_VALUE_MAP;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-graph.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid Graph render",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Graph Test",
9 | "contents": "{{#mermaid:graph TD\nA-->B\nB-->C\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid Graph data-mermaid attribute",
16 | "subject": "Mermaid Test/Graph Test",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"graph TD",
20 | "A-->B",
21 | "B-->C"
22 | ]
23 | }
24 | }
25 | ],
26 | "settings": {
27 | "wgContLang": "en",
28 | "wgLang": "en"
29 | },
30 | "meta": {
31 | "version": "2",
32 | "is-incomplete": false,
33 | "debug": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-node.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid single node flowchart with ID",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Single Node",
9 | "contents": "{{#mermaid:flowchart LR\nid\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with single node ID",
16 | "subject": "Mermaid Test/Single Node",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"",
20 | "flowchart LR",
21 | "id"
22 | ]
23 | }
24 | }
25 | ],
26 | "settings": {
27 | "wgContLang": "en",
28 | "wgLang": "en"
29 | },
30 | "meta": {
31 | "version": "2",
32 | "is-incomplete": false,
33 | "debug": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sankey-beta.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sankey-beta graph",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/Sankey Beta Test",
6 | "contents": "{{#mermaid:sankey-beta\nA,B,10\nA,C,5\nB,D,7\nC,D,3\nD,E,8\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid sankey-beta data-mermaid attribute content",
13 | "subject": "Mermaid Test/Sankey Beta Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"sankey-beta",
17 | "A,B,10",
18 | "A,C,5",
19 | "B,D,7",
20 | "C,D,3",
21 | "D,E,8"
22 | ]
23 | }
24 | }
25 | ],
26 | "settings": {
27 | "wgContLang": "en",
28 | "wgLang": "en"
29 | },
30 | "meta": {
31 | "version": "2",
32 | "is-incomplete": false,
33 | "debug": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-direction.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid flowchart with direction TD",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Direction TD",
9 | "contents": "{{#mermaid:flowchart TD\n Start --> Stop\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with TD direction",
16 | "subject": "Mermaid Test/Direction TD",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart TD",
21 | "Start",
22 | "-->",
23 | "Stop"
24 | ]
25 | }
26 | }
27 | ],
28 | "settings": {
29 | "wgContLang": "en",
30 | "wgLang": "en"
31 | },
32 | "meta": {
33 | "version": "2",
34 | "is-incomplete": false,
35 | "debug": true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-node-with-unicode-text.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid flowchart node with Unicode text",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Unicode Node",
9 | "contents": "{{#mermaid:flowchart LR\n id[\"This ❤ Unicode\"]\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with Unicode text",
16 | "subject": "Mermaid Test/Unicode Node",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart LR",
21 | "id",
22 | "This \\u2764 Unicode"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 | tests/phpunit/Unit
18 |
19 |
20 | tests/phpunit/Integration
21 |
22 |
23 |
24 |
25 | src
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-node-shapes-round-edges.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid node with round edges",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Round Edges Node",
9 | "contents": "{{#mermaid:flowchart LR\n id1(This is the text in the box)\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content for node with round edges",
16 | "subject": "Mermaid Test/Round Edges Node",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart LR",
21 | "id1",
22 | "(This is the text in the box)"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-node-with-text.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid flowchart with node having custom text",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Node with Text",
9 | "contents": "{{#mermaid:flowchart LR\n id1[This is the text in the box]\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content for node with custom text",
16 | "subject": "Mermaid Test/Node with Text",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart LR",
21 | "id1",
22 | "This is the text in the box"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-node-shapes-stadium-shaped.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stadium-shaped node",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Stadium Node",
9 | "contents": "{{#mermaid:flowchart LR\n id1([This is the text in the box])\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content for stadium-shaped node",
16 | "subject": "Mermaid Test/Stadium Node",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart LR",
21 | "id1",
22 | "([This is the text in the box])"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-git-graph-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid gitGraph diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/Git Graph Test",
6 | "contents": "{{#mermaid:\ngitGraph\n commit\n commit\n branch develop\n checkout develop\n commit\n commit\n checkout main\n merge develop\n commit\n commit\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid gitGraph data-mermaid attribute content",
13 | "subject": "Mermaid Test/Git Graph Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"gitGraph",
17 | "commit",
18 | "branch develop",
19 | "checkout develop",
20 | "merge develop"
21 | ]
22 | }
23 | }
24 | ],
25 | "settings": {
26 | "wgContLang": "en",
27 | "wgLang": "en"
28 | },
29 | "meta": {
30 | "version": "2",
31 | "is-incomplete": false,
32 | "debug": true
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Hooks.php:
--------------------------------------------------------------------------------
1 | tag
20 | *
21 | * @param Parser $parser
22 | * @return bool
23 | */
24 | public static function onParserFirstCallInit( Parser $parser ) {
25 | $parser->setFunctionHook( 'mermaid', 'Mermaid\\MermaidParserFunction::onParserFunction' );
26 | return true;
27 | }
28 |
29 | /**
30 | * onOutputPageParserOutput hook handler.
31 | *
32 | * @param OutputPage $out
33 | * @param ParserOutput $parserOutput
34 | * @return bool
35 | */
36 | public static function onOutputPageParserOutput( OutputPage $out, ParserOutput $parserOutput ) {
37 | if ( $parserOutput->getExtensionData( 'ext-mermaid' ) !== null &&
38 | $parserOutput->getExtensionData( 'ext-mermaid' ) === true ) {
39 |
40 | $out->addModules( 'ext.mermaid' );
41 | }
42 | return true;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-entity-relationship-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid ER diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/ER Diagram Test",
6 | "contents": "{{#mermaid:\nerDiagram\n CUSTOMER ||--o{ ORDER : places\n ORDER ||--|{ LINE-ITEM : contains\n CUSTOMER }|..|{ DELIVERY-ADDRESS : uses\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid erDiagram data-mermaid attribute content",
13 | "subject": "Mermaid Test/ER Diagram Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"erDiagram",
17 | "CUSTOMER||--o{ ORDER : places",
18 | "ORDER||--|{ LINE-ITEM : contains",
19 | "CUSTOMER }|..|{ DELIVERY-ADDRESS : uses"
20 | ]
21 | }
22 | }
23 | ],
24 | "settings": {
25 | "wgContLang": "en",
26 | "wgLang": "en"
27 | },
28 | "meta": {
29 | "version": "2",
30 | "is-incomplete": false,
31 | "debug": true
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-timeline-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid timeline diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/Timeline Test",
6 | "contents": "{{#mermaid:timeline\ntitle History of Social Media Platform\n2002 : LinkedIn\n2004 : Facebook\n : Google\n2005 : YouTube\n2006 : Twitter\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid timeline data-mermaid attribute content",
13 | "subject": "Mermaid Test/Timeline Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"timeline",
17 | "title History of Social Media Platform",
18 | "2002 : LinkedIn",
19 | "2004 : Facebook",
20 | " : Google",
21 | "2005 : YouTube",
22 | "2006 : Twitter"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-user-journey-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid journey diagram rendering",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/Journey Diagram",
6 | "contents": "{{#mermaid:\njourney\n title My working day\n section Go to work\n Make tea: 5: Me\n Go upstairs: 3: Me\n Do work: 1: Me, Cat\n section Go home\n Go downstairs: 5: Me\n Sit down: 5: Me\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid journey data-mermaid content",
13 | "subject": "Mermaid Test/Journey Diagram",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"journey",
17 | "title My working day",
18 | "section Go to work",
19 | "Make tea: 5: Me",
20 | "Do work: 1: Me, Cat",
21 | "section Go home"
22 | ]
23 | }
24 | }
25 | ],
26 | "settings": {
27 | "wgContLang": "en",
28 | "wgLang": "en"
29 | },
30 | "meta": {
31 | "version": "2",
32 | "is-incomplete": false,
33 | "debug": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-loops.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with loop block",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram Loop",
9 | "contents": "{{#mermaid:sequenceDiagram\n Alice->John: Hello John, how are you?\n loop Every minute\n John-->Alice: Great!\n end\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid sequence diagram content with loop",
16 | "subject": "Mermaid Test/Sequence Diagram Loop",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "Alice->John: Hello John, how are you?",
22 | "loop Every minute",
23 | "John-->Alice: Great!",
24 | "end"
25 | ]
26 | }
27 | }
28 | ],
29 | "settings": {
30 | "wgContLang": "en",
31 | "wgLang": "en"
32 | },
33 | "meta": {
34 | "version": "2",
35 | "is-incomplete": false,
36 | "debug": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-actors.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with actor type and bidirectional communication",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Actors",
9 | "contents": "{{#mermaid:sequenceDiagram\n actor Alice\n actor Bob\n Alice->>Bob: Hi Bob\n Bob->>Alice: Hi Alice\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Verify actor definitions and bidirectional message arrows",
16 | "subject": "Mermaid Test/Sequence Actors",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "actor Alice",
22 | "actor Bob",
23 | "Alice->>Bob: Hi Bob",
24 | "Bob->>Alice: Hi Alice"
25 | ]
26 | }
27 | }
28 | ],
29 | "settings": {
30 | "wgContLang": "en",
31 | "wgLang": "en"
32 | },
33 | "meta": {
34 | "version": "2",
35 | "is-incomplete": false,
36 | "debug": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-block-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid block-beta diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/Block Diagram",
6 | "contents": "{{#mermaid:\nblock-beta\ncolumns 1\n db((\"DB\"))\n blockArrowId6<[\" \"]>(down)\n block:ID\n A\n B[\"A wide one in the middle\"]\n C\n end\n space\n D\n ID --> D\n C --> D\n style B fill:#969,stroke:#333,stroke-width:4px\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid block-beta data-mermaid attribute",
13 | "subject": "Mermaid Test/Block Diagram",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"block-beta",
17 | "block:ID",
18 | "B["A wide one in the middle"]",
19 | "ID --> D",
20 | "style B fill:#969"
21 | ]
22 | }
23 | }
24 | ],
25 | "settings": {
26 | "wgContLang": "en",
27 | "wgLang": "en"
28 | },
29 | "meta": {
30 | "version": "2",
31 | "is-incomplete": false,
32 | "debug": true
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/phpunit/Unit/ConfigTest.php:
--------------------------------------------------------------------------------
1 | getMockConfig( [] );
11 | $instance = new Config( $globalConfig );
12 | $this->assertEquals( 'forest', $instance->getDefaultTheme() );
13 | }
14 |
15 | public function testGetDefaultThemeWithValueInGlobal() {
16 | $globalConfig = $this->getMockConfig( [ 'mermaidgDefaultTheme' => 'foo' ] );
17 | $instance = new Config( $globalConfig );
18 | $this->assertEquals( 'foo', $instance->getDefaultTheme() );
19 | }
20 |
21 | /**
22 | * @param array $data
23 | * @return \Config
24 | */
25 | protected function getMockConfig( array $data ) {
26 | $configMock = $this->createMock( '\Config' );
27 |
28 | $configMock->method( 'has' )->will( $this->returnCallback( function ( $arg ) use ( $data ) {
29 | return in_array( $arg, array_keys( $data ) );
30 | } ) );
31 |
32 | $configMock->method( 'get' )->will( $this->returnCallback( function ( $arg ) use ( $data ) {
33 | return $data[$arg];
34 | } ) );
35 |
36 | return $configMock;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-participans-aliases.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with participant aliases",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Aliases",
9 | "contents": "{{#mermaid:sequenceDiagram\n participant A as Alice\n participant J as John\n A->>J: Hello John, how are you?\n J->>A: Great!\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Verify participants with aliases and basic message arrows",
16 | "subject": "Mermaid Test/Sequence Aliases",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "participant A as Alice",
22 | "participant J as John",
23 | "A->>J: Hello John, how are you?",
24 | "J->>A: Great!"
25 | ]
26 | }
27 | }
28 | ],
29 | "settings": {
30 | "wgContLang": "en",
31 | "wgLang": "en"
32 | },
33 | "meta": {
34 | "version": "2",
35 | "is-incomplete": false,
36 | "debug": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-gantt-milestones.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Gantt diagram with milestones",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Gantt Milestones",
9 | "contents": "{{#mermaid:gantt\n dateFormat HH:mm\n axisFormat %H:%M\n Initial milestone : milestone, m1, 17:49, 2m\n Task A : 10m\n Task B : 5m\n Final milestone : milestone, m2, 18:08, 4m\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid Gantt diagram with milestones",
16 | "subject": "Mermaid Test/Gantt Milestones",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"gantt",
21 | "dateFormat HH:mm",
22 | "axisFormat %H:%M",
23 | "Initial milestone : milestone, m1, 17:49, 2m",
24 | "Task A : 10m",
25 | "Task B : 5m",
26 | "Final milestone : milestone, m2, 18:08, 4m"
27 | ]
28 | }
29 | }
30 | ],
31 | "settings": {
32 | "wgContLang": "en",
33 | "wgLang": "en"
34 | },
35 | "meta": {
36 | "version": "2",
37 | "is-incomplete": false,
38 | "debug": true
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-class-with-multiplicity.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid classDiagram with cardinality (multiplicity)",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Class Diagram Cardinality",
9 | "contents": "{{#mermaid:classDiagram\n Customer \"1\" --> \"*\" Ticket\n Student \"1\" --> \"1..*\" Course\n Galaxy --> \"many\" Star : Contains\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid classDiagram content with cardinality",
16 | "subject": "Mermaid Test/Class Diagram Cardinality",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | "quot;content":"classDiagram",
21 | "Customer "1" --> "*" Ticket",
22 | "Student "1" --> "1..*" Course",
23 | "Galaxy --> "many" Star : Contains"
24 | ]
25 | }
26 | }
27 | ],
28 | "settings": {
29 | "wgContLang": "en",
30 | "wgLang": "en"
31 | },
32 | "meta": {
33 | "version": "2",
34 | "is-incomplete": false,
35 | "debug": true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-pie-chart-show-data.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid pie chart with showData and title",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Pie Chart ShowData",
9 | "contents": "{{#mermaid:pie showData\n title Key elements in Product X\n \"Calcium\" : 42.96\n \"Potassium\" : 50.05\n \"Magnesium\" : 10.01\n \"Iron\" : 5\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid pie chart content with showData and title",
16 | "subject": "Mermaid Test/Pie Chart ShowData",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"pie showData",
21 | "title Key elements in Product X",
22 | ""Calcium" : 42.96",
23 | ""Potassium" : 50.05",
24 | ""Magnesium" : 10.01",
25 | ""Iron" : 5"
26 | ]
27 | }
28 | }
29 | ],
30 | "settings": {
31 | "wgContLang": "en",
32 | "wgLang": "en"
33 | },
34 | "meta": {
35 | "version": "2",
36 | "is-incomplete": false,
37 | "debug": true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-class-define-members.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid UML classDiagram with class members as attributes and methods",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Class Diagram Members",
9 | "contents": "{{#mermaid:classDiagram\nclass BankAccount\nBankAccount : +String owner\nBankAccount : +BigDecimal balance\nBankAccount : +deposit(amount)\nBankAccount : +withdrawal(amount)\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid UML classDiagram content with attributes and methods",
16 | "subject": "Mermaid Test/Class Diagram Members",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"classDiagram",
21 | "class BankAccount",
22 | "BankAccount : +String owner",
23 | "BankAccount : +BigDecimal balance",
24 | "BankAccount : +deposit(amount)",
25 | "BankAccount : +withdrawal(amount)"
26 | ]
27 | }
28 | }
29 | ],
30 | "settings": {
31 | "wgContLang": "en",
32 | "wgLang": "en"
33 | },
34 | "meta": {
35 | "version": "2",
36 | "is-incomplete": false,
37 | "debug": true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-state-diagram-choice-state.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stateDiagram-v2 with <> state",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/State Choice",
9 | "contents": "{{#mermaid:stateDiagram-v2\n state if_state <>\n [*] --> IsPositive\n IsPositive --> if_state\n if_state --> False: if n < 0\n if_state --> True : if n >= 0\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Verify Mermaid <> state in stateDiagram-v2",
16 | "subject": "Mermaid Test/State Choice",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"stateDiagram-v2",
21 | "state if_state <<choice>>",
22 | "[*] --> IsPositive",
23 | "IsPositive --> if_state",
24 | "if_state --> False: if n < 0",
25 | "if_state --> True : if n >= 0"
26 | ]
27 | }
28 | }
29 | ],
30 | "settings": {
31 | "wgContLang": "en",
32 | "wgLang": "en"
33 | },
34 | "meta": {
35 | "version": "2",
36 | "debug": true,
37 | "is-incomplete": false
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-flowcharts-markdown-formatting.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid flowchart with markdown labels and multiline text",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Markdown Labels",
9 | "contents": "{{#mermaid:flowchart LR\nconfig.flowchart.htmlLabels = false\nmarkdown[\"`This **is** _Markdown_`\"]\nnewLines[\"`Line1\\nLine 2\\nLine 3`\"]\nmarkdown --> newLines\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with markdown and multiline labels",
16 | "subject": "Mermaid Test/Markdown Labels",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"flowchart LR",
21 | "config.flowchart.htmlLabels = false",
22 | "markdown",
23 | "`This **is** _Markdown_`",
24 | "newLines",
25 | "`Line1",
26 | "Line 2",
27 | "Line 3`",
28 | "markdown --> newLines"
29 | ]
30 | }
31 | }
32 | ],
33 | "settings": {
34 | "wgContLang": "en",
35 | "wgLang": "en"
36 | },
37 | "meta": {
38 | "version": "2",
39 | "is-incomplete": false,
40 | "debug": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-state-diagram-with-direction.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stateDiagram with direction LR and nested states",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/State Diagram Direction LR",
9 | "contents": "{{#mermaid:stateDiagram\n direction LR\n [*] --> A\n A --> B\n B --> C\n state B {\n direction LR\n a --> b\n }\n B --> D\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid stateDiagram with direction LR and nested state direction",
16 | "subject": "Mermaid Test/State Diagram Direction LR",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"stateDiagram",
21 | "direction LR",
22 | "[*] --> A",
23 | "A --> B",
24 | "B --> C",
25 | "state B {",
26 | "direction LR",
27 | "a --> b",
28 | "}",
29 | "B --> D"
30 | ]
31 | }
32 | }
33 | ],
34 | "settings": {
35 | "wgContLang": "en",
36 | "wgLang": "en"
37 | },
38 | "meta": {
39 | "version": "2",
40 | "debug": true,
41 | "is-incomplete": false
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | format( 'Y-m-d h:i' ) );
27 |
28 | $autoloader = require $path;
29 | $autoloader->addPsr4( 'Mermaid\\Tests\\', __DIR__ . '/phpunit/Unit' );
30 | $autoloader->addPsr4( 'Mermaid\\Tests\\Integration\\', __DIR__ . '/phpunit/Integration' );
31 | unset( $autoloader );
32 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-line-breaks.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with line breaks in messages, notes and actor aliases",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram Line Breaks",
9 | "contents": "{{#mermaid:sequenceDiagram\n participant Alice as Alice
Johnson\n Alice->John: Hello John,
how are you?\n Note over Alice,John: A typical interaction
But now in two lines\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid sequence diagram content with line breaks",
16 | "subject": "Mermaid Test/Sequence Diagram Line Breaks",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "participant Alice as Alice<br\\/>Johnson",
22 | "Alice->John: Hello John,<br\\/>how are you?",
23 | "Note over Alice,John: A typical interaction<br\\/>But now in two lines"
24 | ]
25 | }
26 | }
27 | ],
28 | "settings": {
29 | "wgContLang": "en",
30 | "wgLang": "en"
31 | },
32 | "meta": {
33 | "version": "2",
34 | "is-incomplete": false,
35 | "debug": true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-notes.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with single and multi-participant notes",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram Notes",
9 | "contents": "{{#mermaid:sequenceDiagram\n participant John\n Note right of John: Text in note\n\n participant Alice\n participant Bob\n Alice->John: Hello John, how are you?\n Note over Alice,John: A typical interaction\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid sequence diagram with notes",
16 | "subject": "Mermaid Test/Sequence Diagram Notes",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "participant John",
22 | "Note right of John: Text in note",
23 | "participant Alice",
24 | "participant Bob",
25 | "Alice->John: Hello John, how are you?",
26 | "Note over Alice,John: A typical interaction"
27 | ]
28 | }
29 | }
30 | ],
31 | "settings": {
32 | "wgContLang": "en",
33 | "wgLang": "en"
34 | },
35 | "meta": {
36 | "version": "2",
37 | "is-incomplete": false,
38 | "debug": true
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-state-diagram-notes-on-states.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stateDiagram-v2 with notes on states",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/State Diagram Notes",
9 | "contents": "{{#mermaid:stateDiagram-v2\n State1: The state with a note\n note right of State1\n Important information! You can write\n notes.\n end note\n State1 --> State2\n note left of State2 : This is the note to the left.\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid stateDiagram-v2 with notes",
16 | "subject": "Mermaid Test/State Diagram Notes",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"stateDiagram-v2",
21 | "State1: The state with a note",
22 | "note right of State1",
23 | "Important information! You can write",
24 | "notes.",
25 | "end note",
26 | "State1 --> State2",
27 | "note left of State2 : This is the note to the left."
28 | ]
29 | }
30 | }
31 | ],
32 | "settings": {
33 | "wgContLang": "en",
34 | "wgLang": "en"
35 | },
36 | "meta": {
37 | "version": "2",
38 | "debug": true,
39 | "is-incomplete": false
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-gantt-title-exclusions.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Gantt diagram with title and exclusions",
3 | "requires": {
4 | "Mermaid": ">=2.0."
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Gantt Title and exclusions",
9 | "contents": "{{#mermaid:gantt\n title A Gantt Diagram Excluding Fri - Sat weekends\n dateFormat YYYY-MM-DD\n excludes weekends\n weekend friday\n section Section\n A task :a1, 2024-01-01, 30d\n Another task :after a1, 20d\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid Gantt diagram with title and exclusions",
16 | "subject": "Mermaid Test/Gantt Title and exclusions",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"gantt",
21 | "title A Gantt Diagram Excluding Fri - Sat weekends",
22 | "dateFormat YYYY-MM-DD",
23 | "excludes weekends",
24 | "weekend friday",
25 | "section Section",
26 | "A task :a1, 2024-01-01, 30d",
27 | "Another task :after a1, 20d"
28 | ]
29 | }
30 | }
31 | ],
32 | "settings": {
33 | "wgContLang": "en",
34 | "wgLang": "en"
35 | },
36 | "meta": {
37 | "version": "2",
38 | "is-incomplete": false,
39 | "debug": true
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-xychart-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid xychart-beta diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/XY Chart Test",
6 | "contents": "{{#mermaid:\nxychart-beta\n title \"Sales Revenue\"\n x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]\n y-axis \"Revenue (in $)\" 4000 --> 11000\n bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]\n line [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000]\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid xychart-beta data-mermaid attribute content",
13 | "subject": "Mermaid Test/XY Chart Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"xychart-beta",
17 | "title "Sales Revenue"",
18 | "x-axis [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec]",
19 | "y-axis "Revenue (in $)" 4000 --> 11000",
20 | "bar [5000, 6000",
21 | "line [5000, 6000"
22 | ]
23 | }
24 | }
25 | ],
26 | "settings": {
27 | "wgContLang": "en",
28 | "wgLang": "en"
29 | },
30 | "meta": {
31 | "version": "2",
32 | "is-incomplete": false,
33 | "debug": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-class-with-annotations.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid classDiagram with annotations on classes",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Class Diagram Annotations",
9 | "contents": "{{#mermaid:classDiagram\nclass Shape {\n <>\n noOfVertices\n draw()\n}\nclass Color {\n <>\n RED\n BLUE\n GREEN\n WHITE\n BLACK\n}\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid classDiagram content with annotations (interface, enumeration)",
16 | "subject": "Mermaid Test/Class Diagram Annotations",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"classDiagram",
21 | "class Shape {",
22 | "<<interface>>",
23 | "noOfVertices",
24 | "draw()",
25 | "class Color {",
26 | "<<enumeration>>",
27 | "RED",
28 | "BLUE",
29 | "GREEN",
30 | "WHITE",
31 | "BLACK"
32 | ]
33 | }
34 | }
35 | ],
36 | "settings": {
37 | "wgContLang": "en",
38 | "wgLang": "en"
39 | },
40 | "meta": {
41 | "version": "2",
42 | "is-incomplete": false,
43 | "debug": true
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-graph-links-tooltips.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid graph with clickable links and tooltips",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Graph Links and Tooltips",
9 | "contents": "{{#mermaid:graph LR;\n A-->B;\n click A \"https://sandbox.semantic-mediawiki.org/wiki/A\" \"This is the tooltip for a link to page A.\"\n click B \"https://sandbox.semantic-mediawiki.org/wiki/B\" \"This is the tooltip for a link to page B.\"\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid graph with links and tooltips in data-mermaid attribute",
16 | "subject": "Mermaid Test/Graph Links and Tooltips",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"graph LR;",
20 | "A-->B;",
21 | "click A",
22 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/A",
23 | "This is the tooltip for a link to page A.",
24 | "click B",
25 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/B",
26 | "This is the tooltip for a link to page B."
27 | ]
28 | }
29 | }
30 | ],
31 | "settings": {
32 | "wgContLang": "en",
33 | "wgLang": "en"
34 | },
35 | "meta": {
36 | "version": "2",
37 | "is-incomplete": false,
38 | "debug": true
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-requirement-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid requirementDiagram with requirement and element relation",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Requirement Diagram Example",
9 | "contents": "{{#mermaid:requirementDiagram\n requirement test_req {\n id: 1\n text: the test text.\n risk: high\n verifymethod: test\n }\n\n element test_entity {\n type: simulation\n }\n\n test_entity - satisfies -> test_req\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid requirementDiagram with requirement and element relation",
16 | "subject": "Mermaid Test/Requirement Diagram Example",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"requirementDiagram",
21 | "requirement test_req",
22 | "id: 1",
23 | "text: the test text.",
24 | "risk: high",
25 | "verifymethod: test",
26 | "element test_entity",
27 | "type: simulation",
28 | "test_entity - satisfies -> test_req"
29 | ]
30 | }
31 | }
32 | ],
33 | "settings": {
34 | "wgContLang": "en",
35 | "wgLang": "en"
36 | },
37 | "meta": {
38 | "version": "2",
39 | "is-incomplete": false,
40 | "debug": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "name": "mediawiki-mermaid",
4 | "version": "10.9.4",
5 | "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
6 | "main": "lib/mermaid.core.js",
7 | "keywords": [
8 | "diagram",
9 | "markdown",
10 | "flowchart",
11 | "sequence diagram",
12 | "gantt",
13 | "class diagram",
14 | "git graph"
15 | ],
16 | "scripts": {
17 | "build": "rollup -c",
18 | "postinstall": "npm run build && node resources/utility/inject-nomin.cjs && npx tsx scripts/generateConfigMap.ts"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/SemanticMediaWiki/Mermaid"
23 | },
24 | "author": "Tyler Gibson",
25 | "license": "GPL-2.0-or-later",
26 | "standard": {
27 | "globals": [
28 | "page"
29 | ]
30 | },
31 | "dependencies": {
32 | "mermaid": "10.9.4",
33 | "node-fetch": "^2.7.0",
34 | "ts-morph": "^26.0.0"
35 | },
36 | "files": [
37 | "lib",
38 | "resources"
39 | ],
40 | "copyFilesSettings": {
41 | "whenFileExists": "overwrite"
42 | },
43 | "devDependencies": {
44 | "@rollup/plugin-commonjs": "^28.0.6",
45 | "@rollup/plugin-node-resolve": "^16.0.1",
46 | "@rollup/plugin-terser": "^0.4.4",
47 | "@types/node": "^24.0.12",
48 | "@types/node-fetch": "^2.6.12",
49 | "copy-files-from-to": "^3.12.1",
50 | "insert-line": "^1.1.0",
51 | "rollup": "^4.0.0",
52 | "tsx": "^4.20.3"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-participans.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram: participants and basic message arrows",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram",
9 | "contents": "{{#mermaid:sequenceDiagram\n participant Alice\n participant Bob\n Alice->>John: Hello John, how are you?\n loop Healthcheck\n John->John: Fight against hypochondria\n end\n Note right of John: Rational thoughts
prevail...\n John-->>Alice: Great!\n John->>Bob: How about you?\n Bob-->>John: Jolly good!\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Test Mermaid sequence diagram: participants and basic message arrows",
16 | "subject": "Mermaid Test/Sequence Diagram",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"sequenceDiagram",
20 | "participant Alice",
21 | "participant Bob",
22 | "Alice->>John: Hello John, how are you?",
23 | "John->John: Fight against hypochondria",
24 | "John-->>Alice: Great!",
25 | "John->>Bob: How about you?",
26 | "Bob-->>John: Jolly good!"
27 | ]
28 | }
29 | }
30 | ],
31 | "settings": {
32 | "wgContLang": "en",
33 | "wgLang": "en"
34 | },
35 | "meta": {
36 | "version": "2",
37 | "is-incomplete": false,
38 | "debug": true
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-class-with-generic-types.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid classDiagram with generic types",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Class Diagram Generics",
9 | "contents": "{{#mermaid:classDiagram\nclass Square~Shape~ {\n int id\n List~int~ position\n setPoints(List~int~ points)\n getPoints() List~int~\n}\n\nSquare : -List~string~ messages\nSquare : +setMessages(List~string~ messages)\nSquare : +getMessages() List~string~\nSquare : +getDistanceMatrix() List~List~int~~\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid classDiagram content with generic types",
16 | "subject": "Mermaid Test/Class Diagram Generics",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"classDiagram",
21 | "class Square~Shape~",
22 | "int id",
23 | "List~int~ position",
24 | "setPoints(List~int~ points)",
25 | "getPoints() List~int~",
26 | "Square : -List~string~ messages",
27 | "Square : +setMessages(List~string~ messages)",
28 | "Square : +getMessages() List~string~",
29 | "Square : +getDistanceMatrix() List~List~int~~"
30 | ]
31 | }
32 | }
33 | ],
34 | "settings": {
35 | "wgContLang": "en",
36 | "wgLang": "en"
37 | },
38 | "meta": {
39 | "version": "2",
40 | "is-incomplete": false,
41 | "debug": true
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-class-relations-with-labels.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid classDiagram relationships with labels",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Class Diagram Relationships",
9 | "contents": "{{#mermaid:classDiagram\nclassA --|> classB : Inheritance\nclassC --* classD : Composition\nclassE --o classF : Aggregation\nclassG --> classH : Association\nclassI -- classJ : Link(Solid)\nclassK ..> classL : Dependency\nclassM ..|> classN : Realization\nclassO .. classP : Link(Dashed)\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid classDiagram relationships with labels",
16 | "subject": "Mermaid Test/Class Diagram Relationships",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"classDiagram",
21 | "classA --|> classB : Inheritance",
22 | "classC --* classD : Composition",
23 | "classE --o classF : Aggregation",
24 | "classG --> classH : Association",
25 | "classI -- classJ : Link(Solid)",
26 | "classK ..> classL : Dependency",
27 | "classM ..|> classN : Realization",
28 | "classO .. classP : Link(Dashed)"
29 | ]
30 | }
31 | }
32 | ],
33 | "settings": {
34 | "wgContLang": "en",
35 | "wgLang": "en"
36 | },
37 | "meta": {
38 | "version": "2",
39 | "is-incomplete": false,
40 | "debug": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/extension.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Mermaid",
3 | "version": "6.0.2",
4 | "author": [
5 | "James Hong Kong",
6 | "Tyler Gibson"
7 | ],
8 | "url": "https://github.com/SemanticMediaWiki/Mermaid/",
9 | "descriptionmsg": "mermaid-desc",
10 | "license-name": "GPL-2.0-or-later",
11 | "type": "parserhook",
12 | "requires": {
13 | "MediaWiki": ">= 1.39"
14 | },
15 | "ExtensionMessagesFiles": {
16 | "MermaidMagic": "i18n/extra/Mermaid.magic.php"
17 | },
18 | "MessagesDirs": {
19 | "Mermaid": [
20 | "i18n"
21 | ]
22 | },
23 | "AutoloadNamespaces": {
24 | "Mermaid\\": "src/"
25 | },
26 | "TestAutoloadNamespaces": {
27 | "Mermaid\\Tests\\": "tests/phpunit/Unit/",
28 | "Mermaid\\Tests\\Integration\\": "tests/phpunit/Integration/"
29 | },
30 | "ResourceModules": {
31 | "ext.mermaid": {
32 | "packageFiles": [
33 | "resources/mermaid.min.js"
34 | ],
35 | "styles": [
36 | "resources/styles/ext.mermaid.css"
37 | ],
38 | "dependencies": [
39 | "mediawiki.api"
40 | ],
41 | "messages": [
42 | "mermaid-desc"
43 | ],
44 | "targets": [
45 | "desktop",
46 | "mobile"
47 | ]
48 | }
49 | },
50 | "ResourceFileModulePaths": {
51 | "localBasePath": "",
52 | "remoteExtPath": "Mermaid/resources"
53 | },
54 |
55 | "ServiceWiringFiles": [
56 | "src/ServiceWiring.php"
57 | ],
58 | "Hooks" : {
59 | "ParserFirstCallInit" : "Mermaid\\Hooks::onParserFirstCallInit",
60 | "OutputPageParserOutput" : "Mermaid\\Hooks::onOutputPageParserOutput"
61 | },
62 | "config": {
63 | "DefaultTheme": {
64 | "value": "forest"
65 | }
66 | },
67 | "config_prefix": "mermaidg",
68 | "manifest_version": 2
69 | }
70 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-state-diagram-fork-join-state.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stateDiagram-v2 with <> and <> states",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/State Fork Join",
9 | "contents": "{{#mermaid:stateDiagram-v2\n state fork_state <>\n [*] --> fork_state\n fork_state --> State2\n fork_state --> State3\n\n state join_state <>\n State2 --> join_state\n State3 --> join_state\n join_state --> State4\n State4 --> [*]\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Verify Mermaid <> and <> states in stateDiagram-v2",
16 | "subject": "Mermaid Test/State Fork Join",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"stateDiagram-v2",
21 | "state fork_state <<fork>>",
22 | "[*] --> fork_state",
23 | "fork_state --> State2",
24 | "fork_state --> State3",
25 | "state join_state <<join>>",
26 | "State2 --> join_state",
27 | "State3 --> join_state",
28 | "join_state --> State4",
29 | "State4 --> [*]"
30 | ]
31 | }
32 | }
33 | ],
34 | "settings": {
35 | "wgContLang": "en",
36 | "wgLang": "en"
37 | },
38 | "meta": {
39 | "version": "2",
40 | "debug": true,
41 | "is-incomplete": false
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-graph-with-links.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid Graph render with clickable links",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Graph Test",
9 | "contents": "{{#mermaid:graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n click A \"https://sandbox.semantic-mediawiki.org/wiki/A\"\n click B \"https://sandbox.semantic-mediawiki.org/wiki/B\"\n click C \"https://sandbox.semantic-mediawiki.org/wiki/C\"\n click D \"https://sandbox.semantic-mediawiki.org/wiki/D\"\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with clickable nodes",
16 | "subject": "Mermaid Test/Graph Test",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"graph TD;",
20 | "A-->B;",
21 | "A-->C;",
22 | "B-->D;",
23 | "C-->D;",
24 | "click A",
25 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/A",
26 | "click B",
27 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/B",
28 | "click C",
29 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/C",
30 | "click D",
31 | "https:\\/\\/sandbox.semantic-mediawiki.org\\/wiki\\/D"
32 | ]
33 | }
34 | }
35 | ],
36 | "settings": {
37 | "wgContLang": "en",
38 | "wgLang": "en"
39 | },
40 | "meta": {
41 | "version": "2",
42 | "is-incomplete": false,
43 | "debug": true
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-gantt-chart.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid Gantt chart render",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Gantt",
9 | "contents": "{{#mermaid:gantt\\ndateFormat YYYY-MM-DD\\ntitle Adding GANTT diagram functionality to mermaid\\nsection A section\\nCompleted task :done, des1, 2014-01-06,2014-01-08\\nActive task :active, des2, 2014-01-09, 3d\\nFuture task : des3, after des2, 5d\\nFuture task2 : des4, after des3, 5d\\nsection Critical tasks\\nCompleted task in the critical line :crit, done, 2014-01-06,24h\\nImplement parser and jison :crit, done, after des1, 2d\\nCreate tests for parser :crit, active, 3d\\nFuture task in critical line :crit, 5d\\nCreate tests for renderer :2d\\nAdd to mermaid :1d\\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid Gantt chart data-mermaid attribute",
16 | "subject": "Mermaid Test/Gantt",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | "gantt\\\\ndateFormat YYYY-MM-DD",
21 | "title Adding GANTT diagram functionality to mermaid",
22 | "Completed task :done, des1, 2014-01-06,2014-01-08",
23 | "Add to mermaid :1d"
24 | ]
25 | }
26 | }
27 | ],
28 | "settings": {
29 | "wgContLang": "en",
30 | "wgLang": "en"
31 | },
32 | "meta": {
33 | "version": "2",
34 | "is-incomplete": false,
35 | "debug": true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-nested-parallel-blocks.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram nested parallel blocks",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram Nested Parallel",
9 | "contents": "{{#mermaid:sequenceDiagram\n par Alice to Bob\n Alice->>Bob: Go help John\n and Alice to John\n Alice->>John: I want this done today\n par John to Charlie\n John->>Charlie: Can we do this today?\n and John to Diana\n John->>Diana: Can you help us today?\n end\n end\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid sequence diagram content with nested parallel blocks",
16 | "subject": "Mermaid Test/Sequence Diagram Nested Parallel",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "par Alice to Bob",
22 | "Alice->>Bob: Go help John",
23 | "and Alice to John",
24 | "Alice->>John: I want this done today",
25 | "par John to Charlie",
26 | "John->>Charlie: Can we do this today?",
27 | "and John to Diana",
28 | "John->>Diana: Can you help us today?",
29 | "end",
30 | "end"
31 | ]
32 | }
33 | }
34 | ],
35 | "settings": {
36 | "wgContLang": "en",
37 | "wgLang": "en"
38 | },
39 | "meta": {
40 | "version": "2",
41 | "is-incomplete": false,
42 | "debug": true
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-create-destroy-alias.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequence diagram with create and destroy directives including aliases",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Create Destroy",
9 | "contents": "{{#mermaid:sequenceDiagram\n Alice->>Bob: Hello Bob, how are you ?\n Bob->>Alice: Fine, thank you. And you?\n create participant Carl\n Alice->>Carl: Hi Carl!\n create actor D as Donald\n Carl->>D: Hi!\n destroy Carl\n Alice-xCarl: We are too many\n destroy Bob\n Bob->>Alice: I agree\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute with create and destroy directives",
16 | "subject": "Mermaid Test/Sequence Create Destroy",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "create participant Carl",
22 | "create actor D as Donald",
23 | "destroy Carl",
24 | "destroy Bob",
25 | "Alice->>Bob: Hello Bob, how are you ?",
26 | "Bob->>Alice: Fine, thank you. And you?",
27 | "Alice->>Carl: Hi Carl!",
28 | "Carl->>D: Hi!",
29 | "Alice-xCarl: We are too many",
30 | "Bob->>Alice: I agree"
31 | ]
32 | }
33 | }
34 | ],
35 | "settings": {
36 | "wgContLang": "en",
37 | "wgLang": "en"
38 | },
39 | "meta": {
40 | "version": "2",
41 | "is-incomplete": false,
42 | "debug": true
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/docs/USAGE.md:
--------------------------------------------------------------------------------
1 | This file contains basic *usage information* for the **Mermaid** extension. See also the [readme].
2 |
3 | The `#mermaid` parser function allows to add [mermaid][mermaid] typed content to a wiki article. Copying,
4 | [example syntax][examplemjs] is as easy as:
5 |
6 | ```
7 | {{#mermaid:sequenceDiagram
8 | participant Alice
9 | participant Bob
10 | Alice->John: Hello John, how are you?
11 | loop Healthcheck
12 | John->John: Fight against hypochondria
13 | end
14 | Note right of John: Rational thoughts
prevail...
15 | John-->Alice: Great!
16 | John->Bob: How about you?
17 | Bob-->John: Jolly good!
18 | }}
19 | ```
20 | 
21 |
22 | This extension now supports all configuration options of MermaidJS
23 |
24 | * Reference - https://mermaid-js.github.io/mermaid/#/Setup?id=configuration
25 |
26 | It is passed to the parser function like shown:
27 | ```
28 | {{#mermaid:graph LR;
29 | ...
30 | |
31 | config.theme = default
32 | config.flowchart.useMaxWidth = false
33 | config.flowchart.curve = basis
34 | }}
35 | ```
36 | Note that is is also possible to further adapt the graph using CSS, e.g. to add a scrollbar:
37 |
38 | ```
39 | .ext-mermaid > div {
40 | overflow: scroll;
41 | }
42 | ```
43 |
44 | Further [examples][examplesmw] have been created on wiki. See also [Drawing Diagrams and Charts with Mermaid](https://www.pro.wiki/help/draw-mermaid-diagrams-charts-in-mediawiki)
45 |
46 |
47 | [readme]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/README.md
48 | [mermaid]: https://github.com/knsv/mermaid
49 | [examplemjs]: https://mermaidjs.github.io/
50 | [examplesmw]: https://sandbox.semantic-mediawiki.org/wiki/Mermaid
51 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-quadrant-chart.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid quadrantChart with title, axes, quadrants and points",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Quadrant Chart",
9 | "contents": "{{#mermaid:quadrantChart\n title Reach and engagement of campaigns\n x-axis Low Reach --> High Reach\n y-axis Low Engagement --> High Engagement\n quadrant-1 We should expand\n quadrant-2 Need to promote\n quadrant-3 Re-evaluate\n quadrant-4 May be improved\n Campaign A: [0.3, 0.6]\n Campaign B: [0.45, 0.23]\n Campaign C: [0.57, 0.69]\n Campaign D: [0.78, 0.34]\n Campaign E: [0.40, 0.34]\n Campaign F: [0.35, 0.78]\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid quadrantChart content with title, axes, quadrants and points",
16 | "subject": "Mermaid Test/Quadrant Chart",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"quadrantChart",
21 | "title Reach and engagement of campaigns",
22 | "x-axis Low Reach --> High Reach",
23 | "y-axis Low Engagement --> High Engagement",
24 | "quadrant-1 We should expand",
25 | "quadrant-2 Need to promote",
26 | "quadrant-3 Re-evaluate",
27 | "quadrant-4 May be improved",
28 | "Campaign A: [0.3, 0.6]",
29 | "Campaign F: [0.35, 0.78]"
30 | ]
31 | }
32 | }
33 | ],
34 | "settings": {
35 | "wgContLang": "en",
36 | "wgLang": "en"
37 | },
38 | "meta": {
39 | "version": "2",
40 | "is-incomplete": false,
41 | "debug": true
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-subgraphs.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid graph with subgraphs",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Subgraph Test",
9 | "contents": "{{#mermaid:graph TD\n subgraph ICT Department\n A1(\"Asset(s) received\")-->A2(Count and check that all items are
delivered according to delivery note)\n A2-->A3(\"Add non-consumable
asset(s) to asset registry\")\n A3-->A4(Store or re-distribute asset)\n end\n subgraph Stores\n A2-->B1(Generate GRV)\n end\n subgraph Sub-process\n A3-->C1(Insurance process)\n end\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid data-mermaid attribute content with subgraphs",
16 | "subject": "Mermaid Test/Subgraph Test",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"graph TD",
20 | "subgraph ICT Department",
21 | "A1",
22 | "Asset(s) received",
23 | "-->A2(Count and check that all items are<br>delivered according to delivery note)",
24 | "A2-->A3",
25 | "Add non-consumable<br>asset(s) to asset registry",
26 | "A3-->A4",
27 | "Store or re-distribute asset",
28 | "end",
29 | "subgraph Stores",
30 | "A2-->B1(Generate GRV)",
31 | "end",
32 | "subgraph Sub-process",
33 | "A3-->C1(Insurance process)"
34 | ]
35 | }
36 | }
37 | ],
38 | "settings": {
39 | "wgContLang": "en",
40 | "wgLang": "en"
41 | },
42 | "meta": {
43 | "version": "2",
44 | "is-incomplete": false,
45 | "debug": true
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 | workflow_dispatch:
9 |
10 | jobs:
11 |
12 | test:
13 |
14 | runs-on: ubuntu-22.04
15 | continue-on-error: ${{ matrix.experimental }}
16 |
17 | strategy:
18 | matrix:
19 | include:
20 | - mediawiki_version: '1.39'
21 | smw_version: '5.1.0'
22 | php_version: 8.1
23 | database_type: mysql
24 | database_image: "mariadb:11.2"
25 | coverage: false
26 | experimental: false
27 | - mediawiki_version: '1.43'
28 | smw_version: '6.0.1'
29 | php_version: 8.3
30 | database_type: mysql
31 | database_image: "mariadb:11.2"
32 | coverage: true
33 | experimental: false
34 |
35 | env:
36 | MW_VERSION: ${{ matrix.mediawiki_version }}
37 | SMW_VERSION: ${{ matrix.smw_version }}
38 | PHP_VERSION: ${{ matrix.php_version }}
39 | DB_TYPE: ${{ matrix.database_type }}
40 | DB_IMAGE: ${{ matrix.database_image }}
41 |
42 | steps:
43 | - name: Checkout
44 | uses: actions/checkout@v4
45 | with:
46 | submodules: recursive
47 |
48 | - name: Update submodules
49 | run: git submodule update --init --remote
50 |
51 | - name: Run tests
52 | run: make ci
53 | if: matrix.coverage == false
54 |
55 | - name: Run tests with coverage
56 | run: make ci-coverage
57 | if: matrix.coverage == true
58 |
59 | - name: Upload code coverage
60 | uses: codecov/codecov-action@v4
61 | with:
62 | token: ${{ secrets.CODECOV_TOKEN }}
63 | files: coverage/php/coverage.xml
64 | if: matrix.coverage == true
65 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-sequence-diagram-popus-menus.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid sequenceDiagram with actor popup menus (links)",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Sequence Diagram Actor Links",
9 | "contents": "{{#mermaid:sequenceDiagram\n participant Alice\n participant John\n link Alice: Dashboard @ https://dashboard.contoso.com/alice\n link Alice: Wiki @ https://wiki.contoso.com/alice\n link John: Dashboard @ https://dashboard.contoso.com/john\n link John: Wiki @ https://wiki.contoso.com/john\n Alice->>John: Hello John, how are you?\n John-->>Alice: Great!\n Alice-)John: See you later!\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid sequenceDiagram with actor popup menus links",
16 | "subject": "Mermaid Test/Sequence Diagram Actor Links",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"",
20 | ""content":"sequenceDiagram",
21 | "participant Alice",
22 | "participant John",
23 | "link Alice: Dashboard @ https:\\/\\/dashboard.contoso.com\\/alice",
24 | "link Alice: Wiki @ https:\\/\\/wiki.contoso.com\\/alice",
25 | "link John: Dashboard @ https:\\/\\/dashboard.contoso.com\\/john",
26 | "link John: Wiki @ https:\\/\\/wiki.contoso.com\\/john",
27 | "Alice->>John: Hello John, how are you?",
28 | "John-->>Alice: Great!",
29 | "Alice-)John: See you later!"
30 | ]
31 | }
32 | }
33 | ],
34 | "settings": {
35 | "wgContLang": "en",
36 | "wgLang": "en"
37 | },
38 | "meta": {
39 | "version": "2",
40 | "is-incomplete": false,
41 | "debug": true
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/docs/UPDATEMERMAID.md:
--------------------------------------------------------------------------------
1 | # Updating `mermaid` Library
2 |
3 | Starting from version 6.0.0, this extension uses a **Rollup-based bundling approach** to include both the `mermaid` library and extension-specific initialization code in a single bundled file (`mermaid.min.js`).
4 |
5 | This document is intended for **developers only**. Users should simply install a tagged release of the extension that already contains the bundled `mermaid.min.js`.
6 |
7 |
8 | ## How It Works
9 |
10 | After running `npm install`, the following occurs:
11 |
12 | 1. **Library Installation**
13 |
14 | The version of `mermaid` specified in `package.json` is installed into `node_modules`.
15 |
16 | 2. **Bundling via Rollup `rollup.config.mjs`**
17 |
18 | This file includes both the `mermaid` library and extension-specific initialization code to find and render Mermaid diagrams on the page using the global mermaid object.
19 |
20 | Rollup is configured to:
21 |
22 | - Bundle both mermaid and the extension code into a single output file (`resources/mermaid.min.js`)
23 | - Use the UMD format, so mermaid becomes available globally
24 | - Inline all dependencies (inlineDynamicImports: true)
25 | - Minify the output with terser
26 |
27 | This approach ensures that ResourceLoader can treat the final file as a single script without requiring multiple scripts or worrying about load order.
28 |
29 | ### To Update `mermaid` and `configMap`
30 |
31 | 1. Open `package.json` and change the version under `"mermaid"`
32 | (e.g., `"mermaid": "latest"` or a specific version like `"10.9.3"`).
33 |
34 | 2. Open `scripts/generateConfigMap.ts` and change the version under `"version"`
35 | (e.g., specific version like `"v10.9.3"` or `"mermaid@11.8.1"`, so it is important to be the same as here https://github.com/mermaid-js/mermaid/releases ).
36 |
37 | 3. Run:
38 |
39 | ```bash
40 | npm install
41 | ```
42 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mediawiki/mermaid",
3 | "type": "mediawiki-extension",
4 | "description": "Provides a parser function to generate diagrams and charts with the help of the mermaid script language",
5 | "keywords": [
6 | "mediawiki",
7 | "mermaid",
8 | "parser function"
9 | ],
10 | "homepage": "https://github.com/SemanticMediaWiki/Mermaid",
11 | "license": "GPL-2.0-or-later",
12 | "authors": [
13 | {
14 | "name": "James Hong Kong",
15 | "role": "Developer"
16 | },
17 | {
18 | "name": "Tyler Gibson",
19 | "role": "Developer"
20 | }
21 | ],
22 | "require": {
23 | "php": ">=7.4",
24 | "composer/installers": "^2.2.0|^1.0.1"
25 | },
26 | "require-dev": {
27 | "mediawiki/mediawiki-codesniffer": "43.0.0",
28 | "mediawiki/mediawiki-phan-config": "0.14.0",
29 | "mediawiki/minus-x": "1.1.3",
30 | "php-parallel-lint/php-console-highlighter": "1.0.0",
31 | "php-parallel-lint/php-parallel-lint": "1.4.0"
32 | },
33 | "extra": {
34 | "branch-alias": {
35 | "dev-master": "4.x-dev"
36 | }
37 | },
38 | "config": {
39 | "process-timeout": 0,
40 | "allow-plugins": {
41 | "composer/installers": true,
42 | "dealerdirect/phpcodesniffer-composer-installer": true
43 | }
44 | },
45 | "scripts":{
46 | "test": [
47 | "@analyze",
48 | "@phpunit"
49 | ],
50 | "test-coverage": [
51 | "@analyze",
52 | "@phpunit-coverage"
53 | ],
54 | "analyze": [
55 | "@lint",
56 | "@phpcs"
57 | ],
58 | "fix": [
59 | "@phpcs-fix"
60 | ],
61 | "lint": "parallel-lint . --exclude vendor --exclude node_modules",
62 | "phpcs": "phpcs -ps",
63 | "phpcs-fix": "phpcbf -p",
64 | "phpunit": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist --testdox",
65 | "phpunit-coverage": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist --testdox --coverage-text --coverage-html coverage/php --coverage-clover coverage/php/coverage.xml",
66 | "minus-x": "minus-x check ."
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/docs/INSTALL.md:
--------------------------------------------------------------------------------
1 | This file contains the *installation and configuration instructions* for the **Mermaid** extension.
2 | See also the [readme], the [release notes] and [usage examples].
3 |
4 | ## Installation
5 |
6 | The recommended way to install this extension is using [Composer](http://getcomposer.org) with
7 | [MediaWiki's built-in support for Composer](https://www.mediawiki.org/wiki/Composer).
8 |
9 | ### Step 1
10 |
11 | If you do not have a "composer.local.json" file yet, create one and add the following content to it:
12 |
13 | ```
14 | {
15 | "require": {
16 | "mediawiki/mermaid": "~6.0.1"
17 | }
18 | }
19 | ```
20 |
21 | If you already have a "composer.local.json" file add the following line to the end of the "require"
22 | section in your file:
23 |
24 | "mediawiki/mermaid": "~6.0.1"
25 |
26 | Remember to add a comma to the end of the preceding line in this section.
27 |
28 | ### Step 2
29 |
30 | Run the following command in your shell:
31 |
32 | php composer.phar update --no-dev
33 |
34 | ### Step 3
35 |
36 | Add the following line to the end of your "LocalSettings.php" file:
37 |
38 | wfLoadExtension( 'Mermaid' );
39 |
40 |
41 | ## Configuration
42 |
43 | One configuration parameter is provided allowing to choose the basic theme for rendering diagrams and charts.
44 | By default the rendering is set to use the `forest` theme:
45 |
46 | $mermaidgDefaultTheme = 'forest';
47 |
48 | If one would like to use one of the other themes provided (`default`, `neutral` or `dark`) the configuration
49 | parameter can be set to it after invoking the extension, e.g.:
50 |
51 | wfLoadExtension( 'Mermaid' );
52 | $mermaidgDefaultTheme = 'neutral';
53 |
54 | [readme]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/README.md
55 | [release notes]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/RELEASE-NOTES.md
56 | [usage examples]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/USAGE.md
57 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-wide-graph-horizontal-scroll.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid wide graph with horizontal scroll config",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/Wide Graph",
9 | "contents": "{{#mermaid:graph LR;\nA[\"This is a very wide box\"]\nB[\"This is a very wide box\"]\nC[\"This is a very wide box\"]\nD[\"This is a very wide box\"]\nE[\"This is a very wide box\"]\nF[\"This is a very wide box\"]\nG[\"This is a very wide box\"]\nH[\"This is a very wide box\"]\nI[\"This is a very wide box\"]\nJ[\"This is a very wide box\"]\nA-->B\nB-->C\nC-->D\nD-->E\nE-->F\nF-->G\nG-->H\nH-->I\nI-->J\n|\nconfig.flowchart.useMaxWidth = false\n}}"
10 | }
11 | ],
12 | "tests": [
13 | {
14 | "type": "parser",
15 | "about": "Check Mermaid wide graph content and config",
16 | "subject": "Mermaid Test/Wide Graph",
17 | "assert-output": {
18 | "to-contain": [
19 | "data-mermaid=\"{"content":"graph LR;",
20 | "A",
21 | "This is a very wide box",
22 | "B",
23 | "This is a very wide box",
24 | "C",
25 | "This is a very wide box",
26 | "D",
27 | "This is a very wide box",
28 | "E",
29 | "This is a very wide box",
30 | "F",
31 | "This is a very wide box",
32 | "G",
33 | "This is a very wide box",
34 | "H",
35 | "This is a very wide box",
36 | "I",
37 | "This is a very wide box",
38 | "J",
39 | "This is a very wide box",
40 | "A-->B",
41 | "B-->C",
42 | "C-->D",
43 | "D-->E",
44 | "E-->F"
45 | ]
46 | }
47 | }
48 | ],
49 | "settings": {
50 | "wgContLang": "en",
51 | "wgLang": "en"
52 | },
53 | "meta": {
54 | "version": "2",
55 | "is-incomplete": false,
56 | "debug": true
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/JsonTestCaseScriptRunnerTest.php:
--------------------------------------------------------------------------------
1 | getParser();
22 | Hooks::onParserFirstCallInit( $parser );
23 | }
24 |
25 | protected function getTestCaseLocation() {
26 | return __DIR__ . '/TestCases';
27 | }
28 |
29 | protected function getPermittedSettings() {
30 | return array_merge( parent::getPermittedSettings(), [] );
31 | }
32 |
33 | /**
34 | * @see JsonTestCaseScriptRunner::getDependencyDefinitions
35 | *
36 | * @return array
37 | */
38 | protected function getDependencyDefinitions() {
39 | return [
40 | 'Mermaid' => [ $this, 'checkMermaidDependency' ]
41 | ];
42 | }
43 |
44 | public function checkMermaidDependency( $val, &$reason ) {
45 | if ( !ExtensionRegistry::getInstance()->isLoaded( 'Mermaid' ) ) {
46 | $reason = "Dependency: Mermaid as requirement is not available!";
47 | return false;
48 | }
49 |
50 | // Match operator and version
51 | if ( !preg_match( '/^(>=|<=|>|<|==)?\s*(.+)$/', $val, $matches ) ) {
52 | $reason = "Dependency: Invalid Mermaid version requirement format: '$val'";
53 | return false;
54 | }
55 |
56 | $compare = $matches[1] ?: '==';
57 | $requiredVersion = $matches[2];
58 |
59 | $version = ExtensionRegistry::getInstance()->getAllThings()['Mermaid']['version'] ?? '0.0.0';
60 |
61 | if ( !version_compare( $version, $requiredVersion, $compare ) ) {
62 | $reason = "Dependency: Required version of Mermaid ($requiredVersion $compare $version) is not available!";
63 | return false;
64 | }
65 |
66 | return true;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/resources/ext.mermaid.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @file
3 | * @ingroup SMW
4 | *
5 | * @licence GNU GPL v2+
6 | * @author mwjames
7 | */
8 |
9 | /*global mediaWiki, mermaid */
10 | /*jslint white: true */
11 |
12 | import mermaid from 'mermaid';
13 | window.mermaid = mermaid;
14 |
15 | const generateString = (length) =>
16 | Array(length)
17 | .fill("")
18 | .map(() => Math.random().toString(36).charAt(2))
19 | .join("");
20 |
21 | function decodeHtmlEntities(str) {
22 | const textarea = document.createElement('textarea');
23 | textarea.innerHTML = str;
24 | return textarea.value;
25 | }
26 |
27 | async function initMermaid() {
28 | if (typeof mermaid === 'undefined') {
29 | console.error('[Mermaid] Global "mermaid" object not found.');
30 | return;
31 | }
32 |
33 | const items = document.querySelectorAll('.ext-mermaid');
34 | await Promise.all(Array.from(items).map(async (item, index) => {
35 | const id = 'ext-mermaid-' + generateString(8) + '-' + index;
36 |
37 | let data;
38 | try {
39 | data = typeof item.dataset.mermaid === 'string'
40 | ? JSON.parse(item.dataset.mermaid)
41 | : {};
42 | } catch (e) {
43 | console.error('[Mermaid] Failed to parse data-mermaid:', e);
44 | return;
45 | }
46 |
47 | if (!data.content || typeof data.content !== 'string') {
48 | console.error('[Mermaid] No diagram content provided.');
49 | return;
50 | }
51 |
52 | // Hide loading animation (dots)
53 | const dots = item.children[0];
54 | if (dots) dots.style.display = 'none';
55 |
56 | try {
57 | mermaid.initialize({
58 | securityLevel: 'loose',
59 | ...data.config
60 | });
61 | const { svg, bindFunctions } = await mermaid.render(id + '-svg', decodeHtmlEntities(data.content));
62 | const graph = document.createElement('div');
63 | graph.id = id;
64 | graph.innerHTML = svg;
65 | item.appendChild(graph);
66 | bindFunctions?.(graph);
67 | } catch (e) {
68 | console.error(`[Mermaid] Failed to render diagram with id=${id}:`, e);
69 | }
70 | }));
71 | }
72 |
73 | initMermaid();
74 |
--------------------------------------------------------------------------------
/.phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | .
29 | /(vendor|conf)/
30 | extensions/*
31 |
32 |
33 |
--------------------------------------------------------------------------------
/resources/styles/ext.mermaid.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * @file
3 | * @ingroup SMW
4 | *
5 | * @licence GNU GPL v2+
6 | * @author mwjames
7 | */
8 | .mermaid-dots {
9 | background: url('data:image/gif;base64,R0lGODlhIgAUAMQRAOjp6dTW19ze3+Xm54iKjevs7IKEh/f396Olp5ianPz8/Judn9fY2YGDhp+ho4CChdHT1P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxRThFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNkVFNURCOUIyREYxMUUyQTBEQUNFNUIzREVGNjg0MyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNkVFNURCOEIyREYxMUUyQTBEQUNFNUIzREVGNjg0MyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyMDhFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxRThFNDZFQ0RFQjJFMjExQUZCNUREQjU1MEFCRTI5OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAkyABEALAAAAAAiABQAAAVeYCSOZGmeaKqubOu+cCzPdM0iBIGYgCAUPB8Q5XgYHw4SAMKEAJRNJ8pwfBhIgagAq0U1qg1ukyFmkk+L6oI0iD5H7ebbdEgYEweSYhAIDEp7fX82hIWGh4iJiosoIQAh+QQJMgARACwAAAAAIgAUAAAFZGAkjmRpnmiqrmzrvnAsz3TNFoIAmAhBICZArpACQI6Q3cjxaD4cJCNSaRIgIQGSwfkwkAJXAYpxzY4a3Mb3ykBJjwPSgrsgDa5U0yAQGChIBwlNCQckCnt9NoqLjI2Oj5CRKSEAIfkEBTIAEQAsAAAAACIAFAAABWNgJI5kaZ5oqq5s675wLM90zRaCAJi4biIEAiIFgBghu1HxmBQ5HtCHAyU4QgKk6hE7MkQfBhTDyhWNt6TGt4FaGgckNwQ+WnwXqUEgMFCU9Hx+IwcJUAkHNomKi4yNjo+QKCEAOw==') no-repeat left center;
10 | padding: 5px 0 5px 35px;
11 | vertical-align: middle;
12 | }
13 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/I18nJsonFileIntegrityTest.php:
--------------------------------------------------------------------------------
1 | assertIsArray(
23 | json_decode( $contents, true ),
24 | 'Failed with ' . $this->getDescriptiveJsonError( json_last_error() ) . ' in ' . $file
25 | );
26 | }
27 |
28 | public function i18nFileProvider() {
29 | $extensionRoot = __DIR__ . '/../../..';
30 | $extensionJsonPath = $extensionRoot . '/extension.json';
31 |
32 | $configContent = file_get_contents( $extensionJsonPath );
33 | $config = json_decode( $configContent );
34 | $provider = array();
35 |
36 | $files = $this->findFilesForExtension(
37 | $config->MessagesDirs->Mermaid[0],
38 | 'json'
39 | );
40 |
41 | foreach ( $files as $file ) {
42 | $provider[] = array( $file );
43 | }
44 |
45 | return $provider;
46 | }
47 |
48 | private function findFilesForExtension( $path, $extension ) {
49 | $files = array();
50 |
51 | $directoryIterator = new \RecursiveDirectoryIterator(
52 | str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $path )
53 | );
54 |
55 | foreach ( new \RecursiveIteratorIterator( $directoryIterator ) as $fileInfo ) {
56 | if ( strtolower( substr( $fileInfo->getFilename(), -( strlen( $extension ) + 1 ) ) ) === ( '.' . $extension ) ) {
57 | $files[$fileInfo->getFilename()] = $fileInfo->getPathname();
58 | }
59 | }
60 |
61 | return $files;
62 | }
63 |
64 | private function getDescriptiveJsonError( $errorCode ) {
65 | $errorMessages = array(
66 | JSON_ERROR_NONE => '',
67 | JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch, malformed JSON',
68 | JSON_ERROR_CTRL_CHAR => 'Unexpected control character found, possibly incorrectly encoded',
69 | JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
70 | JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
71 | JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded'
72 | );
73 |
74 | return $errorMessages[$errorCode];
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/MermaidParserFunction.php:
--------------------------------------------------------------------------------
1 | parser = $parser;
39 | $this->config = $config;
40 | $this->paramExtractor = $mermaidConfigExtractor;
41 | }
42 |
43 | /**
44 | * @param Parser $parser
45 | * @return callable
46 | * @since 1.1
47 | *
48 | */
49 | public static function onParserFunction( Parser $parser ) {
50 | $config = MediaWikiServices::getInstance()->getService( 'Mermaid.Config' );
51 | $paramExtractor = MediaWikiServices::getInstance()->getService( 'Mermaid.MermaidConfigExtractor' );
52 |
53 | $function = new self( $parser, $config, $paramExtractor );
54 | return $function->parse( func_get_args() );
55 | }
56 |
57 | /**
58 | * @param array $params
59 | * @return string
60 | * @since 1.0
61 | *
62 | */
63 | public function parse( array $params ) {
64 | $class = 'ext-mermaid';
65 | $parserOutput = $this->parser->getOutput();
66 | if ( isset( $params[0] ) && $params[0] instanceof \Parser ) {
67 | array_shift( $params );
68 | }
69 |
70 | // Signal the OutputPageParserOutput hook
71 | $parserOutput->setExtensionData( 'ext-mermaid', true );
72 | $parserOutput->addModules( [ 'ext.mermaid' ] );
73 |
74 | $graphConfig = [
75 | 'theme' => $this->config->getDefaultTheme()
76 | ];
77 |
78 | list( $mermaidConfig, $mwParams ) = $this->paramExtractor->extract( $params );
79 |
80 | $content = implode( "|", $mwParams );
81 | $graphConfig = array_merge( $graphConfig, $mermaidConfig );
82 |
83 | if ( class_exists( 'MediaWiki\\Html\\Html' ) ) {
84 | // MW 1.40+
85 | $htmlClass = \MediaWiki\Html\Html::class;
86 | } else {
87 | $htmlClass = \Html::class;
88 | }
89 | return $htmlClass::rawElement(
90 | 'div',
91 | [
92 | 'class' => $class,
93 | 'data-mermaid' => json_encode(
94 | [
95 | 'content' => htmlspecialchars( $content ),
96 | 'config' => $graphConfig
97 | ]
98 | )
99 | ],
100 | $htmlClass::rawElement(
101 | 'div',
102 | [
103 | 'class' => 'mermaid-dots',
104 | ]
105 | )
106 | );
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-state-diagram-composite-states.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid stateDiagram-v2 with composite states",
3 | "requires": {
4 | "Mermaid": ">=2.0"
5 | },
6 | "setup": [
7 | {
8 | "page": "Mermaid Test/State Diagram Composite States",
9 | "contents": "{{#mermaid:stateDiagram-v2\n [*] --> First\n state First {\n [*] --> second\n second --> [*]\n }\n\n [*] --> NamedComposite\n NamedComposite: Another Composite\n state NamedComposite {\n [*] --> namedSimple\n namedSimple --> [*]\n namedSimple: Another simple\n }\n}}"
10 | },
11 | {
12 | "page": "Mermaid Test/State Diagram Nested 3 Levels",
13 | "contents": "{{#mermaid:stateDiagram-v2\n [*] --> First\n\n state First {\n [*] --> Second\n\n state Second {\n [*] --> second\n second --> Third\n\n state Third {\n [*] --> third\n third --> [*]\n }\n }\n }\n}}"
14 | }
15 | ],
16 | "tests": [
17 | {
18 | "type": "parser",
19 | "about": "Check Mermaid stateDiagram-v2 with composite and named states",
20 | "subject": "Mermaid Test/State Diagram Composite States",
21 | "assert-output": {
22 | "to-contain": [
23 | "data-mermaid=\"",
24 | ""content":"stateDiagram-v2",
25 | "[*] --> First",
26 | "state First {",
27 | "[*] --> second",
28 | "second --> [*]",
29 | "[*] --> NamedComposite",
30 | "NamedComposite: Another Composite",
31 | "state NamedComposite {",
32 | "[*] --> namedSimple",
33 | "namedSimple --> [*]",
34 | "namedSimple: Another simple"
35 | ]
36 | }
37 | },
38 | {
39 | "type": "parser",
40 | "about": "Check output of deeply nested stateDiagram-v2",
41 | "subject": "Mermaid Test/State Diagram Nested 3 Levels",
42 | "assert-output": {
43 | "to-contain": [
44 | "data-mermaid=\"",
45 | ""content":"stateDiagram-v2",
46 | "[*] --> First",
47 | "state First {",
48 | "[*] --> Second",
49 | "state Second {",
50 | "[*] --> second",
51 | "second --> Third",
52 | "state Third {",
53 | "[*] --> third",
54 | "third --> [*]"
55 | ]
56 | }
57 | }
58 | ],
59 | "settings": {
60 | "wgContLang": "en",
61 | "wgLang": "en"
62 | },
63 | "meta": {
64 | "version": "2",
65 | "is-incomplete": false,
66 | "debug": true
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mermaid
2 | [](https://github.com/SemanticMediaWiki/Mermaid/actions/workflows/ci.yml)
3 | [](https://codecov.io/gh/SemanticMediaWiki/Mermaid)
4 | [](https://packagist.org/packages/mediawiki/mermaid)
5 | [](https://packagist.org/packages/mediawiki/mermaid)
6 |
7 | This extension provides the `#mermaid` parser function to support the generation of diagrams and flowcharts with the help of the [mermaid][mermaid] script language. Supported diagram forms include:
8 |
9 | - Flowchart
10 | - Sequence Diagram
11 | - Class Diagram
12 | - State Diagram
13 | - Gantt Chart
14 | - Pie Chart
15 | - Entity Relationship Diagram
16 | - Git Flow Chart
17 | - User Journey Chart
18 | - Quadrant Chart
19 | - Requirement Diagram
20 | - C4 Diagram
21 | - Timeline Diagram
22 | - Sankey Diagram
23 | - XY Chart
24 | - Block Diagram
25 |
26 | ## Requirements
27 |
28 | Requirements for Mermaid 6.x:
29 |
30 | - PHP 7.4 or later
31 | - MediaWiki 1.39 or later
32 |
33 | You can use an older version of Mermaid for older versions of MediaWiki and/or PHP.
34 |
35 | ## Installation and configuration
36 |
37 | See the information on [installing and configuring] this extension.
38 |
39 | ## Usage
40 |
41 | See the information on [using] this extension.
42 |
43 | ## Contribution and support
44 |
45 | If you want to contribute work to the project please subscribe to the developers mailing list and
46 | have a look at the contribution guideline.
47 |
48 | * [File an issue](https://github.com/SemanticMediaWiki/Mermaid/issues)
49 | * [Submit a pull request](https://github.com/SemanticMediaWiki/Mermaid/pulls)
50 | * Ask a question on [the mailing list](https://www.semantic-mediawiki.org/wiki/Mailing_list)
51 |
52 | ## For developers
53 |
54 | See the documention on how to [update MermaidJS](https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/UPDATEMERMAID.md).
55 |
56 | ## Tests
57 |
58 | This extension provides unit and integration tests that are run by a [continues integration platform][travis]
59 | but can also be executed using `composer phpunit` from the extension base directory.
60 |
61 | ## License
62 |
63 | [GNU General Public License, version 2 or later][gpl-licence].
64 |
65 | [gpl-licence]: https://www.gnu.org/copyleft/gpl.html
66 | [travis]: https://travis-ci.org/SemanticMediaWiki/Mermaid
67 | [smw]: https://github.com/SemanticMediaWiki/SemanticMediaWiki
68 | [composer]: https://getcomposer.org/
69 | [mermaid]: https://github.com/knsv/mermaid
70 | [installing and configuring]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/INSTALL.md
71 | [using]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/USAGE.md
72 |
73 |
--------------------------------------------------------------------------------
/tests/phpunit/Integration/JSONScript/TestCases/parser-c4-context-diagram.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Test Mermaid C4Context diagram",
3 | "setup": [
4 | {
5 | "page": "Mermaid Test/C4 Context Test",
6 | "contents": "{{#mermaid:\nC4Context\n title System Context diagram for Internet Banking System\n Enterprise_Boundary(b0, \"BankBoundary0\") {\n Person(customerA, \"Banking Customer A\", \"A customer of the bank, with personal bank accounts.\")\n Person(customerB, \"Banking Customer B\")\n Person_Ext(customerC, \"Banking Customer C\", \"desc\")\n\n Person(customerD, \"Banking Customer D\", \"A customer of the bank,
with personal bank accounts.\")\n\n System(SystemAA, \"Internet Banking System\", \"Allows customers to view information about their bank accounts, and make payments.\")\n\n Enterprise_Boundary(b1, \"BankBoundary\") {\n\n SystemDb_Ext(SystemE, \"Mainframe Banking System\", \"Stores all of the core banking information about customers, accounts, transactions, etc.\")\n\n System_Boundary(b2, \"BankBoundary2\") {\n System(SystemA, \"Banking System A\")\n System(SystemB, \"Banking System B\", \"A system of the bank, with personal bank accounts. next line.\")\n }\n\n System_Ext(SystemC, \"E-mail system\", \"The internal Microsoft Exchange e-mail system.\")\n SystemDb(SystemD, \"Banking System D Database\", \"A system of the bank, with personal bank accounts.\")\n\n Boundary(b3, \"BankBoundary3\", \"boundary\") {\n SystemQueue(SystemF, \"Banking System F Queue\", \"A system of the bank.\")\n SystemQueue_Ext(SystemG, \"Banking System G Queue\", \"A system of the bank, with personal bank accounts.\")\n }\n }\n }\n\n BiRel(customerA, SystemAA, \"Uses\")\n BiRel(SystemAA, SystemE, \"Uses\")\n Rel(SystemAA, SystemC, \"Sends e-mails\", \"SMTP\")\n Rel(SystemC, customerA, \"Sends e-mails to\")\n\n UpdateElementStyle(customerA, $fontColor=\"red\", $bgColor=\"grey\", $borderColor=\"red\")\n UpdateRelStyle(customerA, SystemAA, $textColor=\"blue\", $lineColor=\"blue\", $offsetX=\"5\")\n UpdateRelStyle(SystemAA, SystemE, $textColor=\"blue\", $lineColor=\"blue\", $offsetY=\"-10\")\n UpdateRelStyle(SystemAA, SystemC, $textColor=\"blue\", $lineColor=\"blue\", $offsetY=\"-40\", $offsetX=\"-50\")\n UpdateRelStyle(SystemC, customerA, $textColor=\"red\", $lineColor=\"red\", $offsetX=\"-50\", $offsetY=\"20\")\n\n UpdateLayoutConfig($c4ShapeInRow=\"3\", $c4BoundaryInRow=\"1\")\n}}"
7 | }
8 | ],
9 | "tests": [
10 | {
11 | "type": "parser",
12 | "about": "Check Mermaid C4Context data-mermaid attribute content",
13 | "subject": "Mermaid Test/C4 Context Test",
14 | "assert-output": {
15 | "to-contain": [
16 | "data-mermaid=\"{"content":"C4Context",
17 | "Enterprise_Boundary(b0",
18 | "Person(customerA",
19 | "System(SystemAA",
20 | "Rel(SystemAA, SystemC, "Sends e-mails"",
21 | "UpdateElementStyle(customerA",
22 | "UpdateLayoutConfig"
23 | ]
24 | }
25 | }
26 | ],
27 | "settings": {
28 | "wgContLang": "en",
29 | "wgLang": "en"
30 | },
31 | "meta": {
32 | "version": "2",
33 | "is-incomplete": false,
34 | "debug": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/phpunit/Unit/MermaidParserFunctionTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder( '\Parser' )
19 | ->disableOriginalConstructor()
20 | ->getMock();
21 |
22 | $config = $this->getMockConfig();
23 |
24 | $mermaidConfig = $this->getMockBuilder( '\Mermaid\MermaidConfigExtractor' )
25 | ->disableOriginalConstructor()
26 | ->getMock();
27 |
28 | $this->assertInstanceOf(
29 | MermaidParserFunction::class,
30 | new MermaidParserFunction( $parser, $config, $mermaidConfig )
31 | );
32 | }
33 |
34 | /**
35 | * @dataProvider textProvider
36 | */
37 | public function testParse( $text, $expected ) {
38 | $parserOutput = $this->getMockBuilder( '\ParserOutput' )
39 | ->disableOriginalConstructor()
40 | ->getMock();
41 |
42 | $parserOutput->expects( $this->once() )
43 | ->method( 'setExtensionData' )
44 | ->with(
45 | $this->equalTo( 'ext-mermaid' ),
46 | $this->equalTo( true ) );
47 |
48 | $parser = $this->createMock( '\Parser' );
49 |
50 | $parser->expects( $this->any() )
51 | ->method( 'getOutput' )
52 | ->will( $this->returnValue( $parserOutput ) );
53 |
54 | $mockConfig = $this->getMockConfig();
55 | $mockExtractor = $this->getMockConfigExtractor();
56 |
57 | $instance = new MermaidParserFunction(
58 | $parser,
59 | $mockConfig,
60 | $mockExtractor
61 | );
62 |
63 | $this->assertStringContainsStringIgnoringCase(
64 | $expected,
65 | $instance->parse( $text )
66 | );
67 | }
68 |
69 | public function textProvider() {
70 | yield [
71 | [ 'sequenceDiagram...', 'config.theme=foo' ],
72 | ''
73 | ];
74 |
75 | // [ ... ]
76 | yield [
77 | [ 'sequenceDiagram id1["This is the (text) in the box"]', 'config.theme=foo' ],
78 | ''
79 | ];
80 |
81 | // |
82 | yield [
83 | [ 'A[Hard edge] -->|Link text| B(Round edge)' ],
84 | ''
85 | ];
86 |
87 | yield [
88 | [ 'graph LR;', 'config.theme=foo', 'config.flowchart.curve=basis' ],
89 | ''
90 | ];
91 |
92 | yield [
93 | [ 'graph LR;', 'config.theme=foo', 'config.flowchart.useMaxWidth=false' ],
94 | ''
95 | ];
96 |
97 | }
98 |
99 | protected function getMockConfig() {
100 | $configMock = $this->createMock( '\Mermaid\Config' );
101 |
102 | $configMock->method( 'getDefaultTheme' )->willReturn( 'forest' );
103 |
104 | return $configMock;
105 | }
106 |
107 | protected function getMockConfigExtractor() {
108 | $valueMap = TestingConsts::EXTRACTOR_VALUE_MAP;
109 |
110 | $extractorMock = $this->createMock( '\Mermaid\MermaidConfigExtractor' );
111 |
112 | $extractorMock->method( 'extract' )->will( $this->returnValueMap( $valueMap ) );
113 |
114 | return $extractorMock;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/tests/phpunit/Unit/TestingConsts.php:
--------------------------------------------------------------------------------
1 | 'foo' ], [ 'sequenceDiagram...' ] ],
10 | ],
11 | [
12 | [ 'sequenceDiagram id1["This is the (text) in the box"]', 'config.theme=foo' ],
13 | [ [ 'theme' => 'foo' ], [ 'sequenceDiagram id1["This is the (text) in the box"]' ] ],
14 | ],
15 | [
16 | [ 'A[Hard edge] -->|Link text| B(Round edge)' ],
17 | [ [], [ 'A[Hard edge] -->|Link text| B(Round edge)' ] ],
18 | ],
19 | [
20 | [ 'graph LR;', 'config.theme=foo', 'config.flowchart.curve=basis' ],
21 | [ [ 'theme' => 'foo', 'flowchart' => [ 'curve' => 'basis' ] ], [ 'graph LR;' ] ],
22 | ],
23 | [
24 | [ 'graph LR;', 'config.theme=foo', 'config.flowchart.useMaxWidth=false' ],
25 | [ [ 'theme' => 'foo' ], [ 'graph LR;', 'config.flowchart.useMaxWidth=false' ] ],
26 | ],
27 | [
28 | [ 'config.gantt.titleTopMargin=40', 'gantt title A Gantt Diagram' ],
29 | [ [ 'gantt' => [ 'titleTopMargin' => '40' ] ], [ 'gantt title A Gantt Diagram' ] ],
30 | ],
31 | [
32 | [
33 | 'sequenceDiagram;',
34 | 'config.theme=dark',
35 | 'config.flowchart.htmlLabels=true',
36 | 'config.gantt.topAxis=false',
37 | 'config.sequence.actorMargin=25',
38 | 'config.sankey.showValues=true',
39 | ],
40 | [
41 | [
42 | 'theme' => 'dark',
43 | 'flowchart' => [ 'htmlLabels' => true ],
44 | 'gantt' => [ 'topAxis' => false ],
45 | 'sequence' => [ 'actorMargin' => '25' ],
46 | 'sankey' => [ 'showValues' => true ],
47 | ],
48 | [ 'sequenceDiagram;' ],
49 | ],
50 | ],
51 | [
52 | [
53 | 'graph TD;',
54 | 'config.c4.componentFontSize=14',
55 | 'config.c4.wrap=true',
56 | 'config.c4.component_border_color=#000000',
57 | ],
58 | [
59 | [
60 | 'c4' => [
61 | 'componentFontSize' => '14',
62 | 'wrap' => true,
63 | 'component_border_color' => '#000000',
64 | ],
65 | ],
66 | [ 'graph TD;' ],
67 | ],
68 | ],
69 | [
70 | [
71 | 'flowchart;',
72 | 'config.flowchart.arrowMarkerAbsolute=true',
73 | 'config.flowchart.padding=15',
74 | 'config.flowchart.wrappingWidth=300',
75 | ],
76 | [
77 | [
78 | 'flowchart' => [
79 | 'arrowMarkerAbsolute' => true,
80 | 'padding' => '15',
81 | 'wrappingWidth' => '300',
82 | ],
83 | ],
84 | [ 'flowchart;' ],
85 | ],
86 | ],
87 | [
88 | [
89 | 'stateDiagram;',
90 | 'config.state.arrowMarkerAbsolute=false',
91 | 'config.state.fontSize=16',
92 | 'config.state.titleTopMargin=30',
93 | ],
94 | [
95 | [
96 | 'state' => [
97 | 'arrowMarkerAbsolute' => false,
98 | 'fontSize' => '16',
99 | 'titleTopMargin' => '30',
100 | ],
101 | ],
102 | [ 'stateDiagram;' ],
103 | ],
104 | ],
105 | [
106 | [
107 | 'sequenceDiagram;',
108 | 'config.sequence.mirrorActors=true',
109 | 'config.sequence.forceMenus=false',
110 | 'config.sequence.showSequenceNumbers=true',
111 | ],
112 | [
113 | [
114 | 'sequence' => [
115 | 'mirrorActors' => true,
116 | 'forceMenus' => false,
117 | 'showSequenceNumbers' => true,
118 | ],
119 | ],
120 | [ 'sequenceDiagram;' ],
121 | ],
122 | ],
123 | [
124 | [
125 | 'timeline;',
126 | 'config.timeline.activationWidth=120',
127 | 'config.timeline.disableMulticolor=true',
128 | 'config.timeline.rightAngles=false',
129 | 'config.timeline.taskFontSize=14',
130 | 'config.timeline.width=600',
131 | ],
132 | [
133 | [
134 | 'timeline' => [
135 | 'activationWidth' => '120',
136 | 'disableMulticolor' => true,
137 | 'rightAngles' => false,
138 | 'taskFontSize' => '14',
139 | 'width' => '600',
140 | ],
141 | ],
142 | [ 'timeline;' ],
143 | ],
144 | ],
145 | [
146 | [
147 | 'xyChart;',
148 | 'config.xyChart.chartOrientation=horizontal',
149 | 'config.xyChart.showTitle=true',
150 | 'config.xyChart.titleFontSize=18',
151 | 'config.xyChart.width=800',
152 | 'config.xyChart.xAxis.showAxisLine=true',
153 | 'config.xyChart.xAxis.showLabel=false',
154 | 'config.xyChart.xAxis.tickLength=10',
155 | 'config.xyChart.yAxis.showTitle=true',
156 | 'config.xyChart.yAxis.tickWidth=2',
157 | ],
158 | [
159 | [
160 | 'xyChart' => [
161 | 'chartOrientation' => 'horizontal',
162 | 'showTitle' => true,
163 | 'titleFontSize' => '18',
164 | 'width' => '800',
165 | 'xAxis' => [
166 | 'showAxisLine' => true,
167 | 'showLabel' => false,
168 | 'tickLength' => '10',
169 | ],
170 | 'yAxis' => [
171 | 'showTitle' => true,
172 | 'tickWidth' => '2',
173 | ],
174 | ],
175 | ],
176 | [ 'xyChart;' ],
177 | ],
178 | ],
179 | [
180 | [
181 | 'xyChart;',
182 | 'config.xyChart.height=400',
183 | 'config.xyChart.plotReservedSpacePercent=15',
184 | 'config.xyChart.xAxis.labelFontSize=12',
185 | 'config.xyChart.xAxis.showTick=false',
186 | 'config.xyChart.yAxis.labelPadding=8',
187 | 'config.xyChart.yAxis.showAxisLine=false',
188 | ],
189 | [
190 | [
191 | 'xyChart' => [
192 | 'height' => '400',
193 | 'plotReservedSpacePercent' => '15',
194 | 'xAxis' => [
195 | 'labelFontSize' => '12',
196 | 'showTick' => false,
197 | ],
198 | 'yAxis' => [
199 | 'labelPadding' => '8',
200 | 'showAxisLine' => false,
201 | ],
202 | ],
203 | ],
204 | [ 'xyChart;' ],
205 | ],
206 | ],
207 | ];
208 | }
209 |
--------------------------------------------------------------------------------
/docs/RELEASE-NOTES.md:
--------------------------------------------------------------------------------
1 | This file contains the *release notes* of the **Mermaid** extension. See also the
2 | [readme], the [installation and configuration information], and [usage examples].
3 |
4 | ### 6.0.2
5 |
6 | Released October 31, 2025.
7 |
8 | * Upgraded Mermaid.js to version 10.9.4.
9 | * Add support for MediaWiki 1.44
10 | * Translation updates from https://translatewiki.net
11 |
12 | ### 6.0.1
13 |
14 | Released July 9, 2025.
15 |
16 | The `$configMap` is now automatically generated from the `Mermaid.js` source, grouped, and type-aware.
17 |
18 | * Fetches and parses `config.type.ts` from Mermaid.js v10.9.3
19 | * Recursively extracts all config properties, including nested interfaces, into a flat dot-notation map
20 | * Detects boolean properties and assigns FILTER_VALIDATE_BOOLEAN for correct PHP typing
21 | * Groups configuration keys by diagram prefix (e.g., flowchart, gantt, sequence) with comment headers in the PHP array
22 | * Automatically updates `src/MermaidConfigExtractor.php` by replacing the `$configMap` block in-place
23 | * Eliminates manual syncing and reduces the risk of human error or outdated configs
24 | * Improves clarity and maintainability of the config structure
25 | * Adds more test cases for different types of config keys
26 | * Simplifies future Mermaid.js upgrades: update the version in `scripts/generateConfigMap.ts` and regenerate
27 | * steps how to update `configMap` added to `docs/UPDATEMERMAID.md`
28 |
29 | ### 6.0.0
30 |
31 | Released July 7, 2025.
32 |
33 | * Upgraded Mermaid.js to version 10.9.3.
34 | * Updated configMap to align with the official Mermaid.js v10.9.3 configuration.
35 | * Switched from multiple separate script files to a single bundled file using Rollup, improving load performance and simplifying ResourceLoader configuration.
36 | * Refactored initialization code: Mermaid library and extension-specific logic are now bundled together in mermaid.min.js.
37 | * Removed the need for explicit script load ordering by using a single packageFiles entry.
38 | * Dropped usage of global Mermaid variable exposure; now using ES module import internally and UMD bundle output.
39 | * Simplified extension configuration and improved maintainability by consolidating scripts.
40 | * Added more JSONScript test cases.
41 | * Ensured all existing tests pass successfully with the new bundling approach and Mermaid version.
42 |
43 | ### 5.0.2
44 |
45 | Released July 2, 2025.
46 |
47 | * Upgraded Mermaid.js to version `9.4.3`.
48 | * Added support for modern diagram types and improved rendering accuracy from recent Mermaid versions.
49 | * Updated integration logic because Mermaid builds from `9.x+` no longer expose mermaid as a global variable by default.
50 | * Cleanup and optimization of the `ext.mermaid.js` file and ResourceLoader configuration for improved stability and maintainability.
51 | * Wrapped JavaScript initialization in error handling to prevent crashes if rendering fails.
52 |
53 | ### 5.0.1
54 |
55 | Released July 2, 2025.
56 |
57 | * Updated ResourceLoader script path to match build output: `resources/mermaid/mermaid.min.js`.
58 | * Translation updates from https://translatewiki.net
59 |
60 | ### 5.0.0
61 |
62 | Released July 2, 2025.
63 |
64 | * Updated to use version 9.4.0 of the Mermaid script language.
65 | * Translation updates from https://translatewiki.net
66 |
67 | ### 4.0.1
68 |
69 | Released July 2, 2025.
70 |
71 | * Reverted breaking changes (incorrect file deletions, broken ResourceLoader paths)
72 | * Restored stable state from version 4.0.0 as the new baseline
73 | * Cleaned up internal ResourceLoader configuration and ensured proper mermaid.min.js resolution
74 | * Translation updates from https://translatewiki.net
75 |
76 | ### 4.0.0
77 |
78 | Released July 2, 2025.
79 |
80 | * Switched to npm for managing Mermaid dependencies and build scripts
81 | * Removed yarn.lock
82 | * Updated README and developer docs to reflect npm usage starting from this version
83 | * Added extensive JSONScript integration tests covering core Mermaid diagram types:
84 | - flowcharts,
85 | - sequence diagrams,
86 | - class diagrams,
87 | - state diagrams,
88 | - Gantt charts,
89 | - pie charts,
90 | - quadrant charts,
91 | - and requirement diagrams
92 | * Improved test reliability and handling of HTML escaping and multi-line content
93 | * Added PHP CodeSniffer linting and fixed related code style issues
94 | * Updated CI badges and build scripts accordingly
95 |
96 | ### 3.1.0
97 |
98 | Released April 6, 2022.
99 |
100 | * Updated to using version 8.14.0 of the mermaid script language.
101 | * Code improvements and minor issue fixes
102 | * Translation updates from https://translatewiki.net
103 |
104 | ### 3.0.1
105 |
106 | Released January 14, 2021.
107 |
108 | * Fixed issue with class loading in some environments
109 | * Translation updates from https://translatewiki.net
110 |
111 | ### 3.0.0
112 |
113 | Released August 10, 2020.
114 |
115 | * Changed minimum MediaWiki version to 1.33
116 | * Changed minimum PHP version from 5.6 to 7.0
117 | * Mermaid now needs to be enabled with `wfLoadExtension`
118 | * Added support for all configuration options provided by the mermaid script language
119 | * Updated to version 8.5.0 of the Mermaid scripting language
120 | * Translation updates from https://translatewiki.net
121 |
122 | ### 2.2.0
123 |
124 | Released on March 7, 2020.
125 |
126 | * Introduces the flowchart `useMaxWidth` configuration parameter
127 | * Translation updates from https://translatewiki.net
128 |
129 | ### 2.1.1
130 |
131 | Released on May 20, 2019.
132 |
133 | * Fixes loading of configuration settings
134 |
135 | ### 2.1.0
136 |
137 | Released on March 5, 2019.
138 |
139 | * Removes deprecated `mediawiki.api.parse` alias
140 |
141 | ### 2.0.0
142 |
143 | Released on February 18, 2019.
144 |
145 | * Updated to use version 8.0.0 of the mermaid script language.
146 | * Translation updates from https://translatewiki.net
147 |
148 | ### 1.0.1
149 |
150 | Released on February 13, 2018.
151 |
152 | * Improves ID entropy for generated diagrams and charts
153 | * Translation updates from https://translatewiki.net
154 |
155 | ### 1.0.0
156 |
157 | Released on January 16, 2018.
158 |
159 | * Initial release using version 7.0.5 of the mermaid script language.
160 | * Added an `MERMAID` parser to easily generate diagrams and flowcharts with the help of the mermaid script language
161 | * Localizations from https://translatewiki.net
162 |
163 | [readme]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/README.md
164 | [installation and configuration information]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/INSTALL.md
165 | [usage examples]: https://github.com/SemanticMediaWiki/Mermaid/blob/master/docs/USAGE.md
166 |
--------------------------------------------------------------------------------
/scripts/generateConfigMap.ts:
--------------------------------------------------------------------------------
1 | import fetch from 'node-fetch';
2 | import { Node, SyntaxKind, TypeLiteralNode, InterfaceDeclaration, Project } from "ts-morph";
3 | import { readFileSync, writeFileSync } from 'fs';
4 | import path from 'path';
5 |
6 | async function generateConfigMap() {
7 | const version = 'v10.9.4';
8 | const url = `https://raw.githubusercontent.com/mermaid-js/mermaid/${version}/packages/mermaid/src/config.type.ts`;
9 | const response = await fetch(url);
10 | const sourceCode = await response.text();
11 |
12 | // Create a ts-morph project and parse the source code
13 | const project = new Project({ useInMemoryFileSystem: true });
14 | const sourceFile = project.createSourceFile('config.type.ts', sourceCode);
15 |
16 | // Get the main interface MermaidConfig
17 | const mainIface = sourceFile.getInterfaceOrThrow('MermaidConfig');
18 |
19 | // Helper function to find InterfaceDeclaration by name
20 | function getInterfaceByName(name: string): InterfaceDeclaration | undefined {
21 | return sourceFile.getInterface(name);
22 | }
23 |
24 | // Function to determine if a property is boolean or boolean union
25 | function isBooleanProperty(prop: import("ts-morph").PropertySignature): boolean {
26 | const type = prop.getType();
27 | return type.isBoolean() || (type.isUnion() && type.getUnionTypes().some(t => t.isBoolean()));
28 | }
29 |
30 | // Recursive function to extract all properties from an interface, flattening nested properties
31 | // Returns a map of property names (dot notation) to either 'FILTER_VALIDATE_BOOLEAN' or null
32 | function extractProperties(
33 | iface: InterfaceDeclaration,
34 | prefix = ''
35 | ): Record {
36 | const result: Record = {};
37 |
38 | iface.getProperties().forEach(prop => {
39 | const name = prop.getName();
40 | const typeNode = prop.getTypeNode();
41 |
42 | if (!typeNode) {
43 | // No explicit type node, assign null
44 | result[prefix + name] = null;
45 | return;
46 | }
47 |
48 | if (Node.isTypeLiteral(typeNode)) {
49 | // Inline object type (TypeLiteral) - recurse into it
50 | const nestedProps = extractFromTypeLiteral(typeNode as TypeLiteralNode, prefix + name + '.');
51 | Object.assign(result, nestedProps);
52 | } else if (Node.isTypeReference(typeNode)) {
53 | // Type reference - lookup interface and recurse
54 | const typeName = typeNode.getText();
55 | const refIface = getInterfaceByName(typeName);
56 | if (refIface) {
57 | const nestedProps = extractProperties(refIface, prefix + name + '.');
58 | Object.assign(result, nestedProps);
59 | } else {
60 | // Reference not found - just assign null
61 | result[prefix + name] = null;
62 | }
63 | } else {
64 | // Other types - check if boolean to assign filter
65 | if (isBooleanProperty(prop)) {
66 | result[prefix + name] = 'FILTER_VALIDATE_BOOLEAN';
67 | } else {
68 | result[prefix + name] = null;
69 | }
70 | }
71 | });
72 |
73 | return result;
74 | }
75 |
76 | // Recursive extraction of properties from TypeLiteralNode, with same filter logic
77 | function extractFromTypeLiteral(
78 | typeLiteralNode: TypeLiteralNode,
79 | prefix = ''
80 | ): Record {
81 | const result: Record = {};
82 |
83 | typeLiteralNode.getMembers().forEach(member => {
84 | if (member.getKind() === SyntaxKind.PropertySignature) {
85 | const propSig = member.asKindOrThrow(SyntaxKind.PropertySignature);
86 | const name = propSig.getName();
87 | const typeNode = propSig.getTypeNode();
88 |
89 | if (!typeNode) {
90 | result[prefix + name] = null;
91 | return;
92 | }
93 |
94 | if (Node.isTypeLiteral(typeNode)) {
95 | const nestedProps = extractFromTypeLiteral(typeNode as TypeLiteralNode, prefix + name + '.');
96 | Object.assign(result, nestedProps);
97 | } else if (Node.isTypeReference(typeNode)) {
98 | const typeName = typeNode.getText();
99 | const refIface = getInterfaceByName(typeName);
100 | if (refIface) {
101 | const nestedProps = extractProperties(refIface, prefix + name + '.');
102 | Object.assign(result, nestedProps);
103 | } else {
104 | result[prefix + name] = null;
105 | }
106 | } else {
107 | if (isBooleanProperty(propSig)) {
108 | result[prefix + name] = 'FILTER_VALIDATE_BOOLEAN';
109 | } else {
110 | result[prefix + name] = null;
111 | }
112 | }
113 | }
114 | });
115 |
116 | return result;
117 | }
118 |
119 | // Extract all properties starting from the main interface
120 | const configMap = extractProperties(mainIface);
121 |
122 | // Sort keys for nicer output
123 | const sortedKeys = Object.keys(configMap).sort();
124 |
125 | // Group keys by their prefix (segment before first dot), global group for keys without dot
126 | const grouped: Record = {};
127 | for (const key of sortedKeys) {
128 | const group = key.includes('.') ? key.split('.')[0] : 'global';
129 | if (!grouped[group]) grouped[group] = [];
130 | grouped[group].push(key);
131 | }
132 |
133 | // Indentation string: 2 tabs
134 | const indent = '\t\t';
135 |
136 | // Generate PHP array lines with comments grouping each diagram type
137 | const phpLines: string[] = [];
138 | phpLines.push('private $configMap = [');
139 |
140 | // Output global group first without comment
141 | if (grouped['global']) {
142 | phpLines.push(`${indent}// global`);
143 | for (const key of grouped['global']) {
144 | const val = configMap[key];
145 | phpLines.push(`${indent}'${key}' => ${val ?? 'null'},`);
146 | }
147 | delete grouped['global'];
148 | }
149 |
150 | // Output other groups with comment headers
151 | for (const group of Object.keys(grouped).sort()) {
152 | phpLines.push(`\n${indent}// ${group}`);
153 | for (const key of grouped[group]) {
154 | const val = configMap[key];
155 | phpLines.push(`${indent}'${key}' => ${val ?? 'null'},`);
156 | }
157 | }
158 |
159 | phpLines.push(`\t];`);
160 |
161 | const newConfigMapBlock = phpLines.join('\n');
162 |
163 | // --- Automatically update PHP file ---
164 |
165 | const phpFilePath = path.resolve('src', 'MermaidConfigExtractor.php');
166 | const phpFileContent = readFileSync(phpFilePath, 'utf-8');
167 |
168 | // Regex to find the existing $configMap block
169 | const configMapRegex = /private \$configMap = \[[\s\S]*?\];/m;
170 |
171 | if (!configMapRegex.test(phpFileContent)) {
172 | console.error('ERROR: Could not find $configMap block in PHP file.');
173 | process.exit(1);
174 | }
175 |
176 | // Replace the old block with the new generated block
177 | const newPhpFileContent = phpFileContent.replace(configMapRegex, newConfigMapBlock);
178 |
179 | // Write back to the PHP file
180 | writeFileSync(phpFilePath, newPhpFileContent, 'utf-8');
181 |
182 | console.log(`ConfigMap updated successfully!`);
183 | }
184 |
185 | generateConfigMap().catch(err => {
186 | console.error('Error:', err);
187 | process.exit(1);
188 | });
189 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | '''[https://github.com/SemanticMediaWiki/Mermaid Mermaid]''' is a free, open-source MediaWiki extension that adds a parser function to help generate diagrams and flowcharts using the mermaid script language.
2 |
3 | Copyright (C) 2017
4 |
5 |
6 | The license text below "====" applies to all files within this distribution, other than those that are in a directory which contains files named "LICENSE" or "COPYING", or a subdirectory thereof. For those files, the license text contained in said file overrides any license information contained in directories of smaller depth. Alternative licenses are typically used for software that is provided by external parties, and merely packaged with this extension for convenience.
7 | ----
8 | ----
9 |
10 | == GNU GENERAL PUBLIC LICENSE ==
11 | Version 2, June 1991
12 |
13 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 |
16 | Everyone is permitted to copy and distribute verbatim copies
17 | of this license document, but changing it is not allowed.
18 |
19 | === Preamble ===
20 | The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software - to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
23 |
24 | To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
25 |
26 | For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
27 |
28 | We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
29 |
30 | Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original
31 | authors' reputations.
32 |
33 | Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
34 |
35 | The precise terms and conditions for copying, distribution and modification follow.
36 |
37 | === TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ===
38 |
39 | '''0.''' This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
40 |
41 | Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
42 |
43 | '''1.''' You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
44 |
45 | You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
46 |
47 | '''2.''' You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
48 |
49 | : '''a)''' You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
50 |
51 | : '''b)''' You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
52 |
53 | : '''c)''' If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
54 |
55 | These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
56 |
57 | Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
58 |
59 | In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
60 |
61 | '''3.''' You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
62 |
63 | : '''a)''' Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
64 |
65 | : '''b)''' Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
66 |
67 | : '''c)''' Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
68 |
69 | The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
70 |
71 | If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
72 |
73 | '''4.''' You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
74 |
75 | '''5.''' You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
76 |
77 | '''6.''' Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
78 |
79 | '''7.''' If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
80 |
81 | If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
82 |
83 | It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing
84 | to distribute software through any other system and a licensee cannot impose that choice.
85 |
86 | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
87 |
88 | '''8.''' If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
89 |
90 | '''9.''' The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
91 |
92 | Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
93 |
94 | '''10.''' If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
95 |
96 | '''NO WARRANTY'''
97 |
98 | '''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
99 |
100 | '''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
101 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
102 |
103 | '''END OF TERMS AND CONDITIONS'''
104 |
--------------------------------------------------------------------------------
/src/MermaidConfigExtractor.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | private $configMap = [
20 | // global
21 | 'altFontFamily' => null,
22 | 'arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
23 | 'darkMode' => FILTER_VALIDATE_BOOLEAN,
24 | 'deterministicIDSeed' => null,
25 | 'deterministicIds' => FILTER_VALIDATE_BOOLEAN,
26 | 'dompurifyConfig' => null,
27 | 'fontFamily' => null,
28 | 'fontSize' => null,
29 | 'htmlLabels' => FILTER_VALIDATE_BOOLEAN,
30 | 'legacyMathML' => FILTER_VALIDATE_BOOLEAN,
31 | 'logLevel' => null,
32 | 'maxEdges' => null,
33 | 'maxTextSize' => null,
34 | 'secure' => null,
35 | 'securityLevel' => null,
36 | 'startOnLoad' => FILTER_VALIDATE_BOOLEAN,
37 | 'theme' => null,
38 | 'themeCSS' => null,
39 | 'themeVariables' => null,
40 | 'wrap' => FILTER_VALIDATE_BOOLEAN,
41 |
42 | // block
43 | 'block.padding' => null,
44 |
45 | // c4
46 | 'c4.boundaryFont' => null,
47 | 'c4.boundaryFontFamily' => null,
48 | 'c4.boundaryFontSize' => null,
49 | 'c4.boundaryFontWeight' => null,
50 | 'c4.boxMargin' => null,
51 | 'c4.c4BoundaryInRow' => null,
52 | 'c4.c4ShapeInRow' => null,
53 | 'c4.c4ShapeMargin' => null,
54 | 'c4.c4ShapePadding' => null,
55 | 'c4.componentFont' => null,
56 | 'c4.componentFontFamily' => null,
57 | 'c4.componentFontSize' => null,
58 | 'c4.componentFontWeight' => null,
59 | 'c4.component_bg_color' => null,
60 | 'c4.component_border_color' => null,
61 | 'c4.component_dbFont' => null,
62 | 'c4.component_dbFontFamily' => null,
63 | 'c4.component_dbFontSize' => null,
64 | 'c4.component_dbFontWeight' => null,
65 | 'c4.component_db_bg_color' => null,
66 | 'c4.component_db_border_color' => null,
67 | 'c4.component_queueFont' => null,
68 | 'c4.component_queueFontFamily' => null,
69 | 'c4.component_queueFontSize' => null,
70 | 'c4.component_queueFontWeight' => null,
71 | 'c4.component_queue_bg_color' => null,
72 | 'c4.component_queue_border_color' => null,
73 | 'c4.containerFont' => null,
74 | 'c4.containerFontFamily' => null,
75 | 'c4.containerFontSize' => null,
76 | 'c4.containerFontWeight' => null,
77 | 'c4.container_bg_color' => null,
78 | 'c4.container_border_color' => null,
79 | 'c4.container_dbFont' => null,
80 | 'c4.container_dbFontFamily' => null,
81 | 'c4.container_dbFontSize' => null,
82 | 'c4.container_dbFontWeight' => null,
83 | 'c4.container_db_bg_color' => null,
84 | 'c4.container_db_border_color' => null,
85 | 'c4.container_queueFont' => null,
86 | 'c4.container_queueFontFamily' => null,
87 | 'c4.container_queueFontSize' => null,
88 | 'c4.container_queueFontWeight' => null,
89 | 'c4.container_queue_bg_color' => null,
90 | 'c4.container_queue_border_color' => null,
91 | 'c4.diagramMarginX' => null,
92 | 'c4.diagramMarginY' => null,
93 | 'c4.external_componentFont' => null,
94 | 'c4.external_componentFontFamily' => null,
95 | 'c4.external_componentFontSize' => null,
96 | 'c4.external_componentFontWeight' => null,
97 | 'c4.external_component_bg_color' => null,
98 | 'c4.external_component_border_color' => null,
99 | 'c4.external_component_dbFont' => null,
100 | 'c4.external_component_dbFontFamily' => null,
101 | 'c4.external_component_dbFontSize' => null,
102 | 'c4.external_component_dbFontWeight' => null,
103 | 'c4.external_component_db_bg_color' => null,
104 | 'c4.external_component_db_border_color' => null,
105 | 'c4.external_component_queueFont' => null,
106 | 'c4.external_component_queueFontFamily' => null,
107 | 'c4.external_component_queueFontSize' => null,
108 | 'c4.external_component_queueFontWeight' => null,
109 | 'c4.external_component_queue_bg_color' => null,
110 | 'c4.external_component_queue_border_color' => null,
111 | 'c4.external_containerFont' => null,
112 | 'c4.external_containerFontFamily' => null,
113 | 'c4.external_containerFontSize' => null,
114 | 'c4.external_containerFontWeight' => null,
115 | 'c4.external_container_bg_color' => null,
116 | 'c4.external_container_border_color' => null,
117 | 'c4.external_container_dbFont' => null,
118 | 'c4.external_container_dbFontFamily' => null,
119 | 'c4.external_container_dbFontSize' => null,
120 | 'c4.external_container_dbFontWeight' => null,
121 | 'c4.external_container_db_bg_color' => null,
122 | 'c4.external_container_db_border_color' => null,
123 | 'c4.external_container_queueFont' => null,
124 | 'c4.external_container_queueFontFamily' => null,
125 | 'c4.external_container_queueFontSize' => null,
126 | 'c4.external_container_queueFontWeight' => null,
127 | 'c4.external_container_queue_bg_color' => null,
128 | 'c4.external_container_queue_border_color' => null,
129 | 'c4.external_personFont' => null,
130 | 'c4.external_personFontFamily' => null,
131 | 'c4.external_personFontSize' => null,
132 | 'c4.external_personFontWeight' => null,
133 | 'c4.external_person_bg_color' => null,
134 | 'c4.external_person_border_color' => null,
135 | 'c4.external_systemFont' => null,
136 | 'c4.external_systemFontFamily' => null,
137 | 'c4.external_systemFontSize' => null,
138 | 'c4.external_systemFontWeight' => null,
139 | 'c4.external_system_bg_color' => null,
140 | 'c4.external_system_border_color' => null,
141 | 'c4.external_system_dbFont' => null,
142 | 'c4.external_system_dbFontFamily' => null,
143 | 'c4.external_system_dbFontSize' => null,
144 | 'c4.external_system_dbFontWeight' => null,
145 | 'c4.external_system_db_bg_color' => null,
146 | 'c4.external_system_db_border_color' => null,
147 | 'c4.external_system_queueFont' => null,
148 | 'c4.external_system_queueFontFamily' => null,
149 | 'c4.external_system_queueFontSize' => null,
150 | 'c4.external_system_queueFontWeight' => null,
151 | 'c4.external_system_queue_bg_color' => null,
152 | 'c4.external_system_queue_border_color' => null,
153 | 'c4.height' => null,
154 | 'c4.messageFont' => null,
155 | 'c4.messageFontFamily' => null,
156 | 'c4.messageFontSize' => null,
157 | 'c4.messageFontWeight' => null,
158 | 'c4.nextLinePaddingX' => null,
159 | 'c4.personFont' => null,
160 | 'c4.personFontFamily' => null,
161 | 'c4.personFontSize' => null,
162 | 'c4.personFontWeight' => null,
163 | 'c4.person_bg_color' => null,
164 | 'c4.person_border_color' => null,
165 | 'c4.systemFont' => null,
166 | 'c4.systemFontFamily' => null,
167 | 'c4.systemFontSize' => null,
168 | 'c4.systemFontWeight' => null,
169 | 'c4.system_bg_color' => null,
170 | 'c4.system_border_color' => null,
171 | 'c4.system_dbFont' => null,
172 | 'c4.system_dbFontFamily' => null,
173 | 'c4.system_dbFontSize' => null,
174 | 'c4.system_dbFontWeight' => null,
175 | 'c4.system_db_bg_color' => null,
176 | 'c4.system_db_border_color' => null,
177 | 'c4.system_queueFont' => null,
178 | 'c4.system_queueFontFamily' => null,
179 | 'c4.system_queueFontSize' => null,
180 | 'c4.system_queueFontWeight' => null,
181 | 'c4.system_queue_bg_color' => null,
182 | 'c4.system_queue_border_color' => null,
183 | 'c4.width' => null,
184 | 'c4.wrap' => FILTER_VALIDATE_BOOLEAN,
185 | 'c4.wrapPadding' => null,
186 |
187 | // class
188 | 'class.arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
189 | 'class.defaultRenderer' => null,
190 | 'class.diagramPadding' => null,
191 | 'class.dividerMargin' => null,
192 | 'class.htmlLabels' => FILTER_VALIDATE_BOOLEAN,
193 | 'class.nodeSpacing' => null,
194 | 'class.padding' => null,
195 | 'class.rankSpacing' => null,
196 | 'class.textHeight' => null,
197 | 'class.titleTopMargin' => null,
198 |
199 | // er
200 | 'er.diagramPadding' => null,
201 | 'er.entityPadding' => null,
202 | 'er.fill' => null,
203 | 'er.fontSize' => null,
204 | 'er.layoutDirection' => null,
205 | 'er.minEntityHeight' => null,
206 | 'er.minEntityWidth' => null,
207 | 'er.stroke' => null,
208 | 'er.titleTopMargin' => null,
209 |
210 | // flowchart
211 | 'flowchart.arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
212 | 'flowchart.curve' => null,
213 | 'flowchart.defaultRenderer' => null,
214 | 'flowchart.diagramPadding' => null,
215 | 'flowchart.htmlLabels' => FILTER_VALIDATE_BOOLEAN,
216 | 'flowchart.nodeSpacing' => null,
217 | 'flowchart.padding' => null,
218 | 'flowchart.rankSpacing' => null,
219 | 'flowchart.subGraphTitleMargin.bottom' => null,
220 | 'flowchart.subGraphTitleMargin.top' => null,
221 | 'flowchart.titleTopMargin' => null,
222 | 'flowchart.wrappingWidth' => null,
223 |
224 | // gantt
225 | 'gantt.axisFormat' => null,
226 | 'gantt.barGap' => null,
227 | 'gantt.barHeight' => null,
228 | 'gantt.displayMode' => null,
229 | 'gantt.fontSize' => null,
230 | 'gantt.gridLineStartPadding' => null,
231 | 'gantt.leftPadding' => null,
232 | 'gantt.numberSectionStyles' => null,
233 | 'gantt.rightPadding' => null,
234 | 'gantt.sectionFontSize' => null,
235 | 'gantt.tickInterval' => null,
236 | 'gantt.titleTopMargin' => null,
237 | 'gantt.topAxis' => FILTER_VALIDATE_BOOLEAN,
238 | 'gantt.topPadding' => null,
239 | 'gantt.weekday' => null,
240 |
241 | // gitGraph
242 | 'gitGraph.arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
243 | 'gitGraph.diagramPadding' => null,
244 | 'gitGraph.mainBranchName' => null,
245 | 'gitGraph.mainBranchOrder' => null,
246 | 'gitGraph.nodeLabel.height' => null,
247 | 'gitGraph.nodeLabel.width' => null,
248 | 'gitGraph.nodeLabel.x' => null,
249 | 'gitGraph.nodeLabel.y' => null,
250 | 'gitGraph.parallelCommits' => FILTER_VALIDATE_BOOLEAN,
251 | 'gitGraph.rotateCommitLabel' => FILTER_VALIDATE_BOOLEAN,
252 | 'gitGraph.showBranches' => FILTER_VALIDATE_BOOLEAN,
253 | 'gitGraph.showCommitLabel' => FILTER_VALIDATE_BOOLEAN,
254 | 'gitGraph.titleTopMargin' => null,
255 |
256 | // journey
257 | 'journey.activationWidth' => null,
258 | 'journey.actorColours' => null,
259 | 'journey.bottomMarginAdj' => null,
260 | 'journey.boxMargin' => null,
261 | 'journey.boxTextMargin' => null,
262 | 'journey.diagramMarginX' => null,
263 | 'journey.diagramMarginY' => null,
264 | 'journey.height' => null,
265 | 'journey.leftMargin' => null,
266 | 'journey.messageAlign' => null,
267 | 'journey.messageMargin' => null,
268 | 'journey.noteMargin' => null,
269 | 'journey.rightAngles' => FILTER_VALIDATE_BOOLEAN,
270 | 'journey.sectionColours' => null,
271 | 'journey.sectionFills' => null,
272 | 'journey.taskFontFamily' => null,
273 | 'journey.taskFontSize' => null,
274 | 'journey.taskMargin' => null,
275 | 'journey.textPlacement' => null,
276 | 'journey.width' => null,
277 |
278 | // mindmap
279 | 'mindmap.maxNodeWidth' => null,
280 | 'mindmap.padding' => null,
281 |
282 | // pie
283 | 'pie.textPosition' => null,
284 |
285 | // quadrantChart
286 | 'quadrantChart.chartHeight' => null,
287 | 'quadrantChart.chartWidth' => null,
288 | 'quadrantChart.pointLabelFontSize' => null,
289 | 'quadrantChart.pointRadius' => null,
290 | 'quadrantChart.pointTextPadding' => null,
291 | 'quadrantChart.quadrantExternalBorderStrokeWidth' => null,
292 | 'quadrantChart.quadrantInternalBorderStrokeWidth' => null,
293 | 'quadrantChart.quadrantLabelFontSize' => null,
294 | 'quadrantChart.quadrantPadding' => null,
295 | 'quadrantChart.quadrantTextTopPadding' => null,
296 | 'quadrantChart.titleFontSize' => null,
297 | 'quadrantChart.titlePadding' => null,
298 | 'quadrantChart.xAxisLabelFontSize' => null,
299 | 'quadrantChart.xAxisLabelPadding' => null,
300 | 'quadrantChart.xAxisPosition' => null,
301 | 'quadrantChart.yAxisLabelFontSize' => null,
302 | 'quadrantChart.yAxisLabelPadding' => null,
303 | 'quadrantChart.yAxisPosition' => null,
304 |
305 | // requirement
306 | 'requirement.fontSize' => null,
307 | 'requirement.line_height' => null,
308 | 'requirement.rect_border_color' => null,
309 | 'requirement.rect_border_size' => null,
310 | 'requirement.rect_fill' => null,
311 | 'requirement.rect_min_height' => null,
312 | 'requirement.rect_min_width' => null,
313 | 'requirement.rect_padding' => null,
314 | 'requirement.text_color' => null,
315 |
316 | // sankey
317 | 'sankey.height' => null,
318 | 'sankey.linkColor' => null,
319 | 'sankey.nodeAlignment' => null,
320 | 'sankey.prefix' => null,
321 | 'sankey.showValues' => FILTER_VALIDATE_BOOLEAN,
322 | 'sankey.suffix' => null,
323 | 'sankey.useMaxWidth' => FILTER_VALIDATE_BOOLEAN,
324 | 'sankey.width' => null,
325 |
326 | // sequence
327 | 'sequence.activationWidth' => null,
328 | 'sequence.actorFont' => null,
329 | 'sequence.actorFontFamily' => null,
330 | 'sequence.actorFontSize' => null,
331 | 'sequence.actorFontWeight' => null,
332 | 'sequence.actorMargin' => null,
333 | 'sequence.arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
334 | 'sequence.bottomMarginAdj' => null,
335 | 'sequence.boxMargin' => null,
336 | 'sequence.boxTextMargin' => null,
337 | 'sequence.diagramMarginX' => null,
338 | 'sequence.diagramMarginY' => null,
339 | 'sequence.forceMenus' => FILTER_VALIDATE_BOOLEAN,
340 | 'sequence.height' => null,
341 | 'sequence.hideUnusedParticipants' => FILTER_VALIDATE_BOOLEAN,
342 | 'sequence.labelBoxHeight' => null,
343 | 'sequence.labelBoxWidth' => null,
344 | 'sequence.messageAlign' => null,
345 | 'sequence.messageFont' => null,
346 | 'sequence.messageFontFamily' => null,
347 | 'sequence.messageFontSize' => null,
348 | 'sequence.messageFontWeight' => null,
349 | 'sequence.messageMargin' => null,
350 | 'sequence.mirrorActors' => FILTER_VALIDATE_BOOLEAN,
351 | 'sequence.noteAlign' => null,
352 | 'sequence.noteFont' => null,
353 | 'sequence.noteFontFamily' => null,
354 | 'sequence.noteFontSize' => null,
355 | 'sequence.noteFontWeight' => null,
356 | 'sequence.noteMargin' => null,
357 | 'sequence.rightAngles' => FILTER_VALIDATE_BOOLEAN,
358 | 'sequence.showSequenceNumbers' => FILTER_VALIDATE_BOOLEAN,
359 | 'sequence.width' => null,
360 | 'sequence.wrap' => FILTER_VALIDATE_BOOLEAN,
361 | 'sequence.wrapPadding' => null,
362 |
363 | // state
364 | 'state.arrowMarkerAbsolute' => FILTER_VALIDATE_BOOLEAN,
365 | 'state.compositTitleSize' => null,
366 | 'state.defaultRenderer' => null,
367 | 'state.dividerMargin' => null,
368 | 'state.edgeLengthFactor' => null,
369 | 'state.fontSize' => null,
370 | 'state.fontSizeFactor' => null,
371 | 'state.forkHeight' => null,
372 | 'state.forkWidth' => null,
373 | 'state.labelHeight' => null,
374 | 'state.miniPadding' => null,
375 | 'state.noteMargin' => null,
376 | 'state.padding' => null,
377 | 'state.radius' => null,
378 | 'state.sizeUnit' => null,
379 | 'state.textHeight' => null,
380 | 'state.titleShift' => null,
381 | 'state.titleTopMargin' => null,
382 |
383 | // timeline
384 | 'timeline.activationWidth' => null,
385 | 'timeline.actorColours' => null,
386 | 'timeline.bottomMarginAdj' => null,
387 | 'timeline.boxMargin' => null,
388 | 'timeline.boxTextMargin' => null,
389 | 'timeline.diagramMarginX' => null,
390 | 'timeline.diagramMarginY' => null,
391 | 'timeline.disableMulticolor' => FILTER_VALIDATE_BOOLEAN,
392 | 'timeline.height' => null,
393 | 'timeline.leftMargin' => null,
394 | 'timeline.messageAlign' => null,
395 | 'timeline.messageMargin' => null,
396 | 'timeline.noteMargin' => null,
397 | 'timeline.padding' => null,
398 | 'timeline.rightAngles' => FILTER_VALIDATE_BOOLEAN,
399 | 'timeline.sectionColours' => null,
400 | 'timeline.sectionFills' => null,
401 | 'timeline.taskFontFamily' => null,
402 | 'timeline.taskFontSize' => null,
403 | 'timeline.taskMargin' => null,
404 | 'timeline.textPlacement' => null,
405 | 'timeline.width' => null,
406 |
407 | // xyChart
408 | 'xyChart.chartOrientation' => null,
409 | 'xyChart.height' => null,
410 | 'xyChart.plotReservedSpacePercent' => null,
411 | 'xyChart.showTitle' => FILTER_VALIDATE_BOOLEAN,
412 | 'xyChart.titleFontSize' => null,
413 | 'xyChart.titlePadding' => null,
414 | 'xyChart.width' => null,
415 | 'xyChart.xAxis.axisLineWidth' => null,
416 | 'xyChart.xAxis.labelFontSize' => null,
417 | 'xyChart.xAxis.labelPadding' => null,
418 | 'xyChart.xAxis.showAxisLine' => FILTER_VALIDATE_BOOLEAN,
419 | 'xyChart.xAxis.showLabel' => FILTER_VALIDATE_BOOLEAN,
420 | 'xyChart.xAxis.showTick' => FILTER_VALIDATE_BOOLEAN,
421 | 'xyChart.xAxis.showTitle' => FILTER_VALIDATE_BOOLEAN,
422 | 'xyChart.xAxis.tickLength' => null,
423 | 'xyChart.xAxis.tickWidth' => null,
424 | 'xyChart.xAxis.titleFontSize' => null,
425 | 'xyChart.xAxis.titlePadding' => null,
426 | 'xyChart.yAxis.axisLineWidth' => null,
427 | 'xyChart.yAxis.labelFontSize' => null,
428 | 'xyChart.yAxis.labelPadding' => null,
429 | 'xyChart.yAxis.showAxisLine' => FILTER_VALIDATE_BOOLEAN,
430 | 'xyChart.yAxis.showLabel' => FILTER_VALIDATE_BOOLEAN,
431 | 'xyChart.yAxis.showTick' => FILTER_VALIDATE_BOOLEAN,
432 | 'xyChart.yAxis.showTitle' => FILTER_VALIDATE_BOOLEAN,
433 | 'xyChart.yAxis.tickLength' => null,
434 | 'xyChart.yAxis.tickWidth' => null,
435 | 'xyChart.yAxis.titleFontSize' => null,
436 | 'xyChart.yAxis.titlePadding' => null,
437 | ];
438 |
439 | /**
440 | * Extracts the param array into a tuple of two arrays
441 | * @param array $params
442 | * @return array [$mermaidConfig, $mediawikiParam]
443 | */
444 | public function extract( array $params ) {
445 | $configMapKeys = array_keys( $this->configMap );
446 |
447 | // Use reduce to split the param array into two arrays: [$mermaidConfig, $mediawikiParam]
448 | return array_reduce( $params, function ( $prev, $current ) use ( $configMapKeys ) {
449 | // De-structures the two arrays
450 | list( $mermaidConfig, $mwParams ) = $prev;
451 |
452 | // if there is no "=", it belongs in mediawiki params
453 | if ( strpos( $current, '=' ) === false ) {
454 | $mwParams[] = $current;
455 | return [ $mermaidConfig, $mwParams ];
456 | }
457 |
458 | // split from the first "=" into two parts, then trim both parts
459 | list( $key, $value ) = array_map( 'trim', explode( '=', $current, 2 ) );
460 |
461 | // test to see if the leftside of the "=" is in the configMap keys
462 | $normalizedKey = $this->keyNamingNormalizer( $key );
463 | $inConfigMap = in_array( $normalizedKey, $configMapKeys, true );
464 |
465 | // if not in config map, the value belongs in the mediawiki params
466 | if ( !$inConfigMap ) {
467 | $mwParams[] = $current;
468 | return [ $mermaidConfig, $mwParams ];
469 | }
470 |
471 | // config key is in the config map
472 | // check to see if there is a type associated with the key
473 | $normalizedValue = $value;
474 | $valueType = $this->configMap[$normalizedKey];
475 | if ( $valueType !== null ) {
476 | // normalize: 'true' => true, '1' => true, etc
477 | $normalizedValue = filter_var( $value, $valueType, FILTER_NULL_ON_FAILURE );
478 | }
479 |
480 | // set the config with dot.notation
481 | $this->setWithDotNotation( $mermaidConfig, $normalizedKey, $normalizedValue );
482 | return [ $mermaidConfig, $mwParams ];
483 | }, [ [], [] ] );
484 | }
485 |
486 | /**
487 | * Removes "config." from the dot-notationed configuration key
488 | * @param string $key
489 | * @return false|string
490 | */
491 | protected function keyNamingNormalizer( string $key ) {
492 | if ( strpos( $key, 'config.' ) === false ) {
493 | return $key;
494 | }
495 | return substr( $key, 7 );
496 | }
497 |
498 | // Taken from Laravel's Arr::set function
499 | // https://github.com/laravel/framework/blob/7.x/src/Illuminate/Support/Arr.php
500 | /**
501 | * Sets a value onto an array with keys using dot.notation, in-place
502 | * @param &$array
503 | * @param $key
504 | * @param $value
505 | * @return array|mixed
506 | */
507 | protected function setWithDotNotation( &$array, $key, $value ) {
508 | if ( is_null( $key ) ) {
509 | return $array = $value;
510 | }
511 |
512 | $keys = explode( '.', $key );
513 |
514 | foreach ( $keys as $i => $key ) {
515 | if ( count( $keys ) === 1 ) {
516 | break;
517 | }
518 |
519 | unset( $keys[$i] );
520 |
521 | // If the key doesn't exist at this depth, we will just create an empty array
522 | // to hold the next value, allowing us to create the arrays to hold final
523 | // values at the correct depth. Then we'll keep digging into the array.
524 | if ( !isset( $array[$key] ) || !is_array( $array[$key] ) ) {
525 | $array[$key] = [];
526 | }
527 |
528 | $array = &$array[$key];
529 | }
530 |
531 | $array[array_shift( $keys )] = $value;
532 |
533 | return $array;
534 | }
535 | }
536 |
--------------------------------------------------------------------------------