stack-analyze 1.1.7 → 1.2.0

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
@@ -7,10 +7,119 @@ import figlet from "figlet";
7
7
  import colors from "colors";
8
8
 
9
9
  // hash tables
10
- import mainTools from "./hash/mainTools.js";
11
- import hardwareTools from "./hash/hardwareTools.js";
12
- import aboutTool from "./hash/aboutOpts.js";
13
- import infoTools from "./hash/infoTools.js";
10
+ import hardwareTools from "./functions/hardware.js";
11
+ import aboutTool from "./about.js";
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";
24
+
25
+ /**
26
+ * @description web scraping menu
27
+ * @return { Promise<void>} web scraping options
28
+ */
29
+ async function scrapingOpts (url) {
30
+ console.info("web:", url);
31
+
32
+ const { option } = await inquirer.prompt({
33
+ 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
+ ]
48
+ });
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
+
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]();
102
+ }
103
+
104
+ /**
105
+ * @description web scraping menu
106
+ * @return { Promise<void>} web scraping options
107
+ */
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?"
114
+ });
115
+
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
+ }
122
+ }
14
123
 
15
124
  /**
16
125
  * @description about menu
@@ -23,12 +132,11 @@ async function aboutOpts() {
23
132
  name: "about",
24
133
  message: "select about option info",
25
134
  choices: [
26
- "main_info",
135
+ "mainInfo",
27
136
  "lineup",
28
- "youtube_recomendation",
29
- "twitch_recomendation",
30
- "projects_recomendation",
31
- "tools_ideas",
137
+ "youtubeRecomendation",
138
+ "twitchRecomendation",
139
+ "projectsRecomendation",
32
140
  "return to main menu"
33
141
  ]
34
142
  });
@@ -38,7 +146,7 @@ async function aboutOpts() {
38
146
  setTimeout(aboutOpts, 1000);
39
147
  } else {
40
148
  question();
41
- }
149
+ }
42
150
  }
43
151
 
44
152
  /**
@@ -47,7 +155,7 @@ async function aboutOpts() {
47
155
  * @return { Promise<void> } - return in boolean a result question list
48
156
  *
49
157
  */
50
- async function returnWebQuestion() {
158
+ async function returnQuestion() {
51
159
  try {
52
160
  const anw = await inquirer.prompt([
53
161
  {
@@ -59,9 +167,10 @@ async function returnWebQuestion() {
59
167
 
60
168
  if (anw.return) {
61
169
  console.clear();
62
- mainOptions();
63
- } else {
64
170
  question();
171
+ } else {
172
+ console.clear();
173
+ console.info("thanks for use stack-analyze".green);
65
174
  }
66
175
  } catch (err) {
67
176
  console.error(colors.red(err.message));
@@ -69,31 +178,173 @@ async function returnWebQuestion() {
69
178
  }
70
179
 
71
180
  /**
72
- *
73
- * @description call the async function return list to question list
74
- * @return { Promise<void> } - return in boolean a result question list
75
- *
181
+ * @description This is a hash table with the options of the tools menu.
182
+ * @type {Object.<string, function(): void>}
76
183
  */
77
- async function returnInfoQuestion() {
78
- try {
79
- const anw = await inquirer.prompt([
80
- {
81
- type: "confirm",
82
- name: "return",
83
- message: "do you want go to the tools menu?",
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);
84
197
  }
85
- ]);
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 }) => {
86
206
 
87
- if (anw.return) {
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 }) => {
88
313
  console.clear();
89
- infoOpts();
90
- } else {
91
- question();
92
- }
93
- } catch (err) {
94
- console.error(colors.red(err.message));
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
+ });
95
346
  }
96
- }
347
+ };
97
348
 
98
349
  /**
99
350
  * @description call hardware information options
@@ -106,18 +357,18 @@ async function hardwareOpts() {
106
357
  pageSize: 9,
107
358
  message: "select a hardware-information option:",
108
359
  choices: [
109
- "cpu",
110
- "ram_memory",
111
- "os",
112
- "disk",
113
- "controller",
114
- "display",
115
- "bios",
360
+ "cpuInfo",
361
+ "ramMemInfo",
362
+ "osDetail",
363
+ "diskInfo",
364
+ "controllerInfo",
365
+ "displayInfo",
366
+ "biosInfo",
116
367
  "exit to main menu"
117
368
  ]
118
369
  });
119
370
 
120
- if(hardware !== "exit to main menu") {
371
+ if (hardware !== "exit to main menu") {
121
372
  hardwareTools[hardware]();
122
373
  setTimeout(hardwareOpts, 1000);
123
374
  } else {
@@ -127,102 +378,55 @@ async function hardwareOpts() {
127
378
 
128
379
  /**
129
380
  *
130
- * @description call the function question web tools options
131
- * @returns { Promise<void> } return main tools options
381
+ * @description call the function question raw list options
382
+ * @returns { Promise<void> } return exit question
132
383
  *
133
384
  */
134
- async function mainOptions() {
135
- const { main } = await inquirer.prompt({
385
+ async function question() {
386
+ console.clear();
387
+ console.info(colors.yellow(figlet.textSync("stack-analyze")));
388
+ const { analyze } = await inquirer.prompt({
136
389
  type: "list",
137
- pageSize: 9,
138
- name: "main",
139
- message: "",
390
+ pageSize: 15,
391
+ name: "analyze",
392
+ message: "what option do you want to analyze stack",
140
393
  choices: [
141
394
  "single",
142
395
  "multiple",
143
396
  "pagespeed",
144
- "return main menu"
145
- ]
146
- });
147
-
148
- if (main !== "return main menu") {
149
- mainTools[main]();
150
- const timeEnd = performance.now();
151
- setTimeout(returnWebQuestion, timeEnd);
152
- } else {
153
- question();
154
- }
155
- }
156
-
157
- /**
158
- *
159
- * @description call the function question info tools options
160
- * @returns { Promise<void> } return main tools options
161
- *
162
- */
163
- async function infoOpts() {
164
- const { info } = await inquirer.prompt({
165
- type: "list",
166
- pageSize: 9,
167
- name: "info",
168
- message: "enter a info tools option",
169
- choices: [
170
397
  "github_info",
171
398
  "anime_search",
172
399
  "crypto_market",
173
400
  "bitly_info",
174
401
  "movie_info",
175
402
  "twitch_info",
176
- "return main menu"
403
+ "hardware tools",
404
+ "scraping",
405
+ "password",
406
+ "about",
407
+ "exit"
177
408
  ]
178
409
  });
179
410
 
180
- if (info !== "return main menu") {
181
- infoTools[info]();
182
- const timeEnd = performance.now();
183
- setTimeout(returnInfoQuestion, timeEnd);
184
- } else {
185
- question();
186
- }
187
- }
188
-
189
-
190
- /**
191
- *
192
- * @description call the function question raw list options
193
- * @returns { Promise<void> } return exit question
194
- *
195
- */
196
- async function question() {
197
- console.clear();
198
- console.info(colors.yellow(figlet.textSync("stack-analyze")));
199
- const { analyze } = await inquirer.prompt({
200
- type: "list",
201
- name: "analyze",
202
- message: "what option do you want to analyze stack",
203
- choices: ["web tools", "info tools", "hardware tools", "about", "exit"]
204
- });
205
-
206
411
  switch (analyze) {
207
- case "web tools":
208
- mainOptions();
209
- break;
210
- case "info tools":
211
- infoOpts();
212
- break;
213
412
  case "hardware tools":
214
413
  hardwareOpts();
215
414
  break;
216
415
  case "about":
217
416
  aboutOpts();
218
417
  break;
219
- default:
418
+ case "scraping":
419
+ scrapingLink();
420
+ break;
421
+ case "exit":
220
422
  console.clear();
221
423
  console.info("thanks for use stack-analyze".green);
222
424
  break;
425
+ default:
426
+ toolsOpts[analyze]();
427
+ break;
223
428
  }
224
429
  }
225
430
 
226
431
  // call the message title and question list
227
432
  question();
228
-
@@ -1,8 +1,8 @@
1
1
  // modules
2
- import axios from "axios";
2
+ import { default as axios } from "axios";
3
3
  import { format } from "timeago.js";
4
4
  import colors from "colors";
5
- import animeList from "../models/animeTable.js";
5
+ import { printTable } from "console-table-printer";
6
6
 
7
7
  /**
8
8
  *
@@ -15,33 +15,30 @@ const animeSearch = async (query) => {
15
15
  /* error manager */
16
16
  try {
17
17
  // call api
18
- const { data } = await axios.get("https://api.jikan.moe/v3/search/anime", {
18
+ const { data } = await axios.get("https://api.jikan.moe/v4/anime", {
19
19
  params: {
20
20
  q: query,
21
21
  limit: 10
22
22
  }
23
23
  });
24
24
 
25
- const animeData = data.results.map(({
25
+ const animeData = data.data.map(({
26
26
  title,
27
27
  episodes,
28
- start_date,
29
- end_date,
28
+ aired,
29
+ status,
30
30
  type }) => ({
31
31
  title,
32
32
  type,
33
- episodes,
34
- debutDate: format(start_date),
35
- finalDate: end_date !== null
36
- ? format(end_date)
37
- : "current date"
33
+ totalEpisodes: episodes ?? 1,
34
+ debutDate: format(aired.from),
35
+ finalDate: aired.to !== null
36
+ ? format(aired.to)
37
+ : status
38
38
  }));
39
39
 
40
40
 
41
- animeList.addRows(animeData);
42
-
43
- animeList.printTable();
44
-
41
+ printTable(animeData);
45
42
  } catch (err) { console.error(colors.red(err.message)); }
46
43
  };
47
44
 
@@ -1,6 +1,5 @@
1
1
  // modules
2
- import "../env/bitly.env.js";
3
- import axios from "axios";
2
+ import { default as axios } from "axios";
4
3
  import { format } from "timeago.js";
5
4
  import colors from "colors";
6
5
 
@@ -11,7 +10,7 @@ import colors from "colors";
11
10
  * @returns { Promise<void> } - return results serach
12
11
  *
13
12
  */
14
- const bitlyInfo = async (link) => {
13
+ const bitlyInfo = async (link, token) => {
15
14
  try {
16
15
  const { data, status } = await axios.post(
17
16
  "https://api-ssl.bitly.com/v4/expand",
@@ -20,7 +19,7 @@ const bitlyInfo = async (link) => {
20
19
  },
21
20
  {
22
21
  headers: {
23
- Authorization: `Bearer ${process.env.BITLY_TOKEN}`,
22
+ Authorization: `Bearer ${token}`,
24
23
  "Content-Type": "application/json"
25
24
  }
26
25
  }
@@ -1,14 +1,14 @@
1
1
  // modules
2
- import CoinGecko from "coingecko-api";
2
+ import {default as axios} from "axios";
3
3
  import { format } from "timeago.js";
4
4
  import colors from "colors";
5
5
 
6
- import coinTable from "../models/cryptoTables.js";
6
+ import { printTable } from "console-table-printer";
7
7
 
8
- // init coingecko api
9
- const CoinGeckoClient = new CoinGecko();
8
+ // currency format
9
+ import { currency } from "../utils.js";
10
10
 
11
- /*
11
+ /**
12
12
  *
13
13
  * @descripiton call the crypto market list
14
14
  * @returns { Promise<void> } - return results search
@@ -17,12 +17,17 @@ const CoinGeckoClient = new CoinGecko();
17
17
  const cryptoMarket = async () => {
18
18
  try {
19
19
  // start crypto
20
- const coinData = await CoinGeckoClient.coins.markets({
21
- per_page: 10
22
- });
20
+ const { data } = await axios.get(
21
+ "https://api.coingecko.com/api/v3/coins/markets", {
22
+ params: {
23
+ vs_currency: "usd",
24
+ per_page: 10
25
+ }
26
+ }
27
+ );
23
28
 
24
29
  // map coinData
25
- const coinList = coinData.data.map(({
30
+ const coinList = data.map(({
26
31
  symbol,
27
32
  name,
28
33
  current_price,
@@ -31,17 +36,15 @@ const cryptoMarket = async () => {
31
36
  }) => ({
32
37
  symbol,
33
38
  name,
34
- price: current_price,
39
+ price: currency.format(current_price),
35
40
  priceChanged: price_change_percentage_24h > 0
36
41
  ? colors.green(price_change_percentage_24h)
37
42
  : colors.red(price_change_percentage_24h),
38
43
  lastUpdated: format(last_updated)
39
44
  }));
40
45
 
41
- coinTable.addRows(coinList);
42
-
43
46
  // print table
44
- coinTable.printTable();
47
+ printTable(coinList);
45
48
  } catch (err) {
46
49
  // print err message
47
50
  console.error(colors.red(err.message));
@@ -1,5 +1,5 @@
1
1
  // modules
2
- import axios from "axios";
2
+ import { default as axios } from "axios";
3
3
  import { format } from "timeago.js";
4
4
  import colors from "colors";
5
5
 
@@ -12,25 +12,25 @@ import colors from "colors";
12
12
  */
13
13
  export default async function githubInfo(user) {
14
14
  try {
15
- const res = await axios.get(`https://api.github.com/users/${user}`);
15
+ const { data, status } = await axios.get(`https://api.github.com/users/${user}`);
16
16
 
17
- if (res.status !== 404){
17
+ if (status !== 404){
18
18
  const info = {
19
- username: res.data.login,
20
- fullName: res.data.name === null ? "no info": res.data.name,
21
- Email: res.data.email === null ? "no info": res.data.email,
22
- userFollowers: res.data.followers,
23
- userFollowing: res.data.following,
24
- accountAge: format(res.data.created_at),
25
- updated_info: format(res.data.updated_at),
26
- twitter: res.data.twitter_username === null ? "no info": res.data.twitter_username,
27
- repos: res.data.public_repos,
28
- gists: res.data.public_gists
19
+ username: data.login,
20
+ fullName: data.name === null ? "no info": data.name,
21
+ Email: data.email === null ? "no info": data.email,
22
+ userFollowers: data.followers,
23
+ userFollowing: data.following,
24
+ accountAge: format(data.created_at),
25
+ updated_info: format(data.updated_at),
26
+ twitter: data.twitter_username === null ? "no info": data.twitter_username,
27
+ repos: data.public_repos,
28
+ gists: data.public_gists
29
29
  };
30
30
 
31
31
  console.table(info);
32
32
  } else {
33
- console.info(colors.yellow(res.status.toString()));
33
+ console.info(colors.yellow(""+status));
34
34
  }
35
35
  } catch(err) {
36
36
  console.error(colors.red(err.message));