@@ -114,6 +114,29 @@ extension OpenAPI.Components {
114114 return self [ localReference]
115115 }
116116
117+ /// Retrieve schema from the `Components`. If the JSONSchema is not a
118+ /// reference, it will be returned as-is. If it is a reference, it will be
119+ /// looked up in the components if it refers to a components entry. If the
120+ /// reference does not refer to a components entry, the function will return
121+ /// `nil`.
122+ ///
123+ /// This function will follow subsequent refernences found within the
124+ /// `Components` as long as no cycles are encountered. If a cycle is
125+ /// encountered or a reference to a part of the document outside of the
126+ /// `Components` is encountered then the function returns `nil`.
127+ ///
128+ /// If you want a throwing lookup, use the `lookup()` method.
129+ public subscript( _ schema: JSONSchema ) -> JSONSchema ? {
130+ guard case . reference( let reference, _) = schema. value else {
131+ return schema
132+ }
133+ guard case . internal( let localReference) = reference else {
134+ return nil
135+ }
136+
137+ return self [ localReference]
138+ }
139+
117140 /// Retrieve item referenced from the `Components`.
118141 ///
119142 /// This function will follow subsequent refernences found within the
@@ -328,6 +351,13 @@ extension OpenAPI.Components {
328351 guard let value else {
329352 throw ReferenceError . missingOnLookup ( name: reference. name ?? " unnamed " , key: ReferenceType . openAPIComponentsKey)
330353 }
354+
355+ // special case for JSONSchemas that are references
356+ if let schema = value as? JSONSchema ,
357+ case let . reference( newReference, _) = schema. value {
358+ return try _lookup ( newReference, following: visitedReferences. union ( [ reference] ) ) as! ReferenceType
359+ }
360+
331361 return value
332362
333363 case . b( let referencePath) :
@@ -374,6 +404,33 @@ extension OpenAPI.Components {
374404 }
375405 }
376406
407+ /// Lookup schema in the `Components`. If the JSONSchema is not a
408+ /// reference, it will be returned as-is. If it is a reference, it will be
409+ /// looked up in the components if it refers to a components entry.
410+ ///
411+ /// This function will follow subsequent refernences found within the
412+ /// `Components` as long as no cycles are encountered.
413+ ///
414+ /// If you want to look something up without throwing, you might want to use the subscript
415+ /// operator on the `Components`.
416+ ///
417+ /// If you also want to fully dereference the value in question instead
418+ /// of just looking it up see the various `dereference` functions
419+ /// on this type for more information.
420+ ///
421+ /// - Important: Looking up an external reference (i.e. one that points to another file)
422+ /// is not currently supported by OpenAPIKit and will therefore always throw an error.
423+ ///
424+ /// - Throws: `ReferenceError.cannotLookupRemoteReference` or
425+ /// `ReferenceError.missingOnLookup(name:,key:)` or
426+ /// `ReferenceCycleError`
427+ public func lookup( _ schema: JSONSchema ) throws -> JSONSchema {
428+ guard case . reference( let reference, _) = schema. value else {
429+ return schema
430+ }
431+ return try lookup ( reference)
432+ }
433+
377434 /// Create an `OpenAPI.Reference`.
378435 ///
379436 /// - Throws: If the given name does not refer to an existing component of the given type.
0 commit comments