Skip to content

Commit

Permalink
chore: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbbreuer committed Oct 21, 2024
1 parent c00745b commit d2b839b
Showing 1 changed file with 85 additions and 77 deletions.
162 changes: 85 additions & 77 deletions src/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export async function extract(filePath: string): Promise<string> {
}

export function generateDtsTypes(sourceCode: string): string {
console.log('Starting generateDtsTypes')
const lines = sourceCode.split('\n')
const dtsLines: string[] = []
const imports: string[] = []
Expand All @@ -23,37 +24,46 @@ export function generateDtsTypes(sourceCode: string): string {

for (let i = 0; i < lines.length; i++) {
const line = lines[i]
console.log(`Processing line ${i + 1}: ${line}`)

// Handle comments
if (line.trim().startsWith('/**') || line.trim().startsWith('*') || line.trim().startsWith('*/')) {
if (line.trim().startsWith('/**'))
lastCommentBlock = ''
lastCommentBlock += `${line}\n`
console.log('Comment line added to lastCommentBlock')
continue
}

if (line.trim().startsWith('import')) {
imports.push(line)
const processedImport = processImport(line)
imports.push(processedImport)
console.log(`Processed import: ${processedImport}`)
continue
}

if (line.trim().startsWith('export') && (line.includes('{') || line.includes('*') || line.includes('from'))) {
exports.push(line)
console.log(`Export line added: ${line}`)
continue
}

if (isMultiLineDeclaration || line.trim().startsWith('export')) {
currentDeclaration += `${line}\n`
bracketCount += (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length
console.log(`Current declaration: ${currentDeclaration.trim()}, Bracket count: ${bracketCount}`)

if (bracketCount === 0 || (i === lines.length - 1)) {
if (lastCommentBlock) {
dtsLines.push(lastCommentBlock.trimEnd())
console.log(`Comment block added to dtsLines: ${lastCommentBlock.trimEnd()}`)
lastCommentBlock = ''
}
const processed = processDeclaration(currentDeclaration.trim())
if (processed)
if (processed) {
dtsLines.push(processed)
console.log(`Processed declaration added to dtsLines: ${processed}`)
}
isMultiLineDeclaration = false
currentDeclaration = ''
bracketCount = 0
Expand All @@ -73,121 +83,119 @@ export function generateDtsTypes(sourceCode: string): string {
...exports,
].filter(Boolean).join('\n'))

console.log('Final result:', result)
return result
}

function processDeclaration(declaration: string): string {
// Remove comments
const declWithoutComments = declaration.replace(/\/\/.*$/gm, '').trim()
const trimmed = declWithoutComments

if (trimmed.startsWith('export const')) {
return processConstDeclaration(trimmed)
function processImport(importLine: string): string {
console.log(`Processing import: ${importLine}`)
if (importLine.includes('type')) {
const processed = importLine.replace('import', 'import type').replace('type type', 'type')
console.log(`Processed import: ${processed}`)
return processed
}
else if (trimmed.startsWith('export interface')) {
return processInterfaceDeclaration(trimmed)
return importLine
}

function processDeclaration(declaration: string): string {
console.log(`Processing declaration: ${declaration}`)
if (declaration.startsWith('export const')) {
return processConstDeclaration(declaration)
}
else if (trimmed.startsWith('export type')) {
return processTypeDeclaration(trimmed)
else if (declaration.startsWith('export interface')) {
return processInterfaceDeclaration(declaration)
}
else if (trimmed.startsWith('export function') || trimmed.startsWith('export async function')) {
return processFunctionDeclaration(trimmed)
else if (declaration.startsWith('export type')) {
return processTypeDeclaration(declaration)
}
else if (trimmed.startsWith('export default')) {
return `${trimmed};`
else if (declaration.startsWith('export function') || declaration.startsWith('export async function')) {
return processFunctionDeclaration(declaration)
}
else if (trimmed.startsWith('export')) {
return trimmed.endsWith(';') ? trimmed : `${trimmed};`
else if (declaration.startsWith('export default')) {
return `${declaration};`
}

return ''
console.log(`Declaration not processed: ${declaration}`)
return declaration
}

function processConstDeclaration(declaration: string): string {
console.log(`Processing const declaration: ${declaration}`)
const equalIndex = declaration.indexOf('=')
if (equalIndex === -1)
return declaration // No value assigned
return declaration

const name = declaration.slice(0, equalIndex).trim().replace('export const', '').trim()
const value = declaration.slice(equalIndex + 1).trim().replace(/;$/, '')

// Handle object literals
if (value.startsWith('{')) {
const objectType = parseObjectLiteral(value)
return `export declare const ${name}: ${objectType};`
const result = `export declare const ${name}: ${objectType};`
console.log(`Processed const declaration: ${result}`)
return result
}
else {
const valueType = preserveValueType(value)
return `export declare const ${name}: ${valueType};`
const valueType = inferValueType(value)
const result = `export declare const ${name}: ${valueType};`
console.log(`Processed const declaration: ${result}`)
return result
}
}

function processInterfaceDeclaration(declaration: string): string {
const lines = declaration.split('\n')
const interfaceName = lines[0].split('interface')[1].split('{')[0].trim()
const interfaceBody = lines.slice(1, -1).join('\n')
return `export declare interface ${interfaceName} {\n${interfaceBody}\n}`
console.log(`Processing interface declaration: ${declaration}`)
const result = declaration.replace('export interface', 'export declare interface')
console.log(`Processed interface declaration: ${result}`)
return result
}

function processTypeDeclaration(declaration: string): string {
return declaration.replace('export type', 'export declare type')
console.log(`Processing type declaration: ${declaration}`)
const result = declaration.replace('export type', 'export declare type')
console.log(`Processed type declaration: ${result}`)
return result
}

function processFunctionDeclaration(declaration: string): string {
// Remove the function body
const functionSignature = declaration.split('{')[0].trim()
return `export declare ${functionSignature.replace('export ', '')};`
console.log(`Processing function declaration: ${declaration}`)
const functionBody = declaration.match(/\{[\s\S]*\}/)?.[0] || ''
const result = `export declare ${declaration.replace(functionBody, '').trim()};`
console.log(`Processed function declaration: ${result}`)
return result
}

function parseObjectLiteral(objectLiteral: string): string {
// Remove the opening and closing braces and newlines
const content = objectLiteral.replace(/^\{|\}$/g, '').replace(/\n/g, ' ').trim()

const pairs = content.split(',').map(pair => pair.trim()).filter(Boolean)

const parsedProperties = pairs.map((pair) => {
const [key, ...valueParts] = pair.split(':')
const value = valueParts.join(':').trim()

if (value.startsWith('\'') || value.startsWith('"')) {
// For string literals, keep as is
return ` ${key.trim()}: ${value};`
}
else {
// For other types, use preserveValueType
const preservedValue = preserveValueType(value)
return ` ${key.trim()}: ${preservedValue};`
}
console.log(`Parsing object literal: ${objectLiteral}`)
const content = objectLiteral.replace(/^\{|\}$/g, '').split(',').map(pair => pair.trim())
const parsedProperties = content.map((pair) => {
const [key, value] = pair.split(':').map(p => p.trim())
return ` ${key}: ${inferValueType(value)};`
})

return `{\n${parsedProperties.join('\n')}\n}`
const result = `{\n${parsedProperties.join('\n')}\n}`
console.log(`Parsed object literal: ${result}`)
return result
}

function preserveValueType(value: string): string {
value = value.trim()
if (value === 'true' || value === 'false') {
return 'boolean' // Use boolean type for true and false
}
else if (!Number.isNaN(Number(value))) {
return 'number' // Use number type for numeric values
}
else if (value.startsWith('[') && value.endsWith(']')) {
return 'any[]' // Generic array type
}
else if ((value.startsWith('\'') && value.endsWith('\'')) || (value.startsWith('"') && value.endsWith('"'))) {
return 'string' // Use string type for string literals
}
else {
return 'any' // Default to any for other cases
}
function inferValueType(value: string): string {
console.log(`Inferring value type for: ${value}`)
if (value === 'true' || value === 'false')
return value
if (!Number.isNaN(Number(value)))
return value
if (value.startsWith('\'') || value.startsWith('"'))
return value
console.log(`Defaulting to string for: ${value}`)
return 'string' // Default to string for other cases
}

function cleanOutput(output: string): string {
return output
.replace(/\{\s*\}/g, '{}') // Replace empty objects with {}
.replace(/\s*;\s*(?=\}|$)/g, ';') // Clean up semicolons before closing braces or end of string
.replace(/\n+/g, '\n') // Remove multiple consecutive newlines
.replace(/;\n\}/g, ';\n }') // Add indentation to closing brace of object literals
.replace(/\{;/g, '{') // Remove unnecessary semicolons after opening braces
console.log('Cleaning output')
const result = output
.replace(/\{\s*\}/g, '{}')
.replace(/\s*;\s*(?=\}|$)/g, ';')
.replace(/\n+/g, '\n')
.replace(/;\n\}/g, ';\n }')
.replace(/\{;/g, '{')
.trim()
console.log('Cleaned output:', result)
return result
}

0 comments on commit d2b839b

Please # to comment.