pkg-stats 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/bin.js +22 -24
- package/dist/cli-options.js +65 -19
- package/dist/format.js +9 -0
- package/dist/stats.js +9 -9
- package/package.json +3 -4
package/dist/bin.js
CHANGED
@@ -1,12 +1,21 @@
|
|
1
1
|
import chalk from 'chalk';
|
2
2
|
import { renderChart } from './chart.js';
|
3
|
-
import { parseCliOptions } from './cli-options.js';
|
3
|
+
import { parseCliOptions, showHelp } from './cli-options.js';
|
4
4
|
import { getColors } from './colors.js';
|
5
|
+
import { formatDownloads } from './format.js';
|
5
6
|
import { fetchNpmLastWeekDownloads } from './npm-api.js';
|
6
|
-
import {
|
7
|
+
import { groupStats, pickTopStats } from './stats.js';
|
7
8
|
import { parseVersion, versionCompare } from './version.js';
|
8
9
|
export async function pkgStats(argv) {
|
9
|
-
|
10
|
+
let options;
|
11
|
+
try {
|
12
|
+
options = parseCliOptions(argv);
|
13
|
+
}
|
14
|
+
catch (error) {
|
15
|
+
showHelp();
|
16
|
+
console.error(chalk.red(`Error parsing CLI options: ${error instanceof Error ? error.message : error}`));
|
17
|
+
process.exit(2);
|
18
|
+
}
|
10
19
|
let data;
|
11
20
|
try {
|
12
21
|
data = await fetchNpmLastWeekDownloads(options.packageName);
|
@@ -19,7 +28,7 @@ export async function pkgStats(argv) {
|
|
19
28
|
console.error(`No data found for package "${options.packageName}".\n`);
|
20
29
|
process.exit(1);
|
21
30
|
}
|
22
|
-
const
|
31
|
+
const npmStats = Object.keys(data.downloads)
|
23
32
|
.map((versionString) => {
|
24
33
|
const version = parseVersion(versionString);
|
25
34
|
return {
|
@@ -28,33 +37,22 @@ export async function pkgStats(argv) {
|
|
28
37
|
};
|
29
38
|
})
|
30
39
|
.sort(versionCompare);
|
31
|
-
const
|
32
|
-
const totalDownloads = Object.values(
|
33
|
-
const
|
34
|
-
|
35
|
-
: groupedStats;
|
36
|
-
const colors = getColors(groupedStatsToDisplay.length, options.color);
|
40
|
+
const { type, stats } = groupStats(npmStats, options.group);
|
41
|
+
const totalDownloads = Object.values(stats).reduce((sum, version) => sum + version.downloads, 0);
|
42
|
+
const statsToDisplay = options.top ? pickTopStats(stats, options.top) : stats;
|
43
|
+
const colors = getColors(statsToDisplay.length, options.color);
|
37
44
|
const primaryColor = chalk.hex(colors[0]);
|
38
45
|
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(options.packageName)}\n`));
|
39
46
|
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
40
|
-
console.log(options.top ? `Top ${options.top} versions:\n` :
|
41
|
-
const maxDownloads = Math.max(...
|
42
|
-
|
47
|
+
console.log(options.top ? `Top ${options.top} ${type} versions:\n` : `By ${type} version:\n`);
|
48
|
+
const maxDownloads = Math.max(...stats.map((v) => v.downloads));
|
49
|
+
statsToDisplay.forEach((item, i) => {
|
43
50
|
const versionParts = item.versionString.split('.');
|
44
|
-
const
|
51
|
+
const versionString = versionParts.length < 3 ? `${item.versionString}.x` : item.versionString;
|
45
52
|
const chart = renderChart(item.downloads / maxDownloads);
|
46
53
|
const downloads = formatDownloads(item.downloads, maxDownloads);
|
47
54
|
const color = chalk.hex(colors[i]);
|
48
|
-
console.log(`${
|
55
|
+
console.log(`${versionString.padStart(8)} ${color(chart)} ${color(downloads.padStart(6))}`);
|
49
56
|
});
|
50
57
|
console.log('');
|
51
58
|
}
|
52
|
-
function formatDownloads(downloads, maxDownloads) {
|
53
|
-
if (maxDownloads > 1000000) {
|
54
|
-
return `${(downloads / 1000000).toFixed(1)}M`;
|
55
|
-
}
|
56
|
-
if (maxDownloads > 1000) {
|
57
|
-
return `${(downloads / 1000).toFixed(1)}K`;
|
58
|
-
}
|
59
|
-
return downloads.toString();
|
60
|
-
}
|
package/dist/cli-options.js
CHANGED
@@ -1,24 +1,70 @@
|
|
1
|
-
import
|
1
|
+
import meow from 'meow';
|
2
|
+
import redent from 'redent';
|
2
3
|
import { COLOR_SCHEMES } from './colors.js';
|
4
|
+
const HELP = `
|
5
|
+
pkg-stats <package-name>
|
6
|
+
|
7
|
+
Show NPM weekly downloads stats for a package
|
8
|
+
|
9
|
+
Options:
|
10
|
+
-h, --help Show help
|
11
|
+
--major Group by major version
|
12
|
+
--minor Group by minor version
|
13
|
+
--patch Group by patch version
|
14
|
+
-t, --top <number> Show top <number> versions
|
15
|
+
-c, --color <color> Color scheme: ${COLOR_SCHEMES.sort().join(', ')}
|
16
|
+
`;
|
17
|
+
export function showHelp() {
|
18
|
+
console.log(redent(HELP, 2));
|
19
|
+
}
|
3
20
|
export function parseCliOptions(argv) {
|
4
|
-
|
5
|
-
.
|
6
|
-
|
7
|
-
|
8
|
-
.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
const cli = meow(HELP, {
|
22
|
+
argv: argv.slice(2),
|
23
|
+
autoHelp: true,
|
24
|
+
description: 'Show NPM weekly downloads stats for a package',
|
25
|
+
importMeta: import.meta,
|
26
|
+
flags: {
|
27
|
+
help: {
|
28
|
+
type: 'boolean',
|
29
|
+
shortFlag: 'h',
|
30
|
+
},
|
31
|
+
major: {
|
32
|
+
type: 'boolean',
|
33
|
+
shortFlag: 'm',
|
34
|
+
},
|
35
|
+
minor: {
|
36
|
+
type: 'boolean',
|
37
|
+
},
|
38
|
+
patch: {
|
39
|
+
type: 'boolean',
|
40
|
+
},
|
41
|
+
top: {
|
42
|
+
shortFlag: 't',
|
43
|
+
type: 'number',
|
44
|
+
},
|
45
|
+
color: {
|
46
|
+
shortFlag: 'c',
|
47
|
+
type: 'string',
|
48
|
+
choices: COLOR_SCHEMES,
|
49
|
+
},
|
50
|
+
},
|
51
|
+
});
|
52
|
+
if (cli.flags.help) {
|
53
|
+
cli.showHelp();
|
54
|
+
}
|
55
|
+
if (!cli.input[0]) {
|
56
|
+
throw new Error('<package-name> is required');
|
57
|
+
}
|
16
58
|
return {
|
17
|
-
packageName:
|
18
|
-
group:
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
59
|
+
packageName: cli.input[0],
|
60
|
+
group: cli.flags.major
|
61
|
+
? 'major'
|
62
|
+
: cli.flags.minor
|
63
|
+
? 'minor'
|
64
|
+
: cli.flags.patch
|
65
|
+
? 'patch'
|
66
|
+
: undefined,
|
67
|
+
top: cli.flags.top,
|
68
|
+
color: cli.flags.color,
|
23
69
|
};
|
24
70
|
}
|
package/dist/format.js
ADDED
package/dist/stats.js
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
import { versionCompare } from './version.js';
|
2
|
-
export function
|
2
|
+
export function groupStats(stats, type) {
|
3
3
|
if (type === 'major') {
|
4
|
-
return groupByMajor(stats);
|
4
|
+
return { type: 'major', stats: groupByMajor(stats) };
|
5
5
|
}
|
6
6
|
if (type === 'minor') {
|
7
|
-
return groupByMinor(stats);
|
7
|
+
return { type: 'minor', stats: groupByMinor(stats) };
|
8
8
|
}
|
9
9
|
if (type === 'patch') {
|
10
|
-
return groupByPatch(stats);
|
10
|
+
return { type: 'patch', stats: groupByPatch(stats) };
|
11
11
|
}
|
12
12
|
const groupedByMajor = groupByMajor(stats);
|
13
|
-
if (groupedByMajor.length
|
14
|
-
return groupedByMajor;
|
13
|
+
if (groupedByMajor.length >= 3) {
|
14
|
+
return { type: 'major', stats: groupedByMajor };
|
15
15
|
}
|
16
16
|
const groupedByMinor = groupByMinor(stats);
|
17
|
-
if (groupedByMinor.length
|
18
|
-
return groupedByMinor;
|
17
|
+
if (groupedByMinor.length >= 3) {
|
18
|
+
return { type: 'minor', stats: groupedByMinor };
|
19
19
|
}
|
20
|
-
return groupByPatch(stats);
|
20
|
+
return { type: 'patch', stats: groupByPatch(stats) };
|
21
21
|
}
|
22
22
|
function groupByMajor(stats) {
|
23
23
|
const result = {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "pkg-stats",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.1",
|
4
4
|
"description": "Beautiful NPM package download stats",
|
5
5
|
"license": "MIT",
|
6
6
|
"repository": {
|
@@ -34,18 +34,17 @@
|
|
34
34
|
},
|
35
35
|
"dependencies": {
|
36
36
|
"chalk": "^5.4.1",
|
37
|
-
"
|
37
|
+
"meow": "^13.2.0",
|
38
|
+
"redent": "^4.0.0",
|
38
39
|
"tinygradient": "^1.1.5"
|
39
40
|
},
|
40
41
|
"devDependencies": {
|
41
42
|
"@eslint/js": "^9.18.0",
|
42
43
|
"@release-it/conventional-changelog": "^10.0.0",
|
43
|
-
"@types/minimist": "^1.2.5",
|
44
44
|
"@types/node": "^22.10.5",
|
45
45
|
"eslint": "^9.18.0",
|
46
46
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
47
47
|
"globals": "^15.14.0",
|
48
|
-
"redent": "^4.0.0",
|
49
48
|
"release-it": "^18.1.1",
|
50
49
|
"typescript": "^5.7.3",
|
51
50
|
"typescript-eslint": "^8.19.1",
|