mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2025-12-22 12:18:06 +01:00
88 lines
3.2 KiB
Swift
88 lines
3.2 KiB
Swift
import Foundation
|
|
import SwiftParser
|
|
import SwiftSyntax
|
|
|
|
/// The main entry point for generating a JSON schema and Markdown documentation
|
|
/// for the SourceKit-LSP configuration file format
|
|
/// (`.sourcekit-lsp/config.json`) from the Swift type definitions in
|
|
/// `SKOptions` Swift module.
|
|
public struct ConfigSchemaGen {
|
|
static let projectRoot = URL(fileURLWithPath: #filePath)
|
|
.deletingLastPathComponent()
|
|
.deletingLastPathComponent()
|
|
.deletingLastPathComponent()
|
|
.deletingLastPathComponent()
|
|
static let sourceDir =
|
|
projectRoot
|
|
.appendingPathComponent("Sources")
|
|
.appendingPathComponent("SKOptions")
|
|
static let configSchemaJSONPath =
|
|
projectRoot
|
|
.appendingPathComponent("config.schema.json")
|
|
static let configSchemaDocPath =
|
|
projectRoot
|
|
.appendingPathComponent("Documentation")
|
|
.appendingPathComponent("Configuration File.md")
|
|
|
|
public static func generate() throws {
|
|
let sourceFiles = FileManager.default.enumerator(at: sourceDir, includingPropertiesForKeys: nil)!
|
|
let typeNameResolver = TypeDeclResolver()
|
|
|
|
for case let fileURL as URL in sourceFiles {
|
|
guard fileURL.pathExtension == "swift" else {
|
|
continue
|
|
}
|
|
let sourceText = try String(contentsOf: fileURL)
|
|
let sourceFile = Parser.parse(source: sourceText)
|
|
typeNameResolver.append(sourceFile)
|
|
}
|
|
let rootTypeDecl = try typeNameResolver.lookupType(fullyQualified: ["SourceKitLSPOptions"])
|
|
let context = OptionSchemaContext(typeNameResolver: typeNameResolver)
|
|
var schema = try context.buildSchema(from: rootTypeDecl)
|
|
|
|
// Manually annotate the logging level enum since LogLevel type exists
|
|
// outside of the SKOptions module
|
|
schema["logging"]?["level"]?.kind = .enum(
|
|
OptionTypeSchama.Enum(
|
|
name: "LogLevel",
|
|
cases: ["debug", "info", "default", "error", "fault"].map {
|
|
OptionTypeSchama.Case(name: $0)
|
|
}
|
|
)
|
|
)
|
|
schema["logging"]?["privacyLevel"]?.kind = .enum(
|
|
OptionTypeSchama.Enum(
|
|
name: "PrivacyLevel",
|
|
cases: ["sensitive", "private", "public"].map {
|
|
OptionTypeSchama.Case(name: $0)
|
|
}
|
|
)
|
|
)
|
|
|
|
print("Writing schema to \(configSchemaJSONPath.path)")
|
|
try generateJSONSchema(from: schema, context: context).write(to: configSchemaJSONPath)
|
|
|
|
print("Writing schema documentation to \(configSchemaDocPath.path)")
|
|
try generateDocumentation(from: schema, context: context).write(
|
|
to: configSchemaDocPath,
|
|
atomically: true,
|
|
encoding: .utf8
|
|
)
|
|
}
|
|
|
|
static func generateJSONSchema(from schema: OptionTypeSchama, context: OptionSchemaContext) throws -> Data {
|
|
let schemaBuilder = JSONSchemaBuilder(context: context)
|
|
var jsonSchema = try schemaBuilder.build(from: schema)
|
|
jsonSchema.title = "SourceKit-LSP Configuration"
|
|
jsonSchema.comment = "DO NOT EDIT THIS FILE. This file is generated by \(#fileID)."
|
|
let encoder = JSONEncoder()
|
|
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
|
return try encoder.encode(jsonSchema)
|
|
}
|
|
|
|
static func generateDocumentation(from schema: OptionTypeSchama, context: OptionSchemaContext) throws -> String {
|
|
let docBuilder = OptionDocumentBuilder(context: context)
|
|
return try docBuilder.build(from: schema)
|
|
}
|
|
}
|