Files
resgen.swift/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift
Quentin Bandera c4a3aa54d6
Some checks failed
openium/resgen.swift/pipeline/pr-master There was a failure building this commit
Gestion du cas des strings vides
2025-10-21 10:57:20 +02:00

373 lines
11 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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