@@ -9,6 +9,7 @@ interface PropertyInfo {
99 key : string
1010 value : string
1111 type : string
12+ nested ?: PropertyInfo [ ]
1213}
1314
1415export async function extract ( filePath : string ) : Promise < string > {
@@ -95,7 +96,8 @@ function generateDtsTypes(sourceCode: string): string {
9596 . filter ( Boolean )
9697 . join ( '\n' )
9798
98- console . log ( 'Final result' , result )
99+ console . log ( 'result:' , result )
100+
99101 return defaultExport ? `${ result } \n${ defaultExport } ` : result
100102}
101103
@@ -163,79 +165,254 @@ function processConstDeclaration(declaration: string, isExported = true): string
163165 }
164166
165167 const properties = extractObjectProperties ( lines . slice ( 1 , - 1 ) )
166- const propertyStrings = properties . map ( prop => ` ${ prop . key } : ${ prop . type } ;` )
168+ const propertyStrings = formatProperties ( properties )
169+
170+ return `${ isExported ? 'export ' : '' } declare const ${ name } : {\n${ propertyStrings } \n};`
171+ }
167172
168- return `${ isExported ? 'export ' : '' } declare const ${ name } : {\n${ propertyStrings . join ( '\n' ) } \n};`
173+ function formatProperties ( properties : PropertyInfo [ ] , indent = 2 ) : string {
174+ return properties . map ( ( prop ) => {
175+ const spaces = ' ' . repeat ( indent )
176+ if ( prop . nested && prop . nested . length > 0 ) {
177+ const nestedProps = formatProperties ( prop . nested , indent + 2 )
178+ return `${ spaces } ${ prop . key } : {\n${ nestedProps } \n${ spaces } };`
179+ }
180+ return `${ spaces } ${ prop . key } : ${ prop . type } ;`
181+ } ) . join ( '\n' )
169182}
170183
171184function extractObjectProperties ( lines : string [ ] ) : PropertyInfo [ ] {
172185 const properties : PropertyInfo [ ] = [ ]
173- let currentProperty : Partial < PropertyInfo > | null = null
186+ let currentBlock = ''
174187 let bracketCount = 0
188+ let braceCount = 0
175189
176190 for ( const line of lines ) {
177191 const trimmedLine = line . trim ( )
192+
178193 if ( ! trimmedLine || trimmedLine . startsWith ( '//' ) || trimmedLine . startsWith ( '/*' ) )
179194 continue
180195
181- if ( currentProperty === null ) {
182- const match = trimmedLine . match ( / ^ ( \w + ) \s * : \s * ( .+ ?) , ? $ / )
183- if ( match ) {
184- const [ , key , value ] = match
185- properties . push ( {
186- key,
187- value,
188- type : inferType ( value . trim ( ) ) ,
189- } )
190- }
191- }
192- else {
193- bracketCount += ( trimmedLine . match ( / \{ / g) || [ ] ) . length
194- bracketCount -= ( trimmedLine . match ( / \} / g) || [ ] ) . length
195-
196- if ( bracketCount === 0 ) {
197- if ( currentProperty . key ) {
198- properties . push ( {
199- key : currentProperty . key ,
200- value : currentProperty . value || '' ,
201- type : currentProperty . type || 'any' ,
202- } )
196+ // Count brackets and braces
197+ const openBrackets = ( trimmedLine . match ( / \[ / g) || [ ] ) . length
198+ const closeBrackets = ( trimmedLine . match ( / \] / g) || [ ] ) . length
199+ const openBraces = ( trimmedLine . match ( / \{ / g) || [ ] ) . length
200+ const closeBraces = ( trimmedLine . match ( / \} / g) || [ ] ) . length
201+
202+ bracketCount += openBrackets - closeBrackets
203+ braceCount += openBraces - closeBraces
204+
205+ currentBlock += `${ trimmedLine } `
206+
207+ // Process complete property when we're back at root level
208+ if ( bracketCount === 0 && braceCount === 0 && currentBlock . includes ( ':' ) ) {
209+ const propertyMatch = currentBlock . match ( / ^ ( \w + ) \s * : \s * ( .+ ?) (?: , \s * $ | , ? \s * $ ) / )
210+ if ( propertyMatch ) {
211+ const [ , key , rawValue ] = propertyMatch
212+ const value = rawValue . trim ( )
213+ const propertyInfo = extractPropertyInfo ( key , value , lines )
214+ if ( propertyInfo ) {
215+ properties . push ( propertyInfo )
203216 }
204- currentProperty = null
205217 }
218+ currentBlock = ''
206219 }
207220 }
208221
209222 return properties
210223}
211224
212- function inferType ( value : string ) : string {
213- // Handle string literals - keep the quotes
214- if ( value . startsWith ( '"' ) || value . startsWith ( '\'' ) ) {
215- // Ensure consistent quote style (using single quotes)
216- const cleanValue = value . trim ( ) . replace ( / ^ [ " ' ] | [ " ' ] $ / g, '' )
217- return `'${ cleanValue } '`
225+ function extractPropertyInfo ( key : string , value : string , originalLines : string [ ] ) : PropertyInfo {
226+ // Handle multiline object definitions
227+ if ( value . startsWith ( '{' ) && value . includes ( '{}' ) ) {
228+ const objectLines = originalLines . filter ( line =>
229+ line . trim ( ) . startsWith ( key )
230+ || ( line . includes ( '{' ) && line . includes ( '}' ) )
231+ || line . trim ( ) . endsWith ( ',' )
232+ || line . trim ( ) . endsWith ( '}' ) ,
233+ )
234+
235+ const nestedProperties = parseNestedObject ( objectLines )
236+ if ( nestedProperties . length > 0 ) {
237+ return {
238+ key,
239+ value,
240+ type : formatNestedType ( nestedProperties ) ,
241+ nested : nestedProperties ,
242+ }
243+ }
244+ }
245+
246+ // Handle arrow functions and function declarations
247+ if ( ( value . includes ( '=>' ) && ! value . includes ( '[' ) )
248+ || value . startsWith ( 'function' )
249+ || ( value . includes ( '()' ) && value . includes ( '{' ) ) ) {
250+ return {
251+ key,
252+ value,
253+ type : 'Function' ,
254+ }
255+ }
256+
257+ // Handle arrays
258+ if ( value . startsWith ( '[' ) ) {
259+ return {
260+ key,
261+ value,
262+ type : inferArrayType ( value ) ,
263+ }
264+ }
265+
266+ // Handle inline objects
267+ if ( value . startsWith ( '{' ) ) {
268+ const objectContent = value . slice ( 1 , - 1 ) . trim ( )
269+ const nestedProps = extractObjectProperties ( [ objectContent ] )
270+ return {
271+ key,
272+ value,
273+ type : formatObjectType ( nestedProps ) ,
274+ nested : nestedProps . length > 0 ? nestedProps : undefined ,
275+ }
276+ }
277+
278+ // Handle function references and console methods
279+ if ( value === 'console.log' || value . endsWith ( '.log' ) ) {
280+ return {
281+ key,
282+ value,
283+ type : 'Function' ,
284+ }
285+ }
286+
287+ // Handle string literals
288+ if ( value . startsWith ( '\'' ) || value . startsWith ( '"' ) ) {
289+ const cleanValue = value . slice ( 1 , - 1 )
290+ return {
291+ key,
292+ value,
293+ type : `'${ cleanValue } '` ,
294+ }
295+ }
296+
297+ // Handle numbers
298+ if ( ! isNaN ( Number ( value ) ) ) {
299+ return {
300+ key,
301+ value,
302+ type : value ,
303+ }
304+ }
305+
306+ // Handle booleans
307+ if ( value === 'true' || value === 'false' ) {
308+ return {
309+ key,
310+ value,
311+ type : value ,
312+ }
313+ }
314+
315+ // Handle object references
316+ return {
317+ key,
318+ value,
319+ type : 'Object' ,
218320 }
321+ }
322+
323+ function parseNestedObject ( lines : string [ ] ) : PropertyInfo [ ] {
324+ const nestedLines = lines
325+ . map ( line => line . trim ( ) )
326+ . filter ( line => line && ! line . startsWith ( '//' ) )
327+
328+ let braceCount = 0
329+ let currentBlock = ''
330+ const properties : PropertyInfo [ ] = [ ]
331+
332+ for ( const line of nestedLines ) {
333+ braceCount += ( line . match ( / \{ / g) || [ ] ) . length
334+ braceCount -= ( line . match ( / \} / g) || [ ] ) . length
219335
220- if ( value === 'true' || value === 'false' )
221- return value
336+ if ( line . includes ( ':' ) ) {
337+ const [ key , ...valueParts ] = line . split ( ':' )
338+ const value = valueParts . join ( ':' ) . trim ( )
222339
223- if ( ! Number . isNaN ( Number ( value ) ) )
224- return value
340+ if ( value . includes ( '{' ) ) {
341+ // Start of nested object
342+ currentBlock = `${ key . trim ( ) } : ${ value } `
343+ }
344+ else if ( braceCount === 0 ) {
345+ // Simple property
346+ const propInfo = extractPropertyInfo (
347+ key . trim ( ) ,
348+ value . replace ( / , $ / , '' ) ,
349+ nestedLines ,
350+ )
351+ properties . push ( propInfo )
352+ }
353+ }
354+ }
355+
356+ return properties
357+ }
225358
226- if ( value . includes ( '=>' ) || value . includes ( 'function' ) )
227- return 'Function'
359+ function inferArrayType ( arrayValue : string ) : string {
360+ const content = arrayValue . slice ( 1 , - 1 ) . trim ( )
228361
229- if ( value . startsWith ( '[' ) )
362+ if ( ! content )
230363 return 'Array<any>'
231364
232- if ( value . startsWith ( '{' ) )
365+ // Handle nested arrays
366+ if ( content . startsWith ( '[' ) ) {
367+ const nestedContent = content . match ( / \[ ( .* ) \] / ) ?. [ 1 ]
368+ return `Array<${ nestedContent ? inferArrayType ( `[${ nestedContent } ]` ) : 'any' } >`
369+ }
370+
371+ // Handle array of objects
372+ if ( content . includes ( '{' ) ) {
373+ const objects = content . split ( '},{' ) . map ( obj => obj . replace ( / ^ \{ | \} $ / g, '' ) )
374+ const objectProps = objects . map ( obj => extractObjectProperties ( [ obj ] ) )
375+ return `Array<${ formatObjectType ( objectProps [ 0 ] ) } >`
376+ }
377+
378+ // Handle simple numeric arrays
379+ if ( content . split ( ',' ) . every ( item => ! isNaN ( Number ( item . trim ( ) ) ) ) ) {
380+ return 'Array<number>'
381+ }
382+
383+ return 'Array<any>'
384+ }
385+
386+ function formatObjectType ( properties : PropertyInfo [ ] ) : string {
387+ if ( properties . length === 0 )
233388 return 'Object'
234389
235- if ( value . includes ( '.' ) )
390+ const formattedProps = properties
391+ . map ( prop => `${ prop . key } : ${ prop . nested ? formatNestedType ( prop . nested ) : prop . type } ` )
392+ . join ( '; ' )
393+
394+ return `{ ${ formattedProps } }`
395+ }
396+
397+ function isFunctionReference ( value : string ) : boolean {
398+ // Check for common function reference patterns
399+ return value . endsWith ( '.log' )
400+ || value . endsWith ( '()' )
401+ || value . includes ( '.bind' )
402+ || value . includes ( '.call' )
403+ || value . includes ( '.apply' )
404+ || / \w + \. \w + / . test ( value ) // Matches object method references
405+ }
406+
407+ function formatNestedType ( properties : PropertyInfo [ ] ) : string {
408+ if ( properties . length === 0 )
236409 return 'Object'
237410
238- return value
411+ const formattedProps = properties
412+ . map ( prop => `${ prop . key } : ${ prop . nested ? formatNestedType ( prop . nested ) : prop . type } ` )
413+ . join ( ', ' )
414+
415+ return `{ ${ formattedProps } }`
239416}
240417
241418function processInterfaceDeclaration ( declaration : string , isExported = true ) : string {
0 commit comments