stack-analyze 1.2.0 → 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/cli.js CHANGED
@@ -1,432 +1,191 @@
1
1
  #!/usr/bin/env node
2
-
3
- // modules
4
- import { performance } from "perf_hooks";
2
+ import Gauge from "gauge";
3
+ import colors from "colors";
5
4
  import inquirer from "inquirer";
6
5
  import figlet from "figlet";
7
- import colors from "colors";
8
6
 
9
- // hash tables
10
- import hardwareTools from "./functions/hardware.js";
7
+ import webTools from "./hash/webTools.js";
8
+ import queryTools from "./hash/queryTools.js";
9
+ import infoTools from "./hash/infoTools.js";
10
+ import utilityTools from "./hash/utilityTools.js";
11
11
  import aboutTool from "./about.js";
12
12
 
13
- import singleStack from "./functions/singleStack.js";
14
- import multipleStack from "./functions/multipleStack.js";
15
- import pageSpeed from "./functions/pageSpeed.js";
16
- import githubInfo from "./functions/gitUser.js";
17
- import animeSearch from "./functions/animeInfo.js";
18
- import cryptoMarket from "./functions/cryptoList.js";
19
- import bitlyInfo from "./functions/bitly.js";
20
- import movieDB from "./functions/moviesInfo.js";
21
- import twitchInfo from "./functions/twitch.js";
22
- import scrape from "./functions/scraping.js";
23
- import genPassword from "./functions/password.js";
13
+ import {
14
+ menuOpts,
15
+ menuQueryOpts,
16
+ menuWebOpts,
17
+ menuAboutOpts,
18
+ menuInfoOpts,
19
+ menuUtilityOpts
20
+ } from "./utils.js";
21
+
22
+ const [gauge, totalTime, pageSize] = [new Gauge(), 1e4, 9];
23
+
24
+ /** @returns {void} */
25
+ const exitCli = () => {
26
+ console.clear();
27
+ console.info("thanks for use stack-analyze".green);
28
+ };
24
29
 
25
30
  /**
26
- * @description web scraping menu
27
- * @return { Promise<void>} web scraping options
31
+ * @async
32
+ * @returns {Promise<void>}
28
33
  */
29
- async function scrapingOpts (url) {
30
- console.info("web:", url);
31
-
32
- const { option } = await inquirer.prompt({
34
+ async function webOpts() {
35
+ const { web } = await inquirer.prompt({
33
36
  type: "list",
34
- name: "option",
35
- message: "select a options for scraping",
36
- pageSize: 15,
37
- choices: [
38
- "pageTitle",
39
- "pageImages",
40
- "pageMetadata",
41
- "pageHeadings",
42
- "pageTableHead",
43
- "pageTableData",
44
- "pageLinks",
45
- "pageCites",
46
- "exit to main menu"
47
- ]
37
+ pageSize,
38
+ name: "web",
39
+ message: "enter a web tool option",
40
+ choices: menuWebOpts
48
41
  });
49
-
50
- const {
51
- cites,
52
- headings,
53
- images,
54
- links,
55
- title,
56
- metadata,
57
- table_data,
58
- table_heading
59
- } = scrape(url);
60
-
61
- const timeScrape = 2000;
62
42
 
63
- /** @type {Object.<string, function(): void>} */
64
- const scrapeOpt = {
65
- pageTitle() {
66
- title();
67
- setTimeout(returnQuestion, timeScrape);
68
- },
69
- pageImages() {
70
- images();
71
- setTimeout(returnQuestion, timeScrape);
72
- },
73
- pageMetadata() {
74
- metadata();
75
- setTimeout(returnQuestion, timeScrape);
76
- },
77
- pageHeadings() {
78
- headings();
79
- setTimeout(returnQuestion, timeScrape);
80
- },
81
- pageTableHead() {
82
- table_heading();
83
- setTimeout(returnQuestion, timeScrape);
84
- },
85
- pageTableData() {
86
- table_data();
87
- setTimeout(returnQuestion, timeScrape);
88
- },
89
- pageLinks() {
90
- links();
91
- setTimeout(returnQuestion, timeScrape);
92
- },
93
- pageCites() {
94
- cites();
95
- setTimeout(returnQuestion, timeScrape);
96
- },
97
- };
98
-
99
- option === "exit to main menu"
100
- ? question()
101
- : scrapeOpt[option]();
43
+ web !== "return main menu"
44
+ ? webTools[web](returnMain)
45
+ : mainMenu();
102
46
  }
103
47
 
104
48
  /**
105
- * @description web scraping menu
106
- * @return { Promise<void>} web scraping options
49
+ * @async
50
+ * @returns {Promise<void>}
107
51
  */
108
- async function scrapingLink() {
109
- console.clear();
110
- const { link } = await inquirer.prompt({
111
- type: "input",
112
- name: "link",
113
- message: "enter a web scraping options?"
52
+ async function infoOpts() {
53
+ const { info } = await inquirer.prompt({
54
+ type: "list",
55
+ pageSize,
56
+ name: "info",
57
+ message: "enter a info tool option",
58
+ choices: menuInfoOpts
114
59
  });
115
60
 
116
- if(link.indexOf("http") === -1) {
117
- console.error("https:// or http:// is required".red);
118
- setTimeout(question, 5000);
119
- } else {
120
- scrapingOpts(link);
121
- }
61
+ info === "return main menu"
62
+ ? mainMenu()
63
+ : infoTools[info](returnMain);
122
64
  }
123
65
 
124
- /**
125
- * @description about menu
126
- * @return { Promise<void> } about option sections answer
66
+ /**
67
+ * @async
68
+ * @returns {Promise<void>}
127
69
  */
128
- async function aboutOpts() {
129
- const { about } = await inquirer.prompt({
70
+ async function queryOpts() {
71
+ const { query } = await inquirer.prompt({
130
72
  type: "list",
131
- pageSize: 9,
132
- name: "about",
133
- message: "select about option info",
134
- choices: [
135
- "mainInfo",
136
- "lineup",
137
- "youtubeRecomendation",
138
- "twitchRecomendation",
139
- "projectsRecomendation",
140
- "return to main menu"
141
- ]
73
+ pageSize,
74
+ name: "query",
75
+ message: "enter a query tool option",
76
+ choices: menuQueryOpts
142
77
  });
143
78
 
144
- if (about !== "return to main menu") {
145
- aboutTool[about]();
146
- setTimeout(aboutOpts, 1000);
147
- } else {
148
- question();
149
- }
79
+ query === "return main menu"
80
+ ? mainMenu()
81
+ : queryTools[query](returnMain);
150
82
  }
151
83
 
152
84
  /**
153
- *
154
- * @description call the async function return list to question list
155
- * @return { Promise<void> } - return in boolean a result question list
156
- *
85
+ * @async
86
+ * @returns {Promise<void>}
157
87
  */
158
- async function returnQuestion() {
159
- try {
160
- const anw = await inquirer.prompt([
161
- {
162
- type: "confirm",
163
- name: "return",
164
- message: "do you want go to the tools menu?",
165
- }
166
- ]);
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
+ });
167
96
 
168
- if (anw.return) {
169
- console.clear();
170
- question();
171
- } else {
172
- console.clear();
173
- console.info("thanks for use stack-analyze".green);
174
- }
175
- } catch (err) {
176
- console.error(colors.red(err.message));
177
- }
97
+ utility === "return main menu"
98
+ ? mainMenu()
99
+ : utilityTools[utility](returnMain);
178
100
  }
179
101
 
180
102
  /**
181
- * @description This is a hash table with the options of the tools menu.
182
- * @type {Object.<string, function(): void>}
103
+ * @async
104
+ * @returns {Promise<void>}
183
105
  */
184
- const toolsOpts = {
185
- single() {
186
- console.clear();
187
- inquirer.prompt({
188
- name: "url",
189
- message: "enter url for analyze the tech stack:"
190
- }).then(({ url }) => {
191
- if (url.indexOf("http") === 0) {
192
- singleStack(url);
193
- const timeEnd = performance.now();
194
- setTimeout(returnQuestion, timeEnd);
195
- } else {
196
- console.error("please insert a URL with parameter http:// or https://".red);
197
- }
198
- });
199
- },
200
- multiple() {
201
- console.clear();
202
- inquirer.prompt({
203
- name: "urls",
204
- message: "enter URLs for analyze the tech stacks with whitespace without quotes example 'http://example.com https://nodejs.org': \n"
205
- }).then(({ urls }) => {
206
-
207
- if (
208
- urls.match(/(http|https)/g) !== null ||
209
- urls.match(/(http|https)/g) >= 2
210
- ) {
211
- const websites = urls.split(" ");
212
- console.clear();
213
- multipleStack(websites);
214
- const timeEnd = performance.now();
215
- setTimeout(returnQuestion, timeEnd);
216
- } else {
217
- console.error("please in each URL insert a website the parameter https:// or http://".red);
218
- }
219
- });
220
- },
221
- pagespeed() {
222
- console.clear();
223
- inquirer.prompt({
224
- name: "speedWeb",
225
- message: "insert URL for page speed analyze:"
226
- }).then(({ speedWeb }) => {
227
- if (speedWeb.indexOf("http") === 0) {
228
- console.clear();
229
-
230
- // start pagespeed results mobile
231
- figlet.textSync(speedWeb, "Small");
232
- pageSpeed(speedWeb);
233
- const timeEnd = performance.now();
234
- setTimeout(returnQuestion, timeEnd);
235
- } else {
236
- console.error("please insert a URL with parameter https;// or http://".red);
237
- }
238
- });
239
- },
240
- github_info() {
241
- console.clear();
242
- inquirer.prompt({
243
- name: "user",
244
- message: "enter a github user"
245
- }).then(({ user }) => {
246
- if (user !== "") {
247
- console.clear();
248
- githubInfo(user);
249
- setTimeout(returnQuestion, 2000);
250
- } else {
251
- console.error("please the github username is required".red);
252
- }
253
- });
254
- },
255
- anime_search() {
256
- console.clear();
257
- inquirer.prompt({
258
- name: "anime",
259
- message: "enter a anime, movie or ova search"
260
- }).then(({ anime }) => {
261
- if (anime !== "") {
262
- console.clear();
263
- animeSearch(anime);
264
- setTimeout(returnQuestion, 2000);
265
- } else {
266
- console.error("please the anime is required".red);
267
- }
268
- });
269
- },
270
- crypto_market() {
271
- console.clear();
272
- cryptoMarket();
273
- setTimeout(returnQuestion, 5000);
274
- },
275
- password() {
276
- console.clear();
277
- genPassword();
278
- setTimeout(returnQuestion, 3000);
279
- },
280
- bitly_info() {
281
- console.clear();
282
- inquirer.prompt([
283
- {
284
- name: "link",
285
- message: "enter a bitly link without http|https",
286
- },
287
- {
288
- name: "token",
289
- message: "enter a bitly token",
290
- type: "password",
291
- mask: "?"
292
- }
293
- ])
294
- .then(({ link, token }) => {
295
- bitlyInfo(link, token);
296
- setTimeout(returnQuestion, 3000);
297
- });
298
- },
299
- movie_info() {
300
- console.clear();
301
- inquirer.prompt([
302
- {
303
- name: "api_key",
304
- message: "insert api key",
305
- type: "password",
306
- mask: "?"
307
- },
308
- {
309
- name: "query",
310
- message: "please search a movie search",
311
- }
312
- ]).then(({ api_key, query }) => {
313
- console.clear();
314
- movieDB(query, api_key);
315
- setTimeout(returnQuestion, 3000);
316
- });
317
- },
318
- twitch_info() {
319
- console.clear();
320
- inquirer.prompt([
321
- {
322
- name: "user",
323
- message: "get twitch user"
324
- },
325
- {
326
- name: "twitch_client",
327
- message: "enter a twitch token client",
328
- type: "password",
329
- mask: "*"
330
- },
331
- {
332
- name: "twitch_token",
333
- message: "enter a twitch token without the key Bearer",
334
- type: "password",
335
- mask: "?"
336
- }
337
- ]).then(({ user, twitch_client, twitch_token }) => {
338
- if (user !== "" && twitch_client !== "" && twitch_token !== "") {
339
- console.clear();
340
- twitchInfo(user, twitch_client, twitch_token);
341
- setTimeout(returnQuestion, 3000);
342
- } else {
343
- console.error("twitch info fields is required".red);
344
- }
345
- });
346
- }
347
- };
348
-
349
- /**
350
- * @description call hardware information options
351
- * @returns { Promise<void> } hardware options tool
352
- */
353
- async function hardwareOpts() {
354
- const { hardware } = await inquirer.prompt({
106
+ async function aboutOpts() {
107
+ const { about } = await inquirer.prompt({
355
108
  type: "list",
356
- name: "hardware",
357
- pageSize: 9,
358
- message: "select a hardware-information option:",
359
- choices: [
360
- "cpuInfo",
361
- "ramMemInfo",
362
- "osDetail",
363
- "diskInfo",
364
- "controllerInfo",
365
- "displayInfo",
366
- "biosInfo",
367
- "exit to main menu"
368
- ]
109
+ pageSize,
110
+ name: "about",
111
+ message: "select about option info",
112
+ choices: menuAboutOpts
369
113
  });
370
114
 
371
- if (hardware !== "exit to main menu") {
372
- hardwareTools[hardware]();
373
- setTimeout(hardwareOpts, 1000);
374
- } else {
375
- question();
376
- }
115
+ about !== "return main menu"
116
+ ? aboutTool[about](aboutOpts)
117
+ : mainMenu();
377
118
  }
378
119
 
379
120
  /**
380
- *
381
- * @description call the function question raw list options
382
- * @returns { Promise<void> } return exit question
383
- *
121
+ * @async
122
+ * @returns {Promise<void>}
384
123
  */
385
- async function question() {
124
+ async function mainMenu() {
386
125
  console.clear();
387
126
  console.info(colors.yellow(figlet.textSync("stack-analyze")));
388
- const { analyze } = await inquirer.prompt({
127
+
128
+ const { option } = await inquirer.prompt({
389
129
  type: "list",
390
- pageSize: 15,
391
- name: "analyze",
130
+ name: "option",
392
131
  message: "what option do you want to analyze stack",
393
- choices: [
394
- "single",
395
- "multiple",
396
- "pagespeed",
397
- "github_info",
398
- "anime_search",
399
- "crypto_market",
400
- "bitly_info",
401
- "movie_info",
402
- "twitch_info",
403
- "hardware tools",
404
- "scraping",
405
- "password",
406
- "about",
407
- "exit"
408
- ]
132
+ choices: menuOpts
409
133
  });
410
134
 
411
- switch (analyze) {
412
- case "hardware tools":
413
- hardwareOpts();
414
- break;
415
- case "about":
416
- aboutOpts();
417
- break;
418
- case "scraping":
419
- scrapingLink();
420
- break;
421
- case "exit":
135
+ const menuList = {
136
+ web() {
422
137
  console.clear();
423
- console.info("thanks for use stack-analyze".green);
424
- break;
425
- default:
426
- toolsOpts[analyze]();
427
- break;
138
+ webOpts();
139
+ },
140
+ info() {
141
+ console.clear();
142
+ infoOpts();
143
+ },
144
+ query() {
145
+ console.clear();
146
+ queryOpts();
147
+ },
148
+ utility() {
149
+ console.clear();
150
+ utilityOpts();
151
+ },
152
+ about() {
153
+ console.clear();
154
+ aboutOpts();
155
+ }
156
+ };
157
+
158
+ option !== "exit" ? menuList[option]() : exitCli();
159
+ }
160
+
161
+ /**
162
+ * @async
163
+ * @returns {Promise<void>}
164
+ */
165
+ async function returnMain() {
166
+ try {
167
+ const { returnMain } = await inquirer.prompt({
168
+ type: "confirm",
169
+ name: "returnMain",
170
+ message: "do you want go to the main menu?",
171
+ });
172
+
173
+ returnMain ? mainMenu() : exitCli();
174
+ } catch (err) {
175
+ console.error(colors.bgRed(err.message));
428
176
  }
429
177
  }
430
178
 
431
- // call the message title and question list
432
- question();
179
+ for (let i = 50; i < totalTime; i += 50) {
180
+ const percentage = i / totalTime;
181
+
182
+ setTimeout(() => {
183
+ gauge.pulse();
184
+ gauge.show(`Loading app... ${percentage * 100}%`.random, percentage);
185
+ }, i);
186
+ }
187
+
188
+ setTimeout(() => {
189
+ gauge.hide();
190
+ mainMenu();
191
+ }, totalTime);
@@ -4,22 +4,22 @@ 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
10
- * @param { string } query - get query results
13
+ * @async
14
+ * @param { string } q - get query results
11
15
  * @returns { Promise<void> } - return results serach
12
16
  *
13
17
  */
14
- const animeSearch = async (query) => {
15
- /* error manager */
18
+ export default async function animeSearch(q) {
16
19
  try {
17
20
  // call api
18
21
  const { data } = await axios.get("https://api.jikan.moe/v4/anime", {
19
- params: {
20
- q: query,
21
- limit: 10
22
- }
22
+ params: { q }
23
23
  });
24
24
 
25
25
  const animeData = data.data.map(({
@@ -30,17 +30,16 @@ const animeSearch = async (query) => {
30
30
  type }) => ({
31
31
  title,
32
32
  type,
33
- totalEpisodes: episodes ?? 1,
33
+ totalEpisodes: episodes || "current",
34
34
  debutDate: format(aired.from),
35
- finalDate: aired.to !== null
35
+ finalDate: aired?.to
36
36
  ? format(aired.to)
37
37
  : status
38
38
  }));
39
39
 
40
40
 
41
- printTable(animeData);
41
+ printTable(animeData.slice(0, 10));
42
+
43
+ stackSave(`${q}-results.json`, JSON.stringify(animeData, null, 2));
42
44
  } catch (err) { console.error(colors.red(err.message)); }
43
- };
44
-
45
- // exports module
46
- export default animeSearch;
45
+ }
@@ -3,20 +3,23 @@ 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
12
+ * @async
9
13
  * @param { string } link - link for search info
14
+ * @param { string } token - bitly api token is required
10
15
  * @returns { Promise<void> } - return results serach
11
16
  *
12
17
  */
13
- const bitlyInfo = async (link, token) => {
18
+ export default async function bitlyInfo(link, token) {
14
19
  try {
15
- const { data, status } = await axios.post(
20
+ const { data } = await axios.post(
16
21
  "https://api-ssl.bitly.com/v4/expand",
17
- {
18
- bitlink_id: link
19
- },
22
+ { bitlink_id: link },
20
23
  {
21
24
  headers: {
22
25
  Authorization: `Bearer ${token}`,
@@ -25,17 +28,14 @@ const bitlyInfo = async (link, token) => {
25
28
  }
26
29
  );
27
30
 
28
- status === 404
29
- ? console.info("no found link".green)
30
- : console.table({
31
- created_link: format(data.created_at),
32
- bitly_link: data.link,
33
- link: data.long_url
34
- });
31
+ console.table({
32
+ created_link: format(data.created_at),
33
+ bitly_link: data.link,
34
+ link: data.long_url
35
+ });
36
+
37
+ stackSave("bitly.json", JSON.stringify(data, null, 2));
35
38
  } catch (err) {
36
39
  console.error(colors.red(err.message));
37
40
  }
38
- };
39
-
40
- // export
41
- export default bitlyInfo;
41
+ }