markdown_link_checker_sc 0.0.116 → 0.0.118
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/index.js +20 -21
- package/package.json +1 -1
- package/src/helpers.js +18 -1
- package/src/links.js +5 -9
- package/src/output_errors.js +4 -5
- package/src/process_image_orphans.js +4 -6
- package/src/process_internal_url_links.js +2 -0
- package/src/process_local_image_links.js +4 -15
- package/src/process_markdown.js +12 -8
- package/src/process_orphans.js +3 -4
- package/src/process_relative_links.js +2 -3
- package/tests/links/html/img/tests1.md +12 -0
- package/biglog.txt +0 -0
package/index.js
CHANGED
|
@@ -48,7 +48,7 @@ program
|
|
|
48
48
|
)
|
|
49
49
|
.option(
|
|
50
50
|
"-l, --log <types...>",
|
|
51
|
-
"
|
|
51
|
+
"Types of console logs to display logs for debugging. Types: functions, todo etc."
|
|
52
52
|
)
|
|
53
53
|
.option(
|
|
54
54
|
"-f, --files <path>",
|
|
@@ -64,6 +64,11 @@ program
|
|
|
64
64
|
"-u, --site_url [value]",
|
|
65
65
|
"Site base url in form dev.example.com (used to catch absolute urls to local files)"
|
|
66
66
|
)
|
|
67
|
+
.option(
|
|
68
|
+
"-o, --logtofile [value]",
|
|
69
|
+
"Output logs to file",
|
|
70
|
+
true
|
|
71
|
+
)
|
|
67
72
|
|
|
68
73
|
.parse(process.argv);
|
|
69
74
|
|
|
@@ -78,39 +83,30 @@ sharedData.allHTMLFiles = new Set([]);
|
|
|
78
83
|
sharedData.allImageFiles = new Set([]);
|
|
79
84
|
sharedData.allOtherFiles = new Set([]);
|
|
80
85
|
|
|
81
|
-
|
|
82
86
|
const markdownDirectory = path.join(sharedData.options.root, sharedData.options.directory);
|
|
83
|
-
if (sharedData.options.log == "fast") {
|
|
84
|
-
console.log(`MARKDOWN DIR ${markdownDirectory}`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async () => {
|
|
88
|
-
// Load JSON file containing file paths and reassign as array to the JSON path
|
|
89
|
-
sharedData.options.files
|
|
90
|
-
? (sharedData.options.files = await loadJSONFileToReportOn(sharedData.options.files))
|
|
91
|
-
: (sharedData.options.files = []);
|
|
92
|
-
if (sharedData.options.log == "quick") {
|
|
93
|
-
for (const file of sharedData.options.files) {
|
|
94
|
-
console.log(file);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
87
|
|
|
99
88
|
// Function for loading JSON file that contains files to report on
|
|
100
89
|
async function loadJSONFileToReportOn(filePath) {
|
|
101
90
|
sharedData.options.log.includes("functions")
|
|
102
91
|
? console.log(`Function: loadJSONFileToReportOn(): filePath: ${filePath}`)
|
|
103
92
|
: null;
|
|
93
|
+
sharedData.options.log.includes("quick")
|
|
94
|
+
? console.log(`Function: loadJSONFileToReportOn(): filePath: ${filePath}`)
|
|
95
|
+
: null;
|
|
104
96
|
try {
|
|
105
97
|
const fileContent = await fs.promises.readFile(filePath, "utf8");
|
|
106
98
|
let filesArray = JSON.parse(fileContent);
|
|
107
99
|
// Array relative to root, so update to have full path
|
|
108
100
|
filesArray = filesArray.map((str) => path.join(sharedData.options.root, str));
|
|
101
|
+
|
|
102
|
+
sharedData.options.log.includes("quick")
|
|
103
|
+
? console.log(`quick:filesArray: ${filesArray}`)
|
|
104
|
+
: null;
|
|
109
105
|
|
|
110
|
-
//console.log(filesArray);
|
|
111
106
|
return filesArray;
|
|
112
107
|
} catch (error) {
|
|
113
108
|
console.error(`Error reading file: ${error.message}`);
|
|
109
|
+
console.log(`Error reading file: ${error.message}`);
|
|
114
110
|
process.exit(1);
|
|
115
111
|
}
|
|
116
112
|
}
|
|
@@ -193,12 +189,12 @@ function filterErrors(errors) {
|
|
|
193
189
|
// Filter results on specified file names (if any specified)
|
|
194
190
|
//console.log(`Number pages to filter: ${sharedData.options.files.length}`);
|
|
195
191
|
if (sharedData.options.files.length > 0) {
|
|
192
|
+
//console.log(`USharedFileslength: ${sharedData.options.files.length}`);
|
|
196
193
|
filteredErrors = errors.filter((error) => {
|
|
197
194
|
//console.log(`UError: ${error}`);
|
|
198
195
|
//console.log(JSON.stringify(error, null, 2));
|
|
199
|
-
//console.log(`UError
|
|
200
|
-
const filterResult = sharedData.options.files.includes(error.
|
|
201
|
-
//console.log(`filterResult: ${filterResult}`);
|
|
196
|
+
//console.log(`UError file: ${error.file}`);
|
|
197
|
+
const filterResult = sharedData.options.files.includes(error.file);
|
|
202
198
|
return filterResult;
|
|
203
199
|
});
|
|
204
200
|
}
|
|
@@ -210,6 +206,9 @@ function filterErrors(errors) {
|
|
|
210
206
|
|
|
211
207
|
//main function, after options et have been set up.
|
|
212
208
|
(async () => {
|
|
209
|
+
|
|
210
|
+
sharedData.options.files ? (sharedData.options.files = await loadJSONFileToReportOn(sharedData.options.files)) : (sharedData.options.files = []);
|
|
211
|
+
|
|
213
212
|
// process containing markdown, return results which includes links, headings, id anchors
|
|
214
213
|
const results = await processDirectory(markdownDirectory);
|
|
215
214
|
|
package/package.json
CHANGED
package/src/helpers.js
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import fs from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { sharedData } from "./shared_data.js";
|
|
4
|
+
|
|
5
|
+
// Call at start of function to ease logging to console.
|
|
6
|
+
function logFunction(name, ...args) {
|
|
7
|
+
sharedData.options.log.includes("functions")
|
|
8
|
+
? console.log(`${name}: ${args.join(", ")}`)
|
|
9
|
+
: null;
|
|
10
|
+
}
|
|
3
11
|
|
|
4
12
|
// Log data to specified file path, replacing file.
|
|
5
13
|
async function logToFile(filePath, dataString) {
|
|
14
|
+
sharedData.options.log.includes("functions")
|
|
15
|
+
? console.log(`Function: logToFile(${filePath}, dataString))`)
|
|
16
|
+
: null;
|
|
17
|
+
if (!sharedData.options.logtofile) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
try {
|
|
22
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
23
|
+
|
|
7
24
|
await fs.writeFile(filePath, dataString);
|
|
8
25
|
//console.log("Data written to file");
|
|
9
26
|
} catch (err) {
|
|
@@ -38,4 +55,4 @@ function isHTML(file) {
|
|
|
38
55
|
return fileExtension === ".html" || fileExtension === ".htm" ? true : false;
|
|
39
56
|
}
|
|
40
57
|
|
|
41
|
-
export { logToFile, isImage, isMarkdown, isHTML };
|
|
58
|
+
export { logToFile, logFunction, isImage, isMarkdown, isHTML };
|
package/src/links.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { isImage, isMarkdown, isHTML } from "./helpers.js";
|
|
3
3
|
import { sharedData } from "./shared_data.js";
|
|
4
|
+
import { logFunction } from "./helpers.js";
|
|
4
5
|
|
|
5
6
|
class Link {
|
|
6
7
|
address = "";
|
|
@@ -33,9 +34,7 @@ class Link {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
constructor({ page, url, type, text, title }) {
|
|
36
|
-
|
|
37
|
-
? console.log("Link:constructor")
|
|
38
|
-
: null;
|
|
37
|
+
logFunction("Link:constructor");
|
|
39
38
|
|
|
40
39
|
if (page) {
|
|
41
40
|
this.page = page;
|
|
@@ -110,9 +109,8 @@ class Link {
|
|
|
110
109
|
// This is only used if the type is not specified as an argument.
|
|
111
110
|
// Uses file extension etc, so should be run after SplitUrl() which finds the address
|
|
112
111
|
findType() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
: null;
|
|
112
|
+
logFunction("Link:findType()");
|
|
113
|
+
|
|
116
114
|
let linkType = "unHandledLinkType";
|
|
117
115
|
|
|
118
116
|
this.isImage = this.address && isImage(this.address) ? true : false; //only if address is true.
|
|
@@ -182,9 +180,7 @@ class Link {
|
|
|
182
180
|
|
|
183
181
|
//get absolute path to link, if this is a relative URL link.
|
|
184
182
|
getAbsolutePath() {
|
|
185
|
-
|
|
186
|
-
? console.log(`Link:getAbsolutePath: page: ${this.page}, address: ${this.address} `)
|
|
187
|
-
: null;
|
|
183
|
+
logFunction("Link:getAbsolutePath", `this.page: ${this.page}`, `this.address: ${this.address}`);
|
|
188
184
|
if (!this.isRelative) throw new Error("Link:getAbsolutePath() called on non-relative path");
|
|
189
185
|
return path.resolve(path.dirname(this.page), this.address);
|
|
190
186
|
}
|
package/src/output_errors.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
//import { /*LinkError,*/ CurrentFileMissingAnchorError, LinkedFileMissingAnchorError, LinkedInternalPageMissingError, InternalLinkToHTMLError, UrlToLocalSiteError} from "./errors.js"
|
|
2
2
|
|
|
3
3
|
import { sharedData } from "./shared_data.js";
|
|
4
|
-
|
|
4
|
+
import { logFunction } from "./helpers.js";
|
|
5
5
|
|
|
6
6
|
//Function that generates console and/or log output from an array of error objects.
|
|
7
|
-
// - `results` is an array of error objects.
|
|
7
|
+
// - `results` is an array of error objects.
|
|
8
|
+
// These will have a `type` and a `page`. They may also have other values, depending on type of error - such as linkurl
|
|
8
9
|
function outputErrors(results) {
|
|
9
|
-
|
|
10
|
-
? console.log("Function: outputErrors()")
|
|
11
|
-
: null;
|
|
10
|
+
logFunction("Function: outputErrors()");
|
|
12
11
|
|
|
13
12
|
//Sort results by page and type.
|
|
14
13
|
// Perhaps next step is to create only get info for particular pages.
|
|
@@ -3,6 +3,7 @@ import fs from "fs";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { sharedData } from "./shared_data.js";
|
|
5
5
|
import { OrphanedImageError } from "./errors.js";
|
|
6
|
+
import { logFunction } from "./helpers.js";
|
|
6
7
|
|
|
7
8
|
function isImage(file) {
|
|
8
9
|
const imageExtensions = [".jpg", ".jpeg", ".png", ".svg", ".gif", ".webm"];
|
|
@@ -14,9 +15,7 @@ var otherFileTypes = []; // Just used for logging in function below.
|
|
|
14
15
|
|
|
15
16
|
// Gets all image files in a directory.
|
|
16
17
|
async function getAllImageFilesInDirectory(dir) {
|
|
17
|
-
|
|
18
|
-
? console.log(`Function: getAllImageFilesInDirectory(${dir})`)
|
|
19
|
-
: null;
|
|
18
|
+
logFunction(`Function: getAllImageFilesInDirectory(${dir})`)
|
|
20
19
|
|
|
21
20
|
// TODO put this all in a try catch and return a better error.
|
|
22
21
|
// Or perhaps put around parent.
|
|
@@ -43,9 +42,8 @@ async function getAllImageFilesInDirectory(dir) {
|
|
|
43
42
|
|
|
44
43
|
// Checks if any images in the options.directory
|
|
45
44
|
async function checkImageOrphansGlobal(results) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
: null;
|
|
45
|
+
logFunction(`Function: checkImageOrphansGlobal()`)
|
|
46
|
+
|
|
49
47
|
const errors = [];
|
|
50
48
|
let allImagesFound = [];
|
|
51
49
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { UrlToLocalSiteError} from "./errors.js"
|
|
3
|
+
import { logFunction } from "./helpers.js";
|
|
3
4
|
|
|
4
5
|
// An array of errors given a results object that contains our array of objects containing urls that link to our current site.
|
|
5
6
|
function processUrlsToLocalSource(results) {
|
|
7
|
+
logFunction(`Function: processUrlsToLocalSource()`);
|
|
6
8
|
const errors = [];
|
|
7
9
|
results.forEach((page, index, array) => {
|
|
8
10
|
//console.log(`PAGE: ${page}`);
|
|
@@ -2,11 +2,12 @@ import path from "path";
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import { sharedData } from "./shared_data.js";
|
|
4
4
|
import { LocalImageNotFoundError } from "./errors.js";
|
|
5
|
+
import { logFunction } from "./helpers.js";
|
|
5
6
|
|
|
6
7
|
// Checks if every image in every markdown page (results.page.relativeImageLinks) is present on the file system.
|
|
7
8
|
// - results is the array of information coming out of markdown parsing.
|
|
8
9
|
async function checkLocalImageLinks(results) {
|
|
9
|
-
|
|
10
|
+
logFunction(`Function: checkLocalImageLinks()`);
|
|
10
11
|
const errors = [];
|
|
11
12
|
const promises = [];
|
|
12
13
|
|
|
@@ -20,25 +21,13 @@ async function checkLocalImageLinks(results) {
|
|
|
20
21
|
//console.log(`link.linkUrlt: ${link.url}`);
|
|
21
22
|
//console.log(`dirname: ${path.dirname(page.page_file)}`);
|
|
22
23
|
|
|
23
|
-
const fullImagePath = path.join(
|
|
24
|
-
path.dirname(page.page_file),
|
|
25
|
-
link.url
|
|
26
|
-
);
|
|
24
|
+
const fullImagePath = path.join(path.dirname(page.page_file), link.url);
|
|
27
25
|
//console.log(`fullImagePath: ${fullImagePath}`);
|
|
28
26
|
const promise = new Promise((resolve) => {
|
|
29
27
|
fs.access(fullImagePath, fs.constants.F_OK, (err) => {
|
|
30
28
|
if (err) {
|
|
31
29
|
//console.log("Error");
|
|
32
|
-
|
|
33
|
-
/*
|
|
34
|
-
const error = {
|
|
35
|
-
type: "LocalImageNotFound",
|
|
36
|
-
page: `${page.page_file}`,
|
|
37
|
-
linkUrl: `${link.url}`,
|
|
38
|
-
linkText: `${link.text}`,
|
|
39
|
-
linkFullPath: `${fullImagePath}`,
|
|
40
|
-
};
|
|
41
|
-
*/
|
|
30
|
+
const error = new LocalImageNotFoundError({ link: link });
|
|
42
31
|
errors.push(error);
|
|
43
32
|
resolve(false);
|
|
44
33
|
} else {
|
package/src/process_markdown.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Link } from "./links.js";
|
|
2
2
|
import { sharedData } from "./shared_data.js";
|
|
3
|
+
import { logFunction } from "./helpers.js";
|
|
3
4
|
|
|
4
5
|
// Returns slug for a string (markdown heading) using Vuepress algorithm.
|
|
5
6
|
// Algorithm from chatgpt - needs testing.
|
|
6
7
|
const processMarkdown = (contents, page) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
: null;
|
|
8
|
+
logFunction(`Function: processMarkdown(): page: ${page}`);
|
|
9
|
+
|
|
10
10
|
const headings = [];
|
|
11
11
|
//const anchors = [];
|
|
12
12
|
const htmlAnchors = []; //{};
|
|
@@ -103,10 +103,10 @@ const processLineMarkdownLinks = (
|
|
|
103
103
|
unHandledLinkTypes,
|
|
104
104
|
page
|
|
105
105
|
) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
: null;
|
|
106
|
+
logFunction(`Function: processMarkdown(): page: ${page}`);
|
|
107
|
+
|
|
109
108
|
//const regex = /(?<prefix>[!@]?)\[(?<text>[^\]]+)\]\((?<url>\S+?)(?:\s+"(?<title>[^"]+)")?\)/g;
|
|
109
|
+
// Match to Markdown link OR image
|
|
110
110
|
const regex =
|
|
111
111
|
/(?<prefix>[!@]?)\[(?<text>[^\]]*)\]\((?<url>\S+?)(?:\s+"(?<title>[^"]+)")?\)/g;
|
|
112
112
|
const matches = line.matchAll(regex);
|
|
@@ -310,12 +310,16 @@ const processLineMarkdownLinks = (
|
|
|
310
310
|
//Might further parse this to catch img in anchor.
|
|
311
311
|
|
|
312
312
|
//Match for html img - append to the lists
|
|
313
|
-
const regexHTMLImgTotal = /<img\s+(?<attributes>.*?)
|
|
313
|
+
const regexHTMLImgTotal = /<img\s+(?<attributes>.*?)>/gi;
|
|
314
|
+
//const regexHTMLImgTotal = /<img\s+(?<attributes>.*?)\/>/gi;
|
|
315
|
+
|
|
314
316
|
const regex_htmlattr_src =
|
|
315
317
|
/src\s*[=]\s*(?<quote>['"])(?<src>.*?)(?<!\\)\k<quote>/i;
|
|
318
|
+
|
|
319
|
+
|
|
316
320
|
for (const match of line.matchAll(regexHTMLImgTotal)) {
|
|
321
|
+
//console.log(`XXXXXregexHTMLImgTotals: ${match}`)
|
|
317
322
|
const attributes = match.groups.attributes;
|
|
318
|
-
//console.log(`XXXXXImageattributes_s: ${attributes}`)
|
|
319
323
|
const linkText = "";
|
|
320
324
|
let linkTitle = "";
|
|
321
325
|
let linkUrl = "";
|
package/src/process_orphans.js
CHANGED
|
@@ -2,14 +2,13 @@ import { logToFile } from "./helpers.js";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { sharedData } from "./shared_data.js";
|
|
4
4
|
import { PageNotInTOCError, PageNotLinkedInternallyError } from "./errors.js";
|
|
5
|
-
|
|
5
|
+
import { logFunction } from "./helpers.js";
|
|
6
6
|
|
|
7
7
|
// Gets page with most links. Supposed to be used on the allResults object that is an array of objects about each page.
|
|
8
8
|
// Will use to get the summary.
|
|
9
9
|
function getPageWithMostLinks(pages) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
10
|
+
logFunction(`Function: getPageWithMostLinks`);
|
|
11
|
+
|
|
13
12
|
return pages.reduce(
|
|
14
13
|
(maxLinksPage, currentPage) => {
|
|
15
14
|
if (
|
|
@@ -7,12 +7,11 @@ import {
|
|
|
7
7
|
UrlToLocalSiteError,
|
|
8
8
|
} from "./errors.js";
|
|
9
9
|
import { sharedData } from "./shared_data.js";
|
|
10
|
+
import { logFunction } from "./helpers.js";
|
|
10
11
|
|
|
11
12
|
// An array of errors given a results object that contains our array of objects containing relativeLinks (and other information).
|
|
12
13
|
function processRelativeLinks(results) {
|
|
13
|
-
|
|
14
|
-
? console.log("Function: processRelativeLinks")
|
|
15
|
-
: null;
|
|
14
|
+
logFunction(`Function: processRelativeLinks()`);
|
|
16
15
|
const errors = [];
|
|
17
16
|
|
|
18
17
|
//console.log(sharedData);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Test
|
|
2
|
+
|
|
3
|
+
Run like: `node .\index.js -d tests/links/html/img/`
|
|
4
|
+
|
|
5
|
+
Confirm links with and without end backslash are caught.
|
|
6
|
+
Also with/without attributes
|
|
7
|
+
|
|
8
|
+
<img src="../../assets/airframes/multicopter/x500_holybro_pixhawk4/img_with_no_end_backslash_oneofthree.png" width="400" title="Hanger gaskets">
|
|
9
|
+
|
|
10
|
+
<img src="../../assets/airframes/multicopter/x500_holybro_pixhawk4/img_with_backslash_twoofthree.png" width="400" title="Hanger gaskets" />
|
|
11
|
+
|
|
12
|
+
<img src="img_with_backslash_no_attributes_threeofthree.png" />
|
package/biglog.txt
DELETED
|
Binary file
|