hdoc-tools 0.17.16 → 0.17.18

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/README.md CHANGED
@@ -37,6 +37,8 @@ Returns statistics regarding the book you are working on:
37
37
 
38
38
  If the -v switch is provided, then more verbose output is output, which includes a list of each MD and HTML file found, the file sizes, and file-specific word count.
39
39
 
40
+ The book statistics do not include counts for any externally hosted content injected into the book content using the [[INCLUDE]] tags.
41
+
40
42
  ### build
41
43
 
42
44
  Performs a local build of the book, validates the links and static content are present and correct and outputs as a ZIP file.
package/hdoc-build-db.js CHANGED
@@ -115,7 +115,10 @@
115
115
  indexPromises.push(index_records[i]);
116
116
  }
117
117
  await Promise.all(indexPromises.map(async (file) => {
118
- let index_path_name = file.relative_path.replace('\\', '/');
118
+ let index_path_name = file.relative_path.replaceAll('\\', '/');
119
+ if (index_path_name.endsWith('/index.md') || index_path_name.endsWith('/index.html') || index_path_name.endsWith('/index.htm')) {
120
+ index_path_name = index_path_name.substring(0, index_path_name.lastIndexOf('/'));
121
+ }
119
122
  index_path_name = '/' + index_path_name.replace(path.extname(file.relative_path), '');
120
123
  let index_response = {
121
124
  success: true,
package/hdoc-build.js CHANGED
@@ -90,6 +90,8 @@
90
90
  let fm_headers = [];
91
91
  let existing_fm_headers = false;
92
92
  let doc_type = 'Article';
93
+ let doc_title = '',
94
+ doc_description = '';
93
95
 
94
96
  // Check if we have a frontmatter comment
95
97
  const fm_header = hdoc.getHTMLFrontmatterHeader(html_txt);
@@ -106,6 +108,7 @@
106
108
  } else {
107
109
  // We have a value for the title property
108
110
  fm_title_found = true;
111
+ doc_title = fm_header.fm_properties.title.trim();
109
112
  }
110
113
  }
111
114
 
@@ -139,15 +142,42 @@
139
142
  id: 'title',
140
143
  value: html_heading[0].children[0].data
141
144
  });
145
+ doc_title = html_heading[0].children[0].data;
142
146
  } else {
143
147
  // No header tag, no frontmatter title, output a warning
144
148
  console.log(`[WARNING] No frontmatter title property, or ${h_tags_to_search.join(', ')} tags detected in ${file_path.path}`);
145
149
  }
146
150
  }
151
+
152
+ // Do we have a description header?
153
+ if (fm_header.fm_properties && fm_header.fm_properties.description !== undefined) {
154
+ if (fm_header.fm_properties.description === '') {
155
+ const html_p_tag = hdoc.getFirstHTMLHeading(html_txt, ['p']);
156
+ if (html_p_tag && html_p_tag[0] && html_p_tag[0].children && html_p_tag[0].children[0] && html_p_tag[0].children[0].data) {
157
+ fm_headers.push({
158
+ id: 'description',
159
+ value: `${doc_title}: ${html_p_tag[0].children[0].data.split('.')[0] + '.'}`.trim()
160
+ });
161
+ }
162
+ } else {
163
+ fm_headers.push({
164
+ id: 'description',
165
+ value: fm_header.fm_properties.description.trim()
166
+ });
167
+ }
168
+ } else {
169
+ const html_p_tag = hdoc.getFirstHTMLHeading(html_txt, ['p']);
170
+ if (html_p_tag && html_p_tag[0] && html_p_tag[0].children && html_p_tag[0].children[0] && html_p_tag[0].children[0].data) {
171
+ fm_headers.push({
172
+ id: 'description',
173
+ value: `${doc_title}: ${html_p_tag[0].children[0].data.split('.')[0] + '.'}`.trim()
174
+ });
175
+ }
176
+ }
147
177
  } else {
148
178
  // We have no frontmatter headers, get and build one from the html headings
149
179
  const html_heading = hdoc.getFirstHTMLHeading(html_txt, h_tags_to_search);
150
-
180
+ let doc_title = '';
151
181
  // Add the title
152
182
  if (html_heading && html_heading[0] && html_heading[0].children && html_heading[0].children[0] && html_heading[0].children[0].data) {
153
183
  // We've found a heading tag, add that as a title to the frontmatter content
@@ -155,6 +185,7 @@
155
185
  id: 'title',
156
186
  value: html_heading[0].children[0].data
157
187
  });
188
+ doc_title = html_heading[0].children[0].data;
158
189
  } else if (file_path.name !== 'description_ext.md' && file_path.name !== 'article_ext.md') {
159
190
  // No header tag, no frontmatter title, output a warning
160
191
  console.log(`[WARNING] No frontmatter title property, or ${h_tags_to_search.join(', ')} tags detected in ${file_path.path}`);
@@ -167,6 +198,14 @@
167
198
  id: 'reading-time',
168
199
  value: read_time_mins
169
200
  });
201
+
202
+ const html_p_tag = hdoc.getFirstHTMLHeading(html_txt, ['p']);
203
+ if (html_p_tag && html_p_tag[0] && html_p_tag[0].children && html_p_tag[0].children[0] && html_p_tag[0].children[0].data) {
204
+ fm_headers.push({
205
+ id: 'description',
206
+ value: `${doc_title}: ${html_p_tag[0].children[0].data.split('.')[0] + '.'}`.trim()
207
+ });
208
+ }
170
209
  }
171
210
 
172
211
  // Add doc type
@@ -357,6 +396,7 @@
357
396
 
358
397
  let fm_contains_title = false,
359
398
  fm_contains_reading_time = false,
399
+ fm_contains_description = false,
360
400
  doc_title = '',
361
401
  doc_type = 'Article';
362
402
 
@@ -382,6 +422,9 @@
382
422
  book_read_time += parseInt(fm_val.trim(), 10);
383
423
  fm_contains_reading_time = true;
384
424
  }
425
+ if (fm_id.trim() === 'description') {
426
+ fm_contains_description = true;
427
+ }
385
428
  }
386
429
  });
387
430
  }
@@ -389,7 +432,7 @@
389
432
  // Add doc type
390
433
  fm_headers.push({
391
434
  id: 'type',
392
- value: doc_type
435
+ value: doc_type,
393
436
  });
394
437
 
395
438
  // Does frontmatter tag contain a title property
@@ -410,6 +453,17 @@
410
453
  }
411
454
  }
412
455
 
456
+ // Does frontmatter contain a description header, generate one if not
457
+ if (!fm_contains_description) {
458
+ const html_p_tag = hdoc.getFirstHTMLHeading(html_txt, ['p']);
459
+ if (html_p_tag && html_p_tag[0] && html_p_tag[0].children && html_p_tag[0].children[0] && html_p_tag[0].children[0].data) {
460
+ fm_headers.push({
461
+ id: 'description',
462
+ value: `${doc_title}: ${html_p_tag[0].children[0].data.split('.')[0] + '.'}`
463
+ });
464
+ }
465
+ }
466
+
413
467
  // Does frontmatter tag contain a reading-time property
414
468
  if (!fm_contains_reading_time) {
415
469
  const read_time_mins = hdoc.get_html_read_time(html_txt);
package/hdoc-help.js CHANGED
@@ -27,7 +27,8 @@ Commands
27
27
  Starts a local web server on port 3000, serving the content. Supports a -port N to use a different port
28
28
 
29
29
  - stats
30
- Returns statistics regarding the book you are working on. Supports a -v switch for verbose output
30
+ Returns statistics regarding the book you are working on. Supports a -v switch for verbose output.
31
+ The book statistics do not include counts for any externally hosted content injected into the book content using the [[INCLUDE]] tags.
31
32
 
32
33
  - validate
33
34
  Validates the book content
package/hdoc-validate.js CHANGED
@@ -86,6 +86,77 @@
86
86
  return words;
87
87
  };
88
88
 
89
+ const checkInline = async function (source_path, inline, excludes) {
90
+ let inline_errors = [];
91
+ for (let i = 0; i < inline.length; i++) {
92
+ const title = inline[i].title,
93
+ link = inline[i].link;
94
+
95
+ // Validate link segment spellings
96
+ const paths = link.split('/');
97
+ for (let i = 0; i < paths.length; i++) {
98
+ const path_words = paths[i].split('-');
99
+ for (let j = 0; j < path_words.length; j++) {
100
+ const translate_output = translator.translate(path_words[j], spellcheck_options);
101
+ if (Object.keys(translate_output).length) {
102
+ for (const spell_val in translate_output) {
103
+ if (translate_output.hasOwnProperty(spell_val)) {
104
+ for (const spelling in translate_output[spell_val][0]) {
105
+ if (translate_output[spell_val][0].hasOwnProperty(spelling)) {
106
+ if (!excludes[link]) {
107
+ inline_errors.push(`Inline Link [${link}] contains a British English spelling: ${spelling} should be ${translate_output[spell_val][0][spelling].details}`);
108
+ } else if (!excludes[link].includes(spelling.toLowerCase())) {
109
+ inline_errors.push(`Inline Link [${link}] contains a British English spelling: ${spelling} should be ${translate_output[spell_val][0][spelling].details}`);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ // Validate display names
120
+ const translate_output = translator.translate(title, spellcheck_options);
121
+ if (Object.keys(translate_output).length) {
122
+ for (const spell_val in translate_output) {
123
+ if (translate_output.hasOwnProperty(spell_val)) {
124
+ for (let j = 0; j < translate_output[spell_val].length; j++) {
125
+ for (const spelling in translate_output[spell_val][j]) {
126
+ if (translate_output[spell_val][j].hasOwnProperty(spelling)) {
127
+ if (!excludes[link]) {
128
+ inline_errors.push(`Inline title for link [${link}] contains a British English spelling: ${spelling} should be ${translate_output[spell_val][j][spelling].details}`);
129
+ } else if (!excludes[link].includes(spelling.toLowerCase())) {
130
+ inline_errors.push(`Inline title for link [${link}] contains a British English spelling: ${spelling} should be ${translate_output[spell_val][j][spelling].details}`);
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ // Validate path exists - link should be a html file at this point as its after the content has been built
140
+ let file_exists = true;
141
+ let file_name = path.join(source_path, link + '.html');
142
+ if (!fs.existsSync(file_name)) {
143
+ file_name = path.join(source_path, link + '.htm');
144
+ if (!fs.existsSync(file_name)) {
145
+ file_name = path.join(source_path, link, 'index.html');
146
+ if (!fs.existsSync(file_name)) {
147
+ file_name = path.join(source_path, link, 'index.htm');
148
+ if (!fs.existsSync(file_name)) {
149
+ file_exists = false;
150
+ inline_errors.push(`Inline link [${link}] file does not exist.`);
151
+ }
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ return inline_errors;
158
+ };
159
+
89
160
  const checkNavigation = async function (source_path, flat_nav, excludes) {
90
161
  let nav_errors = [];
91
162
  for (let key in flat_nav) {
@@ -506,10 +577,16 @@
506
577
  }
507
578
  }
508
579
 
509
- // Check navigation spellings
580
+ // Check navigation spellings & paths exist
510
581
  const nav_errors = await checkNavigation(source_path, nav_items, exclude_spellcheck);
511
582
  if (nav_errors.length > 0) meta_errors.push(...nav_errors);
512
583
 
584
+ // Check inline content spellings & paths exist
585
+ if (hdocbook_config.inline && hdocbook_config.inline.length > 0) {
586
+ const inline_errors = await checkInline(source_path, hdocbook_config.inline, exclude_spellcheck);
587
+ if (inline_errors.length > 0) meta_errors.push(...inline_errors);
588
+ }
589
+
513
590
  // Check redirects
514
591
  const redirect_errors = await checkRedirects(source_path);
515
592
  if (redirect_errors.length > 0) meta_errors.push(...redirect_errors);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hdoc-tools",
3
- "version": "0.17.16",
3
+ "version": "0.17.18",
4
4
  "description": "Hornbill HDocBook Development Support Tool",
5
5
  "main": "hdoc.js",
6
6
  "bin": {