Optional generation of extension (R.xx)
Optional generation of Colors/Fonts/Images/Stringium extension Fix swiftlint warning
This commit is contained in:
14
README.md
14
README.md
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
ResgenSwift is a package, fully written in Swift, to help you automatize ressource update and generation.
|
ResgenSwift is a package, fully written in Swift, to help you automatize ressource update and generation.
|
||||||
|
|
||||||
> 🧐 For all commands, see samples files in `SampleFiles`
|
> 🧐 For all commands, see samples files in `SampleFiles` and use `resgen-swift help` and `resgen-swift help <subcommand>` for detailed help.
|
||||||
|
|
||||||
## Fonts
|
## Fonts
|
||||||
|
|
||||||
Font generator generates an extension of `UIFont` and `Font` (or custom classes). It also prints content of `UIAppFonts` from your project `.plist`. If project `.plist` is specified, it will update `UIAppFonts` content of all `.plist`.
|
Font generator generates an extension of `UIFont` and `Font` (or custom classes). It also prints content of `UIAppFonts` from your project `.plist`. If project `.plist` is specified, it will update `UIAppFonts` content of all `.plist`.
|
||||||
|
|
||||||
iOS required to use the **real name** of the font, this name can be different from its filename. To get the **real name**, it uses `fc-scan`. So, be sure that the `$PATH` contains path of `fc-scan`.
|
iOS required to use the **real name** of the font, this name can be different from its filename. To get the **real name**, it uses `fc-scan`. So, be sure that your `$PATH` variable contains path of `fc-scan`.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/fonts.txt" \
|
|||||||
|
|
||||||
## Colors
|
## 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
|
```sh
|
||||||
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
|
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
|
||||||
@ -54,12 +54,13 @@ swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
|
|||||||
1. `-f`: force generation
|
1. `-f`: force generation
|
||||||
2. Input colors file
|
2. Input colors file
|
||||||
3. `--style` can be `all` or `light`
|
3. `--style` can be `all` or `light`
|
||||||
4. `--extension-output-path`: path where to generate generated extension
|
4. `--extension-output-path` *(optional)* : path where to generate generated extension
|
||||||
5. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
|
5. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
|
||||||
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
|
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
|
||||||
7. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppColor+GreatApp.swift`)
|
7. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppColor+GreatApp.swift`)
|
||||||
8. `--static-members` *(optional)*: generate static properties or not
|
8. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
|
> ⚠️ Passing a `extensionOutputPath` without any `extensionName` does not generate extension. **But** passing an `extensionName` without `extensionOutputPath` will result in a error.
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
|
|
||||||
@ -266,7 +267,7 @@ events:
|
|||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
Images generator will generate images assets along with extensions to access those images easily.
|
Images generator will generate images assets along with extensions to access those images easily. If the extension name is not specified, no extension will be generated.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
||||||
@ -283,12 +284,13 @@ swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
|||||||
1. `-f`: force generation
|
1. `-f`: force generation
|
||||||
2. Input images definitions file
|
2. Input images definitions file
|
||||||
3. `--xcassets-path`: xcasset path where to generate imagesets
|
3. `--xcassets-path`: xcasset path where to generate imagesets
|
||||||
4. `--extension-output-path`: path where to generate generated extension
|
4. `--extension-output-path` *(optional)* : path where to generate generated extension
|
||||||
5. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
|
5. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
|
||||||
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
|
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
|
||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
|
> ⚠️ Passing a `extensionOutputPath` without any `extensionName` does not generate extension. **But** passing an `extensionName` without `extensionOutputPath` will result in a error.
|
||||||
> ⚠️ Svg images will be copied in the assets and rendered as "Original", however if those images are not rendered correctly you can force the png generation by adding the key word "png" like this: id arrow_back 15 ? png
|
> ⚠️ Svg images will be copied in the assets and rendered as "Original", however if those images are not rendered correctly you can force the png generation by adding the key word "png" like this: id arrow_back 15 ? png
|
||||||
|
|
||||||
## All at once
|
## All at once
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Generated by ResgenSwift.Color 1.2
|
// Generated by ResgenSwift.Color 2.1.0
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
150
SampleFiles/Strings/Generated/sampleStrings.xcstrings
Normal file
150
SampleFiles/Strings/Generated/sampleStrings.xcstrings
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
{
|
||||||
|
"sourceLanguage" : "en",
|
||||||
|
"strings" : {
|
||||||
|
"generic_back" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Back"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Back"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Retour"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generic_loading_data" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Loading data..."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Loading data..."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Chargement des données..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generic_welcome_firstname_format" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Welcome \\\"%@\\\" !"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Welcome \\\"%@\\\" !"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Bienvenue \\\"%@\\\" !"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"param_lang" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "en"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "en-us"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "fr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"placeholders_test_one" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "You %%: %2$@ %1$@ Age: %3$d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "You %%: %2$@ %1$@ Age: %3$d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Vous %%: %1$@ %2$@ Age: %3$d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test_equal_symbol" : {
|
||||||
|
"comment" : "",
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "1€ = 1 point !"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-us" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "1€ = 1 point !"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "1€ = 1 point !"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version" : "1.0"
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
// Generated by ResgenSwift.Analytics 2.1.0
|
// Generated by ResgenSwift.Analytics 2.1.0
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@ -22,75 +24,12 @@ protocol AnalyticsManagerProtocol {
|
|||||||
func setEnable(_ enable: Bool)
|
func setEnable(_ enable: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@ -157,16 +96,16 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setEnable(_ enable: Bool) {
|
func setEnable(_ enable: Bool) {
|
||||||
Analytics.setAnalyticsCollectionEnabled(enable)
|
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Traker Type
|
// MARK: - Traker Type
|
||||||
|
|
||||||
enum TrackerType: CaseIterable {
|
enum TrackerType: CaseIterable {
|
||||||
case matomo
|
|
||||||
case firebase
|
case firebase
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +129,7 @@ class AnalyticsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
managers.forEach { (key, value) in
|
managers.forEach { (key, value) in
|
||||||
@ -210,14 +149,12 @@ class AnalyticsManager {
|
|||||||
setAnalytics(enable: false, analytics)
|
setAnalytics(enable: false, analytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configure(siteId: String, url: String) {
|
func configure() {
|
||||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
|
||||||
siteId: siteId,
|
|
||||||
url: url
|
|
||||||
)
|
|
||||||
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
private func logScreen(
|
private func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@ -262,12 +199,12 @@ class AnalyticsManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func logEventS1DefTwo(
|
func logEventS1DefTwo(
|
||||||
title: String,
|
title: String,
|
||||||
count: String,
|
count: String,
|
||||||
test2: String = "test"
|
test2: String = "test"
|
||||||
) {
|
) {
|
||||||
AnalyticsManager.shared.logEvent(
|
logEvent(
|
||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
|
@ -54,7 +54,7 @@ echo "\n-------------------------\n"
|
|||||||
|
|
||||||
# Analytics
|
# Analytics
|
||||||
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
||||||
--target "firebase matomo" \
|
--target "firebase" \
|
||||||
--extension-output-path "./Tags/Generated" \
|
--extension-output-path "./Tags/Generated" \
|
||||||
--extension-name "Analytics" \
|
--extension-name "Analytics" \
|
||||||
--extension-suffix "GenAllScript" \
|
--extension-suffix "GenAllScript" \
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
// Created by Loris Perret on 08/12/2023.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// CPD-OFF
|
||||||
|
|
||||||
import CoreVideo
|
import CoreVideo
|
||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
// Disabled cause it's a pain to handle in generated string
|
// Disabled cause it's a pain to handle in generated string
|
||||||
|
// swiftlint:disable type_body_length
|
||||||
|
|
||||||
enum AnalyticsGenerator {
|
enum AnalyticsGenerator {
|
||||||
|
|
||||||
@ -94,7 +97,7 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
\(Self.getAnalyticsProtocol(targets: targets))
|
\(Self.getAnalyticsProtocol(targets: targets))
|
||||||
|
|
||||||
\(Self.getTrackerTypeEnum())
|
\(Self.getTrackerTypeEnum(targets: targets))
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
@ -116,9 +119,9 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getTrackerTypeEnum() -> String {
|
private static func getTrackerTypeEnum(targets: [TrackerType]) -> String {
|
||||||
var result: [String] = []
|
var result: [String] = []
|
||||||
TrackerType.allCases.forEach { type in
|
targets.forEach { type in
|
||||||
result.append(" case \(type)")
|
result.append(" case \(type)")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +129,7 @@ enum AnalyticsGenerator {
|
|||||||
// MARK: - Traker Type
|
// MARK: - Traker Type
|
||||||
|
|
||||||
enum TrackerType: CaseIterable {
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
\(result.joined(separator: "\n"))
|
\(result.joined(separator: "\n"))
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -141,7 +145,7 @@ enum AnalyticsGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
managers.forEach { (key, value) in
|
managers.forEach { (key, value) in
|
||||||
@ -171,6 +175,7 @@ enum AnalyticsGenerator {
|
|||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
result.append("import MatomoTracker")
|
result.append("import MatomoTracker")
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
result.append("import FirebaseAnalytics")
|
result.append("import FirebaseAnalytics")
|
||||||
}
|
}
|
||||||
@ -180,6 +185,8 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
private static func getPrivateLogFunction() -> String {
|
private static func getPrivateLogFunction() -> String {
|
||||||
"""
|
"""
|
||||||
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
private func logScreen(
|
private func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@ -235,6 +242,7 @@ enum AnalyticsGenerator {
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||||||
}
|
}
|
||||||
@ -252,6 +260,7 @@ enum AnalyticsGenerator {
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@ -267,7 +276,6 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
func setEnable(_ enable: Bool)
|
func setEnable(_ enable: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var result: [String] = [proto]
|
var result: [String] = [proto]
|
||||||
@ -280,7 +288,7 @@ enum AnalyticsGenerator {
|
|||||||
result.append(FirebaseGenerator.service)
|
result.append(FirebaseGenerator.service)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.joined(separator: "\n")
|
return result.joined(separator: "\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(
|
private static func getProperties(
|
||||||
@ -319,3 +327,5 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CPD-ON
|
||||||
|
@ -13,11 +13,11 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
FirebaseGenerator.header,
|
Self.header,
|
||||||
FirebaseGenerator.logScreen,
|
Self.logScreen,
|
||||||
FirebaseGenerator.logEvent,
|
Self.logEvent,
|
||||||
FirebaseGenerator.enable,
|
Self.enable,
|
||||||
FirebaseGenerator.footer
|
Self.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@ -29,6 +29,9 @@ enum FirebaseGenerator {
|
|||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +108,7 @@ enum FirebaseGenerator {
|
|||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +123,6 @@ enum FirebaseGenerator {
|
|||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,20 @@
|
|||||||
// Created by Loris Perret on 05/12/2023.
|
// Created by Loris Perret on 05/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// CPD-OFF
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum MatomoGenerator {
|
enum MatomoGenerator {
|
||||||
|
|
||||||
static var service: String {
|
static var service: String {
|
||||||
[
|
[
|
||||||
MatomoGenerator.header,
|
Self.header,
|
||||||
MatomoGenerator.setup,
|
Self.setup,
|
||||||
MatomoGenerator.logScreen,
|
Self.logScreen,
|
||||||
MatomoGenerator.logEvent,
|
Self.logEvent,
|
||||||
MatomoGenerator.enable,
|
Self.enable,
|
||||||
MatomoGenerator.footer
|
Self.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
@ -115,7 +117,8 @@ enum MatomoGenerator {
|
|||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CPD-ON
|
||||||
|
@ -60,8 +60,10 @@ class AnalyticsDefinition {
|
|||||||
switch parameter.type {
|
switch parameter.type {
|
||||||
case .bool:
|
case .bool:
|
||||||
defaultValue = "\(parameter.defaultValue.lowercased())"
|
defaultValue = "\(parameter.defaultValue.lowercased())"
|
||||||
|
|
||||||
case .int, .double:
|
case .int, .double:
|
||||||
defaultValue = "\(parameter.defaultValue)"
|
defaultValue = "\(parameter.defaultValue)"
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
defaultValue = "\"\(parameter.defaultValue)\""
|
defaultValue = "\"\(parameter.defaultValue)\""
|
||||||
}
|
}
|
||||||
@ -90,9 +92,13 @@ class AnalyticsDefinition {
|
|||||||
for rep in parameter.replaceIn {
|
for rep in parameter.replaceIn {
|
||||||
switch rep {
|
switch rep {
|
||||||
case "name": name = name.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "name": name = name.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
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 "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
|
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))")
|
param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
@ -117,8 +123,10 @@ class AnalyticsDefinition {
|
|||||||
switch param.type {
|
switch param.type {
|
||||||
case .bool:
|
case .bool:
|
||||||
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
||||||
|
|
||||||
case .int, .double:
|
case .int, .double:
|
||||||
params.append("\"\(param.name)\": \(param.value)")
|
params.append("\"\(param.name)\": \(param.value)")
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
params.append("\"\(param.name)\": \"\(param.value)\"")
|
params.append("\"\(param.name)\": \"\(param.value)\"")
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum ParameterType: String {
|
enum ParameterType: String {
|
||||||
|
|
||||||
case string = "String"
|
case string = "String"
|
||||||
case int = "Int"
|
case int = "Int"
|
||||||
case double = "Double"
|
case double = "Double"
|
||||||
|
@ -78,18 +78,21 @@ class AnalyticsFileParser {
|
|||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .bool:
|
case .bool:
|
||||||
if Bool(value.lowercased()) == nil {
|
if Bool(value.lowercased()) == nil {
|
||||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .double:
|
case .double:
|
||||||
if Double(value) == nil {
|
if Double(value) == nil {
|
||||||
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .string:
|
case .string:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -147,7 +150,7 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let parameters {
|
if let parameters {
|
||||||
definition.parameters = AnalyticsFileParser.getParameters(from: parameters)
|
definition.parameters = Self.getParameters(from: parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
|
@ -21,8 +21,6 @@ struct Colors: ParsableCommand {
|
|||||||
// MARK: - Static
|
// MARK: - Static
|
||||||
|
|
||||||
static let toolName = "Color"
|
static let toolName = "Color"
|
||||||
static let defaultExtensionName = "Color"
|
|
||||||
static let defaultExtensionNameUIKit = "UIColor"
|
|
||||||
static let assetsColorsFolderName = "Colors"
|
static let assetsColorsFolderName = "Colors"
|
||||||
|
|
||||||
// MARK: - Command options
|
// MARK: - Command options
|
||||||
@ -57,22 +55,28 @@ struct Colors: ParsableCommand {
|
|||||||
// -> Time: 3.4505380392074585 seconds
|
// -> Time: 3.4505380392074585 seconds
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
|
if let extensionName = options.extensionName,
|
||||||
|
let extensionFilePath = options.extensionFilePath {
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
ColorExtensionGenerator.writeExtensionFile(
|
||||||
colors: parsedColors,
|
colors: parsedColors,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
extensionName: options.extensionName,
|
extensionName: extensionName,
|
||||||
extensionFilePath: options.extensionFilePath,
|
extensionFilePath: extensionFilePath,
|
||||||
isSwiftUI: true
|
isSwiftUI: true
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
|
if let extensionNameUIKit = options.extensionNameUIKit,
|
||||||
|
let extensionFilePathUIKit = options.extensionFilePathUIKit {
|
||||||
ColorExtensionGenerator.writeExtensionFile(
|
ColorExtensionGenerator.writeExtensionFile(
|
||||||
colors: parsedColors,
|
colors: parsedColors,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionName: extensionNameUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
extensionFilePath: extensionFilePathUIKit,
|
||||||
isSwiftUI: false
|
isSwiftUI: false
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
print("[\(Self.toolName)] Colors generated")
|
print("[\(Self.toolName)] Colors generated")
|
||||||
}
|
}
|
||||||
@ -96,18 +100,40 @@ struct Colors: ParsableCommand {
|
|||||||
Self.exit(withError: error)
|
Self.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name (if both are defined)
|
||||||
guard options.extensionName != options.extensionNameUIKit else {
|
if let extensionName = options.extensionName,
|
||||||
let error = ColorsToolError.extensionNamesCollision(options.extensionName)
|
let extensionNameUIKit = options.extensionNameUIKit {
|
||||||
|
guard extensionName != extensionNameUIKit else {
|
||||||
|
let error = ColorsToolError.extensionNamesCollision(extensionName)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Self.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an extension need to be generated, ensure extensionOutputPath is defined
|
||||||
|
if options.extensionName != nil ||
|
||||||
|
options.extensionNameUIKit != nil {
|
||||||
|
guard let extensionOutputPath = options.extensionOutputPath,
|
||||||
|
extensionOutputPath.isEmpty == false else {
|
||||||
|
let error = ColorsToolError.missingExtensionPath
|
||||||
|
print(error.description)
|
||||||
|
Self.exit(withError: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// 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(
|
guard GeneratorChecker.shouldGenerate(
|
||||||
force: options.forceGeneration,
|
force: options.forceGeneration,
|
||||||
inputFilePath: options.inputFile,
|
inputFilePath: options.inputFile,
|
||||||
extensionFilePath: options.extensionFilePath
|
extensionFilePath: fileToCompareToInput
|
||||||
) else {
|
) else {
|
||||||
print("[\(Self.toolName)] Colors are already up to date :) ")
|
print("[\(Self.toolName)] Colors are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
|
@ -17,11 +17,12 @@ enum ColorsToolError: Error {
|
|||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case badColorDefinition(String, String)
|
case badColorDefinition(String, String)
|
||||||
case deleteExistingColors(String)
|
case deleteExistingColors(String)
|
||||||
|
case missingExtensionPath
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .extensionNamesCollision(let extensionName):
|
case .extensionNamesCollision(let extensionName):
|
||||||
return "error: [\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
return "error: [\(Colors.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
||||||
|
|
||||||
case .badFormat(let info):
|
case .badFormat(let info):
|
||||||
return "error: [\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
|
return "error: [\(Colors.toolName)] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
|
||||||
@ -43,6 +44,9 @@ enum ColorsToolError: Error {
|
|||||||
|
|
||||||
case .deleteExistingColors(let assetsFolder):
|
case .deleteExistingColors(let assetsFolder):
|
||||||
return "error: [\(Colors.toolName)] An error occured while deleting colors folder `\(assetsFolder)`"
|
return "error: [\(Colors.toolName)] An error occured while deleting colors folder `\(assetsFolder)`"
|
||||||
|
|
||||||
|
case .missingExtensionPath:
|
||||||
|
return "error: [\(Colors.toolName)] Extension need to be generated but no `extensionOutputPath` is provided"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,17 +24,17 @@ struct ColorsToolOptions: ParsableArguments {
|
|||||||
@Option(help: "Path of xcassets where to generate colors", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Option(help: "Path of xcassets where to generate colors", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var xcassetsPath: String
|
var xcassetsPath: String
|
||||||
|
|
||||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
|
||||||
var extensionOutputPath: String
|
|
||||||
|
|
||||||
@Option(help: "Tell if it will generate static properties or not")
|
@Option(help: "Tell if it will generate static properties or not")
|
||||||
var staticMembers: Bool = false
|
var staticMembers: Bool = false
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an Color extension.")
|
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var extensionName: String = Colors.defaultExtensionName
|
var extensionOutputPath: String?
|
||||||
|
|
||||||
@Option(help: "SwiftUI Extension name. If not specified, it will generate an UIColor extension.")
|
@Option(help: "SwiftUI extension name. If not specified, no extension will be generated.")
|
||||||
var extensionNameUIKit: String = Colors.defaultExtensionNameUIKit
|
var extensionName: String?
|
||||||
|
|
||||||
|
@Option(help: "UIKit 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")
|
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
|
||||||
var extensionSuffix: String?
|
var extensionSuffix: String?
|
||||||
@ -46,27 +46,35 @@ extension ColorsToolOptions {
|
|||||||
|
|
||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String? {
|
||||||
|
guard let extensionName else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePath: String {
|
var extensionFilePath: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileName)"
|
guard let extensionOutputPath, let extensionFileName else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileName)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String? {
|
||||||
|
guard let extensionNameUIKit else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePathUIKit: String {
|
var extensionFilePathUIKit: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
guard let extensionOutputPath, let extensionFileNameUIKit else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,20 +18,20 @@ struct FontsOptions: ParsableArguments {
|
|||||||
@Argument(help: "Input files where fonts ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Argument(help: "Input files where fonts ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var inputFile: String
|
var inputFile: String
|
||||||
|
|
||||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
|
||||||
var extensionOutputPath: String
|
|
||||||
|
|
||||||
@Option(help: "Tell if it will generate static properties or methods")
|
@Option(help: "Tell if it will generate static properties or methods")
|
||||||
var staticMembers: Bool = false
|
var staticMembers: Bool = false
|
||||||
|
|
||||||
|
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
|
var extensionOutputPath: String
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an Font extension.")
|
@Option(help: "Extension name. If not specified, it will generate an Font extension.")
|
||||||
var extensionName: String = Fonts.defaultExtensionName
|
var extensionName: String = Fonts.defaultExtensionName
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an UIFont extension.")
|
@Option(help: "Extension name. If not specified, no extension will be generated.")
|
||||||
var extensionNameUIKit: String = Fonts.defaultExtensionNameUIKit
|
var extensionNameUIKit: String?
|
||||||
|
|
||||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift")
|
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift")
|
||||||
var extensionSuffix: String = ""
|
var extensionSuffix: String?
|
||||||
|
|
||||||
@Option(name: .customLong("info-plist-paths"), help: "Info.plist paths (array). Will be used to update UIAppFonts content")
|
@Option(name: .customLong("info-plist-paths"), help: "Info.plist paths (array). Will be used to update UIAppFonts content")
|
||||||
fileprivate var infoPlistPathsRaw: String = ""
|
fileprivate var infoPlistPathsRaw: String = ""
|
||||||
@ -44,7 +44,7 @@ extension FontsOptions {
|
|||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if extensionSuffix.isEmpty == false {
|
if let extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
@ -56,15 +56,19 @@ extension FontsOptions {
|
|||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String? {
|
||||||
if extensionSuffix.isEmpty == false {
|
guard let extensionNameUIKit else { return nil }
|
||||||
|
|
||||||
|
if let extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePathUIKit: String {
|
var extensionFilePathUIKit: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
guard let extensionFileNameUIKit else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
@ -22,7 +22,6 @@ struct Fonts: ParsableCommand {
|
|||||||
|
|
||||||
static let toolName = "Fonts"
|
static let toolName = "Fonts"
|
||||||
static let defaultExtensionName = "Font"
|
static let defaultExtensionName = "Font"
|
||||||
static let defaultExtensionNameUIKit = "UIFont"
|
|
||||||
|
|
||||||
// MARK: - Command Options
|
// MARK: - Command Options
|
||||||
|
|
||||||
@ -61,16 +60,25 @@ struct Fonts: ParsableCommand {
|
|||||||
isSwiftUI: true
|
isSwiftUI: true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if let extensionNameUIKit = options.extensionNameUIKit,
|
||||||
|
let extensionFilePathUIKit = options.extensionFilePathUIKit {
|
||||||
FontExtensionGenerator.writeExtensionFile(
|
FontExtensionGenerator.writeExtensionFile(
|
||||||
fontsNames: fontsNames,
|
fontsNames: fontsNames,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionName: extensionNameUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
extensionFilePath: extensionFilePathUIKit,
|
||||||
isSwiftUI: false
|
isSwiftUI: false
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.infoPlistPaths.isEmpty == false {
|
||||||
|
let plistUpdateFontsData = FontPlistGenerator.generatePlistUIAppsFontContent(
|
||||||
|
for: fontsNames,
|
||||||
|
infoPlistPaths: options.infoPlistPaths
|
||||||
|
)
|
||||||
print("Info.plist has been updated with:")
|
print("Info.plist has been updated with:")
|
||||||
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames, infoPlistPaths: options.infoPlistPaths))")
|
print(plistUpdateFontsData)
|
||||||
|
}
|
||||||
|
|
||||||
print("[\(Self.toolName)] Fonts generated")
|
print("[\(Self.toolName)] Fonts generated")
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ enum FontsToolError: Error {
|
|||||||
case inputFolderNotFound(String)
|
case inputFolderNotFound(String)
|
||||||
case fileNotExists(String)
|
case fileNotExists(String)
|
||||||
case writeExtension(String, String)
|
case writeExtension(String, String)
|
||||||
|
case missingExtensionPath
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
@ -31,6 +32,9 @@ enum FontsToolError: Error {
|
|||||||
|
|
||||||
case let .writeExtension(filename, info):
|
case let .writeExtension(filename, info):
|
||||||
return "error: [\(Fonts.toolName)] An error occured while writing extension in \(filename): \(info)"
|
return "error: [\(Fonts.toolName)] An error occured while writing extension in \(filename): \(info)"
|
||||||
|
|
||||||
|
case .missingExtensionPath:
|
||||||
|
return "error: [\(Fonts.toolName)] Extension need to be generated but no `extensionOutputPath` is provided"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
let inputFile: String
|
let inputFile: String
|
||||||
let style: String
|
let style: String
|
||||||
let xcassetsPath: String
|
let xcassetsPath: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String?
|
||||||
let extensionName: String?
|
let extensionName: String?
|
||||||
let extensionNameUIKit: String?
|
let extensionNameUIKit: String?
|
||||||
let extensionSuffix: String?
|
let extensionSuffix: String?
|
||||||
@ -148,7 +148,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
inputFile: String,
|
inputFile: String,
|
||||||
style: String,
|
style: String,
|
||||||
xcassetsPath: String,
|
xcassetsPath: String,
|
||||||
extensionOutputPath: String,
|
extensionOutputPath: String?,
|
||||||
extensionName: String?,
|
extensionName: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionSuffix: String?,
|
extensionSuffix: String?,
|
||||||
@ -170,7 +170,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
- Input file: \(inputFile)
|
- Input file: \(inputFile)
|
||||||
- Style: \(style)
|
- Style: \(style)
|
||||||
- Xcassets path: \(xcassetsPath)
|
- Xcassets path: \(xcassetsPath)
|
||||||
- Extension output path: \(extensionOutputPath)
|
- Extension output path: \(extensionOutputPath ?? "-")
|
||||||
- Extension name: \(extensionName ?? "-")
|
- Extension name: \(extensionName ?? "-")
|
||||||
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
||||||
- Extension suffix: \(extensionSuffix ?? "-")
|
- Extension suffix: \(extensionSuffix ?? "-")
|
||||||
@ -181,7 +181,7 @@ struct ColorsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String?
|
||||||
let extensionName: String?
|
let extensionName: String?
|
||||||
let extensionNameUIKit: String?
|
let extensionNameUIKit: String?
|
||||||
let extensionSuffix: String?
|
let extensionSuffix: String?
|
||||||
@ -197,7 +197,7 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
|
|
||||||
internal init(
|
internal init(
|
||||||
inputFile: String,
|
inputFile: String,
|
||||||
extensionOutputPath: String,
|
extensionOutputPath: String?,
|
||||||
extensionName: String?,
|
extensionName: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionSuffix: String?,
|
extensionSuffix: String?,
|
||||||
@ -217,7 +217,7 @@ struct FontsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
"""
|
"""
|
||||||
Fonts configuration:
|
Fonts configuration:
|
||||||
- Input file: \(inputFile)
|
- Input file: \(inputFile)
|
||||||
- Extension output path: \(extensionOutputPath)
|
- Extension output path: \(extensionOutputPath ?? "-")
|
||||||
- Extension name: \(extensionName ?? "-")
|
- Extension name: \(extensionName ?? "-")
|
||||||
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
||||||
- Extension suffix: \(extensionSuffix ?? "-")
|
- Extension suffix: \(extensionSuffix ?? "-")
|
||||||
@ -230,7 +230,7 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
|
|
||||||
let inputFile: String
|
let inputFile: String
|
||||||
let xcassetsPath: String
|
let xcassetsPath: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String?
|
||||||
let extensionName: String?
|
let extensionName: String?
|
||||||
let extensionNameUIKit: String?
|
let extensionNameUIKit: String?
|
||||||
let extensionSuffix: String?
|
let extensionSuffix: String?
|
||||||
@ -246,7 +246,7 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
internal init(
|
internal init(
|
||||||
inputFile: String,
|
inputFile: String,
|
||||||
xcassetsPath: String,
|
xcassetsPath: String,
|
||||||
extensionOutputPath: String,
|
extensionOutputPath: String?,
|
||||||
extensionName: String?,
|
extensionName: String?,
|
||||||
extensionNameUIKit: String?,
|
extensionNameUIKit: String?,
|
||||||
extensionSuffix: String?,
|
extensionSuffix: String?,
|
||||||
@ -266,7 +266,7 @@ struct ImagesConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
Images configuration:
|
Images configuration:
|
||||||
- Input file: \(inputFile)
|
- Input file: \(inputFile)
|
||||||
- Xcassets path: \(xcassetsPath)
|
- Xcassets path: \(xcassetsPath)
|
||||||
- Extension output path: \(extensionOutputPath)
|
- Extension output path: \(extensionOutputPath ?? "-")
|
||||||
- Extension name: \(extensionName ?? "-")
|
- Extension name: \(extensionName ?? "-")
|
||||||
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
- Extension name UIKit: \(extensionNameUIKit ?? "-")
|
||||||
- Extension suffix: \(extensionSuffix ?? "-")
|
- Extension suffix: \(extensionSuffix ?? "-")
|
||||||
@ -280,7 +280,7 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
let outputPath: String
|
let outputPath: String
|
||||||
let langs: String
|
let langs: String
|
||||||
let defaultLang: String
|
let defaultLang: String
|
||||||
let extensionOutputPath: String
|
let extensionOutputPath: String?
|
||||||
let extensionName: String?
|
let extensionName: String?
|
||||||
let extensionSuffix: String?
|
let extensionSuffix: String?
|
||||||
private let staticMembers: Bool?
|
private let staticMembers: Bool?
|
||||||
@ -305,7 +305,7 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
outputPath: String,
|
outputPath: String,
|
||||||
langs: String,
|
langs: String,
|
||||||
defaultLang: String,
|
defaultLang: String,
|
||||||
extensionOutputPath: String,
|
extensionOutputPath: String?,
|
||||||
extensionName: String?,
|
extensionName: String?,
|
||||||
extensionSuffix: String?,
|
extensionSuffix: String?,
|
||||||
staticMembers: Bool?,
|
staticMembers: Bool?,
|
||||||
@ -329,7 +329,7 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
- Output path: \(outputPath)
|
- Output path: \(outputPath)
|
||||||
- Langs: \(langs)
|
- Langs: \(langs)
|
||||||
- Default lang: \(defaultLang)
|
- Default lang: \(defaultLang)
|
||||||
- Extension output path: \(extensionOutputPath)
|
- Extension output path: \(extensionOutputPath ?? "-")
|
||||||
- Extension name: \(extensionName ?? "-")
|
- Extension name: \(extensionName ?? "-")
|
||||||
- Extension suffix: \(extensionSuffix ?? "-")
|
- Extension suffix: \(extensionSuffix ?? "-")
|
||||||
"""
|
"""
|
||||||
|
@ -27,29 +27,23 @@ extension ColorsConfiguration: Runnable {
|
|||||||
style,
|
style,
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
xcassetsPath.prependIfRelativePath(projectDirectory),
|
xcassetsPath.prependIfRelativePath(projectDirectory),
|
||||||
"--extension-output-path",
|
|
||||||
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
// Add optional parameters
|
||||||
|
[
|
||||||
|
("--extension-output-path", extensionOutputPath?.prependIfRelativePath(projectDirectory)),
|
||||||
|
("--extension-name", extensionName),
|
||||||
|
("--extension-name-ui-kit", extensionNameUIKit),
|
||||||
|
("--extension-suffix", extensionSuffix)
|
||||||
|
].forEach { argumentName, argumentValue in
|
||||||
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
argumentName,
|
||||||
extensionName
|
argumentValue
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionNameUIKit {
|
|
||||||
args += [
|
|
||||||
"--extension-name-ui-kit",
|
|
||||||
extensionNameUIKit
|
|
||||||
]
|
|
||||||
}
|
|
||||||
if let extensionSuffix {
|
|
||||||
args += [
|
|
||||||
"--extension-suffix",
|
|
||||||
extensionSuffix
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
@ -23,32 +23,26 @@ extension FontsConfiguration: Runnable {
|
|||||||
|
|
||||||
args += [
|
args += [
|
||||||
inputFile.prependIfRelativePath(projectDirectory),
|
inputFile.prependIfRelativePath(projectDirectory),
|
||||||
"--extension-output-path",
|
|
||||||
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
// Add optional parameters
|
||||||
|
[
|
||||||
|
("--extension-output-path", extensionOutputPath?.prependIfRelativePath(projectDirectory)),
|
||||||
|
("--extension-name", extensionName),
|
||||||
|
("--extension-name-ui-kit", extensionNameUIKit),
|
||||||
|
("--extension-suffix", extensionSuffix)
|
||||||
|
].forEach { argumentName, argumentValue in
|
||||||
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
argumentName,
|
||||||
extensionName
|
argumentValue
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if let extensionNameUIKit {
|
|
||||||
args += [
|
|
||||||
"--extension-name-ui-kit",
|
|
||||||
extensionNameUIKit
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if let extensionSuffix {
|
|
||||||
args += [
|
|
||||||
"--extension-suffix",
|
|
||||||
extensionSuffix
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add infoPlist paths
|
||||||
if let infoPlistPaths {
|
if let infoPlistPaths {
|
||||||
let adjustedPlistPaths = infoPlistPaths
|
let adjustedPlistPaths = infoPlistPaths
|
||||||
.split(separator: " ")
|
.split(separator: " ")
|
||||||
|
@ -25,31 +25,23 @@ extension ImagesConfiguration: Runnable {
|
|||||||
inputFile.prependIfRelativePath(projectDirectory),
|
inputFile.prependIfRelativePath(projectDirectory),
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
xcassetsPath.prependIfRelativePath(projectDirectory),
|
xcassetsPath.prependIfRelativePath(projectDirectory),
|
||||||
"--extension-output-path",
|
|
||||||
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"\(staticMembersOptions)"
|
"\(staticMembersOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
// Add optional parameters
|
||||||
|
[
|
||||||
|
("--extension-output-path", extensionOutputPath?.prependIfRelativePath(projectDirectory)),
|
||||||
|
("--extension-name", extensionName),
|
||||||
|
("--extension-name-ui-kit", extensionNameUIKit),
|
||||||
|
("--extension-suffix", extensionSuffix)
|
||||||
|
].forEach { argumentName, argumentValue in
|
||||||
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
argumentName,
|
||||||
extensionName
|
argumentValue
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if let extensionNameUIKit {
|
|
||||||
args += [
|
|
||||||
"--extension-name-ui-kit",
|
|
||||||
extensionNameUIKit
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if let extensionSuffix {
|
|
||||||
args += [
|
|
||||||
"--extension-suffix",
|
|
||||||
extensionSuffix
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
@ -24,26 +24,24 @@ extension StringsConfiguration: Runnable {
|
|||||||
langs,
|
langs,
|
||||||
"--default-lang",
|
"--default-lang",
|
||||||
defaultLang,
|
defaultLang,
|
||||||
"--extension-output-path",
|
|
||||||
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"\(staticMembersOptions)",
|
"\(staticMembersOptions)",
|
||||||
"--xc-strings",
|
"--xc-strings",
|
||||||
"\(xcStringsOptions)"
|
"\(xcStringsOptions)"
|
||||||
]
|
]
|
||||||
|
|
||||||
if let extensionName {
|
// Add optional parameters
|
||||||
|
[
|
||||||
|
("--extension-output-path", extensionOutputPath?.prependIfRelativePath(projectDirectory)),
|
||||||
|
("--extension-name", extensionName),
|
||||||
|
("--extension-suffix", extensionSuffix)
|
||||||
|
].forEach { argumentName, argumentValue in
|
||||||
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
"--extension-name",
|
argumentName,
|
||||||
extensionName
|
argumentValue
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if let extensionSuffix {
|
|
||||||
args += [
|
|
||||||
"--extension-suffix",
|
|
||||||
extensionSuffix
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Stringium.main(args)
|
Stringium.main(args)
|
||||||
|
@ -21,8 +21,6 @@ struct Images: ParsableCommand {
|
|||||||
// MARK: - Static
|
// MARK: - Static
|
||||||
|
|
||||||
static let toolName = "Images"
|
static let toolName = "Images"
|
||||||
static let defaultExtensionName = "Image"
|
|
||||||
static let defaultExtensionNameUIKit = "UIImage"
|
|
||||||
|
|
||||||
// MARK: - Command Options
|
// MARK: - Command Options
|
||||||
|
|
||||||
@ -55,23 +53,29 @@ struct Images: ParsableCommand {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
|
if let extensionName = options.extensionName,
|
||||||
|
let extensionFilePath = options.extensionFilePath {
|
||||||
ImageExtensionGenerator.generateExtensionFile(
|
ImageExtensionGenerator.generateExtensionFile(
|
||||||
images: imagesToGenerate,
|
images: imagesToGenerate,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
extensionName: options.extensionName,
|
extensionName: extensionName,
|
||||||
extensionFilePath: options.extensionFilePath,
|
extensionFilePath: extensionFilePath,
|
||||||
isSwiftUI: true
|
isSwiftUI: true
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let extensionNameUIKit = options.extensionNameUIKit,
|
||||||
|
let extensionFilePathUIKit = options.extensionFilePathUIKit {
|
||||||
ImageExtensionGenerator.generateExtensionFile(
|
ImageExtensionGenerator.generateExtensionFile(
|
||||||
images: imagesToGenerate,
|
images: imagesToGenerate,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
extensionName: options.extensionNameUIKit,
|
extensionName: extensionNameUIKit,
|
||||||
extensionFilePath: options.extensionFilePathUIKit,
|
extensionFilePath: extensionFilePathUIKit,
|
||||||
isSwiftUI: false
|
isSwiftUI: false
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
print("[\(Self.toolName)] Images generated")
|
print("[\(Self.toolName)] Images generated")
|
||||||
}
|
}
|
||||||
@ -96,17 +100,39 @@ struct Images: ParsableCommand {
|
|||||||
_ = Self.getSvgConverterPath()
|
_ = Self.getSvgConverterPath()
|
||||||
|
|
||||||
// Extension for UIKit and SwiftUI should have different name
|
// Extension for UIKit and SwiftUI should have different name
|
||||||
guard options.extensionName != options.extensionNameUIKit else {
|
if let extensionName = options.extensionName,
|
||||||
let error = ImagesError.extensionNamesCollision(options.extensionName)
|
let extensionNameUIKit = options.extensionNameUIKit {
|
||||||
|
guard extensionName != extensionNameUIKit else {
|
||||||
|
let error = ImagesError.extensionNamesCollision(extensionName)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Self.exit(withError: error)
|
Self.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an extension need to be generated, ensure extensionOutputPath is defined
|
||||||
|
if options.extensionName != nil ||
|
||||||
|
options.extensionNameUIKit != nil {
|
||||||
|
guard let extensionOutputPath = options.extensionOutputPath,
|
||||||
|
extensionOutputPath.isEmpty == false else {
|
||||||
|
let error = ImagesError.missingExtensionPath
|
||||||
|
print(error.description)
|
||||||
|
Self.exit(withError: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// 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(
|
guard GeneratorChecker.shouldGenerate(
|
||||||
force: options.forceExecution,
|
force: options.forceExecution,
|
||||||
inputFilePath: options.inputFile,
|
inputFilePath: options.inputFile,
|
||||||
extensionFilePath: options.extensionFilePath
|
extensionFilePath: fileToCompareToInput
|
||||||
) else {
|
) else {
|
||||||
print("[\(Self.toolName)] Images are already up to date :) ")
|
print("[\(Self.toolName)] Images are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
|
@ -18,12 +18,13 @@ enum ImagesError: Error {
|
|||||||
case magickConvertNotFound
|
case magickConvertNotFound
|
||||||
case writeFile(String, String)
|
case writeFile(String, String)
|
||||||
case createAssetFolder(String)
|
case createAssetFolder(String)
|
||||||
|
case missingExtensionPath
|
||||||
case unknown(String)
|
case unknown(String)
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .extensionNamesCollision(let extensionName):
|
case .extensionNamesCollision(let extensionName):
|
||||||
return "error: [\(Fonts.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
return "error: [\(Images.toolName)] Error on extension names, extension name and SwiftUI extension name should be different (\(extensionName) is used on both)"
|
||||||
|
|
||||||
case .inputFolderNotFound(let inputFolder):
|
case .inputFolderNotFound(let inputFolder):
|
||||||
return "error: [\(Images.toolName)] Input folder not found: \(inputFolder)"
|
return "error: [\(Images.toolName)] Input folder not found: \(inputFolder)"
|
||||||
@ -47,7 +48,10 @@ enum ImagesError: Error {
|
|||||||
return "error: [\(Images.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
return "error: [\(Images.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
|
||||||
|
|
||||||
case .createAssetFolder(let folder):
|
case .createAssetFolder(let folder):
|
||||||
return "error: [\(Colors.toolName)] An error occured while creating folder `\(folder)`"
|
return "error: [\(Images.toolName)] An error occured while creating folder `\(folder)`"
|
||||||
|
|
||||||
|
case .missingExtensionPath:
|
||||||
|
return "error: [\(Images.toolName)] Extension need to be generated but no `extensionOutputPath` is provided"
|
||||||
|
|
||||||
case .unknown(let errorDescription):
|
case .unknown(let errorDescription):
|
||||||
return "error: [\(Images.toolName)] Unknown error: \(errorDescription)"
|
return "error: [\(Images.toolName)] Unknown error: \(errorDescription)"
|
||||||
|
@ -24,17 +24,17 @@ struct ImagesOptions: ParsableArguments {
|
|||||||
@Option(help: "Xcassets path where to generate images.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Option(help: "Xcassets path where to generate images.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var xcassetsPath: String
|
var xcassetsPath: String
|
||||||
|
|
||||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
|
||||||
var extensionOutputPath: String
|
|
||||||
|
|
||||||
@Option(help: "Tell if it will generate static properties or not")
|
@Option(help: "Tell if it will generate static properties or not")
|
||||||
var staticMembers: Bool = false
|
var staticMembers: Bool = false
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an Image extension.")
|
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var extensionName: String = Images.defaultExtensionName
|
var extensionOutputPath: String?
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an UIImage extension.")
|
@Option(help: "SwiftUI extension name. If not specified, no extension will be generated.")
|
||||||
var extensionNameUIKit: String = Images.defaultExtensionNameUIKit
|
var extensionName: String?
|
||||||
|
|
||||||
|
@Option(help: "UIKit extension name. If not specified, no extension will be generated.")
|
||||||
|
var extensionNameUIKit: String?
|
||||||
|
|
||||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift")
|
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift")
|
||||||
var extensionSuffix: String?
|
var extensionSuffix: String?
|
||||||
@ -46,28 +46,36 @@ extension ImagesOptions {
|
|||||||
|
|
||||||
// MARK: - SwiftUI
|
// MARK: - SwiftUI
|
||||||
|
|
||||||
var extensionFileName: String {
|
var extensionFileName: String? {
|
||||||
|
guard let extensionName else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionName).swift"
|
return "\(extensionName).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePath: String {
|
var extensionFilePath: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileName)"
|
guard let extensionOutputPath, let extensionFileName else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileName)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UIKit
|
// MARK: - UIKit
|
||||||
|
|
||||||
var extensionFileNameUIKit: String {
|
var extensionFileNameUIKit: String? {
|
||||||
|
guard let extensionNameUIKit else { return nil }
|
||||||
|
|
||||||
if let extensionSuffix {
|
if let extensionSuffix {
|
||||||
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
return "\(extensionNameUIKit)+\(extensionSuffix).swift"
|
||||||
}
|
}
|
||||||
return "\(extensionNameUIKit).swift"
|
return "\(extensionNameUIKit).swift"
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePathUIKit: String {
|
var extensionFilePathUIKit: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
guard let extensionOutputPath, let extensionFileNameUIKit else { return nil }
|
||||||
|
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileNameUIKit)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
@ -19,8 +19,7 @@ enum StringsFileGenerator {
|
|||||||
langs: [String],
|
langs: [String],
|
||||||
defaultLang: String,
|
defaultLang: String,
|
||||||
tags: [String],
|
tags: [String],
|
||||||
outputPath: String,
|
lprojPathFormat: String
|
||||||
inputFilenameWithoutExt: String
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var stringsFilesContent = [String: String]()
|
var stringsFilesContent = [String: String]()
|
||||||
@ -37,7 +36,7 @@ enum StringsFileGenerator {
|
|||||||
langs.forEach { lang in
|
langs.forEach { lang in
|
||||||
guard let fileContent = stringsFilesContent[lang] else { return }
|
guard let fileContent = stringsFilesContent[lang] else { return }
|
||||||
|
|
||||||
let stringsFilePath = "\(outputPath)/\(lang).lproj/\(inputFilenameWithoutExt).strings"
|
let stringsFilePath = String(format: lprojPathFormat, lang)
|
||||||
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
||||||
do {
|
do {
|
||||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||||
@ -54,8 +53,7 @@ enum StringsFileGenerator {
|
|||||||
langs: [String],
|
langs: [String],
|
||||||
defaultLang: String,
|
defaultLang: String,
|
||||||
tags: [String],
|
tags: [String],
|
||||||
outputPath: String,
|
xcStringsFilePath: String
|
||||||
inputFilenameWithoutExt: String
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
let fileContent: String = Self.generateXcStringsFileContent(
|
let fileContent: String = Self.generateXcStringsFileContent(
|
||||||
@ -65,12 +63,11 @@ enum StringsFileGenerator {
|
|||||||
sections: sections
|
sections: sections
|
||||||
)
|
)
|
||||||
|
|
||||||
let stringsFilePath = "\(outputPath)/\(inputFilenameWithoutExt).xcstrings"
|
let stringsFilePathURL = URL(fileURLWithPath: xcStringsFilePath)
|
||||||
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
|
|
||||||
do {
|
do {
|
||||||
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8)
|
||||||
} catch {
|
} catch {
|
||||||
let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath)
|
let error = StringiumError.writeFile(error.localizedDescription, xcStringsFilePath)
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Stringium.exit(withError: error)
|
Stringium.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ struct Stringium: ParsableCommand {
|
|||||||
// MARK: - Static
|
// MARK: - Static
|
||||||
|
|
||||||
static let toolName = "Stringium"
|
static let toolName = "Stringium"
|
||||||
static let defaultExtensionName = "String"
|
|
||||||
static let noTranslationTag: String = "notranslation"
|
static let noTranslationTag: String = "notranslation"
|
||||||
|
|
||||||
// MARK: - Command options
|
// MARK: - Command options
|
||||||
@ -49,8 +48,7 @@ struct Stringium: ParsableCommand {
|
|||||||
langs: options.langs,
|
langs: options.langs,
|
||||||
defaultLang: options.defaultLang,
|
defaultLang: options.defaultLang,
|
||||||
tags: options.tags,
|
tags: options.tags,
|
||||||
outputPath: options.stringsFileOutputPath,
|
lprojPathFormat: options.lprojPathFormat
|
||||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
StringsFileGenerator.writeXcStringsFiles(
|
StringsFileGenerator.writeXcStringsFiles(
|
||||||
@ -58,22 +56,25 @@ struct Stringium: ParsableCommand {
|
|||||||
langs: options.langs,
|
langs: options.langs,
|
||||||
defaultLang: options.defaultLang,
|
defaultLang: options.defaultLang,
|
||||||
tags: options.tags,
|
tags: options.tags,
|
||||||
outputPath: options.stringsFileOutputPath,
|
xcStringsFilePath: options.xcStringsFilePath
|
||||||
inputFilenameWithoutExt: options.inputFilenameWithoutExt
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
|
if let extensionName = options.extensionName,
|
||||||
|
let extensionFilePath = options.extensionFilePath {
|
||||||
|
print("Will generate extensions")
|
||||||
StringsFileGenerator.writeExtensionFiles(
|
StringsFileGenerator.writeExtensionFiles(
|
||||||
sections: sections,
|
sections: sections,
|
||||||
defaultLang: options.defaultLang,
|
defaultLang: options.defaultLang,
|
||||||
tags: options.tags,
|
tags: options.tags,
|
||||||
staticVar: options.staticMembers,
|
staticVar: options.staticMembers,
|
||||||
inputFilename: options.inputFilenameWithoutExt,
|
inputFilename: options.inputFilenameWithoutExt,
|
||||||
extensionName: options.extensionName,
|
extensionName: extensionName,
|
||||||
extensionFilePath: options.extensionFilePath,
|
extensionFilePath: extensionFilePath,
|
||||||
extensionSuffix: options.extensionSuffix
|
extensionSuffix: options.extensionSuffix ?? ""
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
print("[\(Self.toolName)] Strings generated")
|
print("[\(Self.toolName)] Strings generated")
|
||||||
}
|
}
|
||||||
@ -104,10 +105,18 @@ struct Stringium: ParsableCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if needed to regenerate
|
// Check if needed to regenerate
|
||||||
|
let fileToCompareToInput: String = {
|
||||||
|
// If there is no extension file to compare
|
||||||
|
// Then check the xcassets file instead
|
||||||
|
if options.xcStrings {
|
||||||
|
return options.xcStringsFilePath
|
||||||
|
}
|
||||||
|
return String(format: options.lprojPathFormat, options.defaultLang)
|
||||||
|
}()
|
||||||
guard GeneratorChecker.shouldGenerate(
|
guard GeneratorChecker.shouldGenerate(
|
||||||
force: options.forceGeneration,
|
force: options.forceGeneration,
|
||||||
inputFilePath: options.inputFile,
|
inputFilePath: options.inputFile,
|
||||||
extensionFilePath: options.extensionFilePath
|
extensionFilePath: fileToCompareToInput
|
||||||
) else {
|
) else {
|
||||||
print("[\(Self.toolName)] Strings are already up to date :) ")
|
print("[\(Self.toolName)] Strings are already up to date :) ")
|
||||||
return false
|
return false
|
||||||
|
@ -15,35 +15,51 @@ struct StringiumOptions: ParsableArguments {
|
|||||||
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
|
||||||
var forceGeneration = false
|
var forceGeneration = false
|
||||||
|
|
||||||
@Argument(help: "Input files where strings are defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Argument(
|
||||||
|
help: "Input files where strings are defined.",
|
||||||
|
transform: { $0.replaceTiltWithHomeDirectoryPath() }
|
||||||
|
)
|
||||||
var inputFile: String
|
var inputFile: String
|
||||||
|
|
||||||
@Option(name: .customLong("output-path"), help: "Path where to strings file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Option(
|
||||||
|
name: .customLong("output-path"),
|
||||||
|
help: "Path where to strings file.",
|
||||||
|
transform: { $0.replaceTiltWithHomeDirectoryPath() }
|
||||||
|
)
|
||||||
fileprivate var outputPathRaw: String
|
fileprivate var outputPathRaw: String
|
||||||
|
|
||||||
@Option(name: .customLong("langs"), help: "Langs to generate.")
|
@Option(
|
||||||
|
name: .customLong("langs"),
|
||||||
|
help: "Langs to generate."
|
||||||
|
)
|
||||||
fileprivate var langsRaw: String
|
fileprivate var langsRaw: String
|
||||||
|
|
||||||
@Option(help: "Default langs.")
|
@Option(help: "Default langs.")
|
||||||
var defaultLang: String
|
var defaultLang: String
|
||||||
|
|
||||||
@Option(name: .customLong("tags"), help: "Tags to generate.")
|
@Option(
|
||||||
|
name: .customLong("tags"),
|
||||||
|
help: "Tags to generate."
|
||||||
|
)
|
||||||
fileprivate var tagsRaw: String = "ios iosonly iosOnly notranslation"
|
fileprivate var tagsRaw: String = "ios iosonly iosOnly notranslation"
|
||||||
|
|
||||||
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Option(help: "Generate static properties. False by default")
|
||||||
var extensionOutputPath: String
|
|
||||||
|
|
||||||
@Option(help: "Tell if it will generate static properties or not")
|
|
||||||
var staticMembers: Bool = false
|
var staticMembers: Bool = false
|
||||||
|
|
||||||
@Option(help: "Tell if it will generate xcStrings file or not")
|
@Option(help: "Tell if it will generate xcStrings file or lproj file. True by default")
|
||||||
var xcStrings: Bool = false
|
var xcStrings: Bool = true
|
||||||
|
|
||||||
@Option(help: "Extension name. If not specified, it will generate an String extension.")
|
@Option(
|
||||||
var extensionName: String = Stringium.defaultExtensionName
|
help: "Path where to generate the extension.",
|
||||||
|
transform: { $0.replaceTiltWithHomeDirectoryPath() }
|
||||||
|
)
|
||||||
|
var extensionOutputPath: String?
|
||||||
|
|
||||||
|
@Option(help: "Extension name. If not specified, no extension will be generated.")
|
||||||
|
var extensionName: String?
|
||||||
|
|
||||||
@Option(help: "Extension suffix: {extensionName}+{extensionSuffix}.swift")
|
@Option(help: "Extension suffix: {extensionName}+{extensionSuffix}.swift")
|
||||||
var extensionSuffix: String
|
var extensionSuffix: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private var getter
|
// MARK: - Private var getter
|
||||||
@ -75,12 +91,21 @@ extension StringiumOptions {
|
|||||||
|
|
||||||
extension StringiumOptions {
|
extension StringiumOptions {
|
||||||
|
|
||||||
var extensionFileName: String {
|
private var extensionFileName: String? {
|
||||||
"\(extensionName)+\(extensionSuffix).swift"
|
if let extensionName {
|
||||||
|
if let extensionSuffix {
|
||||||
|
return "\(extensionName)+\(extensionSuffix).swift"
|
||||||
|
}
|
||||||
|
return "\(extensionName).swift"
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensionFilePath: String {
|
var extensionFilePath: String? {
|
||||||
"\(extensionOutputPath)/\(extensionFileName)"
|
if let extensionOutputPath, let extensionFileName {
|
||||||
|
return "\(extensionOutputPath)/\(extensionFileName)"
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputFilenameWithoutExt: String {
|
var inputFilenameWithoutExt: String {
|
||||||
@ -88,4 +113,12 @@ extension StringiumOptions {
|
|||||||
.deletingPathExtension()
|
.deletingPathExtension()
|
||||||
.lastPathComponent
|
.lastPathComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var xcStringsFilePath: String {
|
||||||
|
"\(stringsFileOutputPath)/\(inputFilenameWithoutExt).xcstrings"
|
||||||
|
}
|
||||||
|
|
||||||
|
var lprojPathFormat: String {
|
||||||
|
"\(stringsFileOutputPath)/%@.lproj/\(inputFilenameWithoutExt).strings"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,8 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
func logScreenDefinitionName() {
|
func logScreenDefinitionName() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
path: "ecran_un/"
|
path: "ecran_un/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -84,7 +85,7 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -103,9 +104,10 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
// Expect
|
// Expect
|
||||||
let expectScreen = """
|
let expectScreen = """
|
||||||
static func logScreenDefinitionName() {
|
static func logScreenDefinitionName() {
|
||||||
logScreen(
|
AnalyticsManager.shared.logScreen(
|
||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
path: "ecran_un/"
|
path: "ecran_un/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -123,11 +125,11 @@ final class AnalyticsDefinitionTests: XCTestCase {
|
|||||||
// Expect
|
// Expect
|
||||||
let expectEvent = """
|
let expectEvent = """
|
||||||
static func logEventDefinitionName() {
|
static func logEventDefinitionName() {
|
||||||
logEvent(
|
AnalyticsManager.shared.logEvent(
|
||||||
name: "Ecran un",
|
name: "Ecran un",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -32,6 +32,182 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
return definition
|
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() {
|
func testGeneratedExtensionContentFirebase() {
|
||||||
// Given
|
// Given
|
||||||
let sectionOne = AnalyticsCategory(id: "section_one")
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
@ -65,64 +241,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
|
||||||
// MARK: - Protocol
|
\(protocolString())
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
\(firebaseString())
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
// MARK: - Traker Type
|
||||||
func logEvent(
|
|
||||||
name: String,
|
|
||||||
action: String,
|
|
||||||
category: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Firebase
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
case firebase
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
@ -131,27 +261,59 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Properties
|
// 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) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
isEnabled = enable
|
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() {
|
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 }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +325,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@ -178,7 +340,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS1DefOne() {
|
func logScreenS1DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s1 def one",
|
name: "s1 def one",
|
||||||
path: ""
|
path: "",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +350,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "",
|
action: "",
|
||||||
category: "",
|
category: "",
|
||||||
params: [:]
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +359,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS2DefOne() {
|
func logScreenS2DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: ""
|
path: "",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,80 +405,18 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
|
|
||||||
// MARK: - Protocol
|
\(protocolString())
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
\(matomoString())
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
// MARK: - Traker Type
|
||||||
func logEvent(
|
|
||||||
name: String,
|
|
||||||
action: String,
|
|
||||||
category: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Matomo
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
case matomo
|
||||||
|
|
||||||
// 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: - Manager
|
// MARK: - Manager
|
||||||
@ -323,32 +425,62 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Properties
|
// 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) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
isEnabled = enable
|
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) {
|
func configure(siteId: String, url: String) {
|
||||||
managers.append(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
MatomoAnalyticsManager(
|
|
||||||
siteId: siteId,
|
siteId: siteId,
|
||||||
url: url
|
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 }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +492,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@ -375,7 +507,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS1DefOne() {
|
func logScreenS1DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s1 def one",
|
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",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [:]
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +526,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS2DefOne() {
|
func logScreenS2DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/"
|
path: "s2_def_one/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,125 +573,22 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
|
||||||
// MARK: - Protocol
|
\(protocolString())
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
\(matomoString())
|
||||||
|
|
||||||
func logScreen(name: String, path: String)
|
\(firebaseString())
|
||||||
func logEvent(
|
|
||||||
name: String,
|
|
||||||
action: String,
|
|
||||||
category: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Matomo
|
// MARK: - Traker Type
|
||||||
|
|
||||||
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
// MARK: - Properties
|
case matomo
|
||||||
|
case firebase
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
@ -566,33 +597,63 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Properties
|
// 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) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
isEnabled = enable
|
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) {
|
func configure(siteId: String, url: String) {
|
||||||
managers.append(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
MatomoAnalyticsManager(
|
|
||||||
siteId: siteId,
|
siteId: siteId,
|
||||||
url: url
|
url: url
|
||||||
)
|
)
|
||||||
)
|
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||||
managers.append(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 }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +665,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@ -619,7 +680,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS1DefOne() {
|
func logScreenS1DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s1 def one",
|
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",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [:]
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +699,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
func logScreenS2DefOne() {
|
func logScreenS2DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/"
|
path: "s2_def_one/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ final class ColorsConfigurationTests: XCTestCase {
|
|||||||
let testingConfiguration = ColorsConfiguration(inputFile: "path/to/colors.txt",
|
let testingConfiguration = ColorsConfiguration(inputFile: "path/to/colors.txt",
|
||||||
style: ColorStyle.all.rawValue,
|
style: ColorStyle.all.rawValue,
|
||||||
xcassetsPath: "path/to/assets.xcassets",
|
xcassetsPath: "path/to/assets.xcassets",
|
||||||
extensionOutputPath: "Colors/Generated",
|
extensionOutputPath: nil,
|
||||||
extensionName: nil,
|
extensionName: nil,
|
||||||
extensionNameUIKit: nil,
|
extensionNameUIKit: nil,
|
||||||
extensionSuffix: nil,
|
extensionSuffix: nil,
|
||||||
@ -34,8 +34,6 @@ final class ColorsConfigurationTests: XCTestCase {
|
|||||||
"all",
|
"all",
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
"projectDirectory/path/to/assets.xcassets",
|
"projectDirectory/path/to/assets.xcassets",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Colors/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"false"
|
"false"
|
||||||
]
|
]
|
||||||
@ -64,10 +62,10 @@ final class ColorsConfigurationTests: XCTestCase {
|
|||||||
"all",
|
"all",
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
"projectDirectory/path/to/assets.xcassets",
|
"projectDirectory/path/to/assets.xcassets",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Colors/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"false",
|
"false",
|
||||||
|
"--extension-output-path",
|
||||||
|
"projectDirectory/Colors/Generated",
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
"AppUIColor",
|
"AppUIColor",
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
|
@ -17,7 +17,7 @@ final class FontsConfigurationTests: XCTestCase {
|
|||||||
func test_argsGeneration_requiredArgs() {
|
func test_argsGeneration_requiredArgs() {
|
||||||
// Given
|
// Given
|
||||||
let testingConfiguration = FontsConfiguration(inputFile: "path/to/fonts.txt",
|
let testingConfiguration = FontsConfiguration(inputFile: "path/to/fonts.txt",
|
||||||
extensionOutputPath: "Fonts/Generated",
|
extensionOutputPath: nil,
|
||||||
extensionName: nil,
|
extensionName: nil,
|
||||||
extensionNameUIKit: nil,
|
extensionNameUIKit: nil,
|
||||||
extensionSuffix: nil,
|
extensionSuffix: nil,
|
||||||
@ -29,8 +29,6 @@ final class FontsConfigurationTests: XCTestCase {
|
|||||||
// Expect
|
// Expect
|
||||||
let expectedArguments = [
|
let expectedArguments = [
|
||||||
"projectDirectory/path/to/fonts.txt",
|
"projectDirectory/path/to/fonts.txt",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Fonts/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"false"
|
"false"
|
||||||
]
|
]
|
||||||
@ -54,10 +52,10 @@ final class FontsConfigurationTests: XCTestCase {
|
|||||||
let expectedArguments = [
|
let expectedArguments = [
|
||||||
"-f",
|
"-f",
|
||||||
"projectDirectory/path/to/fonts.txt",
|
"projectDirectory/path/to/fonts.txt",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Fonts/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"true",
|
"true",
|
||||||
|
"--extension-output-path",
|
||||||
|
"projectDirectory/Fonts/Generated",
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
"AppUIFont",
|
"AppUIFont",
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
|
@ -18,7 +18,7 @@ final class ImagesConfigurationTests: XCTestCase {
|
|||||||
// Given
|
// Given
|
||||||
let testingConfiguration = ImagesConfiguration(inputFile: "path/to/images.txt",
|
let testingConfiguration = ImagesConfiguration(inputFile: "path/to/images.txt",
|
||||||
xcassetsPath: "path/to/assets.xcassets",
|
xcassetsPath: "path/to/assets.xcassets",
|
||||||
extensionOutputPath: "Images/Generated",
|
extensionOutputPath: nil,
|
||||||
extensionName: nil,
|
extensionName: nil,
|
||||||
extensionNameUIKit: nil,
|
extensionNameUIKit: nil,
|
||||||
extensionSuffix: nil,
|
extensionSuffix: nil,
|
||||||
@ -32,8 +32,6 @@ final class ImagesConfigurationTests: XCTestCase {
|
|||||||
"projectDirectory/path/to/images.txt",
|
"projectDirectory/path/to/images.txt",
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
"projectDirectory/path/to/assets.xcassets",
|
"projectDirectory/path/to/assets.xcassets",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Images/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"false"
|
"false"
|
||||||
]
|
]
|
||||||
@ -60,10 +58,10 @@ final class ImagesConfigurationTests: XCTestCase {
|
|||||||
"projectDirectory/path/to/images.txt",
|
"projectDirectory/path/to/images.txt",
|
||||||
"--xcassets-path",
|
"--xcassets-path",
|
||||||
"projectDirectory/path/to/assets.xcassets",
|
"projectDirectory/path/to/assets.xcassets",
|
||||||
"--extension-output-path",
|
|
||||||
"projectDirectory/Images/Generated",
|
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"true",
|
"true",
|
||||||
|
"--extension-output-path",
|
||||||
|
"projectDirectory/Images/Generated",
|
||||||
"--extension-name",
|
"--extension-name",
|
||||||
"AppUIImage",
|
"AppUIImage",
|
||||||
"--extension-name-ui-kit",
|
"--extension-name-ui-kit",
|
||||||
|
Reference in New Issue
Block a user