1+ import { cp , mkdir , readdir } from 'node:fs/promises'
2+ import path from 'node:path'
3+ import fs from 'node:fs'
14import { JSX } from 'typedoc'
25
36/**
4- * Custom TypeDoc plugin to insert FontAwesome into the generated documentation .
5- * @type { (app: import('typedoc').Application) => void }
7+ * Custom TypeDoc plugin.
8+ * @param { import('typedoc').Application } app
69 */
710function customPlugin ( app ) {
11+ /**
12+ * Remove `.html` from internal links while preserving query/hash fragments.
13+ * External links are left untouched.
14+ * @param {string } href
15+ */
16+ function toExtensionlessHref ( href , ignoreAbsolute = true ) {
17+ // Ignore absolute/protocol links and special schemes.
18+ if (
19+ ignoreAbsolute &&
20+ ( / ^ (?: [ a - z ] [ a - z \d + . - ] * : ) ? \/ \/ / i. test ( href ) ||
21+ / ^ [ a - z ] [ a - z \d + . - ] * : / i. test ( href ) )
22+ ) {
23+ return href
24+ }
25+
26+ const [ withoutHash , hash = '' ] = href . split ( '#' , 2 )
27+ const [ pathname , query = '' ] = withoutHash . split ( '?' , 2 )
28+
29+ let nextPath = pathname
30+ if ( nextPath . endsWith ( '/index.html' ) ) {
31+ nextPath = nextPath . slice ( 0 , - 'index.html' . length )
32+ } else if ( nextPath === 'index.html' ) {
33+ nextPath = './'
34+ } else if ( nextPath . endsWith ( '.html' ) ) {
35+ nextPath = nextPath . slice ( 0 , - '.html' . length )
36+ }
37+
38+ const rebuilt = `${ nextPath } ${ query ? `?${ query } ` : '' } `
39+ return `${ rebuilt } ${ hash ? `#${ hash } ` : '' } `
40+ }
41+
42+ // Insert FontAwesome CSS into the head of the generated documentation
843 app . renderer . hooks . on ( 'head.end' , ( _context ) => {
944 return JSX . createElement ( 'link' , {
1045 rel : 'stylesheet' ,
1146 href : 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.2.0/css/fontawesome.min.css' ,
1247 } )
1348 } )
1449
50+ // Insert FontAwesome JS into the body of the generated documentation
1551 app . renderer . hooks . on ( 'body.end' , ( _context ) => {
1652 return JSX . createElement ( 'script' , {
1753 src : 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@7.2.0/js/all.min.js' ,
1854 defer : true ,
1955 } )
2056 } )
57+
58+ // Rewrite generated internal links to extensionless paths.
59+ app . renderer . on ( 'endPage' , ( page ) => {
60+ if ( ! page . contents ) {
61+ return
62+ }
63+
64+ page . contents = page . contents . replaceAll (
65+ / h r e f = " ( [ ^ " ] + ) " / g,
66+ ( _match , href ) => {
67+ return `href="${ toExtensionlessHref ( href ) } "`
68+ } ,
69+ )
70+ } )
71+
72+ app . renderer . postRenderAsyncJobs . push ( async ( event ) => {
73+ // Create `name/index.html` aliases for root-level `name.html` pages.
74+ const rootEntries = await readdir ( event . outputDirectory , {
75+ withFileTypes : true ,
76+ } )
77+ const rootHtmlFiles = rootEntries . filter (
78+ ( entry ) =>
79+ entry . isFile ( ) &&
80+ entry . name . endsWith ( '.html' ) &&
81+ entry . name !== 'index.html' &&
82+ entry . name !== '404.html' ,
83+ )
84+
85+ await Promise . all (
86+ rootHtmlFiles . map ( async ( entry ) => {
87+ const fileName = entry . name
88+ const basename = fileName . slice ( 0 , - '.html' . length )
89+ const source = path . join ( event . outputDirectory , fileName )
90+ const targetDir = path . join ( event . outputDirectory , basename )
91+ const target = path . join ( targetDir , 'index.html' )
92+
93+ await mkdir ( targetDir , { recursive : true } )
94+ await cp ( source , target )
95+ } ) ,
96+ )
97+
98+ // Rewrite the `.html` extension from the generated `sitemap.xml` as well.
99+ const sitemapPath = path . join ( event . outputDirectory , 'sitemap.xml' )
100+ try {
101+ const sitemapContents = fs . readFileSync ( sitemapPath ) . toString ( 'utf-8' )
102+ const rewritten = sitemapContents
103+ . toString ( )
104+ . replaceAll ( / < l o c > ( [ ^ < ] + ) < \/ l o c > / g, ( _match , loc ) => {
105+ return `<loc>${ toExtensionlessHref ( loc , false ) } </loc>`
106+ } )
107+ await fs . writeFile ( sitemapPath , rewritten , ( ) => { } )
108+ } catch ( err ) {
109+ // If the sitemap doesn't exist, ignore the error and continue.
110+ if ( err . code !== 'ENOENT' ) {
111+ throw err
112+ }
113+ }
114+ } )
21115}
22116
23117/** @type {Partial<import('typedoc').TypeDocOptions> & Partial<import('typedoc-plugin-merge-modules').Config> & import('typedoc-plugin-umami-analytics').Config } */
24118const config = {
119+ cleanOutputDir : true ,
25120 commentStyle : 'all' ,
26121 customFooterHtml :
27122 'Built with <i color="#f31e1e" class="fa-solid fa-heart" aria-label="love"></i> by the <a href="https://fontawesome.com/">FontAwesome Team</a> and <a href="https://github.com/FortAwesome/react-fontawesome/graphs/contributors">community contributors</a>.' ,
28123 entryPoints : [ './src/index.ts' , './src/components/rsc/*.tsx' ] ,
29- entryPointStrategy : 'resolve' ,
124+ // entryPointStrategy: 'resolve',
30125 excludeExternals : true ,
31126 excludeNotDocumented : false ,
32127 // Ensure references from @fortawesome packages are not considered external and therefore excluded, e.g. svg-core & common-types (we want them included)
33128 externalPattern : [ '**/node_modules/!(@fortawesome)/**' ] ,
129+ githubPages : true ,
34130 gitRemote : 'origin' ,
35131 gitRevision : 'main' ,
36132 favicon : './docs/src/assets/favicon.ico' ,
37133 hideGenerator : true ,
134+ hostedBaseUrl : 'https://fortawesome.github.io/react-fontawesome/' ,
135+ markdownLinkExternal : true ,
38136 mergeModulesMergeMode : 'module' ,
39137 mergeModulesRenameDefaults : true ,
40138 name : 'FontAwesome React API Reference' ,
@@ -53,20 +151,26 @@ const config = {
53151 'typedoc-plugin-umami-analytics' ,
54152 customPlugin ,
55153 ] ,
56- projectDocuments : [ './CHANGELOG.md' ] ,
154+ projectDocuments : [
155+ './CHANGELOG.md' ,
156+ './CONTRIBUTING.md' ,
157+ './CODE_OF_CONDUCT.md' ,
158+ ] ,
57159 readme : './docs/src/API-Reference-Readme.md' ,
58- router : 'structure' ,
160+ router : 'structure-dir ' ,
59161 sort : [
60162 'required-first' ,
61163 'kind' ,
62164 'instance-first' ,
63165 'alphabetical-ignoring-documents' ,
64166 ] ,
65- tsconfig : './tsconfig.json' ,
167+ sourceLinkExternal : true ,
66168 theme : 'typedoc-github-theme' ,
169+ tsconfig : './tsconfig.json' ,
67170 umamiScriptURL : 'https://analytics.charlesharwood.dev/script.js' ,
68171 umamiWebsiteID : 'd0b01ae4-f0b1-4f6c-8967-6a9c1504cd49' ,
69172 useFirstParagraphOfCommentAsSummary : true ,
173+ visibilityFilters : { } ,
70174}
71175
72176export default config
0 commit comments