docula 0.41.0 → 0.50.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.
Files changed (50) hide show
  1. package/README.md +110 -0
  2. package/dist/docula.d.ts +156 -0
  3. package/dist/docula.js +1628 -0
  4. package/package.json +28 -24
  5. package/{template → templates/classic}/css/base.css +10 -0
  6. package/{template → templates/classic}/css/multipage.css +7 -0
  7. package/{template → templates/classic}/docs.hbs +1 -1
  8. package/{template/index.hbs → templates/classic/home.hbs} +7 -1
  9. package/templates/classic/includes/multipage/api-reference.hbs +1 -0
  10. package/templates/classic/includes/multipage/documentation.hbs +1 -0
  11. package/{template → templates/classic}/includes/multipage/hero.hbs +1 -2
  12. package/{template → templates/classic}/includes/multipage/home.hbs +3 -3
  13. package/{template → templates/classic}/includes/singlepage/content.hbs +3 -3
  14. package/templates/modern/api.hbs +30 -0
  15. package/templates/modern/changelog-entry.hbs +36 -0
  16. package/templates/modern/changelog.hbs +38 -0
  17. package/templates/modern/css/highlight/highlight.min.js +1433 -0
  18. package/templates/modern/css/highlight/styles/base16/docula.css +123 -0
  19. package/templates/modern/css/home.css +96 -0
  20. package/templates/modern/css/styles.css +697 -0
  21. package/templates/modern/docs.hbs +30 -0
  22. package/templates/modern/home.hbs +51 -0
  23. package/templates/modern/includes/api-reference.hbs +1 -0
  24. package/templates/modern/includes/doc.hbs +18 -0
  25. package/templates/modern/includes/documentation.hbs +1 -0
  26. package/templates/modern/includes/footer.hbs +6 -0
  27. package/templates/modern/includes/header-bar.hbs +57 -0
  28. package/templates/modern/includes/header.hbs +15 -0
  29. package/templates/modern/includes/hero.hbs +11 -0
  30. package/templates/modern/includes/home.hbs +46 -0
  31. package/templates/modern/includes/scripts.hbs +161 -0
  32. package/templates/modern/includes/sidebar.hbs +22 -0
  33. package/templates/modern/includes/theme-toggle.hbs +5 -0
  34. package/template/releases.hbs +0 -86
  35. /package/bin/{docula.mjs → docula.js} +0 -0
  36. /package/{template → templates/classic}/api.hbs +0 -0
  37. /package/{template → templates/classic}/changelog-entry.hbs +0 -0
  38. /package/{template → templates/classic}/changelog.hbs +0 -0
  39. /package/{template → templates/classic}/css/highlight/highlight.min.js +0 -0
  40. /package/{template → templates/classic}/css/highlight/styles/base16/dracula.min.css +0 -0
  41. /package/{template → templates/classic}/css/landing.css +0 -0
  42. /package/{template → templates/classic}/css/singlepage.css +0 -0
  43. /package/{template → templates/classic}/includes/footer.hbs +0 -0
  44. /package/{template → templates/classic}/includes/header.hbs +0 -0
  45. /package/{template → templates/classic}/includes/multipage/doc.hbs +0 -0
  46. /package/{template → templates/classic}/includes/multipage/header.hbs +0 -0
  47. /package/{template → templates/classic}/includes/multipage/scripts.hbs +0 -0
  48. /package/{template → templates/classic}/includes/multipage/sidebar.hbs +0 -0
  49. /package/{template → templates/classic}/includes/scripts.hbs +0 -0
  50. /package/{template → templates/classic}/includes/singlepage/hero.hbs +0 -0
package/dist/docula.js ADDED
@@ -0,0 +1,1628 @@
1
+ // src/docula.ts
2
+ import fs3 from "fs";
3
+ import http from "http";
4
+ import path5 from "path";
5
+ import process4 from "process";
6
+ import { pathToFileURL } from "url";
7
+ import { createJiti } from "jiti";
8
+ import handler from "serve-handler";
9
+ import updateNotifier from "update-notifier";
10
+
11
+ // src/builder.ts
12
+ import fs2 from "fs";
13
+ import path4 from "path";
14
+ import { Ecto } from "ecto";
15
+ import { Writr } from "writr";
16
+
17
+ // src/console.ts
18
+ import path from "path";
19
+ import process from "process";
20
+ var DoculaConsole = class {
21
+ log(message) {
22
+ console.log(message);
23
+ }
24
+ error(message) {
25
+ console.error(message);
26
+ }
27
+ warn(message) {
28
+ console.warn(message);
29
+ }
30
+ printHelp() {
31
+ console.log(" Usage: docula [command] [arguments]");
32
+ console.log();
33
+ console.log(" Commands:");
34
+ console.log(" init Initialize a new project");
35
+ console.log(
36
+ " build Build the project. By default just npx docula will build the project if it finds a ./site folder"
37
+ );
38
+ console.log(" serve Serve the project as a local website");
39
+ console.log(" help Print this help");
40
+ console.log(" version Print the version");
41
+ console.log();
42
+ console.log(" Arguments init:");
43
+ console.log(
44
+ " --typescript Generate TypeScript config file (docula.config.ts)"
45
+ );
46
+ console.log(
47
+ " -s, --site Set the path where site files are located"
48
+ );
49
+ console.log();
50
+ console.log(" Arguments build:");
51
+ console.log(" -w, --watch watch for changes and rebuild");
52
+ console.log(
53
+ " -s, --site Set the path where site files are located"
54
+ );
55
+ console.log(
56
+ " -o, --outputPath Set the output directory. Default is ./site/dist"
57
+ );
58
+ console.log(" -t, --templatePath Set the custom template to use");
59
+ console.log(
60
+ " -T, --template Set the built-in template name (e.g., modern, classic)"
61
+ );
62
+ console.log();
63
+ console.log(" Arguments serve:");
64
+ console.log(" -p, --port Set the port number used with serve");
65
+ console.log(" -w, --watch watch for changes and rebuild");
66
+ console.log(
67
+ " -s, --site Set the path where site files are located"
68
+ );
69
+ }
70
+ parseProcessArgv(argv) {
71
+ const command = this.getCommand(argv);
72
+ const arguments_ = this.getArguments(argv);
73
+ return {
74
+ argv,
75
+ command,
76
+ args: arguments_
77
+ };
78
+ }
79
+ getCommand(argv) {
80
+ for (const argument of argv) {
81
+ switch (argument) {
82
+ case "init": {
83
+ return "init";
84
+ }
85
+ case "build": {
86
+ return "build";
87
+ }
88
+ case "serve": {
89
+ return "serve";
90
+ }
91
+ case "help": {
92
+ return "help";
93
+ }
94
+ case "version": {
95
+ return "version";
96
+ }
97
+ }
98
+ }
99
+ }
100
+ getArguments(argv) {
101
+ const arguments_ = {
102
+ sitePath: "",
103
+ templatePath: "",
104
+ template: "",
105
+ output: "",
106
+ watch: false,
107
+ port: 3e3,
108
+ typescript: false
109
+ };
110
+ for (let i = 0; i < argv.length; i++) {
111
+ const argument = argv[i];
112
+ switch (argument) {
113
+ case "-p":
114
+ case "--port": {
115
+ const portString = argv[i + 1];
116
+ if (portString !== void 0) {
117
+ arguments_.port = Number.parseInt(portString, 10);
118
+ }
119
+ break;
120
+ }
121
+ case "-o":
122
+ case "--output": {
123
+ arguments_.output = argv[i + 1];
124
+ arguments_.output = path.join(process.cwd(), arguments_.output);
125
+ break;
126
+ }
127
+ case "-w":
128
+ case "--watch": {
129
+ arguments_.watch = true;
130
+ break;
131
+ }
132
+ case "-s":
133
+ case "--site": {
134
+ arguments_.sitePath = argv[i + 1];
135
+ arguments_.sitePath = path.join(process.cwd(), arguments_.sitePath);
136
+ break;
137
+ }
138
+ case "-t":
139
+ case "--templatePath": {
140
+ arguments_.templatePath = argv[i + 1];
141
+ arguments_.templatePath = path.join(
142
+ process.cwd(),
143
+ arguments_.templatePath
144
+ );
145
+ break;
146
+ }
147
+ case "-T":
148
+ case "--template": {
149
+ arguments_.template = argv[i + 1];
150
+ break;
151
+ }
152
+ case "--typescript": {
153
+ arguments_.typescript = true;
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ return arguments_;
159
+ }
160
+ };
161
+
162
+ // src/github.ts
163
+ import process2 from "process";
164
+ import { CacheableNet } from "@cacheable/net";
165
+ var Github = class {
166
+ options = {
167
+ api: "https://api.github.com",
168
+ author: "",
169
+ repo: ""
170
+ };
171
+ net;
172
+ constructor(options) {
173
+ this.parseOptions(options);
174
+ this.net = new CacheableNet();
175
+ }
176
+ async getData() {
177
+ const data = {
178
+ releases: {},
179
+ contributors: {}
180
+ };
181
+ data.releases = await this.getReleases();
182
+ data.contributors = await this.getContributors();
183
+ return data;
184
+ }
185
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
186
+ async getReleases() {
187
+ const url = `${this.options.api}/repos/${this.options.author}/${this.options.repo}/releases`;
188
+ let options = {};
189
+ if (process2.env.GITHUB_TOKEN) {
190
+ options = {
191
+ headers: {
192
+ Authorization: `Bearer ${process2.env.GITHUB_TOKEN}`,
193
+ Accept: "application/vnd.github.v3+json"
194
+ }
195
+ };
196
+ }
197
+ try {
198
+ const result = await this.net.get(url, options);
199
+ if (result && result.data.length > 0) {
200
+ return this.addAnchorLink(result.data);
201
+ }
202
+ return [];
203
+ } catch (error) {
204
+ const typedError = error;
205
+ if (typedError.response?.status === 404) {
206
+ throw new Error(
207
+ `Repository ${this.options.author}/${this.options.repo} not found.`
208
+ );
209
+ }
210
+ throw error;
211
+ }
212
+ }
213
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
214
+ async getContributors() {
215
+ const url = `${this.options.api}/repos/${this.options.author}/${this.options.repo}/contributors`;
216
+ let options = {};
217
+ if (process2.env.GITHUB_TOKEN) {
218
+ options = {
219
+ headers: {
220
+ Authorization: `Bearer ${process2.env.GITHUB_TOKEN}`,
221
+ Accept: "application/vnd.github.v3+json"
222
+ }
223
+ };
224
+ }
225
+ try {
226
+ const result = await this.net.get(url, options);
227
+ if (result && result.data.length > 0) {
228
+ return result.data;
229
+ }
230
+ } catch (error) {
231
+ const typedError = error;
232
+ if (typedError.response?.status === 404) {
233
+ throw new Error(
234
+ `Repository ${this.options.author}/${this.options.repo} not found.`
235
+ );
236
+ }
237
+ throw error;
238
+ }
239
+ }
240
+ parseOptions(options) {
241
+ if (options.api) {
242
+ this.options.api = options.api;
243
+ }
244
+ this.options.author = options.author;
245
+ this.options.repo = options.repo;
246
+ }
247
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
248
+ addAnchorLink(data) {
249
+ return data.map((release) => {
250
+ const regex = /(?<!]\()(https:\/\/[\w./]+)(?!\))/g;
251
+ release.body = release.body.replaceAll(regex, "[$1]($1)");
252
+ return release;
253
+ });
254
+ }
255
+ };
256
+
257
+ // src/options.ts
258
+ import path2 from "path";
259
+ import process3 from "process";
260
+ var DoculaOptions = class {
261
+ /**
262
+ * Name of the built-in template to use (e.g., "modern", "classic")
263
+ */
264
+ template = "modern";
265
+ /**
266
+ * Path to the template directory. When set, overrides the `template` option.
267
+ */
268
+ templatePath = "";
269
+ /**
270
+ * Path to the output directory
271
+ */
272
+ outputPath = path2.join(process3.cwd(), "./dist");
273
+ /**
274
+ * Path to the site directory
275
+ */
276
+ sitePath = path2.join(process3.cwd(), "./site");
277
+ /**
278
+ * Path to the github repository
279
+ */
280
+ githubPath = "jaredwray/docula";
281
+ /**
282
+ * Site title
283
+ */
284
+ siteTitle = "docula";
285
+ /**
286
+ * Site description
287
+ */
288
+ siteDescription = "Beautiful Website for Your Projects";
289
+ /**
290
+ * Site URL
291
+ */
292
+ siteUrl = "https://docula.org";
293
+ /**
294
+ * Port to run the server
295
+ */
296
+ port = 3e3;
297
+ /**
298
+ * Single page website
299
+ */
300
+ singlePage = true;
301
+ /**
302
+ * Sections
303
+ */
304
+ sections;
305
+ /**
306
+ * OpenAPI specification URL for API documentation.
307
+ * When provided, creates a dedicated /api page
308
+ * Supports both external URLs (https://...) and relative paths (/openapi.json)
309
+ */
310
+ openApiUrl;
311
+ /**
312
+ * When true, GitHub releases are converted to changelog entries and merged
313
+ * with file-based changelog entries. Requires a changelog template to exist.
314
+ */
315
+ enableReleaseChangelog = true;
316
+ /**
317
+ * When false, the first document becomes the home page (index.html)
318
+ * and the home.hbs template is not rendered.
319
+ */
320
+ homePage = true;
321
+ /**
322
+ * When true, generates llms.txt and llms-full.txt files for the built site.
323
+ */
324
+ enableLlmsTxt = true;
325
+ constructor(options) {
326
+ if (options) {
327
+ this.parseOptions(options);
328
+ }
329
+ }
330
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
331
+ parseOptions(options) {
332
+ if (options.template) {
333
+ this.template = options.template;
334
+ }
335
+ if (options.templatePath) {
336
+ this.templatePath = options.templatePath;
337
+ this.templatePath = path2.join(process3.cwd(), this.templatePath);
338
+ }
339
+ if (options.outputPath) {
340
+ this.outputPath = options.outputPath;
341
+ this.outputPath = path2.join(process3.cwd(), this.outputPath);
342
+ }
343
+ if (options.sitePath) {
344
+ this.sitePath = options.sitePath;
345
+ this.sitePath = path2.join(process3.cwd(), this.sitePath);
346
+ }
347
+ if (options.githubPath) {
348
+ this.githubPath = options.githubPath;
349
+ }
350
+ if (options.siteTitle) {
351
+ this.siteTitle = options.siteTitle;
352
+ }
353
+ if (options.siteDescription) {
354
+ this.siteDescription = options.siteDescription;
355
+ }
356
+ if (options.siteUrl) {
357
+ this.siteUrl = options.siteUrl;
358
+ }
359
+ if (options.sections) {
360
+ this.sections = options.sections;
361
+ }
362
+ if (options.port) {
363
+ this.port = options.port;
364
+ }
365
+ if (options.singlePage !== void 0 && typeof options.singlePage === "boolean") {
366
+ this.singlePage = options.singlePage;
367
+ }
368
+ if (options.openApiUrl) {
369
+ this.openApiUrl = options.openApiUrl;
370
+ }
371
+ if (options.enableReleaseChangelog !== void 0 && typeof options.enableReleaseChangelog === "boolean") {
372
+ this.enableReleaseChangelog = options.enableReleaseChangelog;
373
+ }
374
+ if (options.homePage !== void 0 && typeof options.homePage === "boolean") {
375
+ this.homePage = options.homePage;
376
+ }
377
+ if (options.enableLlmsTxt !== void 0 && typeof options.enableLlmsTxt === "boolean") {
378
+ this.enableLlmsTxt = options.enableLlmsTxt;
379
+ }
380
+ }
381
+ };
382
+
383
+ // src/template-resolver.ts
384
+ import fs from "fs";
385
+ import path3 from "path";
386
+ function getBuiltInTemplatesDir() {
387
+ return path3.join(import.meta.url, "../../templates").replace("file:", "");
388
+ }
389
+ function listBuiltInTemplates() {
390
+ const templatesDir = getBuiltInTemplatesDir();
391
+ if (!fs.existsSync(templatesDir)) {
392
+ return [];
393
+ }
394
+ return fs.readdirSync(templatesDir).filter(
395
+ (entry) => fs.statSync(path3.join(templatesDir, entry)).isDirectory()
396
+ );
397
+ }
398
+ function resolveTemplatePath(templatePath, templateName) {
399
+ if (templatePath) {
400
+ return templatePath;
401
+ }
402
+ const resolvedPath = path3.join(getBuiltInTemplatesDir(), templateName);
403
+ if (!fs.existsSync(resolvedPath)) {
404
+ const available = listBuiltInTemplates();
405
+ throw new Error(
406
+ `Built-in template "${templateName}" not found. Available templates: ${available.join(", ")}`
407
+ );
408
+ }
409
+ return resolvedPath;
410
+ }
411
+
412
+ // src/builder.ts
413
+ var DoculaBuilder = class {
414
+ _options = new DoculaOptions();
415
+ _ecto;
416
+ _console = new DoculaConsole();
417
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
418
+ constructor(options, engineOptions) {
419
+ if (options) {
420
+ this._options = options;
421
+ }
422
+ this._ecto = new Ecto(engineOptions);
423
+ }
424
+ get options() {
425
+ return this._options;
426
+ }
427
+ async build() {
428
+ const startTime = Date.now();
429
+ this.validateOptions(this.options);
430
+ const resolvedTemplatePath = resolveTemplatePath(
431
+ this.options.templatePath,
432
+ this.options.template
433
+ );
434
+ const doculaData = {
435
+ siteUrl: this.options.siteUrl,
436
+ siteTitle: this.options.siteTitle,
437
+ siteDescription: this.options.siteDescription,
438
+ sitePath: this.options.sitePath,
439
+ templatePath: resolvedTemplatePath,
440
+ outputPath: this.options.outputPath,
441
+ githubPath: this.options.githubPath,
442
+ sections: this.options.sections,
443
+ openApiUrl: this.options.openApiUrl,
444
+ homePage: this.options.homePage
445
+ };
446
+ if (!doculaData.openApiUrl && fs2.existsSync(`${doculaData.sitePath}/api/swagger.json`)) {
447
+ doculaData.openApiUrl = "/api/swagger.json";
448
+ }
449
+ doculaData.github = await this.getGithubData(this.options.githubPath);
450
+ doculaData.documents = this.getDocuments(
451
+ `${doculaData.sitePath}/docs`,
452
+ doculaData
453
+ );
454
+ doculaData.sections = this.getSections(
455
+ `${doculaData.sitePath}/docs`,
456
+ this.options
457
+ );
458
+ doculaData.hasDocuments = doculaData.documents?.length > 0;
459
+ const changelogPath = `${doculaData.sitePath}/changelog`;
460
+ const fileChangelogEntries = this.getChangelogEntries(changelogPath);
461
+ const hasChangelogTemplate = await this.getTemplateFile(resolvedTemplatePath, "changelog") !== void 0;
462
+ let allChangelogEntries = [...fileChangelogEntries];
463
+ if (this._options.enableReleaseChangelog && hasChangelogTemplate && doculaData.github?.releases && Array.isArray(doculaData.github.releases) && doculaData.github.releases.length > 0) {
464
+ const releaseEntries = this.getReleasesAsChangelogEntries(
465
+ // biome-ignore lint/suspicious/noExplicitAny: GitHub release objects
466
+ doculaData.github.releases
467
+ );
468
+ allChangelogEntries = [...allChangelogEntries, ...releaseEntries];
469
+ }
470
+ allChangelogEntries.sort((a, b) => {
471
+ const dateA = new Date(a.date).getTime();
472
+ const dateB = new Date(b.date).getTime();
473
+ if (Number.isNaN(dateA) && Number.isNaN(dateB)) {
474
+ return 0;
475
+ }
476
+ if (Number.isNaN(dateA)) {
477
+ return 1;
478
+ }
479
+ if (Number.isNaN(dateB)) {
480
+ return -1;
481
+ }
482
+ return dateB - dateA;
483
+ });
484
+ doculaData.changelogEntries = allChangelogEntries;
485
+ doculaData.hasChangelog = allChangelogEntries.length > 0 && hasChangelogTemplate;
486
+ doculaData.templates = await this.getTemplates(
487
+ resolvedTemplatePath,
488
+ doculaData.hasDocuments,
489
+ doculaData.hasChangelog
490
+ );
491
+ doculaData.hasApi = Boolean(
492
+ doculaData.openApiUrl && doculaData.templates?.api
493
+ );
494
+ if (!this.options.homePage && doculaData.hasDocuments) {
495
+ await this.buildDocsHomePage(doculaData);
496
+ } else {
497
+ await this.buildIndexPage(doculaData);
498
+ }
499
+ await this.buildSiteMapPage(doculaData);
500
+ await this.buildRobotsPage(this.options);
501
+ if (doculaData.hasDocuments) {
502
+ await this.buildDocsPages(doculaData);
503
+ }
504
+ if (doculaData.hasApi) {
505
+ await this.buildApiPage(doculaData);
506
+ }
507
+ if (doculaData.hasChangelog) {
508
+ await this.buildChangelogPage(doculaData);
509
+ await this.buildChangelogEntryPages(doculaData);
510
+ }
511
+ const siteRelativePath = this.options.sitePath;
512
+ if (fs2.existsSync(`${siteRelativePath}/favicon.ico`)) {
513
+ await fs2.promises.copyFile(
514
+ `${siteRelativePath}/favicon.ico`,
515
+ `${this.options.outputPath}/favicon.ico`
516
+ );
517
+ }
518
+ if (fs2.existsSync(`${siteRelativePath}/logo.svg`)) {
519
+ await fs2.promises.copyFile(
520
+ `${siteRelativePath}/logo.svg`,
521
+ `${this.options.outputPath}/logo.svg`
522
+ );
523
+ }
524
+ if (fs2.existsSync(`${siteRelativePath}/logo_horizontal.png`)) {
525
+ await fs2.promises.copyFile(
526
+ `${siteRelativePath}/logo_horizontal.png`,
527
+ `${this.options.outputPath}/logo_horizontal.png`
528
+ );
529
+ }
530
+ if (fs2.existsSync(`${resolvedTemplatePath}/css`)) {
531
+ this.copyDirectory(
532
+ `${resolvedTemplatePath}/css`,
533
+ `${this.options.outputPath}/css`
534
+ );
535
+ }
536
+ if (fs2.existsSync(`${siteRelativePath}/variables.css`)) {
537
+ await fs2.promises.copyFile(
538
+ `${siteRelativePath}/variables.css`,
539
+ `${this.options.outputPath}/css/variables.css`
540
+ );
541
+ }
542
+ this.copyPublicFolder(siteRelativePath, this.options.outputPath);
543
+ await this.buildLlmsFiles(doculaData);
544
+ const endTime = Date.now();
545
+ const executionTime = endTime - startTime;
546
+ this._console.log(`Build completed in ${executionTime}ms`);
547
+ }
548
+ validateOptions(options) {
549
+ if (options.githubPath.length < 3) {
550
+ throw new Error("No github options provided");
551
+ }
552
+ if (options.siteDescription.length < 3) {
553
+ throw new Error("No site description options provided");
554
+ }
555
+ if (!options.siteTitle) {
556
+ throw new Error("No site title options provided");
557
+ }
558
+ if (!options.siteUrl) {
559
+ throw new Error("No site url options provided");
560
+ }
561
+ }
562
+ async getGithubData(githubPath) {
563
+ const paths = githubPath.split("/");
564
+ const options = {
565
+ author: paths[0],
566
+ repo: paths[1]
567
+ };
568
+ const github = new Github(options);
569
+ return github.getData();
570
+ }
571
+ async getTemplates(templatePath, hasDocuments, hasChangelog = false) {
572
+ const templates = {
573
+ home: ""
574
+ };
575
+ if (fs2.existsSync(templatePath)) {
576
+ const home = await this.getTemplateFile(templatePath, "home");
577
+ if (home) {
578
+ templates.home = home;
579
+ }
580
+ const documentPage = hasDocuments ? await this.getTemplateFile(templatePath, "docs") : void 0;
581
+ if (documentPage) {
582
+ templates.docPage = documentPage;
583
+ }
584
+ const apiPage = await this.getTemplateFile(templatePath, "api");
585
+ if (apiPage) {
586
+ templates.api = apiPage;
587
+ }
588
+ const changelogPage = hasChangelog ? await this.getTemplateFile(templatePath, "changelog") : void 0;
589
+ if (changelogPage) {
590
+ templates.changelog = changelogPage;
591
+ }
592
+ const changelogEntryPage = hasChangelog ? await this.getTemplateFile(templatePath, "changelog-entry") : void 0;
593
+ if (changelogEntryPage) {
594
+ templates.changelogEntry = changelogEntryPage;
595
+ }
596
+ } else {
597
+ throw new Error(`No template path found at ${templatePath}`);
598
+ }
599
+ return templates;
600
+ }
601
+ async getTemplateFile(path6, name) {
602
+ let result;
603
+ const files = await fs2.promises.readdir(path6);
604
+ for (const file of files) {
605
+ const fileName = file.split(".");
606
+ if (fileName[0].toString().toLowerCase() === name.toLowerCase()) {
607
+ result = file.toString();
608
+ break;
609
+ }
610
+ }
611
+ return result;
612
+ }
613
+ async buildRobotsPage(options) {
614
+ const { sitePath } = options;
615
+ const { outputPath } = options;
616
+ const robotsPath = `${outputPath}/robots.txt`;
617
+ await fs2.promises.mkdir(outputPath, { recursive: true });
618
+ await (fs2.existsSync(`${sitePath}/robots.txt`) ? fs2.promises.copyFile(`${sitePath}/robots.txt`, robotsPath) : fs2.promises.writeFile(robotsPath, "User-agent: *\nDisallow:"));
619
+ }
620
+ async buildSiteMapPage(data) {
621
+ const sitemapPath = `${data.outputPath}/sitemap.xml`;
622
+ const urls = [{ url: data.siteUrl }];
623
+ if (data.openApiUrl && data.templates?.api) {
624
+ urls.push({ url: `${data.siteUrl}/api` });
625
+ }
626
+ if (data.hasChangelog && data.templates?.changelog) {
627
+ urls.push({ url: `${data.siteUrl}/changelog` });
628
+ for (const entry of data.changelogEntries ?? []) {
629
+ urls.push({
630
+ url: `${data.siteUrl}/changelog/${entry.slug}`
631
+ });
632
+ }
633
+ }
634
+ for (const document of data.documents ?? []) {
635
+ let { urlPath } = document;
636
+ if (urlPath.endsWith("index.html")) {
637
+ urlPath = urlPath.slice(0, -10);
638
+ }
639
+ urls.push({ url: `${data.siteUrl}${urlPath}` });
640
+ }
641
+ let xml = '<?xml version="1.0" encoding="UTF-8"?>';
642
+ xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
643
+ for (const { url } of urls) {
644
+ xml += "<url>";
645
+ xml += `<loc>${url}</loc>`;
646
+ xml += "</url>";
647
+ }
648
+ xml += "</urlset>";
649
+ await fs2.promises.mkdir(data.outputPath, { recursive: true });
650
+ await fs2.promises.writeFile(sitemapPath, xml, "utf8");
651
+ }
652
+ async buildLlmsFiles(data) {
653
+ if (!this.options.enableLlmsTxt) {
654
+ return;
655
+ }
656
+ await fs2.promises.mkdir(data.outputPath, { recursive: true });
657
+ const llmsOutputPath = `${data.outputPath}/llms.txt`;
658
+ const llmsFullOutputPath = `${data.outputPath}/llms-full.txt`;
659
+ const llmsOverrideContent = await this.getSafeSiteOverrideFileContent(
660
+ data.sitePath,
661
+ "llms.txt"
662
+ );
663
+ const llmsFullOverrideContent = await this.getSafeSiteOverrideFileContent(
664
+ data.sitePath,
665
+ "llms-full.txt"
666
+ );
667
+ if (llmsOverrideContent !== void 0) {
668
+ await fs2.promises.writeFile(llmsOutputPath, llmsOverrideContent, "utf8");
669
+ } else {
670
+ const llmsContent = this.generateLlmsIndexContent(data);
671
+ await fs2.promises.writeFile(llmsOutputPath, llmsContent, "utf8");
672
+ }
673
+ if (llmsFullOverrideContent !== void 0) {
674
+ await fs2.promises.writeFile(
675
+ llmsFullOutputPath,
676
+ llmsFullOverrideContent,
677
+ "utf8"
678
+ );
679
+ } else {
680
+ const llmsFullContent = await this.generateLlmsFullContent(data);
681
+ await fs2.promises.writeFile(llmsFullOutputPath, llmsFullContent, "utf8");
682
+ }
683
+ }
684
+ generateLlmsIndexContent(data) {
685
+ const lines = [];
686
+ const documents = data.documents ?? [];
687
+ const changelogEntries = data.changelogEntries ?? [];
688
+ lines.push(`# ${data.siteTitle}`);
689
+ lines.push("");
690
+ lines.push(data.siteDescription);
691
+ lines.push("");
692
+ lines.push(
693
+ `- [Full LLM Content](${this.buildAbsoluteSiteUrl(data.siteUrl, "/llms-full.txt")})`
694
+ );
695
+ lines.push("");
696
+ lines.push("## Documentation");
697
+ if (documents.length > 0) {
698
+ for (const document of documents) {
699
+ const documentUrl = this.buildAbsoluteSiteUrl(
700
+ data.siteUrl,
701
+ this.normalizePathForUrl(document.urlPath)
702
+ );
703
+ const description = document.description ? ` - ${document.description}` : "";
704
+ lines.push(`- [${document.navTitle}](${documentUrl})${description}`);
705
+ }
706
+ } else {
707
+ lines.push("- Not available.");
708
+ }
709
+ lines.push("");
710
+ lines.push("## API Reference");
711
+ if (data.hasApi) {
712
+ lines.push(
713
+ `- [API Documentation](${this.buildAbsoluteSiteUrl(data.siteUrl, "/api")})`
714
+ );
715
+ } else {
716
+ lines.push("- Not available.");
717
+ }
718
+ lines.push("");
719
+ lines.push("## Changelog");
720
+ if (data.hasChangelog) {
721
+ lines.push(
722
+ `- [Changelog](${this.buildAbsoluteSiteUrl(data.siteUrl, "/changelog")})`
723
+ );
724
+ for (const entry of changelogEntries.slice(0, 20)) {
725
+ const date = entry.formattedDate || entry.date || "No date";
726
+ lines.push(
727
+ `- [${entry.title}](${this.buildAbsoluteSiteUrl(data.siteUrl, `/changelog/${entry.slug}`)}) (${date})`
728
+ );
729
+ }
730
+ } else {
731
+ lines.push("- Not available.");
732
+ }
733
+ lines.push("");
734
+ return lines.join("\n");
735
+ }
736
+ async generateLlmsFullContent(data) {
737
+ const lines = [];
738
+ const documents = data.documents ?? [];
739
+ const changelogEntries = data.changelogEntries ?? [];
740
+ lines.push(`# ${data.siteTitle}`);
741
+ lines.push("");
742
+ lines.push(data.siteDescription);
743
+ lines.push("");
744
+ lines.push(
745
+ `Source Index: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/llms.txt")}`
746
+ );
747
+ lines.push("");
748
+ lines.push("## Documentation");
749
+ if (documents.length > 0) {
750
+ for (const document of documents) {
751
+ const documentUrl = this.buildAbsoluteSiteUrl(
752
+ data.siteUrl,
753
+ this.normalizePathForUrl(document.urlPath)
754
+ );
755
+ const markdownBody = new Writr(document.content).body.trim();
756
+ lines.push("");
757
+ lines.push(`### ${document.navTitle}`);
758
+ lines.push(`URL: ${documentUrl}`);
759
+ if (document.description) {
760
+ lines.push(`Description: ${document.description}`);
761
+ }
762
+ lines.push("");
763
+ lines.push(markdownBody || "_No content_");
764
+ }
765
+ } else {
766
+ lines.push("- Not available.");
767
+ }
768
+ lines.push("");
769
+ lines.push("## API Reference");
770
+ if (data.hasApi) {
771
+ lines.push(`URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/api")}`);
772
+ lines.push("");
773
+ const localOpenApiSpec = await this.getSafeLocalOpenApiSpec(data);
774
+ if (localOpenApiSpec) {
775
+ lines.push(
776
+ `OpenAPI Spec Source: ${this.toPosixPath(localOpenApiSpec.sourcePath)}`
777
+ );
778
+ lines.push("");
779
+ lines.push(localOpenApiSpec.content || "_No content_");
780
+ } else {
781
+ const openApiSpecUrl = this.resolveOpenApiSpecUrl(data);
782
+ if (openApiSpecUrl) {
783
+ lines.push(`OpenAPI Spec URL: ${openApiSpecUrl}`);
784
+ }
785
+ }
786
+ } else {
787
+ lines.push("- Not available.");
788
+ }
789
+ lines.push("");
790
+ lines.push("## Changelog");
791
+ if (data.hasChangelog && changelogEntries.length > 0) {
792
+ lines.push(
793
+ `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/changelog")}`
794
+ );
795
+ for (const entry of changelogEntries) {
796
+ lines.push("");
797
+ lines.push(`### ${entry.title}`);
798
+ lines.push(
799
+ `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, `/changelog/${entry.slug}`)}`
800
+ );
801
+ if (entry.formattedDate || entry.date) {
802
+ lines.push(`Date: ${entry.formattedDate || entry.date}`);
803
+ }
804
+ if (entry.tag) {
805
+ lines.push(`Tag: ${entry.tag}`);
806
+ }
807
+ lines.push("");
808
+ lines.push(entry.content.trim() || "_No content_");
809
+ }
810
+ } else {
811
+ lines.push("- Not available.");
812
+ }
813
+ lines.push("");
814
+ return lines.join("\n");
815
+ }
816
+ buildAbsoluteSiteUrl(siteUrl, urlPath) {
817
+ const normalizedSiteUrl = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
818
+ const normalizedPath = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
819
+ return `${normalizedSiteUrl}${normalizedPath}`;
820
+ }
821
+ normalizePathForUrl(urlPath) {
822
+ if (urlPath.endsWith("index.html")) {
823
+ return urlPath.slice(0, -10);
824
+ }
825
+ return urlPath;
826
+ }
827
+ isRemoteUrl(url) {
828
+ return /^https?:\/\//i.test(url);
829
+ }
830
+ resolveOpenApiSpecUrl(data) {
831
+ if (!data.openApiUrl) {
832
+ return void 0;
833
+ }
834
+ if (this.isRemoteUrl(data.openApiUrl)) {
835
+ return data.openApiUrl;
836
+ }
837
+ const normalizedPath = data.openApiUrl.startsWith("/") ? data.openApiUrl : `/${data.openApiUrl}`;
838
+ return this.buildAbsoluteSiteUrl(data.siteUrl, normalizedPath);
839
+ }
840
+ resolveLocalOpenApiPath(data) {
841
+ if (!data.openApiUrl || this.isRemoteUrl(data.openApiUrl)) {
842
+ return void 0;
843
+ }
844
+ const openApiPathWithoutQuery = data.openApiUrl.split(/[?#]/)[0];
845
+ if (!openApiPathWithoutQuery) {
846
+ return void 0;
847
+ }
848
+ const normalizedPath = openApiPathWithoutQuery.startsWith("/") ? openApiPathWithoutQuery.slice(1) : openApiPathWithoutQuery;
849
+ return path4.join(data.sitePath, normalizedPath);
850
+ }
851
+ async getSafeSiteOverrideFileContent(sitePath, fileName) {
852
+ const resolvedSitePath = path4.resolve(sitePath);
853
+ const candidatePath = path4.resolve(sitePath, fileName);
854
+ if (!this.isPathWithinBasePath(candidatePath, resolvedSitePath)) {
855
+ return void 0;
856
+ }
857
+ let candidateStats;
858
+ try {
859
+ candidateStats = await fs2.promises.lstat(candidatePath);
860
+ } catch {
861
+ return void 0;
862
+ }
863
+ if (!candidateStats.isFile() || candidateStats.isSymbolicLink()) {
864
+ return void 0;
865
+ }
866
+ let realSitePath;
867
+ let realCandidatePath;
868
+ try {
869
+ realSitePath = await fs2.promises.realpath(resolvedSitePath);
870
+ realCandidatePath = await fs2.promises.realpath(candidatePath);
871
+ } catch {
872
+ return void 0;
873
+ }
874
+ if (!this.isPathWithinBasePath(realCandidatePath, realSitePath)) {
875
+ return void 0;
876
+ }
877
+ return fs2.promises.readFile(realCandidatePath, "utf8");
878
+ }
879
+ async getSafeLocalOpenApiSpec(data) {
880
+ const localOpenApiPath = this.resolveLocalOpenApiPath(data);
881
+ if (!localOpenApiPath) {
882
+ return void 0;
883
+ }
884
+ const resolvedSitePath = path4.resolve(data.sitePath);
885
+ const resolvedLocalOpenApiPath = path4.resolve(localOpenApiPath);
886
+ if (!this.isPathWithinBasePath(resolvedLocalOpenApiPath, resolvedSitePath)) {
887
+ return void 0;
888
+ }
889
+ let localOpenApiStats;
890
+ try {
891
+ localOpenApiStats = await fs2.promises.lstat(resolvedLocalOpenApiPath);
892
+ } catch {
893
+ return void 0;
894
+ }
895
+ if (!localOpenApiStats.isFile() || localOpenApiStats.isSymbolicLink()) {
896
+ return void 0;
897
+ }
898
+ let realSitePath;
899
+ let realLocalOpenApiPath;
900
+ try {
901
+ realSitePath = await fs2.promises.realpath(resolvedSitePath);
902
+ realLocalOpenApiPath = await fs2.promises.realpath(
903
+ resolvedLocalOpenApiPath
904
+ );
905
+ } catch {
906
+ return void 0;
907
+ }
908
+ if (!this.isPathWithinBasePath(realLocalOpenApiPath, realSitePath)) {
909
+ return void 0;
910
+ }
911
+ const localOpenApiContent = (await fs2.promises.readFile(realLocalOpenApiPath, "utf8")).trim();
912
+ return {
913
+ sourcePath: realLocalOpenApiPath,
914
+ content: localOpenApiContent
915
+ };
916
+ }
917
+ isPathWithinBasePath(candidatePath, basePath) {
918
+ const relativePath = path4.relative(
919
+ path4.resolve(basePath),
920
+ path4.resolve(candidatePath)
921
+ );
922
+ return relativePath === "" || !relativePath.startsWith("..") && !path4.isAbsolute(relativePath);
923
+ }
924
+ toPosixPath(filePath) {
925
+ return filePath.replaceAll(path4.sep, path4.posix.sep);
926
+ }
927
+ async buildIndexPage(data) {
928
+ if (data.templates) {
929
+ const indexPath = `${data.outputPath}/index.html`;
930
+ await fs2.promises.mkdir(data.outputPath, { recursive: true });
931
+ const indexTemplate = `${data.templatePath}/${data.templates.home}`;
932
+ let content;
933
+ if (!data.hasDocuments) {
934
+ content = await this.buildReadmeSection(data);
935
+ }
936
+ const announcement = await this.buildAnnouncementSection(data);
937
+ const indexContent = await this._ecto.renderFromFile(
938
+ indexTemplate,
939
+ { ...data, content, announcement },
940
+ data.templatePath
941
+ );
942
+ await fs2.promises.writeFile(indexPath, indexContent, "utf8");
943
+ } else {
944
+ throw new Error("No templates found");
945
+ }
946
+ }
947
+ async buildDocsHomePage(data) {
948
+ if (!data.templates?.docPage) {
949
+ throw new Error("No docPage template found for homePage");
950
+ }
951
+ if (!data.documents?.length) {
952
+ throw new Error("No documents found for homePage");
953
+ }
954
+ const indexPath = `${data.outputPath}/index.html`;
955
+ await fs2.promises.mkdir(data.outputPath, { recursive: true });
956
+ const documentsTemplate = `${data.templatePath}/${data.templates.docPage}`;
957
+ const firstDocument = data.documents[0];
958
+ if (!data.sidebarItems) {
959
+ data.sidebarItems = this.generateSidebarItems(data);
960
+ }
961
+ const documentContent = await this._ecto.renderFromFile(
962
+ documentsTemplate,
963
+ { ...data, ...firstDocument },
964
+ data.templatePath
965
+ );
966
+ await fs2.promises.writeFile(indexPath, documentContent, "utf8");
967
+ }
968
+ async buildReadmeSection(data) {
969
+ let htmlReadme = "";
970
+ if (fs2.existsSync(`${data.sitePath}/README.md`)) {
971
+ const readmeContent = fs2.readFileSync(
972
+ `${data.sitePath}/README.md`,
973
+ "utf8"
974
+ );
975
+ htmlReadme = await new Writr(readmeContent).render();
976
+ }
977
+ return htmlReadme;
978
+ }
979
+ async buildAnnouncementSection(data) {
980
+ const announcementPath = `${data.sitePath}/announcement.md`;
981
+ if (fs2.existsSync(announcementPath)) {
982
+ const announcementContent = fs2.readFileSync(announcementPath, "utf8");
983
+ return new Writr(announcementContent).render();
984
+ }
985
+ return void 0;
986
+ }
987
+ async buildDocsPages(data) {
988
+ if (data.templates && data.documents?.length) {
989
+ const documentsTemplate = `${data.templatePath}/${data.templates.docPage}`;
990
+ await fs2.promises.mkdir(`${data.outputPath}/docs`, { recursive: true });
991
+ data.sidebarItems = this.generateSidebarItems(data);
992
+ const promises = data.documents.map(async (document) => {
993
+ const folder = document.urlPath.split("/").slice(0, -1).join("/");
994
+ await fs2.promises.mkdir(`${data.outputPath}/${folder}`, {
995
+ recursive: true
996
+ });
997
+ const slug = `${data.outputPath}${document.urlPath}`;
998
+ const documentContent = await this._ecto.renderFromFile(
999
+ documentsTemplate,
1000
+ { ...data, ...document },
1001
+ data.templatePath
1002
+ );
1003
+ return fs2.promises.writeFile(slug, documentContent, "utf8");
1004
+ });
1005
+ await Promise.all(promises);
1006
+ } else {
1007
+ throw new Error("No templates found");
1008
+ }
1009
+ }
1010
+ async buildApiPage(data) {
1011
+ if (!data.openApiUrl || !data.templates?.api) {
1012
+ return;
1013
+ }
1014
+ const apiPath = `${data.outputPath}/api/index.html`;
1015
+ const apiOutputPath = `${data.outputPath}/api`;
1016
+ await fs2.promises.mkdir(apiOutputPath, { recursive: true });
1017
+ const swaggerSource = `${data.sitePath}/api/swagger.json`;
1018
+ if (fs2.existsSync(swaggerSource)) {
1019
+ await fs2.promises.copyFile(
1020
+ swaggerSource,
1021
+ `${apiOutputPath}/swagger.json`
1022
+ );
1023
+ }
1024
+ const apiTemplate = `${data.templatePath}/${data.templates.api}`;
1025
+ const apiContent = await this._ecto.renderFromFile(
1026
+ apiTemplate,
1027
+ { ...data, specUrl: data.openApiUrl },
1028
+ data.templatePath
1029
+ );
1030
+ await fs2.promises.writeFile(apiPath, apiContent, "utf8");
1031
+ }
1032
+ getChangelogEntries(changelogPath) {
1033
+ const entries = [];
1034
+ if (!fs2.existsSync(changelogPath)) {
1035
+ return entries;
1036
+ }
1037
+ const files = fs2.readdirSync(changelogPath);
1038
+ for (const file of files) {
1039
+ const filePath = `${changelogPath}/${file}`;
1040
+ const stats = fs2.statSync(filePath);
1041
+ if (stats.isFile() && (file.endsWith(".md") || file.endsWith(".mdx"))) {
1042
+ const entry = this.parseChangelogEntry(filePath);
1043
+ entries.push(entry);
1044
+ }
1045
+ }
1046
+ entries.sort((a, b) => {
1047
+ const dateA = new Date(a.date).getTime();
1048
+ const dateB = new Date(b.date).getTime();
1049
+ if (Number.isNaN(dateA) && Number.isNaN(dateB)) {
1050
+ return 0;
1051
+ }
1052
+ if (Number.isNaN(dateA)) {
1053
+ return 1;
1054
+ }
1055
+ if (Number.isNaN(dateB)) {
1056
+ return -1;
1057
+ }
1058
+ return dateB - dateA;
1059
+ });
1060
+ return entries;
1061
+ }
1062
+ parseChangelogEntry(filePath) {
1063
+ const fileContent = fs2.readFileSync(filePath, "utf8");
1064
+ const writr = new Writr(fileContent);
1065
+ const matterData = writr.frontMatter;
1066
+ const markdownContent = writr.body;
1067
+ const fileName = path4.basename(filePath, path4.extname(filePath));
1068
+ const slug = fileName.replace(/^\d{4}-\d{2}-\d{2}-/, "");
1069
+ const isMdx = filePath.endsWith(".mdx");
1070
+ const tag = matterData.tag;
1071
+ const tagClass = tag ? tag.toLowerCase().replace(/\s+/g, "-") : void 0;
1072
+ let dateString = "";
1073
+ if (matterData.date instanceof Date) {
1074
+ dateString = matterData.date.toISOString().split("T")[0];
1075
+ } else if (matterData.date) {
1076
+ dateString = String(matterData.date);
1077
+ }
1078
+ let formattedDate = dateString;
1079
+ const parsedDate = new Date(dateString);
1080
+ if (!Number.isNaN(parsedDate.getTime())) {
1081
+ formattedDate = parsedDate.toLocaleDateString("en-US", {
1082
+ year: "numeric",
1083
+ month: "long",
1084
+ day: "numeric"
1085
+ });
1086
+ }
1087
+ return {
1088
+ title: matterData.title ?? fileName,
1089
+ date: dateString,
1090
+ formattedDate,
1091
+ tag,
1092
+ tagClass,
1093
+ slug,
1094
+ content: markdownContent,
1095
+ generatedHtml: new Writr(markdownContent).renderSync({ mdx: isMdx }),
1096
+ urlPath: `/changelog/${slug}/index.html`
1097
+ };
1098
+ }
1099
+ convertReleaseToChangelogEntry(release) {
1100
+ const tagName = release.tag_name ?? "";
1101
+ const slug = tagName.replace(/\./g, "-");
1102
+ const name = release.name || tagName;
1103
+ const body = release.body ?? "";
1104
+ const publishedAt = release.published_at ?? "";
1105
+ const prerelease = release.prerelease ?? false;
1106
+ let dateString = "";
1107
+ let formattedDate = "";
1108
+ if (publishedAt) {
1109
+ const parsedDate = new Date(publishedAt);
1110
+ if (!Number.isNaN(parsedDate.getTime())) {
1111
+ dateString = parsedDate.toISOString().split("T")[0];
1112
+ formattedDate = parsedDate.toLocaleDateString("en-US", {
1113
+ year: "numeric",
1114
+ month: "long",
1115
+ day: "numeric"
1116
+ });
1117
+ }
1118
+ }
1119
+ const tag = prerelease ? "Pre-release" : "Release";
1120
+ const tagClass = tag.toLowerCase().replace(/\s+/g, "-");
1121
+ return {
1122
+ title: name,
1123
+ date: dateString,
1124
+ formattedDate,
1125
+ tag,
1126
+ tagClass,
1127
+ slug,
1128
+ content: body,
1129
+ generatedHtml: new Writr(body).renderSync(),
1130
+ urlPath: `/changelog/${slug}/index.html`
1131
+ };
1132
+ }
1133
+ getReleasesAsChangelogEntries(releases) {
1134
+ const entries = [];
1135
+ for (const release of releases) {
1136
+ if (release.draft) {
1137
+ continue;
1138
+ }
1139
+ entries.push(this.convertReleaseToChangelogEntry(release));
1140
+ }
1141
+ return entries;
1142
+ }
1143
+ async buildChangelogPage(data) {
1144
+ if (!data.hasChangelog || !data.templates?.changelog) {
1145
+ return;
1146
+ }
1147
+ const changelogOutputPath = `${data.outputPath}/changelog`;
1148
+ const changelogIndexPath = `${changelogOutputPath}/index.html`;
1149
+ await fs2.promises.mkdir(changelogOutputPath, { recursive: true });
1150
+ const changelogTemplate = `${data.templatePath}/${data.templates.changelog}`;
1151
+ const changelogContent = await this._ecto.renderFromFile(
1152
+ changelogTemplate,
1153
+ { ...data, entries: data.changelogEntries },
1154
+ data.templatePath
1155
+ );
1156
+ await fs2.promises.writeFile(changelogIndexPath, changelogContent, "utf8");
1157
+ }
1158
+ async buildChangelogEntryPages(data) {
1159
+ if (!data.hasChangelog || !data.templates?.changelogEntry || !data.changelogEntries?.length) {
1160
+ return;
1161
+ }
1162
+ const entryTemplate = `${data.templatePath}/${data.templates.changelogEntry}`;
1163
+ const promises = data.changelogEntries.map(async (entry) => {
1164
+ const entryOutputPath = `${data.outputPath}/changelog/${entry.slug}`;
1165
+ await fs2.promises.mkdir(entryOutputPath, { recursive: true });
1166
+ const entryContent = await this._ecto.renderFromFile(
1167
+ entryTemplate,
1168
+ { ...data, ...entry, entries: data.changelogEntries },
1169
+ data.templatePath
1170
+ );
1171
+ const entryFilePath = `${entryOutputPath}/index.html`;
1172
+ return fs2.promises.writeFile(entryFilePath, entryContent, "utf8");
1173
+ });
1174
+ await Promise.all(promises);
1175
+ }
1176
+ generateSidebarItems(data) {
1177
+ let sidebarItems = [...data.sections ?? []];
1178
+ for (const document of data.documents ?? []) {
1179
+ if (document.isRoot) {
1180
+ sidebarItems.unshift({
1181
+ path: document.urlPath.replace("index.html", ""),
1182
+ name: document.navTitle,
1183
+ order: document.order
1184
+ });
1185
+ } else {
1186
+ const relativeFilePath = document.documentPath.replace(
1187
+ `${data.sitePath}/docs/`,
1188
+ ""
1189
+ );
1190
+ const sectionPath = relativeFilePath.slice(
1191
+ 0,
1192
+ Math.max(0, relativeFilePath.lastIndexOf("/"))
1193
+ );
1194
+ const documentSection = document.section ?? sectionPath;
1195
+ const sectionIndex = sidebarItems.findIndex(
1196
+ (section) => section.path === documentSection
1197
+ );
1198
+ if (sectionIndex === -1) {
1199
+ continue;
1200
+ }
1201
+ sidebarItems[sectionIndex].children ??= [];
1202
+ sidebarItems[sectionIndex].children.push({
1203
+ path: document.urlPath.replace("index.html", ""),
1204
+ name: document.navTitle,
1205
+ order: document.order
1206
+ });
1207
+ }
1208
+ }
1209
+ sidebarItems = sidebarItems.map((section) => {
1210
+ if (section.children) {
1211
+ section.children.sort(
1212
+ (a, b) => (
1213
+ // biome-ignore lint/style/noNonNullAssertion: need to fix
1214
+ (a.order ?? section.children.length) - // biome-ignore lint/style/noNonNullAssertion: need to fix
1215
+ (b.order ?? section.children.length)
1216
+ )
1217
+ );
1218
+ }
1219
+ return section;
1220
+ });
1221
+ sidebarItems.sort(
1222
+ (a, b) => (a.order ?? sidebarItems.length) - (b.order ?? sidebarItems.length)
1223
+ );
1224
+ return sidebarItems;
1225
+ }
1226
+ getDocuments(sitePath, doculaData) {
1227
+ let documents = [];
1228
+ if (fs2.existsSync(sitePath)) {
1229
+ documents = this.getDocumentInDirectory(sitePath);
1230
+ doculaData.sections = this.getSections(sitePath, this.options);
1231
+ for (const section of doculaData.sections) {
1232
+ const sectionPath = `${sitePath}/${section.path}`;
1233
+ const sectionDocuments = this.getDocumentInDirectory(sectionPath);
1234
+ documents = [...documents, ...sectionDocuments];
1235
+ }
1236
+ }
1237
+ return documents;
1238
+ }
1239
+ getDocumentInDirectory(sitePath) {
1240
+ const documents = [];
1241
+ const documentList = fs2.readdirSync(sitePath);
1242
+ if (documentList.length > 0) {
1243
+ for (const document of documentList) {
1244
+ const documentPath = `${sitePath}/${document}`;
1245
+ const stats = fs2.statSync(documentPath);
1246
+ if (stats.isFile()) {
1247
+ const documentData = this.parseDocumentData(documentPath);
1248
+ documents.push(documentData);
1249
+ }
1250
+ }
1251
+ }
1252
+ documents.sort(
1253
+ (a, b) => (a.order ?? documents.length) - (b.order ?? documents.length)
1254
+ );
1255
+ return documents;
1256
+ }
1257
+ getSections(sitePath, doculaOptions) {
1258
+ const sections = [];
1259
+ if (fs2.existsSync(sitePath)) {
1260
+ const documentList = fs2.readdirSync(sitePath);
1261
+ if (documentList.length > 0) {
1262
+ for (const document of documentList) {
1263
+ const documentPath = `${sitePath}/${document}`;
1264
+ const stats = fs2.statSync(documentPath);
1265
+ if (stats.isDirectory()) {
1266
+ const section = {
1267
+ name: document.replaceAll("-", " ").replaceAll(/\b\w/g, (l) => l.toUpperCase()),
1268
+ path: document
1269
+ };
1270
+ this.mergeSectionWithOptions(section, doculaOptions);
1271
+ sections.push(section);
1272
+ }
1273
+ }
1274
+ }
1275
+ sections.sort(
1276
+ (a, b) => (a.order ?? sections.length) - (b.order ?? sections.length)
1277
+ );
1278
+ }
1279
+ return sections;
1280
+ }
1281
+ mergeSectionWithOptions(section, options) {
1282
+ if (options.sections) {
1283
+ const sectionOptions = options.sections.find(
1284
+ (sectionOption) => sectionOption.path === section.path
1285
+ );
1286
+ if (sectionOptions) {
1287
+ section.name = sectionOptions.name;
1288
+ section.order = sectionOptions.order;
1289
+ section.path = sectionOptions.path;
1290
+ }
1291
+ }
1292
+ return section;
1293
+ }
1294
+ parseDocumentData(documentPath) {
1295
+ const documentContent = fs2.readFileSync(documentPath, "utf8");
1296
+ const writr = new Writr(documentContent);
1297
+ const matterData = writr.frontMatter;
1298
+ let markdownContent = writr.body;
1299
+ markdownContent = markdownContent.replace(/^# .*\n/, "");
1300
+ const isMdx = documentPath.endsWith(".mdx");
1301
+ const fileExtension = isMdx ? ".mdx" : ".md";
1302
+ const documentsFolderIndex = documentPath.lastIndexOf("/docs/");
1303
+ let urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, "/index.html");
1304
+ let isRoot = urlPath.split("/").length === 3;
1305
+ if (!documentPath.slice(documentsFolderIndex + 6).includes("/")) {
1306
+ isRoot = true;
1307
+ const filePath = documentPath.slice(documentsFolderIndex + 6);
1308
+ if (filePath === "index.md" || filePath === "index.mdx") {
1309
+ urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, ".html");
1310
+ }
1311
+ }
1312
+ if (!this.hasTableOfContents(markdownContent)) {
1313
+ markdownContent = `## Table of Contents
1314
+
1315
+ ${markdownContent}`;
1316
+ }
1317
+ return {
1318
+ title: matterData.title,
1319
+ navTitle: matterData.navTitle ?? matterData.title,
1320
+ description: matterData.description ?? "",
1321
+ order: matterData.order ?? void 0,
1322
+ section: matterData.section ?? void 0,
1323
+ keywords: matterData.keywords ?? [],
1324
+ content: documentContent,
1325
+ markdown: markdownContent,
1326
+ generatedHtml: new Writr(markdownContent).renderSync({
1327
+ toc: true,
1328
+ mdx: isMdx
1329
+ }),
1330
+ documentPath,
1331
+ urlPath,
1332
+ isRoot
1333
+ };
1334
+ }
1335
+ hasTableOfContents(markdown) {
1336
+ const normalized = markdown.replace(/\r\n/g, "\n");
1337
+ const atxHeading = /^#{1,6}\s*(table of contents|toc)\s*$/im;
1338
+ const setextHeading = /^(table of contents|toc)\s*\n[-=]{2,}\s*$/im;
1339
+ const htmlHeading = /<h[1-6][^>]*>\s*(table of contents|toc)\s*<\/h[1-6]>/i;
1340
+ return atxHeading.test(normalized) || setextHeading.test(normalized) || htmlHeading.test(normalized);
1341
+ }
1342
+ copyDirectory(source, target) {
1343
+ const files = fs2.readdirSync(source);
1344
+ for (const file of files) {
1345
+ if (file.startsWith(".")) {
1346
+ continue;
1347
+ }
1348
+ const sourcePath = `${source}/${file}`;
1349
+ const targetPath = `${target}/${file}`;
1350
+ const stat = fs2.lstatSync(sourcePath);
1351
+ if (stat.isDirectory()) {
1352
+ fs2.mkdirSync(targetPath, { recursive: true });
1353
+ this.copyDirectory(sourcePath, targetPath);
1354
+ } else {
1355
+ fs2.mkdirSync(target, { recursive: true });
1356
+ fs2.copyFileSync(sourcePath, targetPath);
1357
+ }
1358
+ }
1359
+ }
1360
+ copyPublicFolder(sitePath, outputPath) {
1361
+ const publicPath = `${sitePath}/public`;
1362
+ if (!fs2.existsSync(publicPath)) {
1363
+ return;
1364
+ }
1365
+ this._console.log("Public folder found, copying contents to dist...");
1366
+ const resolvedOutputPath = path4.resolve(outputPath);
1367
+ this.copyPublicDirectory(
1368
+ publicPath,
1369
+ outputPath,
1370
+ publicPath,
1371
+ resolvedOutputPath
1372
+ );
1373
+ }
1374
+ copyPublicDirectory(source, target, basePath, outputPath) {
1375
+ const files = fs2.readdirSync(source);
1376
+ for (const file of files) {
1377
+ const sourcePath = `${source}/${file}`;
1378
+ const targetPath = `${target}/${file}`;
1379
+ const relativePath = sourcePath.replace(`${basePath}/`, "");
1380
+ const resolvedSourcePath = path4.resolve(sourcePath);
1381
+ if (resolvedSourcePath === outputPath || resolvedSourcePath.startsWith(`${outputPath}${path4.sep}`)) {
1382
+ continue;
1383
+ }
1384
+ const stat = fs2.lstatSync(sourcePath);
1385
+ if (stat.isDirectory()) {
1386
+ fs2.mkdirSync(targetPath, { recursive: true });
1387
+ this.copyPublicDirectory(sourcePath, targetPath, basePath, outputPath);
1388
+ } else {
1389
+ fs2.mkdirSync(target, { recursive: true });
1390
+ fs2.copyFileSync(sourcePath, targetPath);
1391
+ this._console.log(` Copied: ${relativePath}`);
1392
+ }
1393
+ }
1394
+ }
1395
+ };
1396
+
1397
+ // src/init.ts
1398
+ var doculaconfigmjs = "ZXhwb3J0IGNvbnN0IG9wdGlvbnMgPSB7Cgl0ZW1wbGF0ZTogJ21vZGVybicsCglvdXRwdXRQYXRoOiAnLi9kaXN0JywKCXNpdGVQYXRoOiAnLi9zaXRlJywKCWdpdGh1YlBhdGg6ICdqYXJlZHdyYXkvZG9jdWxhJywKCXNpdGVUaXRsZTogJ0RvY3VsYScsCglzaXRlRGVzY3JpcHRpb246ICdCZWF1dGlmdWwgV2Vic2l0ZSBmb3IgWW91ciBQcm9qZWN0cycsCglzaXRlVXJsOiAnaHR0cHM6Ly9kb2N1bGEub3JnJywKfTsKCg==";
1399
+ var doculaconfigts = "aW1wb3J0IHR5cGUgeyBEb2N1bGFPcHRpb25zIH0gZnJvbSAnZG9jdWxhJzsKCmV4cG9ydCBjb25zdCBvcHRpb25zOiBQYXJ0aWFsPERvY3VsYU9wdGlvbnM+ID0gewoJdGVtcGxhdGU6ICdtb2Rlcm4nLAoJb3V0cHV0UGF0aDogJy4vZGlzdCcsCglzaXRlUGF0aDogJy4vc2l0ZScsCglnaXRodWJQYXRoOiAnamFyZWR3cmF5L2RvY3VsYScsCglzaXRlVGl0bGU6ICdEb2N1bGEnLAoJc2l0ZURlc2NyaXB0aW9uOiAnQmVhdXRpZnVsIFdlYnNpdGUgZm9yIFlvdXIgUHJvamVjdHMnLAoJc2l0ZVVybDogJ2h0dHBzOi8vZG9jdWxhLm9yZycsCn07Cg==";
1400
+ var faviconico = "AAABAAEAAAAAAAEAIAA6FAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAEAAAABAAgEAAAA9ntg7QAAAAFvck5UAc+id5oAABP0SURBVHja7V17cFTXfb7iYcnCQmA3tiNDIabYBheHl2OSeKYttsNMKLYcnHFASaAxiYydGfUxiFcdRJOBOsaQPzJITmzcmRpS17ZaFBtIUhOeqjCFoRiQOklw8ASJICIkXooeq6/f7r27Wq12pV3tfZx77u87Mx7Pot17z+/7zjm/8zvn/I5haIISA4llGAowHtMxD0uwElvwBvagDmdwDhdxBe3oQghhhPh/7fzkIj5GPY7wr7bjB1iFpfzmDP5CAYYn/vaLhkAR9CO9EJMxF89gA3ZgPxpwAVfRiR5kih5+6yq/3YAD+Ak2YhkewT0Ywyf0eaJADeILcB8exxqS/gHO4wacQDsacZRiWIsnMAWjRQgqUD8Gs9jaq1CLJrZYt9DJp9Xyqcv49LEiAy+oz8O9WIytbJEt8BItfINKlLD/yRMZuEP9aMxBOXaxow9BFYQ4OOymozknfmAQ2E19AR7GehxCK1RFKw7jn/iWIgObqc/ldGw1vfE2+AFXcJDu6Ey+tcjABvLHcRa/E83wG5r51kv59iKCIZOfyzF1E+oVGusz9w0aWIM5vX2BIF3yx2Ihqj328O2bKVTjqd7poiApZveSX4TldKY6oBM6WKPlrJlVx1IhPEXLn8Ap3skhBG79gB58yNpNlJ4gNflrOGbqjgasFRH0J78IK+juBQX17AmKAi+COIevFCcQNJxgrYPrGMZN9YqxD90IIrpZ8+JAThFj9M/GDlxHkHGdFpgdKAnEyL8T69AIAWiFClojGCKwqjmCXd8RYT4OR/AkRmougVjbn4QqXBPOE3CNVpmkcT9gVW0kFuGUsJ0Cp2gdHfuBuFBPlUP79XTBDbxCK+nVD1jVycF8HBeG08BxWipHGwnENm9W4LJwmyYu01pjtJCARf/9qNF0gce5haMaWs3fEoh1/cUBivLbu2xU7OOhwKI/H6uk689iKFhNC/pRArE1vm0BjfPbt17wenTd0H/0P4D3hUEbsJeW9JMELPofxWnhziacpjX9IYGY41eC88KbrQtGJT5wCGNLPWUKn97xK1pp1RFKSyB2bLMC7cKXA2inZfOUlYBF/y3YjC7hyiF00bq3KCkBi/5CVPr4HI8fEKKFC5WTQCze/5ow5AJei24mVY3+bcKNS3hdoaWiWOcvrd/dXkCNgSDm+lUKJy6jUgl30Jr4bRbXzwN3cLM5KfSa/hGcncrEz5tJYYUZGvKS/hyUSdjHw9BQmRkg9m70L5Ggr8cB4hJPPIHYip+c7fEajR6sFMbW+2XBVwWcdn2/gLXbZ6/YXhHsNXcNuUl/vsT9lMI2c++ge77/atnrpxS6yYgb8wFr9C+Wnb7K4TJZcdoTiB3zaBB7K4h6x4+SWKt+NWJrRVFjrhI6O/pXyCEvZdFDdpzyBKzuf76M/op7AvMdGgas8/1ywFt1HDfzCzhB/0hUiX19gCozy4j93f8iye7hC9wgU/YOA1ZqJ8nt4xecMtNNSfcvw4CNsT9J7OYnXLMtLmhl9ZS0jn5DnZl91J72XyH29CHW2dAHWCmdZd+PH9FopqHOlv5c7BBb+hQ7zGT02QmgOOAJ3f2M66YrmA39Y7FP7Ohj7DMPkg5dAKWy88fX6CaDQxOAtfHzhNjQ5zgxpA2jC0wBrBD7aYAVYS5nD2nxV1K86oD6ISwQRwSwRmynCdZkKACr/cvWT13QkGEfEBFAudhNI5RnIADL/z8pVtMIJzOYC0QEsFz2/mqFHjKangCs+N9hsZlmOJxmTDAigIXoEItphg6yOrgArPW/arGXhqhOY20wIoA5aBFraYgWMpuWADbpWf8DaZ5qOYpDukpg0yACiNA/Ts8A0HsYj2moG/TvDmEqJuBnegqggewOJIGIAJbqmPTxPbPmmIR/GyCpYSe2Y6IVBtVSAiEsGUwAudipX71/jj+NXV88CqX4MOlE+X+xLHpHG8tEPW+82hl2BAdq/zPQrN/YfzeMPmUcvo1f4AJbvDk/amJ7fw53JfzVn+noCzST4VR9QKTWq3Wr8TGO6UaSks/P57NHXML/TsHNSf9mmo77YVYPJIDROKhXbX+Fh5JSm275HH6jmwAOkuWU7f9htOlU19/ji1nRHy4LcFEvAbSR5WR9QKS263Wq6Q18M2v6w+VZ3bJhr08lgNE6eT092Bi9Zi/LMgIv6SWAQ0kGASsE3OongrtjJZRk7fo/o9fq2FBuxbtJnh/ik7tYzDfwEVqThIQj9VypIs3tuISzOI69eBuvYhO+g79np7wUi/BlfAlPsjyFr+Dr+Bb+FmvxIl7Bv3MGvzuF7x8uU/EF3Nbv09v4aervPMCJ4n/hTVThn/mUMg4uX8PTWIhiPBF7g1L8HV5gb/EjvMW/PUb3sZnDkJLbKlYmE0AeraYEOkn5GfychlxLMz9C44/HWE7UhqfZXoezKvkp//UznBl04V8T/iKfn3TxXz6T8nuj+KvDMniDMRiHP8dfoQSrKJs9OEU5dKoigF3hy2YS2/+93l733EWf/QPSsJJt6tO4I3pHqu3l+cjTfmeFfHvjfr+LfP68Q0/Nxe2YxhnFCvwL6nDB6zt2zpPt+D7Auvsj5E17P8f2sYHd6VQURi/IdrBMx0lc50DRV2B5bKXX+S/THX9+Dj2wKRw2vstm+Fuv9t2EzHtG+grA9Yvf/kB39PscRe92rLUnLxPxWRT0+7SAn0509T1y8Sn2CRuxn0Oe69iaKICxOOre0xtRQ0dqVhIaglhuYb/zbfyHuyPw0fAOwfj2P8udXUCXOKF6jp39TUJ8QrkJ93EeUeNW3LGFjEf7gMjzn3H6iR34H07hZrrc3fut5LI3WEtn2AXf4Jm+AnA0C+BlvMO58p8IwWmW2+gkvuV0l1wVL4DRqHXqORfocX/e3I4qJaMh4bP0y5ucE0Bt2AUjvht+2hRnntRMZ3Nm2uETKYllGGbgh055BU10Osi++aQn7A9S3cBPqGEhP3sRPITtTuTp6iTr4UEg8pS19s8ynpJu30bX8Et0DG3H2qgAhtmbCfAqNvfbXycl21KEl2lZW7Ej3EGHf7vQziDQb/CVtJdtpGRShuNpezeofUDmIwKYbF8Qqg4PClUOlgfTONqSwZLQZFMAj9h1E8hJod/xMtu+zB03MNcUwDL7pn21eBsv4Zv4S0xMsdVaSublZkzAX5Cm7+MtHLbz4MYyUwAb7Xcwr+O3eJ9uy9OcbIoQhlrycA++zAb1C3zkzH0dG8ICGM4Ju2PoRiN+hjX4nKz8ZVQKMAersJvDtKOZejkPCD/rgPMrD204iNX4tHmRjZQB9yBPw0rsd2d/7gEUGBjv3nHw3+NNFIfnHlKSltF4nI3ygnu7AhowLrxHysUnAn+k7P4mya7coJdbsQS/dPsIygVMNzDP7gBTOp5BLb4mXkHcnqDFOOTFRtGrmGdQeJ7sVu7ELk5DZbEoh1Pmd73aHNqJJQadTc/OLrRwihPsVYMivIg/wDP0YJWBLfAUdfhCYOl/FP8Nj7HFwHav3+ESVgQwWHQz/kGFZCzbDezx/i268GPcHij6P4FXvD4dZGKPocqlsO/iU4GhfyJqoAjqDJxR5V324Z5A0D+Z831lcMbAx+q8zf5++bz0K3erdRHjOUOttHC7zCuvtS134D0ohYsGrqj1RtswSlv68/EaFMMVQ7UMSN1m+gotS7l617C2G2rMRvrGBR7Tkv7HvDgGPugM3FAxv1Gthp7AHWrewhMyoCQqtBNAhZqG7lFUAOfNnMbalBneJmAaUACKprh7RaPjJcNZG0URUtAJtCaomK3RXn5l8w13Geomwt2sjQA2Q1m0KxcI6sWvzBuPfV8msCbKos1Q94aQEJZqIQClL2G6qNRiUCLetCnft7f7/N+Ewjin0HJwf5x1OXWjM2v/Z1UWwBnDzvPGdqMDC3wvgAVqX8Ncp8SWMJ0jghVQGnsU2BQ6EN72uRcwgjVQGm94vi18YBwzL733bRnLGiiNLZ4eDBkcH/t8k9jdKk+ywgdDVnp2NCw9XDZzGvu2zGINFEbkaJgHh0MziFSG09j4uMxV+8q5yOFQl4+HZyrR+b4WwF+r3L1ax8NdTBCRObpRiiLchdvpTo3ySX6RkXzTsXzju/jmpertAoxHfThBhCspYrIIVuMj/JpvehwH8VO8jo14jr3CA/iEQhPEEXybaXyr57CBb/hTvulxvvGv+eaKXzsbSRHjaJIopyKEzfgQ1fgOjT7Bw35hBJ/+Rb5FNd+mWe2IX3JEkkQ5kibOPSmcxTtsefe7fAnNTXzicrzNp/8RPsYGmxNFeocmyuCr+KQr5N+JEj6tCRpgmc2pYr12GE/iBYcPmE7GP/Ip3dACsVSxk1XdsjoUfITvYZIj5E/iL5+FRogliy50885AN/B/KMOtNsf0y/irmiGWLt7mCyNUQAjv2xhDnMtfC0E7xC6McODKGBVwiRO0MVmTP4a/cglaInZljCOXRqmAHtRgalb0T+Uv9OhJfycejwjghXA9p+gxq0mGU1mcNX6M39YWkWvjVjl/caQKNf3qEK6lz+G3mqAxohdHunF1rNdoxbMZJqUdhuXuJGz3Dn2ujnXh8mhvcRXPZ9AL5PCvr0JzJFwe7dL18d7hCr6RtgC+oe55ObsQf328YUY6jupe50soTov+J3Wd9sXjaHi3rREnAAOV+tf6LB4alP45eoV7U2FrXPu3BFCiY7ArEYcxfkD6x+s8HepFiGz3E8C9Oi0JpcY25KWkP4//GgicJ9vxAjDM2u8OQt07OSVMJYDlegZE+2NXuBUYCQIwsDIYtT+XIgHVTP5LQFCe0P6NqP/TGoz6v5MkHe0oVAeF/lYynSgAKyB8KBgW6DSjIH3KsqB0/yDLo/vRb/UB64Nig9MJqScm8pPAYH2S9m8J4GG0BcUKG/oIYGNw6G8jy8kEYA0CB4Nih/OYHqN/OhqDI4ADsVXApH3A6uBYotJaIRwWhCBoL1anaP9GNKltc1AscREPRqr8oOoHuOxEszkHNlJKIBc7g2ONrchh2Rqk9r+TDBvGAAJQPK+hvWjEVNwfpPE/hCUDtH9LAONUPi5uN77HEiA0kN2BBGBJYFNwLNKk976/RGwahP5YSLgFAv3QkjQEnEQAucEJiwcK1WEHcBABWBJY6MdsB4IB0UFWB6ffiJ6FPCwW0wyHzZybRpoSWK7riaiAooeMpke/JYAinBSraYSTZDRdARjRe04F+qA8A/qN6FU3DWI3TdBgXr9kZCiBNWI5TbAmQ/pjfUC92E4D1Gfc/g1jgSmBFWI9DbAizOVswxhCH1CEE2I/n+NERv5/PwmU6pIUL6AIZ9seGv2xmOA+saKPsS/t+F9KCRTjutjRp7hunog3shJArn5ZBAOD7Wmt/w0qgdlB2jWlERrJXHb0G9GN8+vEmj7EOpM9wwYJ3IkjYk+foY6sZU9/rA8oxjWxqY9wLZoQybBJAiP1ziSoHarMK5VsgpUu/5TY1Sc4ZV6ZYNgqAAOL9LhZRHvcIFOGrQKQYcBn3f9Im+mPWyA+LvZVHMeGsPibwTAwX+3bkAOPy9G7dg2HJJCDCtkvrCx6yE6OQ/THJDAGNWJpRVFj3pFjOCoAA/fLVjElUU9mDEcFEBcXFE9AvdG/2HH64zyBVbJTSCl0k5EcF+iPSSA/KHmVfYJtZMQd+uM2jL4vdlcEe4e88TMrT+CBIKXXVBinyYThqgBiEng0GHcMKI1GsuA2/XESWByUDOOKotW8+8N1+uPmA2VoFx48Qjutn+MR/TEJjEAFuoQLD9BFy4/wkP6YBPLwcnCSSyqDEDab1x8ZngvAwC2olCUil1FJqxueCyAmgUK8Kpy4iNdocRXoj5PAGIkNuobXzVU/JejvI4FXZSBwpfWrRX+fgaBS3EGHXb9KhTr/pO7gyzIpdHDi97Iirt8AEsjj7FRCQ86EfSqi994qCkRDQ2USIHYg6Ftmhn2UpT9OAjlYLMtEtqIRJWbQV2n6E1YKZbHYLpz2aMUv6/0CsmXEDuz1YL3fJgl8Ettk72BW6KYFi3xHf5wE8rFKdhAPGZdpvXxf0t/HISyWcwRDQj0tl+Nb+hOOkuyUIHFG6EGNC8c8XF0nqJChIIOuv0LBeH/WQ8F8HBNu08BxWipHG/rjJBDOL1AlWUYGxA1aaELUXloB0SwjiyTXUEqconVGakh+Qj8wiSq/Kmwn4BqtMknLtp90uagYdcJ5HI7QIiM1Jz+hH7gT6yQHsbXQs87M6hkA+hNEMAvbA56M/jp2mCmdA0N+ggRy2fXtC+h6QTdrXmwmdA8Y/QkiGItvBfBuohMoNW/zCCT5/URQhBUBWjGoZ22LAk9+kjDRmgDcVtrAWk4Q8lOLoBwnNV046mHNyoX8FJgdPxw8i8Po0Ir8DtZoeW+3v0AIH9QxXIhqtGhBfgtr8pQ4fEOZIs7BS3SY/HvWKMQRfxNrkSvkD1UEBsZhCXai2XfkN/Otl/LtDSE/exHkYgZW4wDafEF9Gw7S05/R2+6FfHtkUIDPYz0OKXzqqJVvtx4PY7RQ75wMRnNMLccunFfINwjxbXZjJd9MqHdJBnm4F4uxFR94PFNowVFUooRvkyfUuy+D8GbTmXiGFNSiCZ2u0d7Jp9Wiik+e1Tu9E+q9k0HYP7gPj9P12sE+4bxD+w5v8JeP8glr8QSmxHf2Qr06QhiGQkzGXLbNDaRqP+pxAVfZYjMPLvfwW1f57QbOPnZgI5bhEf5yIZ8gxKuIkkQphMVQwHn4dMzDEjpoW/AG9qAOp3EOF3EF7eii89bDEuL/tfOTi/gYZ/gXe7Cdf72K35rHb4/nrwxP/O0XtbHb/wPBh64vbaYDKgAAAABJRU5ErkJggg==";
1401
+ var logopng = "iVBORw0KGgoAAAANSUhEUgAAAxEAAAHXCAYAAADDSdfmAAAACXBIWXMAACxLAAAsSwGlPZapAAAFw2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDMgNzkuOTY5MGE4N2ZjLCAyMDI1LzAzLzA2LTIwOjUwOjE2ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjYuNiAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjUtMDUtMThUMTM6MzM6NTgtMDc6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI1LTA1LTE4VDEzOjM2OjE5LTA3OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI1LTA1LTE4VDEzOjM2OjE5LTA3OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5YTc4ZDY2Ny02NjAzLTQwNmUtYTViZC02MjYzMTNjY2VmY2QiIHhtcE1NOkRvY3VtZW50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";
1402
+ var variablescss = "OnJvb3QgewogICAgLS1mb250LWZhbWlseTogJ09wZW4gU2FucycsIHNhbnMtc2VyaWY7CiAgCiAgICAtLWNvbG9yLXByaW1hcnk6ICAjMzIyZDNjOwogICAgLS1jb2xvci1zZWNvbmRhcnk6ICM4Y2RjMDA7CiAgICAtLWNvbG9yLXNlY29uZGFyeS1kYXJrOiAjOGNkYzAwOwogICAgLS1jb2xvci10ZXh0OiAjMzIyZDNjOwogIAogICAgLS1iYWNrZ3JvdW5kOiAjZmZmZmZmOwogICAgLS1ob21lLWJhY2tncm91bmQ6ICNmZmZmZmY7CiAgICAtLWhlYWRlci1iYWNrZ3JvdW5kOiAjZmZmZmZmOwogIAogICAgLS1zaWRlYmFyLWJhY2tncm91bmQ6ICNmZmZmZmY7CiAgICAtLXNpZGViYXItdGV4dDogIzMyMmQzYzsKICAgIC0tc2lkZWJhci10ZXh0LWFjdGl2ZTogIzdkNzg4NzsKICAKICAgIC0tYm9yZGVyOiByZ2JhKDIzOCwyMzgsMjQ1LDEpOwogIAogICAgLS1iYWNrZ3JvdW5kLXNlYXJjaC1oaWdobGlnaHQ6IHZhcigtLWNvbG9yLXNlY29uZGFyeS1kYXJrKTsKICAgIC0tY29sb3Itc2VhcmNoLWhpZ2hsaWdodDogI2ZmZmZmZjsKICAgIC0tc2VhcmNoLWlucHV0LWJhY2tncm91bmQ6IHZhcigtLWhlYWRlci1iYWNrZ3JvdW5kKTsKICAKICAgIC0tY29kZTogcmdiYSgyMzgsMjM4LDI0NSwxKTsKICAKICAgIC0tcGFnZWZpbmQtdWktdGV4dDogdmFyKC0tY29sb3ItdGV4dCkgIWltcG9ydGFudDsKICAgIC0tcGFnZWZpbmQtdWktZm9udDogdmFyKC0tZm9udC1mYW1pbHkpICFpbXBvcnRhbnQ7CiAgICAtLXBhZ2VmaW5kLXVpLWJhY2tncm91bmQ6IHZhcigtLWJhY2tncm91bmQpICFpbXBvcnRhbnQ7CiAgICAtLXBhZ2VmaW5kLXVpLWJvcmRlcjogdmFyKC0tYm9yZGVyKSAhaW1wb3J0YW50OwogICAgLS1wYWdlZmluZC11aS1zY2FsZTogLjkgIWltcG9ydGFudDsKICB9";
1403
+
1404
+ // src/docula.ts
1405
+ import { Writr as Writr2 } from "writr";
1406
+ var Docula = class {
1407
+ _options = new DoculaOptions();
1408
+ _console = new DoculaConsole();
1409
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
1410
+ _configFileModule = {};
1411
+ _server;
1412
+ /**
1413
+ * Initialize the Docula class
1414
+ * @param {DoculaOptions} options
1415
+ * @returns {void}
1416
+ * @constructor
1417
+ */
1418
+ constructor(options) {
1419
+ if (options) {
1420
+ this._options = options;
1421
+ }
1422
+ }
1423
+ /**
1424
+ * Get the options
1425
+ * @returns {DoculaOptions}
1426
+ */
1427
+ get options() {
1428
+ return this._options;
1429
+ }
1430
+ /**
1431
+ * Set the options
1432
+ * @param {DoculaOptions} value
1433
+ */
1434
+ set options(value) {
1435
+ this._options = value;
1436
+ }
1437
+ /**
1438
+ * The http server used to serve the site
1439
+ * @returns {http.Server | undefined}
1440
+ */
1441
+ get server() {
1442
+ return this._server;
1443
+ }
1444
+ /**
1445
+ * The config file module. This is the module that is loaded from the docula.config.ts or docula.config.mjs file
1446
+ * @returns {any}
1447
+ */
1448
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
1449
+ get configFileModule() {
1450
+ return this._configFileModule;
1451
+ }
1452
+ /**
1453
+ * Check for updates
1454
+ * @returns {void}
1455
+ */
1456
+ checkForUpdates() {
1457
+ const packageJsonPath = path5.join(process4.cwd(), "package.json");
1458
+ if (fs3.existsSync(packageJsonPath)) {
1459
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
1460
+ updateNotifier({ pkg: packageJson }).notify();
1461
+ }
1462
+ }
1463
+ /**
1464
+ * Is the execution process that runs the docula command
1465
+ * @param {NodeJS.Process} process
1466
+ * @returns {Promise<void>}
1467
+ */
1468
+ async execute(process5) {
1469
+ this.checkForUpdates();
1470
+ const consoleProcess = this._console.parseProcessArgv(process5.argv);
1471
+ this.options.singlePage = this.isSinglePageWebsite(this.options.sitePath);
1472
+ if (consoleProcess.args.sitePath) {
1473
+ this.options.sitePath = consoleProcess.args.sitePath;
1474
+ }
1475
+ await this.loadConfigFile(this.options.sitePath);
1476
+ if (this._configFileModule.options) {
1477
+ this.options.parseOptions(
1478
+ // biome-ignore lint/suspicious/noExplicitAny: need to fix
1479
+ this._configFileModule.options
1480
+ );
1481
+ }
1482
+ if (this._configFileModule.onPrepare) {
1483
+ try {
1484
+ await this._configFileModule.onPrepare(this.options);
1485
+ } catch (error) {
1486
+ this._console.error(error.message);
1487
+ }
1488
+ }
1489
+ if (consoleProcess.args.template) {
1490
+ this.options.template = consoleProcess.args.template;
1491
+ }
1492
+ if (consoleProcess.args.output) {
1493
+ this.options.outputPath = consoleProcess.args.output;
1494
+ }
1495
+ switch (consoleProcess.command) {
1496
+ case "init": {
1497
+ this.generateInit(
1498
+ this.options.sitePath,
1499
+ consoleProcess.args.typescript
1500
+ );
1501
+ break;
1502
+ }
1503
+ case "help": {
1504
+ this._console.printHelp();
1505
+ break;
1506
+ }
1507
+ case "version": {
1508
+ this._console.log(this.getVersion());
1509
+ break;
1510
+ }
1511
+ case "serve": {
1512
+ const builder = new DoculaBuilder(this.options);
1513
+ await builder.build();
1514
+ await this.serve(this.options);
1515
+ break;
1516
+ }
1517
+ default: {
1518
+ const builder = new DoculaBuilder(this.options);
1519
+ await builder.build();
1520
+ break;
1521
+ }
1522
+ }
1523
+ }
1524
+ /**
1525
+ * Checks if the site is a single page website
1526
+ * @param {string} sitePath
1527
+ * @returns {boolean}
1528
+ */
1529
+ isSinglePageWebsite(sitePath) {
1530
+ const documentationPath = `${sitePath}/docs`;
1531
+ if (!fs3.existsSync(documentationPath)) {
1532
+ return true;
1533
+ }
1534
+ const files = fs3.readdirSync(documentationPath);
1535
+ return files.length === 0;
1536
+ }
1537
+ /**
1538
+ * Generate the init files
1539
+ * @param {string} sitePath
1540
+ * @param {boolean} typescript - If true, generates docula.config.ts instead of docula.config.mjs
1541
+ * @returns {void}
1542
+ */
1543
+ generateInit(sitePath, typescript = false) {
1544
+ if (!fs3.existsSync(sitePath)) {
1545
+ fs3.mkdirSync(sitePath);
1546
+ }
1547
+ const configExtension = typescript ? "ts" : "mjs";
1548
+ const doculaConfigFile = `${sitePath}/docula.config.${configExtension}`;
1549
+ const doculaConfigFileBuffer = Buffer.from(
1550
+ typescript ? doculaconfigts : doculaconfigmjs,
1551
+ "base64"
1552
+ );
1553
+ fs3.writeFileSync(doculaConfigFile, doculaConfigFileBuffer);
1554
+ const logoBuffer = Buffer.from(logopng, "base64");
1555
+ fs3.writeFileSync(`${sitePath}/logo.png`, logoBuffer);
1556
+ const faviconBuffer = Buffer.from(faviconico, "base64");
1557
+ fs3.writeFileSync(`${sitePath}/favicon.ico`, faviconBuffer);
1558
+ const variablesBuffer = Buffer.from(variablescss, "base64");
1559
+ fs3.writeFileSync(`${sitePath}/variables.css`, variablesBuffer);
1560
+ this._console.log(
1561
+ `docula initialized. Please update the ${doculaConfigFile} file with your site information. In addition, you can replace the image, favicon, and style the site with site.css file.`
1562
+ );
1563
+ }
1564
+ /**
1565
+ * Get the version of the package
1566
+ * @returns {string}
1567
+ */
1568
+ getVersion() {
1569
+ const packageJson = fs3.readFileSync("./package.json", "utf8");
1570
+ const packageObject = JSON.parse(packageJson);
1571
+ return packageObject.version;
1572
+ }
1573
+ /**
1574
+ * Load the config file. Supports both .mjs and .ts config files.
1575
+ * Priority: docula.config.ts > docula.config.mjs
1576
+ * @param {string} sitePath
1577
+ * @returns {Promise<void>}
1578
+ */
1579
+ async loadConfigFile(sitePath) {
1580
+ if (!fs3.existsSync(sitePath)) {
1581
+ return;
1582
+ }
1583
+ const tsConfigFile = `${sitePath}/docula.config.ts`;
1584
+ const mjsConfigFile = `${sitePath}/docula.config.mjs`;
1585
+ if (fs3.existsSync(tsConfigFile)) {
1586
+ const absolutePath = path5.resolve(tsConfigFile);
1587
+ const jiti = createJiti(import.meta.url, {
1588
+ interopDefault: true
1589
+ });
1590
+ this._configFileModule = await jiti.import(absolutePath);
1591
+ return;
1592
+ }
1593
+ if (fs3.existsSync(mjsConfigFile)) {
1594
+ const absolutePath = path5.resolve(mjsConfigFile);
1595
+ this._configFileModule = await import(pathToFileURL(absolutePath).href);
1596
+ }
1597
+ }
1598
+ /**
1599
+ * Serve the site based on the options (port and output path)
1600
+ * @param {DoculaOptions} options
1601
+ * @returns {Promise<void>}
1602
+ */
1603
+ async serve(options) {
1604
+ if (this._server) {
1605
+ this._server.close();
1606
+ }
1607
+ const { port } = options;
1608
+ const { outputPath } = options;
1609
+ const config = {
1610
+ public: outputPath
1611
+ };
1612
+ this._server = http.createServer(
1613
+ async (request, response) => (
1614
+ /* v8 ignore next -- @preserve */
1615
+ handler(request, response, config)
1616
+ )
1617
+ );
1618
+ this._server.listen(port, () => {
1619
+ this._console.log(`Docula \u{1F987} at http://localhost:${port}`);
1620
+ });
1621
+ return this._server;
1622
+ }
1623
+ };
1624
+ export {
1625
+ Writr2 as Writr,
1626
+ Docula as default
1627
+ };
1628
+ /* v8 ignore next -- @preserve */