@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 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
- ` ```mermaid ` のコードブロックは `figure.rr-mermaid` に置き換わります。図のタイトルはコードブロックの title、またはソース内の `%% caption: ...` 行から取得します。図には代替テキスト相当の `role="img"` を付け、必要に応じて元の記法を折りたたみ表示します。
32
+ このサイトでは `mermaid` フェンスを headless browser 版ではなく Mermaid (Pele) で描画しています。どちらのプラグインも同じフェンスを受け付けます。
33
33
 
34
- `render: "build"` では、Puppeteer が起動するヘッドレス Chromium 上で Mermaid を実行し、静的な SVG を生成します。簡易な DOM 実装や寸法の推測には頼らないため、ブラウザと同じレイアウトエンジンで図を作れます。Mermaid は `securityLevel: "strict"` で実行されます。
34
+ ~~~mermaid
35
+ flowchart LR
36
+ Draft --> Review --> Published
37
+ ~~~
35
38
 
36
- 構文エラーは `invalid-diagram`、描画環境の問題は `renderer-error` として区別して診断します。ビルド時の描画に失敗した場合、既定ではビルドを失敗させます。失敗した図を成功したコンテンツとして保存しません。SVG ID は図の ID をシードにして決定的に生成します。
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` は保留中の図だけを描画します。Mermaid のインスタンスがなければ jsDelivr から Mermaid 11 を読み込みます。描画に失敗した場合は `data-mermaid="error"` となり、CSS のプレースホルダー表示に切り替わります。
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"` を指定するときだけ、ビルド時の描画失敗をクライアント側へ明示的に委譲します。この設定では生成HTMLが描画環境の可用性に依存します。
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(options = {}) {
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 = document.querySelectorAll(
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
- await renderDiagram(mermaid, diagram, index);
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
- function visitElements(node, visitor, parent, index) {
18
- if (isElementNode(node)) visitor(node, parent, index);
19
- for (const [childIndex, child] of [...getChildren(node)].entries()) {
20
- visitElements(
21
- child,
22
- visitor,
23
- hasChildren(node) ? node : parent,
24
- childIndex
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("details", { className: "rr-mermaid__fallback" }, [
139
- element("summary", {}, [text("Diagram source")]),
140
- element("pre", {}, [element("code", {}, [text(input.source)])])
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
  });
@@ -1,8 +1,7 @@
1
1
  import type { ElementNode, HastNode, ParentNode, TextNode } from "./types.js";
2
- export declare function visitElements(node: HastNode, visitor: (node: ElementNode, parent?: ParentNode, index?: number) => void, parent?: ParentNode, index?: number): void;
3
- export declare function element(tagName: string, properties?: Record<string, unknown>, children?: HastNode[]): ElementNode;
4
- export declare function text(value: string): TextNode;
5
- export declare function getTextContent(node: HastNode): string;
6
- export declare function getStringProperty(node: ElementNode, key: string): string | null;
7
- export declare function hasClass(node: ElementNode, className: string): boolean;
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;
@@ -1,2 +1,8 @@
1
1
  import type { MermaidClientOptions } from "./types.js";
2
- export declare function initMermaidDiagrams(options?: MermaidClientOptions): Promise<void>;
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
- export declare const MERMAID_HEADLESS_MODE: "shell";
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 {};
@@ -20,7 +20,7 @@ export type MermaidBuildRenderResult = {
20
20
  kind: MermaidBuildRenderErrorKind;
21
21
  message: string;
22
22
  };
23
- export type MermaidBuildRenderer = (id: string, source: string, theme: string) => Promise<MermaidBuildRenderResult>;
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
- export type MermaidApi = {
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
- export type RawNode = {
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.31",
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.11.0",
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.";