Skip to content
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

Encode JSON with sorted keys by default #158

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 11 additions & 7 deletions Sources/SwiftDocC/Converter/RenderNode+Coding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,25 @@ public enum RenderJSONEncoder {
/// process which should not be shared in other encoding units. Instead, call this API to create a new encoder for each render node you want to encode.
///
/// - Parameters:
/// - prettyPrint: If `true`, the encoder formats its output to make it easy to read; if `false`, the output is compact.
/// - prettyPrint: Whether or not the the encoder should pretty print the RenderJSON output.
///
/// If `true`, the encoder formats its output to make it easy to read. If `false`, the output is compact. If no value is provided, the ``shouldPrettyPrintOutputJSON`` default is used.
/// - emitVariantOverrides: Whether the encoder should emit the top-level ``RenderNode/variantOverrides`` property that holds language-
/// specific documentation data.
/// - Returns: The new JSON encoder.
public static func makeEncoder(
prettyPrint: Bool = shouldPrettyPrintOutputJSON,
prettyPrint: Bool? = nil,
emitVariantOverrides: Bool = true
) -> JSONEncoder {
let encoder = JSONEncoder()
let encoder = JSONEncoder.default

if prettyPrint {
if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
// Only modify the default encoder's pretty print formatting setting
// if a value was provided.
if let prettyPrint = prettyPrint {
if prettyPrint {
encoder.outputFormatting.insert(.prettyPrinted)
} else {
encoder.outputFormatting = [.prettyPrinted]
encoder.outputFormatting.subtract(.prettyPrinted)
}
}

Expand Down
9 changes: 1 addition & 8 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1047,16 +1047,9 @@ extension NavigatorIndex {
if emitJSONRepresentation {
let renderIndex = RenderIndex.fromNavigatorIndex(navigatorIndex, with: self)

let jsonEncoder = JSONEncoder()
if shouldPrettyPrintOutputJSON {
jsonEncoder.outputFormatting = [.sortedKeys, .prettyPrinted]
} else {
jsonEncoder.outputFormatting = [.sortedKeys]
}

let jsonNavigatorIndexURL = outputURL.appendingPathComponent("index.json")
do {
let renderIndexData = try jsonEncoder.encode(renderIndex)
let renderIndexData = try JSONEncoder.default.encode(renderIndex)
try renderIndexData.write(to: jsonNavigatorIndexURL)
} catch {
self.problems.append(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,7 @@ indirect enum JSON: Codable {
extension JSON: CustomDebugStringConvertible {
var debugDescription: String {
let encoder = JSONEncoder()
if #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
} else {
encoder.outputFormatting = [.prettyPrinted]
}
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]

do {
let data = try encoder.encode(self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ class ExternalReferenceResolverServiceClient {
qos: .unspecified
)

private var encoder = JSONEncoder()

init(server: DocumentationServer, convertRequestIdentifier: String?) {
self.server = server
self.convertRequestIdentifier = convertRequestIdentifier
Expand All @@ -46,7 +44,7 @@ class ExternalReferenceResolverServiceClient {
guard let self = self else { return }

do {
let encodedRequest = try self.encoder.encode(
let encodedRequest = try JSONEncoder.default.encode(
ConvertRequestContextWrapper(
convertRequestIdentifier: self.convertRequestIdentifier,
payload: request
Expand All @@ -59,7 +57,7 @@ class ExternalReferenceResolverServiceClient {
payload: encodedRequest
)

let messageData = try self.encoder.encode(message)
let messageData = try JSONEncoder.default.encode(message)

self.server.process(messageData) { responseData in
defer { resultGroup.leave() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ private class LongRunningProcess: ExternalLinkResolving {

func sendAndWait<Request: Codable & CustomStringConvertible, Response: Codable>(request: Request?) throws -> Response {
if let request = request {
guard let requestString = String(data: try JSONEncoder().encode(request), encoding: .utf8)?.appending("\n"),
guard let requestString = String(data: try JSONEncoder.default.encode(request), encoding: .utf8)?.appending("\n"),
let requestData = requestString.data(using: .utf8)
else {
throw OutOfProcessReferenceResolver.Error.unableToEncodeRequestToClient(requestDescription: request.description)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public struct JSONPatchApplier {
return newValue
}

return try JSONEncoder().encode(appliedJSON)
return try JSONEncoder.default.encode(appliedJSON)
}

private func apply(_ operation: JSONPatchOperation, to json: JSON, originalPointer: JSONPointer) throws -> JSON? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
This source file is part of the Swift.org open source project
Copyright (c) 2022 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 Swift project authors
*/

import Foundation

extension JSONEncoder {
/// The encoder that should be used when creating JSON files that
/// are written to disk.
static var `default`: JSONEncoder {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]

if shouldPrettyPrintOutputJSON {
encoder.outputFormatting.insert(.prettyPrinted)
}

return encoder
}
}
63 changes: 0 additions & 63 deletions Sources/SwiftDocC/Utility/MarkupExtensions/ListItemExtractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,6 @@
import Markdown
import Foundation

/// The list of tags that can appear at the start of a list item to indicate
/// some meaning in the markup, taken from Swift documentation comments. These
/// are maintained for backward compatibility but their use should be
/// discouraged.
let simpleListItemTags = [
"attention",
"author",
"authors",
"bug",
"complexity",
"copyright",
"date",
"experiment",
"important",
"invariant",
"localizationkey",
"mutatingvariant",
"nonmutatingvariant",
"note",
"postcondition",
"precondition",
"remark",
"remarks",
"returns",
"throws",
"requires",
"seealso",
"since",
"tag",
"todo",
"version",
"warning",
"keyword",
"recommended",
"recommendedover",
]

extension Collection where Element == InlineMarkup {
func extractParameter() -> Parameter? {
guard let initialTextNode = first as? Text else {
Expand Down Expand Up @@ -102,26 +65,6 @@ extension ListItem {
return nil
}

/**
Extract a "simple tag" from the list of known list item tags.

Expected form:

```markdown
- todo: ...
- seeAlso: ...
```
...etc.
*/
func extractSimpleTag() -> SimpleTag? {
for tag in simpleListItemTags {
if let contents = extractTag(tag + ":") {
return SimpleTag(tag: tag, contents: contents)
}
}
return nil
}

/**
Extract a standalone parameter description from this list item.

Expand Down Expand Up @@ -224,7 +167,6 @@ struct TaggedListItemExtractor: MarkupRewriter {
var parameters = [Parameter]()
var returns = [Return]()
var `throws` = [Throw]()
var otherTags = [SimpleTag]()

init() {}

Expand Down Expand Up @@ -311,11 +253,6 @@ struct TaggedListItemExtractor: MarkupRewriter {
// - parameter x: ...
parameters.append(parameterDescription)
return nil
} else if let simpleTag = listItem.extractSimpleTag() {
// - todo: ...
// etc.
otherTags.append(simpleTag)
return nil
}

// No match; leave this list item alone.
Expand Down
12 changes: 3 additions & 9 deletions Tests/SwiftDocCTests/Converter/RenderNodeCodableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,12 @@ class RenderNodeCodableTests: XCTestCase {
}
}

func testSortedKeys() throws {
guard #available(macOS 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) else {
throw XCTSkip("Skipped on platforms that don't support JSONEncoder.OutputFormatting.sortedKeys")
}

// When prettyPrint is enabled, keys are sorted
func testPrettyPrinted() throws {
let encoderPretty = RenderJSONEncoder.makeEncoder(prettyPrint: true)
XCTAssertTrue(encoderPretty.outputFormatting.contains(.sortedKeys))
XCTAssertTrue(encoderPretty.outputFormatting.contains(.prettyPrinted))

// When prettyPrint is disabled, keys are not sorted
let encoderNotPretty = RenderJSONEncoder.makeEncoder(prettyPrint: false)
XCTAssertFalse(encoderNotPretty.outputFormatting.contains(.sortedKeys))
XCTAssertFalse(encoderNotPretty.outputFormatting.contains(.prettyPrinted))
}

func testEncodesVariantOverridesSetAsProperty() throws {
Expand Down