Files
SwiftGen/Sources/SwiftGenCLI/TemplateRef.swift
2022-07-30 20:47:39 +02:00

110 lines
4.1 KiB
Swift

//
// SwiftGen
// Copyright © 2022 SwiftGen
// MIT Licence
//
import PathKit
public enum TemplateRef: Equatable {
case name(String)
case path(Path)
enum Error: Swift.Error {
case namedTemplateNotFound(name: String)
case templatePathNotFound(path: Path)
case noTemplateProvided
case multipleTemplateOptions(path: String, name: String)
}
public init(templateShortName: String, templateFullPath: String) throws {
switch (!templateFullPath.isEmpty, !templateShortName.isEmpty) {
case (false, false):
throw Self.Error.noTemplateProvided
case (false, true):
self = .name(templateShortName)
case (true, false):
self = .path(Path(templateFullPath))
case (true, true):
throw Self.Error.multipleTemplateOptions(path: templateFullPath, name: templateShortName)
}
}
/// Returns the path of a template
///
/// * If it's a `.path`, check that the path exists and return it (throws if it isn't an existing file)
/// * If it's a `.name`, search the named template in the folder `parserName`
/// in the Application Support directory first, then in the bundled templates,
/// and returns the path if found (throws if none is found)
///
/// - Parameter parserName: The folder to search for the template.
/// Typically the name of one of the SwiftGen parsers like `strings`, `colors`, etc
/// - Returns: The Path matching the template found
/// - Throws: TemplateRef.Error
///
public func resolvePath(forParser parser: ParserCLI, logger: (LogLevel, String) -> Void = logMessage) throws -> Path {
switch self {
case .name(let templateShortName):
var path = Path.deprecatedAppSupportTemplates + parser.templateFolder + "\(templateShortName).stencil"
if path.isFile {
logger(
.warning,
"""
Referring to templates in Application Support by name is deprecated and will be removed in SwiftGen 7.0.
For custom templates, please use `templatePath` instead of `templateName` to point to them.
We also recommend you move your custom templates from \(Path.deprecatedAppSupportTemplates)
to your project's folder so that your project is able to run independently on all machines.
"""
)
} else {
path = Path.bundledTemplates + parser.templateFolder + "\(templateShortName).stencil"
}
guard path.isFile else {
throw Self.Error.namedTemplateNotFound(name: templateShortName)
}
return path
case .path(let fullPath):
guard fullPath.isFile else {
throw Self.Error.templatePathNotFound(path: fullPath)
}
return fullPath
}
}
/// Check if the template is a bundled template for the given parser
/// - Parameter parserName: The folder to search for the template.
/// Typically the name of one of the SwiftGen parsers like `strings`, `colors`, etc
/// - Returns: The Path matching the template found
public func isBundled(forParser parser: ParserCLI) -> Bool {
switch self {
case .name(let templateShortName):
let path = Path.bundledTemplates + parser.templateFolder + "\(templateShortName).stencil"
return path.isFile
case .path:
return false
}
}
}
extension TemplateRef.Error: CustomStringConvertible {
var description: String {
switch self {
case .namedTemplateNotFound(let name):
return """
Template named \(name) not found. Use `swiftgen template list` to list available named templates \
or use `templatePath` to specify a template by its full path.
"""
case .templatePathNotFound(let path):
return "Template not found at path \(path.description)."
case .noTemplateProvided:
return """
You must specify a template by name (templateName) or path (templatePath).
To list all the available named templates, use 'swiftgen template list'.
"""
case .multipleTemplateOptions(let path, let name):
return "You need to choose EITHER a named template OR a template path. Found name '\(name)' and path '\(path)'"
}
}
}