@@ -15,8 +15,8 @@ import { execSync } from 'child_process';
1515import {
1616 existsSync ,
1717 mkdirSync ,
18- readFileSync ,
1918 readdirSync ,
19+ readFileSync ,
2020 renameSync ,
2121 writeFileSync ,
2222} from 'fs' ;
@@ -98,7 +98,13 @@ const TYPE_SECTIONS = [
9898 { prefix : 'Enumeration' , title : 'Enumerations' } ,
9999] ;
100100
101- const TYPEDOC_BIN = join ( DOCS_SITE , 'node_modules' , 'typedoc' , 'bin' , 'typedoc' ) ;
101+ const TYPEDOC_BIN = join (
102+ DOCS_SITE ,
103+ 'node_modules' ,
104+ 'typedoc' ,
105+ 'bin' ,
106+ 'typedoc'
107+ ) ;
102108
103109// ── Helpers ──────────────────────────────────────────────────────────────────
104110
@@ -108,39 +114,41 @@ const TYPEDOC_BIN = join(DOCS_SITE, 'node_modules', 'typedoc', 'bin', 'typedoc')
108114 * folder segment, producing broken links like `/api/Class.ClientManager`
109115 * instead of `/api/core/Class.ClientManager`.
110116 *
117+ * Next.js also routes pages without file extensions, so any `href.md` in
118+ * generated markdown link hrefs will 404 — they must be stripped to `href`.
119+ *
111120 * This function:
112- * 1. Rewrites cross-reference links in all . md files
113- * `Type.Name.md` → `Type-Name .md`
114- * `README .md` → `index.md` (TypeDoc breadcrumb links )
115- * 2 . Renames every ` Type.Name.md` file → ` Type-Name.md`
121+ * 1. Rewrites cross-reference links: Type.Name. md → Type-Name.md
122+ * 2. Rewrites breadcrumb links: README.md → index .md
123+ * 3. Strips .md extension from ALL relative link hrefs ()(path.md) → (path )
124+ * 4 . Renames files: Type.Name.md → Type-Name.md
116125 */
117126function fixDotSlugs ( pkgOut ) {
118127 const TYPE_PREFIXES =
119128 'Class|Interface|TypeAlias|Function|Variable|Enumeration' ;
120- const LINK_RE = new RegExp (
121- `(${ TYPE_PREFIXES } )\\.([^)"\\s]+\\.md)` ,
122- 'g' ,
123- ) ;
129+ const LINK_RE = new RegExp ( `(${ TYPE_PREFIXES } )\\.([^)"\\s]+\\.md)` , 'g' ) ;
130+ // Strip .md from relative link hrefs — skip http(s) and anchor-only hrefs
131+ const MD_EXT_RE = / ( \] \( ) ( (? ! h t t p s ? : \/ \/ ) (? ! # ) [ ^ ) ] + ) \. m d \) / g;
124132
125133 const files = readdirSync ( pkgOut ) . filter ( ( f ) => f . endsWith ( '.md' ) ) ;
126134
127135 // Step 1 — rewrite links inside every file before renaming
128136 for ( const file of files ) {
129137 const path = join ( pkgOut , file ) ;
130138 const original = readFileSync ( path , 'utf8' ) ;
131- let rewritten = original
132- // Type.Name.md → Type-Name.md
139+ const rewritten = original
140+ // Type.Name.md → Type-Name.md (must run before MD_EXT_RE)
133141 . replace ( LINK_RE , ( _ , type , rest ) => `${ type } -${ rest } ` )
134142 // README.md → index.md (TypeDoc breadcrumb links)
135- . replace ( / \( R E A D M E \. m d \) / g, '(index.md)' ) ;
143+ . replace ( / \( R E A D M E \. m d \) / g, '(index.md)' )
144+ // Strip .md extension from all remaining relative link hrefs
145+ . replace ( MD_EXT_RE , ( _ , open , href ) => `${ open } ${ href } )` ) ;
136146 if ( rewritten !== original ) writeFileSync ( path , rewritten ) ;
137147 }
138148
139149 // Step 2 — rename the files themselves
140150 for ( const file of files ) {
141- const match = file . match (
142- new RegExp ( `^(${ TYPE_PREFIXES } )\\.(.+\\.md)$` ) ,
143- ) ;
151+ const match = file . match ( new RegExp ( `^(${ TYPE_PREFIXES } )\\.(.+\\.md)$` ) ) ;
144152 if ( match ) {
145153 renameSync ( join ( pkgOut , file ) , join ( pkgOut , `${ match [ 1 ] } -${ match [ 2 ] } ` ) ) ;
146154 }
@@ -238,7 +246,7 @@ for (const pkg of PACKAGES) {
238246 'false' ,
239247 '--hidePageTitle' ,
240248 'false' ,
241- ] . join ( ' ' ) ,
249+ ] . join ( ' ' )
242250 ) ;
243251
244252 // TypeDoc outputs README.md as the overview page — rename to index.md
0 commit comments