Skip to content

Commit d932a45

Browse files
committed
chore: wip
1 parent 54e763e commit d932a45

File tree

1 file changed

+94
-28
lines changed

1 file changed

+94
-28
lines changed

src/extract.ts

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,14 @@ export interface FunctionSignature {
794794
generics: string
795795
}
796796

797+
/**
798+
* Represents a tracked type reference
799+
*/
800+
export interface TypeReference {
801+
name: string
802+
generics: string[]
803+
isExternal: boolean
804+
}
797805

798806
/**
799807
* Extract complete function signature handling multi-line declarations
@@ -821,13 +829,8 @@ export function extractFunctionSignature(declaration: string): FunctionSignature
821829
const paramsMatch = withoutGenerics.match(/\(([\s\S]*?)\)(?=\s*:)/)
822830
let params = paramsMatch ? paramsMatch[1].trim() : ''
823831

824-
// Handle destructured parameters
825-
if (params.startsWith('{')) {
826-
const typeMatch = params.match(/\}:\s*([^)]+)$/)
827-
if (typeMatch) {
828-
params = `options: ${typeMatch[1].trim()}`
829-
}
830-
}
832+
// Clean up parameters
833+
params = cleanParameters(params)
831834

832835
// Extract return type
833836
const returnTypeMatch = withoutGenerics.match(/\)\s*:\s*([\s\S]+?)(?=\{|$)/)
@@ -858,18 +861,10 @@ export function processFunctionDeclaration(
858861
generics,
859862
} = extractFunctionSignature(declaration)
860863

861-
// Track generic types
862-
if (generics) {
863-
const genericTypes = generics
864-
.slice(1, -1)
865-
.split(',')
866-
.map(t => t.trim().split('extends')[0].trim())
867-
868-
genericTypes.forEach((type) => {
869-
if (type)
870-
usedTypes.add(type)
871-
})
872-
}
864+
// Track types used in the signature
865+
trackUsedTypes(generics, usedTypes)
866+
trackUsedTypes(params, usedTypes)
867+
trackUsedTypes(returnType, usedTypes)
873868

874869
// Build declaration string
875870
let result = `${isExported ? 'export ' : ''}declare `
@@ -882,23 +877,81 @@ export function processFunctionDeclaration(
882877
}
883878

884879
export function cleanParameters(params: string): string {
880+
if (!params.trim())
881+
return ''
882+
885883
return params
884+
// Handle destructured parameters
885+
.replace(/\{([^}]+)\}:\s*([^,)]+)/g, (_, props, type) => {
886+
// Convert destructured parameters to a single options parameter
887+
const typeName = type.trim()
888+
return `options: ${typeName}`
889+
})
890+
// Normalize spaces around special characters
891+
.replace(/\s*([,:])\s*/g, '$1 ')
892+
// Clean up multiple spaces
886893
.replace(/\s+/g, ' ')
887-
.replace(/\s*,\s*/g, ', ')
888-
.replace(/\s*:\s*/g, ': ')
894+
// Add space after commas if missing
895+
.replace(/,(\S)/g, ', $1')
896+
// Normalize optional parameter syntax
897+
.replace(/\s*\?\s*:/g, '?: ')
898+
// Clean up spaces around array/generic brackets
899+
.replace(/\s*([<[\]>])\s*/g, '$1')
900+
// Final cleanup of any double spaces
901+
.replace(/\s{2,}/g, ' ')
889902
.trim()
890903
}
891904

892905
/**
893906
* Analyze a function body to track used type references
894907
*/
895-
export function trackUsedTypes(body: string, usedTypes: Set<string>): void {
896-
const typeMatches = body.match(/[A-Z][a-zA-Z0-9]*(?:<[^>]+>)?/g) || []
897-
typeMatches.forEach((type) => {
898-
const baseType = type.split('<')[0]
899-
if (baseType)
900-
usedTypes.add(baseType)
901-
})
908+
export function trackUsedTypes(content: string, usedTypes: Set<string>): void {
909+
// Reset tracking for this content
910+
const typeRefs = new Set<string>()
911+
912+
// Track explicit type references
913+
const typeMatches = content.matchAll(/(?:typeof\s+)?([A-Z]\w*(?:<[^>]+>)?)/g)
914+
for (const match of typeMatches) {
915+
const fullType = match[1]
916+
const baseType = fullType.split('<')[0]
917+
918+
// Add base type
919+
typeRefs.add(baseType)
920+
921+
// Extract and track generic parameter types
922+
const genericMatch = fullType.match(/<(.+)>/)
923+
if (genericMatch) {
924+
const genericTypes = genericMatch[1].split(',')
925+
for (const genericType of genericTypes) {
926+
const cleanType = genericType.trim().split(/[<>\s]/)[0]
927+
if (/^[A-Z]/.test(cleanType))
928+
typeRefs.add(cleanType)
929+
}
930+
}
931+
}
932+
933+
// Track types used in extends clauses
934+
const extendsMatches = content.matchAll(/extends\s+([A-Z]\w*(?:<[^>]+>)?)/g)
935+
for (const match of extendsMatches) {
936+
const fullType = match[1]
937+
const baseType = fullType.split('<')[0]
938+
typeRefs.add(baseType)
939+
}
940+
941+
// Track types used in type predicates
942+
const predicateMatches = content.matchAll(/is\s+([A-Z]\w*)/g)
943+
for (const match of predicateMatches) {
944+
typeRefs.add(match[1])
945+
}
946+
947+
// Track mapped type references
948+
const mappedMatches = content.matchAll(/(?:in|of)\s+([A-Z]\w*)/g)
949+
for (const match of mappedMatches) {
950+
typeRefs.add(match[1])
951+
}
952+
953+
// Add all discovered types to the main set
954+
typeRefs.forEach(type => usedTypes.add(type))
902955
}
903956

904957
// Helper functions for line processing
@@ -1024,3 +1077,16 @@ export function formatObjectType(properties: PropertyInfo[]): string {
10241077

10251078
return `{ ${formattedProps} }`
10261079
}
1080+
1081+
/**
1082+
* Utility function to format type parameters
1083+
*/
1084+
export function formatTypeParameters(params: string): string {
1085+
return params
1086+
.split(',')
1087+
.map((param) => {
1088+
const [name, constraint] = param.split('extends').map(p => p.trim())
1089+
return constraint ? `${name} extends ${constraint}` : name
1090+
})
1091+
.join(', ')
1092+
}

0 commit comments

Comments
 (0)