@honestjs/rpc-plugin 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -45
- package/dist/index.d.mts +2 -6
- package/dist/index.d.ts +2 -6
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# @honestjs/rpc-plugin
|
|
2
2
|
|
|
3
3
|
A comprehensive RPC plugin for HonestJS that combines route analysis, schema generation, and client generation into a
|
|
4
|
-
single
|
|
4
|
+
single solution.
|
|
5
5
|
|
|
6
6
|
## Features
|
|
7
7
|
|
|
8
8
|
- **Route Analysis**: Automatically analyzes controller methods and extracts type information using ts-morph
|
|
9
9
|
- **Schema Generation**: Generates JSON schemas and TypeScript interfaces from types used in controllers
|
|
10
10
|
- **Client Generation**: Creates a fully-typed TypeScript RPC client with proper parameter typing
|
|
11
|
-
- **Tight Integration**: All components share data directly, eliminating duplication and file I/O overhead
|
|
12
11
|
- **Type Safety**: Full TypeScript support with generated types and interfaces
|
|
13
12
|
|
|
14
13
|
## Installation
|
|
@@ -51,15 +50,16 @@ interface RPCPluginOptions {
|
|
|
51
50
|
|
|
52
51
|
## What It Generates
|
|
53
52
|
|
|
54
|
-
###
|
|
53
|
+
### TypeScript RPC Client (`client.ts`)
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
The plugin generates a single comprehensive file that includes both the client and all type definitions:
|
|
57
56
|
|
|
58
57
|
- **Controller-based organization**: Methods grouped by controller
|
|
59
58
|
- **Type-safe parameters**: Path, query, and body parameters with proper typing
|
|
60
59
|
- **Flexible request options**: Clean separation of params, query, body, and headers
|
|
61
60
|
- **Error handling**: Built-in error handling with custom ApiError class
|
|
62
61
|
- **Authentication support**: Easy header and auth token management
|
|
62
|
+
- **Integrated types**: All DTOs, interfaces, and utility types included in the same file
|
|
63
63
|
|
|
64
64
|
```typescript
|
|
65
65
|
// Generated client usage
|
|
@@ -90,14 +90,12 @@ apiClient.setDefaultHeaders({
|
|
|
90
90
|
})
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
The generated `client.ts` file contains everything you need:
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **
|
|
98
|
-
- **
|
|
99
|
-
- **API response types**: Standardized response and error types
|
|
100
|
-
- **Utility types**: Request options and parameter types
|
|
95
|
+
- **ApiClient class** with all your controller methods
|
|
96
|
+
- **Type definitions** for requests, responses, and DTOs
|
|
97
|
+
- **Utility types** like RequestOptions and ApiResponse
|
|
98
|
+
- **Generated interfaces** from your controller types
|
|
101
99
|
|
|
102
100
|
## How It Works
|
|
103
101
|
|
|
@@ -132,40 +130,6 @@ Comprehensive type definitions including:
|
|
|
132
130
|
|
|
133
131
|
## Example Generated Output
|
|
134
132
|
|
|
135
|
-
### Route Analysis
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
export interface ExtendedRouteInfo {
|
|
139
|
-
controller: string
|
|
140
|
-
handler: string
|
|
141
|
-
method: string
|
|
142
|
-
path: string
|
|
143
|
-
fullPath: string
|
|
144
|
-
returns?: string
|
|
145
|
-
parameters?: ParameterMetadataWithType[]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export const ANALYZED_ROUTES = [
|
|
149
|
-
{
|
|
150
|
-
controller: 'UsersController',
|
|
151
|
-
handler: 'create',
|
|
152
|
-
method: 'POST',
|
|
153
|
-
path: '/',
|
|
154
|
-
fullPath: '/api/v1/users/',
|
|
155
|
-
returns: 'Promise<User>',
|
|
156
|
-
parameters: [
|
|
157
|
-
{
|
|
158
|
-
index: 0,
|
|
159
|
-
name: 'createUserDto',
|
|
160
|
-
type: 'CreateUserDto',
|
|
161
|
-
required: true,
|
|
162
|
-
data: undefined
|
|
163
|
-
}
|
|
164
|
-
]
|
|
165
|
-
}
|
|
166
|
-
] as const
|
|
167
|
-
```
|
|
168
|
-
|
|
169
133
|
### Generated Client
|
|
170
134
|
|
|
171
135
|
```typescript
|
package/dist/index.d.mts
CHANGED
|
@@ -102,8 +102,8 @@ declare class RPCPlugin implements IPlugin {
|
|
|
102
102
|
private readonly routeAnalyzer;
|
|
103
103
|
private readonly schemaGenerator;
|
|
104
104
|
private readonly clientGenerator;
|
|
105
|
-
private
|
|
106
|
-
private
|
|
105
|
+
private analyzedRoutes;
|
|
106
|
+
private analyzedSchemas;
|
|
107
107
|
private generatedInfo;
|
|
108
108
|
constructor(options?: RPCPluginOptions);
|
|
109
109
|
/**
|
|
@@ -138,10 +138,6 @@ declare class RPCPlugin implements IPlugin {
|
|
|
138
138
|
* Cleanup resources to prevent memory leaks
|
|
139
139
|
*/
|
|
140
140
|
dispose(): void;
|
|
141
|
-
/**
|
|
142
|
-
* Plugin lifecycle cleanup
|
|
143
|
-
*/
|
|
144
|
-
onDestroy(): void;
|
|
145
141
|
/**
|
|
146
142
|
* Logs a message with the plugin prefix
|
|
147
143
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -102,8 +102,8 @@ declare class RPCPlugin implements IPlugin {
|
|
|
102
102
|
private readonly routeAnalyzer;
|
|
103
103
|
private readonly schemaGenerator;
|
|
104
104
|
private readonly clientGenerator;
|
|
105
|
-
private
|
|
106
|
-
private
|
|
105
|
+
private analyzedRoutes;
|
|
106
|
+
private analyzedSchemas;
|
|
107
107
|
private generatedInfo;
|
|
108
108
|
constructor(options?: RPCPluginOptions);
|
|
109
109
|
/**
|
|
@@ -138,10 +138,6 @@ declare class RPCPlugin implements IPlugin {
|
|
|
138
138
|
* Cleanup resources to prevent memory leaks
|
|
139
139
|
*/
|
|
140
140
|
dispose(): void;
|
|
141
|
-
/**
|
|
142
|
-
* Plugin lifecycle cleanup
|
|
143
|
-
*/
|
|
144
|
-
onDestroy(): void;
|
|
145
141
|
/**
|
|
146
142
|
* Logs a message with the plugin prefix
|
|
147
143
|
*/
|
package/dist/index.js
CHANGED
|
@@ -746,6 +746,7 @@ var SchemaGeneratorService = class {
|
|
|
746
746
|
const project = new import_ts_morph2.Project({
|
|
747
747
|
tsConfigFilePath: this.tsConfigPath
|
|
748
748
|
});
|
|
749
|
+
project.addSourceFilesAtPaths([this.controllerPattern]);
|
|
749
750
|
this.projects.push(project);
|
|
750
751
|
return project;
|
|
751
752
|
}
|
|
@@ -892,8 +893,11 @@ var RPCPlugin = class {
|
|
|
892
893
|
async analyzeEverything() {
|
|
893
894
|
try {
|
|
894
895
|
this.log("Starting comprehensive RPC analysis...");
|
|
895
|
-
this.analyzedRoutes
|
|
896
|
-
this.analyzedSchemas
|
|
896
|
+
this.analyzedRoutes = [];
|
|
897
|
+
this.analyzedSchemas = [];
|
|
898
|
+
this.generatedInfo = null;
|
|
899
|
+
this.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods();
|
|
900
|
+
this.analyzedSchemas = await this.schemaGenerator.generateSchemas();
|
|
897
901
|
this.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas);
|
|
898
902
|
this.log(
|
|
899
903
|
`\u2705 RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`
|
|
@@ -936,12 +940,6 @@ var RPCPlugin = class {
|
|
|
936
940
|
this.schemaGenerator.dispose();
|
|
937
941
|
this.log("Resources cleaned up");
|
|
938
942
|
}
|
|
939
|
-
/**
|
|
940
|
-
* Plugin lifecycle cleanup
|
|
941
|
-
*/
|
|
942
|
-
onDestroy() {
|
|
943
|
-
this.dispose();
|
|
944
|
-
}
|
|
945
943
|
// ============================================================================
|
|
946
944
|
// LOGGING UTILITIES
|
|
947
945
|
// ============================================================================
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["// Main plugin export\nexport { RPCPlugin } from './rpc.plugin'\n\n// Export all types\nexport type {\n\tApiError,\n\tApiResponse,\n\tControllerGroups,\n\tExtendedRouteInfo,\n\tGeneratedClientInfo,\n\tParameterMetadataWithType,\n\tRequestOptions,\n\tRouteParameter,\n\tRPCPluginOptions,\n\tSchemaInfo\n} from './types'\n\n// Export services for advanced usage\nexport { ClientGeneratorService } from './services/client-generator.service'\nexport { RouteAnalyzerService } from './services/route-analyzer.service'\nexport { SchemaGeneratorService } from './services/schema-generator.service'\n\n// Export utilities for custom implementations\nexport * from './utils/path-utils'\nexport * from './utils/schema-utils'\nexport * from './utils/string-utils'\nexport * from './utils/type-utils'\n\n// Export constants\nexport * from './constants/defaults'\n","import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate readonly analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate readonly analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes.push(...(await this.routeAnalyzer.analyzeControllerMethods()))\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas.push(...(await this.schemaGenerator.generateSchemas()))\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t/**\n\t * Plugin lifecycle cleanup\n\t */\n\tonDestroy(): void {\n\t\tthis.dispose()\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\n\tconstructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...defaultHeaders\n\t\t}\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\t/**\n\t * Set default authorization header\n\t */\n\tsetDefaultAuth(token: string): this {\n\t\tthis.defaultHeaders.Authorization = \\`Bearer \\${token}\\`\n\t\treturn this\n\t}\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["import_path","path","fs","path","import_ts_morph","type","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["// Main plugin export\nexport { RPCPlugin } from './rpc.plugin'\n\n// Export all types\nexport type {\n\tApiError,\n\tApiResponse,\n\tControllerGroups,\n\tExtendedRouteInfo,\n\tGeneratedClientInfo,\n\tParameterMetadataWithType,\n\tRequestOptions,\n\tRouteParameter,\n\tRPCPluginOptions,\n\tSchemaInfo\n} from './types'\n\n// Export services for advanced usage\nexport { ClientGeneratorService } from './services/client-generator.service'\nexport { RouteAnalyzerService } from './services/route-analyzer.service'\nexport { SchemaGeneratorService } from './services/schema-generator.service'\n\n// Export utilities for custom implementations\nexport * from './utils/path-utils'\nexport * from './utils/schema-utils'\nexport * from './utils/string-utils'\nexport * from './utils/type-utils'\n\n// Export constants\nexport * from './constants/defaults'\n","import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\n\tconstructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...defaultHeaders\n\t\t}\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\t/**\n\t * Set default authorization header\n\t */\n\tsetDefaultAuth(token: string): this {\n\t\tthis.defaultHeaders.Authorization = \\`Bearer \\${token}\\`\n\t\treturn this\n\t}\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["import_path","path","fs","path","import_ts_morph","type","path","fs"]}
|
package/dist/index.mjs
CHANGED
|
@@ -694,6 +694,7 @@ var SchemaGeneratorService = class {
|
|
|
694
694
|
const project = new Project2({
|
|
695
695
|
tsConfigFilePath: this.tsConfigPath
|
|
696
696
|
});
|
|
697
|
+
project.addSourceFilesAtPaths([this.controllerPattern]);
|
|
697
698
|
this.projects.push(project);
|
|
698
699
|
return project;
|
|
699
700
|
}
|
|
@@ -840,8 +841,11 @@ var RPCPlugin = class {
|
|
|
840
841
|
async analyzeEverything() {
|
|
841
842
|
try {
|
|
842
843
|
this.log("Starting comprehensive RPC analysis...");
|
|
843
|
-
this.analyzedRoutes
|
|
844
|
-
this.analyzedSchemas
|
|
844
|
+
this.analyzedRoutes = [];
|
|
845
|
+
this.analyzedSchemas = [];
|
|
846
|
+
this.generatedInfo = null;
|
|
847
|
+
this.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods();
|
|
848
|
+
this.analyzedSchemas = await this.schemaGenerator.generateSchemas();
|
|
845
849
|
this.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas);
|
|
846
850
|
this.log(
|
|
847
851
|
`\u2705 RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`
|
|
@@ -884,12 +888,6 @@ var RPCPlugin = class {
|
|
|
884
888
|
this.schemaGenerator.dispose();
|
|
885
889
|
this.log("Resources cleaned up");
|
|
886
890
|
}
|
|
887
|
-
/**
|
|
888
|
-
* Plugin lifecycle cleanup
|
|
889
|
-
*/
|
|
890
|
-
onDestroy() {
|
|
891
|
-
this.dispose();
|
|
892
|
-
}
|
|
893
891
|
// ============================================================================
|
|
894
892
|
// LOGGING UTILITIES
|
|
895
893
|
// ============================================================================
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate readonly analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate readonly analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes.push(...(await this.routeAnalyzer.analyzeControllerMethods()))\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas.push(...(await this.schemaGenerator.generateSchemas()))\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t/**\n\t * Plugin lifecycle cleanup\n\t */\n\tonDestroy(): void {\n\t\tthis.dispose()\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\n\tconstructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...defaultHeaders\n\t\t}\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\t/**\n\t * Set default authorization header\n\t */\n\tsetDefaultAuth(token: string): this {\n\t\tthis.defaultHeaders.Authorization = \\`Bearer \\${token}\\`\n\t\treturn this\n\t}\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":"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","names":["fs","path","path","Project","Project","type","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/rpc.plugin.ts","../src/constants/defaults.ts","../src/services/client-generator.service.ts","../src/utils/path-utils.ts","../src/utils/string-utils.ts","../src/services/route-analyzer.service.ts","../src/services/schema-generator.service.ts","../src/utils/schema-utils.ts","../src/utils/type-utils.ts"],"sourcesContent":["import fs from 'fs'\nimport type { Application, IPlugin } from 'honestjs'\nimport type { Hono } from 'hono'\nimport path from 'path'\n\nimport { DEFAULT_OPTIONS, LOG_PREFIX } from './constants/defaults'\nimport { ClientGeneratorService } from './services/client-generator.service'\nimport { RouteAnalyzerService } from './services/route-analyzer.service'\nimport { SchemaGeneratorService } from './services/schema-generator.service'\nimport type { ExtendedRouteInfo, GeneratedClientInfo, SchemaInfo } from './types'\n\n/**\n * Configuration options for the RPCPlugin\n */\nexport interface RPCPluginOptions {\n\treadonly controllerPattern?: string\n\treadonly tsConfigPath?: string\n\treadonly outputDir?: string\n\treadonly generateOnInit?: boolean\n}\n\n/**\n * Comprehensive RPC plugin that combines route analysis, schema generation, and client generation\n */\nexport class RPCPlugin implements IPlugin {\n\tprivate readonly controllerPattern: string\n\tprivate readonly tsConfigPath: string\n\tprivate readonly outputDir: string\n\tprivate readonly generateOnInit: boolean\n\n\t// Services\n\tprivate readonly routeAnalyzer: RouteAnalyzerService\n\tprivate readonly schemaGenerator: SchemaGeneratorService\n\tprivate readonly clientGenerator: ClientGeneratorService\n\n\t// Internal state\n\tprivate analyzedRoutes: ExtendedRouteInfo[] = []\n\tprivate analyzedSchemas: SchemaInfo[] = []\n\tprivate generatedInfo: GeneratedClientInfo | null = null\n\n\tconstructor(options: RPCPluginOptions = {}) {\n\t\tthis.controllerPattern = options.controllerPattern ?? DEFAULT_OPTIONS.controllerPattern\n\t\tthis.tsConfigPath = options.tsConfigPath ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.tsConfigPath)\n\t\tthis.outputDir = options.outputDir ?? path.resolve(process.cwd(), DEFAULT_OPTIONS.outputDir)\n\t\tthis.generateOnInit = options.generateOnInit ?? DEFAULT_OPTIONS.generateOnInit\n\n\t\t// Initialize services\n\t\tthis.routeAnalyzer = new RouteAnalyzerService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.schemaGenerator = new SchemaGeneratorService(this.controllerPattern, this.tsConfigPath)\n\t\tthis.clientGenerator = new ClientGeneratorService(this.outputDir)\n\n\t\tthis.validateConfiguration()\n\t}\n\n\t/**\n\t * Validates the plugin configuration\n\t */\n\tprivate validateConfiguration(): void {\n\t\tconst errors: string[] = []\n\n\t\tif (!this.controllerPattern?.trim()) {\n\t\t\terrors.push('Controller pattern cannot be empty')\n\t\t}\n\n\t\tif (!this.tsConfigPath?.trim()) {\n\t\t\terrors.push('TypeScript config path cannot be empty')\n\t\t} else {\n\t\t\tif (!fs.existsSync(this.tsConfigPath)) {\n\t\t\t\terrors.push(`TypeScript config file not found at: ${this.tsConfigPath}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!this.outputDir?.trim()) {\n\t\t\terrors.push('Output directory cannot be empty')\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Configuration validation failed: ${errors.join(', ')}`)\n\t\t}\n\n\t\tthis.log(\n\t\t\t`Configuration validated: controllerPattern=${this.controllerPattern}, tsConfigPath=${this.tsConfigPath}, outputDir=${this.outputDir}`\n\t\t)\n\t}\n\n\t/**\n\t * Called after all modules are registered\n\t */\n\tafterModulesRegistered = async (app: Application, hono: Hono): Promise<void> => {\n\t\tif (this.generateOnInit) {\n\t\t\tawait this.analyzeEverything()\n\t\t}\n\t}\n\n\t/**\n\t * Main analysis method that coordinates all three components\n\t */\n\tprivate async analyzeEverything(): Promise<void> {\n\t\ttry {\n\t\t\tthis.log('Starting comprehensive RPC analysis...')\n\n\t\t\t// Clear previous analysis results to prevent memory leaks\n\t\t\tthis.analyzedRoutes = []\n\t\t\tthis.analyzedSchemas = []\n\t\t\tthis.generatedInfo = null\n\n\t\t\t// Step 1: Analyze routes and extract type information\n\t\t\tthis.analyzedRoutes = await this.routeAnalyzer.analyzeControllerMethods()\n\n\t\t\t// Step 2: Generate schemas from the types we found\n\t\t\tthis.analyzedSchemas = await this.schemaGenerator.generateSchemas()\n\n\t\t\t// Step 3: Generate the RPC client\n\t\t\tthis.generatedInfo = await this.clientGenerator.generateClient(this.analyzedRoutes, this.analyzedSchemas)\n\n\t\t\tthis.log(\n\t\t\t\t`✅ RPC analysis complete: ${this.analyzedRoutes.length} routes, ${this.analyzedSchemas.length} schemas`\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tthis.logError('Error during RPC analysis:', error)\n\t\t\t// Ensure cleanup happens even on error\n\t\t\tthis.dispose()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Manually trigger analysis (useful for testing or re-generation)\n\t */\n\tasync analyze(): Promise<void> {\n\t\tawait this.analyzeEverything()\n\t}\n\n\t/**\n\t * Get the analyzed routes\n\t */\n\tgetRoutes(): readonly ExtendedRouteInfo[] {\n\t\treturn this.analyzedRoutes\n\t}\n\n\t/**\n\t * Get the analyzed schemas\n\t */\n\tgetSchemas(): readonly SchemaInfo[] {\n\t\treturn this.analyzedSchemas\n\t}\n\n\t/**\n\t * Get the generation info\n\t */\n\tgetGenerationInfo(): GeneratedClientInfo | null {\n\t\treturn this.generatedInfo\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.routeAnalyzer.dispose()\n\t\tthis.schemaGenerator.dispose()\n\t\tthis.log('Resources cleaned up')\n\t}\n\n\t// ============================================================================\n\t// LOGGING UTILITIES\n\t// ============================================================================\n\n\t/**\n\t * Logs a message with the plugin prefix\n\t */\n\tprivate log(message: string): void {\n\t\tconsole.log(`${LOG_PREFIX} ${message}`)\n\t}\n\n\t/**\n\t * Logs an error with the plugin prefix\n\t */\n\tprivate logError(message: string, error?: unknown): void {\n\t\tconsole.error(`${LOG_PREFIX} ${message}`, error || '')\n\t}\n}\n","/**\n * Default configuration options for the RPCPlugin\n */\nexport const DEFAULT_OPTIONS = {\n\tcontrollerPattern: 'src/modules/*/*.controller.ts',\n\ttsConfigPath: 'tsconfig.json',\n\toutputDir: './generated/rpc',\n\tgenerateOnInit: true\n} as const\n\n/**\n * Log prefix for the RPC plugin\n */\nexport const LOG_PREFIX = '[ RPCPlugin ]'\n\n/**\n * Built-in TypeScript types that should not be imported\n */\nexport const BUILTIN_UTILITY_TYPES = new Set([\n\t'Partial',\n\t'Required',\n\t'Readonly',\n\t'Pick',\n\t'Omit',\n\t'Record',\n\t'Exclude',\n\t'Extract',\n\t'ReturnType',\n\t'InstanceType'\n])\n\n/**\n * Built-in TypeScript types that should be skipped\n */\nexport const BUILTIN_TYPES = new Set(['string', 'number', 'boolean', 'any', 'void', 'unknown'])\n\n/**\n * Generic type names that should be unwrapped\n */\nexport const GENERIC_TYPES = new Set(['Array', 'Promise', 'Partial'])\n","import fs from 'fs/promises'\nimport path from 'path'\nimport type { ControllerGroups, ExtendedRouteInfo, RouteParameter } from '../types/route.types'\nimport type { GeneratedClientInfo, SchemaInfo } from '../types/schema.types'\nimport { buildFullApiPath } from '../utils/path-utils'\nimport { camelCase, safeToString } from '../utils/string-utils'\n\n/**\n * Service for generating TypeScript RPC clients\n */\nexport class ClientGeneratorService {\n\tconstructor(private readonly outputDir: string) {}\n\n\t/**\n\t * Generates the TypeScript RPC client\n\t */\n\tasync generateClient(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<GeneratedClientInfo> {\n\t\tawait fs.mkdir(this.outputDir, { recursive: true })\n\n\t\tawait this.generateClientFile(routes, schemas)\n\n\t\tconst generatedInfo: GeneratedClientInfo = {\n\t\t\tclientFile: path.join(this.outputDir, 'client.ts'),\n\t\t\tgeneratedAt: new Date().toISOString()\n\t\t}\n\n\t\treturn generatedInfo\n\t}\n\n\t/**\n\t * Generates the main client file with types included\n\t */\n\tprivate async generateClientFile(\n\t\troutes: readonly ExtendedRouteInfo[],\n\t\tschemas: readonly SchemaInfo[]\n\t): Promise<void> {\n\t\tconst clientContent = this.generateClientContent(routes, schemas)\n\t\tconst clientPath = path.join(this.outputDir, 'client.ts')\n\t\tawait fs.writeFile(clientPath, clientContent, 'utf-8')\n\t}\n\n\t/**\n\t * Generates the client TypeScript content with types included\n\t */\n\tprivate generateClientContent(routes: readonly ExtendedRouteInfo[], schemas: readonly SchemaInfo[]): string {\n\t\tconst controllerGroups = this.groupRoutesByController(routes)\n\n\t\treturn `// ============================================================================\n// TYPES SECTION\n// ============================================================================\n\n/**\n * API Response wrapper\n */\nexport interface ApiResponse<T = any> {\n\tdata: T\n\tmessage?: string\n\tsuccess: boolean\n}\n\n/**\n * API Error class\n */\nexport class ApiError extends Error {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tmessage: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'ApiError'\n\t}\n}\n\n/**\n * Clean separation of concerns for request options\n */\nexport type RequestOptions<\n\tTParams = undefined,\n\tTQuery = undefined,\n\tTBody = undefined,\n\tTHeaders = undefined\n> = (TParams extends undefined ? object : { params: TParams }) &\n\t(TQuery extends undefined ? object : { query: TQuery }) &\n\t(TBody extends undefined ? object : { body: TBody }) &\n\t(THeaders extends undefined ? object : { headers: THeaders })\n\n// Generated DTOs and types from integrated Schema Generation\n${this.generateSchemaTypes(schemas)}\n\n// ============================================================================\n// CLIENT SECTION\n// ============================================================================\n\n/**\n * Generated RPC Client\n * \n * This class provides a type-safe HTTP client for interacting with your API endpoints.\n * It's automatically generated by the RPCPlugin based on your controller definitions.\n * \n * @example\n * \\`\\`\\`typescript\n * const apiClient = new ApiClient('http://localhost:3000')\n * \n * // Make a request to get users\n * const response = await apiClient.users.getUsers()\n * \n * // Make a request with parameters\n * const user = await apiClient.users.getUser({ params: { id: '123' } })\n * \n * // Make a request with body data\n * const newUser = await apiClient.users.createUser({ \n * body: { name: 'John', email: 'john@example.com' } \n * })\n * \\`\\`\\`\n * \n * @generated This class is auto-generated by RPCPlugin\n */\nexport class ApiClient {\n\tprivate baseUrl: string\n\tprivate defaultHeaders: Record<string, string>\n\n\tconstructor(baseUrl: string, defaultHeaders: Record<string, string> = {}) {\n\t\tthis.baseUrl = baseUrl.replace(/\\\\/$/, '')\n\t\tthis.defaultHeaders = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...defaultHeaders\n\t\t}\n\t}\n\n\t/**\n\t * Set default headers for all requests\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): this {\n\t\tthis.defaultHeaders = { ...this.defaultHeaders, ...headers }\n\t\treturn this\n\t}\n\n\t/**\n\t * Set default authorization header\n\t */\n\tsetDefaultAuth(token: string): this {\n\t\tthis.defaultHeaders.Authorization = \\`Bearer \\${token}\\`\n\t\treturn this\n\t}\n\n\t/**\n\t * Make an HTTP request with flexible options\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions: RequestOptions<any, any, any, any> = {}\n\t): Promise<ApiResponse<T>> {\n\t\tconst { params, query, body, headers = {} } = options as any\n\t\t\n\t\t// Build the final URL with path parameters\n\t\tlet finalPath = path\n\t\tif (params) {\n\t\t\tObject.entries(params).forEach(([key, value]) => {\n\t\t\t\tfinalPath = finalPath.replace(\\`:\\${key}\\`, String(value))\n\t\t\t})\n\t\t}\n\n\t\tconst url = new URL(finalPath, this.baseUrl)\n\t\t\n\t\t// Add query parameters\n\t\tif (query) {\n\t\t\tObject.entries(query).forEach(([key, value]) => {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.append(key, String(value))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// Merge default headers with request-specific headers\n\t\tconst finalHeaders = { ...this.defaultHeaders, ...headers }\n\n\t\tconst requestOptions: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders: finalHeaders,\n\t\t}\n\n\t\tif (body && method !== 'GET') {\n\t\t\trequestOptions.body = JSON.stringify(body)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(url.toString(), requestOptions)\n\t\t\tconst responseData = await response.json()\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ApiError(response.status, responseData.message || 'Request failed')\n\t\t\t}\n\n\t\t\treturn responseData\n\t\t} catch (error) {\n\t\t\tif (error instanceof ApiError) {\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow new ApiError(0, error instanceof Error ? error.message : 'Network error')\n\t\t}\n\t}\n\n${this.generateControllerMethods(controllerGroups)}\n}\n`\n\t}\n\n\t/**\n\t * Generates controller methods for the client\n\t */\n\tprivate generateControllerMethods(controllerGroups: ControllerGroups): string {\n\t\tlet methods = ''\n\n\t\tfor (const [controllerName, routes] of controllerGroups) {\n\t\t\tconst className = controllerName.replace(/Controller$/, '')\n\t\t\tmethods += `\n\t// ${className} Controller\n`\n\t\t\tmethods += `\tget ${camelCase(className)}() {\n`\n\t\t\tmethods += `\t\treturn {\n`\n\n\t\t\tfor (const route of routes) {\n\t\t\t\tconst methodName = camelCase(safeToString(route.handler))\n\t\t\t\tconst httpMethod = safeToString(route.method).toLowerCase()\n\t\t\t\tconst { pathParams, queryParams, bodyParams } = this.analyzeRouteParameters(route)\n\n\t\t\t\tconst hasRequiredParams =\n\t\t\t\t\tpathParams.length > 0 ||\n\t\t\t\t\tqueryParams.some((p) => p.required) ||\n\t\t\t\t\t(bodyParams.length > 0 && httpMethod !== 'get')\n\n\t\t\t\t// Generate the method signature with proper typing\n\t\t\t\tmethods += `\t\t\t${methodName}: async (options${hasRequiredParams ? '' : '?'}: RequestOptions<`\n\n\t\t\t\t// Path parameters type\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tconst pathParamTypes = pathParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${pathParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Query parameters type\n\t\t\t\tif (queryParams.length > 0) {\n\t\t\t\t\tconst queryParamTypes = queryParams.map((p) => {\n\t\t\t\t\t\tconst paramName = p.name\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn `${paramName}: ${paramType}`\n\t\t\t\t\t})\n\t\t\t\t\tmethods += `{ ${queryParamTypes.join(', ')} }`\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Body type\n\t\t\t\tif (bodyParams.length > 0) {\n\t\t\t\t\tconst bodyParamTypes = bodyParams.map((p) => {\n\t\t\t\t\t\tconst paramType = p.type || 'any'\n\t\t\t\t\t\treturn paramType\n\t\t\t\t\t})\n\t\t\t\t\t// Use the first body parameter type, not 'any'\n\t\t\t\t\tmethods += bodyParamTypes[0] || 'any'\n\t\t\t\t} else {\n\t\t\t\t\tmethods += 'undefined'\n\t\t\t\t}\n\n\t\t\t\tmethods += ', '\n\n\t\t\t\t// Headers type - always optional for now, but could be made conditional\n\t\t\t\tmethods += 'undefined'\n\n\t\t\t\t// Extract return type from route analysis for better type safety\n\t\t\t\tconst returnType = this.extractReturnType(route.returns)\n\t\t\t\tmethods += `>): Promise<ApiResponse<${returnType}>> => {\n`\n\n\t\t\t\t// Build the full API path using route information\n\t\t\t\tlet requestPath = buildFullApiPath(route)\n\n\t\t\t\t// Replace path parameters with placeholders for dynamic substitution\n\t\t\t\tif (pathParams.length > 0) {\n\t\t\t\t\tfor (const pathParam of pathParams) {\n\t\t\t\t\t\tconst paramName = pathParam.name\n\t\t\t\t\t\tconst placeholder = `:${String(pathParam.data)}`\n\t\t\t\t\t\trequestPath = requestPath.replace(placeholder, `:${paramName}`)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmethods += `\t\t\t\treturn this.request<${returnType}>('${httpMethod.toUpperCase()}', \\`${requestPath}\\`, options)\n`\n\t\t\t\tmethods += `\t\t\t},\n`\n\t\t\t}\n\n\t\t\tmethods += `\t\t}\n`\n\t\t\tmethods += `\t}\n`\n\t\t}\n\n\t\treturn methods\n\t}\n\n\t/**\n\t * Extracts the proper return type from route analysis\n\t */\n\tprivate extractReturnType(returns?: string): string {\n\t\tif (!returns) return 'any'\n\n\t\t// Handle Promise<T> types\n\t\tconst promiseMatch = returns.match(/Promise<(.+)>/)\n\t\tif (promiseMatch) {\n\t\t\treturn promiseMatch[1]\n\t\t}\n\n\t\t// Handle other types\n\t\treturn returns\n\t}\n\n\t/**\n\t * Generates schema types from integrated schema generation\n\t */\n\tprivate generateSchemaTypes(schemas: readonly SchemaInfo[]): string {\n\t\tif (schemas.length === 0) {\n\t\t\treturn '// No schemas available from integrated Schema Generation\\n'\n\t\t}\n\n\t\tlet content = '// Schema types from integrated Schema Generation\\n'\n\t\tfor (const schemaInfo of schemas) {\n\t\t\tif (schemaInfo.typescriptType) {\n\t\t\t\tcontent += `${schemaInfo.typescriptType}\\n\\n`\n\t\t\t}\n\t\t}\n\t\treturn content\n\t}\n\n\t/**\n\t * Groups routes by controller for better organization\n\t */\n\tprivate groupRoutesByController(routes: readonly ExtendedRouteInfo[]): ControllerGroups {\n\t\tconst groups = new Map<string, ExtendedRouteInfo[]>()\n\n\t\tfor (const route of routes) {\n\t\t\tconst controller = safeToString(route.controller)\n\t\t\tif (!groups.has(controller)) {\n\t\t\t\tgroups.set(controller, [])\n\t\t\t}\n\t\t\tgroups.get(controller)!.push(route)\n\t\t}\n\n\t\treturn groups\n\t}\n\n\t/**\n\t * Analyzes route parameters to determine their types and usage\n\t */\n\tprivate analyzeRouteParameters(route: ExtendedRouteInfo): {\n\t\tpathParams: readonly RouteParameter[]\n\t\tqueryParams: readonly RouteParameter[]\n\t\tbodyParams: readonly RouteParameter[]\n\t} {\n\t\tconst parameters = route.parameters || []\n\t\tconst method = String(route.method || '').toLowerCase()\n\n\t\tconst isInPath = (p: RouteParameter): boolean => {\n\t\t\t// Check if this parameter corresponds to a path segment\n\t\t\t// For path parameters, the data field should contain the path segment name\n\t\t\tconst pathSegment = p.data\n\t\t\treturn !!pathSegment && typeof pathSegment === 'string' && route.path.includes(`:${pathSegment}`)\n\t\t}\n\n\t\t// path params are always required if they exist in the path\n\t\tconst pathParams = parameters.filter((p) => isInPath(p)).map((p) => ({ ...p, required: true }))\n\n\t\t// body is required if any body param exists for non-GET\n\t\tconst rawBody = parameters.filter((p) => !isInPath(p) && method !== 'get')\n\t\tconst bodyParams = rawBody.map((p) => ({\n\t\t\t...p,\n\t\t\trequired: true\n\t\t}))\n\n\t\t// query requiredness comes from analyzer if available; default optional\n\t\tconst queryParams = parameters\n\t\t\t.filter((p) => !isInPath(p) && method === 'get')\n\t\t\t.map((p) => ({\n\t\t\t\t...p,\n\t\t\t\trequired: p.required === true // default false if not provided\n\t\t\t}))\n\n\t\treturn { pathParams, queryParams, bodyParams }\n\t}\n}\n","import type { ParameterMetadata } from 'honestjs'\nimport type { ExtendedRouteInfo } from '../types/route.types'\n\n/**\n * Builds the full path with parameter placeholders\n */\nexport function buildFullPath(basePath: string, parameters: readonly ParameterMetadata[]): string {\n\tif (!basePath || typeof basePath !== 'string') return '/'\n\n\tlet path = basePath\n\n\tif (parameters && Array.isArray(parameters)) {\n\t\tfor (const param of parameters) {\n\t\t\tif (param.data && typeof param.data === 'string' && param.data.startsWith(':')) {\n\t\t\t\tconst paramName = param.data.slice(1)\n\t\t\t\tpath = path.replace(`:${paramName}`, `\\${${paramName}}`)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn path\n}\n\n/**\n * Builds the full API path using route information\n */\nexport function buildFullApiPath(route: ExtendedRouteInfo): string {\n\tconst prefix = route.prefix || ''\n\tconst version = route.version || ''\n\tconst routePath = route.route || ''\n\tconst path = route.path || ''\n\n\tlet fullPath = ''\n\n\t// Add prefix (e.g., /api)\n\tif (prefix && prefix !== '/') {\n\t\tfullPath += prefix.replace(/^\\/+|\\/+$/g, '')\n\t}\n\n\t// Add version (e.g., /v1)\n\tif (version && version !== '/') {\n\t\tfullPath += `/${version.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add route (e.g., /users)\n\tif (routePath && routePath !== '/') {\n\t\tfullPath += `/${routePath.replace(/^\\/+|\\/+$/g, '')}`\n\t}\n\n\t// Add path (e.g., /:id or /)\n\tif (path && path !== '/') {\n\t\tfullPath += `/${path.replace(/^\\/+|\\/+$/g, '')}`\n\t} else if (path === '/') {\n\t\tfullPath += '/'\n\t}\n\n\treturn fullPath || '/'\n}\n","/**\n * Safely converts a value to string, handling symbols and other types\n */\nexport function safeToString(value: unknown): string {\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'symbol') return value.description || 'Symbol'\n\treturn String(value)\n}\n\n/**\n * Converts a string to camelCase\n */\nexport function camelCase(str: string): string {\n\treturn str.charAt(0).toLowerCase() + str.slice(1)\n}\n","import { RouteRegistry, type ParameterMetadata, type RouteInfo } from 'honestjs'\nimport { ClassDeclaration, MethodDeclaration, Project } from 'ts-morph'\nimport type { ExtendedRouteInfo, ParameterMetadataWithType } from '../types/route.types'\nimport { buildFullPath } from '../utils/path-utils'\nimport { safeToString } from '../utils/string-utils'\n\n/**\n * Service for analyzing controller methods and extracting type information\n */\nexport class RouteAnalyzerService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Analyzes controller methods to extract type information\n\t */\n\tasync analyzeControllerMethods(): Promise<ExtendedRouteInfo[]> {\n\t\tconst routes = RouteRegistry.getRoutes()\n\t\tif (!routes?.length) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst project = this.createProject()\n\t\tconst controllers = this.findControllerClasses(project)\n\n\t\tif (controllers.size === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn this.processRoutes(routes, controllers)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Finds controller classes in the project\n\t */\n\tprivate findControllerClasses(project: Project): Map<string, ClassDeclaration> {\n\t\tconst controllers = new Map<string, ClassDeclaration>()\n\t\tconst files = project.getSourceFiles()\n\n\t\tfor (const sourceFile of files) {\n\t\t\tconst classes = sourceFile.getClasses()\n\n\t\t\tfor (const classDeclaration of classes) {\n\t\t\t\tconst className = classDeclaration.getName()\n\n\t\t\t\tif (className?.endsWith('Controller')) {\n\t\t\t\t\tcontrollers.set(className, classDeclaration)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn controllers\n\t}\n\n\t/**\n\t * Processes all routes and extracts type information\n\t */\n\tprivate processRoutes(\n\t\troutes: readonly RouteInfo[],\n\t\tcontrollers: Map<string, ClassDeclaration>\n\t): ExtendedRouteInfo[] {\n\t\tconst analyzedRoutes: ExtendedRouteInfo[] = []\n\t\tconst errors: Error[] = []\n\n\t\tfor (const route of routes) {\n\t\t\ttry {\n\t\t\t\tconst extendedRoute = this.createExtendedRoute(route, controllers)\n\t\t\t\tanalyzedRoutes.push(extendedRoute)\n\t\t\t} catch (routeError) {\n\t\t\t\tconst error = routeError instanceof Error ? routeError : new Error(String(routeError))\n\t\t\t\terrors.push(error)\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error processing route ${safeToString(route.controller)}.${safeToString(route.handler)}:`,\n\t\t\t\t\trouteError\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// If there were any errors, throw a comprehensive error\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(`Failed to process ${errors.length} routes: ${errors.map((e) => e.message).join(', ')}`)\n\t\t}\n\n\t\treturn analyzedRoutes\n\t}\n\n\t/**\n\t * Creates an extended route with type information\n\t */\n\tprivate createExtendedRoute(route: RouteInfo, controllers: Map<string, ClassDeclaration>): ExtendedRouteInfo {\n\t\tconst controllerName = safeToString(route.controller)\n\t\tconst handlerName = safeToString(route.handler)\n\n\t\tconst controllerClass = controllers.get(controllerName)\n\t\tlet returns: string | undefined\n\t\tlet parameters: readonly ParameterMetadataWithType[] | undefined\n\n\t\tif (controllerClass) {\n\t\t\tconst handlerMethod = controllerClass.getMethods().find((method) => method.getName() === handlerName)\n\n\t\t\tif (handlerMethod) {\n\t\t\t\treturns = this.getReturnType(handlerMethod)\n\t\t\t\tparameters = this.getParametersWithTypes(handlerMethod, route.parameters || [])\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcontroller: controllerName,\n\t\t\thandler: handlerName,\n\t\t\tmethod: safeToString(route.method).toUpperCase(),\n\t\t\tprefix: route.prefix,\n\t\t\tversion: route.version,\n\t\t\troute: route.route,\n\t\t\tpath: route.path,\n\t\t\tfullPath: buildFullPath(route.path, route.parameters),\n\t\t\tparameters,\n\t\t\treturns\n\t\t}\n\t}\n\n\t/**\n\t * Gets the return type of a method\n\t */\n\tprivate getReturnType(method: MethodDeclaration): string {\n\t\tconst type = method.getReturnType()\n\t\tconst typeText = type.getText(method)\n\n\t\tconst aliasSymbol = type.getAliasSymbol()\n\t\tif (aliasSymbol) {\n\t\t\treturn aliasSymbol.getName()\n\t\t}\n\n\t\treturn typeText.replace(/import\\(\".*?\"\\)\\./g, '')\n\t}\n\n\t/**\n\t * Gets parameters with their types\n\t */\n\tprivate getParametersWithTypes(\n\t\tmethod: MethodDeclaration,\n\t\tparameters: readonly ParameterMetadata[]\n\t): readonly ParameterMetadataWithType[] {\n\t\tconst result: ParameterMetadataWithType[] = []\n\t\tconst declaredParams = method.getParameters()\n\t\tconst sortedParams = [...parameters].sort((a, b) => a.index - b.index)\n\n\t\tfor (const param of sortedParams) {\n\t\t\tconst index = param.index\n\n\t\t\tif (index < declaredParams.length) {\n\t\t\t\tconst declaredParam = declaredParams[index]\n\t\t\t\tconst paramName = declaredParam.getName()\n\t\t\t\tconst paramType = declaredParam\n\t\t\t\t\t.getType()\n\t\t\t\t\t.getText()\n\t\t\t\t\t.replace(/import\\(\".*?\"\\)\\./g, '')\n\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: paramName,\n\t\t\t\t\ttype: paramType,\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tresult.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tname: `param${index}`,\n\t\t\t\t\ttype: param.metatype?.name || 'unknown',\n\t\t\t\t\trequired: true,\n\t\t\t\t\tdata: param.data,\n\t\t\t\t\tfactory: param.factory,\n\t\t\t\t\tmetatype: param.metatype\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n","import { createGenerator } from 'ts-json-schema-generator'\nimport { MethodDeclaration, Project } from 'ts-morph'\nimport type { SchemaInfo } from '../types/schema.types'\nimport { generateTypeScriptInterface } from '../utils/schema-utils'\nimport { extractNamedType } from '../utils/type-utils'\n\n/**\n * Service for generating JSON schemas from TypeScript types used in controllers\n */\nexport class SchemaGeneratorService {\n\tconstructor(\n\t\tprivate readonly controllerPattern: string,\n\t\tprivate readonly tsConfigPath: string\n\t) {}\n\n\t// Track projects for cleanup\n\tprivate projects: Project[] = []\n\n\t/**\n\t * Generates JSON schemas from types used in controllers\n\t */\n\tasync generateSchemas(): Promise<SchemaInfo[]> {\n\t\tconst project = this.createProject()\n\t\tconst sourceFiles = project.getSourceFiles(this.controllerPattern)\n\n\t\tconst collectedTypes = this.collectTypesFromControllers(sourceFiles)\n\t\treturn this.processTypes(collectedTypes)\n\t}\n\n\t/**\n\t * Creates a new ts-morph project\n\t */\n\tprivate createProject(): Project {\n\t\tconst project = new Project({\n\t\t\ttsConfigFilePath: this.tsConfigPath\n\t\t})\n\n\t\tproject.addSourceFilesAtPaths([this.controllerPattern])\n\t\tthis.projects.push(project)\n\t\treturn project\n\t}\n\n\t/**\n\t * Cleanup resources to prevent memory leaks\n\t */\n\tdispose(): void {\n\t\tthis.projects.forEach((project) => {\n\t\t\t// Remove all source files to free memory\n\t\t\tproject.getSourceFiles().forEach((file) => project.removeSourceFile(file))\n\t\t})\n\t\tthis.projects = []\n\t}\n\n\t/**\n\t * Collects types from controller files\n\t */\n\tprivate collectTypesFromControllers(sourceFiles: readonly any[]): Set<string> {\n\t\tconst collectedTypes = new Set<string>()\n\n\t\tfor (const file of sourceFiles) {\n\t\t\tfor (const cls of file.getClasses()) {\n\t\t\t\tfor (const method of cls.getMethods()) {\n\t\t\t\t\tthis.collectTypesFromMethod(method, collectedTypes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn collectedTypes\n\t}\n\n\t/**\n\t * Collects types from a single method\n\t */\n\tprivate collectTypesFromMethod(method: MethodDeclaration, collectedTypes: Set<string>): void {\n\t\t// Collect parameter types\n\t\tfor (const param of method.getParameters()) {\n\t\t\tconst type = extractNamedType(param.getType())\n\t\t\tif (type) collectedTypes.add(type)\n\t\t}\n\n\t\t// Collect return type\n\t\tconst returnType = method.getReturnType()\n\t\tconst innerType = returnType.getTypeArguments()[0] ?? returnType\n\t\tconst type = extractNamedType(innerType)\n\t\tif (type) collectedTypes.add(type)\n\t}\n\n\t/**\n\t * Processes collected types to generate schemas\n\t */\n\tprivate async processTypes(collectedTypes: Set<string>): Promise<SchemaInfo[]> {\n\t\tconst schemas: SchemaInfo[] = []\n\n\t\tfor (const typeName of collectedTypes) {\n\t\t\ttry {\n\t\t\t\tconst schema = await this.generateSchemaForType(typeName)\n\t\t\t\tconst typescriptType = generateTypeScriptInterface(typeName, schema)\n\n\t\t\t\tschemas.push({\n\t\t\t\t\ttype: typeName,\n\t\t\t\t\tschema,\n\t\t\t\t\ttypescriptType\n\t\t\t\t})\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`Failed to generate schema for ${typeName}:`, err)\n\t\t\t}\n\t\t}\n\n\t\treturn schemas\n\t}\n\n\t/**\n\t * Generates schema for a specific type\n\t */\n\tprivate async generateSchemaForType(typeName: string): Promise<Record<string, any>> {\n\t\ttry {\n\t\t\tconst generator = createGenerator({\n\t\t\t\tpath: this.controllerPattern,\n\t\t\t\ttsconfig: this.tsConfigPath,\n\t\t\t\ttype: typeName,\n\t\t\t\tskipTypeCheck: false // Enable type checking for better error detection\n\t\t\t})\n\n\t\t\treturn generator.createSchema(typeName)\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to generate schema for type ${typeName}:`, error)\n\t\t\t// Return a basic schema structure as fallback\n\t\t\treturn {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {},\n\t\t\t\trequired: []\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * Maps JSON schema types to TypeScript types\n */\nexport function mapJsonSchemaTypeToTypeScript(schema: Record<string, any>): string {\n\tconst type = schema.type as string\n\n\tswitch (type) {\n\t\tcase 'string':\n\t\t\tif (schema.enum && Array.isArray(schema.enum)) {\n\t\t\t\treturn `'${schema.enum.join(\"' | '\")}'`\n\t\t\t}\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\tcase 'integer':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'array': {\n\t\t\tconst itemType = mapJsonSchemaTypeToTypeScript(schema.items || {})\n\t\t\treturn `${itemType}[]`\n\t\t}\n\t\tcase 'object':\n\t\t\treturn 'Record<string, any>'\n\t\tdefault:\n\t\t\treturn 'any'\n\t}\n}\n\n/**\n * Generates TypeScript interface from JSON schema\n */\nexport function generateTypeScriptInterface(typeName: string, schema: Record<string, any>): string {\n\ttry {\n\t\tconst typeDefinition = schema.definitions?.[typeName]\n\t\tif (!typeDefinition) {\n\t\t\treturn `export interface ${typeName} {\\n\\t// No schema definition found\\n}`\n\t\t}\n\n\t\tconst properties = typeDefinition.properties || {}\n\t\tconst required = typeDefinition.required || []\n\n\t\tlet interfaceCode = `export interface ${typeName} {\\n`\n\n\t\tfor (const [propName, propSchema] of Object.entries(properties)) {\n\t\t\tconst isRequired = required.includes(propName)\n\t\t\tconst type = mapJsonSchemaTypeToTypeScript(propSchema as Record<string, any>)\n\t\t\tconst optional = isRequired ? '' : '?'\n\n\t\t\tinterfaceCode += `\\t${propName}${optional}: ${type}\\n`\n\t\t}\n\n\t\tinterfaceCode += '}'\n\t\treturn interfaceCode\n\t} catch (error) {\n\t\tconsole.error(`Failed to generate TypeScript interface for ${typeName}:`, error)\n\t\treturn `export interface ${typeName} {\\n\\t// Failed to generate interface\\n}`\n\t}\n}\n","import type { Type } from 'ts-morph'\nimport { BUILTIN_TYPES, BUILTIN_UTILITY_TYPES, GENERIC_TYPES } from '../constants/defaults'\n\n/**\n * Extracts a named type from a TypeScript type\n */\nexport function extractNamedType(type: Type): string | null {\n\tconst symbol = type.getAliasSymbol() || type.getSymbol()\n\tif (!symbol) return null\n\n\tconst name = symbol.getName()\n\n\t// Handle generic types by unwrapping them\n\tif (GENERIC_TYPES.has(name)) {\n\t\tconst inner = type.getAliasTypeArguments()?.[0] || type.getTypeArguments()?.[0]\n\t\treturn inner ? extractNamedType(inner) : null\n\t}\n\n\t// Skip built-in types\n\tif (BUILTIN_TYPES.has(name)) return null\n\n\treturn name\n}\n\n/**\n * Generates type imports for the client\n */\nexport function generateTypeImports(routes: readonly any[]): string {\n\tconst types = new Set<string>()\n\n\tfor (const route of routes) {\n\t\t// Collect parameter types\n\t\tif (route.parameters) {\n\t\t\tfor (const param of route.parameters) {\n\t\t\t\tif (param.type && !['string', 'number', 'boolean'].includes(param.type)) {\n\t\t\t\t\t// Extract type name from complex types like Partial<CreateUserDto> or User[]\n\t\t\t\t\tconst typeMatch = param.type.match(/(\\w+)(?:<.*>)?/)\n\t\t\t\t\tif (typeMatch) {\n\t\t\t\t\t\tconst typeName = typeMatch[1]\n\t\t\t\t\t\t// Don't import built-in TypeScript utility types\n\t\t\t\t\t\tif (!BUILTIN_UTILITY_TYPES.has(typeName)) {\n\t\t\t\t\t\t\ttypes.add(typeName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Collect return types\n\t\tif (route.returns) {\n\t\t\tconst returnType = route.returns.replace(/Promise<(.+)>/, '$1')\n\t\t\t// Extract base type name from array types (e.g., 'User[]' -> 'User')\n\t\t\tconst baseType = returnType.replace(/\\[\\]$/, '')\n\t\t\tif (!['string', 'number', 'boolean', 'any', 'void', 'unknown'].includes(baseType)) {\n\t\t\t\ttypes.add(baseType)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Array.from(types).join(', ')\n}\n"],"mappings":";AAAA,OAAOA,SAAQ;AAGf,OAAOC,WAAU;;;ACAV,IAAM,kBAAkB;AAAA,EAC9B,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,WAAW;AAAA,EACX,gBAAgB;AACjB;AAKO,IAAM,aAAa;AAKnB,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAKM,IAAM,gBAAgB,oBAAI,IAAI,CAAC,UAAU,UAAU,WAAW,OAAO,QAAQ,SAAS,CAAC;AAKvF,IAAM,gBAAgB,oBAAI,IAAI,CAAC,SAAS,WAAW,SAAS,CAAC;;;ACvCpE,OAAO,QAAQ;AACf,OAAO,UAAU;;;ACKV,SAAS,cAAc,UAAkB,YAAkD;AACjG,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,QAAO;AAEtD,MAAIC,QAAO;AAEX,MAAI,cAAc,MAAM,QAAQ,UAAU,GAAG;AAC5C,eAAW,SAAS,YAAY;AAC/B,UAAI,MAAM,QAAQ,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,WAAW,GAAG,GAAG;AAC/E,cAAM,YAAY,MAAM,KAAK,MAAM,CAAC;AACpC,QAAAA,QAAOA,MAAK,QAAQ,IAAI,SAAS,IAAI,MAAM,SAAS,GAAG;AAAA,MACxD;AAAA,IACD;AAAA,EACD;AAEA,SAAOA;AACR;AAKO,SAAS,iBAAiB,OAAkC;AAClE,QAAM,SAAS,MAAM,UAAU;AAC/B,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,YAAY,MAAM,SAAS;AACjC,QAAMA,QAAO,MAAM,QAAQ;AAE3B,MAAI,WAAW;AAGf,MAAI,UAAU,WAAW,KAAK;AAC7B,gBAAY,OAAO,QAAQ,cAAc,EAAE;AAAA,EAC5C;AAGA,MAAI,WAAW,YAAY,KAAK;AAC/B,gBAAY,IAAI,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAAA,EAClD;AAGA,MAAI,aAAa,cAAc,KAAK;AACnC,gBAAY,IAAI,UAAU,QAAQ,cAAc,EAAE,CAAC;AAAA,EACpD;AAGA,MAAIA,SAAQA,UAAS,KAAK;AACzB,gBAAY,IAAIA,MAAK,QAAQ,cAAc,EAAE,CAAC;AAAA,EAC/C,WAAWA,UAAS,KAAK;AACxB,gBAAY;AAAA,EACb;AAEA,SAAO,YAAY;AACpB;;;ACtDO,SAAS,aAAa,OAAwB;AACpD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,eAAe;AAC3D,SAAO,OAAO,KAAK;AACpB;AAKO,SAAS,UAAU,KAAqB;AAC9C,SAAO,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC;AACjD;;;AFJO,IAAM,yBAAN,MAA6B;AAAA,EACnC,YAA6B,WAAmB;AAAnB;AAAA,EAAoB;AAAA;AAAA;AAAA;AAAA,EAKjD,MAAM,eACL,QACA,SAC+B;AAC/B,UAAM,GAAG,MAAM,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAElD,UAAM,KAAK,mBAAmB,QAAQ,OAAO;AAE7C,UAAM,gBAAqC;AAAA,MAC1C,YAAY,KAAK,KAAK,KAAK,WAAW,WAAW;AAAA,MACjD,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBACb,QACA,SACgB;AAChB,UAAM,gBAAgB,KAAK,sBAAsB,QAAQ,OAAO;AAChE,UAAM,aAAa,KAAK,KAAK,KAAK,WAAW,WAAW;AACxD,UAAM,GAAG,UAAU,YAAY,eAAe,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,QAAsC,SAAwC;AAC3G,UAAM,mBAAmB,KAAK,wBAAwB,MAAM;AAE5D,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwCP,KAAK,oBAAoB,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoHjC,KAAK,0BAA0B,gBAAgB,CAAC;AAAA;AAAA;AAAA,EAGjD;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,kBAA4C;AAC7E,QAAI,UAAU;AAEd,eAAW,CAAC,gBAAgB,MAAM,KAAK,kBAAkB;AACxD,YAAM,YAAY,eAAe,QAAQ,eAAe,EAAE;AAC1D,iBAAW;AAAA,MACR,SAAS;AAAA;AAEZ,iBAAW,QAAQ,UAAU,SAAS,CAAC;AAAA;AAEvC,iBAAW;AAAA;AAGX,iBAAW,SAAS,QAAQ;AAC3B,cAAM,aAAa,UAAU,aAAa,MAAM,OAAO,CAAC;AACxD,cAAM,aAAa,aAAa,MAAM,MAAM,EAAE,YAAY;AAC1D,cAAM,EAAE,YAAY,aAAa,WAAW,IAAI,KAAK,uBAAuB,KAAK;AAEjF,cAAM,oBACL,WAAW,SAAS,KACpB,YAAY,KAAK,CAAC,MAAM,EAAE,QAAQ,KACjC,WAAW,SAAS,KAAK,eAAe;AAG1C,mBAAW,MAAM,UAAU,mBAAmB,oBAAoB,KAAK,GAAG;AAG1E,YAAI,WAAW,SAAS,GAAG;AAC1B,gBAAM,iBAAiB,WAAW,IAAI,CAAC,MAAM;AAC5C,kBAAM,YAAY,EAAE;AACpB,kBAAM,YAAY,EAAE,QAAQ;AAC5B,mBAAO,GAAG,SAAS,KAAK,SAAS;AAAA,UAClC,CAAC;AACD,qBAAW,KAAK,eAAe,KAAK,IAAI,CAAC;AAAA,QAC1C,OAAO;AACN,qBAAW;AAAA,QACZ;AAEA,mBAAW;AAGX,YAAI,YAAY,SAAS,GAAG;AAC3B,gBAAM,kBAAkB,YAAY,IAAI,CAAC,MAAM;AAC9C,kBAAM,YAAY,EAAE;AACpB,kBAAM,YAAY,EAAE,QAAQ;AAC5B,mBAAO,GAAG,SAAS,KAAK,SAAS;AAAA,UAClC,CAAC;AACD,qBAAW,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAAA,QAC3C,OAAO;AACN,qBAAW;AAAA,QACZ;AAEA,mBAAW;AAGX,YAAI,WAAW,SAAS,GAAG;AAC1B,gBAAM,iBAAiB,WAAW,IAAI,CAAC,MAAM;AAC5C,kBAAM,YAAY,EAAE,QAAQ;AAC5B,mBAAO;AAAA,UACR,CAAC;AAED,qBAAW,eAAe,CAAC,KAAK;AAAA,QACjC,OAAO;AACN,qBAAW;AAAA,QACZ;AAEA,mBAAW;AAGX,mBAAW;AAGX,cAAM,aAAa,KAAK,kBAAkB,MAAM,OAAO;AACvD,mBAAW,2BAA2B,UAAU;AAAA;AAIhD,YAAI,cAAc,iBAAiB,KAAK;AAGxC,YAAI,WAAW,SAAS,GAAG;AAC1B,qBAAW,aAAa,YAAY;AACnC,kBAAM,YAAY,UAAU;AAC5B,kBAAM,cAAc,IAAI,OAAO,UAAU,IAAI,CAAC;AAC9C,0BAAc,YAAY,QAAQ,aAAa,IAAI,SAAS,EAAE;AAAA,UAC/D;AAAA,QACD;AAEA,mBAAW,2BAA2B,UAAU,MAAM,WAAW,YAAY,CAAC,QAAQ,WAAW;AAAA;AAEjG,mBAAW;AAAA;AAAA,MAEZ;AAEA,iBAAW;AAAA;AAEX,iBAAW;AAAA;AAAA,IAEZ;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,SAA0B;AACnD,QAAI,CAAC,QAAS,QAAO;AAGrB,UAAM,eAAe,QAAQ,MAAM,eAAe;AAClD,QAAI,cAAc;AACjB,aAAO,aAAa,CAAC;AAAA,IACtB;AAGA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,SAAwC;AACnE,QAAI,QAAQ,WAAW,GAAG;AACzB,aAAO;AAAA,IACR;AAEA,QAAI,UAAU;AACd,eAAW,cAAc,SAAS;AACjC,UAAI,WAAW,gBAAgB;AAC9B,mBAAW,GAAG,WAAW,cAAc;AAAA;AAAA;AAAA,MACxC;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAAwB,QAAwD;AACvF,UAAM,SAAS,oBAAI,IAAiC;AAEpD,eAAW,SAAS,QAAQ;AAC3B,YAAM,aAAa,aAAa,MAAM,UAAU;AAChD,UAAI,CAAC,OAAO,IAAI,UAAU,GAAG;AAC5B,eAAO,IAAI,YAAY,CAAC,CAAC;AAAA,MAC1B;AACA,aAAO,IAAI,UAAU,EAAG,KAAK,KAAK;AAAA,IACnC;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,OAI7B;AACD,UAAM,aAAa,MAAM,cAAc,CAAC;AACxC,UAAM,SAAS,OAAO,MAAM,UAAU,EAAE,EAAE,YAAY;AAEtD,UAAM,WAAW,CAAC,MAA+B;AAGhD,YAAM,cAAc,EAAE;AACtB,aAAO,CAAC,CAAC,eAAe,OAAO,gBAAgB,YAAY,MAAM,KAAK,SAAS,IAAI,WAAW,EAAE;AAAA,IACjG;AAGA,UAAM,aAAa,WAAW,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,UAAU,KAAK,EAAE;AAG9F,UAAM,UAAU,WAAW,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,WAAW,KAAK;AACzE,UAAM,aAAa,QAAQ,IAAI,CAAC,OAAO;AAAA,MACtC,GAAG;AAAA,MACH,UAAU;AAAA,IACX,EAAE;AAGF,UAAM,cAAc,WAClB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,WAAW,KAAK,EAC9C,IAAI,CAAC,OAAO;AAAA,MACZ,GAAG;AAAA,MACH,UAAU,EAAE,aAAa;AAAA;AAAA,IAC1B,EAAE;AAEH,WAAO,EAAE,YAAY,aAAa,WAAW;AAAA,EAC9C;AACD;;;AGrZA,SAAS,qBAA6D;AACtE,SAA8C,eAAe;AAQtD,IAAM,uBAAN,MAA2B;AAAA,EACjC,YACkB,mBACA,cAChB;AAFgB;AACA;AAAA,EACf;AAAA;AAAA,EAGK,WAAsB,CAAC;AAAA;AAAA;AAAA;AAAA,EAK/B,MAAM,2BAAyD;AAC9D,UAAM,SAAS,cAAc,UAAU;AACvC,QAAI,CAAC,QAAQ,QAAQ;AACpB,aAAO,CAAC;AAAA,IACT;AAEA,UAAM,UAAU,KAAK,cAAc;AACnC,UAAM,cAAc,KAAK,sBAAsB,OAAO;AAEtD,QAAI,YAAY,SAAS,GAAG;AAC3B,aAAO,CAAC;AAAA,IACT;AAEA,WAAO,KAAK,cAAc,QAAQ,WAAW;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAyB;AAChC,UAAM,UAAU,IAAI,QAAQ;AAAA,MAC3B,kBAAkB,KAAK;AAAA,IACxB,CAAC;AAED,YAAQ,sBAAsB,CAAC,KAAK,iBAAiB,CAAC;AACtD,SAAK,SAAS,KAAK,OAAO;AAC1B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACf,SAAK,SAAS,QAAQ,CAAC,YAAY;AAElC,cAAQ,eAAe,EAAE,QAAQ,CAAC,SAAS,QAAQ,iBAAiB,IAAI,CAAC;AAAA,IAC1E,CAAC;AACD,SAAK,WAAW,CAAC;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,SAAiD;AAC9E,UAAM,cAAc,oBAAI,IAA8B;AACtD,UAAM,QAAQ,QAAQ,eAAe;AAErC,eAAW,cAAc,OAAO;AAC/B,YAAM,UAAU,WAAW,WAAW;AAEtC,iBAAW,oBAAoB,SAAS;AACvC,cAAM,YAAY,iBAAiB,QAAQ;AAE3C,YAAI,WAAW,SAAS,YAAY,GAAG;AACtC,sBAAY,IAAI,WAAW,gBAAgB;AAAA,QAC5C;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,cACP,QACA,aACsB;AACtB,UAAM,iBAAsC,CAAC;AAC7C,UAAM,SAAkB,CAAC;AAEzB,eAAW,SAAS,QAAQ;AAC3B,UAAI;AACH,cAAM,gBAAgB,KAAK,oBAAoB,OAAO,WAAW;AACjE,uBAAe,KAAK,aAAa;AAAA,MAClC,SAAS,YAAY;AACpB,cAAM,QAAQ,sBAAsB,QAAQ,aAAa,IAAI,MAAM,OAAO,UAAU,CAAC;AACrF,eAAO,KAAK,KAAK;AACjB,gBAAQ;AAAA,UACP,0BAA0B,aAAa,MAAM,UAAU,CAAC,IAAI,aAAa,MAAM,OAAO,CAAC;AAAA,UACvF;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,OAAO,SAAS,GAAG;AACtB,YAAM,IAAI,MAAM,qBAAqB,OAAO,MAAM,YAAY,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,IACxG;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,OAAkB,aAA+D;AAC5G,UAAM,iBAAiB,aAAa,MAAM,UAAU;AACpD,UAAM,cAAc,aAAa,MAAM,OAAO;AAE9C,UAAM,kBAAkB,YAAY,IAAI,cAAc;AACtD,QAAI;AACJ,QAAI;AAEJ,QAAI,iBAAiB;AACpB,YAAM,gBAAgB,gBAAgB,WAAW,EAAE,KAAK,CAAC,WAAW,OAAO,QAAQ,MAAM,WAAW;AAEpG,UAAI,eAAe;AAClB,kBAAU,KAAK,cAAc,aAAa;AAC1C,qBAAa,KAAK,uBAAuB,eAAe,MAAM,cAAc,CAAC,CAAC;AAAA,MAC/E;AAAA,IACD;AAEA,WAAO;AAAA,MACN,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,QAAQ,aAAa,MAAM,MAAM,EAAE,YAAY;AAAA,MAC/C,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,UAAU,cAAc,MAAM,MAAM,MAAM,UAAU;AAAA,MACpD;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,QAAmC;AACxD,UAAM,OAAO,OAAO,cAAc;AAClC,UAAM,WAAW,KAAK,QAAQ,MAAM;AAEpC,UAAM,cAAc,KAAK,eAAe;AACxC,QAAI,aAAa;AAChB,aAAO,YAAY,QAAQ;AAAA,IAC5B;AAEA,WAAO,SAAS,QAAQ,sBAAsB,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKQ,uBACP,QACA,YACuC;AACvC,UAAM,SAAsC,CAAC;AAC7C,UAAM,iBAAiB,OAAO,cAAc;AAC5C,UAAM,eAAe,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAErE,eAAW,SAAS,cAAc;AACjC,YAAM,QAAQ,MAAM;AAEpB,UAAI,QAAQ,eAAe,QAAQ;AAClC,cAAM,gBAAgB,eAAe,KAAK;AAC1C,cAAM,YAAY,cAAc,QAAQ;AACxC,cAAM,YAAY,cAChB,QAAQ,EACR,QAAQ,EACR,QAAQ,sBAAsB,EAAE;AAElC,eAAO,KAAK;AAAA,UACX;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN,UAAU;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,UAAU,MAAM;AAAA,QACjB,CAAC;AAAA,MACF,OAAO;AACN,eAAO,KAAK;AAAA,UACX;AAAA,UACA,MAAM,QAAQ,KAAK;AAAA,UACnB,MAAM,MAAM,UAAU,QAAQ;AAAA,UAC9B,UAAU;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,UAAU,MAAM;AAAA,QACjB,CAAC;AAAA,MACF;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AACD;;;AClNA,SAAS,uBAAuB;AAChC,SAA4B,WAAAC,gBAAe;;;ACEpC,SAAS,8BAA8B,QAAqC;AAClF,QAAM,OAAO,OAAO;AAEpB,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,UAAI,OAAO,QAAQ,MAAM,QAAQ,OAAO,IAAI,GAAG;AAC9C,eAAO,IAAI,OAAO,KAAK,KAAK,OAAO,CAAC;AAAA,MACrC;AACA,aAAO;AAAA,IACR,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK,SAAS;AACb,YAAM,WAAW,8BAA8B,OAAO,SAAS,CAAC,CAAC;AACjE,aAAO,GAAG,QAAQ;AAAA,IACnB;AAAA,IACA,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAKO,SAAS,4BAA4B,UAAkB,QAAqC;AAClG,MAAI;AACH,UAAM,iBAAiB,OAAO,cAAc,QAAQ;AACpD,QAAI,CAAC,gBAAgB;AACpB,aAAO,oBAAoB,QAAQ;AAAA;AAAA;AAAA,IACpC;AAEA,UAAM,aAAa,eAAe,cAAc,CAAC;AACjD,UAAM,WAAW,eAAe,YAAY,CAAC;AAE7C,QAAI,gBAAgB,oBAAoB,QAAQ;AAAA;AAEhD,eAAW,CAAC,UAAU,UAAU,KAAK,OAAO,QAAQ,UAAU,GAAG;AAChE,YAAM,aAAa,SAAS,SAAS,QAAQ;AAC7C,YAAM,OAAO,8BAA8B,UAAiC;AAC5E,YAAM,WAAW,aAAa,KAAK;AAEnC,uBAAiB,IAAK,QAAQ,GAAG,QAAQ,KAAK,IAAI;AAAA;AAAA,IACnD;AAEA,qBAAiB;AACjB,WAAO;AAAA,EACR,SAAS,OAAO;AACf,YAAQ,MAAM,+CAA+C,QAAQ,KAAK,KAAK;AAC/E,WAAO,oBAAoB,QAAQ;AAAA;AAAA;AAAA,EACpC;AACD;;;ACnDO,SAAS,iBAAiB,MAA2B;AAC3D,QAAM,SAAS,KAAK,eAAe,KAAK,KAAK,UAAU;AACvD,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,OAAO,OAAO,QAAQ;AAG5B,MAAI,cAAc,IAAI,IAAI,GAAG;AAC5B,UAAM,QAAQ,KAAK,sBAAsB,IAAI,CAAC,KAAK,KAAK,iBAAiB,IAAI,CAAC;AAC9E,WAAO,QAAQ,iBAAiB,KAAK,IAAI;AAAA,EAC1C;AAGA,MAAI,cAAc,IAAI,IAAI,EAAG,QAAO;AAEpC,SAAO;AACR;AAKO,SAAS,oBAAoB,QAAgC;AACnE,QAAM,QAAQ,oBAAI,IAAY;AAE9B,aAAW,SAAS,QAAQ;AAE3B,QAAI,MAAM,YAAY;AACrB,iBAAW,SAAS,MAAM,YAAY;AACrC,YAAI,MAAM,QAAQ,CAAC,CAAC,UAAU,UAAU,SAAS,EAAE,SAAS,MAAM,IAAI,GAAG;AAExE,gBAAM,YAAY,MAAM,KAAK,MAAM,gBAAgB;AACnD,cAAI,WAAW;AACd,kBAAM,WAAW,UAAU,CAAC;AAE5B,gBAAI,CAAC,sBAAsB,IAAI,QAAQ,GAAG;AACzC,oBAAM,IAAI,QAAQ;AAAA,YACnB;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAGA,QAAI,MAAM,SAAS;AAClB,YAAM,aAAa,MAAM,QAAQ,QAAQ,iBAAiB,IAAI;AAE9D,YAAM,WAAW,WAAW,QAAQ,SAAS,EAAE;AAC/C,UAAI,CAAC,CAAC,UAAU,UAAU,WAAW,OAAO,QAAQ,SAAS,EAAE,SAAS,QAAQ,GAAG;AAClF,cAAM,IAAI,QAAQ;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAEA,SAAO,MAAM,KAAK,KAAK,EAAE,KAAK,IAAI;AACnC;;;AFnDO,IAAM,yBAAN,MAA6B;AAAA,EACnC,YACkB,mBACA,cAChB;AAFgB;AACA;AAAA,EACf;AAAA;AAAA,EAGK,WAAsB,CAAC;AAAA;AAAA;AAAA;AAAA,EAK/B,MAAM,kBAAyC;AAC9C,UAAM,UAAU,KAAK,cAAc;AACnC,UAAM,cAAc,QAAQ,eAAe,KAAK,iBAAiB;AAEjE,UAAM,iBAAiB,KAAK,4BAA4B,WAAW;AACnE,WAAO,KAAK,aAAa,cAAc;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAyB;AAChC,UAAM,UAAU,IAAIC,SAAQ;AAAA,MAC3B,kBAAkB,KAAK;AAAA,IACxB,CAAC;AAED,YAAQ,sBAAsB,CAAC,KAAK,iBAAiB,CAAC;AACtD,SAAK,SAAS,KAAK,OAAO;AAC1B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACf,SAAK,SAAS,QAAQ,CAAC,YAAY;AAElC,cAAQ,eAAe,EAAE,QAAQ,CAAC,SAAS,QAAQ,iBAAiB,IAAI,CAAC;AAAA,IAC1E,CAAC;AACD,SAAK,WAAW,CAAC;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKQ,4BAA4B,aAA0C;AAC7E,UAAM,iBAAiB,oBAAI,IAAY;AAEvC,eAAW,QAAQ,aAAa;AAC/B,iBAAW,OAAO,KAAK,WAAW,GAAG;AACpC,mBAAW,UAAU,IAAI,WAAW,GAAG;AACtC,eAAK,uBAAuB,QAAQ,cAAc;AAAA,QACnD;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,QAA2B,gBAAmC;AAE5F,eAAW,SAAS,OAAO,cAAc,GAAG;AAC3C,YAAMC,QAAO,iBAAiB,MAAM,QAAQ,CAAC;AAC7C,UAAIA,MAAM,gBAAe,IAAIA,KAAI;AAAA,IAClC;AAGA,UAAM,aAAa,OAAO,cAAc;AACxC,UAAM,YAAY,WAAW,iBAAiB,EAAE,CAAC,KAAK;AACtD,UAAM,OAAO,iBAAiB,SAAS;AACvC,QAAI,KAAM,gBAAe,IAAI,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAa,gBAAoD;AAC9E,UAAM,UAAwB,CAAC;AAE/B,eAAW,YAAY,gBAAgB;AACtC,UAAI;AACH,cAAM,SAAS,MAAM,KAAK,sBAAsB,QAAQ;AACxD,cAAM,iBAAiB,4BAA4B,UAAU,MAAM;AAEnE,gBAAQ,KAAK;AAAA,UACZ,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACD,CAAC;AAAA,MACF,SAAS,KAAK;AACb,gBAAQ,MAAM,iCAAiC,QAAQ,KAAK,GAAG;AAAA,MAChE;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,UAAgD;AACnF,QAAI;AACH,YAAM,YAAY,gBAAgB;AAAA,QACjC,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM;AAAA,QACN,eAAe;AAAA;AAAA,MAChB,CAAC;AAED,aAAO,UAAU,aAAa,QAAQ;AAAA,IACvC,SAAS,OAAO;AACf,cAAQ,MAAM,sCAAsC,QAAQ,KAAK,KAAK;AAEtE,aAAO;AAAA,QACN,MAAM;AAAA,QACN,YAAY,CAAC;AAAA,QACb,UAAU,CAAC;AAAA,MACZ;AAAA,IACD;AAAA,EACD;AACD;;;AN9GO,IAAM,YAAN,MAAmC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGT,iBAAsC,CAAC;AAAA,EACvC,kBAAgC,CAAC;AAAA,EACjC,gBAA4C;AAAA,EAEpD,YAAY,UAA4B,CAAC,GAAG;AAC3C,SAAK,oBAAoB,QAAQ,qBAAqB,gBAAgB;AACtE,SAAK,eAAe,QAAQ,gBAAgBC,MAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB,YAAY;AACpG,SAAK,YAAY,QAAQ,aAAaA,MAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB,SAAS;AAC3F,SAAK,iBAAiB,QAAQ,kBAAkB,gBAAgB;AAGhE,SAAK,gBAAgB,IAAI,qBAAqB,KAAK,mBAAmB,KAAK,YAAY;AACvF,SAAK,kBAAkB,IAAI,uBAAuB,KAAK,mBAAmB,KAAK,YAAY;AAC3F,SAAK,kBAAkB,IAAI,uBAAuB,KAAK,SAAS;AAEhE,SAAK,sBAAsB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAA8B;AACrC,UAAM,SAAmB,CAAC;AAE1B,QAAI,CAAC,KAAK,mBAAmB,KAAK,GAAG;AACpC,aAAO,KAAK,oCAAoC;AAAA,IACjD;AAEA,QAAI,CAAC,KAAK,cAAc,KAAK,GAAG;AAC/B,aAAO,KAAK,wCAAwC;AAAA,IACrD,OAAO;AACN,UAAI,CAACC,IAAG,WAAW,KAAK,YAAY,GAAG;AACtC,eAAO,KAAK,wCAAwC,KAAK,YAAY,EAAE;AAAA,MACxE;AAAA,IACD;AAEA,QAAI,CAAC,KAAK,WAAW,KAAK,GAAG;AAC5B,aAAO,KAAK,kCAAkC;AAAA,IAC/C;AAEA,QAAI,OAAO,SAAS,GAAG;AACtB,YAAM,IAAI,MAAM,oCAAoC,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,IACxE;AAEA,SAAK;AAAA,MACJ,8CAA8C,KAAK,iBAAiB,kBAAkB,KAAK,YAAY,eAAe,KAAK,SAAS;AAAA,IACrI;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyB,OAAO,KAAkB,SAA8B;AAC/E,QAAI,KAAK,gBAAgB;AACxB,YAAM,KAAK,kBAAkB;AAAA,IAC9B;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAmC;AAChD,QAAI;AACH,WAAK,IAAI,wCAAwC;AAGjD,WAAK,iBAAiB,CAAC;AACvB,WAAK,kBAAkB,CAAC;AACxB,WAAK,gBAAgB;AAGrB,WAAK,iBAAiB,MAAM,KAAK,cAAc,yBAAyB;AAGxE,WAAK,kBAAkB,MAAM,KAAK,gBAAgB,gBAAgB;AAGlE,WAAK,gBAAgB,MAAM,KAAK,gBAAgB,eAAe,KAAK,gBAAgB,KAAK,eAAe;AAExG,WAAK;AAAA,QACJ,iCAA4B,KAAK,eAAe,MAAM,YAAY,KAAK,gBAAgB,MAAM;AAAA,MAC9F;AAAA,IACD,SAAS,OAAO;AACf,WAAK,SAAS,8BAA8B,KAAK;AAEjD,WAAK,QAAQ;AACb,YAAM;AAAA,IACP;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC9B,UAAM,KAAK,kBAAkB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,YAA0C;AACzC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,aAAoC;AACnC,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAgD;AAC/C,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACf,SAAK,cAAc,QAAQ;AAC3B,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,IAAI,sBAAsB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,IAAI,SAAuB;AAClC,YAAQ,IAAI,GAAG,UAAU,IAAI,OAAO,EAAE;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,SAAiB,OAAuB;AACxD,YAAQ,MAAM,GAAG,UAAU,IAAI,OAAO,IAAI,SAAS,EAAE;AAAA,EACtD;AACD;","names":["fs","path","path","Project","Project","type","path","fs"]}
|