@matfsw/docusaurus-plantuml-plugin 1.2.0 → 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 +65 -1
- package/README.md +144 -18
- 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/index.cjs +380 -7
- package/dist/index.d.cts +86 -3
- package/dist/index.d.ts +12 -2
- package/dist/index.js +20 -1
- package/dist/options.d.ts +52 -1
- package/dist/options.js +81 -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/PlantUmlDiagram/index.js +2 -1
- package/dist/theme/usePlantUmlConfig.d.ts +8 -0
- package/dist/theme/usePlantUmlConfig.js +14 -8
- package/package.json +3 -1
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",
|
|
@@ -127,7 +133,8 @@ var DEFAULT_OPTIONS = {
|
|
|
127
133
|
cacheMaxEntries: 50,
|
|
128
134
|
zoom: true,
|
|
129
135
|
showSource: true,
|
|
130
|
-
graphviz: DEFAULT_GRAPHVIZ_OPTIONS
|
|
136
|
+
graphviz: DEFAULT_GRAPHVIZ_OPTIONS,
|
|
137
|
+
stdlib: DEFAULT_STDLIB_OPTIONS
|
|
131
138
|
};
|
|
132
139
|
var CACHE_MODES = ["none", "memory", "session"];
|
|
133
140
|
var THEMES = ["auto", "light", "dark"];
|
|
@@ -234,6 +241,68 @@ function validateGraphviz(value) {
|
|
|
234
241
|
)
|
|
235
242
|
};
|
|
236
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
|
+
}
|
|
237
306
|
function validateRenderTimeout(value) {
|
|
238
307
|
if (value === void 0) return DEFAULT_OPTIONS.renderTimeoutMs;
|
|
239
308
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -261,7 +330,8 @@ function resolveOptions(rawOptions) {
|
|
|
261
330
|
return {
|
|
262
331
|
...DEFAULT_OPTIONS,
|
|
263
332
|
languages: [...DEFAULT_OPTIONS.languages],
|
|
264
|
-
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: [] }
|
|
265
335
|
};
|
|
266
336
|
}
|
|
267
337
|
if (!isPlainObject(rawOptions)) {
|
|
@@ -279,6 +349,7 @@ function resolveOptions(rawOptions) {
|
|
|
279
349
|
"zoom",
|
|
280
350
|
"showSource",
|
|
281
351
|
"graphviz",
|
|
352
|
+
"stdlib",
|
|
282
353
|
// Docusaurus injects `id` for multi-instance plugins.
|
|
283
354
|
"id"
|
|
284
355
|
]);
|
|
@@ -299,6 +370,7 @@ function resolveOptions(rawOptions) {
|
|
|
299
370
|
}
|
|
300
371
|
const languages = validateLanguages(rawOptions.languages, "languages", DEFAULT_OPTIONS.languages);
|
|
301
372
|
const graphviz = validateGraphviz(rawOptions.graphviz);
|
|
373
|
+
const stdlib = validateStdlib(rawOptions.stdlib);
|
|
302
374
|
if (graphviz.enabled) {
|
|
303
375
|
const claimedTwice = graphviz.languages.filter((entry) => languages.includes(entry));
|
|
304
376
|
if (claimedTwice.length > 0) {
|
|
@@ -310,6 +382,7 @@ function resolveOptions(rawOptions) {
|
|
|
310
382
|
return {
|
|
311
383
|
languages,
|
|
312
384
|
graphviz,
|
|
385
|
+
stdlib,
|
|
313
386
|
theme: theme ?? DEFAULT_OPTIONS.theme,
|
|
314
387
|
lazy: validateBoolean(rawOptions.lazy, "lazy", DEFAULT_OPTIONS.lazy),
|
|
315
388
|
cache: cache ?? DEFAULT_OPTIONS.cache,
|
|
@@ -330,8 +403,291 @@ function resolveOptions(rawOptions) {
|
|
|
330
403
|
};
|
|
331
404
|
}
|
|
332
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
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
|
|
333
689
|
// src/index.ts
|
|
334
|
-
var currentDir =
|
|
690
|
+
var currentDir = import_node_path4.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
335
691
|
function createCopyPlugin(currentBundler, patterns) {
|
|
336
692
|
if (currentBundler?.name === "rspack") {
|
|
337
693
|
const { CopyRspackPlugin } = currentBundler.instance;
|
|
@@ -344,20 +700,28 @@ function createCopyPlugin(currentBundler, patterns) {
|
|
|
344
700
|
}
|
|
345
701
|
return new import_copy_webpack_plugin.default({ patterns });
|
|
346
702
|
}
|
|
347
|
-
function plantumlPlugin(
|
|
703
|
+
function plantumlPlugin(context, options = {}) {
|
|
348
704
|
const resolved = resolveOptions(options);
|
|
349
705
|
const core = locatePlantUmlCore();
|
|
350
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;
|
|
351
714
|
return {
|
|
352
715
|
name: PLUGIN_NAME,
|
|
353
716
|
getThemePath() {
|
|
354
|
-
return
|
|
717
|
+
return import_node_path4.default.join(currentDir, "theme");
|
|
355
718
|
},
|
|
356
719
|
contentLoaded({ actions }) {
|
|
357
720
|
const globalData = {
|
|
358
721
|
options: resolved,
|
|
359
722
|
assetsDir,
|
|
360
|
-
coreVersion: core.version
|
|
723
|
+
coreVersion: core.version,
|
|
724
|
+
stdlib: stdlib && stdlibDir ? { dir: stdlibDir, manifest: stdlib.manifest } : null
|
|
361
725
|
};
|
|
362
726
|
actions.setGlobalData(globalData);
|
|
363
727
|
},
|
|
@@ -371,6 +735,15 @@ function plantumlPlugin(_context, options = {}) {
|
|
|
371
735
|
// These files are already minified upstream; re-processing 8 MB is wasted work.
|
|
372
736
|
info: { minimized: true }
|
|
373
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
|
+
}
|
|
374
747
|
return { plugins: [createCopyPlugin(utils?.currentBundler, patterns)] };
|
|
375
748
|
}
|
|
376
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
|
*
|
|
@@ -76,14 +120,20 @@ interface PlantUmlPluginOptions {
|
|
|
76
120
|
showSource?: boolean;
|
|
77
121
|
/** Graphviz/DOT diagram support. See {@link GraphvizOptions}. */
|
|
78
122
|
graphviz?: GraphvizOptions;
|
|
123
|
+
/**
|
|
124
|
+
* PlantUML standard library support. See {@link StdlibOptions}. `false` is shorthand for
|
|
125
|
+
* `{enabled: false}`.
|
|
126
|
+
*/
|
|
127
|
+
stdlib?: StdlibOptions | false;
|
|
79
128
|
/** Docusaurus plugin instance id, used when the plugin is registered more than once. */
|
|
80
129
|
id?: string;
|
|
81
130
|
}
|
|
82
131
|
/** Plugin options after validation, with every default applied. */
|
|
83
|
-
type ResolvedPlantUmlOptions = Required<Omit<PlantUmlPluginOptions, 'id' | 'languages' | 'graphviz'>> & {
|
|
132
|
+
type ResolvedPlantUmlOptions = Required<Omit<PlantUmlPluginOptions, 'id' | 'languages' | 'graphviz' | 'stdlib'>> & {
|
|
84
133
|
/** Normalized to lower case; matching is case-insensitive. */
|
|
85
134
|
languages: string[];
|
|
86
135
|
graphviz: ResolvedGraphvizOptions;
|
|
136
|
+
stdlib: ResolvedStdlibOptions;
|
|
87
137
|
};
|
|
88
138
|
declare const DEFAULT_OPTIONS: ResolvedPlantUmlOptions;
|
|
89
139
|
/** Thrown for invalid plugin options so Docusaurus fails the build with a useful message. */
|
|
@@ -98,6 +148,31 @@ declare class PlantUmlOptionsError extends Error {
|
|
|
98
148
|
*/
|
|
99
149
|
declare function resolveOptions(rawOptions: unknown): ResolvedPlantUmlOptions;
|
|
100
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
|
+
|
|
101
176
|
/**
|
|
102
177
|
* Identifiers shared by the Node-side plugin and the browser-side theme components.
|
|
103
178
|
*
|
|
@@ -116,6 +191,14 @@ interface PlantUmlGlobalData {
|
|
|
116
191
|
assetsDir: string;
|
|
117
192
|
/** Installed `@plantuml/core` version; part of the cache key. */
|
|
118
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;
|
|
119
202
|
}
|
|
120
203
|
/** One copy pattern per runtime file, shared by the webpack and Rspack code paths. */
|
|
121
204
|
interface CopyPattern {
|
|
@@ -132,7 +215,7 @@ interface CopyPattern {
|
|
|
132
215
|
* it is `undefined` and webpack is the only bundler, so an absent value is not an error.
|
|
133
216
|
*/
|
|
134
217
|
declare function createCopyPlugin(currentBundler: ConfigureWebpackUtils['currentBundler'] | undefined, patterns: CopyPattern[]): WebpackPluginInstance;
|
|
135
|
-
declare function plantumlPlugin(
|
|
218
|
+
declare function plantumlPlugin(context: LoadContext, options?: PlantUmlPluginOptions): Plugin<void>;
|
|
136
219
|
/**
|
|
137
220
|
* Docusaurus option validation hook. Runs before the plugin function so configuration
|
|
138
221
|
* mistakes fail the build immediately with an actionable message.
|
|
@@ -144,4 +227,4 @@ declare function validateOptions({ options, }: {
|
|
|
144
227
|
options: PlantUmlPluginOptions & Partial<PluginOptions>;
|
|
145
228
|
}): PlantUmlPluginOptions & PluginOptions;
|
|
146
229
|
|
|
147
|
-
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.
|