1
1
import { h as createElement } from 'hastscript' ;
2
2
3
- import {
4
- isTypedList ,
5
- parseListItem ,
6
- } from '../../legacy-json/utils/parseList.mjs' ;
3
+ import { isTypedList } from '../../../utils/generators.mjs' ;
4
+ import { parseListItem } from '../../legacy-json/utils/parseList.mjs' ;
7
5
import parseSignature from '../../legacy-json/utils/parseSignature.mjs' ;
8
6
9
7
/**
10
8
* Extracts types and description from content nodes
11
- * @param {Array } contentNodes - Content nodes to process
12
- * @returns {Object } Object containing types and description
9
+ * @param {import('@types/mdast').Node[] } contentNodes - Content nodes to process
13
10
*/
14
11
const extractTypesAndDescription = contentNodes => {
15
- if ( ! contentNodes . length ) return { types : [ ] , description : [ ] } ;
12
+ const types = [ ] ;
13
+ let i = 0 ;
16
14
17
- const types = [ contentNodes [ 0 ] ] ;
18
- let descIndex = 1 ;
15
+ // Skip initial whitespace if present
16
+ if ( contentNodes [ 0 ] ?. value ?. trim ( ) === '' ) {
17
+ i ++ ;
18
+ }
19
+
20
+ // Extract type information
21
+ while ( i < contentNodes . length ) {
22
+ const current = contentNodes [ i ] ;
23
+ const next = contentNodes [ i + 1 ] ;
19
24
20
- // Process union types (separated by " | ")
21
- while ( descIndex < contentNodes . length ) {
22
- const current = contentNodes [ descIndex ] ;
23
- const next = contentNodes [ descIndex + 1 ] ;
25
+ const isTypeSeparator =
26
+ current . type === 'text' && current . value === ' | ' && next ;
27
+ const isGenericType =
28
+ current . type === 'link' &&
29
+ current . children ?. [ 0 ] ?. type === 'inlineCode' &&
30
+ current . children [ 0 ] . value ?. startsWith ( '<' ) ;
24
31
25
- if ( current . type === 'text' && current . value === ' | ' && next ) {
32
+ if ( isTypeSeparator ) {
26
33
types . push ( current , next ) ;
27
- descIndex += 2 ;
28
- }
29
- // Handle link as the entire type
30
- else if ( current . type === 'link' && types . length === 1 ) {
31
- types [ 0 ] = current ;
32
- descIndex ++ ;
34
+ i += 2 ;
35
+ } else if ( isGenericType ) {
36
+ types . push ( current ) ;
37
+ i ++ ;
33
38
} else {
34
39
break ;
35
40
}
36
41
}
37
42
38
43
return {
39
44
types,
40
- description : contentNodes . slice ( descIndex ) ,
45
+ description : contentNodes . slice ( i ) ,
41
46
} ;
42
47
} ;
43
48
44
49
/**
45
- * Creates a table from a list of properties
46
- * @param {import('mdast').List } node
50
+ * Recursively processes list items into property data objects
51
+ * @param {import('@types/mdast').ListItem[] } items - List items to process
52
+ * @param {string } prefix - Property name prefix for nested properties
47
53
*/
48
- const createPropertyTable = node => {
49
- const tableRows = [ ] ;
50
- let hasAnyDescription = false ;
51
- const allProperties = [ ] ;
52
-
53
- /**
54
- * Recursively processes list items into table rows
55
- * @param {Array } items - List items to process
56
- * @param {string } prefix - Property name prefix for nested properties
57
- */
58
- const processItems = ( items , prefix = '' ) => {
59
- for ( const item of items ) {
60
- if ( ! item . children . length ) continue ;
61
-
62
- const [ paragraph , ...nestedContent ] = item . children ;
63
-
64
- // Extract property name
65
- const propNode = paragraph . children [ 0 ] ;
66
- const propName = propNode . value || '' ;
67
- const fullPropName = prefix ? `${ prefix } .${ propName } ` : propName ;
68
- const displayName = prefix
69
- ? { ...propNode , value : fullPropName }
70
- : propNode ;
71
-
72
- // Process types and description
73
- const { types, description } = extractTypesAndDescription (
74
- paragraph . children . slice ( 1 )
75
- ) ;
54
+ const processListItemsIntoProperties = ( items , prefix = '' ) => {
55
+ const properties = [ ] ;
76
56
77
- // Check if this property has a description
78
- if ( description && description . length > 0 ) {
79
- hasAnyDescription = true ;
80
- }
57
+ for ( const item of items ) {
58
+ if ( ! item . children . length ) {
59
+ continue ;
60
+ }
61
+
62
+ const [ paragraph , ...nestedContent ] = item . children ;
63
+
64
+ // Extract property name
65
+ const propNode = paragraph . children [ 0 ] ;
66
+ let propName = propNode . value || '' ;
67
+ let displayName = propNode ;
68
+ let additionalDescription = [ ] ;
69
+ let types = [ ] ;
70
+ let description = [ ] ;
71
+
72
+ // Special handling for "Returns: " nodes with a description, and no type
73
+ if ( propName . startsWith ( 'Returns: ' ) && propName . length > 9 ) {
74
+ description = propName . substring ( 9 ) . trim ( ) ;
75
+ propName = 'Returns' ;
76
+ displayName = { ...propNode , value : 'Returns' } ;
77
+ } else {
78
+ const extracted = extractTypesAndDescription ( paragraph . children . slice ( 1 ) ) ;
79
+ types = extracted . types ;
80
+ description = extracted . description ;
81
+ }
82
+
83
+ const fullPropName = prefix ? `${ prefix } .${ propName } ` : propName ;
84
+ if ( prefix ) {
85
+ displayName = { ...propNode , value : fullPropName } ;
86
+ }
81
87
82
- // Store property data
83
- allProperties . push ( {
84
- nameCell : createElement ( 'td' , displayName ) ,
85
- typeCell : createElement ( 'td' , types ) ,
86
- descriptionCell : createElement ( 'td' , description ) ,
87
- } ) ;
88
-
89
- // Process nested properties
90
- const nestedList = nestedContent . find ( isTypedList ) ;
91
- if ( nestedList ) {
92
- processItems ( nestedList . children , fullPropName ) ;
88
+ // Combine any additional description
89
+ const combinedDescription = [ ...additionalDescription ] ;
90
+ if ( description && description . length > 0 ) {
91
+ if ( combinedDescription . length > 0 ) {
92
+ combinedDescription . push ( { type : 'text' , value : ' ' } ) ;
93
93
}
94
+ combinedDescription . push (
95
+ ...( Array . isArray ( description ) ? description : [ description ] )
96
+ ) ;
94
97
}
95
- } ;
96
98
97
- processItems ( node . children ) ;
99
+ // Store property data
100
+ properties . push ( {
101
+ nameCell : createElement ( 'td' , displayName ) ,
102
+ typeCell : createElement ( 'td' , types ) ,
103
+ descriptionCell : createElement ( 'td' , combinedDescription ) ,
104
+ hasDescription : combinedDescription . length > 0 ,
105
+ hasTypes : types && types . length > 0 ,
106
+ } ) ;
98
107
99
- // Create table rows based on whether any property has a description
100
- for ( const prop of allProperties ) {
101
- const rowCells = [ prop . nameCell , prop . typeCell ] ;
102
- if ( hasAnyDescription ) {
103
- rowCells . push ( prop . descriptionCell ) ;
108
+ // Process nested properties
109
+ const nestedList = nestedContent . find ( isTypedList ) ;
110
+ if ( nestedList ) {
111
+ const nestedProperties = processListItemsIntoProperties (
112
+ nestedList . children ,
113
+ fullPropName
114
+ ) ;
115
+ properties . push ( ...nestedProperties ) ;
104
116
}
105
- tableRows . push ( createElement ( 'tr' , rowCells ) ) ;
106
117
}
107
118
108
- // Create table headers based on whether any property has a description
109
- const headerCells = [
110
- createElement ( 'th' , 'Property' ) ,
111
- createElement ( 'th' , 'Type' ) ,
112
- ] ;
119
+ return properties ;
120
+ } ;
121
+
122
+ /**
123
+ * Creates a table from a list of properties
124
+ * @param {import('mdast').List } node
125
+ */
126
+ const createPropertyTable = node => {
127
+ // Process all properties
128
+ const allProperties = processListItemsIntoProperties ( node . children ) ;
129
+
130
+ // Determine if any properties have descriptions or types
131
+ const hasAnyDescription = allProperties . some ( prop => prop . hasDescription ) ;
132
+ const hasAnyTypes = allProperties . some ( prop => prop . hasTypes ) ;
113
133
134
+ // Create table headers
135
+ const headerCells = [ createElement ( 'th' , 'Property' ) ] ;
136
+ if ( hasAnyTypes ) {
137
+ headerCells . push ( createElement ( 'th' , 'Type' ) ) ;
138
+ }
114
139
if ( hasAnyDescription ) {
115
140
headerCells . push ( createElement ( 'th' , 'Description' ) ) ;
116
141
}
117
142
143
+ // Create table rows
144
+ const tableRows = allProperties . map ( prop => {
145
+ const rowCells = [ prop . nameCell ] ;
146
+
147
+ if ( hasAnyTypes ) {
148
+ rowCells . push ( prop . typeCell ) ;
149
+ }
150
+
151
+ if ( hasAnyDescription ) {
152
+ rowCells . push ( prop . descriptionCell ) ;
153
+ }
154
+
155
+ return createElement ( 'tr' , rowCells ) ;
156
+ } ) ;
157
+
118
158
return createElement ( 'table' , [
119
159
createElement ( 'thead' , [ createElement ( 'tr' , headerCells ) ] ) ,
120
160
createElement ( 'tbody' , tableRows ) ,
@@ -125,7 +165,6 @@ const createPropertyTable = node => {
125
165
* Generates all valid function signatures based on optional parameters
126
166
* @param {string } functionName - Name of the function
127
167
* @param {import('../../legacy-json/types.d.ts').MethodSignature } signature - Signature object
128
- * @returns {string[] } Array of signature strings
129
168
*/
130
169
const generateSignatures = ( functionName , signature ) => {
131
170
const { params, return : returnType } = signature ;
@@ -150,7 +189,9 @@ const generateSignatures = (functionName, signature) => {
150
189
for ( let i = 0 ; i < totalCombinations ; i ++ ) {
151
190
const includedParams = params . filter ( ( param , index ) => {
152
191
// Always include required parameters
153
- if ( ! param . optional ) return true ;
192
+ if ( ! param . optional ) {
193
+ return true ;
194
+ }
154
195
155
196
// For optional parameters, check if this combination includes it
156
197
const optionalIndex = optionalIndexes . indexOf ( index ) ;
@@ -160,7 +201,9 @@ const generateSignatures = (functionName, signature) => {
160
201
const paramsStr = includedParams
161
202
. map ( param => {
162
203
let paramStr = param . name ;
163
- if ( param . optional || param . default ) paramStr += '?' ;
204
+ if ( param . optional || param . default ) {
205
+ paramStr += '?' ;
206
+ }
164
207
return paramStr ;
165
208
} )
166
209
. join ( ', ' ) ;
@@ -175,16 +218,10 @@ const generateSignatures = (functionName, signature) => {
175
218
* Creates a code block with function signatures
176
219
* @param {string } functionName - Name of the function
177
220
* @param {import('../../legacy-json/types.d.ts').MethodSignature } signature - Signature object
178
- * @returns {Object } Code block node
179
221
*/
180
222
const createSignatureCodeBlock = ( functionName , signature ) => {
181
- // Generate all valid signatures
182
223
const signatures = generateSignatures ( functionName , signature ) ;
183
-
184
- // Join all signatures with newlines
185
224
const codeContent = signatures . join ( '\n' ) ;
186
-
187
- // Create code block
188
225
return createElement ( 'pre' , codeContent ) ;
189
226
} ;
190
227
@@ -203,15 +240,11 @@ export const getFullName = ({ name, text }) => {
203
240
* Creates documentation from API metadata entries
204
241
* @param {import('@types/mdast').Parent } parent - The parent node
205
242
* @param {ApiDocMetadataEntry[] } entries - Array of API documentation metadata entries
243
+ * @param {number } backupIndex - If there isn't a list, use this index
206
244
*/
207
- export default ( parent , entries ) => {
245
+ export default ( parent , entries , backupIndex ) => {
208
246
// Find the list index in the parent for later replacement
209
247
const listIdx = parent . children . findIndex ( isTypedList ) ;
210
- if ( listIdx === - 1 ) {
211
- return ;
212
- }
213
-
214
- // Create array for all elements from all entries
215
248
const elements = [ ] ;
216
249
217
250
// Process all entries
@@ -225,18 +258,20 @@ export default (parent, entries) => {
225
258
const displayName = getFullName ( entry . heading . data ) ;
226
259
227
260
// Create signature code block
228
- const signatureCodeBlock = createSignatureCodeBlock ( displayName , signature ) ;
229
- if ( signatureCodeBlock ) elements . push ( signatureCodeBlock ) ;
261
+ elements . push ( createSignatureCodeBlock ( displayName , signature ) ) ;
230
262
231
- // Create property table
263
+ // Create property table if a list exists
232
264
if ( list ) {
233
- const propertyTable = createPropertyTable ( list ) ;
234
- elements . push ( propertyTable ) ;
265
+ elements . push ( createPropertyTable ( list ) ) ;
235
266
}
236
267
}
237
268
238
269
// Replace the list in the parent with all collected elements
239
270
if ( elements . length > 0 ) {
240
- parent . children . splice ( listIdx , 1 , ...elements ) ;
271
+ if ( listIdx > - 1 ) {
272
+ parent . children . splice ( listIdx , 1 , ...elements ) ;
273
+ } else {
274
+ parent . children . splice ( backupIndex , 0 , ...elements ) ;
275
+ }
241
276
}
242
277
} ;
0 commit comments