@@ -5,55 +5,111 @@ import YAML from 'yaml'
55
66import { siteSections } from './lib/config.js'
77
8- const gitbookConfig = YAML . parse ( readFileSync ( '.gitbook.yaml' , 'utf-8' ) ) as {
8+ interface GitbookConfig {
9+ root ?: string
910 redirects ?: Record < string , string >
1011}
1112
12- interface Redirect {
13+ interface BrokenRedirect {
14+ configPath : string
1315 source : string
1416 target : string
17+ reason : string
1518}
1619
17- const redirects : Redirect [ ] = Object . entries ( gitbookConfig . redirects ?? { } ) . map (
18- ( [ source , target ] ) => ( { source, target } ) ,
19- )
20+ function findForeignSection ( path : string , ownRoot : string ) : string | undefined {
21+ for ( const other of siteSections ) {
22+ if ( other . root === ownRoot ) continue
23+ const prefix = other . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
24+ if ( prefix !== '/' && path . startsWith ( prefix ) ) return other . name
25+ }
26+ return undefined
27+ }
2028
21- function pageExists ( fullPath : string ) : boolean {
22- return existsSync ( fullPath ) && statSync ( fullPath ) . isFile ( )
29+ const broken : BrokenRedirect [ ] = [ ]
30+
31+ interface ConfigToValidate {
32+ configPath : string
33+ root : string
34+ redirects : Record < string , string >
2335}
2436
25- function resolveTarget ( target : string ) : boolean {
26- for ( const section of siteSections ) {
27- if ( section . urlPrefix === '' ) continue
37+ const configs : ConfigToValidate [ ] = [ ]
38+
39+ for ( const section of siteSections ) {
40+ const configPath = join ( section . root , '.gitbook.yaml' )
41+ if ( ! existsSync ( configPath ) ) continue
42+ const config = YAML . parse ( readFileSync ( configPath , 'utf-8' ) ) as GitbookConfig
43+ configs . push ( {
44+ configPath,
45+ root : section . root ,
46+ redirects : config . redirects ?? { } ,
47+ } )
48+ }
49+
50+ const rootConfigPath = '.gitbook.yaml'
51+ const rootIsSection = configs . some ( ( c ) => c . configPath === rootConfigPath )
52+ if ( ! rootIsSection && existsSync ( rootConfigPath ) ) {
53+ const config = YAML . parse (
54+ readFileSync ( rootConfigPath , 'utf-8' ) ,
55+ ) as GitbookConfig
56+ const root = ( config . root ?? './' ) . replace ( / ^ \. \/ / , '' ) . replace ( / \/ $ / , '' )
57+ configs . push ( {
58+ configPath : rootConfigPath ,
59+ root,
60+ redirects : config . redirects ?? { } ,
61+ } )
62+ }
2863
29- const prefix = section . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
30- if ( target . startsWith ( prefix ) ) {
31- const relativePath = target . slice ( prefix . length )
32- return pageExists ( join ( section . root , relativePath ) )
64+ for ( const { configPath, root, redirects } of configs ) {
65+ for ( const [ source , target ] of Object . entries ( redirects ) ) {
66+ const foreignSource = findForeignSection ( source , root )
67+ if ( foreignSource != null ) {
68+ broken . push ( {
69+ configPath,
70+ source,
71+ target,
72+ reason : `Source belongs to the "${ foreignSource } " section. Use a site-level redirect in the GitBook UI instead` ,
73+ } )
74+ continue
3375 }
34- }
3576
36- const guidesSection = siteSections . find ( ( s ) => s . urlPrefix === '' )
37- if ( guidesSection == null ) return false
77+ const foreignTarget = findForeignSection ( target , root )
78+ if ( foreignTarget != null ) {
79+ broken . push ( {
80+ configPath,
81+ source,
82+ target,
83+ reason : `Target points to the "${ foreignTarget } " section. Use a site-level redirect in the GitBook UI instead` ,
84+ } )
85+ continue
86+ }
3887
39- return pageExists ( join ( guidesSection . root , target ) )
88+ const fullPath = join ( root , target )
89+ if ( ! existsSync ( fullPath ) || ! statSync ( fullPath ) . isFile ( ) ) {
90+ broken . push ( {
91+ configPath,
92+ source,
93+ target,
94+ reason : `File not found: ${ fullPath } ` ,
95+ } )
96+ }
97+ }
4098}
4199
42- const broken : Redirect [ ] = redirects . filter ( ( r ) => ! resolveTarget ( r . target ) )
43-
44100if ( broken . length > 0 ) {
45101 // eslint-disable-next-line no-console
46- console . error (
47- `Found ${ broken . length } redirect(s) with missing target(s) in .gitbook.yaml:\n` ,
48- )
49- for ( const { source, target } of broken ) {
102+ console . error ( `Found ${ broken . length } redirect issue(s):\n` )
103+ for ( const { configPath , source , target, reason } of broken ) {
104+ // eslint-disable-next-line no-console
105+ console . error ( ` [ ${ configPath } ] ${ source } ` )
50106 // eslint-disable-next-line no-console
51- console . error ( ` ${ source } ` )
107+ console . error ( ` target: ${ target } ` )
52108 // eslint-disable-next-line no-console
53- console . error ( ` target: ${ target } \n` )
109+ console . error ( ` ${ reason } \n` )
54110 }
55111 process . exit ( 1 )
56112} else {
57113 // eslint-disable-next-line no-console
58- console . log ( 'All .gitbook.yaml redirect targets are valid.' )
114+ console . log ( 'All redirect targets are valid.' )
59115}
0 commit comments