swaggie 1.5.2 → 1.5.3-beta.2
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 +20 -1
- package/dist/gen/genOperations.js +6 -3
- package/dist/gen/genTypes.js +8 -1
- package/dist/swagger/typesExtractor.js +38 -8
- package/dist/types.d.ts +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -103,6 +103,7 @@ Sample configuration looks like this:
|
|
|
103
103
|
"preferAny": true,
|
|
104
104
|
"servicePrefix": "",
|
|
105
105
|
"dateFormat": "Date", // "string" | "Date"
|
|
106
|
+
"nullableStrategy": "ignore", // "ignore" | "include" | "nullableAsOptional"
|
|
106
107
|
"queryParamsSerialization": {
|
|
107
108
|
"arrayFormat": "repeat", // "repeat" | "brackets" | "indices"
|
|
108
109
|
"allowDots": true
|
|
@@ -162,6 +163,24 @@ Once you know what your backend expects, you can adjust the configuration file a
|
|
|
162
163
|
}
|
|
163
164
|
```
|
|
164
165
|
|
|
166
|
+
### Nullable Strategy
|
|
167
|
+
|
|
168
|
+
OpenAPI 3.0 allows marking fields as `nullable: true`. Swaggie provides three strategies for translating this into TypeScript, controlled by the `nullableStrategy` option:
|
|
169
|
+
|
|
170
|
+
| Value | Description |
|
|
171
|
+
| ---------------------- | ---------------------------------------------------------------------------------- |
|
|
172
|
+
| `"ignore"` (default) | `nullable: true` is ignored. Types are generated as if `nullable` was not set. |
|
|
173
|
+
| `"include"` | `nullable: true` appends `\| null` to the TypeScript type (e.g. `string \| null`). |
|
|
174
|
+
| `"nullableAsOptional"` | `nullable: true` makes the property optional (`?`) instead of adding `\| null`. |
|
|
175
|
+
|
|
176
|
+
**Examples** for a schema with `tenant: { type: 'string', nullable: true }` (required):
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// nullableStrategy: "ignore" → tenant: string;
|
|
180
|
+
// nullableStrategy: "include" → tenant: string | null;
|
|
181
|
+
// nullableStrategy: "nullableAsOptional" → tenant?: string;
|
|
182
|
+
```
|
|
183
|
+
|
|
165
184
|
### Code Quality
|
|
166
185
|
|
|
167
186
|
> Please note that it's **recommended** to pipe Swaggie command to some prettifier like `prettier`, `biome` or `dprint` to make the generated code look not only nice, but also persistent.
|
|
@@ -301,7 +320,7 @@ function error(e) {
|
|
|
301
320
|
| Content types: `JSON`, `text`, `multipart/form-data` | Multiple request types (only one will be used) |
|
|
302
321
|
| Content types: `application/x-www-form-urlencoded`, `application/octet-stream` | References to other spec files |
|
|
303
322
|
| Different types of enum definitions (+ OpenAPI 3.1 support for enums) | OpenAPI callbacks |
|
|
304
|
-
| Paths inheritance, comments (descriptions)
|
|
323
|
+
| Paths inheritance, comments (descriptions), nullable | OpenAPI webhooks |
|
|
305
324
|
| Getting documents from remote locations or as path reference (local file) | |
|
|
306
325
|
| Grouping endpoints by tags + handle gracefully duplicate operation ids | |
|
|
307
326
|
|
|
@@ -98,7 +98,7 @@ function prepareClient(
|
|
|
98
98
|
const [respObject, responseContentType] = _utils.getBestResponse.call(void 0, op);
|
|
99
99
|
const returnType = _swagger.getParameterType.call(void 0, respObject, options);
|
|
100
100
|
|
|
101
|
-
const body = getRequestBody(op.requestBody);
|
|
101
|
+
const body = getRequestBody(op.requestBody, options);
|
|
102
102
|
const queryParams = getParams(op.parameters , options, ['query']);
|
|
103
103
|
const params = getParams(op.parameters , options);
|
|
104
104
|
|
|
@@ -278,7 +278,10 @@ function prepareUrl(path) {
|
|
|
278
278
|
);
|
|
279
279
|
} exports.getParamName = getParamName;
|
|
280
280
|
|
|
281
|
-
function getRequestBody(
|
|
281
|
+
function getRequestBody(
|
|
282
|
+
reqBody,
|
|
283
|
+
options
|
|
284
|
+
) {
|
|
282
285
|
if (reqBody && 'content' in reqBody) {
|
|
283
286
|
const [bodyContent, contentType] = _utils.getBestContentType.call(void 0, reqBody);
|
|
284
287
|
const isFormData = contentType === 'form-data';
|
|
@@ -287,7 +290,7 @@ function getRequestBody(reqBody) {
|
|
|
287
290
|
return {
|
|
288
291
|
originalName: _nullishCoalesce(reqBody['x-name'], () => ( 'body')),
|
|
289
292
|
name: getParamName(_nullishCoalesce(reqBody['x-name'], () => ( 'body'))),
|
|
290
|
-
type: isFormData ? 'FormData' : _swagger.getParameterType.call(void 0, bodyContent,
|
|
293
|
+
type: isFormData ? 'FormData' : _swagger.getParameterType.call(void 0, bodyContent, options),
|
|
291
294
|
optional: !reqBody.required,
|
|
292
295
|
original: reqBody,
|
|
293
296
|
contentType,
|
package/dist/gen/genTypes.js
CHANGED
|
@@ -200,7 +200,14 @@ function renderTypeProp(
|
|
|
200
200
|
if ('description' in definition || 'title' in definition) {
|
|
201
201
|
lines.push(_jsDocs.renderComment.call(void 0, _nullishCoalesce(definition.description, () => ( definition.title))));
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
|
|
204
|
+
// When nullableAsOptional strategy is set, nullable properties are treated as optional
|
|
205
|
+
const isNullableAsOptional =
|
|
206
|
+
options.nullableStrategy === 'nullableAsOptional' &&
|
|
207
|
+
!('$ref' in definition) &&
|
|
208
|
+
(definition ).nullable === true;
|
|
209
|
+
const isOptional = !required || isNullableAsOptional;
|
|
210
|
+
const optionalMark = isOptional ? '?' : '';
|
|
204
211
|
// If prop name is not a valid identifier, we need to wrap it in quotes.
|
|
205
212
|
// We can't use getSafeIdentifier here because it will affect the data model.
|
|
206
213
|
const safePropName = _utils.escapePropName.call(void 0, propName);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
2
|
|
|
3
3
|
var _utils = require('../utils');
|
|
4
4
|
|
|
@@ -48,25 +48,42 @@ var _utils = require('../utils');
|
|
|
48
48
|
return getSafeIdentifier(refName) || unknownType;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
if (schema.type === 'null') {
|
|
52
|
+
return 'null';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isNullable = 'nullable' in schema && schema.nullable === true;
|
|
56
|
+
const strategy = _nullishCoalesce(options.nullableStrategy, () => ( 'ignore'));
|
|
57
|
+
const isNullableSuffix = isNullable && strategy === 'include' ? ' | null' : '';
|
|
58
|
+
const type = getTypeFromSchemaInternal(schema, options);
|
|
59
|
+
|
|
60
|
+
if (isNullableSuffix && type.endsWith('| null')) {
|
|
61
|
+
return type;
|
|
62
|
+
}
|
|
63
|
+
return type + isNullableSuffix;
|
|
64
|
+
} exports.getTypeFromSchema = getTypeFromSchema;
|
|
65
|
+
|
|
66
|
+
function getTypeFromSchemaInternal(
|
|
67
|
+
schema,
|
|
68
|
+
options
|
|
69
|
+
) {
|
|
70
|
+
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
71
|
+
|
|
51
72
|
if ('allOf' in schema || 'oneOf' in schema || 'anyOf' in schema) {
|
|
52
73
|
return getTypeFromComposites(schema , options);
|
|
53
74
|
}
|
|
54
75
|
|
|
55
76
|
if (schema.type === 'array') {
|
|
56
77
|
if (schema.items) {
|
|
57
|
-
return `${
|
|
78
|
+
return `${getNestedTypeFromSchema(schema.items, options)}[]`;
|
|
58
79
|
}
|
|
59
80
|
return `${unknownType}[]`;
|
|
60
81
|
}
|
|
61
82
|
if (schema.type === 'object') {
|
|
62
83
|
return getTypeFromObject(schema, options);
|
|
63
84
|
}
|
|
64
|
-
if (schema.type === 'null') {
|
|
65
|
-
return 'null';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
85
|
if ('enum' in schema) {
|
|
69
|
-
return
|
|
86
|
+
return `${schema.enum.map((v) => JSON.stringify(v)).join(' | ')}`;
|
|
70
87
|
}
|
|
71
88
|
if (schema.type === 'integer' || schema.type === 'number') {
|
|
72
89
|
return 'number';
|
|
@@ -81,7 +98,20 @@ var _utils = require('../utils');
|
|
|
81
98
|
return 'boolean';
|
|
82
99
|
}
|
|
83
100
|
return unknownType;
|
|
84
|
-
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getNestedTypeFromSchema(
|
|
104
|
+
schema,
|
|
105
|
+
options
|
|
106
|
+
) {
|
|
107
|
+
const strategy = _nullishCoalesce(options.nullableStrategy, () => ( 'ignore'));
|
|
108
|
+
const isNullableAndActive =
|
|
109
|
+
'nullable' in schema && schema.nullable === true && strategy === 'include';
|
|
110
|
+
if (isNullableAndActive || ('enum' in schema && schema.enum)) {
|
|
111
|
+
return `(${getTypeFromSchema(schema, options)})`;
|
|
112
|
+
}
|
|
113
|
+
return getTypeFromSchema(schema, options);
|
|
114
|
+
}
|
|
85
115
|
|
|
86
116
|
/**
|
|
87
117
|
* Knowing that the schema is an object, this function returns a TypeScript type definition
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export interface ClientOptions {
|
|
|
20
20
|
servicePrefix?: string;
|
|
21
21
|
/** How date should be handled. It does not do any special serialization */
|
|
22
22
|
dateFormat?: DateSupport;
|
|
23
|
+
/**
|
|
24
|
+
* Controls how OpenAPI 'nullable' is translated into TypeScript types. Default: 'ignore'.
|
|
25
|
+
* 'include' - 'nullable: true' appends `| null` to the TypeScript type (e.g. `string | null`).
|
|
26
|
+
* 'nullableAsOptional' - 'nullable: true' makes the property optional (`?`) instead of adding `| null`.
|
|
27
|
+
* 'ignore' - 'nullable: true' is ignored.
|
|
28
|
+
*/
|
|
29
|
+
nullableStrategy?: NullableStrategy;
|
|
23
30
|
/** Options for query parameters serialization */
|
|
24
31
|
queryParamsSerialization: QueryParamsSerializationOptions;
|
|
25
32
|
/** Offers ability to adjust the OpenAPI spec before it is processed */
|
|
@@ -42,6 +49,7 @@ export type Template = 'axios' | 'fetch' | 'ng1' | 'ng2' | 'swr-axios' | 'xior'
|
|
|
42
49
|
export type HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch';
|
|
43
50
|
export type DateSupport = 'string' | 'Date';
|
|
44
51
|
export type ArrayFormat = 'indices' | 'repeat' | 'brackets';
|
|
52
|
+
export type NullableStrategy = 'include' | 'nullableAsOptional' | 'ignore';
|
|
45
53
|
/**
|
|
46
54
|
* Local type that represent Operation as understood by Swaggie
|
|
47
55
|
**/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swaggie",
|
|
3
|
-
"version": "1.5.2",
|
|
3
|
+
"version": "1.5.3-beta.2",
|
|
4
4
|
"description": "Generate TypeScript REST client code from an OpenAPI spec",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Piotr Dabrowski",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"homepage": "https://github.com/yhnavein/swaggie",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "https://github.com/yhnavein/swaggie.git"
|
|
13
|
+
"url": "git+https://github.com/yhnavein/swaggie.git"
|
|
14
14
|
},
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/yhnavein/swaggie/issues"
|