Skip to content

Commit 45b22ec

Browse files
committed
[xcodegen] NFC: Factor out xcodeClassName in serialization logic
1 parent a3d5f73 commit 45b22ec

File tree

1 file changed

+66
-76
lines changed

1 file changed

+66
-76
lines changed

utils/swift-xcodegen/Sources/SwiftXcodeGen/Xcodeproj/XcodeProjectModelSerialization.swift

Lines changed: 66 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ extension Xcode.Project {
4343
}
4444

4545
extension Xcode.Project: PropertyListSerializable {
46+
fileprivate var xcodeClassName: String { "PBXProject" }
4647

4748
/// Generates and returns the contents of a `project.pbxproj` plist. Does
4849
/// not generate any ancillary files, such as a set of schemes.
@@ -77,7 +78,7 @@ extension Xcode.Project: PropertyListSerializable {
7778
// by Xcode when it opens the project and notices that they are missing.
7879
// Note: we also skip schemes, since they are not in the project plist.
7980
var dict = [String: PropertyList]()
80-
dict["isa"] = .string("PBXProject")
81+
dict["isa"] = .string(xcodeClassName)
8182
// Since the project file is generated, we opt out of upgrade-checking.
8283
// FIXME: Should we really? Why would we not want to get upgraded?
8384
dict["attributes"] = .dictionary(["LastUpgradeCheck": .string("9999"),
@@ -108,26 +109,35 @@ extension Xcode.Project: PropertyListSerializable {
108109
}
109110

110111
extension Xcode.Reference: PropertyListSerializable {
111-
fileprivate dynamic func serialize(
112+
fileprivate var xcodeClassName: String {
113+
switch self {
114+
case is Xcode.Group:
115+
"PBXGroup"
116+
case let fileRef as Xcode.FileReference:
117+
fileRef.isBuildableFolder ? "PBXFileSystemSynchronizedRootGroup"
118+
: "PBXFileReference"
119+
default:
120+
fatalError("Unhandled subclass")
121+
}
122+
}
123+
124+
fileprivate func serialize(
112125
to serializer: PropertyListSerializer
113126
) throws -> [String : PropertyList] {
114127
var dict = [String: PropertyList]()
128+
dict["isa"] = .string(xcodeClassName)
115129
dict["path"] = .string(path)
116130
if let name = name {
117131
dict["name"] = .string(name)
118132
}
119133
dict["sourceTree"] = .string(pathBase.rawValue)
120134

121-
let xcodeClassName: String
122135
switch self {
123136
case let group as Xcode.Group:
124-
xcodeClassName = "PBXGroup"
125137
dict["children"] = try .array(group.subitems.map({ reference in
126138
try .identifier(serializer.serialize(object: reference))
127139
}))
128140
case let fileRef as Xcode.FileReference:
129-
xcodeClassName = fileRef.isBuildableFolder
130-
? "PBXFileSystemSynchronizedRootGroup" : "PBXFileReference"
131141
if let fileType = fileRef.fileType {
132142
dict["explicitFileType"] = .string(fileType)
133143
}
@@ -138,19 +148,21 @@ extension Xcode.Reference: PropertyListSerializable {
138148
default:
139149
fatalError("Unhandled subclass")
140150
}
141-
dict["isa"] = .string(xcodeClassName)
142151
return dict
143152
}
144153
}
145154

146155
extension Xcode.Target: PropertyListSerializable {
156+
fileprivate var xcodeClassName: String {
157+
productType == nil ? "PBXAggregateTarget" : "PBXNativeTarget"
158+
}
147159

148160
/// Called by the Serializer to serialize the Target.
149161
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
150162
// Create either a `PBXNativeTarget` or an `PBXAggregateTarget` plist
151163
// dictionary (depending on whether or not we have a product type).
152164
var dict = [String: PropertyList]()
153-
dict["isa"] = .string(productType == nil ? "PBXAggregateTarget" : "PBXNativeTarget")
165+
dict["isa"] = .string(xcodeClassName)
154166
dict["name"] = .string(name)
155167
// Build settings are a bit tricky; in Xcode, each is stored in a named
156168
// XCBuildConfiguration object, and the list of build configurations is
@@ -169,14 +181,16 @@ extension Xcode.Target: PropertyListSerializable {
169181
/// glue between our value-based settings structures and the Xcode
170182
/// project model's identity-based TargetDependency objects.
171183
class TargetDependency: PropertyListSerializable {
184+
var xcodeClassName: String { "PBXTargetDependency" }
185+
172186
var target: Xcode.Target
173187
init(target: Xcode.Target) {
174188
self.target = target
175189
}
176190
func serialize(to serializer: PropertyListSerializer) -> [String: PropertyList] {
177191
// Create a `PBXTargetDependency` plist dictionary.
178192
var dict = [String: PropertyList]()
179-
dict["isa"] = .string("PBXTargetDependency")
193+
dict["isa"] = .string(xcodeClassName)
180194
dict["target"] = .identifier(serializer.id(of: target))
181195
return dict
182196
}
@@ -202,91 +216,60 @@ extension Xcode.Target: PropertyListSerializable {
202216
}
203217
}
204218

205-
/// Private helper function that constructs and returns a partial property list
206-
/// dictionary for build phases. The caller can add to the returned dictionary.
207-
/// FIXME: It would be nicer to be able to use inheritance to serialize the
208-
/// attributes inherited from BuildPhase, but but in Swift 3.0 we get an error
209-
/// that "declarations in extensions cannot override yet".
210-
fileprivate func makeBuildPhaseDict(
211-
buildPhase: Xcode.BuildPhase,
212-
serializer: PropertyListSerializer,
213-
xcodeClassName: String
214-
) throws -> [String: PropertyList] {
215-
var dict = [String: PropertyList]()
216-
dict["isa"] = .string(xcodeClassName)
217-
dict["files"] = try .array(buildPhase.files.map({ file in
218-
try .identifier(serializer.serialize(object: file))
219-
}))
220-
return dict
219+
extension PropertyListSerializable where Self: Xcode.BuildPhase {
220+
/// Helper function that constructs and returns the base property list
221+
/// dictionary for build phases.
222+
fileprivate func makeBuildPhaseDict(
223+
serializer: PropertyListSerializer
224+
) throws -> [String: PropertyList] {
225+
var dict = [String: PropertyList]()
226+
dict["isa"] = .string(xcodeClassName)
227+
dict["files"] = try .array(files.map({ file in
228+
try .identifier(serializer.serialize(object: file))
229+
}))
230+
return dict
231+
}
232+
233+
/// Default serialization implementation.
234+
fileprivate func serialize(
235+
to serializer: PropertyListSerializer
236+
) throws -> [String: PropertyList] {
237+
try makeBuildPhaseDict(serializer: serializer)
238+
}
221239
}
222240

223241
extension Xcode.HeadersBuildPhase: PropertyListSerializable {
224-
225-
/// Called by the Serializer to serialize the HeadersBuildPhase.
226-
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
227-
// Create a `PBXHeadersBuildPhase` plist dictionary.
228-
// FIXME: It would be nicer to be able to use inheritance for the code
229-
// inherited from BuildPhase, but but in Swift 3.0 we get an error that
230-
// "declarations in extensions cannot override yet".
231-
return try makeBuildPhaseDict(buildPhase: self, serializer: serializer, xcodeClassName: "PBXHeadersBuildPhase")
232-
}
242+
fileprivate var xcodeClassName: String { "PBXHeadersBuildPhase" }
233243
}
234244

235245
extension Xcode.SourcesBuildPhase: PropertyListSerializable {
236-
237-
/// Called by the Serializer to serialize the SourcesBuildPhase.
238-
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
239-
// Create a `PBXSourcesBuildPhase` plist dictionary.
240-
// FIXME: It would be nicer to be able to use inheritance for the code
241-
// inherited from BuildPhase, but but in Swift 3.0 we get an error that
242-
// "declarations in extensions cannot override yet".
243-
return try makeBuildPhaseDict(buildPhase: self, serializer: serializer, xcodeClassName: "PBXSourcesBuildPhase")
244-
}
246+
fileprivate var xcodeClassName: String { "PBXSourcesBuildPhase" }
245247
}
246248

247249
extension Xcode.FrameworksBuildPhase: PropertyListSerializable {
248-
249-
/// Called by the Serializer to serialize the FrameworksBuildPhase.
250-
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
251-
// Create a `PBXFrameworksBuildPhase` plist dictionary.
252-
// FIXME: It would be nicer to be able to use inheritance for the code
253-
// inherited from BuildPhase, but but in Swift 3.0 we get an error that
254-
// "declarations in extensions cannot override yet".
255-
return try makeBuildPhaseDict(buildPhase: self, serializer: serializer, xcodeClassName: "PBXFrameworksBuildPhase")
256-
}
250+
fileprivate var xcodeClassName: String { "PBXFrameworksBuildPhase" }
257251
}
258252

259253
extension Xcode.CopyFilesBuildPhase: PropertyListSerializable {
254+
fileprivate var xcodeClassName: String { "PBXCopyFilesBuildPhase" }
260255

261-
/// Called by the Serializer to serialize the FrameworksBuildPhase.
262-
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
263-
// Create a `PBXCopyFilesBuildPhase` plist dictionary.
264-
// FIXME: It would be nicer to be able to use inheritance for the code
265-
// inherited from BuildPhase, but but in Swift 3.0 we get an error that
266-
// "declarations in extensions cannot override yet".
267-
var dict = try makeBuildPhaseDict(
268-
buildPhase: self,
269-
serializer: serializer,
270-
xcodeClassName: "PBXCopyFilesBuildPhase"
271-
)
256+
fileprivate func serialize(
257+
to serializer: PropertyListSerializer
258+
) throws -> [String: PropertyList] {
259+
var dict = try makeBuildPhaseDict(serializer: serializer)
272260
dict["dstPath"] = .string("") // FIXME: needs to be real
273261
dict["dstSubfolderSpec"] = .string("") // FIXME: needs to be real
274262
return dict
275263
}
276264
}
277265

278266
extension Xcode.ShellScriptBuildPhase: PropertyListSerializable {
267+
fileprivate var xcodeClassName: String { "PBXShellScriptBuildPhase" }
279268

280-
/// Called by the Serializer to serialize the ShellScriptBuildPhase.
281-
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
282-
// Create a `PBXShellScriptBuildPhase` plist dictionary.
283-
// FIXME: It would be nicer to be able to use inheritance for the code
284-
// inherited from BuildPhase, but but in Swift 3.0 we get an error that
285-
// "declarations in extensions cannot override yet".
286-
var dict = try makeBuildPhaseDict(
287-
buildPhase: self,
288-
serializer: serializer,
289-
xcodeClassName: "PBXShellScriptBuildPhase")
269+
fileprivate func serialize(
270+
to serializer: PropertyListSerializer
271+
) throws -> [String: PropertyList] {
272+
var dict = try makeBuildPhaseDict(serializer: serializer)
290273
dict["shellPath"] = .string("/bin/sh") // FIXME: should be settable
291274
dict["shellScript"] = .string(script)
292275
dict["inputPaths"] = .array(inputs.map { .string($0) })
@@ -297,12 +280,13 @@ extension Xcode.ShellScriptBuildPhase: PropertyListSerializable {
297280
}
298281

299282
extension Xcode.BuildFile: PropertyListSerializable {
283+
fileprivate var xcodeClassName: String { "PBXBuildFile" }
300284

301285
/// Called by the Serializer to serialize the BuildFile.
302286
fileprivate func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
303287
// Create a `PBXBuildFile` plist dictionary.
304288
var dict = [String: PropertyList]()
305-
dict["isa"] = .string("PBXBuildFile")
289+
dict["isa"] = .string(xcodeClassName)
306290
if let fileRef = fileRef {
307291
dict["fileRef"] = .identifier(serializer.id(of: fileRef))
308292
}
@@ -317,6 +301,7 @@ extension Xcode.BuildFile: PropertyListSerializable {
317301
}
318302

319303
extension Xcode.BuildSettingsTable: PropertyListSerializable {
304+
fileprivate var xcodeClassName: String { "XCConfigurationList" }
320305

321306
/// Called by the Serializer to serialize the BuildFile. It is serialized
322307
/// as an XCBuildConfigurationList and two additional XCBuildConfiguration
@@ -331,6 +316,8 @@ extension Xcode.BuildSettingsTable: PropertyListSerializable {
331316
var overlaySettings: BuildSettings
332317
let xcconfigFileRef: Xcode.FileReference?
333318

319+
var xcodeClassName: String { "XCBuildConfiguration" }
320+
334321
init(
335322
name: String,
336323
baseSettings: BuildSettings,
@@ -346,7 +333,7 @@ extension Xcode.BuildSettingsTable: PropertyListSerializable {
346333
func serialize(to serializer: PropertyListSerializer) throws -> [String: PropertyList] {
347334
// Create a `XCBuildConfiguration` plist dictionary.
348335
var dict = [String: PropertyList]()
349-
dict["isa"] = .string("XCBuildConfiguration")
336+
dict["isa"] = .string(xcodeClassName)
350337
dict["name"] = .string(name)
351338
// Combine the base settings and the overlay settings.
352339
dict["buildSettings"] = try combineBuildSettingsPropertyLists(
@@ -363,7 +350,7 @@ extension Xcode.BuildSettingsTable: PropertyListSerializable {
363350

364351
// Create a `XCConfigurationList` plist dictionary.
365352
var dict = [String: PropertyList]()
366-
dict["isa"] = .string("XCConfigurationList")
353+
dict["isa"] = .string(xcodeClassName)
367354
dict["buildConfigurations"] = .array([
368355
// We use a private wrapper to "objectify" our two build settings
369356
// structures (which, being structs, are value types).
@@ -535,6 +522,9 @@ fileprivate protocol PropertyListSerializable: AnyObject {
535522
/// matters. So this is acceptable for now in the interest of getting it
536523
/// done.
537524

525+
/// The ID for the `isa` field of the object.
526+
var xcodeClassName: String { get }
527+
538528
/// A custom ID to use for the instance, if enabled.
539529
///
540530
/// This ID must be unique across the entire serialized graph.

0 commit comments

Comments
 (0)