From 1f2193e2b606d3925f10f73c76870fc9c3feb6bb Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sun, 30 May 2021 20:02:46 +0900
Subject: [PATCH 01/10] =?UTF-8?q?mermaid.js=20=E5=AF=BE=E5=BF=9C=E3=81=AE?=
=?UTF-8?q?=E9=80=94=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/example/articles/example.md | 11 +++++-
.../src/classes/mermaid.ts | 34 +++++++++++++++++++
packages/zenn-embed-elements/src/index.ts | 2 ++
.../__tests__/mermaid.test.ts | 8 +++++
packages/zenn-markdown-html/jest.config.js | 2 +-
packages/zenn-markdown-html/src/index.ts | 4 ++-
.../src/utils/md-mermaid.ts | 33 ++++++++++++++++++
7 files changed, 91 insertions(+), 3 deletions(-)
create mode 100644 packages/zenn-embed-elements/src/classes/mermaid.ts
create mode 100644 packages/zenn-markdown-html/__tests__/mermaid.test.ts
create mode 100644 packages/zenn-markdown-html/src/utils/md-mermaid.ts
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index de9b4bc1..8a214a04 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -135,4 +135,13 @@ $a^*b$ with $a^*$
$\sum_{i=1}^n$
fafa
-a
\ No newline at end of file
+a
+
+```mermaid
+%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
\ No newline at end of file
diff --git a/packages/zenn-embed-elements/src/classes/mermaid.ts b/packages/zenn-embed-elements/src/classes/mermaid.ts
new file mode 100644
index 00000000..86a2df47
--- /dev/null
+++ b/packages/zenn-embed-elements/src/classes/mermaid.ts
@@ -0,0 +1,34 @@
+import { loadScript } from '../utils/load-script';
+
+declare let mermaid: any;
+const containerId = 'mermaid-container';
+
+export class EmbedMermaid extends HTMLElement {
+ private _container: HTMLDivElement;
+
+ constructor() {
+ super();
+ const container = document.createElement('div');
+ container.setAttribute('id', containerId);
+ this._container = container;
+ }
+
+ async connectedCallback() {
+ this.render();
+ }
+
+ async render() {
+ if (typeof mermaid === 'undefined') {
+ await loadScript({
+ src: 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js',
+ id: 'mermaid-js',
+ });
+ }
+
+ mermaid?.initialize({
+ startOnLoad: true,
+ });
+ mermaid?.render('id1', this.innerText || '', undefined, this._container);
+ this.innerHTML = this._container.innerHTML;
+ }
+}
diff --git a/packages/zenn-embed-elements/src/index.ts b/packages/zenn-embed-elements/src/index.ts
index 12373376..8de07abe 100644
--- a/packages/zenn-embed-elements/src/index.ts
+++ b/packages/zenn-embed-elements/src/index.ts
@@ -1,7 +1,9 @@
import { EmbedGist } from './classes/gist';
import { EmbedTweet } from './classes/tweet';
import { EmbedKatex } from './classes/katex';
+import { EmbedMermaid } from './classes/mermaid';
customElements.define('embed-gist', EmbedGist);
customElements.define('embed-tweet', EmbedTweet);
customElements.define('embed-katex', EmbedKatex);
+customElements.define('embed-mermaid', EmbedMermaid);
diff --git a/packages/zenn-markdown-html/__tests__/mermaid.test.ts b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
new file mode 100644
index 00000000..09d7e392
--- /dev/null
+++ b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
@@ -0,0 +1,8 @@
+import markdownToHtml from '../src/index';
+
+describe('Detect mermaid propley', () => {
+ test('should generate TD valid code format html', () => {
+ const html = markdownToHtml(`\`\`\`mermaid\ngraph TD\nA --> B\n\`\`\``);
+ expect(html).toContain('graph TD\nA --> B
');
+ });
+});
diff --git a/packages/zenn-markdown-html/jest.config.js b/packages/zenn-markdown-html/jest.config.js
index 4805cba6..c42bb78c 100644
--- a/packages/zenn-markdown-html/jest.config.js
+++ b/packages/zenn-markdown-html/jest.config.js
@@ -2,7 +2,7 @@ module.exports = {
globals: {
'ts-jest': {
// avoid "jsx" treated as "preserved"
- tsConfig: 'tsconfig.json',
+ tsconfig: 'tsconfig.json',
},
},
moduleFileExtensions: ['js', 'json', 'ts'],
diff --git a/packages/zenn-markdown-html/src/index.ts b/packages/zenn-markdown-html/src/index.ts
index 4c91eb16..ffd1ac13 100644
--- a/packages/zenn-markdown-html/src/index.ts
+++ b/packages/zenn-markdown-html/src/index.ts
@@ -14,6 +14,7 @@ import { mdBr } from './utils/md-br';
import { mdCustomBlock } from './utils/md-custom-block';
import markdownItImSize from '@steelydylan/markdown-it-imsize';
import markdownItAnchor from 'markdown-it-anchor';
+import { mdMermaid } from './utils/md-mermaid';
const mdContainer = require('markdown-it-container');
const mdFootnote = require('markdown-it-footnote');
@@ -52,7 +53,8 @@ md.use(mdBr)
},
})
.use(mdKatex)
- .use(mdLinkifyToCard);
+ .use(mdLinkifyToCard)
+ .use(mdMermaid);
// custom footnote => TODO: ファイルを分ける
md.renderer.rules.footnote_block_open = () =>
diff --git a/packages/zenn-markdown-html/src/utils/md-mermaid.ts b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
new file mode 100644
index 00000000..61b8a2d8
--- /dev/null
+++ b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
@@ -0,0 +1,33 @@
+/**
+ * forked from https://github.com/tylingsoft/markdown-it-mermaid
+ */
+// import mermaid from 'mermaid';
+import MarkdownIt from 'markdown-it';
+
+function mermaidChart(code: string): string {
+ // mermaid.parse(code);
+ return `${code}
`;
+}
+
+/**
+ * ```merdmaid
+ * ```
+ * =>
+ *
+ * @param md
+ */
+export function mdMermaid(md: MarkdownIt) {
+ // const temp = md.renderer.rules.fence.bind(md.renderer.rules);
+ const defaultRender =
+ md.renderer.rules.fence ||
+ function (tokens, idx, options, env, self) {
+ return self.renderToken(tokens, idx, options);
+ };
+ md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
+ const langInfo = tokens[idx];
+ if (langInfo.info === 'mermaid') {
+ return mermaidChart(langInfo.content.trim());
+ }
+ return defaultRender(tokens, idx, options, env, slf);
+ };
+}
From 2caa5cef68ebd2f38daca167d60e6bf695628148 Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sun, 30 May 2021 20:09:11 +0900
Subject: [PATCH 02/10] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?=
=?UTF-8?q?=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/zenn-markdown-html/__tests__/mermaid.test.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/zenn-markdown-html/__tests__/mermaid.test.ts b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
index 09d7e392..9c0f8ef4 100644
--- a/packages/zenn-markdown-html/__tests__/mermaid.test.ts
+++ b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
@@ -3,6 +3,8 @@ import markdownToHtml from '../src/index';
describe('Detect mermaid propley', () => {
test('should generate TD valid code format html', () => {
const html = markdownToHtml(`\`\`\`mermaid\ngraph TD\nA --> B\n\`\`\``);
- expect(html).toContain('graph TD\nA --> B
');
+ expect(html).toContain(
+ 'graph TD\nA --> B
'
+ );
});
});
From 3cce81bc0df98765f4535a9a2adb4a56b7bc1146 Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sun, 30 May 2021 20:12:56 +0900
Subject: [PATCH 03/10] =?UTF-8?q?=E8=A8=98=E8=BF=B0=E3=82=92=E4=BF=AE?=
=?UTF-8?q?=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/example/articles/example.md | 2 +-
.../src/utils/md-mermaid.ts | 20 ++-----------------
2 files changed, 3 insertions(+), 19 deletions(-)
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index 8a214a04..9858d52f 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -138,7 +138,7 @@ fafa
a
```mermaid
-%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
+%%{init: { 'theme': 'forest' } }%%
graph TD;
A-->B;
A-->C;
diff --git a/packages/zenn-markdown-html/src/utils/md-mermaid.ts b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
index 61b8a2d8..3bafc82f 100644
--- a/packages/zenn-markdown-html/src/utils/md-mermaid.ts
+++ b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
@@ -1,23 +1,6 @@
-/**
- * forked from https://github.com/tylingsoft/markdown-it-mermaid
- */
-// import mermaid from 'mermaid';
import MarkdownIt from 'markdown-it';
-function mermaidChart(code: string): string {
- // mermaid.parse(code);
- return `${code}
`;
-}
-
-/**
- * ```merdmaid
- * ```
- * =>
- *
- * @param md
- */
export function mdMermaid(md: MarkdownIt) {
- // const temp = md.renderer.rules.fence.bind(md.renderer.rules);
const defaultRender =
md.renderer.rules.fence ||
function (tokens, idx, options, env, self) {
@@ -26,7 +9,8 @@ export function mdMermaid(md: MarkdownIt) {
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
const langInfo = tokens[idx];
if (langInfo.info === 'mermaid') {
- return mermaidChart(langInfo.content.trim());
+ const code = langInfo.content.trim();
+ return `${code}
`;
}
return defaultRender(tokens, idx, options, env, slf);
};
From be3feacb14022760095798d6afc00ed1ae621cf0 Mon Sep 17 00:00:00 2001
From: GitHub
Date: Fri, 4 Jun 2021 08:16:35 +0000
Subject: [PATCH 04/10] v0.1.82
---
lerna.json | 2 +-
packages/example/package.json | 4 ++--
packages/zenn-cli/package.json | 8 ++++----
packages/zenn-content-css/package.json | 2 +-
packages/zenn-embed-elements/package.json | 2 +-
packages/zenn-markdown-html/package.json | 2 +-
6 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/lerna.json b/lerna.json
index c180ff1b..1c71c6cf 100644
--- a/lerna.json
+++ b/lerna.json
@@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"npmClient": "yarn",
"useWorkspaces": true
}
diff --git a/packages/example/package.json b/packages/example/package.json
index 9ea80e61..4ee7387c 100644
--- a/packages/example/package.json
+++ b/packages/example/package.json
@@ -1,8 +1,8 @@
{
"private": true,
"name": "example",
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"dependencies": {
- "zenn-cli": "^0.1.82-alpha.2"
+ "zenn-cli": "^0.1.82"
}
}
diff --git a/packages/zenn-cli/package.json b/packages/zenn-cli/package.json
index acaae1bc..ee419881 100644
--- a/packages/zenn-cli/package.json
+++ b/packages/zenn-cli/package.json
@@ -1,7 +1,7 @@
{
"name": "zenn-cli",
"license": "MIT",
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"description": "Preview Zenn content locally.",
"repository": {
"type": "git",
@@ -49,9 +49,9 @@
"socket.io": "^3.1.0",
"socket.io-client": "^3.1.0",
"update-notifier": "^5.1.0",
- "zenn-content-css": "^0.1.82-alpha.2",
- "zenn-embed-elements": "^0.1.82-alpha.2",
- "zenn-markdown-html": "^0.1.82-alpha.2"
+ "zenn-content-css": "^0.1.82",
+ "zenn-embed-elements": "^0.1.82",
+ "zenn-markdown-html": "^0.1.82"
},
"devDependencies": {
"@testing-library/react": "^11.2.1",
diff --git a/packages/zenn-content-css/package.json b/packages/zenn-content-css/package.json
index 10ced279..5d2f6d90 100644
--- a/packages/zenn-content-css/package.json
+++ b/packages/zenn-content-css/package.json
@@ -1,6 +1,6 @@
{
"name": "zenn-content-css",
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"license": "MIT",
"description": "Zenn flavor content style.",
"repository": {
diff --git a/packages/zenn-embed-elements/package.json b/packages/zenn-embed-elements/package.json
index d7a9f788..f5f69f9f 100644
--- a/packages/zenn-embed-elements/package.json
+++ b/packages/zenn-embed-elements/package.json
@@ -1,6 +1,6 @@
{
"name": "zenn-embed-elements",
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"description": "Web components for embedded contents.",
"repository": {
"type": "git",
diff --git a/packages/zenn-markdown-html/package.json b/packages/zenn-markdown-html/package.json
index db96fcb0..10ada661 100644
--- a/packages/zenn-markdown-html/package.json
+++ b/packages/zenn-markdown-html/package.json
@@ -1,6 +1,6 @@
{
"name": "zenn-markdown-html",
- "version": "0.1.82-alpha.2",
+ "version": "0.1.82",
"description": "Convert markdown to zenn flavor html.",
"main": "lib/index.js",
"repository": {
From 0896fec57bd2179bc46546ad0816230d2e8c316c Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Fri, 4 Jun 2021 18:53:14 +0900
Subject: [PATCH 05/10] =?UTF-8?q?=E3=83=91=E3=83=BC=E3=82=B9=E3=82=A8?=
=?UTF-8?q?=E3=83=A9=E3=83=BC=E3=81=AB=E5=AF=BE=E5=87=A6=E3=81=99=E3=82=8B?=
=?UTF-8?q?=E9=80=94=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/example/articles/example.md | 90 ++++++++----
.../src/classes/mermaid.ts | 128 ++++++++++++++++--
.../src/utils/md-mermaid.ts | 2 +-
3 files changed, 183 insertions(+), 37 deletions(-)
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index 9858d52f..420f7717 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -7,25 +7,78 @@ topics:
emoji: 👩💻
published: false
---
+```mermaid
+graph LR
+A:::someclass B
+classDef someclass fill:#f96;
+```
+```mermaid
+graph LR
+id1[(Database)]:::someclass-->B
+classDef someclass fill:#f96;
-https://twitter.com/jack/status/20
-https://twitter.com/jack/status/20
-https://twitter.com/jack/status/20
+```
-https://twitter.com/jack/status/20
-https://twitter.com/jack/status/20
-https://twitter.com/jack/status/20
+```mermaid
+%%{init: { 'theme': 'forest' } }%%
+graph LR;
+ A-->B & C-->D & E-->F & Z-->X;
+ F-->G
+ G-->H
+ H-->I
+ I-->J
+ J-->K
+ K-->L
+ L-->M
+ M-->N
+ N-->O
+ O-->P
+```
+
+```mermaid
+%%{init: { 'theme': 'forest' } }%%
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
+
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
+
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
+
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
+
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
-![](https://octodex.github.com/images/stormtroopocat.jpg =200x)
-*captions*
-dfasdfa
-dfa
-fd
-a
-fafdafdafda
```bash
console.log({
a: "a",
@@ -108,7 +161,7 @@ aaa
$a$
-$a\ne0$
+$a\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0$
$\varphi$
@@ -136,12 +189,3 @@ $\sum_{i=1}^n$
fafa
a
-
-```mermaid
-%%{init: { 'theme': 'forest' } }%%
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
\ No newline at end of file
diff --git a/packages/zenn-embed-elements/src/classes/mermaid.ts b/packages/zenn-embed-elements/src/classes/mermaid.ts
index 86a2df47..71f517d5 100644
--- a/packages/zenn-embed-elements/src/classes/mermaid.ts
+++ b/packages/zenn-embed-elements/src/classes/mermaid.ts
@@ -1,16 +1,93 @@
+/**
+ * original: https://github.com/gitlabhq/gitlabhq/blob/master/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+ */
+
import { loadScript } from '../utils/load-script';
+// レンダリングする図ごとの最大文字数
+const MAX_CHAR_LIMIT = 2000;
+
+// https://mermaid-js.github.io/mermaid/#/flowchart?id=chaining-of-links
+// 新しい仕様で
+// graph LR
+// a --> b & c--> d
+// に対応するが、少ない記述でノード接続が爆発する可能性があるため最大数を制限する
+const MAX_CHAINING_OF_LINKS_LIMIT = 10;
+
+// Page values
declare let mermaid: any;
const containerId = 'mermaid-container';
+async function initMermaid(): Promise {
+ if (typeof mermaid === 'undefined') {
+ await loadScript({
+ src: 'https://cdn.jsdelivr.net/npm/mermaid@8.10/dist/mermaid.min.js',
+ id: 'mermaid-js',
+ });
+ const theme = 'neutral';
+
+ mermaid!.mermaidAPI.initialize({
+ startOnLoad: false, // レンダリングはこちらでやるので false
+ securityLevel: 'strict', // tags in text are encoded, click functionality is disabled
+ theme,
+ er: {
+ useMaxWidth: true,
+ },
+ flowchart: {
+ useMaxWidth: true, // 表示の都合上見切れるのもスクロールするのも嫌なので最大幅を有効にする
+ htmlLabels: false, // セキュリティのため、HTMLラベルは許可しない
+ },
+ sequence: {
+ useMaxWidth: true,
+ },
+ });
+
+ console.log(mermaid!.mermaidAPI.getConfig());
+ }
+}
+
+type ErrorContainer = {
+ yes: boolean;
+ message: string;
+};
+
+type PotentialRisk = {
+ syntaxError: ErrorContainer;
+ charLimitOver: ErrorContainer;
+ chainingOfLinksOver: ErrorContainer;
+};
+
+function getPotentialPerformanceRisk(source: string): PotentialRisk {
+ return {
+ syntaxError: {
+ yes: mermaid!.mermaidAPI
+ .parse(source)
+ .then((_: any) => false)
+ .catch((_: any) => true),
+ message: `シンタックスエラーです`,
+ },
+ charLimitOver: {
+ yes: source.length > MAX_CHAR_LIMIT,
+ message: `ブロックあたりの文字数上限は${MAX_CHAR_LIMIT}です`,
+ },
+ chainingOfLinksOver: {
+ yes: (source.match(/&/g) || []).length > MAX_CHAINING_OF_LINKS_LIMIT,
+ message: `ブロックあたりの&によるチェイン上限は${MAX_CHAINING_OF_LINKS_LIMIT}です`,
+ },
+ };
+}
+
+function fixElementContent(content: string) {
+ // Mermaid doesn't like `
` tags, so collapse all like tags into `
`, which is parsed correctly.
+ return content.replace(/
/g, '
');
+}
+
export class EmbedMermaid extends HTMLElement {
private _container: HTMLDivElement;
constructor() {
super();
- const container = document.createElement('div');
- container.setAttribute('id', containerId);
- this._container = container;
+ this._container = this.childNodes[0] as HTMLDivElement;
}
async connectedCallback() {
@@ -18,17 +95,42 @@ export class EmbedMermaid extends HTMLElement {
}
async render() {
- if (typeof mermaid === 'undefined') {
- await loadScript({
- src: 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js',
- id: 'mermaid-js',
- });
+ await initMermaid();
+ const source = fixElementContent(this._container.innerText || '');
+
+ // Mermaid モジュールの読み込みに失敗したり、レンダリング対象のコンテンツが空の場合は何もせずに終了
+ if (!source) {
+ return;
}
- mermaid?.initialize({
- startOnLoad: true,
- });
- mermaid?.render('id1', this.innerText || '', undefined, this._container);
- this.innerHTML = this._container.innerHTML;
+ // パフォーマンスリスクが検出された場合、注意書きをレンダリングして終了
+ const risk = getPotentialPerformanceRisk(source);
+ if (
+ Object.values(risk)
+ .map((r) => r.yes)
+ .includes(true)
+ ) {
+ this.innerHTML = `
+
+ mermaidのレンダリングでパフォーマンス上のリスクが検出されました。
+
+ ${risk.charLimitOver.yes ? risk.charLimitOver.message : ''}
+ ${risk.chainingOfLinksOver.yes ? risk.chainingOfLinksOver.message : ''}
+
+
+ `;
+ return;
+ }
+
+ // すべて通過した場合はレンダリングする
+ const insert = (svgCode: string, bindFunctions: any) => {
+ this.innerHTML = svgCode;
+ bindFunctions(this._container);
+ };
+ mermaid?.mermaidAPI.render(
+ `${containerId}-${Date.now().valueOf()}`,
+ source,
+ insert
+ );
}
}
diff --git a/packages/zenn-markdown-html/src/utils/md-mermaid.ts b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
index 3bafc82f..6204d545 100644
--- a/packages/zenn-markdown-html/src/utils/md-mermaid.ts
+++ b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
@@ -10,7 +10,7 @@ export function mdMermaid(md: MarkdownIt) {
const langInfo = tokens[idx];
if (langInfo.info === 'mermaid') {
const code = langInfo.content.trim();
- return `${code}
`;
+ return `${code}
`;
}
return defaultRender(tokens, idx, options, env, slf);
};
From 91d124c1d798c5bacc1c3d9669739885d41e1b03 Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sat, 5 Jun 2021 23:53:32 +0900
Subject: [PATCH 06/10] =?UTF-8?q?XSS=E8=80=83=E6=85=AE=E5=AF=BE=E5=BF=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/example/articles/embed.md | 189 ++++++++++++++++++
packages/example/articles/example.md | 109 +++-------
.../src/classes/mermaid.ts | 66 ++++--
.../__tests__/mermaid.test.ts | 18 +-
.../zenn-markdown-html/__tests__/xss.test.ts | 8 +
.../src/utils/md-mermaid.ts | 4 +-
6 files changed, 289 insertions(+), 105 deletions(-)
diff --git a/packages/example/articles/embed.md b/packages/example/articles/embed.md
index a2d8b9ed..e01ba6aa 100644
--- a/packages/example/articles/embed.md
+++ b/packages/example/articles/embed.md
@@ -23,3 +23,192 @@ https://gist.github.com/mattpodwysocki/218388
@[gist](https://gist.github.com/hofmannsven/9164408?file=my.cnf)
ssfafafaffafa
+
+
+## mermaid.js
+
+```mermaid
+%%{init: { 'theme': 'forest' } }%%
+graph LR;
+ A-->B & C-->D & E-->F & Z-->X;
+ F-->G
+ G-->H
+ H-->I
+ I-->J
+ J-->K
+ K-->L
+ L-->M
+ M-->N
+ N-->O
+ O-->P
+ P-->ID1[ノード1
ノード2]
+```
+
+### flowchart
+
+```mermaid
+flowchart TB
+ c1-->a2
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+ one --> two
+ three --> two
+ two --> c2
+```
+
+### sequence diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ アリス->>光輝: Hello John, how are you?
+ loop Healthcheck
+ 光輝->>光輝: Fight against hypochondria
+ end
+ Note right of 光輝: Rational thoughts!
+ 光輝-->>アリス: Great!
+ 光輝->>Bob: How about you?
+ Bob-->>光輝: Jolly good!
+```
+
+### class diagram
+
+```mermaid
+ classDiagram
+ Animal <|-- Duck
+ Animal <|-- Fish
+ Animal <|-- Zebra
+ Animal : +int age
+ Animal : +String gender
+ Animal: +isMammal()
+ Animal: +mate()
+ class Duck{
+ +String beakColor
+ +swim()
+ +quack()
+ }
+ class Fish{
+ -int sizeInFeet
+ -canEat()
+ }
+ class Zebra{
+ +bool is_wild
+ +run()
+ }
+ callback Duck callback "Tooltip"
+```
+
+
+### state diagram
+
+```mermaid
+stateDiagram-v2
+ [*] --> Active
+
+ state Active {
+ [*] --> NumLockOff
+ NumLockOff --> NumLockOn : EvNumLockPressed
+ NumLockOn --> NumLockOff : EvNumLockPressed
+ --
+ [*] --> CapsLockOff
+ CapsLockOff --> CapsLockOn : EvCapsLockPressed
+ CapsLockOn --> CapsLockOff : EvCapsLockPressed
+ --
+ [*] --> ScrollLockOff
+ ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+ ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+
+ }
+```
+
+
+
+```mermaid
+graph LR
+A:::someclass B
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+```
+
+
+```mermaid
+graph LR;
+ A[""] --> B;
+ alert`md5_salt`-->B;
+ click alert`md5_salt` eval "Tooltip for a callback"
+ click B "javascript:alert('XSS')" "This is a tooltip for a link"
+```
+
+```mermaid
+graph LR;
+ alert`md5_salt`-->B;
+ click alert`md5_salt` eval "Tooltip for a callback"
+ click B "javascript:alert('XSS')" "This is a tooltip for a link"
+ link Zebra "http://www.github.com" "This is a link"
+```
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index 420f7717..935ed0d2 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -1,84 +1,31 @@
---
title: "example"
type: "idea" # or "idea"
-topics:
+topics:
- React
- Rust
emoji: 👩💻
published: false
---
-```mermaid
-graph LR
-A:::someclass B
-classDef someclass fill:#f96;
-
-```
-```mermaid
-graph LR
-id1[(Database)]:::someclass-->B
-classDef someclass fill:#f96;
-
-```
-```mermaid
-%%{init: { 'theme': 'forest' } }%%
-graph LR;
- A-->B & C-->D & E-->F & Z-->X;
- F-->G
- G-->H
- H-->I
- I-->J
- J-->K
- K-->L
- L-->M
- M-->N
- N-->O
- O-->P
-```
+https://twitter.com/jack/status/20
+https://twitter.com/jack/status/20
+https://twitter.com/jack/status/20
-```mermaid
-%%{init: { 'theme': 'forest' } }%%
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
+https://twitter.com/jack/status/20
+https://twitter.com/jack/status/20
-```mermaid
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
-
-```mermaid
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
-
-```mermaid
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
-
-```mermaid
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
-```
+https://twitter.com/jack/status/20
+![](https://octodex.github.com/images/stormtroopocat.jpg =200x)
+*captions*
+dfasdfa
+dfa
+fd
+a
+fafdafdafda
```bash
console.log({
a: "a",
@@ -159,33 +106,33 @@ aaa
[test on markdown-it-textmath](https://goessner.github.io/markdown-it-texmath/index.html)
-$a$
+$a$
-$a\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0\ne0$
+$a\ne0$
$\varphi$
-$1+1=2$
+$1+1=2$
-$1+1<3$
+$1+1<3$
-$a \backslash$
+$a \backslash$
-You get 3$ if you solve $1+2$
+You get 3$ if you solve $1+2$
-If you solve $1+2$ you get $3
+If you solve $1+2$ you get $3
-$\frac{1}{2}$
+$\frac{1}{2}$
-$\begin{pmatrix}x\\y\end{pmatrix}$
+$\begin{pmatrix}x\\y\end{pmatrix}$
-${\tilde\bold e}_\alpha$
+${\tilde\bold e}_\alpha$
-$a^{b}$
+$a^{b}$
-$a^*b$ with $a^*$
+$a^*b$ with $a^*$
-$\sum_{i=1}^n$
+$\sum_{i=1}^n$
fafa
-a
+a
\ No newline at end of file
diff --git a/packages/zenn-embed-elements/src/classes/mermaid.ts b/packages/zenn-embed-elements/src/classes/mermaid.ts
index 71f517d5..108be398 100644
--- a/packages/zenn-embed-elements/src/classes/mermaid.ts
+++ b/packages/zenn-embed-elements/src/classes/mermaid.ts
@@ -24,8 +24,17 @@ async function initMermaid(): Promise {
src: 'https://cdn.jsdelivr.net/npm/mermaid@8.10/dist/mermaid.min.js',
id: 'mermaid-js',
});
- const theme = 'neutral';
+ const theme = 'default';
+ // mermaid 本体がロード時に走らないように設定
+ // mermaid 本体は使わないのでほかは設定しない
+ mermaid!.initialize({
+ mermaid: {
+ startOnLoad: false,
+ },
+ });
+
+ // mermaidAPI の設定
mermaid!.mermaidAPI.initialize({
startOnLoad: false, // レンダリングはこちらでやるので false
securityLevel: 'strict', // tags in text are encoded, click functionality is disabled
@@ -41,8 +50,6 @@ async function initMermaid(): Promise {
useMaxWidth: true,
},
});
-
- console.log(mermaid!.mermaidAPI.getConfig());
}
}
@@ -58,12 +65,17 @@ type PotentialRisk = {
};
function getPotentialPerformanceRisk(source: string): PotentialRisk {
+ const cool = (() => {
+ try {
+ mermaid!.mermaidAPI.parse(source);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ })();
return {
syntaxError: {
- yes: mermaid!.mermaidAPI
- .parse(source)
- .then((_: any) => false)
- .catch((_: any) => true),
+ yes: !cool,
message: `シンタックスエラーです`,
},
charLimitOver: {
@@ -77,17 +89,23 @@ function getPotentialPerformanceRisk(source: string): PotentialRisk {
};
}
-function fixElementContent(content: string) {
- // Mermaid doesn't like `
` tags, so collapse all like tags into `
`, which is parsed correctly.
- return content.replace(/
/g, '
');
-}
-
export class EmbedMermaid extends HTMLElement {
- private _container: HTMLDivElement;
+ // mermaid のソース記述が格納されているpreタグ
+ private readonly _sourceContainer: HTMLPreElement;
+
+ // 描画後の svg を格納するdivタグ ここで作る
+ private readonly _svgContainer: HTMLDivElement;
constructor() {
super();
- this._container = this.childNodes[0] as HTMLDivElement;
+
+ // コード記述が格納されている pre タグを取得
+ this._sourceContainer = this.childNodes[0] as HTMLPreElement;
+
+ // 描画後のSVGを格納する div タグを作成
+ const container = document.createElement('div');
+ this.appendChild(container);
+ this._svgContainer = container;
}
async connectedCallback() {
@@ -96,14 +114,14 @@ export class EmbedMermaid extends HTMLElement {
async render() {
await initMermaid();
- const source = fixElementContent(this._container.innerText || '');
+ const source = this._sourceContainer.innerText || '';
// Mermaid モジュールの読み込みに失敗したり、レンダリング対象のコンテンツが空の場合は何もせずに終了
if (!source) {
return;
}
- // パフォーマンスリスクが検出された場合、注意書きをレンダリングして終了
+ // 文法エラーやパフォーマンスリスクが検出された場合、注意書きをレンダリングして終了
const risk = getPotentialPerformanceRisk(source);
if (
Object.values(risk)
@@ -112,8 +130,9 @@ export class EmbedMermaid extends HTMLElement {
) {
this.innerHTML = `
- mermaidのレンダリングでパフォーマンス上のリスクが検出されました。
+ mermaidをレンダリングできません。
+ ${risk.syntaxError.yes ? risk.syntaxError.message : ''}
${risk.charLimitOver.yes ? risk.charLimitOver.message : ''}
${risk.chainingOfLinksOver.yes ? risk.chainingOfLinksOver.message : ''}
@@ -123,14 +142,19 @@ export class EmbedMermaid extends HTMLElement {
}
// すべて通過した場合はレンダリングする
+ // セキュリティリスクを考慮して bindFunctions は実行しない方針にする
+ // 今回は `securityLevel='strict'` にしているのでどのみち実行されない
+ // securityLevel='loose'にし、かつ `Interaction` を有効にする場合は
+ // https://github.com/mermaidjs/mermaid-gitbook/blob/master/content/usage.md#binding-events
+ // ここを参考に追加する
const insert = (svgCode: string, bindFunctions: any) => {
- this.innerHTML = svgCode;
- bindFunctions(this._container);
+ this._svgContainer.innerHTML = svgCode;
};
mermaid?.mermaidAPI.render(
- `${containerId}-${Date.now().valueOf()}`,
+ `${containerId}-${Date.now().valueOf()}-render`,
source,
- insert
+ insert,
+ this._sourceContainer
);
}
}
diff --git a/packages/zenn-markdown-html/__tests__/mermaid.test.ts b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
index 9c0f8ef4..f9af4f02 100644
--- a/packages/zenn-markdown-html/__tests__/mermaid.test.ts
+++ b/packages/zenn-markdown-html/__tests__/mermaid.test.ts
@@ -1,10 +1,24 @@
import markdownToHtml from '../src/index';
-describe('Detect mermaid propley', () => {
+describe('Detect mermaid property', () => {
test('should generate TD valid code format html', () => {
const html = markdownToHtml(`\`\`\`mermaid\ngraph TD\nA --> B\n\`\`\``);
expect(html).toContain(
- 'graph TD\nA --> B
'
+ ''
+ );
+ });
+ test('should keep directive', () => {
+ const html = markdownToHtml(`\`\`\`mermaid\n%%{init: { 'theme': 'forest' } }%%\ngraph TD\nA --> B\n\`\`\``);
+ expect(html).toContain(
+ '%%{init: { \'theme\': \'forest\' } }%%\ngraph TD\nA --> B
'
+ );
+ });
+ test('should escape html tag', () => {
+ const html = markdownToHtml(
+ `\`\`\`mermaid\ngraph TD\nA --> B\n
\`\`\``
+ );
+ expect(html).toContain(
+ 'graph TD\nA --> B\n<br><script>alert("XSS")</script>```
'
);
});
});
diff --git a/packages/zenn-markdown-html/__tests__/xss.test.ts b/packages/zenn-markdown-html/__tests__/xss.test.ts
index 5178d02b..286d2cbf 100644
--- a/packages/zenn-markdown-html/__tests__/xss.test.ts
+++ b/packages/zenn-markdown-html/__tests__/xss.test.ts
@@ -44,4 +44,12 @@ describe('No XSS Vulnerability', () => {
''
);
});
+ test('should escape img tag around mermaid syntax', () => {
+ const html = markdownToHtml(
+ `\`\`\`mermaid\ngraph TD\nA[""] --> B\`\`\``
+ );
+ expect(html).toContain(
+ 'graph TD\nA["<img src="invalid" onerror=alert(\'XSS\')/>"] --> B```
'
+ );
+ });
});
diff --git a/packages/zenn-markdown-html/src/utils/md-mermaid.ts b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
index 6204d545..242d0d0e 100644
--- a/packages/zenn-markdown-html/src/utils/md-mermaid.ts
+++ b/packages/zenn-markdown-html/src/utils/md-mermaid.ts
@@ -10,7 +10,9 @@ export function mdMermaid(md: MarkdownIt) {
const langInfo = tokens[idx];
if (langInfo.info === 'mermaid') {
const code = langInfo.content.trim();
- return `${code}
`;
+ return `${md.utils.escapeHtml(
+ code
+ )}
`;
}
return defaultRender(tokens, idx, options, env, slf);
};
From d6230647ab924a2dd17be0f22d7ede9f91be621e Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sat, 5 Jun 2021 23:58:16 +0900
Subject: [PATCH 07/10] reset
---
packages/example/articles/example.md | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index 935ed0d2..de9b4bc1 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -1,7 +1,7 @@
---
title: "example"
type: "idea" # or "idea"
-topics:
+topics:
- React
- Rust
emoji: 👩💻
@@ -106,33 +106,33 @@ aaa
[test on markdown-it-textmath](https://goessner.github.io/markdown-it-texmath/index.html)
-$a$
+$a$
$a\ne0$
$\varphi$
-$1+1=2$
+$1+1=2$
-$1+1<3$
+$1+1<3$
-$a \backslash$
+$a \backslash$
-You get 3$ if you solve $1+2$
+You get 3$ if you solve $1+2$
-If you solve $1+2$ you get $3
+If you solve $1+2$ you get $3
-$\frac{1}{2}$
+$\frac{1}{2}$
-$\begin{pmatrix}x\\y\end{pmatrix}$
+$\begin{pmatrix}x\\y\end{pmatrix}$
-${\tilde\bold e}_\alpha$
+${\tilde\bold e}_\alpha$
-$a^{b}$
+$a^{b}$
-$a^*b$ with $a^*$
+$a^*b$ with $a^*$
-$\sum_{i=1}^n$
+$\sum_{i=1}^n$
fafa
a
\ No newline at end of file
From 11a6f756e9a64c270fa91ad398f2075a6d6faeee Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sun, 6 Jun 2021 00:02:17 +0900
Subject: [PATCH 08/10] fix example
---
packages/example/articles/embed.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/example/articles/embed.md b/packages/example/articles/embed.md
index e01ba6aa..56b57026 100644
--- a/packages/example/articles/embed.md
+++ b/packages/example/articles/embed.md
@@ -102,7 +102,6 @@ sequenceDiagram
+bool is_wild
+run()
}
- callback Duck callback "Tooltip"
```
From ac93508d5a436963acda8b5d83fd234829cd75c0 Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Sun, 6 Jun 2021 10:01:07 +0900
Subject: [PATCH 09/10] =?UTF-8?q?embed=20=E3=81=A7=E3=81=AF=E3=81=AA?=
=?UTF-8?q?=E3=81=8F=20example=20=E3=81=AB=E5=85=A5=E3=82=8C=E3=81=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/example/articles/embed.md | 188 --------------------------
packages/example/articles/example.md | 191 ++++++++++++++++++++++++++-
2 files changed, 190 insertions(+), 189 deletions(-)
diff --git a/packages/example/articles/embed.md b/packages/example/articles/embed.md
index 56b57026..a2d8b9ed 100644
--- a/packages/example/articles/embed.md
+++ b/packages/example/articles/embed.md
@@ -23,191 +23,3 @@ https://gist.github.com/mattpodwysocki/218388
@[gist](https://gist.github.com/hofmannsven/9164408?file=my.cnf)
ssfafafaffafa
-
-
-## mermaid.js
-
-```mermaid
-%%{init: { 'theme': 'forest' } }%%
-graph LR;
- A-->B & C-->D & E-->F & Z-->X;
- F-->G
- G-->H
- H-->I
- I-->J
- J-->K
- K-->L
- L-->M
- M-->N
- N-->O
- O-->P
- P-->ID1[ノード1
ノード2]
-```
-
-### flowchart
-
-```mermaid
-flowchart TB
- c1-->a2
- subgraph one
- a1-->a2
- end
- subgraph two
- b1-->b2
- end
- subgraph three
- c1-->c2
- end
- one --> two
- three --> two
- two --> c2
-```
-
-### sequence diagram
-
-```mermaid
-sequenceDiagram
- autonumber
- アリス->>光輝: Hello John, how are you?
- loop Healthcheck
- 光輝->>光輝: Fight against hypochondria
- end
- Note right of 光輝: Rational thoughts!
- 光輝-->>アリス: Great!
- 光輝->>Bob: How about you?
- Bob-->>光輝: Jolly good!
-```
-
-### class diagram
-
-```mermaid
- classDiagram
- Animal <|-- Duck
- Animal <|-- Fish
- Animal <|-- Zebra
- Animal : +int age
- Animal : +String gender
- Animal: +isMammal()
- Animal: +mate()
- class Duck{
- +String beakColor
- +swim()
- +quack()
- }
- class Fish{
- -int sizeInFeet
- -canEat()
- }
- class Zebra{
- +bool is_wild
- +run()
- }
-```
-
-
-### state diagram
-
-```mermaid
-stateDiagram-v2
- [*] --> Active
-
- state Active {
- [*] --> NumLockOff
- NumLockOff --> NumLockOn : EvNumLockPressed
- NumLockOn --> NumLockOff : EvNumLockPressed
- --
- [*] --> CapsLockOff
- CapsLockOff --> CapsLockOn : EvCapsLockPressed
- CapsLockOn --> CapsLockOff : EvCapsLockPressed
- --
- [*] --> ScrollLockOff
- ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
- ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
-
- }
-```
-
-
-
-```mermaid
-graph LR
-A:::someclass B
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
-classDef someclass fill:#f96;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
- A-->B & C-->D & E-->F & Z-->X;
-```
-
-
-```mermaid
-graph LR;
- A[""] --> B;
- alert`md5_salt`-->B;
- click alert`md5_salt` eval "Tooltip for a callback"
- click B "javascript:alert('XSS')" "This is a tooltip for a link"
-```
-
-```mermaid
-graph LR;
- alert`md5_salt`-->B;
- click alert`md5_salt` eval "Tooltip for a callback"
- click B "javascript:alert('XSS')" "This is a tooltip for a link"
- link Zebra "http://www.github.com" "This is a link"
-```
diff --git a/packages/example/articles/example.md b/packages/example/articles/example.md
index de9b4bc1..7722231d 100644
--- a/packages/example/articles/example.md
+++ b/packages/example/articles/example.md
@@ -135,4 +135,193 @@ $a^*b$ with $a^*$
$\sum_{i=1}^n$
fafa
-a
\ No newline at end of file
+a
+
+
+
+## mermaid.js
+
+```mermaid
+%%{init: { 'theme': 'forest' } }%%
+graph LR;
+ A-->B & C-->D & E-->F & Z-->X;
+ F-->G
+ G-->H
+ H-->I
+ I-->J
+ J-->K
+ K-->L
+ L-->M
+ M-->N
+ N-->O
+ O-->P
+ P-->ID1[ノード1
ノード2]
+```
+
+### flowchart
+
+```mermaid
+flowchart TB
+ c1-->a2
+ subgraph one
+ a1-->a2
+ end
+ subgraph two
+ b1-->b2
+ end
+ subgraph three
+ c1-->c2
+ end
+ one --> two
+ three --> two
+ two --> c2
+```
+
+### sequence diagram
+
+```mermaid
+sequenceDiagram
+ autonumber
+ アリス->>光輝: Hello John, how are you?
+ loop Healthcheck
+ 光輝->>光輝: Fight against hypochondria
+ end
+ Note right of 光輝: Rational thoughts!
+ 光輝-->>アリス: Great!
+ 光輝->>Bob: How about you?
+ Bob-->>光輝: Jolly good!
+```
+
+### class diagram
+
+```mermaid
+ classDiagram
+ Animal <|-- Duck
+ Animal <|-- Fish
+ Animal <|-- Zebra
+ Animal : +int age
+ Animal : +String gender
+ Animal: +isMammal()
+ Animal: +mate()
+ class Duck{
+ +String beakColor
+ +swim()
+ +quack()
+ }
+ class Fish{
+ -int sizeInFeet
+ -canEat()
+ }
+ class Zebra{
+ +bool is_wild
+ +run()
+ }
+```
+
+
+### state diagram
+
+```mermaid
+stateDiagram-v2
+ [*] --> Active
+
+ state Active {
+ [*] --> NumLockOff
+ NumLockOff --> NumLockOn : EvNumLockPressed
+ NumLockOn --> NumLockOff : EvNumLockPressed
+ --
+ [*] --> CapsLockOff
+ CapsLockOff --> CapsLockOn : EvCapsLockPressed
+ CapsLockOn --> CapsLockOff : EvCapsLockPressed
+ --
+ [*] --> ScrollLockOff
+ ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+ ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+
+ }
+```
+
+
+
+```mermaid
+graph LR
+A:::someclass B
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+classDef someclass fill:#f96;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+ A-->B & C-->D & E-->F & Z-->X;
+```
+
+
+```mermaid
+graph LR;
+ A[""] --> B;
+ alert`md5_salt`-->B;
+ click alert`md5_salt` eval "Tooltip for a callback"
+ click B "javascript:alert('XSS')" "This is a tooltip for a link"
+```
+
+```mermaid
+graph LR;
+ alert`md5_salt`-->B;
+ click alert`md5_salt` eval "Tooltip for a callback"
+ click B "javascript:alert('XSS')" "This is a tooltip for a link"
+ link Zebra "http://www.github.com" "This is a link"
+```
From a4d07014aef99ed9970cfb0782074bed281b773d Mon Sep 17 00:00:00 2001
From: Yusuke Wada
Date: Mon, 7 Jun 2021 13:15:03 +0900
Subject: [PATCH 10/10] =?UTF-8?q?=E3=83=91=E3=83=BC=E3=82=B9=E3=82=A8?=
=?UTF-8?q?=E3=83=A9=E3=83=BC=E7=99=BA=E7=94=9F=E6=99=82=E3=81=AB=E3=83=AD?=
=?UTF-8?q?=E3=82=B0=E5=87=BA=E5=8A=9B=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?=
=?UTF-8?q?=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/zenn-embed-elements/src/classes/mermaid.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/packages/zenn-embed-elements/src/classes/mermaid.ts b/packages/zenn-embed-elements/src/classes/mermaid.ts
index 108be398..3703252b 100644
--- a/packages/zenn-embed-elements/src/classes/mermaid.ts
+++ b/packages/zenn-embed-elements/src/classes/mermaid.ts
@@ -70,6 +70,10 @@ function getPotentialPerformanceRisk(source: string): PotentialRisk {
mermaid!.mermaidAPI.parse(source);
return true;
} catch (e) {
+ console.log(
+ 'mermaid.js のレンダリングでシンタックスエラーが発生しました',
+ e
+ );
return false;
}
})();