Skip to content

Commit

Permalink
chore: wip
Browse files Browse the repository at this point in the history
chore: wip

chore: wip
  • Loading branch information
chrisbbreuer committed Oct 26, 2024
1 parent a93b244 commit 90af188
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 114 deletions.
38 changes: 12 additions & 26 deletions fixtures/output/example-0001.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { BunPlugin } from 'bun'
import type { DtsGenerationConfig, DtsGenerationOption } from '@stacksjs/dtsx'
import { generate } from '@stacksjs/dtsx'
import type { BunPlugin } from 'bun';
import type { DtsGenerationConfig, DtsGenerationOption } from '@stacksjs/dtsx';
import { generate } from '@stacksjs/dtsx';

/**
* Example of const declaration
*/
export declare const conf: { [key: string]: string };

export declare const conf: { [key: string]: string };
export declare const someObject: {
someString: 'Stacks';
someNumber: 1000;
Expand All @@ -32,104 +33,89 @@ export declare const someObject: {
};
};
};

/**
* Example of interface declaration
* with another comment in an extra line
*/

export declare interface User {
id: number
name: string
email: string
}

/**
* Example of type declaration
*
* with multiple lines of comments, including an empty line
*/

export declare interface ResponseData {
success: boolean
data: User[]
}

/**
* Example of function declaration
*
*
* with multiple empty lines, including an empty lines
*/
export declare function fetchUsers(): Promise<ResponseData>;

export declare function fetchUsers(): Promise<ResponseData>;
export declare interface ApiResponse<T> {
status: number
message: string
data: T
}

/**
* Example of another const declaration
*
* with multiple empty lines, including being poorly formatted
*/
declare const settings: { [key: string]: any };

declare const settings: { [key: string]: any };
export declare interface Product {
id: number
name: string
price: number
}

/**
* Example of function declaration
*/
export declare function getProduct(id: number): Promise<ApiResponse<Product>>;

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(user: string, password: string): Promise<AuthResponse>;

export declare const defaultHeaders: {
'Content-Type': 'application/json';
};

export declare function dts(options?: DtsGenerationOption): BunPlugin;

declare interface Options<T> {
name: string
cwd?: string
defaultConfig: T
}

export declare function loadConfig<T extends Record<string, unknown>>({ name, cwd, defaultConfig }: Options<T>): Promise<T>;

declare const dtsConfig: DtsGenerationConfig;

export { generate, dtsConfig }

export type { DtsGenerationOption }

export declare interface ComplexGeneric<T extends Record<string, unknown>, K extends keyof T> {
data: T
key: K
value: T[K]
transform: (input: T[K]) => string
nested: Array<Partial<T>>
}

export declare type ComplexUnionIntersection =
| (User & { role: 'admin' })
| (Product & { category: string })
& {
metadata: Record<string, unknown>
}


export { generate, dtsConfig }
export type { DtsGenerationOption }
export { config } from './config'
export * from './extract'
export * from './generate'
Expand Down
137 changes: 49 additions & 88 deletions src/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,10 @@ export function extractDtsTypes(sourceCode: string): string {
// Generate optimized imports based on actual output
const optimizedImports = generateOptimizedImports(state.importTracking, state.dtsLines)

// Replace existing imports with optimized ones
// Clear any existing imports and set up dtsLines with optimized imports
state.dtsLines = [
...optimizedImports,
'', // Add blank line after imports
...optimizedImports.map(imp => `${imp};`), // Ensure semicolons
'', // Single empty line after imports
...state.dtsLines.filter(line => !line.trim().startsWith('import')),
]

Expand Down Expand Up @@ -2228,101 +2228,62 @@ function formatOutput(state: ProcessingState): string {
hasDefaultExport: !!state.defaultExport,
})

const sections: string[] = []

// Process imports
if (state.imports.length > 0) {
const imports = state.imports.join('\n')
sections.push(imports)
sections.push('') // Add empty line after imports
console.log('Added imports section with trailing newline')
}

// Process declarations with proper spacing
const declarationLines = state.dtsLines
.filter(line => !line.startsWith('export *') && !line.startsWith('export { config }'))

// Group declarations and add spacing
const declarations = declarationLines
.reduce((acc: string[], line: string, index: number, lines: string[]) => {
if (line.trim()) {
// If current line is a JSDoc comment start, include all JSDoc lines
if (line.trim().startsWith('/**')) {
console.log('Found JSDoc start:', line)
const jsdocBlock = [line]
let j = index + 1
// Collect all lines until we find the end of the JSDoc block
while (j < lines.length && !lines[j].includes('*/')) {
jsdocBlock.push(lines[j])
console.log('Added JSDoc line:', lines[j])
j++
}
if (j < lines.length) {
jsdocBlock.push(lines[j]) // Include the closing */
console.log('Added JSDoc end:', lines[j])
}
acc.push(...jsdocBlock)
// Don't add empty line after JSDoc block since it should be attached to the declaration
}
// If not part of a JSDoc block already processed, add the line
else if (!line.trim().startsWith('*') && !line.includes('*/')) {
acc.push(line)
// Add newline after declarations, but not after type union/intersection lines
if (
(line.match(/^export\s+declare\s+(const|interface|function|type|class|enum|namespace|module|global|abstract\s+class)/)
|| line.match(/^declare\s+(const|interface|function|type|class|enum|namespace|module|global|abstract\s+class)/)
|| line.match(/^export\s+\{/) // Match direct exports like "export { generate, dtsConfig }"
|| line.match(/^export\s+type\s+\{/) // Match type exports like "export type { DtsGenerationOption }"
|| line.endsWith('}') // Add newline after closing braces of interfaces/types
|| line.endsWith(';')) // Add newline after semicolons
&& !line.match(/^\s*[|&]\s+/) // Don't add newline for union/intersection type lines
&& !line.match(/^\s*extends\s+/) // Don't add newline for extends clauses
&& !lines[index + 1]?.match(/^\s*[|&]\s+/) // Don't add newline if next line is a union/intersection
&& !lines[index + 1]?.match(/^\s*extends\s+/) // Don't add newline if next line is an extends clause
) {
acc.push('')
console.log('Added empty line after:', line)
}
}
}
return acc
}, [])
.join('\n')
const parts: string[] = []

if (declarations) {
sections.push(declarations)
console.log('Added declarations section')
// Group lines by type
const isExportStatement = (line: string) => {
const trimmed = line.trim()
return trimmed.startsWith('export *')
|| (trimmed.startsWith('export {') && !trimmed.startsWith('export declare'))
|| (trimmed.startsWith('export type {') && !trimmed.startsWith('export declare type'))
}

// Group all export * and export { config } statements
const exportStatements = [
...state.dtsLines.filter(line => line.startsWith('export *') || line.startsWith('export { config }')),
...state.exportAllStatements,
].join('\n').trim()
// Get declarations (everything except bare exports)
const declarations = state.dtsLines.filter(line => !isExportStatement(line))

// Process declarations preserving empty lines
const currentSection: string[] = []
let lastLineWasEmpty = false

// Add default export if it exists
const defaultExport = state.defaultExport?.trim()
for (const line of declarations) {
const trimmedLine = line.trim()

// Combine sections with appropriate spacing
let output = sections.join('\n\n')
console.log('Combined sections')
if (!trimmedLine) {
if (!lastLineWasEmpty) {
currentSection.push('')
}
lastLineWasEmpty = true
continue
}
lastLineWasEmpty = false
currentSection.push(line)
}

// Add declarations
if (currentSection.length > 0) {
parts.push(currentSection.join('\n'))
}

// Deduplicate and add export statements
const exportLines = new Set([
...state.dtsLines.filter(isExportStatement),
...state.exportAllStatements,
])

// Add export statements group before default export
if (exportStatements) {
output += output ? '\n\n' : ''
output += exportStatements
console.log('Added export statements')
if (exportLines.size > 0) {
if (parts.length > 0)
parts.push('')
parts.push([...exportLines].join('\n'))
}

// Add default export with spacing
if (defaultExport) {
output += output ? '\n\n' : ''
output += defaultExport
console.log('Added default export')
// Add default export
if (state.defaultExport) {
if (parts.length > 0)
parts.push('')
parts.push(state.defaultExport)
}

// Ensure output ends with a single newline
return `${output.trimEnd()}\n`
return `${parts.join('\n')}\n`
}

function getIndentation(line: string): string {
Expand Down

0 comments on commit 90af188

Please # to comment.