hdoc-tools 0.11.9 → 0.13.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/hdoc-build-db.js +31 -1
- package/hdoc-build.js +72 -16
- package/hdoc-serve.js +18 -4
- package/hdoc-validate.js +48 -2
- package/package.json +1 -1
package/hdoc-build-db.js
CHANGED
@@ -33,6 +33,11 @@
|
|
33
33
|
'name',
|
34
34
|
'avatar UNINDEXED',
|
35
35
|
'url UNINDEXED'
|
36
|
+
],
|
37
|
+
hdoc_redirects: [
|
38
|
+
'resource_url',
|
39
|
+
'location_url',
|
40
|
+
'http_code INTEGER UNINDEXED'
|
36
41
|
]
|
37
42
|
};
|
38
43
|
|
@@ -71,6 +76,31 @@
|
|
71
76
|
return response;
|
72
77
|
};
|
73
78
|
|
79
|
+
exports.populate_redirects = function (db, redirect_records, verbose = false) {
|
80
|
+
let response = {
|
81
|
+
success: true,
|
82
|
+
errors: [],
|
83
|
+
index_success_count: 0
|
84
|
+
};
|
85
|
+
|
86
|
+
for (let i = 0; i < redirect_records.length; i++) {
|
87
|
+
const index_vals = [
|
88
|
+
redirect_records[i].url,
|
89
|
+
redirect_records[i].location ? redirect_records[i].location : '',
|
90
|
+
redirect_records[i].code
|
91
|
+
];
|
92
|
+
const index_response = hdoc_index.insert_record(db, 'hdoc_redirects', db_schema.hdoc_redirects, index_vals);
|
93
|
+
if (!index_response.success) {
|
94
|
+
response.success = false;
|
95
|
+
response.errors.push(`Redirect record creation failed - ${redirect_records[i].url}: ${index_response.error}`);
|
96
|
+
} else {
|
97
|
+
response.index_success_count++
|
98
|
+
}
|
99
|
+
}
|
100
|
+
console.log(`\nRedirect Index Build Complete: ${response.index_success_count} document records created.`);
|
101
|
+
return response;
|
102
|
+
};
|
103
|
+
|
74
104
|
exports.populate_index = async function (db, doc_id, book_config, index_records, verbose = false) {
|
75
105
|
let response = {
|
76
106
|
success: false,
|
@@ -137,7 +167,7 @@
|
|
137
167
|
continue;
|
138
168
|
}
|
139
169
|
if (verbose) {
|
140
|
-
console.log(`Inserted document contributor
|
170
|
+
console.log(`Inserted document contributor record ${cont_response.row_id}`);
|
141
171
|
}
|
142
172
|
}
|
143
173
|
response.index_success_count++;
|
package/hdoc-build.js
CHANGED
@@ -54,6 +54,7 @@
|
|
54
54
|
index_records = [],
|
55
55
|
md_files = [],
|
56
56
|
md_files_delete = [],
|
57
|
+
redirects = {},
|
57
58
|
static_html_files = [],
|
58
59
|
work_path_content = '',
|
59
60
|
verbose = false;
|
@@ -214,6 +215,13 @@
|
|
214
215
|
});
|
215
216
|
}
|
216
217
|
|
218
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath)) {
|
219
|
+
fm_headers.push({
|
220
|
+
id: 'pdf-path',
|
221
|
+
value: file_path.relativePath.replace(path.extname(file_path.relativePath), '.pdf')
|
222
|
+
})
|
223
|
+
}
|
224
|
+
|
217
225
|
let fm_header_content = '<!--[[FRONTMATTER\n';
|
218
226
|
if (fm_headers.length > 0) {
|
219
227
|
for (let i = 0; i < fm_headers.length; i++) {
|
@@ -228,13 +236,20 @@
|
|
228
236
|
|
229
237
|
let doc_header = '';
|
230
238
|
let pdf_header = '';
|
239
|
+
const inline_content = file_path.relativePath.startsWith(`${hdocbook_config.docId}/_inline/`);
|
231
240
|
if (hdocbook_config.publicSource && hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
232
241
|
// Build doc header from template and frontmatter tags
|
233
|
-
|
234
|
-
|
242
|
+
if (!inline_content)
|
243
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template);
|
244
|
+
|
245
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath))
|
246
|
+
pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template);
|
235
247
|
} else {
|
236
|
-
|
237
|
-
|
248
|
+
if (!inline_content)
|
249
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template_non_git);
|
250
|
+
|
251
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath))
|
252
|
+
pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template_non_git);
|
238
253
|
}
|
239
254
|
|
240
255
|
let pdf_size = 0;
|
@@ -248,7 +263,10 @@
|
|
248
263
|
}
|
249
264
|
if (pdf_size > 0) pdf_created++;
|
250
265
|
|
251
|
-
|
266
|
+
if (inline_content)
|
267
|
+
html_txt = `${fm_header_content}\n${html_txt}`;
|
268
|
+
else
|
269
|
+
html_txt = `${fm_header_content}\n${doc_header}\n${html_txt}`;
|
252
270
|
|
253
271
|
index_records.push({
|
254
272
|
relative_path: file_path.relativePath,
|
@@ -430,6 +448,13 @@
|
|
430
448
|
});
|
431
449
|
}
|
432
450
|
|
451
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath)) {
|
452
|
+
fm_headers.push({
|
453
|
+
id: 'pdf-path',
|
454
|
+
value: file_path.relativePath.replace(path.extname(file_path.relativePath), '.pdf')
|
455
|
+
})
|
456
|
+
}
|
457
|
+
|
433
458
|
// Add frontmatter tags as comment
|
434
459
|
let fm_header = '<!--[[FRONTMATTER\n';
|
435
460
|
if (fm_headers.length > 0) {
|
@@ -441,14 +466,21 @@
|
|
441
466
|
|
442
467
|
let doc_header = '';
|
443
468
|
let pdf_header = '';
|
469
|
+
const inline_content = file_path.relativePath.startsWith(`${hdocbook_config.docId}/_inline/`);
|
444
470
|
if (hdocbook_config.publicSource && hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
445
471
|
// Build doc header from template and frontmatter tags
|
446
|
-
|
447
|
-
|
472
|
+
if (!inline_content)
|
473
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template);
|
474
|
+
|
475
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath))
|
476
|
+
pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template);
|
448
477
|
} else {
|
449
478
|
// Build doc header from template and frontmatter tags
|
450
|
-
|
451
|
-
|
479
|
+
if (!inline_content)
|
480
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template_non_git);
|
481
|
+
|
482
|
+
if (pdf_enable && !pdf_path_excluded(file_path.relativePath))
|
483
|
+
pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template_non_git);
|
452
484
|
}
|
453
485
|
|
454
486
|
let pdf_size = 0;
|
@@ -461,7 +493,11 @@
|
|
461
493
|
pdf_size = await hdoc_build_pdf.generate_pdf(browser, pdf_template_path, pdf_template, hdocbook_config, pdf_txt, pdf_file_path, css_templates, verbose);
|
462
494
|
}
|
463
495
|
if (pdf_size > 0) pdf_created++;
|
464
|
-
|
496
|
+
|
497
|
+
if (inline_content)
|
498
|
+
html_txt = `${fm_header}\n${html_txt}`;
|
499
|
+
else
|
500
|
+
html_txt = `${fm_header}\n${doc_header}\n${html_txt}`;
|
465
501
|
|
466
502
|
// Save HTML into HTML file
|
467
503
|
const target_file = file_path.path.replace(path.extname(file_path.path), '.html');
|
@@ -528,7 +564,14 @@
|
|
528
564
|
let bc_tags = '\n';
|
529
565
|
if (bc_for_path) {
|
530
566
|
for (let i = 0; i < bc_for_path.length - 1; i++) {
|
531
|
-
|
567
|
+
let bc_link = '/';
|
568
|
+
if (redirects[bc_for_path[i].link]) {
|
569
|
+
if (redirects[bc_for_path[i].link].location) {
|
570
|
+
bc_link += redirects[bc_for_path[i].link].location;
|
571
|
+
}
|
572
|
+
} else {
|
573
|
+
bc_link = bc_for_path[i].link.startsWith('/') ? bc_for_path[i].link : `/${bc_for_path[i].link}`;
|
574
|
+
}
|
532
575
|
bc_tags += `\t\t\t\t<li class="mt-0 nav-bar-item"><a href="${bc_link}" class="ps-0 pe-0 text-decoration-none">${bc_for_path[i].text}</a></li>\n`;
|
533
576
|
}
|
534
577
|
} else {
|
@@ -622,6 +665,12 @@
|
|
622
665
|
pdf_enable = hdocbook_project.pdfGeneration.enable;
|
623
666
|
}
|
624
667
|
|
668
|
+
if (hdocbook_project.redirects && hdocbook_project.redirects instanceof Array) {
|
669
|
+
for (let i = 0; i < hdocbook_project.redirects.length; i++) {
|
670
|
+
redirects[hdocbook_project.redirects[i].url] = hdocbook_project.redirects[i];
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
625
674
|
console.log(`Loading hdocbook config...`);
|
626
675
|
|
627
676
|
const book_path = path.join(source_path, doc_id),
|
@@ -777,7 +826,6 @@
|
|
777
826
|
}));
|
778
827
|
}
|
779
828
|
|
780
|
-
|
781
829
|
if (pdf_enable) {
|
782
830
|
// Close the Chromium browser instance
|
783
831
|
await browser.close();
|
@@ -796,7 +844,7 @@
|
|
796
844
|
}
|
797
845
|
|
798
846
|
// Validate content
|
799
|
-
const validation_success = await hdoc_validate.run(work_path, doc_id, verbose, hdocbook_config, hdocbook_project, bc, prod_families, prods_supported, gen_exclude);
|
847
|
+
const validation_success = await hdoc_validate.run(work_path, doc_id, verbose, hdocbook_config, hdocbook_project, bc, prod_families, prods_supported, gen_exclude, redirects);
|
800
848
|
if (!validation_success) {
|
801
849
|
const end_time = Date.now();
|
802
850
|
console.log(`\nTime Taken: ${get_duration(start_time, end_time)}\n`);
|
@@ -835,14 +883,22 @@
|
|
835
883
|
console.log(db.error);
|
836
884
|
process.exit(1);
|
837
885
|
}
|
838
|
-
|
886
|
+
// Populate primary index tables
|
839
887
|
const index = await hdoc_build_db.populate_index(db.db, doc_id, hdocbook_config, index_records, verbose);
|
840
888
|
if (!index.success) {
|
841
889
|
console.log(index.error);
|
842
890
|
process.exit(1);
|
843
891
|
}
|
844
|
-
|
845
|
-
|
892
|
+
|
893
|
+
// Populate redirect index table records
|
894
|
+
if (hdocbook_project.redirects && hdocbook_project.redirects instanceof Array && hdocbook_project.redirects.length > 0) {
|
895
|
+
const redirects_index = hdoc_build_db.populate_redirects(db.db, hdocbook_project.redirects, verbose);
|
896
|
+
if (!redirects_index.success) {
|
897
|
+
for (let i = 0; i < index.errors.length; i++) {
|
898
|
+
console.log(index.errors[i]);
|
899
|
+
}
|
900
|
+
process.exit(1);
|
901
|
+
}
|
846
902
|
}
|
847
903
|
|
848
904
|
if (!validate) {
|
package/hdoc-serve.js
CHANGED
@@ -12,7 +12,8 @@
|
|
12
12
|
|
13
13
|
let port = 3000;
|
14
14
|
let docId;
|
15
|
-
let hdocbook_config
|
15
|
+
let hdocbook_config,
|
16
|
+
hdocbook_project;
|
16
17
|
|
17
18
|
exports.run = async function (ui_path, source_path, md) {
|
18
19
|
|
@@ -35,7 +36,7 @@
|
|
35
36
|
console.log(' Server Port:', port);
|
36
37
|
|
37
38
|
if (fs.existsSync(path.join(source_path, 'hdocbook-project.json')) == false) {
|
38
|
-
console.log("No hdocbook-project.
|
39
|
+
console.log("No hdocbook-project.json file found in working folder. Unable to continue.");
|
39
40
|
return -1;
|
40
41
|
}
|
41
42
|
|
@@ -47,7 +48,7 @@
|
|
47
48
|
const hdocbook_project_config_path = path.join(source_path, 'hdocbook-project.json');
|
48
49
|
|
49
50
|
// Load the hdocbook config file
|
50
|
-
|
51
|
+
hdocbook_project = require(hdocbook_project_config_path);
|
51
52
|
|
52
53
|
// Get the ID of the hdocbook we are serving
|
53
54
|
docId = hdocbook_project.docId;
|
@@ -134,8 +135,10 @@
|
|
134
135
|
return false;
|
135
136
|
}
|
136
137
|
|
137
|
-
function send_content_file(req, res, file_path) {
|
138
|
+
function send_content_file(req, res, file_path, redirected = false) {
|
138
139
|
let content_txt = hdoc.expand_variables(fs.readFileSync(file_path).toString(), docId);
|
140
|
+
if (redirected)
|
141
|
+
content_txt = `Redirected from ${redirected}\n\n${content_txt}`;
|
139
142
|
|
140
143
|
let contentType = hdoc.content_type_for_ext(path.extname(file_path));
|
141
144
|
|
@@ -198,6 +201,17 @@
|
|
198
201
|
|
199
202
|
console.log('URL Requested:', url);
|
200
203
|
|
204
|
+
// Process redirect
|
205
|
+
if (hdocbook_project.redirects && hdocbook_project.redirects instanceof Array && hdocbook_project.redirects.length > 0) {
|
206
|
+
const source_url = url.indexOf('/') === 0 ? url.replace('/', '') : url;
|
207
|
+
hdocbook_project.redirects.forEach(function (redir) {
|
208
|
+
if (redir.url === source_url && redir.location && redir.location !== '') {
|
209
|
+
url = `/${redir.location}`;
|
210
|
+
console.log(`Redirecting to ${url}`);
|
211
|
+
}
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
201
215
|
let file_path = path.join(source_path, url);
|
202
216
|
|
203
217
|
if (path.extname(file_path) == '.html') {
|
package/hdoc-validate.js
CHANGED
@@ -27,6 +27,7 @@
|
|
27
27
|
md_to_validate = [],
|
28
28
|
exclude_links = {},
|
29
29
|
exclude_spellcheck = {},
|
30
|
+
redirects = {},
|
30
31
|
exclude_h1_count = {},
|
31
32
|
exclude_spellcheck_output = [];
|
32
33
|
|
@@ -97,6 +98,17 @@
|
|
97
98
|
const key_split = key.split('#');
|
98
99
|
const key_no_hash = key_split[0];
|
99
100
|
|
101
|
+
// See if there's a redirect in place
|
102
|
+
let redirected = false;
|
103
|
+
let redirect_errored = false;
|
104
|
+
const redir = await checkRedirect(source_path, key_no_hash);
|
105
|
+
if (redir.exists && redir.error !== null) {
|
106
|
+
nav_errors.push(redir.error);
|
107
|
+
redirect_errored = true;
|
108
|
+
} else if (redir.exists && redir.error === null) {
|
109
|
+
redirected = true;
|
110
|
+
}
|
111
|
+
|
100
112
|
// Validate path exists - key should be a html file at this point
|
101
113
|
let file_exists = true;
|
102
114
|
let file_name = path.join(source_path, key_no_hash + '.html');
|
@@ -108,13 +120,19 @@
|
|
108
120
|
file_name = path.join(source_path, key_no_hash, 'index.htm');
|
109
121
|
if (!fs.existsSync(file_name)) {
|
110
122
|
file_exists = false;
|
111
|
-
|
123
|
+
if (!redirected && !redirect_errored)
|
124
|
+
nav_errors.push(`Navigation path [${key_no_hash}] file does not exist.`);
|
112
125
|
}
|
113
126
|
}
|
114
127
|
}
|
115
128
|
}
|
116
129
|
|
117
130
|
if (file_exists) {
|
131
|
+
// File exists - but is there a redirect? If so, we want to flag this as an error
|
132
|
+
if (redirected)
|
133
|
+
nav_errors.push(`Navigation path [${key_no_hash}] is redirected, but path still exists.`);
|
134
|
+
|
135
|
+
// Check file path case match
|
118
136
|
const true_file = trueCasePathSync(file_name).replace(source_path, '').replaceAll('\\', '/');
|
119
137
|
const relative_file = file_name.replace(source_path, '').replaceAll('\\', '/');
|
120
138
|
if (true_file !== relative_file) {
|
@@ -175,6 +193,33 @@
|
|
175
193
|
return nav_errors;
|
176
194
|
};
|
177
195
|
|
196
|
+
const checkRedirect = async function (source_path, nav_path) {
|
197
|
+
let response = {
|
198
|
+
exists: false,
|
199
|
+
error: null
|
200
|
+
}
|
201
|
+
if (redirects[nav_path]) {
|
202
|
+
response.exists = true;
|
203
|
+
if (redirects[nav_path].location) {
|
204
|
+
// We have a redirect, check if it's a valid location
|
205
|
+
let file_path = path.join(source_path, redirects[nav_path].location + '.html');
|
206
|
+
if (!fs.existsSync(file_path)) {
|
207
|
+
file_path = path.join(source_path, redirects[nav_path].location + '.htm');
|
208
|
+
if (!fs.existsSync(file_path)) {
|
209
|
+
file_path = path.join(source_path, redirects[nav_path].location, 'index.html');
|
210
|
+
if (!fs.existsSync(file_path)) {
|
211
|
+
file_path = path.join(source_path, redirects[nav_path].location, 'index.htm');
|
212
|
+
if (!fs.existsSync(file_path)) {
|
213
|
+
response.error = `Redirect path for [${nav_path}] does not exist: ${redirects[nav_path].location}`;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
return response;
|
221
|
+
}
|
222
|
+
|
178
223
|
const checkLinks = async function (source_path, htmlFile, links, hdocbook_config) {
|
179
224
|
for (let i = 0; i < links.length; i++) {
|
180
225
|
|
@@ -369,8 +414,9 @@
|
|
369
414
|
return links;
|
370
415
|
};
|
371
416
|
|
372
|
-
exports.run = async function (source_path, doc_id, verbose, hdocbook_config, hdocbook_project, nav_items, prod_families, prods_supported, gen_exclude) {
|
417
|
+
exports.run = async function (source_path, doc_id, verbose, hdocbook_config, hdocbook_project, nav_items, prod_families, prods_supported, gen_exclude, gen_redirects) {
|
373
418
|
console.log(`Performing Validation and Building SEO Link List...`);
|
419
|
+
redirects = gen_redirects;
|
374
420
|
|
375
421
|
// Get a list of HTML files in source_path
|
376
422
|
dree.scan(source_path, dreeOptions, fileCallback);
|