@@ -247,10 +247,29 @@ struct TypeMatcher {
247
247
/// - Throws: An error if there's an issue while checking the schema.
248
248
/// - Returns: `true` if the schema is optional, `false` otherwise.
249
249
func isOptional( _ schema: JSONSchema , components: OpenAPI . Components ) throws -> Bool {
250
+ var cache = [ JSONReference < JSONSchema > : Bool ] ( )
251
+ return try isOptional ( schema, components: components, cache: & cache)
252
+ }
253
+
254
+ /// Returns a Boolean value indicating whether the schema is optional.
255
+ /// - Parameters:
256
+ /// - schema: The schema to check.
257
+ /// - components: The OpenAPI components for looking up references.
258
+ /// - cache: Memoised optionality by reference.
259
+ /// - Throws: An error if there's an issue while checking the schema.
260
+ /// - Returns: `true` if the schema is optional, `false` otherwise.
261
+ func isOptional( _ schema: JSONSchema , components: OpenAPI . Components , cache: inout [ JSONReference < JSONSchema > : Bool ] ) throws -> Bool {
250
262
if schema. nullable || !schema. required { return true }
251
- guard case . reference( let ref, _) = schema. value else { return false }
252
- let targetSchema = try components. lookup ( ref)
253
- return try isOptional ( targetSchema, components: components)
263
+ switch schema. value {
264
+ case . null( _) :
265
+ return true
266
+ case . reference( let ref, _) :
267
+ return try isOptional ( ref, components: components, cache: & cache)
268
+ case . one( of: let schemas, core: _) :
269
+ return try schemas. contains ( where: { try isOptional ( $0, components: components, cache: & cache) } )
270
+ default :
271
+ return schema. nullable
272
+ }
254
273
}
255
274
256
275
/// Returns a Boolean value indicating whether the schema is optional.
@@ -260,16 +279,56 @@ struct TypeMatcher {
260
279
/// - Throws: An error if there's an issue while checking the schema.
261
280
/// - Returns: `true` if the schema is optional, `false` otherwise.
262
281
func isOptional( _ schema: UnresolvedSchema ? , components: OpenAPI . Components ) throws -> Bool {
282
+ var cache = [ JSONReference < JSONSchema > : Bool ] ( )
283
+ return try isOptional ( schema, components: components, cache: & cache)
284
+ }
285
+
286
+ /// Returns a Boolean value indicating whether the schema is optional.
287
+ /// - Parameters:
288
+ /// - schema: The schema to check.
289
+ /// - components: The OpenAPI components for looking up references.
290
+ /// - cache: Memoised optionality by reference.
291
+ /// - Throws: An error if there's an issue while checking the schema.
292
+ /// - Returns: `true` if the schema is optional, `false` otherwise.
293
+ func isOptional( _ schema: UnresolvedSchema ? , components: OpenAPI . Components , cache: inout [ JSONReference < JSONSchema > : Bool ] ) throws -> Bool {
263
294
guard let schema else {
264
295
// A nil unresolved schema represents a non-optional fragment.
265
296
return false
266
297
}
267
298
switch schema {
268
299
case . a( let ref) :
269
- let targetSchema = try components. lookup ( ref)
270
- return try isOptional ( targetSchema, components: components)
271
- case . b( let schema) : return try isOptional ( schema, components: components)
300
+ return try isOptional ( ref. jsonReference, components: components, cache: & cache)
301
+ case . b( let schema) : return try isOptional ( schema, components: components, cache: & cache)
302
+ }
303
+ }
304
+
305
+ /// Returns a Boolean value indicating whether the referenced schema is optional.
306
+ /// - Parameters:
307
+ /// - schema: The reference to check.
308
+ /// - components: The OpenAPI components for looking up references.
309
+ /// - Throws: An error if there's an issue while checking the schema.
310
+ /// - Returns: `true` if the schema is optional, `false` otherwise.
311
+ func isOptional( _ ref: JSONReference < JSONSchema > , components: OpenAPI . Components ) throws -> Bool {
312
+ var cache = [ JSONReference < JSONSchema > : Bool ] ( )
313
+ return try isOptional ( ref, components: components, cache: & cache)
314
+ }
315
+
316
+ /// Returns a Boolean value indicating whether the referenced schema is optional.
317
+ /// - Parameters:
318
+ /// - schema: The reference to check.
319
+ /// - components: The OpenAPI components for looking up references.
320
+ /// - cache: Memoised optionality by reference.
321
+ /// - Throws: An error if there's an issue while checking the schema.
322
+ /// - Returns: `true` if the schema is optional, `false` otherwise.
323
+ func isOptional( _ ref: JSONReference < JSONSchema > , components: OpenAPI . Components , cache: inout [ JSONReference < JSONSchema > : Bool ] ) throws -> Bool {
324
+ if let result = cache [ ref] {
325
+ return result
272
326
}
327
+ let targetSchema = try components. lookup ( ref)
328
+ cache [ ref] = false // Pre-cache to treat directly recursive types as non-nullable.
329
+ let result = try isOptional ( targetSchema, components: components, cache: & cache)
330
+ cache [ ref] = result
331
+ return result
273
332
}
274
333
275
334
// MARK: - Private
0 commit comments