1- import { transformNodesToString } from '../../../utils/unist.mjs' ;
21import {
32 DOC_MDN_BASE_URL_JS_GLOBALS ,
43 DOC_MDN_BASE_URL_JS_PRIMITIVES ,
@@ -7,8 +6,10 @@ import {
76 DOC_TYPES_MAPPING_PRIMITIVES ,
87 DOC_MAN_BASE_URL ,
98 DOC_API_HEADING_TYPES ,
9+ TYPE_GENERIC_REGEX ,
1010} from '../constants.mjs' ;
1111import { slug } from './slugger.mjs' ;
12+ import { transformNodesToString } from '../../../utils/unist.mjs' ;
1213
1314/**
1415 * @param {string } text The inner text
@@ -24,7 +25,81 @@ export const transformUnixManualToLink = (
2425) => {
2526 return `[\`${ text } \`](${ DOC_MAN_BASE_URL } ${ sectionNumber } /${ command } .${ sectionNumber } ${ sectionLetter } .html)` ;
2627} ;
28+ /**
29+ * Safely splits the string by `|`, ignoring pipes that are inside `< >`
30+ *
31+ * @param {string } str The type string to split
32+ * @returns {string[] } An array of type pieces
33+ */
34+ const splitByOuterUnion = str => {
35+ const result = [ ] ;
36+ let current = '' ;
37+ let depth = 0 ;
38+
39+ for ( const char of str ) {
40+ if ( char === '<' ) {
41+ depth ++ ;
42+ } else if ( char === '>' ) {
43+ depth -- ;
44+ } else if ( char === '|' && depth === 0 ) {
45+ result . push ( current ) ;
46+ current = '' ;
47+ continue ;
48+ }
49+ current += char ;
50+ }
51+
52+ result . push ( current ) ;
53+ return result ;
54+ } ;
2755
56+ /**
57+ * Attempts to parse and format a basic Generic type (e.g., Promise<string>).
58+ * It also supports union and multi-parameter types within the generic brackets.
59+ *
60+ * @param {string } typePiece The plain type piece to be evaluated
61+ * @param {Function } transformType The function used to resolve individual types into links
62+ * @returns {string|null } The formatted Markdown link, or null if no match is found
63+ */
64+ const formatBasicGeneric = ( typePiece , transformType ) => {
65+ const genericMatch = typePiece . match ( TYPE_GENERIC_REGEX ) ;
66+
67+ if ( genericMatch ) {
68+ const baseType = genericMatch [ 1 ] . trim ( ) ;
69+ const innerType = genericMatch [ 2 ] . trim ( ) ;
70+
71+ const baseResult = transformType ( baseType . replace ( / \[ \] $ / , '' ) ) ;
72+ const baseFormatted = baseResult
73+ ? `[\`<${ baseType } >\`](${ baseResult } )`
74+ : `\`<${ baseType } >\`` ;
75+
76+ // Split while capturing delimiters (| or ,) to preserve original syntax
77+ const parts = innerType . split ( / ( [ | , ] ) / ) ;
78+
79+ const innerFormatted = parts
80+ . map ( part => {
81+ const trimmed = part . trim ( ) ;
82+ // If it is a delimiter, return it as is
83+ if ( trimmed === '|' ) {
84+ return ' | ' ;
85+ }
86+
87+ if ( trimmed === ',' ) {
88+ return ', ' ;
89+ }
90+
91+ const innerRes = transformType ( trimmed . replace ( / \[ \] $ / , '' ) ) ;
92+ return innerRes
93+ ? `[\`<${ trimmed } >\`](${ innerRes } )`
94+ : `\`<${ trimmed } >\`` ;
95+ } )
96+ . join ( '' ) ;
97+
98+ return `${ baseFormatted } <${ innerFormatted } >` ;
99+ }
100+
101+ return null ;
102+ } ;
28103/**
29104 * This method replaces plain text Types within the Markdown content into Markdown links
30105 * that link to the actual relevant reference for such type (either internal or external link)
@@ -34,8 +109,9 @@ export const transformUnixManualToLink = (
34109 * @returns {string } The Markdown link as a string (formatted in Markdown)
35110 */
36111export const transformTypeToReferenceLink = ( type , record ) => {
37- // Removes the wrapping tags that wrap the type references such as `<>` and `{}`
38- const typeInput = type . replace ( / [ { } < > ] / g, '' ) ;
112+ // Removes the wrapping curly braces that wrap the type references
113+ // We keep the angle brackets `<>` intact here to parse Generics later
114+ const typeInput = type . replace ( / [ { } ] / g, '' ) ;
39115
40116 /**
41117 * Handles the mapping (if there's a match) of the input text
@@ -65,7 +141,7 @@ export const transformTypeToReferenceLink = (type, record) => {
65141
66142 // Transform Node.js type/module references into Markdown links
67143 // that refer to other API docs pages within the Node.js API docs
68- if ( lookupPiece in record ) {
144+ if ( record && lookupPiece in record ) {
69145 return record [ lookupPiece ] ;
70146 }
71147
@@ -80,13 +156,20 @@ export const transformTypeToReferenceLink = (type, record) => {
80156 return '' ;
81157 } ;
82158
83- const typePieces = typeInput . split ( '|' ) . map ( piece => {
159+ const typePieces = splitByOuterUnion ( typeInput ) . map ( piece => {
84160 // This is the content to render as the text of the Markdown link
85161 const trimmedPiece = piece . trim ( ) ;
86162
163+ // 1. Attempt to format as a basic Generic type first
164+ const genericMarkdown = formatBasicGeneric ( trimmedPiece , transformType ) ;
165+ if ( genericMarkdown ) {
166+ return genericMarkdown ;
167+ }
168+
169+ // 2. Fallback to the logic for plain types
87170 // This is what we will compare against the API types mappings
88171 // The ReGeX below is used to remove `[]` from the end of the type
89- const result = transformType ( trimmedPiece . replace ( '[]' , '' ) ) ;
172+ const result = transformType ( trimmedPiece . replace ( / \[ \] $ / , '' ) ) ;
90173
91174 // If we have a valid result and the piece is not empty, we return the Markdown link
92175 if ( trimmedPiece . length && result . length ) {
0 commit comments