feat(RES-34): Fix plist font filename (#14)
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #14
This commit is contained in:
@ -5,30 +5,30 @@
|
||||
// Created by Loris Perret on 08/12/2023.
|
||||
//
|
||||
|
||||
import ToolCore
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import Foundation
|
||||
import ToolCore
|
||||
|
||||
struct Analytics: ParsableCommand {
|
||||
|
||||
|
||||
// MARK: - Command Configuration
|
||||
|
||||
|
||||
static var configuration = CommandConfiguration(
|
||||
abstract: "Generate analytics extension file.",
|
||||
version: ResgenSwiftVersion
|
||||
)
|
||||
|
||||
|
||||
// MARK: - Static
|
||||
|
||||
|
||||
static let toolName = "Analytics"
|
||||
static let defaultExtensionName = "Analytics"
|
||||
|
||||
|
||||
// MARK: - Command Options
|
||||
|
||||
|
||||
@OptionGroup var options: AnalyticsOptions
|
||||
|
||||
|
||||
// MARK: - Run
|
||||
|
||||
|
||||
mutating func run() {
|
||||
print("[\(Self.toolName)] Starting analytics generation")
|
||||
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate analytics for target: \(options.target)")
|
||||
@ -37,50 +37,54 @@ struct Analytics: ParsableCommand {
|
||||
guard checkRequirements() else { return }
|
||||
|
||||
print("[\(Self.toolName)] Will generate analytics")
|
||||
|
||||
|
||||
// Check requirements
|
||||
guard checkRequirements() else { return }
|
||||
|
||||
|
||||
// Parse input file
|
||||
let sections = AnalyticsFileParser.parse(options.inputFile, target: options.target)
|
||||
|
||||
let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target)
|
||||
|
||||
// Generate extension
|
||||
AnalyticsGenerator.writeExtensionFiles(sections: sections,
|
||||
target: options.target,
|
||||
tags: ["ios", "iosonly"],
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionName,
|
||||
extensionFilePath: options.extensionFilePath)
|
||||
|
||||
AnalyticsGenerator.writeExtensionFiles(
|
||||
sections: sections,
|
||||
target: options.target,
|
||||
tags: ["ios", "iosonly"],
|
||||
staticVar: options.staticMembers,
|
||||
extensionName: options.extensionName,
|
||||
extensionFilePath: options.extensionFilePath
|
||||
)
|
||||
|
||||
print("[\(Self.toolName)] Analytics generated")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Requirements
|
||||
|
||||
|
||||
private func checkRequirements() -> Bool {
|
||||
let fileManager = FileManager()
|
||||
|
||||
|
||||
// Input file
|
||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
||||
let error = AnalyticsError.fileNotExists(options.inputFile)
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
|
||||
guard TrackerType.hasValidTarget(in: options.target) else {
|
||||
let error = AnalyticsError.noValidTracker(options.target)
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
Self.exit(withError: error)
|
||||
}
|
||||
|
||||
// Check if needed to regenerate
|
||||
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
||||
inputFilePath: options.inputFile,
|
||||
extensionFilePath: options.extensionFilePath) else {
|
||||
guard GeneratorChecker.shouldGenerate(
|
||||
force: options.forceGeneration,
|
||||
inputFilePath: options.inputFile,
|
||||
extensionFilePath: options.extensionFilePath
|
||||
) else {
|
||||
print("[\(Self.toolName)] Analytics are already up to date :) ")
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,14 @@
|
||||
import Foundation
|
||||
|
||||
enum AnalyticsError: Error {
|
||||
|
||||
case noValidTracker(String)
|
||||
case fileNotExists(String)
|
||||
case missingElement(String)
|
||||
case invalidParameter(String)
|
||||
case parseFailed(String)
|
||||
case writeFile(String, String)
|
||||
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .noValidTracker(let inputTargets):
|
||||
@ -22,17 +23,17 @@ enum AnalyticsError: Error {
|
||||
|
||||
case .fileNotExists(let filename):
|
||||
return "error: [\(Analytics.toolName)] File \(filename) does not exists"
|
||||
|
||||
|
||||
case .missingElement(let element):
|
||||
return "error: [\(Analytics.toolName)] Missing \(element) for Matomo"
|
||||
|
||||
|
||||
case .invalidParameter(let reason):
|
||||
return "error: [\(Analytics.toolName)] Invalid parameter \(reason)"
|
||||
|
||||
|
||||
case .parseFailed(let baseError):
|
||||
return "error: [\(Analytics.toolName)] Parse input file failed: \(baseError)"
|
||||
|
||||
case .writeFile(let subErrorDescription, let filename):
|
||||
case let .writeFile(subErrorDescription, filename):
|
||||
return "error: [\(Analytics.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
||||
}
|
||||
}
|
||||
|
@ -5,28 +5,31 @@
|
||||
// Created by Loris Perret on 08/12/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ArgumentParser
|
||||
import Foundation
|
||||
|
||||
// swiftlint:disable no_grouping_extension
|
||||
|
||||
struct AnalyticsOptions: ParsableArguments {
|
||||
|
||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||
var forceGeneration = false
|
||||
|
||||
|
||||
@Argument(help: "Input files where tags ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var inputFile: String
|
||||
|
||||
|
||||
@Option(help: "Target(s) analytics to generate. (\"matomo\" | \"firebase\")")
|
||||
var target: String
|
||||
|
||||
|
||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||
var extensionOutputPath: String
|
||||
|
||||
|
||||
@Option(help: "Tell if it will generate static properties or not")
|
||||
var staticMembers: Bool = false
|
||||
|
||||
|
||||
@Option(help: "Extension name. If not specified, it will generate a Analytics extension.")
|
||||
var extensionName: String = Analytics.defaultExtensionName
|
||||
|
||||
|
||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Analytics{extensionSuffix}.swift")
|
||||
var extensionSuffix: String?
|
||||
}
|
||||
@ -34,13 +37,14 @@ struct AnalyticsOptions: ParsableArguments {
|
||||
// MARK: - Computed var
|
||||
|
||||
extension AnalyticsOptions {
|
||||
|
||||
var extensionFileName: String {
|
||||
if let extensionSuffix = extensionSuffix {
|
||||
if let extensionSuffix {
|
||||
return "\(extensionName)+\(extensionSuffix).swift"
|
||||
}
|
||||
return "\(extensionName).swift"
|
||||
}
|
||||
|
||||
|
||||
var extensionFilePath: String {
|
||||
"\(extensionOutputPath)/\(extensionFileName)"
|
||||
}
|
||||
|
@ -5,112 +5,147 @@
|
||||
// Created by Loris Perret on 08/12/2023.
|
||||
//
|
||||
|
||||
import CoreVideo
|
||||
import Foundation
|
||||
import ToolCore
|
||||
import CoreVideo
|
||||
|
||||
class AnalyticsGenerator {
|
||||
static var targets: [TrackerType] = []
|
||||
// Disabled cause it's a pain to handle in generated string
|
||||
|
||||
static func writeExtensionFiles(sections: [AnalyticsCategory], target: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
|
||||
enum AnalyticsGenerator {
|
||||
|
||||
// MARK: - Write content
|
||||
|
||||
static func writeExtensionFiles(
|
||||
sections: [AnalyticsCategory],
|
||||
target: String,
|
||||
tags: [String],
|
||||
staticVar: Bool,
|
||||
extensionName: String,
|
||||
extensionFilePath: String
|
||||
) {
|
||||
// Get target type from enum
|
||||
let targetsString: [String] = target.components(separatedBy: " ")
|
||||
|
||||
TrackerType.allCases.forEach { enumTarget in
|
||||
if targetsString.contains(enumTarget.value) {
|
||||
targets.append(enumTarget)
|
||||
let targets = {
|
||||
var targets = [TrackerType]()
|
||||
TrackerType.allCases.forEach { enumTarget in
|
||||
if targetsString.contains(enumTarget.value) {
|
||||
targets.append(enumTarget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targets
|
||||
}()
|
||||
|
||||
// Get extension content
|
||||
let extensionFileContent = Self.getExtensionContent(sections: sections,
|
||||
tags: tags,
|
||||
staticVar: staticVar,
|
||||
extensionName: extensionName)
|
||||
|
||||
let extensionFileContent = getExtensionContent(
|
||||
targets: targets,
|
||||
sections: sections,
|
||||
tags: tags,
|
||||
staticVar: staticVar,
|
||||
extensionName: extensionName
|
||||
)
|
||||
|
||||
// Write content
|
||||
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
|
||||
do {
|
||||
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
|
||||
} catch let error {
|
||||
} catch {
|
||||
let error = AnalyticsError.writeFile(extensionFilePath, error.localizedDescription)
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Extension content
|
||||
|
||||
static func getExtensionContent(sections: [AnalyticsCategory], tags: [String], staticVar: Bool, extensionName: String) -> String {
|
||||
|
||||
static func getExtensionContent(
|
||||
targets: [TrackerType],
|
||||
sections: [AnalyticsCategory],
|
||||
tags: [String],
|
||||
staticVar: Bool,
|
||||
extensionName: String
|
||||
) -> String {
|
||||
[
|
||||
Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
|
||||
Self.getProperties(sections: sections, tags: tags, staticVar: staticVar),
|
||||
Self.getFooter()
|
||||
getHeader(
|
||||
targets: targets,
|
||||
extensionClassname: extensionName,
|
||||
staticVar: staticVar
|
||||
),
|
||||
getProperties(
|
||||
sections: sections,
|
||||
tags: tags,
|
||||
staticVar: staticVar
|
||||
),
|
||||
getFooter()
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Extension part
|
||||
|
||||
private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
|
||||
|
||||
private static func getHeader(
|
||||
targets: [TrackerType],
|
||||
extensionClassname: String,
|
||||
staticVar: Bool
|
||||
) -> String {
|
||||
"""
|
||||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||
|
||||
\(Self.getImport())
|
||||
|
||||
\(Self.getAnalyticsProtocol())
|
||||
|
||||
\(getImport(targets: targets))
|
||||
|
||||
\(getAnalyticsProtocol(targets: targets))
|
||||
// MARK: - Manager
|
||||
|
||||
|
||||
class AnalyticsManager {
|
||||
|
||||
static var shared = AnalyticsManager()
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
|
||||
var managers: [AnalyticsManagerProtocol] = []
|
||||
|
||||
\(Self.getEnabledContent())
|
||||
|
||||
\(Self.getAnalyticsProperties())
|
||||
|
||||
\(Self.getPrivateLogFunction())
|
||||
|
||||
\(getEnabledContent())
|
||||
|
||||
\(getAnalyticsProperties(targets: targets))
|
||||
|
||||
\(getPrivateLogFunction())
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static func getEnabledContent() -> String {
|
||||
"""
|
||||
private var isEnabled: Bool = true
|
||||
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
|
||||
func setAnalyticsEnabled(_ enable: Bool) {
|
||||
isEnabled = enable
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private static func getImport() -> String {
|
||||
|
||||
private static func getImport(targets: [TrackerType]) -> String {
|
||||
var result: [String] = []
|
||||
|
||||
|
||||
if targets.contains(TrackerType.matomo) {
|
||||
result.append("import MatomoTracker")
|
||||
}
|
||||
if targets.contains(TrackerType.firebase) {
|
||||
result.append("import FirebaseAnalytics")
|
||||
}
|
||||
|
||||
|
||||
return result.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
private static func getPrivateLogFunction() -> String {
|
||||
"""
|
||||
private func logScreen(name: String, path: String) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
|
||||
managers.forEach { manager in
|
||||
manager.logScreen(name: name, path: path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func logEvent(
|
||||
name: String,
|
||||
action: String,
|
||||
@ -118,7 +153,7 @@ class AnalyticsGenerator {
|
||||
params: [String: Any]?
|
||||
) {
|
||||
guard isEnabled else { return }
|
||||
|
||||
|
||||
managers.forEach { manager in
|
||||
manager.logEvent(
|
||||
name: name,
|
||||
@ -130,18 +165,18 @@ class AnalyticsGenerator {
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private static func getAnalyticsProperties() -> String {
|
||||
|
||||
private static func getAnalyticsProperties(targets: [TrackerType]) -> String {
|
||||
var header = ""
|
||||
var content: [String] = []
|
||||
let footer = " }"
|
||||
|
||||
|
||||
if targets.contains(TrackerType.matomo) {
|
||||
header = "func configure(siteId: String, url: String) {"
|
||||
} else if targets.contains(TrackerType.firebase) {
|
||||
header = "func configure() {"
|
||||
}
|
||||
|
||||
|
||||
if targets.contains(TrackerType.matomo) {
|
||||
content.append("""
|
||||
managers.append(
|
||||
@ -155,7 +190,7 @@ class AnalyticsGenerator {
|
||||
if targets.contains(TrackerType.firebase) {
|
||||
content.append(" managers.append(FirebaseAnalyticsManager())")
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
header,
|
||||
content.joined(separator: "\n"),
|
||||
@ -163,12 +198,13 @@ class AnalyticsGenerator {
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
private static func getAnalyticsProtocol() -> String {
|
||||
|
||||
private static func getAnalyticsProtocol(targets: [TrackerType]) -> String {
|
||||
let proto = """
|
||||
// MARK: - Protocol
|
||||
|
||||
|
||||
protocol AnalyticsManagerProtocol {
|
||||
|
||||
func logScreen(name: String, path: String)
|
||||
func logEvent(
|
||||
name: String,
|
||||
@ -177,36 +213,40 @@ class AnalyticsGenerator {
|
||||
params: [String: Any]?
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
var result: [String] = [proto]
|
||||
|
||||
|
||||
if targets.contains(TrackerType.matomo) {
|
||||
result.append(MatomoGenerator.service)
|
||||
}
|
||||
|
||||
|
||||
if targets.contains(TrackerType.firebase) {
|
||||
result.append(FirebaseGenerator.service)
|
||||
}
|
||||
|
||||
|
||||
return result.joined(separator: "\n")
|
||||
}
|
||||
|
||||
private static func getProperties(sections: [AnalyticsCategory], tags: [String], staticVar: Bool) -> String {
|
||||
|
||||
private static func getProperties(
|
||||
sections: [AnalyticsCategory],
|
||||
tags: [String],
|
||||
staticVar: Bool
|
||||
) -> String {
|
||||
sections
|
||||
.compactMap { section in
|
||||
// Check that at least one string will be generated
|
||||
guard section.hasOneOrMoreMatchingTags(tags: tags) else {
|
||||
return nil// Go to next section
|
||||
}
|
||||
|
||||
|
||||
var res = "\n // MARK: - \(section.id)"
|
||||
section.definitions.forEach { definition in
|
||||
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
|
||||
return // Go to next definition
|
||||
}
|
||||
|
||||
|
||||
if staticVar {
|
||||
res += "\n\n\(definition.getStaticProperty())"
|
||||
} else {
|
||||
@ -217,11 +257,11 @@ class AnalyticsGenerator {
|
||||
}
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
private static func getFooter() -> String {
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
@ -5,20 +5,22 @@
|
||||
// Created by Loris Perret on 05/12/2023.
|
||||
//
|
||||
|
||||
// CPD-OFF
|
||||
|
||||
import Foundation
|
||||
|
||||
enum FirebaseGenerator {
|
||||
|
||||
static var service: String {
|
||||
[
|
||||
FirebaseGenerator.header,
|
||||
FirebaseGenerator.logScreen,
|
||||
FirebaseGenerator.logEvent,
|
||||
FirebaseGenerator.footer
|
||||
Self.header,
|
||||
Self.logScreen,
|
||||
Self.logEvent,
|
||||
Self.footer
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private vars
|
||||
|
||||
private static var header: String {
|
||||
@ -28,23 +30,23 @@ enum FirebaseGenerator {
|
||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var logScreen: String {
|
||||
"""
|
||||
func logScreen(name: String, path: String) {
|
||||
var parameters = [
|
||||
AnalyticsParameterScreenName: name as NSObject
|
||||
]
|
||||
|
||||
|
||||
Analytics.logEvent(
|
||||
AnalyticsEventScreenView,
|
||||
parameters: parameters
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var logEvent: String {
|
||||
"""
|
||||
func logEvent(
|
||||
@ -57,7 +59,7 @@ enum FirebaseGenerator {
|
||||
"action": action as NSObject,
|
||||
"category": category as NSObject,
|
||||
]
|
||||
|
||||
|
||||
if let supplementaryParameters = params {
|
||||
for (newKey, newValue) in supplementaryParameters {
|
||||
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||
@ -65,11 +67,11 @@ enum FirebaseGenerator {
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
parameters[newKey] = newValue as? NSObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Analytics.logEvent(
|
||||
name.replacingOccurrences(of: [" "], with: "_"),
|
||||
parameters: parameters
|
||||
@ -77,11 +79,13 @@ enum FirebaseGenerator {
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var footer: String {
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
// CPD-ON
|
||||
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// MatomoGenerator.swift
|
||||
//
|
||||
//
|
||||
//
|
||||
// Created by Loris Perret on 05/12/2023.
|
||||
//
|
||||
@ -11,15 +11,15 @@ enum MatomoGenerator {
|
||||
|
||||
static var service: String {
|
||||
[
|
||||
MatomoGenerator.header,
|
||||
MatomoGenerator.setup,
|
||||
MatomoGenerator.logScreen,
|
||||
MatomoGenerator.logEvent,
|
||||
MatomoGenerator.footer
|
||||
Self.header,
|
||||
Self.setup,
|
||||
Self.logScreen,
|
||||
Self.logEvent,
|
||||
Self.footer
|
||||
]
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private vars
|
||||
|
||||
private static var header: String {
|
||||
@ -27,18 +27,18 @@ enum MatomoGenerator {
|
||||
// MARK: - Matomo
|
||||
|
||||
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
||||
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
|
||||
private var tracker: MatomoTracker
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var setup: String {
|
||||
"""
|
||||
// MARK: - Init
|
||||
|
||||
|
||||
init(siteId: String, url: String) {
|
||||
debugPrint("[Matomo service] Server URL: \\(url)")
|
||||
debugPrint("[Matomo service] Site ID: \\(siteId)")
|
||||
@ -46,40 +46,40 @@ enum MatomoGenerator {
|
||||
siteId: siteId,
|
||||
baseURL: URL(string: url)!
|
||||
)
|
||||
|
||||
|
||||
#if DEBUG
|
||||
tracker.dispatchInterval = 5
|
||||
#endif
|
||||
|
||||
|
||||
#if DEBUG
|
||||
tracker.logger = DefaultLogger(minLevel: .verbose)
|
||||
#endif
|
||||
|
||||
|
||||
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
|
||||
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var logScreen: String {
|
||||
"""
|
||||
func logScreen(name: String, path: String) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||
|
||||
|
||||
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
||||
tracker.track(
|
||||
view: [name],
|
||||
url: urlString
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var logEvent: String {
|
||||
"""
|
||||
func logEvent(
|
||||
@ -89,7 +89,7 @@ enum MatomoGenerator {
|
||||
params: [String: Any]?
|
||||
) {
|
||||
guard !tracker.isOptedOut else { return }
|
||||
|
||||
|
||||
tracker.track(
|
||||
eventWithCategory: category,
|
||||
action: action,
|
||||
@ -100,11 +100,11 @@ enum MatomoGenerator {
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
private static var footer: String {
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
@ -8,21 +8,24 @@
|
||||
import Foundation
|
||||
|
||||
class AnalyticsCategory {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
let id: String // OnBoarding
|
||||
var definitions = [AnalyticsDefinition]()
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(id: String) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
func hasOneOrMoreMatchingTags(tags: [String]) -> Bool {
|
||||
let allTags = definitions.flatMap { $0.tags }
|
||||
let allTagsSet = Set(allTags)
|
||||
|
||||
|
||||
let intersection = Set(tags).intersection(allTagsSet)
|
||||
if intersection.isEmpty {
|
||||
return false
|
||||
|
@ -9,6 +9,9 @@ import Foundation
|
||||
import ToolCore
|
||||
|
||||
class AnalyticsDefinition {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
let id: String
|
||||
var name: String
|
||||
var path: String = ""
|
||||
@ -18,7 +21,7 @@ class AnalyticsDefinition {
|
||||
var tags: [String] = []
|
||||
var parameters: [AnalyticsParameter] = []
|
||||
var type: TagType
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
init(id: String, name: String, type: TagType) {
|
||||
@ -26,7 +29,7 @@ class AnalyticsDefinition {
|
||||
self.name = name
|
||||
self.type = type
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
func hasOneOrMoreMatchingTags(inputTags: [String]) -> Bool {
|
||||
@ -35,7 +38,7 @@ class AnalyticsDefinition {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private Methods
|
||||
|
||||
private func getFuncName() -> String {
|
||||
@ -43,24 +46,24 @@ class AnalyticsDefinition {
|
||||
id.components(separatedBy: "_").forEach { word in
|
||||
pascalCaseTitle.append(contentsOf: word.uppercasedFirst())
|
||||
}
|
||||
|
||||
|
||||
return "log\(type == .screen ? "Screen" : "Event")\(pascalCaseTitle)"
|
||||
}
|
||||
|
||||
|
||||
private func getParameters() -> String {
|
||||
var params = parameters
|
||||
var result: String
|
||||
|
||||
|
||||
if type == .screen {
|
||||
params = params.filter { param in
|
||||
!param.replaceIn.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let paramsString = params.map { parameter in
|
||||
"\(parameter.name): \(parameter.type)"
|
||||
}
|
||||
|
||||
|
||||
if paramsString.count > 2 {
|
||||
result = """
|
||||
(
|
||||
@ -72,10 +75,10 @@ class AnalyticsDefinition {
|
||||
(\(paramsString.joined(separator: ", ")))
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private func replaceIn() {
|
||||
for parameter in parameters {
|
||||
for rep in parameter.replaceIn {
|
||||
@ -89,15 +92,15 @@ class AnalyticsDefinition {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func getlogFunction() -> String {
|
||||
var params: [String] = []
|
||||
var result: String
|
||||
|
||||
|
||||
let supplementaryParams = parameters.filter { param in
|
||||
param.replaceIn.isEmpty
|
||||
}
|
||||
|
||||
|
||||
supplementaryParams.forEach { param in
|
||||
params.append("\"\(param.name)\": \(param.name)")
|
||||
}
|
||||
@ -115,7 +118,7 @@ class AnalyticsDefinition {
|
||||
} else {
|
||||
result = "[:]"
|
||||
}
|
||||
|
||||
|
||||
if type == .screen {
|
||||
return """
|
||||
logScreen(
|
||||
@ -134,9 +137,9 @@ class AnalyticsDefinition {
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Raw strings
|
||||
|
||||
|
||||
func getProperty() -> String {
|
||||
replaceIn()
|
||||
return """
|
||||
@ -145,7 +148,7 @@ class AnalyticsDefinition {
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
func getStaticProperty() -> String {
|
||||
replaceIn()
|
||||
return """
|
||||
|
@ -8,37 +8,42 @@
|
||||
import Foundation
|
||||
|
||||
struct AnalyticsFile: Codable {
|
||||
|
||||
var categories: [AnalyticsCategoryDTO]
|
||||
}
|
||||
|
||||
struct AnalyticsCategoryDTO: Codable {
|
||||
|
||||
var id: String
|
||||
var screens: [AnalyticsDefinitionScreenDTO]?
|
||||
var events: [AnalyticsDefinitionEventDTO]?
|
||||
}
|
||||
|
||||
struct AnalyticsDefinitionScreenDTO: Codable {
|
||||
|
||||
var id: String
|
||||
var name: String
|
||||
var tags: String
|
||||
var comments: String?
|
||||
var parameters: [AnalyticsParameterDTO]?
|
||||
|
||||
|
||||
var path: String?
|
||||
}
|
||||
|
||||
struct AnalyticsDefinitionEventDTO: Codable {
|
||||
|
||||
var id: String
|
||||
var name: String
|
||||
var tags: String
|
||||
var comments: String?
|
||||
var parameters: [AnalyticsParameterDTO]?
|
||||
|
||||
|
||||
var category: String?
|
||||
var action: String?
|
||||
}
|
||||
|
||||
struct AnalyticsParameterDTO: Codable {
|
||||
|
||||
var name: String
|
||||
var type: String
|
||||
var replaceIn: String?
|
||||
|
@ -8,12 +8,15 @@
|
||||
import Foundation
|
||||
|
||||
class AnalyticsParameter {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var name: String
|
||||
var type: String
|
||||
var replaceIn: [String] = []
|
||||
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
|
||||
init(name: String, type: String) {
|
||||
self.name = name
|
||||
self.type = type
|
||||
|
@ -8,8 +8,9 @@
|
||||
import Foundation
|
||||
|
||||
extension AnalyticsDefinition {
|
||||
|
||||
|
||||
enum TagType {
|
||||
|
||||
case screen
|
||||
case event
|
||||
}
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum TrackerType: CaseIterable {
|
||||
enum TrackerType: CaseIterable, Sendable {
|
||||
|
||||
case matomo
|
||||
case firebase
|
||||
|
||||
@ -15,6 +16,7 @@ enum TrackerType: CaseIterable {
|
||||
switch self {
|
||||
case .matomo:
|
||||
"matomo"
|
||||
|
||||
case .firebase:
|
||||
"firebase"
|
||||
}
|
||||
|
@ -9,16 +9,54 @@ import Foundation
|
||||
import Yams
|
||||
|
||||
class AnalyticsFileParser {
|
||||
private static var inputFile: String = ""
|
||||
private static var target: String = ""
|
||||
|
||||
private static func parseYaml() -> AnalyticsFile {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
private var inputFile: String = ""
|
||||
private var target: String = ""
|
||||
|
||||
// MARK: - Methods
|
||||
|
||||
func parse(_ inputFile: String, target: String) -> [AnalyticsCategory] {
|
||||
self.inputFile = inputFile
|
||||
self.target = target
|
||||
|
||||
let tagFile = parseYaml()
|
||||
|
||||
return tagFile
|
||||
.categories
|
||||
.map { categorie in
|
||||
let section = AnalyticsCategory(id: categorie.id)
|
||||
|
||||
if let screens = categorie.screens {
|
||||
section
|
||||
.definitions
|
||||
.append(
|
||||
contentsOf: getTagDefinitionScreen(from: screens)
|
||||
)
|
||||
}
|
||||
|
||||
if let events = categorie.events {
|
||||
section
|
||||
.definitions
|
||||
.append(
|
||||
contentsOf: getTagDefinitionEvent(from: events)
|
||||
)
|
||||
}
|
||||
|
||||
return section
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func parseYaml() -> AnalyticsFile {
|
||||
guard let data = FileManager().contents(atPath: inputFile) else {
|
||||
let error = AnalyticsError.fileNotExists(inputFile)
|
||||
print(error.description)
|
||||
Analytics.exit(withError: error)
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
let tagFile = try YAMLDecoder().decode(AnalyticsFile.self, from: data)
|
||||
return tagFile
|
||||
@ -29,13 +67,12 @@ class AnalyticsFileParser {
|
||||
}
|
||||
}
|
||||
|
||||
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||
private func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||
parameters.map { dtoParameter in
|
||||
// Type
|
||||
|
||||
let type = dtoParameter.type.uppercasedFirst()
|
||||
|
||||
guard
|
||||
guard
|
||||
type == "String" ||
|
||||
type == "Int" ||
|
||||
type == "Double" ||
|
||||
@ -59,7 +96,7 @@ class AnalyticsFileParser {
|
||||
}
|
||||
}
|
||||
|
||||
private static func getTagDefinition(
|
||||
private func getTagDefinition(
|
||||
id: String,
|
||||
name: String,
|
||||
type: AnalyticsDefinition.TagType,
|
||||
@ -72,20 +109,20 @@ class AnalyticsFileParser {
|
||||
.components(separatedBy: ",")
|
||||
.map { $0.removeLeadingTrailingWhitespace() }
|
||||
|
||||
if let comments = comments {
|
||||
if let comments {
|
||||
definition.comments = comments
|
||||
}
|
||||
|
||||
if let parameters = parameters {
|
||||
definition.parameters = Self.getParameters(from: parameters)
|
||||
|
||||
if let parameters {
|
||||
definition.parameters = getParameters(from: parameters)
|
||||
}
|
||||
|
||||
|
||||
return definition
|
||||
}
|
||||
|
||||
private static func getTagDefinitionScreen(from screens: [AnalyticsDefinitionScreenDTO]) -> [AnalyticsDefinition] {
|
||||
|
||||
private func getTagDefinitionScreen(from screens: [AnalyticsDefinitionScreenDTO]) -> [AnalyticsDefinition] {
|
||||
screens.map { screen in
|
||||
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||
let definition: AnalyticsDefinition = getTagDefinition(
|
||||
id: screen.id,
|
||||
name: screen.name,
|
||||
type: .screen,
|
||||
@ -109,10 +146,10 @@ class AnalyticsFileParser {
|
||||
return definition
|
||||
}
|
||||
}
|
||||
|
||||
private static func getTagDefinitionEvent(from events: [AnalyticsDefinitionEventDTO]) -> [AnalyticsDefinition] {
|
||||
|
||||
private func getTagDefinitionEvent(from events: [AnalyticsDefinitionEventDTO]) -> [AnalyticsDefinition] {
|
||||
events.map { event in
|
||||
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||
let definition: AnalyticsDefinition = getTagDefinition(
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
type: .event,
|
||||
@ -144,35 +181,4 @@ class AnalyticsFileParser {
|
||||
return definition
|
||||
}
|
||||
}
|
||||
|
||||
static func parse(_ inputFile: String, target: String) -> [AnalyticsCategory] {
|
||||
self.inputFile = inputFile
|
||||
self.target = target
|
||||
|
||||
let tagFile = Self.parseYaml()
|
||||
|
||||
return tagFile
|
||||
.categories
|
||||
.map { categorie in
|
||||
let section: AnalyticsCategory = AnalyticsCategory(id: categorie.id)
|
||||
|
||||
if let screens = categorie.screens {
|
||||
section
|
||||
.definitions
|
||||
.append(
|
||||
contentsOf: Self.getTagDefinitionScreen(from: screens)
|
||||
)
|
||||
}
|
||||
|
||||
if let events = categorie.events {
|
||||
section
|
||||
.definitions
|
||||
.append(
|
||||
contentsOf: Self.getTagDefinitionEvent(from: events)
|
||||
)
|
||||
}
|
||||
|
||||
return section
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user