pkg-stats 0.1.0 → 0.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/README.md CHANGED
@@ -1,3 +1,16 @@
1
1
  ## PKG Stats
2
2
 
3
- Beautiful package download stats.
3
+ Beautiful NPM package download stats.
4
+
5
+ ```
6
+ npx pkg-stats react
7
+ ```
8
+
9
+ <div align='center'>
10
+ <img src="https://raw.githubusercontent.com/mdjastrzebski/pkg-stats/main/docs/public/example-react.png" alt="pkg-stats" height="210" width="538" />
11
+ </div>
12
+
13
+ ### Options:
14
+
15
+ - version grouping: `--group major|minor|patch` (alias `-g`, `--major`, `--minor`, `--patch`)
16
+ - top version: `--top <number>` (alias `-t`)
package/bin.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { pkgStats } from './dist/index.js';
4
+
5
+ pkgStats(process.argv.slice(2));
package/dist/bin.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import chalk from 'chalk';
2
2
  import minimist from 'minimist';
3
3
  import { renderChart } from './chart.js';
4
- import { gradients } from './colors.js';
4
+ import { getColors } from './colors.js';
5
5
  import { parseVersion, versionCompare } from './version.js';
6
+ import { groupByType, pickTopStats } from './stats.js';
6
7
  export async function pkgStats(argv) {
7
8
  const options = parseCliOptions(argv);
8
9
  if (options.help) {
@@ -31,27 +32,20 @@ export async function pkgStats(argv) {
31
32
  };
32
33
  })
33
34
  .sort(versionCompare);
34
- let groupedStats;
35
- if (options.group === 'patch') {
36
- groupedStats = sumByPatch(rawStats);
37
- }
38
- else if (options.group === 'minor') {
39
- groupedStats = sumByMinor(rawStats);
40
- }
41
- else {
42
- groupedStats = sumByMajor(rawStats);
43
- }
35
+ let groupedStats = groupByType(options.group, rawStats);
44
36
  const totalDownloads = Object.values(groupedStats).reduce((sum, version) => sum + version.downloads, 0);
45
37
  const groupedStatsToDisplay = options.top
46
38
  ? pickTopStats(groupedStats, options.top)
47
39
  : groupedStats;
48
- console.log(chalk.bold(`\nNPM weekly downloads for ${chalk.cyan(options.name)}\n`));
49
- console.log(`Total: ${chalk.cyan(totalDownloads.toLocaleString())}\n`);
40
+ const colors = getColors(groupedStatsToDisplay.length);
41
+ const primaryColor = chalk.hex(colors[0]);
42
+ console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(options.name)}\n`));
43
+ console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
50
44
  console.log(options.top ? `Top ${options.top} versions:\n` : 'By version:\n');
51
- const colors = gradients.passion(groupedStatsToDisplay.length);
52
45
  const maxDownloads = Math.max(...groupedStats.map((v) => v.downloads));
53
46
  groupedStatsToDisplay.forEach((item, i) => {
54
- const version = options.group != 'patch' ? `${item.versionString}.x` : item.versionString;
47
+ const versionParts = item.versionString.split('.');
48
+ const version = versionParts.length < 3 ? `${item.versionString}.x` : item.versionString;
55
49
  const chart = renderChart(item.downloads / maxDownloads);
56
50
  const downloads = formatDownloads(item.downloads, maxDownloads);
57
51
  const color = chalk.hex(colors[i]);
@@ -65,8 +59,11 @@ function parseCliOptions(argv) {
65
59
  boolean: ['help'],
66
60
  alias: { g: 'group', h: 'help', t: 'top' },
67
61
  });
68
- let group = 'major';
69
- if (options.group === 'minor' || options.minor) {
62
+ let group;
63
+ if (options.group === 'major' || options.major) {
64
+ group = 'major';
65
+ }
66
+ else if (options.group === 'minor' || options.minor) {
70
67
  group = 'minor';
71
68
  }
72
69
  else if (options.group === 'patch' || options.patch) {
@@ -93,52 +90,6 @@ function printHelp() {
93
90
  --top <number> Show top <number> versions
94
91
  `);
95
92
  }
96
- function sumByMajor(stats) {
97
- const result = {};
98
- for (const versionStats of stats) {
99
- const key = `${versionStats.major}`;
100
- const entry = result[key] ?? {
101
- version: { major: versionStats.major },
102
- versionString: key,
103
- downloads: 0,
104
- };
105
- result[key] = entry;
106
- entry.downloads += versionStats.downloads;
107
- }
108
- return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
109
- }
110
- function sumByMinor(stats) {
111
- const result = {};
112
- for (const versionStats of stats) {
113
- const key = `${versionStats.major}.${versionStats.minor}`;
114
- const entry = result[key] ?? {
115
- version: { major: versionStats.major, minor: versionStats.minor },
116
- versionString: key,
117
- downloads: 0,
118
- };
119
- result[key] = entry;
120
- entry.downloads += versionStats.downloads;
121
- }
122
- return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
123
- }
124
- function sumByPatch(stats) {
125
- const result = {};
126
- for (const versionStats of stats) {
127
- const key = `${versionStats.major}.${versionStats.minor}.${versionStats.patch}`;
128
- const entry = result[key] ?? {
129
- version: {
130
- major: versionStats.major,
131
- minor: versionStats.minor,
132
- patch: versionStats.patch,
133
- },
134
- versionString: key,
135
- downloads: 0,
136
- };
137
- result[key] = entry;
138
- entry.downloads += versionStats.downloads;
139
- }
140
- return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
141
- }
142
93
  function formatDownloads(downloads, maxDownloads) {
143
94
  if (maxDownloads > 1000000) {
144
95
  return `${(downloads / 1000000).toFixed(1)}M`;
@@ -148,8 +99,3 @@ function formatDownloads(downloads, maxDownloads) {
148
99
  }
149
100
  return downloads.toString();
150
101
  }
151
- function pickTopStats(stats, top) {
152
- const sortedStats = stats.sort((a, b) => b.downloads - a.downloads);
153
- const topStats = sortedStats.slice(0, top);
154
- return topStats.sort((a, b) => versionCompare(a.version, b.version));
155
- }
package/dist/colors.js CHANGED
@@ -1,11 +1,44 @@
1
1
  import tinygradient from 'tinygradient';
2
2
  // See: https://github.com/bokub/gradient-string/blob/465e86c8499a7f427c45afb1861f1444a2db74b9/src/index.ts#L166
3
- export const gradients = {
4
- mind: (count) => toColors(tinygradient(['#473b7b', '#3584a7', '#30d2be']).rgb(count)),
5
- pastel: (count) => toColors(tinygradient(['#74ebd5', '#74ecd5']).hsv(count, 'long')),
6
- passion: (count) => toColors(tinygradient(['#f43b47', '#453a94']).rgb(count)),
7
- retro: (count) => toColors(tinygradient(['#4150AB', '#AE6F97', '#EFCB84']).rgb(count)),
3
+ const gradients = {
4
+ atlas: { colors: ['#feac5e', '#c779d0', '#4bc0c8'], options: {} },
5
+ cristal: { colors: ['#bdfff3', '#4ac29a'], options: {} },
6
+ teen: { colors: ['#77a1d3', '#79cbca', '#e684ae'], options: {} },
7
+ mind: { colors: ['#473b7b', '#3584a7', '#30d2be'], options: {} },
8
+ morning: { colors: ['#ff5f6d', '#ffc371'], options: { interpolation: 'hsv' } },
9
+ vice: { colors: ['#5ee7df', '#b490ca'], options: { interpolation: 'hsv' } },
10
+ passion: { colors: ['#f43b47', '#453a94'], options: {} },
11
+ fruit: { colors: ['#ff4e50', '#f9d423'], options: {} },
12
+ instagram: { colors: ['#833ab4', '#fd1d1d', '#fcb045'], options: {} },
13
+ retro: {
14
+ colors: [
15
+ '#3f51b1',
16
+ '#5a55ae',
17
+ '#7b5fac',
18
+ '#8f6aae',
19
+ '#a86aa4',
20
+ '#cc6b8e',
21
+ '#f18271',
22
+ '#f3a469',
23
+ '#f7c978',
24
+ ],
25
+ options: {},
26
+ },
27
+ summer: { colors: ['#fdbb2d', '#22c1c3'], options: {} },
28
+ rainbow: { colors: ['#ff0000', '#ff0100'], options: { interpolation: 'hsv', hsvSpin: 'long' } },
29
+ pastel: { colors: ['#74ebd5', '#74ecd5'], options: { interpolation: 'hsv', hsvSpin: 'long' } },
8
30
  };
9
- function toColors(colors) {
10
- return colors.map((c) => c.toHexString());
31
+ export function getColors(count, colorScheme) {
32
+ const { colors, options } = gradients[colorScheme ?? getRandomScheme()];
33
+ if (count < colors.length) {
34
+ return colors;
35
+ }
36
+ const gradient = tinygradient(colors);
37
+ const tinyColors = options.interpolation === 'hsv'
38
+ ? gradient.hsv(count, options.hsvSpin ?? false)
39
+ : gradient.rgb(count);
40
+ return tinyColors.map((c) => c.toHexString());
41
+ }
42
+ function getRandomScheme() {
43
+ return Object.keys(gradients)[Math.floor(Math.random() * Object.keys(gradients).length)];
11
44
  }
package/dist/stats.js ADDED
@@ -0,0 +1,72 @@
1
+ import { versionCompare } from './version.js';
2
+ export function groupByType(type, stats) {
3
+ if (type === 'major') {
4
+ return groupByMajor(stats);
5
+ }
6
+ if (type === 'minor') {
7
+ return groupByMinor(stats);
8
+ }
9
+ if (type === 'patch') {
10
+ return groupByPatch(stats);
11
+ }
12
+ const groupedByMajor = groupByMajor(stats);
13
+ if (groupedByMajor.length > 1) {
14
+ return groupedByMajor;
15
+ }
16
+ const groupedByMinor = groupByMinor(stats);
17
+ if (groupedByMinor.length > 1) {
18
+ return groupedByMinor;
19
+ }
20
+ return groupByPatch(stats);
21
+ }
22
+ function groupByMajor(stats) {
23
+ const result = {};
24
+ for (const versionStats of stats) {
25
+ const key = `${versionStats.major}`;
26
+ const entry = result[key] ?? {
27
+ version: { major: versionStats.major },
28
+ versionString: key,
29
+ downloads: 0,
30
+ };
31
+ result[key] = entry;
32
+ entry.downloads += versionStats.downloads;
33
+ }
34
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
35
+ }
36
+ function groupByMinor(stats) {
37
+ const result = {};
38
+ for (const versionStats of stats) {
39
+ const key = `${versionStats.major}.${versionStats.minor}`;
40
+ const entry = result[key] ?? {
41
+ version: { major: versionStats.major, minor: versionStats.minor },
42
+ versionString: key,
43
+ downloads: 0,
44
+ };
45
+ result[key] = entry;
46
+ entry.downloads += versionStats.downloads;
47
+ }
48
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
49
+ }
50
+ function groupByPatch(stats) {
51
+ const result = {};
52
+ for (const versionStats of stats) {
53
+ const key = `${versionStats.major}.${versionStats.minor}.${versionStats.patch}`;
54
+ const entry = result[key] ?? {
55
+ version: {
56
+ major: versionStats.major,
57
+ minor: versionStats.minor,
58
+ patch: versionStats.patch,
59
+ },
60
+ versionString: key,
61
+ downloads: 0,
62
+ };
63
+ result[key] = entry;
64
+ entry.downloads += versionStats.downloads;
65
+ }
66
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
67
+ }
68
+ export function pickTopStats(stats, top) {
69
+ const sortedStats = stats.sort((a, b) => b.downloads - a.downloads);
70
+ const topStats = sortedStats.slice(0, top);
71
+ return topStats.sort((a, b) => versionCompare(a.version, b.version));
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pkg-stats",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Beautiful NPM package download stats",
5
5
  "author": "Maciej Jastrzębski <mdjastrzebski@gmail.com> (https://github.com/mdjastrzebski)",
6
6
  "license": "MIT",
@@ -17,7 +17,7 @@
17
17
  "dist"
18
18
  ],
19
19
  "bin": {
20
- "pkg-stats": "./dist/bin.js"
20
+ "pkg-stats": "./bin.js"
21
21
  },
22
22
  "dependencies": {
23
23
  "chalk": "^5.4.1",