@forsakringskassan/docs-generator 1.26.0 → 1.28.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/dist/index.js ADDED
@@ -0,0 +1,2283 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs/promises');
4
+ var path = require('node:path');
5
+ var vendor = require('./vendor-uab7h6x-.js');
6
+ var createMarkdownRenderer = require('./create-markdown-renderer-CPrI2LLQ.js');
7
+ var require$$1 = require('crypto');
8
+ require('node:crypto');
9
+ var vueDocgenApi = require('vue-docgen-api');
10
+ var path$1 = require('node:path/posix');
11
+ var fs$1 = require('node:fs');
12
+ var sass = require('sass');
13
+ var node_url = require('node:url');
14
+ var esbuild = require('esbuild');
15
+ var node_util = require('node:util');
16
+ var nunjucks = require('nunjucks');
17
+ var vue = require('vue');
18
+ var vue2 = require('./vue2-CBDrnmVO.js');
19
+ var vue3 = require('./vue3-xJIC7Aol.js');
20
+ var express = require('express');
21
+ var childProcess = require('node:child_process');
22
+ require('path');
23
+ require('url');
24
+ require('fs');
25
+ require('fs/promises');
26
+ require('events');
27
+ require('stream');
28
+ require('string_decoder');
29
+ require('constants');
30
+ require('util');
31
+ require('assert');
32
+ require('readline');
33
+ require('child_process');
34
+ require('node:buffer');
35
+ require('node:process');
36
+ require('node:os');
37
+ require('node:timers/promises');
38
+ require('@vue/compiler-sfc');
39
+ require('typescript');
40
+ require('os');
41
+ require('http');
42
+ require('https');
43
+ require('buffer');
44
+ require('net');
45
+ require('tls');
46
+ require('tty');
47
+ require('querystring');
48
+
49
+ function defineSources(sources) {
50
+ return sources;
51
+ }
52
+
53
+ function formatSize(value) {
54
+ const suffices = ["kB", "MB"];
55
+ if (value < 1e3) {
56
+ return `${value}`;
57
+ }
58
+ for (const suffix of suffices) {
59
+ value = Math.round(value / 1e3 * 100) / 100;
60
+ if (value < 1e3) {
61
+ return `${value} ${suffix}`;
62
+ }
63
+ }
64
+ value = Math.round(value / 1e3 * 100) / 100;
65
+ return `${value} GB`;
66
+ }
67
+
68
+ const matchHeading = /^(#+)(.*)$/gm;
69
+ function getHeadings(text) {
70
+ return Array.from(text.matchAll(matchHeading), parseHeading);
71
+ }
72
+ function parseHeading(match) {
73
+ const [, prefix, text] = match;
74
+ const rank = prefix.length;
75
+ const id = createMarkdownRenderer.generateId(text);
76
+ return {
77
+ rank,
78
+ title: text.trim(),
79
+ anchor: id
80
+ };
81
+ }
82
+ function getDocumentOutline(text, _format) {
83
+ const entries = getHeadings(text);
84
+ const root = { title: "", rank: 0, anchor: "", subheadings: [] };
85
+ const stack = [root];
86
+ const top = () => stack[stack.length - 1];
87
+ for (const entry of entries) {
88
+ const heading = {
89
+ title: entry.title,
90
+ rank: entry.rank,
91
+ anchor: entry.anchor,
92
+ subheadings: []
93
+ };
94
+ while (top().rank >= entry.rank) {
95
+ stack.pop();
96
+ }
97
+ top().subheadings.push(heading);
98
+ stack.push(heading);
99
+ }
100
+ return root.subheadings;
101
+ }
102
+
103
+ function getIntegrity(source) {
104
+ const hash = require$$1.createHash("sha384").update(source).digest("base64");
105
+ return `sha384-${hash}`;
106
+ }
107
+
108
+ function haveOutput(doc) {
109
+ const { fileInfo } = doc;
110
+ return Boolean(fileInfo.outputName);
111
+ }
112
+
113
+ function interpolate(value, data) {
114
+ return value.replace(/{{([^}]+)}}/g, (match, raw) => {
115
+ const key = raw.trim();
116
+ return data[key] ?? match;
117
+ });
118
+ }
119
+
120
+ function parseImport(raw) {
121
+ const comments = [];
122
+ const stripped = raw.replace(/<!--.*?-->/gms, (match) => {
123
+ comments.push(match);
124
+ return "";
125
+ });
126
+ const filename = stripped.trim();
127
+ const extension = path.parse(filename).ext.slice(1);
128
+ return {
129
+ filename,
130
+ extension,
131
+ comments
132
+ };
133
+ }
134
+
135
+ function quote(text) {
136
+ return String(text).replace(/"/g, "&quot;");
137
+ }
138
+ function* serializeAttr(key, value) {
139
+ if (value === null || value === false) {
140
+ return;
141
+ }
142
+ if (value === true) {
143
+ yield key;
144
+ return;
145
+ }
146
+ if (typeof value === "string" || typeof value === "number") {
147
+ yield `${key}="${quote(value)}"`;
148
+ return;
149
+ }
150
+ for (const [innerKey, innerValue] of Object.entries(value)) {
151
+ yield* serializeAttr([key, innerKey].join("-"), innerValue);
152
+ }
153
+ }
154
+ function* serializeAttrs(attrs) {
155
+ for (const [key, value] of Object.entries(attrs)) {
156
+ yield* serializeAttr(key, value);
157
+ }
158
+ }
159
+
160
+ function difference(a, b) {
161
+ const _difference = new Set(a);
162
+ for (const elem of b) {
163
+ _difference.delete(elem);
164
+ }
165
+ return _difference;
166
+ }
167
+
168
+ function slugify(value) {
169
+ return value.toLowerCase().replace(/\//g, "--").replace(/[^a-z]+/g, "-").replace(/(^-+|-+$)/, "");
170
+ }
171
+
172
+ function toArray$3(value) {
173
+ return Array.isArray(value) ? value : [value];
174
+ }
175
+ function isIndexPage(parsed) {
176
+ const folder = path.basename(parsed.dir);
177
+ if (parsed.name === folder) {
178
+ return true;
179
+ }
180
+ if (parsed.name.toLowerCase() === "readme") {
181
+ return true;
182
+ }
183
+ if (parsed.name === "index") {
184
+ return true;
185
+ }
186
+ return false;
187
+ }
188
+ function getBadge(attrs) {
189
+ if (!attrs.status) {
190
+ return void 0;
191
+ }
192
+ switch (attrs.status) {
193
+ case "Produktionsklar":
194
+ return "success";
195
+ case "Deprekerad":
196
+ case "Experimentell":
197
+ return "error";
198
+ case "Prelimin\xE4r":
199
+ case "Draft":
200
+ case "Beta":
201
+ return "info";
202
+ default:
203
+ return "info";
204
+ }
205
+ }
206
+ function getComponentAlias(attrs) {
207
+ if (attrs.component) {
208
+ return toArray$3(attrs.component).map((it) => `component:${it}`);
209
+ } else {
210
+ return [];
211
+ }
212
+ }
213
+ function parseFile$1(filePath, basePath, content) {
214
+ const relative = basePath ? path.relative(basePath, createMarkdownRenderer.normalizePath(filePath)) : createMarkdownRenderer.normalizePath(filePath);
215
+ const parsed = path.parse(relative);
216
+ const blocks = vendor.fm(content);
217
+ const attributes = blocks.attributes;
218
+ const isIndex = isIndexPage(parsed);
219
+ const filename = isIndex ? "index" : parsed.name.toLowerCase();
220
+ const name = attributes.name ? attributes.name : parsed.name;
221
+ const urlpath = parsed.dir;
222
+ const outline = getDocumentOutline(blocks.body);
223
+ return {
224
+ id: `fs:${filePath.replace(/\\/g, "/")}`,
225
+ name,
226
+ alias: [...getComponentAlias(attributes)],
227
+ visible: attributes.visible ?? true,
228
+ attributes: {
229
+ title: attributes.title ?? name,
230
+ layout: attributes.layout,
231
+ status: attributes.status,
232
+ badge: getBadge(attributes),
233
+ component: attributes.component ? toArray$3(attributes.component) : void 0,
234
+ sortorder: attributes.sortorder ?? Infinity
235
+ },
236
+ body: blocks.body,
237
+ outline,
238
+ format: "markdown",
239
+ tags: [],
240
+ template: blocks.attributes.layout ?? "default",
241
+ fileInfo: {
242
+ path: ["", "."].includes(urlpath) ? "." : `./${createMarkdownRenderer.normalizePath(urlpath)}`,
243
+ name: filename,
244
+ fullPath: createMarkdownRenderer.normalizePath(filePath),
245
+ outputName: `${filename}.html`
246
+ }
247
+ };
248
+ }
249
+ async function frontMatterFileReader(filePath, basePath) {
250
+ const content = await fs.readFile(filePath, "utf-8");
251
+ const doc = parseFile$1(filePath, basePath, content);
252
+ return [doc];
253
+ }
254
+
255
+ const EMPTY_CHAR = "&#8208;";
256
+ const EM_DASH = "&#8212;";
257
+ function translateProps(props) {
258
+ var _a, _b;
259
+ const translatedProps = [];
260
+ for (const prop of props) {
261
+ const translatedProp = {
262
+ name: prop.name,
263
+ description: prop.description ?? EMPTY_CHAR,
264
+ type: ((_a = prop.type) == null ? void 0 : _a.name) ?? EMPTY_CHAR,
265
+ required: prop.required ? "true" : "false",
266
+ default: ((_b = prop.defaultValue) == null ? void 0 : _b.value) ?? EMPTY_CHAR
267
+ };
268
+ translatedProps.push(translatedProp);
269
+ }
270
+ return translatedProps;
271
+ }
272
+ function translateEvents(events) {
273
+ const translatedEvents = [];
274
+ for (const event of events) {
275
+ const translatedEvent = {
276
+ name: event.name,
277
+ description: event.description ?? EMPTY_CHAR,
278
+ properties: translateEventProperties(event)
279
+ };
280
+ translatedEvents.push(translatedEvent);
281
+ }
282
+ return translatedEvents;
283
+ }
284
+ function translateEventProperties(event) {
285
+ const properties = event.properties;
286
+ const types = event.type ? Object.values(event.type.names) : [];
287
+ if (!properties && !types.length) {
288
+ return EMPTY_CHAR;
289
+ }
290
+ if (!properties) {
291
+ return `<anonymous>: ${String(types)}`;
292
+ }
293
+ const translatedProperties = [];
294
+ for (let i = 0; i < properties.length; i++) {
295
+ const property = properties[i];
296
+ const name = property.name ?? "<anonymous>";
297
+ const eventType = types[i];
298
+ const hasEventType = !eventType || eventType !== "undefined";
299
+ const resolvedType = hasEventType ? eventType : String(property.type.names);
300
+ const type = `: ${resolvedType}`;
301
+ const description = property.description ? ` ${EM_DASH} ${property.description}` : "";
302
+ translatedProperties.push(`${name}${type}${description}`);
303
+ }
304
+ return translatedProperties.join("\n");
305
+ }
306
+ function translateSlots(slots) {
307
+ const translatedSlots = [];
308
+ for (const slot of slots) {
309
+ const translatedSlot = {
310
+ name: slot.name,
311
+ description: slot.description ?? EMPTY_CHAR,
312
+ bindings: translateSlotBindings(slot)
313
+ };
314
+ translatedSlots.push(translatedSlot);
315
+ }
316
+ return translatedSlots;
317
+ }
318
+ function translateSlotBindings(slot) {
319
+ if (!slot.bindings) {
320
+ return EMPTY_CHAR;
321
+ }
322
+ const translatedBindings = [];
323
+ for (const binding of slot.bindings) {
324
+ translatedBindings.push(binding.name ? binding.name : EMPTY_CHAR);
325
+ }
326
+ return translatedBindings.join("\n");
327
+ }
328
+ async function translateAPI(filePath) {
329
+ const api = await vueDocgenApi.parse(filePath);
330
+ const props = api.props ? translateProps(api.props) : [];
331
+ const events = api.events ? translateEvents(api.events) : [];
332
+ const slots = api.slots ? translateSlots(api.slots) : [];
333
+ return {
334
+ props,
335
+ events,
336
+ slots
337
+ };
338
+ }
339
+
340
+ const md = vendor.MarkdownIt({ breaks: true });
341
+ function generateTableHead(headers) {
342
+ return [
343
+ "<thead><tr>",
344
+ ...headers.map((header) => `<th>${header}</th>`),
345
+ "</tr></thead>"
346
+ ].join("");
347
+ }
348
+ function generateTableBody(content) {
349
+ const rows = content.map((row) => {
350
+ return [
351
+ "<tr>",
352
+ ...row.map((value) => `<td>${md.render(value)}</td>`),
353
+ "</tr>"
354
+ ].join("");
355
+ });
356
+ return ["<tbody>", ...rows, "</tbody>"].join("");
357
+ }
358
+ function generateTable(caption, headers, content) {
359
+ return [
360
+ '<div class="docs-table"><table>',
361
+ `<caption>${caption}</caption>`,
362
+ generateTableHead(headers),
363
+ generateTableBody(content),
364
+ "</table></div>"
365
+ ].join("");
366
+ }
367
+
368
+ function capitalize(text) {
369
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
370
+ }
371
+ function parseAPIToArray(api) {
372
+ const content = [];
373
+ const headers = Object.keys(api[0]);
374
+ const capitalizedHeaders = headers.map(capitalize);
375
+ content.push(capitalizedHeaders);
376
+ for (const row of api) {
377
+ content.push(Object.values(row));
378
+ }
379
+ return content;
380
+ }
381
+ function parseAPI(filePath, api) {
382
+ const relative = createMarkdownRenderer.normalizePath(filePath);
383
+ const parsedPath = path.parse(relative);
384
+ const componentName = parsedPath.name;
385
+ let html = "";
386
+ if (api.props.length) {
387
+ const propsArray = parseAPIToArray(api.props);
388
+ html += generateTable("Props", propsArray[0], propsArray.slice(1));
389
+ }
390
+ if (api.events.length) {
391
+ const eventsArray = parseAPIToArray(api.events);
392
+ html += generateTable("Events", eventsArray[0], eventsArray.slice(1));
393
+ }
394
+ if (api.slots.length) {
395
+ const slotsArray = parseAPIToArray(api.slots);
396
+ html += generateTable("Slots", slotsArray[0], slotsArray.slice(1));
397
+ }
398
+ return {
399
+ id: `fs:${filePath.replace(/\\/g, "/")}`,
400
+ name: `vue:${componentName}`,
401
+ alias: [],
402
+ visible: false,
403
+ attributes: { sortorder: Infinity },
404
+ body: html,
405
+ outline: [],
406
+ format: "html",
407
+ tags: [],
408
+ template: "",
409
+ fileInfo: {
410
+ path: "",
411
+ name: "",
412
+ fullPath: "",
413
+ outputName: false
414
+ }
415
+ };
416
+ }
417
+ async function vueFileReader(filePath) {
418
+ const translated = await translateAPI(filePath);
419
+ const doc = parseAPI(filePath, translated);
420
+ return [doc];
421
+ }
422
+
423
+ async function globAll(pattern) {
424
+ if (!pattern) {
425
+ return /* @__PURE__ */ new Set();
426
+ }
427
+ if (!Array.isArray(pattern)) {
428
+ return globAll([pattern]);
429
+ }
430
+ const results = await Promise.all(pattern.map((it) => vendor.glob(it)));
431
+ return new Set(results.flat());
432
+ }
433
+ async function getDocumentsForSource(src) {
434
+ const { transform } = src;
435
+ const include = await globAll(src.include);
436
+ const exclude = await globAll(src.exclude);
437
+ const files = Array.from(difference(include, exclude));
438
+ const promises = files.map(async (it) => {
439
+ const docs2 = await src.fileReader(it, src.basePath);
440
+ if (transform) {
441
+ return docs2.map((it2) => transform(it2));
442
+ } else {
443
+ return docs2;
444
+ }
445
+ });
446
+ const docs = await Promise.all(promises);
447
+ return docs.flat();
448
+ }
449
+ async function getAllDocuments(sourceFiles) {
450
+ const result = await Promise.all(sourceFiles.map(getDocumentsForSource));
451
+ return result.flat();
452
+ }
453
+ function fileReaderProcessor(sourceFiles) {
454
+ return {
455
+ stage: "generate-docs",
456
+ name: "file-reader-processor",
457
+ async handler(context) {
458
+ const result = await getAllDocuments(sourceFiles);
459
+ context.addDocument(result);
460
+ context.log(result.length, "documents found");
461
+ }
462
+ };
463
+ }
464
+
465
+ function parseFile(filePath, basePath, content) {
466
+ const attributes = JSON.parse(content);
467
+ const { title, href } = attributes;
468
+ if (!title) {
469
+ throw new Error(`No title property set in "${filePath}"`);
470
+ }
471
+ const relative = basePath ? path.relative(basePath, createMarkdownRenderer.normalizePath(filePath)) : createMarkdownRenderer.normalizePath(filePath);
472
+ const parsed = path.parse(relative);
473
+ const filename = parsed.name.toLowerCase();
474
+ const name = parsed.name;
475
+ const urlpath = parsed.dir;
476
+ return {
477
+ id: `nav:${filePath.replace(/\\/g, "/")}`,
478
+ name,
479
+ alias: [],
480
+ visible: attributes.href ? true : false,
481
+ attributes: {
482
+ title,
483
+ href,
484
+ sortorder: attributes.sortorder ?? Infinity
485
+ },
486
+ body: content,
487
+ outline: [],
488
+ format: "json",
489
+ tags: [],
490
+ template: "default",
491
+ fileInfo: {
492
+ path: ["", "."].includes(urlpath) ? "." : `./${createMarkdownRenderer.normalizePath(urlpath)}`,
493
+ name: filename,
494
+ fullPath: createMarkdownRenderer.normalizePath(filePath),
495
+ outputName: false
496
+ }
497
+ };
498
+ }
499
+ async function navigationFileReader(filePath, basePath) {
500
+ const content = await fs.readFile(filePath, "utf-8");
501
+ const doc = parseFile(filePath, basePath, content);
502
+ return [doc];
503
+ }
504
+
505
+ function resolveScssImport(filePath) {
506
+ const { dir, base } = path$1.parse(filePath);
507
+ const search = [`${base}.css`, `${base}.scss`, `_${base}.scss`, `${base}`];
508
+ for (const variant of search) {
509
+ try {
510
+ const moduleName = path$1.join(dir, variant);
511
+ const resolved = require.resolve(moduleName);
512
+ return node_url.pathToFileURL(resolved);
513
+ } catch (err) {
514
+ if (err.code !== "MODULE_NOT_FOUND") {
515
+ throw err;
516
+ }
517
+ }
518
+ }
519
+ throw new Error(`Failed to resolve "${filePath}"`);
520
+ }
521
+ const tildeImporter = {
522
+ canonicalize(url) {
523
+ const indexOfTilde = url.indexOf("~");
524
+ if (indexOfTilde >= 0) {
525
+ return resolveScssImport(url.slice(indexOfTilde + 1));
526
+ }
527
+ if (url.startsWith("file://")) {
528
+ const path$1 = node_url.fileURLToPath(url);
529
+ const relative = path.isAbsolute(path$1) ? path.relative(__dirname, path$1) : path$1;
530
+ return resolveScssImport(relative.replace(/\\/g, "/"));
531
+ }
532
+ return null;
533
+ },
534
+ async load(url) {
535
+ const filepath = node_url.fileURLToPath(url);
536
+ const parsed = path.parse(filepath);
537
+ const contents = await fs.readFile(filepath, "utf-8");
538
+ return {
539
+ contents,
540
+ syntax: parsed.ext.slice(1) === "scss" ? "scss" : "css"
541
+ };
542
+ }
543
+ };
544
+
545
+ async function compileSassString(dst, style) {
546
+ const result = await sass.compileStringAsync(style, {
547
+ style: "expanded",
548
+ importers: [tildeImporter]
549
+ });
550
+ await fs.mkdir(path.dirname(dst), { recursive: true });
551
+ await fs.writeFile(dst, result.css, "utf-8");
552
+ }
553
+
554
+ async function compileStyle(assetFolder, name, src) {
555
+ try {
556
+ const outfile = path$1.join("temp", `asset-${name}.css`);
557
+ const source = await fs.readFile(src, "utf-8");
558
+ await compileSassString(outfile, source);
559
+ const content = await fs.readFile(outfile, "utf-8");
560
+ const fingerprint = createMarkdownRenderer.getFingerprint(content);
561
+ const integrity = getIntegrity(content);
562
+ const filename = `${name}-${fingerprint}.css`;
563
+ const dst = path$1.join(assetFolder, filename);
564
+ await fs.rename(outfile, dst);
565
+ const stat = await fs.stat(dst);
566
+ return {
567
+ name,
568
+ filename,
569
+ publicPath: `./assets/${filename}`,
570
+ integrity,
571
+ size: stat.size,
572
+ type: "css"
573
+ };
574
+ } catch (err) {
575
+ console.error(err);
576
+ throw new Error(`Failed to compile style "${name}"`);
577
+ }
578
+ }
579
+
580
+ function cssAssetProcessor(assetFolder, assets) {
581
+ return {
582
+ name: "css-asset-processor",
583
+ after: "assets",
584
+ async handler(context) {
585
+ const assetInfo = context.getTemplateData("assets") ?? {};
586
+ const head = context.getTemplateData("injectHead") ?? [];
587
+ const body = context.getTemplateData("injectBody") ?? [];
588
+ for (const asset of assets) {
589
+ const info = await compileStyle(
590
+ assetFolder,
591
+ asset.name,
592
+ asset.src
593
+ );
594
+ const attrs = serializeAttrs(asset.options.attributes);
595
+ const inject = { ...info, attrs: Array.from(attrs).join(" ") };
596
+ assetInfo[asset.name] = info;
597
+ switch (asset.options.appendTo) {
598
+ case "none":
599
+ break;
600
+ case "head":
601
+ head.push(inject);
602
+ break;
603
+ case "body":
604
+ body.push(inject);
605
+ break;
606
+ }
607
+ context.setTemplateData("injectHead", head);
608
+ context.setTemplateData("injectBody", body);
609
+ context.log(info.filename, formatSize(info.size));
610
+ }
611
+ context.setTemplateData("assets", assetInfo);
612
+ }
613
+ };
614
+ }
615
+
616
+ function toArray$2(value) {
617
+ if (Array.isArray(value)) {
618
+ return value;
619
+ } else {
620
+ return [value];
621
+ }
622
+ }
623
+ async function compileScript(assetFolder, name, src, options) {
624
+ const iconLib = process.env.DOCS_ICON_LIB ?? "@fkui/icon-lib-default";
625
+ try {
626
+ const outfile = path.join("temp", `asset-${name}.js`);
627
+ await esbuild.build({
628
+ entryPoints: toArray$2(src),
629
+ outfile,
630
+ bundle: true,
631
+ format: "iife",
632
+ platform: "browser",
633
+ external: ["vue", "@fkui/vue"],
634
+ tsconfig: path.join(__dirname, "../tsconfig-examples.json"),
635
+ define: {
636
+ "process.env.DOCS_ICON_LIB": JSON.stringify(iconLib)
637
+ },
638
+ ...options
639
+ });
640
+ const content = await fs.readFile(outfile, "utf-8");
641
+ const fingerprint = createMarkdownRenderer.getFingerprint(content);
642
+ const integrity = getIntegrity(content);
643
+ const filename = `${name}-${fingerprint}.js`;
644
+ const dst = path.join(assetFolder, filename);
645
+ await fs.rename(outfile, dst);
646
+ const stat = await fs.stat(dst);
647
+ return {
648
+ name,
649
+ filename,
650
+ publicPath: `./assets/${filename}`,
651
+ integrity,
652
+ size: stat.size,
653
+ type: "js"
654
+ };
655
+ } catch {
656
+ throw new Error(`Failed to compile script "${name}"`);
657
+ }
658
+ }
659
+
660
+ function jsAssetProcessor(assetFolder, assets) {
661
+ return {
662
+ name: "js-asset-processor",
663
+ after: "assets",
664
+ async handler(context) {
665
+ const assetInfo = context.getTemplateData("assets") ?? {};
666
+ const head = context.getTemplateData("injectHead") ?? [];
667
+ const body = context.getTemplateData("injectBody") ?? [];
668
+ for (const asset of assets) {
669
+ const info = await compileScript(
670
+ assetFolder,
671
+ asset.name,
672
+ asset.src
673
+ );
674
+ const attrs = serializeAttrs(asset.options.attributes);
675
+ const inject = { ...info, attrs: Array.from(attrs).join(" ") };
676
+ assetInfo[asset.name] = info;
677
+ switch (asset.options.appendTo) {
678
+ case "none":
679
+ break;
680
+ case "head":
681
+ head.push(inject);
682
+ break;
683
+ case "body":
684
+ body.push(inject);
685
+ break;
686
+ }
687
+ context.setTemplateData("injectHead", head);
688
+ context.setTemplateData("injectBody", body);
689
+ context.log(info.filename, formatSize(info.size));
690
+ }
691
+ }
692
+ };
693
+ }
694
+
695
+ function staticResourcesProcessor(assetFolder, resources) {
696
+ return {
697
+ name: "static-resources-processor",
698
+ after: "render",
699
+ async handler(context) {
700
+ for (const resource of [...resources, ...context.resources]) {
701
+ const src = resource.from;
702
+ const dst = path$1.join(assetFolder, resource.to);
703
+ await fs.cp(src, dst, {
704
+ recursive: true
705
+ });
706
+ context.log(src, "->", dst);
707
+ }
708
+ }
709
+ };
710
+ }
711
+
712
+ function getExampleImport(searchDirs, filename) {
713
+ const pattern = searchDirs.map((dir) => `${dir}/**/${filename}`);
714
+ const matches = vendor.globSync(pattern);
715
+ if (matches.length === 0) {
716
+ const message = `No files matched import "${filename}"`;
717
+ throw new Error(message);
718
+ } else if (matches.length > 1) {
719
+ const message = `Multiple files matched import "${filename}"`;
720
+ throw new Error(message);
721
+ } else {
722
+ return createMarkdownRenderer.normalizePath(matches[0]);
723
+ }
724
+ }
725
+
726
+ function getExampleName(filename) {
727
+ return path.parse(filename).name;
728
+ }
729
+
730
+ const vueMajor = parseInt(vue.version.split(".", 2)[0], 10);
731
+ const vueGenerator = {
732
+ [2]: vue2.generateCode,
733
+ [3]: vue3.generateCode
734
+ };
735
+ function generateExample(options) {
736
+ const { language } = options;
737
+ if (language === "import") {
738
+ const parsed = parseImport(options.source);
739
+ const filename = getExampleImport(
740
+ options.exampleFolders,
741
+ parsed.filename
742
+ );
743
+ const source = fs$1.readFileSync(filename, "utf-8");
744
+ const language2 = parsed.extension;
745
+ const comments = parsed.comments;
746
+ const example = generateExample({
747
+ ...options,
748
+ source,
749
+ language: language2,
750
+ filename
751
+ });
752
+ return { ...example, comments };
753
+ }
754
+ switch (language) {
755
+ case "vue":
756
+ return generateVueExample(options);
757
+ case "html":
758
+ return generateStaticExample(options);
759
+ default:
760
+ return generateStaticExample(options);
761
+ }
762
+ }
763
+ function generateVueExample(options) {
764
+ const { filename, source, parent, setupPath, tags } = options;
765
+ const fn = vueGenerator[vueMajor];
766
+ const slug = getExampleName(filename);
767
+ const fingerprint = createMarkdownRenderer.getFingerprint(source);
768
+ const { markup, sourcecode, output } = fn({
769
+ filename,
770
+ slug,
771
+ fingerprint,
772
+ code: source,
773
+ setupPath
774
+ });
775
+ return {
776
+ source,
777
+ language: options.language,
778
+ comments: [],
779
+ tags,
780
+ markup,
781
+ output,
782
+ runtime: true,
783
+ task: {
784
+ outputFile: output,
785
+ sourcecode,
786
+ sourceFile: filename,
787
+ parent
788
+ }
789
+ };
790
+ }
791
+ function generateStaticExample(options) {
792
+ const { source, language, tags } = options;
793
+ const runtimeLanguages = ["html"];
794
+ return {
795
+ source,
796
+ language: options.language,
797
+ comments: [],
798
+ tags,
799
+ markup: source,
800
+ output: null,
801
+ runtime: runtimeLanguages.includes(language)
802
+ };
803
+ }
804
+
805
+ function isNavigationSection(node) {
806
+ return "key" in node;
807
+ }
808
+ function pathFromDoc({ fileInfo }) {
809
+ if (fileInfo.name === "index") {
810
+ return [fileInfo.path.replace(/\\/g, "/"), true];
811
+ } else {
812
+ return [
813
+ `./${path.join(fileInfo.path, fileInfo.name).replace(/\\/g, "/")}`,
814
+ false
815
+ ];
816
+ }
817
+ }
818
+ function getParentKey(name) {
819
+ return name.split("/").slice(0, -1).join("/");
820
+ }
821
+ function generateNavtree(docs) {
822
+ const section = {};
823
+ function createSection(key, title, sortorder) {
824
+ const existing = section[key];
825
+ if (existing) {
826
+ existing.title = title;
827
+ existing.sortorder = sortorder;
828
+ } else {
829
+ const node = {
830
+ key,
831
+ title,
832
+ path: "",
833
+ sortorder,
834
+ children: []
835
+ };
836
+ section[key] = node;
837
+ if (key !== ".") {
838
+ const parent = attach(key);
839
+ parent.children.push(node);
840
+ }
841
+ }
842
+ }
843
+ function attach(key) {
844
+ const parentKey = getParentKey(key);
845
+ let parent = section[parentKey];
846
+ if (parent) {
847
+ return parent;
848
+ }
849
+ parent = {
850
+ key: parentKey,
851
+ title: parentKey.split("/").at(-1) ?? "(missing title)",
852
+ path: "",
853
+ sortorder: Infinity,
854
+ children: []
855
+ };
856
+ section[parentKey] = parent;
857
+ let anchestor = parentKey;
858
+ let current = parent;
859
+ while (anchestor !== ".") {
860
+ anchestor = getParentKey(anchestor);
861
+ if (section[anchestor]) {
862
+ section[anchestor].children.push(current);
863
+ break;
864
+ }
865
+ const node = {
866
+ key: anchestor,
867
+ title: "",
868
+ path: "",
869
+ sortorder: Infinity,
870
+ children: [current]
871
+ };
872
+ section[anchestor] = node;
873
+ current = node;
874
+ }
875
+ return parent;
876
+ }
877
+ for (const doc of docs) {
878
+ const [name, isSection] = pathFromDoc(doc);
879
+ const title = doc.attributes.title ?? doc.fileInfo.name;
880
+ const sortorder = doc.attributes.sortorder;
881
+ if (doc.attributes.href) {
882
+ const parent2 = attach(name);
883
+ const leafNode = {
884
+ id: doc.id,
885
+ title,
886
+ path: doc.attributes.href,
887
+ sortorder,
888
+ external: true
889
+ };
890
+ parent2.children.push(leafNode);
891
+ continue;
892
+ }
893
+ if (!doc.fileInfo.outputName) {
894
+ if (isSection) {
895
+ createSection(name, title, sortorder);
896
+ }
897
+ continue;
898
+ }
899
+ if (!doc.visible) {
900
+ if (isSection) {
901
+ createSection(name, title, sortorder);
902
+ }
903
+ continue;
904
+ }
905
+ if (name === ".") {
906
+ createSection(name, title, sortorder);
907
+ continue;
908
+ }
909
+ const parent = attach(name);
910
+ if (isSection) {
911
+ const leafNode = {
912
+ id: doc.id,
913
+ title,
914
+ path: `${name}/`,
915
+ sortorder,
916
+ external: false
917
+ };
918
+ const existing = section[name];
919
+ if (existing) {
920
+ existing.title = title;
921
+ existing.path = leafNode.path;
922
+ existing.sortorder = sortorder;
923
+ existing.children.unshift(leafNode);
924
+ } else {
925
+ const sectionNode = {
926
+ key: name,
927
+ title,
928
+ path: leafNode.path,
929
+ sortorder,
930
+ children: [leafNode]
931
+ };
932
+ section[name] = sectionNode;
933
+ parent.children.push(sectionNode);
934
+ }
935
+ } else {
936
+ const leafNode = {
937
+ id: doc.id,
938
+ title,
939
+ path: `${doc.fileInfo.path}/${doc.fileInfo.outputName}`,
940
+ sortorder,
941
+ external: false
942
+ };
943
+ parent.children.push(leafNode);
944
+ }
945
+ }
946
+ const root = section["."];
947
+ if (root) {
948
+ return root;
949
+ } else {
950
+ return {
951
+ key: ".",
952
+ title: "",
953
+ path: "",
954
+ sortorder: Infinity,
955
+ children: []
956
+ };
957
+ }
958
+ }
959
+
960
+ function navigationProcessor() {
961
+ return {
962
+ stage: "generate-nav",
963
+ name: "navigation-processor",
964
+ handler(context) {
965
+ const navtree = generateNavtree(context.docs);
966
+ context.setTopNavigation(navtree);
967
+ context.setSideNavigation(navtree);
968
+ }
969
+ };
970
+ }
971
+
972
+ function sortNavigationTree(tree) {
973
+ tree.children.sort((a, b) => {
974
+ if (a.sortorder < b.sortorder) {
975
+ return -1;
976
+ } else if (a.sortorder > b.sortorder) {
977
+ return 1;
978
+ }
979
+ const titleA = a.title.toUpperCase();
980
+ const titleB = b.title.toUpperCase();
981
+ if (titleA < titleB) {
982
+ return -1;
983
+ }
984
+ if (titleA > titleB) {
985
+ return 1;
986
+ }
987
+ return 0;
988
+ });
989
+ for (const child of tree.children) {
990
+ if (isNavigationSection(child)) {
991
+ sortNavigationTree(child);
992
+ }
993
+ }
994
+ }
995
+
996
+ class TemplateLoader {
997
+ async = true;
998
+ folders;
999
+ templateCache;
1000
+ constructor(folders = []) {
1001
+ this.folders = [...folders, path.join(__dirname, "../templates")];
1002
+ this.templateCache = /* @__PURE__ */ new Map();
1003
+ }
1004
+ async getSource(name, callback) {
1005
+ try {
1006
+ const { content, filePath } = await this.resolveTemplate(name);
1007
+ callback(null, {
1008
+ src: content,
1009
+ path: filePath,
1010
+ noCache: false
1011
+ });
1012
+ } catch (err) {
1013
+ if (err instanceof Error) {
1014
+ callback(err, null);
1015
+ } else {
1016
+ callback(new Error(String(err)), null);
1017
+ }
1018
+ }
1019
+ }
1020
+ async resolveTemplate(name) {
1021
+ const { templateCache, folders } = this;
1022
+ const cached = templateCache.get(name);
1023
+ if (cached) {
1024
+ return cached;
1025
+ }
1026
+ const searchPaths = folders.map((it) => path.join(it, name));
1027
+ const filePath = searchPaths.find((it) => fs$1.existsSync(it));
1028
+ if (!filePath) {
1029
+ const searched = folders.map((it) => ` - "${it}"`).join("\n");
1030
+ const message = `Failed to resolve template "${name}", searched in:
1031
+
1032
+ ${searched}
1033
+
1034
+ Make sure the name is correct and the template file exists in one of the listed directories.`;
1035
+ throw new Error(message);
1036
+ }
1037
+ const content = await fs.readFile(filePath, "utf-8");
1038
+ const resolved = { content, filePath };
1039
+ templateCache.set(name, resolved);
1040
+ return resolved;
1041
+ }
1042
+ }
1043
+
1044
+ function dump(value) {
1045
+ return `<pre>${JSON.stringify(value, null, 2)}</pre>`;
1046
+ }
1047
+
1048
+ function json(value) {
1049
+ return JSON.stringify(value, null, 2);
1050
+ }
1051
+
1052
+ function isExternalUrl(url) {
1053
+ return url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//");
1054
+ }
1055
+ function isAbsoluteUrl(url) {
1056
+ return url.startsWith("/");
1057
+ }
1058
+ function relative(url, { fileInfo }) {
1059
+ if (isExternalUrl(url)) {
1060
+ return url;
1061
+ }
1062
+ if (isAbsoluteUrl(url)) {
1063
+ url = `.${url}`;
1064
+ }
1065
+ url = createMarkdownRenderer.normalizePath(url);
1066
+ const outputPath = createMarkdownRenderer.normalizePath(fileInfo.path);
1067
+ if (outputPath === url || `${outputPath}/` === url) {
1068
+ return "./";
1069
+ }
1070
+ const relative2 = path$1.relative(outputPath, url);
1071
+ const prefix = relative2.startsWith(".") ? "" : "./";
1072
+ const suffix = url.endsWith("/") ? "/" : "";
1073
+ return [prefix, relative2, suffix].join("");
1074
+ }
1075
+
1076
+ function take(haystack, key, value) {
1077
+ return haystack.filter((it) => it[key] === value);
1078
+ }
1079
+
1080
+ class MissingTemplateError extends Error {
1081
+ searchDir;
1082
+ constructor(fileInfo, template, format, searchDir) {
1083
+ const message = `Failed to find template "${template}" (${format} format) when rendering "${fileInfo.fullPath}"`;
1084
+ super(message);
1085
+ this.name = "MissingTemplateError";
1086
+ this.searchDir = searchDir;
1087
+ }
1088
+ prettyError() {
1089
+ return [
1090
+ this.message,
1091
+ "",
1092
+ "Searched the following directories:",
1093
+ ...this.searchDir.map((it) => ` - ${it}`)
1094
+ ].join("\n");
1095
+ }
1096
+ }
1097
+ const templateDirectory = path.join(__dirname, "../templates");
1098
+ const cache$1 = /* @__PURE__ */ new Map();
1099
+ function cacheKey(layout, extension) {
1100
+ return [layout, extension].join("|");
1101
+ }
1102
+ function findTemplate(from, src, format) {
1103
+ let layout;
1104
+ if (typeof src === "string") {
1105
+ layout = src;
1106
+ format ??= "html";
1107
+ } else {
1108
+ layout = src.template;
1109
+ format = src.format !== "json" ? "html" : "json";
1110
+ }
1111
+ const key = cacheKey(layout, format);
1112
+ const cached = cache$1.get(key);
1113
+ if (cached) {
1114
+ return cached;
1115
+ }
1116
+ const template = `${layout}.template.${format}`;
1117
+ const templateFile = path.join(templateDirectory, template);
1118
+ if (!fs$1.existsSync(templateFile)) {
1119
+ throw new MissingTemplateError(from, template, format, [
1120
+ templateDirectory
1121
+ ]);
1122
+ }
1123
+ cache$1.set(key, template);
1124
+ return template;
1125
+ }
1126
+
1127
+ const scriptPath = path.join(__dirname, "compile-example.js");
1128
+ let loader = null;
1129
+ function haveOutputFile(fileInfo) {
1130
+ return fileInfo.outputName !== false;
1131
+ }
1132
+ function fillActiveNavigation(doc, node) {
1133
+ if (isNavigationSection(node)) {
1134
+ const children = node.children.map(
1135
+ (it) => fillActiveNavigation(doc, it)
1136
+ );
1137
+ const active = children.some((it) => it.active);
1138
+ return {
1139
+ ...node,
1140
+ active,
1141
+ children
1142
+ };
1143
+ } else {
1144
+ const active = doc.id === node.id;
1145
+ return {
1146
+ ...node,
1147
+ active
1148
+ };
1149
+ }
1150
+ }
1151
+ function findSidenav(doc, tree) {
1152
+ const { path: path2, name } = doc.fileInfo;
1153
+ const category = path2 === "." ? name : path2.split("/")[1];
1154
+ const sidenav = tree.children.filter(isNavigationSection).find((it) => it.key === `./${category}`);
1155
+ if (sidenav) {
1156
+ return fillActiveNavigation(doc, sidenav);
1157
+ }
1158
+ }
1159
+ function cache(cacheFolder, outputFolder) {
1160
+ return (it) => {
1161
+ const cacheFile = path.join(cacheFolder, it.outputFile);
1162
+ const outputFile = path.join(outputFolder, it.outputFile);
1163
+ if (fs$1.existsSync(cacheFile)) {
1164
+ fs$1.copyFileSync(cacheFile, outputFile);
1165
+ return false;
1166
+ } else {
1167
+ return true;
1168
+ }
1169
+ };
1170
+ }
1171
+ async function compileExamples(options) {
1172
+ const { fileInfo, tasks, vendors } = options;
1173
+ if (tasks.length === 0) {
1174
+ return;
1175
+ }
1176
+ const cacheFolder = path.posix.join(options.cacheFolder, fileInfo.path);
1177
+ const outputFolder = path.posix.join(options.outputFolder, fileInfo.path);
1178
+ const cacheMiss = cache(cacheFolder, outputFolder);
1179
+ const dirtyTasks = tasks.filter(cacheMiss);
1180
+ const batch = {
1181
+ outputFolder,
1182
+ external: vendors.map((it) => it.package),
1183
+ tasks: dirtyTasks
1184
+ };
1185
+ const result = await vendor.execa("node", [scriptPath], {
1186
+ input: JSON.stringify(batch),
1187
+ all: true
1188
+ });
1189
+ const hasOutput = result.all ? result.all.length > 0 : false;
1190
+ if (hasOutput) {
1191
+ console.log(result.all);
1192
+ }
1193
+ }
1194
+ async function compileStandalones(options) {
1195
+ const { fileInfo, tasks, renderTemplate, templateData } = options;
1196
+ if (tasks.length === 0) {
1197
+ return;
1198
+ }
1199
+ const cacheFolder = path.posix.join(options.cacheFolder, fileInfo.path);
1200
+ const outputFolder = path.posix.join(options.outputFolder, fileInfo.path);
1201
+ const cacheMiss = cache(cacheFolder, outputFolder);
1202
+ const dirtyTasks = tasks.filter(cacheMiss);
1203
+ const standaloneTemplate = findTemplate(fileInfo, "example");
1204
+ for (const task of dirtyTasks) {
1205
+ const outputFile = path.join(outputFolder, task.outputFile);
1206
+ const content = await renderTemplate(standaloneTemplate, {
1207
+ ...templateData,
1208
+ content: task.content
1209
+ });
1210
+ await fs.writeFile(outputFile, content, "utf-8");
1211
+ }
1212
+ }
1213
+ function createTemplateLoader(folders) {
1214
+ loader = new TemplateLoader(folders);
1215
+ }
1216
+ async function render(doc, docs, nav, vendors, options) {
1217
+ const { fileInfo } = doc;
1218
+ const { outputFolder, cacheFolder } = options;
1219
+ if (!haveOutputFile(fileInfo)) {
1220
+ return null;
1221
+ }
1222
+ const dst = createMarkdownRenderer.getOutputFilePath(outputFolder, fileInfo);
1223
+ const mkdir = fs.mkdir(path.dirname(dst), { recursive: true });
1224
+ const topnav = nav.topnav;
1225
+ const sidenav = findSidenav(doc, nav.sidenav);
1226
+ if (sidenav && isNavigationSection(sidenav)) {
1227
+ sortNavigationTree(sidenav);
1228
+ }
1229
+ const njk = new nunjucks.Environment(loader, { autoescape: false });
1230
+ const asyncRender = node_util.promisify(njk.render);
1231
+ const renderTemplate = asyncRender.bind(njk);
1232
+ const template = findTemplate(doc.fileInfo, doc);
1233
+ const templateData = {
1234
+ ...options.templateData,
1235
+ site: options.site,
1236
+ doc,
1237
+ topnav,
1238
+ sidenav,
1239
+ vendors
1240
+ };
1241
+ const generatedExamples = [];
1242
+ const generatedStandalone = [];
1243
+ const markdownRenderer = createMarkdownRenderer.createMarkdownRenderer({
1244
+ docs,
1245
+ generateExample({ source, language, filename, tags }) {
1246
+ const example = generateExample({
1247
+ source,
1248
+ language,
1249
+ filename,
1250
+ parent: fileInfo.fullPath,
1251
+ setupPath: options.setupPath,
1252
+ exampleFolders: options.exampleFolders,
1253
+ tags
1254
+ });
1255
+ if (example.output) {
1256
+ const { dir, name } = path.parse(example.output);
1257
+ generatedExamples.push(example.task);
1258
+ generatedStandalone.push({
1259
+ outputFile: path.join(dir, `${name}.html`),
1260
+ content: example.markup
1261
+ });
1262
+ }
1263
+ return example;
1264
+ },
1265
+ addResource(dst2, src) {
1266
+ if (!fs$1.existsSync(src)) {
1267
+ throw new Error(`Failed to find image "${src}"`);
1268
+ }
1269
+ options.addResource(dst2, src);
1270
+ },
1271
+ handleSoftError(error) {
1272
+ throw error;
1273
+ }
1274
+ });
1275
+ njk.addFilter("marked", (content2) => {
1276
+ return markdownRenderer.render(doc, content2);
1277
+ });
1278
+ njk.addFilter("json", json);
1279
+ njk.addFilter("dump", dump);
1280
+ njk.addFilter("relative", relative);
1281
+ njk.addFilter("take", take);
1282
+ njk.addExtension("BlockContainer", {
1283
+ tags: ["container"],
1284
+ parse(parser, nodes) {
1285
+ const tok = parser.nextToken();
1286
+ const args = parser.parseSignature(null, true);
1287
+ parser.advanceAfterBlockEnd(tok.value);
1288
+ return new nodes.CallExtensionAsync(this, "run", args, []);
1289
+ },
1290
+ async run({ ctx }, container, callback) {
1291
+ const blocks = options.templateBlocks.get(container) ?? [];
1292
+ const promises = blocks.map(({ renderer }) => {
1293
+ if ("filename" in renderer) {
1294
+ const data = renderer.data;
1295
+ return renderTemplate(renderer.filename, {
1296
+ ...ctx,
1297
+ ...data
1298
+ });
1299
+ }
1300
+ if ("render" in renderer) {
1301
+ return Promise.resolve(renderer.render());
1302
+ }
1303
+ return Promise.resolve("");
1304
+ });
1305
+ const content2 = await Promise.all(promises);
1306
+ const markup = content2.join("");
1307
+ return callback(null, new nunjucks.runtime.SafeString(markup));
1308
+ }
1309
+ });
1310
+ await mkdir;
1311
+ let content;
1312
+ try {
1313
+ content = await renderTemplate(template, templateData);
1314
+ } catch (err) {
1315
+ const prefix = `Failed to render "${fileInfo.fullPath}"`;
1316
+ const message = err instanceof Error ? err.message : String(err);
1317
+ throw new Error(`${prefix}: ${message}`, { cause: err });
1318
+ }
1319
+ const expandedDst = dst.replace(/\[([^]+)\]/g, (match, key) => {
1320
+ if (key === "hash") {
1321
+ return createMarkdownRenderer.getFingerprint(doc.body);
1322
+ } else {
1323
+ return match;
1324
+ }
1325
+ });
1326
+ const writeFile = fs.writeFile(expandedDst, content ?? "null", "utf-8");
1327
+ try {
1328
+ await compileExamples({
1329
+ fileInfo,
1330
+ cacheFolder,
1331
+ outputFolder,
1332
+ tasks: generatedExamples,
1333
+ vendors
1334
+ });
1335
+ } catch (err) {
1336
+ const prefix = `Failed to compile examples from "${fileInfo.fullPath}"`;
1337
+ const message = err instanceof Error ? err.message : String(err);
1338
+ throw new Error(`${prefix}: ${message}`, { cause: err });
1339
+ }
1340
+ try {
1341
+ await compileStandalones({
1342
+ fileInfo,
1343
+ cacheFolder,
1344
+ outputFolder,
1345
+ tasks: generatedStandalone,
1346
+ renderTemplate,
1347
+ templateData
1348
+ });
1349
+ } catch (err) {
1350
+ const prefix = `Failed to render standalone examples from "${fileInfo.fullPath}"`;
1351
+ const message = err instanceof Error ? err.message : String(err);
1352
+ throw new Error(`${prefix}: ${message}`, { cause: err });
1353
+ }
1354
+ await writeFile;
1355
+ return dst;
1356
+ }
1357
+
1358
+ const progressbar = new vendor.cliProgress.SingleBar({
1359
+ format: " {bar} {percentage}% | {value}/{total} documents | {filename}",
1360
+ barCompleteChar: "\u2588",
1361
+ barIncompleteChar: "\u2591",
1362
+ hideCursor: true,
1363
+ clearOnComplete: true
1364
+ });
1365
+ function nunjucksProcessor(options) {
1366
+ return {
1367
+ stage: "render",
1368
+ name: "nunjucks-renderer",
1369
+ async handler(context) {
1370
+ function renderDocument(doc) {
1371
+ const nav = {
1372
+ topnav: context.topnav,
1373
+ sidenav: context.sidenav
1374
+ };
1375
+ return render(doc, context.docs, nav, context.vendors, {
1376
+ ...options,
1377
+ templateBlocks: context.getAllTemplateBlocks(),
1378
+ templateData: context.getAllTemplateData(),
1379
+ addResource(dst, src) {
1380
+ context.addResource(dst, src);
1381
+ }
1382
+ });
1383
+ }
1384
+ const docs = context.docs.filter((it) => {
1385
+ return it.fileInfo.outputName;
1386
+ });
1387
+ createTemplateLoader(options.templateFolders);
1388
+ progressbar.start(docs.length, 0, {
1389
+ filename: docs.length > 0 ? docs[0].fileInfo.fullPath : ""
1390
+ });
1391
+ const generatedFiles = [];
1392
+ try {
1393
+ for (const doc of context.docs) {
1394
+ const filePath = await renderDocument(doc);
1395
+ if (filePath) {
1396
+ generatedFiles.push(filePath);
1397
+ }
1398
+ progressbar.increment(1, {
1399
+ filename: doc.fileInfo.fullPath
1400
+ });
1401
+ }
1402
+ } finally {
1403
+ progressbar.stop();
1404
+ }
1405
+ context.log(docs.length, "documents rendered");
1406
+ return generatedFiles;
1407
+ }
1408
+ };
1409
+ }
1410
+
1411
+ function flattenOutline(outline) {
1412
+ return outline.flatMap((entry) => {
1413
+ return [
1414
+ { heading: entry.title, anchor: entry.anchor },
1415
+ ...flattenOutline(entry.subheadings)
1416
+ ];
1417
+ });
1418
+ }
1419
+ function findExamples(doc) {
1420
+ if (doc.format !== "markdown") {
1421
+ return [];
1422
+ }
1423
+ const collected = [];
1424
+ const md = vendor.MarkdownIt();
1425
+ md.renderer.rules.fence = (tokens, idx) => {
1426
+ const { content, info, map } = tokens[idx];
1427
+ const [language, ...tags] = info.split(/\s+/);
1428
+ const hashContent = `${map == null ? void 0 : map[0]}:${map == null ? void 0 : map[1]}:${info}:${content}`;
1429
+ const fingerprint = createMarkdownRenderer.getFingerprint(hashContent);
1430
+ collected.push({
1431
+ selector: `#example-${fingerprint}`,
1432
+ language,
1433
+ tags
1434
+ });
1435
+ return "";
1436
+ };
1437
+ md.render(doc.body);
1438
+ return collected;
1439
+ }
1440
+ function manifestPageFromDocument(doc) {
1441
+ const { fileInfo } = doc;
1442
+ return {
1443
+ path: createMarkdownRenderer.getOutputFilePath("", fileInfo),
1444
+ title: doc.attributes.title ?? doc.name ?? "",
1445
+ outline: flattenOutline(doc.outline),
1446
+ examples: findExamples(doc)
1447
+ };
1448
+ }
1449
+
1450
+ function customRequire(name) {
1451
+ if (typeof window.__modules__ === "undefined") {
1452
+ window.__modules__ = {};
1453
+ }
1454
+ const mod = window.__modules__[name];
1455
+ if (!mod) {
1456
+ throw new Error(`Cannot find module "${name}"`);
1457
+ }
1458
+ return mod;
1459
+ }
1460
+ function getAssetSource(asset, require) {
1461
+ const lines = [];
1462
+ const pkg = asset.package.replace(/\\/g, "/");
1463
+ if (!asset.expose) {
1464
+ return `import "${pkg}"`;
1465
+ }
1466
+ if (asset.expose === "named") {
1467
+ lines.push(`import * as lib from "${pkg}";`);
1468
+ } else {
1469
+ lines.push(`import lib from "${pkg}";`);
1470
+ }
1471
+ asset.subpaths.map((subpath, index) => {
1472
+ if (asset.expose === "named") {
1473
+ lines.push(`import * as lib$${index} from "${subpath}";`);
1474
+ } else {
1475
+ lines.push(`import lib$${index} from "${subpath}";`);
1476
+ }
1477
+ });
1478
+ lines.push(`window.require = window.require || ${require};`);
1479
+ lines.push(`window.__modules__ = window.__modules__ || {};`);
1480
+ lines.push(`window.__modules__["${asset.package}"] = lib;`);
1481
+ if (typeof asset.alias !== "undefined") {
1482
+ lines.push(`window.__modules__["${asset.alias}"] = lib;`);
1483
+ }
1484
+ asset.subpaths.map((subpath, index) => {
1485
+ lines.push(`window.__modules__["${subpath}"] = lib$${index};`);
1486
+ });
1487
+ if (typeof asset.global !== "undefined") {
1488
+ lines.push(`window["${asset.global}"] = lib;`);
1489
+ }
1490
+ return lines.join("\n");
1491
+ }
1492
+ async function compileVendor(assetFolder, vendor, options) {
1493
+ const name = path.isAbsolute(vendor.package) ? path.basename(vendor.package) : vendor.package;
1494
+ const slug = slugify(name);
1495
+ const outfile = `temp/vendor-${slug}.out.js`;
1496
+ const tmpfile = `temp/vendor-${slug}.in.js`;
1497
+ const source = getAssetSource(vendor, customRequire.toString());
1498
+ const tsconfig = path.resolve(__dirname, "../tsconfig-examples.json");
1499
+ await fs.writeFile(tmpfile, source, "utf-8");
1500
+ await esbuild.build({
1501
+ entryPoints: [tmpfile],
1502
+ outfile,
1503
+ bundle: true,
1504
+ format: "iife",
1505
+ platform: "browser",
1506
+ tsconfig,
1507
+ define: {
1508
+ "process.env.NODE_ENV": JSON.stringify(
1509
+ process.env.NODE_ENV ?? "production"
1510
+ )
1511
+ },
1512
+ alias: vendor.alias ? { [`${vendor.package}`]: vendor.alias } : void 0,
1513
+ ...options
1514
+ });
1515
+ const content = await fs.readFile(outfile, "utf-8");
1516
+ const fingerprint = createMarkdownRenderer.getFingerprint(content);
1517
+ const integrity = getIntegrity(content);
1518
+ const filename = `vendor-${slug}-${fingerprint}.js`;
1519
+ const dst = path.join(assetFolder, filename).replace(/\\/g, "/");
1520
+ await fs.rename(outfile, dst);
1521
+ const stat = await fs.stat(dst);
1522
+ return {
1523
+ package: vendor.package,
1524
+ filename,
1525
+ publicPath: `./assets/${filename}`,
1526
+ integrity,
1527
+ size: stat.size
1528
+ };
1529
+ }
1530
+
1531
+ function normalizeVendorDefinition(vendor) {
1532
+ if (typeof vendor === "string") {
1533
+ return {
1534
+ package: vendor,
1535
+ global: void 0,
1536
+ expose: "named",
1537
+ subpaths: []
1538
+ };
1539
+ } else {
1540
+ return {
1541
+ package: vendor.package,
1542
+ global: vendor.global,
1543
+ expose: vendor.expose ?? "named",
1544
+ subpaths: vendor.subpaths ?? [],
1545
+ alias: vendor.alias ?? void 0
1546
+ };
1547
+ }
1548
+ }
1549
+
1550
+ function getPackageName(vendor) {
1551
+ return typeof vendor === "string" ? vendor : vendor.package;
1552
+ }
1553
+ function generateVendorAssets(assetFolder, assets) {
1554
+ const packages = assets.map(getPackageName);
1555
+ const normalized = assets.map(normalizeVendorDefinition);
1556
+ const promises = normalized.map((it) => {
1557
+ const external = packages.filter((pkg) => pkg !== it.package);
1558
+ return compileVendor(assetFolder, it, {
1559
+ external
1560
+ });
1561
+ });
1562
+ return Promise.all(promises);
1563
+ }
1564
+ function vendorProcessor(assetFolder, vendor) {
1565
+ return {
1566
+ stage: "assets",
1567
+ name: "vendor-processor",
1568
+ async handler(context) {
1569
+ const assets = await generateVendorAssets(assetFolder, vendor);
1570
+ context.addVendorAsset(assets);
1571
+ for (const asset of assets) {
1572
+ const filename = path$1.basename(asset.publicPath);
1573
+ context.log(filename, formatSize(asset.size));
1574
+ }
1575
+ }
1576
+ };
1577
+ }
1578
+
1579
+ function livereloadProcessor(options) {
1580
+ const { enabled } = options;
1581
+ return {
1582
+ after: "generate-docs",
1583
+ name: "livereload-processor",
1584
+ enabled,
1585
+ handler(context) {
1586
+ context.addTemplateBlock("body:end", "livereload", {
1587
+ filename: "partials/livereload.html"
1588
+ });
1589
+ }
1590
+ };
1591
+ }
1592
+
1593
+ async function keypress() {
1594
+ process.stdin.setRawMode(true);
1595
+ process.stdin.resume();
1596
+ return new Promise((resolve) => {
1597
+ process.stdin.once("data", (data) => {
1598
+ process.stdin.setRawMode(false);
1599
+ process.stdin.resume();
1600
+ resolve(data.toString("utf-8"));
1601
+ });
1602
+ });
1603
+ }
1604
+
1605
+ function printMenu(addr) {
1606
+ console.log();
1607
+ console.group(
1608
+ `Starting development server at http://localhost:${addr.port}`
1609
+ );
1610
+ console.log();
1611
+ console.log("[q] quit");
1612
+ console.log();
1613
+ console.groupEnd();
1614
+ }
1615
+
1616
+ function sleep(ms) {
1617
+ return new Promise((resolve) => setTimeout(resolve, ms));
1618
+ }
1619
+ function createRebuilder(callback, livereload) {
1620
+ let inflight = false;
1621
+ let queue = [];
1622
+ async function rebuild(filePath) {
1623
+ queue.push(filePath);
1624
+ if (inflight) {
1625
+ return;
1626
+ }
1627
+ inflight = true;
1628
+ try {
1629
+ while (queue.length > 0) {
1630
+ const modifiedFiles = queue;
1631
+ queue = [];
1632
+ const generatedFiles = await callback(modifiedFiles);
1633
+ livereload(generatedFiles);
1634
+ await sleep(200);
1635
+ }
1636
+ } finally {
1637
+ inflight = false;
1638
+ }
1639
+ }
1640
+ return rebuild;
1641
+ }
1642
+ async function serve(options) {
1643
+ const app = express();
1644
+ app.use(express.static(options.outputFolder));
1645
+ const server = app.listen(8080);
1646
+ printMenu(server.address());
1647
+ const livereload = vendor.tinylr();
1648
+ livereload.listen(35729);
1649
+ const watcher = vendor.chokidar.watch(options.watch);
1650
+ const rebuild = createRebuilder(options.rebuild, (filePath) => {
1651
+ const files = filePath.map((it) => {
1652
+ return path$1.relative(options.outputFolder, it);
1653
+ });
1654
+ livereload.changed({ body: { files } });
1655
+ });
1656
+ watcher.on("change", async (filePath) => {
1657
+ rebuild(filePath);
1658
+ });
1659
+ for (; ; ) {
1660
+ const key = await keypress();
1661
+ switch (key) {
1662
+ case "":
1663
+ case "q":
1664
+ console.log("Shutting down gracefully");
1665
+ server.close();
1666
+ watcher.close();
1667
+ livereload.close();
1668
+ process.stdin.unref();
1669
+ return;
1670
+ }
1671
+ }
1672
+ }
1673
+
1674
+ function toArray$1(value) {
1675
+ return Array.isArray(value) ? value : [value];
1676
+ }
1677
+ function filterProcessors(stage2, processors) {
1678
+ const before = [];
1679
+ const during = [];
1680
+ const after = [];
1681
+ for (const processor of processors) {
1682
+ if (processor.enabled === false) {
1683
+ continue;
1684
+ }
1685
+ if (processor.before === stage2) {
1686
+ before.push(processor);
1687
+ }
1688
+ if (processor.stage === stage2) {
1689
+ during.push(processor);
1690
+ }
1691
+ if (processor.after === stage2) {
1692
+ after.push(processor);
1693
+ }
1694
+ }
1695
+ return [...before, ...during, ...after];
1696
+ }
1697
+ async function stage(stage2, context, processors, { verbose } = { verbose: true }) {
1698
+ if (verbose) {
1699
+ console.log(`stage:${stage2}`);
1700
+ }
1701
+ let generatedFiles = [];
1702
+ const filteredProcessors = filterProcessors(stage2, processors);
1703
+ for (let i = 0; i < filteredProcessors.length; i++) {
1704
+ const processor = filteredProcessors[i];
1705
+ const isLast = i === filteredProcessors.length - 1;
1706
+ if (verbose) {
1707
+ console.log(isLast ? " \u2514\u2500" : " \u251C\u2500", processor.name);
1708
+ }
1709
+ try {
1710
+ const result = await processor.handler({
1711
+ ...context,
1712
+ log(...args) {
1713
+ if (verbose) {
1714
+ console.log(isLast ? " " : " \u2502 ", ...args);
1715
+ }
1716
+ }
1717
+ });
1718
+ if (result) {
1719
+ generatedFiles = [...generatedFiles, ...result];
1720
+ }
1721
+ } catch (err) {
1722
+ console.error(`When running processor "${processor.name}":`);
1723
+ console.error(err);
1724
+ throw err;
1725
+ }
1726
+ }
1727
+ return generatedFiles;
1728
+ }
1729
+ function createContext() {
1730
+ let docs = [];
1731
+ let vendors = [];
1732
+ const resources = [];
1733
+ const templateBlocks = /* @__PURE__ */ new Map();
1734
+ let topnav = {
1735
+ key: ".",
1736
+ title: "",
1737
+ path: "",
1738
+ sortorder: Infinity,
1739
+ children: []
1740
+ };
1741
+ let sidenav = {
1742
+ key: ".",
1743
+ title: "",
1744
+ path: "",
1745
+ sortorder: Infinity,
1746
+ children: []
1747
+ };
1748
+ const templateData = {};
1749
+ return {
1750
+ get docs() {
1751
+ return docs;
1752
+ },
1753
+ get vendors() {
1754
+ return vendors;
1755
+ },
1756
+ get resources() {
1757
+ return resources;
1758
+ },
1759
+ get topnav() {
1760
+ return topnav;
1761
+ },
1762
+ get sidenav() {
1763
+ return sidenav;
1764
+ },
1765
+ addDocument(document) {
1766
+ docs = [...docs, ...toArray$1(document)];
1767
+ },
1768
+ addVendorAsset(asset) {
1769
+ vendors = [...vendors, ...toArray$1(asset)];
1770
+ },
1771
+ addResource(dst, src) {
1772
+ resources.push({
1773
+ from: src.replace(/\\/g, "/"),
1774
+ to: dst
1775
+ });
1776
+ },
1777
+ addTemplateBlock(container, id, renderer) {
1778
+ const block = {
1779
+ container,
1780
+ id,
1781
+ renderer
1782
+ };
1783
+ const list = templateBlocks.get(container) ?? [];
1784
+ templateBlocks.set(container, [...list, block]);
1785
+ },
1786
+ getAllTemplateBlocks() {
1787
+ return templateBlocks;
1788
+ },
1789
+ setTopNavigation(root) {
1790
+ topnav = root;
1791
+ },
1792
+ setSideNavigation(root) {
1793
+ sidenav = root;
1794
+ },
1795
+ getAllTemplateData() {
1796
+ return templateData;
1797
+ },
1798
+ getTemplateData(key) {
1799
+ return templateData[key];
1800
+ },
1801
+ setTemplateData(key, value) {
1802
+ templateData[key] = value;
1803
+ }
1804
+ };
1805
+ }
1806
+ class Generator {
1807
+ site;
1808
+ outputFolder;
1809
+ cacheFolder;
1810
+ assetFolder;
1811
+ exampleFolders;
1812
+ templateFolders;
1813
+ processors;
1814
+ vendor;
1815
+ setupPath;
1816
+ scripts;
1817
+ styles;
1818
+ resources;
1819
+ sourceFiles;
1820
+ constructor(options) {
1821
+ if (typeof options.site === "undefined") {
1822
+ throw new Error("site metadata not set in configuration");
1823
+ }
1824
+ this.site = options.site;
1825
+ this.outputFolder = options.outputFolder;
1826
+ this.cacheFolder = options.cacheFolder;
1827
+ this.assetFolder = path.posix.join(options.outputFolder, "assets");
1828
+ this.exampleFolders = options.exampleFolders;
1829
+ this.templateFolders = options.templateFolders ?? [];
1830
+ this.processors = options.processors ?? [];
1831
+ this.vendor = options.vendor ?? [];
1832
+ this.setupPath = options.setupPath.replace(/\\/g, "/");
1833
+ this.scripts = [];
1834
+ this.styles = [];
1835
+ this.resources = [];
1836
+ this.sourceFiles = [];
1837
+ }
1838
+ compileScript(name, src, options) {
1839
+ this.scripts.push({
1840
+ name,
1841
+ src,
1842
+ options: {
1843
+ appendTo: "none",
1844
+ attributes: {},
1845
+ ...options
1846
+ }
1847
+ });
1848
+ }
1849
+ compileStyle(name, src, options) {
1850
+ this.styles.push({
1851
+ name,
1852
+ src,
1853
+ options: {
1854
+ appendTo: "none",
1855
+ attributes: {},
1856
+ ...options
1857
+ }
1858
+ });
1859
+ }
1860
+ /**
1861
+ * @param dst - Destination directory relative to asset folder.
1862
+ * @param src - File or directory to copy.
1863
+ */
1864
+ copyResource(dst, src) {
1865
+ this.resources.push({
1866
+ from: src.replace(/\\/g, "/"),
1867
+ to: dst
1868
+ });
1869
+ }
1870
+ /**
1871
+ * Generate a manifest listing all generated documents that will be present
1872
+ * in `outputFolder`.
1873
+ *
1874
+ * Note: this only collects documents from the `generate-docs` stage,
1875
+ * potential documents generated at later stages will not be present.
1876
+ *
1877
+ * @public
1878
+ */
1879
+ async manifest(sourceFiles) {
1880
+ const processors = [
1881
+ fileReaderProcessor(sourceFiles),
1882
+ ...this.processors
1883
+ ];
1884
+ const context = createContext();
1885
+ await stage("generate-docs", context, processors, { verbose: false });
1886
+ const docs = context.docs.filter(haveOutput);
1887
+ const pages = docs.map(manifestPageFromDocument);
1888
+ return { pages };
1889
+ }
1890
+ async build(sourceFiles) {
1891
+ this.sourceFiles = sourceFiles;
1892
+ const {
1893
+ site,
1894
+ outputFolder,
1895
+ cacheFolder,
1896
+ assetFolder,
1897
+ exampleFolders,
1898
+ templateFolders,
1899
+ setupPath
1900
+ } = this;
1901
+ await this._prepareFolders();
1902
+ const processors = [
1903
+ fileReaderProcessor(sourceFiles),
1904
+ vendorProcessor(assetFolder, this.vendor),
1905
+ cssAssetProcessor(assetFolder, this.styles),
1906
+ jsAssetProcessor(assetFolder, this.scripts),
1907
+ staticResourcesProcessor(assetFolder, this.resources),
1908
+ navigationProcessor(),
1909
+ nunjucksProcessor({
1910
+ site: {
1911
+ lang: "en",
1912
+ ...site
1913
+ },
1914
+ outputFolder,
1915
+ cacheFolder,
1916
+ exampleFolders,
1917
+ templateFolders,
1918
+ setupPath
1919
+ }),
1920
+ ...this.processors
1921
+ ];
1922
+ const context = createContext();
1923
+ const generatedFiles = [
1924
+ await stage("generate-docs", context, processors),
1925
+ await stage("generate-nav", context, processors),
1926
+ await stage("assets", context, processors),
1927
+ await stage("render", context, processors)
1928
+ ];
1929
+ return generatedFiles.flat();
1930
+ }
1931
+ /**
1932
+ * Start a development server hosting the generated documentation.
1933
+ */
1934
+ serve() {
1935
+ const { outputFolder, sourceFiles } = this;
1936
+ const watch = sourceFiles.map((it) => it.include).flat();
1937
+ return serve({
1938
+ outputFolder,
1939
+ watch,
1940
+ rebuild: (_filePath) => {
1941
+ return this.build(sourceFiles);
1942
+ }
1943
+ });
1944
+ }
1945
+ async _prepareFolders() {
1946
+ const { outputFolder, cacheFolder, assetFolder } = this;
1947
+ await fs.rm(cacheFolder, { force: true, recursive: true });
1948
+ if (fs$1.existsSync(outputFolder)) {
1949
+ await fs.mkdir(path.dirname(cacheFolder), { recursive: true });
1950
+ await vendor.fse.copy(outputFolder, cacheFolder);
1951
+ await fs.rm(outputFolder, { recursive: true });
1952
+ }
1953
+ await fs.mkdir(outputFolder, { recursive: true });
1954
+ await fs.mkdir(assetFolder, { recursive: true });
1955
+ await fs.mkdir("temp", { recursive: true });
1956
+ }
1957
+ }
1958
+
1959
+ function toArray(value) {
1960
+ return Array.isArray(value) ? value : [value];
1961
+ }
1962
+ function matomoProcessor(options) {
1963
+ const { enabled, siteId, apiUrl, trackerUrl, hostname } = options;
1964
+ return {
1965
+ after: "generate-docs",
1966
+ name: "matomo-processor",
1967
+ enabled,
1968
+ handler(context) {
1969
+ context.addTemplateBlock("head", "matomo", {
1970
+ filename: "partials/matomo.html",
1971
+ data: {
1972
+ siteId,
1973
+ apiUrl,
1974
+ trackerUrl,
1975
+ hostname: hostname ? toArray(hostname) : []
1976
+ }
1977
+ });
1978
+ }
1979
+ };
1980
+ }
1981
+
1982
+ function renderMarkdown(manifest) {
1983
+ return [
1984
+ "## Documentation manifest",
1985
+ "",
1986
+ "> Do not edit this file. It is a automatically generated by `@forsakringskassan/docs-generator`.",
1987
+ "",
1988
+ "```",
1989
+ ...manifest.pages.map((it) => it.path),
1990
+ "```",
1991
+ ""
1992
+ ].join("\n");
1993
+ }
1994
+ function renderJSON(manifest) {
1995
+ return JSON.stringify(manifest, null, 2);
1996
+ }
1997
+ function manifestProcessor(options) {
1998
+ const { markdown, json } = options;
1999
+ return {
2000
+ name: "manifestProcessor",
2001
+ before: "render",
2002
+ async handler(context) {
2003
+ const docs = context.docs.filter(haveOutput);
2004
+ const pages = docs.map(manifestPageFromDocument);
2005
+ pages.sort((a, b) => {
2006
+ return a.path.localeCompare(b.path);
2007
+ });
2008
+ const manifest = { pages };
2009
+ if (markdown) {
2010
+ const content = renderMarkdown(manifest);
2011
+ await fs.writeFile(markdown, content, "utf-8");
2012
+ }
2013
+ if (json) {
2014
+ const content = renderJSON(manifest);
2015
+ await fs.writeFile(json, content, "utf-8");
2016
+ }
2017
+ }
2018
+ };
2019
+ }
2020
+
2021
+ function themeSelectProcessor() {
2022
+ return {
2023
+ name: "theme-select-processor",
2024
+ after: "generate-docs",
2025
+ handler(context) {
2026
+ context.addTemplateBlock("toolbar", "theme-select", {
2027
+ filename: "partials/theme-select.html"
2028
+ });
2029
+ }
2030
+ };
2031
+ }
2032
+
2033
+ function selectableVersionProcessor(pkg, container) {
2034
+ return {
2035
+ name: "selectable-version-processor",
2036
+ after: "generate-docs",
2037
+ handler(context) {
2038
+ context.addTemplateBlock(container, "version", {
2039
+ filename: "partials/selectable-version.html",
2040
+ data: { pkg }
2041
+ });
2042
+ }
2043
+ };
2044
+ }
2045
+
2046
+ function generateNavigation(entries) {
2047
+ const children = entries.map((it, index) => {
2048
+ const key = path$1.parse(it.path).name;
2049
+ return {
2050
+ key,
2051
+ sortorder: index,
2052
+ children: [],
2053
+ ...it
2054
+ };
2055
+ });
2056
+ return {
2057
+ key: ".",
2058
+ path: "./index.html",
2059
+ sortorder: Infinity,
2060
+ children
2061
+ };
2062
+ }
2063
+ function topnavProcessor(filename, title) {
2064
+ return {
2065
+ after: "generate-nav",
2066
+ name: "topnav-processor",
2067
+ async handler(context) {
2068
+ const content = await fs.readFile(filename, "utf-8");
2069
+ const parsed = JSON.parse(content);
2070
+ const rootNode = generateNavigation(parsed);
2071
+ context.setTopNavigation({
2072
+ title,
2073
+ ...rootNode
2074
+ });
2075
+ }
2076
+ };
2077
+ }
2078
+
2079
+ function run(cmd, defaultValue) {
2080
+ return new Promise((resolve) => {
2081
+ childProcess.exec(cmd, { encoding: "utf-8" }, (error, stdout) => {
2082
+ if (error) {
2083
+ console.error(error);
2084
+ resolve(defaultValue);
2085
+ } else {
2086
+ resolve(stdout.trim());
2087
+ }
2088
+ });
2089
+ });
2090
+ }
2091
+ async function getGitBranch() {
2092
+ const { CHANGE_BRANCH, CHANGE_NAME } = process.env;
2093
+ if (CHANGE_BRANCH) {
2094
+ return CHANGE_BRANCH;
2095
+ }
2096
+ if (CHANGE_NAME) {
2097
+ return CHANGE_NAME;
2098
+ }
2099
+ const branch = await run("git rev-parse --abbrev-ref HEAD", "unknown");
2100
+ if (branch === "HEAD" || branch === "") {
2101
+ return "unknown";
2102
+ } else {
2103
+ return branch;
2104
+ }
2105
+ }
2106
+ function getPullRequestID() {
2107
+ return process.env.JOB_BASE_NAME;
2108
+ }
2109
+ async function getSCMData(pkg, options) {
2110
+ const commitHash = await run(`git rev-parse HEAD`);
2111
+ const commitShort = await run(`git rev-parse --short HEAD`);
2112
+ if (!commitHash || !commitShort) {
2113
+ return null;
2114
+ }
2115
+ const { homepage } = pkg;
2116
+ const pr = getPullRequestID();
2117
+ const prUrl = pr ? interpolate(options.prUrlFormat, { homepage, pr }) : void 0;
2118
+ return {
2119
+ branch: await getGitBranch(),
2120
+ commitShort,
2121
+ commitHash,
2122
+ commitUrl: interpolate(options.commitUrlFormat, {
2123
+ hash: commitHash,
2124
+ short: commitShort,
2125
+ homepage
2126
+ }),
2127
+ pr,
2128
+ prUrl
2129
+ };
2130
+ }
2131
+ function getBuildDatetime() {
2132
+ const date = /* @__PURE__ */ new Date();
2133
+ return {
2134
+ date: date.toLocaleDateString("sv-SE"),
2135
+ time: date.toLocaleTimeString("sv-SE")
2136
+ };
2137
+ }
2138
+ function versionProcessor(pkg, container, options) {
2139
+ const { enabled = true, scm = false } = options ?? {};
2140
+ return {
2141
+ name: "version-processor",
2142
+ after: "generate-docs",
2143
+ async handler(context) {
2144
+ if (!enabled) {
2145
+ return;
2146
+ }
2147
+ const scmData = scm ? await getSCMData(pkg, scm) : null;
2148
+ const buildData = getBuildDatetime();
2149
+ const data = {
2150
+ pkg,
2151
+ scm: scmData,
2152
+ build: buildData
2153
+ };
2154
+ context.addTemplateBlock(container, "version", {
2155
+ filename: "partials/version.njk.html",
2156
+ data
2157
+ });
2158
+ }
2159
+ };
2160
+ }
2161
+
2162
+ function versionBannerProcessor(message, container) {
2163
+ return {
2164
+ name: "version-banner-processor",
2165
+ after: "generate-docs",
2166
+ handler(context) {
2167
+ context.addTemplateBlock(container, "version-banner", {
2168
+ filename: "partials/version-banner.html",
2169
+ data: { message }
2170
+ });
2171
+ }
2172
+ };
2173
+ }
2174
+
2175
+ function generateIndex(entries) {
2176
+ const index = {
2177
+ terms: [],
2178
+ results: [],
2179
+ mapping: {}
2180
+ };
2181
+ for (const entry of entries) {
2182
+ index.results.push({
2183
+ url: entry.url,
2184
+ title: entry.title
2185
+ });
2186
+ const resultIndex = index.results.length - 1;
2187
+ for (const word of entry.words) {
2188
+ index.terms.push(word);
2189
+ const termIndex = index.terms.length - 1;
2190
+ index.mapping[termIndex] = resultIndex;
2191
+ }
2192
+ }
2193
+ return index;
2194
+ }
2195
+
2196
+ function extractTerms(doc) {
2197
+ const { title, component } = doc.attributes;
2198
+ if (title && component) {
2199
+ return component.map((it) => `${title} (${it})`);
2200
+ } else if (component) {
2201
+ return component;
2202
+ } else if (title) {
2203
+ return [title];
2204
+ } else {
2205
+ return [];
2206
+ }
2207
+ }
2208
+ function isIndexable(doc) {
2209
+ return Boolean(doc.visible && doc.fileInfo.outputName);
2210
+ }
2211
+ function getTerms(doc) {
2212
+ return {
2213
+ url: createMarkdownRenderer.getOutputFilePath(".", doc.fileInfo) ?? "",
2214
+ title: doc.name,
2215
+ words: extractTerms(doc)
2216
+ };
2217
+ }
2218
+ function searchProcessor() {
2219
+ return {
2220
+ after: "generate-docs",
2221
+ name: "search-processor",
2222
+ handler(context) {
2223
+ const entries = context.docs.filter(isIndexable).map(getTerms);
2224
+ const index = generateIndex(entries);
2225
+ const body = JSON.stringify(index);
2226
+ const fingerprint = createMarkdownRenderer.getFingerprint(body);
2227
+ const integrity = getIntegrity(body);
2228
+ const outputName = `search-data-[hash].json`;
2229
+ const expandedName = `search-data-${fingerprint}.json`;
2230
+ context.setTemplateData("searchDataUrl", expandedName);
2231
+ context.setTemplateData("searchDataIntegrity", integrity);
2232
+ context.addDocument({
2233
+ id: "search:data",
2234
+ name: "search-data",
2235
+ alias: [],
2236
+ visible: false,
2237
+ attributes: {
2238
+ sortorder: Infinity
2239
+ },
2240
+ body,
2241
+ outline: [],
2242
+ format: "json",
2243
+ tags: [],
2244
+ template: "json",
2245
+ fileInfo: {
2246
+ path: "",
2247
+ name: "virtual:search-data",
2248
+ fullPath: "virtual:search-data",
2249
+ outputName
2250
+ }
2251
+ });
2252
+ context.addTemplateBlock("toolbar", "search-toolbar", {
2253
+ filename: "partials/search-toolbar.html",
2254
+ data: {
2255
+ rootUrl(doc) {
2256
+ const { fileInfo } = doc;
2257
+ const relative = path$1.relative(fileInfo.path, ".");
2258
+ return relative !== "" ? relative : ".";
2259
+ }
2260
+ }
2261
+ });
2262
+ context.addTemplateBlock("body:end", "search-dialog", {
2263
+ filename: "partials/search-dialog.html"
2264
+ });
2265
+ context.log("Indexed", entries.length, "documents");
2266
+ }
2267
+ };
2268
+ }
2269
+
2270
+ exports.Generator = Generator;
2271
+ exports.defineSources = defineSources;
2272
+ exports.frontMatterFileReader = frontMatterFileReader;
2273
+ exports.livereloadProcessor = livereloadProcessor;
2274
+ exports.manifestProcessor = manifestProcessor;
2275
+ exports.matomoProcessor = matomoProcessor;
2276
+ exports.navigationFileReader = navigationFileReader;
2277
+ exports.searchProcessor = searchProcessor;
2278
+ exports.selectableVersionProcessor = selectableVersionProcessor;
2279
+ exports.themeSelectProcessor = themeSelectProcessor;
2280
+ exports.topnavProcessor = topnavProcessor;
2281
+ exports.versionBannerProcessor = versionBannerProcessor;
2282
+ exports.versionProcessor = versionProcessor;
2283
+ exports.vueFileReader = vueFileReader;