make-mp-data 1.2.21 → 1.2.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +19 -1
- package/index.js +30 -17
- package/models/complex.js +143 -16
- package/models/deepNest.js +4 -4
- package/models/simple.js +6 -3
- package/package.json +6 -4
- package/tests/unit.test.js +19 -27
- package/types.d.ts +56 -56
- package/utils.js +6 -59
package/.vscode/settings.json
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cSpell.words": [
|
|
3
|
+
"AVCHD",
|
|
4
|
+
"chupacabra",
|
|
5
|
+
"darr",
|
|
6
|
+
"dislikers",
|
|
7
|
+
"Dont",
|
|
8
|
+
"jackalope",
|
|
9
|
+
"mbembe",
|
|
10
|
+
"megalodon",
|
|
11
|
+
"Miley",
|
|
12
|
+
"mokele",
|
|
13
|
+
"mothman",
|
|
14
|
+
"nessie",
|
|
15
|
+
"nesty",
|
|
16
|
+
"planthopper",
|
|
17
|
+
"psyllid",
|
|
18
|
+
"tatzelwurm",
|
|
3
19
|
"timesoup",
|
|
4
|
-
"unparse"
|
|
20
|
+
"unparse",
|
|
21
|
+
"Vlogs",
|
|
22
|
+
"weindgo"
|
|
5
23
|
],
|
|
6
24
|
"jest.runMode": "on-demand",
|
|
7
25
|
"jest.jestCommandLine": "npm run test --",
|
package/index.js
CHANGED
|
@@ -41,7 +41,7 @@ async function main(config) {
|
|
|
41
41
|
superProps = { platform: ["web", "iOS", "Android"] },
|
|
42
42
|
userProps = {
|
|
43
43
|
favoriteColor: ["red", "green", "blue", "yellow"],
|
|
44
|
-
spiritAnimal: chance.animal,
|
|
44
|
+
spiritAnimal: chance.animal.bind(chance),
|
|
45
45
|
},
|
|
46
46
|
scdProps = { NPS: u.weightedRange(0, 10, 150, 1.6) },
|
|
47
47
|
groupKeys = [],
|
|
@@ -54,6 +54,7 @@ async function main(config) {
|
|
|
54
54
|
region = "US",
|
|
55
55
|
writeToDisk = false,
|
|
56
56
|
verbose = false,
|
|
57
|
+
hook = (record) => record,
|
|
57
58
|
} = config;
|
|
58
59
|
VERBOSE = verbose;
|
|
59
60
|
config.simulationName = makeName();
|
|
@@ -97,11 +98,11 @@ async function main(config) {
|
|
|
97
98
|
.filter((e) => !e.isFirstEvent);
|
|
98
99
|
|
|
99
100
|
const firstEvents = events.filter((e) => e.isFirstEvent);
|
|
100
|
-
const eventData = [];
|
|
101
|
-
const userProfilesData = [];
|
|
102
|
-
let scdTableData = [];
|
|
103
|
-
const groupProfilesData = [];
|
|
104
|
-
const lookupTableData = [];
|
|
101
|
+
const eventData = enrichArray([], { hook, type: "event", config });
|
|
102
|
+
const userProfilesData = enrichArray([], { hook, type: "user", config });
|
|
103
|
+
let scdTableData = enrichArray([], { hook, type: "scd", config });
|
|
104
|
+
const groupProfilesData = enrichArray([], { hook, type: "groups", config });
|
|
105
|
+
const lookupTableData = enrichArray([], { hook, type: "lookups", config });
|
|
105
106
|
const avgEvPerUser = Math.floor(numEvents / numUsers);
|
|
106
107
|
|
|
107
108
|
//user loop
|
|
@@ -110,15 +111,15 @@ async function main(config) {
|
|
|
110
111
|
u.progress("users", i);
|
|
111
112
|
const user = generateUser();
|
|
112
113
|
const { distinct_id, $created, anonymousIds, sessionIds } = user;
|
|
113
|
-
userProfilesData.
|
|
114
|
+
userProfilesData.hPush(makeProfile(userProps, user));
|
|
114
115
|
const mutations = chance.integer({ min: 1, max: 10 });
|
|
115
|
-
scdTableData.
|
|
116
|
+
scdTableData.hPush(makeSCD(scdProps, distinct_id, mutations, $created));
|
|
116
117
|
const numEventsThisUser = Math.round(
|
|
117
118
|
chance.normal({ mean: avgEvPerUser, dev: avgEvPerUser / u.integer(3, 7) })
|
|
118
119
|
);
|
|
119
|
-
|
|
120
|
+
|
|
120
121
|
if (firstEvents.length) {
|
|
121
|
-
eventData.
|
|
122
|
+
eventData.hPush(
|
|
122
123
|
makeEvent(
|
|
123
124
|
distinct_id,
|
|
124
125
|
anonymousIds,
|
|
@@ -134,7 +135,7 @@ async function main(config) {
|
|
|
134
135
|
|
|
135
136
|
//event loop
|
|
136
137
|
for (let j = 0; j < numEventsThisUser; j++) {
|
|
137
|
-
eventData.
|
|
138
|
+
eventData.hPush(
|
|
138
139
|
makeEvent(
|
|
139
140
|
distinct_id,
|
|
140
141
|
anonymousIds,
|
|
@@ -163,11 +164,11 @@ async function main(config) {
|
|
|
163
164
|
const group = {
|
|
164
165
|
[groupKey]: i,
|
|
165
166
|
...makeProfile(groupProps[groupKey]),
|
|
166
|
-
$distinct_id: i,
|
|
167
|
+
// $distinct_id: i,
|
|
167
168
|
};
|
|
168
169
|
groupProfiles.push(group);
|
|
169
170
|
}
|
|
170
|
-
groupProfilesData.
|
|
171
|
+
groupProfilesData.hPush({ key: groupKey, data: groupProfiles });
|
|
171
172
|
}
|
|
172
173
|
log("\n");
|
|
173
174
|
|
|
@@ -183,7 +184,7 @@ async function main(config) {
|
|
|
183
184
|
};
|
|
184
185
|
data.push(item);
|
|
185
186
|
}
|
|
186
|
-
lookupTableData.
|
|
187
|
+
lookupTableData.hPush({ key, data });
|
|
187
188
|
}
|
|
188
189
|
const { eventFiles, userFiles, scdFiles, groupFiles, lookupFiles, folder } =
|
|
189
190
|
buildFileNames(config);
|
|
@@ -194,7 +195,7 @@ async function main(config) {
|
|
|
194
195
|
[groupFiles, groupProfilesData],
|
|
195
196
|
[lookupFiles, lookupTableData],
|
|
196
197
|
];
|
|
197
|
-
log("\n")
|
|
198
|
+
log("\n");
|
|
198
199
|
log(`---------------SIMULATION----------------`, "\n");
|
|
199
200
|
|
|
200
201
|
if (!writeToDisk && !token) {
|
|
@@ -445,6 +446,18 @@ function buildFileNames(config) {
|
|
|
445
446
|
}
|
|
446
447
|
|
|
447
448
|
|
|
449
|
+
function enrichArray(arr = [], opts = {}) {
|
|
450
|
+
const { hook = a => a, type = "", config = {} } = opts;
|
|
451
|
+
|
|
452
|
+
function transformThenPush(item) {
|
|
453
|
+
return arr.push(hook(item, type, config));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
arr.hPush = transformThenPush;
|
|
457
|
+
|
|
458
|
+
return arr;
|
|
459
|
+
};
|
|
460
|
+
|
|
448
461
|
|
|
449
462
|
|
|
450
463
|
// this is for CLI
|
|
@@ -489,8 +502,8 @@ if (require.main === module) {
|
|
|
489
502
|
main(config)
|
|
490
503
|
.then((data) => {
|
|
491
504
|
log(`-----------------SUMMARY-----------------`);
|
|
492
|
-
const d = {success: 0, bytes: 0};
|
|
493
|
-
const darr = [d]
|
|
505
|
+
const d = { success: 0, bytes: 0 };
|
|
506
|
+
const darr = [d];
|
|
494
507
|
const { events = d, groups = darr, users = d } = data.import;
|
|
495
508
|
const files = data.files;
|
|
496
509
|
const folder = files?.pop();
|
package/models/complex.js
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
const Chance = require('chance');
|
|
10
10
|
const chance = new Chance();
|
|
11
|
-
const { weightedRange,
|
|
11
|
+
const { weightedRange, date, integer } = require('../utils.js');
|
|
12
|
+
const u = require('ak-tools');
|
|
12
13
|
|
|
13
14
|
/** @type {import('../types.js').Config} */
|
|
14
15
|
const config = {
|
|
@@ -28,26 +29,24 @@ const config = {
|
|
|
28
29
|
"weight": 2,
|
|
29
30
|
"properties": {
|
|
30
31
|
amount: weightedRange(5, 500, 1000, .25),
|
|
31
|
-
currency: ["USD", "CAD", "EUR", "BTC", "ETH", "JPY"],
|
|
32
|
-
cart: makeProducts,
|
|
32
|
+
currency: ["USD", "USD", "USD", "CAD", "EUR", "EUR", "BTC", "BTC", "ETH", "JPY"],
|
|
33
|
+
cart: makeProducts(12),
|
|
33
34
|
}
|
|
34
35
|
},
|
|
35
36
|
{
|
|
36
37
|
"event": "add to cart",
|
|
37
38
|
"weight": 4,
|
|
38
39
|
"properties": {
|
|
39
|
-
isFeaturedItem: [true, false, false],
|
|
40
40
|
amount: weightedRange(5, 500, 1000, .25),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
product_id: weightedRange(1, 1000)
|
|
41
|
+
qty: integer(1, 5),
|
|
42
|
+
product_id: weightedRange(1, 1000, 42, 1.4)
|
|
44
43
|
}
|
|
45
44
|
},
|
|
46
45
|
{
|
|
47
46
|
"event": "page view",
|
|
48
47
|
"weight": 10,
|
|
49
48
|
"properties": {
|
|
50
|
-
page: ["/", "/", "/
|
|
49
|
+
page: ["/", "/", "/", "/learn-more", "/pricing", "/contact", "/about", "/careers", "/sign-up", "/login", "/app", "/app", "/app", "/app"],
|
|
51
50
|
utm_source: ["$organic", "$organic", "$organic", "$organic", "google", "google", "google", "facebook", "facebook", "twitter", "linkedin"],
|
|
52
51
|
}
|
|
53
52
|
},
|
|
@@ -68,7 +67,7 @@ const config = {
|
|
|
68
67
|
"event": "view item",
|
|
69
68
|
"weight": 8,
|
|
70
69
|
"properties": {
|
|
71
|
-
product_id: weightedRange(1, 1000),
|
|
70
|
+
product_id: weightedRange(1, 1000, 24, 3),
|
|
72
71
|
colors: ["light", "dark", "custom", "dark"]
|
|
73
72
|
}
|
|
74
73
|
},
|
|
@@ -76,22 +75,33 @@ const config = {
|
|
|
76
75
|
"event": "save item",
|
|
77
76
|
"weight": 5,
|
|
78
77
|
"properties": {
|
|
79
|
-
product_id: weightedRange(1, 1000),
|
|
78
|
+
product_id: weightedRange(1, 1000, 8, 12),
|
|
80
79
|
colors: ["light", "dark", "custom", "dark"]
|
|
81
80
|
}
|
|
82
81
|
},
|
|
82
|
+
{
|
|
83
|
+
"event": "support ticket",
|
|
84
|
+
"weight": 2,
|
|
85
|
+
"properties": {
|
|
86
|
+
product_id: weightedRange(1, 1000, 420, .6),
|
|
87
|
+
description: chance.sentence.bind(chance),
|
|
88
|
+
severity: ["low", "medium", "high"],
|
|
89
|
+
ticket_id: chance.guid.bind(chance)
|
|
90
|
+
}
|
|
91
|
+
},
|
|
83
92
|
{
|
|
84
93
|
"event": "sign up",
|
|
85
94
|
"isFirstEvent": true,
|
|
86
95
|
"weight": 0,
|
|
87
96
|
"properties": {
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
plan: ["free", "free", "free", "free", "basic", "basic", "basic", "premium", "premium", "enterprise"],
|
|
98
|
+
dateOfRenewal: date(100, false),
|
|
99
|
+
codewords: u.makeName,
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
],
|
|
93
103
|
superProps: {
|
|
94
|
-
|
|
104
|
+
device: deviceAttributes()
|
|
95
105
|
// emotions: generateEmoji(),
|
|
96
106
|
|
|
97
107
|
},
|
|
@@ -102,8 +112,12 @@ const config = {
|
|
|
102
112
|
userProps: {
|
|
103
113
|
title: chance.profession.bind(chance),
|
|
104
114
|
luckyNumber: weightedRange(42, 420),
|
|
105
|
-
|
|
106
|
-
spiritAnimal:
|
|
115
|
+
experiment: designExperiment(),
|
|
116
|
+
spiritAnimal: ["unicorn", "dragon", "phoenix", "sasquatch", "yeti", "kraken", "jackalope", "thunderbird", "mothman", "nessie", "chupacabra", "jersey devil", "bigfoot", "weindgo", "bunyip", "mokele-mbembe", "tatzelwurm", "megalodon"],
|
|
117
|
+
timezone: chance.timezone.bind(chance), // ["America/New_York", "America/Los_Angeles", "America/Chicago", "America/Denver", "America/Phoenix", "America/Anchorage", "Pacific/Honolulu"]
|
|
118
|
+
ip: chance.ip.bind(chance),
|
|
119
|
+
lastCart: makeProducts(5),
|
|
120
|
+
|
|
107
121
|
},
|
|
108
122
|
|
|
109
123
|
scdProps: {
|
|
@@ -127,8 +141,9 @@ const config = {
|
|
|
127
141
|
$name: () => { return chance.company(); },
|
|
128
142
|
$email: () => { return `CSM: ${chance.pickone(["AK", "Jessica", "Michelle", "Dana", "Brian", "Dave"])}`; },
|
|
129
143
|
"# of employees": weightedRange(3, 10000),
|
|
130
|
-
"
|
|
144
|
+
"industry": ["tech", "finance", "healthcare", "education", "government", "non-profit"],
|
|
131
145
|
"segment": ["enterprise", "SMB", "mid-market"],
|
|
146
|
+
"products": [["core"], ["core"], ["core", "add-ons"], ["core", "pro-serve"], ["core", "add-ons", "pro-serve"], ["core", "BAA", "enterprise"], ["free"], ["free"], ["free", "addons"]],
|
|
132
147
|
}
|
|
133
148
|
},
|
|
134
149
|
|
|
@@ -172,6 +187,118 @@ const config = {
|
|
|
172
187
|
|
|
173
188
|
}
|
|
174
189
|
],
|
|
190
|
+
|
|
191
|
+
hook: function (record, type, meta) {
|
|
192
|
+
return record;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
function makeHashTags() {
|
|
199
|
+
const possibleHashtags = [];
|
|
200
|
+
for (let i = 0; i < 20; i++) {
|
|
201
|
+
possibleHashtags.push('#' + u.makeName(2, ''));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const numHashtags = integer(integer(1, 5), integer(5, 10));
|
|
205
|
+
const hashtags = [];
|
|
206
|
+
for (let i = 0; i < numHashtags; i++) {
|
|
207
|
+
hashtags.push(chance.pickone(possibleHashtags));
|
|
208
|
+
}
|
|
209
|
+
return [hashtags];
|
|
175
210
|
};
|
|
176
211
|
|
|
212
|
+
function makeProducts(maxItems = 10) {
|
|
213
|
+
|
|
214
|
+
return function () {
|
|
215
|
+
const categories = ["Device Accessories", "eBooks", "Automotive", "Baby Products", "Beauty", "Books", "Camera & Photo", "Cell Phones & Accessories", "Collectible Coins", "Consumer Electronics", "Entertainment Collectibles", "Fine Art", "Grocery & Gourmet Food", "Health & Personal Care", "Home & Garden", "Independent Design", "Industrial & Scientific", "Accessories", "Major Appliances", "Music", "Musical Instruments", "Office Products", "Outdoors", "Personal Computers", "Pet Supplies", "Software", "Sports", "Sports Collectibles", "Tools & Home Improvement", "Toys & Games", "Video, DVD & Blu-ray", "Video Games", "Watches"];
|
|
216
|
+
const slugs = ['/sale/', '/featured/', '/home/', '/search/', '/wishlist/', '/'];
|
|
217
|
+
const assetExtension = ['.png', '.jpg', '.jpeg', '.heic', '.mp4', '.mov', '.avi'];
|
|
218
|
+
const data = [];
|
|
219
|
+
const numOfItems = integer(1, 12);
|
|
220
|
+
|
|
221
|
+
for (var i = 0; i < numOfItems; i++) {
|
|
222
|
+
const category = chance.pickone(categories);
|
|
223
|
+
const slug = chance.pickone(slugs);
|
|
224
|
+
const asset = chance.pickone(assetExtension);
|
|
225
|
+
const product_id = chance.guid();
|
|
226
|
+
const price = integer(1, 300);
|
|
227
|
+
const quantity = integer(1, 5);
|
|
228
|
+
|
|
229
|
+
const item = {
|
|
230
|
+
product_id: product_id,
|
|
231
|
+
sku: integer(11111, 99999),
|
|
232
|
+
amount: price,
|
|
233
|
+
quantity: quantity,
|
|
234
|
+
value: price * quantity,
|
|
235
|
+
featured: chance.pickone([true, false]),
|
|
236
|
+
category: category,
|
|
237
|
+
urlSlug: slug + category,
|
|
238
|
+
asset: `${category}-${integer(1, 20)}${asset}`
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
data.push(item);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return [data];
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
function designExperiment() {
|
|
250
|
+
return function () {
|
|
251
|
+
const variants = ["A", "B", "C", "Control"];
|
|
252
|
+
const variant = chance.pickone(variants);
|
|
253
|
+
const experiments = ["no password", "social sign in", "new tutorial", "new search"];
|
|
254
|
+
const experiment = chance.pickone(experiments);
|
|
255
|
+
const multi_variates = ["A/B", "A/B/C", "A/B/C/D", "Control"];
|
|
256
|
+
const multi_variate = chance.pickone(multi_variates);
|
|
257
|
+
const impression_id = chance.guid();
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
const chosen = {
|
|
262
|
+
variant,
|
|
263
|
+
experiment,
|
|
264
|
+
multi_variate,
|
|
265
|
+
impression_id
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
return [chosen];
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function deviceAttributes(isMobile = false) {
|
|
273
|
+
return function () {
|
|
274
|
+
let devices = ["desktop", "laptop", "desktop", "laptop", "desktop", "laptop", "other"];
|
|
275
|
+
if (isMobile) devices = [...devices, "mobile", "mobile", "mobile", "tablet"];
|
|
276
|
+
const device = chance.pickone(devices);
|
|
277
|
+
const oses = ["Windows", "macOS", "Windows", "macOS", "macOS", "Linux", "Windows", "macOS", "Windows", "macOS", "macOS", "TempleOS"];
|
|
278
|
+
if (isMobile) oses = [...oses, "iOS", "Android", "iOS", "Android"];
|
|
279
|
+
const os = chance.pickone(oses);
|
|
280
|
+
const browser = chance.pickone(["Chrome", "Firefox", "Safari", "Edge", "Opera", "IE", "Brave", "Vivaldi"]);
|
|
281
|
+
const version = chance.integer({ min: 1, max: 15 });
|
|
282
|
+
const resolution = chance.pickone(["1920x1080", "1280x720", "1024x768", "800x600", "640x480"]);
|
|
283
|
+
const language = chance.pickone(["en-US", "en-US", "en-US", "en-GB", "es", "es", "fr", "de", "it", "ja", "zh", "ru"]);
|
|
284
|
+
|
|
285
|
+
const chosen = {
|
|
286
|
+
platform: device,
|
|
287
|
+
os,
|
|
288
|
+
browser,
|
|
289
|
+
version,
|
|
290
|
+
resolution,
|
|
291
|
+
language
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
return [chosen];
|
|
295
|
+
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
177
304
|
module.exports = config;
|
package/models/deepNest.js
CHANGED
|
@@ -38,8 +38,8 @@ function generateVideoMeta() {
|
|
|
38
38
|
observedLatencyTimestamps: chance.pickset([].range(1, 300000), int(1, 40))
|
|
39
39
|
},
|
|
40
40
|
videoStats: {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
numberOfPlays: int(10, 10000000),
|
|
42
|
+
isRecommendedVideo: chance.bool(),
|
|
43
43
|
inPlaylists: chance.pickset(hashtags, int(1, hashtags.length)),
|
|
44
44
|
likers: chance.n(chance.guid, int(3, 100)),
|
|
45
45
|
dislikers: chance.n(chance.guid, int(3, 100)),
|
|
@@ -49,12 +49,12 @@ function generateVideoMeta() {
|
|
|
49
49
|
hashtags: chance.pickset(hashtags, int(1, 10)),
|
|
50
50
|
category: chance.pickone(categories),
|
|
51
51
|
},
|
|
52
|
-
|
|
52
|
+
availability: {
|
|
53
53
|
hasAdvertisements: chance.bool(),
|
|
54
54
|
canBeSeenOnPlans: chance.pickset(plans, int(1, plans.length)),
|
|
55
55
|
releaseInfo: {
|
|
56
56
|
isReleased: chance.bool({ likelihood: 90 }),
|
|
57
|
-
|
|
57
|
+
releaseDate: chance.date({ year: 2021 })
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
package/models/simple.js
CHANGED
|
@@ -4,7 +4,7 @@ const dayjs = require("dayjs");
|
|
|
4
4
|
const utc = require("dayjs/plugin/utc");
|
|
5
5
|
dayjs.extend(utc);
|
|
6
6
|
const { uid, comma } = require('ak-tools');
|
|
7
|
-
const { weighList, weightedRange, date, integer } = require('../utils')
|
|
7
|
+
const { weighList, weightedRange, date, integer } = require('../utils');
|
|
8
8
|
|
|
9
9
|
const itemCategories = ["Books", "Movies", "Music", "Games", "Electronics", "Computers", "Smart Home", "Home", "Garden", "Pet", "Beauty", "Health", "Toys", "Kids", "Baby", "Handmade", "Sports", "Outdoors", "Automotive", "Industrial", "Entertainment", "Art", "Food", "Appliances", "Office", "Wedding", "Software"];
|
|
10
10
|
|
|
@@ -114,10 +114,10 @@ const config = {
|
|
|
114
114
|
userProps: {
|
|
115
115
|
title: chance.profession.bind(chance),
|
|
116
116
|
luckyNumber: weightedRange(42, 420),
|
|
117
|
-
spiritAnimal:
|
|
117
|
+
spiritAnimal: ["duck", "dog", "otter", "penguin", "cat", "elephant", "lion", "cheetah", "giraffe", "zebra", "rhino", "hippo", "whale", "dolphin", "shark", "octopus", "squid", "jellyfish", "starfish", "seahorse", "crab", "lobster", "shrimp", "clam", "snail", "slug", "butterfly", "moth", "bee", "wasp", "ant", "beetle", "ladybug", "caterpillar", "centipede", "millipede", "scorpion", "spider", "tarantula", "tick", "mite", "mosquito", "fly", "dragonfly", "damselfly", "grasshopper", "cricket", "locust", "mantis", "cockroach", "termite", "praying mantis", "walking stick", "stick bug", "leaf insect", "lacewing", "aphid", "cicada", "thrips", "psyllid", "scale insect", "whitefly", "mealybug", "planthopper", "leafhopper", "treehopper", "flea", "louse", "bedbug", "flea beetle", "weevil", "longhorn beetle", "leaf beetle", "tiger beetle", "ground beetle", "lady beetle", "firefly", "click beetle", "rove beetle", "scarab beetle", "dung beetle", "stag beetle", "rhinoceros beetle", "hercules beetle", "goliath beetle", "jewel beetle", "tortoise beetle"]
|
|
118
118
|
},
|
|
119
119
|
|
|
120
|
-
scdProps: {
|
|
120
|
+
scdProps: {},
|
|
121
121
|
|
|
122
122
|
/*
|
|
123
123
|
for group analytics keys, we need an array of arrays [[],[],[]]
|
|
@@ -126,6 +126,9 @@ const config = {
|
|
|
126
126
|
groupKeys: [],
|
|
127
127
|
groupProps: {},
|
|
128
128
|
lookupTables: [],
|
|
129
|
+
hook: function (record, type, meta) {
|
|
130
|
+
return record;
|
|
131
|
+
}
|
|
129
132
|
};
|
|
130
133
|
|
|
131
134
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-mp-data",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.25",
|
|
4
4
|
"description": "builds all mixpanel primitives for a given project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node index.js",
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
"dev": "./scripts/go.sh",
|
|
10
|
+
"complex": "nodemon index.js --complex",
|
|
11
|
+
"simple": "nodemon index.js",
|
|
12
|
+
"prune": "rm ./data/*",
|
|
11
13
|
"post": "npm publish",
|
|
12
14
|
"test": "jest --runInBand",
|
|
13
15
|
"deps": "sh ./scripts/deps.sh"
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
},
|
|
39
41
|
"homepage": "https://github.com/ak--47/make-mp-data#readme",
|
|
40
42
|
"dependencies": {
|
|
41
|
-
"ak-tools": "^1.0.
|
|
43
|
+
"ak-tools": "^1.0.57",
|
|
42
44
|
"chance": "^1.1.11",
|
|
43
45
|
"dayjs": "^1.11.11",
|
|
44
46
|
"mixpanel-import": "^2.5.51",
|
package/tests/unit.test.js
CHANGED
|
@@ -55,16 +55,6 @@ describe('utils', () => {
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
test('hashtags', () => {
|
|
59
|
-
const hashtags = makeHashTags();
|
|
60
|
-
expect(hashtags).toBeInstanceOf(Array);
|
|
61
|
-
expect(hashtags).not.toHaveLength(0);
|
|
62
|
-
hashtags.forEach(tag => {
|
|
63
|
-
expect(tag).toMatch(/^#/);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
|
|
68
58
|
|
|
69
59
|
test('person: fields', () => {
|
|
70
60
|
const generatedPerson = person();
|
|
@@ -74,19 +64,19 @@ describe('utils', () => {
|
|
|
74
64
|
});
|
|
75
65
|
|
|
76
66
|
|
|
77
|
-
test('date: past
|
|
67
|
+
test('date: past', () => {
|
|
78
68
|
const pastDate = date(10, true, 'YYYY-MM-DD')();
|
|
79
69
|
expect(dayjs(pastDate, 'YYYY-MM-DD').isValid()).toBeTruthy();
|
|
80
70
|
expect(dayjs(pastDate).isBefore(dayjs())).toBeTruthy();
|
|
81
71
|
});
|
|
82
72
|
|
|
83
|
-
test('date: future
|
|
73
|
+
test('date: future', () => {
|
|
84
74
|
const futureDate = date(10, false, 'YYYY-MM-DD')();
|
|
85
75
|
expect(dayjs(futureDate, 'YYYY-MM-DD').isValid()).toBeTruthy();
|
|
86
76
|
expect(dayjs(futureDate).isAfter(dayjs())).toBeTruthy();
|
|
87
77
|
});
|
|
88
78
|
|
|
89
|
-
test('dates:
|
|
79
|
+
test('dates: pairs', () => {
|
|
90
80
|
const datePairs = dates(10, 3, 'YYYY-MM-DD');
|
|
91
81
|
expect(datePairs).toBeInstanceOf(Array);
|
|
92
82
|
expect(datePairs).toHaveLength(3);
|
|
@@ -95,18 +85,18 @@ describe('utils', () => {
|
|
|
95
85
|
});
|
|
96
86
|
});
|
|
97
87
|
|
|
98
|
-
test('choose:
|
|
88
|
+
test('choose: array', () => {
|
|
99
89
|
const options = ['apple', 'banana', 'cherry'];
|
|
100
90
|
const choice = choose(options);
|
|
101
91
|
expect(options).toContain(choice);
|
|
102
92
|
});
|
|
103
93
|
|
|
104
|
-
test('choose:
|
|
94
|
+
test('choose: function', () => {
|
|
105
95
|
const result = choose(() => 'test');
|
|
106
96
|
expect(result).toBe('test');
|
|
107
97
|
});
|
|
108
98
|
|
|
109
|
-
test('exhaust:
|
|
99
|
+
test('exhaust: elements', () => {
|
|
110
100
|
const arr = [1, 2, 3];
|
|
111
101
|
const exhaustFn = exhaust([...arr]);
|
|
112
102
|
expect(exhaustFn()).toBe(1);
|
|
@@ -115,25 +105,21 @@ describe('utils', () => {
|
|
|
115
105
|
expect(exhaustFn()).toBeUndefined();
|
|
116
106
|
});
|
|
117
107
|
|
|
118
|
-
test('generateEmoji: returns string of emojis', () => {
|
|
119
|
-
const emojis = generateEmoji(5)();
|
|
120
|
-
expect(typeof emojis).toBe('string');
|
|
121
|
-
expect(emojis.split(', ').length).toBeLessThanOrEqual(5);
|
|
122
|
-
});
|
|
123
108
|
|
|
124
|
-
|
|
109
|
+
|
|
110
|
+
test('unique keys', () => {
|
|
125
111
|
const objects = [{ a: 1, b: 2 }, { a: 3, c: 4 }, { a: 5, b: 6 }];
|
|
126
112
|
const uniqueKeys = getUniqueKeys(objects);
|
|
127
113
|
expect(uniqueKeys).toEqual(expect.arrayContaining(['a', 'b', 'c']));
|
|
128
114
|
});
|
|
129
115
|
|
|
130
116
|
|
|
131
|
-
test('date
|
|
117
|
+
test('date', () => {
|
|
132
118
|
const result = date();
|
|
133
119
|
expect(dayjs(result()).isValid()).toBe(true);
|
|
134
120
|
});
|
|
135
121
|
|
|
136
|
-
test('dates
|
|
122
|
+
test('dates', () => {
|
|
137
123
|
const result = dates();
|
|
138
124
|
expect(result).toBeInstanceOf(Array);
|
|
139
125
|
expect(result.length).toBe(5); // Assuming default numPairs is 5
|
|
@@ -145,7 +131,7 @@ describe('utils', () => {
|
|
|
145
131
|
});
|
|
146
132
|
});
|
|
147
133
|
|
|
148
|
-
test('day
|
|
134
|
+
test('day', () => {
|
|
149
135
|
const start = '2020-01-01';
|
|
150
136
|
const end = '2020-01-30';
|
|
151
137
|
const result = day(start, end);
|
|
@@ -154,7 +140,7 @@ describe('utils', () => {
|
|
|
154
140
|
expect(dayjs(dayResult.day).isBefore(dayjs(dayResult.end))).toBe(true);
|
|
155
141
|
});
|
|
156
142
|
|
|
157
|
-
test('exhaust
|
|
143
|
+
test('exhaust', () => {
|
|
158
144
|
const arr = [1, 2, 3];
|
|
159
145
|
const next = exhaust(arr);
|
|
160
146
|
expect(next()).toBe(1);
|
|
@@ -163,7 +149,13 @@ describe('utils', () => {
|
|
|
163
149
|
expect(next()).toBe(undefined); // or whatever your implementation does after array is exhausted
|
|
164
150
|
});
|
|
165
151
|
|
|
166
|
-
test('
|
|
152
|
+
test('emoji: works', () => {
|
|
153
|
+
const emojis = generateEmoji(5)();
|
|
154
|
+
expect(typeof emojis).toBe('string');
|
|
155
|
+
expect(emojis.split(', ').length).toBeLessThanOrEqual(5);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('emoji: length', () => {
|
|
167
159
|
const result = generateEmoji();
|
|
168
160
|
const emojis = result();
|
|
169
161
|
expect(typeof emojis).toBe('string');
|
package/types.d.ts
CHANGED
|
@@ -1,73 +1,76 @@
|
|
|
1
1
|
declare namespace main {
|
|
2
|
+
type primitives = string | number | boolean | Date | Object;
|
|
3
|
+
type valueValid =
|
|
4
|
+
| primitives
|
|
5
|
+
| primitives[]
|
|
6
|
+
| (() => primitives | primitives[]);
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
8
|
+
export interface Config {
|
|
9
|
+
token?: string;
|
|
10
|
+
seed?: string;
|
|
11
|
+
numDays?: number;
|
|
12
|
+
numEvents?: number;
|
|
13
|
+
numUsers?: number;
|
|
14
|
+
format?: "csv" | "json";
|
|
15
|
+
region?: string;
|
|
16
|
+
events?: EventConfig[];
|
|
17
|
+
superProps?: Record<string, valueValid>;
|
|
18
|
+
userProps?: Record<string, valueValid>;
|
|
19
|
+
scdProps?: Record<string, valueValid>;
|
|
20
|
+
groupKeys?: [string, number][];
|
|
21
|
+
groupProps?: Record<string, GroupProperty>; // Adjust according to usage
|
|
22
|
+
lookupTables?: LookupTable[];
|
|
23
|
+
writeToDisk?: boolean;
|
|
24
|
+
simulationName?: string;
|
|
25
|
+
verbose?: boolean;
|
|
26
|
+
anonIds?: boolean;
|
|
27
|
+
sessionIds?: boolean;
|
|
28
|
+
hook?: Hook;
|
|
29
|
+
}
|
|
5
30
|
|
|
6
|
-
export
|
|
7
|
-
token?: string;
|
|
8
|
-
seed?: string;
|
|
9
|
-
numDays?: number;
|
|
10
|
-
numEvents?: number;
|
|
11
|
-
numUsers?: number;
|
|
12
|
-
format?: "csv" | "json";
|
|
13
|
-
region?: string;
|
|
14
|
-
events?: EventConfig[];
|
|
15
|
-
superProps?: Record<string, valueValid>;
|
|
16
|
-
userProps?: Record<string, valueValid>;
|
|
17
|
-
scdProps?: Record<string, valueValid>;
|
|
18
|
-
groupKeys?: [string, number][];
|
|
19
|
-
groupProps?: Record<string, GroupProperty>; // Adjust according to usage
|
|
20
|
-
lookupTables?: LookupTable[];
|
|
21
|
-
writeToDisk?: boolean;
|
|
22
|
-
simulationName?: string;
|
|
23
|
-
verbose?: boolean;
|
|
24
|
-
anonIds?: boolean;
|
|
25
|
-
sessionIds?: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface EventConfig {
|
|
29
|
-
event?: string;
|
|
30
|
-
weight?: number;
|
|
31
|
-
properties?: {
|
|
32
|
-
[key: string]: valueValid; // Consider refining based on actual properties used
|
|
33
|
-
};
|
|
34
|
-
isFirstEvent?: boolean;
|
|
35
|
-
}
|
|
31
|
+
export type Hook = (record: any, type: string, meta: any) => any;
|
|
36
32
|
|
|
37
|
-
interface
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
interface EventConfig {
|
|
34
|
+
event?: string;
|
|
35
|
+
weight?: number;
|
|
36
|
+
properties?: {
|
|
37
|
+
[key: string]: valueValid; // Consider refining based on actual properties used
|
|
38
|
+
};
|
|
39
|
+
isFirstEvent?: boolean;
|
|
40
|
+
}
|
|
40
41
|
|
|
41
|
-
interface
|
|
42
|
-
key: string;
|
|
43
|
-
entries: number;
|
|
44
|
-
attributes: {
|
|
42
|
+
interface GroupProperty {
|
|
45
43
|
[key?: string]: valueValid;
|
|
46
|
-
}
|
|
47
|
-
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface LookupTable {
|
|
47
|
+
key: string;
|
|
48
|
+
entries: number;
|
|
49
|
+
attributes: {
|
|
50
|
+
[key?: string]: valueValid;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
48
53
|
|
|
49
|
-
type Result = {
|
|
54
|
+
type Result = {
|
|
50
55
|
eventData: {
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
event: any;
|
|
57
|
+
$source: string;
|
|
53
58
|
}[];
|
|
54
59
|
userProfilesData: any[];
|
|
55
60
|
scdTableData: any[];
|
|
56
61
|
groupProfilesData: {
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
key: string;
|
|
63
|
+
data: any[];
|
|
59
64
|
}[];
|
|
60
65
|
lookupTableData: {
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
key: string;
|
|
67
|
+
data: any[];
|
|
63
68
|
}[];
|
|
64
69
|
import?: undefined;
|
|
65
70
|
files?: undefined;
|
|
71
|
+
};
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
74
|
/**
|
|
72
75
|
* Mixpanel Data Generator
|
|
73
76
|
* model events, users, groups, and lookup tables (and SCD props!)
|
|
@@ -75,8 +78,5 @@ type Result = {
|
|
|
75
78
|
* const gen = require('make-mp-data')
|
|
76
79
|
* const dta = gen({writeToDisk: false})
|
|
77
80
|
*/
|
|
78
|
-
declare function main(
|
|
79
|
-
|
|
80
|
-
): Promise<main.Result>;
|
|
81
|
-
export = main;
|
|
82
|
-
|
|
81
|
+
declare function main(config: main.Config): Promise<main.Result>;
|
|
82
|
+
export = main;
|
package/utils.js
CHANGED
|
@@ -92,10 +92,15 @@ function choose(value) {
|
|
|
92
92
|
return chance.pickone(value);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
if (typeof value === 'string') {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
// If it's not a function or array, return it as is
|
|
96
100
|
return value;
|
|
97
101
|
}
|
|
98
102
|
catch (e) {
|
|
103
|
+
console.error(`\n\nerror on value: ${value};\n\n`,e, '\n\n');
|
|
99
104
|
return '';
|
|
100
105
|
}
|
|
101
106
|
}
|
|
@@ -128,63 +133,6 @@ function integer(min, max) {
|
|
|
128
133
|
return 0;
|
|
129
134
|
};
|
|
130
135
|
|
|
131
|
-
function makeHashTags() {
|
|
132
|
-
const popularHashtags = [
|
|
133
|
-
'#GalacticAdventures',
|
|
134
|
-
'#EnchantedExplorations',
|
|
135
|
-
'#MagicalMoments',
|
|
136
|
-
'#EpicQuests',
|
|
137
|
-
'#WonderfulWorlds',
|
|
138
|
-
'#FantasyFrenzy',
|
|
139
|
-
'#MysticalMayhem',
|
|
140
|
-
'#MythicalMarvels',
|
|
141
|
-
'#LegendaryLegends',
|
|
142
|
-
'#DreamlandDiaries',
|
|
143
|
-
'#WhimsicalWonders',
|
|
144
|
-
'#FabledFables'
|
|
145
|
-
];
|
|
146
|
-
|
|
147
|
-
const numHashtags = integer(integer(1, 5), integer(5, 10));
|
|
148
|
-
const hashtags = [];
|
|
149
|
-
for (let i = 0; i < numHashtags; i++) {
|
|
150
|
-
hashtags.push(chance.pickone(popularHashtags));
|
|
151
|
-
}
|
|
152
|
-
return hashtags;
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
function makeProducts() {
|
|
156
|
-
let categories = ["Device Accessories", "eBooks", "Automotive", "Baby Products", "Beauty", "Books", "Camera & Photo", "Cell Phones & Accessories", "Collectible Coins", "Consumer Electronics", "Entertainment Collectibles", "Fine Art", "Grocery & Gourmet Food", "Health & Personal Care", "Home & Garden", "Independent Design", "Industrial & Scientific", "Accessories", "Major Appliances", "Music", "Musical Instruments", "Office Products", "Outdoors", "Personal Computers", "Pet Supplies", "Software", "Sports", "Sports Collectibles", "Tools & Home Improvement", "Toys & Games", "Video, DVD & Blu-ray", "Video Games", "Watches"];
|
|
157
|
-
let slugs = ['/sale/', '/featured/', '/home/', '/search/', '/wishlist/', '/'];
|
|
158
|
-
let assetExtension = ['.png', '.jpg', '.jpeg', '.heic', '.mp4', '.mov', '.avi'];
|
|
159
|
-
let data = [];
|
|
160
|
-
let numOfItems = integer(1, 12);
|
|
161
|
-
|
|
162
|
-
for (var i = 0; i < numOfItems; i++) {
|
|
163
|
-
|
|
164
|
-
let category = chance.pickone(categories);
|
|
165
|
-
let slug = chance.pickone(slugs);
|
|
166
|
-
let asset = chance.pickone(assetExtension);
|
|
167
|
-
let product_id = chance.guid();
|
|
168
|
-
let price = integer(1, 300);
|
|
169
|
-
let quantity = integer(1, 5);
|
|
170
|
-
|
|
171
|
-
let item = {
|
|
172
|
-
product_id: product_id,
|
|
173
|
-
sku: integer(11111, 99999),
|
|
174
|
-
amount: price,
|
|
175
|
-
quantity: quantity,
|
|
176
|
-
value: price * quantity,
|
|
177
|
-
featured: chance.pickone([true, false]),
|
|
178
|
-
category: category,
|
|
179
|
-
urlSlug: slug + category,
|
|
180
|
-
asset: `${category}-${integer(1, 20)}${asset}`
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
data.push(item);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return data;
|
|
187
|
-
};
|
|
188
136
|
|
|
189
137
|
// Box-Muller transform to generate standard normally distributed values
|
|
190
138
|
function boxMullerRandom() {
|
|
@@ -359,8 +307,7 @@ module.exports = {
|
|
|
359
307
|
choose,
|
|
360
308
|
exhaust,
|
|
361
309
|
integer,
|
|
362
|
-
|
|
363
|
-
makeProducts,
|
|
310
|
+
|
|
364
311
|
boxMullerRandom,
|
|
365
312
|
applySkew,
|
|
366
313
|
mapToRange,
|