hdoc-tools 0.25.0 → 0.26.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-validate.js +69 -42
- package/package.json +1 -1
package/hdoc-validate.js
CHANGED
@@ -4,6 +4,7 @@ const e = require("express");
|
|
4
4
|
const axios = require("axios");
|
5
5
|
const cheerio = require("cheerio");
|
6
6
|
const dree = require("dree");
|
7
|
+
const dns = require("node:dns");
|
7
8
|
const fs = require("node:fs");
|
8
9
|
const path = require("node:path");
|
9
10
|
const https = require("node:https");
|
@@ -53,7 +54,8 @@ const e = require("express");
|
|
53
54
|
"",
|
54
55
|
);
|
55
56
|
|
56
|
-
const
|
57
|
+
const markdown_paths = getMDPathFromHtmlPath(sourceFile);
|
58
|
+
|
57
59
|
const translate_output = translator.translate(text, spellcheck_options);
|
58
60
|
if (Object.keys(translate_output).length) {
|
59
61
|
for (const key in translate_output) {
|
@@ -68,9 +70,9 @@ const e = require("express");
|
|
68
70
|
) {
|
69
71
|
const link_location = hdoc.find_string_in_string(text.split('\n')[key - 1], spelling);
|
70
72
|
if (link_location !== null)
|
71
|
-
error_message = `${
|
73
|
+
error_message = `${markdown_paths.relativePath}:${key}:${link_location.column} - ${error_message}`;
|
72
74
|
else
|
73
|
-
error_message = `${
|
75
|
+
error_message = `${markdown_paths.relativePath}:${key} - ${error_message}`;
|
74
76
|
if (!excludes[source_path]) {
|
75
77
|
errors[sourceFile.relativePath].push(
|
76
78
|
`${error_message} ${spelling} should be ${translate_output[key][i][spelling].details}`,
|
@@ -433,17 +435,20 @@ const e = require("express");
|
|
433
435
|
};
|
434
436
|
|
435
437
|
const getMDPathFromHtmlPath = (htmlFile) => {
|
436
|
-
const
|
437
|
-
|
438
|
+
const returnPaths = {
|
439
|
+
markdownPath: htmlFile.path.replace(`.${htmlFile.extension}`, '.md'),
|
440
|
+
relativePath: htmlFile.relativePath.replace(`.${htmlFile.extension}`, '.md')
|
441
|
+
};
|
442
|
+
if (!fs.existsSync(returnPaths.markdownPath)) {
|
438
443
|
// No matching markdown
|
439
|
-
|
444
|
+
returnPaths.markdownPath = htmlFile.path;
|
440
445
|
}
|
441
|
-
return
|
446
|
+
return returnPaths;
|
442
447
|
}
|
443
448
|
|
444
449
|
const checkLinks = async (source_path, htmlFile, links, hdocbook_config) => {
|
445
|
-
const
|
446
|
-
const markdown_content = fs.readFileSync(
|
450
|
+
const markdown_paths = getMDPathFromHtmlPath(htmlFile);
|
451
|
+
const markdown_content = fs.readFileSync(markdown_paths.markdownPath, 'utf8');
|
447
452
|
|
448
453
|
for (let i = 0; i < links.length; i++) {
|
449
454
|
// Validate that link is a valid URL first
|
@@ -465,7 +470,7 @@ const e = require("express");
|
|
465
470
|
//Flat Anchor - validate we have a same-file hit
|
466
471
|
isHashAnchor(htmlFile, links[i]);
|
467
472
|
} else {
|
468
|
-
const error_message = processErrorMessage(`Root relative links should start with a forward-slash: ${links[i]}`,
|
473
|
+
const error_message = processErrorMessage(`Root relative links should start with a forward-slash: ${links[i]}`, markdown_paths.relativePath, markdown_content, links[i]);
|
469
474
|
errors[htmlFile.relativePath].push(error_message);
|
470
475
|
}
|
471
476
|
} else {
|
@@ -490,7 +495,29 @@ const e = require("express");
|
|
490
495
|
if (valid_url.protocol === "mailto:") {
|
491
496
|
continue;
|
492
497
|
}
|
493
|
-
|
498
|
+
|
499
|
+
// Skip internal.hornbill.com link validation if run outside of the Hornbill network
|
500
|
+
if (links[i].toLowerCase().includes(".internal.hornbill.com")) {
|
501
|
+
// DNS lookup internal docs endpoint
|
502
|
+
const hostname = 'docs-internal.hornbill.com';
|
503
|
+
let on_int_net = false;
|
504
|
+
try {
|
505
|
+
on_int_net = await checkHostExistsInDNS(hostname);
|
506
|
+
} catch (e) {
|
507
|
+
// Don't need to do anything here
|
508
|
+
}
|
509
|
+
|
510
|
+
if (!on_int_net) {
|
511
|
+
messages[htmlFile.relativePath].push(
|
512
|
+
`Outside of Hornbill network - skipping internal link validation for: ${links[i]}`,
|
513
|
+
);
|
514
|
+
continue;
|
515
|
+
}
|
516
|
+
messages[htmlFile.relativePath].push(
|
517
|
+
`Inside of Hornbill network - performing internal link validation for: ${links[i]}`,
|
518
|
+
);
|
519
|
+
}
|
520
|
+
|
494
521
|
// Skip if the link is excluded in the project config
|
495
522
|
const skip_link = await excludeLink(links[i]);
|
496
523
|
if (skip_link) {
|
@@ -500,12 +527,14 @@ const e = require("express");
|
|
500
527
|
continue;
|
501
528
|
}
|
502
529
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
530
|
+
if (
|
531
|
+
( links[i].toLowerCase().includes("docs.hornbill.com") ||
|
532
|
+
links[i].toLowerCase().includes("docs-internal.hornbill.com")
|
533
|
+
) &&
|
534
|
+
!links[i].toLowerCase().endsWith(".hornbill.com") &&
|
535
|
+
!links[i].toLowerCase().endsWith(".hornbill.com/")
|
507
536
|
) {
|
508
|
-
const error_message = processErrorMessage(`Hornbill Docs links should not be fully-qualified: ${links[i]}`,
|
537
|
+
const error_message = processErrorMessage(`Hornbill Docs links should not be fully-qualified: ${links[i]}`, markdown_paths.relativePath, markdown_content, links[i]);
|
509
538
|
errors[htmlFile.relativePath].push( error_message );
|
510
539
|
continue;
|
511
540
|
}
|
@@ -524,21 +553,33 @@ const e = require("express");
|
|
524
553
|
`Link is a valid external URL: ${links[i]}`,
|
525
554
|
);
|
526
555
|
} catch (e) {
|
527
|
-
const error_message = processErrorMessage(`Issue with external link: ${e} - ${links[i]}`,
|
556
|
+
const error_message = processErrorMessage(`Issue with external link: ${e} - ${links[i]}`, markdown_paths.relativePath, markdown_content, links[i]);
|
528
557
|
errors[htmlFile.relativePath].push(error_message);
|
529
558
|
}
|
530
559
|
}
|
531
560
|
}
|
532
561
|
};
|
533
562
|
|
563
|
+
const checkHostExistsInDNS = async (hostname) => {
|
564
|
+
return new Promise((resolve, reject) => {
|
565
|
+
dns.lookup(hostname, { all:true }, (err, addresses) => {
|
566
|
+
if (err) {
|
567
|
+
reject(err);
|
568
|
+
} else {
|
569
|
+
resolve(addresses !== undefined);
|
570
|
+
}
|
571
|
+
});
|
572
|
+
});
|
573
|
+
}
|
574
|
+
|
534
575
|
const checkImages = async (source_path, htmlFile, links) => {
|
535
|
-
const
|
536
|
-
const markdown_content = fs.readFileSync(
|
576
|
+
const markdown_paths = getMDPathFromHtmlPath(htmlFile);
|
577
|
+
const markdown_content = fs.readFileSync(markdown_paths.markdownPath, 'utf8');
|
537
578
|
for (let i = 0; i < links.length; i++) {
|
538
579
|
// Validate that image is a valid URL first
|
539
580
|
if (!hdoc.valid_url(links[i])) {
|
540
581
|
// Could be a relative path, check image exists
|
541
|
-
doesFileExist(source_path, htmlFile, links[i],
|
582
|
+
doesFileExist(source_path, htmlFile, links[i], markdown_paths.relativePath, markdown_content);
|
542
583
|
} else {
|
543
584
|
messages[htmlFile.relativePath].push(
|
544
585
|
`Image link is a properly formatted external URL: ${links[i]}`,
|
@@ -551,7 +592,7 @@ const e = require("express");
|
|
551
592
|
);
|
552
593
|
} catch (e) {
|
553
594
|
// Handle errors
|
554
|
-
const error_message = processErrorMessage(`External image link error: ${links[i]} - ${e.message}`,
|
595
|
+
const error_message = processErrorMessage(`External image link error: ${links[i]} - ${e.message}`, markdown_paths.relativePath, markdown_content, links[i]);
|
555
596
|
errors[htmlFile.relativePath].push(error_message);
|
556
597
|
}
|
557
598
|
}
|
@@ -559,7 +600,7 @@ const e = require("express");
|
|
559
600
|
};
|
560
601
|
|
561
602
|
const checkTags = async (htmlFile) => {
|
562
|
-
const
|
603
|
+
const markdown_paths = getMDPathFromHtmlPath(htmlFile);
|
563
604
|
// Check if file is excluded from tag check
|
564
605
|
const file_no_ext = htmlFile.relativePath.replace(
|
565
606
|
path.extname(htmlFile.relativePath),
|
@@ -582,7 +623,7 @@ const e = require("express");
|
|
582
623
|
error_msg += h1_tags[i].text();
|
583
624
|
if (i < h1_tags.length - 1) error_msg += "; ";
|
584
625
|
}
|
585
|
-
errors[htmlFile.relativePath].push(`${
|
626
|
+
errors[htmlFile.relativePath].push(`${markdown_paths.relativePath} - ${error_msg}`);
|
586
627
|
}
|
587
628
|
};
|
588
629
|
|
@@ -608,8 +649,8 @@ const e = require("express");
|
|
608
649
|
};
|
609
650
|
|
610
651
|
const isRelativePath = (source_path, html_path, relative_path) => {
|
611
|
-
const
|
612
|
-
const markdown_content = fs.readFileSync(
|
652
|
+
const markdown_paths = getMDPathFromHtmlPath(html_path);
|
653
|
+
const markdown_content = fs.readFileSync(markdown_paths.markdownPath, 'utf8');
|
613
654
|
|
614
655
|
const rel_path_ext = path.extname(relative_path);
|
615
656
|
const response = {
|
@@ -660,7 +701,7 @@ const e = require("express");
|
|
660
701
|
}
|
661
702
|
}
|
662
703
|
if (response.has_md_extension || response.has_html_extension) {
|
663
|
-
const error_message = processErrorMessage(`Relative link has ${rel_path_ext} extension, but should not: ${relative_path}`,
|
704
|
+
const error_message = processErrorMessage(`Relative link has ${rel_path_ext} extension, but should not: ${relative_path}`, markdown_paths.relativePath, markdown_content, relative_path);
|
664
705
|
errors[html_path.relativePath].push(error_message);
|
665
706
|
return;
|
666
707
|
}
|
@@ -679,11 +720,11 @@ const e = require("express");
|
|
679
720
|
const redir = checkRedirect(source_path, relpath);
|
680
721
|
if (redir.exists) {
|
681
722
|
if (redir.error !== null) {
|
682
|
-
const error_message = processErrorMessage(`${redir.error}: ${relative_path}`,
|
723
|
+
const error_message = processErrorMessage(`${redir.error}: ${relative_path}`, markdown_paths.relativePath, markdown_content, clean_relative_path);
|
683
724
|
errors[html_path.relativePath].push(error_message);
|
684
725
|
}
|
685
726
|
} else {
|
686
|
-
const error_message = processErrorMessage(`Link path does not exist: ${relative_path}`,
|
727
|
+
const error_message = processErrorMessage(`Link path does not exist: ${relative_path}`, markdown_paths.relativePath, markdown_content, clean_relative_path);
|
687
728
|
errors[html_path.relativePath].push(error_message);
|
688
729
|
}
|
689
730
|
};
|
@@ -896,7 +937,6 @@ const e = require("express");
|
|
896
937
|
);
|
897
938
|
|
898
939
|
// Perform rest of validation against HTML files
|
899
|
-
let listContent = "";
|
900
940
|
const htmlPromiseArray = [];
|
901
941
|
for (let i = 0; i < html_to_validate.length; i++) {
|
902
942
|
errors[html_to_validate[i].relativePath] = [];
|
@@ -937,24 +977,11 @@ const e = require("express");
|
|
937
977
|
|
938
978
|
// Check for multiple H1 tags
|
939
979
|
await checkTags(file);
|
940
|
-
|
941
|
-
// Build list content for Google
|
942
|
-
listContent += `/${file.relativePath.replace(path.extname(file.relativePath), "")}`;
|
943
|
-
listContent += "\r\n";
|
944
980
|
}),
|
945
981
|
);
|
946
982
|
|
947
983
|
if (gen_exclude) console.log(JSON.stringify(excl_output, null, 2));
|
948
984
|
|
949
|
-
try {
|
950
|
-
// Write list
|
951
|
-
const listFile = path.join(source_path, doc_id, "links.txt");
|
952
|
-
fs.writeFileSync(listFile, listContent);
|
953
|
-
console.log(`\r\nLink list text file created successfully: ${listFile}`);
|
954
|
-
} catch (err) {
|
955
|
-
console.error(err);
|
956
|
-
}
|
957
|
-
|
958
985
|
if (verbose) {
|
959
986
|
console.log("\r\n-------------");
|
960
987
|
console.log(" Verbose ");
|