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

Feature: Strict decoding #17

Closed
stackotter opened this issue May 8, 2022 · 4 comments · Fixed by #18
Closed

Feature: Strict decoding #17

stackotter opened this issue May 8, 2022 · 4 comments · Fixed by #18

Comments

@stackotter
Copy link
Contributor

I am currently using TOMLKit in a few projects to decode configuration files. It would be extremely useful if TOMLKit's Codable implementation had an option to do strict decoding. By strict decoding I mean throwing an error if any unexpected keys are present. This makes typos of optional keys a lot easier for users to detect (because the typoed key would cause an error to be thrown instead of just silently being ignored).

@LebJe LebJe linked a pull request May 10, 2022 that will close this issue
@LebJe
Copy link
Owner

LebJe commented May 10, 2022

@stackotter, I've pushed an implementation to strictDecoding. Can you try it and see if it works for you?

let decoder = TOMLDecoder(strictDecoding: true)

struct A: Decodable {
    let a: String
    let b: B

    struct B: Decodable {
        let c: Double
    }
}

let toml = """
a = "abc"

[b]
c = 25.353
d = "def"
f = [1, 2, 3]
"""

do {
    let a = try decoder.decode(A.self, from: toml)
} catch let error as UnexpectedKeysError {
    print("\(error.keys) were not decoded")
}

@stackotter
Copy link
Contributor Author

Hi @LebJe, the code snippet you have provided does seem to work correctly. However, when I tried to enable strict decoding in swift-bundler, I seem to have run into an issue. Here's the input toml:

description = "A simple 'Hello, World!' SwiftUI app."
platforms = ["macOS"]
minimum_swift_version = "5.5"

And here's the code I'm using to decode that snippet.

import Foundation
import TOMLKit
import Version

/// The contents of a template's manifest file.
struct TemplateManifest: Codable {
  /// A short description of the package.
  var description: String
  /// The list of supported platforms.
  var platforms: [String]
  /// The minimum Swift version required to use the template.
  var minimumSwiftVersion: Version
  /// The system dependencies required by this template (keyed by the user-facing dependency name).
  var systemDependencies: [String: SystemDependency]?

  private enum CodingKeys: String, CodingKey {
    case description
    case platforms
    case minimumSwiftVersion = "minimum_swift_version"
    case systemDependencies = "system_dependencies"
  }

  /// Loads a template's manifest file.
  /// - Parameters:
  ///   - file: The manifest file to load.
  ///   - template: The name of the template that the manifest is for.
  /// - Returns: The loaded manifest, or a failure if the file could not be read or decoded.
  static func load(from file: URL, template: String) -> Result<TemplateManifest, TemplaterError> {
    let contents: String
    do {
      contents = try String.init(contentsOf: file)
    } catch {
      return .failure(.failedToReadTemplateManifest(template: template, manifest: file, error))
    }

    let manifest: TemplateManifest
    do {
      var decoder = TOMLDecoder(strictDecoding: true)

      // Set the Version decoding method to tolerant
      decoder.userInfo[.decodingMethod] = DecodingMethod.tolerant

      manifest = try decoder.decode(TemplateManifest.self, from: contents)
    } catch {
      return .failure(.failedToDecodeTemplateManifest(template: template, manifest: file, error))
    }

    return .success(manifest)
  }
}

Without specifying strictDecoding: true, the TemplateManifest toml successfully decodes, and the minimum_swift_version key can be read. However, with strictDecoding enabled, I get the following error: TOMLKit.UnexpectedKeysError(keys: ["minimum_swift_version"]).

@LebJe
Copy link
Owner

LebJe commented Sep 2, 2022

@stackotter, sorry for the long delay. I have fixed the issue you posted, and changed UnexpectedKeysError’s keys property from an Array of keys, to a Dictionary whose keys are the un-decoded TOML keys, and whose values are the CodingKey’s that leads to the TOML key.
If this works for you, I'll create a new release.

@LebJe LebJe closed this as completed in #18 Sep 8, 2022
@stackotter
Copy link
Contributor Author

stackotter commented Sep 9, 2022

Thanks! This fixes the issue I was having :)

Sorry that I took a while to get around to testing this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants