vite-plugin-openapi-codegen 1.1.3 → 1.2.0
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 +2 -0
- package/dist/cli.mjs +51 -15
- package/dist/index.mjs +51 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -225,6 +225,8 @@ The generated client shape depends on the OpenAPI operation:
|
|
|
225
225
|
- path parameters become `options.path`
|
|
226
226
|
- query parameters become `options.query`
|
|
227
227
|
- JSON request bodies become `options.body`
|
|
228
|
+
- `application/octet-stream` request bodies become `options.body` with `contentType: "application/octet-stream"`
|
|
229
|
+
- `multipart/form-data` request bodies become `options.body` as `FormData`
|
|
228
230
|
- JSON responses become typed `Promise<T>`
|
|
229
231
|
- empty responses use the configured void request function
|
|
230
232
|
|
package/dist/cli.mjs
CHANGED
|
@@ -146,7 +146,11 @@ function createClientChannelField(key, channel) {
|
|
|
146
146
|
function createClientFunctionDeclaration(operation) {
|
|
147
147
|
const requestProperties = [ts.factory.createSpreadAssignment(ts.factory.createIdentifier("requestOptions")), ts.factory.createPropertyAssignment(ts.factory.createIdentifier("method"), ts.factory.createStringLiteral(operation.methodUpper))];
|
|
148
148
|
if (operation.queryChannel.present) requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("searchParams"), ts.factory.createCallExpression(ts.factory.createIdentifier("buildSearchParams"), void 0, [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "query")])));
|
|
149
|
-
if (operation.bodyChannel.present)
|
|
149
|
+
if (operation.bodyChannel.present) {
|
|
150
|
+
if (operation.bodyContentType === "json") requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("json"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "body")));
|
|
151
|
+
else requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("body"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "body")));
|
|
152
|
+
if (operation.bodyContentType === "binary") requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("contentType"), ts.factory.createStringLiteral("application/octet-stream")));
|
|
153
|
+
}
|
|
150
154
|
requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("signal"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "signal")));
|
|
151
155
|
const requestCall = ts.factory.createCallExpression(ts.factory.createIdentifier(operation.requestFunction), operation.responseTypeExpr ? [createTypeNodeFromText(operation.responseTypeExpr)] : void 0, [parseExpression(operation.pathInvocationExpr), ts.factory.createObjectLiteralExpression(requestProperties, true)]);
|
|
152
156
|
return ts.factory.createFunctionDeclaration([createExportModifier()], void 0, ts.factory.createIdentifier(operation.funcName), void 0, [ts.factory.createParameterDeclaration(void 0, void 0, ts.factory.createIdentifier("options"), void 0, ts.factory.createTypeReferenceNode(operation.optionTypeName)), ts.factory.createParameterDeclaration(void 0, void 0, ts.factory.createIdentifier("requestOptions"), void 0, ts.factory.createTypeReferenceNode("RuntimeRequestOptions"), ts.factory.createObjectLiteralExpression())], createTypeNodeFromText(operation.returnTypeExpr), ts.factory.createBlock([ts.factory.createReturnStatement(requestCall)], true));
|
|
@@ -242,13 +246,6 @@ function getParametersByLocation(operation, location) {
|
|
|
242
246
|
function hasRequiredChannel(parameters) {
|
|
243
247
|
return parameters.some((parameter) => parameter.required);
|
|
244
248
|
}
|
|
245
|
-
function getJsonRequestBody(operation) {
|
|
246
|
-
const requestBody = operation.requestBody;
|
|
247
|
-
if (!requestBody) return void 0;
|
|
248
|
-
const jsonBody = requestBody.content?.["application/json"];
|
|
249
|
-
if (!jsonBody) throw new Error(`Operation "${operation.operationId ?? "unknown"}" has a requestBody but no application/json content`);
|
|
250
|
-
return jsonBody;
|
|
251
|
-
}
|
|
252
249
|
function getSuccessResponseInfo(operation) {
|
|
253
250
|
const successResponses = Object.entries(operation.responses ?? {}).filter(([statusKey]) => isSuccessStatus(statusKey)).sort(([left], [right]) => Number(left) - Number(right));
|
|
254
251
|
if (successResponses.length === 0) throw new Error(`Operation "${operation.operationId ?? "unknown"}" has no 2xx success response`);
|
|
@@ -335,10 +332,11 @@ function normalizeOperation(entry, context, requestFunctionNames) {
|
|
|
335
332
|
const builderAlias = getBuilderAlias(entry.funcName);
|
|
336
333
|
const pathChannel = normalizeParameterChannel(entry, context, "path");
|
|
337
334
|
const queryChannel = normalizeParameterChannel(entry, context, "query");
|
|
338
|
-
const
|
|
335
|
+
const bodyResolution = normalizeBodyChannel(entry, context);
|
|
339
336
|
const responseTypeRef = resolveResponseTypeReference(entry, context, successResponse);
|
|
340
337
|
return {
|
|
341
|
-
bodyChannel,
|
|
338
|
+
bodyChannel: bodyResolution.channel,
|
|
339
|
+
bodyContentType: bodyResolution.contentType,
|
|
342
340
|
builderAlias,
|
|
343
341
|
entry,
|
|
344
342
|
optionTypeName: getClientOptionTypeName(entry.funcName),
|
|
@@ -364,7 +362,35 @@ function normalizeParameterChannel(entry, context, location) {
|
|
|
364
362
|
};
|
|
365
363
|
}
|
|
366
364
|
function normalizeBodyChannel(entry, context) {
|
|
367
|
-
const
|
|
365
|
+
const requestBody = entry.operation.requestBody;
|
|
366
|
+
if (!requestBody) return {
|
|
367
|
+
channel: {
|
|
368
|
+
present: false,
|
|
369
|
+
required: false,
|
|
370
|
+
typeRef: null
|
|
371
|
+
},
|
|
372
|
+
contentType: null
|
|
373
|
+
};
|
|
374
|
+
const content = requestBody.content ?? {};
|
|
375
|
+
const jsonBody = content["application/json"];
|
|
376
|
+
if (jsonBody) return {
|
|
377
|
+
channel: createRequestBodyChannel(entry, context, jsonBody, "json"),
|
|
378
|
+
contentType: "json"
|
|
379
|
+
};
|
|
380
|
+
const binaryBody = content["application/octet-stream"];
|
|
381
|
+
if (binaryBody) return {
|
|
382
|
+
channel: createRequestBodyChannel(entry, context, binaryBody, "binary"),
|
|
383
|
+
contentType: "binary"
|
|
384
|
+
};
|
|
385
|
+
const multipartBody = content["multipart/form-data"];
|
|
386
|
+
if (multipartBody) return {
|
|
387
|
+
channel: createRequestBodyChannel(entry, context, multipartBody, "formData"),
|
|
388
|
+
contentType: "formData"
|
|
389
|
+
};
|
|
390
|
+
throw new Error(`Operation "${entry.operationId ?? "unknown"}" has a requestBody but no supported content type`);
|
|
391
|
+
}
|
|
392
|
+
function createRequestBodyChannel(entry, context, body, kind) {
|
|
393
|
+
const typeRef = resolveRequestBodyTypeReference(entry, context, body, kind);
|
|
368
394
|
if (!typeRef) return {
|
|
369
395
|
present: false,
|
|
370
396
|
required: false,
|
|
@@ -376,10 +402,18 @@ function normalizeBodyChannel(entry, context) {
|
|
|
376
402
|
typeRef
|
|
377
403
|
};
|
|
378
404
|
}
|
|
379
|
-
function resolveRequestBodyTypeReference(entry, context) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
405
|
+
function resolveRequestBodyTypeReference(entry, context, body, kind) {
|
|
406
|
+
if (kind === "formData") return {
|
|
407
|
+
aliasDefinitionExpr: "FormData",
|
|
408
|
+
sourceExpr: "FormData",
|
|
409
|
+
typeName: allocateOperationTypeName(context, entry.funcName, "Request")
|
|
410
|
+
};
|
|
411
|
+
if (kind === "binary") return {
|
|
412
|
+
aliasDefinitionExpr: "Blob | File | ArrayBuffer | string",
|
|
413
|
+
sourceExpr: "Blob | File | ArrayBuffer | string",
|
|
414
|
+
typeName: allocateOperationTypeName(context, entry.funcName, "Request")
|
|
415
|
+
};
|
|
416
|
+
const schemaTypeRef = resolveSchemaTypeReference(context, body.schema);
|
|
383
417
|
if (schemaTypeRef) return schemaTypeRef;
|
|
384
418
|
return {
|
|
385
419
|
aliasDefinitionExpr: `operations['${entry.operationId}']['requestBody']['content']['application/json']`,
|
|
@@ -526,6 +560,7 @@ function createApiEntries(normalizedOps, useTypeAliases) {
|
|
|
526
560
|
return normalizedOps.map((op) => ({
|
|
527
561
|
funcName: op.entry.funcName,
|
|
528
562
|
group: op.entry.group,
|
|
563
|
+
bodyContentType: op.bodyContentType,
|
|
529
564
|
pathTypeExpr: op.pathChannel.typeRef == null ? null : useTypeAliases ? op.pathChannel.typeRef.typeName : op.pathChannel.typeRef.sourceExpr,
|
|
530
565
|
strippedPath: op.entry.strippedPath
|
|
531
566
|
}));
|
|
@@ -540,6 +575,7 @@ function createClientRenderModel(model, useTypeAliases) {
|
|
|
540
575
|
needsSearchParamsHelper: model.needsSearchParamsHelper,
|
|
541
576
|
operations: model.operations.map((operation) => ({
|
|
542
577
|
bodyChannel: resolveChannel(operation.bodyChannel, useTypeAliases),
|
|
578
|
+
bodyContentType: operation.bodyContentType,
|
|
543
579
|
builderAlias: operation.builderAlias,
|
|
544
580
|
funcName: operation.entry.funcName,
|
|
545
581
|
group: operation.entry.group,
|
package/dist/index.mjs
CHANGED
|
@@ -144,7 +144,11 @@ function createClientChannelField(key, channel) {
|
|
|
144
144
|
function createClientFunctionDeclaration(operation) {
|
|
145
145
|
const requestProperties = [ts.factory.createSpreadAssignment(ts.factory.createIdentifier("requestOptions")), ts.factory.createPropertyAssignment(ts.factory.createIdentifier("method"), ts.factory.createStringLiteral(operation.methodUpper))];
|
|
146
146
|
if (operation.queryChannel.present) requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("searchParams"), ts.factory.createCallExpression(ts.factory.createIdentifier("buildSearchParams"), void 0, [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "query")])));
|
|
147
|
-
if (operation.bodyChannel.present)
|
|
147
|
+
if (operation.bodyChannel.present) {
|
|
148
|
+
if (operation.bodyContentType === "json") requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("json"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "body")));
|
|
149
|
+
else requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("body"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "body")));
|
|
150
|
+
if (operation.bodyContentType === "binary") requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("contentType"), ts.factory.createStringLiteral("application/octet-stream")));
|
|
151
|
+
}
|
|
148
152
|
requestProperties.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier("signal"), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("options"), "signal")));
|
|
149
153
|
const requestCall = ts.factory.createCallExpression(ts.factory.createIdentifier(operation.requestFunction), operation.responseTypeExpr ? [createTypeNodeFromText(operation.responseTypeExpr)] : void 0, [parseExpression(operation.pathInvocationExpr), ts.factory.createObjectLiteralExpression(requestProperties, true)]);
|
|
150
154
|
return ts.factory.createFunctionDeclaration([createExportModifier()], void 0, ts.factory.createIdentifier(operation.funcName), void 0, [ts.factory.createParameterDeclaration(void 0, void 0, ts.factory.createIdentifier("options"), void 0, ts.factory.createTypeReferenceNode(operation.optionTypeName)), ts.factory.createParameterDeclaration(void 0, void 0, ts.factory.createIdentifier("requestOptions"), void 0, ts.factory.createTypeReferenceNode("RuntimeRequestOptions"), ts.factory.createObjectLiteralExpression())], createTypeNodeFromText(operation.returnTypeExpr), ts.factory.createBlock([ts.factory.createReturnStatement(requestCall)], true));
|
|
@@ -240,13 +244,6 @@ function getParametersByLocation(operation, location) {
|
|
|
240
244
|
function hasRequiredChannel(parameters) {
|
|
241
245
|
return parameters.some((parameter) => parameter.required);
|
|
242
246
|
}
|
|
243
|
-
function getJsonRequestBody(operation) {
|
|
244
|
-
const requestBody = operation.requestBody;
|
|
245
|
-
if (!requestBody) return void 0;
|
|
246
|
-
const jsonBody = requestBody.content?.["application/json"];
|
|
247
|
-
if (!jsonBody) throw new Error(`Operation "${operation.operationId ?? "unknown"}" has a requestBody but no application/json content`);
|
|
248
|
-
return jsonBody;
|
|
249
|
-
}
|
|
250
247
|
function getSuccessResponseInfo(operation) {
|
|
251
248
|
const successResponses = Object.entries(operation.responses ?? {}).filter(([statusKey]) => isSuccessStatus(statusKey)).sort(([left], [right]) => Number(left) - Number(right));
|
|
252
249
|
if (successResponses.length === 0) throw new Error(`Operation "${operation.operationId ?? "unknown"}" has no 2xx success response`);
|
|
@@ -333,10 +330,11 @@ function normalizeOperation(entry, context, requestFunctionNames) {
|
|
|
333
330
|
const builderAlias = getBuilderAlias(entry.funcName);
|
|
334
331
|
const pathChannel = normalizeParameterChannel(entry, context, "path");
|
|
335
332
|
const queryChannel = normalizeParameterChannel(entry, context, "query");
|
|
336
|
-
const
|
|
333
|
+
const bodyResolution = normalizeBodyChannel(entry, context);
|
|
337
334
|
const responseTypeRef = resolveResponseTypeReference(entry, context, successResponse);
|
|
338
335
|
return {
|
|
339
|
-
bodyChannel,
|
|
336
|
+
bodyChannel: bodyResolution.channel,
|
|
337
|
+
bodyContentType: bodyResolution.contentType,
|
|
340
338
|
builderAlias,
|
|
341
339
|
entry,
|
|
342
340
|
optionTypeName: getClientOptionTypeName(entry.funcName),
|
|
@@ -362,7 +360,35 @@ function normalizeParameterChannel(entry, context, location) {
|
|
|
362
360
|
};
|
|
363
361
|
}
|
|
364
362
|
function normalizeBodyChannel(entry, context) {
|
|
365
|
-
const
|
|
363
|
+
const requestBody = entry.operation.requestBody;
|
|
364
|
+
if (!requestBody) return {
|
|
365
|
+
channel: {
|
|
366
|
+
present: false,
|
|
367
|
+
required: false,
|
|
368
|
+
typeRef: null
|
|
369
|
+
},
|
|
370
|
+
contentType: null
|
|
371
|
+
};
|
|
372
|
+
const content = requestBody.content ?? {};
|
|
373
|
+
const jsonBody = content["application/json"];
|
|
374
|
+
if (jsonBody) return {
|
|
375
|
+
channel: createRequestBodyChannel(entry, context, jsonBody, "json"),
|
|
376
|
+
contentType: "json"
|
|
377
|
+
};
|
|
378
|
+
const binaryBody = content["application/octet-stream"];
|
|
379
|
+
if (binaryBody) return {
|
|
380
|
+
channel: createRequestBodyChannel(entry, context, binaryBody, "binary"),
|
|
381
|
+
contentType: "binary"
|
|
382
|
+
};
|
|
383
|
+
const multipartBody = content["multipart/form-data"];
|
|
384
|
+
if (multipartBody) return {
|
|
385
|
+
channel: createRequestBodyChannel(entry, context, multipartBody, "formData"),
|
|
386
|
+
contentType: "formData"
|
|
387
|
+
};
|
|
388
|
+
throw new Error(`Operation "${entry.operationId ?? "unknown"}" has a requestBody but no supported content type`);
|
|
389
|
+
}
|
|
390
|
+
function createRequestBodyChannel(entry, context, body, kind) {
|
|
391
|
+
const typeRef = resolveRequestBodyTypeReference(entry, context, body, kind);
|
|
366
392
|
if (!typeRef) return {
|
|
367
393
|
present: false,
|
|
368
394
|
required: false,
|
|
@@ -374,10 +400,18 @@ function normalizeBodyChannel(entry, context) {
|
|
|
374
400
|
typeRef
|
|
375
401
|
};
|
|
376
402
|
}
|
|
377
|
-
function resolveRequestBodyTypeReference(entry, context) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
403
|
+
function resolveRequestBodyTypeReference(entry, context, body, kind) {
|
|
404
|
+
if (kind === "formData") return {
|
|
405
|
+
aliasDefinitionExpr: "FormData",
|
|
406
|
+
sourceExpr: "FormData",
|
|
407
|
+
typeName: allocateOperationTypeName(context, entry.funcName, "Request")
|
|
408
|
+
};
|
|
409
|
+
if (kind === "binary") return {
|
|
410
|
+
aliasDefinitionExpr: "Blob | File | ArrayBuffer | string",
|
|
411
|
+
sourceExpr: "Blob | File | ArrayBuffer | string",
|
|
412
|
+
typeName: allocateOperationTypeName(context, entry.funcName, "Request")
|
|
413
|
+
};
|
|
414
|
+
const schemaTypeRef = resolveSchemaTypeReference(context, body.schema);
|
|
381
415
|
if (schemaTypeRef) return schemaTypeRef;
|
|
382
416
|
return {
|
|
383
417
|
aliasDefinitionExpr: `operations['${entry.operationId}']['requestBody']['content']['application/json']`,
|
|
@@ -524,6 +558,7 @@ function createApiEntries(normalizedOps, useTypeAliases) {
|
|
|
524
558
|
return normalizedOps.map((op) => ({
|
|
525
559
|
funcName: op.entry.funcName,
|
|
526
560
|
group: op.entry.group,
|
|
561
|
+
bodyContentType: op.bodyContentType,
|
|
527
562
|
pathTypeExpr: op.pathChannel.typeRef == null ? null : useTypeAliases ? op.pathChannel.typeRef.typeName : op.pathChannel.typeRef.sourceExpr,
|
|
528
563
|
strippedPath: op.entry.strippedPath
|
|
529
564
|
}));
|
|
@@ -538,6 +573,7 @@ function createClientRenderModel(model, useTypeAliases) {
|
|
|
538
573
|
needsSearchParamsHelper: model.needsSearchParamsHelper,
|
|
539
574
|
operations: model.operations.map((operation) => ({
|
|
540
575
|
bodyChannel: resolveChannel(operation.bodyChannel, useTypeAliases),
|
|
576
|
+
bodyContentType: operation.bodyContentType,
|
|
541
577
|
builderAlias: operation.builderAlias,
|
|
542
578
|
funcName: operation.entry.funcName,
|
|
543
579
|
group: operation.entry.group,
|