@riebeckite/plugin-mermaid 0.0.31 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/README_ja.md +18 -7
- package/dist/client.js +9 -4
- package/dist/index.js +27 -49
- package/dist/src/hast.d.ts +6 -7
- package/dist/src/init.d.ts +7 -1
- package/dist/src/render-static.d.ts +2 -3
- package/dist/src/types.d.ts +4 -3
- package/package.json +4 -3
- package/style.css +0 -20
package/README.md
CHANGED
|
@@ -31,6 +31,17 @@ export default defineConfig({
|
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## Live example
|
|
35
|
+
|
|
36
|
+
This site renders `mermaid` fences with Mermaid (Pele), not the headless browser build. Both plugins accept the same fence:
|
|
37
|
+
|
|
38
|
+
~~~mermaid
|
|
39
|
+
flowchart LR
|
|
40
|
+
Draft --> Review --> Published
|
|
41
|
+
~~~
|
|
42
|
+
|
|
43
|
+
See [Mermaid (Pele)](../mermaid-pele/README.md) for the renderer used here.
|
|
44
|
+
|
|
34
45
|
## Behavior
|
|
35
46
|
|
|
36
47
|
### Build
|
package/README_ja.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
ヘッドレスブラウザを使わずに静的 SVG を生成したい場合は [Mermaid (Pele)](../mermaid-pele/README_ja.md) を使ってください。
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 使い方
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import { defineConfig } from "@riebeckite/core";
|
|
@@ -27,17 +27,28 @@ export default defineConfig({
|
|
|
27
27
|
|
|
28
28
|
このプラグインは `order: -10` で実行されます。Mermaid のコードブロックを先に処理したい場合に適した順序です。
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## 実行例
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
このサイトでは `mermaid` フェンスを headless browser 版ではなく Mermaid (Pele) で描画しています。どちらのプラグインも同じフェンスを受け付けます。
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
~~~mermaid
|
|
35
|
+
flowchart LR
|
|
36
|
+
Draft --> Review --> Published
|
|
37
|
+
~~~
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
ここで使っている描画器は [Mermaid (Pele)](../mermaid-pele/README_ja.md) です。
|
|
40
|
+
|
|
41
|
+
## 描画の仕組み
|
|
42
|
+
|
|
43
|
+
` ```mermaid ` のコードブロックは `figure.rr-mermaid` に置き換わります。図のタイトルはコードブロックの `title`、またはソース内の `%% caption: ...` 行から取得します。図には `role="img"` を付け、キャプションがあればそれをラベルにします。元の記法は必要に応じて折りたたみで残します。
|
|
44
|
+
|
|
45
|
+
`render: "build"` では、Puppeteer が起動するヘッドレス Chromium 上で Mermaid を実行し、静的な SVG を生成します。JSDOM のような簡易な DOM 実装や寸法の推測には頼らないため、ブラウザと同じレイアウトエンジンで図を作れます。Mermaid は `securityLevel: "strict"` で実行されます。
|
|
46
|
+
|
|
47
|
+
構文エラーは `invalid-diagram`、描画環境の問題は `renderer-error` として区別して診断します。ビルド時の描画に失敗した場合、既定ではビルドを失敗させます。失敗した描画が成功したコンテンツとして保存されることはありません。SVG ID は図の ID をシードにして決定的に生成します。
|
|
37
48
|
|
|
38
49
|
## クライアント側の再試行
|
|
39
50
|
|
|
40
|
-
`initMermaidDiagrams`
|
|
51
|
+
`initMermaidDiagrams` は未描画の図だけを描画します。Mermaid のインスタンスがなければ jsDelivr から Mermaid 11 を読み込みます。描画に失敗した場合は `data-mermaid="error"` となり、CSS のプレースホルダー表示に切り替わります。
|
|
41
52
|
|
|
42
53
|
明暗別のテーマを指定した場合は、`html[data-theme]` を優先し、なければ OS の配色設定に従います。
|
|
43
54
|
|
|
@@ -51,7 +62,7 @@ export default defineConfig({
|
|
|
51
62
|
| `caption` | `true` | タイトルまたは `%% caption:` をキャプションとして表示する |
|
|
52
63
|
| `fallback` | `true` | 元の Mermaid 記法を `<details>` に残す |
|
|
53
64
|
|
|
54
|
-
`"client"` はビルド時の描画を行いません。`render: "build"` で `onRenderError: "client"`
|
|
65
|
+
`"client"` はビルド時の描画を行いません。`render: "build"` で `onRenderError: "client"` を指定するときだけ、ビルド時の描画失敗をクライアント側へ明示的に委譲します。この設定では、生成される HTML がレンダラーの可用性に左右されます。
|
|
55
66
|
|
|
56
67
|
## 主なエクスポート
|
|
57
68
|
|
package/dist/client.js
CHANGED
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
// src/init.ts
|
|
2
2
|
var DEFAULT_THEME = { light: "default", dark: "dark" };
|
|
3
3
|
var DEFAULT_SCRIPT_URL = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js";
|
|
4
|
-
async function initMermaidDiagrams(
|
|
4
|
+
async function initMermaidDiagrams(context = {}) {
|
|
5
|
+
const options = context.config ?? {};
|
|
6
|
+
const root = context.root ?? document;
|
|
5
7
|
const mermaid = options.mermaid ?? await loadMermaid(options.scriptUrl);
|
|
6
8
|
if (!mermaid) return;
|
|
9
|
+
if (context.signal?.aborted) return;
|
|
7
10
|
mermaid.initialize({
|
|
8
11
|
startOnLoad: false,
|
|
9
12
|
securityLevel: "strict",
|
|
10
13
|
theme: selectTheme(options.theme ?? DEFAULT_THEME)
|
|
11
14
|
});
|
|
12
|
-
const diagrams =
|
|
15
|
+
const diagrams = root.querySelectorAll(
|
|
13
16
|
'.rr-mermaid[data-mermaid="pending"]'
|
|
14
17
|
);
|
|
15
18
|
for (const [index, diagram] of Array.from(diagrams).entries()) {
|
|
16
|
-
|
|
19
|
+
if (context.signal?.aborted || !diagram.isConnected) return;
|
|
20
|
+
await renderDiagram(mermaid, diagram, index, context.signal);
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
|
-
async function renderDiagram(mermaid, diagram, index) {
|
|
23
|
+
async function renderDiagram(mermaid, diagram, index, signal) {
|
|
20
24
|
const source = diagram.dataset.mermaidSource;
|
|
21
25
|
const canvas = diagram.querySelector(".rr-mermaid__canvas");
|
|
22
26
|
if (!source || !canvas) return;
|
|
23
27
|
try {
|
|
24
28
|
const { svg } = await mermaid.render(`rr-mermaid-client-${index}`, source);
|
|
29
|
+
if (signal?.aborted || !diagram.isConnected) return;
|
|
25
30
|
canvas.innerHTML = svg;
|
|
26
31
|
diagram.removeAttribute("data-mermaid");
|
|
27
32
|
} catch {
|
package/dist/index.js
CHANGED
|
@@ -14,52 +14,23 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/hast.ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function element(tagName, properties = {}, children = []) {
|
|
29
|
-
return { type: "element", tagName, properties, children };
|
|
30
|
-
}
|
|
31
|
-
function text(value) {
|
|
32
|
-
return { type: "text", value };
|
|
33
|
-
}
|
|
34
|
-
function getTextContent(node) {
|
|
35
|
-
if (node.type === "text" && "value" in node && typeof node.value === "string") {
|
|
36
|
-
return node.value;
|
|
37
|
-
}
|
|
38
|
-
return getChildren(node).map(getTextContent).join("");
|
|
39
|
-
}
|
|
40
|
-
function getStringProperty(node, key) {
|
|
41
|
-
const value = node.properties?.[key];
|
|
42
|
-
if (typeof value === "string") return value;
|
|
43
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
function hasClass(node, className) {
|
|
47
|
-
const value = node.properties?.className;
|
|
48
|
-
const classes = Array.isArray(value) ? value.map(String) : typeof value === "string" ? value.split(/\s+/) : [];
|
|
49
|
-
return classes.includes(className);
|
|
50
|
-
}
|
|
51
|
-
function isElementNode(node) {
|
|
52
|
-
return node.type === "element";
|
|
53
|
-
}
|
|
54
|
-
function hasChildren(node) {
|
|
55
|
-
return Array.isArray(node.children);
|
|
56
|
-
}
|
|
57
|
-
function getChildren(node) {
|
|
58
|
-
const children = node.children;
|
|
59
|
-
return Array.isArray(children) ? children : [];
|
|
60
|
-
}
|
|
17
|
+
import {
|
|
18
|
+
element as sharedElement,
|
|
19
|
+
getStringProperty as sharedGetStringProperty,
|
|
20
|
+
getTextContent as sharedGetTextContent,
|
|
21
|
+
hasClass as sharedHasClass,
|
|
22
|
+
text as sharedText,
|
|
23
|
+
visitElements as sharedVisitElements
|
|
24
|
+
} from "@riebeckite/diagram";
|
|
25
|
+
var element, text, getTextContent, getStringProperty, hasClass, visitElements;
|
|
61
26
|
var init_hast = __esm({
|
|
62
27
|
"src/hast.ts"() {
|
|
28
|
+
element = sharedElement;
|
|
29
|
+
text = sharedText;
|
|
30
|
+
getTextContent = sharedGetTextContent;
|
|
31
|
+
getStringProperty = sharedGetStringProperty;
|
|
32
|
+
hasClass = sharedHasClass;
|
|
33
|
+
visitElements = sharedVisitElements;
|
|
63
34
|
}
|
|
64
35
|
});
|
|
65
36
|
|
|
@@ -135,10 +106,14 @@ function buildFigure(input) {
|
|
|
135
106
|
);
|
|
136
107
|
if (input.fallback) {
|
|
137
108
|
children.push(
|
|
138
|
-
element(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
109
|
+
element(
|
|
110
|
+
"details",
|
|
111
|
+
{ className: "rr-mermaid__fallback rb-source-fallback" },
|
|
112
|
+
[
|
|
113
|
+
element("summary", {}, [text("Diagram source")]),
|
|
114
|
+
element("pre", {}, [element("code", {}, [text(input.source)])])
|
|
115
|
+
]
|
|
116
|
+
)
|
|
142
117
|
);
|
|
143
118
|
}
|
|
144
119
|
return element(
|
|
@@ -538,7 +513,10 @@ function mermaid(options = {}) {
|
|
|
538
513
|
createClientEntry(
|
|
539
514
|
"mermaid",
|
|
540
515
|
"@riebeckite/plugin-mermaid/client",
|
|
541
|
-
"initMermaidDiagrams"
|
|
516
|
+
"initMermaidDiagrams",
|
|
517
|
+
void 0,
|
|
518
|
+
void 0,
|
|
519
|
+
"context"
|
|
542
520
|
)
|
|
543
521
|
]
|
|
544
522
|
});
|
package/dist/src/hast.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ElementNode, HastNode, ParentNode, TextNode } from "./types.js";
|
|
2
|
-
export declare
|
|
3
|
-
export declare
|
|
4
|
-
export declare
|
|
5
|
-
export declare
|
|
6
|
-
export declare
|
|
7
|
-
export declare
|
|
8
|
-
export declare function mergeClassName(current: unknown, next: string): string;
|
|
2
|
+
export declare const element: (tagName: string, properties?: Record<string, unknown>, children?: HastNode[]) => ElementNode;
|
|
3
|
+
export declare const text: (value: string) => TextNode;
|
|
4
|
+
export declare const getTextContent: (node: HastNode) => string;
|
|
5
|
+
export declare const getStringProperty: (node: ElementNode, key: string) => string | null;
|
|
6
|
+
export declare const hasClass: (node: ElementNode, className: string) => boolean;
|
|
7
|
+
export declare const visitElements: (node: HastNode, visitor: (node: ElementNode, parent?: ParentNode, index?: number) => void, parent?: ParentNode, index?: number) => void;
|
package/dist/src/init.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import type { MermaidClientOptions } from "./types.js";
|
|
2
|
-
|
|
2
|
+
type ClientContext = {
|
|
3
|
+
root?: ParentNode;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
config?: MermaidClientOptions;
|
|
6
|
+
};
|
|
7
|
+
export declare function initMermaidDiagrams(context?: ClientContext): Promise<void>;
|
|
8
|
+
export {};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { Browser } from "puppeteer";
|
|
2
2
|
import type { MermaidRenderSession } from "./types.js";
|
|
3
|
-
|
|
4
|
-
export declare const MERMAID_PUPPETEER_BROWSER = "chrome-headless-shell";
|
|
5
|
-
export type MermaidSessionDependencies = {
|
|
3
|
+
type MermaidSessionDependencies = {
|
|
6
4
|
/**
|
|
7
5
|
* Overrides browser launch. Tests inject a fake browser so session
|
|
8
6
|
* lifecycle can be asserted without launching Chrome.
|
|
@@ -21,3 +19,4 @@ export type MermaidSessionDependencies = {
|
|
|
21
19
|
* the plugin `buildEnd`/`dispose` hooks.
|
|
22
20
|
*/
|
|
23
21
|
export declare function createMermaidRenderSession(dependencies?: MermaidSessionDependencies): MermaidRenderSession;
|
|
22
|
+
export {};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type MermaidBuildRenderResult = {
|
|
|
20
20
|
kind: MermaidBuildRenderErrorKind;
|
|
21
21
|
message: string;
|
|
22
22
|
};
|
|
23
|
-
|
|
23
|
+
type MermaidBuildRenderer = (id: string, source: string, theme: string) => Promise<MermaidBuildRenderResult>;
|
|
24
24
|
/**
|
|
25
25
|
* Build-scoped render resource. Owns one browser/page session, serializes
|
|
26
26
|
* renders, and releases the browser on `dispose`.
|
|
@@ -34,7 +34,7 @@ export type MermaidClientOptions = {
|
|
|
34
34
|
mermaid?: MermaidApi;
|
|
35
35
|
scriptUrl?: string;
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
type MermaidApi = {
|
|
38
38
|
initialize(options: Record<string, unknown>): void;
|
|
39
39
|
render(id: string, source: string): Promise<{
|
|
40
40
|
svg: string;
|
|
@@ -55,7 +55,7 @@ export type TextNode = {
|
|
|
55
55
|
type: "text";
|
|
56
56
|
value: string;
|
|
57
57
|
};
|
|
58
|
-
|
|
58
|
+
type RawNode = {
|
|
59
59
|
type: "raw";
|
|
60
60
|
value: string;
|
|
61
61
|
};
|
|
@@ -63,3 +63,4 @@ export type HastNode = ElementNode | TextNode | RawNode | {
|
|
|
63
63
|
type: string;
|
|
64
64
|
[key: string]: unknown;
|
|
65
65
|
};
|
|
66
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-mermaid",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
"./style.css": "./style.css"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@riebeckite/core": "0.0.33",
|
|
25
|
+
"@riebeckite/diagram": "0.0.33",
|
|
24
26
|
"mermaid": "^11.12.2",
|
|
25
|
-
"puppeteer": "^25.
|
|
26
|
-
"@riebeckite/core": "0.0.31"
|
|
27
|
+
"puppeteer": "^25.16.0"
|
|
27
28
|
},
|
|
28
29
|
"publishConfig": {
|
|
29
30
|
"access": "public"
|
package/style.css
CHANGED
|
@@ -36,26 +36,6 @@
|
|
|
36
36
|
height: auto;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
.rr-mermaid__fallback {
|
|
40
|
-
border-top: 1px solid var(--rr-mermaid-rule);
|
|
41
|
-
color: var(--rr-mermaid-muted);
|
|
42
|
-
font-size: 0.8125rem;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.rr-mermaid__fallback summary {
|
|
46
|
-
cursor: pointer;
|
|
47
|
-
padding: 0.5rem 0.75rem;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.rr-mermaid__fallback pre {
|
|
51
|
-
overflow: auto;
|
|
52
|
-
margin: 0 1rem;
|
|
53
|
-
padding: 0.75rem;
|
|
54
|
-
border-top: 1px solid var(--rr-mermaid-rule);
|
|
55
|
-
color: var(--rr-mermaid-ink);
|
|
56
|
-
background: color-mix(in srgb, var(--rr-mermaid-ink) 6%, transparent);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
39
|
.rr-mermaid[data-mermaid="error"] .rr-mermaid__canvas::before,
|
|
60
40
|
.rr-mermaid[data-mermaid="pending"] .rr-mermaid__canvas:empty::before {
|
|
61
41
|
content: "Diagram could not be rendered.";
|