@@ -25,6 +25,7 @@ const TEMPLATE_PATH = path.join(__dirname, "docs-json-template.json");
2525const STYLING_CSS_PATH = path . join ( __dirname , "styling.css" ) ;
2626const CATEGORY_MAP_PATH = path . join ( __dirname , "../category-map.json" ) ;
2727const TYPES_TO_EXPOSE_PATH = path . join ( __dirname , ".." , "types-to-expose.json" ) ;
28+ const TYPES_TO_DELETE_PATH = path . join ( __dirname , ".." , "types-to-delete-after-processing.json" ) ;
2829const APPENDED_ARTICLES_PATH = path . join (
2930 __dirname ,
3031 "../appended-articles.json"
@@ -135,9 +136,11 @@ function processLinksInFile(filePath) {
135136 modified = true ;
136137 }
137138
138- // Remove undesirable lines like "> **IntegrationsModule** = `object` & `object`"
139- // This typically appears in type alias files using intersection types
140- const typeDefinitionRegex = / ^ > \* \* \w + \* \* = ` o b j e c t ` & ` o b j e c t ` \s * $ / m;
139+ // Remove undesirable type-alias definition lines like:
140+ // > **IntegrationsModule** = `object` & `object`
141+ // > **EntitiesModule** = `TypedEntitiesModule` & `DynamicEntitiesModule`
142+ // These appear in type alias files using intersection types and are not useful in docs.
143+ const typeDefinitionRegex = / ^ > \* \* \w + \* \* = ` \w + ` & ` \w + ` \s * $ / m;
141144 if ( typeDefinitionRegex . test ( content ) ) {
142145 content = content . replace ( typeDefinitionRegex , "" ) ;
143146 modified = true ;
@@ -761,6 +764,255 @@ function applyAppendedArticles(appendedArticles) {
761764 }
762765}
763766
767+ /**
768+ * Clean up method signatures and type parameter sections:
769+ * 1. Replace truncated generics (e.g., Pick<..., ...> → Pick<T, K>)
770+ * 2. Simplify resolved keyof constraints (string | number | symbol → keyof T)
771+ * 3. Break long signature lines into multi-line blockquote format
772+ * 4. Remove method-level Type Parameters sections (redundant with signature + param docs)
773+ * 4b. Remove page-level ## Type Parameters sections (not useful in docs)
774+ * 5. Clean up broken function-return-type sections (e.g., () => void returns)
775+ * 7. Simplify field-selection generics: remove \<K\> from signatures, Pick<T,K> → T, K[] → (keyof T)[]
776+ */
777+ function cleanupSignatures ( content ) {
778+ let modified = false ;
779+
780+ // Fix 7: Simplify field-selection generic K out of signatures.
781+ // K is a TypeScript implementation detail for field selection (Pick<T, K>).
782+ // In docs it's confusing — replace with clearer types.
783+
784+ // 7a: Annotate \<`K`\> with its constraint → \<`K extends keyof T`\>
785+ if ( content . includes ( "\\<`K`\\>" ) ) {
786+ content = content . replace ( / \\ < ` K ` \\ > / g, "\\<`K extends keyof T`\\>" ) ;
787+ modified = true ;
788+ }
789+
790+ // 7b: Expand truncated `Pick`\<..., ...\> to `Pick`\<`T`, `K`\>
791+ if ( content . includes ( "`Pick`\\<..., ...\\>" ) ) {
792+ content = content . replace ( / ` P i c k ` \\ < \. \. \. , \. \. \. \\ > / g, "`Pick`\\<`T`, `K`\\>" ) ;
793+ modified = true ;
794+ }
795+
796+ // 7c: Replace type="K[]" with type="(keyof T)[]" in ParamField elements
797+ if ( content . includes ( 'type="K[]"' ) ) {
798+ content = content . replace ( / t y p e = " K \[ \] " / g, 'type="(keyof T)[]"' ) ;
799+ modified = true ;
800+ }
801+
802+ // Fix 5: Clean up broken function-return-type patterns.
803+ // When a method returns a function (e.g., () => void), TypeDoc generates a stray
804+ // function signature and an empty Accordion in the Returns section. Remove them.
805+ // Pattern: "> (): `void`" followed by empty Accordion with "Returns" ResponseField.
806+ content = content . replace (
807+ / \n > \( \) : ` v o i d ` \n \n < A c c o r d i o n t i t l e = " P r o p e r t i e s " > \n \n < R e s p o n s e F i e l d n a m e = " R e t u r n s " t y p e = " v o i d " r e q u i r e d > \n \n < \/ R e s p o n s e F i e l d > \n < \/ A c c o r d i o n > \n / g,
808+ ( ) => {
809+ modified = true ;
810+ return "\n" ;
811+ }
812+ ) ;
813+
814+ // Fix 6: Clean up truncated EntityRecord mapped type signature.
815+ // TypeDoc renders `EntityTypeRegistry[K]` as `(...)[(...)]`.
816+ content = content . replace (
817+ / \( \. \. \. \) \[ \( \. \. \. \) \] \s * & \s * S e r v e r E n t i t y F i e l d s / g,
818+ ( ) => {
819+ modified = true ;
820+ return "EntityTypeRegistry[K] & ServerEntityFields" ;
821+ }
822+ ) ;
823+
824+ const lines = content . split ( "\n" ) ;
825+
826+ // Collect page-level type parameter names from ## Type Parameters section.
827+ // Before heading demotion, these are ### headings (e.g., ### T).
828+ const pageTypeParams = [ ] ;
829+ for ( let i = 0 ; i < lines . length ; i ++ ) {
830+ if ( lines [ i ] . trim ( ) === "## Type Parameters" ) {
831+ for ( let j = i + 1 ; j < lines . length ; j ++ ) {
832+ if ( lines [ j ] . startsWith ( "## " ) && lines [ j ] . trim ( ) !== "## Type Parameters" )
833+ break ;
834+ const paramMatch = lines [ j ] . match ( / ^ # { 3 , 5 } \s + ( \w + ) \s * $ / ) ;
835+ if ( paramMatch ) {
836+ pageTypeParams . push ( paramMatch [ 1 ] ) ;
837+ }
838+ }
839+ break ;
840+ }
841+ }
842+
843+ const result = [ ] ;
844+ for ( let i = 0 ; i < lines . length ; i ++ ) {
845+ let line = lines [ i ] ;
846+
847+ // Fix 1: Replace `string` | `number` | `symbol` with keyof `T`
848+ // TypeDoc resolves `keyof T` to `string | number | symbol` when T is unconstrained.
849+ if ( line . includes ( "`string` | `number` | `symbol`" ) ) {
850+ const defaultMatch = line . match ( / = k e y o f ` ( \w + ) ` / ) ;
851+ const typeName =
852+ defaultMatch ? defaultMatch [ 1 ] : pageTypeParams [ 0 ] || "T" ;
853+ line = line . replace (
854+ / ` s t r i n g ` \| ` n u m b e r ` \| ` s y m b o l ` ( = k e y o f ` \w + ` ) ? / ,
855+ "keyof `" + typeName + "`"
856+ ) ;
857+ modified = true ;
858+ }
859+
860+ // Fix 4b: Remove page-level ## Type Parameters sections.
861+ // These are not useful in docs — generic type params are an implementation detail.
862+ // Skip from "## Type Parameters" until the next "## " heading.
863+ if ( line . trim ( ) === "## Type Parameters" ) {
864+ let j = i + 1 ;
865+ while ( j < lines . length ) {
866+ const upcoming = lines [ j ] . trim ( ) ;
867+ if ( upcoming . startsWith ( "## " ) && upcoming !== "## Type Parameters" ) break ;
868+ j ++ ;
869+ }
870+ // Skip trailing blank lines
871+ while ( j > i + 1 && lines [ j - 1 ] . trim ( ) === "" ) {
872+ j -- ;
873+ }
874+ i = j - 1 ;
875+ modified = true ;
876+ continue ;
877+ }
878+
879+ // Fix 4: Remove method-level #### Type Parameters sections.
880+ // These are redundant — the info is already in the signature and parameter docs.
881+ // Skip from "#### Type Parameters" until the next "#### " heading.
882+ if ( line . trim ( ) === "#### Type Parameters" ) {
883+ // Skip ahead past this section until the next #### heading or ### heading
884+ let j = i + 1 ;
885+ while ( j < lines . length ) {
886+ const upcoming = lines [ j ] . trim ( ) ;
887+ if ( upcoming . startsWith ( "#### " ) && upcoming !== "#### Type Parameters" ) break ;
888+ if ( upcoming . startsWith ( "### " ) ) break ;
889+ if ( upcoming . startsWith ( "## " ) ) break ;
890+ j ++ ;
891+ }
892+ // Also skip any trailing blank lines
893+ while ( j > i + 1 && lines [ j - 1 ] . trim ( ) === "" ) {
894+ j -- ;
895+ }
896+ i = j - 1 ; // -1 because the loop will increment
897+ modified = true ;
898+ continue ;
899+ }
900+
901+ // Fix 2 & 3: Signatures starting with > **methodName**
902+ if ( line . startsWith ( "> **" ) && line . includes ( "(" ) ) {
903+ // Extract method-level type params from signature (e.g., \<`K`\>)
904+ const methodTypeParams = [ ] ;
905+ const typeParamMatch = line . match ( / \\ < ` ( \w + ) ` \\ > / ) ;
906+ if ( typeParamMatch ) {
907+ methodTypeParams . push ( typeParamMatch [ 1 ] ) ;
908+ }
909+
910+ // Replace truncated generics: \<..., ...\> → \<`T`, `K`\>
911+ if ( line . includes ( "\\<..., ...\\>" ) ) {
912+ const allTypeParams = [ ...pageTypeParams , ...methodTypeParams ] ;
913+ if ( allTypeParams . length >= 2 ) {
914+ line = line . replace (
915+ / \\ < \. \. \. , \. \. \. \\ > / g,
916+ "\\<`" + allTypeParams [ 0 ] + "`, `" + allTypeParams [ 1 ] + "`\\>"
917+ ) ;
918+ modified = true ;
919+ }
920+ }
921+
922+ // Break long signatures into multi-line blockquote format.
923+ // Each line ends with two trailing spaces to force a hard line break
924+ // in Mintlify's Markdown renderer (otherwise blockquote lines get joined).
925+ if ( line . length > 85 ) {
926+ const openParen = line . indexOf ( "(" ) ;
927+ const returnMarker = line . lastIndexOf ( "): " ) ;
928+
929+ if ( openParen > - 1 && returnMarker > openParen ) {
930+ const prefix = line . slice ( 0 , openParen ) ;
931+ const params = line . slice ( openParen + 1 , returnMarker ) ;
932+ const returnType = line . slice ( returnMarker + 1 ) ;
933+
934+ const paramList = params . split ( ", " ) ;
935+ if ( paramList . length >= 3 ) {
936+ result . push ( prefix + "( " ) ;
937+ for ( let j = 0 ; j < paramList . length ; j ++ ) {
938+ const comma = j < paramList . length - 1 ? "," : "" ;
939+ result . push ( "> " + paramList [ j ] + comma + " " ) ;
940+ }
941+ result . push ( "> )" + returnType ) ;
942+ modified = true ;
943+ continue ;
944+ }
945+ }
946+ }
947+ }
948+
949+ result . push ( line ) ;
950+ }
951+
952+ // Fix 6: Enrich bare type names in Returns sections with generics from signatures.
953+ // E.g., `ImportResult` → `ImportResult<T>` when the signature shows ImportResult\<T\>.
954+ for ( let i = 0 ; i < result . length ; i ++ ) {
955+ const line = result [ i ] ;
956+ // Match a standalone backtick-wrapped type name (only content on the line)
957+ const bareTypeMatch = line . match ( / ^ ` ( [ A - Z ] \w + ) ` $ / ) ;
958+ if ( ! bareTypeMatch ) continue ;
959+ const typeName = bareTypeMatch [ 1 ] ;
960+
961+ // Verify this follows a Returns heading (scan back past blank lines)
962+ let isInReturns = false ;
963+ for ( let j = i - 1 ; j >= Math . max ( 0 , i - 3 ) ; j -- ) {
964+ if ( result [ j ] . trim ( ) === "" ) continue ;
965+ if ( / ^ # { 2 , 5 } R e t u r n s / . test ( result [ j ] ) ) {
966+ isInReturns = true ;
967+ }
968+ break ;
969+ }
970+ if ( ! isInReturns ) continue ;
971+
972+ // Scan backwards for the nearest signature line
973+ for ( let j = i - 1 ; j >= Math . max ( 0 , i - 30 ) ; j -- ) {
974+ const sigLine = result [ j ] ;
975+ if ( ! sigLine . startsWith ( "> **" ) && ! sigLine . startsWith ( "> )" ) ) continue ;
976+ // Look for TypeName\<`GenericParam`\> in the signature
977+ const genericPattern = new RegExp (
978+ "`" + typeName . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) +
979+ "`\\\\<`(\\w+)`\\\\>"
980+ ) ;
981+ const genMatch = sigLine . match ( genericPattern ) ;
982+ if ( genMatch ) {
983+ result [ i ] = "`" + typeName + "<" + genMatch [ 1 ] + ">`" ;
984+ modified = true ;
985+ }
986+ break ;
987+ }
988+ }
989+
990+ return { content : result . join ( "\n" ) , modified } ;
991+ }
992+
993+ function applySignatureCleanup ( dir ) {
994+ if ( ! fs . existsSync ( dir ) ) return ;
995+ const entries = fs . readdirSync ( dir , { withFileTypes : true } ) ;
996+ for ( const entry of entries ) {
997+ const entryPath = path . join ( dir , entry . name ) ;
998+ if ( entry . isDirectory ( ) ) {
999+ applySignatureCleanup ( entryPath ) ;
1000+ } else if (
1001+ entry . isFile ( ) &&
1002+ ( entry . name . endsWith ( ".mdx" ) || entry . name . endsWith ( ".md" ) )
1003+ ) {
1004+ const content = fs . readFileSync ( entryPath , "utf-8" ) ;
1005+ const { content : updated , modified } = cleanupSignatures ( content ) ;
1006+ if ( modified ) {
1007+ fs . writeFileSync ( entryPath , updated , "utf-8" ) ;
1008+ console . log (
1009+ `Cleaned up signatures: ${ path . relative ( DOCS_DIR , entryPath ) } `
1010+ ) ;
1011+ }
1012+ }
1013+ }
1014+ }
1015+
7641016function demoteNonCallableHeadings ( content ) {
7651017 const lines = content . split ( "\n" ) ;
7661018 let inFence = false ;
@@ -967,6 +1219,48 @@ function applyNonExposedTypeLinkRemoval(dir, exposedTypeNames) {
9671219/**
9681220 * Main function
9691221 */
1222+ /**
1223+ * Delete types that should not appear in navigation but were needed for inline rendering.
1224+ * These types are listed in types-to-delete-after-processing.json
1225+ */
1226+ function deleteTypesAfterProcessing ( docsDir ) {
1227+ let typesToDelete = new Set ( ) ;
1228+ try {
1229+ const content = fs . readFileSync ( TYPES_TO_DELETE_PATH , "utf-8" ) ;
1230+ const parsed = JSON . parse ( content ) ;
1231+ if ( Array . isArray ( parsed ) ) {
1232+ typesToDelete = new Set ( parsed ) ;
1233+ }
1234+ } catch ( e ) {
1235+ // No types to delete, that's fine
1236+ return ;
1237+ }
1238+
1239+ if ( typesToDelete . size === 0 ) {
1240+ return ;
1241+ }
1242+
1243+ const contentDir = path . join ( docsDir , "content" ) ;
1244+ const sections = [ "functions" , "interfaces" , "classes" , "type-aliases" ] ;
1245+
1246+ for ( const section of sections ) {
1247+ const sectionDir = path . join ( contentDir , section ) ;
1248+ if ( ! fs . existsSync ( sectionDir ) ) continue ;
1249+
1250+ const files = fs . readdirSync ( sectionDir ) ;
1251+ for ( const file of files ) {
1252+ if ( ! file . endsWith ( ".mdx" ) && ! file . endsWith ( ".md" ) ) continue ;
1253+
1254+ const fileName = path . basename ( file , path . extname ( file ) ) ;
1255+ if ( typesToDelete . has ( fileName ) ) {
1256+ const filePath = path . join ( sectionDir , file ) ;
1257+ fs . unlinkSync ( filePath ) ;
1258+ console . log ( `Removed (after processing): content/${ section } /${ file } ` ) ;
1259+ }
1260+ }
1261+ }
1262+ }
1263+
9701264function main ( ) {
9711265 console . log ( "Processing TypeDoc MDX files for Mintlify...\n" ) ;
9721266
@@ -990,6 +1284,9 @@ function main() {
9901284 const appendedArticles = loadAppendedArticlesConfig ( ) ;
9911285 applyAppendedArticles ( appendedArticles ) ;
9921286
1287+ // Clean up signatures: fix truncated generics, simplify keyof constraints, break long lines
1288+ applySignatureCleanup ( DOCS_DIR ) ;
1289+
9931290 applyHeadingDemotion ( DOCS_DIR ) ;
9941291
9951292 // Link type names in Type Declarations sections to their corresponding headings
@@ -998,6 +1295,9 @@ function main() {
9981295 // Remove links to types that aren't exposed (would 404)
9991296 applyNonExposedTypeLinkRemoval ( DOCS_DIR , exposedTypeNames ) ;
10001297
1298+ // Delete types that should not appear in navigation but were needed for inline rendering
1299+ deleteTypesAfterProcessing ( DOCS_DIR ) ;
1300+
10011301 // Clean up the linked types file
10021302 try {
10031303 if ( fs . existsSync ( LINKED_TYPES_FILE ) ) {
0 commit comments