diff --git a/Package.resolved b/Package.resolved index 824db60..c83ac83 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,32 +1,5 @@ { "pins" : [ - { - "identity" : "collectionconcurrencykit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", - "state" : { - "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", - "version" : "0.2.0" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", - "state" : { - "revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0", - "version" : "1.8.2" - } - }, - { - "identity" : "sourcekitten", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jpsim/SourceKitten.git", - "state" : { - "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version" : "0.34.1" - } - }, { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", @@ -37,39 +10,12 @@ } }, { - "identity" : "swift-syntax", + "identity" : "swiftlintplugin", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/lukepistrol/SwiftLintPlugin", "state" : { - "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", - "version" : "509.0.2" - } - }, - { - "identity" : "swiftlint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/realm/SwiftLint.git", - "state" : { - "revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee", - "version" : "0.54.0" - } - }, - { - "identity" : "swiftytexttable", - "kind" : "remoteSourceControl", - "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", - "state" : { - "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", - "version" : "0.9.0" - } - }, - { - "identity" : "swxmlhash", - "kind" : "remoteSourceControl", - "location" : "https://github.com/drmohundro/SWXMLHash.git", - "state" : { - "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", - "version" : "7.0.2" + "revision" : "5a65f4074975f811da666dfe31a19850950b1ea4", + "version" : "0.56.2" } }, { diff --git a/Package.swift b/Package.swift index f9cc54c..ab38332 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"), - .package(url: "https://github.com/realm/SwiftLint.git", .upToNextMajor(from: "0.54.0")), + .package(url: "https://github.com/lukepistrol/SwiftLintPlugin", exact: "0.56.2"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -22,7 +22,9 @@ let package = Package( .product(name: "ArgumentParser", package: "swift-argument-parser"), "Yams" ], - plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] + plugins: [ + .plugin(name: "SwiftLint", package: "SwiftLintPlugin") + ] ), // Helper targets 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 3cd930c..b26a508 100644 --- a/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift +++ b/SampleFiles/Tags/Generated/Analytics+GenAllScript.swift @@ -6,13 +6,20 @@ import FirebaseAnalytics // 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) } // MARK: - Matomo @@ -47,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") @@ -64,8 +74,6 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol { category: String, params: [String: Any]? ) { - guard !tracker.isOptedOut else { return } - tracker.track( eventWithCategory: category, action: action, @@ -74,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 @@ -97,9 +129,16 @@ 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 { @@ -114,10 +153,13 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol { } Analytics.logEvent( - name.replacingOccurrences(of: [" "], with: "_"), + AnalyticsEventSelectContent, parameters: parameters ) } + func setEnable(_ enable: Bool) { + Analytics.setAnalyticsCollectionEnabled(enable) + } } // MARK: - Manager @@ -127,31 +169,57 @@ class AnalyticsManager { // MARK: - Properties - var managers: [AnalyticsManagerProtocol] = [] + var managers: [TargetType: 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) { + managers.forEach { (key, value) in + if analytics.contains(where: { type in + type == key + }) { + value.setEnable(enable) + } + } + } + + func enableAnalytics(_ analytics: [TargetType] = TargetType.allCases) { + setAnalytics(enable: true) + } + + func disableAnalytics(_ analytics: [TargetType] = TargetType.allCases) { + setAnalytics(enable: false) } 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 + ) } } @@ -163,7 +231,7 @@ class AnalyticsManager { ) { guard isEnabled else { return } - managers.forEach { manager in + managers.values.forEach { manager in manager.logEvent( name: name, action: action, @@ -175,31 +243,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 63c1949..44c6e7d 100755 --- a/SampleFiles/genAllRessources.sh +++ b/SampleFiles/genAllRessources.sh @@ -54,10 +54,11 @@ FORCE_FLAG="$1" # 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 02973c6..f20c26e 100644 --- a/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift @@ -59,14 +59,18 @@ class AnalyticsGenerator { \(Self.getImport()) \(Self.getAnalyticsProtocol()) + + \(Self.getTrackerTypeEnum()) + // MARK: - Manager class AnalyticsManager { + static var shared = AnalyticsManager() // MARK: - Properties - var managers: [AnalyticsManagerProtocol] = [] + var managers: [TrackerType: AnalyticsManagerProtocol] = [:] \(Self.getEnabledContent()) @@ -76,14 +80,49 @@ class AnalyticsGenerator { """ } + 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) } """ } @@ -103,11 +142,19 @@ class 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 + ) } } @@ -119,7 +166,7 @@ class AnalyticsGenerator { ) { guard isEnabled else { return } - managers.forEach { manager in + managers.values.forEach { manager in manager.logEvent( name: name, action: action, @@ -144,16 +191,14 @@ class 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 [ @@ -169,13 +214,20 @@ class 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 1957156..796b339 100644 --- a/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/FirebaseGenerator.swift @@ -14,6 +14,7 @@ enum FirebaseGenerator { FirebaseGenerator.header, FirebaseGenerator.logScreen, FirebaseGenerator.logEvent, + FirebaseGenerator.enable, FirebaseGenerator.footer ] .joined(separator: "\n") @@ -31,11 +32,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 @@ -54,9 +75,16 @@ 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 { @@ -71,13 +99,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 740cf95..f6f29ba 100644 --- a/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift +++ b/Sources/ResgenSwift/Analytics/Generator/MatomoGenerator.swift @@ -15,6 +15,7 @@ enum MatomoGenerator { 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 2f350cf..f014543 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift @@ -48,17 +48,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 { @@ -84,7 +90,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))") + } } } } @@ -99,7 +108,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 { @@ -113,14 +133,15 @@ class AnalyticsDefinition { [\(params.joined(separator: ", "))] """ } else { - result = "[:]" + result = "nil" } if type == .screen { return """ logScreen( name: "\(name)", - path: "\(path)" + path: "\(path)", + params: \(result) ) """ } else { @@ -150,7 +171,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 d775768..26b9122 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift @@ -41,5 +41,7 @@ struct AnalyticsDefinitionEventDTO: Codable { 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 9c659c3..048553a 100644 --- a/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift +++ b/Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift @@ -9,13 +9,17 @@ import Foundation class AnalyticsParameter { 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 1137f8e..2d893a7 100644 --- a/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift +++ b/Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift @@ -30,25 +30,58 @@ class AnalyticsFileParser { } private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] { - parameters.map { dtoParameter in + 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 { @@ -103,6 +136,8 @@ class AnalyticsFileParser { Analytics.exit(withError: error) } + definition.path = path + } else if let path = screen.path { definition.path = path } @@ -139,6 +174,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