@matfsw/docusaurus-plantuml-plugin 1.1.2 → 1.3.0
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/CHANGELOG.md +103 -1
- package/README.md +211 -32
- package/assets/stdlib/LICENSES.md +21 -0
- package/assets/stdlib/archimate.min.js +22 -0
- package/assets/stdlib/azure.min.js +305 -0
- package/assets/stdlib/c4.min.js +47 -0
- package/assets/stdlib/cloudinsight.min.js +93 -0
- package/assets/stdlib/eip.min.js +14 -0
- package/assets/stdlib/k8s.min.js +52 -0
- package/assets/stdlib/kubernetes.min.js +17 -0
- package/assets/stdlib/manifest.json +112 -0
- package/assets/stdlib/office.min.js +557 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/index.cjs +384 -8
- package/dist/index.d.cts +91 -3
- package/dist/index.d.ts +12 -2
- package/dist/index.js +20 -1
- package/dist/options.d.ts +57 -1
- package/dist/options.js +84 -0
- package/dist/runtime/assetLoader.d.ts +13 -1
- package/dist/runtime/assetLoader.js +36 -13
- package/dist/runtime/cache.d.ts +6 -1
- package/dist/runtime/cache.js +2 -2
- package/dist/runtime/errors.d.ts +3 -1
- package/dist/runtime/errors.js +27 -1
- package/dist/runtime/renderer.d.ts +3 -0
- package/dist/runtime/renderer.js +21 -7
- package/dist/runtime/stdlibLoader.d.ts +31 -0
- package/dist/runtime/stdlibLoader.js +99 -0
- package/dist/stdlib.d.ts +35 -0
- package/dist/stdlib.js +163 -0
- package/dist/stdlibBundle.d.ts +60 -0
- package/dist/stdlibBundle.js +218 -0
- package/dist/stdlibShared.d.ts +51 -0
- package/dist/stdlibShared.js +54 -0
- package/dist/theme/MDXComponents/Code/index.js +1 -1
- package/dist/theme/PlantUmlDiagram/index.d.ts +6 -1
- package/dist/theme/PlantUmlDiagram/index.js +53 -5
- package/dist/theme/PlantUmlDiagram/styles.module.css +117 -0
- package/dist/theme/usePlantUmlConfig.d.ts +8 -0
- package/dist/theme/usePlantUmlConfig.js +14 -8
- package/package.json +3 -1
package/dist/constants.d.ts
CHANGED
|
@@ -39,4 +39,6 @@ export declare const DATA_ATTR: {
|
|
|
39
39
|
readonly zoom: "data-plantuml-zoom";
|
|
40
40
|
/** `"true"` on the figure while the diagram fills the browser viewport. */
|
|
41
41
|
readonly maximized: "data-plantuml-maximized";
|
|
42
|
+
/** `"true"` on the figure while the source panel is open. */
|
|
43
|
+
readonly sourceOpen: "data-plantuml-source-open";
|
|
42
44
|
};
|
package/dist/constants.js
CHANGED
|
@@ -41,4 +41,6 @@ export const DATA_ATTR = {
|
|
|
41
41
|
zoom: 'data-plantuml-zoom',
|
|
42
42
|
/** `"true"` on the figure while the diagram fills the browser viewport. */
|
|
43
43
|
maximized: 'data-plantuml-maximized',
|
|
44
|
+
/** `"true"` on the figure while the source panel is open. */
|
|
45
|
+
sourceOpen: 'data-plantuml-source-open',
|
|
44
46
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -46,7 +46,7 @@ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${_
|
|
|
46
46
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
47
47
|
|
|
48
48
|
// src/index.ts
|
|
49
|
-
var
|
|
49
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
50
50
|
var import_node_url = require("url");
|
|
51
51
|
var import_copy_webpack_plugin = __toESM(require("copy-webpack-plugin"), 1);
|
|
52
52
|
|
|
@@ -116,6 +116,12 @@ var DEFAULT_GRAPHVIZ_OPTIONS = {
|
|
|
116
116
|
maxSourceBytes: 1e5,
|
|
117
117
|
transparentBackground: true
|
|
118
118
|
};
|
|
119
|
+
var DEFAULT_STDLIB_OPTIONS = {
|
|
120
|
+
enabled: true,
|
|
121
|
+
include: [],
|
|
122
|
+
source: [],
|
|
123
|
+
namespaces: null
|
|
124
|
+
};
|
|
119
125
|
var DEFAULT_OPTIONS = {
|
|
120
126
|
languages: ["plantuml", "puml"],
|
|
121
127
|
theme: "auto",
|
|
@@ -126,7 +132,9 @@ var DEFAULT_OPTIONS = {
|
|
|
126
132
|
renderTimeoutMs: 2e4,
|
|
127
133
|
cacheMaxEntries: 50,
|
|
128
134
|
zoom: true,
|
|
129
|
-
|
|
135
|
+
showSource: true,
|
|
136
|
+
graphviz: DEFAULT_GRAPHVIZ_OPTIONS,
|
|
137
|
+
stdlib: DEFAULT_STDLIB_OPTIONS
|
|
130
138
|
};
|
|
131
139
|
var CACHE_MODES = ["none", "memory", "session"];
|
|
132
140
|
var THEMES = ["auto", "light", "dark"];
|
|
@@ -233,6 +241,68 @@ function validateGraphviz(value) {
|
|
|
233
241
|
)
|
|
234
242
|
};
|
|
235
243
|
}
|
|
244
|
+
function validateNamespaceList(value, key) {
|
|
245
|
+
if (!Array.isArray(value)) {
|
|
246
|
+
fail(`options.${key} must be an array of strings, received ${JSON.stringify(value)}.`);
|
|
247
|
+
}
|
|
248
|
+
const normalized = value.map((entry, index) => {
|
|
249
|
+
if (typeof entry !== "string" || entry.trim() === "") {
|
|
250
|
+
fail(
|
|
251
|
+
`options.${key}[${index}] must be a non-empty string, received ${JSON.stringify(entry)}.`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return entry.trim().toLowerCase();
|
|
255
|
+
});
|
|
256
|
+
const duplicates = normalized.filter((entry, index) => normalized.indexOf(entry) !== index);
|
|
257
|
+
if (duplicates.length > 0) {
|
|
258
|
+
fail(`options.${key} contains duplicate entries: ${quoteList([...new Set(duplicates)])}.`);
|
|
259
|
+
}
|
|
260
|
+
return normalized;
|
|
261
|
+
}
|
|
262
|
+
function validateStdlibSource(value) {
|
|
263
|
+
if (value === void 0) return [];
|
|
264
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
265
|
+
return entries.map((entry, index) => {
|
|
266
|
+
if (typeof entry !== "string" || entry.trim() === "") {
|
|
267
|
+
const where = Array.isArray(value) ? `stdlib.source[${index}]` : "stdlib.source";
|
|
268
|
+
fail(`options.${where} must be a non-empty string, received ${JSON.stringify(entry)}.`);
|
|
269
|
+
}
|
|
270
|
+
return entry.trim();
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
function validateStdlib(value) {
|
|
274
|
+
if (value === void 0) return { ...DEFAULT_STDLIB_OPTIONS, include: [], source: [] };
|
|
275
|
+
if (value === false) return { ...DEFAULT_STDLIB_OPTIONS, enabled: false, include: [], source: [] };
|
|
276
|
+
if (!isPlainObject(value)) {
|
|
277
|
+
fail(`options.stdlib must be an object or false, received ${JSON.stringify(value)}.`);
|
|
278
|
+
}
|
|
279
|
+
const allowedKeys = ["enabled", "include", "source", "namespaces"];
|
|
280
|
+
const unknownKeys = Object.keys(value).filter((key) => !allowedKeys.includes(key));
|
|
281
|
+
if (unknownKeys.length > 0) {
|
|
282
|
+
fail(
|
|
283
|
+
`Unknown option${unknownKeys.length > 1 ? "s" : ""} ${quoteList(unknownKeys.map((key) => `stdlib.${key}`))}. Supported options: ${quoteList(allowedKeys.map((key) => `stdlib.${key}`))}.`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const include = value.include === void 0 ? [] : validateNamespaceList(value.include, "stdlib.include");
|
|
287
|
+
const source = validateStdlibSource(value.source);
|
|
288
|
+
const namespaces = value.namespaces === void 0 ? null : validateNamespaceList(value.namespaces, "stdlib.namespaces");
|
|
289
|
+
if (namespaces !== null && namespaces.length === 0) {
|
|
290
|
+
fail(
|
|
291
|
+
"options.stdlib.namespaces must name at least one namespace. To turn the standard library off entirely, use `stdlib: false`."
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (include.length > 0 && source.length === 0) {
|
|
295
|
+
fail(
|
|
296
|
+
`options.stdlib.include names ${quoteList(include)}, but options.stdlib.source is not set, so there is nowhere to read them from. Point it at the \`stdlib\` directory of a plantuml-stdlib checkout.`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
enabled: validateBoolean(value.enabled, "stdlib.enabled", DEFAULT_STDLIB_OPTIONS.enabled),
|
|
301
|
+
include,
|
|
302
|
+
source,
|
|
303
|
+
namespaces
|
|
304
|
+
};
|
|
305
|
+
}
|
|
236
306
|
function validateRenderTimeout(value) {
|
|
237
307
|
if (value === void 0) return DEFAULT_OPTIONS.renderTimeoutMs;
|
|
238
308
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -260,7 +330,8 @@ function resolveOptions(rawOptions) {
|
|
|
260
330
|
return {
|
|
261
331
|
...DEFAULT_OPTIONS,
|
|
262
332
|
languages: [...DEFAULT_OPTIONS.languages],
|
|
263
|
-
graphviz: { ...DEFAULT_GRAPHVIZ_OPTIONS, languages: [...DEFAULT_GRAPHVIZ_OPTIONS.languages] }
|
|
333
|
+
graphviz: { ...DEFAULT_GRAPHVIZ_OPTIONS, languages: [...DEFAULT_GRAPHVIZ_OPTIONS.languages] },
|
|
334
|
+
stdlib: { ...DEFAULT_STDLIB_OPTIONS, include: [], source: [] }
|
|
264
335
|
};
|
|
265
336
|
}
|
|
266
337
|
if (!isPlainObject(rawOptions)) {
|
|
@@ -276,7 +347,9 @@ function resolveOptions(rawOptions) {
|
|
|
276
347
|
"renderTimeoutMs",
|
|
277
348
|
"cacheMaxEntries",
|
|
278
349
|
"zoom",
|
|
350
|
+
"showSource",
|
|
279
351
|
"graphviz",
|
|
352
|
+
"stdlib",
|
|
280
353
|
// Docusaurus injects `id` for multi-instance plugins.
|
|
281
354
|
"id"
|
|
282
355
|
]);
|
|
@@ -297,6 +370,7 @@ function resolveOptions(rawOptions) {
|
|
|
297
370
|
}
|
|
298
371
|
const languages = validateLanguages(rawOptions.languages, "languages", DEFAULT_OPTIONS.languages);
|
|
299
372
|
const graphviz = validateGraphviz(rawOptions.graphviz);
|
|
373
|
+
const stdlib = validateStdlib(rawOptions.stdlib);
|
|
300
374
|
if (graphviz.enabled) {
|
|
301
375
|
const claimedTwice = graphviz.languages.filter((entry) => languages.includes(entry));
|
|
302
376
|
if (claimedTwice.length > 0) {
|
|
@@ -308,6 +382,7 @@ function resolveOptions(rawOptions) {
|
|
|
308
382
|
return {
|
|
309
383
|
languages,
|
|
310
384
|
graphviz,
|
|
385
|
+
stdlib,
|
|
311
386
|
theme: theme ?? DEFAULT_OPTIONS.theme,
|
|
312
387
|
lazy: validateBoolean(rawOptions.lazy, "lazy", DEFAULT_OPTIONS.lazy),
|
|
313
388
|
cache: cache ?? DEFAULT_OPTIONS.cache,
|
|
@@ -323,12 +398,296 @@ function resolveOptions(rawOptions) {
|
|
|
323
398
|
),
|
|
324
399
|
renderTimeoutMs: validateRenderTimeout(rawOptions.renderTimeoutMs),
|
|
325
400
|
cacheMaxEntries: validateCacheMaxEntries(rawOptions.cacheMaxEntries),
|
|
326
|
-
zoom: validateBoolean(rawOptions.zoom, "zoom", DEFAULT_OPTIONS.zoom)
|
|
401
|
+
zoom: validateBoolean(rawOptions.zoom, "zoom", DEFAULT_OPTIONS.zoom),
|
|
402
|
+
showSource: validateBoolean(rawOptions.showSource, "showSource", DEFAULT_OPTIONS.showSource)
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/stdlib.ts
|
|
407
|
+
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
408
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
409
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
410
|
+
|
|
411
|
+
// src/stdlibBundle.ts
|
|
412
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
413
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
414
|
+
|
|
415
|
+
// src/stdlibShared.ts
|
|
416
|
+
var STDLIB_EXAMPLES_DIRECTORY = "_examples_";
|
|
417
|
+
var STDLIB_INCLUDE_PATTERN = /^[^\S\r\n]*!include(?:sub|url|_many)?[^\S\r\n]+<([^>\r\n]+)>/gim;
|
|
418
|
+
function findStdlibIncludes(source) {
|
|
419
|
+
const found = [];
|
|
420
|
+
const seen = /* @__PURE__ */ new Set();
|
|
421
|
+
for (const match of source.matchAll(STDLIB_INCLUDE_PATTERN)) {
|
|
422
|
+
const raw = match[1]?.trim() ?? "";
|
|
423
|
+
if (raw.includes("$") || raw.includes("%")) continue;
|
|
424
|
+
const slash = raw.indexOf("/");
|
|
425
|
+
if (slash <= 0) continue;
|
|
426
|
+
const namespace = raw.slice(0, slash).toLowerCase();
|
|
427
|
+
const target = raw.slice(slash + 1).toLowerCase();
|
|
428
|
+
if (target === "") continue;
|
|
429
|
+
const key = `${namespace}/${target}`;
|
|
430
|
+
if (seen.has(key)) continue;
|
|
431
|
+
seen.add(key);
|
|
432
|
+
found.push({
|
|
433
|
+
namespace,
|
|
434
|
+
target,
|
|
435
|
+
fromExamples: target.startsWith(`${STDLIB_EXAMPLES_DIRECTORY}/`)
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
return found;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/stdlibBundle.ts
|
|
442
|
+
function isSkippedDirectory(name) {
|
|
443
|
+
if (name === STDLIB_EXAMPLES_DIRECTORY) return false;
|
|
444
|
+
return name.startsWith("_") && name.endsWith("_");
|
|
445
|
+
}
|
|
446
|
+
function collectFiles(directory, namespaceRoot) {
|
|
447
|
+
const entries = import_node_fs2.default.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
448
|
+
const files = [];
|
|
449
|
+
for (const entry of entries) {
|
|
450
|
+
const absolutePath = import_node_path2.default.join(directory, entry.name);
|
|
451
|
+
if (entry.isDirectory()) {
|
|
452
|
+
if (!isSkippedDirectory(entry.name)) files.push(...collectFiles(absolutePath, namespaceRoot));
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
const extension = import_node_path2.default.extname(entry.name).toLowerCase();
|
|
456
|
+
if (extension !== ".puml" && extension !== ".json") continue;
|
|
457
|
+
const key = import_node_path2.default.relative(namespaceRoot, absolutePath).split(import_node_path2.default.sep).join("/").toLowerCase();
|
|
458
|
+
files.push({
|
|
459
|
+
key,
|
|
460
|
+
absolutePath,
|
|
461
|
+
extension,
|
|
462
|
+
fromExamples: key.startsWith(`${STDLIB_EXAMPLES_DIRECTORY}/`)
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
return files;
|
|
466
|
+
}
|
|
467
|
+
function readNamespaceInfo(namespaceRoot) {
|
|
468
|
+
const readme = import_node_path2.default.join(namespaceRoot, "README.md");
|
|
469
|
+
if (!import_node_fs2.default.existsSync(readme)) return {};
|
|
470
|
+
const lines = import_node_fs2.default.readFileSync(readme, "utf8").split(/\r\n|\r|\n/);
|
|
471
|
+
if (lines[0]?.trim() !== "---") return {};
|
|
472
|
+
const info = {};
|
|
473
|
+
for (const line of lines.slice(1)) {
|
|
474
|
+
const trimmed = line.trim();
|
|
475
|
+
if (trimmed === "---") break;
|
|
476
|
+
const colon = trimmed.indexOf(":");
|
|
477
|
+
if (colon === -1) continue;
|
|
478
|
+
info[trimmed.slice(0, colon).trim()] = trimmed.slice(colon + 1).trim();
|
|
479
|
+
}
|
|
480
|
+
return info;
|
|
481
|
+
}
|
|
482
|
+
function toJsLiteral(value) {
|
|
483
|
+
return JSON.stringify(value).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
484
|
+
}
|
|
485
|
+
function toJsonLiteral(text, file) {
|
|
486
|
+
try {
|
|
487
|
+
return toJsLiteral(JSON.parse(text));
|
|
488
|
+
} catch (cause) {
|
|
489
|
+
throw new Error(`'${file ?? "a standard library JSON file"}' is not valid JSON.`, { cause });
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function unwrapDocument(lines) {
|
|
493
|
+
if (lines.filter((line) => /^@startuml\b/.test(line.trim())).length !== 1) return lines;
|
|
494
|
+
let first = 0;
|
|
495
|
+
while (first < lines.length && lines[first]?.trim() === "") first += 1;
|
|
496
|
+
if (!/^@startuml\b/.test(lines[first]?.trim() ?? "")) return lines;
|
|
497
|
+
let last = lines.length - 1;
|
|
498
|
+
while (last > first && lines[last]?.trim() === "") last -= 1;
|
|
499
|
+
if (lines[last]?.trim() !== "@enduml") return lines;
|
|
500
|
+
return lines.slice(first + 1, last);
|
|
501
|
+
}
|
|
502
|
+
function withoutExtension(key) {
|
|
503
|
+
return key.replace(/\.(puml|json)$/, "");
|
|
504
|
+
}
|
|
505
|
+
function stdlibBundleFileName(namespace) {
|
|
506
|
+
return `${namespace.toLowerCase()}.min.js`;
|
|
507
|
+
}
|
|
508
|
+
function buildStdlibNamespace(stdlibRoot, directoryName) {
|
|
509
|
+
const namespaceRoot = import_node_path2.default.join(stdlibRoot, directoryName);
|
|
510
|
+
if (!import_node_fs2.default.existsSync(namespaceRoot) || !import_node_fs2.default.statSync(namespaceRoot).isDirectory()) {
|
|
511
|
+
throw new Error(`'${namespaceRoot}' is not a plantuml-stdlib namespace directory.`);
|
|
512
|
+
}
|
|
513
|
+
const namespace = directoryName.toLowerCase();
|
|
514
|
+
const info = readNamespaceInfo(namespaceRoot);
|
|
515
|
+
const files = collectFiles(namespaceRoot, namespaceRoot);
|
|
516
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
517
|
+
const exampleDependencies = /* @__PURE__ */ new Set();
|
|
518
|
+
const quoted = toJsLiteral(namespace);
|
|
519
|
+
const lines = [
|
|
520
|
+
`// ${namespace}.min.js - generated from plantuml-stdlib by @matfsw/docusaurus-plantuml-plugin.`,
|
|
521
|
+
"(function () {",
|
|
522
|
+
" var w = window;",
|
|
523
|
+
" w.PLANTUML_STDLIB = w.PLANTUML_STDLIB || {};",
|
|
524
|
+
" w.PLANTUML_STDLIB_JSON = w.PLANTUML_STDLIB_JSON || {};",
|
|
525
|
+
" w.PLANTUML_STDLIB_INFO = w.PLANTUML_STDLIB_INFO || {};",
|
|
526
|
+
` w.PLANTUML_STDLIB_INFO[${quoted}] = ${toJsLiteral(info)};`,
|
|
527
|
+
` var P = (w.PLANTUML_STDLIB[${quoted}] = w.PLANTUML_STDLIB[${quoted}] || {});`,
|
|
528
|
+
` var J = (w.PLANTUML_STDLIB_JSON[${quoted}] = w.PLANTUML_STDLIB_JSON[${quoted}] || {});`
|
|
529
|
+
];
|
|
530
|
+
for (const file of files) {
|
|
531
|
+
const text = import_node_fs2.default.readFileSync(file.absolutePath, "utf8");
|
|
532
|
+
const bare = withoutExtension(file.key);
|
|
533
|
+
const target = file.extension === ".puml" ? "P" : "J";
|
|
534
|
+
const value = file.extension === ".puml" ? toJsLiteral(unwrapDocument(text.split(/\r\n|\r|\n/))) : toJsonLiteral(text, file.absolutePath);
|
|
535
|
+
lines.push(
|
|
536
|
+
` ${target}[${toJsLiteral(bare)}] = ${target}[${toJsLiteral(file.key)}] = ${value};`
|
|
537
|
+
);
|
|
538
|
+
if (file.extension !== ".puml") continue;
|
|
539
|
+
for (const reference of findStdlibIncludes(text)) {
|
|
540
|
+
if (reference.namespace === namespace) continue;
|
|
541
|
+
(file.fromExamples ? exampleDependencies : dependencies).add(reference.namespace);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
lines.push("})();", "");
|
|
545
|
+
return {
|
|
546
|
+
namespace,
|
|
547
|
+
directoryName,
|
|
548
|
+
script: lines.join("\n"),
|
|
549
|
+
info,
|
|
550
|
+
dependencies: [...dependencies].sort(),
|
|
551
|
+
// An example-only dependency that the library already needs is not worth recording twice.
|
|
552
|
+
exampleDependencies: [...exampleDependencies].filter((name) => !dependencies.has(name)).sort(),
|
|
553
|
+
fileCount: files.length
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// src/stdlib.ts
|
|
558
|
+
function vendoredDirectory(currentDir2) {
|
|
559
|
+
return import_node_path3.default.join(currentDir2, "..", "assets", "stdlib");
|
|
560
|
+
}
|
|
561
|
+
function readVendoredManifest(directory) {
|
|
562
|
+
const manifestPath = import_node_path3.default.join(directory, "manifest.json");
|
|
563
|
+
if (!import_node_fs3.default.existsSync(manifestPath)) {
|
|
564
|
+
throw new Error(
|
|
565
|
+
`[${PLUGIN_NAME}] The vendored standard library manifest is missing from '${manifestPath}'. This is a packaging fault: reinstall the plugin, or run 'npm run stdlib:update' if you are working in a checkout of it.`
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
return JSON.parse(import_node_fs3.default.readFileSync(manifestPath, "utf8"));
|
|
569
|
+
}
|
|
570
|
+
function digest(...parts) {
|
|
571
|
+
const hash = import_node_crypto.default.createHash("sha256");
|
|
572
|
+
for (const part of parts) hash.update(part).update("\0");
|
|
573
|
+
return hash.digest("hex").slice(0, 12);
|
|
574
|
+
}
|
|
575
|
+
function directoryStamp(directory) {
|
|
576
|
+
const parts = [];
|
|
577
|
+
const walk = (current) => {
|
|
578
|
+
for (const entry of import_node_fs3.default.readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : 1)) {
|
|
579
|
+
const absolute = import_node_path3.default.join(current, entry.name);
|
|
580
|
+
if (entry.isDirectory()) {
|
|
581
|
+
walk(absolute);
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const stats = import_node_fs3.default.statSync(absolute);
|
|
585
|
+
parts.push(`${absolute}:${stats.size}:${stats.mtimeMs}`);
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
walk(directory);
|
|
589
|
+
return digest(...parts);
|
|
590
|
+
}
|
|
591
|
+
function findNamespaceDirectory(sourceRoots, namespace) {
|
|
592
|
+
for (const root of sourceRoots) {
|
|
593
|
+
if (!import_node_fs3.default.existsSync(root)) continue;
|
|
594
|
+
for (const entry of import_node_fs3.default.readdirSync(root, { withFileTypes: true })) {
|
|
595
|
+
if (entry.isDirectory() && entry.name.toLowerCase() === namespace) {
|
|
596
|
+
return import_node_path3.default.join(root, entry.name);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
function resolveStdlibAssets({
|
|
603
|
+
options,
|
|
604
|
+
currentDir: currentDir2,
|
|
605
|
+
siteDir,
|
|
606
|
+
cacheDir
|
|
607
|
+
}) {
|
|
608
|
+
if (!options.enabled) return null;
|
|
609
|
+
const directory = vendoredDirectory(currentDir2);
|
|
610
|
+
const vendored = readVendoredManifest(directory);
|
|
611
|
+
const vendoredNamespaces = vendored.namespaces ?? {};
|
|
612
|
+
const files = [];
|
|
613
|
+
const namespaces = {};
|
|
614
|
+
const addVendored = (namespace) => {
|
|
615
|
+
if (namespace in namespaces) return;
|
|
616
|
+
const entry = vendoredNamespaces[namespace];
|
|
617
|
+
if (!entry) return;
|
|
618
|
+
const bundlePath = import_node_path3.default.join(directory, entry.file);
|
|
619
|
+
if (!import_node_fs3.default.existsSync(bundlePath)) {
|
|
620
|
+
throw new Error(
|
|
621
|
+
`[${PLUGIN_NAME}] The vendored standard library manifest lists '${entry.file}', but '${bundlePath}' does not exist. Reinstall the plugin.`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
files.push(bundlePath);
|
|
625
|
+
namespaces[namespace] = {
|
|
626
|
+
dependencies: entry.dependencies ?? [],
|
|
627
|
+
exampleDependencies: entry.exampleDependencies ?? []
|
|
628
|
+
};
|
|
629
|
+
for (const dependency of entry.dependencies ?? []) addVendored(dependency);
|
|
630
|
+
};
|
|
631
|
+
const selected = options.namespaces ?? Object.keys(vendoredNamespaces);
|
|
632
|
+
if (options.namespaces) {
|
|
633
|
+
const unknown = options.namespaces.filter(
|
|
634
|
+
(namespace) => !(namespace in vendoredNamespaces) && !options.include.includes(namespace)
|
|
635
|
+
);
|
|
636
|
+
if (unknown.length > 0) {
|
|
637
|
+
throw new Error(
|
|
638
|
+
`[${PLUGIN_NAME}] options.stdlib.namespaces names ${unknown.map((name) => `'${name}'`).join(", ")}, which ${unknown.length > 1 ? "are" : "is"} not vendored with this plugin. Vendored namespaces: ${Object.keys(vendoredNamespaces).join(", ")}. To use another one, add it to options.stdlib.include and point options.stdlib.source at a plantuml-stdlib checkout.`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
for (const namespace of selected) addVendored(namespace);
|
|
643
|
+
const sourceRoots = options.source.map((entry) => import_node_path3.default.resolve(siteDir, entry));
|
|
644
|
+
const generatedDir = import_node_path3.default.join(cacheDir ?? import_node_path3.default.join(siteDir, ".docusaurus"), "plantuml-stdlib");
|
|
645
|
+
const stamps = [];
|
|
646
|
+
for (const namespace of options.include) {
|
|
647
|
+
const namespaceDir = findNamespaceDirectory(sourceRoots, namespace);
|
|
648
|
+
if (!namespaceDir) {
|
|
649
|
+
throw new Error(
|
|
650
|
+
`[${PLUGIN_NAME}] options.stdlib.include names '${namespace}', which was not found in ${sourceRoots.map((root) => `'${root}'`).join(", ")}. Clone the standard library (git clone --depth 1 https://github.com/plantuml/plantuml-stdlib) and point options.stdlib.source at its 'stdlib' directory.`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
const stamp = directoryStamp(namespaceDir);
|
|
654
|
+
stamps.push(`${namespace}:${stamp}`);
|
|
655
|
+
const cached = import_node_path3.default.join(generatedDir, stamp, stdlibBundleFileName(namespace));
|
|
656
|
+
if (!import_node_fs3.default.existsSync(cached)) {
|
|
657
|
+
const bundle = buildStdlibNamespace(import_node_path3.default.dirname(namespaceDir), import_node_path3.default.basename(namespaceDir));
|
|
658
|
+
import_node_fs3.default.mkdirSync(import_node_path3.default.dirname(cached), { recursive: true });
|
|
659
|
+
import_node_fs3.default.writeFileSync(cached, bundle.script, "utf8");
|
|
660
|
+
import_node_fs3.default.writeFileSync(
|
|
661
|
+
`${cached}.json`,
|
|
662
|
+
JSON.stringify({
|
|
663
|
+
dependencies: bundle.dependencies,
|
|
664
|
+
exampleDependencies: bundle.exampleDependencies
|
|
665
|
+
}),
|
|
666
|
+
"utf8"
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
const meta = JSON.parse(import_node_fs3.default.readFileSync(`${cached}.json`, "utf8"));
|
|
670
|
+
const previous = files.findIndex(
|
|
671
|
+
(file) => import_node_path3.default.basename(file) === stdlibBundleFileName(namespace)
|
|
672
|
+
);
|
|
673
|
+
if (previous !== -1) files.splice(previous, 1);
|
|
674
|
+
files.push(cached);
|
|
675
|
+
namespaces[namespace] = {
|
|
676
|
+
dependencies: meta.dependencies,
|
|
677
|
+
exampleDependencies: meta.exampleDependencies
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
return {
|
|
681
|
+
files,
|
|
682
|
+
manifest: {
|
|
683
|
+
revision: digest(vendored.upstream?.commit ?? "unknown", ...stamps.sort()),
|
|
684
|
+
namespaces
|
|
685
|
+
}
|
|
327
686
|
};
|
|
328
687
|
}
|
|
329
688
|
|
|
330
689
|
// src/index.ts
|
|
331
|
-
var currentDir =
|
|
690
|
+
var currentDir = import_node_path4.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
332
691
|
function createCopyPlugin(currentBundler, patterns) {
|
|
333
692
|
if (currentBundler?.name === "rspack") {
|
|
334
693
|
const { CopyRspackPlugin } = currentBundler.instance;
|
|
@@ -341,20 +700,28 @@ function createCopyPlugin(currentBundler, patterns) {
|
|
|
341
700
|
}
|
|
342
701
|
return new import_copy_webpack_plugin.default({ patterns });
|
|
343
702
|
}
|
|
344
|
-
function plantumlPlugin(
|
|
703
|
+
function plantumlPlugin(context, options = {}) {
|
|
345
704
|
const resolved = resolveOptions(options);
|
|
346
705
|
const core = locatePlantUmlCore();
|
|
347
706
|
const assetsDir = assetsDirForVersion(core.version);
|
|
707
|
+
const stdlib = resolveStdlibAssets({
|
|
708
|
+
options: resolved.stdlib,
|
|
709
|
+
currentDir,
|
|
710
|
+
siteDir: context.siteDir,
|
|
711
|
+
cacheDir: context.generatedFilesDir
|
|
712
|
+
});
|
|
713
|
+
const stdlibDir = stdlib ? `${assetsDir}/stdlib-${stdlib.manifest.revision}` : null;
|
|
348
714
|
return {
|
|
349
715
|
name: PLUGIN_NAME,
|
|
350
716
|
getThemePath() {
|
|
351
|
-
return
|
|
717
|
+
return import_node_path4.default.join(currentDir, "theme");
|
|
352
718
|
},
|
|
353
719
|
contentLoaded({ actions }) {
|
|
354
720
|
const globalData = {
|
|
355
721
|
options: resolved,
|
|
356
722
|
assetsDir,
|
|
357
|
-
coreVersion: core.version
|
|
723
|
+
coreVersion: core.version,
|
|
724
|
+
stdlib: stdlib && stdlibDir ? { dir: stdlibDir, manifest: stdlib.manifest } : null
|
|
358
725
|
};
|
|
359
726
|
actions.setGlobalData(globalData);
|
|
360
727
|
},
|
|
@@ -368,6 +735,15 @@ function plantumlPlugin(_context, options = {}) {
|
|
|
368
735
|
// These files are already minified upstream; re-processing 8 MB is wasted work.
|
|
369
736
|
info: { minimized: true }
|
|
370
737
|
}));
|
|
738
|
+
if (stdlib && stdlibDir) {
|
|
739
|
+
patterns.push(
|
|
740
|
+
...stdlib.files.map((absolutePath) => ({
|
|
741
|
+
from: absolutePath,
|
|
742
|
+
to: `${stdlibDir}/[name][ext]`,
|
|
743
|
+
info: { minimized: true }
|
|
744
|
+
}))
|
|
745
|
+
);
|
|
746
|
+
}
|
|
371
747
|
return { plugins: [createCopyPlugin(utils?.currentBundler, patterns)] };
|
|
372
748
|
}
|
|
373
749
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -42,6 +42,50 @@ type ResolvedGraphvizOptions = Required<Omit<GraphvizOptions, 'languages'>> & {
|
|
|
42
42
|
/** Normalized to lower case; matching is case-insensitive. */
|
|
43
43
|
languages: string[];
|
|
44
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* PlantUML standard library support: `!include <C4/C4_Container>` and friends.
|
|
47
|
+
*
|
|
48
|
+
* On by default and normally not worth configuring. The two lists exist for the namespaces
|
|
49
|
+
* this package does not vendor — the standard library is 265 MB in full, and several of its
|
|
50
|
+
* namespaces carry no upstream licence — which a site can still opt into from its own
|
|
51
|
+
* checkout. See `assets/stdlib/LICENSES.md` for what is vendored and under what terms.
|
|
52
|
+
*/
|
|
53
|
+
interface StdlibOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Resolve `!include <namespace/…>` at all. `false` (or `stdlib: false`) leaves such
|
|
56
|
+
* diagrams to fail in the engine, exactly as they did before this feature existed.
|
|
57
|
+
*/
|
|
58
|
+
enabled?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Extra namespaces to make available, beyond the vendored ones — `['aws', 'tupadr3']`.
|
|
61
|
+
* Each must be found in one of {@link StdlibOptions.source}, and the build fails naming
|
|
62
|
+
* the namespace if it is not.
|
|
63
|
+
*/
|
|
64
|
+
include?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* Directories to resolve {@link StdlibOptions.include} from: the `stdlib/` directory of a
|
|
67
|
+
* `plantuml-stdlib` checkout, relative to the site directory or absolute. Searched in
|
|
68
|
+
* order, before the vendored bundles, so a namespace can also be replaced with a newer one
|
|
69
|
+
* by naming it in `include`.
|
|
70
|
+
*/
|
|
71
|
+
source?: string | string[];
|
|
72
|
+
/**
|
|
73
|
+
* Narrow the vendored namespaces emitted into the build, for sites that care more about
|
|
74
|
+
* build output size than about which diagrams keep working. Dependencies of the named
|
|
75
|
+
* namespaces are kept regardless. Defaults to all of them; a reader only downloads the
|
|
76
|
+
* ones a page uses either way.
|
|
77
|
+
*/
|
|
78
|
+
namespaces?: string[];
|
|
79
|
+
}
|
|
80
|
+
/** Standard library options after validation, with every default applied. */
|
|
81
|
+
interface ResolvedStdlibOptions {
|
|
82
|
+
enabled: boolean;
|
|
83
|
+
/** Normalized to lower case. */
|
|
84
|
+
include: string[];
|
|
85
|
+
source: string[];
|
|
86
|
+
/** Normalized to lower case. `null` means "every vendored namespace". */
|
|
87
|
+
namespaces: string[] | null;
|
|
88
|
+
}
|
|
45
89
|
/**
|
|
46
90
|
* Options accepted by the plugin in `docusaurus.config.*`.
|
|
47
91
|
*
|
|
@@ -69,16 +113,27 @@ interface PlantUmlPluginOptions {
|
|
|
69
113
|
* Override for a single fence with `zoom` or `zoom=false` in its metastring.
|
|
70
114
|
*/
|
|
71
115
|
zoom?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Offer a control that reveals the diagram's source and copies it to the clipboard.
|
|
118
|
+
* Override for a single fence with `showSource` or `showSource=false` in its metastring.
|
|
119
|
+
*/
|
|
120
|
+
showSource?: boolean;
|
|
72
121
|
/** Graphviz/DOT diagram support. See {@link GraphvizOptions}. */
|
|
73
122
|
graphviz?: GraphvizOptions;
|
|
123
|
+
/**
|
|
124
|
+
* PlantUML standard library support. See {@link StdlibOptions}. `false` is shorthand for
|
|
125
|
+
* `{enabled: false}`.
|
|
126
|
+
*/
|
|
127
|
+
stdlib?: StdlibOptions | false;
|
|
74
128
|
/** Docusaurus plugin instance id, used when the plugin is registered more than once. */
|
|
75
129
|
id?: string;
|
|
76
130
|
}
|
|
77
131
|
/** Plugin options after validation, with every default applied. */
|
|
78
|
-
type ResolvedPlantUmlOptions = Required<Omit<PlantUmlPluginOptions, 'id' | 'languages' | 'graphviz'>> & {
|
|
132
|
+
type ResolvedPlantUmlOptions = Required<Omit<PlantUmlPluginOptions, 'id' | 'languages' | 'graphviz' | 'stdlib'>> & {
|
|
79
133
|
/** Normalized to lower case; matching is case-insensitive. */
|
|
80
134
|
languages: string[];
|
|
81
135
|
graphviz: ResolvedGraphvizOptions;
|
|
136
|
+
stdlib: ResolvedStdlibOptions;
|
|
82
137
|
};
|
|
83
138
|
declare const DEFAULT_OPTIONS: ResolvedPlantUmlOptions;
|
|
84
139
|
/** Thrown for invalid plugin options so Docusaurus fails the build with a useful message. */
|
|
@@ -93,6 +148,31 @@ declare class PlantUmlOptionsError extends Error {
|
|
|
93
148
|
*/
|
|
94
149
|
declare function resolveOptions(rawOptions: unknown): ResolvedPlantUmlOptions;
|
|
95
150
|
|
|
151
|
+
/**
|
|
152
|
+
* What the Node side and the browser side of standard library support both need: the shape
|
|
153
|
+
* of the manifest, and the one definition of what a `<namespace/…>` include looks like.
|
|
154
|
+
*
|
|
155
|
+
* Deliberately free of `node:` imports. `stdlibBundle.ts` reads the file system and
|
|
156
|
+
* `stdlib.ts` resolves paths; neither may be pulled into a theme component's bundle, and
|
|
157
|
+
* keeping the shared half here is what stops that from happening by accident.
|
|
158
|
+
*/
|
|
159
|
+
/** One namespace as the browser needs to know about it. Kept small: this ships in global data. */
|
|
160
|
+
interface StdlibNamespaceEntry {
|
|
161
|
+
/** Namespaces the engine will need as soon as this one is included. */
|
|
162
|
+
dependencies: string[];
|
|
163
|
+
/** Namespaces needed only by this one's `_examples_/` files. */
|
|
164
|
+
exampleDependencies: string[];
|
|
165
|
+
}
|
|
166
|
+
interface StdlibRuntimeManifest {
|
|
167
|
+
/**
|
|
168
|
+
* Changes whenever the emitted bundles change. Part of the asset directory name, so a
|
|
169
|
+
* refreshed standard library can never be served from a stale HTTP cache, and part of the
|
|
170
|
+
* render cache key, so it can never be served from a stale SVG either.
|
|
171
|
+
*/
|
|
172
|
+
revision: string;
|
|
173
|
+
namespaces: Record<string, StdlibNamespaceEntry>;
|
|
174
|
+
}
|
|
175
|
+
|
|
96
176
|
/**
|
|
97
177
|
* Identifiers shared by the Node-side plugin and the browser-side theme components.
|
|
98
178
|
*
|
|
@@ -111,6 +191,14 @@ interface PlantUmlGlobalData {
|
|
|
111
191
|
assetsDir: string;
|
|
112
192
|
/** Installed `@plantuml/core` version; part of the cache key. */
|
|
113
193
|
coreVersion: string;
|
|
194
|
+
/**
|
|
195
|
+
* `baseUrl`-relative directory holding the standard library bundles, and what is in it.
|
|
196
|
+
* `null` when the standard library is switched off.
|
|
197
|
+
*/
|
|
198
|
+
stdlib: {
|
|
199
|
+
dir: string;
|
|
200
|
+
manifest: StdlibRuntimeManifest;
|
|
201
|
+
} | null;
|
|
114
202
|
}
|
|
115
203
|
/** One copy pattern per runtime file, shared by the webpack and Rspack code paths. */
|
|
116
204
|
interface CopyPattern {
|
|
@@ -127,7 +215,7 @@ interface CopyPattern {
|
|
|
127
215
|
* it is `undefined` and webpack is the only bundler, so an absent value is not an error.
|
|
128
216
|
*/
|
|
129
217
|
declare function createCopyPlugin(currentBundler: ConfigureWebpackUtils['currentBundler'] | undefined, patterns: CopyPattern[]): WebpackPluginInstance;
|
|
130
|
-
declare function plantumlPlugin(
|
|
218
|
+
declare function plantumlPlugin(context: LoadContext, options?: PlantUmlPluginOptions): Plugin<void>;
|
|
131
219
|
/**
|
|
132
220
|
* Docusaurus option validation hook. Runs before the plugin function so configuration
|
|
133
221
|
* mistakes fail the build immediately with an actionable message.
|
|
@@ -139,4 +227,4 @@ declare function validateOptions({ options, }: {
|
|
|
139
227
|
options: PlantUmlPluginOptions & Partial<PluginOptions>;
|
|
140
228
|
}): PlantUmlPluginOptions & PluginOptions;
|
|
141
229
|
|
|
142
|
-
export { type CacheMode, DEFAULT_OPTIONS, type DiagramTheme, PLUGIN_ID, PLUGIN_NAME, type PlantUmlGlobalData, PlantUmlOptionsError, type PlantUmlPluginOptions, type ResolvedPlantUmlOptions, createCopyPlugin, plantumlPlugin as default, resolveOptions, validateOptions };
|
|
230
|
+
export { type CacheMode, DEFAULT_OPTIONS, type DiagramTheme, PLUGIN_ID, PLUGIN_NAME, type PlantUmlGlobalData, PlantUmlOptionsError, type PlantUmlPluginOptions, type ResolvedPlantUmlOptions, type ResolvedStdlibOptions, type StdlibOptions, type StdlibRuntimeManifest, createCopyPlugin, plantumlPlugin as default, resolveOptions, validateOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ConfigureWebpackUtils, LoadContext, Plugin, PluginOptions as DocusaurusPluginOptions } from '@docusaurus/types';
|
|
2
2
|
import type { WebpackPluginInstance } from 'webpack';
|
|
3
3
|
import { type PlantUmlPluginOptions, type ResolvedPlantUmlOptions } from './options.js';
|
|
4
|
-
|
|
4
|
+
import { type StdlibRuntimeManifest } from './stdlib.js';
|
|
5
|
+
export type { CacheMode, DiagramTheme, PlantUmlPluginOptions, ResolvedPlantUmlOptions, StdlibOptions, ResolvedStdlibOptions, } from './options.js';
|
|
5
6
|
export { DEFAULT_OPTIONS, PlantUmlOptionsError, resolveOptions } from './options.js';
|
|
6
7
|
export { PLUGIN_ID, PLUGIN_NAME } from './constants.js';
|
|
8
|
+
export type { StdlibRuntimeManifest } from './stdlib.js';
|
|
7
9
|
/** Shape of the data this plugin publishes to the browser through Docusaurus global data. */
|
|
8
10
|
export interface PlantUmlGlobalData {
|
|
9
11
|
options: ResolvedPlantUmlOptions;
|
|
@@ -11,6 +13,14 @@ export interface PlantUmlGlobalData {
|
|
|
11
13
|
assetsDir: string;
|
|
12
14
|
/** Installed `@plantuml/core` version; part of the cache key. */
|
|
13
15
|
coreVersion: string;
|
|
16
|
+
/**
|
|
17
|
+
* `baseUrl`-relative directory holding the standard library bundles, and what is in it.
|
|
18
|
+
* `null` when the standard library is switched off.
|
|
19
|
+
*/
|
|
20
|
+
stdlib: {
|
|
21
|
+
dir: string;
|
|
22
|
+
manifest: StdlibRuntimeManifest;
|
|
23
|
+
} | null;
|
|
14
24
|
}
|
|
15
25
|
/** One copy pattern per runtime file, shared by the webpack and Rspack code paths. */
|
|
16
26
|
interface CopyPattern {
|
|
@@ -27,7 +37,7 @@ interface CopyPattern {
|
|
|
27
37
|
* it is `undefined` and webpack is the only bundler, so an absent value is not an error.
|
|
28
38
|
*/
|
|
29
39
|
export declare function createCopyPlugin(currentBundler: ConfigureWebpackUtils['currentBundler'] | undefined, patterns: CopyPattern[]): WebpackPluginInstance;
|
|
30
|
-
export default function plantumlPlugin(
|
|
40
|
+
export default function plantumlPlugin(context: LoadContext, options?: PlantUmlPluginOptions): Plugin<void>;
|
|
31
41
|
/**
|
|
32
42
|
* Docusaurus option validation hook. Runs before the plugin function so configuration
|
|
33
43
|
* mistakes fail the build immediately with an actionable message.
|