7 Commits

Author SHA1 Message Date
087280502e Fix Tests
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2025-07-17 10:49:09 +02:00
9f59b53e35 RES-32 Ajouter la possibilité désactiver des traqueurs spécifiques 2025-07-17 10:49:01 +02:00
d05f18321f Fix some error when value and replaceIn 2025-07-17 10:48:02 +02:00
91cc63f942 Add parameter defaultValue and value and add replaceIn parameter in another parameter 2025-07-17 10:48:02 +02:00
187980933e Optional generation of Colors extension
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2025-07-17 09:40:08 +02:00
a64a956254 Optional generation of Colors extension 2025-07-17 09:39:43 +02:00
c3b8ebfb37 Analytics improvement (#9)
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Co-authored-by: Quentin Bandera <q.bandera@openium.fr>
Reviewed-on: #9
Co-authored-by: Loris Perret <l.perret@openium.fr>
Co-committed-by: Loris Perret <l.perret@openium.fr>
2025-07-17 09:15:43 +02:00
17 changed files with 908 additions and 521 deletions

View File

@@ -36,7 +36,7 @@ swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/fonts.txt" \
## Colors
Colors generator generates an extension of `UIColor` (or a custom class) along with colorsets in specified xcassets.
Colors generator generates colorsets in specified xcassets and an extension of `Color` (or a custom class) associated to those colorsets. If the extension name is not specified, no extension will be generated.
```sh
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
@@ -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
@@ -192,13 +192,77 @@ 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

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,5 +1,6 @@
// Generated by ResgenSwift.Analytics 2.1.0
import Foundation
import MatomoTracker
import FirebaseAnalytics
@@ -7,101 +8,41 @@ import FirebaseAnalytics
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]?
)
}
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \(url)")
debugPrint("[Matomo service] Site ID: \(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
func setEnable(_ enable: Bool)
}
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
func logScreen(name: String, path: String) {
// MARK: - Methods
func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
if path.isEmpty == false {
parameters["path"] = path + "/iOS" as NSObject
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category as NSObject,
]
if let supplementaryParameters = params {
for (newKey, newValue) in supplementaryParameters {
if parameters.contains(where: { (key: String, value: NSObject) in
@@ -115,10 +56,57 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
}
Analytics.logEvent(
name.replacingOccurrences(of: [" "], with: "_"),
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String: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
key == newKey
}) {
continue
}
parameters[newKey] = newValue as? NSObject
}
}
Analytics.logEvent(
AnalyticsEventSelectContent,
parameters: parameters
)
}
func setEnable(_ enable: Bool) {
Analytics.setAnalyticsCollectionEnabled(enable)
}
}
// MARK: - Traker Type
enum TrackerType: CaseIterable {
case firebase
}
// MARK: - Manager
@@ -127,33 +115,59 @@ class AnalyticsManager {
static var shared = AnalyticsManager()
private init() {}
// MARK: - Properties
var managers: [AnalyticsManagerProtocol] = []
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
private var isEnabled: Bool = true
// MARK: - Methods
func setAnalyticsEnabled(_ enable: Bool) {
isEnabled = enable
private var isEnabled: Bool {
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
false
} else {
true
}
}
func configure(siteId: String, url: String) {
managers.append(
MatomoAnalyticsManager(
siteId: siteId,
url: url
)
)
managers.append(FirebaseAnalyticsManager())
// 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)
}
}
}
private func logScreen(name: String, path: String) {
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: true, analytics)
}
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
setAnalytics(enable: false, analytics)
}
func configure() {
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
}
// MARK: - Private Log Methods
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 +179,7 @@ class AnalyticsManager {
) {
guard isEnabled else { return }
managers.forEach { manager in
managers.values.forEach { manager in
manager.logEvent(
name: name,
action: action,
@@ -177,31 +191,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) {
func logEventS1DefTwo(
title: String,
count: String,
test2: String = "test"
) {
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
)
}
}

View File

@@ -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:

View File

@@ -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" \
--extension-output-path "./Tags/Generated" \
--extension-name "Analytics" \
--extension-suffix "GenAllScript"
--extension-suffix "GenAllScript" \
--static-members true
echo "\n-------------------------\n"

View File

@@ -90,35 +90,76 @@ enum AnalyticsGenerator {
"""
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
\(getImport(targets: targets))
\(Self.getImport(targets: targets))
\(Self.getAnalyticsProtocol(targets: targets))
\(Self.getTrackerTypeEnum(targets: targets))
\(getAnalyticsProtocol(targets: targets))
// MARK: - Manager
class AnalyticsManager {
static var shared = AnalyticsManager()
private init() {}
// MARK: - Properties
var managers: [AnalyticsManagerProtocol] = []
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
\(getEnabledContent())
\(Self.getEnabledContent())
\(getAnalyticsProperties(targets: targets))
\(Self.getAnalyticsProperties(targets: targets))
\(getPrivateLogFunction())
\(Self.getPrivateLogFunction())
"""
}
private static func getTrackerTypeEnum(targets: [TrackerType]) -> String {
var result: [String] = []
targets.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
// MARK: - Enable 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 +167,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 +181,21 @@ enum AnalyticsGenerator {
private static func getPrivateLogFunction() -> String {
"""
private func logScreen(name: String, path: String) {
// MARK: - Private Log Methods
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
)
}
}
@@ -154,7 +207,7 @@ enum AnalyticsGenerator {
) {
guard isEnabled else { return }
managers.forEach { manager in
managers.values.forEach { manager in
manager.logEvent(
name: name,
action: action,
@@ -179,16 +232,14 @@ enum AnalyticsGenerator {
if targets.contains(TrackerType.matomo) {
content.append("""
managers.append(
MatomoAnalyticsManager(
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 [
@@ -205,15 +256,21 @@ enum AnalyticsGenerator {
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)
}
"""
var result: [String] = [proto]
@@ -226,7 +283,7 @@ enum AnalyticsGenerator {
result.append(FirebaseGenerator.service)
}
return result.joined(separator: "\n")
return result.joined(separator: "\n\n")
}
private static func getProperties(

View File

@@ -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")
}
@@ -28,16 +29,39 @@ enum FirebaseGenerator {
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Methods
"""
}
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 +80,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,17 +104,25 @@ 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 {
"""
}
"""
}
}

View File

@@ -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,13 +100,21 @@ enum MatomoGenerator {
url: nil
)
}
"""
}
private static var enable: String {
"""
func setEnable(_ enable: Bool) {
tracker.isOptedOut = !enable
}
"""
}
private static var footer: String {
"""
}
"""
}
}

View File

@@ -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
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())
}
"""
}

View File

@@ -46,5 +46,7 @@ struct AnalyticsParameterDTO: Codable {
var name: String
var type: String
var value: String?
var defaultValue: String?
var replaceIn: String?
}

View File

@@ -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
}
}

View File

@@ -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"
}

View File

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

View File

@@ -21,8 +21,6 @@ struct Colors: ParsableCommand {
// MARK: - Static
static let toolName = "Color"
static let defaultExtensionName = "Color"
static let defaultExtensionNameUIKit = "UIColor"
static let assetsColorsFolderName = "Colors"
// MARK: - Command options
@@ -57,22 +55,28 @@ struct Colors: ParsableCommand {
// -> Time: 3.4505380392074585 seconds
// Generate extension
if let extensionName = options.extensionName,
let extensionFilePath = options.extensionFilePath {
ColorExtensionGenerator.writeExtensionFile(
colors: parsedColors,
staticVar: options.staticMembers,
extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath,
extensionName: extensionName,
extensionFilePath: extensionFilePath,
isSwiftUI: true
)
}
// Generate extension
if let extensionNameUIKit = options.extensionNameUIKit,
let extensionFilePathUIKit = options.extensionFilePathUIKit {
ColorExtensionGenerator.writeExtensionFile(
colors: parsedColors,
staticVar: options.staticMembers,
extensionName: options.extensionNameUIKit,
extensionFilePath: options.extensionFilePathUIKit,
extensionName: extensionNameUIKit,
extensionFilePath: extensionFilePathUIKit,
isSwiftUI: false
)
}
print("[\(Self.toolName)] Colors generated")
}
@@ -96,18 +100,29 @@ struct Colors: ParsableCommand {
Self.exit(withError: error)
}
// Extension for UIKit and SwiftUI should have different name
guard options.extensionName != options.extensionNameUIKit else {
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
// Extension for UIKit and SwiftUI should have different name (if both are defined)
if let extensionName = options.extensionName,
let extensionNameUIKit = options.extensionNameUIKit {
guard extensionName != extensionNameUIKit else {
let error = ColorsToolError.extensionNamesCollision(extensionName)
print(error.description)
Self.exit(withError: error)
}
}
// Check if needed to regenerate
let fileToCompareToInput: String = {
// If there is no extension file to compare
// Then check the xcassets file instead
if let extensionFilePath = options.extensionFilePath {
return extensionFilePath
}
return options.xcassetsPath
}()
guard GeneratorChecker.shouldGenerate(
force: options.forceGeneration,
inputFilePath: options.inputFile,
extensionFilePath: options.extensionFilePath
extensionFilePath: fileToCompareToInput
) else {
print("[\(Self.toolName)] Colors are already up to date :) ")
return false

View File

@@ -30,11 +30,11 @@ struct ColorsToolOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate an Color extension.")
var extensionName: String = Colors.defaultExtensionName
@Option(help: "Extension name. If not specified, no extension will be generated.")
var extensionName: String?
@Option(help: "SwiftUI Extension name. If not specified, it will generate an UIColor extension.")
var extensionNameUIKit: String = Colors.defaultExtensionNameUIKit
@Option(help: "SwiftUI Extension name. If not specified, no extension will be generated.")
var extensionNameUIKit: String?
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
var extensionSuffix: String?
@@ -46,27 +46,35 @@ extension ColorsToolOptions {
// MARK: - SwiftUI
var extensionFileName: String {
var extensionFileName: String? {
guard let extensionName else { return nil }
if let extensionSuffix {
return "\(extensionName)+\(extensionSuffix).swift"
}
return "\(extensionName).swift"
}
var extensionFilePath: String {
"\(extensionOutputPath)/\(extensionFileName)"
var extensionFilePath: String? {
guard let extensionFileName else { return nil }
return "\(extensionOutputPath)/\(extensionFileName)"
}
// MARK: - UIKit
var extensionFileNameUIKit: String {
var extensionFileNameUIKit: String? {
guard let extensionNameUIKit else { return nil }
if let extensionSuffix {
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
}
return "\(extensionNameUIKit).swift"
}
var extensionFilePathUIKit: String {
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
var extensionFilePathUIKit: String? {
guard let extensionFileNameUIKit else { return nil }
return "\(extensionOutputPath)/\(extensionFileNameUIKit)"
}
}

View File

@@ -62,7 +62,8 @@ final class AnalyticsDefinitionTests: XCTestCase {
func logScreenDefinitionName() {
logScreen(
name: "Ecran un",
path: "ecran_un/"
path: "ecran_un/",
params: nil
)
}
"""
@@ -84,7 +85,7 @@ final class AnalyticsDefinitionTests: XCTestCase {
name: "Ecran un",
action: "",
category: "",
params: [:]
params: nil
)
}
"""
@@ -103,9 +104,10 @@ final class AnalyticsDefinitionTests: XCTestCase {
// Expect
let expectScreen = """
static func logScreenDefinitionName() {
logScreen(
AnalyticsManager.shared.logScreen(
name: "Ecran un",
path: "ecran_un/"
path: "ecran_un/",
params: nil
)
}
"""
@@ -123,11 +125,11 @@ final class AnalyticsDefinitionTests: XCTestCase {
// Expect
let expectEvent = """
static func logEventDefinitionName() {
logEvent(
AnalyticsManager.shared.logEvent(
name: "Ecran un",
action: "",
category: "",
params: [:]
params: nil
)
}
"""

View File

@@ -32,6 +32,182 @@ final class AnalyticsGeneratorTests: XCTestCase {
return definition
}
private func protocolString() -> String {
"""
// MARK: - Protocol
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)
}
"""
}
private func firebaseString() -> String {
"""
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Methods
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
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String: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
key == newKey
}) {
continue
}
parameters[newKey] = newValue as? NSObject
}
}
Analytics.logEvent(
AnalyticsEventSelectContent,
parameters: parameters
)
}
func setEnable(_ enable: Bool) {
Analytics.setAnalyticsCollectionEnabled(enable)
}
}
"""
}
private func matomoString() -> String {
"""
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(
name: String,
path: String,
params: [String: Any]?
) {
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
func setEnable(_ enable: Bool) {
tracker.isOptedOut = !enable
}
}
"""
}
func testGeneratedExtensionContentFirebase() {
// Given
let sectionOne = AnalyticsCategory(id: "section_one")
@@ -65,64 +241,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import FirebaseAnalytics
// MARK: - Protocol
\(protocolString())
protocol AnalyticsManagerProtocol {
\(firebaseString())
func logScreen(name: String, path: String)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Traker Type
// MARK: - Firebase
enum TrackerType: CaseIterable {
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
case firebase
}
// MARK: - Manager
@@ -131,27 +261,59 @@ final class AnalyticsGeneratorTests: XCTestCase {
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
// MARK: - Enable 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() {
managers.append(FirebaseAnalyticsManager())
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
}
private func logScreen(name: String, path: String) {
// MARK: - Private Log Methods
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 +325,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) {
guard isEnabled else { return }
managers.forEach { manager in
managers.values.forEach { manager in
manager.logEvent(
name: name,
action: action,
@@ -178,7 +340,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() {
logScreen(
name: "s1 def one",
path: ""
path: "",
params: nil
)
}
@@ -187,7 +350,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two",
action: "",
category: "",
params: [:]
params: nil
)
}
@@ -196,7 +359,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() {
logScreen(
name: "s2 def one",
path: ""
path: "",
params: nil
)
}
}
@@ -241,80 +405,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import MatomoTracker
// MARK: - Protocol
\(protocolString())
protocol AnalyticsManagerProtocol {
\(matomoString())
func logScreen(name: String, path: String)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Traker Type
// MARK: - Matomo
enum TrackerType: CaseIterable {
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
case matomo
}
// MARK: - Manager
@@ -323,32 +425,62 @@ final class AnalyticsGeneratorTests: XCTestCase {
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
// MARK: - Enable 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(
managers[TrackerType.matomo] = MatomoAnalyticsManager(
siteId: siteId,
url: url
)
)
}
private func logScreen(name: String, path: String) {
// MARK: - Private Log Methods
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
)
}
}
@@ -360,7 +492,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) {
guard isEnabled else { return }
managers.forEach { manager in
managers.values.forEach { manager in
manager.logEvent(
name: name,
action: action,
@@ -375,7 +507,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() {
logScreen(
name: "s1 def one",
path: "s1_def_one/"
path: "s1_def_one/",
params: nil
)
}
@@ -384,7 +517,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two",
action: "test",
category: "test",
params: [:]
params: nil
)
}
@@ -393,7 +526,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() {
logScreen(
name: "s2 def one",
path: "s2_def_one/"
path: "s2_def_one/",
params: nil
)
}
}
@@ -439,125 +573,22 @@ final class AnalyticsGeneratorTests: XCTestCase {
let expect = """
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
import Foundation
import MatomoTracker
import FirebaseAnalytics
// MARK: - Protocol
\(protocolString())
protocol AnalyticsManagerProtocol {
\(matomoString())
func logScreen(name: String, path: String)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
\(firebaseString())
// MARK: - Matomo
// MARK: - Traker Type
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
enum TrackerType: CaseIterable {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
}
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
case matomo
case firebase
}
// MARK: - Manager
@@ -566,33 +597,63 @@ final class AnalyticsGeneratorTests: XCTestCase {
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
// MARK: - Enable 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(
managers[TrackerType.matomo] = MatomoAnalyticsManager(
siteId: siteId,
url: url
)
)
managers.append(FirebaseAnalyticsManager())
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
}
private func logScreen(name: String, path: String) {
// MARK: - Private Log Methods
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
)
}
}
@@ -604,7 +665,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
) {
guard isEnabled else { return }
managers.forEach { manager in
managers.values.forEach { manager in
manager.logEvent(
name: name,
action: action,
@@ -619,7 +680,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS1DefOne() {
logScreen(
name: "s1 def one",
path: "s1_def_one/"
path: "s1_def_one/",
params: nil
)
}
@@ -628,7 +690,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
name: "s1 def two",
action: "test",
category: "test",
params: [:]
params: nil
)
}
@@ -637,7 +699,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
func logScreenS2DefOne() {
logScreen(
name: "s2 def one",
path: "s2_def_one/"
path: "s2_def_one/",
params: nil
)
}
}