Skip to content

Commit

Permalink
fix: fixed error with private access modifier on type declaration (#46
Browse files Browse the repository at this point in the history
)
  • Loading branch information
soumyamahunt committed Dec 4, 2023
1 parent 12784b2 commit d378204
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@_implementationOnly import SwiftSyntax

extension Registrar.Options {
/// A declaration modifiers generator for `Codable`
/// conformance implementations.
///
/// This generator keeps track of original declaration
/// and modifiers, then generates modifiers for
/// `Decodable` or `Encodable` implementations.
struct DeclModifiersGenerator {
/// The declaration for which modifiers generated.
let decl: DeclGroupSyntax

/// The generated list of modifiers.
///
/// If declaration has `public` or `package` modifier
/// then same is generated, otherwise no extra modifiers
/// generated.
var generated: DeclModifierListSyntax {
let `public` = DeclModifierSyntax(name: "public")
let package = DeclModifierSyntax(name: "package")
var modifiers = DeclModifierListSyntax()
let accessModifier = [`public`, package].first { accessModifier in
decl.modifiers.contains { modifier in
modifier.name.text == accessModifier.name.text
}
}
if let accessModifier {
modifiers.append(accessModifier)
}
return modifiers
}
}
}
37 changes: 37 additions & 0 deletions Sources/CodableMacroPlugin/Registration/Options/Options.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@_implementationOnly import SwiftSyntax

extension Registrar {
/// A type indicating various configurations available
/// for `Registrar`.
///
/// These options are used as global level customization
/// performed on the final generated implementation
/// of `Codable` conformance.
struct Options {
/// The list of modifiers generator for
/// conformance implementation declarations.
let modifiersGenerator: DeclModifiersGenerator
/// The where clause generator for generic type arguments.
let constraintGenerator: ConstraintGenerator

/// Memberwise initialization generator with provided options.
///
/// Creates memberwise initialization generator by passing
/// the provided access modifiers.
var initGenerator: MemberwiseInitGenerator {
let modifiers = modifiersGenerator.generated
return .init(options: .init(modifiers: modifiers))
}

/// Creates a new options instance with provided declaration group.
///
/// - Parameters:
/// - decl: The declaration group options will be applied to.
///
/// - Returns: The newly created options.
init(decl: DeclGroupSyntax) {
self.modifiersGenerator = .init(decl: decl)
self.constraintGenerator = .init(decl: decl)
}
}
}
39 changes: 4 additions & 35 deletions Sources/CodableMacroPlugin/Registration/Registrar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,6 @@
/// use `decoding`, `encoding` and `codingKeys` methods
/// to get final generated implementation of `Codable` conformance.
struct Registrar {
/// A type indicating various configurations available
/// for `Registrar`.
///
/// These options are used as global level customization
/// performed on the final generated implementation
/// of `Codable` conformance.
struct Options {
/// The default list of modifiers to be applied to generated
/// conformance implementation declarations.
fileprivate let modifiers: DeclModifierListSyntax
/// The where clause generator for generic type arguments.
fileprivate let constraintGenerator: ConstraintGenerator

/// Memberwise initialization generator with provided options.
///
/// Creates memberwise initialization generator by passing
/// the provided access modifiers.
var initGenerator: MemberwiseInitGenerator {
return .init(options: .init(modifiers: modifiers))
}

/// Creates a new options instance with provided declaration group.
///
/// - Parameters:
/// - decl: The declaration group options will be applied to.
///
/// - Returns: The newly created options.
init(decl: DeclGroupSyntax) {
self.modifiers = decl.modifiers
self.constraintGenerator = .init(decl: decl)
}
}

/// The root node containing all the keys
/// and associated field metadata maps.
private var root: Node
Expand Down Expand Up @@ -190,7 +157,7 @@ struct Registrar {
)
) {
InitializerDeclSyntax.decode(
modifiers: options.modifiers
modifiers: options.modifiersGenerator.generated
) { decoder in
let type = caseMap.type
root.decoding(in: context, from: .coder(decoder, keyType: type))
Expand Down Expand Up @@ -223,7 +190,9 @@ struct Registrar {
conformingTo: `protocol`
)
) {
FunctionDeclSyntax.encode(modifiers: options.modifiers) { encoder in
FunctionDeclSyntax.encode(
modifiers: options.modifiersGenerator.generated
) { encoder in
let type = caseMap.type
root.encoding(in: context, from: .coder(encoder, keyType: type))
}
Expand Down
137 changes: 137 additions & 0 deletions Tests/MetaCodableTests/AccessModifierTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#if SWIFT_SYNTAX_EXTENSION_MACRO_FIXED
import XCTest

@testable import CodableMacroPlugin

final class AccessModifierTests: XCTestCase {

func testPublic() throws {
assertMacroExpansion(
"""
@Codable
@MemberInit
public struct SomeCodable {
let value: String
}
""",
expandedSource:
"""
public struct SomeCodable {
let value: String
public init(value: String) {
self.value = value
}
}
extension SomeCodable: Decodable {
public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
}
}
extension SomeCodable: Encodable {
public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.value, forKey: CodingKeys.value)
}
}
extension SomeCodable {
enum CodingKeys: String, CodingKey {
case value = "value"
}
}
"""
)
}

func testPackage() throws {
assertMacroExpansion(
"""
@Codable
@MemberInit
package struct SomeCodable {
let value: String
}
""",
expandedSource:
"""
package struct SomeCodable {
let value: String
package init(value: String) {
self.value = value
}
}
extension SomeCodable: Decodable {
package init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
}
}
extension SomeCodable: Encodable {
package func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.value, forKey: CodingKeys.value)
}
}
extension SomeCodable {
enum CodingKeys: String, CodingKey {
case value = "value"
}
}
"""
)
}

func testOthers() throws {
for modifier in ["internal", "fileprivate", "private", ""] {
let prefix = modifier.isEmpty ? "" : "\(modifier) "
assertMacroExpansion(
"""
@Codable
@MemberInit
\(prefix)struct SomeCodable {
let value: String
}
""",
expandedSource:
"""
\(prefix)struct SomeCodable {
let value: String
init(value: String) {
self.value = value
}
}
extension SomeCodable: Decodable {
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.value = try container.decode(String.self, forKey: CodingKeys.value)
}
}
extension SomeCodable: Encodable {
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.value, forKey: CodingKeys.value)
}
}
extension SomeCodable {
enum CodingKeys: String, CodingKey {
case value = "value"
}
}
"""
)
}
}
}
#endif

0 comments on commit d378204

Please sign in to comment.