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
    ' + '
    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; } })();