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 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: "audiovisual student with ADHD."
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 hardwareTools from "./functions/hardware.js";
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
- menuHardwareOpts
18
+ menuInfoOpts,
19
+ menuUtilityOpts
18
20
  } from "./utils.js";
19
21
 
20
- const [ gauge, totalTime, pageSize ] = [ new Gauge(), 1e4, 9 ];
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: menuQueryOpts
58
+ choices: menuInfoOpts
57
59
  });
58
60
 
59
61
  info === "return main menu"
60
62
  ? mainMenu()
61
- : queryTools[info](returnMain);
63
+ : infoTools[info](returnMain);
62
64
  }
63
65
 
64
66
  /**
65
67
  * @async
66
68
  * @returns {Promise<void>}
67
69
  */
68
- async function hardwareOpts() {
69
- const { hardware } = await inquirer.prompt({
70
+ async function queryOpts() {
71
+ const { query } = await inquirer.prompt({
70
72
  type: "list",
71
- name: "hardware",
72
73
  pageSize,
73
- message: "select a hardware-information option:",
74
- choices: menuHardwareOpts
74
+ name: "query",
75
+ message: "enter a query tool option",
76
+ choices: menuQueryOpts
75
77
  });
76
78
 
77
- hardware !== "return main menu"
78
- ? hardwareTools[hardware](hardwareOpts)
79
- : mainMenu();
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
- query() {
140
+ info() {
121
141
  console.clear();
122
142
  infoOpts();
123
143
  },
124
- hardware() {
144
+ query() {
145
+ console.clear();
146
+ queryOpts();
147
+ },
148
+ utility() {
125
149
  console.clear();
126
- hardwareOpts();
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
  }
@@ -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
  }
@@ -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
  }
@@ -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));
@@ -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
  }
@@ -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
- const timeout = 1e3;
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
- const hardwareTools = {
24
- async cpuInfo(refreshCallback) {
25
- console.clear();
26
-
27
- try {
28
- const {
29
- manufacturer,
30
- brand,
31
- speed,
32
- cores,
33
- physicalCores,
34
- processors,
35
- vendor,
36
- family,
37
- model
38
- } = await cpu();
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
- // show results
70
- console.table({
71
- total_mem: `${gigabyteConvert(total)} GB`,
72
- free_mem: `${gigabyteConvert(free)} GB`,
73
- used_mem: `${gigabyteConvert(used)} GB`,
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
- try {
86
- const {
87
- hostname,
88
- platform,
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
- setTimeout(refreshCallback, timeout);
112
- },
113
- async diskInfo(refreshCallback) {
114
- console.clear();
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
- try {
144
- const { controllers } = await graphics();
145
-
146
- const controllersList = controllers.map(({
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
- try {
169
- const { displays } = await graphics();
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
- setTimeout(refreshCallback, timeout);
191
- },
192
- async biosInfo(refreshCallback) {
193
- console.clear();
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
- try {
196
- const {
197
- releaseDate,
198
- vendor,
199
- revision,
200
- version
201
- } = await bios();
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
+ }
@@ -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
  }
@@ -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
  }
@@ -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
  }
@@ -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: () => console.info($("title").text()),
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
- imageList.length === 0
28
- ? console.info("no found images")
29
- : printTable(imageList);
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
- printTable(headingList);
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
- headingRow: i,
51
- text: $(el).text()
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
- tableHeadList.length === 0
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
- tableRow: i + 1,
61
- tableData: $(el).text(),
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
- tableColumnList.length === 0
65
- ? console.info("no found td tags")
66
- : console.table(tableColumnList.slice(0, 10), ["tableData"]);
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
- citeList.length === 0
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
  }
@@ -2,8 +2,10 @@
2
2
  import colors from "colors";
3
3
  import { printTable } from "console-table-printer";
4
4
 
5
- // list format
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
  }
@@ -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 { string } twitchUser - twitch user for search
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(twitchUser, twitchClient, apiToken) {
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: { login: twitchUser },
47
+ params,
20
48
  headers: {
21
- Authorization: `Bearer ${apiToken}`,
49
+ Authorization: `Bearer ${twitchToken}`,
22
50
  "Client-Id": twitchClient
23
51
  }
24
52
  });
25
53
 
26
- const result = {
27
- username: twitchData.data[0].display_name,
28
- broadcaster: twitchData.data[0]?.broadcaster_type || "user",
29
- viewCount: twitchData.data[0].view_count,
30
- accountAge: format(twitchData.data[0].created_at)
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
- console.table(result);
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;
@@ -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
- github_info(refreshCallback) {
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("twitchUser", "enter a twitch user"),
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(({twitchUser, twitchClient, twitchToken}) => {
65
- twitchInfo(twitchUser, twitchClient, twitchToken);
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.1",
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
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "metaInfo": "viewport",
4
+ "metaContent": "width=device-width, initial-scale=1"
5
+ }
6
+ ]
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 = ["web", "query", "hardware", "about", "exit"];
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
- "github_info", "anime_Search", "bitly_info", "movie_info",
20
- "twitch_info", "crypto_market", "password", returnMainOpts
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