Skip to content
This repository was archived by the owner on Feb 26, 2026. It is now read-only.

Commit f93b40b

Browse files
pepicrftclaude
andauthored
feat: add support for strictMemorySafety SwiftSetting and improve error handling (#354)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 49026b3 commit f93b40b

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

Sources/XcodeGraph/PackageInfo.swift

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ extension PackageInfo.Target {
436436
/// A namespace for target-specific build settings.
437437
public enum TargetBuildSettingDescription {
438438
/// The tool for which a build setting is declared.
439-
public enum Tool: String, Codable, Hashable, CaseIterable {
439+
public enum Tool: String, Codable, Hashable, CaseIterable, Sendable {
440440
case c
441441
case cxx
442442
case swift
@@ -455,6 +455,7 @@ extension PackageInfo.Target {
455455
case enableExperimentalFeature
456456
case interoperabilityMode
457457
case defaultIsolation
458+
case strictMemorySafety
458459
}
459460

460461
/// An individual build setting.
@@ -506,6 +507,26 @@ extension PackageInfo.Target {
506507
case enableExperimentalFeature(String)
507508
case interoperabilityMode(String)
508509
case defaultIsolation(String)
510+
case strictMemorySafety(String)
511+
}
512+
513+
enum SettingDecodingError: LocalizedError {
514+
case missingRequiredKeys(tool: Tool, availableKeys: [String], codingPath: [CodingKey])
515+
516+
var errorDescription: String? {
517+
switch self {
518+
case let .missingRequiredKeys(tool, availableKeys, codingPath):
519+
let path = codingPath.map(\.stringValue).joined(separator: ".")
520+
return """
521+
Failed to decode target build setting at '\(path)'.
522+
Expected either 'kind' (Xcode 14+ format) or 'name' (legacy format) key, but neither was found.
523+
Tool: \(tool)
524+
Available keys: \(availableKeys.joined(separator: ", "))
525+
526+
This usually indicates a malformed Package.swift manifest or an unsupported Swift Package Manager version.
527+
"""
528+
}
529+
}
509530
}
510531

511532
public init(from decoder: Decoder) throws {
@@ -545,10 +566,24 @@ extension PackageInfo.Target {
545566
case let .defaultIsolation(value):
546567
name = .defaultIsolation
547568
self.value = [value]
569+
case let .strictMemorySafety(value):
570+
name = .strictMemorySafety
571+
self.value = [value]
548572
}
549573
} else {
550-
name = try container.decode(SettingName.self, forKey: .name)
551-
value = try container.decode([String].self, forKey: .value)
574+
// Legacy format - try to decode name
575+
do {
576+
name = try container.decode(SettingName.self, forKey: .name)
577+
value = try container.decode([String].self, forKey: .value)
578+
} catch {
579+
// Neither 'kind' nor 'name' was found - provide helpful error
580+
let availableKeys = container.allKeys.map(\.stringValue)
581+
throw SettingDecodingError.missingRequiredKeys(
582+
tool: tool,
583+
availableKeys: availableKeys,
584+
codingPath: decoder.codingPath
585+
)
586+
}
552587
}
553588
}
554589

@@ -578,6 +613,8 @@ extension PackageInfo.Target {
578613
try container.encode(Kind.swiftLanguageMode(value.first!), forKey: .kind)
579614
case .defaultIsolation:
580615
try container.encode(Kind.defaultIsolation(value.first!), forKey: .kind)
616+
case .strictMemorySafety:
617+
try container.encode(Kind.strictMemorySafety(value.first!), forKey: .kind)
581618
}
582619
}
583620
}

0 commit comments

Comments
 (0)