Skip to content

Commit

Permalink
chore: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbbreuer committed Oct 23, 2024
1 parent 3d8a35f commit e83ce80
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 66 deletions.
8 changes: 4 additions & 4 deletions fixtures/output/example-0001.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export declare interface ResponseData {
*
* with multiple empty lines, including an empty lines
*/
export declare function fetchUsers<ResponseData>(): Promise;
export declare function fetchUsers(): Promise<ResponseData>;
export declare interface ApiResponse<T> {
status: number;
message: string;
Expand All @@ -77,13 +77,13 @@ export declare interface Product {
/**
* Example of function declaration
*/
export declare function getProduct<ApiResponse<Product>(id: number): Promise>;
export declare function getProduct(id: number): Promise<ApiResponse<Product>>;
export declare interface AuthResponse {
token: string;
expiresIn: number;
}
export declare type AuthStatus = 'authenticated' | 'unauthenticated';
export declare function authenticate<AuthResponse>(user: string, password: string): Promise;
export declare function authenticate(user: string, password: string): Promise<AuthResponse>;
export declare const defaultHeaders: {
'Content-Type': 'application/json';
};
Expand All @@ -93,7 +93,7 @@ declare interface Options<T> {
cwd?: string;
defaultConfig: T;
}
export declare async function loadConfig><T extends Record<string, unknown>(options: Options<T>): Promise<T>;
export declare async function loadConfig(options: Options<T>): Promise<T>;
declare const dtsConfig: DtsGenerationConfig;
export { generate, dtsConfig }
export declare type { DtsGenerationOption }
Expand Down
119 changes: 57 additions & 62 deletions src/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,12 @@ export function extractFunctionSignature(declaration: string): FunctionSignature
.replace(/^function\s+/, '')
.trim()

// Extract generics first
const genericsMatch = cleanDeclaration.match(/<([^>]+)>/)
// Extract generics with improved regex
const genericsMatch = cleanDeclaration.match(/<([^>]+)>(?=\s*\()/)
const generics = genericsMatch ? `<${genericsMatch[1]}>` : ''

// Remove generics from declaration for easier parsing
const withoutGenerics = cleanDeclaration.replace(/<([^>]+)>/, '')
// Remove generics for further parsing
const withoutGenerics = cleanDeclaration.replace(/<([^>]+)>(?=\s*\()/, '')

// Extract function name
const nameMatch = withoutGenerics.match(/^([^(<\s]+)/)
Expand All @@ -832,9 +832,12 @@ export function extractFunctionSignature(declaration: string): FunctionSignature
// Clean up parameters
params = cleanParameters(params)

// Extract return type
// Extract return type with improved generic handling
const returnTypeMatch = withoutGenerics.match(/\)\s*:\s*([\s\S]+?)(?=\{|$)/)
const returnType = returnTypeMatch ? returnTypeMatch[1].trim() : 'void'
let returnType = returnTypeMatch ? returnTypeMatch[1].trim() : 'void'

// Ensure generic type parameters in return types are preserved
returnType = returnType.replace(/\s+/g, '')

return {
name,
Expand All @@ -846,7 +849,7 @@ export function extractFunctionSignature(declaration: string): FunctionSignature
}

/**
* Process function declarations with full type information preservation
* Process function declaration with fixed generic handling
*/
export function processFunctionDeclaration(
declaration: string,
Expand All @@ -861,21 +864,35 @@ export function processFunctionDeclaration(
generics,
} = extractFunctionSignature(declaration)

// Track types used in the signature
trackUsedTypes(generics, usedTypes)
trackUsedTypes(params, usedTypes)
trackUsedTypes(returnType, usedTypes)

// Build declaration string
let result = `${isExported ? 'export ' : ''}declare `
if (isAsync)
result += 'async '
// Track all used types
trackUsedTypes(`${generics} ${params} ${returnType}`, usedTypes)

result += `function ${name}${generics}(${params}): ${returnType};`
// Build declaration string ensuring correct placement of generics
const parts = [
isExported ? 'export' : '',
'declare',
isAsync ? 'async' : '',
'function',
name,
generics,
`(${params})`,
`:`,
returnType,
';',
]

return result.trim()
return parts
.filter(Boolean)
.join(' ')
.replace(/\s+([<>(),;:])/g, '$1')
.replace(/([<>(),;:])\s+/g, '$1 ')
.replace(/\s+/g, ' ')
.trim()
}

/**
* Clean and normalize parameter declarations
*/
export function cleanParameters(params: string): string {
if (!params.trim())
return ''
Expand Down Expand Up @@ -903,55 +920,33 @@ export function cleanParameters(params: string): string {
}

/**
* Analyze a function body to track used type references
* Track used types in function signatures and bodies
*/
export function trackUsedTypes(content: string, usedTypes: Set<string>): void {
// Reset tracking for this content
const typeRefs = new Set<string>()

// Track explicit type references
const typeMatches = content.matchAll(/(?:typeof\s+)?([A-Z]\w*(?:<[^>]+>)?)/g)
for (const match of typeMatches) {
const fullType = match[1]
const baseType = fullType.split('<')[0]

// Add base type
typeRefs.add(baseType)

// Extract and track generic parameter types
const genericMatch = fullType.match(/<(.+)>/)
if (genericMatch) {
const genericTypes = genericMatch[1].split(',')
for (const genericType of genericTypes) {
const cleanType = genericType.trim().split(/[<>\s]/)[0]
if (/^[A-Z]/.test(cleanType))
typeRefs.add(cleanType)
// Track type references in generics, parameters, and return types
const typePattern = /(?:typeof\s+)?([A-Z]\w*(?:<[^>]+>)?)|extends\s+([A-Z]\w*(?:<[^>]+>)?)/g
let match

while ((match = typePattern.exec(content)) !== null) {
const type = match[1] || match[2]
if (type) {
// Extract base type and any nested generic types
const [baseType, ...genericParams] = type.split(/[<>]/)
if (baseType)
usedTypes.add(baseType)

// Process generic parameters
if (genericParams.length > 0) {
genericParams.forEach((param) => {
const nestedTypes = param.split(/[,\s]/)
nestedTypes.forEach((t) => {
if (/^[A-Z]/.test(t))
usedTypes.add(t)
})
})
}
}
}

// Track types used in extends clauses
const extendsMatches = content.matchAll(/extends\s+([A-Z]\w*(?:<[^>]+>)?)/g)
for (const match of extendsMatches) {
const fullType = match[1]
const baseType = fullType.split('<')[0]
typeRefs.add(baseType)
}

// Track types used in type predicates
const predicateMatches = content.matchAll(/is\s+([A-Z]\w*)/g)
for (const match of predicateMatches) {
typeRefs.add(match[1])
}

// Track mapped type references
const mappedMatches = content.matchAll(/(?:in|of)\s+([A-Z]\w*)/g)
for (const match of mappedMatches) {
typeRefs.add(match[1])
}

// Add all discovered types to the main set
typeRefs.forEach(type => usedTypes.add(type))
}

// Helper functions for line processing
Expand Down

0 comments on commit e83ce80

Please sign in to comment.