swaggie 1.5.3-beta.2 → 1.5.3-beta.3

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 CHANGED
@@ -313,14 +313,14 @@ function error(e) {
313
313
 
314
314
  | Supported | Not supported |
315
315
  | ------------------------------------------------------------------------------ | ----------------------------------------------- |
316
- | OpenAPI 3 | Swagger, Open API 2.0 |
316
+ | OpenAPI 3, OpenAPI 3.1, OpenAPI 3.2 | Swagger, Open API 2.0 |
317
317
  | `allOf`, `oneOf`, `anyOf`, `$ref` to schemas | `not` |
318
- | Spec formats: `JSON`, `YAML` | Very complex query params |
318
+ | Spec formats: `JSON`, `YAML` | VERY complex query params |
319
319
  | Extensions: `x-position`, `x-name`, `x-enumNames`, `x-enum-varnames` | Multiple response types (only one will be used) |
320
320
  | Content types: `JSON`, `text`, `multipart/form-data` | Multiple request types (only one will be used) |
321
- | Content types: `application/x-www-form-urlencoded`, `application/octet-stream` | References to other spec files |
322
- | Different types of enum definitions (+ OpenAPI 3.1 support for enums) | OpenAPI callbacks |
323
- | Paths inheritance, comments (descriptions), nullable | OpenAPI webhooks |
321
+ | Content types: `application/x-www-form-urlencoded`, `application/octet-stream` | References to external spec files |
322
+ | Different types of enum definitions | OpenAPI callbacks |
323
+ | Paths inheritance, comments (descriptions), nullable, `["<TYPE>", null]` | OpenAPI webhooks |
324
324
  | Getting documents from remote locations or as path reference (local file) | |
325
325
  | Grouping endpoints by tags + handle gracefully duplicate operation ids | |
326
326
 
@@ -201,12 +201,7 @@ function renderTypeProp(
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;
204
+ const isOptional = !required || isNullableAsOptional(definition, options);
210
205
  const optionalMark = isOptional ? '?' : '';
211
206
  // If prop name is not a valid identifier, we need to wrap it in quotes.
212
207
  // We can't use getSafeIdentifier here because it will affect the data model.
@@ -216,6 +211,26 @@ function renderTypeProp(
216
211
  return lines.join('\n');
217
212
  }
218
213
 
214
+ /**
215
+ * When nullableAsOptional strategy is set, nullable properties are treated as optional.
216
+ * Supports both OA3.0 (nullable: true) and OA3.1 (type: ["string", "null"]).
217
+ * @returns True if the property should be treated as optional, false otherwise.
218
+ */
219
+ function isNullableAsOptional(
220
+ definition,
221
+ options
222
+ ) {
223
+ if ('$ref' in definition) {
224
+ return false;
225
+ }
226
+
227
+ return (
228
+ options.nullableStrategy === 'nullableAsOptional' &&
229
+ (definition.nullable === true ||
230
+ (Array.isArray(definition.type) && definition.type.includes('null')))
231
+ );
232
+ }
233
+
219
234
  function getMergedCompositeObjects(schema) {
220
235
  const { allOf, oneOf, anyOf, ...safeSchema } = schema;
221
236
  const composite = allOf || oneOf || anyOf || [];
@@ -52,6 +52,12 @@ var _utils = require('../utils');
52
52
  return 'null';
53
53
  }
54
54
 
55
+ // OpenAPI 3.1 nullable: type is an array containing 'null', e.g. ["string", "null"]
56
+ if (Array.isArray(schema.type)) {
57
+ return getTypeFromOA31ArrayType(schema , options);
58
+ }
59
+
60
+ // OpenAPI 3.0 nullable: nullable: true
55
61
  const isNullable = 'nullable' in schema && schema.nullable === true;
56
62
  const strategy = _nullishCoalesce(options.nullableStrategy, () => ( 'ignore'));
57
63
  const isNullableSuffix = isNullable && strategy === 'include' ? ' | null' : '';
@@ -63,6 +69,58 @@ var _utils = require('../utils');
63
69
  return type + isNullableSuffix;
64
70
  } exports.getTypeFromSchema = getTypeFromSchema;
65
71
 
72
+ /**
73
+ * Handles OpenAPI 3.1 schemas where `type` is an array (e.g. `["string", "null"]`).
74
+ * The presence of `"null"` in the array is the OA3.1 way of marking a field as nullable.
75
+ * Respects `nullableStrategy` the same way as OA3.0 `nullable: true`.
76
+ */
77
+ function getTypeFromOA31ArrayType(
78
+ schema,
79
+ options
80
+ ) {
81
+ const unknownType = options.preferAny ? 'any' : 'unknown';
82
+ const types = schema.type ;
83
+ const isNullable = types.includes('null');
84
+ const nonNullTypes = types.filter((t) => t !== 'null');
85
+
86
+ // Build the base type from the non-null types
87
+ let baseType;
88
+ if (nonNullTypes.length === 0) {
89
+ baseType = 'null';
90
+ } else if (nonNullTypes.length === 1) {
91
+ // Synthesize a single-type schema to reuse existing resolution logic
92
+ const singleTypeSchema = { ...schema, type: nonNullTypes[0] } ;
93
+ baseType = getTypeFromSchemaInternal(singleTypeSchema, options);
94
+ } else {
95
+ // Multiple non-null types — resolve each independently and join as a union
96
+ baseType = nonNullTypes
97
+ .map((t) => getTypeFromSchemaInternal({ ...schema, type: t } , options))
98
+ .join(' | ');
99
+ }
100
+
101
+ if (!isNullable) {
102
+ return baseType || unknownType;
103
+ }
104
+
105
+ // All types were 'null' — just return 'null' regardless of strategy
106
+ if (nonNullTypes.length === 0) {
107
+ return 'null';
108
+ }
109
+
110
+ const strategy = _nullishCoalesce(options.nullableStrategy, () => ( 'ignore'));
111
+ if (strategy === 'include') {
112
+ // We don't want multiple nulls in the type string
113
+ if (baseType.endsWith('| null')) {
114
+ return baseType;
115
+ }
116
+ return `${baseType} | null`;
117
+ }
118
+
119
+ // 'ignore' and 'nullableAsOptional' — null is stripped from the type itself
120
+ // (for nullableAsOptional, the optionality is applied at the property level in genTypes.ts)
121
+ return baseType || unknownType;
122
+ }
123
+
66
124
  function getTypeFromSchemaInternal(
67
125
  schema,
68
126
  options
@@ -105,11 +163,22 @@ function getNestedTypeFromSchema(
105
163
  options
106
164
  ) {
107
165
  const strategy = _nullishCoalesce(options.nullableStrategy, () => ( 'ignore'));
108
- const isNullableAndActive =
166
+
167
+ // OA3.0 nullable: true
168
+ const isOA30NullableAndActive =
109
169
  'nullable' in schema && schema.nullable === true && strategy === 'include';
110
- if (isNullableAndActive || ('enum' in schema && schema.enum)) {
170
+
171
+ // OA3.1 nullable: type array containing 'null'
172
+ const isOA31NullableAndActive =
173
+ 'type' in schema &&
174
+ Array.isArray(schema.type) &&
175
+ schema.type.includes('null') &&
176
+ strategy === 'include';
177
+
178
+ if (isOA30NullableAndActive || isOA31NullableAndActive || ('enum' in schema && schema.enum)) {
111
179
  return `(${getTypeFromSchema(schema, options)})`;
112
180
  }
181
+
113
182
  return getTypeFromSchema(schema, options);
114
183
  }
115
184
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swaggie",
3
- "version": "1.5.3-beta.2",
3
+ "version": "1.5.3-beta.3",
4
4
  "description": "Generate TypeScript REST client code from an OpenAPI spec",
5
5
  "author": {
6
6
  "name": "Piotr Dabrowski",