swaggie 1.8.0 → 1.8.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 +14 -4
- package/dist/cli.js +6 -1
- package/dist/gen/genOperations.js +69 -35
- package/dist/gen/genTypes.js +57 -25
- package/dist/index.js +3 -0
- package/dist/swagger/typesExtractor.js +142 -30
- package/dist/types.d.ts +5 -0
- package/dist/utils/utils.js +19 -2
- package/package.json +1 -1
- package/templates/fetch/operation.ejs +30 -10
package/README.md
CHANGED
|
@@ -80,7 +80,8 @@ swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./client/petstore
|
|
|
80
80
|
-t, --template <string> Template to use for code generation (default: "axios")
|
|
81
81
|
-m, --mode <mode> Generation mode: "full" or "schemas" (default: "full")
|
|
82
82
|
-d, --schemaStyle <style> Schema object style: "interface" or "type" (default: "interface")
|
|
83
|
-
--
|
|
83
|
+
--enumStyle <style> Enum style for plain string enums: "union" or "enum" (default: "union")
|
|
84
|
+
--preferAny Use "any" instead of "unknown" for untyped values (default: false)
|
|
84
85
|
--skipDeprecated Exclude deprecated operations from the output (default: false)
|
|
85
86
|
--servicePrefix Prefix for service names — useful when generating multiple APIs
|
|
86
87
|
--allowDots Use dot notation to serialize nested object query params
|
|
@@ -123,6 +124,7 @@ swaggie -c swaggie.config.json
|
|
|
123
124
|
"nullableStrategy": "ignore",
|
|
124
125
|
"generationMode": "full",
|
|
125
126
|
"schemaDeclarationStyle": "interface",
|
|
127
|
+
"enumDeclarationStyle": "union",
|
|
126
128
|
"queryParamsSerialization": {
|
|
127
129
|
"arrayFormat": "repeat",
|
|
128
130
|
"allowDots": true
|
|
@@ -279,6 +281,14 @@ Use `schemaDeclarationStyle` (or CLI `--schemaStyle`) to control object schema o
|
|
|
279
281
|
| `"interface"`| `export interface Tag { ... }` (default) |
|
|
280
282
|
| `"type"` | `export type Tag = { ... };` |
|
|
281
283
|
|
|
284
|
+
### Enum Declaration Style
|
|
285
|
+
|
|
286
|
+
Use `enumDeclarationStyle` (or CLI `--enumStyle`) for plain string enums:
|
|
287
|
+
- `"union"` (default): `export type Status = "active" | "disabled";`
|
|
288
|
+
- `"enum"`: `export enum Status { active = "active", disabled = "disabled" }`
|
|
289
|
+
|
|
290
|
+
Note: this applies only to plain string enums. Non-string enums are still emitted as union types.
|
|
291
|
+
|
|
282
292
|
### Parameter Modifiers
|
|
283
293
|
|
|
284
294
|
Sometimes an API spec marks a parameter as required, but your client handles it in an interceptor and you don't want it cluttering every method signature. Parameter modifiers let you override this globally without touching the spec.
|
|
@@ -360,12 +370,12 @@ Swaggie only needs a JSON or YAML OpenAPI spec file — it does not require a ru
|
|
|
360
370
|
| Supported | Not Supported |
|
|
361
371
|
| ------------------------------------------------------------------------------ | ---------------------------------------------------- |
|
|
362
372
|
| OpenAPI 3.0, 3.1, 3.2 | Swagger / OpenAPI 2.0 |
|
|
363
|
-
| `allOf`, `oneOf`, `anyOf`, `$ref
|
|
373
|
+
| `allOf`, `oneOf`, `anyOf`, `$ref`, external $refs | `not` keyword |
|
|
364
374
|
| Spec formats: JSON, YAML | Very complex query parameter structures |
|
|
365
375
|
| Extensions: `x-position`, `x-name`, `x-enumNames`, `x-enum-varnames` | Multiple response types (only the first is used) |
|
|
366
376
|
| Content types: JSON, plain text, multipart/form-data | Multiple request body types (only the first is used) |
|
|
367
|
-
| Content types: `application/x-www-form-urlencoded`, `application/octet-stream` |
|
|
368
|
-
| Various enum definition styles
|
|
377
|
+
| Content types: `application/x-www-form-urlencoded`, `application/octet-stream` | OpenAPI callbacks and webhooks |
|
|
378
|
+
| Various enum definition styles, support for additionalProperties | |
|
|
369
379
|
| Nullable types, path inheritance, JSDoc descriptions | |
|
|
370
380
|
| Remote URLs and local file paths as spec source | |
|
|
371
381
|
| Grouping by tags, graceful handling of duplicate operation IDs | |
|
package/dist/cli.js
CHANGED
|
@@ -23,6 +23,10 @@ const schemaStyleOption = new (0, _commander.Option)(
|
|
|
23
23
|
'-d, --schemaStyle <style>',
|
|
24
24
|
'Schema object declaration style'
|
|
25
25
|
).choices(['interface', 'type']);
|
|
26
|
+
const enumStyleOption = new (0, _commander.Option)(
|
|
27
|
+
'--enumStyle <style>',
|
|
28
|
+
'Enum declaration style for plain string enums'
|
|
29
|
+
).choices(['union', 'enum']);
|
|
26
30
|
|
|
27
31
|
const program = new (0, _commander.Command)();
|
|
28
32
|
program
|
|
@@ -64,7 +68,8 @@ program
|
|
|
64
68
|
)
|
|
65
69
|
.addOption(arrayFormatOption)
|
|
66
70
|
.addOption(modeOption)
|
|
67
|
-
.addOption(schemaStyleOption)
|
|
71
|
+
.addOption(schemaStyleOption)
|
|
72
|
+
.addOption(enumStyleOption);
|
|
68
73
|
|
|
69
74
|
program.parse(process.argv);
|
|
70
75
|
|
|
@@ -96,45 +96,63 @@ function prepareClient(
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
return ops.map((op) => {
|
|
99
|
-
const
|
|
100
|
-
const returnType = _swagger.getParameterType.call(void 0, respObject, options);
|
|
99
|
+
const operationContext = `${op.method.toUpperCase()} ${op.path} (${op.operationId || 'unknown operationId'})`;
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
try {
|
|
102
|
+
const [respObject, responseContentType] = _utils.getBestResponse.call(void 0, op, components);
|
|
103
|
+
const returnType = _swagger.getParameterType.call(void 0, respObject, options);
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
const body = getRequestBody(op.requestBody, components, options);
|
|
106
|
+
const queryParams = getParams(op.parameters , options, ['query']);
|
|
107
|
+
const params = getParams(op.parameters , options);
|
|
108
|
+
|
|
109
|
+
if (body) {
|
|
110
|
+
params.unshift(body);
|
|
111
|
+
}
|
|
109
112
|
|
|
110
113
|
// If all parameters have 'x-position' defined, sort them by it
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
if (params.every((p) => p.original['x-position'])) {
|
|
115
|
+
params.sort((a, b) => a.original['x-position'] - b.original['x-position']);
|
|
116
|
+
}
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
markParametersAsSkippable(params);
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
const headers = getParams(
|
|
121
|
+
op.parameters ,
|
|
122
|
+
options,
|
|
123
|
+
['header']
|
|
124
|
+
);
|
|
125
|
+
// Some libraries need explicit Content-Type for request bodies.
|
|
126
|
+
if (_optionalChain([body, 'optionalAccess', _2 => _2.contentType]) === 'urlencoded') {
|
|
127
|
+
upsertFixedHeader(headers, 'Content-Type', 'application/x-www-form-urlencoded');
|
|
128
|
+
} else if (_optionalChain([body, 'optionalAccess', _3 => _3.contentType]) === 'json' && options.template === 'fetch') {
|
|
129
|
+
upsertFixedHeader(headers, 'Content-Type', 'application/json');
|
|
130
|
+
}
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
return {
|
|
133
|
+
jsDocs: _jsDocs.prepareJsDocsForOperation.call(void 0, op, params),
|
|
134
|
+
returnType,
|
|
135
|
+
responseContentType,
|
|
136
|
+
method: op.method.toUpperCase(),
|
|
137
|
+
name: getOperationName(op.operationId, op.group),
|
|
138
|
+
url: prepareUrl(op.path),
|
|
139
|
+
parameters: params,
|
|
140
|
+
query: queryParams,
|
|
141
|
+
body,
|
|
142
|
+
headers,
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
146
|
+
if (message.includes('Invalid schema at')) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Failed to prepare operation ${operationContext}. ` +
|
|
149
|
+
'Check if schema is valid for this operation. ' +
|
|
150
|
+
'Most common culprit is `properties.$ref` (use `schema.$ref` at root, or put `$ref` under a named property).'
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
throw new Error(`Failed to prepare operation ${operationContext}: ${message}`);
|
|
155
|
+
}
|
|
138
156
|
});
|
|
139
157
|
} exports.prepareOperations = prepareOperations;
|
|
140
158
|
|
|
@@ -237,10 +255,10 @@ function prepareUrl(path) {
|
|
|
237
255
|
type: _swagger.getParameterType.call(void 0, p, options),
|
|
238
256
|
optional: p.required === undefined || p.required === null ? true : !p.required,
|
|
239
257
|
original: p,
|
|
240
|
-
jsDoc: _optionalChain([p, 'access',
|
|
258
|
+
jsDoc: _optionalChain([p, 'access', _4 => _4.description, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]),
|
|
241
259
|
}));
|
|
242
260
|
|
|
243
|
-
if (_optionalChain([options, 'access',
|
|
261
|
+
if (_optionalChain([options, 'access', _7 => _7.modifiers, 'optionalAccess', _8 => _8.parameters])) {
|
|
244
262
|
for (const [name, modifier] of Object.entries(options.modifiers.parameters)) {
|
|
245
263
|
const paramIndex = result.findIndex(
|
|
246
264
|
(p) => p.original.in !== 'path' && (p.originalName === name || p.name === name)
|
|
@@ -291,7 +309,7 @@ function getRequestBody(
|
|
|
291
309
|
let reqBody;
|
|
292
310
|
if ('$ref' in rawReqBody) {
|
|
293
311
|
const refName = rawReqBody.$ref.replace('#/components/requestBodies/', '');
|
|
294
|
-
const resolved = _optionalChain([components, 'optionalAccess',
|
|
312
|
+
const resolved = _optionalChain([components, 'optionalAccess', _9 => _9.requestBodies, 'optionalAccess', _10 => _10[refName]]);
|
|
295
313
|
if (!resolved || '$ref' in resolved) {
|
|
296
314
|
console.error(`RequestBody $ref '${rawReqBody.$ref}' not found in components/requestBodies`);
|
|
297
315
|
return null;
|
|
@@ -317,3 +335,19 @@ function getRequestBody(
|
|
|
317
335
|
|
|
318
336
|
return null;
|
|
319
337
|
}
|
|
338
|
+
|
|
339
|
+
function upsertFixedHeader(headers, headerName, value) {
|
|
340
|
+
const headerIndex = headers.findIndex(
|
|
341
|
+
(header) => header.originalName.toLowerCase() === headerName.toLowerCase()
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
if (headerIndex >= 0) {
|
|
345
|
+
headers[headerIndex].value = value;
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
headers.push({
|
|
350
|
+
originalName: headerName,
|
|
351
|
+
value,
|
|
352
|
+
});
|
|
353
|
+
}
|
package/dist/gen/genTypes.js
CHANGED
|
@@ -61,6 +61,7 @@ function renderSchema(
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const result = [];
|
|
64
|
+
const schemaContext = `components.schemas.${safeName}`;
|
|
64
65
|
if (_nullishCoalesce(schema.description, () => ( schema.title))) {
|
|
65
66
|
result.push(_jsDocs.renderComment.call(void 0, _nullishCoalesce(schema.description, () => ( schema.title))));
|
|
66
67
|
}
|
|
@@ -70,7 +71,7 @@ function renderSchema(
|
|
|
70
71
|
return result.join('\n');
|
|
71
72
|
}
|
|
72
73
|
if ('enum' in schema) {
|
|
73
|
-
result.push(renderEnumType(safeName, schema));
|
|
74
|
+
result.push(renderEnumType(safeName, schema, options));
|
|
74
75
|
return result.join('\n');
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -83,7 +84,15 @@ function renderSchema(
|
|
|
83
84
|
if ('allOf' in schema) {
|
|
84
85
|
const types = _swagger.getRefCompositeTypes.call(void 0, schema);
|
|
85
86
|
const mergedSchema = getMergedCompositeObjects(schema);
|
|
86
|
-
const
|
|
87
|
+
const objectType = _swagger.getTypeFromSchema.call(void 0, mergedSchema, options, `${schemaContext}.allOf`);
|
|
88
|
+
const objectContents = generateObjectTypeContents(mergedSchema, options, schemaContext);
|
|
89
|
+
const hasAdditionalProperties = !!mergedSchema.additionalProperties;
|
|
90
|
+
|
|
91
|
+
if (hasAdditionalProperties) {
|
|
92
|
+
const compositeTypes = [...types, objectType].join(' & ');
|
|
93
|
+
result.push(`export type ${safeName} = ${compositeTypes};`);
|
|
94
|
+
return `${result.join('\n')}\n`;
|
|
95
|
+
}
|
|
87
96
|
|
|
88
97
|
if (useTypeAliases) {
|
|
89
98
|
const compositeTypes = [...types, `{${objectContents ? `\n${objectContents}\n` : ''}}`].join(' & ');
|
|
@@ -95,7 +104,7 @@ function renderSchema(
|
|
|
95
104
|
result.push(`export interface ${safeName} ${extensions}{`);
|
|
96
105
|
result.push(objectContents);
|
|
97
106
|
} else if ('oneOf' in schema || 'anyOf' in schema) {
|
|
98
|
-
const typeDefinition =
|
|
107
|
+
const typeDefinition = _swagger.getTypeFromSchema.call(void 0, schema, options, schemaContext);
|
|
99
108
|
result.push(`export type ${safeName} = ${typeDefinition};`);
|
|
100
109
|
|
|
101
110
|
return `${result.join('\n')}\n`;
|
|
@@ -105,7 +114,15 @@ function renderSchema(
|
|
|
105
114
|
result.push(`export type ${safeName} = ${generateItemsType(schema.items, options)}[];`);
|
|
106
115
|
return result.join('\n');
|
|
107
116
|
} else {
|
|
108
|
-
const
|
|
117
|
+
const objectType = _swagger.getTypeFromSchema.call(void 0, schema, options, schemaContext);
|
|
118
|
+
const hasAdditionalProperties = !!schema.additionalProperties;
|
|
119
|
+
|
|
120
|
+
const objectContents = generateObjectTypeContents(schema, options, schemaContext);
|
|
121
|
+
if (hasAdditionalProperties) {
|
|
122
|
+
result.push(`export type ${safeName} = ${objectType};`);
|
|
123
|
+
return `${result.join('\n')}\n`;
|
|
124
|
+
}
|
|
125
|
+
|
|
109
126
|
if (useTypeAliases) {
|
|
110
127
|
result.push(`export type ${safeName} = {`);
|
|
111
128
|
result.push(objectContents);
|
|
@@ -119,25 +136,14 @@ function renderSchema(
|
|
|
119
136
|
return `${result.join('\n')}\n}\n`;
|
|
120
137
|
}
|
|
121
138
|
|
|
122
|
-
/**
|
|
123
|
-
* Generates the type definition for an `anyOf` or `oneOf` schema.
|
|
124
|
-
* @param schema - The schema object to generate the type definition for.
|
|
125
|
-
* @param options - The options for the generation.
|
|
126
|
-
* @returns The type definition for the `anyOf` or `oneOf` schema.
|
|
127
|
-
*/
|
|
128
|
-
function getTypesFromAnyOrOneOf(schema, options) {
|
|
129
|
-
const composite = schema.allOf || schema.oneOf || schema.anyOf;
|
|
130
|
-
if (!composite) {
|
|
131
|
-
return '';
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return composite.map((s) => _swagger.getTypeFromSchema.call(void 0, s, options)).join(' | ');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
139
|
/**
|
|
138
140
|
* Generates the inline contents of an object type.
|
|
139
141
|
*/
|
|
140
|
-
function generateObjectTypeContents(
|
|
142
|
+
function generateObjectTypeContents(
|
|
143
|
+
schema,
|
|
144
|
+
options,
|
|
145
|
+
schemaContext = 'components.schemas.unknown'
|
|
146
|
+
) {
|
|
141
147
|
const result = [];
|
|
142
148
|
const required = schema.required || [];
|
|
143
149
|
const props = Object.keys(schema.properties || {});
|
|
@@ -145,7 +151,7 @@ function generateObjectTypeContents(schema, options) {
|
|
|
145
151
|
for (const prop of props) {
|
|
146
152
|
const propDefinition = schema.properties[prop];
|
|
147
153
|
const isRequired = !!~required.indexOf(prop);
|
|
148
|
-
result.push(renderTypeProp(prop, propDefinition, isRequired, options));
|
|
154
|
+
result.push(renderTypeProp(prop, propDefinition, isRequired, options, schemaContext));
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
return result.join('\n');
|
|
@@ -182,11 +188,36 @@ function renderExtendedEnumType(name, def) {
|
|
|
182
188
|
/**
|
|
183
189
|
* Render simple enum types (just a union of values)
|
|
184
190
|
*/
|
|
185
|
-
function renderEnumType(name, def) {
|
|
191
|
+
function renderEnumType(name, def, options) {
|
|
192
|
+
if (options.enumDeclarationStyle === 'enum' && shouldRenderStringEnumDeclaration(def)) {
|
|
193
|
+
return renderStringEnumDeclaration(name, def);
|
|
194
|
+
}
|
|
195
|
+
|
|
186
196
|
const values = def.enum.map((v) => (typeof v === 'number' ? v : `"${v}"`)).join(' | ');
|
|
187
197
|
return `export type ${name} = ${values};\n`;
|
|
188
198
|
}
|
|
189
199
|
|
|
200
|
+
function shouldRenderStringEnumDeclaration(def)
|
|
201
|
+
|
|
202
|
+
{
|
|
203
|
+
return (
|
|
204
|
+
def.type === 'string' &&
|
|
205
|
+
Array.isArray(def.enum) &&
|
|
206
|
+
def.enum.every((value) => typeof value === 'string')
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function renderStringEnumDeclaration(name, def) {
|
|
211
|
+
let res = `export enum ${name} {\n`;
|
|
212
|
+
for (let index = 0; index < def.enum.length; index++) {
|
|
213
|
+
const value = def.enum[index];
|
|
214
|
+
const memberName = _nullishCoalesce(_utils.escapePropName.call(void 0, value), () => ( `VALUE_${index}`));
|
|
215
|
+
res += ` ${memberName} = ${JSON.stringify(value)},\n`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return `${res}}\n`;
|
|
219
|
+
}
|
|
220
|
+
|
|
190
221
|
/**
|
|
191
222
|
* OpenApi 3.1 introduced a new way to define enums that we support here.
|
|
192
223
|
*/
|
|
@@ -207,10 +238,11 @@ function renderTypeProp(
|
|
|
207
238
|
propName,
|
|
208
239
|
definition,
|
|
209
240
|
required,
|
|
210
|
-
options
|
|
241
|
+
options,
|
|
242
|
+
schemaContext
|
|
211
243
|
) {
|
|
212
244
|
const lines = [];
|
|
213
|
-
const type = _swagger.getTypeFromSchema.call(void 0, definition, options);
|
|
245
|
+
const type = _swagger.getTypeFromSchema.call(void 0, definition, options, `${schemaContext}.properties.${propName}`);
|
|
214
246
|
|
|
215
247
|
if ('description' in definition || 'title' in definition) {
|
|
216
248
|
const renderedComment = _jsDocs.renderComment.call(void 0, _nullishCoalesce(definition.description, () => ( definition.title)));
|
|
@@ -267,7 +299,7 @@ function getMergedCompositeObjects(schema) {
|
|
|
267
299
|
subSchemas.push(safeSchema);
|
|
268
300
|
}
|
|
269
301
|
|
|
270
|
-
return deepMerge({}, ...subSchemas);
|
|
302
|
+
return deepMerge({}, ...subSchemas) ;
|
|
271
303
|
}
|
|
272
304
|
|
|
273
305
|
function isObject(item) {
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,7 @@ function readFile(filePath) {
|
|
|
83
83
|
arrayFormat,
|
|
84
84
|
mode,
|
|
85
85
|
schemaStyle,
|
|
86
|
+
enumStyle,
|
|
86
87
|
template,
|
|
87
88
|
queryParamsSerialization = {},
|
|
88
89
|
...rest
|
|
@@ -104,6 +105,8 @@ function readFile(filePath) {
|
|
|
104
105
|
generationMode: _nullishCoalesce(_nullishCoalesce(mode, () => ( rest.generationMode)), () => ( _swagger.APP_DEFAULTS.generationMode)),
|
|
105
106
|
schemaDeclarationStyle:
|
|
106
107
|
_nullishCoalesce(_nullishCoalesce(schemaStyle, () => ( rest.schemaDeclarationStyle)), () => ( _swagger.APP_DEFAULTS.schemaDeclarationStyle)),
|
|
108
|
+
enumDeclarationStyle:
|
|
109
|
+
_nullishCoalesce(_nullishCoalesce(enumStyle, () => ( rest.enumDeclarationStyle)), () => ( _swagger.APP_DEFAULTS.enumDeclarationStyle)),
|
|
107
110
|
queryParamsSerialization: mergedQueryParamsSerialization,
|
|
108
111
|
};
|
|
109
112
|
} exports.prepareAppOptions = prepareAppOptions;
|
|
@@ -16,7 +16,8 @@ var _utils = require('../utils');
|
|
|
16
16
|
*/
|
|
17
17
|
function getParameterType(
|
|
18
18
|
param,
|
|
19
|
-
options
|
|
19
|
+
options,
|
|
20
|
+
context = 'schema'
|
|
20
21
|
) {
|
|
21
22
|
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
22
23
|
|
|
@@ -24,7 +25,7 @@ var _utils = require('../utils');
|
|
|
24
25
|
return unknownType;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
return getTypeFromSchemaResolved(param.schema, options);
|
|
28
|
+
return getTypeFromSchemaResolved(param.schema, options, `${context}.schema`);
|
|
28
29
|
} exports.getParameterType = getParameterType;
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -35,9 +36,10 @@ var _utils = require('../utils');
|
|
|
35
36
|
*/
|
|
36
37
|
function getTypeFromSchema(
|
|
37
38
|
schema,
|
|
38
|
-
options
|
|
39
|
+
options,
|
|
40
|
+
context = 'schema'
|
|
39
41
|
) {
|
|
40
|
-
return getTypeFromSchemaResolved(schema, options);
|
|
42
|
+
return getTypeFromSchemaResolved(schema, options, context);
|
|
41
43
|
} exports.getTypeFromSchema = getTypeFromSchema;
|
|
42
44
|
|
|
43
45
|
/**
|
|
@@ -46,7 +48,8 @@ var _utils = require('../utils');
|
|
|
46
48
|
*/
|
|
47
49
|
function getTypeFromSchemaResolved(
|
|
48
50
|
schema,
|
|
49
|
-
options
|
|
51
|
+
options,
|
|
52
|
+
context
|
|
50
53
|
) {
|
|
51
54
|
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
52
55
|
|
|
@@ -54,6 +57,17 @@ function getTypeFromSchemaResolved(
|
|
|
54
57
|
return unknownType;
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
if (typeof schema !== 'object' || Array.isArray(schema)) {
|
|
61
|
+
if (context.endsWith('.properties.$ref') && typeof schema === 'string') {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Invalid schema at ${context}: string value under properties.$ref is not a valid schema. ` +
|
|
64
|
+
'Did you mean to use schema.$ref at the root, or wrap it in a named property (for example properties.data.$ref)?'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw new Error(`Invalid schema at ${context}: expected an object schema, got ${typeof schema}.`);
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
if ('$ref' in schema) {
|
|
58
72
|
const refName = schema.$ref.split('/').pop();
|
|
59
73
|
return getSafeIdentifier(refName) || unknownType;
|
|
@@ -65,13 +79,13 @@ function getTypeFromSchemaResolved(
|
|
|
65
79
|
|
|
66
80
|
// OpenAPI 3.1 nullable: type is an array containing 'null', e.g. ["string", "null"]
|
|
67
81
|
if (Array.isArray(schema.type)) {
|
|
68
|
-
return getTypeFromOA31ArrayType(schema , options);
|
|
82
|
+
return getTypeFromOA31ArrayType(schema , options, context);
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
// OpenAPI 3.0 nullable: nullable: true
|
|
72
86
|
const isNullable = 'nullable' in schema && schema.nullable === true;
|
|
73
87
|
const isNullableSuffix = isNullable && options.nullableStrategy === 'include' ? ' | null' : '';
|
|
74
|
-
const type = getTypeFromSchemaInternal(schema, options);
|
|
88
|
+
const type = getTypeFromSchemaInternal(schema, options, context);
|
|
75
89
|
|
|
76
90
|
if (isNullableSuffix && type.endsWith('| null')) {
|
|
77
91
|
return type;
|
|
@@ -84,7 +98,11 @@ function getTypeFromSchemaResolved(
|
|
|
84
98
|
* The presence of `"null"` in the array is the OA3.1 way of marking a field as nullable.
|
|
85
99
|
* Respects `nullableStrategy` the same way as OA3.0 `nullable: true`.
|
|
86
100
|
*/
|
|
87
|
-
function getTypeFromOA31ArrayType(
|
|
101
|
+
function getTypeFromOA31ArrayType(
|
|
102
|
+
schema,
|
|
103
|
+
options,
|
|
104
|
+
context
|
|
105
|
+
) {
|
|
88
106
|
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
89
107
|
const types = schema.type ;
|
|
90
108
|
const isNullable = types.includes('null');
|
|
@@ -97,11 +115,17 @@ function getTypeFromOA31ArrayType(schema, options) {
|
|
|
97
115
|
} else if (nonNullTypes.length === 1) {
|
|
98
116
|
// Synthesize a single-type schema to reuse existing resolution logic
|
|
99
117
|
const singleTypeSchema = { ...schema, type: nonNullTypes[0] } ;
|
|
100
|
-
baseType = getTypeFromSchemaInternal(singleTypeSchema, options);
|
|
118
|
+
baseType = getTypeFromSchemaInternal(singleTypeSchema, options, context);
|
|
101
119
|
} else {
|
|
102
120
|
// Multiple non-null types — resolve each independently and join as a union
|
|
103
121
|
baseType = nonNullTypes
|
|
104
|
-
.map((t) =>
|
|
122
|
+
.map((t) =>
|
|
123
|
+
getTypeFromSchemaInternal(
|
|
124
|
+
{ ...schema, type: t } ,
|
|
125
|
+
options,
|
|
126
|
+
`${context}.type`
|
|
127
|
+
)
|
|
128
|
+
)
|
|
105
129
|
.join(' | ');
|
|
106
130
|
}
|
|
107
131
|
|
|
@@ -129,22 +153,23 @@ function getTypeFromOA31ArrayType(schema, options) {
|
|
|
129
153
|
|
|
130
154
|
function getTypeFromSchemaInternal(
|
|
131
155
|
schema,
|
|
132
|
-
options
|
|
156
|
+
options,
|
|
157
|
+
context
|
|
133
158
|
) {
|
|
134
159
|
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
135
160
|
|
|
136
161
|
if ('allOf' in schema || 'oneOf' in schema || 'anyOf' in schema) {
|
|
137
|
-
return getTypeFromComposites(schema , options);
|
|
162
|
+
return getTypeFromComposites(schema , options, context);
|
|
138
163
|
}
|
|
139
164
|
|
|
140
165
|
if (schema.type === 'array') {
|
|
141
166
|
if (schema.items) {
|
|
142
|
-
return `${getNestedTypeFromSchema(schema.items, options)}[]`;
|
|
167
|
+
return `${getNestedTypeFromSchema(schema.items, options, `${context}.items`)}[]`;
|
|
143
168
|
}
|
|
144
169
|
return `${unknownType}[]`;
|
|
145
170
|
}
|
|
146
171
|
if (schema.type === 'object') {
|
|
147
|
-
return getTypeFromObject(schema, options);
|
|
172
|
+
return getTypeFromObject(schema, options, undefined, context);
|
|
148
173
|
}
|
|
149
174
|
if ('enum' in schema) {
|
|
150
175
|
return `${schema.enum.map((v) => JSON.stringify(v)).join(' | ')}`;
|
|
@@ -166,7 +191,8 @@ function getTypeFromSchemaInternal(
|
|
|
166
191
|
|
|
167
192
|
function getNestedTypeFromSchema(
|
|
168
193
|
schema,
|
|
169
|
-
options
|
|
194
|
+
options,
|
|
195
|
+
context
|
|
170
196
|
) {
|
|
171
197
|
// OA3.0 nullable: true
|
|
172
198
|
const isOA30NullableAndActive =
|
|
@@ -180,10 +206,10 @@ function getNestedTypeFromSchema(
|
|
|
180
206
|
options.nullableStrategy === 'include';
|
|
181
207
|
|
|
182
208
|
if (isOA30NullableAndActive || isOA31NullableAndActive || ('enum' in schema && schema.enum)) {
|
|
183
|
-
return `(${getTypeFromSchemaResolved(schema, options)})`;
|
|
209
|
+
return `(${getTypeFromSchemaResolved(schema, options, context)})`;
|
|
184
210
|
}
|
|
185
211
|
|
|
186
|
-
return getTypeFromSchemaResolved(schema, options);
|
|
212
|
+
return getTypeFromSchemaResolved(schema, options, context);
|
|
187
213
|
}
|
|
188
214
|
|
|
189
215
|
/**
|
|
@@ -192,20 +218,17 @@ function getNestedTypeFromSchema(
|
|
|
192
218
|
*/
|
|
193
219
|
function getTypeFromObject(
|
|
194
220
|
schema,
|
|
195
|
-
options
|
|
221
|
+
options,
|
|
222
|
+
requiredOverride,
|
|
223
|
+
context = 'schema'
|
|
196
224
|
) {
|
|
197
225
|
const unknownType = options.preferAny ? 'any' : 'unknown';
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const extraProps = schema.additionalProperties;
|
|
201
|
-
return `{ [key: string]: ${
|
|
202
|
-
extraProps === true ? 'any' : getTypeFromSchemaResolved(extraProps, options)
|
|
203
|
-
} }`;
|
|
204
|
-
}
|
|
226
|
+
let objectWithNamedPropsType = '';
|
|
227
|
+
let objectWithIndexSignatureType = '';
|
|
205
228
|
|
|
206
229
|
if (schema.properties) {
|
|
207
230
|
const props = Object.keys(schema.properties);
|
|
208
|
-
const required = schema.required
|
|
231
|
+
const required = _nullishCoalesce(_nullishCoalesce(requiredOverride, () => ( schema.required)), () => ( []));
|
|
209
232
|
const result = [];
|
|
210
233
|
|
|
211
234
|
for (const prop of props) {
|
|
@@ -213,11 +236,36 @@ function getTypeFromObject(
|
|
|
213
236
|
const isRequired = required.includes(prop);
|
|
214
237
|
const safePropName = _utils.escapePropName.call(void 0, prop);
|
|
215
238
|
result.push(
|
|
216
|
-
`${safePropName}${isRequired ? '' : '?'}: ${getTypeFromSchemaResolved(
|
|
239
|
+
`${safePropName}${isRequired ? '' : '?'}: ${getTypeFromSchemaResolved(
|
|
240
|
+
propDefinition,
|
|
241
|
+
options,
|
|
242
|
+
`${context}.properties.${prop}`
|
|
243
|
+
)};`
|
|
217
244
|
);
|
|
218
245
|
}
|
|
219
246
|
|
|
220
|
-
|
|
247
|
+
objectWithNamedPropsType = `{ ${result.join('\n')} }`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (schema.additionalProperties) {
|
|
251
|
+
const extraProps = schema.additionalProperties;
|
|
252
|
+
objectWithIndexSignatureType = `{ [key: string]: ${
|
|
253
|
+
extraProps === true
|
|
254
|
+
? 'any'
|
|
255
|
+
: getTypeFromSchemaResolved(extraProps, options, `${context}.additionalProperties`)
|
|
256
|
+
} }`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (objectWithNamedPropsType && objectWithIndexSignatureType) {
|
|
260
|
+
return `${objectWithNamedPropsType} & ${objectWithIndexSignatureType}`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (objectWithNamedPropsType) {
|
|
264
|
+
return objectWithNamedPropsType;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (objectWithIndexSignatureType) {
|
|
268
|
+
return objectWithIndexSignatureType;
|
|
221
269
|
}
|
|
222
270
|
|
|
223
271
|
return unknownType;
|
|
@@ -226,14 +274,76 @@ function getTypeFromObject(
|
|
|
226
274
|
/**
|
|
227
275
|
* Simplified way of extracting correct type from `anyOf`, `oneOf` or `allOf` schema.
|
|
228
276
|
*/
|
|
229
|
-
function getTypeFromComposites(
|
|
277
|
+
function getTypeFromComposites(
|
|
278
|
+
schema,
|
|
279
|
+
options,
|
|
280
|
+
context = 'schema'
|
|
281
|
+
) {
|
|
230
282
|
const composite = schema.allOf || schema.oneOf || schema.anyOf;
|
|
231
283
|
|
|
284
|
+
if (!composite) {
|
|
285
|
+
return options.preferAny ? 'any' : 'unknown';
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const isUnionComposite = !!schema.oneOf || !!schema.anyOf;
|
|
289
|
+
const hasParentObjectShape = !!schema.properties || !!schema.additionalProperties;
|
|
290
|
+
|
|
291
|
+
if (isUnionComposite && hasParentObjectShape) {
|
|
292
|
+
const fallbackType = options.preferAny ? 'any' : 'unknown';
|
|
293
|
+
const parentObjectType = getTypeFromObject(schema, options, undefined, context);
|
|
294
|
+
const parentRequired = schema.required || [];
|
|
295
|
+
const parentPropSet = new Set(Object.keys(schema.properties || {}));
|
|
296
|
+
|
|
297
|
+
return composite
|
|
298
|
+
.map((subSchema) => {
|
|
299
|
+
if (!('$ref' in subSchema) && isRequiredOnlyCompositeBranch(subSchema)) {
|
|
300
|
+
const branchRequired = subSchema.required || [];
|
|
301
|
+
const validRequired = branchRequired.filter((name) => {
|
|
302
|
+
const isKnown = parentPropSet.has(name);
|
|
303
|
+
if (!isKnown) {
|
|
304
|
+
console.warn(
|
|
305
|
+
`Composite required key '${name}' is not present in schema properties and will be ignored.`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
return isKnown;
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return getTypeFromObject(
|
|
312
|
+
schema,
|
|
313
|
+
options,
|
|
314
|
+
Array.from(new Set([...parentRequired, ...validRequired])),
|
|
315
|
+
context
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const subType = getTypeFromSchemaResolved(subSchema, options, `${context}.composite`);
|
|
320
|
+
if (subType === fallbackType) {
|
|
321
|
+
return parentObjectType;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return `${parentObjectType} & ${subType}`;
|
|
325
|
+
})
|
|
326
|
+
.join(' | ');
|
|
327
|
+
}
|
|
328
|
+
|
|
232
329
|
return composite
|
|
233
|
-
.map((s) => getTypeFromSchemaResolved(s, options))
|
|
330
|
+
.map((s, index) => getTypeFromSchemaResolved(s, options, `${context}.composite[${index}]`))
|
|
234
331
|
.join(schema.allOf ? ' & ' : ' | ');
|
|
235
332
|
}
|
|
236
333
|
|
|
334
|
+
function isRequiredOnlyCompositeBranch(schema) {
|
|
335
|
+
return (
|
|
336
|
+
Array.isArray(schema.required) &&
|
|
337
|
+
!schema.type &&
|
|
338
|
+
!schema.properties &&
|
|
339
|
+
!schema.additionalProperties &&
|
|
340
|
+
!schema.allOf &&
|
|
341
|
+
!schema.oneOf &&
|
|
342
|
+
!schema.anyOf &&
|
|
343
|
+
!schema.enum
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
237
347
|
/**
|
|
238
348
|
* Escapes name so it can be used as a valid identifier in the generated code.
|
|
239
349
|
* Component names can contain certain characters that are not allowed in identifiers.
|
|
@@ -264,6 +374,7 @@ function getTypeFromComposites(schema, options) {
|
|
|
264
374
|
nullableStrategy: 'ignore',
|
|
265
375
|
generationMode: 'full',
|
|
266
376
|
schemaDeclarationStyle: 'interface',
|
|
377
|
+
enumDeclarationStyle: 'union',
|
|
267
378
|
queryParamsSerialization: {
|
|
268
379
|
allowDots: true,
|
|
269
380
|
arrayFormat: 'repeat',
|
|
@@ -283,6 +394,7 @@ function getTypeFromComposites(schema, options) {
|
|
|
283
394
|
nullableStrategy: _nullishCoalesce(opts.nullableStrategy, () => ( exports.APP_DEFAULTS.nullableStrategy)),
|
|
284
395
|
generationMode: _nullishCoalesce(opts.generationMode, () => ( exports.APP_DEFAULTS.generationMode)),
|
|
285
396
|
schemaDeclarationStyle: _nullishCoalesce(opts.schemaDeclarationStyle, () => ( exports.APP_DEFAULTS.schemaDeclarationStyle)),
|
|
397
|
+
enumDeclarationStyle: _nullishCoalesce(opts.enumDeclarationStyle, () => ( exports.APP_DEFAULTS.enumDeclarationStyle)),
|
|
286
398
|
queryParamsSerialization: {
|
|
287
399
|
...exports.APP_DEFAULTS.queryParamsSerialization,
|
|
288
400
|
...opts.queryParamsSerialization,
|
package/dist/types.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface ClientOptions {
|
|
|
33
33
|
generationMode?: GenerationMode;
|
|
34
34
|
/** Controls whether object schemas are emitted as interfaces or type aliases */
|
|
35
35
|
schemaDeclarationStyle?: SchemaDeclarationStyle;
|
|
36
|
+
/** Controls whether plain string enums are emitted as unions or TypeScript enums */
|
|
37
|
+
enumDeclarationStyle?: EnumDeclarationStyle;
|
|
36
38
|
/** Offers ability to adjust the OpenAPI spec before it is processed */
|
|
37
39
|
modifiers?: {
|
|
38
40
|
/** Global-level modifiers for parameter with a given name */
|
|
@@ -46,6 +48,7 @@ export interface CliOptions extends FullAppOptions {
|
|
|
46
48
|
arrayFormat?: ArrayFormat;
|
|
47
49
|
mode?: GenerationMode;
|
|
48
50
|
schemaStyle?: SchemaDeclarationStyle;
|
|
51
|
+
enumStyle?: EnumDeclarationStyle;
|
|
49
52
|
}
|
|
50
53
|
export interface FullAppOptions extends ClientOptions {
|
|
51
54
|
/** Path to the configuration file that contains actual config to be used */
|
|
@@ -58,6 +61,7 @@ export type ArrayFormat = 'indices' | 'repeat' | 'brackets';
|
|
|
58
61
|
export type NullableStrategy = 'include' | 'nullableAsOptional' | 'ignore';
|
|
59
62
|
export type GenerationMode = 'full' | 'schemas';
|
|
60
63
|
export type SchemaDeclarationStyle = 'interface' | 'type';
|
|
64
|
+
export type EnumDeclarationStyle = 'union' | 'enum';
|
|
61
65
|
/**
|
|
62
66
|
* Internal options type used throughout the app after `prepareAppOptions` has run.
|
|
63
67
|
* All fields that have defaults are required here so the rest of the codebase never
|
|
@@ -69,6 +73,7 @@ export interface AppOptions extends ClientOptions {
|
|
|
69
73
|
nullableStrategy: NullableStrategy;
|
|
70
74
|
generationMode: GenerationMode;
|
|
71
75
|
schemaDeclarationStyle: SchemaDeclarationStyle;
|
|
76
|
+
enumDeclarationStyle: EnumDeclarationStyle;
|
|
72
77
|
queryParamsSerialization: {
|
|
73
78
|
allowDots: boolean;
|
|
74
79
|
arrayFormat: ArrayFormat;
|
package/dist/utils/utils.js
CHANGED
|
@@ -240,12 +240,11 @@ function resolveResponseRef(
|
|
|
240
240
|
const sortByKey = (key) => (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0);
|
|
241
241
|
|
|
242
242
|
const orderedContentTypes = [
|
|
243
|
-
'application/json',
|
|
244
|
-
'text/json',
|
|
245
243
|
'text/plain',
|
|
246
244
|
'application/x-www-form-urlencoded',
|
|
247
245
|
'multipart/form-data',
|
|
248
246
|
];
|
|
247
|
+
const preferredJsonContentTypes = ['application/json', 'text/json'];
|
|
249
248
|
function getBestContentType(
|
|
250
249
|
reqBody
|
|
251
250
|
) {
|
|
@@ -254,6 +253,19 @@ const orderedContentTypes = [
|
|
|
254
253
|
return [null, null];
|
|
255
254
|
}
|
|
256
255
|
|
|
256
|
+
const preferredJsonContentType = preferredJsonContentTypes.find((ct) => contentTypes.includes(ct));
|
|
257
|
+
if (preferredJsonContentType) {
|
|
258
|
+
const typeObject = reqBody.content[preferredJsonContentType];
|
|
259
|
+
const type = getContentType(preferredJsonContentType);
|
|
260
|
+
return [typeObject, type];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const jsonLikeContentType = contentTypes.find(isJsonLikeContentType);
|
|
264
|
+
if (jsonLikeContentType) {
|
|
265
|
+
const typeObject = reqBody.content[jsonLikeContentType];
|
|
266
|
+
return [typeObject, 'json'];
|
|
267
|
+
}
|
|
268
|
+
|
|
257
269
|
const firstContentType = orderedContentTypes.find((ct) => contentTypes.includes(ct));
|
|
258
270
|
if (firstContentType) {
|
|
259
271
|
const typeObject = reqBody.content[firstContentType];
|
|
@@ -266,6 +278,11 @@ const orderedContentTypes = [
|
|
|
266
278
|
return [typeObject, type];
|
|
267
279
|
} exports.getBestContentType = getBestContentType;
|
|
268
280
|
|
|
281
|
+
function isJsonLikeContentType(contentType) {
|
|
282
|
+
const normalized = contentType.split(';')[0].trim().toLowerCase();
|
|
283
|
+
return normalized === 'application/*+json' || /^application\/.+\+json$/.test(normalized);
|
|
284
|
+
}
|
|
285
|
+
|
|
269
286
|
function getContentType(type) {
|
|
270
287
|
if (type === 'application/x-www-form-urlencoded') {
|
|
271
288
|
return 'urlencoded';
|
package/package.json
CHANGED
|
@@ -11,6 +11,21 @@ $config?: RequestInit
|
|
|
11
11
|
'<%= parameter.originalName %>': <%= parameter.name %>,
|
|
12
12
|
<% }); %>})}<% } %>`;
|
|
13
13
|
|
|
14
|
+
<% if(it.headers && it.headers.length > 0) { %>
|
|
15
|
+
const { headers: $configHeaders, ...$configRest } = $config ?? {};
|
|
16
|
+
const headers = new Headers({
|
|
17
|
+
<% it.headers.forEach((parameter) => { %>
|
|
18
|
+
<% if (parameter.value) { %>
|
|
19
|
+
'<%= parameter.originalName %>': '<%= parameter.value %>',
|
|
20
|
+
<% } else { %>
|
|
21
|
+
'<%= parameter.originalName %>': <%= parameter.name %> ?? '',
|
|
22
|
+
<% } %>
|
|
23
|
+
<% }); %>
|
|
24
|
+
});
|
|
25
|
+
if ($configHeaders) {
|
|
26
|
+
new Headers($configHeaders).forEach((value, key) => headers.set(key, value));
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
return fetch(url, {
|
|
15
30
|
method: '<%= it.method %>',
|
|
16
31
|
<% if(it.body) { %>
|
|
@@ -22,19 +37,24 @@ $config?: RequestInit
|
|
|
22
37
|
body: <%= it.body.name %>,
|
|
23
38
|
<% } %>
|
|
24
39
|
<% } %>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
40
|
+
headers,
|
|
41
|
+
...$configRest,
|
|
42
|
+
})
|
|
43
|
+
<% } else { %>
|
|
44
|
+
return fetch(url, {
|
|
45
|
+
method: '<%= it.method %>',
|
|
46
|
+
<% if(it.body) { %>
|
|
47
|
+
<% if(it.body.contentType === 'json') { %>
|
|
48
|
+
body: JSON.stringify(<%= it.body.name %>),
|
|
49
|
+
<% } else if(it.body.contentType === 'urlencoded') { %>
|
|
50
|
+
body: new URLSearchParams(<%= it.body.name %> as any),
|
|
51
|
+
<% } else { %>
|
|
52
|
+
body: <%= it.body.name %>,
|
|
53
|
+
<% } %>
|
|
35
54
|
<% } %>
|
|
36
55
|
...$config,
|
|
37
56
|
})
|
|
57
|
+
<% } %>
|
|
38
58
|
<% if(it.responseContentType === 'binary') { %>
|
|
39
59
|
.then((response) => response.blob() as Promise<<%~ it.returnType %>>);
|
|
40
60
|
<% } else if(it.responseContentType === 'text') { %>
|