@riebeckite/plugin-mermaid 0.0.14 → 0.0.15
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 +2 -1
- package/README_ja.md +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +238 -172
- package/dist/src/rehype.d.ts +2 -2
- package/dist/src/render-static.d.ts +20 -2
- package/dist/src/types.d.ts +8 -0
- package/package.json +4 -3
package/README.md
CHANGED
package/README_ja.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { MermaidOptions } from "./src/types.js";
|
|
2
|
-
export type { MermaidClientOptions, MermaidOptions, MermaidRenderMode, MermaidTheme, } from "./src/types.js";
|
|
2
|
+
export type { MermaidClientOptions, MermaidOptions, MermaidRenderMode, MermaidRenderSession, MermaidTheme, } from "./src/types.js";
|
|
3
3
|
export declare function mermaid(options?: MermaidOptions): import("@riebeckite/core").RiebeckitePlugin<MermaidOptions>;
|
package/dist/index.js
CHANGED
|
@@ -63,175 +63,12 @@ var init_hast = __esm({
|
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
// src/render-static.ts
|
|
67
|
-
var render_static_exports = {};
|
|
68
|
-
__export(render_static_exports, {
|
|
69
|
-
renderMermaidStaticSvg: () => renderMermaidStaticSvg
|
|
70
|
-
});
|
|
71
|
-
import { access, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
72
|
-
import { tmpdir } from "node:os";
|
|
73
|
-
import { join } from "node:path";
|
|
74
|
-
import { fileURLToPath } from "node:url";
|
|
75
|
-
async function renderWithBrowser(scriptPath) {
|
|
76
|
-
const browser = await launchBrowser();
|
|
77
|
-
const page = await browser.newPage();
|
|
78
|
-
try {
|
|
79
|
-
page.setDefaultTimeout(RENDER_TIMEOUT_MS);
|
|
80
|
-
await page.setContent("<!doctype html><html><body></body></html>");
|
|
81
|
-
await page.addScriptTag({ path: await resolveMermaidScriptPath() });
|
|
82
|
-
await page.addScriptTag({ path: scriptPath });
|
|
83
|
-
const result = await page.evaluate(() => {
|
|
84
|
-
return globalThis.__rrMermaidResult;
|
|
85
|
-
});
|
|
86
|
-
return normalizeRenderResult(result);
|
|
87
|
-
} catch (error) {
|
|
88
|
-
return {
|
|
89
|
-
ok: false,
|
|
90
|
-
kind: "renderer-error",
|
|
91
|
-
message: formatError(error)
|
|
92
|
-
};
|
|
93
|
-
} finally {
|
|
94
|
-
await page.close();
|
|
95
|
-
await browser.close();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
async function resolveMermaidScriptPath() {
|
|
99
|
-
const candidates = [
|
|
100
|
-
resolveWithImportMeta(),
|
|
101
|
-
fileURLToPath(
|
|
102
|
-
new URL(`../node_modules/${MERMAID_SCRIPT_SUBPATH}`, import.meta.url)
|
|
103
|
-
),
|
|
104
|
-
join(process.cwd(), "node_modules", MERMAID_SCRIPT_SUBPATH),
|
|
105
|
-
join(
|
|
106
|
-
process.cwd(),
|
|
107
|
-
"..",
|
|
108
|
-
"..",
|
|
109
|
-
"packages",
|
|
110
|
-
"plugin-mermaid",
|
|
111
|
-
"node_modules",
|
|
112
|
-
MERMAID_SCRIPT_SUBPATH
|
|
113
|
-
)
|
|
114
|
-
].filter((path) => typeof path === "string");
|
|
115
|
-
for (const candidate of candidates) {
|
|
116
|
-
if (await fileExists(candidate)) return candidate;
|
|
117
|
-
}
|
|
118
|
-
return candidates.at(0) ?? MERMAID_SCRIPT_SUBPATH;
|
|
119
|
-
}
|
|
120
|
-
function resolveWithImportMeta() {
|
|
121
|
-
const resolver = import.meta.resolve;
|
|
122
|
-
if (typeof resolver !== "function") return void 0;
|
|
123
|
-
return fileURLToPath(resolver(MERMAID_SCRIPT_SUBPATH));
|
|
124
|
-
}
|
|
125
|
-
async function fileExists(path) {
|
|
126
|
-
try {
|
|
127
|
-
await access(path);
|
|
128
|
-
return true;
|
|
129
|
-
} catch {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
async function launchBrowser() {
|
|
134
|
-
const puppeteer = await importPuppeteer();
|
|
135
|
-
return puppeteer.default.launch({
|
|
136
|
-
headless: "shell",
|
|
137
|
-
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
async function importPuppeteer() {
|
|
141
|
-
const importModule = new Function(
|
|
142
|
-
"specifier",
|
|
143
|
-
"return import(specifier)"
|
|
144
|
-
);
|
|
145
|
-
return importModule("puppeteer");
|
|
146
|
-
}
|
|
147
|
-
function buildRenderScript(id, source, theme) {
|
|
148
|
-
return `
|
|
149
|
-
(async () => {
|
|
150
|
-
try {
|
|
151
|
-
mermaid.initialize({
|
|
152
|
-
startOnLoad: false,
|
|
153
|
-
securityLevel: "strict",
|
|
154
|
-
theme: ${JSON.stringify(theme)},
|
|
155
|
-
});
|
|
156
|
-
const { svg } = await mermaid.render(
|
|
157
|
-
${JSON.stringify(id)},
|
|
158
|
-
${JSON.stringify(source)},
|
|
159
|
-
);
|
|
160
|
-
globalThis.__rrMermaidResult = { ok: true, svg };
|
|
161
|
-
} catch (error) {
|
|
162
|
-
globalThis.__rrMermaidResult = {
|
|
163
|
-
ok: false,
|
|
164
|
-
kind: "invalid-diagram",
|
|
165
|
-
message: error instanceof Error ? error.message : String(error),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
})();
|
|
169
|
-
`;
|
|
170
|
-
}
|
|
171
|
-
function normalizeRenderResult(value) {
|
|
172
|
-
if (!value || typeof value !== "object") {
|
|
173
|
-
return {
|
|
174
|
-
ok: false,
|
|
175
|
-
kind: "renderer-error",
|
|
176
|
-
message: "Mermaid renderer returned no result."
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
const result = value;
|
|
180
|
-
if (result.ok === true && typeof result.svg === "string") {
|
|
181
|
-
return { ok: true, svg: result.svg };
|
|
182
|
-
}
|
|
183
|
-
if (result.ok === false) {
|
|
184
|
-
return {
|
|
185
|
-
ok: false,
|
|
186
|
-
kind: normalizeErrorKind(result.kind),
|
|
187
|
-
message: typeof result.message === "string" ? result.message : "Mermaid renderer failed."
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
return {
|
|
191
|
-
ok: false,
|
|
192
|
-
kind: "renderer-error",
|
|
193
|
-
message: "Mermaid renderer returned an invalid result."
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function normalizeErrorKind(value) {
|
|
197
|
-
return value === "invalid-diagram" || value === "renderer-error" ? value : "renderer-error";
|
|
198
|
-
}
|
|
199
|
-
async function enqueueMermaidRender(render) {
|
|
200
|
-
const current = renderQueue.then(render, render);
|
|
201
|
-
renderQueue = current.catch(() => void 0);
|
|
202
|
-
return current;
|
|
203
|
-
}
|
|
204
|
-
function formatError(error) {
|
|
205
|
-
if (error instanceof Error) return error.message;
|
|
206
|
-
return String(error);
|
|
207
|
-
}
|
|
208
|
-
var RENDER_TIMEOUT_MS, MERMAID_SCRIPT_SUBPATH, renderQueue, renderMermaidStaticSvg;
|
|
209
|
-
var init_render_static = __esm({
|
|
210
|
-
"src/render-static.ts"() {
|
|
211
|
-
RENDER_TIMEOUT_MS = 3e4;
|
|
212
|
-
MERMAID_SCRIPT_SUBPATH = "mermaid/dist/mermaid.min.js";
|
|
213
|
-
renderQueue = Promise.resolve();
|
|
214
|
-
renderMermaidStaticSvg = async (id, source, theme) => {
|
|
215
|
-
return enqueueMermaidRender(async () => {
|
|
216
|
-
const workDir = await mkdtemp(join(tmpdir(), "riebeckite-mermaid-"));
|
|
217
|
-
const scriptPath = join(workDir, "render-mermaid.js");
|
|
218
|
-
try {
|
|
219
|
-
await writeFile(scriptPath, buildRenderScript(id, source, theme), "utf8");
|
|
220
|
-
return await renderWithBrowser(scriptPath);
|
|
221
|
-
} finally {
|
|
222
|
-
await rm(workDir, { force: true, recursive: true });
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
|
|
229
66
|
// src/rehype.ts
|
|
230
67
|
var rehype_exports = {};
|
|
231
68
|
__export(rehype_exports, {
|
|
232
69
|
rehypeMermaid: () => rehypeMermaid
|
|
233
70
|
});
|
|
234
|
-
function rehypeMermaid(options = {}) {
|
|
71
|
+
function rehypeMermaid(options = {}, session) {
|
|
235
72
|
const renderMode = options.render ?? "build";
|
|
236
73
|
const theme = options.theme ?? DEFAULT_THEME;
|
|
237
74
|
return async (tree, file) => {
|
|
@@ -243,7 +80,8 @@ function rehypeMermaid(options = {}) {
|
|
|
243
80
|
render: renderMode,
|
|
244
81
|
theme,
|
|
245
82
|
caption: options.caption !== false,
|
|
246
|
-
fallback: options.fallback !== false
|
|
83
|
+
fallback: options.fallback !== false,
|
|
84
|
+
session
|
|
247
85
|
})
|
|
248
86
|
);
|
|
249
87
|
});
|
|
@@ -255,7 +93,7 @@ async function replaceMermaidBlock(parent, index, pre, file, options) {
|
|
|
255
93
|
const source = code ? getTextContent(code).trim() : getTextContent(pre).trim();
|
|
256
94
|
const caption = options.caption ? extractCaption(source, pre, code) : null;
|
|
257
95
|
const id = `rr-mermaid-${hashSource(source)}`;
|
|
258
|
-
const renderResult = shouldRenderAtBuild(options.render) ? await renderStaticSvg(id, source, options.theme, file) : null;
|
|
96
|
+
const renderResult = shouldRenderAtBuild(options.render) ? await renderStaticSvg(id, source, options.theme, file, options.session) : null;
|
|
259
97
|
const staticSvg = renderResult?.ok ? renderResult.svg : null;
|
|
260
98
|
parent.children = parent.children ?? [];
|
|
261
99
|
parent.children[index] = buildFigure({
|
|
@@ -307,10 +145,9 @@ function buildFigure(input) {
|
|
|
307
145
|
children
|
|
308
146
|
);
|
|
309
147
|
}
|
|
310
|
-
async function renderStaticSvg(id, source, theme, file) {
|
|
148
|
+
async function renderStaticSvg(id, source, theme, file, session) {
|
|
311
149
|
try {
|
|
312
|
-
const
|
|
313
|
-
const result = await renderMermaidStaticSvg2(
|
|
150
|
+
const result = await session.render(
|
|
314
151
|
id,
|
|
315
152
|
source,
|
|
316
153
|
selectTheme(theme, "light")
|
|
@@ -390,14 +227,243 @@ import {
|
|
|
390
227
|
createStyleAsset,
|
|
391
228
|
definePlugin
|
|
392
229
|
} from "@riebeckite/core";
|
|
230
|
+
|
|
231
|
+
// src/render-static.ts
|
|
232
|
+
import { access } from "node:fs/promises";
|
|
233
|
+
import { join } from "node:path";
|
|
234
|
+
import { fileURLToPath } from "node:url";
|
|
235
|
+
var RENDER_TIMEOUT_MS = 3e4;
|
|
236
|
+
var MERMAID_SCRIPT_SUBPATH = "mermaid/dist/mermaid.min.js";
|
|
237
|
+
function createMermaidRenderSession(dependencies = {}) {
|
|
238
|
+
const launchBrowser = dependencies.launch ?? defaultLaunchBrowser;
|
|
239
|
+
let state = null;
|
|
240
|
+
let queue = Promise.resolve();
|
|
241
|
+
let exitListenerAttached = false;
|
|
242
|
+
const handleExit = () => {
|
|
243
|
+
const browser = state?.browser;
|
|
244
|
+
state = null;
|
|
245
|
+
if (!browser) return;
|
|
246
|
+
try {
|
|
247
|
+
browser.process()?.kill();
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
function attachExitListener() {
|
|
252
|
+
if (exitListenerAttached) return;
|
|
253
|
+
process.once("exit", handleExit);
|
|
254
|
+
exitListenerAttached = true;
|
|
255
|
+
}
|
|
256
|
+
function detachExitListener() {
|
|
257
|
+
if (!exitListenerAttached) return;
|
|
258
|
+
process.removeListener("exit", handleExit);
|
|
259
|
+
exitListenerAttached = false;
|
|
260
|
+
}
|
|
261
|
+
async function ensureSession() {
|
|
262
|
+
if (state) return state;
|
|
263
|
+
const browser = await launchBrowser();
|
|
264
|
+
attachExitListener();
|
|
265
|
+
try {
|
|
266
|
+
const page = await browser.newPage();
|
|
267
|
+
page.setDefaultTimeout(RENDER_TIMEOUT_MS);
|
|
268
|
+
await page.setContent("<!doctype html><html><body></body></html>");
|
|
269
|
+
await page.addScriptTag({ path: await resolveMermaidScriptPath() });
|
|
270
|
+
state = { browser, page };
|
|
271
|
+
return state;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
await teardownBrowser(browser);
|
|
274
|
+
detachExitListener();
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
async function teardownBrowser(browser) {
|
|
279
|
+
try {
|
|
280
|
+
await browser.close();
|
|
281
|
+
} catch {
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async function teardown() {
|
|
285
|
+
const current = state;
|
|
286
|
+
state = null;
|
|
287
|
+
detachExitListener();
|
|
288
|
+
if (current) await teardownBrowser(current.browser);
|
|
289
|
+
}
|
|
290
|
+
async function evaluateRender(session, id, source, theme) {
|
|
291
|
+
const result = await session.page.evaluate(
|
|
292
|
+
renderMermaidInPage,
|
|
293
|
+
id,
|
|
294
|
+
source,
|
|
295
|
+
theme
|
|
296
|
+
);
|
|
297
|
+
return normalizeRenderResult(result);
|
|
298
|
+
}
|
|
299
|
+
async function renderWithRecovery(id, source, theme) {
|
|
300
|
+
let established = false;
|
|
301
|
+
try {
|
|
302
|
+
const session = await ensureSession();
|
|
303
|
+
established = true;
|
|
304
|
+
return await evaluateRender(session, id, source, theme);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
await teardown();
|
|
307
|
+
if (!established) {
|
|
308
|
+
return rendererErrorResult(error);
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const session = await ensureSession();
|
|
312
|
+
return await evaluateRender(session, id, source, theme);
|
|
313
|
+
} catch (retryError) {
|
|
314
|
+
await teardown();
|
|
315
|
+
return rendererErrorResult(retryError);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function enqueue(task) {
|
|
320
|
+
const run = queue.then(task, task);
|
|
321
|
+
queue = run.then(
|
|
322
|
+
() => void 0,
|
|
323
|
+
() => void 0
|
|
324
|
+
);
|
|
325
|
+
return run;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
render(id, source, theme) {
|
|
329
|
+
return enqueue(() => renderWithRecovery(id, source, theme));
|
|
330
|
+
},
|
|
331
|
+
dispose() {
|
|
332
|
+
return enqueue(() => teardown());
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
async function renderMermaidInPage(id, source, theme) {
|
|
337
|
+
const mermaid2 = globalThis.mermaid;
|
|
338
|
+
if (!mermaid2) {
|
|
339
|
+
return {
|
|
340
|
+
ok: false,
|
|
341
|
+
kind: "renderer-error",
|
|
342
|
+
message: "Mermaid script is not loaded."
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
document.body.innerHTML = "";
|
|
347
|
+
mermaid2.initialize({
|
|
348
|
+
startOnLoad: false,
|
|
349
|
+
securityLevel: "strict",
|
|
350
|
+
theme
|
|
351
|
+
});
|
|
352
|
+
const { svg } = await mermaid2.render(id, source);
|
|
353
|
+
return { ok: true, svg };
|
|
354
|
+
} catch (error) {
|
|
355
|
+
return {
|
|
356
|
+
ok: false,
|
|
357
|
+
kind: "invalid-diagram",
|
|
358
|
+
message: error instanceof Error ? error.message : String(error)
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async function defaultLaunchBrowser() {
|
|
363
|
+
const puppeteer = await importPuppeteer();
|
|
364
|
+
return puppeteer.default.launch({
|
|
365
|
+
headless: "shell",
|
|
366
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
async function importPuppeteer() {
|
|
370
|
+
const importModule = new Function(
|
|
371
|
+
"specifier",
|
|
372
|
+
"return import(specifier)"
|
|
373
|
+
);
|
|
374
|
+
return importModule("puppeteer");
|
|
375
|
+
}
|
|
376
|
+
async function resolveMermaidScriptPath() {
|
|
377
|
+
const candidates = [
|
|
378
|
+
resolveWithImportMeta(),
|
|
379
|
+
fileURLToPath(
|
|
380
|
+
new URL(`../node_modules/${MERMAID_SCRIPT_SUBPATH}`, import.meta.url)
|
|
381
|
+
),
|
|
382
|
+
join(process.cwd(), "node_modules", MERMAID_SCRIPT_SUBPATH),
|
|
383
|
+
join(
|
|
384
|
+
process.cwd(),
|
|
385
|
+
"..",
|
|
386
|
+
"..",
|
|
387
|
+
"packages",
|
|
388
|
+
"plugin-mermaid",
|
|
389
|
+
"node_modules",
|
|
390
|
+
MERMAID_SCRIPT_SUBPATH
|
|
391
|
+
)
|
|
392
|
+
].filter((path) => typeof path === "string");
|
|
393
|
+
for (const candidate of candidates) {
|
|
394
|
+
if (await fileExists(candidate)) return candidate;
|
|
395
|
+
}
|
|
396
|
+
return candidates.at(0) ?? MERMAID_SCRIPT_SUBPATH;
|
|
397
|
+
}
|
|
398
|
+
function resolveWithImportMeta() {
|
|
399
|
+
const resolver = import.meta.resolve;
|
|
400
|
+
if (typeof resolver !== "function") return void 0;
|
|
401
|
+
return fileURLToPath(resolver(MERMAID_SCRIPT_SUBPATH));
|
|
402
|
+
}
|
|
403
|
+
async function fileExists(path) {
|
|
404
|
+
try {
|
|
405
|
+
await access(path);
|
|
406
|
+
return true;
|
|
407
|
+
} catch {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function rendererErrorResult(error) {
|
|
412
|
+
return { ok: false, kind: "renderer-error", message: formatError(error) };
|
|
413
|
+
}
|
|
414
|
+
function normalizeRenderResult(value) {
|
|
415
|
+
if (!value || typeof value !== "object") {
|
|
416
|
+
return {
|
|
417
|
+
ok: false,
|
|
418
|
+
kind: "renderer-error",
|
|
419
|
+
message: "Mermaid renderer returned no result."
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const result = value;
|
|
423
|
+
if (result.ok === true && typeof result.svg === "string") {
|
|
424
|
+
return { ok: true, svg: result.svg };
|
|
425
|
+
}
|
|
426
|
+
if (result.ok === false) {
|
|
427
|
+
return {
|
|
428
|
+
ok: false,
|
|
429
|
+
kind: normalizeErrorKind(result.kind),
|
|
430
|
+
message: typeof result.message === "string" ? result.message : "Mermaid renderer failed."
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
ok: false,
|
|
435
|
+
kind: "renderer-error",
|
|
436
|
+
message: "Mermaid renderer returned an invalid result."
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function normalizeErrorKind(value) {
|
|
440
|
+
return value === "invalid-diagram" || value === "renderer-error" ? value : "renderer-error";
|
|
441
|
+
}
|
|
442
|
+
function formatError(error) {
|
|
443
|
+
if (error instanceof Error) return error.message;
|
|
444
|
+
return String(error);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// index.ts
|
|
393
448
|
function mermaid(options = {}) {
|
|
449
|
+
const session = createMermaidRenderSession();
|
|
394
450
|
return definePlugin({
|
|
395
451
|
name: "mermaid",
|
|
396
452
|
order: -10,
|
|
453
|
+
processedContentCache: {
|
|
454
|
+
version: "mermaid-v1",
|
|
455
|
+
dependencyMode: "none"
|
|
456
|
+
},
|
|
397
457
|
options,
|
|
398
458
|
validateOptions: validateMermaidOptions,
|
|
399
459
|
extendHtmlPipeline: (pipeline) => {
|
|
400
|
-
pipeline.use(rehypeMermaidLazy, options);
|
|
460
|
+
pipeline.use(rehypeMermaidLazy, { options, session });
|
|
461
|
+
},
|
|
462
|
+
buildEnd: async () => {
|
|
463
|
+
await session.dispose();
|
|
464
|
+
},
|
|
465
|
+
dispose: async () => {
|
|
466
|
+
await session.dispose();
|
|
401
467
|
},
|
|
402
468
|
assets: [createStyleAsset("mermaid")],
|
|
403
469
|
clientEntries: [createClientEntry("mermaid", "initMermaidDiagrams")]
|
|
@@ -428,10 +494,10 @@ function validateMermaidOptions(options) {
|
|
|
428
494
|
function isMermaidTheme(value) {
|
|
429
495
|
return value === void 0 || typeof value === "string" || typeof value === "object" && value !== null && "light" in value && "dark" in value && typeof value.light === "string" && typeof value.dark === "string";
|
|
430
496
|
}
|
|
431
|
-
function rehypeMermaidLazy(
|
|
497
|
+
function rehypeMermaidLazy(settings) {
|
|
432
498
|
return async (tree, file) => {
|
|
433
499
|
const { rehypeMermaid: rehypeMermaid2 } = await Promise.resolve().then(() => (init_rehype(), rehype_exports));
|
|
434
|
-
const transformer = rehypeMermaid2(options);
|
|
500
|
+
const transformer = rehypeMermaid2(settings.options, settings.session);
|
|
435
501
|
await transformer(tree, file);
|
|
436
502
|
};
|
|
437
503
|
}
|
package/dist/src/rehype.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { HastNode, MermaidOptions } from "./types.js";
|
|
2
|
-
export declare function rehypeMermaid(options
|
|
1
|
+
import type { HastNode, MermaidOptions, MermaidRenderSession } from "./types.js";
|
|
2
|
+
export declare function rehypeMermaid(options: MermaidOptions, session: MermaidRenderSession): (tree: HastNode, file: unknown) => Promise<void>;
|
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { Browser } from "puppeteer";
|
|
2
|
+
import type { MermaidRenderSession } from "./types.js";
|
|
3
|
+
export type MermaidSessionDependencies = {
|
|
4
|
+
/**
|
|
5
|
+
* Overrides browser launch. Tests inject a fake browser so session
|
|
6
|
+
* lifecycle can be asserted without launching Chrome.
|
|
7
|
+
*/
|
|
8
|
+
launch?: () => Promise<Browser>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Creates a build-scoped Mermaid render session.
|
|
12
|
+
*
|
|
13
|
+
* The session owns one browser + one page and injects `mermaid.min.js` a
|
|
14
|
+
* single time; every diagram render reuses that page through
|
|
15
|
+
* `page.evaluate`. Each `mermaid()` plugin instance creates its own
|
|
16
|
+
* session, so resource ownership stays with the plugin rather than a
|
|
17
|
+
* module-global singleton. `dispose` releases the browser and is wired to
|
|
18
|
+
* the plugin `buildEnd`/`dispose` hooks.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createMermaidRenderSession(dependencies?: MermaidSessionDependencies): MermaidRenderSession;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -19,6 +19,14 @@ export type MermaidBuildRenderResult = {
|
|
|
19
19
|
message: string;
|
|
20
20
|
};
|
|
21
21
|
export type MermaidBuildRenderer = (id: string, source: string, theme: string) => Promise<MermaidBuildRenderResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Build-scoped render resource. Owns one browser/page session, serializes
|
|
24
|
+
* renders, and releases the browser on `dispose`.
|
|
25
|
+
*/
|
|
26
|
+
export type MermaidRenderSession = {
|
|
27
|
+
render: MermaidBuildRenderer;
|
|
28
|
+
dispose: () => Promise<void>;
|
|
29
|
+
};
|
|
22
30
|
export type MermaidClientOptions = {
|
|
23
31
|
theme?: MermaidTheme;
|
|
24
32
|
mermaid?: MermaidApi;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-mermaid",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"mermaid": "^11.12.2",
|
|
25
25
|
"puppeteer": "^25.11.0",
|
|
26
|
-
"@riebeckite/core": "0.0.
|
|
26
|
+
"@riebeckite/core": "0.0.15"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"./style.css"
|
|
59
59
|
],
|
|
60
60
|
"scripts": {
|
|
61
|
-
"build": "node ../../../scripts/build_package.mjs"
|
|
61
|
+
"build": "node ../../../scripts/build_package.mjs",
|
|
62
|
+
"test": "node --import tsx --test \"test/*.test.ts\""
|
|
62
63
|
}
|
|
63
64
|
}
|