hdoc-tools 0.8.21 → 0.8.23
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 -0
- package/hdoc-build-db.js +141 -0
- package/hdoc-build.js +153 -117
- package/hdoc-db.js +12 -8
- package/hdoc-validate.js +5 -3
- package/hdoc.js +3 -3
- package/package.json +4 -1
- package/templates/doc-header-non-git.html +23 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2022 Hornbill Docs
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
package/hdoc-build-db.js
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
(function () {
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
const path = require('path'),
|
5
|
+
hdoc_index = require(path.join(__dirname, 'hdoc-db.js')),
|
6
|
+
database = require('better-sqlite3');
|
7
|
+
|
8
|
+
const db_schema = {
|
9
|
+
hdoc_index: [
|
10
|
+
'relative_url UNINDEXED',
|
11
|
+
'book_id',
|
12
|
+
'book_audience UNINDEXED',
|
13
|
+
'book_tags',
|
14
|
+
'doc_title',
|
15
|
+
'doc_content',
|
16
|
+
'doc_preview UNINDEXED',
|
17
|
+
'doc_family_id'
|
18
|
+
],
|
19
|
+
hdoc_meta: [
|
20
|
+
'doc_id INTEGER',
|
21
|
+
'contributor_count INTEGER UNINDEXED',
|
22
|
+
'edit_url UNINDEXED',
|
23
|
+
'last_commit UNINDEXED'
|
24
|
+
],
|
25
|
+
hdoc_contributors: [
|
26
|
+
'doc_id INTEGER',
|
27
|
+
'login',
|
28
|
+
'name',
|
29
|
+
'avatar UNINDEXED',
|
30
|
+
'url UNINDEXED'
|
31
|
+
]
|
32
|
+
};
|
33
|
+
|
34
|
+
exports.create_table = function (db, table, cols, virtual, fts5) {
|
35
|
+
const table_created = hdoc_index.create_table(db, table, cols, virtual, fts5);
|
36
|
+
if (table_created !== null) {
|
37
|
+
return `\nError creating table: ${table_created}`;
|
38
|
+
} else {
|
39
|
+
console.log(`\nTable created: ${table}`);
|
40
|
+
}
|
41
|
+
return null;
|
42
|
+
};
|
43
|
+
|
44
|
+
exports.create_db = function (db_path, doc_id) {
|
45
|
+
let response = {
|
46
|
+
error: null,
|
47
|
+
db: null
|
48
|
+
};
|
49
|
+
console.log('Performing SQlite index creation...');
|
50
|
+
let db_name = path.join(db_path, doc_id, 'index.db');
|
51
|
+
response.db = new database(db_name);
|
52
|
+
response.db.pragma('encoding="UTF-8"');
|
53
|
+
console.log(`\nDatabase created: ${db_name}`);
|
54
|
+
|
55
|
+
// Create tables
|
56
|
+
for (const key in db_schema) {
|
57
|
+
if (db_schema.hasOwnProperty(key)) {
|
58
|
+
const virtual = key === 'hdoc_index' ? true : false;
|
59
|
+
const fts5 = key === 'hdoc_index' ? true : false;
|
60
|
+
const table_created_error = this.create_table(response.db, key, db_schema[key], virtual, fts5);
|
61
|
+
if (table_created_error !== null) {
|
62
|
+
console.log(table_created_error);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
return response;
|
67
|
+
};
|
68
|
+
|
69
|
+
exports.populate_index = function (db, doc_id, book_config, index_records, verbose = false) {
|
70
|
+
let response = {
|
71
|
+
success: false,
|
72
|
+
index_success_count: 0,
|
73
|
+
error: ''
|
74
|
+
};
|
75
|
+
|
76
|
+
if (!book_config.tags) book_config.tags = [];
|
77
|
+
|
78
|
+
for (let i = 0; i < index_records.length; i++) {
|
79
|
+
let index_path_name = index_records[i].relative_path.replace('\\', '/').replace(`${doc_id}/`, '');
|
80
|
+
index_path_name = index_path_name.replace(path.extname(index_records[i].relative_path), '');
|
81
|
+
const index_vals = [
|
82
|
+
index_path_name,
|
83
|
+
doc_id,
|
84
|
+
book_config.audience.join(','),
|
85
|
+
book_config.tags.join(','),
|
86
|
+
index_records[i].index_html.fm_props.title,
|
87
|
+
index_records[i].index_html.text,
|
88
|
+
index_records[i].index_html.preview,
|
89
|
+
book_config.productFamily
|
90
|
+
];
|
91
|
+
const index_response = hdoc_index.insert_record(db, 'hdoc_index', db_schema.hdoc_index, index_vals);
|
92
|
+
if (!index_response.success) {
|
93
|
+
console.log(`Index record creation failed - ${doc_id}/${index_records[i].index_html.fm_props.title}: ${index_response.error}`);
|
94
|
+
continue;
|
95
|
+
}
|
96
|
+
|
97
|
+
// Now add metadata
|
98
|
+
const meta_vals = [
|
99
|
+
parseInt(index_response.row_id, 10),
|
100
|
+
index_records[i].metadata.contributor_count,
|
101
|
+
index_records[i].metadata.edit_url,
|
102
|
+
index_records[i].metadata.last_commit
|
103
|
+
];
|
104
|
+
const meta_response = hdoc_index.insert_record(db, 'hdoc_meta', db_schema.hdoc_meta, meta_vals);
|
105
|
+
if (!meta_response.success) {
|
106
|
+
console.log(`Index metadata record creation failed - ${doc_id}/${index_response.row_id}/${index_records[i].index_html.fm_props.title}: ${meta_response.error}`);
|
107
|
+
continue;
|
108
|
+
}
|
109
|
+
if (verbose) {
|
110
|
+
console.log(`Inserted index record ${index_response.row_id}: ${doc_id} - ${index_records[i].index_html.fm_props.title}`);
|
111
|
+
console.log(`Inserted index metadata record for index ID: ${meta_response.row_id}`);
|
112
|
+
}
|
113
|
+
|
114
|
+
// Now add contributor records
|
115
|
+
for (let j = 0; j < index_records[i].contributors.length; j++) {
|
116
|
+
const contrib_vals = [
|
117
|
+
parseInt(index_response.row_id, 10),
|
118
|
+
index_records[i].contributors[j].login,
|
119
|
+
index_records[i].contributors[j].name,
|
120
|
+
index_records[i].contributors[j].avatar_url,
|
121
|
+
index_records[i].contributors[j].html_url
|
122
|
+
];
|
123
|
+
const cont_response = hdoc_index.insert_record(db, 'hdoc_contributors', db_schema.hdoc_contributors, contrib_vals);
|
124
|
+
if (!cont_response.success) {
|
125
|
+
console.log(`Index document contributor record creation failed - ${doc_id}/${index_response.row_id}/${index_records[i].index_html.fm_props.title}: ${cont_response.error}`);
|
126
|
+
continue;
|
127
|
+
}
|
128
|
+
if (verbose) {
|
129
|
+
console.log(`Inserted document contributor recordL ${cont_response.row_id}`);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
response.index_success_count++;
|
134
|
+
|
135
|
+
}
|
136
|
+
response.success = true;
|
137
|
+
console.log(`\nIndex Build Complete:`);
|
138
|
+
console.log(`${response.index_success_count} document index records created.`);
|
139
|
+
return response;
|
140
|
+
};
|
141
|
+
})();
|
package/hdoc-build.js
CHANGED
@@ -1,32 +1,21 @@
|
|
1
1
|
(function () {
|
2
2
|
'use strict';
|
3
3
|
|
4
|
-
const
|
5
|
-
createHash
|
6
|
-
} = require('crypto'),
|
4
|
+
const crypto = require('crypto'),
|
7
5
|
dree = require('dree'),
|
8
6
|
fs = require('fs-extra'),
|
9
7
|
mdfm = require('markdown-it-front-matter'),
|
10
8
|
path = require('path'),
|
11
|
-
Database = require('better-sqlite3'),
|
12
9
|
URL = require("url").URL,
|
13
10
|
validate = require(path.join(__dirname, 'hdoc-validate.js')),
|
14
11
|
hdoc = require(path.join(__dirname, 'hdoc-module.js')),
|
12
|
+
hdoc_build_db = require(path.join(__dirname, 'hdoc-build-db.js')),
|
15
13
|
hdoc_index = require(path.join(__dirname, 'hdoc-db.js')),
|
16
14
|
zipper = require('zip-local');
|
17
15
|
|
18
16
|
const h_tags_to_search = ['h1', 'h2', 'h3'],
|
19
|
-
|
20
|
-
|
21
|
-
'book_id',
|
22
|
-
'book_audience UNINDEXED',
|
23
|
-
'book_tags',
|
24
|
-
'doc_title',
|
25
|
-
'doc_content',
|
26
|
-
'doc_preview UNINDEXED',
|
27
|
-
'doc_family_id'
|
28
|
-
],
|
29
|
-
doc_header_template_path = path.join(__dirname, 'templates', 'doc-header.html');
|
17
|
+
doc_header_template_path = path.join(__dirname, 'templates', 'doc-header.html'),
|
18
|
+
non_git_doc_header_template_path = path.join(__dirname, 'templates', 'doc-header-non-git.html');
|
30
19
|
|
31
20
|
let bc = {}, // Breadcrumbs map
|
32
21
|
book_read_time = 0,
|
@@ -35,6 +24,7 @@
|
|
35
24
|
conversion_success = 0,
|
36
25
|
conversion_failed = 0,
|
37
26
|
doc_header_template = '',
|
27
|
+
doc_header_template_non_git = '',
|
38
28
|
doc_id = '',
|
39
29
|
git_token = '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', // Github fine-grained personal access token that has minimum read-only access to Hornbill Docs org repo content
|
40
30
|
hdocbook_config = {},
|
@@ -47,16 +37,15 @@
|
|
47
37
|
static_html_files = [],
|
48
38
|
work_path_content = '';
|
49
39
|
|
50
|
-
const transform_static_html = function (file_path) {
|
40
|
+
const transform_static_html = async function (file_path) {
|
51
41
|
if (fs.existsSync(file_path.path)) {
|
52
42
|
// Load HTML file
|
53
43
|
let html_txt = fs.readFileSync(file_path.path, 'utf8');
|
54
44
|
html_txt = html_txt.replace(/\r/gm, ''); // Remove CR's so we're just dealing with newlines
|
55
45
|
|
56
|
-
let html_txt_updated = false;
|
57
|
-
|
58
46
|
let fm_headers = [];
|
59
47
|
let existing_fm_headers = false;
|
48
|
+
let doc_type = 'Article';
|
60
49
|
|
61
50
|
// Check if we have a frontmatter comment
|
62
51
|
const fm_header = hdoc.getHTMLFrontmatterHeader(html_txt);
|
@@ -85,10 +74,13 @@
|
|
85
74
|
|
86
75
|
for (const key in fm_header.fm_properties) {
|
87
76
|
if (fm_header.fm_properties.hasOwnProperty(key)) {
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
77
|
+
if (key === 'type') doc_type = fm_header.fm_properties[key];
|
78
|
+
else {
|
79
|
+
fm_headers.push({
|
80
|
+
id: key,
|
81
|
+
value: fm_header.fm_properties[key]
|
82
|
+
});
|
83
|
+
}
|
92
84
|
}
|
93
85
|
}
|
94
86
|
|
@@ -133,36 +125,93 @@
|
|
133
125
|
});
|
134
126
|
}
|
135
127
|
|
128
|
+
// Add doc type
|
129
|
+
fm_headers.push({
|
130
|
+
id: 'type',
|
131
|
+
value: doc_type
|
132
|
+
});
|
133
|
+
|
134
|
+
let metadata = {};
|
135
|
+
|
136
|
+
// Get contributor data from Github, if exists
|
137
|
+
let contribs = [];
|
138
|
+
if (hdocbook_config.publicSource && hdocbook_config.publicSource !== '' && hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
139
|
+
// Remove the first <h1>title</h1> from the HTML as we'll add that in the document header
|
140
|
+
html_txt = html_txt.replace(/(<h1.*?>)\s*.*\s*(.*<\/h1>)/, '');
|
141
|
+
|
142
|
+
const github_paths = hdoc.get_github_api_path(hdocbook_config.publicSource, file_path.relativePath);
|
143
|
+
const contributors = hdoc.get_github_contributors(github_paths.api_path, git_token);
|
144
|
+
|
145
|
+
if (!contributors.success) {
|
146
|
+
console.log(`Error retrieving contributors from Github: ${contributors.error}`);
|
147
|
+
} else {
|
148
|
+
metadata.last_commit = contributors.last_commit_date;
|
149
|
+
metadata.contributor_count = contributors.contributor_count;
|
150
|
+
metadata.edit_url = github_paths.edit_path;
|
151
|
+
contribs = contributors.contributors;
|
152
|
+
contributors.editPath = github_paths.edit_path;
|
153
|
+
fm_headers.push({
|
154
|
+
id: 'contributor-count',
|
155
|
+
value: contributors.contributor_count
|
156
|
+
});
|
157
|
+
fm_headers.push({
|
158
|
+
id: 'last-commit',
|
159
|
+
value: contributors.last_commit_date
|
160
|
+
});
|
161
|
+
const target_file = file_path.path.replace(path.extname(file_path.path), '._info.json');
|
162
|
+
delete contributors.success;
|
163
|
+
delete contributors.error;
|
164
|
+
contributors.editPath = github_paths.edit_path;
|
165
|
+
try {
|
166
|
+
fs.writeFileSync(target_file, JSON.stringify(contributors, null, 2));
|
167
|
+
} catch (err) {
|
168
|
+
console.log('Error writing:', target_file, '\n', err);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
fm_headers.push({
|
172
|
+
id: 'edit-path',
|
173
|
+
value: github_paths.edit_path
|
174
|
+
});
|
175
|
+
}
|
176
|
+
|
177
|
+
let fm_header_content = '<!--[[FRONTMATTER\n';
|
136
178
|
if (fm_headers.length > 0) {
|
137
|
-
let fm_headers_content = '[[FRONTMATTER\n';
|
138
179
|
for (let i = 0; i < fm_headers.length; i++) {
|
139
|
-
|
180
|
+
fm_header_content += `${fm_headers[i].id}: ${fm_headers[i].value}\n`;
|
140
181
|
}
|
141
|
-
|
182
|
+
fm_header_content += ']]-->';
|
142
183
|
|
143
184
|
if (existing_fm_headers) {
|
144
|
-
html_txt = html_txt.replace(fm_header.fm_header,
|
145
|
-
html_txt_updated = true;
|
146
|
-
} else {
|
147
|
-
html_txt = `<!--${fm_headers_content}-->\n${html_txt}`;
|
148
|
-
html_txt_updated = true;
|
185
|
+
html_txt = html_txt.replace('<!--' + fm_header.fm_header + '-->', '');
|
149
186
|
}
|
150
187
|
}
|
151
188
|
|
189
|
+
let doc_header = '';
|
190
|
+
if (hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
191
|
+
// Build doc header from template and frontmatter tags
|
192
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template);
|
193
|
+
} else {
|
194
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template_non_git);
|
195
|
+
}
|
196
|
+
|
197
|
+
html_txt = `${fm_header_content}\n${doc_header}\n${html_txt}`;
|
198
|
+
|
152
199
|
index_records.push({
|
153
200
|
relative_path: file_path.relativePath,
|
154
|
-
index_html: hdoc_index.transform_html_for_index(html_txt)
|
201
|
+
index_html: hdoc_index.transform_html_for_index(html_txt),
|
202
|
+
metadata: metadata,
|
203
|
+
contributors: contribs
|
155
204
|
});
|
156
|
-
|
157
|
-
|
158
|
-
fs.
|
159
|
-
|
160
|
-
|
205
|
+
// Save HTML into HTML file
|
206
|
+
try {
|
207
|
+
fs.writeFileSync(file_path.path, html_txt);
|
208
|
+
} catch (err) {
|
209
|
+
console.log('Error writing:', target_file, '\n', err);
|
161
210
|
}
|
162
211
|
}
|
163
212
|
};
|
164
213
|
|
165
|
-
const transform_markdown_and_save_html = function (file_path) {
|
214
|
+
const transform_markdown_and_save_html = async function (file_path) {
|
166
215
|
conversion_attempted++;
|
167
216
|
if (fs.existsSync(file_path.path)) {
|
168
217
|
// Load markdown file
|
@@ -226,7 +275,6 @@
|
|
226
275
|
doc_title = fm_property[1].trim();
|
227
276
|
}
|
228
277
|
if (fm_property[0].trim() === 'type') {
|
229
|
-
fm_contains_type = true;
|
230
278
|
doc_type = fm_property[1].trim();
|
231
279
|
}
|
232
280
|
if (fm_property[0].trim() === 'reading-time') {
|
@@ -270,8 +318,10 @@
|
|
270
318
|
value: read_time_mins
|
271
319
|
});
|
272
320
|
}
|
321
|
+
let metadata = {};
|
273
322
|
|
274
323
|
// Get contributor data from Github, if exists
|
324
|
+
let contribs = [];
|
275
325
|
if (hdocbook_config.publicSource && hdocbook_config.publicSource !== '' && hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
276
326
|
// Remove the first <h1>title</h1> from the HTML as we'll add that in the document header
|
277
327
|
html_txt = html_txt.replace(/(<h1.*?>)\s*.*\s*(.*<\/h1>)/, '');
|
@@ -282,6 +332,12 @@
|
|
282
332
|
if (!contributors.success) {
|
283
333
|
console.log(`Error retrieving contributors from Github: ${contributors.error}`);
|
284
334
|
} else {
|
335
|
+
metadata.last_commit = contributors.last_commit_date;
|
336
|
+
metadata.contributor_count = contributors.contributor_count;
|
337
|
+
metadata.edit_url = github_paths.edit_path;
|
338
|
+
contribs = contributors.contributors;
|
339
|
+
contributors.editPath = github_paths.edit_path;
|
340
|
+
|
285
341
|
fm_headers.push({
|
286
342
|
id: 'contributor-count',
|
287
343
|
value: contributors.contributor_count
|
@@ -290,25 +346,23 @@
|
|
290
346
|
id: 'last-commit',
|
291
347
|
value: contributors.last_commit_date
|
292
348
|
});
|
349
|
+
const target_file = file_path.path.replace(path.extname(file_path.path), '._info.json');
|
350
|
+
delete contributors.success;
|
351
|
+
delete contributors.error;
|
352
|
+
contributors.editPath = github_paths.edit_path;
|
353
|
+
try {
|
354
|
+
fs.writeFileSync(target_file, JSON.stringify(contributors, null, 2));
|
355
|
+
} catch (err) {
|
356
|
+
console.log('Error writing:', target_file, '\n', err);
|
357
|
+
}
|
293
358
|
}
|
294
359
|
fm_headers.push({
|
295
360
|
id: 'edit-path',
|
296
361
|
value: github_paths.edit_path
|
297
362
|
});
|
298
|
-
const target_file = file_path.path.replace(path.extname(file_path.path), '._info.json');
|
299
|
-
delete contributors.success;
|
300
|
-
delete contributors.error;
|
301
|
-
contributors.editPath = github_paths.edit_path;
|
302
|
-
try {
|
303
|
-
fs.writeFileSync(target_file, JSON.stringify(contributors, null, 2));
|
304
|
-
} catch (err) {
|
305
|
-
console.log('Error writing:', target_file, '\n', err);
|
306
|
-
}
|
307
363
|
}
|
308
364
|
|
309
|
-
|
310
|
-
// Add frontmatter tags as comment to front of HTML
|
311
|
-
|
365
|
+
// Add frontmatter tags as comment
|
312
366
|
let fm_header = '<!--[[FRONTMATTER\n';
|
313
367
|
if (fm_headers.length > 0) {
|
314
368
|
for (let i = 0; i < fm_headers.length; i++) {
|
@@ -316,29 +370,37 @@
|
|
316
370
|
}
|
317
371
|
}
|
318
372
|
fm_header += ']]-->';
|
319
|
-
|
373
|
+
|
374
|
+
let doc_header = '';
|
320
375
|
if (hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
|
321
376
|
// Build doc header from template and frontmatter tags
|
322
|
-
|
323
|
-
html_txt = `${fm_header}\n${doc_header}\n${html_txt}`;
|
377
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template);
|
324
378
|
} else {
|
325
|
-
|
379
|
+
// Build doc header from template and frontmatter tags
|
380
|
+
doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template_non_git);
|
326
381
|
}
|
327
|
-
|
328
|
-
|
382
|
+
/*
|
383
|
+
const pdf_html = `${fm_header}\n${doc_header}\n${html_txt}`;
|
384
|
+
const pdf_file = file_path.path.replace(path.extname(file_path.path), '.pdf');
|
385
|
+
*/
|
386
|
+
html_txt = `${fm_header}\n${doc_header}\n${html_txt}`;
|
329
387
|
|
330
388
|
// Save HTML into HTML file
|
331
389
|
const target_file = file_path.path.replace(path.extname(file_path.path), '.html');
|
332
390
|
const relative_path = file_path.relativePath.replace(path.extname(file_path.path), '.html');
|
333
|
-
|
334
|
-
|
335
|
-
})
|
391
|
+
try {
|
392
|
+
fs.writeFileSync(target_file, html_txt);
|
393
|
+
} catch (err) {
|
394
|
+
console.log('Error writing:', target_file, '\n', err);
|
395
|
+
}
|
336
396
|
|
337
397
|
const index_details = hdoc_index.transform_html_for_index(html_txt);
|
338
398
|
|
339
399
|
index_records.push({
|
340
400
|
relative_path: relative_path,
|
341
|
-
index_html: index_details
|
401
|
+
index_html: index_details,
|
402
|
+
metadata: metadata,
|
403
|
+
contributors: contribs
|
342
404
|
});
|
343
405
|
|
344
406
|
// Delete MD file from _work path
|
@@ -355,8 +417,8 @@
|
|
355
417
|
return false;
|
356
418
|
};
|
357
419
|
|
358
|
-
const process_doc_header = function (fm_headers, doc_path) {
|
359
|
-
let wip_doc_header =
|
420
|
+
const process_doc_header = function (fm_headers, doc_path, template) {
|
421
|
+
let wip_doc_header = template;
|
360
422
|
|
361
423
|
// Process fm_headers properties first
|
362
424
|
for (let i = 0; i < fm_headers.length; i++) {
|
@@ -430,10 +492,7 @@
|
|
430
492
|
|
431
493
|
const md5DreeOptions = {
|
432
494
|
hash: true,
|
433
|
-
hashAlgorithm: 'md5',
|
434
|
-
hashEncoding: 'hex',
|
435
495
|
normalize: true,
|
436
|
-
size: true,
|
437
496
|
sorted: true
|
438
497
|
};
|
439
498
|
|
@@ -507,6 +566,10 @@
|
|
507
566
|
for (let d = 0; d < nav_c.items.length; d++) {
|
508
567
|
const nav_d = nav_c.items[d];
|
509
568
|
if (nav_d.link) {
|
569
|
+
if (nav_d.link.includes('\\')) {
|
570
|
+
console.log(`Navigation items should not contain backslashes: ${nav_d.link}`);
|
571
|
+
process.exit(1);
|
572
|
+
}
|
510
573
|
if (bc[nav_c.link]) {
|
511
574
|
bc[nav_d.link] = bc[nav_c.link];
|
512
575
|
} else {
|
@@ -529,7 +592,7 @@
|
|
529
592
|
});
|
530
593
|
}
|
531
594
|
}
|
532
|
-
|
595
|
+
|
533
596
|
}
|
534
597
|
}
|
535
598
|
}
|
@@ -540,11 +603,11 @@
|
|
540
603
|
//console.log(JSON.stringify(bc, null, 2));
|
541
604
|
};
|
542
605
|
|
543
|
-
exports.run = function (source_path, verbose, github_api_token) {
|
606
|
+
exports.run = async function (source_path, verbose, github_api_token) {
|
544
607
|
if (github_api_token !== '') {
|
545
608
|
git_token = github_api_token;
|
546
609
|
}
|
547
|
-
|
610
|
+
|
548
611
|
// GERRY: The purpose of this function is to create a zip file containing the hdocbook content,
|
549
612
|
// * Create a _work folder
|
550
613
|
// * copy the hdocbook content to the work folder
|
@@ -591,9 +654,10 @@
|
|
591
654
|
process.exit(1);
|
592
655
|
}
|
593
656
|
|
594
|
-
// Load document header
|
657
|
+
// Load document header templates
|
595
658
|
try {
|
596
659
|
doc_header_template = fs.readFileSync(doc_header_template_path, 'utf8');
|
660
|
+
doc_header_template_non_git = fs.readFileSync(non_git_doc_header_template_path, 'utf8');
|
597
661
|
} catch (err) {
|
598
662
|
console.log(`Error reading document header template: ${err}`);
|
599
663
|
process.exit(1);
|
@@ -605,15 +669,16 @@
|
|
605
669
|
dree.scan(work_path, dreeOptions, build_file_callback);
|
606
670
|
|
607
671
|
// Work through MD files and convert to HTML
|
608
|
-
md_files.
|
609
|
-
transform_markdown_and_save_html(
|
610
|
-
}
|
611
|
-
|
672
|
+
for (let i = 0; i < md_files.length; i++) {
|
673
|
+
await transform_markdown_and_save_html(md_files[i]);
|
674
|
+
}
|
675
|
+
|
612
676
|
// Work through Static HTML files and add Frontmatter tags
|
613
|
-
static_html_files.
|
614
|
-
transform_static_html(
|
615
|
-
}
|
677
|
+
for (let i = 0; i < static_html_files.length; i++) {
|
678
|
+
await transform_static_html(static_html_files[i]);
|
679
|
+
}
|
616
680
|
|
681
|
+
// Output to console
|
617
682
|
console.log(` MD files found: ${conversion_attempted}`);
|
618
683
|
console.log(`Successfully converted to HTML: ${conversion_success}`);
|
619
684
|
console.log(` Failed to convert: ${conversion_failed}\n`);
|
@@ -628,47 +693,18 @@
|
|
628
693
|
process.exit(1);
|
629
694
|
}
|
630
695
|
|
631
|
-
//
|
632
|
-
|
633
|
-
let
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
// Now add the table
|
639
|
-
const table_name = 'hdoc_index';
|
640
|
-
const table_created = hdoc_index.create_virtual_table(db, table_name, index_cols);
|
696
|
+
// Build the index
|
697
|
+
// Create the DB and tables
|
698
|
+
let db = hdoc_build_db.create_db(work_path, doc_id);
|
699
|
+
if (db.error && db.error !== null) {
|
700
|
+
console.log(db.error);
|
701
|
+
process.exit(1);
|
702
|
+
}
|
641
703
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
if (!hdocbook_config.tags) hdocbook_config.tags = [];
|
647
|
-
let index_success_count = 0;
|
648
|
-
for (let i = 0; i < index_records.length; i++) {
|
649
|
-
let index_path_name = index_records[i].relative_path.replace('\\', '/').replace(`${doc_id}/`, '');
|
650
|
-
index_path_name = index_path_name.replace(path.extname(index_records[i].relative_path), '');
|
651
|
-
const index_vals = [
|
652
|
-
index_path_name,
|
653
|
-
doc_id,
|
654
|
-
hdocbook_config.audience.join(','),
|
655
|
-
hdocbook_config.tags.join(','),
|
656
|
-
index_records[i].index_html.fm_props.title,
|
657
|
-
index_records[i].index_html.text,
|
658
|
-
index_records[i].index_html.preview,
|
659
|
-
hdocbook_config.productFamily
|
660
|
-
];
|
661
|
-
const index_response = hdoc_index.insert_record(db, table_name, index_cols, index_vals, doc_id, index_records[i].index_html.fm_props.title);
|
662
|
-
if (!index_response.success) {
|
663
|
-
console.log(`Index record creation failed - ${doc_id}/${index_records[i].index_html.fm_props.title}: ${index_response.error}`);
|
664
|
-
continue;
|
665
|
-
}
|
666
|
-
index_success_count++;
|
667
|
-
if (verbose) {
|
668
|
-
console.log(`Inserted index record ${index_response.row_id}: ${doc_id} - ${index_records[i].index_html.fm_props.title}`);
|
669
|
-
}
|
670
|
-
}
|
671
|
-
console.log(`\nIndex Build Complete: ${index_success_count} records created.`);
|
704
|
+
const index = hdoc_build_db.populate_index(db.db, doc_id, hdocbook_config, index_records, verbose);
|
705
|
+
if (!index.success) {
|
706
|
+
console.log(index.error);
|
707
|
+
process.exit(1);
|
672
708
|
}
|
673
709
|
|
674
710
|
// Now create MD5 hash of built content
|
@@ -682,7 +718,7 @@
|
|
682
718
|
process.exit(1);
|
683
719
|
}
|
684
720
|
|
685
|
-
const hash = createHash("md5").update(concat_hash).digest("hex");
|
721
|
+
const hash = crypto.createHash("md5").update(concat_hash).digest("hex");
|
686
722
|
const checksum_path = path.join(work_path_content, 'checksum.md5');
|
687
723
|
try {
|
688
724
|
fs.writeFileSync(checksum_path, hash);
|
package/hdoc-db.js
CHANGED
@@ -5,9 +5,13 @@
|
|
5
5
|
path = require('path'),
|
6
6
|
hdoc = require(path.join(__dirname, 'hdoc-module.js'));
|
7
7
|
|
8
|
-
exports.
|
9
|
-
let create_sql = [];
|
10
|
-
create_sql.push(
|
8
|
+
exports.create_table = function (db, table_name, columns, virtual, fts5) {
|
9
|
+
let create_sql = ['CREATE'];
|
10
|
+
if (virtual) create_sql.push('VIRTUAL');
|
11
|
+
create_sql.push('TABLE');
|
12
|
+
create_sql.push(table_name);
|
13
|
+
if (fts5) create_sql.push('USING fts5(');
|
14
|
+
else create_sql.push('(');
|
11
15
|
for (let i = 0; i < columns.length; i++) {
|
12
16
|
if (i !== 0) create_sql.push(`,${columns[i]}`);
|
13
17
|
else create_sql.push(columns[i]);
|
@@ -21,7 +25,7 @@
|
|
21
25
|
}
|
22
26
|
};
|
23
27
|
|
24
|
-
exports.insert_record = function (db, table, columns, values
|
28
|
+
exports.insert_record = function (db, table, columns, values) {
|
25
29
|
let response = {
|
26
30
|
success: false,
|
27
31
|
row_id: 0,
|
@@ -33,11 +37,11 @@
|
|
33
37
|
let vals = 'VALUES (';
|
34
38
|
for (let i = 0; i < columns.length; i++) {
|
35
39
|
if (i === 0) {
|
36
|
-
cols += `${columns[i].replace('UNINDEXED', '').trim()}`;
|
40
|
+
cols += `${columns[i].replace('UNINDEXED', '').replace('INTEGER', '').trim()}`;
|
37
41
|
vals += '?';
|
38
42
|
} else {
|
39
|
-
cols +=
|
40
|
-
vals += '
|
43
|
+
cols += `, ${columns[i].replace('UNINDEXED', '').replace('INTEGER', '').trim()}`;
|
44
|
+
vals += ', ?';
|
41
45
|
}
|
42
46
|
}
|
43
47
|
cols += ')';
|
@@ -46,7 +50,7 @@
|
|
46
50
|
queryProps.push(vals);
|
47
51
|
|
48
52
|
try {
|
49
|
-
const stmt = db.prepare(queryProps.join('
|
53
|
+
const stmt = db.prepare(queryProps.join(' '));
|
50
54
|
const info = stmt.run(values);
|
51
55
|
response.row_id = info.lastInsertRowid;
|
52
56
|
response.success = true;
|
package/hdoc-validate.js
CHANGED
@@ -12,6 +12,7 @@ const parseLinkDestination = require('markdown-it/lib/helpers/parse_link_destina
|
|
12
12
|
|
13
13
|
let errors = {},
|
14
14
|
messages = {},
|
15
|
+
warnings = {},
|
15
16
|
errorcount = 0,
|
16
17
|
filecount = 0,
|
17
18
|
htmlFiles = [];
|
@@ -58,11 +59,11 @@ const parseLinkDestination = require('markdown-it/lib/helpers/parse_link_destina
|
|
58
59
|
|
59
60
|
// Replace /_books/ with /
|
60
61
|
file_path = file_path.replace(path.sep + '_books' + path.sep, path.sep);
|
61
|
-
if (!fs.existsSync(file_path) && !fs.existsSync(file_path + '.htm') && !fs.existsSync(file_path + '.html')) {
|
62
|
-
errors[html_path.relativePath].push(`Book resource does not exist: ${
|
62
|
+
if (!fs.existsSync(file_path) && !fs.existsSync(file_path + path.sep + 'index.htm') && !fs.existsSync(file_path + 'index.html') && !fs.existsSync(file_path + '.htm') && !fs.existsSync(file_path + '.html')) {
|
63
|
+
errors[html_path.relativePath].push(`Book resource does not exist: ${relative_path}`);
|
63
64
|
return false;
|
64
65
|
} else {
|
65
|
-
messages[html_path.relativePath].push(`Book resource exists: ${
|
66
|
+
messages[html_path.relativePath].push(`Book resource exists: ${relative_path}`);
|
66
67
|
}
|
67
68
|
return true;
|
68
69
|
};
|
@@ -96,6 +97,7 @@ const parseLinkDestination = require('markdown-it/lib/helpers/parse_link_destina
|
|
96
97
|
// Initiate maps for errors and verbose messages for HTML file
|
97
98
|
errors[htmlFiles[i].relativePath] = [];
|
98
99
|
messages[htmlFiles[i].relativePath] = [];
|
100
|
+
warnings[htmlFiles[i].relativePath] = [];
|
99
101
|
|
100
102
|
const links = getLinks(htmlFiles[i]);
|
101
103
|
if (links.length === 0) {
|
package/hdoc.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#!/usr/bin/env node
|
1
|
+
#!/usr/bin/env node
|
2
2
|
|
3
|
-
(function () {
|
3
|
+
(async function () {
|
4
4
|
'use strict';
|
5
5
|
|
6
6
|
const preRun = require('./validateNodeVer.js'),
|
@@ -71,7 +71,7 @@
|
|
71
71
|
server.run(ui_path, source_path);
|
72
72
|
} else if (command == 'build') {
|
73
73
|
const builder = require(path.join(__dirname, 'hdoc-build.js'));
|
74
|
-
builder.run(source_path, verbose, git_token);
|
74
|
+
await builder.run(source_path, verbose, git_token);
|
75
75
|
} else if (command == 'stats') {
|
76
76
|
const stats = require(path.join(__dirname, 'hdoc-stats.js'));
|
77
77
|
stats.run(ui_path, source_path, verbose);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "hdoc-tools",
|
3
|
-
"version": "0.8.
|
3
|
+
"version": "0.8.23",
|
4
4
|
"description": "Hornbill HDocBook Development Support Tool",
|
5
5
|
"main": "hdoc.js",
|
6
6
|
"bin": {
|
@@ -10,6 +10,7 @@
|
|
10
10
|
"hdoc.js",
|
11
11
|
"hdoc-db.js",
|
12
12
|
"hdoc-build.js",
|
13
|
+
"hdoc-build-db.js",
|
13
14
|
"hdoc-help.js",
|
14
15
|
"hdoc-init.js",
|
15
16
|
"hdoc-module.js",
|
@@ -38,10 +39,12 @@
|
|
38
39
|
"highlight.js": "^11.6.0",
|
39
40
|
"html-to-text": "^8.2.1",
|
40
41
|
"js-yaml": "^4.1.0",
|
42
|
+
"jspdf": "^2.5.1",
|
41
43
|
"markdown-it": "^13.0.1",
|
42
44
|
"markdown-it-container": "^3.0.0",
|
43
45
|
"markdown-it-front-matter": "^0.2.3",
|
44
46
|
"multer": "^1.4.5-lts.1",
|
47
|
+
"pdf-creator-node": "^2.3.5",
|
45
48
|
"prompt": "^1.3.0",
|
46
49
|
"stream": "0.0.2",
|
47
50
|
"sync-request": "^6.1.0",
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<div class="document-header">
|
2
|
+
<div class="hb-container-horizontal">
|
3
|
+
<div class="hb-center-v hb-container-expand">
|
4
|
+
<ul class="ps-0 nav-bar-nav-list noeffects after-fslash overflow-ellipsis">{{breadcrumbs}}</ul>
|
5
|
+
</div>
|
6
|
+
<div class="toolbar-right hb-center-v">
|
7
|
+
<a class="toolbar-action documentation-menu-popper">
|
8
|
+
<i class="bi bi-three-dots-vertical"></i>
|
9
|
+
</a>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<h1>{{title}}</h1>
|
14
|
+
|
15
|
+
<div class="hb-container-horizontal">
|
16
|
+
<div class="hb-center-v hb-container-expand">
|
17
|
+
<ul class="ps-0 nav-bar-nav-list noeffects after-bullets overflow-ellipsis text-light-2">
|
18
|
+
<li class="ps-0 mt-0 nav-bar-item">{{doc-type}}</li>
|
19
|
+
<li class="ps-0 mt-0 nav-bar-item">{{reading-time}} minutes to read</li>
|
20
|
+
</ul>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
</div>
|