From c3b8ebfb37fa746ad05d08877439a99782511b76 Mon Sep 17 00:00:00 2001 From: Loris Perret Date: Thu, 17 Jul 2025 09:15:43 +0200 Subject: [PATCH] Analytics improvement (#9) Co-authored-by: Quentin Bandera Reviewed-on: https://gitea.openium.fr/openium/resgen.swift/pulls/9 Co-authored-by: Loris Perret Co-committed-by: Loris Perret --- README.md | 83 +++++++++- .../Generated/Analytics+GenAllScript.swift | 151 ++++++++++++++---- SampleFiles/Tags/sampleTags.yml | 6 + SampleFiles/genAllRessources.sh | 7 +- .../Generator/AnalyticsGenerator.swift | 120 ++++++++++---- .../Generator/FirebaseGenerator.swift | 58 +++++-- .../Analytics/Generator/MatomoGenerator.swift | 29 ++-- .../Analytics/Model/AnalyticsDefinition.swift | 49 ++++-- .../Analytics/Model/AnalyticsFile.swift | 2 + .../Analytics/Model/AnalyticsParameter.swift | 10 +- .../Analytics/Model/ParameterType.swift | 15 ++ .../Parser/AnalyticsFileParser.swift | 63 ++++++-- 12 files changed, 472 insertions(+), 121 deletions(-) create mode 100644 Sources/ResgenSwift/Analytics/Model/ParameterType.swift diff --git a/README.md b/README.md index 580516f..3b85ede 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \ 6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`) 7. `--static-members` *(optional)*: generate static properties or not -> ⚠️ If extension name is not set or is `Tags`, it will generate the following typaloas `typealias Tags = String`. +> ⚠️ If extension name is not set or is `Tags`, it will generate the following typealias `typealias Tags = String`. ## Analytics @@ -141,7 +141,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \ Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site. ```sh -swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \ +swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/analytics.yml" \ --target "matomo firebase" \ --extension-output-path "./Analytics/Generated" \ --extension-name "AppAnalytics" \ @@ -159,7 +159,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \ 6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`) 7. `--static-members` *(optional)*: generate static properties or not -> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typaloas `typealias Analytics = String`. +> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typealias `typealias Analytics = String`. ### YAML @@ -186,19 +186,83 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \ 7. `comments` *(optional)* 8. `parameters` *(optional)* - **Parameters** +**Parameters** You can use parameters in generate methods. 1. `name`: name of the parameter 2. `type`: type of the parameter (Int, String, Bool, Double) +3. `value`: value of the parameter +4. `defaultValue`: defaultValue of the parameter 3. `replaceIn` *(optional)* +**Value** + +If you want to send another parameter with a static value. For example, you want to send to which screen the event is triggered. +You can add the parameter 'screenName' for example and its 'value' is 'Home'. With this, you do not need to specify the value in the function call. + +**DefaultValue** + +If you want ta add a parameter in the call of the function but you want to make it optionnal with a default value you need to use this property. + +Example: +``` +events: + id: id_of_tag + name: _TITLE_ + tags: ios,droid + parameters: + - name: title + type: String + defaultValue: someTitle +``` + +The generated method will be: +``` +logIdOfTag(title: String = "someTitle") +``` + **Replace in** This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*. -You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase) +You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase). +You can't use `value`and `replaceIn`in thge same time. +Example: +``` +events: + id: id_of_tag + name: _TITLE_ + tags: ios,droid + parameters: + - name: title + type: String + replaceIn: name +``` + +In this sample, we want to add the parameter `title` in the field `name`. So, we need to place `_TITLE_` in the field `name`. + +The generated method will be: +``` +logIdOfTag(title: String) +``` + +You can also want to replace a parameter in an other parameter. You can do this with the `replaceIn` property. The condition is that the parameter which will use the `replaceIn`need to have the `value`property + +Example: +``` +events: + id: id_of_tag + name: title + tags: ios,droid + parameters: + - name: something + type: String + value: test _TEXT_ + - name: text + type: String + replaceIn: something +``` ## Images @@ -287,6 +351,15 @@ tags: extensionName: String? extensionSuffix: String? staticMembers: Bool? + +analytics: +- + inputFile: String + target: String + extensionOutputPath: String + extensionName: String? + extensionSuffix: String? + staticMembers: Bool? ``` ### Multiple configurations diff --git a/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift b/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift index 6d0cf11..8742801 100644 --- a/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift +++ b/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift @@ -6,14 +6,20 @@ import FirebaseAnalytics // MARK: - Protocol protocol AnalyticsManagerProtocol { + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) - func logScreen(name: String, path: String) func logEvent( name: String, action: String, category: String, params: [String: Any]? ) + + func setEnable(_ enable: Bool) } // MARK: - Matomo @@ -48,8 +54,11 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol { // MARK: - Methods - func logScreen(name: String, path: String) { - guard !tracker.isOptedOut else { return } + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard let trackerUrl = tracker.contentBase?.absoluteString else { return } let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS") @@ -65,8 +74,6 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol { category: String, params: [String: Any]? ) { - guard !tracker.isOptedOut else { return } - tracker.track( eventWithCategory: category, action: action, @@ -75,16 +82,40 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol { url: nil ) } + + func setEnable(_ enable: Bool) { + tracker.isOptedOut = !enable + } } // MARK: - Firebase class FirebaseAnalyticsManager: AnalyticsManagerProtocol { - func logScreen(name: String, path: String) { + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { var parameters = [ AnalyticsParameterScreenName: name as NSObject ] + if path.isEmpty == false { + parameters["path"] = path + "/iOS" as NSObject + } + + if let supplementaryParameters = params { + for (newKey, newValue) in supplementaryParameters { + if parameters.contains(where: { (key: String, value: NSObject) in + key == newKey + }) { + continue + } + + parameters[newKey] = newValue as? NSObject + } + } + Analytics.logEvent( AnalyticsEventScreenView, parameters: parameters @@ -98,10 +129,17 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol { params: [String: Any]? ) { var parameters: [String:NSObject] = [ - "action": action as NSObject, - "category": category as NSObject, + AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject ] + if category.isEmpty == false { + parameters["AnalyticsParameterItemCategory"] = category as NSObject + } + + if action.isEmpty == false { + parameters["action"] = action as NSObject + } + if let supplementaryParameters = params { for (newKey, newValue) in supplementaryParameters { if parameters.contains(where: { (key: String, value: NSObject) in @@ -115,10 +153,21 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol { } Analytics.logEvent( - name.replacingOccurrences(of: [" "], with: "_"), + AnalyticsEventSelectContent, parameters: parameters ) } + func setEnable(_ enable: Bool) { + Analytics.setAnalyticsCollectionEnabled(enable) + } +} + + +// MARK: - Traker Type + +enum TrackerType: CaseIterable { + case matomo + case firebase } // MARK: - Manager @@ -127,33 +176,61 @@ class AnalyticsManager { static var shared = AnalyticsManager() + private init() {} + // MARK: - Properties - var managers: [AnalyticsManagerProtocol] = [] + var managers: [TrackerType: AnalyticsManagerProtocol] = [:] - private var isEnabled: Bool = true + private var isEnabled: Bool { + if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { + false + } else { + true + } + } // MARK: - Methods - func setAnalyticsEnabled(_ enable: Bool) { - isEnabled = enable + private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { + managers.forEach { (key, value) in + if analytics.contains(where: { type in + type == key + }) { + value.setEnable(enable) + } + } + } + + func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { + setAnalytics(enable: true, analytics) + } + + func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { + setAnalytics(enable: false, analytics) } func configure(siteId: String, url: String) { - managers.append( - MatomoAnalyticsManager( - siteId: siteId, - url: url - ) + managers[TrackerType.matomo] = MatomoAnalyticsManager( + siteId: siteId, + url: url ) - managers.append(FirebaseAnalyticsManager()) + managers[TrackerType.firebase] = FirebaseAnalyticsManager() } - - private func logScreen(name: String, path: String) { + + private func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard isEnabled else { return } - managers.forEach { manager in - manager.logScreen(name: name, path: path) + managers.values.forEach { manager in + manager.logScreen( + name: name, + path: path, + params: params + ) } } @@ -165,7 +242,7 @@ class AnalyticsManager { ) { guard isEnabled else { return } - managers.forEach { manager in + managers.values.forEach { manager in manager.logEvent( name: name, action: action, @@ -177,31 +254,39 @@ class AnalyticsManager { // MARK: - section_one - func logScreenS1DefOne(title: String) { - logScreen( + static func logScreenS1DefOne(title: String) { + AnalyticsManager.shared.logScreen( name: "s1 def one \(title)", - path: "s1_def_one/\(title)" + path: "s1_def_one/\(title)", + params: nil ) } - func logEventS1DefTwo(title: String, count: String) { - logEvent( + static func logEventS1DefTwo( + title: String, + count: String, + test2: String = "test" + ) { + AnalyticsManager.shared.logEvent( name: "s1 def two", action: "test", category: "test", params: [ "title": title, - "count": count + "count": count, + "test": "test", + "test2": test2 ] ) } // MARK: - section_two - func logScreenS2DefOne() { - logScreen( + static func logScreenS2DefOne() { + AnalyticsManager.shared.logScreen( name: "s2 def one", - path: "s2_def_one/" + path: "s2_def_one/", + params: nil ) } } diff --git a/SampleFiles/Tags/sampleTags.yml b/SampleFiles/Tags/sampleTags.yml index 4c91dd0..1b40b76 100644 --- a/SampleFiles/Tags/sampleTags.yml +++ b/SampleFiles/Tags/sampleTags.yml @@ -22,6 +22,12 @@ categories: type: String - name: count type: String + - name: test + type: String + value: test + - name: test2 + type: String + defaultValue: test - id: section_two screens: diff --git a/SampleFiles/genAllRessources.sh b/SampleFiles/genAllRessources.sh index b8e4930..3de2c99 100755 --- a/SampleFiles/genAllRessources.sh +++ b/SampleFiles/genAllRessources.sh @@ -50,14 +50,15 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/sampleTags.txt --extension-name "Tags" \ --extension-suffix "GenAllScript" -#echo "\n-------------------------\n" +echo "\n-------------------------\n" # Analytics swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \ - --target "matomo firebase" \ + --target "firebase matomo" \ --extension-output-path "./Tags/Generated" \ --extension-name "Analytics" \ - --extension-suffix "GenAllScript" + --extension-suffix "GenAllScript" \ + --static-members true echo "\n-------------------------\n" diff --git a/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift index fdcc03e..0cff0cf 100644 --- a/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift @@ -89,36 +89,76 @@ enum AnalyticsGenerator { ) -> String { """ // Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion) - - \(getImport(targets: targets)) - - \(getAnalyticsProtocol(targets: targets)) + + \(Self.getImport(targets: targets)) + + \(Self.getAnalyticsProtocol(targets: targets)) + + \(Self.getTrackerTypeEnum()) + // MARK: - Manager class AnalyticsManager { - + static var shared = AnalyticsManager() + + private init() {} // MARK: - Properties - - var managers: [AnalyticsManagerProtocol] = [] - - \(getEnabledContent()) - - \(getAnalyticsProperties(targets: targets)) - - \(getPrivateLogFunction()) + + var managers: [TrackerType: AnalyticsManagerProtocol] = [:] + + \(Self.getEnabledContent()) + + \(Self.getAnalyticsProperties(targets: targets)) + + \(Self.getPrivateLogFunction()) """ } - + + private static func getTrackerTypeEnum() -> String { + var result: [String] = [] + TrackerType.allCases.forEach { type in + result.append(" case \(type)") + } + + return """ + // MARK: - Traker Type + + enum TrackerType: CaseIterable { + \(result.joined(separator: "\n")) + } + """ + } + private static func getEnabledContent() -> String { """ - private var isEnabled: Bool = true - + private var isEnabled: Bool { + if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { + false + } else { + true + } + } + // MARK: - Methods - - func setAnalyticsEnabled(_ enable: Bool) { - isEnabled = enable + + private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) { + managers.forEach { (key, value) in + if analytics.contains(where: { type in + type == key + }) { + value.setEnable(enable) + } + } + } + + func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { + setAnalytics(enable: true, analytics) + } + + func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) { + setAnalytics(enable: false, analytics) } """ } @@ -126,6 +166,8 @@ enum AnalyticsGenerator { private static func getImport(targets: [TrackerType]) -> String { var result: [String] = [] + result.append("import Foundation") + if targets.contains(TrackerType.matomo) { result.append("import MatomoTracker") } @@ -138,11 +180,19 @@ enum AnalyticsGenerator { private static func getPrivateLogFunction() -> String { """ - private func logScreen(name: String, path: String) { + private func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard isEnabled else { return } - - managers.forEach { manager in - manager.logScreen(name: name, path: path) + + managers.values.forEach { manager in + manager.logScreen( + name: name, + path: path, + params: params + ) } } @@ -153,8 +203,8 @@ enum AnalyticsGenerator { params: [String: Any]? ) { guard isEnabled else { return } - - managers.forEach { manager in + + managers.values.forEach { manager in manager.logEvent( name: name, action: action, @@ -179,16 +229,14 @@ enum AnalyticsGenerator { if targets.contains(TrackerType.matomo) { content.append(""" - managers.append( - MatomoAnalyticsManager( - siteId: siteId, - url: url - ) + managers[TrackerType.matomo] = MatomoAnalyticsManager( + siteId: siteId, + url: url ) """) } if targets.contains(TrackerType.firebase) { - content.append(" managers.append(FirebaseAnalyticsManager())") + content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()") } return [ @@ -204,14 +252,20 @@ enum AnalyticsGenerator { // MARK: - Protocol protocol AnalyticsManagerProtocol { - - func logScreen(name: String, path: String) + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) + func logEvent( name: String, action: String, category: String, params: [String: Any]? ) + + func setEnable(_ enable: Bool) } """ diff --git a/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift index e5aef8c..8d2d22d 100644 --- a/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift @@ -13,10 +13,11 @@ enum FirebaseGenerator { static var service: String { [ - Self.header, - Self.logScreen, - Self.logEvent, - Self.footer + FirebaseGenerator.header, + FirebaseGenerator.logScreen, + FirebaseGenerator.logEvent, + FirebaseGenerator.enable, + FirebaseGenerator.footer ] .joined(separator: "\n") } @@ -33,11 +34,31 @@ enum FirebaseGenerator { private static var logScreen: String { """ - func logScreen(name: String, path: String) { + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { var parameters = [ AnalyticsParameterScreenName: name as NSObject ] - + + if path.isEmpty == false { + parameters["path"] = path + "/iOS" as NSObject + } + + if let supplementaryParameters = params { + for (newKey, newValue) in supplementaryParameters { + if parameters.contains(where: { (key: String, value: NSObject) in + key == newKey + }) { + continue + } + + parameters[newKey] = newValue as? NSObject + } + } + Analytics.logEvent( AnalyticsEventScreenView, parameters: parameters @@ -56,10 +77,17 @@ enum FirebaseGenerator { params: [String: Any]? ) { var parameters: [String:NSObject] = [ - "action": action as NSObject, - "category": category as NSObject, + AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject ] - + + if category.isEmpty == false { + parameters["AnalyticsParameterItemCategory"] = category as NSObject + } + + if action.isEmpty == false { + parameters["action"] = action as NSObject + } + if let supplementaryParameters = params { for (newKey, newValue) in supplementaryParameters { if parameters.contains(where: { (key: String, value: NSObject) in @@ -73,13 +101,21 @@ enum FirebaseGenerator { } Analytics.logEvent( - name.replacingOccurrences(of: [" "], with: "_"), + AnalyticsEventSelectContent, parameters: parameters ) } """ } - + + private static var enable: String { + """ + func setEnable(_ enable: Bool) { + Analytics.setAnalyticsCollectionEnabled(enable) + } + """ + } + private static var footer: String { """ } diff --git a/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift b/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift index 4bd4320..0217328 100644 --- a/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift @@ -11,11 +11,12 @@ enum MatomoGenerator { static var service: String { [ - Self.header, - Self.setup, - Self.logScreen, - Self.logEvent, - Self.footer + MatomoGenerator.header, + MatomoGenerator.setup, + MatomoGenerator.logScreen, + MatomoGenerator.logEvent, + MatomoGenerator.enable, + MatomoGenerator.footer ] .joined(separator: "\n") } @@ -66,8 +67,11 @@ enum MatomoGenerator { private static var logScreen: String { """ - func logScreen(name: String, path: String) { - guard !tracker.isOptedOut else { return } + func logScreen( + name: String, + path: String, + params: [String: Any]? + ) { guard let trackerUrl = tracker.contentBase?.absoluteString else { return } let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS") @@ -88,8 +92,6 @@ enum MatomoGenerator { category: String, params: [String: Any]? ) { - guard !tracker.isOptedOut else { return } - tracker.track( eventWithCategory: category, action: action, @@ -98,6 +100,15 @@ enum MatomoGenerator { url: nil ) } + + """ + } + + private static var enable: String { + """ + func setEnable(_ enable: Bool) { + tracker.isOptedOut = !enable + } """ } diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift index 41ade03..c84bf1c 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift @@ -51,17 +51,23 @@ class AnalyticsDefinition { } private func getParameters() -> String { - var params = parameters var result: String - - if type == .screen { - params = params.filter { param in - !param.replaceIn.isEmpty + + let paramsString = parameters.compactMap { parameter -> String? in + guard parameter.value.isEmpty else { return nil } + + let defaultValue: String + switch parameter.type { + case .bool: + defaultValue = "\(parameter.defaultValue.lowercased())" + case .int, .double: + defaultValue = "\(parameter.defaultValue)" + case .string: + defaultValue = "\"\(parameter.defaultValue)\"" } - } - - let paramsString = params.map { parameter in - "\(parameter.name): \(parameter.type)" + + let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)" + return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)" } if paramsString.count > 2 { @@ -87,7 +93,10 @@ class AnalyticsDefinition { case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") - default: break + default: + if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false { + param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))") + } } } } @@ -102,7 +111,18 @@ class AnalyticsDefinition { } supplementaryParams.forEach { param in - params.append("\"\(param.name)\": \(param.name)") + if param.value.isEmpty { + params.append("\"\(param.name)\": \(param.name)") + } else { + switch param.type { + case .bool: + params.append("\"\(param.name)\": \(param.value.lowercased())") + case .int, .double: + params.append("\"\(param.name)\": \(param.value)") + case .string: + params.append("\"\(param.name)\": \"\(param.value)\"") + } + } } if params.count > 1 { @@ -116,14 +136,15 @@ class AnalyticsDefinition { [\(params.joined(separator: ", "))] """ } else { - result = "[:]" + result = "nil" } if type == .screen { return """ logScreen( name: "\(name)", - path: "\(path)" + path: "\(path)", + params: \(result) ) """ } else { @@ -153,7 +174,7 @@ class AnalyticsDefinition { replaceIn() return """ static func \(getFuncName())\(getParameters()) { - \(getlogFunction()) + AnalyticsManager.shared.\(getlogFunction()) } """ } diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift index bbfaba0..209700f 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift @@ -46,5 +46,7 @@ struct AnalyticsParameterDTO: Codable { var name: String var type: String + var value: String? + var defaultValue: String? var replaceIn: String? } diff --git a/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift b/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift index 3bb7c3a..42dd8b5 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift @@ -12,13 +12,17 @@ class AnalyticsParameter { // MARK: - Properties var name: String - var type: String + var type: ParameterType + var value: String + var defaultValue: String var replaceIn: [String] = [] // MARK: - Init - - init(name: String, type: String) { + + init(name: String, type: ParameterType, value: String, defaultValue: String) { self.name = name self.type = type + self.value = value + self.defaultValue = defaultValue } } diff --git a/Sources/ResgenSwift/Analytics/Model/ParameterType.swift b/Sources/ResgenSwift/Analytics/Model/ParameterType.swift new file mode 100644 index 0000000..1f60ef9 --- /dev/null +++ b/Sources/ResgenSwift/Analytics/Model/ParameterType.swift @@ -0,0 +1,15 @@ +// +// File.swift +// +// +// Created by Loris Perret on 17/07/2024. +// + +import Foundation + +enum ParameterType: String { + case string = "String" + case int = "Int" + case double = "Double" + case bool = "Bool" +} diff --git a/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift b/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift index 6168b73..64a5cec 100644 --- a/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift +++ b/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift @@ -67,25 +67,58 @@ class AnalyticsFileParser { } } - private func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] { - parameters.map { dtoParameter in + private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] { + func verify(value: String?, for type: ParameterType) { + guard let value, value.isEmpty == false else { return } + + switch type { + case .int: + if Int(value) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .bool: + if Bool(value.lowercased()) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .double: + if Double(value) == nil { + let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)") + print(error.description) + Analytics.exit(withError: error) + } + case .string: + break + } + } + + return parameters.map { dtoParameter in // Type let type = dtoParameter.type.uppercasedFirst() - guard - type == "String" || - type == "Int" || - type == "Double" || - type == "Bool" - else { + guard let typeEnum = ParameterType(rawValue: type) else { let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)") print(error.description) Analytics.exit(withError: error) } + + if dtoParameter.value != nil, dtoParameter.replaceIn != nil { + let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)") + print(error.description) + Analytics.exit(withError: error) + } + + verify(value: dtoParameter.value, for: typeEnum) + verify(value: dtoParameter.defaultValue, for: typeEnum) let parameter = AnalyticsParameter( name: dtoParameter.name, - type: type + type: typeEnum, + value: dtoParameter.value ?? "", + defaultValue: dtoParameter.defaultValue ?? "" ) if let replaceIn = dtoParameter.replaceIn { @@ -114,7 +147,7 @@ class AnalyticsFileParser { } if let parameters { - definition.parameters = getParameters(from: parameters) + definition.parameters = AnalyticsFileParser.getParameters(from: parameters) } return definition @@ -140,6 +173,8 @@ class AnalyticsFileParser { Analytics.exit(withError: error) } + definition.path = path + } else if let path = screen.path { definition.path = path } @@ -176,6 +211,14 @@ class AnalyticsFileParser { } definition.action = action + } else { + if let category = event.category { + definition.category = category + } + + if let action = event.action { + definition.action = action + } } return definition