1- const fs = require ( 'fs' ) ;
2- const gulp = require ( 'gulp' ) ;
3- const { exec} = require ( 'child_process' ) ;
4- const express = require ( 'express' ) ;
5- const checkPages = require ( 'check-pages' ) ;
6- const { glob } = require ( 'glob' ) ;
7- const cheerio = require ( 'cheerio' ) ;
1+ import { exec } from 'child_process' ;
2+ import { readFileSync } from 'fs' ;
3+ import gulp from 'gulp' ;
4+ import express from 'express' ;
5+ import { glob } from 'glob' ;
6+ import { LinkChecker } from 'linkinator' ;
7+
8+ const cheerio = await import ( 'cheerio' ) ;
89
910function displayErrors ( err , stdout , stderr ) {
1011 if ( err ) {
@@ -19,7 +20,7 @@ function checkInternalLinksAndExit(htmlPath) {
1920 const duplicateHeadingIds = [ ] ;
2021 const seenHeadingIds = new Set ( ) ;
2122 const badLinks = [ ] ;
22- const $ = cheerio . load ( fs . readFileSync ( htmlPath , 'utf8' ) ) ;
23+ const $ = cheerio . load ( readFileSync ( htmlPath , 'utf8' ) ) ;
2324
2425 $ ( 'a' ) . each ( ( index , anchor ) => {
2526 const href = $ ( anchor ) . attr ( 'href' ) || '' ;
@@ -32,13 +33,12 @@ function checkInternalLinksAndExit(htmlPath) {
3233 if ( foundElementByName ) return ;
3334
3435 const text = $ ( anchor ) . text ( ) ;
35- badLinks . push ( { text, href} ) ;
36+ badLinks . push ( { text, href } ) ;
3637 }
3738 } ) ;
3839
3940 $ ( 'h1,h2,h3' ) . each ( ( index , element ) => {
4041 const id = $ ( element ) . attr ( 'id' ) ;
41-
4242 if ( id ) {
4343 if ( seenHeadingIds . has ( id ) ) duplicateHeadingIds . push ( id ) ;
4444 else seenHeadingIds . add ( id ) ;
@@ -48,7 +48,7 @@ function checkInternalLinksAndExit(htmlPath) {
4848 if ( badLinks . length ) {
4949 console . error ( 'v3 docs error: Found invalid internal links' ) ;
5050 console . error ( 'Make sure these `href`s correspond to the `id`s of real headings in the HTML:' ) ;
51- console . error ( badLinks . map ( ( { text, href} ) => ` - [${ text } ](${ href } )` ) . join ( '\n' ) ) ;
51+ console . error ( badLinks . map ( ( { text, href } ) => ` - [${ text } ](${ href } )` ) . join ( '\n' ) ) ;
5252 }
5353
5454 if ( duplicateHeadingIds . length ) {
@@ -63,8 +63,9 @@ function checkInternalLinksAndExit(htmlPath) {
6363}
6464
6565function checkSyntaxErrorsAndExit ( htmlPath ) {
66- const $ = cheerio . load ( fs . readFileSync ( htmlPath , 'utf8' ) ) ;
66+ const $ = cheerio . load ( readFileSync ( htmlPath , 'utf8' ) ) ;
6767 const syntaxErrors = $ ( 'code .err' ) ;
68+
6869 if ( syntaxErrors . length ) {
6970 syntaxErrors . each ( ( _index , errorElement ) => {
7071 console . error ( '⚠️ v3 docs error: Found syntax error' ) ;
@@ -73,25 +74,66 @@ function checkSyntaxErrorsAndExit(htmlPath) {
7374 console . error ( '👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆\n' )
7475 } ) ;
7576
76- process . exit ( 1 )
77+ process . exit ( 1 ) ;
7778 }
7879}
7980
80- function checkPathAndExit ( path , options , done ) {
81+ async function checkPathAndExit ( path , options , done ) {
8182 const app = express ( ) ;
8283 app . use ( express . static ( path ) ) ;
83- const server = app . listen ( { port : 8001 } ) ;
84+ const server = app . listen ( { port : 8001 } ) ;
85+
86+ const url = 'http://localhost:8001/' ;
87+
88+ const config = {
89+ path : url ,
90+ linksToSkip : options . linksToSkip || [ ] ,
91+ recurse : options . recurse ,
92+ silent : options . silent ,
93+ markdown : options . markdown ,
94+ } ;
95+
96+ try {
97+ const checker = new LinkChecker ( ) ;
98+
99+ if ( path === '../v2' ) {
100+ const htmlFiles = await glob ( path + '/**/*.html' ) ;
101+ let allResults = { links : [ ] } ;
102+ for ( let file of htmlFiles ) {
103+ const fileUrl = url + file . substr ( path . length ) ;
104+ const fileConfig = { ...config , path : fileUrl } ;
105+ const results = await checker . check ( fileConfig ) ;
106+ allResults . links = allResults . links . concat ( results . links ) ;
107+ }
108+ displayResults ( allResults ) ;
109+ } else {
110+ const results = await checker . check ( config ) ;
111+ displayResults ( results ) ;
112+ }
84113
85- return checkPages ( console , options , ( err , stdout , stderr ) => {
86114 server . close ( ) ;
87115 done ( ) ;
88116
89- if ( err ) {
90- return displayErrors ( err , stdout , stderr ) ;
91- }
117+ } catch ( err ) {
118+ server . close ( ) ;
119+ done ( err ) ;
120+ process . exit ( 1 ) ;
121+ }
122+ }
92123
93- return true ;
94- } ) ;
124+ function displayResults ( results ) {
125+ const totalLinks = results . links . length ;
126+ const brokenLinks = results . links . filter ( link => link . state === 'BROKEN' ) ;
127+
128+ console . log ( `Total Links Checked: ${ totalLinks } ` ) ;
129+ console . log ( `Broken Links Found: ${ brokenLinks . length } ` ) ;
130+ if ( brokenLinks . length > 0 ) {
131+ console . log ( 'Broken Links:' ) ;
132+ brokenLinks . forEach ( link => {
133+ console . log ( ` - ${ link . url } (status: ${ link . status } )` ) ;
134+ } ) ;
135+ process . exitCode = 1 ;
136+ }
95137}
96138
97139gulp . task ( 'build' , cb => {
@@ -110,7 +152,7 @@ gulp.task('webserver', cb => {
110152 }
111153 cb ( ) ;
112154 } ) ;
113- console . log ( 'Your docs are waiting for you at http://localhost:8000' )
155+ console . log ( 'Your docs are waiting for you at http://localhost:8000' ) ;
114156} ) ;
115157
116158gulp . task ( 'default' , gulp . series ( 'webserver' ) ) ;
@@ -119,29 +161,29 @@ gulp.task('checkV3docs', gulp.series('build', done => {
119161 checkInternalLinksAndExit ( 'build/index.html' ) ;
120162 checkSyntaxErrorsAndExit ( 'build/index.html' ) ;
121163
122- checkPathAndExit ( 'build' , {
123- checkLinks : true ,
124- summary : true ,
125- terse : true ,
126- onlySameDomain : true ,
127- pageUrls : [ 'http://localhost:8001/' ] ,
128- linksToIgnore : [ 'http://localhost:8001/version/release-candidate' ]
129- } , done ) ;
164+ try {
165+ checkPathAndExit ( 'build' , {
166+ linksToSkip : [ 'http://localhost:8001/version/release-candidate' ] ,
167+ recurse : true ,
168+ silent : true ,
169+ markdown : true ,
170+ } , done ) ;
171+ } catch ( err ) {
172+ done ( err ) ;
173+ }
130174} ) ) ;
131175
132- gulp . task ( 'checkV2docs' , async ( done ) => {
133- const htmlFiles = await glob ( '../v2/**/*.html' )
134- const fixedFiles = htmlFiles . map ( fname => {
135- return 'http://localhost:8001' + fname . substr ( '../v2' . length ) ;
136- } ) ;
137-
138- checkPathAndExit ( '../v2' , {
139- checkLinks : true ,
140- summary : true ,
141- terse : true ,
142- onlySameDomain : true ,
143- pageUrls : [ 'http://localhost:8001/' ] . concat ( fixedFiles )
144- } , done ) ;
176+ gulp . task ( 'checkV2docs' , done => {
177+ try {
178+ checkPathAndExit ( '../v2' , {
179+ linksToSkip : [ ] ,
180+ recurse : true ,
181+ silent : true ,
182+ markdown : true ,
183+ } , done ) ;
184+ } catch ( err ) {
185+ done ( err ) ;
186+ }
145187} ) ;
146188
147- gulp . task ( 'checkdocs' , gulp . parallel ( 'checkV2docs' , 'checkV3docs' ) ) ;
189+ gulp . task ( 'checkdocs' , gulp . series ( 'checkV2docs' , 'checkV3docs' ) ) ;
0 commit comments