@appweaver/client 1.0.23 → 1.0.25
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/cjs/package.json +3 -0
- package/{weaver-client.js → cjs/weaver-client.js} +1 -1
- package/esm/angular/index.d.ts +1 -0
- package/esm/angular/index.js +1 -0
- package/esm/clients/angular-client.d.ts +26 -0
- package/esm/clients/angular-client.js +53 -0
- package/esm/clients/base-client-interface.d.ts +86 -0
- package/esm/clients/base-client-interface.js +1 -0
- package/esm/clients/base-client.d.ts +216 -0
- package/esm/clients/base-client.js +242 -0
- package/esm/clients/fetch-client.d.ts +6 -0
- package/esm/clients/fetch-client.js +6 -0
- package/esm/clients/index.d.ts +4 -0
- package/esm/clients/index.js +4 -0
- package/esm/clients/modules/account-client.d.ts +69 -0
- package/esm/clients/modules/account-client.js +107 -0
- package/esm/clients/modules/auth-client.d.ts +56 -0
- package/esm/clients/modules/auth-client.js +74 -0
- package/esm/clients/modules/base-module.d.ts +17 -0
- package/esm/clients/modules/base-module.js +49 -0
- package/esm/clients/modules/files-client.d.ts +27 -0
- package/esm/clients/modules/files-client.js +42 -0
- package/esm/clients/modules/health-client.d.ts +25 -0
- package/esm/clients/modules/health-client.js +30 -0
- package/esm/clients/modules/index.d.ts +6 -0
- package/esm/clients/modules/index.js +6 -0
- package/esm/clients/modules/resource-client.d.ts +90 -0
- package/esm/clients/modules/resource-client.js +173 -0
- package/esm/clients/responses/file-data-response.d.ts +78 -0
- package/esm/clients/responses/file-data-response.js +105 -0
- package/esm/clients/responses/index.d.ts +1 -0
- package/esm/clients/responses/index.js +1 -0
- package/esm/commands/generate-command.d.ts +3 -0
- package/esm/commands/generate-command.js +122 -0
- package/esm/commands/index.d.ts +1 -0
- package/esm/commands/index.js +1 -0
- package/esm/constants.d.ts +67 -0
- package/esm/constants.js +94 -0
- package/esm/errors/client-error.d.ts +6 -0
- package/esm/errors/client-error.js +11 -0
- package/esm/errors/index.d.ts +1 -0
- package/esm/errors/index.js +1 -0
- package/esm/generators/generate-client.d.ts +16 -0
- package/esm/generators/generate-client.js +399 -0
- package/esm/generators/generate-types.d.ts +9 -0
- package/esm/generators/generate-types.js +486 -0
- package/esm/generators/index.d.ts +2 -0
- package/esm/generators/index.js +2 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +2 -0
- package/esm/package.json +3 -0
- package/esm/types/index.d.ts +1 -0
- package/esm/types/index.js +1 -0
- package/esm/types/routes.d.ts +15 -0
- package/esm/types/routes.js +1 -0
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.js +1 -0
- package/esm/utils/schema-util.d.ts +3 -0
- package/esm/utils/schema-util.js +39 -0
- package/package.json +29 -5
- /package/{angular → cjs/angular}/index.d.ts +0 -0
- /package/{angular → cjs/angular}/index.js +0 -0
- /package/{clients → cjs/clients}/angular-client.d.ts +0 -0
- /package/{clients → cjs/clients}/angular-client.js +0 -0
- /package/{clients → cjs/clients}/base-client-interface.d.ts +0 -0
- /package/{clients → cjs/clients}/base-client-interface.js +0 -0
- /package/{clients → cjs/clients}/base-client.d.ts +0 -0
- /package/{clients → cjs/clients}/base-client.js +0 -0
- /package/{clients → cjs/clients}/fetch-client.d.ts +0 -0
- /package/{clients → cjs/clients}/fetch-client.js +0 -0
- /package/{clients → cjs/clients}/index.d.ts +0 -0
- /package/{clients → cjs/clients}/index.js +0 -0
- /package/{clients → cjs/clients}/modules/account-client.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/account-client.js +0 -0
- /package/{clients → cjs/clients}/modules/auth-client.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/auth-client.js +0 -0
- /package/{clients → cjs/clients}/modules/base-module.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/base-module.js +0 -0
- /package/{clients → cjs/clients}/modules/files-client.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/files-client.js +0 -0
- /package/{clients → cjs/clients}/modules/health-client.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/health-client.js +0 -0
- /package/{clients → cjs/clients}/modules/index.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/index.js +0 -0
- /package/{clients → cjs/clients}/modules/resource-client.d.ts +0 -0
- /package/{clients → cjs/clients}/modules/resource-client.js +0 -0
- /package/{clients → cjs/clients}/responses/file-data-response.d.ts +0 -0
- /package/{clients → cjs/clients}/responses/file-data-response.js +0 -0
- /package/{clients → cjs/clients}/responses/index.d.ts +0 -0
- /package/{clients → cjs/clients}/responses/index.js +0 -0
- /package/{commands → cjs/commands}/generate-command.d.ts +0 -0
- /package/{commands → cjs/commands}/generate-command.js +0 -0
- /package/{commands → cjs/commands}/index.d.ts +0 -0
- /package/{commands → cjs/commands}/index.js +0 -0
- /package/{constants.d.ts → cjs/constants.d.ts} +0 -0
- /package/{constants.js → cjs/constants.js} +0 -0
- /package/{errors → cjs/errors}/client-error.d.ts +0 -0
- /package/{errors → cjs/errors}/client-error.js +0 -0
- /package/{errors → cjs/errors}/index.d.ts +0 -0
- /package/{errors → cjs/errors}/index.js +0 -0
- /package/{generators → cjs/generators}/generate-client.d.ts +0 -0
- /package/{generators → cjs/generators}/generate-client.js +0 -0
- /package/{generators → cjs/generators}/generate-types.d.ts +0 -0
- /package/{generators → cjs/generators}/generate-types.js +0 -0
- /package/{generators → cjs/generators}/index.d.ts +0 -0
- /package/{generators → cjs/generators}/index.js +0 -0
- /package/{index.d.ts → cjs/index.d.ts} +0 -0
- /package/{index.js → cjs/index.js} +0 -0
- /package/{types → cjs/types}/index.d.ts +0 -0
- /package/{types → cjs/types}/index.js +0 -0
- /package/{types → cjs/types}/routes.d.ts +0 -0
- /package/{types → cjs/types}/routes.js +0 -0
- /package/{utils → cjs/utils}/index.d.ts +0 -0
- /package/{utils → cjs/utils}/index.js +0 -0
- /package/{utils → cjs/utils}/schema-util.d.ts +0 -0
- /package/{utils → cjs/utils}/schema-util.js +0 -0
- /package/{weaver-client.d.ts → cjs/weaver-client.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './client-error.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './client-error.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { OpenAPI3 } from 'openapi-typescript';
|
|
2
|
+
import { FRAMEWORKS } from '../constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates a client class based on the provided OpenAPI schema and already generated types.
|
|
5
|
+
*
|
|
6
|
+
* @param {string | OpenAPI3} schema - The OpenAPI schema used to generate the client. Can be a string
|
|
7
|
+
* (URL or JSON/YAML) or an object.
|
|
8
|
+
* @param {string} [clientName] - Optional name of the client class name to be generated. (default: derived from OpenAPI
|
|
9
|
+
* title or WeaverClient if title is missing)
|
|
10
|
+
* @param {string} [framework='fetch'] - Optional framework for which to generate the client class.
|
|
11
|
+
* @param {string} [typesPath] - Optional path to the types module, for importing related type definitions.
|
|
12
|
+
* @param {boolean} [noTypes=false] - Optional flag to disable client class generic types, useful for environments
|
|
13
|
+
* without type support.
|
|
14
|
+
* @return {Promise<string>} A Promise that resolves to the generated client class as a string.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateClient(schema: string | OpenAPI3, clientName?: string, framework?: (typeof FRAMEWORKS)[number], typesPath?: string, noTypes?: boolean): Promise<string>;
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { FetchClient } from '../clients/index.js';
|
|
2
|
+
import { toSchemaObject } from '../utils/index.js';
|
|
3
|
+
import { ACCOUNT_MODULE_TYPE, ACCOUNT_OPERATIONS, AUTH_MODULE_TYPE, AUTH_OPERATIONS, CONFIG_FIELD, CONFIG_RESOURCE_FIELD, FILE_OPERATIONS, HEALTH_MODULE_TYPE, HEALTH_OPERATIONS, RESOURCE_MODULE_TYPE, RESOURCE_OPERATIONS } from '../constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* Generates a client class based on the provided OpenAPI schema and already generated types.
|
|
6
|
+
*
|
|
7
|
+
* @param {string | OpenAPI3} schema - The OpenAPI schema used to generate the client. Can be a string
|
|
8
|
+
* (URL or JSON/YAML) or an object.
|
|
9
|
+
* @param {string} [clientName] - Optional name of the client class name to be generated. (default: derived from OpenAPI
|
|
10
|
+
* title or WeaverClient if title is missing)
|
|
11
|
+
* @param {string} [framework='fetch'] - Optional framework for which to generate the client class.
|
|
12
|
+
* @param {string} [typesPath] - Optional path to the types module, for importing related type definitions.
|
|
13
|
+
* @param {boolean} [noTypes=false] - Optional flag to disable client class generic types, useful for environments
|
|
14
|
+
* without type support.
|
|
15
|
+
* @return {Promise<string>} A Promise that resolves to the generated client class as a string.
|
|
16
|
+
*/
|
|
17
|
+
export async function generateClient(schema, clientName, framework = 'fetch', typesPath, noTypes = false) {
|
|
18
|
+
const schemaObject = typeof schema === 'string' ? await toSchemaObject(schema) : schema;
|
|
19
|
+
// Resolve the client class name, convert to CamelCase, and sanitize
|
|
20
|
+
const className = (clientName || `${toCamelCase(schemaObject.info.title) || 'Weaver'}Client`).replace(/[^a-zA-Z0-9_$]/g, '');
|
|
21
|
+
// Resolve the type import statement and types prefix
|
|
22
|
+
const typeName = 'Type';
|
|
23
|
+
const typePrefix = typesPath ? `${typeName}.` : '';
|
|
24
|
+
const pathsTypeImport = typesPath && !noTypes
|
|
25
|
+
? `import * as ${typeName} from '${typesPath}';\n`
|
|
26
|
+
: '';
|
|
27
|
+
const pathsTypeGeneric = !noTypes ? `<${typePrefix}paths>` : '';
|
|
28
|
+
const config = schemaObject[CONFIG_FIELD];
|
|
29
|
+
const schemaRoutes = {
|
|
30
|
+
resource: {},
|
|
31
|
+
auth: [],
|
|
32
|
+
account: [],
|
|
33
|
+
health: [],
|
|
34
|
+
files: [],
|
|
35
|
+
custom: []
|
|
36
|
+
};
|
|
37
|
+
for (const [path, item] of Object.entries(schemaObject.paths || {})) {
|
|
38
|
+
// Skip object references
|
|
39
|
+
if (item['$ref']) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
for (const [method, operation] of Object.entries(item)) {
|
|
43
|
+
// Pass only for valid HTTP methods
|
|
44
|
+
if (['servers', 'parameters'].includes(method)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const { type, operationName, resourceName } = routeDetails(path, method, operation, config);
|
|
48
|
+
// Populate schema routes based on route details
|
|
49
|
+
if (type === 'resource') {
|
|
50
|
+
if (!resourceName) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
schemaRoutes.resource[resourceName] ??= [];
|
|
54
|
+
schemaRoutes.resource[resourceName].push(operationName);
|
|
55
|
+
}
|
|
56
|
+
else if (type === 'custom') {
|
|
57
|
+
if (path.startsWith(`${config.routePrefixes.auth}/login/`)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
schemaRoutes.custom.push({
|
|
61
|
+
method,
|
|
62
|
+
path,
|
|
63
|
+
operationName
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
schemaRoutes[type].push(operationName);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const clientMethods = [];
|
|
72
|
+
// Utility function for generating generic types for client methods using
|
|
73
|
+
// module type prefix and omitted types based on operations usage
|
|
74
|
+
const makeGenericTypes = (moduleTypeName, operations, usedOperations) => {
|
|
75
|
+
if (noTypes) {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
const genericTypes = [];
|
|
79
|
+
if (moduleTypeName) {
|
|
80
|
+
genericTypes.push(`${typePrefix}${moduleTypeName}`);
|
|
81
|
+
}
|
|
82
|
+
const omittedFields = Object.keys(operations).filter((o) => !usedOperations.includes(o));
|
|
83
|
+
if (omittedFields.length > 0) {
|
|
84
|
+
genericTypes.push(`[${omittedFields.map((field) => "'" + field + "'").join(', ')}]`);
|
|
85
|
+
}
|
|
86
|
+
return genericTypes.length > 0 ? `<${genericTypes.join(', ')}>` : '';
|
|
87
|
+
};
|
|
88
|
+
// Add auth client
|
|
89
|
+
if (schemaRoutes.auth.length > 0) {
|
|
90
|
+
const genericTypes = makeGenericTypes(AUTH_MODULE_TYPE, AUTH_OPERATIONS, schemaRoutes.auth);
|
|
91
|
+
clientMethods.push({
|
|
92
|
+
name: 'auth',
|
|
93
|
+
expression: `this.authClient${genericTypes}('${config.routePrefixes.auth}')`
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Add account client
|
|
97
|
+
if (schemaRoutes.account.length > 0) {
|
|
98
|
+
const genericTypes = makeGenericTypes(ACCOUNT_MODULE_TYPE, ACCOUNT_OPERATIONS, schemaRoutes.account);
|
|
99
|
+
clientMethods.push({
|
|
100
|
+
name: 'account',
|
|
101
|
+
expression: `this.accountClient${genericTypes}('${config.routePrefixes.account}')`
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Add health client
|
|
105
|
+
if (schemaRoutes.health.length > 0) {
|
|
106
|
+
const genericTypes = makeGenericTypes(HEALTH_MODULE_TYPE, HEALTH_OPERATIONS, schemaRoutes.health);
|
|
107
|
+
clientMethods.push({
|
|
108
|
+
name: 'health',
|
|
109
|
+
expression: `this.healthClient${genericTypes}('${config.routePrefixes.health}')`
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// Add file client
|
|
113
|
+
if (schemaRoutes.files.length > 0) {
|
|
114
|
+
const genericTypes = makeGenericTypes(undefined, FILE_OPERATIONS, schemaRoutes.files);
|
|
115
|
+
clientMethods.push({
|
|
116
|
+
name: 'files',
|
|
117
|
+
expression: `this.filesClient${genericTypes}('${config.routePrefixes.files}')`
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Add resource clients
|
|
121
|
+
for (const [name, operations] of Object.entries(schemaRoutes.resource)) {
|
|
122
|
+
const basePath = config.resourcePaths.find((p) => p.name === name)?.basePath;
|
|
123
|
+
if (!basePath) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const lowerName = name.charAt(0).toLowerCase() + name.slice(1);
|
|
127
|
+
const resourcePath = `${config.routePrefixes.api}${basePath}`;
|
|
128
|
+
const genericTypes = makeGenericTypes(`${name}${RESOURCE_MODULE_TYPE}`, RESOURCE_OPERATIONS, operations);
|
|
129
|
+
clientMethods.push({
|
|
130
|
+
name: lowerName,
|
|
131
|
+
expression: `this.resourceClient${genericTypes}('${resourcePath}')`
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Add custom requests
|
|
135
|
+
for (const customRoute of schemaRoutes.custom) {
|
|
136
|
+
const { method, path, operationName } = customRoute;
|
|
137
|
+
clientMethods.push({
|
|
138
|
+
name: operationName,
|
|
139
|
+
expression: `this.customRequest('${method}', '${path}')`
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Combine and resolve all client methods
|
|
143
|
+
let clientMethodContent = '';
|
|
144
|
+
const usedMethodNames = new Set(Object.getOwnPropertyNames(FetchClient.prototype));
|
|
145
|
+
for (const { name, expression } of clientMethods) {
|
|
146
|
+
// Uppercase the method name if it conflicts with existing class properties
|
|
147
|
+
const propName = usedMethodNames.has(name)
|
|
148
|
+
? name.charAt(0).toUpperCase() + name.slice(1)
|
|
149
|
+
: name;
|
|
150
|
+
clientMethodContent += `public ${propName} = ${expression};\n\n`;
|
|
151
|
+
usedMethodNames.add(propName);
|
|
152
|
+
}
|
|
153
|
+
// Generate framework-specific client code
|
|
154
|
+
return framework === 'angular'
|
|
155
|
+
? generateAngularClient(pathsTypeImport, pathsTypeGeneric, className, clientMethodContent)
|
|
156
|
+
: generateFetchClient(pathsTypeImport, pathsTypeGeneric, className, clientMethodContent);
|
|
157
|
+
}
|
|
158
|
+
function generateFetchClient(pathsTypeImport, pathsTypeGeneric, className, clientMethodContent) {
|
|
159
|
+
return `import { ClientConfig, ClientError, FetchClient } from '@appweaver/client';
|
|
160
|
+
${pathsTypeImport}
|
|
161
|
+
export class ${className} extends FetchClient${pathsTypeGeneric} {
|
|
162
|
+
${clientMethodContent}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function createClient(config: ClientConfig): ${className} {
|
|
166
|
+
return new ${className}(config);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export { ClientError };
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
function generateAngularClient(pathsTypeImport, pathsTypeGeneric, className, clientMethodContent) {
|
|
173
|
+
return `import { ClientConfig, ClientError } from '@appweaver/client';
|
|
174
|
+
import { AngularClient } from '@appweaver/client/angular';
|
|
175
|
+
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
|
|
176
|
+
import { firstValueFrom } from 'rxjs';
|
|
177
|
+
${pathsTypeImport}
|
|
178
|
+
export class ${className} extends AngularClient${pathsTypeGeneric} {
|
|
179
|
+
constructor(http: HttpClient, config: ClientConfig) {
|
|
180
|
+
super(${className}.fetchHandler(http), config);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
${clientMethodContent}
|
|
184
|
+
|
|
185
|
+
private static fetchHandler(http: HttpClient) {
|
|
186
|
+
return async (
|
|
187
|
+
input: RequestInfo | URL,
|
|
188
|
+
init?: RequestInit
|
|
189
|
+
): Promise<Response> => {
|
|
190
|
+
const request = input instanceof Request ? input : null;
|
|
191
|
+
|
|
192
|
+
const url = request
|
|
193
|
+
? request.url
|
|
194
|
+
: input instanceof URL
|
|
195
|
+
? input.toString()
|
|
196
|
+
: input;
|
|
197
|
+
|
|
198
|
+
const method = init?.method ?? request?.method ?? 'GET';
|
|
199
|
+
|
|
200
|
+
const headers = new HttpHeaders(
|
|
201
|
+
Object.fromEntries(
|
|
202
|
+
new Headers(init?.headers ?? request?.headers ?? {}).entries()
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const body =
|
|
207
|
+
method === 'GET' || method === 'HEAD'
|
|
208
|
+
? undefined
|
|
209
|
+
: (init?.body ?? request?.body ?? undefined);
|
|
210
|
+
|
|
211
|
+
let parsedBody: any;
|
|
212
|
+
if (body) {
|
|
213
|
+
if (headers.get('Content-Type')?.includes('multipart')) {
|
|
214
|
+
parsedBody = await new Response(body).blob();
|
|
215
|
+
} else {
|
|
216
|
+
try {
|
|
217
|
+
parsedBody = JSON.parse(await new Response(body).text());
|
|
218
|
+
} catch (e) {
|
|
219
|
+
parsedBody = body;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const angularResponse: HttpResponse<Blob> = await firstValueFrom(
|
|
225
|
+
http.request(method, url as string, {
|
|
226
|
+
body: parsedBody,
|
|
227
|
+
headers: headers,
|
|
228
|
+
observe: 'response',
|
|
229
|
+
responseType: 'blob',
|
|
230
|
+
withCredentials: init?.credentials === 'include'
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const responseHeaders = new Headers();
|
|
235
|
+
|
|
236
|
+
angularResponse.headers.keys().forEach((key: string) => {
|
|
237
|
+
const value = angularResponse.headers.get(key);
|
|
238
|
+
if (value !== null) {
|
|
239
|
+
responseHeaders.set(key, value);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return new Response(angularResponse.body, {
|
|
244
|
+
status: angularResponse.status,
|
|
245
|
+
statusText: angularResponse.statusText,
|
|
246
|
+
headers: responseHeaders
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export { ClientError };
|
|
253
|
+
`;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Retrieves the details for a specific route based on the provided path, HTTP method, and configuration.
|
|
257
|
+
*
|
|
258
|
+
* @param {string} path - The URL path for which route details are determined.
|
|
259
|
+
* @param {HttpMethod} method - The HTTP method associated with the route (e.g., GET, POST).
|
|
260
|
+
* @param {OperationObject} operation - The operation object containing metadata related to the route.
|
|
261
|
+
* @param {RoutePathConfig} config - The schema configuration object containing route prefixes and resource paths.
|
|
262
|
+
* @return {RouteDetails} An object representing the type of route, optionally including the operation name and
|
|
263
|
+
* resource name if applicable.
|
|
264
|
+
*/
|
|
265
|
+
function routeDetails(path, method, operation, config) {
|
|
266
|
+
try {
|
|
267
|
+
const prefixChecks = [
|
|
268
|
+
['auth', config.routePrefixes.auth, AUTH_OPERATIONS],
|
|
269
|
+
['account', config.routePrefixes.account, ACCOUNT_OPERATIONS],
|
|
270
|
+
['health', config.routePrefixes.health, HEALTH_OPERATIONS],
|
|
271
|
+
['files', config.routePrefixes.files, FILE_OPERATIONS]
|
|
272
|
+
];
|
|
273
|
+
// Try to detect predefined module-specific routes
|
|
274
|
+
for (const [routeType, prefix, operations] of prefixChecks) {
|
|
275
|
+
const operationName = routeOperation(path, method, prefix, operations);
|
|
276
|
+
if (operationName) {
|
|
277
|
+
return { type: routeType, operationName };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Try to detect resource routes using resource name and route prefix
|
|
281
|
+
const resourceName = operation[CONFIG_RESOURCE_FIELD];
|
|
282
|
+
const resourcePath = config.resourcePaths.find((rp) => rp.name === resourceName)?.basePath;
|
|
283
|
+
const resourcePathPrefix = `${config.routePrefixes.api}${resourcePath}`;
|
|
284
|
+
if (resourceName && resourcePath && path.startsWith(resourcePathPrefix)) {
|
|
285
|
+
const pathSuffix = path.replace(resourcePathPrefix, '');
|
|
286
|
+
const operationName = resourceOperation(pathSuffix, method);
|
|
287
|
+
if (operationName) {
|
|
288
|
+
return { type: 'resource', resourceName, operationName };
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
// If schema config is invalid or missing, default to custom route type
|
|
294
|
+
return {
|
|
295
|
+
type: 'custom',
|
|
296
|
+
operationName: createOperationName(path, method, config)
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
type: 'custom',
|
|
301
|
+
operationName: createOperationName(path, method, config)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Generates an operation name based on the provided API path, HTTP method, and schema configuration.
|
|
306
|
+
*
|
|
307
|
+
* @param {string} path - The API path for which the operation name is being generated.
|
|
308
|
+
* @param {HttpMethod} method - The HTTP method (e.g., GET, POST, PUT) associated with the operation.
|
|
309
|
+
* @param {RoutePathConfig} config - The configuration object containing schema details, including route prefixes.
|
|
310
|
+
* @return {string} A generated string representing the operation name.
|
|
311
|
+
*/
|
|
312
|
+
function createOperationName(path, method, config) {
|
|
313
|
+
if (path.replace(config.routePrefixes.api, '').replace('/', '') === '') {
|
|
314
|
+
return 'info';
|
|
315
|
+
}
|
|
316
|
+
const capitalize = (str) => {
|
|
317
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
318
|
+
};
|
|
319
|
+
const parts = path.split('/');
|
|
320
|
+
const camelCasePath = parts
|
|
321
|
+
.filter((part) => part.length > 0)
|
|
322
|
+
.map((part, index) => {
|
|
323
|
+
if (part.startsWith('{') && part.endsWith('}')) {
|
|
324
|
+
const nextPart = parts[index + 1];
|
|
325
|
+
const partSlice = part.slice(1, -1).replace('*', 'Any');
|
|
326
|
+
if (nextPart && nextPart.length > 0) {
|
|
327
|
+
return 'By' + capitalize(partSlice);
|
|
328
|
+
}
|
|
329
|
+
return 'By' + capitalize(partSlice);
|
|
330
|
+
}
|
|
331
|
+
return capitalize(part);
|
|
332
|
+
})
|
|
333
|
+
.join('')
|
|
334
|
+
.replace(/-[a-z0-9]/g, (match) => match.replace('-', '').toUpperCase())
|
|
335
|
+
.replace(/^By(.*)/g, 'by$1');
|
|
336
|
+
return `${method}${camelCasePath}`;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Finds a route operation based on the given path, method, prefix, and operations mappings.
|
|
340
|
+
*
|
|
341
|
+
* @param {string} path - The request path to be matched against the operations.
|
|
342
|
+
* @param {HttpMethod} method - The HTTP method to be matched (e.g., GET, POST).
|
|
343
|
+
* @param {string} prefix - The prefix to be removed from the path before processing.
|
|
344
|
+
* @param {Record<string, HttpMethod>} operations - A record mapping operation names to their corresponding HTTP methods.
|
|
345
|
+
* @return {string | undefined} The matching operation name, or `undefined` if no match is found.
|
|
346
|
+
*/
|
|
347
|
+
function routeOperation(path, method, prefix, operations) {
|
|
348
|
+
if (!path.startsWith(prefix)) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
const normalizedRoute = path
|
|
352
|
+
.replace(prefix, '')
|
|
353
|
+
.replace(/^\//, '')
|
|
354
|
+
.replace(/\/\{[\w*]+}$/, '')
|
|
355
|
+
.replace(/-/g, '')
|
|
356
|
+
.toLowerCase();
|
|
357
|
+
return Object.entries(operations).find(([operation, operationMethod]) => normalizedRoute === operation.toLowerCase() && method === operationMethod)?.[0];
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Determines the resource operation based on the provided path suffix and HTTP method.
|
|
361
|
+
*
|
|
362
|
+
* @param {string} pathSuffix - The suffix of the path used to identify a specific resource operation.
|
|
363
|
+
* @param {HttpMethod} method - The HTTP method (e.g., GET, POST, PUT, DELETE) corresponding to the operation.
|
|
364
|
+
* @return {string | undefined} - The matching resource operation key, or undefined if no
|
|
365
|
+
* match is found.
|
|
366
|
+
*/
|
|
367
|
+
function resourceOperation(pathSuffix, method) {
|
|
368
|
+
const operationMap = {
|
|
369
|
+
get: {
|
|
370
|
+
'{id}': 'find'
|
|
371
|
+
},
|
|
372
|
+
post: {
|
|
373
|
+
query: 'query',
|
|
374
|
+
aggregate: 'aggregate',
|
|
375
|
+
'': 'create',
|
|
376
|
+
export: 'export',
|
|
377
|
+
'{id}/files': 'uploadFiles',
|
|
378
|
+
'{id}/delete-files': 'deleteFiles'
|
|
379
|
+
},
|
|
380
|
+
put: {
|
|
381
|
+
'{id}': 'update'
|
|
382
|
+
},
|
|
383
|
+
delete: {
|
|
384
|
+
'{id}': 'delete'
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
return operationMap[method]?.[pathSuffix.replace(/^\//, '')];
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Converts a given string to CamelCase format.
|
|
391
|
+
* Words in the input string can be separated by spaces, dashes, or underscores.
|
|
392
|
+
*
|
|
393
|
+
* @param {string} text - The input string to be converted to CamelCase.
|
|
394
|
+
* @return {string} The converted string in CamelCase format.
|
|
395
|
+
*/
|
|
396
|
+
function toCamelCase(text) {
|
|
397
|
+
const result = text.replace(/[\s\-_]+[a-z0-9]/g, (match) => match.replace(/[\s\-_]+/, '').toUpperCase());
|
|
398
|
+
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
399
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { OpenAPI3 } from 'openapi-typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Generates TypeScript types based on an OpenAPI V3 schema content.
|
|
4
|
+
*
|
|
5
|
+
* @param {string | OpenAPI3} schema - The OpenAPI V3 schema to generate types from. The value can be a string
|
|
6
|
+
* representing JSON or YAML format, or already parsed OpenAPI3 object.
|
|
7
|
+
* @return {Promise<string>} A promise that resolves to a string containing the generated TypeScript types.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateTypes(schema: string | OpenAPI3): Promise<string>;
|