Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit 96036de

Browse files
authored
Validate broken images (#107)
* Add check for broken image links * Check for broken image paths
1 parent c0192d7 commit 96036de

File tree

2 files changed

+30
-21
lines changed

2 files changed

+30
-21
lines changed

scripts/validation/domain/tutorial.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ var Tutorial = class Tutorial {
1313
}
1414

1515
get path(){
16+
return this.basePath;
17+
}
18+
19+
get contentFilePath(){
1620
return this.basePath + "/content.md";
1721
}
1822

1923
get markdown(){
20-
if(!fs.existsSync(this.path)){
21-
console.log("❌ File doens't exist " + this.path);
24+
if(!fs.existsSync(this.contentFilePath)){
25+
console.log("❌ File doens't exist " + this.contentFilePath);
2226
return null;
2327
}
24-
let rawData = fs.readFileSync(this.path).toString();
28+
let rawData = fs.readFileSync(this.contentFilePath).toString();
2529
const content = fm(rawData);
2630
return content.body;
2731
}
@@ -80,11 +84,11 @@ var Tutorial = class Tutorial {
8084

8185
get metadata(){
8286
try {
83-
let rawData = fs.readFileSync(this.path).toString();
87+
let rawData = fs.readFileSync(this.contentFilePath).toString();
8488
const content = fm(rawData);
8589
return content.attributes;
8690
} catch (error) {
87-
console.log("Error occurred while parsing " + this.path);
91+
console.log("Error occurred while parsing " + this.contentFilePath);
8892
console.log(error);
8993
return null;
9094
}

scripts/validation/validate.js

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,29 @@ validator.addValidation(async (tutorials) => {
3333
let jsonData = tutorial.metadata;
3434
if(!jsonData) {
3535
const errorMessage = "No metadata found";
36-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
36+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
3737
return;
3838
}
3939

4040
try {
4141
if(!jsonData.coverImage){
4242
const errorMessage = "No cover image found";
43-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
43+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
4444
} else if (jsonData.coverImage.indexOf(".svg") == -1) {
4545
const errorMessage = "Cover image is not in SVG format.";
46-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
46+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
4747
}
4848

4949
let jsonSchema = JSON.parse(fs.readFileSync(config.metadataSchema));
5050
let validationResult = validate(jsonData, jsonSchema);
5151
if(validationResult.errors.length != 0){
5252
const errorMessage = `An error occurred while validating the metadata ${validationResult}`;
53-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
53+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
5454
}
5555

5656
} catch (error) {
5757
const errorMessage = "An error occurred while parsing the metadata";
58-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
58+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
5959
}
6060
});
6161
return errorsOccurred;
@@ -70,11 +70,11 @@ validator.addValidation(async (tutorials) => {
7070
tutorial.headings.forEach(heading => {
7171
if(tc.titleCase(heading) != heading){
7272
const errorMessage = heading + "' is not title case";
73-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
73+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
7474
}
7575
if(heading.length > config.headingMaxLength){
7676
const errorMessage = heading + "' (" + heading.length + ") exceeds the max length (" + config.headingMaxLength + ")";
77-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
77+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
7878
}
7979
});
8080
});
@@ -97,7 +97,7 @@ validator.addValidation(async (tutorials) => {
9797
// Detect if there are embedded images that are actually rendered
9898
if(image.attributes.width || image.attributes.height){
9999
const errorMessage = path + " contains embedded binary images.";
100-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path, "warning"));
100+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath, "warning"));
101101
}
102102
}
103103
});
@@ -131,7 +131,7 @@ validator.addValidation(async (tutorials) => {
131131
console.log('👍 %s is alive', result.link);
132132
} else if(result.status == "dead" && result.statusCode !== 0){
133133
const errorMessage = `${result.link} is dead 💀 HTTP ${result.statusCode}`;
134-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
134+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
135135
}
136136
});
137137
resolve(errorsOccurred);
@@ -159,7 +159,7 @@ validator.addValidation(async (tutorials) => {
159159
assetNames.forEach(asset => {
160160
if(coverImageName == asset) return;
161161
if(!imageNames.includes(asset) && !linkNames.includes(asset)){
162-
const errorMessage = asset + " is not used";
162+
const errorMessage = asset + " is not used.";
163163
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
164164
}
165165
});
@@ -169,7 +169,7 @@ validator.addValidation(async (tutorials) => {
169169

170170

171171
/**
172-
* Verify that the images don't have an absolute path
172+
* Verify that the images exist and don't have an absolute path
173173
*/
174174
validator.addValidation(async (tutorials) => {
175175
let errorsOccurred = [];
@@ -179,7 +179,12 @@ validator.addValidation(async (tutorials) => {
179179
const errorMessage = "Image uses an absolute path: " + imagePath;
180180
const content = tutorial.markdown;
181181
const lineNumber = fileHelper.getLineNumberFromIndex(content.indexOf(imagePath), content);
182-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path, lineNumber));
182+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath, "error", lineNumber));
183+
} else if(!imagePath.startsWith("http") && !fs.existsSync(`${tutorial.path}/${imagePath}`)){
184+
const errorMessage = "Image doesn't exist: " + imagePath;
185+
const content = tutorial.markdown;
186+
const lineNumber = fileHelper.getLineNumberFromIndex(content.indexOf(imagePath), content);
187+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath, "error", lineNumber));
183188
}
184189
});
185190
});
@@ -197,7 +202,7 @@ validator.addValidation(async (tutorials) => {
197202
let nodes = tutorial.html.querySelectorAll("li ul");
198203
if(nodes && nodes.length > 0){
199204
const errorMessage = "Content uses nested lists";
200-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
205+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
201206
}
202207
});
203208
return errorsOccurred;
@@ -214,7 +219,7 @@ validator.addValidation(async (tutorials) => {
214219
const imageDescription = image.attributes.alt;
215220
if(imageDescription.split(" ").length <= 1){
216221
const errorMessage = "Image doesn't have a description: " + image.attributes.src;
217-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
222+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
218223
}
219224
});
220225
});
@@ -233,7 +238,7 @@ validator.addValidation(async (tutorials) => {
233238
if(syntax) syntax = syntax.replace(PARSER_SYNTAX_PREFIX, '');
234239
if(!config.allowedSyntaxSpecifiers.includes(syntax)){
235240
const errorMessage = "Code block uses unsupported syntax: " + syntax;
236-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path));
241+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath));
237242
}
238243
});
239244
});
@@ -274,7 +279,7 @@ validator.addValidation(async (tutorials) => {
274279
}
275280
if((match === null && rule.shouldMatch) || (match !== null && !rule.shouldMatch)) {
276281
const errorMessage = rule.errorMessage;
277-
errorsOccurred.push(new ValidationError(errorMessage, tutorial.path, ruleType, lineNumber));
282+
errorsOccurred.push(new ValidationError(errorMessage, tutorial.contentFilePath, ruleType, lineNumber));
278283
}
279284
}
280285

0 commit comments

Comments
 (0)