diff --git a/Sources/ProjectSpec/Project.swift b/Sources/ProjectSpec/Project.swift index 05905ccb..da092574 100644 --- a/Sources/ProjectSpec/Project.swift +++ b/Sources/ProjectSpec/Project.swift @@ -191,7 +191,7 @@ extension Project { // as well as platform specific templates in multi-platform targets jsonDictionary = Target.resolveMultiplatformTargets(jsonDictionary: jsonDictionary) jsonDictionary = Target.resolveTargetTemplates(jsonDictionary: jsonDictionary) - jsonDictionary = Target.resolveSchemeTemplates(jsonDictionary: jsonDictionary) + jsonDictionary = Scheme.resolveSchemeTemplates(jsonDictionary: jsonDictionary) jsonDictionary = Target.resolveMultiplatformTargets(jsonDictionary: jsonDictionary) return jsonDictionary diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index 59947313..ef2ba36d 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -159,7 +159,9 @@ extension Dictionary where Key == String, Value: Any { var replaced: JSONDictionary = self for (key, value) in self { let newKey = key.replacingOccurrences(of: template, with: replacement) - replaced.removeValue(forKey: key) + if newKey != key { + replaced.removeValue(forKey: key) + } replaced[newKey] = replace(value: value, template, with: replacement) } return replaced diff --git a/Sources/ProjectSpec/Target.swift b/Sources/ProjectSpec/Target.swift index e31aee50..8fa85a66 100644 --- a/Sources/ProjectSpec/Target.swift +++ b/Sources/ProjectSpec/Target.swift @@ -105,12 +105,6 @@ public struct Target: ProjectTarget { } } -struct TemplateStructure { - let baseKey: String - let templatesKey: String - let nameToReplace: String -} - extension Target: CustomStringConvertible { public var description: String { @@ -190,72 +184,6 @@ extension Target { merged["targets"] = crossPlatformTargets return merged } - - static func resolveTargetTemplates(jsonDictionary: JSONDictionary) -> JSONDictionary { - return resolveTemplates(jsonDictionary: jsonDictionary, - templateStructure: TemplateStructure(baseKey: "targets", - templatesKey: "targetTemplates", - nameToReplace: "target_name")) - } - - static func resolveSchemeTemplates(jsonDictionary: JSONDictionary) -> JSONDictionary { - return resolveTemplates(jsonDictionary: jsonDictionary, - templateStructure: TemplateStructure(baseKey: "schemes", - templatesKey: "schemeTemplates", - nameToReplace: "scheme_name")) - } - - private static func resolveTemplates(jsonDictionary: JSONDictionary, templateStructure: TemplateStructure) -> JSONDictionary { - guard var baseDictionary: [String: JSONDictionary] = jsonDictionary[templateStructure.baseKey] as? [String: JSONDictionary] else { - return jsonDictionary - } - - let templatesDictionary: [String: JSONDictionary] = jsonDictionary[templateStructure.templatesKey] as? [String: JSONDictionary] ?? [:] - - // Recursively collects all nested template names of a given dictionary. - func collectTemplates(of jsonDictionary: JSONDictionary, - into allTemplates: inout [String], - insertAt insertionIndex: inout Int) { - guard let templates = jsonDictionary["templates"] as? [String] else { - return - } - for template in templates where !allTemplates.contains(template) { - guard let templateDictionary = templatesDictionary[template] else { - continue - } - allTemplates.insert(template, at: insertionIndex) - collectTemplates(of: templateDictionary, into: &allTemplates, insertAt: &insertionIndex) - insertionIndex += 1 - } - } - - for (referenceName, var reference) in baseDictionary { - var templates: [String] = [] - var index: Int = 0 - collectTemplates(of: reference, into: &templates, insertAt: &index) - if !templates.isEmpty { - var mergedDictionary: JSONDictionary = [:] - for template in templates { - if let templateDictionary = templatesDictionary[template] { - mergedDictionary = templateDictionary.merged(onto: mergedDictionary) - } - } - reference = reference.merged(onto: mergedDictionary) - reference = reference.replaceString("$\(templateStructure.nameToReplace)", with: referenceName) // Will be removed in upcoming version - reference = reference.replaceString("${\(templateStructure.nameToReplace)}", with: referenceName) - if let templateAttributes = reference["templateAttributes"] as? [String: String] { - for (templateAttribute, value) in templateAttributes { - reference = reference.replaceString("${\(templateAttribute)}", with: value) - } - } - } - baseDictionary[referenceName] = reference - } - - var jsonDictionary = jsonDictionary - jsonDictionary[templateStructure.baseKey] = baseDictionary - return jsonDictionary - } } extension Target: Equatable { diff --git a/Sources/ProjectSpec/Template.swift b/Sources/ProjectSpec/Template.swift new file mode 100644 index 00000000..974fe3d4 --- /dev/null +++ b/Sources/ProjectSpec/Template.swift @@ -0,0 +1,78 @@ +import Foundation +import JSONUtilities + +struct TemplateStructure { + let baseKey: String + let templatesKey: String + let nameToReplace: String +} + +extension Target { + static func resolveTargetTemplates(jsonDictionary: JSONDictionary) -> JSONDictionary { + return resolveTemplates(jsonDictionary: jsonDictionary, + templateStructure: TemplateStructure(baseKey: "targets", + templatesKey: "targetTemplates", + nameToReplace: "target_name")) + } +} + +extension Scheme { + static func resolveSchemeTemplates(jsonDictionary: JSONDictionary) -> JSONDictionary { + return resolveTemplates(jsonDictionary: jsonDictionary, + templateStructure: TemplateStructure(baseKey: "schemes", + templatesKey: "schemeTemplates", + nameToReplace: "scheme_name")) + } +} + +private func resolveTemplates(jsonDictionary: JSONDictionary, templateStructure: TemplateStructure) -> JSONDictionary { + guard var baseDictionary: [String: JSONDictionary] = jsonDictionary[templateStructure.baseKey] as? [String: JSONDictionary] else { + return jsonDictionary + } + + let templatesDictionary: [String: JSONDictionary] = jsonDictionary[templateStructure.templatesKey] as? [String: JSONDictionary] ?? [:] + + // Recursively collects all nested template names of a given dictionary. + func collectTemplates(of jsonDictionary: JSONDictionary, + into allTemplates: inout [String], + insertAt insertionIndex: inout Int) { + guard let templates = jsonDictionary["templates"] as? [String] else { + return + } + for template in templates where !allTemplates.contains(template) { + guard let templateDictionary = templatesDictionary[template] else { + continue + } + allTemplates.insert(template, at: insertionIndex) + collectTemplates(of: templateDictionary, into: &allTemplates, insertAt: &insertionIndex) + insertionIndex += 1 + } + } + + for (referenceName, var reference) in baseDictionary { + var templates: [String] = [] + var index: Int = 0 + collectTemplates(of: reference, into: &templates, insertAt: &index) + if !templates.isEmpty { + var mergedDictionary: JSONDictionary = [:] + for template in templates { + if let templateDictionary = templatesDictionary[template] { + mergedDictionary = templateDictionary.merged(onto: mergedDictionary) + } + } + reference = reference.merged(onto: mergedDictionary) + reference = reference.replaceString("$\(templateStructure.nameToReplace)", with: referenceName) // Will be removed in upcoming version + reference = reference.replaceString("${\(templateStructure.nameToReplace)}", with: referenceName) + if let templateAttributes = reference["templateAttributes"] as? [String: String] { + for (templateAttribute, value) in templateAttributes { + reference = reference.replaceString("${\(templateAttribute)}", with: value) + } + } + } + baseDictionary[referenceName] = reference + } + + var jsonDictionary = jsonDictionary + jsonDictionary[templateStructure.baseKey] = baseDictionary + return jsonDictionary +}