@@ -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 */
174174validator . 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