hdoc-tools 0.20.0 → 0.22.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 +262 -260
- package/hdoc-build.js +42 -3
- package/hdoc-module.js +728 -708
- package/hdoc-validate.js +4 -2
- package/package.json +1 -1
package/hdoc-build-db.js
CHANGED
@@ -1,260 +1,262 @@
|
|
1
|
-
(() => {
|
2
|
-
const path = require("node:path");
|
3
|
-
const hdoc_index = require(path.join(__dirname, "hdoc-db.js"));
|
4
|
-
const database = require("better-sqlite3");
|
5
|
-
|
6
|
-
const db_schema = {
|
7
|
-
hdoc_index: [
|
8
|
-
"resource_url UNINDEXED",
|
9
|
-
"book_id",
|
10
|
-
"book_audience UNINDEXED",
|
11
|
-
"book_tags",
|
12
|
-
"doc_title",
|
13
|
-
"doc_content",
|
14
|
-
"doc_preview UNINDEXED",
|
15
|
-
"doc_family_id",
|
16
|
-
"doc_md5_hash UNINDEXED",
|
17
|
-
"doc_lastmod",
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
response.db
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
const
|
73
|
-
const
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
redirect_records[i].
|
99
|
-
redirect_records[i].
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
response.
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
index_path_name.endsWith("/index.
|
148
|
-
index_path_name.endsWith("/index.
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
book_config.
|
170
|
-
|
171
|
-
file.index_html.
|
172
|
-
file.index_html.
|
173
|
-
|
174
|
-
|
175
|
-
file.
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
file.metadata.
|
198
|
-
file.
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
file.contributors[j].
|
228
|
-
file.contributors[j].
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
1
|
+
(() => {
|
2
|
+
const path = require("node:path");
|
3
|
+
const hdoc_index = require(path.join(__dirname, "hdoc-db.js"));
|
4
|
+
const database = require("better-sqlite3");
|
5
|
+
|
6
|
+
const db_schema = {
|
7
|
+
hdoc_index: [
|
8
|
+
"resource_url UNINDEXED",
|
9
|
+
"book_id",
|
10
|
+
"book_audience UNINDEXED",
|
11
|
+
"book_tags",
|
12
|
+
"doc_title",
|
13
|
+
"doc_content",
|
14
|
+
"doc_preview UNINDEXED",
|
15
|
+
"doc_family_id",
|
16
|
+
"doc_md5_hash UNINDEXED",
|
17
|
+
"doc_lastmod",
|
18
|
+
"doc_status",
|
19
|
+
],
|
20
|
+
hdoc_meta: [
|
21
|
+
"resource_url",
|
22
|
+
"book_id",
|
23
|
+
"contributor_count INTEGER UNINDEXED",
|
24
|
+
"edit_url UNINDEXED",
|
25
|
+
"last_commit UNINDEXED",
|
26
|
+
"pdf_size INTEGER UNINDEXED",
|
27
|
+
],
|
28
|
+
hdoc_contributors: [
|
29
|
+
"resource_url",
|
30
|
+
"book_id",
|
31
|
+
"login",
|
32
|
+
"name",
|
33
|
+
"avatar UNINDEXED",
|
34
|
+
"url UNINDEXED",
|
35
|
+
],
|
36
|
+
hdoc_redirects: [
|
37
|
+
"resource_url",
|
38
|
+
"location_url",
|
39
|
+
"http_code INTEGER UNINDEXED",
|
40
|
+
],
|
41
|
+
};
|
42
|
+
|
43
|
+
exports.create_table = (db, table, cols, virtual, fts5) => {
|
44
|
+
const table_created = hdoc_index.create_table(
|
45
|
+
db,
|
46
|
+
table,
|
47
|
+
cols,
|
48
|
+
virtual,
|
49
|
+
fts5,
|
50
|
+
);
|
51
|
+
if (table_created !== null) {
|
52
|
+
return `\nError creating table: ${table_created}`;
|
53
|
+
}
|
54
|
+
console.log(`\nTable created: ${table}`);
|
55
|
+
return null;
|
56
|
+
};
|
57
|
+
|
58
|
+
exports.create_db = function (db_path, doc_id) {
|
59
|
+
const response = {
|
60
|
+
error: null,
|
61
|
+
db: null,
|
62
|
+
};
|
63
|
+
console.log("\nPerforming SQlite index creation...");
|
64
|
+
const db_name = path.join(db_path, doc_id, "index.db");
|
65
|
+
response.db = new database(db_name);
|
66
|
+
response.db.pragma('encoding="UTF-8"');
|
67
|
+
console.log(`\nDatabase created: ${db_name}`);
|
68
|
+
|
69
|
+
// Create tables
|
70
|
+
for (const key in db_schema) {
|
71
|
+
if (Object.hasOwn(db_schema, key)) {
|
72
|
+
const virtual = key === "hdoc_index";
|
73
|
+
const fts5 = key === "hdoc_index";
|
74
|
+
const table_created_error = this.create_table(
|
75
|
+
response.db,
|
76
|
+
key,
|
77
|
+
db_schema[key],
|
78
|
+
virtual,
|
79
|
+
fts5,
|
80
|
+
);
|
81
|
+
if (table_created_error !== null) {
|
82
|
+
console.error(table_created_error);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return response;
|
87
|
+
};
|
88
|
+
|
89
|
+
exports.populate_redirects = (db, redirect_records, verbose = false) => {
|
90
|
+
const response = {
|
91
|
+
success: true,
|
92
|
+
errors: [],
|
93
|
+
index_success_count: 0,
|
94
|
+
};
|
95
|
+
|
96
|
+
for (let i = 0; i < redirect_records.length; i++) {
|
97
|
+
const index_vals = [
|
98
|
+
redirect_records[i].url,
|
99
|
+
redirect_records[i].location ? redirect_records[i].location : "",
|
100
|
+
redirect_records[i].code,
|
101
|
+
];
|
102
|
+
const index_response = hdoc_index.insert_record(
|
103
|
+
db,
|
104
|
+
"hdoc_redirects",
|
105
|
+
db_schema.hdoc_redirects,
|
106
|
+
index_vals,
|
107
|
+
);
|
108
|
+
if (!index_response.success) {
|
109
|
+
response.success = false;
|
110
|
+
response.errors.push(
|
111
|
+
`Redirect record creation failed - ${redirect_records[i].url}: ${index_response.error}`,
|
112
|
+
);
|
113
|
+
} else {
|
114
|
+
response.index_success_count++;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
console.log(
|
118
|
+
`\nRedirect Index Build Complete: ${response.index_success_count} document records created.`,
|
119
|
+
);
|
120
|
+
return response;
|
121
|
+
};
|
122
|
+
|
123
|
+
exports.populate_index = async (
|
124
|
+
db,
|
125
|
+
doc_id,
|
126
|
+
book_config,
|
127
|
+
index_records,
|
128
|
+
verbose = false,
|
129
|
+
) => {
|
130
|
+
const response = {
|
131
|
+
success: false,
|
132
|
+
index_success_count: 0,
|
133
|
+
error: "",
|
134
|
+
};
|
135
|
+
|
136
|
+
if (!book_config.tags) book_config.tags = [];
|
137
|
+
|
138
|
+
const indexPromises = [];
|
139
|
+
for (let i = 0; i < index_records.length; i++) {
|
140
|
+
indexPromises.push(index_records[i]);
|
141
|
+
}
|
142
|
+
let curr_file = "";
|
143
|
+
await Promise.all(
|
144
|
+
indexPromises.map(async (file) => {
|
145
|
+
let index_path_name = file.relative_path.replaceAll("\\", "/");
|
146
|
+
if (
|
147
|
+
index_path_name.endsWith("/index.md") ||
|
148
|
+
index_path_name.endsWith("/index.html") ||
|
149
|
+
index_path_name.endsWith("/index.htm")
|
150
|
+
) {
|
151
|
+
index_path_name = index_path_name.substring(
|
152
|
+
0,
|
153
|
+
index_path_name.lastIndexOf("/"),
|
154
|
+
);
|
155
|
+
}
|
156
|
+
index_path_name = `/${index_path_name.replace(path.extname(file.relative_path), "")}`;
|
157
|
+
|
158
|
+
let index_response = {
|
159
|
+
success: true,
|
160
|
+
row_id: 0,
|
161
|
+
};
|
162
|
+
let index_content_path = index_path_name;
|
163
|
+
if (file.index_html.id !== null)
|
164
|
+
index_content_path += `#${file.index_html.id}`;
|
165
|
+
if (!file.inline) {
|
166
|
+
const index_vals = [
|
167
|
+
index_content_path,
|
168
|
+
doc_id,
|
169
|
+
book_config.audience.join(","),
|
170
|
+
book_config.tags.join(","),
|
171
|
+
file.index_html.fm_props.title,
|
172
|
+
file.index_html.text,
|
173
|
+
file.index_html.preview,
|
174
|
+
book_config.productFamily,
|
175
|
+
file.md5,
|
176
|
+
file.lastmod,
|
177
|
+
file.status,
|
178
|
+
];
|
179
|
+
index_response = hdoc_index.insert_record(
|
180
|
+
db,
|
181
|
+
"hdoc_index",
|
182
|
+
db_schema.hdoc_index,
|
183
|
+
index_vals,
|
184
|
+
);
|
185
|
+
}
|
186
|
+
if (!index_response.success) {
|
187
|
+
console.error(
|
188
|
+
`Index record creation failed - ${doc_id}/${file.index_html.fm_props.title}: ${index_response.error}`,
|
189
|
+
);
|
190
|
+
} else {
|
191
|
+
if (curr_file === index_path_name) return;
|
192
|
+
curr_file = index_path_name;
|
193
|
+
// Now add metadata
|
194
|
+
const meta_vals = [
|
195
|
+
index_path_name,
|
196
|
+
doc_id,
|
197
|
+
file.metadata.contributor_count,
|
198
|
+
file.metadata.edit_url,
|
199
|
+
file.metadata.last_commit,
|
200
|
+
file.pdf_size,
|
201
|
+
];
|
202
|
+
const meta_response = await hdoc_index.insert_record(
|
203
|
+
db,
|
204
|
+
"hdoc_meta",
|
205
|
+
db_schema.hdoc_meta,
|
206
|
+
meta_vals,
|
207
|
+
);
|
208
|
+
if (!meta_response.success) {
|
209
|
+
console.error(
|
210
|
+
`Index metadata record creation failed - ${doc_id}/${index_response.row_id}/${file.index_html.fm_props.title}: ${meta_response.error}`,
|
211
|
+
);
|
212
|
+
} else {
|
213
|
+
if (verbose) {
|
214
|
+
console.log(
|
215
|
+
`Inserted index record ${index_response.row_id}: ${doc_id} - ${file.index_html.fm_props.title}`,
|
216
|
+
);
|
217
|
+
console.log(
|
218
|
+
`Inserted index metadata record for index ID: ${meta_response.row_id}`,
|
219
|
+
);
|
220
|
+
}
|
221
|
+
|
222
|
+
// Now add contributor records
|
223
|
+
for (let j = 0; j < file.contributors.length; j++) {
|
224
|
+
const contrib_vals = [
|
225
|
+
index_path_name,
|
226
|
+
doc_id,
|
227
|
+
file.contributors[j].login,
|
228
|
+
file.contributors[j].name,
|
229
|
+
file.contributors[j].avatar_url,
|
230
|
+
file.contributors[j].html_url,
|
231
|
+
];
|
232
|
+
const cont_response = await hdoc_index.insert_record(
|
233
|
+
db,
|
234
|
+
"hdoc_contributors",
|
235
|
+
db_schema.hdoc_contributors,
|
236
|
+
contrib_vals,
|
237
|
+
);
|
238
|
+
if (!cont_response.success) {
|
239
|
+
console.error(
|
240
|
+
`Index document contributor record creation failed - ${doc_id}/${index_response.row_id}/${file.index_html.fm_props.title}: ${cont_response.error}`,
|
241
|
+
);
|
242
|
+
continue;
|
243
|
+
}
|
244
|
+
if (verbose) {
|
245
|
+
console.log(
|
246
|
+
`Inserted document contributor record ${cont_response.row_id}`,
|
247
|
+
);
|
248
|
+
}
|
249
|
+
}
|
250
|
+
response.index_success_count++;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}),
|
254
|
+
);
|
255
|
+
|
256
|
+
response.success = true;
|
257
|
+
console.log(
|
258
|
+
`\nIndex Build Complete: ${response.index_success_count} document index records created.`,
|
259
|
+
);
|
260
|
+
return response;
|
261
|
+
};
|
262
|
+
})();
|
package/hdoc-build.js
CHANGED
@@ -5,7 +5,6 @@
|
|
5
5
|
const mdfm = require("markdown-it-front-matter");
|
6
6
|
const path = require("node:path");
|
7
7
|
const puppeteer = require("puppeteer");
|
8
|
-
const URL = require("node:url").URL;
|
9
8
|
const hdoc_validate = require(path.join(__dirname, "hdoc-validate.js"));
|
10
9
|
const hdoc = require(path.join(__dirname, "hdoc-module.js"));
|
11
10
|
const hdoc_build_db = require(path.join(__dirname, "hdoc-build-db.js"));
|
@@ -45,6 +44,7 @@
|
|
45
44
|
|
46
45
|
const built_file_hashes = [];
|
47
46
|
const css_templates = [];
|
47
|
+
const draft_links = [];
|
48
48
|
const errors_filename = [];
|
49
49
|
const index_records = [];
|
50
50
|
const md_files = [];
|
@@ -119,9 +119,18 @@
|
|
119
119
|
|
120
120
|
// Check if we have a frontmatter comment
|
121
121
|
const fm_header = hdoc.getHTMLFrontmatterHeader(html_txt);
|
122
|
+
|
123
|
+
let rel_path = file_path.relativePath.replace(path.extname(file_path.relativePath), '');
|
124
|
+
if (rel_path.endsWith('/index')) rel_path = rel_path.substring(0, rel_path.length - 6);
|
125
|
+
const is_draft = draft_links.indexOf(rel_path) !== -1;
|
126
|
+
|
127
|
+
let fm_status = false;
|
122
128
|
if (Object.keys(fm_header.fm_properties).length > 0) {
|
123
129
|
existing_fm_headers = true;
|
124
130
|
|
131
|
+
if (fm_header.fm_properties?.status) {
|
132
|
+
fm_status = true;
|
133
|
+
}
|
125
134
|
// We have some frontmatter headers, check if title is one of them
|
126
135
|
let fm_title_found = false;
|
127
136
|
if (
|
@@ -268,6 +277,14 @@
|
|
268
277
|
value: doc_type,
|
269
278
|
});
|
270
279
|
|
280
|
+
// Add status if we don't have one defined and the nav tree defines the document as draft
|
281
|
+
if (!fm_status && is_draft) {
|
282
|
+
fm_headers.push({
|
283
|
+
id: "status",
|
284
|
+
value: "draft"
|
285
|
+
});
|
286
|
+
}
|
287
|
+
|
271
288
|
const metadata = {};
|
272
289
|
|
273
290
|
// Remove the first <h1>title</h1> from the HTML as we'll add that in the document header
|
@@ -443,6 +460,7 @@
|
|
443
460
|
md5: file_path.hash,
|
444
461
|
lastmod: last_commit !== null ? last_commit : file_path.hb_lastmod,
|
445
462
|
inline: inline_content,
|
463
|
+
status: index_data.fm_props.status ? index_data.fm_props.status : 'release',
|
446
464
|
});
|
447
465
|
}
|
448
466
|
|
@@ -506,7 +524,6 @@
|
|
506
524
|
});
|
507
525
|
|
508
526
|
// Tidy up ```json and ```xml code tags
|
509
|
-
|
510
527
|
if (md_txt.includes("```json") || md_txt.includes("```xml"))
|
511
528
|
md_txt = tidy_code_tags(md_txt, file_path.relativePath);
|
512
529
|
|
@@ -523,6 +540,11 @@
|
|
523
540
|
let doc_title = "";
|
524
541
|
let doc_type = "Article";
|
525
542
|
|
543
|
+
let rel_path = file_path.relativePath.replace(path.extname(file_path.relativePath), '');
|
544
|
+
if (rel_path.endsWith('/index')) rel_path = rel_path.substring(0, rel_path.length - 6);
|
545
|
+
const is_draft = draft_links.indexOf(rel_path) !== -1;
|
546
|
+
let fm_status = false;
|
547
|
+
|
526
548
|
if (fm_content.length >= 0) {
|
527
549
|
for (fm_prop of fm_content) {
|
528
550
|
const fm_id = fm_prop.slice(0, fm_prop.indexOf(":"));
|
@@ -543,6 +565,9 @@
|
|
543
565
|
fm_contains_title = true;
|
544
566
|
doc_title = fm_val.trim();
|
545
567
|
}
|
568
|
+
if (fm_id.trim() === "status") {
|
569
|
+
fm_status = true;
|
570
|
+
}
|
546
571
|
if (fm_id.trim() === "type") {
|
547
572
|
doc_type = fm_val.trim();
|
548
573
|
}
|
@@ -563,6 +588,14 @@
|
|
563
588
|
value: doc_type,
|
564
589
|
});
|
565
590
|
|
591
|
+
// Add status if we don't have one defined and the nav tree defines the document as draft
|
592
|
+
if (!fm_status && is_draft) {
|
593
|
+
fm_headers.push({
|
594
|
+
id: "status",
|
595
|
+
value: "draft"
|
596
|
+
});
|
597
|
+
}
|
598
|
+
|
566
599
|
// Does frontmatter tag contain a title property
|
567
600
|
if (!fm_contains_title) {
|
568
601
|
// Frontmatter tags don't contain a title property - go pull the first one from the html heading tags
|
@@ -791,7 +824,6 @@
|
|
791
824
|
}
|
792
825
|
|
793
826
|
const index_data = hdoc_index.transform_html_for_index(html_txt);
|
794
|
-
|
795
827
|
for (section of index_data.sections) {
|
796
828
|
index_records.push({
|
797
829
|
relative_path: relative_path,
|
@@ -807,6 +839,7 @@
|
|
807
839
|
md5: file_path.hash,
|
808
840
|
lastmod: last_commit !== null ? last_commit : file_path.hb_lastmod,
|
809
841
|
inline: inline_content,
|
842
|
+
status: index_data.fm_props.status ? index_data.fm_props.status : 'release',
|
810
843
|
});
|
811
844
|
}
|
812
845
|
|
@@ -1269,6 +1302,10 @@
|
|
1269
1302
|
}
|
1270
1303
|
console.log("Processing navigation breadcrumbs...");
|
1271
1304
|
const bc_build = hdoc.build_breadcrumbs(hdocbook_config.navigation.items);
|
1305
|
+
|
1306
|
+
console.log("Getting list of draft links to exclude from the build...");
|
1307
|
+
draft_links.push(...hdoc.get_draft_links(hdocbook_config.navigation.items));
|
1308
|
+
|
1272
1309
|
if (bc_build.errors.length > 0) {
|
1273
1310
|
console.log("\r\n-----------------------");
|
1274
1311
|
console.log(" Validation Output ");
|
@@ -1282,6 +1319,7 @@
|
|
1282
1319
|
}
|
1283
1320
|
bc = bc_build.bc;
|
1284
1321
|
console.log("Processing content...");
|
1322
|
+
|
1285
1323
|
// Get a list of MD files in work_path
|
1286
1324
|
dree.scan(work_path, dreeOptions, build_file_callback);
|
1287
1325
|
|
@@ -1355,6 +1393,7 @@
|
|
1355
1393
|
prods_supported,
|
1356
1394
|
gen_exclude,
|
1357
1395
|
redirects,
|
1396
|
+
draft_links,
|
1358
1397
|
);
|
1359
1398
|
if (!validation_success) {
|
1360
1399
|
const end_time = Date.now();
|