stack-analyze 1.1.9 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  // modules
2
2
  import {default as axios} from "axios";
3
- import CoinGecko from "coingecko-api";
4
3
  import {
5
4
  cpu,
6
5
  mem,
@@ -10,30 +9,38 @@ import {
10
9
  bios
11
10
  } from "systeminformation";
12
11
  import Wappalyzer from "wappalyzer";
12
+ import { load } from "cheerio";
13
13
 
14
- const animeSearch = async ({ query, results }) => {
14
+ const gigabyteConvert = (size, base=1073741824) => (size / base).toFixed(2);
15
+
16
+ const wappalyzer = new Wappalyzer();
17
+
18
+ const pagespeedApi = async (url, strategy) => await axios.get("https://www.googleapis.com/pagespeedonline/v5/runPagespeed", {
19
+ params: {
20
+ url,
21
+ key: "AIzaSyBEDaW4FxSZ2s1vz5CdD5Ai6PGZGdAzij0",
22
+ strategy
23
+ }
24
+ });
25
+
26
+ const animeSearch = async ({ query, results, failed }) => {
15
27
  /* error manager */
16
28
  try {
17
29
  // call api
18
- const { data } = await axios.get("https://api.jikan.moe/v3/search/anime", {
19
- params: {
20
- q: query,
21
- limit: 10
22
- }
30
+ const { data } = await axios.get("https://api.jikan.moe/v/anime", {
31
+ params: { q: query }
23
32
  });
24
33
 
25
34
  results(data.results);
26
35
 
27
- } catch (err) { results(err); }
36
+ } catch (err) { failed(err); }
28
37
  };
29
38
 
30
- const bitlyInfo = async ({ link, token, results }) => {
39
+ const bitlyInfo = async ({ link, token, results, failed }) => {
31
40
  try {
32
41
  const { data } = await axios.post(
33
42
  "https://api-ssl.bitly.com/v4/expand",
34
- {
35
- bitlink_id: link
36
- },
43
+ { bitlink_id: link },
37
44
  {
38
45
  headers: {
39
46
  Authorization: `Bearer ${token}`,
@@ -43,32 +50,29 @@ const bitlyInfo = async ({ link, token, results }) => {
43
50
  );
44
51
 
45
52
  results(data);
46
- } catch (err) { results(err); }
53
+ } catch (err) { failed(err); }
47
54
  };
48
55
 
49
- const cryptoMarket = async (callback) => {
56
+ const cryptoMarket = async ({results, failed}) => {
50
57
  try {
51
58
  // start crypto
52
59
  const { data } = await axios.get(
53
60
  "https://api.coingecko.com/api/v3/coins/markets", {
54
- params: {
55
- vs_currency: "usd",
56
- per_page: 10
57
- }
61
+ params: { vs_currency: "usd" }
58
62
  }
59
63
  );
60
64
 
61
65
  // map coinData
62
- callback(data);
63
- } catch (err) { callback(err); }
66
+ results(data);
67
+ } catch (err) { failed(err); }
64
68
  };
65
69
 
66
- async function githubInfo({ user, results }) {
70
+ async function githubInfo({ user, results, failed }) {
67
71
  try {
68
72
  const { data } = await axios.get(`https://api.github.com/users/${user}`);
69
73
 
70
74
  results(data);
71
- } catch (err) { results(err); }
75
+ } catch (err) { failed(err); }
72
76
  }
73
77
 
74
78
  async function cpuInfo(callback) {
@@ -112,11 +116,11 @@ async function ramMemInfo(callback) {
112
116
 
113
117
  // show results
114
118
  callback({
115
- total_mem: `${(total / 1073741824).toFixed(2)} GB`,
116
- free_mem: `${(free / 1073741824).toFixed(2)} GB`,
117
- used_mem: `${(used / 1073741824).toFixed(2)} GB`,
118
- active_mem: `${(active / 1073741824).toFixed(2)} GB`,
119
- available_mem: `${(available / 1073741824).toFixed(2)} GB`
119
+ total_mem: `${gigabyteConvert(total)} GB`,
120
+ free_mem: `${gigabyteConvert(free)} GB`,
121
+ used_mem: `${gigabyteConvert(used)} GB`,
122
+ active_mem: `${gigabyteConvert(active)} GB`,
123
+ available_mem: `${gigabyteConvert(available)} GB`
120
124
  });
121
125
  } catch (err) { callback(err); }
122
126
  }
@@ -162,7 +166,7 @@ async function diskInfo(callback) {
162
166
  type,
163
167
  name,
164
168
  vendor,
165
- diskSize: `${(size / 1073741824).toFixed(2)} GB`,
169
+ diskSize: `${gigabyteConvert(size)} GB`,
166
170
  interfaceType
167
171
  }));
168
172
 
@@ -184,7 +188,7 @@ async function controllerInfo(callback) {
184
188
  vendor,
185
189
  vramSize: vram < 1024
186
190
  ? `${vram} MB`
187
- : `${(vram / 1024).toFixed(2)} GB`
191
+ : `${gigabyteConvert(vram, 1024)} GB`
188
192
  }));
189
193
 
190
194
  callback(controllersList);
@@ -226,14 +230,10 @@ async function biosInfo(callback) {
226
230
  } catch (err) { callback(err); }
227
231
  }
228
232
 
229
- const movieDB = async ({ api_key, query, results }) => {
233
+ const movieDB = async ({ api_key, query, results, failed }) => {
230
234
  try {
231
235
  const { data } = await axios.get("https://api.themoviedb.org/3/search/movie", {
232
- params: {
233
- api_key,
234
- query,
235
- page: 1
236
- }
236
+ params: { api_key, query, }
237
237
  });
238
238
 
239
239
  const movieData = data.results
@@ -257,15 +257,15 @@ const movieDB = async ({ api_key, query, results }) => {
257
257
 
258
258
  return primaryDate.getTime() - secondaryDate.getTime();
259
259
  })
260
- .filter(({ release_date }) => release_date !== undefined && release_date !== "");
260
+ .filter((data) => data?.release_date);
261
261
 
262
262
  results(movieData);
263
- } catch (err) { results(err); }
263
+ } catch (err) { failed(err); }
264
264
  };
265
265
 
266
- async function multipleStack({ urls, results }) {
266
+ async function multipleStack({ urls, results, failed }) {
267
267
  let result;
268
- const wappalyzer = new Wappalyzer();
268
+
269
269
  try {
270
270
  await wappalyzer.init();
271
271
  result = await Promise.all(
@@ -277,41 +277,28 @@ async function multipleStack({ urls, results }) {
277
277
  };
278
278
  })
279
279
  );
280
- } catch (err) { result = err; }
280
+ results(result);
281
+ } catch (err) { failed(err); }
281
282
  await wappalyzer.destroy();
282
- results(result);
283
283
  }
284
284
 
285
- const pageSpeed = async ({ url, results }) => {
285
+ const pageSpeed = async ({ url, results, failed }) => {
286
286
  try {
287
- const resMobile = await axios.get("https://www.googleapis.com/pagespeedonline/v5/runPagespeed", {
288
- params: {
289
- url,
290
- key: "AIzaSyBEDaW4FxSZ2s1vz5CdD5Ai6PGZGdAzij0",
291
- strategy: "mobile"
292
- }
293
- });
287
+ const resMobile = await pagespeedApi(url, "mobile");
294
288
 
295
- const resDesktop = await axios.get("https://www.googleapis.com/pagespeedonline/v5/runPagespeed", {
296
- params: {
297
- url,
298
- key: "AIzaSyBEDaW4FxSZ2s1vz5CdD5Ai6PGZGdAzij0",
299
- strategy: "desktop"
300
- }
301
- });
289
+ const resDesktop = await pagespeedApi(url, "desktop");
302
290
 
303
291
  // extract results
304
292
  const mobile = Math.round(resMobile.data.lighthouseResult.categories.performance.score * 100);
305
293
  const desktop = Math.round(resDesktop.data.lighthouseResult.categories.performance.score * 100);
306
294
 
307
295
  results({ mobile, desktop });
308
- } catch (err) { results(err); }
296
+ } catch (err) { failed(err); }
309
297
  };
310
298
 
311
- async function singleStack({ url, results }) {
312
- const wappalyzer = await new Wappalyzer;
313
-
299
+ async function singleStack({ url, results, failed }) {
314
300
  let result;
301
+
315
302
  try {
316
303
  await wappalyzer.init();
317
304
 
@@ -326,16 +313,17 @@ async function singleStack({ url, results }) {
326
313
  techWebsite: website,
327
314
  techCategories: categories.map(({ name }) => name).join(", ")
328
315
  }));
329
- } catch (err) { results(err); }
316
+ results(result);
317
+ } catch (err) { failed(err); }
330
318
 
331
319
  await wappalyzer.destroy();
332
- results(result);
333
320
  }
334
321
 
335
- async function twitchInfo({ query, token, clientID, results }) {
322
+ async function twitchInfo({ query, token, clientID, results, failed }) {
336
323
  try {
337
- const { data: twitchData } = await axios.get(`https://api.twitch.tv/helix/users?login=${query}`,
324
+ const { data: twitchData } = await axios.get("https://api.twitch.tv/helix/users",
338
325
  {
326
+ params: { login: query },
339
327
  headers: {
340
328
  Authorization: `Bearer ${token}`,
341
329
  "Client-Id": clientID
@@ -343,136 +331,116 @@ async function twitchInfo({ query, token, clientID, results }) {
343
331
  });
344
332
 
345
333
  results(twitchData.data);
346
- } catch (err) { results(err); }
334
+ } catch (err) { failed(err); }
347
335
  }
348
336
 
349
- function scrape(url) {
350
- let $;
351
-
352
- const scraping = axios.create({
353
- baseURL: url
354
- });
355
-
356
- const title = async (callback) => {
357
- try {
358
- const { data } = await scraping.get("");
359
- $ = load(data);
360
-
361
- callback($("title").text());
362
- } catch (err) { console.error(colors.red(err.message)); }
363
- };
364
-
365
- const images = async (callback) => {
366
- try {
367
- const { data } = await scraping.get("");
368
- $ = load(data);
369
-
370
- const imgs = $("img").map((i, el) => ({
371
- imagePath: $(el).attr("src"),
372
- imageTitle: $(el).attr("alt")
373
- })).toArray();
374
-
375
- callback(imgs);
376
- } catch (err) { console.error(colors.red(err.message)); }
377
- };
378
-
379
- const metadata = async (callback) => {
380
- try {
381
- const { data } = await scraping.get("");
382
- $ = load(data);
383
-
384
- const metadataList = $("meta").map((i, el) => ({
385
- metaInfo: $(el).attr("name"),
386
- metaContent: $(el).attr("content")
387
- })).toArray()
388
- .filter(({ metaInfo }) => metaInfo !== undefined);
389
-
390
- callback(metadataList);
391
- } catch (err) { console.error(colors.red(err.message)); }
392
- };
393
-
394
- const headings = async (callback) => {
395
- try {
396
- const { data } = await scraping.get("");
397
- $ = load(data);
398
-
399
- const headingList = $("h1, h2, h3, h4, h5, h6").map((i, el) => ({
400
- headingTag: $(el).prop("tagName"),
401
- headingText: $(el).text()
402
- })).toArray();
403
-
404
- callback(headingList);
405
- } catch (err) { console.error(colors.red(err.message)); }
406
- };
407
-
408
- const table_heading = async (callback) => {
409
- try {
410
- const { data } = await scraping.get("");
411
- $ = load(data);
412
-
413
- const tableHeadList = $("th").map((i, el) => ({
414
- headingRow: i,
415
- text: $(el).text()
416
- })).toArray();
417
-
418
- callback(tableHeadList);
419
- } catch (err) { console.error(colors.red(err.message)); }
420
- };
421
-
422
- const table_data = async (callback) => {
423
- try {
424
- const { data } = await scraping.get("");
425
- $ = load(data);
426
-
427
- const tableColumnList = $("td").map((i, el) => $(el).text()).toArray();
428
-
429
- callback(tableColumnList);
430
- } catch (err) { console.error(colors.red(err.message)); }
431
- };
432
-
433
-
434
- const links = async (callback) => {
435
- try {
436
- const { data } = await scraping.get("");
437
- $ = load(data);
438
-
439
- const linkList = $("a").map((i, el) => ({
440
- url: $(el).attr("href"),
441
- text: $(el).text()
442
- })).toArray()
443
- .filter(({ url }) => url.indexOf("#") !== 0);
444
-
445
- callback(linkList);
446
- } catch (err) { console.error(colors.red(err.message)); }
447
- };
448
-
449
- const cites = async (callback) => {
450
- try {
451
- const { data } = await scraping.get("");
452
- $ = load(data);
453
-
454
- const citeList = $("q, blockquote").map((i, el) => ({
455
- citeTag: $(el).prop("tagName"),
456
- citeLink: $(el).attr("cite"),
457
- citeText: $(el).text()
458
- })).toArray();
459
-
460
- callback(citeList);
461
- } catch (err) { console.error(colors.red(err.message)); }
462
- };
463
-
464
- return {
465
- title,
466
- images,
467
- metadata,
468
- headings,
469
- table_heading,
470
- table_data,
471
- links,
472
- cites
473
- };
337
+ async function scrape({url, options, results, failed}) {
338
+ let scrapingResult;
339
+
340
+ try {
341
+ const { data } = await axios.get(url);
342
+ const $ = load(data);
343
+
344
+ const scraping = {
345
+ title() {
346
+ results($("title").text());
347
+ },
348
+ images() {
349
+ const imageList = $("img").map((i, el) => ({
350
+ imagePath: $(el).attr("src"),
351
+ imageTitle: $(el).attr("alt")
352
+ })).toArray();
353
+
354
+ scrapingResult = imageList.length === 0
355
+ ? "no found images"
356
+ : imageList;
357
+
358
+ results(scrapingResult);
359
+ },
360
+ metadata() {
361
+ const metadataList = $("meta").map((i, el) => ({
362
+ metaInfo: $(el).attr("name"),
363
+ metaContent: $(el).attr("content")
364
+ })).toArray()
365
+ .filter((data) => data?.metaInfo);
366
+
367
+ results(metadataList);
368
+ },
369
+ headings() {
370
+ const headingList = $("h1, h2, h3, h4, h5, h6").map((i, el) => ({
371
+ headingTag: $(el).prop("tagName"),
372
+ headingText: $(el).text()
373
+ })).toArray();
374
+
375
+ results(headingList);
376
+ },
377
+ tableHead() {
378
+ const tableHeadList = $("th").map((i, el) => ({
379
+ headingRow: i,
380
+ text: $(el).text()
381
+ })).toArray();
382
+
383
+ scrapingResult = tableHeadList.length === 0
384
+ ? "no found th tags" : tableHeadList;
385
+
386
+ results(scrapingResult);
387
+ },
388
+ tableData() {
389
+ const tableColumnList = $("td").map((i, el) => ({
390
+ tableRow: i + 1,
391
+ tableData: $(el).text(),
392
+ })).toArray();
393
+
394
+ scrapingResult = tableColumnList.length === 0
395
+ ? "no found td tags" : tableColumnList;
396
+
397
+ results(scrapingResult);
398
+ },
399
+ links() {
400
+ const linkList = $("a").map((i, el) => ({
401
+ url: $(el).attr("href"),
402
+ text: $(el).text()
403
+ })).toArray()
404
+ .filter(({ url }) => url.indexOf("#") !== 0);
405
+
406
+ results(linkList);
407
+ },
408
+ cites() {
409
+ const citeList = $("q, blockquote").map((i, el) => ({
410
+ citeTag: $(el).prop("tagName"),
411
+ citeLink: $(el).attr("cite"),
412
+ citeText: $(el).text()
413
+ })).toArray();
414
+
415
+ scrapingResult = citeList.length === 0
416
+ ? "no found q and/or blockquote tags" : citeList;
417
+
418
+ results(scrapingResult);
419
+ }
420
+ };
421
+
422
+ scraping[options]();
423
+ } catch (err) {
424
+ failed(err.message);
425
+ }
474
426
  }
475
427
 
428
+ const password = () => {
429
+ const chars = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ";
430
+
431
+ // blank password var
432
+ let password = "";
433
+
434
+ // loop generate chars
435
+ for(let i = 0; i < 12; i++) {
436
+ const randomNumber = Math.floor(Math.random() * chars.length);
437
+
438
+ password += chars.substring(randomNumber, randomNumber + 1);
439
+ }
440
+
441
+ // print new passwors
442
+ return password;
443
+ };
476
444
 
477
445
  // exports
478
446
  export {
@@ -492,5 +460,6 @@ export {
492
460
  pageSpeed,
493
461
  singleStack,
494
462
  twitchInfo,
495
- scrape
463
+ scrape,
464
+ password
496
465
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stack-analyze",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
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",
@@ -14,29 +14,29 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "axios": "^0.27.2",
17
+ "axios": "^1.1.3",
18
18
  "cheerio": "^1.0.0-rc.12",
19
19
  "cli-progress": "^3.11.2",
20
20
  "colors": "^1.4.0",
21
- "console-table-printer": "^2.11.0",
21
+ "console-table-printer": "^2.11.1",
22
22
  "figlet": "^1.5.2",
23
- "inquirer": "^9.0.0",
24
- "systeminformation": "^5.11.22",
23
+ "gauge": "^5.0.0",
24
+ "inquirer": "^9.1.4",
25
+ "systeminformation": "^5.12.11",
25
26
  "timeago.js": "^4.0.2",
26
- "wappalyzer": "^6.10.37"
27
+ "wappalyzer": "^6.10.41"
27
28
  },
28
29
  "devDependencies": {
29
- "eslint": "^8.18.0",
30
+ "eslint": "^8.26.0",
30
31
  "gh-pages": "^4.0.0",
31
- "jest": "^28.1.2",
32
- "jsdoc": "^3.6.10",
33
- "minami": "^1.2.3"
32
+ "jest": "^29.2.2",
33
+ "jsdoc": "^3.6.11"
34
34
  },
35
35
  "scripts": {
36
36
  "start": "node cli.js",
37
37
  "test": "jest",
38
- "lint:test": "eslint . --ext .js",
39
- "lint:fix": "eslint . --ext .js --fix",
38
+ "lint:test": "eslint . --ext .js,.cjs,.mjs",
39
+ "lint:fix": "eslint . --ext .js,.cjs,.mjs --fix",
40
40
  "docs": "jsdoc -c jsdoc.json",
41
41
  "docs:deploy": "npm run docs && gh-pages -d docs"
42
42
  },
package/readme.md CHANGED
@@ -12,19 +12,42 @@
12
12
 
13
13
  cli tech stack analyze with **node.js** using the wappalyzer and google pagespeed api the module this node external module or install.
14
14
 
15
- use the cli program install
15
+ ## use the cli program install
16
16
 
17
- ## example module
17
+ ## cli module
18
18
  ``` sh
19
- # global old npm versions
19
+ # old npm mode
20
20
  npm i -g stack-analyze
21
21
 
22
- # global new module
22
+ # new npm mode
23
23
  npm i --location=global
24
24
 
25
+ # if using global install
26
+ stack-analyze
27
+
25
28
  # portable
26
29
  npx stack-analyze
27
30
  ```
31
+
32
+ ## module
33
+
34
+ ``` sh
35
+ npm i stack-analyze
36
+ ```
37
+
38
+ ``` js
39
+ // cjs
40
+ const stackAnalyze = require('stack-analyze') // full
41
+ const { password } = require('stack-analyze') // destructuring
42
+
43
+ // esm
44
+ import stackAnalyze from 'stack-analyze' // full
45
+ import { password } from 'stack-analyze' // destructuring
46
+
47
+ // examples
48
+ password()
49
+ ```
50
+
28
51
  >note: if global install fail using npx
29
52
 
30
53
  [github repo](https://github.com/stack-analyze/stack-analyze.git)
package/utils.js CHANGED
@@ -3,13 +3,49 @@ const listFormat = new Intl.ListFormat("en", {
3
3
  type: "conjunction"
4
4
  });
5
5
 
6
- const currency = Intl.NumberFormat("en-us", {
7
- style: "currency",
8
- currency: "USD"
6
+ const currency = new Intl.NumberFormat("en-us", {
7
+ style: "currency", currency: "USD"
9
8
  });
10
9
 
10
+ const returnMainOpts = "return main menu";
11
+
12
+ const menuOpts = ["web", "query", "hardware", "about", "exit"];
13
+
14
+ const menuWebOpts = [
15
+ "single", "multiple", "pagespeed", "scraping", returnMainOpts
16
+ ];
17
+
18
+ const menuQueryOpts = [
19
+ "github_info", "anime_Search", "bitly_info", "movie_info",
20
+ "twitch_info", "crypto_market", "password", returnMainOpts
21
+ ];
22
+
23
+ const menuHardwareOpts = [
24
+ "cpuInfo", "ramMemInfo", "osDetail", "diskInfo",
25
+ "controllerInfo", "displayInfo", "biosInfo", returnMainOpts
26
+ ];
27
+
28
+ const menuAboutOpts = [
29
+ "mainInfo", "lineup", "youtubeRecomendation",
30
+ "twitchRecomendation", "projectsRecomendation", returnMainOpts
31
+ ];
32
+
33
+ const scrapingOpts = [
34
+ "title", "images", "metadata", "headings",
35
+ "tableHead", "tableData", "links", "cites"
36
+ ];
37
+
38
+ const exitCli = "thanks for use stack-analyze";
39
+
11
40
  export {
12
41
  listFormat,
13
- currency
42
+ currency,
43
+ menuOpts,
44
+ menuWebOpts,
45
+ menuQueryOpts,
46
+ menuHardwareOpts,
47
+ menuAboutOpts,
48
+ scrapingOpts,
49
+ exitCli
14
50
  };
15
51
 
@@ -0,0 +1,37 @@
1
+ // bitly regexp
2
+ const bitlyRegexp = /bit\.ly\//g;
3
+
4
+ const bitlyQuery = {
5
+ name: "bitlyLink",
6
+ message: "enter a short link:",
7
+ validate: input => bitlyRegexp.test(input) || "only bitly link".yellow
8
+ };
9
+
10
+ /**
11
+ * @param {string} name
12
+ * @param {string} message
13
+ */
14
+ const promptParams = (name, message) => ({
15
+ name,
16
+ message,
17
+ validate: input => input !== "" || "this field is required".yellow
18
+ });
19
+
20
+ /**
21
+ * @param {string} name
22
+ * @param {string} message
23
+ */
24
+ const promptKey = (name, message) => ({
25
+ name,
26
+ message,
27
+ type: "password",
28
+ mask: "?",
29
+ validate: input => input !== "" || "token field is required".yellow
30
+ });
31
+
32
+ export {
33
+ bitlyQuery,
34
+ promptParams,
35
+ promptKey
36
+ };
37
+