make-mp-data 1.3.4 → 1.4.1
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/launch.json +11 -3
- package/.vscode/settings.json +11 -1
- package/README.md +2 -2
- package/chart.js +180 -0
- package/defaults.js +11662 -0
- package/index.js +485 -298
- package/package.json +59 -52
- package/{models → schemas}/complex.js +18 -18
- package/{models → schemas}/foobar.js +1 -1
- package/schemas/funnels.js +221 -0
- package/{models → schemas}/simple.js +10 -10
- package/scratch.mjs +22 -0
- package/testCases.mjs +229 -0
- package/testSoup.mjs +27 -0
- package/tests/e2e.test.js +27 -20
- package/tests/jest.config.js +30 -0
- package/tests/unit.test.js +444 -17
- package/tmp/.gitkeep +0 -0
- package/tsconfig.json +1 -1
- package/types.d.ts +81 -15
- package/utils.js +670 -155
- package/timesoup.js +0 -92
- /package/{models → schemas}/deepNest.js +0 -0
package/.vscode/launch.json
CHANGED
|
@@ -15,7 +15,13 @@
|
|
|
15
15
|
"name": "complex",
|
|
16
16
|
"request": "launch",
|
|
17
17
|
"type": "node-terminal"
|
|
18
|
-
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"command": "npm run dev",
|
|
21
|
+
"name": "dev",
|
|
22
|
+
"request": "launch",
|
|
23
|
+
"type": "node-terminal"
|
|
24
|
+
},
|
|
19
25
|
{
|
|
20
26
|
"type": "node",
|
|
21
27
|
"request": "launch",
|
|
@@ -25,8 +31,10 @@
|
|
|
25
31
|
"restart": true,
|
|
26
32
|
"console": "integratedTerminal",
|
|
27
33
|
"internalConsoleOptions": "neverOpen",
|
|
28
|
-
"args": [
|
|
34
|
+
"args": [
|
|
35
|
+
"--ignore",
|
|
36
|
+
"./data/"
|
|
37
|
+
]
|
|
29
38
|
}
|
|
30
|
-
|
|
31
39
|
]
|
|
32
40
|
}
|
package/.vscode/settings.json
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cSpell.words": [
|
|
3
3
|
"AVCHD",
|
|
4
|
+
"chartjs",
|
|
4
5
|
"chupacabra",
|
|
6
|
+
"Colour",
|
|
7
|
+
"crumn",
|
|
5
8
|
"darr",
|
|
6
9
|
"dislikers",
|
|
7
10
|
"Dont",
|
|
11
|
+
"durtle",
|
|
12
|
+
"fonk",
|
|
13
|
+
"garply",
|
|
8
14
|
"jackalope",
|
|
15
|
+
"linny",
|
|
9
16
|
"mbembe",
|
|
10
17
|
"megalodon",
|
|
11
18
|
"Miley",
|
|
12
19
|
"mokele",
|
|
13
20
|
"mothman",
|
|
21
|
+
"nanodegree",
|
|
14
22
|
"nessie",
|
|
15
23
|
"nesty",
|
|
16
24
|
"planthopper",
|
|
17
25
|
"psyllid",
|
|
18
26
|
"tatzelwurm",
|
|
19
27
|
"timesoup",
|
|
28
|
+
"udacity",
|
|
20
29
|
"unparse",
|
|
21
30
|
"Vlogs",
|
|
22
|
-
"weindgo"
|
|
31
|
+
"weindgo",
|
|
32
|
+
"whomacity"
|
|
23
33
|
],
|
|
24
34
|
"jest.runMode": "on-demand",
|
|
25
35
|
"jest.jestCommandLine": "npm run test --",
|
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ npx make-mp-data ecommSpec.js --token 1234 --numDays 30 --numUsers 1000 --numEve
|
|
|
69
69
|
|
|
70
70
|
### Data Models
|
|
71
71
|
|
|
72
|
-
Check out `./
|
|
72
|
+
Check out `./schemas/` for example `dataModel.js` files to get started quickly.
|
|
73
73
|
|
|
74
74
|
## 🛠️ CLI Options
|
|
75
75
|
|
|
@@ -91,7 +91,7 @@ Here's a breakdown of the CLI options you can use with `make-mp-data`:
|
|
|
91
91
|
Check out the examples directory for sample data models:
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
ls ./
|
|
94
|
+
ls ./schemas/
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
These models provide a great starting point for creating your own custom data generation scripts.
|
package/chart.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const { ChartJSNodeCanvas } = require('chartjs-node-canvas');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const u = require('ak-tools');
|
|
4
|
+
const dayjs = require('dayjs');
|
|
5
|
+
const { openFinder } = require('./utils');
|
|
6
|
+
|
|
7
|
+
const tempDir = u.mkdir('./tmp');
|
|
8
|
+
|
|
9
|
+
// Function to count events per day
|
|
10
|
+
function countDailyEvents(eventData) {
|
|
11
|
+
const dailyCounts = {};
|
|
12
|
+
|
|
13
|
+
eventData.forEach(event => {
|
|
14
|
+
const date = dayjs(event.time).format('YYYY-MM-DD');
|
|
15
|
+
if (!dailyCounts[date]) {
|
|
16
|
+
dailyCounts[date] = 0;
|
|
17
|
+
}
|
|
18
|
+
dailyCounts[date]++;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return dailyCounts;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Function to count daily users
|
|
25
|
+
function countDailyUsers(eventData) {
|
|
26
|
+
const dailyUsers = {};
|
|
27
|
+
|
|
28
|
+
eventData.forEach(event => {
|
|
29
|
+
const date = dayjs(event.time).format('YYYY-MM-DD');
|
|
30
|
+
if (!dailyUsers[date]) {
|
|
31
|
+
dailyUsers[date] = new Set();
|
|
32
|
+
}
|
|
33
|
+
dailyUsers[date].add(event.user_id);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return dailyUsers;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Function to count daily new users based on signup events
|
|
40
|
+
function countDailyNewUsers(eventData, signupEvents) {
|
|
41
|
+
const dailyNewUsers = {};
|
|
42
|
+
const seenUsers = new Set();
|
|
43
|
+
|
|
44
|
+
eventData.forEach(event => {
|
|
45
|
+
const date = dayjs(event.time).format('YYYY-MM-DD');
|
|
46
|
+
if (!dailyNewUsers[date]) {
|
|
47
|
+
dailyNewUsers[date] = new Set();
|
|
48
|
+
}
|
|
49
|
+
if (signupEvents.includes(event.event) && !seenUsers.has(event.user_id)) {
|
|
50
|
+
dailyNewUsers[date].add(event.user_id);
|
|
51
|
+
seenUsers.add(event.user_id);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return dailyNewUsers;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Function to generate line chart
|
|
59
|
+
async function generateLineChart(rawData, signupEvents = ["sign up"], fileName) {
|
|
60
|
+
const width = 1600;
|
|
61
|
+
const height = 1200;
|
|
62
|
+
const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height, backgroundColour: 'black' });
|
|
63
|
+
const eventData = countDailyEvents(rawData);
|
|
64
|
+
const userData = countDailyUsers(rawData);
|
|
65
|
+
const newUserData = countDailyNewUsers(rawData, signupEvents);
|
|
66
|
+
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
const sortedEventEntries = Object.entries(eventData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
|
|
69
|
+
const eventLabels = sortedEventEntries.map(entry => entry[0]);
|
|
70
|
+
const eventValues = sortedEventEntries.map(entry => entry[1]);
|
|
71
|
+
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
const sortedUserEntries = Object.entries(userData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
|
|
74
|
+
const userLabels = sortedUserEntries.map(entry => entry[0]);
|
|
75
|
+
const userValues = sortedUserEntries.map(entry => entry[1].size);
|
|
76
|
+
|
|
77
|
+
// @ts-ignore
|
|
78
|
+
const sortedNewUserEntries = Object.entries(newUserData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
|
|
79
|
+
const newUserLabels = sortedNewUserEntries.map(entry => entry[0]);
|
|
80
|
+
const newUserValues = sortedNewUserEntries.map(entry => entry[1].size);
|
|
81
|
+
|
|
82
|
+
const configuration = {
|
|
83
|
+
type: 'line',
|
|
84
|
+
data: {
|
|
85
|
+
labels: eventLabels,
|
|
86
|
+
datasets: [
|
|
87
|
+
{
|
|
88
|
+
label: '# EVENTS',
|
|
89
|
+
data: eventValues,
|
|
90
|
+
yAxisID: 'y1',
|
|
91
|
+
fill: true,
|
|
92
|
+
borderColor: '#4F44E0',
|
|
93
|
+
tension: 0.1
|
|
94
|
+
},
|
|
95
|
+
// {
|
|
96
|
+
// label: '# USERS',
|
|
97
|
+
// data: userValues,
|
|
98
|
+
// yAxisID: 'y2',
|
|
99
|
+
// fill: true,
|
|
100
|
+
// borderColor: '#E34F2F',
|
|
101
|
+
// tension: 0.1
|
|
102
|
+
// },
|
|
103
|
+
{
|
|
104
|
+
label: '# NEW',
|
|
105
|
+
data: newUserValues,
|
|
106
|
+
yAxisID: 'y3',
|
|
107
|
+
fill: true,
|
|
108
|
+
borderColor: '#219464',
|
|
109
|
+
tension: 0.1
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
options: {
|
|
114
|
+
scales: {
|
|
115
|
+
x: {
|
|
116
|
+
title: {
|
|
117
|
+
display: true,
|
|
118
|
+
text: 'Date',
|
|
119
|
+
color: 'white'
|
|
120
|
+
},
|
|
121
|
+
ticks: {
|
|
122
|
+
color: 'white'
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
y1: {
|
|
126
|
+
type: 'linear',
|
|
127
|
+
display: true,
|
|
128
|
+
position: 'left',
|
|
129
|
+
title: {
|
|
130
|
+
display: true,
|
|
131
|
+
text: 'Count of Events',
|
|
132
|
+
color: '#4F44E0'
|
|
133
|
+
},
|
|
134
|
+
ticks: {
|
|
135
|
+
color: '#4F44E0'
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
y3: {
|
|
139
|
+
type: 'linear',
|
|
140
|
+
display: true,
|
|
141
|
+
position: 'right',
|
|
142
|
+
offset: true,
|
|
143
|
+
title: {
|
|
144
|
+
display: true,
|
|
145
|
+
text: 'Count of New Users',
|
|
146
|
+
color: '#219464'
|
|
147
|
+
},
|
|
148
|
+
ticks: {
|
|
149
|
+
color: '#219464'
|
|
150
|
+
},
|
|
151
|
+
grid: {
|
|
152
|
+
drawOnChartArea: false
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
plugins: {
|
|
157
|
+
legend: {
|
|
158
|
+
labels: {
|
|
159
|
+
color: 'white'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// @ts-ignore
|
|
167
|
+
if (typeof fileName === undefined) fileName = 'chart';
|
|
168
|
+
if (typeof fileName !== 'string') fileName = 'chart';
|
|
169
|
+
// @ts-ignore
|
|
170
|
+
const imageBuffer = await chartJSNodeCanvas.renderToBuffer(configuration);
|
|
171
|
+
const path = `./tmp/${fileName}.png`;
|
|
172
|
+
const removed = await u.rm(path);
|
|
173
|
+
const file = await u.touch(path, imageBuffer);
|
|
174
|
+
|
|
175
|
+
console.log(`Chart saved as ${fileName}.png`);
|
|
176
|
+
openFinder(path)
|
|
177
|
+
return file;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = { generateLineChart };
|