Skip to content

Commit ff1f9f0

Browse files
committed
fix: configure jsdoc generation for API Client Errors, add protected where necessary
1 parent b072527 commit ff1f9f0

File tree

6 files changed

+136
-55
lines changed

6 files changed

+136
-55
lines changed

docs/interfaces/openapi_client.OpenApiClientGeneratorConfigClient.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Configuration for generating the client.
1414
- [errorClassName](openapi_client.OpenApiClientGeneratorConfigClient.md#errorclassname)
1515
- [exportErrorClass](openapi_client.OpenApiClientGeneratorConfigClient.md#exporterrorclass)
1616
- [exportModels](openapi_client.OpenApiClientGeneratorConfigClient.md#exportmodels)
17+
- [exportOptionsType](openapi_client.OpenApiClientGeneratorConfigClient.md#exportoptionstype)
1718
- [exportServices](openapi_client.OpenApiClientGeneratorConfigClient.md#exportservices)
1819
- [filename](openapi_client.OpenApiClientGeneratorConfigClient.md#filename)
1920
- [filenameFormat](openapi_client.OpenApiClientGeneratorConfigClient.md#filenameformat)
21+
- [generateErrorJsDoc](openapi_client.OpenApiClientGeneratorConfigClient.md#generateerrorjsdoc)
2022
- [generateJsDoc](openapi_client.OpenApiClientGeneratorConfigClient.md#generatejsdoc)
2123
- [includeServices](openapi_client.OpenApiClientGeneratorConfigClient.md#includeservices)
2224
- [name](openapi_client.OpenApiClientGeneratorConfigClient.md#name)
@@ -69,6 +71,20 @@ Whether to export models from the client file.
6971

7072
___
7173

74+
### exportOptionsType
75+
76+
`Optional` **exportOptionsType**: `boolean`
77+
78+
Whether to export the client constructor options type.
79+
80+
**`Default`**
81+
82+
```ts
83+
true
84+
```
85+
86+
___
87+
7288
### exportServices
7389

7490
`Optional` **exportServices**: ``"all"`` \| ``"none"`` \| \{ `services`: `string`[] }
@@ -105,6 +121,14 @@ Filename format for the client class. Ignored if `filename` is set.
105121

106122
___
107123

124+
### generateErrorJsDoc
125+
126+
`Optional` **generateErrorJsDoc**: `GenerateClientErrorJsDoc`
127+
128+
Client error class JSDoc generation callback.
129+
130+
___
131+
108132
### generateJsDoc
109133

110134
`Optional` **generateJsDoc**: [`GenerateClientJsDoc`](../modules/openapi_client.md#generateclientjsdoc)

src/schema-to-typescript/common.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Identifier,
99
identifier,
1010
isValidIdentifier,
11+
Noop,
1112
nullLiteral,
1213
NumericLiteral,
1314
numericLiteral,
@@ -34,7 +35,8 @@ import {
3435
tsTypeLiteral,
3536
tsTypeReference,
3637
tsUnionType,
37-
tsUnknownKeyword
38+
tsUnknownKeyword,
39+
TypeAnnotation
3840
} from '@babel/types';
3941
import {OpenApiClientGeneratorConfig} from './openapi-to-typescript-client';
4042
import {
@@ -317,7 +319,10 @@ export function isNamedSchema(schema: OpenApiSchema): schema is OpenApiExpandedS
317319
return typeof schema !== 'boolean' && schema.name !== undefined;
318320
}
319321

320-
export function attachTypeAnnotation(node: Identifier, typeAnnotation: TSTypeAnnotation): Identifier {
322+
export function attachTypeAnnotation<T extends {typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null}>(
323+
node: T,
324+
typeAnnotation: TSTypeAnnotation
325+
): T {
321326
node.typeAnnotation = typeAnnotation;
322327
return node;
323328
}

src/schema-to-typescript/common/client.ts

Lines changed: 57 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {generateOperationMethods} from './operation-methods';
3434
import {GeneratedServicesImportInfo} from './services';
3535
import {OpenApiInfo, OpenApiServer} from '../../schemas/common';
3636
import {OpenApiPaths} from '../../schemas/openapi';
37+
import {makeProtected} from '../../utils/ast';
3738
import {
3839
addDependencyImport,
3940
DependencyImports,
@@ -67,8 +68,10 @@ export function generateClient({
6768
exportModels,
6869
exportServices,
6970
exportErrorClass,
71+
exportOptionsType,
7072
errorClassName,
7173
generateJsDoc,
74+
generateErrorJsDoc,
7275
...filenameConfig
7376
},
7477
generatedServiceImports,
@@ -107,41 +110,47 @@ export function generateClient({
107110
const clientPropertyName = 'client';
108111
const commonHttpClientImportName = 'commonHttpClient';
109112
const {importPath: clientImportPath, filename} = getFilenameAndImportPath(name, filenameConfig);
110-
const clientProperty = classProperty(identifier(clientPropertyName));
111-
clientProperty.typeAnnotation = tsTypeAnnotation(
112-
tsTypeReference(tsQualifiedName(identifier(commonHttpClientImportName), identifier(commonHttpClientClassName)))
113-
);
114-
115113
const errorTypeName = errorClassName ?? `${name}Error`;
116114
const additionalTypeStatements: Statement[] = [];
117115
const errorClassDeclaration = classDeclaration(
118116
identifier(errorTypeName),
119117
memberExpression(identifier(commonHttpClientImportName), identifier(commonHttpClientErrorClassName)),
120118
classBody([classProperty(identifier('name'), stringLiteral(errorTypeName))])
121119
);
122-
if (exportErrorClass !== false) {
123-
additionalTypeStatements.push(exportNamedDeclaration(errorClassDeclaration));
124-
} else {
125-
additionalTypeStatements.push(errorClassDeclaration);
126-
}
120+
const errorClassSuggestedJsDoc: JsDocBlock = {title: `Error class for ${info.summary}`, tags: []};
121+
additionalTypeStatements.push(
122+
attachJsDocComment(
123+
exportErrorClass !== false ? exportNamedDeclaration(errorClassDeclaration) : errorClassDeclaration,
124+
renderJsDoc(
125+
generateErrorJsDoc
126+
? generateErrorJsDoc({suggestedJsDoc: errorClassSuggestedJsDoc, info})
127+
: errorClassSuggestedJsDoc,
128+
jsDocRenderConfig
129+
)
130+
)
131+
);
127132

128133
const clientClassBody = classBody([
129-
classProperty(
130-
identifier(clientPropertyName),
131-
newExpression(
132-
memberExpression(identifier(commonHttpClientImportName), identifier(commonHttpClientClassName)),
133-
[
134-
objectExpression([
135-
objectProperty(identifier('baseUrl'), stringLiteral(servers[0]?.url ?? defaultServerUrl)),
136-
objectProperty(identifier('binaryResponseType'), stringLiteral(responseBinaryType)),
137-
objectProperty(identifier('errorClass'), identifier(errorTypeName))
138-
])
139-
]
134+
makeProtected(
135+
classProperty(
136+
identifier(clientPropertyName),
137+
newExpression(
138+
memberExpression(identifier(commonHttpClientImportName), identifier(commonHttpClientClassName)),
139+
[
140+
objectExpression([
141+
objectProperty(identifier('baseUrl'), stringLiteral(servers[0]?.url ?? defaultServerUrl)),
142+
objectProperty(identifier('binaryResponseType'), stringLiteral(responseBinaryType)),
143+
objectProperty(identifier('errorClass'), identifier(errorTypeName))
144+
])
145+
]
146+
)
140147
)
141148
),
142-
classProperty(
143-
identifier('getClient'),
144-
arrowFunctionExpression([], memberExpression(thisExpression(), identifier(clientPropertyName)))
149+
makeProtected(
150+
classProperty(
151+
identifier('getClient'),
152+
arrowFunctionExpression([], memberExpression(thisExpression(), identifier(clientPropertyName)))
153+
)
145154
)
146155
]);
147156
const dependencyImports: DependencyImports = {};
@@ -186,23 +195,23 @@ export function generateClient({
186195
}
187196

188197
const optionsTypeName = `${name}Options`;
189-
const optionsTypeExport = exportNamedDeclaration(
190-
tsTypeAliasDeclaration(
191-
identifier(optionsTypeName),
192-
null,
193-
tsTypeReference(
194-
identifier('Partial'),
195-
tsTypeParameterInstantiation([
196-
tsTypeReference(
197-
tsQualifiedName(
198-
identifier(commonHttpClientImportName),
199-
identifier(commonHttpClientClassOptionsName)
200-
)
198+
const optionsTypeDeclaration = tsTypeAliasDeclaration(
199+
identifier(optionsTypeName),
200+
null,
201+
tsTypeReference(
202+
identifier('Partial'),
203+
tsTypeParameterInstantiation([
204+
tsTypeReference(
205+
tsQualifiedName(
206+
identifier(commonHttpClientImportName),
207+
identifier(commonHttpClientClassOptionsName)
201208
)
202-
])
203-
)
209+
)
210+
])
204211
)
205212
);
213+
const optionsTypeStatement =
214+
exportOptionsType === false ? optionsTypeDeclaration : exportNamedDeclaration(optionsTypeDeclaration);
206215

207216
const generatedMethods = generateOperationMethods({
208217
paths,
@@ -260,13 +269,15 @@ export function generateClient({
260269

261270
if (generatedMethods.validationStatements.length > 0) {
262271
clientClassBody.body.push(
263-
classMethod(
264-
'method',
265-
identifier('initialize'),
266-
[],
267-
blockStatement(generatedMethods.validationStatements),
268-
false,
269-
true
272+
makeProtected(
273+
classMethod(
274+
'method',
275+
identifier('initialize'),
276+
[],
277+
blockStatement(generatedMethods.validationStatements),
278+
false,
279+
true
280+
)
270281
)
271282
);
272283
}
@@ -350,7 +361,7 @@ export function generateClient({
350361
stringLiteral(getRelativeImportPath(clientImportPath, commonHttpClientImportPath))
351362
),
352363
...generateTsImports(dependencyImports),
353-
optionsTypeExport,
364+
optionsTypeStatement,
354365
...additionalTypeStatements,
355366
clientClass,
356367
...otherStatements,

src/schema-to-typescript/common/services.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import {GetModelData} from './models';
1717
import {generateOperationMethods} from './operation-methods';
1818
import {openApiHttpMethods, OpenApiPaths, OpenApiTag} from '../../schemas/openapi';
19+
import {makeProtected} from '../../utils/ast';
1920
import {generateTsImports} from '../../utils/dependencies';
2021
import {attachJsDocComment, JsDocBlock, JsDocRenderConfig, renderJsDoc} from '../../utils/jsdoc';
2122
import {getRelativeImportPath} from '../../utils/paths';
@@ -142,13 +143,15 @@ export function generateServices({
142143

143144
if (serviceMethods.validationStatements.length > 0) {
144145
serviceClassBody.body.push(
145-
classMethod(
146-
'method',
147-
identifier('initialize'),
148-
[],
149-
blockStatement(serviceMethods.validationStatements),
150-
false,
151-
true
146+
makeProtected(
147+
classMethod(
148+
'method',
149+
identifier('initialize'),
150+
[],
151+
blockStatement(serviceMethods.validationStatements),
152+
false,
153+
true
154+
)
152155
)
153156
);
154157
}

src/schema-to-typescript/openapi-to-typescript-client.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,28 @@ export type GenerateClientJsDoc = (params: {
511511
info: OpenApiInfo;
512512
}) => JsDocBlock;
513513

514+
/**
515+
* Callback for generating the JSDoc of a client.
516+
*
517+
* @example
518+
* function generateClientErrorJsDoc({suggestedJsDoc, info}) {
519+
* return {
520+
* ...suggestedJsDoc,
521+
* title: 'Error Class for ' + info.summary
522+
* };
523+
* }
524+
*/
525+
export type GenerateClientErrorJsDoc = (params: {
526+
/**
527+
* Suggested JSDoc block. Used by default if the callback is not specified.
528+
*/
529+
suggestedJsDoc: JsDocBlock;
530+
/**
531+
* OpenAPI Info Object.
532+
*/
533+
info: OpenApiInfo;
534+
}) => JsDocBlock;
535+
514536
/**
515537
* What needs to be imported from the external source.
516538
*/
@@ -715,10 +737,20 @@ export interface OpenApiClientGeneratorConfigClient {
715737
* @default true
716738
*/
717739
exportErrorClass?: boolean;
740+
/**
741+
* Whether to export the client constructor options type.
742+
*
743+
* @default true
744+
*/
745+
exportOptionsType?: boolean;
718746
/**
719747
* Client JSDoc generation callback.
720748
*/
721749
generateJsDoc?: GenerateClientJsDoc;
750+
/**
751+
* Client error class JSDoc generation callback.
752+
*/
753+
generateErrorJsDoc?: GenerateClientErrorJsDoc;
722754
}
723755

724756
/**

src/utils/ast.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {ClassMethod, ClassProperty} from '@babel/types';
2+
3+
export function makeProtected(entity: ClassProperty | ClassMethod) {
4+
entity.accessibility = 'protected';
5+
return entity;
6+
}

0 commit comments

Comments
 (0)