|
1 | 1 | /* eslint-disable no-case-declarations, regexp/no-contradiction-with-assertion */ |
2 | 2 | import type { ClassDeclaration, EnumDeclaration, ExportAssignment, ExportDeclaration, FunctionDeclaration, ImportDeclaration, InterfaceDeclaration, Modifier, ModuleDeclaration, Node, ParameterDeclaration, SourceFile, TypeAliasDeclaration, VariableStatement } from 'typescript' |
3 | 3 | import type { Declaration } from './types' |
4 | | -import { createSourceFile, forEachChild, isArrayBindingPattern, isBindingElement, isCallSignatureDeclaration, isConstructorDeclaration, isConstructSignatureDeclaration, isEnumDeclaration, isEnumMember, isExportAssignment, isFunctionDeclaration, isIdentifier, isInterfaceDeclaration, isMethodDeclaration, isMethodSignature, isModuleBlock, isModuleDeclaration, isObjectBindingPattern, isPropertyDeclaration, isPropertySignature, isStringLiteral, isTypeAliasDeclaration, isVariableStatement, NodeFlags, ScriptKind, ScriptTarget, SyntaxKind } from 'typescript' |
| 4 | +import { createSourceFile, forEachChild, isArrayBindingPattern, isBindingElement, isCallSignatureDeclaration, isConstructorDeclaration, isConstructSignatureDeclaration, isEnumDeclaration, isEnumMember, isExportAssignment, isFunctionDeclaration, isGetAccessorDeclaration, isIdentifier, isIndexSignatureDeclaration, isInterfaceDeclaration, isMethodDeclaration, isMethodSignature, isModuleBlock, isModuleDeclaration, isObjectBindingPattern, isPropertyDeclaration, isPropertySignature, isSetAccessorDeclaration, isStringLiteral, isTypeAliasDeclaration, isVariableStatement, NodeFlags, ScriptKind, ScriptTarget, SyntaxKind } from 'typescript' |
5 | 5 |
|
6 | 6 | /** |
7 | 7 | * Cache for parsed SourceFile objects to avoid re-parsing |
@@ -179,12 +179,16 @@ function extractImportDeclaration(node: ImportDeclaration, sourceCode: string): |
179 | 179 | const text = getNodeText(node, sourceCode) |
180 | 180 | const isTypeOnly = !!(node.importClause?.isTypeOnly) |
181 | 181 |
|
| 182 | + // Detect side-effect imports (no import clause, e.g., `import 'module'`) |
| 183 | + const isSideEffectImport = !node.importClause |
| 184 | + |
182 | 185 | return { |
183 | 186 | kind: 'import', |
184 | 187 | name: '', // Imports don't have a single name |
185 | 188 | text, |
186 | 189 | isExported: false, |
187 | 190 | isTypeOnly, |
| 191 | + isSideEffect: isSideEffectImport, |
188 | 192 | source: node.moduleSpecifier.getText().slice(1, -1), // Remove quotes |
189 | 193 | start: node.getStart(), |
190 | 194 | end: node.getEnd(), |
@@ -538,6 +542,16 @@ function getInterfaceBody(node: InterfaceDeclaration): string { |
538 | 542 | const returnType = member.type?.getText() || 'any' |
539 | 543 | members.push(` new (${params}): ${returnType}`) |
540 | 544 | } |
| 545 | + else if (isIndexSignatureDeclaration(member)) { |
| 546 | + // Index signature: [key: string]: T or [index: number]: T |
| 547 | + const params = member.parameters.map((param) => { |
| 548 | + const paramName = param.name.getText() |
| 549 | + const paramType = param.type?.getText() || 'any' |
| 550 | + return `${paramName}: ${paramType}` |
| 551 | + }).join(', ') |
| 552 | + const returnType = member.type?.getText() || 'any' |
| 553 | + members.push(` [${params}]: ${returnType}`) |
| 554 | + } |
541 | 555 | } |
542 | 556 |
|
543 | 557 | return `{\n${members.join('\n')}\n}` |
@@ -794,6 +808,56 @@ function buildClassBody(node: ClassDeclaration): string { |
794 | 808 | const type = member.type?.getText() || 'any' |
795 | 809 | signature += `: ${type};` |
796 | 810 |
|
| 811 | + members.push(signature) |
| 812 | + } |
| 813 | + else if (isGetAccessorDeclaration(member)) { |
| 814 | + // Get accessor declaration |
| 815 | + const name = member.name?.getText() || '' |
| 816 | + const isStatic = member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword) |
| 817 | + const isPrivate = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword) |
| 818 | + const isProtected = member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword) |
| 819 | + const isAbstract = member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword) |
| 820 | + |
| 821 | + let signature = ' ' |
| 822 | + if (isStatic) |
| 823 | + signature += 'static ' |
| 824 | + if (isAbstract) |
| 825 | + signature += 'abstract ' |
| 826 | + if (isPrivate) |
| 827 | + signature += 'private ' |
| 828 | + else if (isProtected) |
| 829 | + signature += 'protected ' |
| 830 | + |
| 831 | + const returnType = member.type?.getText() || 'any' |
| 832 | + signature += `get ${name}(): ${returnType};` |
| 833 | + |
| 834 | + members.push(signature) |
| 835 | + } |
| 836 | + else if (isSetAccessorDeclaration(member)) { |
| 837 | + // Set accessor declaration |
| 838 | + const name = member.name?.getText() || '' |
| 839 | + const isStatic = member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword) |
| 840 | + const isPrivate = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword) |
| 841 | + const isProtected = member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword) |
| 842 | + const isAbstract = member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword) |
| 843 | + |
| 844 | + let signature = ' ' |
| 845 | + if (isStatic) |
| 846 | + signature += 'static ' |
| 847 | + if (isAbstract) |
| 848 | + signature += 'abstract ' |
| 849 | + if (isPrivate) |
| 850 | + signature += 'private ' |
| 851 | + else if (isProtected) |
| 852 | + signature += 'protected ' |
| 853 | + |
| 854 | + // Get parameter type from the setter's parameter |
| 855 | + const param = member.parameters[0] |
| 856 | + const paramType = param?.type?.getText() || 'any' |
| 857 | + const paramName = param?.name?.getText() || 'value' |
| 858 | + |
| 859 | + signature += `set ${name}(${paramName}: ${paramType});` |
| 860 | + |
797 | 861 | members.push(signature) |
798 | 862 | } |
799 | 863 | } |
|
0 commit comments