Skip to content

Commit f88d676

Browse files
authored
Breaking changes (#28)
* first pass at refactor * LivePlugin refactor and tests * Runtime initial changes * spec updates round 1 * more fixups. * fixed test warning * fixed warning * remove ds_store * Updated tests * fix syntax error * cleanup
1 parent 7c3ffca commit f88d676

33 files changed

+1916
-706
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,4 @@ Examples/BasicExample/.DS_Store
9999
Sources/.DS_Store
100100

101101
Sources/AnalyticsLive/.DS_Store
102+
.DS_Store

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version: 5.7
1+
// swift-tools-version: 5.9
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -18,7 +18,7 @@ let package = Package(
1818
targets: ["AnalyticsLive"])
1919
],
2020
dependencies: [
21-
.package(url: "https://github.com/segmentio/analytics-swift.git", from: "1.7.2"),
21+
.package(url: "https://github.com/segmentio/analytics-swift.git", from: "1.8.0"),
2222
.package(url: "https://github.com/segmentio/substrata-swift.git", from: "2.0.11"),
2323
//.package(path: "../substrata-swift")
2424
],
@@ -37,9 +37,13 @@ let package = Package(
3737
],
3838
resources: [
3939
.copy("TestHelpers/filterSettings.json"),
40+
.copy("TestHelpers/badSettings.json"),
4041
.copy("TestHelpers/testbundle.js"),
4142
.copy("TestHelpers/addliveplugin.js"),
4243
.copy("TestHelpers/MyEdgeFunctions.js"),
44+
.copy("TestHelpers/badtest.js"),
45+
.copy("TestHelpers/runtimeBundle.js"),
46+
.copy("TestHelpers/runtimeBundleNoProcess.js")
4347
]),
4448
]
4549
)
Lines changed: 106 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
22
// File.swift
3-
//
3+
//
44
//
55
// Created by Brandon Sneed on 5/5/22.
66
//
@@ -14,8 +14,6 @@ public class AnalyticsJS: JSExport {
1414

1515
internal weak var analytics: Analytics?
1616

17-
internal var addedPlugins = [(String?, LivePlugin)]()
18-
1917
internal lazy var currentLivePluginVersion: String? = {
2018
return LivePlugins.currentLivePluginVersion()
2119
}()
@@ -36,60 +34,95 @@ public class AnalyticsJS: JSExport {
3634
Self.existingInstances.removeAll(where: { $0 === self.analytics })
3735
}
3836

37+
3938
static func insertOrigin(event: RawEvent?, data: [String: Any]) -> RawEvent? {
4039
guard var working = event else { return event }
41-
if let newContext = try? working.context?.add(value: data, forKey: "__eventOrigin") {
40+
if let newContext = try? working.context?.add(
41+
value: data,
42+
forKey: "__eventOrigin"
43+
) {
4244
working.context = newContext
4345
}
4446
return working
4547
}
4648

4749
internal func originMarkerEnrichment(event: RawEvent?) -> RawEvent? {
4850
return Self.insertOrigin(event: event, data: [
49-
"type": "signals",
51+
"type": "js",
5052
"version": currentLivePluginVersion ?? ""
5153
])
5254
}
5355

56+
private func contextEnrichment(with context: [String: Any]?) -> EnrichmentClosure {
57+
return { event in
58+
guard var working = event, let context = context else {
59+
return event
60+
}
61+
62+
// Get existing context as dictionary and merge with new context
63+
var mergedContext = working.context?.dictionaryValue ?? [:]
64+
mergedContext.merge(context) { _, new in new }
65+
66+
do {
67+
working.context = try JSON(mergedContext)
68+
} catch {
69+
// If JSON creation fails, return original event
70+
return event
71+
}
72+
return working
73+
}
74+
}
75+
76+
private func enrichments(with context: [String: Any]?) -> [EnrichmentClosure] {
77+
var enrichments = [originMarkerEnrichment]
78+
if let context = context {
79+
enrichments.append(contextEnrichment(with: context))
80+
}
81+
return enrichments
82+
}
83+
5484
internal func setupExports() {
5585
exportProperty(named: "traits") { [weak self] in
56-
guard let self else { return nil }
57-
let traits: [String: Any]? = analytics?.traits()
86+
guard let self, let analytics = self.analytics else { return nil }
87+
let traits: [String: Any]? = analytics.traits()
5888
return traits as? JSConvertible
5989
}
6090

6191
exportProperty(named: "userId") { [weak self] in
62-
guard let self else { return nil }
63-
return analytics?.userId
92+
return self?.analytics?.userId
6493
}
6594

6695
exportProperty(named: "anonymousId") { [weak self] in
67-
guard let self else { return nil }
68-
return analytics?.anonymousId
96+
return self?.analytics?.anonymousId
6997
}
7098

7199
exportMethod(named: "track") { [weak self] in self?.track(args: $0) }
72-
exportMethod(named: "identify") { [weak self] in self?.identify(args: $0) }
100+
exportMethod(named: "identify") {
101+
[weak self] in self?.identify(args: $0)
102+
}
73103
exportMethod(named: "screen") { [weak self] in self?.screen(args: $0) }
74104
exportMethod(named: "group") { [weak self] in self?.group(args: $0) }
75-
exportMethod(named: "alias") { [weak self] in self?.alias(args: $0) }
76105
exportMethod(named: "add") { [weak self] in self?.add(args: $0) }
77106
exportMethod(named: "flush") { [weak self] in self?.flush(args: $0) }
78107
exportMethod(named: "reset") { [weak self] in self?.reset(args: $0) }
79-
exportMethod(named: "removeLivePlugins") { [weak self] in self?.removeLivePlugins(args: $0) }
80108
}
81109

82110
public override func construct(args: [JSConvertible?]) {
83111
if let writeKey = args.typed(as: String.self, index: 0) {
84-
let existing = Self.existingInstances.first(where: { $0.writeKey == writeKey })
112+
let existing = Self.existingInstances.first(
113+
where: { $0.writeKey == writeKey
114+
})
85115
if let existing {
86116
self.analytics = existing
87117
return
88118
} else {
89119
// we do some work on user-created instances to avoid multiple instances of the same write key
90120
// by just attaching whatever existing instance that might exist with that write key.
91-
let createdAnalytics = Analytics(configuration: Configuration(writeKey: writeKey)
92-
.trackApplicationLifecycleEvents(false)
121+
let createdAnalytics = Analytics(
122+
configuration: Configuration(
123+
writeKey: writeKey
124+
)
125+
.setTrackedApplicationLifecycleEvents(.none)
93126
)
94127
Self.existingInstances.append(createdAnalytics)
95128
self.analytics = createdAnalytics
@@ -99,113 +132,109 @@ public class AnalyticsJS: JSExport {
99132

100133
public func track(args: [JSConvertible?]) -> JSConvertible? {
101134
guard let analytics else { return nil }
102-
guard let name = args.typed(as: String.self, index: 0) else { return nil }
103-
let properties = args.typed(as: Dictionary.self, index: 1)
104-
105-
let addEventOrigin: EnrichmentClosure = { [weak self] event in
106-
return Self.insertOrigin(event: event, data: [
107-
"type": "signals",
108-
"version": self?.currentLivePluginVersion ?? ""
109-
])
135+
guard let name = args.typed(as: String.self, index: 0) else {
136+
return nil
110137
}
138+
let properties = args.typed(as: Dictionary.self, index: 1)
139+
let context = args.typed(as: Dictionary.self, index: 2)
111140

112-
analytics.track(name: name, properties: properties, enrichments: [addEventOrigin])
141+
analytics
142+
.track(
143+
name: name,
144+
properties: properties,
145+
enrichments: enrichments(with: context)
146+
)
113147
return nil
114148
}
115149

116150
public func identify(args: [JSConvertible?]) -> JSConvertible? {
117151
guard let analytics else { return nil }
118-
guard let userId = args.typed(as: String.self, index: 0) else { return nil }
152+
guard let userId = args.typed(as: String.self, index: 0) else {
153+
return nil
154+
}
119155
let traits = args.typed(as: Dictionary.self, index: 1)
120-
analytics.identify(userId: userId, traits: traits, enrichments: [originMarkerEnrichment])
156+
let context = args.typed(as: Dictionary.self, index: 2)
157+
analytics
158+
.identify(
159+
userId: userId,
160+
traits: traits,
161+
enrichments: enrichments(with: context)
162+
)
121163
return nil
122164
}
123165

124166
public func screen(args: [JSConvertible?]) -> JSConvertible? {
125167
guard let analytics else { return nil }
126-
guard let title = args.typed(as: String.self, index: 0) else { return nil }
168+
guard let title = args.typed(as: String.self, index: 0) else {
169+
return nil
170+
}
127171
let category = args.typed(as: String.self, index: 1)
128172
let properties = args.typed(as: Dictionary.self, index: 2)
129-
analytics.screen(title: title, category: category, properties: properties, enrichments: [originMarkerEnrichment])
173+
let context = args.typed(as: Dictionary.self, index: 3)
174+
analytics
175+
.screen(
176+
title: title,
177+
category: category,
178+
properties: properties,
179+
enrichments: enrichments(with: context)
180+
)
130181
return nil
182+
131183
}
132184

133185
public func group(args: [JSConvertible?]) -> JSConvertible? {
134186
guard let analytics else { return nil }
135-
guard let groupId = args.typed(as: String.self, index: 0) else { return nil }
187+
guard let groupId = args.typed(as: String.self, index: 0) else {
188+
return nil
189+
}
136190
let traits = args.typed(as: Dictionary.self, index: 1)
137-
analytics.group(groupId: groupId, traits: traits, enrichments: [originMarkerEnrichment])
138-
return nil
139-
}
140-
141-
public func alias(args: [JSConvertible?]) -> JSConvertible? {
142-
guard let analytics else { return nil }
143-
guard let newId = args.typed(as: String.self, index: 0) else { return nil }
144-
analytics.alias(newId: newId, enrichments: [originMarkerEnrichment])
191+
let context = args.typed(as: Dictionary.self, index: 2)
192+
analytics
193+
.group(
194+
groupId: groupId,
195+
traits: traits,
196+
enrichments: enrichments(with: context)
197+
)
145198
return nil
199+
146200
}
147201

148202
public func flush(args: [JSConvertible?]) -> JSConvertible? {
149203
guard let analytics else { return nil }
150204
analytics.flush()
151205
return nil
206+
152207
}
153208

154209
public func reset(args: [JSConvertible?]) -> JSConvertible? {
155210
guard let analytics else { return nil }
156211
analytics.reset()
157212
return nil
213+
158214
}
159215

160216
public func add(args: [JSConvertible?]) -> JSConvertible? {
161-
var result = false
162-
163-
guard let analytics else { return result }
164-
guard let plugin = args.typed(as: JSClass.self, index: 0) else { return result }
217+
guard let analytics else { return nil }
218+
guard let plugin = args.typed(as: JSClass.self, index: 0) else {
219+
return false
220+
}
165221

166222
let type = plugin["type"]?.typed(as: Int.self)
167223
let destination = plugin["destination"]?.typed(as: String.self)
168224

169-
guard let type = type else { return result }
225+
guard let type = type else { return false }
226+
guard let pluginType = PluginType(rawValue: type) else { return false }
170227

171-
guard let pluginType = PluginType(rawValue: type) else { return result }
172228
let edgeFn = LivePlugin(jsPlugin: plugin, type: pluginType)
173229

174230
if let dest = destination {
175231
// we have a destination specified, so add it there
176-
if let d = analytics.find(key: dest) {
177-
//DispatchQueue.main.async {
178-
_ = d.add(plugin: edgeFn)
179-
//}
180-
result = true
181-
self.addedPlugins.append((dest, edgeFn))
182-
}
232+
guard let d = analytics.find(key: dest) else { return false }
233+
_ = d.add(plugin: edgeFn)
234+
return true
183235
} else {
184-
//DispatchQueue.main.async {
185-
_ = analytics.add(plugin: edgeFn)
186-
//}
187-
result = true
188-
self.addedPlugins.append((nil, edgeFn))
236+
_ = analytics.add(plugin: edgeFn)
237+
return true
189238
}
190-
return result
191-
}
192-
193-
public func removeLivePlugins(args: [JSConvertible?]) -> JSConvertible? {
194-
guard let analytics else { return nil }
195-
196-
for tuple in self.addedPlugins {
197-
let (dest, p) = tuple
198-
if let dst = dest {
199-
// Remove from destination
200-
if let d = analytics.find(key: dst) {
201-
d.remove(plugin: p)
202-
}
203-
} else {
204-
// Remove from main timeline
205-
analytics.remove(plugin: p)
206-
}
207-
}
208-
self.addedPlugins.removeAll()
209-
return nil
210239
}
211240
}

Sources/AnalyticsLive/LivePlugins/Bundler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal class Bundler {
1111
static var sessionConfig = URLSessionConfiguration.default
1212

1313
class func getLocalBundleFolderURL() -> URL {
14-
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
14+
let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
1515
var result = paths[0]
1616
result.appendPathComponent("segmentJSBundles")
1717
if let identifier = Bundle.main.bundleIdentifier {

Sources/AnalyticsLive/LivePlugins/EmbeddedJS.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public struct EmbeddedJS {
2323
public static let edgeFnBaseSetupScript = """
2424
class LivePlugin {
2525
constructor(type, destination) {
26-
console.log("js: LivePlugin.constructor() called");
26+
//console.log("js: LivePlugin.constructor() called");
2727
this._type = type;
2828
this._destination = destination;
2929
}
@@ -39,7 +39,7 @@ public struct EmbeddedJS {
3939
update(settings, type) { }
4040
4141
execute(event) {
42-
console.log("js: LivePlugin.execute() called");
42+
//console.log("js: LivePlugin.execute() called");
4343
var result = event;
4444
switch(event.type) {
4545
case "identify":
@@ -66,7 +66,7 @@ public struct EmbeddedJS {
6666
}
6767
6868
track(event) {
69-
console.log("js: Super.track() called");
69+
//console.log("js: Super.track() called");
7070
return event;
7171
}
7272
@@ -79,7 +79,7 @@ public struct EmbeddedJS {
7979
}
8080
8181
screen(event) {
82-
console.log("js: Super.screen() called");
82+
//console.log("js: Super.screen() called");
8383
return event;
8484
}
8585

0 commit comments

Comments
 (0)