Some checks are pending
openium/resgen.swift/pipeline/pr-master Build started...
373 lines
11 KiB
Swift
373 lines
11 KiB
Swift
//
|
||
// AnalyticsGenerator.swift
|
||
//
|
||
//
|
||
// Created by Loris Perret on 08/12/2023.
|
||
//
|
||
|
||
// CPD-OFF
|
||
|
||
import CoreVideo
|
||
import Foundation
|
||
import ToolCore
|
||
|
||
// Disabled cause it's a pain to handle in generated string
|
||
// swiftlint:disable type_body_length
|
||
|
||
enum AnalyticsGenerator {
|
||
|
||
// MARK: - Write content
|
||
|
||
static func writeExtensionFiles(
|
||
sections: [AnalyticsCategory],
|
||
target: String,
|
||
tags: [String],
|
||
isStatic: Bool,
|
||
outputFile: String,
|
||
visibility: ExtensionVisibility
|
||
) {
|
||
// Get target type from enum
|
||
let targetsString: [String] = target.components(separatedBy: " ")
|
||
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 = getExtensionContent(
|
||
targets: targets,
|
||
sections: sections,
|
||
tags: tags,
|
||
isStatic: isStatic,
|
||
visibility: visibility
|
||
)
|
||
|
||
// Write content
|
||
let outputFilePathURL = URL(fileURLWithPath: outputFile)
|
||
do {
|
||
try extensionFileContent.write(to: outputFilePathURL, atomically: false, encoding: .utf8)
|
||
} catch {
|
||
let error = AnalyticsError.writeFile(outputFile, error.localizedDescription)
|
||
print(error.description)
|
||
Analytics.exit(withError: error)
|
||
}
|
||
}
|
||
|
||
// MARK: - Extension content
|
||
|
||
static func getExtensionContent(
|
||
targets: [TrackerType],
|
||
sections: [AnalyticsCategory],
|
||
tags: [String],
|
||
isStatic: Bool,
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
[
|
||
getHeader(
|
||
targets: targets,
|
||
isStatic: isStatic,
|
||
visibility: visibility
|
||
),
|
||
getProperties(
|
||
sections: sections,
|
||
tags: tags,
|
||
isStatic: isStatic,
|
||
visibility: visibility
|
||
),
|
||
getFooter()
|
||
]
|
||
.joined(separator: "\n")
|
||
}
|
||
|
||
// MARK: - Extension part
|
||
|
||
private static func getHeader(
|
||
targets: [TrackerType],
|
||
isStatic: Bool,
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
"""
|
||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||
|
||
\(Self.getImport(targets: targets))
|
||
|
||
\(Self.getAnalyticsProtocol(targets: targets, visibility: visibility))
|
||
|
||
\(Self.getTrackerTypeEnum(targets: targets, visibility: visibility))
|
||
|
||
// MARK: - Manager
|
||
|
||
\(visibility) class AnalyticsManager {
|
||
|
||
\(visibility) static var shared = AnalyticsManager()
|
||
|
||
private init() {}
|
||
|
||
// MARK: - Properties
|
||
|
||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||
|
||
\(Self.getEnabledContent(visibility: visibility))
|
||
|
||
\(Self.getAnalyticsProperties(targets: targets, visibility: visibility))
|
||
|
||
\(Self.getPrivateLogFunction())
|
||
"""
|
||
}
|
||
|
||
private static func getTrackerTypeEnum(
|
||
targets: [TrackerType],
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
var result: [String] = []
|
||
targets.forEach { type in
|
||
result.append(" case \(type)")
|
||
}
|
||
|
||
return """
|
||
// MARK: - Traker Type
|
||
|
||
\(visibility) enum TrackerType: CaseIterable {
|
||
|
||
\(result.joined(separator: "\n"))
|
||
}
|
||
"""
|
||
}
|
||
|
||
private static func getEnabledContent(
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
"""
|
||
private var isDebugMode: Bool = false
|
||
|
||
private var isEnabled: Bool {
|
||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||
false
|
||
} else {
|
||
true
|
||
}
|
||
}
|
||
|
||
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||
|
||
// MARK: - Enable Methods
|
||
|
||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||
managers.forEach { (key, value) in
|
||
if analytics.contains(where: { type in
|
||
type == key
|
||
}) {
|
||
value.setEnable(enable)
|
||
}
|
||
}
|
||
}
|
||
|
||
\(visibility) func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||
setAnalytics(enable: true, analytics)
|
||
}
|
||
|
||
\(visibility) func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||
setAnalytics(enable: false, analytics)
|
||
}
|
||
"""
|
||
}
|
||
|
||
private static func getImport(targets: [TrackerType]) -> String {
|
||
var result: [String] = []
|
||
|
||
result.append("import Foundation")
|
||
|
||
if targets.contains(TrackerType.matomo) {
|
||
result.append("import MatomoTracker")
|
||
}
|
||
|
||
if targets.contains(TrackerType.firebase) {
|
||
result.append("import FirebaseAnalytics")
|
||
}
|
||
|
||
result.append("import os")
|
||
|
||
return result.joined(separator: "\n")
|
||
}
|
||
|
||
private static func getPrivateLogFunction() -> String {
|
||
"""
|
||
// MARK: - Private Log Methods
|
||
|
||
private func logScreen(
|
||
name: String,
|
||
path: String,
|
||
params: [String: Any]?
|
||
) {
|
||
guard isEnabled else {
|
||
if isDebugMode {
|
||
logger.log("Analytics disabled")
|
||
}
|
||
return
|
||
}
|
||
|
||
managers.values.forEach { manager in
|
||
|
||
if isDebugMode {
|
||
logger.debug("🖥️ Screen: \\(name, privacy: .public) | Path: \\(path, privacy: .public) | Params: \\(String(describing: params ?? [:]), privacy: .public)")
|
||
}
|
||
|
||
manager.logScreen(
|
||
name: name,
|
||
path: path,
|
||
params: params
|
||
)
|
||
}
|
||
}
|
||
|
||
private func logEvent(
|
||
name: String,
|
||
action: String,
|
||
category: String,
|
||
params: [String: Any]?
|
||
) {
|
||
guard isEnabled else {
|
||
if isDebugMode {
|
||
logger.log("Analytics disabled")
|
||
}
|
||
return
|
||
}
|
||
|
||
managers.values.forEach { manager in
|
||
|
||
if isDebugMode {
|
||
logger.debug("📊 Event: \\(name, privacy: .public) | Action: \\(action.isEmpty ? "-" : action, privacy: .public) | Category: \\(category.isEmpty ? "-" : category, privacy: .public) | Params: \\(String(describing: params ?? [:]), privacy: .public)")
|
||
}
|
||
|
||
manager.logEvent(
|
||
name: name,
|
||
action: action,
|
||
category: category,
|
||
params: params
|
||
)
|
||
}
|
||
}
|
||
"""
|
||
}
|
||
|
||
private static func getAnalyticsProperties(
|
||
targets: [TrackerType],
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
var header = ""
|
||
var content: [String] = []
|
||
let footer = " }"
|
||
|
||
if targets.contains(TrackerType.matomo) {
|
||
header = "\(visibility) func configure(siteId: String, url: String, isDebugMode: Bool = false) {"
|
||
} else if targets.contains(TrackerType.firebase) {
|
||
header = "\(visibility) func configure(isDebugMode: Bool = false) {"
|
||
}
|
||
|
||
content.append(" self.isDebugMode = isDebugMode")
|
||
|
||
if targets.contains(TrackerType.matomo) {
|
||
content.append("""
|
||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||
siteId: siteId,
|
||
url: url
|
||
)
|
||
""")
|
||
}
|
||
|
||
if targets.contains(TrackerType.firebase) {
|
||
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||
}
|
||
|
||
return [
|
||
header,
|
||
content.joined(separator: "\n"),
|
||
footer
|
||
]
|
||
.joined(separator: "\n")
|
||
}
|
||
|
||
private static func getAnalyticsProtocol(
|
||
targets: [TrackerType],
|
||
visibility: ExtensionVisibility
|
||
) -> String {
|
||
let proto = """
|
||
// MARK: - Protocol
|
||
|
||
\(visibility) protocol AnalyticsManagerProtocol {
|
||
|
||
func logScreen(
|
||
name: String,
|
||
path: String,
|
||
params: [String: Any]?
|
||
)
|
||
|
||
func logEvent(
|
||
name: String,
|
||
action: String,
|
||
category: String,
|
||
params: [String: Any]?
|
||
)
|
||
|
||
func setEnable(_ enable: Bool)
|
||
}
|
||
"""
|
||
|
||
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\n")
|
||
}
|
||
|
||
private static func getProperties(
|
||
sections: [AnalyticsCategory],
|
||
tags: [String],
|
||
isStatic: Bool,
|
||
visibility: ExtensionVisibility
|
||
) -> 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 isStatic {
|
||
res += "\n\n\(definition.getStaticProperty(visibility: visibility))"
|
||
} else {
|
||
res += "\n\n\(definition.getProperty(visibility: visibility))"
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
.joined(separator: "\n")
|
||
}
|
||
|
||
private static func getFooter() -> String {
|
||
"""
|
||
}
|
||
|
||
"""
|
||
}
|
||
}
|
||
|
||
// CPD-ON
|