Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 30 additions & 39 deletions Sources/AnyLanguageModelMacros/GenerableMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,11 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
extendedType: type,
inheritanceClause: InheritanceClauseSyntax(
inheritedTypes: InheritedTypeListSyntax([
InheritedTypeSyntax(
type: TypeSyntax("Generable")
)
InheritedTypeSyntax(type: TypeSyntax(stringLiteral: "Generable"))
])
),
memberBlock: MemberBlockSyntax(
members: MemberBlockItemListSyntax([])
)
memberBlock: MemberBlockSyntax(members: [])
)

return [extensionDecl]
}

Expand Down Expand Up @@ -263,9 +258,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
if properties.isEmpty {
return DeclSyntax(
stringLiteral: """
public init(_ generatedContent: GeneratedContent) throws {
nonisolated public init(_ generatedContent: GeneratedContent) throws {
self._rawGeneratedContent = generatedContent

guard case .structure = generatedContent.kind else {
throw DecodingError.typeMismatch(
\(structName).self,
Expand All @@ -278,16 +273,16 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
} else {
return DeclSyntax(
stringLiteral: """
public init(_ generatedContent: GeneratedContent) throws {
nonisolated public init(_ generatedContent: GeneratedContent) throws {
self._rawGeneratedContent = generatedContent

guard case .structure(let properties, _) = generatedContent.kind else {
throw DecodingError.typeMismatch(
\(structName).self,
DecodingError.Context(codingPath: [], debugDescription: "Expected structure for \(structName)")
)
}

\(propertyExtractions)
}
"""
Expand Down Expand Up @@ -489,9 +484,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
if properties.isEmpty {
return DeclSyntax(
stringLiteral: """
public var generatedContent: GeneratedContent {
nonisolated public var generatedContent: GeneratedContent {
let properties: [String: GeneratedContent] = [:]

return GeneratedContent(
kind: .structure(
properties: properties,
Expand All @@ -504,10 +499,10 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
} else {
return DeclSyntax(
stringLiteral: """
public var generatedContent: GeneratedContent {
nonisolated public var generatedContent: GeneratedContent {
var properties: [String: GeneratedContent] = [:]
\(propertyConversions)

return GeneratedContent(
kind: .structure(
properties: properties,
Expand Down Expand Up @@ -565,8 +560,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public static var generationSchema: GenerationSchema {

nonisolated public static var generationSchema: GenerationSchema {
return GenerationSchema(
type: Self.self,
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(structName)\""),
Expand All @@ -580,7 +574,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
private static func generateAsPartiallyGeneratedMethod(structName: String) -> DeclSyntax {
return DeclSyntax(
stringLiteral: """
public func asPartiallyGenerated() -> PartiallyGenerated {
nonisolated public func asPartiallyGenerated() -> PartiallyGenerated {
return try! PartiallyGenerated(_rawGeneratedContent)
}
"""
Expand All @@ -590,7 +584,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
private static func generateAsPartiallyGeneratedMethodForEnum(enumName: String) -> DeclSyntax {
return DeclSyntax(
stringLiteral: """
public func asPartiallyGenerated() -> \(enumName) {
nonisolated public func asPartiallyGenerated() -> \(enumName) {
return self
}
"""
Expand Down Expand Up @@ -618,19 +612,19 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
stringLiteral: """
public struct PartiallyGenerated: Sendable, ConvertibleFromGeneratedContent {
\(optionalProperties)

private let rawContent: GeneratedContent

public init(_ generatedContent: GeneratedContent) throws {
self.rawContent = generatedContent

if \(properties.isEmpty ? "case .structure = generatedContent.kind" : "case .structure(let properties, _) = generatedContent.kind") {
\(propertyExtractions)
} else {
\(properties.map { "self.\($0.name) = nil" }.joined(separator: "\n "))
}
}

public var generatedContent: GeneratedContent {
return rawContent
}
Expand All @@ -642,7 +636,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
private static func generateInstructionsRepresentationProperty() -> DeclSyntax {
return DeclSyntax(
stringLiteral: """
public var instructionsRepresentation: Instructions {
nonisolated public var instructionsRepresentation: Instructions {
return Instructions(self.generatedContent.jsonString)
}
"""
Expand All @@ -652,7 +646,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
private static func generatePromptRepresentationProperty() -> DeclSyntax {
return DeclSyntax(
stringLiteral: """
public var promptRepresentation: Prompt {
nonisolated public var promptRepresentation: Prompt {
return Prompt(self.generatedContent.jsonString)
}
"""
Expand Down Expand Up @@ -720,16 +714,15 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public init(_ generatedContent: GeneratedContent) throws {

nonisolated public init(_ generatedContent: GeneratedContent) throws {
do {
guard case .structure(let properties, _) = generatedContent.kind else {
throw DecodingError.typeMismatch(
\(enumName).self,
DecodingError.Context(codingPath: [], debugDescription: "Expected structure for enum \(enumName)")
)
}

guard case .string(let caseValue) = properties["case"]?.kind else {
struct Key: CodingKey {
var stringValue: String
Expand All @@ -742,9 +735,9 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {
DecodingError.Context(codingPath: [], debugDescription: "Missing 'case' property in enum data for \(enumName)")
)
}

let valueContent = properties["value"]

switch caseValue {
\(switchCases)
default:
Expand Down Expand Up @@ -775,15 +768,15 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public init(_ generatedContent: GeneratedContent) throws {
nonisolated public init(_ generatedContent: GeneratedContent) throws {
guard case .string(let value) = generatedContent.kind else {
throw DecodingError.typeMismatch(
\(enumName).self,
DecodingError.Context(codingPath: [], debugDescription: "Expected string for enum \(enumName)")
)
}
let trimmedValue = value.trimmingCharacters(in: .whitespacesAndNewlines)

switch trimmedValue {
\(switchCases)
default:
Expand Down Expand Up @@ -942,7 +935,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public var generatedContent: GeneratedContent {
nonisolated public var generatedContent: GeneratedContent {
switch self {
\(switchCases)
}
Expand All @@ -956,7 +949,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public var generatedContent: GeneratedContent {
nonisolated public var generatedContent: GeneratedContent {
switch self {
\(switchCases)
}
Expand Down Expand Up @@ -1059,8 +1052,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public static var generationSchema: GenerationSchema {

nonisolated public static var generationSchema: GenerationSchema {
return GenerationSchema(
type: Self.self,
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(enumName)\""),
Expand All @@ -1077,8 +1069,7 @@ public struct GenerableMacro: MemberMacro, ExtensionMacro {

return DeclSyntax(
stringLiteral: """
public static var generationSchema: GenerationSchema {

nonisolated public static var generationSchema: GenerationSchema {
return GenerationSchema(
type: Self.self,
description: \(description.map { "\"\($0)\"" } ?? "\"Generated \(enumName)\""),
Expand Down
27 changes: 27 additions & 0 deletions Tests/AnyLanguageModelTests/GenerableMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,31 @@ struct GenerableMacroTests {
let decodedSchema = try decoder.decode(GenerationSchema.self, from: jsonData)
#expect(decodedSchema.debugDescription.contains("object"))
}

@MainActor
@Generable
struct MainActorIsolatedStruct {
@Guide(description: "A test field")
var field: String
}

/// Test to verify @Generable works correctly with MainActor isolation.
@MainActor
@Test func mainActorIsolation() async throws {
let generatedContent = GeneratedContent(properties: [
"field": "test value"
])
let instance = try MainActorIsolatedStruct(generatedContent)
#expect(instance.field == "test value")

let convertedBack = instance.generatedContent
let decoded = try MainActorIsolatedStruct(convertedBack)
#expect(decoded.field == "test value")

let schema = MainActorIsolatedStruct.generationSchema
#expect(schema.debugDescription.contains("MainActorIsolatedStruct"))

let partiallyGenerated = instance.asPartiallyGenerated()
#expect(partiallyGenerated.field == "test value")
}
}