hdoc-tools 0.5.0 → 0.6.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.js CHANGED
@@ -1,15 +1,18 @@
1
+ (function () {
2
+ 'use strict';
1
3
 
2
- exports.run = function(ui_path, source_path, md) {
3
-
4
- // GERRY: The purpose of this function is to create a zip file containing the hdocbook content,
5
- // * Create a _work folder
6
- // * copy the hdocbook content to the work folder
7
- // * Render all markdown into side-by-side HTML file
8
- // * Replace SERVER_VARS embedded in documents with the right base path, version information etc.
9
- // * Build an index (sqlite FTS5) by extracting text from all HTML content in the work
10
- // folder, conceptually we are making a little mini websirte crawler to index all of the content
11
- // within the book.
12
- // * Package everything up into a ZIP file, ready for the build controller to package and publish
4
+ exports.run = function(ui_path, source_path, md) {
5
+
6
+ // GERRY: The purpose of this function is to create a zip file containing the hdocbook content,
7
+ // * Create a _work folder
8
+ // * copy the hdocbook content to the work folder
9
+ // * Render all markdown into side-by-side HTML file
10
+ // * Replace SERVER_VARS embedded in documents with the right base path, version information etc.
11
+ // * Build an index (sqlite FTS5) by extracting text from all HTML content in the work
12
+ // folder, conceptually we are making a little mini website crawler to index all of the content
13
+ // within the book.
14
+ // * Package everything up into a ZIP file, ready for the build controller to package and publish
13
15
 
14
- console.log("Build is not yet implemented")
15
- }
16
+ console.log("Build is not yet implemented");
17
+ };
18
+ })();
package/hdoc-serve.js CHANGED
@@ -1,367 +1,363 @@
1
- const fs = require('fs');
2
- var path = require('path');
3
- const stream = require('stream');
4
- var express = require('express');
5
-
6
- exports.run = function(ui_path, source_path, md) {
7
-
8
- console.log("Hornbill HDocBook Preview/Dev Server", "\r\n");
9
- console.log(" Server Path:", __dirname);
10
- console.log(" UI Root Path:", ui_path);
11
- console.log(" Document Path:", source_path, "\r\n");
12
-
13
- // Get an express server instance
14
- var app = express();
15
-
16
- // In the root of the project there is a hdocbook.json file which includes
17
- // the id of the hdocbook we are working with
18
- const hdocbook_project_config_path = path.join(source_path, "hdocbook-project.json");
19
-
20
- // Load the hdocbook config file
21
- var hdocbook_project = require(hdocbook_project_config_path);
22
-
23
- // Get the ID of the hdocbook we are serving
24
- var docId = hdocbook_project.docId;
25
-
26
- // Get the path of the book.json file
27
- const hdocbook_path = path.join(source_path, docId, "hdocbook.json");
28
-
29
- // Pull in the book config file
30
- var hdocbook_config = require(hdocbook_path);
31
- var hdocbook_mtime = fs.statSync(hdocbook_path).mtime;
32
-
33
- app.get('/content/library.json', function (req, res) {
34
- let library = {
35
- books: [
36
- {
37
- docId: hdocbook_config.docId,
38
- title: hdocbook_config.title
39
- }
40
- ]
41
- }
42
- res.setHeader("Content-Type", "application/json");
43
- res.send(JSON.stringify(library, null, 3));
44
- });
45
-
46
-
47
- function content_type_for_ext(ext) {
48
- switch (ext)
49
- {
50
- case ".z":
51
- return "application/x-compress";
52
- case ".tgz":
53
- return "application/x-compressed";
54
- case ".gz":
55
- return "application/x-gzip";
56
- case ".zip":
57
- return "application/x-zip-compressed";
58
- case ".xml":
59
- return "application/xml";
60
- case ".bmp":
61
- return "image/bmp";
62
- case ".gif":
63
- return "image/gif";
64
- case ".jpg":
65
- return "image/jpeg";
66
- case ".png":
67
- return "image/png";
68
- case ".tiff":
69
- return "image/tiff";
70
- case ".ico":
71
- return "image/x-icon";
72
- case ".png":
73
- return "image/png";
74
- case ".svg":
75
- return "image/svg+xml";
76
- case ".css":
77
- return "text/css";
78
- case ".htm":
79
- case ".html":
80
- return "text/html";
81
- case ".txt":
82
- return "text/plain";
83
- case ".md":
84
- return "text/plain";
85
- case ".json":
86
- return "application/json";
87
- case ".js":
88
- return "application/javascript";
89
- default:
90
- return "application/octet-stream";
91
- }
92
- }
93
-
94
- function expand_variables(text) {
95
- // For debug mode our base path is our root??
96
- text = text.replaceAll("{{BASE_PATH}}", "/" + docId);
97
- text = text.replaceAll("{{BUILD_NUMBER}}", "0");
98
-
99
- let build_date = new Date().toISOString();
100
- build_date = build_date.replace('T', ' ');
101
- build_date = build_date.substring(0,19);
102
-
103
- text = text.replaceAll("{{BUILD_DATE}}", build_date);
104
- return text;
105
- }
106
-
107
- function transform_markdown_and_send_html(req, res, file_path) {
108
-
109
- if(fs.existsSync(file_path)) {
110
- // we have a markdown representation of the requested HTML file, transform and return
111
- // it to the caller
112
-
113
- // Load markdown file
114
- let md_txt = expand_variables(fs.readFileSync(file_path).toString());
115
-
116
- // Render markdown into HTML
117
- frontmatter_content = "";
118
- var html_txt = md.render(md_txt.toString());
119
-
120
- if(frontmatter_content.length) {
121
-
122
- const obj = yaml.load(frontmatter_content);
123
-
124
- const buff = Buffer.from(JSON.stringify(obj), 'utf-8');
125
-
126
- const base64 = buff.toString('base64');
127
-
128
- res.setHeader("X-frontmatter", base64);
129
- }
130
-
131
- res.setHeader("Content-Type", "text/html");
132
- res.send(html_txt);
133
- return true;
134
- }
135
- return false;
136
- }
137
-
138
- function send_content_file(req, res, file_path) {
139
- let content_txt = expand_variables(fs.readFileSync(file_path).toString());
140
-
141
- let contentType = content_type_for_ext(path.extname(file_path));
142
-
143
- if(path.extname(file_path) == ".md") {
144
- res.setHeader("Content-Disposition", "inline");
145
- }
146
-
147
- res.setHeader("Content-Type", contentType);
148
-
149
- res.send(content_txt);
150
- }
151
-
152
- function send_file(req, res, file_path) {
153
- // Need to set the content type here??
154
- let contentType = content_type_for_ext(path.extname(file_path));
155
- res.setHeader("Content-Type", contentType);
156
-
157
- const r = fs.createReadStream(file_path)
158
- const ps = new stream.PassThrough()
159
- stream.pipeline(
160
- r,
161
- ps,
162
- (err) => {
163
- if (err) {
164
- console.log(err) // No such file or any other kind of error
165
- return res.sendStatus(400).send("Unexpected error");
166
- }
167
- })
168
- ps.pipe(res)
169
- }
170
-
171
- function send_content_resource_404(req, res) {
172
- res.setHeader("Content-Type", "text/html");
173
- res.status(404).send("Content resource not found");
174
- }
175
-
176
- // 1. If we request a file with a .html file extension, and that file DOES NOT exist,
177
- // we will look for the same file but with a .md extension. If we find that
178
- // corresponding markdown file, we will transform that markdown file to HTML and
179
- // return the HTML content
180
- //
181
- // 2. If we request a file, without any file extension then we will look for that file
182
- // with a .md extension, and if that file exists, we will transform that markdown
183
- // file to HTML and return that file.
184
- //
185
- // For all other requests, we are going to look on the filesystem. If we request
186
- // a specific file with its extension (including .md files), then we will simply
187
- // return the file verbatum as a static file.
188
- //
189
- // If we request a file without an extension and that file does not exist, we will
190
- // assume that is a folder, will append index.html and look for that file, if present
191
- // we will send it, if not present we will look for index.md, and if thats present
192
- // we will transform to HTML and return that
193
- //
194
- // Anything else in this handler will return a 404 error
195
-
196
- app.get('/content/*', function (req, res) {
197
-
198
- let url = req.url;
199
-
200
- let segs = url.split('/');
201
-
202
- if(segs.length == 4 && segs[1] == "content" && segs[3] == "book.json") {
203
- // Special case of a virtual file here, we need to check the book ID and
204
- // if its our book, send the json
205
- if(hdocbook_config.docId == segs[2]) {
206
- res.setHeader("Content-Type", "application/json");
207
- res.send(JSON.stringify(hdocbook_config, null, 3));
208
- } else {
209
- // Return a 404 error here
210
- res.setHeader("Content-Type", "text/html");
211
- res.status(404).send("Specified bookId " + segs[2] + " not found");
212
- }
213
- return;
214
- } else if (segs.length == 3 && segs[1] == "content" && segs[2] == "index.json") {
215
- // For development mode, we always have an index with one book in it, the one being developed
216
- if (hdocbook_config) {
217
- let index = {
218
- books: [
219
- {
220
- docId: hdocbook_config.docId,
221
- title: hdocbook_config.title,
222
- description: hdocbook_config.description,
223
- version: hdocbook_config.version
224
- }
225
- ]
226
- };
227
- res.setHeader("Content-Type", "application/json");
228
- res.send(JSON.stringify(index, null, 3));
229
- } else {
230
- // Return a 404 error here
231
- res.setHeader("Content-Type", "text/html");
232
- res.status(404).send("Specified bookId " + segs[2] + " not found");
233
- }
234
- return;
235
- }
236
-
237
- url = url.replace("/content/", "/");
238
-
239
- console.log("URL Requested: ", url);
240
-
241
- let file_path = path.join(source_path, url);
242
- let ui_file_path = path.join(ui_path, url);
243
-
244
- // If the requested file is found in the UI folder
245
- if(url == "/")
246
- {
247
- if(fs.existsSync(path.join(ui_file_path, "index.html"))) {
248
- // We want the index.html, send it here
249
- send_file(req, res, path.join(ui_file_path, "index.html"));
250
- return;
251
- }
252
- // Return a 404 error here
253
- send_content_resource_404(req, res);
254
- return;
255
- } else if(fs.existsSync(ui_file_path)) {
256
- // File is found in the UI folder, that takes priority, send the file
257
- send_file(req, res, ui_file_path);
258
- return;
259
- }
260
-
261
- if(path.extname(file_path) == ".html") {
262
- // 1a. check for html files, and send/transform as required
263
- if(fs.existsSync(file_path)) {
264
- // HTML file exists on disk, just return it verbatum
265
- res.setHeader("Content-Type", "text/html");
266
- send_file(req, res, file_path);
267
- return true;
268
- }
269
-
270
- if(fs.existsSync(file_path.replace(".html", ".md"))){
271
- if(transform_markdown_and_send_html(req, res, file_path.replace(".html", ".md"))) {
272
- return;
273
- }
274
- }
275
- } else if(path.extname(file_path) == ".md") {
276
- // If the markdown file exists, just send to caller as is
277
- if(fs.existsSync(file_path)) {
278
- send_content_file(req, res, file_path);
279
- return true;
280
- }
281
- } else if(path.extname(file_path).length == 0)
282
- {
283
- // 2. If we request a file, without any file extension
284
- if(fs.existsSync(file_path + ".md")) {
285
- if(transform_markdown_and_send_html(req, res, file_path + ".md")) {
286
- return;
287
- }
288
- } else if(fs.existsSync(path.join(file_path + "index.md"))) {
289
- if(transform_markdown_and_send_html(req, res, path.join(file_path, "index.md"))) {
290
- return;
291
- }
292
- } else if(fs.existsSync(path.join(file_path + "index.html"))) {
293
- console.log("jdhsfkjhdkjfhjkshdkfjhkjsdf", file_path);
294
- res.setHeader("Content-Type", "text/html");
295
- send_content_file(req, res, path.join(file_path + "index.html"));
296
- return;
297
- } else if(fs.existsSync(file_path + "/index.md")) {
298
- if(transform_markdown_and_send_html(req, res, file_path + "/index.md")) {
299
- return;
300
- }
301
- } else if(fs.existsSync(path.join(file_path + "/index.html"))) {
302
- res.setHeader("Content-Type", "text/html");
303
- send_content_file(req, res, path.join(file_path + "/index.html"));
304
- return;
305
- }
306
- } else if(fs.existsSync(file_path)) {
307
- send_file(req, res, file_path);
308
- return;
309
- }
310
-
311
- // Return a 404 error here
312
- send_content_resource_404(req, res);
313
- })
314
-
315
- // Cacth all
316
- app.get('/*', function (req, res) {
317
-
318
- let segs = req.url.split('/');
319
-
320
- if(segs.length > 3 && segs[2] == "content") {
321
- // In this case we are looking for static content within the book
322
-
323
- // Creat the file path
324
- let url = req.url.replace("/content/", "/");
325
- let file_path = path.join(source_path, url);
326
-
327
- // If the file exists, send it.
328
- if(fs.existsSync(file_path) == true) {
329
- send_file(req, res, file_path);
330
- return;
331
- }
332
-
333
- // All else fails, we have not file to return, so return a 404 error here
334
- send_content_resource_404(req, res);
335
- return;
336
- }
337
-
338
- let ui_file_path = path.join(ui_path, req.url);
339
-
340
- console.log("URL Root: ", req.url);
341
-
342
- // To suport the SPA application behaviour, if there is no file extension present, then
343
- // we simply return the /index.html file content to the client
344
- if(path.extname(ui_file_path).length == 0) {
345
- send_content_file(req, res, path.join(ui_path, "index.html"));
346
- return;
347
- }
348
-
349
- // If the file exists, send it.
350
- if(fs.existsSync(ui_file_path) == true) {
351
- send_content_file(req, res, ui_file_path);
352
- return;
353
- }
354
-
355
- // All else fails, we have not file to return, so return a 404 error here
356
- send_content_resource_404(req, res);
357
- });
358
-
359
- var server = app.listen(3000, "0.0.0.0", function () {
360
- var host = server.address().address
361
- var port = server.address().port
362
-
363
- console.log("Server listening at http://%s:%s", host, port)
364
- console.log("Document source path is: " + source_path);
365
- })
366
-
367
- }
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ var path = require('path');
6
+ const stream = require('stream');
7
+ var express = require('express');
8
+
9
+ exports.run = function (ui_path, source_path, md) {
10
+
11
+ console.log("Hornbill HDocBook Preview/Dev Server", "\r\n");
12
+ console.log(" Server Path:", __dirname);
13
+ console.log(" UI Root Path:", ui_path);
14
+ console.log(" Document Path:", source_path, "\r\n");
15
+
16
+ // Get an express server instance
17
+ var app = express();
18
+
19
+ // In the root of the project there is a hdocbook.json file which includes
20
+ // the id of the hdocbook we are working with
21
+ const hdocbook_project_config_path = path.join(source_path, "hdocbook-project.json");
22
+
23
+ // Load the hdocbook config file
24
+ var hdocbook_project = require(hdocbook_project_config_path);
25
+
26
+ // Get the ID of the hdocbook we are serving
27
+ var docId = hdocbook_project.docId;
28
+
29
+ // Get the path of the book.json file
30
+ const hdocbook_path = path.join(source_path, docId, "hdocbook.json");
31
+
32
+ // Pull in the book config file
33
+ var hdocbook_config = require(hdocbook_path);
34
+ var hdocbook_mtime = fs.statSync(hdocbook_path).mtime;
35
+
36
+ app.get('/content/library.json', function (req, res) {
37
+ let library = {
38
+ books: [{
39
+ docId: hdocbook_config.docId,
40
+ title: hdocbook_config.title
41
+ }]
42
+ };
43
+ res.setHeader("Content-Type", "application/json");
44
+ res.send(JSON.stringify(library, null, 3));
45
+ });
46
+
47
+
48
+ function content_type_for_ext(ext) {
49
+ switch (ext) {
50
+ case ".z":
51
+ return "application/x-compress";
52
+ case ".tgz":
53
+ return "application/x-compressed";
54
+ case ".gz":
55
+ return "application/x-gzip";
56
+ case ".zip":
57
+ return "application/x-zip-compressed";
58
+ case ".xml":
59
+ return "application/xml";
60
+ case ".bmp":
61
+ return "image/bmp";
62
+ case ".gif":
63
+ return "image/gif";
64
+ case ".jpg":
65
+ return "image/jpeg";
66
+ case ".png":
67
+ return "image/png";
68
+ case ".tiff":
69
+ return "image/tiff";
70
+ case ".ico":
71
+ return "image/x-icon";
72
+ case ".png":
73
+ return "image/png";
74
+ case ".svg":
75
+ return "image/svg+xml";
76
+ case ".css":
77
+ return "text/css";
78
+ case ".htm":
79
+ case ".html":
80
+ return "text/html";
81
+ case ".txt":
82
+ return "text/plain";
83
+ case ".md":
84
+ return "text/plain";
85
+ case ".json":
86
+ return "application/json";
87
+ case ".js":
88
+ return "application/javascript";
89
+ default:
90
+ return "application/octet-stream";
91
+ }
92
+ }
93
+
94
+ function expand_variables(text) {
95
+ // For debug mode our base path is our root??
96
+ text = text.replaceAll("{{BASE_PATH}}", "/" + docId);
97
+ text = text.replaceAll("{{BUILD_NUMBER}}", "0");
98
+
99
+ let build_date = new Date().toISOString();
100
+ build_date = build_date.replace('T', ' ');
101
+ build_date = build_date.substring(0, 19);
102
+
103
+ text = text.replaceAll("{{BUILD_DATE}}", build_date);
104
+ return text;
105
+ }
106
+
107
+ function transform_markdown_and_send_html(req, res, file_path) {
108
+
109
+ if (fs.existsSync(file_path)) {
110
+ // we have a markdown representation of the requested HTML file, transform and return
111
+ // it to the caller
112
+
113
+ // Load markdown file
114
+ let md_txt = expand_variables(fs.readFileSync(file_path).toString());
115
+
116
+ // Render markdown into HTML
117
+ let frontmatter_content = "";
118
+ var html_txt = md.render(md_txt.toString());
119
+
120
+ if (frontmatter_content.length) {
121
+
122
+ const obj = yaml.load(frontmatter_content);
123
+
124
+ const buff = Buffer.from(JSON.stringify(obj), 'utf-8');
125
+
126
+ const base64 = buff.toString('base64');
127
+
128
+ res.setHeader("X-frontmatter", base64);
129
+ }
130
+
131
+ res.setHeader("Content-Type", "text/html");
132
+ res.send(html_txt);
133
+ return true;
134
+ }
135
+ return false;
136
+ }
137
+
138
+ function send_content_file(req, res, file_path) {
139
+ let content_txt = expand_variables(fs.readFileSync(file_path).toString());
140
+
141
+ let contentType = content_type_for_ext(path.extname(file_path));
142
+
143
+ if (path.extname(file_path) == ".md") {
144
+ res.setHeader("Content-Disposition", "inline");
145
+ }
146
+
147
+ res.setHeader("Content-Type", contentType);
148
+
149
+ res.send(content_txt);
150
+ }
151
+
152
+ function send_file(req, res, file_path) {
153
+ // Need to set the content type here??
154
+ let contentType = content_type_for_ext(path.extname(file_path));
155
+ res.setHeader("Content-Type", contentType);
156
+
157
+ const r = fs.createReadStream(file_path);
158
+ const ps = new stream.PassThrough();
159
+ stream.pipeline(
160
+ r,
161
+ ps,
162
+ (err) => {
163
+ if (err) {
164
+ console.log(err); // No such file or any other kind of error
165
+ return res.sendStatus(400).send("Unexpected error");
166
+ }
167
+ });
168
+ ps.pipe(res);
169
+ }
170
+
171
+ function send_content_resource_404(req, res) {
172
+ res.setHeader("Content-Type", "text/html");
173
+ res.status(404).send("Content resource not found");
174
+ }
175
+
176
+ // 1. If we request a file with a .html file extension, and that file DOES NOT exist,
177
+ // we will look for the same file but with a .md extension. If we find that
178
+ // corresponding markdown file, we will transform that markdown file to HTML and
179
+ // return the HTML content
180
+ //
181
+ // 2. If we request a file, without any file extension then we will look for that file
182
+ // with a .md extension, and if that file exists, we will transform that markdown
183
+ // file to HTML and return that file.
184
+ //
185
+ // For all other requests, we are going to look on the filesystem. If we request
186
+ // a specific file with its extension (including .md files), then we will simply
187
+ // return the file verbatim as a static file.
188
+ //
189
+ // If we request a file without an extension and that file does not exist, we will
190
+ // assume that is a folder, will append index.html and look for that file, if present
191
+ // we will send it, if not present we will look for index.md, and if thats present
192
+ // we will transform to HTML and return that
193
+ //
194
+ // Anything else in this handler will return a 404 error
195
+
196
+ app.get('/content/*', function (req, res) {
197
+
198
+ let url = req.url;
199
+
200
+ let segs = url.split('/');
201
+
202
+ if (segs.length == 4 && segs[1] == "content" && segs[3] == "book.json") {
203
+ // Special case of a virtual file here, we need to check the book ID and
204
+ // if its our book, send the json
205
+ if (hdocbook_config.docId == segs[2]) {
206
+ res.setHeader("Content-Type", "application/json");
207
+ res.send(JSON.stringify(hdocbook_config, null, 3));
208
+ } else {
209
+ // Return a 404 error here
210
+ res.setHeader("Content-Type", "text/html");
211
+ res.status(404).send("Specified bookId " + segs[2] + " not found");
212
+ }
213
+ return;
214
+ } else if (segs.length == 3 && segs[1] == "content" && segs[2] == "index.json") {
215
+ // For development mode, we always have an index with one book in it, the one being developed
216
+ if (hdocbook_config) {
217
+ let index = {
218
+ books: [{
219
+ docId: hdocbook_config.docId,
220
+ title: hdocbook_config.title,
221
+ description: hdocbook_config.description,
222
+ version: hdocbook_config.version
223
+ }]
224
+ };
225
+ res.setHeader("Content-Type", "application/json");
226
+ res.send(JSON.stringify(index, null, 3));
227
+ } else {
228
+ // Return a 404 error here
229
+ res.setHeader("Content-Type", "text/html");
230
+ res.status(404).send("Specified bookId " + segs[2] + " not found");
231
+ }
232
+ return;
233
+ }
234
+
235
+ url = url.replace("/content/", "/");
236
+
237
+ console.log("URL Requested: ", url);
238
+
239
+ let file_path = path.join(source_path, url);
240
+ let ui_file_path = path.join(ui_path, url);
241
+
242
+ // If the requested file is found in the UI folder
243
+ if (url == "/") {
244
+ if (fs.existsSync(path.join(ui_file_path, "index.html"))) {
245
+ // We want the index.html, send it here
246
+ send_file(req, res, path.join(ui_file_path, "index.html"));
247
+ return;
248
+ }
249
+ // Return a 404 error here
250
+ send_content_resource_404(req, res);
251
+ return;
252
+ } else if (fs.existsSync(ui_file_path)) {
253
+ // File is found in the UI folder, that takes priority, send the file
254
+ send_file(req, res, ui_file_path);
255
+ return;
256
+ }
257
+
258
+ if (path.extname(file_path) == ".html") {
259
+ // 1a. check for html files, and send/transform as required
260
+ if (fs.existsSync(file_path)) {
261
+ // HTML file exists on disk, just return it verbatim
262
+ res.setHeader("Content-Type", "text/html");
263
+ send_file(req, res, file_path);
264
+ return true;
265
+ }
266
+
267
+ if (fs.existsSync(file_path.replace(".html", ".md"))) {
268
+ if (transform_markdown_and_send_html(req, res, file_path.replace(".html", ".md"))) {
269
+ return;
270
+ }
271
+ }
272
+ } else if (path.extname(file_path) == ".md") {
273
+ // If the markdown file exists, just send to caller as is
274
+ if (fs.existsSync(file_path)) {
275
+ send_content_file(req, res, file_path);
276
+ return true;
277
+ }
278
+ } else if (path.extname(file_path).length == 0) {
279
+ // 2. If we request a file, without any file extension
280
+ if (fs.existsSync(file_path + ".md")) {
281
+ if (transform_markdown_and_send_html(req, res, file_path + ".md")) {
282
+ return;
283
+ }
284
+ } else if (fs.existsSync(path.join(file_path + "index.md"))) {
285
+ if (transform_markdown_and_send_html(req, res, path.join(file_path, "index.md"))) {
286
+ return;
287
+ }
288
+ } else if (fs.existsSync(path.join(file_path + "index.html"))) {
289
+ res.setHeader("Content-Type", "text/html");
290
+ send_content_file(req, res, path.join(file_path + "index.html"));
291
+ return;
292
+ } else if (fs.existsSync(file_path + "/index.md")) {
293
+ if (transform_markdown_and_send_html(req, res, file_path + "/index.md")) {
294
+ return;
295
+ }
296
+ } else if (fs.existsSync(path.join(file_path + "/index.html"))) {
297
+ res.setHeader("Content-Type", "text/html");
298
+ send_content_file(req, res, path.join(file_path + "/index.html"));
299
+ return;
300
+ }
301
+ } else if (fs.existsSync(file_path)) {
302
+ send_file(req, res, file_path);
303
+ return;
304
+ }
305
+
306
+ // Return a 404 error here
307
+ send_content_resource_404(req, res);
308
+ });
309
+
310
+ // Catch all
311
+ app.get('/*', function (req, res) {
312
+
313
+ let segs = req.url.split('/');
314
+
315
+ if (segs.length > 3 && segs[2] == "content") {
316
+ // In this case we are looking for static content within the book
317
+
318
+ // Create the file path
319
+ let url = req.url.replace("/content/", "/");
320
+ let file_path = path.join(source_path, url);
321
+
322
+ // If the file exists, send it.
323
+ if (fs.existsSync(file_path) == true) {
324
+ send_file(req, res, file_path);
325
+ return;
326
+ }
327
+
328
+ // All else fails, we have not file to return, so return a 404 error here
329
+ send_content_resource_404(req, res);
330
+ return;
331
+ }
332
+
333
+ let ui_file_path = path.join(ui_path, req.url);
334
+
335
+ console.log("URL Root: ", req.url);
336
+
337
+ // To support the SPA application behavior, if there is no file extension present, then
338
+ // we simply return the /index.html file content to the client
339
+ if (path.extname(ui_file_path).length == 0) {
340
+ send_content_file(req, res, path.join(ui_path, "index.html"));
341
+ return;
342
+ }
343
+
344
+ // If the file exists, send it.
345
+ if (fs.existsSync(ui_file_path) == true) {
346
+ send_content_file(req, res, ui_file_path);
347
+ return;
348
+ }
349
+
350
+ // All else fails, we have not file to return, so return a 404 error here
351
+ send_content_resource_404(req, res);
352
+ });
353
+
354
+ var server = app.listen(3000, "0.0.0.0", function () {
355
+ var host = server.address().address;
356
+ var port = server.address().port;
357
+
358
+ console.log("Server listening at http://%s:%s", host, port);
359
+ console.log("Document source path is: " + source_path);
360
+ });
361
+
362
+ };
363
+ })();
package/hdoc.js CHANGED
@@ -1,92 +1,89 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- var path = require('path');
5
- const stream = require('stream');
6
- const yaml = require('js-yaml');
7
- const mdfm = require('markdown-it-front-matter');
8
- var hljs = require('highlight.js') // https://highlightjs.org/
9
- const md = require('markdown-it') ({
10
- // enable everything
11
- html: true,
12
- linkify: true,
13
- typographer: true,
14
- // highlight: function (str, lang) {
15
- // if (lang && hljs.getLanguage(lang)) {
16
- // try {
17
- // return hljs.highlight(lang, str, true).value;
18
- // } catch (__) {}
19
- // }
20
- // }
21
- });
22
- const html2text = require('html-to-text');
23
-
24
- var frontmatter_content;
25
- md.use(mdfm, function(fm) {
26
- frontmatter_content = fm;
27
- });
28
-
29
- const tips = require(__dirname + '/custom_modules/tips.js');
30
-
31
- md.use(tips, {links: true});
32
-
33
- // Default source path to working directory
34
- const source_path = process.cwd();
35
- const ui_path = path.join(__dirname, "ui");
36
-
37
- var command = ""; // Our command to run
38
-
39
- const commands = {
40
- "serve": {},
41
- "build": {}
42
- };
43
-
44
- // Get options from command args
45
- for(x = 0; x < process.argv.length; x++)
46
- {
47
- // First two arguments are command, and script
48
- if(x == 0 || x == 1)
49
- continue;
50
- // Third argument is command
51
- if(x == 2) {
52
- command = process.argv[x];
53
- // Is command allowed
54
- if(commands[command] === undefined)
55
- throw "The specified command '" + command + "' is not known\r\n";
3
+ (function () {
4
+ 'use strict';
5
+
6
+ const fs = require('fs');
7
+ var path = require('path');
8
+ const stream = require('stream');
9
+ const yaml = require('js-yaml');
10
+ const mdfm = require('markdown-it-front-matter');
11
+ var hljs = require('highlight.js'); // https://highlightjs.org/
12
+ const md = require('markdown-it')({
13
+ // enable everything
14
+ html: true,
15
+ linkify: true,
16
+ typographer: true,
17
+ // highlight: function (str, lang) {
18
+ // if (lang && hljs.getLanguage(lang)) {
19
+ // try {
20
+ // return hljs.highlight(lang, str, true).value;
21
+ // } catch (__) {}
22
+ // }
23
+ // }
24
+ });
25
+
26
+ var frontmatter_content;
27
+ md.use(mdfm, function (fm) {
28
+ frontmatter_content = fm;
29
+ });
30
+
31
+ const tips = require(__dirname + '/custom_modules/tips.js');
32
+
33
+ md.use(tips, {
34
+ links: true
35
+ });
36
+
37
+ // Default source path to working directory
38
+ let source_path = process.cwd();
39
+ let ui_path = path.join(__dirname, "ui");
40
+
41
+ var command = ""; // Our command to run
42
+
43
+ // Get options from command args
44
+ for (let x = 0; x < process.argv.length; x++) {
45
+ // First two arguments are command, and script
46
+ if (x == 0 || x == 1)
47
+ continue;
48
+ // Third argument is command
49
+ if (x == 2) {
50
+ command = process.argv[x];
51
+ continue;
52
+ }
53
+
54
+ if (process.argv[x] == "-path") {
55
+ x++;
56
+ if (x < process.argv.length) {
57
+ source_path = process.argv[x];
58
+ }
59
+ } else if (process.argv[x] == "-ui-path") {
60
+ x++;
61
+ if (x < process.argv.length) {
62
+ ui_path = process.argv[x];
63
+ }
64
+ }
56
65
  }
57
66
 
58
- if(process.argv[x] == "-path") {
59
- x++;
60
- if(x < process.argv.length)
61
- {
62
- source_path = process.argv[x];
63
- }
64
- } else if(process.argv[x] == "-ui-path") {
65
- x++;
66
- if(x < process.argv.length)
67
- {
68
- ui_path = process.argv[x];
69
- }
67
+ console.log("Hornbill HDocBook Tools v0.1", "\r\n");
68
+ console.log(" Server Path:", __dirname);
69
+ console.log(" Document Path:", source_path, "\r\n");
70
+
71
+ if (command == "serve") {
72
+ const server = require(path.join(__dirname, "hdoc-serve.js"));
73
+ server.run(ui_path, source_path, md);
74
+ } else if (command == "build") {
75
+ const builder = require(path.join(__dirname, "hdoc-build.js"));
76
+ builder.run(ui_path, source_path, md);
77
+ } else if (command == "stats") {
78
+ const stats = require(path.join(__dirname, "hdoc-stats.js"));
79
+ stats.run(ui_path, source_path, md);
80
+ } else if (command == "statsv") {
81
+ const stats = require(path.join(__dirname, "hdoc-stats.js"));
82
+ stats.run(ui_path, source_path, md, true);
83
+ } else if (command == "init") {
84
+ const init = require(path.join(__dirname, "hdoc-init.js"));
85
+ init.run(ui_path, source_path, md);
86
+ } else {
87
+ console.log("Unknown command: " + command);
70
88
  }
71
- }
72
-
73
- console.log("Hornbill HDocBook Tools v0.1", "\r\n");
74
- console.log(" Server Path:", __dirname);
75
- console.log(" Document Path:", source_path, "\r\n");
76
-
77
- if(command == "serve") {
78
- const server = require(path.join(__dirname, "hdoc-serve.js"));
79
-
80
- server.run(ui_path, source_path, md);
81
- } else if(command == "build") {
82
-
83
- const builder = require(path.join(__dirname, "hdoc-build.js"));
84
-
85
- builder.run(ui_path, source_path, md);
86
- } else if(command == "stats") {
87
-
88
- const stats = require(path.join(__dirname, "hdoc-stats.js"));
89
-
90
- stats.run(ui_path, source_path, md);
91
- }
92
-
89
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hdoc-tools",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Hornbill HDocBook Development Support Tool",
5
5
  "main": "hdoc.js",
6
6
  "bin": {
@@ -21,15 +21,19 @@
21
21
  "dependencies": {
22
22
  "body-parser": "^1.20.1",
23
23
  "cookie-parser": "^1.4.6",
24
+ "dree": "^3.4.2",
24
25
  "express": "^4.18.2",
25
26
  "hdoc-tools": "^0.1.0",
26
27
  "highlight.js": "^11.6.0",
27
28
  "html-to-text": "^8.2.1",
28
29
  "js-yaml": "^4.1.0",
30
+ "lodash": "^4.17.21",
29
31
  "markdown-it": "^13.0.1",
30
32
  "markdown-it-container": "^3.0.0",
31
33
  "markdown-it-front-matter": "^0.2.3",
34
+ "markdown-to-txt": "^2.0.1",
32
35
  "multer": "^1.4.5-lts.1",
33
- "stream": "0.0.2"
36
+ "stream": "0.0.2",
37
+ "words-count": "^2.0.2"
34
38
  }
35
39
  }
@@ -9,18 +9,18 @@ var global = {stateParams:{},lastLayoutClass:""};
9
9
  var docAppMethods = {
10
10
  switchViewTheme:function()
11
11
  {
12
- if(ThemePreference)document.documentElement.classList.remove(ThemePreference)
12
+ if(ThemePreference)document.documentElement.classList.remove(ThemePreference);
13
13
 
14
14
  if(ThemePreference === 'dark')
15
15
  {
16
16
  ThemePreference = 'light';
17
17
  }
18
18
  else{
19
- ThemePreference = 'dark'
19
+ ThemePreference = 'dark';
20
20
  }
21
21
 
22
- localStorage.setItem('hdocbook-theme-appearance',ThemePreference)
23
- document.documentElement.classList.add(ThemePreference)
22
+ localStorage.setItem('hdocbook-theme-appearance',ThemePreference);
23
+ document.documentElement.classList.add(ThemePreference);
24
24
  },
25
25
  renderNavigation:function()
26
26
  {
@@ -146,7 +146,7 @@ function highlightNavigationLinkFromUrl(matchLinkHref)
146
146
  }
147
147
  catch(e)
148
148
  {
149
- console.log("BAD navigation menu item found",el.href)
149
+ console.log("BAD navigation menu item found",el.href);
150
150
  }
151
151
 
152
152
  if(checkUrl)
@@ -371,7 +371,7 @@ function setBrowserViewUrl(strHrefToLoad,viewData,fromPageRefresh,fromPopState)
371
371
  }
372
372
 
373
373
  //-- store global params
374
- global.stateParams = viewData
374
+ global.stateParams = viewData;
375
375
 
376
376
  if(!fromPopState)
377
377
  {
@@ -479,7 +479,7 @@ async function intialiseApp() {
479
479
  //-- we are loading root so select for link
480
480
  loadBookDefaultLink();
481
481
  }
482
- },200)
483
- })
484
- })
482
+ },200);
483
+ });
484
+ });
485
485
  }