Skip to content

Commit

Permalink
new api
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkhazi committed Jul 30, 2019
1 parent a12b226 commit 366dd0b
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 46 deletions.
118 changes: 93 additions & 25 deletions Sources/ProjectDescription/TuistConfig.swift
Expand Up @@ -7,8 +7,7 @@ public class TuistConfig: Encodable, Decodable {
/// - generateManifestElement: When passed, Tuist generates the projects, targets and schemes to compile the project manifest.
public enum GenerationOption: Encodable, Decodable, Equatable {
case generateManifest
case suffixProjectNames(with: String)
case prefixProjectNames(with: String)
case xcodeProjectName(TemplateString)
}

/// Generation options.
Expand All @@ -23,12 +22,82 @@ public class TuistConfig: Encodable, Decodable {
}
}

public struct TemplateString: Encodable, Decodable {
let rawString: String
}

extension TemplateString: ExpressibleByStringLiteral {
public init(stringLiteral: String) {
rawString = stringLiteral
}
}

extension TemplateString: CustomStringConvertible {
public var description: String {
return rawString
}
}

extension TemplateString: ExpressibleByStringInterpolation {
public init(stringInterpolation: StringInterpolation) {
rawString = stringInterpolation.string
}

public struct StringInterpolation: StringInterpolationProtocol {
var string: String

public init(literalCapacity _: Int, interpolationCount _: Int) {
string = String()
}

public mutating func appendLiteral(_ literal: String) {
string.append(literal)
}

public func appendInterpolation(_: String) {}
}
}

extension TemplateString {
public enum Token: String {
case projectName = "${project_name}"
}
}

public extension TemplateString.StringInterpolation {
mutating func appendInterpolation(_ token: TemplateString.Token) {
string.append(token.rawValue)
}
}

extension TemplateString.Token {
enum CodingKeys: String, CodingKey {
case projectName
}

internal init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

let enumCase = try container.decode(String.self)
switch enumCase {
case CodingKeys.projectName.rawValue: self = .projectName
default: throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case '\(enumCase)'"))
}
}

internal func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()

switch self {
case .projectName: try container.encode(CodingKeys.projectName.rawValue)
}
}
}

extension TuistConfig.GenerationOption {
enum CodingKeys: String, CodingKey {
case generateManifest
case suffixProjectNames
case prefixProjectNames
case with
case xcodeProjectName
}

public init(from decoder: Decoder) throws {
Expand All @@ -38,16 +107,10 @@ extension TuistConfig.GenerationOption {
self = .generateManifest
return
}
if container.allKeys.contains(.suffixProjectNames), try container.decodeNil(forKey: .suffixProjectNames) == false {
let associatedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .suffixProjectNames)
let with = try associatedValues.decode(String.self, forKey: .with)
self = .suffixProjectNames(with: with)
return
}
if container.allKeys.contains(.prefixProjectNames), try container.decodeNil(forKey: .prefixProjectNames) == false {
let associatedValues = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .prefixProjectNames)
let with = try associatedValues.decode(String.self, forKey: .with)
self = .prefixProjectNames(with: with)
if container.allKeys.contains(.xcodeProjectName), try container.decodeNil(forKey: .xcodeProjectName) == false {
var associatedValues = try container.nestedUnkeyedContainer(forKey: .xcodeProjectName)
let associatedValue0 = try associatedValues.decode(TemplateString.self)
self = .xcodeProjectName(associatedValue0)
return
}
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case"))
Expand All @@ -59,24 +122,29 @@ extension TuistConfig.GenerationOption {
switch self {
case .generateManifest:
_ = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .generateManifest)
case let .suffixProjectNames(with):
var associatedValues = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .suffixProjectNames)
try associatedValues.encode(with, forKey: .with)
case let .prefixProjectNames(with):
var associatedValues = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .prefixProjectNames)
try associatedValues.encode(with, forKey: .with)
case let .xcodeProjectName(associatedValue0):
var associatedValues = container.nestedUnkeyedContainer(forKey: .xcodeProjectName)
try associatedValues.encode(associatedValue0)
}
}
}

extension TemplateString.Token: Equatable {}
public func == (lhs: TemplateString.Token, rhs: TemplateString.Token) -> Bool {
switch (lhs, rhs) {
case (.projectName, .projectName):
return true
}
}

// MARK: - TuistConfig.GenerationOption AutoEquatable

public func == (lhs: TuistConfig.GenerationOption, rhs: TuistConfig.GenerationOption) -> Bool {
switch (lhs, rhs) {
case (.generateManifest, .generateManifest):
return true
case let (.suffixProjectNames(lhs), .suffixProjectNames(rhs)):
return lhs == rhs
case let (.prefixProjectNames(lhs), .prefixProjectNames(rhs)):
return lhs == rhs
case let (.xcodeProjectName(lhs), .xcodeProjectName(rhs)):
return lhs.rawString == rhs.rawString
default: return false
}
}
134 changes: 132 additions & 2 deletions Sources/TuistGenerator/Models/TuistConfig.swift
Expand Up @@ -9,8 +9,7 @@ public class TuistConfig: Equatable, Hashable {
/// - generateManifestElement: When passed, Tuist generates the projects, targets and schemes to compile the project manifest.
public enum GenerationOption: Hashable {
case generateManifest
case suffixProjectNames(with: String)
case prefixProjectNames(with: String)
case xcodeProjectName(TemplateString)
}

/// Generation options.
Expand Down Expand Up @@ -51,3 +50,134 @@ public class TuistConfig: Equatable, Hashable {
return lhs.generationOptions == rhs.generationOptions
}
}

public struct TemplateString: Encodable, Decodable, Hashable {

This comment has been minimized.

Copy link
@ollieatkinson

ollieatkinson Jul 30, 2019

Collaborator

we might not need all of the API available at the TuistGenerator level. Since the API is to expose something for consumers to use.

This comment has been minimized.

Copy link
@adamkhazi

adamkhazi Jul 30, 2019

Author Contributor

I made the API simpler at the generator level:

  • Changed .xcodeProjectName(TemplateString) to .xcodeProjectName(String)
  • removed Encodable and Decodable

Not sure if this is what you meant. 🙂

This comment has been minimized.

Copy link
@ollieatkinson

ollieatkinson Jul 30, 2019

Collaborator

That's exactly what I meant! Great job @adamkhazi !

public let rawString: String
public init(rawString: String) {
self.rawString = rawString
}
}

extension TemplateString: ExpressibleByStringLiteral {
public init(stringLiteral: String) {
rawString = stringLiteral
}
}

extension TemplateString: CustomStringConvertible {
public var description: String {
return rawString
}
}

extension TemplateString: ExpressibleByStringInterpolation {
public init(stringInterpolation: StringInterpolation) {
rawString = stringInterpolation.string
}

public struct StringInterpolation: StringInterpolationProtocol {
var string: String

public init(literalCapacity _: Int, interpolationCount _: Int) {
string = String()
}

public mutating func appendLiteral(_ literal: String) {
string.append(literal)
}

public func appendInterpolation(_: String) {}
}
}

extension TemplateString {
public enum Token: String {
case projectName = "${project_name}"
}
}

extension TemplateString.StringInterpolation {
public mutating func appendInterpolation(_ token: TemplateString.Token) {
string.append(token.rawValue)
}
}

extension TemplateString.Token {
enum CodingKeys: String, CodingKey {
case projectName
}

internal init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

let enumCase = try container.decode(String.self)
switch enumCase {
case CodingKeys.projectName.rawValue: self = .projectName
default: throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case '\(enumCase)'"))
}
}

internal func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()

switch self {
case .projectName: try container.encode(CodingKeys.projectName.rawValue)
}
}
}

extension TuistConfig.GenerationOption {
enum CodingKeys: String, CodingKey {
case generateManifest
case xcodeProjectName
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

if container.allKeys.contains(.generateManifest), try container.decodeNil(forKey: .generateManifest) == false {
self = .generateManifest
return
}
if container.allKeys.contains(.xcodeProjectName), try container.decodeNil(forKey: .xcodeProjectName) == false {
var associatedValues = try container.nestedUnkeyedContainer(forKey: .xcodeProjectName)
let associatedValue0 = try associatedValues.decode(TemplateString.self)
self = .xcodeProjectName(associatedValue0)
return
}
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Unknown enum case"))
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

switch self {
case .generateManifest:
_ = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .generateManifest)
case let .xcodeProjectName(associatedValue0):
var associatedValues = container.nestedUnkeyedContainer(forKey: .xcodeProjectName)
try associatedValues.encode(associatedValue0)
}
}
}

extension TemplateString.Token: Equatable {}
public func == (lhs: TemplateString.Token, rhs: TemplateString.Token) -> Bool {
switch (lhs, rhs) {
case (.projectName, .projectName):
return true
}
}

// MARK: - TuistConfig.GenerationOption AutoEquatable

extension TuistConfig.GenerationOption: Equatable {}
public func == (lhs: TuistConfig.GenerationOption, rhs: TuistConfig.GenerationOption) -> Bool {
switch (lhs, rhs) {
case (.generateManifest, .generateManifest):
return true
case let (.xcodeProjectName(lhs), .xcodeProjectName(rhs)):
return lhs == rhs
default: return false
}
}
25 changes: 12 additions & 13 deletions Sources/TuistKit/Generator/GeneratorModelLoader.swift
Expand Up @@ -125,10 +125,8 @@ extension TuistGenerator.TuistConfig.GenerationOption {
switch manifest {
case .generateManifest:
return .generateManifest
case let .suffixProjectNames(suffixRaw):
return .suffixProjectNames(with: suffixRaw)
case let .prefixProjectNames(prefixRaw):
return .prefixProjectNames(with: prefixRaw)
case let .xcodeProjectName(templateString):
return .xcodeProjectName(TemplateString(rawString: templateString.description))
}
}
}
Expand Down Expand Up @@ -237,19 +235,20 @@ extension TuistGenerator.Project {
printer: printer)
}

let xcodeProjFileName = tuistConfig.generationOptions.reduce(name) { acc, item in
if case let .prefixProjectNames(prefixRaw) = item {
return prefixRaw + acc
var xcodeFilename = tuistConfig.generationOptions.compactMap { (item) -> String? in
if case let .xcodeProjectName(projectName) = item {
return projectName.rawString
}
if case let .suffixProjectNames(suffixRaw) = item {
return acc + suffixRaw
}
return acc
}
return nil
}.first

let projectNameTemplate = TuistGenerator.TemplateString.Token.projectName.rawValue
xcodeFilename = xcodeFilename?
.replacingOccurrences(of: projectNameTemplate, with: manifest.name)

return Project(path: path,
name: name,
fileName: xcodeProjFileName,
fileName: xcodeFilename,
settings: settings ?? .default,
filesGroup: .group(name: "Project"),
targets: targets,
Expand Down
5 changes: 2 additions & 3 deletions Tests/TuistKitTests/Generator/GeneratorModelLoaderTests.swift
Expand Up @@ -186,8 +186,7 @@ class GeneratorModelLoaderTest: XCTestCase {
]),
]
let configs = [
path: ProjectDescription.TuistConfig.test(generationOptions: [.prefixProjectNames(with: "something-"),
.suffixProjectNames(with: "-something")]),
path: ProjectDescription.TuistConfig.test(generationOptions: [.xcodeProjectName("one \(.projectName) two")]),
]
let manifestLoader = createManifestLoader(with: manifests, configs: configs)
let subject = GeneratorModelLoader(fileHandler: fileHandler,
Expand All @@ -198,7 +197,7 @@ class GeneratorModelLoaderTest: XCTestCase {
let model = try subject.loadProject(at: path)

// Then
XCTAssertEqual(model.fileName, "something-SomeProject-something")
XCTAssertEqual(model.fileName, "one SomeProject two")
}

func test_loadWorkspace() throws {
Expand Down
Expand Up @@ -3,7 +3,6 @@ import ProjectDescription
let config = TuistConfig(
generationOptions: [
.generateManifest,
.prefixProjectNames(with: "AwesomePrefix-"),
.suffixProjectNames(with: "-AwesomeSuffix")
.xcodeProjectName("AwesomePrefix-\(.projectName)-AwesomeSuffix")
]
)
)

0 comments on commit 366dd0b

Please sign in to comment.