@@ -5,55 +5,136 @@ 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 {
99 redirects ?: Record < string , string >
1010}
1111
12- interface Redirect {
12+ interface BrokenRedirect {
13+ configPath : string
1314 source : string
1415 target : string
16+ reason : string
1517}
1618
17- const redirects : Redirect [ ] = Object . entries ( gitbookConfig . redirects ?? { } ) . map (
18- ( [ source , target ] ) => ( { source, target } ) ,
19- )
19+ const broken : BrokenRedirect [ ] = [ ]
2020
21- function pageExists ( fullPath : string ) : boolean {
22- return existsSync ( fullPath ) && statSync ( fullPath ) . isFile ( )
23- }
21+ for ( const section of siteSections ) {
22+ const configPath = join ( section . root , '.gitbook.yaml' )
23+ if ( ! existsSync ( configPath ) ) continue
2424
25- function resolveTarget ( target : string ) : boolean {
26- for ( const section of siteSections ) {
27- if ( section . urlPrefix === '' ) continue
25+ const config = YAML . parse ( readFileSync ( configPath , 'utf-8' ) ) as GitbookConfig
26+ const redirects = config . redirects ?? { }
27+ for ( const [ source , target ] of Object . entries ( redirects ) ) {
28+ // Source must not start with another section's URL prefix
29+ for ( const other of siteSections ) {
30+ if ( other . root === section . root ) continue
31+ const otherPrefix = other . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
32+ if ( otherPrefix !== '/' && source . startsWith ( otherPrefix ) ) {
33+ broken . push ( {
34+ configPath,
35+ source,
36+ target,
37+ reason : `Source belongs to the "${ other . name } " section, not "${ section . name } ". Move this redirect to ${ join ( other . root , '.gitbook.yaml' ) } ` ,
38+ } )
39+ }
40+ }
41+
42+ // Target must not start with another section's URL prefix
43+ for ( const other of siteSections ) {
44+ if ( other . root === section . root ) continue
45+ const otherPrefix = other . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
46+ if ( otherPrefix !== '/' && target . startsWith ( otherPrefix ) ) {
47+ broken . push ( {
48+ configPath,
49+ source,
50+ target,
51+ reason : `Target points to the "${ other . name } " section. Move this redirect to ${ join ( other . root , '.gitbook.yaml' ) } ` ,
52+ } )
53+ }
54+ }
2855
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 ) )
56+ // Target must resolve to an existing file within this section
57+ const fullPath = join ( section . root , target )
58+ if ( ! existsSync ( fullPath ) || ! statSync ( fullPath ) . isFile ( ) ) {
59+ broken . push ( {
60+ configPath,
61+ source,
62+ target,
63+ reason : `File not found: ${ fullPath } ` ,
64+ } )
3365 }
3466 }
67+ }
3568
36- const guidesSection = siteSections . find ( ( s ) => s . urlPrefix === '' )
37- if ( guidesSection == null ) return false
69+ // Also check the root .gitbook.yaml if it's not already a section config
70+ const rootConfigPath = '.gitbook.yaml'
71+ const rootIsSection = siteSections . some (
72+ ( s ) => join ( s . root , '.gitbook.yaml' ) === rootConfigPath ,
73+ )
3874
39- return pageExists ( join ( guidesSection . root , target ) )
40- }
75+ if ( ! rootIsSection && existsSync ( rootConfigPath ) ) {
76+ const config = YAML . parse (
77+ readFileSync ( rootConfigPath , 'utf-8' ) ,
78+ ) as GitbookConfig & { root ?: string }
79+ const redirects = config . redirects ?? { }
80+ const root = ( config . root ?? './' ) . replace ( / ^ \. \/ / , '' ) . replace ( / \/ $ / , '' )
4181
42- const broken : Redirect [ ] = redirects . filter ( ( r ) => ! resolveTarget ( r . target ) )
82+ const section = siteSections . find ( ( s ) => s . root === root )
83+
84+ for ( const [ source , target ] of Object . entries ( redirects ) ) {
85+ for ( const other of siteSections ) {
86+ if ( section != null && other . root === section . root ) continue
87+ const otherPrefix = other . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
88+ if ( otherPrefix !== '/' && source . startsWith ( otherPrefix ) ) {
89+ broken . push ( {
90+ configPath : rootConfigPath ,
91+ source,
92+ target,
93+ reason : `Source belongs to the "${ other . name } " section. Move this redirect to ${ join ( other . root , '.gitbook.yaml' ) } ` ,
94+ } )
95+ }
96+ }
97+
98+ for ( const other of siteSections ) {
99+ if ( section != null && other . root === section . root ) continue
100+ const otherPrefix = other . urlPrefix . replace ( / ^ \/ / , '' ) + '/'
101+ if ( otherPrefix !== '/' && target . startsWith ( otherPrefix ) ) {
102+ broken . push ( {
103+ configPath : rootConfigPath ,
104+ source,
105+ target,
106+ reason : `Target points to the "${ other . name } " section. Move this redirect to ${ join ( other . root , '.gitbook.yaml' ) } ` ,
107+ } )
108+ }
109+ }
110+
111+ const fullPath = join ( root , target )
112+ if ( ! existsSync ( fullPath ) || ! statSync ( fullPath ) . isFile ( ) ) {
113+ broken . push ( {
114+ configPath : rootConfigPath ,
115+ source,
116+ target,
117+ reason : `File not found: ${ fullPath } ` ,
118+ } )
119+ }
120+ }
121+ }
43122
44123if ( broken . length > 0 ) {
45124 // eslint-disable-next-line no-console
46125 console . error (
47- `Found ${ broken . length } redirect(s) with missing target (s) in .gitbook.yaml :\n` ,
126+ `Found ${ broken . length } redirect issue (s):\n` ,
48127 )
49- for ( const { source, target } of broken ) {
128+ for ( const { configPath, source, target, reason } of broken ) {
129+ // eslint-disable-next-line no-console
130+ console . error ( ` [${ configPath } ] ${ source } ` )
50131 // eslint-disable-next-line no-console
51- console . error ( ` ${ source } ` )
132+ console . error ( ` target: ${ target } ` )
52133 // eslint-disable-next-line no-console
53- console . error ( ` target: ${ target } \n` )
134+ console . error ( ` ${ reason } \n` )
54135 }
55136 process . exit ( 1 )
56137} else {
57138 // eslint-disable-next-line no-console
58- console . log ( 'All .gitbook.yaml redirect targets are valid.' )
139+ console . log ( 'All redirect targets are valid.' )
59140}
0 commit comments