Files
resgen.swift/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift
Thibaut Schmitt 7162f13166
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Add visibility parameters to control scope of generated extension
2025-07-18 11:53:46 +02:00

345 lines
9.4 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],
staticVar: 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,
staticVar: staticVar,
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],
staticVar: Bool,
visibility: ExtensionVisibility
) -> String {
[
getHeader(
targets: targets,
staticVar: staticVar,
visibility: visibility
),
getProperties(
sections: sections,
tags: tags,
staticVar: staticVar,
visibility: visibility
),
getFooter()
]
.joined(separator: "\n")
}
// MARK: - Extension part
private static func getHeader(
targets: [TrackerType],
staticVar: 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 isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false
} else {
true
}
}
// 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")
}
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 { return }
managers.values.forEach { manager in
manager.logScreen(
name: name,
path: path,
params: params
)
}
}
private func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard isEnabled else { return }
managers.values.forEach { manager in
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) {"
} else if targets.contains(TrackerType.firebase) {
header = "\(visibility) func configure() {"
}
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],
staticVar: 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 staticVar {
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