From 1aa14fdd807e499933953f62c2455b9eb3703534 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 18 Oct 2024 19:59:54 +0200 Subject: [PATCH] chore: wip --- bin/cli.ts | 1 + src/extract.ts | 92 +++++++++++++++++++++++++++++++------------------- src/utils.ts | 1 + 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/bin/cli.ts b/bin/cli.ts index 5aa7e19..9d8f83a 100644 --- a/bin/cli.ts +++ b/bin/cli.ts @@ -1,5 +1,6 @@ import type { DtsGenerationConfig, DtsGenerationOption } from '../src/types' import { resolve } from 'node:path' +import process from 'node:process' import { CAC } from '@stacksjs/cli' import { version } from '../package.json' import { generate } from '../src/generate' diff --git a/src/extract.ts b/src/extract.ts index 7ddbda1..ebf0c69 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -8,22 +8,20 @@ export async function extractTypeFromSource(filePath: string): Promise { const importMap = new Map>() // Handle re-exports - const reExportRegex = /export\s*(?:\*|\{[^}]*\})\s*from\s*['"]([^'"]+)['"]/g - let reExportMatch - while ((reExportMatch = reExportRegex.exec(fileContent)) !== null) { - declarations += `${reExportMatch[0]}\n` - } + const reExportRegex = /export\s*(?:\*|\{[^}]*\})\s*from\s*['"][^'"]+['"]/g + const reExports = fileContent.match(reExportRegex) || [] + declarations += `${reExports.join('\n')}\n` // Capture all imports const importRegex = /import\s+(?:(type)\s+)?(?:(\{[^}]+\})|(\w+))(?:\s*,\s*(?:(\{[^}]+\})|(\w+)))?\s+from\s+['"]([^'"]+)['"]/g - let importMatch - while ((importMatch = importRegex.exec(fileContent)) !== null) { - const [, isTypeImport, namedImports1, defaultImport1, namedImports2, defaultImport2, from] = importMatch + const imports = Array.from(fileContent.matchAll(importRegex)) + + imports.forEach(([, isTypeImport, namedImports1, defaultImport1, namedImports2, defaultImport2, from]) => { if (!importMap.has(from)) { importMap.set(from, new Set()) } - const processImports = (imports: string | undefined, isType: boolean) => { + const processImports = (imports: string | undefined, _isType: boolean) => { if (imports) { const types = imports.replace(/[{}]/g, '').split(',').map((t) => { const [name, alias] = t.split(' as ').map(s => s.trim()) @@ -41,38 +39,64 @@ export async function extractTypeFromSource(filePath: string): Promise { importMap.get(from)!.add(defaultImport1) if (defaultImport2) importMap.get(from)!.add(defaultImport2) - } + }) // Handle exports with comments - const exportRegex = /(\/\*\*[\s\S]*?\*\/\s*)?(export\s+(?:async\s+)?(?:function|const|let|var|class|interface|type)\s+\w[\s\S]*?)(?=\n\s*(?:\/\*\*|export|$))/g - let match - while ((match = exportRegex.exec(fileContent)) !== null) { - const [, comment, exportStatement] = match - const formattedComment = comment ? formatComment(comment.trim()) : '' - let formattedExport = exportStatement.trim() - - if (formattedExport.startsWith('export function') || formattedExport.startsWith('export async function')) { - formattedExport = formattedExport.replace(/^export\s+(async\s+)?function/, 'export declare function') - const functionSignature = formattedExport.match(/^.*?\)/) - if (functionSignature) { - let params = functionSignature[0].slice(functionSignature[0].indexOf('(') + 1, -1) - params = params.replace(/\s*=[^,)]+/g, '') // Remove default values - const returnType = formattedExport.match(/\):\s*([^{]+)/) - formattedExport = `export declare function ${formattedExport.split('function')[1].split('(')[0].trim()}(${params})${returnType ? `: ${returnType[1].trim()}` : ''};` + const exportLines = fileContent.split('\n') + let i = 0 + while (i < exportLines.length) { + let comment = '' + let exportStatement = '' + + // Collect comment + if (exportLines[i].trim().startsWith('/**')) { + while (i < exportLines.length && !exportLines[i].includes('*/')) { + comment += `${exportLines[i]}\n` + i++ } + comment += `${exportLines[i]}\n` + i++ } - else if (formattedExport.startsWith('export const') || formattedExport.startsWith('export let') || formattedExport.startsWith('export var')) { - formattedExport = formattedExport.replace(/^export\s+(const|let|var)/, 'export declare $1') - formattedExport = `${formattedExport.split('=')[0].trim()};` + + // Collect export statement + if (i < exportLines.length && exportLines[i].trim().startsWith('export')) { + exportStatement = exportLines[i] + i++ + while (i < exportLines.length && !exportLines[i].trim().startsWith('export') && !exportLines[i].trim().startsWith('/**')) { + exportStatement += `\n${exportLines[i]}` + i++ + } } - declarations += `${formattedComment}\n${formattedExport}\n\n` + if (exportStatement) { + const formattedComment = comment ? formatComment(comment.trim()) : '' + let formattedExport = exportStatement.trim() + + if (formattedExport.startsWith('export function') || formattedExport.startsWith('export async function')) { + formattedExport = formattedExport.replace(/^export\s+(async\s+)?function/, 'export declare function') + const functionSignature = formattedExport.match(/^.*?\)/) + if (functionSignature) { + let params = functionSignature[0].slice(functionSignature[0].indexOf('(') + 1, -1) + params = params.replace(/\s*=[^,)]+/g, '') // Remove default values + const returnType = formattedExport.match(/\):\s*([^{]+)/) + formattedExport = `export declare function ${formattedExport.split('function')[1].split('(')[0].trim()}(${params})${returnType ? `: ${returnType[1].trim()}` : ''};` + } + } + else if (formattedExport.startsWith('export const') || formattedExport.startsWith('export let') || formattedExport.startsWith('export var')) { + formattedExport = formattedExport.replace(/^export\s+(const|let|var)/, 'export declare $1') + formattedExport = `${formattedExport.split('=')[0].trim()};` + } + + declarations += `${formattedComment}\n${formattedExport}\n\n` + + // Add types used in the export to usedTypes + const typeRegex = /\b([A-Z]\w+)(?:<[^>]*>)?/g + const types = Array.from(formattedExport.matchAll(typeRegex)) + types.forEach(([, type]) => usedTypes.add(type)) + } - // Add types used in the export to usedTypes - const typeRegex = /\b([A-Z]\w+)(?:<[^>]*>)?/g - let typeMatch - while ((typeMatch = typeRegex.exec(formattedExport)) !== null) { - usedTypes.add(typeMatch[1]) + if (!exportStatement && !comment) { + i++ } } diff --git a/src/utils.ts b/src/utils.ts index 586d4b1..2868a83 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,7 @@ import type { DtsGenerationConfig } from './types' import { readdir, readFile } from 'node:fs/promises' import { extname, join } from 'node:path' +import process from 'node:process' import { config } from './config' export async function writeToFile(filePath: string, content: string): Promise {