hdoc-tools 0.60.1 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +89 -75
- package/hdoc-build-db.js +275 -275
- package/hdoc-build-embeddings.js +202 -202
- package/hdoc-build-pdf.js +232 -232
- package/hdoc-build.js +14 -6
- package/hdoc-bump.js +4 -2
- package/hdoc-content-routes.js +143 -83
- package/hdoc-create.js +110 -108
- package/hdoc-db.js +114 -114
- package/hdoc-help.js +60 -60
- package/hdoc-init.js +103 -68
- package/hdoc-install-browser.js +145 -145
- package/hdoc-mermaid.js +204 -204
- package/hdoc-module.js +1102 -1079
- package/hdoc-serve.js +13 -7
- package/hdoc-stats.js +9 -9
- package/hdoc-validate-config.js +355 -329
- package/hdoc-validate-interbook.js +321 -0
- package/hdoc-validate.js +1231 -1158
- package/hdoc-ver.js +4 -2
- package/hdoc.js +12 -11
- package/npm-shrinkwrap.json +2 -2
- package/package.json +13 -2
- package/schemas/hdocbook-project.schema.json +20 -0
- package/schemas/hdocbook.schema.json +6 -2
- package/templates/doc-header-non-git.html +19 -19
- package/templates/doc-header.html +26 -26
- package/templates/init/.github/workflows/hdocbuild_onpull.yml +16 -16
- package/templates/init/.github/workflows/hdocbuild_onpush.yml +15 -15
- package/templates/init/LICENSE +21 -21
- package/templates/init/README.md +9 -9
- package/templates/init/_hdocbook/index.md +4 -4
- package/templates/init/gitignore +8 -8
- package/templates/init/resources/README.md +2 -2
- package/templates/pdf/css/custom-block.css +90 -90
- package/templates/pdf/css/fonts.css +221 -221
- package/templates/pdf/css/hdocs-pdf.css +495 -495
- package/templates/pdf/css/vars.css +404 -404
- package/templates/pdf/template-footer.html +19 -19
- package/templates/pdf/template-header.html +37 -37
- package/templates/pdf/template.html +20 -20
- package/templates/pdf-header-non-git.html +12 -12
- package/templates/pdf-header.html +16 -16
- package/ui/content/invalid-hdocbook-json.html +6 -6
- package/ui/content/invalid-hdocbook-json.md +7 -7
- package/ui/css/theme-default/styles/components/content.css +124 -124
- package/ui/css/theme-default/styles/components/sidebar.css +182 -182
- package/ui/css/theme-default/styles/htldoc.layouts.css +310 -310
- package/ui/index.html +419 -419
- package/ui/js/doc.hornbill.js +31 -44
- package/ui/js/mermaid-theme.json +27 -0
- package/hdoc-build-onyx.js +0 -134
- package/templates/mermaid-theme.yaml +0 -28
- package/templates/pdf/fonts/inter-cyrillic copy.woff2 +0 -0
package/hdoc-content-routes.js
CHANGED
|
@@ -33,6 +33,34 @@ function escape_html(str) {
|
|
|
33
33
|
.replace(/>/g, ">");
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Resolve a request URL path against a root directory, refusing anything that
|
|
37
|
+
// escapes the root (path traversal via ../, encoded %2e%2e%2f, backslashes on
|
|
38
|
+
// Windows, or NUL bytes). Returns the absolute resolved path, or null when the
|
|
39
|
+
// URL is malformed or lands outside the root. Both `hdoc serve` (which binds
|
|
40
|
+
// 0.0.0.0 and is LAN-reachable) and `hdoc edit` route raw request URLs through
|
|
41
|
+
// this before touching the filesystem.
|
|
42
|
+
function resolve_within_root(root, url_path) {
|
|
43
|
+
let decoded;
|
|
44
|
+
try {
|
|
45
|
+
decoded = decodeURIComponent(url_path);
|
|
46
|
+
} catch {
|
|
47
|
+
return null; // malformed percent-encoding
|
|
48
|
+
}
|
|
49
|
+
// Drop any query string and reject NUL bytes outright
|
|
50
|
+
decoded = decoded.split("?")[0];
|
|
51
|
+
if (decoded.includes("\0")) return null;
|
|
52
|
+
const resolved_root = path.resolve(root);
|
|
53
|
+
const resolved = path.resolve(resolved_root, `.${path.sep}${decoded.replace(/^[/\\]+/, "")}`);
|
|
54
|
+
if (
|
|
55
|
+
resolved !== resolved_root &&
|
|
56
|
+
!resolved.startsWith(resolved_root + path.sep)
|
|
57
|
+
) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
62
|
+
exports.resolve_within_root = resolve_within_root;
|
|
63
|
+
|
|
36
64
|
// Recursively walk <source_path>/<docId>/_inline building the nav fragment
|
|
37
65
|
// consumed by the viewer's nav-section-component. Subfolders become
|
|
38
66
|
// expandable container nodes (items, no link); files become leaf links.
|
|
@@ -94,6 +122,30 @@ exports.create_content_handler = (ctx) => {
|
|
|
94
122
|
// process_includes resolves include paths relative to the source root.
|
|
95
123
|
const global_source_path = source_path;
|
|
96
124
|
|
|
125
|
+
// Configs are re-read from disk per request so `hdoc serve` / `hdoc edit`
|
|
126
|
+
// pick up edits to hdocbook.json / hdocbook-project.json without a restart.
|
|
127
|
+
// Falls back to the startup copy when a mid-edit save is momentarily
|
|
128
|
+
// invalid JSON.
|
|
129
|
+
function load_json(file_path, fallback) {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(fs.readFileSync(file_path, "utf8"));
|
|
132
|
+
} catch {
|
|
133
|
+
return fallback;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function get_project_config() {
|
|
137
|
+
return load_json(
|
|
138
|
+
path.join(source_path, "hdocbook-project.json"),
|
|
139
|
+
hdocbook_project,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function get_book_config() {
|
|
143
|
+
return load_json(
|
|
144
|
+
path.join(source_path, docId, "hdocbook.json"),
|
|
145
|
+
hdocbook_config,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
97
149
|
// Render markdown SOURCE to HTML through the same pipeline as published output:
|
|
98
150
|
// expand_variables -> process_includes -> markdown-it (+ mermaid, tips, frontmatter).
|
|
99
151
|
//
|
|
@@ -236,45 +288,50 @@ exports.create_content_handler = (ctx) => {
|
|
|
236
288
|
// we will transform to HTML and return that
|
|
237
289
|
//
|
|
238
290
|
// Anything else in this handler will return a 404 error
|
|
239
|
-
function handle_books_request(req, res) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
291
|
+
async function handle_books_request(req, res) {
|
|
292
|
+
try {
|
|
293
|
+
let url = req.url.replace("/_books/", "/");
|
|
294
|
+
|
|
295
|
+
console.log("URL Requested:", url);
|
|
296
|
+
|
|
297
|
+
// Process redirect (config read fresh so redirect edits apply live)
|
|
298
|
+
const project_config = get_project_config();
|
|
299
|
+
if (
|
|
300
|
+
project_config.redirects &&
|
|
301
|
+
Array.isArray(project_config.redirects) &&
|
|
302
|
+
project_config.redirects.length > 0
|
|
303
|
+
) {
|
|
304
|
+
const source_url = url.indexOf("/") === 0 ? url : `/${url}`;
|
|
305
|
+
for (const redir of project_config.redirects) {
|
|
306
|
+
redir.url =
|
|
307
|
+
redir.url.indexOf("/") === 0 ? redir.url : `/${redir.url}`;
|
|
308
|
+
if (
|
|
309
|
+
redir.url === source_url &&
|
|
310
|
+
redir.location &&
|
|
311
|
+
redir.location !== ""
|
|
312
|
+
) {
|
|
313
|
+
url = `${redir.location}`;
|
|
314
|
+
console.log(`Redirecting to ${url}`);
|
|
315
|
+
}
|
|
261
316
|
}
|
|
262
317
|
}
|
|
263
|
-
}
|
|
264
318
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (fs.existsSync(file_path)) {
|
|
270
|
-
// HTML file exists on disk, just return it verbatim
|
|
271
|
-
res.setHeader("Content-Type", "text/html");
|
|
272
|
-
send_file(req, res, file_path);
|
|
273
|
-
return true;
|
|
319
|
+
const file_path = resolve_within_root(source_path, url);
|
|
320
|
+
if (file_path === null) {
|
|
321
|
+
send_content_resource_404(req, res);
|
|
322
|
+
return;
|
|
274
323
|
}
|
|
275
|
-
|
|
324
|
+
|
|
325
|
+
if (path.extname(file_path) === ".html") {
|
|
326
|
+
// 1a. check for html files, and send/transform as required
|
|
327
|
+
if (fs.existsSync(file_path)) {
|
|
328
|
+
// HTML file exists on disk, just return it verbatim
|
|
329
|
+
res.setHeader("Content-Type", "text/html");
|
|
330
|
+
send_file(req, res, file_path);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
276
333
|
if (
|
|
277
|
-
transform_markdown_and_send_html(
|
|
334
|
+
await transform_markdown_and_send_html(
|
|
278
335
|
req,
|
|
279
336
|
res,
|
|
280
337
|
file_path.replace(".html", ".md"),
|
|
@@ -282,22 +339,19 @@ exports.create_content_handler = (ctx) => {
|
|
|
282
339
|
) {
|
|
283
340
|
return;
|
|
284
341
|
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (fs.existsSync(`${file_path}.md`)) {
|
|
295
|
-
if (transform_markdown_and_send_html(req, res, `${file_path}.md`)) {
|
|
342
|
+
} else if (path.extname(file_path) === ".md") {
|
|
343
|
+
// If the markdown file exists, just send to caller as is
|
|
344
|
+
if (fs.existsSync(file_path)) {
|
|
345
|
+
send_content_file(req, res, file_path);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
} else if (path.extname(file_path).length === 0) {
|
|
349
|
+
// 2. If we request a file, without any file extension
|
|
350
|
+
if (await transform_markdown_and_send_html(req, res, `${file_path}.md`)) {
|
|
296
351
|
return;
|
|
297
352
|
}
|
|
298
|
-
} else if (fs.existsSync(path.join(`${file_path}index.md`))) {
|
|
299
353
|
if (
|
|
300
|
-
transform_markdown_and_send_html(
|
|
354
|
+
await transform_markdown_and_send_html(
|
|
301
355
|
req,
|
|
302
356
|
res,
|
|
303
357
|
path.join(file_path, "index.md"),
|
|
@@ -305,55 +359,61 @@ exports.create_content_handler = (ctx) => {
|
|
|
305
359
|
) {
|
|
306
360
|
return;
|
|
307
361
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
362
|
+
if (fs.existsSync(path.join(`${file_path}index.html`))) {
|
|
363
|
+
res.setHeader("Content-Type", "text/html");
|
|
364
|
+
send_content_file(req, res, path.join(`${file_path}index.html`));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (fs.existsSync(path.join(`${file_path}/index.html`))) {
|
|
368
|
+
res.setHeader("Content-Type", "text/html");
|
|
369
|
+
send_content_file(req, res, path.join(`${file_path}/index.html`));
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (fs.existsSync(path.join(`${file_path}.html`))) {
|
|
373
|
+
res.setHeader("Content-Type", "text/html");
|
|
374
|
+
send_content_file(req, res, path.join(`${file_path}.html`));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (fs.existsSync(path.join(`${file_path}.htm`))) {
|
|
378
|
+
res.setHeader("Content-Type", "text/html");
|
|
379
|
+
send_content_file(req, res, path.join(`${file_path}.htm`));
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
} else if (fs.existsSync(file_path)) {
|
|
313
383
|
if (
|
|
314
|
-
|
|
384
|
+
file_path.endsWith("hdocbook.json") ||
|
|
385
|
+
file_path.endsWith("hdocbook_project.json")
|
|
315
386
|
) {
|
|
316
|
-
|
|
387
|
+
try {
|
|
388
|
+
// Read & parse file
|
|
389
|
+
JSON.parse(fs.readFileSync(file_path));
|
|
390
|
+
} catch (e) {
|
|
391
|
+
console.error(`Error parsing hdocbook.json: ${e}`);
|
|
392
|
+
}
|
|
317
393
|
}
|
|
318
|
-
|
|
319
|
-
res.setHeader("Content-Type", "text/html");
|
|
320
|
-
send_content_file(req, res, path.join(`${file_path}/index.html`));
|
|
321
|
-
return;
|
|
322
|
-
} else if (fs.existsSync(path.join(`${file_path}.html`))) {
|
|
323
|
-
res.setHeader("Content-Type", "text/html");
|
|
324
|
-
send_content_file(req, res, path.join(`${file_path}.html`));
|
|
325
|
-
return;
|
|
326
|
-
} else if (fs.existsSync(path.join(`${file_path}.htm`))) {
|
|
327
|
-
res.setHeader("Content-Type", "text/html");
|
|
328
|
-
send_content_file(req, res, path.join(`${file_path}.htm`));
|
|
394
|
+
send_file(req, res, file_path);
|
|
329
395
|
return;
|
|
330
396
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
console.error(`Error parsing hdocbook.json: ${e}`);
|
|
341
|
-
}
|
|
397
|
+
|
|
398
|
+
// Return a 404 error here
|
|
399
|
+
send_content_resource_404(req, res);
|
|
400
|
+
} catch (e) {
|
|
401
|
+
// A markdown render failure (bad include, plugin throw, etc.) lands
|
|
402
|
+
// here rather than as an unhandled promise rejection.
|
|
403
|
+
console.error(`Error handling content request ${req.url}:`, e);
|
|
404
|
+
if (!res.headersSent) {
|
|
405
|
+
res.status(500).send("Error rendering content");
|
|
342
406
|
}
|
|
343
|
-
send_file(req, res, file_path);
|
|
344
|
-
return;
|
|
345
407
|
}
|
|
346
|
-
|
|
347
|
-
// Return a 404 error here
|
|
348
|
-
send_content_resource_404(req, res);
|
|
349
408
|
}
|
|
350
409
|
|
|
351
410
|
function handle_library_request(req, res) {
|
|
411
|
+
const book_config = get_book_config();
|
|
352
412
|
const library = {
|
|
353
413
|
books: [
|
|
354
414
|
{
|
|
355
|
-
docId:
|
|
356
|
-
title:
|
|
415
|
+
docId: book_config.docId,
|
|
416
|
+
title: book_config.title,
|
|
357
417
|
nav_inline: nav_inline,
|
|
358
418
|
},
|
|
359
419
|
],
|
package/hdoc-create.js
CHANGED
|
@@ -1,108 +1,110 @@
|
|
|
1
|
-
(() => {
|
|
2
|
-
const fs = require("node:fs");
|
|
3
|
-
const path = require("node:path");
|
|
4
|
-
const hdoc = require(path.join(__dirname, "hdoc-module.js"));
|
|
5
|
-
|
|
6
|
-
let doc_id;
|
|
7
|
-
let file_count = 0;
|
|
8
|
-
let folder_count = 0;
|
|
9
|
-
|
|
10
|
-
const processed_links = {};
|
|
11
|
-
|
|
12
|
-
exports.run = async (source_path) => {
|
|
13
|
-
console.log("Hornbill HDocBook Create", "\n");
|
|
14
|
-
console.log("Path:", source_path, "\n");
|
|
15
|
-
|
|
16
|
-
// Load the hdocbook-project.json file to get the docId
|
|
17
|
-
// use the docId to get the book config
|
|
18
|
-
const hdocbook_project_config_path = path.join(
|
|
19
|
-
source_path,
|
|
20
|
-
"hdocbook-project.json",
|
|
21
|
-
);
|
|
22
|
-
let hdocbook_project = {};
|
|
23
|
-
try {
|
|
24
|
-
hdocbook_project =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
nav_paths[key][navkey][i].
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log("
|
|
73
|
-
console.log(
|
|
74
|
-
console.log(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
!fs.existsSync(`${doc_info.path}.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
1
|
+
(() => {
|
|
2
|
+
const fs = require("node:fs");
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
const hdoc = require(path.join(__dirname, "hdoc-module.js"));
|
|
5
|
+
|
|
6
|
+
let doc_id;
|
|
7
|
+
let file_count = 0;
|
|
8
|
+
let folder_count = 0;
|
|
9
|
+
|
|
10
|
+
const processed_links = {};
|
|
11
|
+
|
|
12
|
+
exports.run = async (source_path) => {
|
|
13
|
+
console.log("Hornbill HDocBook Create", "\n");
|
|
14
|
+
console.log("Path:", source_path, "\n");
|
|
15
|
+
|
|
16
|
+
// Load the hdocbook-project.json file to get the docId
|
|
17
|
+
// use the docId to get the book config
|
|
18
|
+
const hdocbook_project_config_path = path.join(
|
|
19
|
+
source_path,
|
|
20
|
+
"hdocbook-project.json",
|
|
21
|
+
);
|
|
22
|
+
let hdocbook_project = {};
|
|
23
|
+
try {
|
|
24
|
+
hdocbook_project = JSON.parse(
|
|
25
|
+
fs.readFileSync(hdocbook_project_config_path, "utf8"),
|
|
26
|
+
);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error(`File not found: ${hdocbook_project_config_path}\n`);
|
|
29
|
+
console.error(
|
|
30
|
+
"hdoc create needs to be run in the root of a HDoc Book.\n",
|
|
31
|
+
);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
doc_id = hdocbook_project.docId;
|
|
35
|
+
|
|
36
|
+
const book_path = path.join(source_path, doc_id);
|
|
37
|
+
const hdocbook_path = path.join(book_path, "hdocbook.json");
|
|
38
|
+
|
|
39
|
+
let hdocbook = {};
|
|
40
|
+
try {
|
|
41
|
+
hdocbook = JSON.parse(fs.readFileSync(hdocbook_path, "utf8"));
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error(`File not found: ${hdocbook_path}\n`);
|
|
44
|
+
console.error(
|
|
45
|
+
"hdoc create needs to be run in the root of a HDoc Book.\n",
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Get paths from breadcrumb builder
|
|
51
|
+
const nav_paths = hdoc.build_breadcrumbs(hdocbook.navigation.items);
|
|
52
|
+
for (const key in nav_paths) {
|
|
53
|
+
if (Object.hasOwn(nav_paths, key)) {
|
|
54
|
+
for (const navkey in nav_paths[key]) {
|
|
55
|
+
if (Object.hasOwn(nav_paths[key], navkey)) {
|
|
56
|
+
for (let i = 0; i < nav_paths[key][navkey].length; i++) {
|
|
57
|
+
if (
|
|
58
|
+
nav_paths[key][navkey][i].link &&
|
|
59
|
+
!processed_links[nav_paths[key][navkey][i].link]
|
|
60
|
+
) {
|
|
61
|
+
nav_paths[key][navkey][i].path = path.join(
|
|
62
|
+
source_path,
|
|
63
|
+
nav_paths[key][navkey][i].link,
|
|
64
|
+
);
|
|
65
|
+
await add_doc(nav_paths[key][navkey][i]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.log("\n-----------------------");
|
|
73
|
+
console.log(" Docs Creation Summary");
|
|
74
|
+
console.log("-----------------------\n");
|
|
75
|
+
console.log(` Files Created: ${file_count}`);
|
|
76
|
+
console.log(`Folders Created: ${folder_count}\n`);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const add_doc = async (doc_info) => {
|
|
80
|
+
// Does folder exist? Create if not
|
|
81
|
+
const folder = path.dirname(doc_info.path);
|
|
82
|
+
if (!fs.existsSync(folder)) {
|
|
83
|
+
try {
|
|
84
|
+
fs.mkdirSync(folder, { recursive: true });
|
|
85
|
+
console.log("Folder created:", folder);
|
|
86
|
+
folder_count++;
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("\nError creating folder", folder, ":", e);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Does file exist? Create if not
|
|
94
|
+
if (
|
|
95
|
+
!fs.existsSync(`${doc_info.path}.md`) &&
|
|
96
|
+
!fs.existsSync(`${doc_info.path}.htm`) &&
|
|
97
|
+
!fs.existsSync(`${doc_info.path}.html`)
|
|
98
|
+
) {
|
|
99
|
+
try {
|
|
100
|
+
const file_path = `${doc_info.path}.md`;
|
|
101
|
+
fs.writeFileSync(file_path, `# ${doc_info.text}\n`);
|
|
102
|
+
console.log(" File created:", file_path);
|
|
103
|
+
processed_links[doc_info.link] = true;
|
|
104
|
+
file_count++;
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.error("\nError creating file", doc_info.path, ":", e);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
})();
|