Skip to content

Instantly share code, notes, and snippets.

@mattpolzin
Last active October 26, 2025 01:55
Show Gist options
  • Select an option

  • Save mattpolzin/950f1478f781716948ee3dd8e8996c34 to your computer and use it in GitHub Desktop.

Select an option

Save mattpolzin/950f1478f781716948ee3dd8e8996c34 to your computer and use it in GitHub Desktop.
External File Loading for Swift OpenAPI Generator
import Foundation
import OpenAPIKit
import Yams
struct NonFileURLError: Swift.Error {
let url: URL
}
public struct GeneratorExternalLoader: ExternalLoader {
public typealias Message = Void
public static func load<T>(_ url: URL) async throws -> (T, [Message]) where T: Decodable {
// guard url.isFileURL else { throw NonFileURLError(url: url) }
let fileUrl = URL(string: url.absoluteString, relativeTo: URL.currentDirectory())!
let (data, _) = try await URLSession.shared.data(from: fileUrl)
let decodedValue = try YAMLDecoder().decode(T.self, from: data)
let augmentedValue: T
// we want to keep track of where a reference was loaded from. Vendor
// Extensions are a nice place for this information.
if var extendable = decodedValue as? any VendorExtendable {
extendable.vendorExtensions["x-source-url"] = AnyCodable(url)
augmentedValue = extendable as! T
} else {
augmentedValue = decodedValue
}
return (augmentedValue, [])
}
public static func componentKey<T>(type: T.Type, at url: URL) throws -> OpenAPIKit.OpenAPI.ComponentKey {
// unverified whether this will always result in a valid components key.
// needs more thinking.
let pathExtension = url.pathExtension
let urlString = url.pathComponents.dropFirst().joined(separator: "_").replacingOccurrences(of: ".", with: "_")
let componentKeyString: String
if pathExtension.isEmpty {
componentKeyString = urlString
} else {
componentKeyString = String(urlString.dropLast(pathExtension.count + 1))
}
return try .forceInit(rawValue: componentKeyString)
}
}
diff --git a/Sources/swift-openapi-generator/FilterCommand.swift b/Sources/swift-openapi-generator/FilterCommand.swift
index bb689b5..27881ba 100644
--- a/Sources/swift-openapi-generator/FilterCommand.swift
+++ b/Sources/swift-openapi-generator/FilterCommand.swift
@@ -43,10 +43,11 @@ struct _FilterCommand: AsyncParsableCommand {
let configData = try Data(contentsOf: config)
let config = try YAMLDecoder().decode(_UserConfig.self, from: configData)
let documentInput = try InMemoryInputFile(absolutePath: docPath, contents: Data(contentsOf: docPath))
- let document = try timing(
+ var document = try timing(
"Parsing document",
YamsParser.parseOpenAPIDocument(documentInput, diagnostics: StdErrPrintingDiagnosticCollector())
)
+ try await document.externallyDereference(with: GeneratorExternalLoader.self, depth: 1)
guard let documentFilter = config.filter else {
FileHandle.standardError.write("warning: No filter config provided\n")
FileHandle.standardOutput.write(try encode(document, outputFormat))
summary: hello
openapi: '3.2.0'
info:
title: test
version: '1.0.0'
paths:
'/hello':
$ref: './Hello.yml'
openapi: 3.1.2
info:
title: test
version: 1.0.0
paths:
/hello:
$ref: '#/components/pathItems/Hello'
components:
pathItems:
Hello:
summary: hello
x-source-url: ./Hello.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment