pkg-stats 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/__tests__/chart.test.js +1 -1
- package/dist/bin.js +13 -51
- package/dist/chart.js +4 -2
- package/dist/cli-options.js +101 -19
- package/dist/format.js +9 -0
- package/dist/mode/compare-packages.js +48 -0
- package/dist/mode/package-details.js +57 -0
- package/dist/mode/package-stats.js +57 -0
- package/dist/mode/single-package.js +58 -0
- package/dist/mode/single-package.ts +0 -0
- package/dist/stats.js +20 -10
- package/package.json +3 -4
@@ -1,7 +1,7 @@
|
|
1
1
|
import { expect, test } from 'vitest';
|
2
2
|
import { renderChart } from '../chart.js';
|
3
3
|
test('renderChart basic tests', () => {
|
4
|
-
expect(renderChart(0.0, { length: 10 })).toMatchInlineSnapshot(`"
|
4
|
+
expect(renderChart(0.0, { length: 10 })).toMatchInlineSnapshot(`"▏ "`);
|
5
5
|
expect(renderChart(0.5, { length: 10 })).toMatchInlineSnapshot(`"█████ "`);
|
6
6
|
expect(renderChart(1.0, { length: 10 })).toMatchInlineSnapshot(`"██████████"`);
|
7
7
|
});
|
package/dist/bin.js
CHANGED
@@ -1,60 +1,22 @@
|
|
1
1
|
import chalk from 'chalk';
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import { fetchNpmLastWeekDownloads } from './npm-api.js';
|
6
|
-
import { groupByType, pickTopStats } from './stats.js';
|
7
|
-
import { parseVersion, versionCompare } from './version.js';
|
2
|
+
import { parseCliOptions, showHelp } from './cli-options.js';
|
3
|
+
import { comparePackages } from './mode/compare-packages.js';
|
4
|
+
import { printPackageStats } from './mode/package-stats.js';
|
8
5
|
export async function pkgStats(argv) {
|
9
|
-
|
10
|
-
let data;
|
6
|
+
let options;
|
11
7
|
try {
|
12
|
-
|
8
|
+
options = parseCliOptions(argv);
|
13
9
|
}
|
14
10
|
catch (error) {
|
15
|
-
|
16
|
-
|
11
|
+
showHelp();
|
12
|
+
console.error(chalk.red(`Error parsing CLI options: ${error instanceof Error ? error.message : error}`));
|
13
|
+
process.exit(2);
|
17
14
|
}
|
18
|
-
if (
|
19
|
-
|
20
|
-
process.exit(1);
|
15
|
+
if (options.packageNames.length === 1) {
|
16
|
+
await printPackageStats(options.packageNames[0], options);
|
21
17
|
}
|
22
|
-
|
23
|
-
.
|
24
|
-
const version = parseVersion(versionString);
|
25
|
-
return {
|
26
|
-
...version,
|
27
|
-
downloads: data.downloads[versionString],
|
28
|
-
};
|
29
|
-
})
|
30
|
-
.sort(versionCompare);
|
31
|
-
const groupedStats = groupByType(options.group, rawStats);
|
32
|
-
const totalDownloads = Object.values(groupedStats).reduce((sum, version) => sum + version.downloads, 0);
|
33
|
-
const groupedStatsToDisplay = options.top
|
34
|
-
? pickTopStats(groupedStats, options.top)
|
35
|
-
: groupedStats;
|
36
|
-
const colors = getColors(groupedStatsToDisplay.length, options.color);
|
37
|
-
const primaryColor = chalk.hex(colors[0]);
|
38
|
-
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(options.packageName)}\n`));
|
39
|
-
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
40
|
-
console.log(options.top ? `Top ${options.top} versions:\n` : 'By version:\n');
|
41
|
-
const maxDownloads = Math.max(...groupedStats.map((v) => v.downloads));
|
42
|
-
groupedStatsToDisplay.forEach((item, i) => {
|
43
|
-
const versionParts = item.versionString.split('.');
|
44
|
-
const version = versionParts.length < 3 ? `${item.versionString}.x` : item.versionString;
|
45
|
-
const chart = renderChart(item.downloads / maxDownloads);
|
46
|
-
const downloads = formatDownloads(item.downloads, maxDownloads);
|
47
|
-
const color = chalk.hex(colors[i]);
|
48
|
-
console.log(`${version.padStart(8)} ${color(chart)} ${color(downloads.padStart(6))}`);
|
49
|
-
});
|
50
|
-
console.log('');
|
51
|
-
}
|
52
|
-
function formatDownloads(downloads, maxDownloads) {
|
53
|
-
if (maxDownloads > 1000000) {
|
54
|
-
return `${(downloads / 1000000).toFixed(1)}M`;
|
18
|
+
else {
|
19
|
+
await comparePackages(options.packageNames, options);
|
55
20
|
}
|
56
|
-
|
57
|
-
return `${(downloads / 1000).toFixed(1)}K`;
|
58
|
-
}
|
59
|
-
return downloads.toString();
|
21
|
+
console.log('');
|
60
22
|
}
|
package/dist/chart.js
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
export function renderChart(value, { length = 50 } = {}) {
|
2
2
|
const filledChars = Math.round(value * length);
|
3
|
-
|
4
|
-
|
3
|
+
if (filledChars === 0) {
|
4
|
+
return '▏' + ' '.repeat(length - 1);
|
5
|
+
}
|
6
|
+
return '█'.repeat(filledChars) + ' '.repeat(length - filledChars);
|
5
7
|
}
|
package/dist/cli-options.js
CHANGED
@@ -1,24 +1,106 @@
|
|
1
|
-
import
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import meow from 'meow';
|
3
|
+
import redent from 'redent';
|
2
4
|
import { COLOR_SCHEMES } from './colors.js';
|
5
|
+
const colorCommand = chalk.hex('#22c1c3');
|
6
|
+
const colorOption = chalk.hex('#fdbb2d');
|
7
|
+
const HELP = `
|
8
|
+
${colorCommand('pkg-stats')} <package> - Show version stats
|
9
|
+
${colorCommand('pkg-stats')} <package-1> <package-2>... - Compare between packages
|
10
|
+
|
11
|
+
Options:
|
12
|
+
${colorOption('--major')} Group by major version
|
13
|
+
${colorOption('--minor')} Group by minor version
|
14
|
+
${colorOption('--patch')} Group by patch version
|
15
|
+
${colorOption('-t, --top')} <number> Show top <number> most downloaded versions
|
16
|
+
${colorOption('-a, --all')} Include all versions in output, even those with minimal downloads
|
17
|
+
${colorOption('-c, --color')} <scheme> ${wrapOption(`Choose color scheme from: ${COLOR_SCHEMES.sort().join(', ')}`, 50, 24)}
|
18
|
+
|
19
|
+
Examples:
|
20
|
+
${chalk.dim('# Show stats for react')}
|
21
|
+
${colorCommand('pkg-stats')} react
|
22
|
+
|
23
|
+
${chalk.dim('# Compare react, vue, angular and svelte')}
|
24
|
+
${colorCommand('pkg-stats')} react vue @angular/core svelte
|
25
|
+
|
26
|
+
${chalk.dim('# Show top 10 major versions of lodash')}
|
27
|
+
${colorCommand('pkg-stats')} lodash ${colorOption('--major -t 10')}
|
28
|
+
`;
|
29
|
+
function wrapOption(text, maxLength, indent) {
|
30
|
+
const words = text.split(' ');
|
31
|
+
let result = '';
|
32
|
+
let currentLine = words[0];
|
33
|
+
for (let i = 1; i < words.length; i++) {
|
34
|
+
const nextCurrentLine = currentLine + ' ' + words[i];
|
35
|
+
if (nextCurrentLine.length <= maxLength) {
|
36
|
+
currentLine = nextCurrentLine;
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
result += `\n${currentLine}`;
|
40
|
+
currentLine = words[i];
|
41
|
+
}
|
42
|
+
}
|
43
|
+
if (currentLine) {
|
44
|
+
result += `\n${currentLine}`;
|
45
|
+
}
|
46
|
+
return redent(result.trim(), indent).trim();
|
47
|
+
}
|
48
|
+
export function showHelp() {
|
49
|
+
console.log(redent(HELP, 2));
|
50
|
+
}
|
3
51
|
export function parseCliOptions(argv) {
|
4
|
-
|
5
|
-
.
|
6
|
-
|
7
|
-
|
8
|
-
.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
52
|
+
const cli = meow(HELP, {
|
53
|
+
argv: argv.slice(2),
|
54
|
+
autoHelp: true,
|
55
|
+
description: 'Show NPM weekly downloads stats:',
|
56
|
+
importMeta: import.meta,
|
57
|
+
flags: {
|
58
|
+
help: {
|
59
|
+
type: 'boolean',
|
60
|
+
shortFlag: 'h',
|
61
|
+
},
|
62
|
+
major: {
|
63
|
+
type: 'boolean',
|
64
|
+
shortFlag: 'm',
|
65
|
+
},
|
66
|
+
minor: {
|
67
|
+
type: 'boolean',
|
68
|
+
},
|
69
|
+
patch: {
|
70
|
+
type: 'boolean',
|
71
|
+
},
|
72
|
+
top: {
|
73
|
+
shortFlag: 't',
|
74
|
+
type: 'number',
|
75
|
+
},
|
76
|
+
all: {
|
77
|
+
type: 'boolean',
|
78
|
+
shortFlag: 'a',
|
79
|
+
},
|
80
|
+
color: {
|
81
|
+
shortFlag: 'c',
|
82
|
+
type: 'string',
|
83
|
+
choices: COLOR_SCHEMES,
|
84
|
+
},
|
85
|
+
},
|
86
|
+
});
|
87
|
+
if (cli.flags.help) {
|
88
|
+
cli.showHelp();
|
89
|
+
}
|
90
|
+
if (!cli.input.length) {
|
91
|
+
throw new Error('At least one <package-name> is required');
|
92
|
+
}
|
16
93
|
return {
|
17
|
-
|
18
|
-
group:
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
94
|
+
packageNames: cli.input,
|
95
|
+
group: cli.flags.major
|
96
|
+
? 'major'
|
97
|
+
: cli.flags.minor
|
98
|
+
? 'minor'
|
99
|
+
: cli.flags.patch
|
100
|
+
? 'patch'
|
101
|
+
: undefined,
|
102
|
+
top: cli.flags.top,
|
103
|
+
all: cli.flags.all,
|
104
|
+
color: cli.flags.color,
|
23
105
|
};
|
24
106
|
}
|
package/dist/format.js
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import { renderChart } from '../chart.js';
|
3
|
+
import { getColors } from '../colors.js';
|
4
|
+
import { formatDownloads } from '../format.js';
|
5
|
+
import { fetchNpmLastWeekDownloads } from '../npm-api.js';
|
6
|
+
export async function comparePackages(packageNames, options) {
|
7
|
+
const rawPackages = await Promise.all(packageNames.map((packageName) => fetchPackageData(packageName)));
|
8
|
+
const packagesToDisplay = rawPackages
|
9
|
+
.filter((pkg) => pkg !== undefined)
|
10
|
+
.sort((a, b) => b.downloads - a.downloads);
|
11
|
+
if (packagesToDisplay.length === 0) {
|
12
|
+
console.error(chalk.red('\nNo packages found.\n'));
|
13
|
+
process.exit(1);
|
14
|
+
}
|
15
|
+
console.log(chalk.bold(`\nNPM weekly downloads\n`));
|
16
|
+
const maxDownloads = Math.max(...packagesToDisplay.map((v) => v.downloads));
|
17
|
+
const displayData = packagesToDisplay.map((item) => {
|
18
|
+
return {
|
19
|
+
name: item.packageName,
|
20
|
+
chart: renderChart(item.downloads / maxDownloads),
|
21
|
+
downloads: formatDownloads(item.downloads, maxDownloads),
|
22
|
+
};
|
23
|
+
});
|
24
|
+
const maxNameLength = Math.max(...displayData.map((item) => item.name.length));
|
25
|
+
const maxDownloadsLength = Math.max(...displayData.map((item) => item.downloads.length));
|
26
|
+
const colors = getColors(packagesToDisplay.length, options.color);
|
27
|
+
displayData.forEach((item, i) => {
|
28
|
+
const color = chalk.hex(colors[i]);
|
29
|
+
console.log(`${item.name.padStart(2 + maxNameLength)} ${color(item.chart)} ${color(item.downloads.padStart(maxDownloadsLength))}`);
|
30
|
+
});
|
31
|
+
}
|
32
|
+
async function fetchPackageData(packageName) {
|
33
|
+
try {
|
34
|
+
const data = await fetchNpmLastWeekDownloads(packageName);
|
35
|
+
if (!Object.keys(data.downloads).length) {
|
36
|
+
console.warn(chalk.yellow(`No data found for package "${packageName}".`));
|
37
|
+
return undefined;
|
38
|
+
}
|
39
|
+
return {
|
40
|
+
packageName,
|
41
|
+
downloads: Object.values(data.downloads).reduce((sum, downloads) => sum + downloads, 0),
|
42
|
+
};
|
43
|
+
}
|
44
|
+
catch (error) {
|
45
|
+
console.warn(chalk.yellow(`Failed to fetch data for package "${packageName}"`, error));
|
46
|
+
return undefined;
|
47
|
+
}
|
48
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import { renderChart } from '../chart.js';
|
3
|
+
import { getColors } from '../colors.js';
|
4
|
+
import { formatDownloads } from '../format.js';
|
5
|
+
import { fetchNpmLastWeekDownloads } from '../npm-api.js';
|
6
|
+
import { filterStats, groupStats } from '../stats.js';
|
7
|
+
import { parseVersion, versionCompare } from '../version.js';
|
8
|
+
export async function packageDetails(packageName, options) {
|
9
|
+
let data;
|
10
|
+
try {
|
11
|
+
data = await fetchNpmLastWeekDownloads(packageName);
|
12
|
+
}
|
13
|
+
catch (error) {
|
14
|
+
console.error(`Failed to fetch data for package "${packageName}"`, error);
|
15
|
+
return;
|
16
|
+
}
|
17
|
+
if (!Object.keys(data.downloads).length) {
|
18
|
+
console.error(`No data found for package "${packageName}".\n`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
21
|
+
const npmStats = Object.keys(data.downloads)
|
22
|
+
.map((versionString) => {
|
23
|
+
const version = parseVersion(versionString);
|
24
|
+
return {
|
25
|
+
...version,
|
26
|
+
downloads: data.downloads[versionString],
|
27
|
+
};
|
28
|
+
})
|
29
|
+
.sort(versionCompare);
|
30
|
+
const { type, stats } = groupStats(npmStats, options.group);
|
31
|
+
const totalDownloads = Object.values(stats).reduce((sum, version) => sum + version.downloads, 0);
|
32
|
+
const statsToDisplay = filterStats(stats, {
|
33
|
+
totalDownloads,
|
34
|
+
all: options.all,
|
35
|
+
top: options.top,
|
36
|
+
});
|
37
|
+
const colors = getColors(statsToDisplay.length, options.color);
|
38
|
+
const primaryColor = chalk.hex(colors[0]);
|
39
|
+
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(packageName)}\n`));
|
40
|
+
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
41
|
+
console.log(options.top ? `Top ${options.top} ${type} versions:\n` : `By ${type} version:\n`);
|
42
|
+
const maxDownloads = Math.max(...stats.map((v) => v.downloads));
|
43
|
+
const displayData = statsToDisplay.map((item) => {
|
44
|
+
const versionParts = item.versionString.split('.');
|
45
|
+
return {
|
46
|
+
version: versionParts.length < 3 ? `${item.versionString}.x` : item.versionString,
|
47
|
+
chart: renderChart(item.downloads / maxDownloads),
|
48
|
+
downloads: formatDownloads(item.downloads, maxDownloads),
|
49
|
+
};
|
50
|
+
});
|
51
|
+
const maxVersionLength = Math.max(...displayData.map((item) => item.version.length));
|
52
|
+
const maxDownloadsLength = Math.max(...displayData.map((item) => item.downloads.length));
|
53
|
+
displayData.forEach((item, i) => {
|
54
|
+
const color = chalk.hex(colors[i]);
|
55
|
+
console.log(`${item.version.padStart(2 + maxVersionLength)} ${color(item.chart)} ${color(item.downloads.padStart(maxDownloadsLength))}`);
|
56
|
+
});
|
57
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import { renderChart } from '../chart.js';
|
3
|
+
import { getColors } from '../colors.js';
|
4
|
+
import { formatDownloads } from '../format.js';
|
5
|
+
import { fetchNpmLastWeekDownloads } from '../npm-api.js';
|
6
|
+
import { filterStats, groupStats } from '../stats.js';
|
7
|
+
import { parseVersion, versionCompare } from '../version.js';
|
8
|
+
export async function printPackageStats(packageName, options) {
|
9
|
+
let data;
|
10
|
+
try {
|
11
|
+
data = await fetchNpmLastWeekDownloads(packageName);
|
12
|
+
}
|
13
|
+
catch (error) {
|
14
|
+
console.error(`Failed to fetch data for package "${packageName}"`, error);
|
15
|
+
return;
|
16
|
+
}
|
17
|
+
if (!Object.keys(data.downloads).length) {
|
18
|
+
console.error(`No data found for package "${packageName}".\n`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
21
|
+
const npmStats = Object.keys(data.downloads)
|
22
|
+
.map((versionString) => {
|
23
|
+
const version = parseVersion(versionString);
|
24
|
+
return {
|
25
|
+
...version,
|
26
|
+
downloads: data.downloads[versionString],
|
27
|
+
};
|
28
|
+
})
|
29
|
+
.sort(versionCompare);
|
30
|
+
const { type, stats } = groupStats(npmStats, options.group);
|
31
|
+
const totalDownloads = Object.values(stats).reduce((sum, version) => sum + version.downloads, 0);
|
32
|
+
const statsToDisplay = filterStats(stats, {
|
33
|
+
totalDownloads,
|
34
|
+
all: options.all,
|
35
|
+
top: options.top,
|
36
|
+
});
|
37
|
+
const colors = getColors(statsToDisplay.length, options.color);
|
38
|
+
const primaryColor = chalk.hex(colors[0]);
|
39
|
+
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(packageName)}\n`));
|
40
|
+
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
41
|
+
console.log(options.top ? `Top ${options.top} ${type} versions:\n` : `By ${type} version:\n`);
|
42
|
+
const maxDownloads = Math.max(...stats.map((v) => v.downloads));
|
43
|
+
const displayData = statsToDisplay.map((item) => {
|
44
|
+
const versionParts = item.versionString.split('.');
|
45
|
+
return {
|
46
|
+
version: versionParts.length < 3 ? `${item.versionString}.x` : item.versionString,
|
47
|
+
chart: renderChart(item.downloads / maxDownloads),
|
48
|
+
downloads: formatDownloads(item.downloads, maxDownloads),
|
49
|
+
};
|
50
|
+
});
|
51
|
+
const maxVersionLength = Math.max(...displayData.map((item) => item.version.length));
|
52
|
+
const maxDownloadsLength = Math.max(...displayData.map((item) => item.downloads.length));
|
53
|
+
displayData.forEach((item, i) => {
|
54
|
+
const color = chalk.hex(colors[i]);
|
55
|
+
console.log(`${item.version.padStart(2 + maxVersionLength)} ${color(item.chart)} ${color(item.downloads.padStart(maxDownloadsLength))}`);
|
56
|
+
});
|
57
|
+
}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import chalk from 'chalk';
|
2
|
+
import { renderChart } from '../chart.js';
|
3
|
+
import { getColors } from '../colors.js';
|
4
|
+
import { formatDownloads } from '../format.js';
|
5
|
+
import { fetchNpmLastWeekDownloads } from '../npm-api.js';
|
6
|
+
import { filterStats, groupStats } from '../stats.js';
|
7
|
+
import { parseVersion, versionCompare } from '../version.js';
|
8
|
+
export async function singlePackage(packageName, options) {
|
9
|
+
let data;
|
10
|
+
try {
|
11
|
+
data = await fetchNpmLastWeekDownloads(packageName);
|
12
|
+
}
|
13
|
+
catch (error) {
|
14
|
+
console.error(`Failed to fetch data for package "${packageName}"`, error);
|
15
|
+
return;
|
16
|
+
}
|
17
|
+
if (!Object.keys(data.downloads).length) {
|
18
|
+
console.error(`No data found for package "${packageName}".\n`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
21
|
+
const npmStats = Object.keys(data.downloads)
|
22
|
+
.map((versionString) => {
|
23
|
+
const version = parseVersion(versionString);
|
24
|
+
return {
|
25
|
+
...version,
|
26
|
+
downloads: data.downloads[versionString],
|
27
|
+
};
|
28
|
+
})
|
29
|
+
.sort(versionCompare);
|
30
|
+
const { type, stats } = groupStats(npmStats, options.group);
|
31
|
+
const totalDownloads = Object.values(stats).reduce((sum, version) => sum + version.downloads, 0);
|
32
|
+
const statsToDisplay = filterStats(stats, {
|
33
|
+
totalDownloads,
|
34
|
+
all: options.all,
|
35
|
+
top: options.top,
|
36
|
+
});
|
37
|
+
const colors = getColors(statsToDisplay.length, options.color);
|
38
|
+
const primaryColor = chalk.hex(colors[0]);
|
39
|
+
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(packageName)}\n`));
|
40
|
+
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
41
|
+
console.log(options.top ? `Top ${options.top} ${type} versions:\n` : `By ${type} version:\n`);
|
42
|
+
const maxDownloads = Math.max(...stats.map((v) => v.downloads));
|
43
|
+
const displayData = statsToDisplay.map((item) => {
|
44
|
+
const versionParts = item.versionString.split('.');
|
45
|
+
return {
|
46
|
+
version: versionParts.length < 3 ? `${item.versionString}.x` : item.versionString,
|
47
|
+
chart: renderChart(item.downloads / maxDownloads),
|
48
|
+
downloads: formatDownloads(item.downloads, maxDownloads),
|
49
|
+
};
|
50
|
+
});
|
51
|
+
const maxVersionLength = Math.max(...displayData.map((item) => item.version.length));
|
52
|
+
const maxDownloadsLength = Math.max(...displayData.map((item) => item.downloads.length));
|
53
|
+
displayData.forEach((item, i) => {
|
54
|
+
const color = chalk.hex(colors[i]);
|
55
|
+
console.log(`${item.version.padStart(2 + maxVersionLength)} ${color(item.chart)} ${color(item.downloads.padStart(maxDownloadsLength))}`);
|
56
|
+
});
|
57
|
+
console.log('');
|
58
|
+
}
|
File without changes
|
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 = {};
|
@@ -65,7 +65,17 @@ function groupByPatch(stats) {
|
|
65
65
|
}
|
66
66
|
return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
|
67
67
|
}
|
68
|
-
export function
|
68
|
+
export function filterStats(stats, options) {
|
69
|
+
if (options.all) {
|
70
|
+
return stats;
|
71
|
+
}
|
72
|
+
if (options.top) {
|
73
|
+
return pickTopStats(stats, options.top);
|
74
|
+
}
|
75
|
+
const downloadThreshold = 0.005 * options.totalDownloads; // 0.5%
|
76
|
+
return stats.filter((stat) => stat.downloads >= downloadThreshold);
|
77
|
+
}
|
78
|
+
function pickTopStats(stats, top) {
|
69
79
|
const sortedStats = stats.sort((a, b) => b.downloads - a.downloads);
|
70
80
|
const topStats = sortedStats.slice(0, top);
|
71
81
|
return topStats.sort((a, b) => versionCompare(a.version, b.version));
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "pkg-stats",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
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",
|