docula 0.41.0 → 0.41.1
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/docula.d.ts +138 -0
- package/dist/docula.js +1195 -0
- package/package.json +23 -23
- /package/bin/{docula.mjs → docula.js} +0 -0
package/dist/docula.js
ADDED
|
@@ -0,0 +1,1195 @@
|
|
|
1
|
+
// src/docula.ts
|
|
2
|
+
import fs2 from "fs";
|
|
3
|
+
import http from "http";
|
|
4
|
+
import path4 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 fs from "fs";
|
|
13
|
+
import path3 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
|
+
console.log(" Arguments serve:");
|
|
61
|
+
console.log(" -p, --port Set the port number used with serve");
|
|
62
|
+
console.log(" -w, --watch watch for changes and rebuild");
|
|
63
|
+
console.log(
|
|
64
|
+
" -s, --site Set the path where site files are located"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
parseProcessArgv(argv) {
|
|
68
|
+
const command = this.getCommand(argv);
|
|
69
|
+
const arguments_ = this.getArguments(argv);
|
|
70
|
+
return {
|
|
71
|
+
argv,
|
|
72
|
+
command,
|
|
73
|
+
args: arguments_
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
getCommand(argv) {
|
|
77
|
+
for (const argument of argv) {
|
|
78
|
+
switch (argument) {
|
|
79
|
+
case "init": {
|
|
80
|
+
return "init";
|
|
81
|
+
}
|
|
82
|
+
case "build": {
|
|
83
|
+
return "build";
|
|
84
|
+
}
|
|
85
|
+
case "serve": {
|
|
86
|
+
return "serve";
|
|
87
|
+
}
|
|
88
|
+
case "help": {
|
|
89
|
+
return "help";
|
|
90
|
+
}
|
|
91
|
+
case "version": {
|
|
92
|
+
return "version";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
getArguments(argv) {
|
|
98
|
+
const arguments_ = {
|
|
99
|
+
sitePath: "",
|
|
100
|
+
templatePath: "",
|
|
101
|
+
output: "",
|
|
102
|
+
watch: false,
|
|
103
|
+
port: 3e3,
|
|
104
|
+
typescript: false
|
|
105
|
+
};
|
|
106
|
+
for (let i = 0; i < argv.length; i++) {
|
|
107
|
+
const argument = argv[i];
|
|
108
|
+
switch (argument) {
|
|
109
|
+
case "-p":
|
|
110
|
+
case "--port": {
|
|
111
|
+
const portString = argv[i + 1];
|
|
112
|
+
if (portString !== void 0) {
|
|
113
|
+
arguments_.port = Number.parseInt(portString, 10);
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case "-o":
|
|
118
|
+
case "--output": {
|
|
119
|
+
arguments_.output = argv[i + 1];
|
|
120
|
+
arguments_.output = path.join(process.cwd(), arguments_.output);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case "-w":
|
|
124
|
+
case "--watch": {
|
|
125
|
+
arguments_.watch = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case "-s":
|
|
129
|
+
case "--site": {
|
|
130
|
+
arguments_.sitePath = argv[i + 1];
|
|
131
|
+
arguments_.sitePath = path.join(process.cwd(), arguments_.sitePath);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "-t":
|
|
135
|
+
case "--templatePath": {
|
|
136
|
+
arguments_.templatePath = argv[i + 1];
|
|
137
|
+
arguments_.templatePath = path.join(
|
|
138
|
+
process.cwd(),
|
|
139
|
+
arguments_.templatePath
|
|
140
|
+
);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case "--typescript": {
|
|
144
|
+
arguments_.typescript = true;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return arguments_;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/github.ts
|
|
154
|
+
import process2 from "process";
|
|
155
|
+
import { CacheableNet } from "@cacheable/net";
|
|
156
|
+
var Github = class {
|
|
157
|
+
options = {
|
|
158
|
+
api: "https://api.github.com",
|
|
159
|
+
author: "",
|
|
160
|
+
repo: ""
|
|
161
|
+
};
|
|
162
|
+
net;
|
|
163
|
+
constructor(options) {
|
|
164
|
+
this.parseOptions(options);
|
|
165
|
+
this.net = new CacheableNet();
|
|
166
|
+
}
|
|
167
|
+
async getData() {
|
|
168
|
+
const data = {
|
|
169
|
+
releases: {},
|
|
170
|
+
contributors: {}
|
|
171
|
+
};
|
|
172
|
+
data.releases = await this.getReleases();
|
|
173
|
+
data.contributors = await this.getContributors();
|
|
174
|
+
return data;
|
|
175
|
+
}
|
|
176
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
177
|
+
async getReleases() {
|
|
178
|
+
const url = `${this.options.api}/repos/${this.options.author}/${this.options.repo}/releases`;
|
|
179
|
+
let options = {};
|
|
180
|
+
if (process2.env.GITHUB_TOKEN) {
|
|
181
|
+
options = {
|
|
182
|
+
headers: {
|
|
183
|
+
Authorization: `Bearer ${process2.env.GITHUB_TOKEN}`,
|
|
184
|
+
Accept: "application/vnd.github.v3+json"
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const result = await this.net.get(url, options);
|
|
190
|
+
if (result && result.data.length > 0) {
|
|
191
|
+
return this.addAnchorLink(result.data);
|
|
192
|
+
}
|
|
193
|
+
return [];
|
|
194
|
+
} catch (error) {
|
|
195
|
+
const typedError = error;
|
|
196
|
+
if (typedError.response?.status === 404) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Repository ${this.options.author}/${this.options.repo} not found.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
205
|
+
async getContributors() {
|
|
206
|
+
const url = `${this.options.api}/repos/${this.options.author}/${this.options.repo}/contributors`;
|
|
207
|
+
let options = {};
|
|
208
|
+
if (process2.env.GITHUB_TOKEN) {
|
|
209
|
+
options = {
|
|
210
|
+
headers: {
|
|
211
|
+
Authorization: `Bearer ${process2.env.GITHUB_TOKEN}`,
|
|
212
|
+
Accept: "application/vnd.github.v3+json"
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const result = await this.net.get(url, options);
|
|
218
|
+
if (result && result.data.length > 0) {
|
|
219
|
+
return result.data;
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
const typedError = error;
|
|
223
|
+
if (typedError.response?.status === 404) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`Repository ${this.options.author}/${this.options.repo} not found.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
parseOptions(options) {
|
|
232
|
+
if (options.api) {
|
|
233
|
+
this.options.api = options.api;
|
|
234
|
+
}
|
|
235
|
+
this.options.author = options.author;
|
|
236
|
+
this.options.repo = options.repo;
|
|
237
|
+
}
|
|
238
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
239
|
+
addAnchorLink(data) {
|
|
240
|
+
return data.map((release) => {
|
|
241
|
+
const regex = /(?<!]\()(https:\/\/[\w./]+)(?!\))/g;
|
|
242
|
+
release.body = release.body.replaceAll(regex, "[$1]($1)");
|
|
243
|
+
return release;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// src/options.ts
|
|
249
|
+
import path2 from "path";
|
|
250
|
+
import process3 from "process";
|
|
251
|
+
var DoculaOptions = class {
|
|
252
|
+
/**
|
|
253
|
+
* Path to the template directory
|
|
254
|
+
*/
|
|
255
|
+
templatePath = path2.join(import.meta.url, "../../template").replace("file:", "");
|
|
256
|
+
/**
|
|
257
|
+
* Path to the output directory
|
|
258
|
+
*/
|
|
259
|
+
outputPath = path2.join(process3.cwd(), "./dist");
|
|
260
|
+
/**
|
|
261
|
+
* Path to the site directory
|
|
262
|
+
*/
|
|
263
|
+
sitePath = path2.join(process3.cwd(), "./site");
|
|
264
|
+
/**
|
|
265
|
+
* Path to the github repository
|
|
266
|
+
*/
|
|
267
|
+
githubPath = "jaredwray/docula";
|
|
268
|
+
/**
|
|
269
|
+
* Site title
|
|
270
|
+
*/
|
|
271
|
+
siteTitle = "docula";
|
|
272
|
+
/**
|
|
273
|
+
* Site description
|
|
274
|
+
*/
|
|
275
|
+
siteDescription = "Beautiful Website for Your Projects";
|
|
276
|
+
/**
|
|
277
|
+
* Site URL
|
|
278
|
+
*/
|
|
279
|
+
siteUrl = "https://docula.org";
|
|
280
|
+
/**
|
|
281
|
+
* Port to run the server
|
|
282
|
+
*/
|
|
283
|
+
port = 3e3;
|
|
284
|
+
/**
|
|
285
|
+
* Single page website
|
|
286
|
+
*/
|
|
287
|
+
singlePage = true;
|
|
288
|
+
/**
|
|
289
|
+
* Sections
|
|
290
|
+
*/
|
|
291
|
+
sections;
|
|
292
|
+
/**
|
|
293
|
+
* OpenAPI specification URL for API documentation.
|
|
294
|
+
* When provided, creates a dedicated /api page
|
|
295
|
+
* Supports both external URLs (https://...) and relative paths (/openapi.json)
|
|
296
|
+
*/
|
|
297
|
+
openApiUrl;
|
|
298
|
+
constructor(options) {
|
|
299
|
+
if (options) {
|
|
300
|
+
this.parseOptions(options);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
304
|
+
parseOptions(options) {
|
|
305
|
+
if (options.templatePath) {
|
|
306
|
+
this.templatePath = options.templatePath;
|
|
307
|
+
this.templatePath = path2.join(process3.cwd(), this.templatePath);
|
|
308
|
+
}
|
|
309
|
+
if (options.outputPath) {
|
|
310
|
+
this.outputPath = options.outputPath;
|
|
311
|
+
this.githubPath = path2.join(process3.cwd(), this.outputPath);
|
|
312
|
+
}
|
|
313
|
+
if (options.sitePath) {
|
|
314
|
+
this.sitePath = options.sitePath;
|
|
315
|
+
this.sitePath = path2.join(process3.cwd(), this.sitePath);
|
|
316
|
+
}
|
|
317
|
+
if (options.githubPath) {
|
|
318
|
+
this.githubPath = options.githubPath;
|
|
319
|
+
}
|
|
320
|
+
if (options.siteTitle) {
|
|
321
|
+
this.siteTitle = options.siteTitle;
|
|
322
|
+
}
|
|
323
|
+
if (options.siteDescription) {
|
|
324
|
+
this.siteDescription = options.siteDescription;
|
|
325
|
+
}
|
|
326
|
+
if (options.siteUrl) {
|
|
327
|
+
this.siteUrl = options.siteUrl;
|
|
328
|
+
}
|
|
329
|
+
if (options.sections) {
|
|
330
|
+
this.sections = options.sections;
|
|
331
|
+
}
|
|
332
|
+
if (options.port) {
|
|
333
|
+
this.port = options.port;
|
|
334
|
+
}
|
|
335
|
+
if (options.singlePage !== void 0 && typeof options.singlePage === "boolean") {
|
|
336
|
+
this.singlePage = options.singlePage;
|
|
337
|
+
}
|
|
338
|
+
if (options.openApiUrl) {
|
|
339
|
+
this.openApiUrl = options.openApiUrl;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// src/builder.ts
|
|
345
|
+
var DoculaBuilder = class {
|
|
346
|
+
_options = new DoculaOptions();
|
|
347
|
+
_ecto;
|
|
348
|
+
_console = new DoculaConsole();
|
|
349
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
350
|
+
constructor(options, engineOptions) {
|
|
351
|
+
if (options) {
|
|
352
|
+
this._options = options;
|
|
353
|
+
}
|
|
354
|
+
this._ecto = new Ecto(engineOptions);
|
|
355
|
+
}
|
|
356
|
+
get options() {
|
|
357
|
+
return this._options;
|
|
358
|
+
}
|
|
359
|
+
async build() {
|
|
360
|
+
const startTime = Date.now();
|
|
361
|
+
this.validateOptions(this.options);
|
|
362
|
+
const doculaData = {
|
|
363
|
+
siteUrl: this.options.siteUrl,
|
|
364
|
+
siteTitle: this.options.siteTitle,
|
|
365
|
+
siteDescription: this.options.siteDescription,
|
|
366
|
+
sitePath: this.options.sitePath,
|
|
367
|
+
templatePath: this.options.templatePath,
|
|
368
|
+
outputPath: this.options.outputPath,
|
|
369
|
+
githubPath: this.options.githubPath,
|
|
370
|
+
sections: this.options.sections,
|
|
371
|
+
openApiUrl: this.options.openApiUrl
|
|
372
|
+
};
|
|
373
|
+
doculaData.github = await this.getGithubData(this.options.githubPath);
|
|
374
|
+
doculaData.documents = this.getDocuments(
|
|
375
|
+
`${doculaData.sitePath}/docs`,
|
|
376
|
+
doculaData
|
|
377
|
+
);
|
|
378
|
+
doculaData.sections = this.getSections(
|
|
379
|
+
`${doculaData.sitePath}/docs`,
|
|
380
|
+
this.options
|
|
381
|
+
);
|
|
382
|
+
doculaData.hasDocuments = doculaData.documents?.length > 0;
|
|
383
|
+
const changelogPath = `${doculaData.sitePath}/changelog`;
|
|
384
|
+
doculaData.changelogEntries = this.getChangelogEntries(changelogPath);
|
|
385
|
+
doculaData.hasChangelog = doculaData.changelogEntries.length > 0;
|
|
386
|
+
doculaData.templates = await this.getTemplates(
|
|
387
|
+
this.options,
|
|
388
|
+
doculaData.hasDocuments,
|
|
389
|
+
doculaData.hasChangelog
|
|
390
|
+
);
|
|
391
|
+
await this.buildIndexPage(doculaData);
|
|
392
|
+
await this.buildReleasePage(doculaData);
|
|
393
|
+
await this.buildSiteMapPage(doculaData);
|
|
394
|
+
await this.buildRobotsPage(this.options);
|
|
395
|
+
if (doculaData.hasDocuments) {
|
|
396
|
+
await this.buildDocsPages(doculaData);
|
|
397
|
+
}
|
|
398
|
+
if (doculaData.openApiUrl) {
|
|
399
|
+
await this.buildApiPage(doculaData);
|
|
400
|
+
}
|
|
401
|
+
if (doculaData.hasChangelog) {
|
|
402
|
+
await this.buildChangelogPage(doculaData);
|
|
403
|
+
await this.buildChangelogEntryPages(doculaData);
|
|
404
|
+
}
|
|
405
|
+
const siteRelativePath = this.options.sitePath;
|
|
406
|
+
if (fs.existsSync(`${siteRelativePath}/favicon.ico`)) {
|
|
407
|
+
await fs.promises.copyFile(
|
|
408
|
+
`${siteRelativePath}/favicon.ico`,
|
|
409
|
+
`${this.options.outputPath}/favicon.ico`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
if (fs.existsSync(`${siteRelativePath}/logo.svg`)) {
|
|
413
|
+
await fs.promises.copyFile(
|
|
414
|
+
`${siteRelativePath}/logo.svg`,
|
|
415
|
+
`${this.options.outputPath}/logo.svg`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
if (fs.existsSync(`${siteRelativePath}/logo_horizontal.png`)) {
|
|
419
|
+
await fs.promises.copyFile(
|
|
420
|
+
`${siteRelativePath}/logo_horizontal.png`,
|
|
421
|
+
`${this.options.outputPath}/logo_horizontal.png`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
if (fs.existsSync(`${this.options.templatePath}/css`)) {
|
|
425
|
+
this.copyDirectory(
|
|
426
|
+
`${this.options.templatePath}/css`,
|
|
427
|
+
`${this.options.outputPath}/css`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
if (fs.existsSync(`${siteRelativePath}/variables.css`)) {
|
|
431
|
+
await fs.promises.copyFile(
|
|
432
|
+
`${siteRelativePath}/variables.css`,
|
|
433
|
+
`${this.options.outputPath}/css/variables.css`
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
this.copyPublicFolder(siteRelativePath, this.options.outputPath);
|
|
437
|
+
const endTime = Date.now();
|
|
438
|
+
const executionTime = endTime - startTime;
|
|
439
|
+
this._console.log(`Build completed in ${executionTime}ms`);
|
|
440
|
+
}
|
|
441
|
+
validateOptions(options) {
|
|
442
|
+
if (options.githubPath.length < 3) {
|
|
443
|
+
throw new Error("No github options provided");
|
|
444
|
+
}
|
|
445
|
+
if (options.siteDescription.length < 3) {
|
|
446
|
+
throw new Error("No site description options provided");
|
|
447
|
+
}
|
|
448
|
+
if (!options.siteTitle) {
|
|
449
|
+
throw new Error("No site title options provided");
|
|
450
|
+
}
|
|
451
|
+
if (!options.siteUrl) {
|
|
452
|
+
throw new Error("No site url options provided");
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async getGithubData(githubPath) {
|
|
456
|
+
const paths = githubPath.split("/");
|
|
457
|
+
const options = {
|
|
458
|
+
author: paths[0],
|
|
459
|
+
repo: paths[1]
|
|
460
|
+
};
|
|
461
|
+
const github = new Github(options);
|
|
462
|
+
return github.getData();
|
|
463
|
+
}
|
|
464
|
+
async getTemplates(options, hasDocuments, hasChangelog = false) {
|
|
465
|
+
const templates = {
|
|
466
|
+
index: "",
|
|
467
|
+
releases: ""
|
|
468
|
+
};
|
|
469
|
+
if (fs.existsSync(options.templatePath)) {
|
|
470
|
+
const index = await this.getTemplateFile(options.templatePath, "index");
|
|
471
|
+
if (index) {
|
|
472
|
+
templates.index = index;
|
|
473
|
+
}
|
|
474
|
+
const releases = await this.getTemplateFile(
|
|
475
|
+
options.templatePath,
|
|
476
|
+
"releases"
|
|
477
|
+
);
|
|
478
|
+
if (releases) {
|
|
479
|
+
templates.releases = releases;
|
|
480
|
+
}
|
|
481
|
+
const documentPage = hasDocuments ? await this.getTemplateFile(options.templatePath, "docs") : void 0;
|
|
482
|
+
if (documentPage) {
|
|
483
|
+
templates.docPage = documentPage;
|
|
484
|
+
}
|
|
485
|
+
const apiPage = options.openApiUrl ? await this.getTemplateFile(options.templatePath, "api") : void 0;
|
|
486
|
+
if (apiPage) {
|
|
487
|
+
templates.api = apiPage;
|
|
488
|
+
}
|
|
489
|
+
const changelogPage = hasChangelog ? await this.getTemplateFile(options.templatePath, "changelog") : void 0;
|
|
490
|
+
if (changelogPage) {
|
|
491
|
+
templates.changelog = changelogPage;
|
|
492
|
+
}
|
|
493
|
+
const changelogEntryPage = hasChangelog ? await this.getTemplateFile(options.templatePath, "changelog-entry") : void 0;
|
|
494
|
+
if (changelogEntryPage) {
|
|
495
|
+
templates.changelogEntry = changelogEntryPage;
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
498
|
+
throw new Error(`No template path found at ${options.templatePath}`);
|
|
499
|
+
}
|
|
500
|
+
return templates;
|
|
501
|
+
}
|
|
502
|
+
async getTemplateFile(path5, name) {
|
|
503
|
+
let result;
|
|
504
|
+
const files = await fs.promises.readdir(path5);
|
|
505
|
+
for (const file of files) {
|
|
506
|
+
const fileName = file.split(".");
|
|
507
|
+
if (fileName[0].toString().toLowerCase() === name.toLowerCase()) {
|
|
508
|
+
result = file.toString();
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return result;
|
|
513
|
+
}
|
|
514
|
+
async buildRobotsPage(options) {
|
|
515
|
+
const { sitePath } = options;
|
|
516
|
+
const { outputPath } = options;
|
|
517
|
+
const robotsPath = `${outputPath}/robots.txt`;
|
|
518
|
+
await fs.promises.mkdir(outputPath, { recursive: true });
|
|
519
|
+
await (fs.existsSync(`${sitePath}/robots.txt`) ? fs.promises.copyFile(`${sitePath}/robots.txt`, robotsPath) : fs.promises.writeFile(robotsPath, "User-agent: *\nDisallow:"));
|
|
520
|
+
}
|
|
521
|
+
async buildSiteMapPage(data) {
|
|
522
|
+
const sitemapPath = `${data.outputPath}/sitemap.xml`;
|
|
523
|
+
const urls = [{ url: data.siteUrl }, { url: `${data.siteUrl}/releases` }];
|
|
524
|
+
if (data.openApiUrl && data.templates?.api) {
|
|
525
|
+
urls.push({ url: `${data.siteUrl}/api` });
|
|
526
|
+
}
|
|
527
|
+
if (data.hasChangelog && data.templates?.changelog) {
|
|
528
|
+
urls.push({ url: `${data.siteUrl}/changelog` });
|
|
529
|
+
for (const entry of data.changelogEntries ?? []) {
|
|
530
|
+
urls.push({
|
|
531
|
+
url: `${data.siteUrl}/changelog/${entry.slug}`
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
for (const document of data.documents ?? []) {
|
|
536
|
+
let { urlPath } = document;
|
|
537
|
+
if (urlPath.endsWith("index.html")) {
|
|
538
|
+
urlPath = urlPath.slice(0, -10);
|
|
539
|
+
}
|
|
540
|
+
urls.push({ url: `${data.siteUrl}${urlPath}` });
|
|
541
|
+
}
|
|
542
|
+
let xml = '<?xml version="1.0" encoding="UTF-8"?>';
|
|
543
|
+
xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
|
|
544
|
+
for (const { url } of urls) {
|
|
545
|
+
xml += "<url>";
|
|
546
|
+
xml += `<loc>${url}</loc>`;
|
|
547
|
+
xml += "</url>";
|
|
548
|
+
}
|
|
549
|
+
xml += "</urlset>";
|
|
550
|
+
await fs.promises.mkdir(data.outputPath, { recursive: true });
|
|
551
|
+
await fs.promises.writeFile(sitemapPath, xml, "utf8");
|
|
552
|
+
}
|
|
553
|
+
async buildIndexPage(data) {
|
|
554
|
+
if (data.templates) {
|
|
555
|
+
const indexPath = `${data.outputPath}/index.html`;
|
|
556
|
+
await fs.promises.mkdir(data.outputPath, { recursive: true });
|
|
557
|
+
const indexTemplate = `${data.templatePath}/${data.templates.index}`;
|
|
558
|
+
let content;
|
|
559
|
+
if (!data.hasDocuments) {
|
|
560
|
+
content = await this.buildReadmeSection(data);
|
|
561
|
+
}
|
|
562
|
+
const announcement = await this.buildAnnouncementSection(data);
|
|
563
|
+
const indexContent = await this._ecto.renderFromFile(
|
|
564
|
+
indexTemplate,
|
|
565
|
+
{ ...data, content, announcement },
|
|
566
|
+
data.templatePath
|
|
567
|
+
);
|
|
568
|
+
await fs.promises.writeFile(indexPath, indexContent, "utf8");
|
|
569
|
+
} else {
|
|
570
|
+
throw new Error("No templates found");
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
async buildReleasePage(data) {
|
|
574
|
+
if (data.github && data.templates) {
|
|
575
|
+
const releasesPath = `${data.outputPath}/releases/index.html`;
|
|
576
|
+
const releaseOutputPath = `${data.outputPath}/releases`;
|
|
577
|
+
await fs.promises.mkdir(releaseOutputPath, { recursive: true });
|
|
578
|
+
const releasesTemplate = `${data.templatePath}/${data.templates.releases}`;
|
|
579
|
+
const releasesContent = await this._ecto.renderFromFile(
|
|
580
|
+
releasesTemplate,
|
|
581
|
+
data,
|
|
582
|
+
data.templatePath
|
|
583
|
+
);
|
|
584
|
+
await fs.promises.writeFile(releasesPath, releasesContent, "utf8");
|
|
585
|
+
} else {
|
|
586
|
+
throw new Error("No github data found");
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
async buildReadmeSection(data) {
|
|
590
|
+
let htmlReadme = "";
|
|
591
|
+
if (fs.existsSync(`${data.sitePath}/README.md`)) {
|
|
592
|
+
const readmeContent = fs.readFileSync(
|
|
593
|
+
`${data.sitePath}/README.md`,
|
|
594
|
+
"utf8"
|
|
595
|
+
);
|
|
596
|
+
htmlReadme = await new Writr(readmeContent).render();
|
|
597
|
+
}
|
|
598
|
+
return htmlReadme;
|
|
599
|
+
}
|
|
600
|
+
async buildAnnouncementSection(data) {
|
|
601
|
+
const announcementPath = `${data.sitePath}/announcement.md`;
|
|
602
|
+
if (fs.existsSync(announcementPath)) {
|
|
603
|
+
const announcementContent = fs.readFileSync(announcementPath, "utf8");
|
|
604
|
+
return new Writr(announcementContent).render();
|
|
605
|
+
}
|
|
606
|
+
return void 0;
|
|
607
|
+
}
|
|
608
|
+
async buildDocsPages(data) {
|
|
609
|
+
if (data.templates && data.documents?.length) {
|
|
610
|
+
const documentsTemplate = `${data.templatePath}/${data.templates.docPage}`;
|
|
611
|
+
await fs.promises.mkdir(`${data.outputPath}/docs`, { recursive: true });
|
|
612
|
+
data.sidebarItems = this.generateSidebarItems(data);
|
|
613
|
+
const promises = data.documents.map(async (document) => {
|
|
614
|
+
const folder = document.urlPath.split("/").slice(0, -1).join("/");
|
|
615
|
+
await fs.promises.mkdir(`${data.outputPath}/${folder}`, {
|
|
616
|
+
recursive: true
|
|
617
|
+
});
|
|
618
|
+
const slug = `${data.outputPath}${document.urlPath}`;
|
|
619
|
+
const documentContent = await this._ecto.renderFromFile(
|
|
620
|
+
documentsTemplate,
|
|
621
|
+
{ ...data, ...document },
|
|
622
|
+
data.templatePath
|
|
623
|
+
);
|
|
624
|
+
return fs.promises.writeFile(slug, documentContent, "utf8");
|
|
625
|
+
});
|
|
626
|
+
await Promise.all(promises);
|
|
627
|
+
} else {
|
|
628
|
+
throw new Error("No templates found");
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
async buildApiPage(data) {
|
|
632
|
+
if (!data.openApiUrl || !data.templates?.api) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const apiPath = `${data.outputPath}/api/index.html`;
|
|
636
|
+
const apiOutputPath = `${data.outputPath}/api`;
|
|
637
|
+
await fs.promises.mkdir(apiOutputPath, { recursive: true });
|
|
638
|
+
const apiTemplate = `${data.templatePath}/${data.templates.api}`;
|
|
639
|
+
const apiContent = await this._ecto.renderFromFile(
|
|
640
|
+
apiTemplate,
|
|
641
|
+
{ ...data, specUrl: data.openApiUrl },
|
|
642
|
+
data.templatePath
|
|
643
|
+
);
|
|
644
|
+
await fs.promises.writeFile(apiPath, apiContent, "utf8");
|
|
645
|
+
}
|
|
646
|
+
getChangelogEntries(changelogPath) {
|
|
647
|
+
const entries = [];
|
|
648
|
+
if (!fs.existsSync(changelogPath)) {
|
|
649
|
+
return entries;
|
|
650
|
+
}
|
|
651
|
+
const files = fs.readdirSync(changelogPath);
|
|
652
|
+
for (const file of files) {
|
|
653
|
+
const filePath = `${changelogPath}/${file}`;
|
|
654
|
+
const stats = fs.statSync(filePath);
|
|
655
|
+
if (stats.isFile() && (file.endsWith(".md") || file.endsWith(".mdx"))) {
|
|
656
|
+
const entry = this.parseChangelogEntry(filePath);
|
|
657
|
+
entries.push(entry);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
entries.sort((a, b) => {
|
|
661
|
+
const dateA = new Date(a.date).getTime();
|
|
662
|
+
const dateB = new Date(b.date).getTime();
|
|
663
|
+
if (Number.isNaN(dateA) && Number.isNaN(dateB)) {
|
|
664
|
+
return 0;
|
|
665
|
+
}
|
|
666
|
+
if (Number.isNaN(dateA)) {
|
|
667
|
+
return 1;
|
|
668
|
+
}
|
|
669
|
+
if (Number.isNaN(dateB)) {
|
|
670
|
+
return -1;
|
|
671
|
+
}
|
|
672
|
+
return dateB - dateA;
|
|
673
|
+
});
|
|
674
|
+
return entries;
|
|
675
|
+
}
|
|
676
|
+
parseChangelogEntry(filePath) {
|
|
677
|
+
const fileContent = fs.readFileSync(filePath, "utf8");
|
|
678
|
+
const writr = new Writr(fileContent);
|
|
679
|
+
const matterData = writr.frontMatter;
|
|
680
|
+
const markdownContent = writr.body;
|
|
681
|
+
const fileName = path3.basename(filePath, path3.extname(filePath));
|
|
682
|
+
const slug = fileName.replace(/^\d{4}-\d{2}-\d{2}-/, "");
|
|
683
|
+
const isMdx = filePath.endsWith(".mdx");
|
|
684
|
+
const tag = matterData.tag;
|
|
685
|
+
const tagClass = tag ? tag.toLowerCase().replace(/\s+/g, "-") : void 0;
|
|
686
|
+
let dateString = "";
|
|
687
|
+
if (matterData.date instanceof Date) {
|
|
688
|
+
dateString = matterData.date.toISOString().split("T")[0];
|
|
689
|
+
} else if (matterData.date) {
|
|
690
|
+
dateString = String(matterData.date);
|
|
691
|
+
}
|
|
692
|
+
let formattedDate = dateString;
|
|
693
|
+
const parsedDate = new Date(dateString);
|
|
694
|
+
if (!Number.isNaN(parsedDate.getTime())) {
|
|
695
|
+
formattedDate = parsedDate.toLocaleDateString("en-US", {
|
|
696
|
+
year: "numeric",
|
|
697
|
+
month: "long",
|
|
698
|
+
day: "numeric"
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
title: matterData.title ?? fileName,
|
|
703
|
+
date: dateString,
|
|
704
|
+
formattedDate,
|
|
705
|
+
tag,
|
|
706
|
+
tagClass,
|
|
707
|
+
slug,
|
|
708
|
+
content: markdownContent,
|
|
709
|
+
generatedHtml: new Writr(markdownContent).renderSync({ mdx: isMdx }),
|
|
710
|
+
urlPath: `/changelog/${slug}/index.html`
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
async buildChangelogPage(data) {
|
|
714
|
+
if (!data.hasChangelog || !data.templates?.changelog) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const changelogOutputPath = `${data.outputPath}/changelog`;
|
|
718
|
+
const changelogIndexPath = `${changelogOutputPath}/index.html`;
|
|
719
|
+
await fs.promises.mkdir(changelogOutputPath, { recursive: true });
|
|
720
|
+
const changelogTemplate = `${data.templatePath}/${data.templates.changelog}`;
|
|
721
|
+
const changelogContent = await this._ecto.renderFromFile(
|
|
722
|
+
changelogTemplate,
|
|
723
|
+
{ ...data, entries: data.changelogEntries },
|
|
724
|
+
data.templatePath
|
|
725
|
+
);
|
|
726
|
+
await fs.promises.writeFile(changelogIndexPath, changelogContent, "utf8");
|
|
727
|
+
}
|
|
728
|
+
async buildChangelogEntryPages(data) {
|
|
729
|
+
if (!data.hasChangelog || !data.templates?.changelogEntry || !data.changelogEntries?.length) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
const entryTemplate = `${data.templatePath}/${data.templates.changelogEntry}`;
|
|
733
|
+
const promises = data.changelogEntries.map(async (entry) => {
|
|
734
|
+
const entryOutputPath = `${data.outputPath}/changelog/${entry.slug}`;
|
|
735
|
+
await fs.promises.mkdir(entryOutputPath, { recursive: true });
|
|
736
|
+
const entryContent = await this._ecto.renderFromFile(
|
|
737
|
+
entryTemplate,
|
|
738
|
+
{ ...data, ...entry, entries: data.changelogEntries },
|
|
739
|
+
data.templatePath
|
|
740
|
+
);
|
|
741
|
+
const entryFilePath = `${entryOutputPath}/index.html`;
|
|
742
|
+
return fs.promises.writeFile(entryFilePath, entryContent, "utf8");
|
|
743
|
+
});
|
|
744
|
+
await Promise.all(promises);
|
|
745
|
+
}
|
|
746
|
+
generateSidebarItems(data) {
|
|
747
|
+
let sidebarItems = [...data.sections ?? []];
|
|
748
|
+
for (const document of data.documents ?? []) {
|
|
749
|
+
if (document.isRoot) {
|
|
750
|
+
sidebarItems.unshift({
|
|
751
|
+
path: document.urlPath.replace("index.html", ""),
|
|
752
|
+
name: document.navTitle,
|
|
753
|
+
order: document.order
|
|
754
|
+
});
|
|
755
|
+
} else {
|
|
756
|
+
const relativeFilePath = document.documentPath.replace(
|
|
757
|
+
`${data.sitePath}/docs/`,
|
|
758
|
+
""
|
|
759
|
+
);
|
|
760
|
+
const sectionPath = relativeFilePath.slice(
|
|
761
|
+
0,
|
|
762
|
+
Math.max(0, relativeFilePath.lastIndexOf("/"))
|
|
763
|
+
);
|
|
764
|
+
const documentSection = document.section ?? sectionPath;
|
|
765
|
+
const sectionIndex = sidebarItems.findIndex(
|
|
766
|
+
(section) => section.path === documentSection
|
|
767
|
+
);
|
|
768
|
+
if (sectionIndex === -1) {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
sidebarItems[sectionIndex].children ??= [];
|
|
772
|
+
sidebarItems[sectionIndex].children.push({
|
|
773
|
+
path: document.urlPath.replace("index.html", ""),
|
|
774
|
+
name: document.navTitle,
|
|
775
|
+
order: document.order
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
sidebarItems = sidebarItems.map((section) => {
|
|
780
|
+
if (section.children) {
|
|
781
|
+
section.children.sort(
|
|
782
|
+
(a, b) => (
|
|
783
|
+
// biome-ignore lint/style/noNonNullAssertion: need to fix
|
|
784
|
+
(a.order ?? section.children.length) - // biome-ignore lint/style/noNonNullAssertion: need to fix
|
|
785
|
+
(b.order ?? section.children.length)
|
|
786
|
+
)
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
return section;
|
|
790
|
+
});
|
|
791
|
+
sidebarItems.sort(
|
|
792
|
+
(a, b) => (a.order ?? sidebarItems.length) - (b.order ?? sidebarItems.length)
|
|
793
|
+
);
|
|
794
|
+
return sidebarItems;
|
|
795
|
+
}
|
|
796
|
+
getDocuments(sitePath, doculaData) {
|
|
797
|
+
let documents = [];
|
|
798
|
+
if (fs.existsSync(sitePath)) {
|
|
799
|
+
documents = this.getDocumentInDirectory(sitePath);
|
|
800
|
+
doculaData.sections = this.getSections(sitePath, this.options);
|
|
801
|
+
for (const section of doculaData.sections) {
|
|
802
|
+
const sectionPath = `${sitePath}/${section.path}`;
|
|
803
|
+
const sectionDocuments = this.getDocumentInDirectory(sectionPath);
|
|
804
|
+
documents = [...documents, ...sectionDocuments];
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
return documents;
|
|
808
|
+
}
|
|
809
|
+
getDocumentInDirectory(sitePath) {
|
|
810
|
+
const documents = [];
|
|
811
|
+
const documentList = fs.readdirSync(sitePath);
|
|
812
|
+
if (documentList.length > 0) {
|
|
813
|
+
for (const document of documentList) {
|
|
814
|
+
const documentPath = `${sitePath}/${document}`;
|
|
815
|
+
const stats = fs.statSync(documentPath);
|
|
816
|
+
if (stats.isFile()) {
|
|
817
|
+
const documentData = this.parseDocumentData(documentPath);
|
|
818
|
+
documents.push(documentData);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
documents.sort(
|
|
823
|
+
(a, b) => (a.order ?? documents.length) - (b.order ?? documents.length)
|
|
824
|
+
);
|
|
825
|
+
return documents;
|
|
826
|
+
}
|
|
827
|
+
getSections(sitePath, doculaOptions) {
|
|
828
|
+
const sections = [];
|
|
829
|
+
if (fs.existsSync(sitePath)) {
|
|
830
|
+
const documentList = fs.readdirSync(sitePath);
|
|
831
|
+
if (documentList.length > 0) {
|
|
832
|
+
for (const document of documentList) {
|
|
833
|
+
const documentPath = `${sitePath}/${document}`;
|
|
834
|
+
const stats = fs.statSync(documentPath);
|
|
835
|
+
if (stats.isDirectory()) {
|
|
836
|
+
const section = {
|
|
837
|
+
name: document.replaceAll("-", " ").replaceAll(/\b\w/g, (l) => l.toUpperCase()),
|
|
838
|
+
path: document
|
|
839
|
+
};
|
|
840
|
+
this.mergeSectionWithOptions(section, doculaOptions);
|
|
841
|
+
sections.push(section);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
sections.sort(
|
|
846
|
+
(a, b) => (a.order ?? sections.length) - (b.order ?? sections.length)
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
return sections;
|
|
850
|
+
}
|
|
851
|
+
mergeSectionWithOptions(section, options) {
|
|
852
|
+
if (options.sections) {
|
|
853
|
+
const sectionOptions = options.sections.find(
|
|
854
|
+
(sectionOption) => sectionOption.path === section.path
|
|
855
|
+
);
|
|
856
|
+
if (sectionOptions) {
|
|
857
|
+
section.name = sectionOptions.name;
|
|
858
|
+
section.order = sectionOptions.order;
|
|
859
|
+
section.path = sectionOptions.path;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return section;
|
|
863
|
+
}
|
|
864
|
+
parseDocumentData(documentPath) {
|
|
865
|
+
const documentContent = fs.readFileSync(documentPath, "utf8");
|
|
866
|
+
const writr = new Writr(documentContent);
|
|
867
|
+
const matterData = writr.frontMatter;
|
|
868
|
+
let markdownContent = writr.body;
|
|
869
|
+
markdownContent = markdownContent.replace(/^# .*\n/, "");
|
|
870
|
+
const isMdx = documentPath.endsWith(".mdx");
|
|
871
|
+
const fileExtension = isMdx ? ".mdx" : ".md";
|
|
872
|
+
const documentsFolderIndex = documentPath.lastIndexOf("/docs/");
|
|
873
|
+
let urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, "/index.html");
|
|
874
|
+
let isRoot = urlPath.split("/").length === 3;
|
|
875
|
+
if (!documentPath.slice(documentsFolderIndex + 6).includes("/")) {
|
|
876
|
+
isRoot = true;
|
|
877
|
+
const filePath = documentPath.slice(documentsFolderIndex + 6);
|
|
878
|
+
if (filePath === "index.md" || filePath === "index.mdx") {
|
|
879
|
+
urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, ".html");
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
if (!this.hasTableOfContents(markdownContent)) {
|
|
883
|
+
markdownContent = `## Table of Contents
|
|
884
|
+
|
|
885
|
+
${markdownContent}`;
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
title: matterData.title,
|
|
889
|
+
navTitle: matterData.navTitle ?? matterData.title,
|
|
890
|
+
description: matterData.description ?? "",
|
|
891
|
+
order: matterData.order ?? void 0,
|
|
892
|
+
section: matterData.section ?? void 0,
|
|
893
|
+
keywords: matterData.keywords ?? [],
|
|
894
|
+
content: documentContent,
|
|
895
|
+
markdown: markdownContent,
|
|
896
|
+
generatedHtml: new Writr(markdownContent).renderSync({
|
|
897
|
+
toc: true,
|
|
898
|
+
mdx: isMdx
|
|
899
|
+
}),
|
|
900
|
+
documentPath,
|
|
901
|
+
urlPath,
|
|
902
|
+
isRoot
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
hasTableOfContents(markdown) {
|
|
906
|
+
const normalized = markdown.replace(/\r\n/g, "\n");
|
|
907
|
+
const atxHeading = /^#{1,6}\s*(table of contents|toc)\s*$/im;
|
|
908
|
+
const setextHeading = /^(table of contents|toc)\s*\n[-=]{2,}\s*$/im;
|
|
909
|
+
const htmlHeading = /<h[1-6][^>]*>\s*(table of contents|toc)\s*<\/h[1-6]>/i;
|
|
910
|
+
return atxHeading.test(normalized) || setextHeading.test(normalized) || htmlHeading.test(normalized);
|
|
911
|
+
}
|
|
912
|
+
copyDirectory(source, target) {
|
|
913
|
+
const files = fs.readdirSync(source);
|
|
914
|
+
for (const file of files) {
|
|
915
|
+
if (file.startsWith(".")) {
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
const sourcePath = `${source}/${file}`;
|
|
919
|
+
const targetPath = `${target}/${file}`;
|
|
920
|
+
const stat = fs.lstatSync(sourcePath);
|
|
921
|
+
if (stat.isDirectory()) {
|
|
922
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
923
|
+
this.copyDirectory(sourcePath, targetPath);
|
|
924
|
+
} else {
|
|
925
|
+
fs.mkdirSync(target, { recursive: true });
|
|
926
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
copyPublicFolder(sitePath, outputPath) {
|
|
931
|
+
const publicPath = `${sitePath}/public`;
|
|
932
|
+
if (!fs.existsSync(publicPath)) {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
this._console.log("Public folder found, copying contents to dist...");
|
|
936
|
+
const resolvedOutputPath = path3.resolve(outputPath);
|
|
937
|
+
this.copyPublicDirectory(
|
|
938
|
+
publicPath,
|
|
939
|
+
outputPath,
|
|
940
|
+
publicPath,
|
|
941
|
+
resolvedOutputPath
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
copyPublicDirectory(source, target, basePath, outputPath) {
|
|
945
|
+
const files = fs.readdirSync(source);
|
|
946
|
+
for (const file of files) {
|
|
947
|
+
const sourcePath = `${source}/${file}`;
|
|
948
|
+
const targetPath = `${target}/${file}`;
|
|
949
|
+
const relativePath = sourcePath.replace(`${basePath}/`, "");
|
|
950
|
+
const resolvedSourcePath = path3.resolve(sourcePath);
|
|
951
|
+
if (resolvedSourcePath === outputPath || resolvedSourcePath.startsWith(`${outputPath}${path3.sep}`)) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
const stat = fs.lstatSync(sourcePath);
|
|
955
|
+
if (stat.isDirectory()) {
|
|
956
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
957
|
+
this.copyPublicDirectory(sourcePath, targetPath, basePath, outputPath);
|
|
958
|
+
} else {
|
|
959
|
+
fs.mkdirSync(target, { recursive: true });
|
|
960
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
961
|
+
this._console.log(` Copied: ${relativePath}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
// src/init.ts
|
|
968
|
+
var doculaconfigmjs = "ZXhwb3J0IGNvbnN0IG9wdGlvbnMgPSB7Cgl0ZW1wbGF0ZVBhdGg6ICcuL3RlbXBsYXRlJywKCW91dHB1dFBhdGg6ICcuL2Rpc3QnLAoJc2l0ZVBhdGg6ICcuL3NpdGUnLAoJZ2l0aHViUGF0aDogJ2phcmVkd3JheS9kb2N1bGEnLAoJc2l0ZVRpdGxlOiAnRG9jdWxhJywKCXNpdGVEZXNjcmlwdGlvbjogJ0JlYXV0aWZ1bCBXZWJzaXRlIGZvciBZb3VyIFByb2plY3RzJywKCXNpdGVVcmw6ICdodHRwczovL2RvY3VsYS5vcmcnLAp9OwoK";
|
|
969
|
+
var doculaconfigts = "aW1wb3J0IHR5cGUgeyBEb2N1bGFPcHRpb25zIH0gZnJvbSAnZG9jdWxhJzsKCmV4cG9ydCBjb25zdCBvcHRpb25zOiBQYXJ0aWFsPERvY3VsYU9wdGlvbnM+ID0gewoJdGVtcGxhdGVQYXRoOiAnLi90ZW1wbGF0ZScsCglvdXRwdXRQYXRoOiAnLi9kaXN0JywKCXNpdGVQYXRoOiAnLi9zaXRlJywKCWdpdGh1YlBhdGg6ICdqYXJlZHdyYXkvZG9jdWxhJywKCXNpdGVUaXRsZTogJ0RvY3VsYScsCglzaXRlRGVzY3JpcHRpb246ICdCZWF1dGlmdWwgV2Vic2l0ZSBmb3IgWW91ciBQcm9qZWN0cycsCglzaXRlVXJsOiAnaHR0cHM6Ly9kb2N1bGEub3JnJywKfTsK";
|
|
970
|
+
var faviconico = "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";
|
|
971
|
+
var logopng = "iVBORw0KGgoAAAANSUhEUgAAAxEAAAHXCAYAAADDSdfmAAAACXBIWXMAACxLAAAsSwGlPZapAAAFw2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDMgNzkuOTY5MGE4N2ZjLCAyMDI1LzAzLzA2LTIwOjUwOjE2ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjYuNiAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjUtMDUtMThUMTM6MzM6NTgtMDc6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI1LTA1LTE4VDEzOjM2OjE5LTA3OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI1LTA1LTE4VDEzOjM2OjE5LTA3OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5YTc4ZDY2Ny02NjAzLTQwNmUtYTViZC02MjYzMTNjY2VmY2QiIHhtcE1NOkRvY3VtZW50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";
|
|
972
|
+
var variablescss = "OnJvb3QgewogICAgLS1mb250LWZhbWlseTogJ09wZW4gU2FucycsIHNhbnMtc2VyaWY7CiAgCiAgICAtLWNvbG9yLXByaW1hcnk6ICAjMzIyZDNjOwogICAgLS1jb2xvci1zZWNvbmRhcnk6ICM4Y2RjMDA7CiAgICAtLWNvbG9yLXNlY29uZGFyeS1kYXJrOiAjOGNkYzAwOwogICAgLS1jb2xvci10ZXh0OiAjMzIyZDNjOwogIAogICAgLS1iYWNrZ3JvdW5kOiAjZmZmZmZmOwogICAgLS1ob21lLWJhY2tncm91bmQ6ICNmZmZmZmY7CiAgICAtLWhlYWRlci1iYWNrZ3JvdW5kOiAjZmZmZmZmOwogIAogICAgLS1zaWRlYmFyLWJhY2tncm91bmQ6ICNmZmZmZmY7CiAgICAtLXNpZGViYXItdGV4dDogIzMyMmQzYzsKICAgIC0tc2lkZWJhci10ZXh0LWFjdGl2ZTogIzdkNzg4NzsKICAKICAgIC0tYm9yZGVyOiByZ2JhKDIzOCwyMzgsMjQ1LDEpOwogIAogICAgLS1iYWNrZ3JvdW5kLXNlYXJjaC1oaWdobGlnaHQ6IHZhcigtLWNvbG9yLXNlY29uZGFyeS1kYXJrKTsKICAgIC0tY29sb3Itc2VhcmNoLWhpZ2hsaWdodDogI2ZmZmZmZjsKICAgIC0tc2VhcmNoLWlucHV0LWJhY2tncm91bmQ6IHZhcigtLWhlYWRlci1iYWNrZ3JvdW5kKTsKICAKICAgIC0tY29kZTogcmdiYSgyMzgsMjM4LDI0NSwxKTsKICAKICAgIC0tcGFnZWZpbmQtdWktdGV4dDogdmFyKC0tY29sb3ItdGV4dCkgIWltcG9ydGFudDsKICAgIC0tcGFnZWZpbmQtdWktZm9udDogdmFyKC0tZm9udC1mYW1pbHkpICFpbXBvcnRhbnQ7CiAgICAtLXBhZ2VmaW5kLXVpLWJhY2tncm91bmQ6IHZhcigtLWJhY2tncm91bmQpICFpbXBvcnRhbnQ7CiAgICAtLXBhZ2VmaW5kLXVpLWJvcmRlcjogdmFyKC0tYm9yZGVyKSAhaW1wb3J0YW50OwogICAgLS1wYWdlZmluZC11aS1zY2FsZTogLjkgIWltcG9ydGFudDsKICB9";
|
|
973
|
+
|
|
974
|
+
// src/docula.ts
|
|
975
|
+
import { Writr as Writr2 } from "writr";
|
|
976
|
+
var Docula = class {
|
|
977
|
+
_options = new DoculaOptions();
|
|
978
|
+
_console = new DoculaConsole();
|
|
979
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
980
|
+
_configFileModule = {};
|
|
981
|
+
_server;
|
|
982
|
+
/**
|
|
983
|
+
* Initialize the Docula class
|
|
984
|
+
* @param {DoculaOptions} options
|
|
985
|
+
* @returns {void}
|
|
986
|
+
* @constructor
|
|
987
|
+
*/
|
|
988
|
+
constructor(options) {
|
|
989
|
+
if (options) {
|
|
990
|
+
this._options = options;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Get the options
|
|
995
|
+
* @returns {DoculaOptions}
|
|
996
|
+
*/
|
|
997
|
+
get options() {
|
|
998
|
+
return this._options;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Set the options
|
|
1002
|
+
* @param {DoculaOptions} value
|
|
1003
|
+
*/
|
|
1004
|
+
set options(value) {
|
|
1005
|
+
this._options = value;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* The http server used to serve the site
|
|
1009
|
+
* @returns {http.Server | undefined}
|
|
1010
|
+
*/
|
|
1011
|
+
get server() {
|
|
1012
|
+
return this._server;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* The config file module. This is the module that is loaded from the docula.config.ts or docula.config.mjs file
|
|
1016
|
+
* @returns {any}
|
|
1017
|
+
*/
|
|
1018
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
1019
|
+
get configFileModule() {
|
|
1020
|
+
return this._configFileModule;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Check for updates
|
|
1024
|
+
* @returns {void}
|
|
1025
|
+
*/
|
|
1026
|
+
checkForUpdates() {
|
|
1027
|
+
const packageJsonPath = path4.join(process4.cwd(), "package.json");
|
|
1028
|
+
if (fs2.existsSync(packageJsonPath)) {
|
|
1029
|
+
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf8"));
|
|
1030
|
+
updateNotifier({ pkg: packageJson }).notify();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Is the execution process that runs the docula command
|
|
1035
|
+
* @param {NodeJS.Process} process
|
|
1036
|
+
* @returns {Promise<void>}
|
|
1037
|
+
*/
|
|
1038
|
+
async execute(process5) {
|
|
1039
|
+
this.checkForUpdates();
|
|
1040
|
+
const consoleProcess = this._console.parseProcessArgv(process5.argv);
|
|
1041
|
+
this.options.singlePage = this.isSinglePageWebsite(this.options.sitePath);
|
|
1042
|
+
if (consoleProcess.args.sitePath) {
|
|
1043
|
+
this.options.sitePath = consoleProcess.args.sitePath;
|
|
1044
|
+
}
|
|
1045
|
+
await this.loadConfigFile(this.options.sitePath);
|
|
1046
|
+
if (this._configFileModule.options) {
|
|
1047
|
+
this.options.parseOptions(
|
|
1048
|
+
// biome-ignore lint/suspicious/noExplicitAny: need to fix
|
|
1049
|
+
this._configFileModule.options
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
if (this._configFileModule.onPrepare) {
|
|
1053
|
+
try {
|
|
1054
|
+
await this._configFileModule.onPrepare(this.options);
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
this._console.error(error.message);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (consoleProcess.args.output) {
|
|
1060
|
+
this.options.outputPath = consoleProcess.args.output;
|
|
1061
|
+
}
|
|
1062
|
+
switch (consoleProcess.command) {
|
|
1063
|
+
case "init": {
|
|
1064
|
+
this.generateInit(
|
|
1065
|
+
this.options.sitePath,
|
|
1066
|
+
consoleProcess.args.typescript
|
|
1067
|
+
);
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
case "help": {
|
|
1071
|
+
this._console.printHelp();
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
case "version": {
|
|
1075
|
+
this._console.log(this.getVersion());
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
case "serve": {
|
|
1079
|
+
const builder = new DoculaBuilder(this.options);
|
|
1080
|
+
await builder.build();
|
|
1081
|
+
await this.serve(this.options);
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
default: {
|
|
1085
|
+
const builder = new DoculaBuilder(this.options);
|
|
1086
|
+
await builder.build();
|
|
1087
|
+
break;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Checks if the site is a single page website
|
|
1093
|
+
* @param {string} sitePath
|
|
1094
|
+
* @returns {boolean}
|
|
1095
|
+
*/
|
|
1096
|
+
isSinglePageWebsite(sitePath) {
|
|
1097
|
+
const documentationPath = `${sitePath}/docs`;
|
|
1098
|
+
if (!fs2.existsSync(documentationPath)) {
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
1101
|
+
const files = fs2.readdirSync(documentationPath);
|
|
1102
|
+
return files.length === 0;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Generate the init files
|
|
1106
|
+
* @param {string} sitePath
|
|
1107
|
+
* @param {boolean} typescript - If true, generates docula.config.ts instead of docula.config.mjs
|
|
1108
|
+
* @returns {void}
|
|
1109
|
+
*/
|
|
1110
|
+
generateInit(sitePath, typescript = false) {
|
|
1111
|
+
if (!fs2.existsSync(sitePath)) {
|
|
1112
|
+
fs2.mkdirSync(sitePath);
|
|
1113
|
+
}
|
|
1114
|
+
const configExtension = typescript ? "ts" : "mjs";
|
|
1115
|
+
const doculaConfigFile = `${sitePath}/docula.config.${configExtension}`;
|
|
1116
|
+
const doculaConfigFileBuffer = Buffer.from(
|
|
1117
|
+
typescript ? doculaconfigts : doculaconfigmjs,
|
|
1118
|
+
"base64"
|
|
1119
|
+
);
|
|
1120
|
+
fs2.writeFileSync(doculaConfigFile, doculaConfigFileBuffer);
|
|
1121
|
+
const logoBuffer = Buffer.from(logopng, "base64");
|
|
1122
|
+
fs2.writeFileSync(`${sitePath}/logo.png`, logoBuffer);
|
|
1123
|
+
const faviconBuffer = Buffer.from(faviconico, "base64");
|
|
1124
|
+
fs2.writeFileSync(`${sitePath}/favicon.ico`, faviconBuffer);
|
|
1125
|
+
const variablesBuffer = Buffer.from(variablescss, "base64");
|
|
1126
|
+
fs2.writeFileSync(`${sitePath}/variables.css`, variablesBuffer);
|
|
1127
|
+
this._console.log(
|
|
1128
|
+
`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.`
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Get the version of the package
|
|
1133
|
+
* @returns {string}
|
|
1134
|
+
*/
|
|
1135
|
+
getVersion() {
|
|
1136
|
+
const packageJson = fs2.readFileSync("./package.json", "utf8");
|
|
1137
|
+
const packageObject = JSON.parse(packageJson);
|
|
1138
|
+
return packageObject.version;
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Load the config file. Supports both .mjs and .ts config files.
|
|
1142
|
+
* Priority: docula.config.ts > docula.config.mjs
|
|
1143
|
+
* @param {string} sitePath
|
|
1144
|
+
* @returns {Promise<void>}
|
|
1145
|
+
*/
|
|
1146
|
+
async loadConfigFile(sitePath) {
|
|
1147
|
+
if (!fs2.existsSync(sitePath)) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
const tsConfigFile = `${sitePath}/docula.config.ts`;
|
|
1151
|
+
const mjsConfigFile = `${sitePath}/docula.config.mjs`;
|
|
1152
|
+
if (fs2.existsSync(tsConfigFile)) {
|
|
1153
|
+
const absolutePath = path4.resolve(tsConfigFile);
|
|
1154
|
+
const jiti = createJiti(import.meta.url, {
|
|
1155
|
+
interopDefault: true
|
|
1156
|
+
});
|
|
1157
|
+
this._configFileModule = await jiti.import(absolutePath);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (fs2.existsSync(mjsConfigFile)) {
|
|
1161
|
+
const absolutePath = path4.resolve(mjsConfigFile);
|
|
1162
|
+
this._configFileModule = await import(pathToFileURL(absolutePath).href);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Serve the site based on the options (port and output path)
|
|
1167
|
+
* @param {DoculaOptions} options
|
|
1168
|
+
* @returns {Promise<void>}
|
|
1169
|
+
*/
|
|
1170
|
+
async serve(options) {
|
|
1171
|
+
if (this._server) {
|
|
1172
|
+
this._server.close();
|
|
1173
|
+
}
|
|
1174
|
+
const { port } = options;
|
|
1175
|
+
const { outputPath } = options;
|
|
1176
|
+
const config = {
|
|
1177
|
+
public: outputPath
|
|
1178
|
+
};
|
|
1179
|
+
this._server = http.createServer(
|
|
1180
|
+
async (request, response) => (
|
|
1181
|
+
/* v8 ignore next -- @preserve */
|
|
1182
|
+
handler(request, response, config)
|
|
1183
|
+
)
|
|
1184
|
+
);
|
|
1185
|
+
this._server.listen(port, () => {
|
|
1186
|
+
this._console.log(`Docula \u{1F987} at http://localhost:${port}`);
|
|
1187
|
+
});
|
|
1188
|
+
return this._server;
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
export {
|
|
1192
|
+
Writr2 as Writr,
|
|
1193
|
+
Docula as default
|
|
1194
|
+
};
|
|
1195
|
+
/* v8 ignore next -- @preserve */
|