hdoc-tools 0.7.25 → 0.7.27
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/custom_modules/tips.js +78 -61
- package/hdoc-build.js +140 -22
- package/hdoc-db.js +39 -49
- package/hdoc-module.js +43 -1
- package/hdoc-serve.js +6 -2
- package/hdoc.js +12 -41
- package/package.json +1 -1
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/custom_modules/tips.js
CHANGED
|
@@ -1,69 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
(function () {
|
|
2
|
+
'use strict';
|
|
2
3
|
|
|
3
|
-
// GS: based on markdown-it-tips extension but customized for our specific needs
|
|
4
|
+
// GS: based on markdown-it-tips extension but customized for our specific needs
|
|
4
5
|
|
|
5
|
-
var container = require('markdown-it-container');
|
|
6
|
+
var container = require('markdown-it-container');
|
|
6
7
|
|
|
7
|
-
module.exports = function md_tip_plugin(md, options) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
module.exports = function md_tip_plugin(md, options) {
|
|
9
|
+
var containerOpenCount = 0;
|
|
10
|
+
var links = options ? options.links : true;
|
|
11
|
+
init();
|
|
12
|
+
return;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
function icon_from_type(name) {
|
|
15
|
+
switch (name) {
|
|
16
|
+
case "note":
|
|
17
|
+
return {
|
|
18
|
+
class: "bi bi-exclamation-circle", title: "Note"
|
|
19
|
+
};
|
|
20
|
+
case "tip":
|
|
21
|
+
return {
|
|
22
|
+
class: "bi bi-lightbulb", title: "Tip"
|
|
23
|
+
};
|
|
24
|
+
case "important":
|
|
25
|
+
return {
|
|
26
|
+
class: "bi bi-megaphone", title: "Important"
|
|
27
|
+
};
|
|
28
|
+
case "caution":
|
|
29
|
+
return {
|
|
30
|
+
class: "bi bi-x-circle", title: "Caution"
|
|
31
|
+
};
|
|
32
|
+
case "warning":
|
|
33
|
+
return {
|
|
34
|
+
class: "bi bi-exclamation-triangle", title: "Warning"
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function setupContainer(name) {
|
|
40
|
+
md.use(container, name, {
|
|
41
|
+
render: function (tokens, idx) {
|
|
42
|
+
if (tokens[idx].nesting === 1) {
|
|
43
|
+
containerOpenCount += 1;
|
|
44
|
+
let inf = icon_from_type(name);
|
|
45
|
+
return '<div class="hdoc-alert alert-icon-' + name + '">\n<p class="hdoc-alert-title"><span class="' + inf.class + '"></span>' + inf.title + '</p>\n';
|
|
46
|
+
} else {
|
|
47
|
+
containerOpenCount -= 1;
|
|
48
|
+
return '</div>\n';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isContainerOpen() {
|
|
55
|
+
return containerOpenCount > 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function selfRender(tokens, idx, options, env, self) {
|
|
59
|
+
return self.renderToken(tokens, idx, options);
|
|
20
60
|
}
|
|
21
|
-
}
|
|
22
61
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return '<div class="hdoc-alert alert-icon-' + name + '">\n<p class="hdoc-alert-title"><span class="' + inf.class + '"></span>' + inf.title + '</p>\n';
|
|
30
|
-
} else {
|
|
31
|
-
containerOpenCount -= 1;
|
|
32
|
-
return '</div>\n';
|
|
62
|
+
function setupLinks() {
|
|
63
|
+
var defaultRender = md.renderer.rules.link_open || selfRender;
|
|
64
|
+
|
|
65
|
+
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
|
66
|
+
if (isContainerOpen()) {
|
|
67
|
+
tokens[idx].attrPush(['class', 'md-tip-link']);
|
|
33
68
|
}
|
|
69
|
+
|
|
70
|
+
return defaultRender(tokens, idx, options, env, self);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function init() {
|
|
75
|
+
setupContainer('note');
|
|
76
|
+
setupContainer('tip');
|
|
77
|
+
setupContainer('important');
|
|
78
|
+
setupContainer('caution');
|
|
79
|
+
setupContainer('warning');
|
|
80
|
+
|
|
81
|
+
if (links) {
|
|
82
|
+
setupLinks();
|
|
34
83
|
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function isContainerOpen() {
|
|
39
|
-
return containerOpenCount > 0;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function selfRender(tokens, idx, options, env, self) {
|
|
43
|
-
return self.renderToken(tokens, idx, options);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function setupLinks() {
|
|
47
|
-
var defaultRender = md.renderer.rules.link_open || selfRender;
|
|
48
|
-
|
|
49
|
-
md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
|
|
50
|
-
if (isContainerOpen()) {
|
|
51
|
-
tokens[idx].attrPush(['class', 'md-tip-link']);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return defaultRender(tokens, idx, options, env, self);
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function init() {
|
|
59
|
-
setupContainer('note');
|
|
60
|
-
setupContainer('tip');
|
|
61
|
-
setupContainer('important');
|
|
62
|
-
setupContainer('caution');
|
|
63
|
-
setupContainer('warning');
|
|
64
|
-
|
|
65
|
-
if (links) {
|
|
66
|
-
setupLinks();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
})();
|
package/hdoc-build.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
const { stat } = require('fs');
|
|
2
|
+
|
|
1
3
|
(function () {
|
|
2
4
|
'use strict';
|
|
3
5
|
|
|
4
6
|
const dree = require('dree'),
|
|
5
7
|
fs = require('fs-extra'),
|
|
8
|
+
mdfm = require('markdown-it-front-matter'),
|
|
6
9
|
path = require('path'),
|
|
7
10
|
URL = require("url").URL,
|
|
8
11
|
validate = require(path.join(__dirname, 'hdoc-validate.js')),
|
|
9
12
|
hdoc = require(path.join(__dirname, 'hdoc-module.js')),
|
|
10
13
|
zipper = require('zip-local');
|
|
11
|
-
|
|
14
|
+
|
|
15
|
+
const h_tags_to_search = ['h1', 'h2', 'h3'];
|
|
12
16
|
|
|
13
17
|
let conversion_attempted = 0,
|
|
14
18
|
conversion_success = 0,
|
|
@@ -17,9 +21,79 @@
|
|
|
17
21
|
includes_success = 0,
|
|
18
22
|
includes_failed = 0,
|
|
19
23
|
docId = '',
|
|
20
|
-
md_files = []
|
|
24
|
+
md_files = [],
|
|
25
|
+
static_html_files = [];
|
|
26
|
+
|
|
27
|
+
const transform_html = function(file_path) {
|
|
28
|
+
if (fs.existsSync(file_path)) {
|
|
29
|
+
// Load HTML file
|
|
30
|
+
let html_txt = fs.readFileSync(file_path, 'utf8');
|
|
31
|
+
html_txt = html_txt.replace(/\r/gm,''); // Remove CR's so we're just dealing with newlines
|
|
32
|
+
|
|
33
|
+
let html_txt_updated = false;
|
|
34
|
+
|
|
35
|
+
// Check if we have a frontmatter comment
|
|
36
|
+
const fm_header = hdoc.getHTMLFrontmatterHeader(html_txt);
|
|
37
|
+
if (fm_header.fm_properties.length > 0 ) {
|
|
38
|
+
// We have some frontmatter headers, check if title is one of them
|
|
39
|
+
let fm_title_found = false;
|
|
40
|
+
for (let i = 0; i < fm_header.fm_properties.length; i++) {
|
|
41
|
+
if (fm_header.fm_properties[i].key.toLowerCase() === 'title') {
|
|
42
|
+
|
|
43
|
+
// We have a title - bur does the title have a value
|
|
44
|
+
if (fm_header.fm_properties[i].value === '') {
|
|
45
|
+
// No value - remove title from the properties array
|
|
46
|
+
// so we don't end up with 2 title properties, one empty and one with a value
|
|
47
|
+
fm_header.fm_properties.splice(i, 1);
|
|
48
|
+
} else {
|
|
49
|
+
// We have a value for the title property
|
|
50
|
+
fm_title_found = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!fm_title_found) {
|
|
56
|
+
// No frontmatter title found in properties
|
|
57
|
+
// Go get title from h tags in html
|
|
58
|
+
const html_heading = hdoc.getFirstHTMLHeading(html_txt, h_tags_to_search);
|
|
59
|
+
|
|
60
|
+
if (html_heading && html_heading[0] && html_heading[0].children && html_heading[0].children[0] && html_heading[0].children[0].data) {
|
|
61
|
+
// We've found a heading tag, add that as a title to the existing frontmatter properties
|
|
62
|
+
let frontmatter_header = `[[FRONTMATTER\ntitle: ${html_heading[0].children[0].data}`;
|
|
63
|
+
fm_header.fm_properties.forEach(function(fm_prop){
|
|
64
|
+
frontmatter_header += `\n${fm_prop.key}: ${fm_prop.value}`;
|
|
65
|
+
});
|
|
66
|
+
frontmatter_header += '\n]]';
|
|
67
|
+
html_txt = html_txt.replace(fm_header.fm_header, frontmatter_header);
|
|
68
|
+
html_txt_updated = true;
|
|
69
|
+
} else {
|
|
70
|
+
// No header tag, no frontmatter title, output a warning
|
|
71
|
+
console.log(`No frontmatter title property, or ${h_tags_to_search.join(', ')} tags detected in ${file_path}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
// We have no frontmatter headers, get and build one from the html headings
|
|
76
|
+
const html_heading = hdoc.getFirstHTMLHeading(html_txt, h_tags_to_search);
|
|
77
|
+
if (html_heading && html_heading[0] && html_heading[0].children && html_heading[0].children[0] && html_heading[0].children[0].data) {
|
|
78
|
+
// We've found a heading tag, add that as a title to the frontmatter content
|
|
79
|
+
const frontmatter_header = `<!--[[FRONTMATTER\r\ntitle: ${html_heading[0].children[0].data}\r\n]]-->\r\n`;
|
|
80
|
+
html_txt = frontmatter_header + html_txt;
|
|
81
|
+
html_txt_updated = true;
|
|
82
|
+
} else {
|
|
83
|
+
// No header tag, no frontmatter title, output a warning
|
|
84
|
+
console.log(`No frontmatter title property, or ${h_tags_to_search.join(', ')} tags detected in ${file_path}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (html_txt_updated) {
|
|
88
|
+
// Save HTML into HTML file
|
|
89
|
+
fs.writeFile(file_path, html_txt, function writeJSON(err) {
|
|
90
|
+
if (err) return console.log('Error writing:', target_file, '\r\n', err);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
21
95
|
|
|
22
|
-
const transform_markdown_and_save_html = function (file_path
|
|
96
|
+
const transform_markdown_and_save_html = function (file_path) {
|
|
23
97
|
conversion_attempted++;
|
|
24
98
|
if (fs.existsSync(file_path)) {
|
|
25
99
|
// Load markdown file
|
|
@@ -37,29 +111,54 @@
|
|
|
37
111
|
}
|
|
38
112
|
}
|
|
39
113
|
|
|
40
|
-
|
|
114
|
+
// One markdown parser per file. Seems wrong, but doesn't work with a global one once past the first md file
|
|
115
|
+
// Steve - revisit this
|
|
41
116
|
const md = require('markdown-it')({
|
|
42
|
-
// enable everything
|
|
43
117
|
html: true,
|
|
44
118
|
linkify: true,
|
|
45
|
-
typographer: true
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// } catch (__) {}
|
|
51
|
-
// }
|
|
52
|
-
// }
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
var frontmatter_content = "";
|
|
119
|
+
typographer: true
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Process Frontmatter tags
|
|
123
|
+
let frontmatter_content = "";
|
|
56
124
|
md.use(mdfm, function (fm) {
|
|
57
125
|
frontmatter_content = fm;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Process tips
|
|
129
|
+
const tips = require(__dirname + '/custom_modules/tips.js');
|
|
130
|
+
md.use(tips, {
|
|
131
|
+
links: true
|
|
58
132
|
});
|
|
59
|
-
|
|
133
|
+
|
|
60
134
|
// Render markdown into HTML
|
|
61
|
-
|
|
135
|
+
let html_txt = md.render(md_txt.toString());
|
|
62
136
|
|
|
137
|
+
// Does frontmatter tag contain a title property
|
|
138
|
+
let fm_contains_title = false;
|
|
139
|
+
let fm_content = frontmatter_content.split(/\r?\n/);
|
|
140
|
+
if (fm_content.length >= 0) {
|
|
141
|
+
fm_content.forEach(function(fm_prop){
|
|
142
|
+
const fm_property = fm_prop.split(':');
|
|
143
|
+
if (fm_property[0] && fm_property[0] === 'title' && fm_property[1] && fm_property[1].length > 0) fm_contains_title = true;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!fm_contains_title) {
|
|
148
|
+
// Frontmatter tags don't contain a title property - go pull the first one from the html heading tags
|
|
149
|
+
const html_heading = hdoc.getFirstHTMLHeading(html_txt, h_tags_to_search);
|
|
150
|
+
|
|
151
|
+
if (html_heading && html_heading[0] && html_heading[0].children && html_heading[0].children[0] && html_heading[0].children[0].data) {
|
|
152
|
+
// We've found a heading tag, add that as a title to the frontmatter content
|
|
153
|
+
if (frontmatter_content.length > 0) frontmatter_content += '\r\n';
|
|
154
|
+
frontmatter_content += `title: ${html_heading[0].children[0].data}`;
|
|
155
|
+
} else {
|
|
156
|
+
// No header tag, no frontmatter title, output a warning
|
|
157
|
+
console.log(`No frontmatter title property, or h1, h2 or h3 header tags detected in ${file_path}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Add frontmatter tags as comment to front of HTML
|
|
63
162
|
if (frontmatter_content.length) {
|
|
64
163
|
html_txt = "<!--[[FRONTMATTER\r\n" + frontmatter_content + "\r\n]]-->\r\n" + html_txt;
|
|
65
164
|
}
|
|
@@ -69,6 +168,13 @@
|
|
|
69
168
|
fs.writeFile(target_file, html_txt, function writeJSON(err) {
|
|
70
169
|
if (err) return console.log('Error writing:', target_file, '\r\n', err);
|
|
71
170
|
});
|
|
171
|
+
|
|
172
|
+
// Delete MD file from _work path
|
|
173
|
+
try {
|
|
174
|
+
fs.unlinkSync(file_path);
|
|
175
|
+
} catch (e) {
|
|
176
|
+
console.log(`Error deleting ${file_path}: ${e}`);
|
|
177
|
+
}
|
|
72
178
|
conversion_success++;
|
|
73
179
|
return true;
|
|
74
180
|
}
|
|
@@ -79,13 +185,17 @@
|
|
|
79
185
|
|
|
80
186
|
// File callbacks for scans
|
|
81
187
|
const fileCallback = function (element) {
|
|
82
|
-
|
|
188
|
+
if (element.extension === 'md') {
|
|
189
|
+
md_files.push(element.path);
|
|
190
|
+
} else {
|
|
191
|
+
static_html_files.push(element.path);
|
|
192
|
+
}
|
|
83
193
|
};
|
|
84
194
|
|
|
85
195
|
const dreeOptions = {
|
|
86
196
|
descendants: true,
|
|
87
197
|
depth: 10,
|
|
88
|
-
extensions: ['md'],
|
|
198
|
+
extensions: ['md','html','htm'],
|
|
89
199
|
hash: false,
|
|
90
200
|
normalize: true,
|
|
91
201
|
size: false,
|
|
@@ -94,7 +204,7 @@
|
|
|
94
204
|
symbolicLinks: false
|
|
95
205
|
};
|
|
96
206
|
|
|
97
|
-
exports.run = function (source_path,
|
|
207
|
+
exports.run = function (source_path, verbose) {
|
|
98
208
|
// GERRY: The purpose of this function is to create a zip file containing the hdocbook content,
|
|
99
209
|
// * Create a _work folder
|
|
100
210
|
// * copy the hdocbook content to the work folder
|
|
@@ -145,8 +255,14 @@
|
|
|
145
255
|
|
|
146
256
|
// Work through MD files and convert to HTML
|
|
147
257
|
md_files.forEach(function (md_file) {
|
|
148
|
-
transform_markdown_and_save_html(md_file
|
|
258
|
+
transform_markdown_and_save_html(md_file);
|
|
149
259
|
});
|
|
260
|
+
|
|
261
|
+
// Work through Static HTML files and add Frontmatter tags
|
|
262
|
+
static_html_files.forEach(function(static_html_file){
|
|
263
|
+
transform_html(static_html_file);
|
|
264
|
+
});
|
|
265
|
+
|
|
150
266
|
console.log(` MD files found: ${conversion_attempted}`);
|
|
151
267
|
console.log(`Successfully converted to HTML: ${conversion_success}`);
|
|
152
268
|
console.log(` Failed to convert: ${conversion_failed}\r\n`);
|
|
@@ -154,6 +270,8 @@
|
|
|
154
270
|
console.log(` Includes Success: ${includes_success}`);
|
|
155
271
|
console.log(` Includes Failed: ${includes_failed}\r\n`);
|
|
156
272
|
|
|
273
|
+
console.log(` Static HTML Files Found: ${static_html_files.length}\r\n`);
|
|
274
|
+
|
|
157
275
|
const validation_success = validate.run(work_path, docId, verbose);
|
|
158
276
|
if (!validation_success) {
|
|
159
277
|
process.exit(1);
|
package/hdoc-db.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
nextTick
|
|
3
|
+
} = require('process');
|
|
2
4
|
|
|
3
|
-
(function() {
|
|
5
|
+
(function () {
|
|
4
6
|
'use strict';
|
|
5
7
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const dree = require('dree'),
|
|
9
|
+
fs = require('fs-extra'),
|
|
10
|
+
html2text = require('html-to-text'),
|
|
11
|
+
sqlite3 = require('sqlite3'),
|
|
12
|
+
path = require('path'),
|
|
13
|
+
hdoc = require(path.join(__dirname, 'hdoc-module.js'));
|
|
11
14
|
|
|
12
|
-
const
|
|
15
|
+
const table_name = 'hbdocs';
|
|
13
16
|
|
|
14
|
-
let
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
let db_name = 'hbdocs.db',
|
|
18
|
+
hdocbook_meta = null,
|
|
19
|
+
md_files = [];
|
|
17
20
|
|
|
18
21
|
// File callbacks for scan
|
|
19
22
|
const file_callback = function (element) {
|
|
@@ -25,7 +28,7 @@ const { nextTick } = require('process');
|
|
|
25
28
|
}
|
|
26
29
|
};
|
|
27
30
|
|
|
28
|
-
const create_table = function(db) {
|
|
31
|
+
const create_table = function (db) {
|
|
29
32
|
db.exec(`
|
|
30
33
|
create table ${table_name} (
|
|
31
34
|
relative_url text primary key not null,
|
|
@@ -35,7 +38,7 @@ const { nextTick } = require('process');
|
|
|
35
38
|
tags text null,
|
|
36
39
|
audience text not null
|
|
37
40
|
);
|
|
38
|
-
`, (err)
|
|
41
|
+
`, (err) => {
|
|
39
42
|
if (err !== null) {
|
|
40
43
|
console.error(`Error creating table [${table_name}]: ${err}`);
|
|
41
44
|
return false;
|
|
@@ -47,8 +50,10 @@ const { nextTick } = require('process');
|
|
|
47
50
|
return true;
|
|
48
51
|
};
|
|
49
52
|
|
|
50
|
-
const build_db = function(db, md, book_def, md_files) {
|
|
53
|
+
const build_db = function (db, md, book_def, md_files) {
|
|
51
54
|
for (let i = 0; i < md_files.length; i++) {
|
|
55
|
+
|
|
56
|
+
const content = transform_markdown(md_files[i].path, md);
|
|
52
57
|
db.exec(`
|
|
53
58
|
insert into ${table_name}
|
|
54
59
|
(book_id, title, relative_url, content, tags, audience)
|
|
@@ -57,13 +62,13 @@ const { nextTick } = require('process');
|
|
|
57
62
|
'${book_def.docId}',
|
|
58
63
|
'${book_def.title}',
|
|
59
64
|
'${md_files[i].relativePath}',
|
|
60
|
-
'
|
|
65
|
+
'${content}',
|
|
61
66
|
'${book_def.tags.join(';')}',
|
|
62
67
|
'${book_def.audience.join(';')}'
|
|
63
68
|
);
|
|
64
|
-
`, (err)
|
|
69
|
+
`, (err) => {
|
|
65
70
|
if (err !== null) {
|
|
66
|
-
console.error(`Error inserting record [${md_files[i].relativePath}]
|
|
71
|
+
console.error(` Error inserting record: [${md_files[i].relativePath}] ${err}`);
|
|
67
72
|
return false;
|
|
68
73
|
} else {
|
|
69
74
|
console.log(` Record inserted successfully: ${md_files[i].relativePath}`);
|
|
@@ -73,43 +78,28 @@ const { nextTick } = require('process');
|
|
|
73
78
|
}
|
|
74
79
|
};
|
|
75
80
|
|
|
76
|
-
const transform_markdown
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let md_txt = hdoc.expand_variables(fs.readFileSync(file_path, 'utf8'));
|
|
80
|
-
|
|
81
|
-
// Pull in external includes
|
|
82
|
-
const includes_processed = hdoc.process_includes(file_path, md_txt);
|
|
83
|
-
md_txt = includes_processed.body;
|
|
84
|
-
includes_found += includes_processed.found;
|
|
85
|
-
includes_success += includes_processed.success;
|
|
86
|
-
includes_failed += includes_processed.failed;
|
|
87
|
-
if (includes_processed.errors.length > 0) {
|
|
88
|
-
for (let i = 0; i < includes_processed.errors.length; i++) {
|
|
89
|
-
console.error(includes_processed.errors[i]);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
81
|
+
const transform_markdown = function (file_path, md) {
|
|
82
|
+
// Load markdown file
|
|
83
|
+
let md_txt = hdoc.expand_variables(fs.readFileSync(file_path, 'utf8'));
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
// Pull in external includes
|
|
86
|
+
const includes_processed = hdoc.process_includes(file_path, md_txt);
|
|
87
|
+
md_txt = includes_processed.body;
|
|
95
88
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
conversion_failed++;
|
|
105
|
-
console.error('MD file does not exist:', file_path);
|
|
106
|
-
return false;
|
|
89
|
+
// Render markdown into HTML
|
|
90
|
+
var html_txt = md.render(md_txt.toString());
|
|
91
|
+
|
|
92
|
+
// Convert HTML into plain text
|
|
93
|
+
const text = html2text.convert(html_txt, {
|
|
94
|
+
wordwrap: null
|
|
95
|
+
});
|
|
96
|
+
return text;
|
|
107
97
|
};
|
|
108
98
|
|
|
109
99
|
const dree_options = {
|
|
110
100
|
descendants: true,
|
|
111
101
|
depth: 10,
|
|
112
|
-
extensions: ['md','json'],
|
|
102
|
+
extensions: ['md', 'json'],
|
|
113
103
|
hash: false,
|
|
114
104
|
normalize: true,
|
|
115
105
|
size: false,
|
|
@@ -118,7 +108,7 @@ const { nextTick } = require('process');
|
|
|
118
108
|
symbolicLinks: false
|
|
119
109
|
};
|
|
120
110
|
|
|
121
|
-
exports.run = function(source_path, md) {
|
|
111
|
+
exports.run = function (source_path, md) {
|
|
122
112
|
/*
|
|
123
113
|
STEVE - The purpose of this command is to allow content developers to do local builds of
|
|
124
114
|
the SQlite database and index file, for validation before commit and build
|
|
@@ -151,7 +141,7 @@ const { nextTick } = require('process');
|
|
|
151
141
|
console.log(`DB file created successfully: ${db_name}`);
|
|
152
142
|
if (create_table(db)) {
|
|
153
143
|
if (!hdocbook_meta.tags) hdocbook_meta.tags = [];
|
|
154
|
-
build_db(db, md, hdocbook_meta, md_files
|
|
144
|
+
build_db(db, md, hdocbook_meta, md_files);
|
|
155
145
|
}
|
|
156
146
|
});
|
|
157
147
|
};
|
package/hdoc-module.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const cheerio = require('cheerio'),
|
|
5
|
+
request = require('sync-request');
|
|
5
6
|
|
|
6
7
|
let includesCache = {};
|
|
7
8
|
|
|
@@ -143,4 +144,45 @@
|
|
|
143
144
|
response.body = body;
|
|
144
145
|
return response;
|
|
145
146
|
};
|
|
147
|
+
|
|
148
|
+
// Takes html, returns the first heading detected in the order provided in h_to_search
|
|
149
|
+
// Looks for h1 tags first, then hX, hY, hZ in order
|
|
150
|
+
exports.getFirstHTMLHeading = function (html_body, h_to_search = ['h1']) {
|
|
151
|
+
const $ = cheerio.load(html_body);
|
|
152
|
+
for (let i = 0; i < h_to_search.length; i++) {
|
|
153
|
+
let heading = $(h_to_search[i]).map(function (i) {
|
|
154
|
+
return $(this);
|
|
155
|
+
}).get();
|
|
156
|
+
if (heading.length > 0) {
|
|
157
|
+
return heading[0];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
exports.getHTMLFrontmatterHeader = function(html_body) {
|
|
164
|
+
let response = {
|
|
165
|
+
fm_header: '',
|
|
166
|
+
fm_properties: []
|
|
167
|
+
};
|
|
168
|
+
const $ = cheerio.load(html_body, { decodeEntities: false });
|
|
169
|
+
if ($._root && $._root.children && $._root.children instanceof Array && $._root.children.length > 0) {
|
|
170
|
+
$._root.children.forEach(function(child){
|
|
171
|
+
if (child.type === 'comment' && child.data && child.data.startsWith('[[FRONTMATTER')) {
|
|
172
|
+
// We have a Frontmatter header - return each property in an array
|
|
173
|
+
const fm_properties = child.data.split(/\r?\n/);
|
|
174
|
+
for (let i = 0; i < fm_properties.length; i++) {
|
|
175
|
+
const property_details = fm_properties[i].split(':', 2);
|
|
176
|
+
if (property_details.length > 1) {
|
|
177
|
+
response.fm_properties.push({key: property_details[0].trim(), value: property_details[1].trim()});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// And return the header as a whole so it can be easily replaced
|
|
182
|
+
response.fm_header = child.data;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return response;
|
|
187
|
+
};
|
|
146
188
|
})();
|
package/hdoc-serve.js
CHANGED
|
@@ -92,7 +92,6 @@
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
const mdfm = require('markdown-it-front-matter');
|
|
96
95
|
const md = require('markdown-it')({
|
|
97
96
|
// enable everything
|
|
98
97
|
html: true,
|
|
@@ -106,12 +105,17 @@
|
|
|
106
105
|
// }
|
|
107
106
|
// }
|
|
108
107
|
});
|
|
109
|
-
|
|
108
|
+
|
|
110
109
|
var frontmatter_content = "";
|
|
111
110
|
md.use(mdfm, function (fm) {
|
|
112
111
|
frontmatter_content = fm;
|
|
113
112
|
});
|
|
114
113
|
|
|
114
|
+
const tips = require(__dirname + '/custom_modules/tips.js');
|
|
115
|
+
md.use(tips, {
|
|
116
|
+
links: true
|
|
117
|
+
});
|
|
118
|
+
|
|
115
119
|
// Render markdown into HTML
|
|
116
120
|
var html_txt = md.render(md_txt.toString());
|
|
117
121
|
|
package/hdoc.js
CHANGED
|
@@ -1,37 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { createCipheriv } = require('crypto');
|
|
1
|
+
#!/usr/bin/env node
|
|
4
2
|
|
|
5
3
|
(function () {
|
|
6
4
|
'use strict';
|
|
7
5
|
|
|
8
|
-
const preRun = require('./validateNodeVer.js')
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const stream = require('stream');
|
|
12
|
-
const yaml = require('js-yaml');
|
|
13
|
-
const mdfm = require('markdown-it-front-matter');
|
|
14
|
-
const hljs = require('highlight.js'); // https://highlightjs.org/
|
|
15
|
-
const md = require('markdown-it')({
|
|
16
|
-
// enable everything
|
|
17
|
-
html: true,
|
|
18
|
-
linkify: true,
|
|
19
|
-
typographer: true,
|
|
20
|
-
// highlight: function (str, lang) {
|
|
21
|
-
// if (lang && hljs.getLanguage(lang)) {
|
|
22
|
-
// try {
|
|
23
|
-
// return hljs.highlight(lang, str, true).value;
|
|
24
|
-
// } catch (__) {}
|
|
25
|
-
// }
|
|
26
|
-
// }
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
var frontmatter_content;
|
|
30
|
-
md.use(mdfm, function (fm) {
|
|
31
|
-
frontmatter_content = fm;
|
|
32
|
-
});
|
|
6
|
+
const preRun = require('./validateNodeVer.js'),
|
|
7
|
+
fs = require('fs'),
|
|
8
|
+
path = require('path');
|
|
33
9
|
|
|
34
10
|
const packageFile = path.join(__dirname, 'package.json');
|
|
11
|
+
|
|
35
12
|
const getHdocPackageVersion = function (packagePath) {
|
|
36
13
|
if (fs.existsSync(packagePath)) {
|
|
37
14
|
try {
|
|
@@ -44,19 +21,13 @@ const { createCipheriv } = require('crypto');
|
|
|
44
21
|
console.error('Package file not found: ', packagePath);
|
|
45
22
|
}
|
|
46
23
|
};
|
|
47
|
-
const tips = require(__dirname + '/custom_modules/tips.js');
|
|
48
|
-
|
|
49
|
-
md.use(tips, {
|
|
50
|
-
links: true
|
|
51
|
-
});
|
|
52
24
|
|
|
53
25
|
// Default source path to working directory
|
|
54
26
|
let source_path = process.cwd();
|
|
55
27
|
let ui_path = path.join(__dirname, 'ui');
|
|
56
28
|
|
|
57
|
-
let
|
|
58
|
-
|
|
59
|
-
build_index = false;
|
|
29
|
+
let command = '', // Our command to run
|
|
30
|
+
verbose = false;
|
|
60
31
|
|
|
61
32
|
// Get options from command args
|
|
62
33
|
for (let x = 0; x < process.argv.length; x++) {
|
|
@@ -93,22 +64,22 @@ const { createCipheriv } = require('crypto');
|
|
|
93
64
|
|
|
94
65
|
if (command == 'serve') {
|
|
95
66
|
const server = require(path.join(__dirname, 'hdoc-serve.js'));
|
|
96
|
-
server.run(ui_path, source_path
|
|
67
|
+
server.run(ui_path, source_path);
|
|
97
68
|
} else if (command == 'build') {
|
|
98
69
|
const builder = require(path.join(__dirname, 'hdoc-build.js'));
|
|
99
|
-
builder.run(source_path,
|
|
70
|
+
builder.run(source_path, verbose);
|
|
100
71
|
} else if (command == 'stats') {
|
|
101
72
|
const stats = require(path.join(__dirname, 'hdoc-stats.js'));
|
|
102
|
-
stats.run(ui_path, source_path,
|
|
73
|
+
stats.run(ui_path, source_path, verbose);
|
|
103
74
|
} else if (command == 'init') {
|
|
104
75
|
const init = require(path.join(__dirname, 'hdoc-init.js'));
|
|
105
|
-
init.run(__dirname, source_path
|
|
76
|
+
init.run(__dirname, source_path);
|
|
106
77
|
} else if (command == 'help') {
|
|
107
78
|
const help = require(path.join(__dirname, 'hdoc-help.js'));
|
|
108
79
|
help.run();
|
|
109
80
|
} else if (command == 'buildindex') {
|
|
110
81
|
const build_db = require(path.join(__dirname, 'hdoc-db.js'));
|
|
111
|
-
build_db.run(source_path
|
|
82
|
+
build_db.run(source_path);
|
|
112
83
|
} else {
|
|
113
84
|
console.log('Unknown command:', command, '\r\n');
|
|
114
85
|
console.log('Run hdoc help for information regarding this tool.\r\n');
|