hdoc-tools 0.40.0 → 0.41.1

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
@@ -13,6 +13,9 @@
13
13
  const archiver = require("archiver");
14
14
  const xmlFormat = require("xml-formatter");
15
15
 
16
+ const { execSync } = require("child_process");
17
+ const tmp = require("tmp");
18
+
16
19
  const h_tags_to_search = ["h1", "h2", "h3"];
17
20
  const image_extensions = ["png", "svg", "jpg"];
18
21
  const doc_header_template_path = path.join(
@@ -35,6 +38,13 @@
35
38
  "templates",
36
39
  "pdf-header-non-git.html",
37
40
  );
41
+
42
+ const mermaid_theme_path = path.resolve(
43
+ __dirname,
44
+ "templates",
45
+ "mermaid-theme.yaml",
46
+ );
47
+
38
48
  const pdf_template_path = path.join(__dirname, "templates", "pdf");
39
49
  const ui_css_path = path.join(__dirname, "ui", "css");
40
50
  const pdf_template_file_path = path.join(pdf_template_path, "template.html");
@@ -52,6 +62,7 @@
52
62
  const md_files_delete = [];
53
63
  const redirects = {};
54
64
  const static_html_files = [];
65
+ const mermaid_failures = [];
55
66
 
56
67
  let bc = {}; // Breadcrumbs map
57
68
  let book_read_time = 0;
@@ -508,6 +519,38 @@
508
519
  html: true,
509
520
  linkify: true,
510
521
  typographer: true,
522
+ highlight: function (str, lang) {
523
+ if (lang === "mermaid") {
524
+ try {
525
+ const tmpInput = tmp.fileSync({ postfix: ".mmd" });
526
+ const tmpOutput = tmp.fileSync({ postfix: ".svg" });
527
+
528
+ if (!str.startsWith('---')) {
529
+ str = '---\n' + fs.readFileSync(mermaid_theme_path, {encoding: 'utf-8'}) + `\n---\n${str}`;
530
+ }
531
+
532
+ fs.writeFileSync(tmpInput.name, str);
533
+
534
+ const cmd = `${__dirname}/node_modules/.bin/mmdc -i "${tmpInput.name}" -o "${tmpOutput.name}" --quiet --backgroundColor transparent`;
535
+ console.log(`Generating Inline Mermaid SVG found in: ${file_path.relativePath}`);
536
+ execSync(cmd);
537
+
538
+ if (!fs.existsSync(tmpOutput.name)) {
539
+ throw new Error("mmdc did not generate output");
540
+ }
541
+
542
+ const svg = fs.readFileSync(tmpOutput.name, "utf8");
543
+
544
+ tmpInput.removeCallback();
545
+ tmpOutput.removeCallback();
546
+
547
+ return `<div class="text-body">${svg}</div>`;
548
+ } catch (err) {
549
+ mermaid_failures.push({path: file_path.relativePath, error: err.message});
550
+ return ``;
551
+ }
552
+ }
553
+ }
511
554
  });
512
555
  md.linkify.set({
513
556
  fuzzyEmail: false,
@@ -1396,6 +1439,21 @@
1396
1439
  console.log(` PDF Files Created: ${pdf_created}\n`);
1397
1440
  }
1398
1441
 
1442
+
1443
+ if (mermaid_failures.length > 0) {
1444
+ console.log("\r\n-----------------------");
1445
+ console.log(" Validation Output ");
1446
+ console.log("-----------------------");
1447
+ console.log(
1448
+ `\n${mermaid_failures.length} errors found when processing markdown SVG generation:\n`,
1449
+ );
1450
+ for (const key in mermaid_failures) {
1451
+ console.error(` - ${mermaid_failures[key].path}:\n${mermaid_failures[key].error}`);
1452
+ }
1453
+ console.log("\n");
1454
+ process.exit(1);
1455
+ }
1456
+
1399
1457
  // Validate content
1400
1458
  const validation_success = await hdoc_validate.run(
1401
1459
  work_path,
package/hdoc-serve.js CHANGED
@@ -6,7 +6,16 @@
6
6
  const stream = require("node:stream");
7
7
 
8
8
  const yaml = require("js-yaml");
9
- const mdfm = require("markdown-it-front-matter");
9
+ const mdfm = require("markdown-it-front-matter");
10
+
11
+ const { execSync } = require("child_process");
12
+ const tmp = require("tmp");
13
+
14
+ const mermaid_theme_path = path.resolve(
15
+ __dirname,
16
+ "templates",
17
+ "mermaid-theme.yaml",
18
+ );
10
19
 
11
20
  let port = 3000;
12
21
  let docId;
@@ -105,78 +114,98 @@
105
114
  });
106
115
 
107
116
  async function transform_markdown_and_send_html(req, res, file_path) {
108
- if (fs.existsSync(file_path)) {
109
- // we have a markdown representation of the requested HTML file, transform and return
110
- // it to the caller
111
-
112
- // Load markdown file
113
- let md_txt = hdoc.expand_variables(
114
- fs.readFileSync(file_path).toString(),
115
- docId,
116
- );
117
-
118
- // Pull in external includes
119
- const includes_processed = await hdoc.process_includes(
120
- file_path,
121
- md_txt,
122
- global_source_path,
123
- );
124
- md_txt = includes_processed.body;
125
- if (includes_processed.errors && includes_processed.errors.length > 0) {
126
- console.error(`Error(s) when processing includes in ${file_path}`);
127
- for (let i = 0; i < includes_processed.errors.length; i++) {
128
- console.error(includes_processed.errors[i]);
129
- }
130
- } else {
131
- if (includes_processed.success > 0) {
132
- console.log(
133
- `Includes injected into document: ${includes_processed.success}`,
134
- );
135
- }
136
- }
137
-
138
- const md = require("markdown-it")({
139
- // enable everything
140
- html: true,
141
- linkify: true,
142
- typographer: true,
143
- });
117
+ if (!fs.existsSync(file_path)) return false;
144
118
 
145
- md.linkify.set({
146
- fuzzyEmail: false,
147
- fuzzyLink: false,
148
- fuzzyIP: false,
149
- });
150
- let frontmatter_content = "";
151
- md.use(mdfm, (fm) => {
152
- frontmatter_content = fm;
153
- });
154
-
155
- const tips = require(`${__dirname}/custom_modules/tips.js`);
156
- md.use(tips, {
157
- links: true,
158
- });
159
-
160
- // Render markdown into HTML
161
- const html_txt = md.render(md_txt.toString());
119
+ let md_txt = hdoc.expand_variables(
120
+ fs.readFileSync(file_path).toString(),
121
+ docId,
122
+ );
162
123
 
163
- if (frontmatter_content.length) {
164
- const obj = yaml.load(frontmatter_content);
124
+ const includes_processed = await hdoc.process_includes(
125
+ file_path,
126
+ md_txt,
127
+ global_source_path,
128
+ );
129
+ md_txt = includes_processed.body;
130
+ const md = require("markdown-it")({
131
+ html: true,
132
+ linkify: true,
133
+ typographer: true,
134
+ highlight: function (str, lang) {
135
+ if (lang === "mermaid") {
136
+ try {
137
+ const tmpInput = tmp.fileSync({ postfix: ".mmd" });
138
+ const tmpOutput = tmp.fileSync({ postfix: ".svg" });
139
+
140
+ if (!str.startsWith('---')) {
141
+ str = '---\n' + fs.readFileSync(mermaid_theme_path, {encoding: 'utf-8'}) + `\n---\n${str}`;
142
+ }
143
+
144
+ fs.writeFileSync(tmpInput.name, str);
145
+
146
+ const cmd = `${__dirname}/node_modules/.bin/mmdc -i "${tmpInput.name}" -o "${tmpOutput.name}" --quiet --backgroundColor transparent`;
147
+ console.log(`Generating Inline Mermaid SVG found in: ${file_path}`);
148
+ execSync(cmd);
149
+
150
+ if (!fs.existsSync(tmpOutput.name)) {
151
+ throw new Error("mmdc did not generate output");
152
+ }
153
+
154
+ const svg = fs.readFileSync(tmpOutput.name, "utf8");
155
+
156
+ tmpInput.removeCallback();
157
+ tmpOutput.removeCallback();
158
+
159
+ return `<div class="text-body">${svg}</div>`;
160
+ } catch (err) {
161
+ return `<div class="alert alert-danger mb-0 text-break"
162
+ role="alert"
163
+ data-bs-toggle="collapse"
164
+ data-bs-target="#alertContent"
165
+ aria-expanded="false"
166
+ aria-controls="alertContent">
167
+ <div>
168
+ <strong>Error!</strong> Mermaid was unable to generate the SVG expected here. Click for more details
169
+ </div>
170
+ <div class="collapse mt-3" id="alertContent">
171
+ <p class="mb-0 text-break">
172
+ ${err.message}
173
+ </p>
174
+ </div>
175
+ </div>`;
176
+ }
177
+ }
178
+ }
179
+ });
180
+ md.linkify.set({
181
+ fuzzyEmail: false,
182
+ fuzzyLink: false,
183
+ fuzzyIP: false,
184
+ });
165
185
 
166
- const buff = Buffer.from(JSON.stringify(obj), "utf-8");
186
+ let frontmatter_content = "";
187
+ md.use(mdfm, (fm) => {
188
+ frontmatter_content = fm;
189
+ });
167
190
 
168
- const base64 = buff.toString("base64");
191
+ const tips = require(`${__dirname}/custom_modules/tips.js`);
192
+ md.use(tips, { links: true });
169
193
 
170
- res.setHeader("X-frontmatter", base64);
171
- }
194
+ const html_txt = md.render(md_txt.toString());
172
195
 
173
- res.setHeader("Content-Type", "text/html");
174
- res.send(html_txt);
175
- return true;
196
+ if (frontmatter_content.length) {
197
+ const obj = yaml.load(frontmatter_content);
198
+ const buff = Buffer.from(JSON.stringify(obj), "utf-8");
199
+ const base64 = buff.toString("base64");
200
+ res.setHeader("X-frontmatter", base64);
176
201
  }
177
- return false;
202
+
203
+ res.setHeader("Content-Type", "text/html");
204
+ res.send(html_txt);
205
+ return true;
178
206
  }
179
207
 
208
+
180
209
  function send_content_file(req, res, file_path, redirected = false) {
181
210
  let content_txt = hdoc.expand_variables(
182
211
  fs.readFileSync(file_path).toString(),
@@ -386,4 +415,5 @@
386
415
  }
387
416
  });
388
417
  };
418
+
389
419
  })();
package/hdoc-validate.js CHANGED
@@ -474,8 +474,8 @@ const e = require("express");
474
474
 
475
475
  for (let i = 0; i < links.length; i++) {
476
476
  // Validate that link is a valid URL first
477
- if (exclude_links[links[i]]) continue;
478
477
  console.log(` - ${links[i]}`);
478
+ if (exclude_links[links[i]]) continue;
479
479
  if (global_links_checked.includes(links[i])) continue;
480
480
  global_links_checked.push(links[i]);
481
481
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hdoc-tools",
3
- "version": "0.40.0",
3
+ "version": "0.41.1",
4
4
  "description": "Hornbill HDocBook Development Support Tool",
5
5
  "main": "hdoc.js",
6
6
  "bin": {
@@ -51,10 +51,12 @@
51
51
  "markdown-it": "14.1.0",
52
52
  "markdown-it-container": "^4.0.0",
53
53
  "markdown-it-front-matter": "^0.2.4",
54
+ "@mermaid-js/mermaid-cli": "11.6.0",
54
55
  "mime-types": "^2.1.35",
55
56
  "prompt": "^1.3.0",
56
- "puppeteer": "^22.12.1",
57
+ "puppeteer": "^23.11.1",
57
58
  "stream": "0.0.3",
59
+ "tmp": "^0.2.3",
58
60
  "true-case-path": "^2.2.1",
59
61
  "words-count": "^2.0.2",
60
62
  "xml-formatter": "^3.6.2"
@@ -0,0 +1,28 @@
1
+ config:
2
+ theme: 'base'
3
+ themeVariables:
4
+ background: transparent
5
+ fontSize: 14px
6
+ primaryColor: "#85D2FF" # Medium blue
7
+ primaryColorLight: "#85D2FF" # Light accent blue
8
+ primaryColorDark: "#0065CB" # Medium-dark blue
9
+
10
+ secondaryColor: "#219BFF" # Medium blue
11
+ secondaryColorLight: "#85D2FF" # Light accent blue
12
+ secondaryColorDark: "#0C4C8C" # Medium-dark blue
13
+
14
+ tertiaryColor: "#219BFF" # Medium blue
15
+ tertiaryColorLight: "#85D2FF" # Light accent blue
16
+ tertiaryColorDark: "#0C4C8C" # Medium-dark blue
17
+
18
+ lineColor: "#808080" # Medium grey for lines
19
+ border1: "#606060" # Darker grey for borders
20
+ textColor: "#A0A0A0" # Light grey text (visible on both)
21
+ titleColor: "#A0A0A0"
22
+ labelColor: "#404040"
23
+ loopTextColor: "#A0A0A0"
24
+ nodeTextColor: "#404040"
25
+ labelTextColor: "#404040"
26
+ pieSectionTextColor: "#404040"
27
+ nodeBorder: "#219BFF" # Match node border to primary blue
28
+ nodeBg: transparent