stack-analyze 1.2.1 → 1.2.2
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/CHANGELOG.md +8 -0
- package/about.js +6 -2
- package/cli.js +42 -18
- package/functions/animeInfo.js +5 -0
- package/functions/bitly.js +5 -0
- package/functions/cryptoList.js +3 -1
- package/functions/gitUser.js +5 -0
- package/functions/hardware.js +89 -186
- package/functions/moviesInfo.js +5 -0
- package/functions/multipleStack.js +8 -2
- package/functions/pageSpeed.js +12 -0
- package/functions/password.js +4 -0
- package/functions/scraping.js +53 -14
- package/functions/singleStack.js +7 -3
- package/functions/twitch.js +49 -14
- package/hash/infoTools.js +46 -0
- package/hash/queryTools.js +5 -34
- package/hash/utilityTools.js +21 -0
- package/package.json +1 -1
- package/scraping.json +6 -0
- package/utils.js +41 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
stack-analyze all version and notable changes, fixed, remove and new additions in code.
|
|
4
4
|
|
|
5
|
+
## version 1.2.2
|
|
6
|
+
### Added
|
|
7
|
+
- add save file function for the tools
|
|
8
|
+
### change
|
|
9
|
+
- change the hash table to unique function in hardware information
|
|
10
|
+
### fixed
|
|
11
|
+
- fixed to unique user to multiple users with split params
|
|
12
|
+
|
|
5
13
|
## version 1.2.1
|
|
6
14
|
### fixed
|
|
7
15
|
- rewrite form arrow functions to named function with export default.
|
package/about.js
CHANGED
|
@@ -84,7 +84,7 @@ const aboutTool = {
|
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
user: "Lunanny",
|
|
87
|
-
details: "
|
|
87
|
+
details: "art director with ADHD."
|
|
88
88
|
}
|
|
89
89
|
];
|
|
90
90
|
|
|
@@ -102,7 +102,11 @@ const aboutTool = {
|
|
|
102
102
|
{
|
|
103
103
|
name: "black metal promotion",
|
|
104
104
|
desc: "promos albums and community"
|
|
105
|
-
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "black metal catalog",
|
|
108
|
+
desc: "promos albums and community"
|
|
109
|
+
},
|
|
106
110
|
];
|
|
107
111
|
|
|
108
112
|
console.clear();
|
package/cli.js
CHANGED
|
@@ -6,7 +6,8 @@ import figlet from "figlet";
|
|
|
6
6
|
|
|
7
7
|
import webTools from "./hash/webTools.js";
|
|
8
8
|
import queryTools from "./hash/queryTools.js";
|
|
9
|
-
import
|
|
9
|
+
import infoTools from "./hash/infoTools.js";
|
|
10
|
+
import utilityTools from "./hash/utilityTools.js";
|
|
10
11
|
import aboutTool from "./about.js";
|
|
11
12
|
|
|
12
13
|
import {
|
|
@@ -14,10 +15,11 @@ import {
|
|
|
14
15
|
menuQueryOpts,
|
|
15
16
|
menuWebOpts,
|
|
16
17
|
menuAboutOpts,
|
|
17
|
-
|
|
18
|
+
menuInfoOpts,
|
|
19
|
+
menuUtilityOpts
|
|
18
20
|
} from "./utils.js";
|
|
19
21
|
|
|
20
|
-
const [
|
|
22
|
+
const [gauge, totalTime, pageSize] = [new Gauge(), 1e4, 9];
|
|
21
23
|
|
|
22
24
|
/** @returns {void} */
|
|
23
25
|
const exitCli = () => {
|
|
@@ -53,30 +55,48 @@ async function infoOpts() {
|
|
|
53
55
|
pageSize,
|
|
54
56
|
name: "info",
|
|
55
57
|
message: "enter a info tool option",
|
|
56
|
-
choices:
|
|
58
|
+
choices: menuInfoOpts
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
info === "return main menu"
|
|
60
62
|
? mainMenu()
|
|
61
|
-
:
|
|
63
|
+
: infoTools[info](returnMain);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
/**
|
|
65
67
|
* @async
|
|
66
68
|
* @returns {Promise<void>}
|
|
67
69
|
*/
|
|
68
|
-
async function
|
|
69
|
-
const {
|
|
70
|
+
async function queryOpts() {
|
|
71
|
+
const { query } = await inquirer.prompt({
|
|
70
72
|
type: "list",
|
|
71
|
-
name: "hardware",
|
|
72
73
|
pageSize,
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
name: "query",
|
|
75
|
+
message: "enter a query tool option",
|
|
76
|
+
choices: menuQueryOpts
|
|
75
77
|
});
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
?
|
|
79
|
-
:
|
|
79
|
+
query === "return main menu"
|
|
80
|
+
? mainMenu()
|
|
81
|
+
: queryTools[query](returnMain);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @async
|
|
86
|
+
* @returns {Promise<void>}
|
|
87
|
+
*/
|
|
88
|
+
async function utilityOpts() {
|
|
89
|
+
const { utility } = await inquirer.prompt({
|
|
90
|
+
type: "list",
|
|
91
|
+
pageSize,
|
|
92
|
+
name: "utility",
|
|
93
|
+
message: "enter a utility tool option",
|
|
94
|
+
choices: menuUtilityOpts
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
utility === "return main menu"
|
|
98
|
+
? mainMenu()
|
|
99
|
+
: utilityTools[utility](returnMain);
|
|
80
100
|
}
|
|
81
101
|
|
|
82
102
|
/**
|
|
@@ -117,13 +137,17 @@ async function mainMenu() {
|
|
|
117
137
|
console.clear();
|
|
118
138
|
webOpts();
|
|
119
139
|
},
|
|
120
|
-
|
|
140
|
+
info() {
|
|
121
141
|
console.clear();
|
|
122
142
|
infoOpts();
|
|
123
143
|
},
|
|
124
|
-
|
|
144
|
+
query() {
|
|
145
|
+
console.clear();
|
|
146
|
+
queryOpts();
|
|
147
|
+
},
|
|
148
|
+
utility() {
|
|
125
149
|
console.clear();
|
|
126
|
-
|
|
150
|
+
utilityOpts();
|
|
127
151
|
},
|
|
128
152
|
about() {
|
|
129
153
|
console.clear();
|
|
@@ -131,7 +155,7 @@ async function mainMenu() {
|
|
|
131
155
|
}
|
|
132
156
|
};
|
|
133
157
|
|
|
134
|
-
option !== "exit" ?menuList[option]() : exitCli();
|
|
158
|
+
option !== "exit" ? menuList[option]() : exitCli();
|
|
135
159
|
}
|
|
136
160
|
|
|
137
161
|
/**
|
|
@@ -146,7 +170,7 @@ async function returnMain() {
|
|
|
146
170
|
message: "do you want go to the main menu?",
|
|
147
171
|
});
|
|
148
172
|
|
|
149
|
-
returnMain ? mainMenu(): exitCli();
|
|
173
|
+
returnMain ? mainMenu() : exitCli();
|
|
150
174
|
} catch (err) {
|
|
151
175
|
console.error(colors.bgRed(err.message));
|
|
152
176
|
}
|
package/functions/animeInfo.js
CHANGED
|
@@ -4,6 +4,9 @@ import { format } from "timeago.js";
|
|
|
4
4
|
import colors from "colors";
|
|
5
5
|
import { printTable } from "console-table-printer";
|
|
6
6
|
|
|
7
|
+
// save anime
|
|
8
|
+
import { stackSave } from "../utils.js";
|
|
9
|
+
|
|
7
10
|
/**
|
|
8
11
|
*
|
|
9
12
|
* @description call the anime serach info
|
|
@@ -36,5 +39,7 @@ export default async function animeSearch(q) {
|
|
|
36
39
|
|
|
37
40
|
|
|
38
41
|
printTable(animeData.slice(0, 10));
|
|
42
|
+
|
|
43
|
+
stackSave(`${q}-results.json`, JSON.stringify(animeData, null, 2));
|
|
39
44
|
} catch (err) { console.error(colors.red(err.message)); }
|
|
40
45
|
}
|
package/functions/bitly.js
CHANGED
|
@@ -3,6 +3,9 @@ import { default as axios } from "axios";
|
|
|
3
3
|
import { format } from "timeago.js";
|
|
4
4
|
import colors from "colors";
|
|
5
5
|
|
|
6
|
+
// save bitly
|
|
7
|
+
import { stackSave } from "../utils.js";
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
*
|
|
8
11
|
* @description call the bitly info data
|
|
@@ -30,6 +33,8 @@ export default async function bitlyInfo(link, token) {
|
|
|
30
33
|
bitly_link: data.link,
|
|
31
34
|
link: data.long_url
|
|
32
35
|
});
|
|
36
|
+
|
|
37
|
+
stackSave("bitly.json", JSON.stringify(data, null, 2));
|
|
33
38
|
} catch (err) {
|
|
34
39
|
console.error(colors.red(err.message));
|
|
35
40
|
}
|
package/functions/cryptoList.js
CHANGED
|
@@ -6,7 +6,7 @@ import colors from "colors";
|
|
|
6
6
|
import { printTable } from "console-table-printer";
|
|
7
7
|
|
|
8
8
|
// currency format
|
|
9
|
-
import { currency } from "../utils.js";
|
|
9
|
+
import { currency, stackSave } from "../utils.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @descripiton call the crypto market list
|
|
@@ -39,6 +39,8 @@ export default async function cryptoMarket() {
|
|
|
39
39
|
|
|
40
40
|
// print table
|
|
41
41
|
printTable(coinList.slice(0, 10));
|
|
42
|
+
|
|
43
|
+
stackSave("crypto-list.json", JSON.stringify(coinList, null, 2));
|
|
42
44
|
} catch (err) {
|
|
43
45
|
// print err message
|
|
44
46
|
console.error(colors.red(err.message));
|
package/functions/gitUser.js
CHANGED
|
@@ -3,6 +3,9 @@ import { default as axios } from "axios";
|
|
|
3
3
|
import { format } from "timeago.js";
|
|
4
4
|
import colors from "colors";
|
|
5
5
|
|
|
6
|
+
// save git user
|
|
7
|
+
import { stackSave } from "../utils.js";
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
*
|
|
8
11
|
* @description call github info user
|
|
@@ -27,6 +30,8 @@ export default async function githubInfo(user) {
|
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
console.table(info);
|
|
33
|
+
|
|
34
|
+
stackSave(`${user}-info.json`, JSON.stringify(info, null, 2))
|
|
30
35
|
} catch(err) {
|
|
31
36
|
console.error(colors.red(err.message));
|
|
32
37
|
}
|
package/functions/hardware.js
CHANGED
|
@@ -8,9 +8,8 @@ import {
|
|
|
8
8
|
bios
|
|
9
9
|
} from "systeminformation";
|
|
10
10
|
import colors from "colors";
|
|
11
|
-
import { printTable } from "console-table-printer";
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
import { stackSave } from "../utils.js";
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
*
|
|
@@ -20,198 +19,102 @@ const timeout = 1e3;
|
|
|
20
19
|
*/
|
|
21
20
|
const gigabyteConvert = (size, base=1073741824) => (size / base).toFixed(2);
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// show results
|
|
41
|
-
console.table({
|
|
42
|
-
manufacturer,
|
|
43
|
-
brand,
|
|
44
|
-
speed,
|
|
45
|
-
cores,
|
|
46
|
-
physicalCores,
|
|
47
|
-
processors,
|
|
48
|
-
vendor,
|
|
49
|
-
family,
|
|
50
|
-
model
|
|
51
|
-
});
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error(colors.red(err.message));
|
|
54
|
-
}
|
|
55
|
-
setTimeout(refreshCallback, timeout);
|
|
56
|
-
},
|
|
57
|
-
async ramMemInfo(refreshCallback) {
|
|
58
|
-
console.clear();
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const {
|
|
62
|
-
total,
|
|
63
|
-
free,
|
|
64
|
-
used,
|
|
65
|
-
active,
|
|
66
|
-
available
|
|
67
|
-
} = await mem();
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @async
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
export default async function hardware() {
|
|
28
|
+
try {
|
|
29
|
+
// Map object
|
|
30
|
+
const hardware = new Map();
|
|
31
|
+
|
|
32
|
+
// info
|
|
33
|
+
const biosInfo = await bios()
|
|
34
|
+
const cpuInfo = await cpu()
|
|
35
|
+
const ram = await mem()
|
|
36
|
+
const os = await osInfo()
|
|
37
|
+
const disks = await diskLayout()
|
|
38
|
+
const { displays, controllers } = await graphics();
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
active_mem: `${gigabyteConvert(active)} GB`,
|
|
75
|
-
available_mem: `${gigabyteConvert(available)} GB`
|
|
76
|
-
});
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.error(colors.red(err.message));
|
|
40
|
+
// omit falsy values
|
|
41
|
+
for(const key in biosInfo) {
|
|
42
|
+
if(!biosInfo[key]) {
|
|
43
|
+
delete biosInfo[key];
|
|
44
|
+
}
|
|
79
45
|
}
|
|
80
|
-
setTimeout(refreshCallback, timeout);
|
|
81
|
-
},
|
|
82
|
-
async osDetail(refreshCallback) {
|
|
83
|
-
console.clear();
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
distro,
|
|
90
|
-
release,
|
|
91
|
-
kernel,
|
|
92
|
-
arch,
|
|
93
|
-
serial,
|
|
94
|
-
uefi
|
|
95
|
-
} = await osInfo();
|
|
96
|
-
|
|
97
|
-
// show results
|
|
98
|
-
console.table({
|
|
99
|
-
hostname,
|
|
100
|
-
platform,
|
|
101
|
-
distro,
|
|
102
|
-
release,
|
|
103
|
-
kernel,
|
|
104
|
-
arch,
|
|
105
|
-
serial,
|
|
106
|
-
uefi
|
|
107
|
-
});
|
|
108
|
-
} catch (err) {
|
|
109
|
-
console.error(colors.red(err.message));
|
|
47
|
+
for(const key in cpuInfo) {
|
|
48
|
+
if(!cpuInfo[key]) {
|
|
49
|
+
delete cpuInfo[key];
|
|
50
|
+
}
|
|
110
51
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
const disks = await diskLayout();
|
|
118
|
-
|
|
119
|
-
const disksList = disks.map(({
|
|
120
|
-
type,
|
|
121
|
-
name,
|
|
122
|
-
vendor,
|
|
123
|
-
size,
|
|
124
|
-
interfaceType
|
|
125
|
-
}) => ({
|
|
126
|
-
type,
|
|
127
|
-
name,
|
|
128
|
-
vendor,
|
|
129
|
-
diskSize: `${gigabyteConvert(size)} GB`,
|
|
130
|
-
interfaceType
|
|
131
|
-
}));
|
|
132
|
-
|
|
133
|
-
printTable(disksList);
|
|
134
|
-
|
|
135
|
-
} catch (err) {
|
|
136
|
-
console.error(colors.red(err.message));
|
|
52
|
+
|
|
53
|
+
for(const key in cpuInfo.cache) {
|
|
54
|
+
if(!cpuInfo.cache[key]) {
|
|
55
|
+
delete cpuInfo.cache[key];
|
|
56
|
+
}
|
|
137
57
|
}
|
|
138
|
-
setTimeout(refreshCallback, timeout);
|
|
139
|
-
},
|
|
140
|
-
async controllerInfo(refreshCallback) {
|
|
141
|
-
console.clear();
|
|
142
58
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
model,
|
|
148
|
-
vendor,
|
|
149
|
-
vram
|
|
150
|
-
}) => ({
|
|
151
|
-
model,
|
|
152
|
-
vendor,
|
|
153
|
-
vramSize: vram < 1024
|
|
154
|
-
? `${vram} MB`
|
|
155
|
-
: `${gigabyteConvert(vram, 1024)} GB`
|
|
156
|
-
}));
|
|
157
|
-
|
|
158
|
-
// show results
|
|
159
|
-
printTable(controllersList);
|
|
160
|
-
} catch (err) {
|
|
161
|
-
console.error(colors.red(err.message));
|
|
59
|
+
for(const key in os) {
|
|
60
|
+
if(!os[key]) {
|
|
61
|
+
delete os[key];
|
|
62
|
+
}
|
|
162
63
|
}
|
|
163
|
-
setTimeout(refreshCallback, timeout);
|
|
164
|
-
},
|
|
165
|
-
async displayInfo(refreshCallback) {
|
|
166
|
-
console.clear();
|
|
167
64
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const displayList = displays.map(({
|
|
172
|
-
model,
|
|
173
|
-
main,
|
|
174
|
-
connection,
|
|
175
|
-
resolutionX,
|
|
176
|
-
resolutionY
|
|
177
|
-
}) => ({
|
|
178
|
-
model,
|
|
179
|
-
main,
|
|
180
|
-
connection,
|
|
181
|
-
resolutionX,
|
|
182
|
-
resolutionY
|
|
183
|
-
}));
|
|
184
|
-
|
|
185
|
-
// show results
|
|
186
|
-
printTable(displayList);
|
|
187
|
-
} catch (err) {
|
|
188
|
-
console.error(colors.red(err.message));
|
|
65
|
+
for(const key in ram) {
|
|
66
|
+
ram[key] = `${gigabyteConvert(ram[key])} GB`;
|
|
189
67
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
68
|
+
|
|
69
|
+
disks.forEach(disk => {
|
|
70
|
+
for(const key in disk) {
|
|
71
|
+
if(!disk[key]) {
|
|
72
|
+
delete disk[key];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if(typeof disk[key] === "number") {
|
|
76
|
+
disk[key] = `${gigabyteConvert(ram[key])} GB`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
controllers.forEach(controller => {
|
|
82
|
+
for(const key in controller) {
|
|
83
|
+
if(!controller[key]) {
|
|
84
|
+
delete controller[key];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if(typeof controller[key] === "number") {
|
|
88
|
+
controller[key] = controller[key] < 1024
|
|
89
|
+
? `${controller[key]} MB`
|
|
90
|
+
: `${gigabyteConvert(controller[key])} GB`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
displays.forEach(display => {
|
|
96
|
+
for(const key in display) {
|
|
97
|
+
if(!display[key]) {
|
|
98
|
+
delete display[key];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// add values
|
|
104
|
+
hardware.set("bios", biosInfo);
|
|
105
|
+
hardware.set("cpu", cpuInfo);
|
|
106
|
+
hardware.set("ram", ram);
|
|
107
|
+
hardware.set("os", os);
|
|
108
|
+
hardware.set("disks", disks);
|
|
109
|
+
hardware.set("graphics", controllers);
|
|
110
|
+
hardware.set("displays", displays);
|
|
194
111
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
console.table({
|
|
204
|
-
releaseDate,
|
|
205
|
-
vendor,
|
|
206
|
-
bios_revision: revision || "no info",
|
|
207
|
-
version
|
|
208
|
-
});
|
|
209
|
-
} catch (err) {
|
|
210
|
-
console.error(colors.red(err.message));
|
|
211
|
-
}
|
|
212
|
-
setTimeout(refreshCallback, timeout);
|
|
112
|
+
// save file
|
|
113
|
+
stackSave("hardware.json", JSON.stringify(Object.fromEntries(hardware), null, 2));
|
|
114
|
+
|
|
115
|
+
// finish
|
|
116
|
+
console.info("finish the hardware information file");
|
|
117
|
+
} catch (err) {
|
|
118
|
+
console.error(colors.red(err.message));
|
|
213
119
|
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// exports modules
|
|
217
|
-
export default hardwareTools;
|
|
120
|
+
}
|
package/functions/moviesInfo.js
CHANGED
|
@@ -3,6 +3,9 @@ import { default as axios } from "axios";
|
|
|
3
3
|
import colors from "colors";
|
|
4
4
|
import { printTable } from "console-table-printer";
|
|
5
5
|
|
|
6
|
+
// save movies
|
|
7
|
+
import { stackSave } from "../utils.js";
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* @description movie info tool
|
|
8
11
|
* @async
|
|
@@ -44,6 +47,8 @@ export default async function movieDB(query, token) {
|
|
|
44
47
|
.filter((data) => data?.release_date);
|
|
45
48
|
|
|
46
49
|
printTable(movieData);
|
|
50
|
+
|
|
51
|
+
stackSave("movie-list.json", JSON.stringify(movieData, null, 2));
|
|
47
52
|
} catch (err) {
|
|
48
53
|
console.error(colors.red(err.message));
|
|
49
54
|
}
|
|
@@ -4,7 +4,7 @@ import { printTable } from "console-table-printer";
|
|
|
4
4
|
import { wappalyzer } from "../api/webApis.js";
|
|
5
5
|
|
|
6
6
|
// list format
|
|
7
|
-
import { listFormat } from "../utils.js";
|
|
7
|
+
import { listFormat, stackSave } from "../utils.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
*
|
|
@@ -19,6 +19,8 @@ export default async function multipleStack(urlList) {
|
|
|
19
19
|
|
|
20
20
|
console.info("multiple websites tech stack \n");
|
|
21
21
|
|
|
22
|
+
const stacks = {};
|
|
23
|
+
|
|
22
24
|
for await (const url of urlList) {
|
|
23
25
|
console.info(url.green);
|
|
24
26
|
|
|
@@ -37,8 +39,12 @@ export default async function multipleStack(urlList) {
|
|
|
37
39
|
};
|
|
38
40
|
});
|
|
39
41
|
|
|
40
|
-
printTable(stackResult);
|
|
42
|
+
printTable(stackResult.slice(0, 10));
|
|
43
|
+
|
|
44
|
+
stacks[url] = stackResult;
|
|
41
45
|
}
|
|
46
|
+
|
|
47
|
+
stackSave("multiple-stack.json", JSON.stringify(stacks, null, 2));
|
|
42
48
|
} catch (err) {
|
|
43
49
|
console.error(colors.red(err.message));
|
|
44
50
|
}
|
package/functions/pageSpeed.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// modules
|
|
2
2
|
import { MultiBar, Presets } from "cli-progress";
|
|
3
|
+
import figlet from "figlet";
|
|
3
4
|
import colors from "colors";
|
|
4
5
|
|
|
6
|
+
// save file
|
|
7
|
+
import { stackSave } from "../utils.js";
|
|
8
|
+
|
|
5
9
|
// pagespeed api
|
|
6
10
|
import { pagespeedApi } from "../api/webApis.js";
|
|
7
11
|
|
|
@@ -66,6 +70,14 @@ export default async function pagespeed(url) {
|
|
|
66
70
|
|
|
67
71
|
// stop multibar
|
|
68
72
|
multibar.stop();
|
|
73
|
+
|
|
74
|
+
const resultTxt = `
|
|
75
|
+
${figlet.textSync(url)} \n
|
|
76
|
+
mobile: ${mobile}/100 \n
|
|
77
|
+
desktop: ${desktop}/100
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
stackSave("pagespeed.txt", resultTxt);
|
|
69
81
|
} catch (err) {
|
|
70
82
|
console.error(colors.red(err.message));
|
|
71
83
|
}
|
package/functions/password.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// save password
|
|
2
|
+
import { stackSave } from "../utils.js";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* It generates a random password
|
|
3
6
|
* @returns {void}
|
|
@@ -17,4 +20,5 @@ export default function genPassword() {
|
|
|
17
20
|
|
|
18
21
|
// print new passwors
|
|
19
22
|
console.info("new password:", password);
|
|
23
|
+
stackSave("password.txt", `new password: ${password}`)
|
|
20
24
|
}
|
package/functions/scraping.js
CHANGED
|
@@ -3,6 +3,9 @@ import { load } from "cheerio";
|
|
|
3
3
|
import colors from "colors";
|
|
4
4
|
import { printTable } from "console-table-printer";
|
|
5
5
|
|
|
6
|
+
// stack save
|
|
7
|
+
import { stackSave } from "../utils.js";
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* @typedef {"title"|"images"|"metadata"|"headings"|"table_heading"|"table_data"|"links"|"cites"} Options
|
|
8
11
|
*
|
|
@@ -15,18 +18,27 @@ export default async function scrape(url, options) {
|
|
|
15
18
|
try {
|
|
16
19
|
const { data } = await axios.get(url);
|
|
17
20
|
const $ = load(data);
|
|
21
|
+
|
|
22
|
+
let result;
|
|
18
23
|
|
|
19
24
|
const scraping = {
|
|
20
|
-
title
|
|
25
|
+
title() {
|
|
26
|
+
result = `url title: ${$("title").text()}`;
|
|
27
|
+
console.info($("title").text());
|
|
28
|
+
},
|
|
21
29
|
images() {
|
|
22
30
|
const imageList = $("img").map((i, el) => ({
|
|
23
31
|
imagePath: $(el).attr("src"),
|
|
24
32
|
imageTitle: $(el).attr("alt")
|
|
25
33
|
})).toArray();
|
|
34
|
+
|
|
35
|
+
result = imageList.length === 0
|
|
36
|
+
? "no found images"
|
|
37
|
+
: imageList;
|
|
26
38
|
|
|
27
|
-
|
|
28
|
-
? console.info(
|
|
29
|
-
: printTable(
|
|
39
|
+
typeof result === "string"
|
|
40
|
+
? console.info(result)
|
|
41
|
+
: printTable(result);
|
|
30
42
|
},
|
|
31
43
|
metadata() {
|
|
32
44
|
const metadataList = $("meta").map((i, el) => ({
|
|
@@ -34,6 +46,8 @@ export default async function scrape(url, options) {
|
|
|
34
46
|
metaContent: $(el).attr("content")
|
|
35
47
|
})).toArray()
|
|
36
48
|
.filter((data) => data?.metaInfo);
|
|
49
|
+
|
|
50
|
+
result = metadataList;
|
|
37
51
|
|
|
38
52
|
printTable(metadataList);
|
|
39
53
|
},
|
|
@@ -42,28 +56,43 @@ export default async function scrape(url, options) {
|
|
|
42
56
|
headingTag: $(el).prop("tagName"),
|
|
43
57
|
headingText: $(el).text()
|
|
44
58
|
})).toArray();
|
|
59
|
+
|
|
60
|
+
result = headingList.length === 0
|
|
61
|
+
? "no found heading tags"
|
|
62
|
+
: headingList;
|
|
45
63
|
|
|
46
|
-
|
|
64
|
+
typeof result === "string"
|
|
65
|
+
? console.info("no found heading tags")
|
|
66
|
+
:printTable(headingList);
|
|
47
67
|
},
|
|
48
68
|
tableHead() {
|
|
49
69
|
const tableHeadList = $("th").map((i, el) => ({
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
thCol: $(el).index(),
|
|
71
|
+
thData: $(el).text()
|
|
52
72
|
})).toArray();
|
|
73
|
+
|
|
74
|
+
result = tableHeadList.length === 0
|
|
75
|
+
? "no found th tags"
|
|
76
|
+
: tableHeadList;
|
|
53
77
|
|
|
54
|
-
|
|
78
|
+
typeof result === "string"
|
|
55
79
|
? console.info("no found th tags")
|
|
56
80
|
: printTable(tableHeadList);
|
|
57
81
|
},
|
|
58
82
|
tableData() {
|
|
59
83
|
const tableColumnList = $("td").map((i, el) => ({
|
|
60
|
-
|
|
61
|
-
|
|
84
|
+
rowID: $(el).parent().index(),
|
|
85
|
+
colID: $(el).index(),
|
|
86
|
+
colData: $(el).text(),
|
|
62
87
|
})).toArray();
|
|
88
|
+
|
|
89
|
+
result = tableColumnList.length === 0
|
|
90
|
+
? "no found td tags"
|
|
91
|
+
: tableColumnList;
|
|
63
92
|
|
|
64
|
-
|
|
65
|
-
? console.info(
|
|
66
|
-
: console.table(
|
|
93
|
+
typeof result === "string"
|
|
94
|
+
? console.info(result)
|
|
95
|
+
: console.table(result.slice(0, 10));
|
|
67
96
|
},
|
|
68
97
|
links() {
|
|
69
98
|
const linkList = $("a").map((i, el) => ({
|
|
@@ -72,6 +101,8 @@ export default async function scrape(url, options) {
|
|
|
72
101
|
})).toArray()
|
|
73
102
|
.filter(({ url }) => url.indexOf("#") !== 0);
|
|
74
103
|
|
|
104
|
+
result = linkList
|
|
105
|
+
|
|
75
106
|
printTable(linkList);
|
|
76
107
|
},
|
|
77
108
|
cites() {
|
|
@@ -80,14 +111,22 @@ export default async function scrape(url, options) {
|
|
|
80
111
|
citeLink: $(el).attr("cite"),
|
|
81
112
|
citeText: $(el).text()
|
|
82
113
|
})).toArray();
|
|
114
|
+
|
|
115
|
+
result = citeList.length === 0
|
|
116
|
+
? "no found q and/or blockquote tags"
|
|
117
|
+
: citeList;
|
|
83
118
|
|
|
84
|
-
|
|
119
|
+
typeof result === "string"
|
|
85
120
|
? console.info("no found q and/or blockquote tags")
|
|
86
121
|
: printTable(citeList);
|
|
87
122
|
}
|
|
88
123
|
};
|
|
89
124
|
|
|
90
125
|
scraping[options]();
|
|
126
|
+
|
|
127
|
+
typeof result === "string"
|
|
128
|
+
? stackSave('scraping.txt', result)
|
|
129
|
+
: stackSave('scraping.json', JSON.stringify(result, null, 2));
|
|
91
130
|
} catch (err) {
|
|
92
131
|
console.error(colors.red(err.message));
|
|
93
132
|
}
|
package/functions/singleStack.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import colors from "colors";
|
|
3
3
|
import { printTable } from "console-table-printer";
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
import { listFormat } from "../utils.js";
|
|
5
|
+
// utils
|
|
6
|
+
import { listFormat, stackSave } from "../utils.js";
|
|
7
|
+
|
|
8
|
+
// wappalyzer
|
|
7
9
|
import { wappalyzer } from "../api/webApis.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -35,7 +37,9 @@ export default async function singleStack(url) {
|
|
|
35
37
|
|
|
36
38
|
console.info(url.green);
|
|
37
39
|
|
|
38
|
-
printTable(stackResult);
|
|
40
|
+
printTable(stackResult.slice(0, 10));
|
|
41
|
+
|
|
42
|
+
stackSave("single-stack.json", JSON.stringify(stackResult, null, 2));
|
|
39
43
|
} catch (err) {
|
|
40
44
|
console.error(colors.red(err.message));
|
|
41
45
|
}
|
package/functions/twitch.js
CHANGED
|
@@ -1,36 +1,71 @@
|
|
|
1
1
|
// modules
|
|
2
2
|
import { default as axios } from "axios";
|
|
3
3
|
import { format } from "timeago.js";
|
|
4
|
+
import { printTable } from "console-table-printer";
|
|
4
5
|
import colors from "colors";
|
|
5
6
|
|
|
7
|
+
// save twitch users
|
|
8
|
+
import { stackSave } from "../utils.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* types for twitch info
|
|
12
|
+
*
|
|
13
|
+
* @typedef {Object} Twitch
|
|
14
|
+
* @property {string} Twitch.twitchUsers
|
|
15
|
+
* @property {string} Twitch.twitchSeparator
|
|
16
|
+
* @property {string} Twitch.twitchToken
|
|
17
|
+
* @property {string} Twitch.twitchClient
|
|
18
|
+
*/
|
|
19
|
+
|
|
6
20
|
/**
|
|
7
|
-
*
|
|
8
21
|
* @description twitch user info
|
|
9
22
|
* @async
|
|
10
|
-
* @param {
|
|
11
|
-
* @param { string } twitchClient - twitch client code
|
|
12
|
-
* @param { string } apiToken - twitch api token
|
|
23
|
+
* @param {Twitch} param
|
|
13
24
|
* @returns { Promise<void> } - return twitch results
|
|
14
25
|
*/
|
|
15
|
-
export default async function twitchInfo(
|
|
26
|
+
export default async function twitchInfo({
|
|
27
|
+
twitchUsers,
|
|
28
|
+
twitchSeparator,
|
|
29
|
+
twitchToken,
|
|
30
|
+
twitchClient
|
|
31
|
+
}) {
|
|
32
|
+
|
|
33
|
+
const userList = twitchUsers.split(twitchSeparator);
|
|
34
|
+
|
|
35
|
+
if(userList.length === 10) {
|
|
36
|
+
console.error("twitch users must be 10".bgRed);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const params = new URLSearchParams();
|
|
40
|
+
|
|
41
|
+
userList.forEach((item) => {
|
|
42
|
+
params.append("login", item);
|
|
43
|
+
});
|
|
16
44
|
|
|
17
45
|
try {
|
|
18
46
|
const { data: twitchData } = await axios.get("https://api.twitch.tv/helix/users", {
|
|
19
|
-
params
|
|
47
|
+
params,
|
|
20
48
|
headers: {
|
|
21
|
-
Authorization: `Bearer ${
|
|
49
|
+
Authorization: `Bearer ${twitchToken}`,
|
|
22
50
|
"Client-Id": twitchClient
|
|
23
51
|
}
|
|
24
52
|
});
|
|
25
53
|
|
|
26
|
-
const result = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
54
|
+
const result = twitchData.data.map(({
|
|
55
|
+
display_name,
|
|
56
|
+
broadcaster_type,
|
|
57
|
+
view_count,
|
|
58
|
+
created_at
|
|
59
|
+
}) => ({
|
|
60
|
+
username: display_name,
|
|
61
|
+
broadcaster: broadcaster_type || "user",
|
|
62
|
+
viewCount: view_count,
|
|
63
|
+
accountDate: new Date(created_at).toLocaleDateString(),
|
|
64
|
+
accountAge: format(created_at)
|
|
65
|
+
}));
|
|
32
66
|
|
|
33
|
-
|
|
67
|
+
printTable(result);
|
|
68
|
+
stackSave("twitch-users.json", JSON.stringify(result, null, 2));
|
|
34
69
|
} catch (err) {
|
|
35
70
|
console.error(colors.red(err));
|
|
36
71
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// inquirer
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
|
|
4
|
+
// functions
|
|
5
|
+
import bitlyInfo from "../functions/bitly.js";
|
|
6
|
+
import cryptoMarket from "../functions/cryptoList.js";
|
|
7
|
+
import githubInfo from "../functions/gitUser.js";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// fields
|
|
11
|
+
import {
|
|
12
|
+
bitlyQuery,
|
|
13
|
+
promptParams,
|
|
14
|
+
promptKey
|
|
15
|
+
} from "../validations/infoValidations.js";
|
|
16
|
+
|
|
17
|
+
const infoTools = {
|
|
18
|
+
github_info(refreshCallback) {
|
|
19
|
+
console.clear();
|
|
20
|
+
inquirer.prompt([
|
|
21
|
+
promptParams("gitUser", "enter a github user for search")
|
|
22
|
+
])
|
|
23
|
+
.then(({ gitUser }) => {
|
|
24
|
+
githubInfo(gitUser);
|
|
25
|
+
setTimeout(refreshCallback, 2e3);
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
bitly_info(refreshCallback) {
|
|
29
|
+
console.clear();
|
|
30
|
+
inquirer.prompt([
|
|
31
|
+
bitlyQuery,
|
|
32
|
+
promptKey("token", "enter a bitly token")
|
|
33
|
+
])
|
|
34
|
+
.then(({ bitlyLink, token }) => {
|
|
35
|
+
bitlyInfo(bitlyLink, token);
|
|
36
|
+
setTimeout(refreshCallback, 2e3);
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
crypto_market(refreshCallback) {
|
|
40
|
+
console.clear();
|
|
41
|
+
cryptoMarket();
|
|
42
|
+
setTimeout(refreshCallback, 5e3);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default infoTools;
|
package/hash/queryTools.js
CHANGED
|
@@ -2,31 +2,19 @@
|
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
|
|
4
4
|
// functions
|
|
5
|
-
import genPassword from "../functions/password.js";
|
|
6
|
-
import bitlyInfo from "../functions/bitly.js";
|
|
7
|
-
import cryptoMarket from "../functions/cryptoList.js";
|
|
8
|
-
import githubInfo from "../functions/gitUser.js";
|
|
9
5
|
import animeSearch from "../functions/animeInfo.js";
|
|
10
6
|
import movieDB from "../functions/moviesInfo.js";
|
|
11
7
|
import twitchInfo from "../functions/twitch.js";
|
|
12
8
|
|
|
13
9
|
// fields
|
|
14
10
|
import {
|
|
15
|
-
bitlyQuery,
|
|
16
11
|
promptParams,
|
|
17
12
|
promptKey
|
|
18
13
|
} from "../validations/infoValidations.js";
|
|
19
14
|
|
|
20
15
|
/** query tools */
|
|
21
16
|
const queryTools = {
|
|
22
|
-
|
|
23
|
-
console.clear();
|
|
24
|
-
inquirer.prompt([promptParams("gitUser", "enter a github user for search")])
|
|
25
|
-
.then(({ gitUser }) => {
|
|
26
|
-
githubInfo(gitUser);
|
|
27
|
-
setTimeout(refreshCallback, 2e3);
|
|
28
|
-
});
|
|
29
|
-
},
|
|
17
|
+
|
|
30
18
|
anime_Search(refreshCallback) {
|
|
31
19
|
console.clear();
|
|
32
20
|
inquirer.prompt([promptParams("query", "")])
|
|
@@ -35,14 +23,6 @@ const queryTools = {
|
|
|
35
23
|
setTimeout(refreshCallback, 2e3);
|
|
36
24
|
});
|
|
37
25
|
},
|
|
38
|
-
bitly_info(refreshCallback) {
|
|
39
|
-
console.clear();
|
|
40
|
-
inquirer.prompt([bitlyQuery, promptKey("token", "enter a bitly token")])
|
|
41
|
-
.then(({ bitlyLink, token }) => {
|
|
42
|
-
bitlyInfo(bitlyLink, token);
|
|
43
|
-
setTimeout(refreshCallback, 2e3);
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
26
|
movie_info(refreshCallback) {
|
|
47
27
|
console.clear();
|
|
48
28
|
inquirer.prompt([
|
|
@@ -57,24 +37,15 @@ const queryTools = {
|
|
|
57
37
|
twitch_info(refreshCallback) {
|
|
58
38
|
console.clear();
|
|
59
39
|
inquirer.prompt([
|
|
60
|
-
promptParams("
|
|
40
|
+
promptParams("twitchSeparator", "enter a separator for split"),
|
|
41
|
+
promptParams("twitchUsers", "enter a twitch user"),
|
|
61
42
|
promptKey("twitchClient", "enter a twitch client ID"),
|
|
62
43
|
promptKey("twitchToken", "enter a twitch token"),
|
|
63
44
|
])
|
|
64
|
-
.then(({
|
|
65
|
-
twitchInfo(
|
|
45
|
+
.then(({ twitchSeparator, twitchUsers, twitchClient, twitchToken }) => {
|
|
46
|
+
twitchInfo({ twitchSeparator, twitchUsers, twitchClient, twitchToken });
|
|
66
47
|
setTimeout(refreshCallback, 2e3);
|
|
67
48
|
});
|
|
68
|
-
},
|
|
69
|
-
crypto_market(refreshCallback) {
|
|
70
|
-
console.clear();
|
|
71
|
-
cryptoMarket();
|
|
72
|
-
setTimeout(refreshCallback, 5e3);
|
|
73
|
-
},
|
|
74
|
-
password(refreshCallback) {
|
|
75
|
-
console.clear();
|
|
76
|
-
genPassword();
|
|
77
|
-
setTimeout(refreshCallback, 3e3);
|
|
78
49
|
}
|
|
79
50
|
};
|
|
80
51
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// functions
|
|
2
|
+
import genPassword from "../functions/password.js";
|
|
3
|
+
import hardware from "../functions/hardware.js";
|
|
4
|
+
|
|
5
|
+
// opts
|
|
6
|
+
import { menuHardwareOpts } from "../utils.js";
|
|
7
|
+
|
|
8
|
+
const utilityTools = {
|
|
9
|
+
password(refreshCallback) {
|
|
10
|
+
console.clear();
|
|
11
|
+
genPassword();
|
|
12
|
+
setTimeout(refreshCallback, 3e3);
|
|
13
|
+
},
|
|
14
|
+
async hardware(refreshCallback) {
|
|
15
|
+
console.clear();
|
|
16
|
+
hardware();
|
|
17
|
+
setTimeout(refreshCallback, 3e3);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default utilityTools;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stack-analyze",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "cli tech stack analyze and pagespeed with node.js using the wappalyzer module. with google pagespeed api, hardware and crypto market",
|
|
6
6
|
"main": "index.mjs",
|
package/scraping.json
ADDED
package/utils.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
|
|
1
3
|
const listFormat = new Intl.ListFormat("en", {
|
|
2
4
|
style: "short",
|
|
3
5
|
type: "conjunction"
|
|
@@ -9,15 +11,24 @@ const currency = new Intl.NumberFormat("en-us", {
|
|
|
9
11
|
|
|
10
12
|
const returnMainOpts = "return main menu";
|
|
11
13
|
|
|
12
|
-
const menuOpts = [
|
|
14
|
+
const menuOpts = [
|
|
15
|
+
"web", "info", "query", "utility", "about", "exit"
|
|
16
|
+
];
|
|
13
17
|
|
|
14
18
|
const menuWebOpts = [
|
|
15
19
|
"single", "multiple", "pagespeed", "scraping", returnMainOpts
|
|
16
20
|
];
|
|
17
21
|
|
|
22
|
+
const menuInfoOpts = [
|
|
23
|
+
"github_info", "crypto_market", "bitly_info", returnMainOpts
|
|
24
|
+
];
|
|
25
|
+
|
|
18
26
|
const menuQueryOpts = [
|
|
19
|
-
"
|
|
20
|
-
|
|
27
|
+
"anime_Search", "movie_info", "twitch_info", returnMainOpts
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const menuUtilityOpts = [
|
|
31
|
+
"hardware", "password", returnMainOpts
|
|
21
32
|
];
|
|
22
33
|
|
|
23
34
|
const menuHardwareOpts = [
|
|
@@ -35,6 +46,30 @@ const scrapingOpts = [
|
|
|
35
46
|
"tableHead", "tableData", "links", "cites"
|
|
36
47
|
];
|
|
37
48
|
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {string} filename
|
|
52
|
+
* @param {any} data
|
|
53
|
+
* @returns {Promise<void>}
|
|
54
|
+
*/
|
|
55
|
+
const stackSave = async (filename, data) => {
|
|
56
|
+
if (!data) {
|
|
57
|
+
console.error("stackSave no using falsy values");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if(typeof data === "boolean") {
|
|
62
|
+
console.info("stackSave no using boolean types");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await writeFile(filename, data);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.info(err.message);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
38
73
|
const exitCli = "thanks for use stack-analyze";
|
|
39
74
|
|
|
40
75
|
export {
|
|
@@ -42,10 +77,13 @@ export {
|
|
|
42
77
|
currency,
|
|
43
78
|
menuOpts,
|
|
44
79
|
menuWebOpts,
|
|
80
|
+
menuInfoOpts,
|
|
45
81
|
menuQueryOpts,
|
|
82
|
+
menuUtilityOpts,
|
|
46
83
|
menuHardwareOpts,
|
|
47
84
|
menuAboutOpts,
|
|
48
85
|
scrapingOpts,
|
|
86
|
+
stackSave,
|
|
49
87
|
exitCli
|
|
50
88
|
};
|
|
51
89
|
|