mise-a-jour-tags #6
190
SampleFiles/Tags/Generated/Analytics+GenAllScript.swift
Normal file
190
SampleFiles/Tags/Generated/Analytics+GenAllScript.swift
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
|
import MatomoTracker
|
||||||
|
import Firebase
|
||||||
|
|
||||||
|
// MARK: - Protocol
|
||||||
|
|
||||||
|
protocol AnalyticsManagerProtocol {
|
||||||
|
func logScreen(name: String, path: String)
|
||||||
|
func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Matomo
|
||||||
|
|
||||||
|
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
private var tracker: MatomoTracker
|
||||||
|
|
||||||
|
// MARK: - Init
|
||||||
|
|
||||||
|
init(siteId: String, url: String) {
|
||||||
|
debugPrint("[Matomo service] Server URL: \(url)")
|
||||||
|
debugPrint("[Matomo service] Site ID: \(siteId)")
|
||||||
|
tracker = MatomoTracker(
|
||||||
|
siteId: siteId,
|
||||||
|
baseURL: URL(string: url)!
|
||||||
|
)
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
tracker.dispatchInterval = 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
tracker.logger = DefaultLogger(minLevel: .verbose)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
debugPrint("[Matomo service] Configured with content base: \(tracker.contentBase?.absoluteString ?? "-")")
|
||||||
|
debugPrint("[Matomo service] Opt out: \(tracker.isOptedOut)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
|
func logScreen(name: String, path: String) {
|
||||||
|
guard !tracker.isOptedOut else { return }
|
||||||
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
|
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
||||||
|
tracker.track(
|
||||||
|
view: [name],
|
||||||
|
url: urlString
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard !tracker.isOptedOut else { return }
|
||||||
|
|
||||||
|
tracker.track(
|
||||||
|
eventWithCategory: category,
|
||||||
|
action: action,
|
||||||
|
name: name,
|
||||||
|
number: nil,
|
||||||
|
url: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Firebase
|
||||||
|
|
||||||
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
|
func logScreen(name: String, path: String) {
|
||||||
|
var parameters = [
|
||||||
|
AnalyticsParameterScreenName: name
|
||||||
|
]
|
||||||
|
|
||||||
|
Analytics.logEvent(
|
||||||
|
AnalyticsEventScreenView,
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
var parameters: [String:Any] = [
|
||||||
|
"action": action,
|
||||||
|
"category": category,
|
||||||
|
]
|
||||||
|
|
||||||
|
if let supplementaryParameters = params {
|
||||||
|
parameters.merge(supplementaryParameters) { (origin, new) -> Any in
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Analytics.logEvent(
|
||||||
|
name,
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Manager
|
||||||
|
|
||||||
|
class AnalyticsManager {
|
||||||
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
var managers: [AnalyticsManagerProtocol] = []
|
||||||
|
|
||||||
|
private var isEnabled: Bool = true
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
|
func setAnalyticsEnabled(_ enable: Bool) {
|
||||||
|
isEnabled = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
func configure(siteId: String, url: String) {
|
||||||
|
managers.append(
|
||||||
|
MatomoAnalyticsManager(
|
||||||
|
siteId: siteId,
|
||||||
|
url: url
|
||||||
|
)
|
||||||
|
)
|
||||||
|
managers.append(FirebaseAnalyticsManager())
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logScreen(name: String, path: String) {
|
||||||
|
guard isEnabled else { return }
|
||||||
|
|
||||||
|
managers.forEach { manager in
|
||||||
|
manager.logScreen(name: name, path: path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard isEnabled else { return }
|
||||||
|
|
||||||
|
managers.forEach { manager in
|
||||||
|
manager.logEvent(
|
||||||
|
name: name,
|
||||||
|
action: action,
|
||||||
|
category: category,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Introduction
|
||||||
|
|
||||||
|
func logScreenIntroductionScreen(title: String) {
|
||||||
|
logScreen(
|
||||||
|
name: "Bienvenue \(title)",
|
||||||
|
path: "introduction/"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logEventIntroductionScreen(test: String, data: Int) {
|
||||||
|
logEvent(
|
||||||
|
name: "Bienvenue",
|
||||||
|
action: "action",
|
||||||
|
category: "category",
|
||||||
|
params: [
|
||||||
|
"test": test,
|
||||||
|
"data": data
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
24
SampleFiles/Tags/sampleTags.yml
Normal file
24
SampleFiles/Tags/sampleTags.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
categories:
|
||||||
|
- id: Introduction
|
||||||
|
screens:
|
||||||
|
- id: introduction_screen
|
||||||
|
name: Bienvenue _TITLE_
|
||||||
|
path: introduction/
|
||||||
|
tags: droid,ios
|
||||||
|
parameters:
|
||||||
|
- name: title
|
||||||
|
type: String
|
||||||
|
replaceIn: name
|
||||||
|
|
||||||
|
events:
|
||||||
|
- id: introduction_screen
|
||||||
|
name: Bienvenue
|
||||||
|
category: category
|
||||||
|
action: action
|
||||||
|
tags: droid,ios
|
||||||
|
parameters:
|
||||||
|
- name: test
|
||||||
|
type: String
|
||||||
|
- name: data
|
||||||
|
type: Int
|
67
Sources/ResgenSwift/Analytics/Analytics.swift
Normal file
67
Sources/ResgenSwift/Analytics/Analytics.swift
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// Analytics.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 08/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ToolCore
|
||||||
|
import Foundation
|
||||||
|
import ArgumentParser
|
||||||
|
|
||||||
|
struct Analytics: ParsableCommand {
|
||||||
|
|
||||||
|
// MARK: - Command Configuration
|
||||||
|
|
||||||
|
static var configuration = CommandConfiguration(
|
||||||
|
abstract: "Generate analytics extension file.",
|
||||||
|
version: ResgenSwiftVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Static
|
||||||
|
|
||||||
|
static let toolName = "Analytics"
|
||||||
|
static let defaultExtensionName = "Analytics"
|
||||||
|
|
||||||
|
// MARK: - Command Options
|
||||||
|
|
||||||
|
@OptionGroup var options: AnalyticsOptions
|
||||||
|
|
||||||
|
// MARK: - Run
|
||||||
|
|
||||||
|
mutating func run() {
|
||||||
|
print("[\(Self.toolName)] Starting analytics generation")
|
||||||
|
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate analytics for target: \(options.target)")
|
||||||
|
print("[\(Self.toolName)] Will generate analytics")
|
||||||
|
|
||||||
|
// Parse input file
|
||||||
|
let sections = AnalyticsFileParser.parse(options.inputFile, target: options.target)
|
||||||
|
|
||||||
|
// Generate extension
|
||||||
|
AnalyticsGenerator.writeExtensionFiles(sections: sections,
|
||||||
|
target: options.target,
|
||||||
|
tags: ["ios", "iosonly"],
|
||||||
|
staticVar: options.staticMembers,
|
||||||
|
extensionName: options.extensionName,
|
||||||
|
extensionFilePath: options.extensionFilePath)
|
||||||
|
|
||||||
|
print("[\(Self.toolName)] Analytics generated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Analytics {
|
||||||
|
enum TargetType: CaseIterable {
|
||||||
|
case matomo
|
||||||
|
case firebase
|
||||||
|
|
||||||
|
var value: String {
|
||||||
|
switch self {
|
||||||
|
case .matomo:
|
||||||
|
"matomo"
|
||||||
|
case .firebase:
|
||||||
|
"firebase"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
//
|
//
|
||||||
// TagOptions.swift
|
// AnalyticsOptions.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
|
|
||||||
struct TagsOptions: ParsableArguments {
|
struct AnalyticsOptions: 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
|
||||||
|
|
||||||
@ -24,16 +24,16 @@ struct TagsOptions: ParsableArguments {
|
|||||||
@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 a Tag extension.")
|
@Option(help: "Extension name. If not specified, it will generate a Analytics extension.")
|
||||||
var extensionName: String = Tags.defaultExtensionName
|
var extensionName: String = Analytics.defaultExtensionName
|
||||||
|
|
||||||
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Tag{extensionSuffix}.swift")
|
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Analytics{extensionSuffix}.swift")
|
||||||
var extensionSuffix: String?
|
var extensionSuffix: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Computed var
|
// MARK: - Computed var
|
||||||
|
|
||||||
extension TagsOptions {
|
extension AnalyticsOptions {
|
||||||
var extensionFileName: String {
|
var extensionFileName: String {
|
||||||
if let extensionSuffix = extensionSuffix {
|
if let extensionSuffix = extensionSuffix {
|
||||||
return "\(extensionName)+\(extensionSuffix).swift"
|
return "\(extensionName)+\(extensionSuffix).swift"
|
@ -1,22 +1,22 @@
|
|||||||
//
|
//
|
||||||
// TagsGenerator.swift
|
// AnalyticsGenerator.swift
|
||||||
//
|
|
||||||
//
|
//
|
||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
//
|
||||||
|
// Created by Loris Perret on 08/12/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
import CoreVideo
|
import CoreVideo
|
||||||
|
|
||||||
class TagsGenerator {
|
class AnalyticsGenerator {
|
||||||
static var targets: [Tags.TargetType] = []
|
static var targets: [Analytics.TargetType] = []
|
||||||
|
|
||||||
static func writeExtensionFiles(sections: [TagSection], target: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
|
static func writeExtensionFiles(sections: [AnalyticsCategory], target: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
|
||||||
// Get target type from enum
|
// Get target type from enum
|
||||||
let targetsString: [String] = target.components(separatedBy: " ")
|
let targetsString: [String] = target.components(separatedBy: " ")
|
||||||
|
|
||||||
Tags.TargetType.allCases.forEach { enumTarget in
|
Analytics.TargetType.allCases.forEach { enumTarget in
|
||||||
if targetsString.contains(enumTarget.value) {
|
if targetsString.contains(enumTarget.value) {
|
||||||
targets.append(enumTarget)
|
targets.append(enumTarget)
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ class TagsGenerator {
|
|||||||
|
|
||||||
// MARK: - Extension content
|
// MARK: - Extension content
|
||||||
|
|
||||||
static func getExtensionContent(sections: [TagSection], tags: [String], staticVar: Bool, extensionName: String) -> String {
|
static func getExtensionContent(sections: [AnalyticsCategory], tags: [String], staticVar: Bool, extensionName: String) -> String {
|
||||||
[
|
[
|
||||||
Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
|
Self.getHeader(extensionClassname: extensionName, staticVar: staticVar),
|
||||||
Self.getProperties(sections: sections, tags: tags, staticVar: staticVar),
|
Self.getProperties(sections: sections, tags: tags, staticVar: staticVar),
|
||||||
@ -56,9 +56,8 @@ class TagsGenerator {
|
|||||||
|
|
||||||
private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
|
private static func getHeader(extensionClassname: String, staticVar: Bool) -> String {
|
||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Tags.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||||
|
|
||||||
\(staticVar ? "typelias Tags = String\n\n" : "")import UIKit
|
|
||||||
\(Self.getImport())
|
\(Self.getImport())
|
||||||
|
|
||||||
\(Self.getAnalytics())
|
\(Self.getAnalytics())
|
||||||
@ -85,17 +84,19 @@ class TagsGenerator {
|
|||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
|
|
||||||
func setAnalyticsEnabled(_ enable: Bool) { isEnabled = enable }
|
func setAnalyticsEnabled(_ enable: Bool) {
|
||||||
|
isEnabled = enable
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getImport() -> String {
|
private static func getImport() -> String {
|
||||||
var result: [String] = []
|
var result: [String] = []
|
||||||
|
|
||||||
if targets.contains(Tags.TargetType.matomo) {
|
if targets.contains(Analytics.TargetType.matomo) {
|
||||||
result.append("import MatomoTracker")
|
result.append("import MatomoTracker")
|
||||||
}
|
}
|
||||||
if targets.contains(Tags.TargetType.firebase) {
|
if targets.contains(Analytics.TargetType.firebase) {
|
||||||
result.append("import Firebase")
|
result.append("import Firebase")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,15 +107,27 @@ class TagsGenerator {
|
|||||||
"""
|
"""
|
||||||
private func logScreen(name: String, path: String) {
|
private func logScreen(name: String, path: String) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(name: name, path: path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func logEvent(name: String) {
|
private func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.forEach { manager in
|
||||||
manager.logEvent(name: name)
|
manager.logEvent(
|
||||||
|
name: name,
|
||||||
|
action: action,
|
||||||
|
category: category,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -125,16 +138,23 @@ class TagsGenerator {
|
|||||||
var content: [String] = []
|
var content: [String] = []
|
||||||
let footer = " }"
|
let footer = " }"
|
||||||
|
|
||||||
if targets.contains(Tags.TargetType.matomo) {
|
if targets.contains(Analytics.TargetType.matomo) {
|
||||||
header = "func configure(siteId: String, url: String) {"
|
header = "func configure(siteId: String, url: String) {"
|
||||||
} else if targets.contains(Tags.TargetType.firebase) {
|
} else if targets.contains(Analytics.TargetType.firebase) {
|
||||||
header = "func configure() {"
|
header = "func configure() {"
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(Tags.TargetType.matomo) {
|
if targets.contains(Analytics.TargetType.matomo) {
|
||||||
content.append(" managers.append(MatomoAnalyticsManager(siteId: siteId, url: url))")
|
content.append("""
|
||||||
|
managers.append(
|
||||||
|
MatomoAnalyticsManager(
|
||||||
|
siteId: siteId,
|
||||||
|
url: url
|
||||||
|
)
|
||||||
|
)
|
||||||
|
""")
|
||||||
}
|
}
|
||||||
if targets.contains(Tags.TargetType.firebase) {
|
if targets.contains(Analytics.TargetType.firebase) {
|
||||||
content.append(" managers.append(FirebaseAnalyticsManager())")
|
content.append(" managers.append(FirebaseAnalyticsManager())")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,25 +172,30 @@ class TagsGenerator {
|
|||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(name: String, path: String)
|
||||||
func logEvent(name: String)
|
func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var result: [String] = [proto]
|
var result: [String] = [proto]
|
||||||
|
|
||||||
if targets.contains(Tags.TargetType.matomo) {
|
if targets.contains(Analytics.TargetType.matomo) {
|
||||||
result.append(MatomoGenerator.service.content)
|
result.append(MatomoGenerator.service.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(Tags.TargetType.firebase) {
|
if targets.contains(Analytics.TargetType.firebase) {
|
||||||
result.append(FirebaseGenerator.service.content)
|
result.append(FirebaseGenerator.service.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.joined(separator: "\n")
|
return result.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func getProperties(sections: [TagSection], tags: [String], staticVar: Bool) -> String {
|
private static func getProperties(sections: [AnalyticsCategory], tags: [String], staticVar: Bool) -> String {
|
||||||
sections
|
sections
|
||||||
.compactMap { section in
|
.compactMap { section in
|
||||||
// Check that at least one string will be generated
|
// Check that at least one string will be generated
|
||||||
@ -178,7 +203,7 @@ class TagsGenerator {
|
|||||||
return nil// Go to next section
|
return nil// Go to next section
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = "\n // MARK: - \(section.name)"
|
var res = "\n // MARK: - \(section.id)"
|
||||||
section.definitions.forEach { definition in
|
section.definitions.forEach { definition in
|
||||||
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
|
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
|
||||||
return // Go to next definition
|
return // Go to next definition
|
@ -31,7 +31,14 @@ enum FirebaseGenerator {
|
|||||||
private var logScreen: String {
|
private var logScreen: String {
|
||||||
"""
|
"""
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(name: String, path: String) {
|
||||||
Analytics.logEvent(AnalyticsEventScreenView, parameters: [AnalyticsParameterScreenName: name])
|
var parameters = [
|
||||||
|
AnalyticsParameterScreenName: name
|
||||||
|
]
|
||||||
|
|
||||||
|
Analytics.logEvent(
|
||||||
|
AnalyticsEventScreenView,
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -39,12 +46,27 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
private var logEvent: String {
|
private var logEvent: String {
|
||||||
"""
|
"""
|
||||||
func logEvent(name: String) {
|
func logEvent(
|
||||||
var parameters = [
|
name: String,
|
||||||
AnalyticsParameterValue: name
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
var parameters: [String:Any] = [
|
||||||
|
"action": action,
|
||||||
|
"category": category,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if let supplementaryParameters = params {
|
||||||
|
parameters.merge(supplementaryParameters) { (origin, new) -> Any in
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Analytics.logEvent(AnalyticsEventSelectContent, parameters: parameters)
|
Analytics.logEvent(
|
||||||
|
name,
|
||||||
|
parameters: parameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
@ -41,7 +41,10 @@ enum MatomoGenerator {
|
|||||||
init(siteId: String, url: String) {
|
init(siteId: String, url: String) {
|
||||||
debugPrint("[Matomo service] Server URL: \\(url)")
|
debugPrint("[Matomo service] Server URL: \\(url)")
|
||||||
debugPrint("[Matomo service] Site ID: \\(siteId)")
|
debugPrint("[Matomo service] Site ID: \\(siteId)")
|
||||||
tracker = MatomoTracker(siteId: siteId, baseURL: URL(string: url)!)
|
tracker = MatomoTracker(
|
||||||
|
siteId: siteId,
|
||||||
|
baseURL: URL(string: url)!
|
||||||
|
)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
tracker.dispatchInterval = 5
|
tracker.dispatchInterval = 5
|
||||||
@ -65,6 +68,7 @@ enum MatomoGenerator {
|
|||||||
func logScreen(name: String, path: String) {
|
func logScreen(name: String, path: String) {
|
||||||
guard !tracker.isOptedOut else { return }
|
guard !tracker.isOptedOut else { return }
|
||||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
||||||
tracker.track(
|
tracker.track(
|
||||||
view: [name],
|
view: [name],
|
||||||
@ -77,11 +81,17 @@ enum MatomoGenerator {
|
|||||||
|
|
||||||
private var logEvent: String {
|
private var logEvent: String {
|
||||||
"""
|
"""
|
||||||
func logEvent(name: String) {
|
func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard !tracker.isOptedOut else { return }
|
guard !tracker.isOptedOut else { return }
|
||||||
|
|
||||||
tracker.track(
|
tracker.track(
|
||||||
eventWithCategory: "category",
|
eventWithCategory: category,
|
||||||
action: "action",
|
action: action,
|
||||||
name: name,
|
name: name,
|
||||||
number: nil,
|
number: nil,
|
||||||
url: nil
|
url: nil
|
28
Sources/ResgenSwift/Analytics/Model/AnalyticsCategory.swift
Normal file
28
Sources/ResgenSwift/Analytics/Model/AnalyticsCategory.swift
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsCategory.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 05/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class AnalyticsCategory {
|
||||||
|
let id: String // OnBoarding
|
||||||
|
var definitions = [AnalyticsDefinition]()
|
||||||
|
|
||||||
|
init(id: String) {
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasOneOrMoreMatchingTags(tags: [String]) -> Bool {
|
||||||
|
let allTags = definitions.flatMap { $0.tags }
|
||||||
|
let allTagsSet = Set(allTags)
|
||||||
|
|
||||||
|
let intersection = Set(tags).intersection(allTagsSet)
|
||||||
|
if intersection.isEmpty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
174
Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift
Normal file
174
Sources/ResgenSwift/Analytics/Model/AnalyticsDefinition.swift
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsDefinition.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 05/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class AnalyticsDefinition {
|
||||||
|
let id: String
|
||||||
|
var name: String
|
||||||
|
var path: String = ""
|
||||||
|
var category: String = ""
|
||||||
|
var action: String = ""
|
||||||
|
var comments: String = ""
|
||||||
|
var tags: [String] = []
|
||||||
|
var parameters: [AnalyticsParameter] = []
|
||||||
|
var type: TagType
|
||||||
|
|
||||||
|
init(id: String, name: String, type: TagType) {
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasOneOrMoreMatchingTags(inputTags: [String]) -> Bool {
|
||||||
|
if Set(inputTags).intersection(Set(self.tags)).isEmpty {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Methods
|
||||||
|
|
||||||
|
private func getFuncName() -> String {
|
||||||
|
var pascalCaseTitle: String = ""
|
||||||
|
id.components(separatedBy: "_").forEach { word in
|
||||||
|
pascalCaseTitle.append(contentsOf: word.uppercasedFirst())
|
||||||
|
}
|
||||||
|
|
||||||
|
return "log\(type == .screen ? "Screen" : "Event")\(pascalCaseTitle)"
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getParameters() -> String {
|
||||||
|
var params = parameters
|
||||||
|
var result: String
|
||||||
|
|
||||||
|
if type == .screen {
|
||||||
|
params = params.filter{ param in
|
||||||
|
!param.replaceIn.isEmpty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let paramsString = params.map { parameter in
|
||||||
|
"\(parameter.name): \(parameter.type)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if paramsString.count > 2 {
|
||||||
|
result = """
|
||||||
|
(
|
||||||
|
\(paramsString.joined(separator: ",\n\t\t"))
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
} else {
|
||||||
|
result = """
|
||||||
|
(\(paramsString.joined(separator: ", ")))
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private func replaceIn(){
|
||||||
|
for parameter in parameters {
|
||||||
|
for rep in parameter.replaceIn {
|
||||||
|
switch rep {
|
||||||
|
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 "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getlogFunction() -> String {
|
||||||
|
var params: [String] = []
|
||||||
|
var result: String
|
||||||
|
|
||||||
|
let supplementaryParams = parameters.filter { param in
|
||||||
|
param.replaceIn.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
supplementaryParams.forEach { param in
|
||||||
|
params.append("\"\(param.name)\": \(param.name)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.count > 1 {
|
||||||
|
result = """
|
||||||
|
[
|
||||||
|
\(params.joined(separator: ",\n\t\t\t\t"))
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
} else {
|
||||||
|
result = """
|
||||||
|
[\(params.joined(separator: ", "))]
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
if type == .screen {
|
||||||
|
return """
|
||||||
|
logScreen(
|
||||||
|
name: "\(name)",
|
||||||
|
path: "\(path)"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
} else {
|
||||||
|
return """
|
||||||
|
logEvent(
|
||||||
|
name: "\(name)",
|
||||||
|
action: "\(action)",
|
||||||
|
category: "\(category)",
|
||||||
|
params: \(result)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Raw strings
|
||||||
|
|
||||||
|
func getProperty() -> String {
|
||||||
|
replaceIn()
|
||||||
|
return """
|
||||||
|
func \(getFuncName())\(getParameters()) {
|
||||||
|
\(getlogFunction())
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStaticProperty() -> String {
|
||||||
|
replaceIn()
|
||||||
|
return """
|
||||||
|
static func \(getFuncName())\(getParameters()) {
|
||||||
|
\(getlogFunction())
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AnalyticsDefinition {
|
||||||
|
enum TagType {
|
||||||
|
case screen
|
||||||
|
case event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
func replacingFirstOccurrence(of: String, with: String) -> Self {
|
||||||
|
if let range = self.range(of: of) {
|
||||||
|
let tmp = self.replacingOccurrences(
|
||||||
|
of: of,
|
||||||
|
with: with,
|
||||||
|
options: .literal,
|
||||||
|
range: range
|
||||||
|
)
|
||||||
|
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
}
|
47
Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift
Normal file
47
Sources/ResgenSwift/Analytics/Model/AnalyticsFile.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsFile.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 06/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct AnalyticsFile: Codable {
|
||||||
|
var categories: [AnalyticsCategoryDTO]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnalyticsCategoryDTO: Codable {
|
||||||
|
var id: String
|
||||||
|
var screens: [AnalyticsDefinitionScreenDTO]?
|
||||||
|
var events: [AnalyticsDefinitionEventDTO]?
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol AnalyticsDefinitionDTO: Codable {}
|
||||||
|
|
||||||
|
struct AnalyticsDefinitionScreenDTO: AnalyticsDefinitionDTO {
|
||||||
|
var id: String
|
||||||
|
var name: String
|
||||||
|
var tags: String
|
||||||
|
var comments: String?
|
||||||
|
var parameters: [AnalyticsParameterDTO]?
|
||||||
|
|
||||||
|
var path: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnalyticsDefinitionEventDTO: AnalyticsDefinitionDTO {
|
||||||
|
var id: String
|
||||||
|
var name: String
|
||||||
|
var tags: String
|
||||||
|
var comments: String?
|
||||||
|
var parameters: [AnalyticsParameterDTO]?
|
||||||
|
|
||||||
|
var category: String?
|
||||||
|
var action: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnalyticsParameterDTO: Codable {
|
||||||
|
var name: String
|
||||||
|
var type: String
|
||||||
|
var replaceIn: String?
|
||||||
|
}
|
19
Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift
Normal file
19
Sources/ResgenSwift/Analytics/Model/AnalyticsParameter.swift
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsParameter.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 06/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class AnalyticsParameter {
|
||||||
|
var name: String
|
||||||
|
var type: String
|
||||||
|
var replaceIn: [String] = []
|
||||||
|
|
||||||
|
init(name: String, type: String) {
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
}
|
||||||
|
}
|
173
Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift
Normal file
173
Sources/ResgenSwift/Analytics/Parser/AnalyticsFileParser.swift
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsFileParser.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 06/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Yams
|
||||||
|
|
||||||
|
class AnalyticsFileParser {
|
||||||
|
private static var inputFile: String = ""
|
||||||
|
private static var target: String = ""
|
||||||
|
|
||||||
|
private static func parseYaml() -> AnalyticsFile {
|
||||||
|
guard let data = FileManager().contents(atPath: inputFile) else {
|
||||||
|
let error = GenerateError.fileNotExists(inputFile)
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let tagFile = try YAMLDecoder().decode(AnalyticsFile.self, from: data)
|
||||||
|
return tagFile
|
||||||
|
} catch let error {
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getParameters(fromData data: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||||
|
var parameters: [AnalyticsParameter] = []
|
||||||
|
|
||||||
|
data.forEach { value in
|
||||||
|
// Type
|
||||||
|
|
||||||
|
let type = value.type.uppercasedFirst()
|
||||||
|
|
||||||
|
guard
|
||||||
|
type == "String" ||
|
||||||
|
type == "Int" ||
|
||||||
|
type == "Double" ||
|
||||||
|
type == "Bool"
|
||||||
|
else {
|
||||||
|
let error = GenerateError.invalidParameter("type of \(value.name)")
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let parameter: AnalyticsParameter = AnalyticsParameter(name: value.name, type: type)
|
||||||
|
|
||||||
|
if let replaceIn = value.replaceIn {
|
||||||
|
parameter.replaceIn = replaceIn.components(separatedBy: ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.append(parameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getTagDefinition(
|
||||||
|
id: String,
|
||||||
|
name: String,
|
||||||
|
type: AnalyticsDefinition.TagType,
|
||||||
|
tags: String,
|
||||||
|
comments: String?,
|
||||||
|
parameters: [AnalyticsParameterDTO]?
|
||||||
|
) -> AnalyticsDefinition {
|
||||||
|
let definition: AnalyticsDefinition = AnalyticsDefinition(id: id, name: name, type: type)
|
||||||
|
definition.tags = tags.components(separatedBy: ",")
|
||||||
|
|
||||||
|
if let comments = comments {
|
||||||
|
definition.comments = comments
|
||||||
|
}
|
||||||
|
|
||||||
|
if let parameters = parameters {
|
||||||
|
definition.parameters = Self.getParameters(fromData: parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
return definition
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getTagDefinitionScreen(fromData screens: [AnalyticsDefinitionScreenDTO]) -> [AnalyticsDefinition] {
|
||||||
|
var definitions: [AnalyticsDefinition] = []
|
||||||
|
|
||||||
|
for screen in screens {
|
||||||
|
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||||
|
id: screen.id,
|
||||||
|
name: screen.name,
|
||||||
|
type: .screen,
|
||||||
|
tags: screen.tags,
|
||||||
|
comments: screen.comments,
|
||||||
|
parameters: screen.parameters
|
||||||
|
)
|
||||||
|
|
||||||
|
guard target.contains(Analytics.TargetType.matomo.value) else { continue }
|
||||||
|
|
||||||
|
// Path
|
||||||
|
|
||||||
|
guard let path = screen.path else {
|
||||||
|
let error = GenerateError.missingElement("screen path")
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
definition.path = path
|
||||||
|
|
||||||
|
definitions.append(definition)
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitions
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func getTagDefinitionEvent(fromData events: [AnalyticsDefinitionEventDTO]) -> [AnalyticsDefinition] {
|
||||||
|
var definitions: [AnalyticsDefinition] = []
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
let definition: AnalyticsDefinition = Self.getTagDefinition(
|
||||||
|
id: event.id,
|
||||||
|
name: event.name,
|
||||||
|
type: .event,
|
||||||
|
tags: event.tags,
|
||||||
|
comments: event.comments,
|
||||||
|
parameters: event.parameters
|
||||||
|
)
|
||||||
|
|
||||||
|
guard target.contains(Analytics.TargetType.matomo.value) else { continue }
|
||||||
|
|
||||||
|
// Category
|
||||||
|
|
||||||
|
guard let category = event.category else {
|
||||||
|
let error = GenerateError.missingElement("event category")
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
definition.category = category
|
||||||
|
|
||||||
|
// Action
|
||||||
|
|
||||||
|
guard let action = event.action else {
|
||||||
|
let error = GenerateError.missingElement("event action")
|
||||||
|
Generate.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
definition.action = action
|
||||||
|
|
||||||
|
definitions.append(definition)
|
||||||
|
}
|
||||||
|
|
||||||
|
return definitions
|
||||||
|
}
|
||||||
|
|
||||||
|
static func parse(_ inputFile: String, target: String) -> [AnalyticsCategory] {
|
||||||
|
self.inputFile = inputFile
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
let tagFile: AnalyticsFile = Self.parseYaml()
|
||||||
|
var sections: [AnalyticsCategory] = []
|
||||||
|
|
||||||
|
tagFile.categories.forEach { categorie in
|
||||||
|
let section: AnalyticsCategory = AnalyticsCategory(id: categorie.id)
|
||||||
|
|
||||||
|
if let screens = categorie.screens {
|
||||||
|
section.definitions.append(contentsOf: Self.getTagDefinitionScreen(fromData: screens))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let events = categorie.events {
|
||||||
|
section.definitions.append(contentsOf: Self.getTagDefinitionEvent(fromData: events))
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.append(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// AnalyticsConfiguration+Runnable.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 08/12/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension AnalyticsConfiguration: Runnable {
|
||||||
|
func run(projectDirectory: String, force: Bool) {
|
||||||
|
var args = [String]()
|
||||||
|
|
||||||
|
if force {
|
||||||
|
args += ["-f"]
|
||||||
|
}
|
||||||
|
|
||||||
|
args += [
|
||||||
|
inputFile.prependIfRelativePath(projectDirectory),
|
||||||
|
"--target",
|
||||||
|
target,
|
||||||
|
"--extension-output-path",
|
||||||
|
extensionOutputPath.prependIfRelativePath(projectDirectory),
|
||||||
|
"--static-members",
|
||||||
|
"\(staticMembersOptions)"
|
||||||
|
]
|
||||||
|
|
||||||
|
if let extensionName = extensionName {
|
||||||
|
args += [
|
||||||
|
"--extension-name",
|
||||||
|
extensionName
|
||||||
|
]
|
||||||
|
}
|
||||||
|
if let extensionSuffix = extensionSuffix {
|
||||||
|
args += [
|
||||||
|
"--extension-suffix",
|
||||||
|
extensionSuffix
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Analytics.main(args)
|
||||||
|
}
|
||||||
|
}
|
@ -1,138 +0,0 @@
|
|||||||
//
|
|
||||||
// TagDefinition.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Loris Perret on 05/12/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class TagDefinition {
|
|
||||||
let title: String
|
|
||||||
var path: String = ""
|
|
||||||
var name: String = ""
|
|
||||||
var type: String = ""
|
|
||||||
var tags = [String]()
|
|
||||||
var comment: String?
|
|
||||||
|
|
||||||
var isValid: Bool {
|
|
||||||
title.isEmpty == false &&
|
|
||||||
name.isEmpty == false &&
|
|
||||||
(type == TagType.screen.value || type == TagType.event.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
init(title: String) {
|
|
||||||
self.title = title
|
|
||||||
}
|
|
||||||
|
|
||||||
static func match(_ line: String) -> TagDefinition? {
|
|
||||||
guard line.range(of: "\\[(.*?)]$", options: .regularExpression, range: nil, locale: nil) != nil else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let definitionTitle = line
|
|
||||||
.replacingOccurrences(of: ["[", "]"], with: "")
|
|
||||||
.removeLeadingTrailingWhitespace()
|
|
||||||
|
|
||||||
return TagDefinition(title: definitionTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasOneOrMoreMatchingTags(inputTags: [String]) -> Bool {
|
|
||||||
if Set(inputTags).intersection(Set(self.tags)).isEmpty {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: -
|
|
||||||
|
|
||||||
private func getStringParameters(input: String) -> (inputParameters: [String], translationArguments: [String])? {
|
|
||||||
var methodsParameters = [String]()
|
|
||||||
|
|
||||||
let printfPlaceholderRegex = try! NSRegularExpression(pattern: "%(?:\\d+\\$)?[+-]?(?:[ 0]|'.{1})?-?\\d*(?:\\.\\d+)?[blcdeEufFgGosxX@]*")
|
|
||||||
printfPlaceholderRegex.enumerateMatches(in: input, options: [], range: NSRange(location: 0, length: input.count)) { match, _, stop in
|
|
||||||
guard let match = match else { return }
|
|
||||||
|
|
||||||
if let range = Range(match.range, in: input), let last = input[range].last {
|
|
||||||
switch last {
|
|
||||||
case "d", "u":
|
|
||||||
methodsParameters.append("Int")
|
|
||||||
case "f", "F":
|
|
||||||
methodsParameters.append("Double")
|
|
||||||
case "@", "s", "c":
|
|
||||||
methodsParameters.append("String")
|
|
||||||
case "%":
|
|
||||||
// if you need to print %, you have to add %%
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if methodsParameters.isEmpty {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputParameters = [String]()
|
|
||||||
var translationArguments = [String]()
|
|
||||||
for (index, paramType) in methodsParameters.enumerated() {
|
|
||||||
let paramName = "arg\(index)"
|
|
||||||
translationArguments.append(paramName)
|
|
||||||
inputParameters.append("\(paramName): \(paramType)")
|
|
||||||
}
|
|
||||||
|
|
||||||
return (inputParameters: inputParameters, translationArguments: translationArguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getFuncName() -> String {
|
|
||||||
var pascalCaseTitle: String = ""
|
|
||||||
name.components(separatedBy: " ").forEach { word in
|
|
||||||
pascalCaseTitle.append(contentsOf: word.uppercasedFirst())
|
|
||||||
}
|
|
||||||
|
|
||||||
return "log\(type == TagType.screen.value ? "Screen" : "Event")\(pascalCaseTitle)"
|
|
||||||
}
|
|
||||||
|
|
||||||
private func getlogFunction() -> String {
|
|
||||||
if type == TagType.screen.value {
|
|
||||||
"logScreen(name: \"\(name)\", path: \"\(path)\")"
|
|
||||||
} else {
|
|
||||||
"logEvent(name: \"\(name)\")"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Raw strings
|
|
||||||
|
|
||||||
func getProperty() -> String {
|
|
||||||
"""
|
|
||||||
func \(getFuncName())() {
|
|
||||||
\(getlogFunction())
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStaticProperty() -> String {
|
|
||||||
"""
|
|
||||||
static func \(getFuncName())() {
|
|
||||||
\(getlogFunction())
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TagDefinition {
|
|
||||||
enum TagType {
|
|
||||||
case screen
|
|
||||||
case event
|
|
||||||
|
|
||||||
var value: String {
|
|
||||||
switch self {
|
|
||||||
case .screen:
|
|
||||||
"screen"
|
|
||||||
case .event:
|
|
||||||
"event"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// TagSection.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Loris Perret on 05/12/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class TagSection {
|
|
||||||
let name: String // OnBoarding
|
|
||||||
var definitions = [TagDefinition]()
|
|
||||||
|
|
||||||
init(name: String) {
|
|
||||||
self.name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
static func match(_ line: String) -> TagSection? {
|
|
||||||
guard line.range(of: "\\[\\[(.*?)]]$", options: .regularExpression, range: nil, locale: nil) != nil else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let sectionName = line
|
|
||||||
.replacingOccurrences(of: ["[", "]"], with: "")
|
|
||||||
.removeLeadingTrailingWhitespace()
|
|
||||||
return TagSection(name: sectionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasOneOrMoreMatchingTags(tags: [String]) -> Bool {
|
|
||||||
let allTags = definitions.flatMap { $0.tags }
|
|
||||||
let allTagsSet = Set(allTags)
|
|
||||||
|
|
||||||
let intersection = Set(tags).intersection(allTagsSet)
|
|
||||||
if intersection.isEmpty {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
//
|
|
||||||
// TagFileParser.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Loris Perret on 05/12/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class TagFileParser {
|
|
||||||
static func parse(_ inputFile: String) -> [TagSection] {
|
|
||||||
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
|
|
||||||
let stringsByLines = inputFileContent.components(separatedBy: .newlines)
|
|
||||||
|
|
||||||
var sections = [TagSection]()
|
|
||||||
|
|
||||||
// Parse file
|
|
||||||
stringsByLines.forEach {
|
|
||||||
// TagSection
|
|
||||||
if let section = TagSection.match($0) {
|
|
||||||
sections.append(section)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Definition
|
|
||||||
if let definition = TagDefinition.match($0) {
|
|
||||||
sections.last?.definitions.append(definition)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Definition content
|
|
||||||
if $0.isEmpty == false {
|
|
||||||
// name = Test => ["name ", " Test"]
|
|
||||||
let splitLine = $0
|
|
||||||
.removeLeadingTrailingWhitespace()
|
|
||||||
.split(separator: "=")
|
|
||||||
|
|
||||||
guard let lastDefinition = sections.last?.definitions.last,
|
|
||||||
let leftElement = splitLine.first else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let rightElement: String = splitLine.dropFirst().joined(separator: "=")
|
|
||||||
|
|
||||||
// "name " => "name"
|
|
||||||
let leftHand = String(leftElement).removeTrailingWhitespace()
|
|
||||||
// " Test" => "Test"
|
|
||||||
let rightHand = String(rightElement).removeLeadingWhitespace()
|
|
||||||
|
|
||||||
// Handle comments, tags and translation
|
|
||||||
switch leftHand {
|
|
||||||
case "comments":
|
|
||||||
lastDefinition.comment = rightHand
|
|
||||||
|
|
||||||
case "tags":
|
|
||||||
lastDefinition.tags = rightHand
|
|
||||||
.split(separator: ",")
|
|
||||||
.map { String($0) }
|
|
||||||
|
|
||||||
case "path":
|
|
||||||
lastDefinition.path = rightHand
|
|
||||||
|
|
||||||
case "name":
|
|
||||||
lastDefinition.name = rightHand
|
|
||||||
|
|
||||||
case "type":
|
|
||||||
lastDefinition.type = rightHand
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep only valid definition
|
|
||||||
var invalidDefinitionNames = [String]()
|
|
||||||
sections.forEach { section in
|
|
||||||
section.definitions = section.definitions
|
|
||||||
.filter {
|
|
||||||
if $0.isValid == false {
|
|
||||||
invalidDefinitionNames.append($0.name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if invalidDefinitionNames.count > 0 {
|
|
||||||
print("warning: [\(Stringium.toolName)] Found \(invalidDefinitionNames.count) definition (\(invalidDefinitionNames.joined(separator: ", "))")
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
//
|
|
||||||
// Tag.swift
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Created by Thibaut Schmitt on 10/01/2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
import ToolCore
|
|
||||||
import Foundation
|
|
||||||
import ArgumentParser
|
|
||||||
|
|
||||||
struct Tags: ParsableCommand {
|
|
||||||
|
|
||||||
// MARK: - Command Configuration
|
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
|
||||||
abstract: "Generate tags extension file.",
|
|
||||||
version: ResgenSwiftVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Static
|
|
||||||
|
|
||||||
static let toolName = "Tags"
|
|
||||||
static let defaultExtensionName = "Tags"
|
|
||||||
static let noTranslationTag: String = "notranslation"
|
|
||||||
|
|
||||||
// MARK: - Command Options
|
|
||||||
|
|
||||||
@OptionGroup var options: TagsOptions
|
|
||||||
|
|
||||||
// MARK: - Run
|
|
||||||
|
|
||||||
mutating func run() {
|
|
||||||
print("[\(Self.toolName)] Starting tags generation")
|
|
||||||
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate tags for target: \(options.target)")
|
|
||||||
|
|
||||||
// Check requirements
|
|
||||||
guard checkRequirements() else { return }
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Will generate tags")
|
|
||||||
|
|
||||||
// Parse input file
|
|
||||||
let sections = TagFileParser.parse(options.inputFile)
|
|
||||||
|
|
||||||
// Generate extension
|
|
||||||
TagsGenerator.writeExtensionFiles(sections: sections,
|
|
||||||
target: options.target,
|
|
||||||
tags: ["ios", "iosonly", Self.noTranslationTag],
|
|
||||||
staticVar: options.staticMembers,
|
|
||||||
extensionName: options.extensionName,
|
|
||||||
extensionFilePath: options.extensionFilePath)
|
|
||||||
|
|
||||||
print("[\(Self.toolName)] Tags generated")
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Requirements
|
|
||||||
|
|
||||||
private func checkRequirements() -> Bool {
|
|
||||||
let fileManager = FileManager()
|
|
||||||
|
|
||||||
// Input file
|
|
||||||
guard fileManager.fileExists(atPath: options.inputFile) else {
|
|
||||||
let error = StringiumError.fileNotExists(options.inputFile)
|
|
||||||
print(error.description)
|
|
||||||
Stringium.exit(withError: error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if needed to regenerate
|
|
||||||
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration,
|
|
||||||
inputFilePath: options.inputFile,
|
|
||||||
extensionFilePath: options.extensionFilePath) else {
|
|
||||||
print("[\(Self.toolName)] Tags are already up to date :) ")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Tags {
|
|
||||||
enum TargetType: CaseIterable {
|
|
||||||
case matomo
|
|
||||||
case firebase
|
|
||||||
|
|
||||||
var value: String {
|
|
||||||
switch self {
|
|
||||||
case .matomo:
|
|
||||||
"matomo"
|
|
||||||
case .firebase:
|
|
||||||
"firebase"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// TagDefinitionTests.swift
|
// AnalyticsDefinitionTests.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Loris Perret on 06/12/2023.
|
// Created by Loris Perret on 06/12/2023.
|
||||||
@ -10,44 +10,13 @@ import XCTest
|
|||||||
|
|
||||||
@testable import ResgenSwift
|
@testable import ResgenSwift
|
||||||
|
|
||||||
final class TagDefinitionTests: XCTestCase {
|
final class AnalyticsDefinitionTests: XCTestCase {
|
||||||
|
|
||||||
// MARK: - Match line
|
|
||||||
|
|
||||||
func testMatchingTagDefinition() {
|
|
||||||
// Given
|
|
||||||
let line = "[definition_name]"
|
|
||||||
|
|
||||||
// When
|
|
||||||
let definition = TagDefinition.match(line)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertNotNil(definition)
|
|
||||||
XCTAssertEqual(definition?.title, "definition_name")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testNotMatchingTagDefinition() {
|
|
||||||
// Given
|
|
||||||
let line1 = "definition_name"
|
|
||||||
let line2 = "[definition_name"
|
|
||||||
let line3 = "definition_name]"
|
|
||||||
|
|
||||||
// When
|
|
||||||
let definition1 = TagDefinition.match(line1)
|
|
||||||
let definition2 = TagDefinition.match(line2)
|
|
||||||
let definition3 = TagDefinition.match(line3)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertNil(definition1)
|
|
||||||
XCTAssertNil(definition2)
|
|
||||||
XCTAssertNil(definition3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Matching tags
|
// MARK: - Matching tags
|
||||||
|
|
||||||
func testMatchingTags() {
|
func testMatchingAnalyticss() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "", type: .screen)
|
||||||
definition.tags = ["ios","iosonly","notranslation"]
|
definition.tags = ["ios","iosonly","notranslation"]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@ -62,9 +31,9 @@ final class TagDefinitionTests: XCTestCase {
|
|||||||
XCTAssertTrue(match3)
|
XCTAssertTrue(match3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNotMatchingTags() {
|
func testNotMatchingAnalyticss() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "", type: .screen)
|
||||||
definition.tags = ["ios","iosonly","notranslation"]
|
definition.tags = ["ios","iosonly","notranslation"]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@ -82,10 +51,8 @@ final class TagDefinitionTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedRawPropertyScreen() {
|
func testGeneratedRawPropertyScreen() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "Ecran un", type: .screen)
|
||||||
definition.path = "ecran_un/"
|
|
||||||
definition.name = "Ecran un"
|
|
||||||
definition.type = "screen"
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let propertyScreen = definition.getProperty()
|
let propertyScreen = definition.getProperty()
|
||||||
@ -102,10 +69,7 @@ final class TagDefinitionTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedRawPropertyEvent() {
|
func testGeneratedRawPropertyEvent() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "Ecran un", type: .screen)
|
||||||
definition.path = "ecran_un/"
|
|
||||||
definition.name = "Ecran un"
|
|
||||||
definition.type = "event"
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let propertyEvent = definition.getProperty()
|
let propertyEvent = definition.getProperty()
|
||||||
@ -122,10 +86,7 @@ final class TagDefinitionTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedRawStaticPropertyScreen() {
|
func testGeneratedRawStaticPropertyScreen() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "Ecran un", type: .screen)
|
||||||
definition.path = "ecran_un/"
|
|
||||||
definition.name = "Ecran un"
|
|
||||||
definition.type = "screen"
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let propertyScreen = definition.getStaticProperty()
|
let propertyScreen = definition.getStaticProperty()
|
||||||
@ -142,10 +103,7 @@ final class TagDefinitionTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedRawStaticPropertyEvent() {
|
func testGeneratedRawStaticPropertyEvent() {
|
||||||
// Given
|
// Given
|
||||||
let definition = TagDefinition(title: "definition_name")
|
let definition = AnalyticsDefinition(id: "definition_name", name: "Ecran un", type: .screen)
|
||||||
definition.path = "ecran_un/"
|
|
||||||
definition.name = "Ecran un"
|
|
||||||
definition.type = "event"
|
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let propertyEvent = definition.getStaticProperty()
|
let propertyEvent = definition.getStaticProperty()
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// TagsGeneratorTests.swift
|
// AnalyticsGeneratorTests.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Thibaut Schmitt on 06/09/2022.
|
// Created by Thibaut Schmitt on 06/09/2022.
|
||||||
@ -11,46 +11,43 @@ import ToolCore
|
|||||||
|
|
||||||
@testable import ResgenSwift
|
@testable import ResgenSwift
|
||||||
|
|
||||||
final class TagsGeneratorTests: XCTestCase {
|
final class AnalyticsGeneratorTests: XCTestCase {
|
||||||
|
|
||||||
private func getTagDefinition(title: String, path: String, name: String, type: String, tags: [String]) -> TagDefinition {
|
private func getAnalyticsDefinition(id: String, path: String, name: String, type: AnalyticsDefinition.TagType, tags: [String]) -> AnalyticsDefinition {
|
||||||
let definition = TagDefinition(title: title)
|
let definition = AnalyticsDefinition(id: id, name: name, type: type)
|
||||||
definition.path = path
|
|
||||||
definition.name = name
|
|
||||||
definition.type = type
|
|
||||||
definition.tags = tags
|
definition.tags = tags
|
||||||
return definition
|
return definition
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGeneratedExtensionContentFirebase() {
|
func testGeneratedExtensionContentFirebase() {
|
||||||
// Given
|
// Given
|
||||||
let sectionOne = TagSection(name: "section_one")
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
sectionOne.definitions = [
|
sectionOne.definitions = [
|
||||||
getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios", "iosonly"]),
|
||||||
getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: AnalyticsDefinition.TagType.event, tags: ["ios", "iosonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionTwo = TagSection(name: "section_two")
|
let sectionTwo = AnalyticsCategory(id: "section_two")
|
||||||
sectionTwo.definitions = [
|
sectionTwo.definitions = [
|
||||||
getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]),
|
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios","iosonly"]),
|
||||||
getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionThree = TagSection(name: "section_three")
|
let sectionThree = AnalyticsCategory(id: "section_three")
|
||||||
sectionThree.definitions = [
|
sectionThree.definitions = [
|
||||||
getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: AnalyticsDefinition.TagType.screen, tags: ["droid","droidonly"]),
|
||||||
getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
TagsGenerator.targets = [Tags.TargetType.firebase]
|
AnalyticsGenerator.targets = [Analytics.TargetType.firebase]
|
||||||
let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
tags: ["ios", "iosonly"],
|
tags: ["ios", "iosonly"],
|
||||||
staticVar: false,
|
staticVar: false,
|
||||||
extensionName: "GenTags")
|
extensionName: "GenAnalytics")
|
||||||
// Expect Tags
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Tags 1.2
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Firebase
|
import Firebase
|
||||||
@ -138,33 +135,33 @@ final class TagsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedExtensionContentMatomo() {
|
func testGeneratedExtensionContentMatomo() {
|
||||||
// Given
|
// Given
|
||||||
let sectionOne = TagSection(name: "section_one")
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
sectionOne.definitions = [
|
sectionOne.definitions = [
|
||||||
getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios", "iosonly"]),
|
||||||
getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: AnalyticsDefinition.TagType.event, tags: ["ios", "iosonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionTwo = TagSection(name: "section_two")
|
let sectionTwo = AnalyticsCategory(id: "section_two")
|
||||||
sectionTwo.definitions = [
|
sectionTwo.definitions = [
|
||||||
getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]),
|
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios","iosonly"]),
|
||||||
getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionThree = TagSection(name: "section_three")
|
let sectionThree = AnalyticsCategory(id: "section_three")
|
||||||
sectionThree.definitions = [
|
sectionThree.definitions = [
|
||||||
getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: AnalyticsDefinition.TagType.screen, tags: ["droid","droidonly"]),
|
||||||
getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
TagsGenerator.targets = [Tags.TargetType.matomo]
|
AnalyticsGenerator.targets = [Analytics.TargetType.matomo]
|
||||||
let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
tags: ["ios", "iosonly"],
|
tags: ["ios", "iosonly"],
|
||||||
staticVar: false,
|
staticVar: false,
|
||||||
extensionName: "GenTags")
|
extensionName: "GenAnalytics")
|
||||||
// Expect Tags
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Tags 1.2
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
@ -287,33 +284,33 @@ final class TagsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
func testGeneratedExtensionContentMatomoAndFirebase() {
|
func testGeneratedExtensionContentMatomoAndFirebase() {
|
||||||
// Given
|
// Given
|
||||||
let sectionOne = TagSection(name: "section_one")
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
sectionOne.definitions = [
|
sectionOne.definitions = [
|
||||||
getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios", "iosonly"]),
|
||||||
getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]),
|
getAnalyticsDefinition(id: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: AnalyticsDefinition.TagType.event, tags: ["ios", "iosonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionTwo = TagSection(name: "section_two")
|
let sectionTwo = AnalyticsCategory(id: "section_two")
|
||||||
sectionTwo.definitions = [
|
sectionTwo.definitions = [
|
||||||
getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]),
|
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: AnalyticsDefinition.TagType.screen, tags: ["ios","iosonly"]),
|
||||||
getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
let sectionThree = TagSection(name: "section_three")
|
let sectionThree = AnalyticsCategory(id: "section_three")
|
||||||
sectionThree.definitions = [
|
sectionThree.definitions = [
|
||||||
getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: AnalyticsDefinition.TagType.screen, tags: ["droid","droidonly"]),
|
||||||
getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]),
|
getAnalyticsDefinition(id: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: AnalyticsDefinition.TagType.event, tags: ["droid","droidonly"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
// When
|
// When
|
||||||
TagsGenerator.targets = [Tags.TargetType.matomo, Tags.TargetType.firebase]
|
AnalyticsGenerator.targets = [Analytics.TargetType.matomo, Analytics.TargetType.firebase]
|
||||||
let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
let extensionContent = AnalyticsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
tags: ["ios", "iosonly"],
|
tags: ["ios", "iosonly"],
|
||||||
staticVar: false,
|
staticVar: false,
|
||||||
extensionName: "GenTags")
|
extensionName: "GenAnalytics")
|
||||||
// Expect Tags
|
// Expect Analytics
|
||||||
let expect = """
|
let expect = """
|
||||||
// Generated by ResgenSwift.Tags 1.2
|
// Generated by ResgenSwift.Analytics 1.2
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MatomoTracker
|
import MatomoTracker
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// TagSectionTests.swift
|
// AnalyticsSectionTests.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Loris Perret on 06/12/2023.
|
// Created by Loris Perret on 06/12/2023.
|
||||||
@ -10,53 +10,21 @@ import XCTest
|
|||||||
|
|
||||||
@testable import ResgenSwift
|
@testable import ResgenSwift
|
||||||
|
|
||||||
final class TagSectionTests: XCTestCase {
|
final class AnalyticsSectionTests: XCTestCase {
|
||||||
|
|
||||||
// MARK: - Match line
|
|
||||||
|
|
||||||
func testMatchingTagSection() {
|
|
||||||
// Given
|
|
||||||
let line = "[[section_name]]"
|
|
||||||
|
|
||||||
// When
|
|
||||||
let section = TagSection.match(line)
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertNotNil(section)
|
|
||||||
XCTAssertEqual(section?.name, "section_name")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testNotMatchingTagSection() {
|
|
||||||
// Given
|
|
||||||
let lines = ["section_name",
|
|
||||||
"[section_name]",
|
|
||||||
"[section_name",
|
|
||||||
"[[section_name",
|
|
||||||
"[[section_name]",
|
|
||||||
"section_name]",
|
|
||||||
"section_name]]",
|
|
||||||
"[section_name]]"]
|
|
||||||
|
|
||||||
// When
|
|
||||||
let matches = lines.compactMap { TagSection.match($0) }
|
|
||||||
|
|
||||||
// Expect
|
|
||||||
XCTAssertEqual(matches.isEmpty, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Matching tags
|
// MARK: - Matching tags
|
||||||
|
|
||||||
func testMatchingTags() {
|
func testMatchingAnalytics() {
|
||||||
// Given
|
// Given
|
||||||
let section = TagSection(name: "section_name")
|
let section = AnalyticsCategory(id: "section_name")
|
||||||
section.definitions = [
|
section.definitions = [
|
||||||
{
|
{
|
||||||
let def = TagDefinition(title: "definition_name")
|
let def = AnalyticsDefinition(id: "definition_name", name: "", type: .screen)
|
||||||
def.tags = ["ios","iosonly"]
|
def.tags = ["ios","iosonly"]
|
||||||
return def
|
return def
|
||||||
}(),
|
}(),
|
||||||
{
|
{
|
||||||
let def = TagDefinition(title: "definition_name_two")
|
let def = AnalyticsDefinition(id: "definition_name_two", name: "", type: .screen)
|
||||||
def.tags = ["droid","droidonly"]
|
def.tags = ["droid","droidonly"]
|
||||||
return def
|
return def
|
||||||
}()
|
}()
|
||||||
@ -75,17 +43,17 @@ final class TagSectionTests: XCTestCase {
|
|||||||
XCTAssertTrue(match4)
|
XCTAssertTrue(match4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNotMatchingTags() {
|
func testNotMatchingAnalytics() {
|
||||||
// Given
|
// Given
|
||||||
let section = TagSection(name: "section_name")
|
let section = AnalyticsCategory(id: "section_name")
|
||||||
section.definitions = [
|
section.definitions = [
|
||||||
{
|
{
|
||||||
let def = TagDefinition(title: "definition_name")
|
let def = AnalyticsDefinition(id: "definition_name", name: "", type: .screen)
|
||||||
def.tags = ["ios","iosonly"]
|
def.tags = ["ios","iosonly"]
|
||||||
return def
|
return def
|
||||||
}(),
|
}(),
|
||||||
{
|
{
|
||||||
let def = TagDefinition(title: "definition_name_two")
|
let def = AnalyticsDefinition(id: "definition_name_two", name: "", type: .screen)
|
||||||
def.tags = ["droid","droidonly"]
|
def.tags = ["droid","droidonly"]
|
||||||
return def
|
return def
|
||||||
}()
|
}()
|
Loading…
x
Reference in New Issue
Block a user