pkg-stats 0.0.1 → 0.1.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/dist/bin.js +87 -14
- package/dist/chart.js +1 -1
- package/dist/colors.js +11 -0
- package/dist/index.js +1 -2
- package/dist/version.js +2 -2
- package/package.json +23 -9
package/dist/bin.js
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import minimist from 'minimist';
|
|
3
|
+
import { renderChart } from './chart.js';
|
|
4
|
+
import { gradients } from './colors.js';
|
|
5
|
+
import { parseVersion, versionCompare } from './version.js';
|
|
6
|
+
export async function pkgStats(argv) {
|
|
7
|
+
const options = parseCliOptions(argv);
|
|
8
|
+
if (options.help) {
|
|
9
|
+
printHelp();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
let data;
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(`https://api.npmjs.org/versions/${encodeURIComponent(options.name)}/last-week`);
|
|
15
|
+
data = await response.json();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error(`Failed to fetch data for package "${options.name}"`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!Object.keys(data.downloads).length) {
|
|
22
|
+
console.error(`No data found for package "${options.name}".\n`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
8
25
|
const rawStats = Object.keys(data.downloads)
|
|
9
26
|
.map((versionString) => {
|
|
10
27
|
const version = parseVersion(versionString);
|
|
@@ -14,16 +31,67 @@ export async function bin() {
|
|
|
14
31
|
};
|
|
15
32
|
})
|
|
16
33
|
.sort(versionCompare);
|
|
17
|
-
|
|
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
|
+
}
|
|
18
44
|
const totalDownloads = Object.values(groupedStats).reduce((sum, version) => sum + version.downloads, 0);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
45
|
+
const groupedStatsToDisplay = options.top
|
|
46
|
+
? pickTopStats(groupedStats, options.top)
|
|
47
|
+
: groupedStats;
|
|
48
|
+
console.log(chalk.bold(`\nNPM weekly downloads for ${chalk.cyan(options.name)}\n`));
|
|
49
|
+
console.log(`Total: ${chalk.cyan(totalDownloads.toLocaleString())}\n`);
|
|
50
|
+
console.log(options.top ? `Top ${options.top} versions:\n` : 'By version:\n');
|
|
51
|
+
const colors = gradients.passion(groupedStatsToDisplay.length);
|
|
22
52
|
const maxDownloads = Math.max(...groupedStats.map((v) => v.downloads));
|
|
23
|
-
|
|
24
|
-
|
|
53
|
+
groupedStatsToDisplay.forEach((item, i) => {
|
|
54
|
+
const version = options.group != 'patch' ? `${item.versionString}.x` : item.versionString;
|
|
55
|
+
const chart = renderChart(item.downloads / maxDownloads);
|
|
56
|
+
const downloads = formatDownloads(item.downloads, maxDownloads);
|
|
57
|
+
const color = chalk.hex(colors[i]);
|
|
58
|
+
console.log(`${version.padStart(8)} ${color(chart)} ${color(downloads.padStart(6))}`);
|
|
59
|
+
});
|
|
60
|
+
console.log('');
|
|
61
|
+
}
|
|
62
|
+
function parseCliOptions(argv) {
|
|
63
|
+
const options = minimist(argv, {
|
|
64
|
+
string: ['group', 'top'],
|
|
65
|
+
boolean: ['help'],
|
|
66
|
+
alias: { g: 'group', h: 'help', t: 'top' },
|
|
67
|
+
});
|
|
68
|
+
let group = 'major';
|
|
69
|
+
if (options.group === 'minor' || options.minor) {
|
|
70
|
+
group = 'minor';
|
|
71
|
+
}
|
|
72
|
+
else if (options.group === 'patch' || options.patch) {
|
|
73
|
+
group = 'patch';
|
|
25
74
|
}
|
|
26
|
-
|
|
75
|
+
const top = options.top ? parseInt(options.top) : undefined;
|
|
76
|
+
if (!options._[0]) {
|
|
77
|
+
console.error('Package name is required');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
return { name: options._[0], group, help: options.help, top };
|
|
81
|
+
}
|
|
82
|
+
function printHelp() {
|
|
83
|
+
console.log(`
|
|
84
|
+
Usage:
|
|
85
|
+
pkg-stats [options] <package-name>
|
|
86
|
+
|
|
87
|
+
Options:
|
|
88
|
+
-h, --help Show help
|
|
89
|
+
--group <group> Group by major, minor, or patch (default: major)
|
|
90
|
+
--major Group by major
|
|
91
|
+
--minor Group by minor
|
|
92
|
+
--patch Group by patch
|
|
93
|
+
--top <number> Show top <number> versions
|
|
94
|
+
`);
|
|
27
95
|
}
|
|
28
96
|
function sumByMajor(stats) {
|
|
29
97
|
const result = {};
|
|
@@ -80,3 +148,8 @@ function formatDownloads(downloads, maxDownloads) {
|
|
|
80
148
|
}
|
|
81
149
|
return downloads.toString();
|
|
82
150
|
}
|
|
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/chart.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function renderChart(value, { length = 50 } = {}) {
|
|
2
2
|
const filledChars = Math.round(value * length);
|
|
3
3
|
const emptyChars = length - filledChars;
|
|
4
|
-
return
|
|
4
|
+
return '█'.repeat(filledChars) + ' '.repeat(emptyChars);
|
|
5
5
|
}
|
package/dist/colors.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import tinygradient from 'tinygradient';
|
|
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)),
|
|
8
|
+
};
|
|
9
|
+
function toColors(colors) {
|
|
10
|
+
return colors.map((c) => c.toHexString());
|
|
11
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
bin();
|
|
1
|
+
export { pkgStats } from './bin.js';
|
package/dist/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function parseVersion(version) {
|
|
2
|
-
const [versionCore, preRelease] = version.split(
|
|
3
|
-
const [major, minor, patch] = versionCore.split(
|
|
2
|
+
const [versionCore, preRelease] = version.split('-');
|
|
3
|
+
const [major, minor, patch] = versionCore.split('.');
|
|
4
4
|
return {
|
|
5
5
|
major: Number(major),
|
|
6
6
|
minor: Number(minor),
|
package/package.json
CHANGED
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pkg-stats",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Beautiful package download stats",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Beautiful NPM package download stats",
|
|
5
|
+
"author": "Maciej Jastrzębski <mdjastrzebski@gmail.com> (https://github.com/mdjastrzebski)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"npm",
|
|
9
|
+
"package",
|
|
10
|
+
"stats",
|
|
11
|
+
"downloads",
|
|
12
|
+
"weekly"
|
|
13
|
+
],
|
|
5
14
|
"type": "module",
|
|
6
15
|
"main": "dist/index.js",
|
|
7
16
|
"files": [
|
|
8
17
|
"dist"
|
|
9
18
|
],
|
|
10
|
-
"
|
|
11
|
-
"
|
|
19
|
+
"bin": {
|
|
20
|
+
"pkg-stats": "./dist/bin.js"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"chalk": "^5.4.1",
|
|
24
|
+
"minimist": "^1.2.8",
|
|
25
|
+
"tinygradient": "^1.1.5"
|
|
12
26
|
},
|
|
13
|
-
"keywords": [],
|
|
14
|
-
"author": "",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c",
|
|
17
27
|
"devDependencies": {
|
|
28
|
+
"@types/minimist": "^1.2.5",
|
|
18
29
|
"@types/node": "^22.10.5",
|
|
19
30
|
"typescript": "^5.7.3"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc"
|
|
20
34
|
}
|
|
21
|
-
}
|
|
35
|
+
}
|