-
Notifications
You must be signed in to change notification settings - Fork 307
Generate JSON Schema and Markdown doc for .sourcekit-lsp/config.json
#1849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
9b07134
Generate JSON Schema and Markdown doc for `.sourcekit-lsp/config.json`
kateinoigakukun 2270836
Add missing periods to doc comment sentences for SourceKitLSPOptions
kateinoigakukun cbf04ea
Replace newlines with spaces in property descriptions
kateinoigakukun 96b582c
Remove duplicate possible values from `defaultWorkspaceType`
kateinoigakukun 7597945
Use an enum for `backgroundPreparationMode` in the configuration file…
kateinoigakukun f298dbe
Use top-level .gitignore for ConfigSchemaGen
kateinoigakukun 62c4d26
Make `ConfigSchemaGen` as a subcommand of `sourcekit-lsp-dev-utils`
kateinoigakukun 2c403e7
Add copyright headers to new files
kateinoigakukun e399754
Add `./sourcekit-lsp-dev-utils` script
kateinoigakukun 864af4d
Add `verify-config-schema` command to `sourcekit-lsp-dev-utils`
kateinoigakukun d3ad334
Address code-style feedback
kateinoigakukun aa7be46
Fix the scope building for type declarations
kateinoigakukun 1847dc7
Rename `OptionTypeSchama.Object` to `Struct`
kateinoigakukun 6aaa056
Throw errors instead of using fatalError
kateinoigakukun 2778a19
Use `representedLiteralValue` to get the string value of a string lit…
kateinoigakukun c106f5c
Fix formatting of ./SourceKitLSPDevUtils
kateinoigakukun 90dc733
Keep the original order of `privacyLevel` enum cases
kateinoigakukun e495589
Fix `markdownEnumDescriptions` encoding for JSON Schema
kateinoigakukun 185438c
swift-format -i -r SourceKitLSPDevUtils/Sources
kateinoigakukun 6803d8c
Address code style feedbacks
kateinoigakukun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
.DS_Store | ||
default.profraw | ||
Package.resolved | ||
/.build | ||
.build | ||
/.*-build | ||
/Packages | ||
/*.xcodeproj | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// swift-tools-version: 6.0 | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "SourceKitLSPDevUtils", | ||
platforms: [.macOS(.v10_15)], | ||
products: [ | ||
.executable(name: "sourcekit-lsp-dev-utils", targets: ["SourceKitLSPDevUtils"]) | ||
], | ||
dependencies: [ | ||
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"), | ||
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"), | ||
], | ||
targets: [ | ||
.executableTarget( | ||
name: "SourceKitLSPDevUtils", | ||
dependencies: [ | ||
"ConfigSchemaGen", | ||
.product(name: "ArgumentParser", package: "swift-argument-parser"), | ||
] | ||
), | ||
.target( | ||
name: "ConfigSchemaGen", | ||
dependencies: [ | ||
.product(name: "SwiftSyntax", package: "swift-syntax"), | ||
.product(name: "SwiftParser", package: "swift-syntax"), | ||
] | ||
), | ||
] | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# sourcekit-lsp-dev-utils | ||
|
||
This directory contains utilities for developing SourceKit-LSP. [CONTRIBUTING.md](../CONTRIBUTING.md) covers how to use these utilities. |
151 changes: 151 additions & 0 deletions
151
SourceKitLSPDevUtils/Sources/ConfigSchemaGen/ConfigSchemaGen.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
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. | ||
package struct ConfigSchemaGen { | ||
private struct WritePlan { | ||
fileprivate let category: String | ||
fileprivate let path: URL | ||
fileprivate let contents: () throws -> Data | ||
|
||
fileprivate func write() throws { | ||
try contents().write(to: path) | ||
} | ||
} | ||
|
||
private static let projectRoot = URL(fileURLWithPath: #filePath) | ||
.deletingLastPathComponent() | ||
.deletingLastPathComponent() | ||
.deletingLastPathComponent() | ||
.deletingLastPathComponent() | ||
private static let sourceDir = | ||
projectRoot | ||
.appendingPathComponent("Sources") | ||
.appendingPathComponent("SKOptions") | ||
private static let configSchemaJSONPath = | ||
projectRoot | ||
.appendingPathComponent("config.schema.json") | ||
private static let configSchemaDocPath = | ||
projectRoot | ||
.appendingPathComponent("Documentation") | ||
.appendingPathComponent("Configuration File.md") | ||
|
||
/// Generates and writes the JSON schema and documentation for the SourceKit-LSP configuration file format. | ||
package static func generate() throws { | ||
let plans = try plan() | ||
for plan in plans { | ||
print("Writing \(plan.category) to \"\(plan.path.path)\"") | ||
try plan.write() | ||
} | ||
} | ||
|
||
/// Verifies that the generated JSON schema and documentation in the current source tree | ||
/// are up-to-date with the Swift type definitions in `SKOptions`. | ||
/// - Returns: `true` if the generated files are up-to-date, `false` otherwise. | ||
package static func verify() throws -> Bool { | ||
let plans = try plan() | ||
for plan in plans { | ||
print("Verifying \(plan.category) at \"\(plan.path.path)\"") | ||
let expectedContents = try plan.contents() | ||
let actualContents = try Data(contentsOf: plan.path) | ||
guard expectedContents == actualContents else { | ||
print("error: \(plan.category) is out-of-date!") | ||
print("Please run `./sourcekit-lsp-dev-utils generate-config-schema` to update it.") | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
private static func plan() throws -> [WritePlan] { | ||
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.collect(from: 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: ["public", "private", "sensitive"].map { | ||
OptionTypeSchama.Case(name: $0) | ||
} | ||
) | ||
) | ||
|
||
return [ | ||
WritePlan( | ||
category: "JSON Schema", | ||
path: configSchemaJSONPath, | ||
contents: { try generateJSONSchema(from: schema, context: context) } | ||
), | ||
WritePlan( | ||
category: "Schema Documentation", | ||
path: configSchemaDocPath, | ||
contents: { try generateDocumentation(from: schema, context: context) } | ||
), | ||
] | ||
} | ||
|
||
private 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) | ||
} | ||
|
||
private static func generateDocumentation(from schema: OptionTypeSchama, context: OptionSchemaContext) throws -> Data | ||
{ | ||
let docBuilder = OptionDocumentBuilder(context: context) | ||
guard let data = try docBuilder.build(from: schema).data(using: .utf8) else { | ||
throw ConfigSchemaGenError("Failed to encode documentation as UTF-8") | ||
} | ||
return data | ||
} | ||
} | ||
|
||
struct ConfigSchemaGenError: Error, CustomStringConvertible { | ||
let description: String | ||
|
||
init(_ description: String) { | ||
self.description = description | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.