pkg-stats 0.5.0 → 0.6.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/__tests__/output.test.js +3 -3
- package/dist/cli-options.js +1 -7
- package/dist/mode/compare-packages.js +1 -1
- package/dist/mode/package-stats.js +1 -1
- package/dist/output.js +15 -10
- package/package.json +1 -1
- package/dist/__tests__/output.js +0 -8
- package/dist/chart.js +0 -7
- package/dist/mode/package-details.js +0 -57
- package/dist/mode/package-info.js +0 -64
- package/dist/mode/single-package.js +0 -58
- package/dist/mode/single-package.ts +0 -0
- package/dist/render.js +0 -23
- package/dist/style.js +0 -16
- package/dist/types.js +0 -1
@@ -1,7 +1,7 @@
|
|
1
1
|
import { expect, test } from 'vitest';
|
2
2
|
import { formatBar } from '../output.js';
|
3
3
|
test('renderChart basic tests', () => {
|
4
|
-
expect(formatBar(0.0, {
|
5
|
-
expect(formatBar(0.5, {
|
6
|
-
expect(formatBar(1.0, {
|
4
|
+
expect(formatBar(0.0, { width: 10 })).toMatchInlineSnapshot(`"▏ "`);
|
5
|
+
expect(formatBar(0.5, { width: 10 })).toMatchInlineSnapshot(`"█████ "`);
|
6
|
+
expect(formatBar(1.0, { width: 10 })).toMatchInlineSnapshot(`"██████████"`);
|
7
7
|
});
|
package/dist/cli-options.js
CHANGED
@@ -14,7 +14,6 @@ Options:
|
|
14
14
|
${colorOption('--patch')} Group by patch version
|
15
15
|
${colorOption('-t, --top')} <number> Show top <number> most downloaded versions
|
16
16
|
${colorOption('-a, --all')} Include all versions in output, even those with minimal downloads
|
17
|
-
${colorOption('-x, --extended')} Show extended stats
|
18
17
|
${colorOption('-c, --color')} <scheme> ${wrapOption(`Choose color scheme from: ${COLOR_SCHEMES.sort().join(', ')}`, 50, 24)}
|
19
18
|
|
20
19
|
Examples:
|
@@ -78,10 +77,6 @@ export function parseCliOptions(argv) {
|
|
78
77
|
type: 'boolean',
|
79
78
|
shortFlag: 'a',
|
80
79
|
},
|
81
|
-
extended: {
|
82
|
-
type: 'boolean',
|
83
|
-
shortFlag: 'x',
|
84
|
-
},
|
85
80
|
color: {
|
86
81
|
shortFlag: 'c',
|
87
82
|
type: 'string',
|
@@ -106,8 +101,7 @@ export function parseCliOptions(argv) {
|
|
106
101
|
: undefined,
|
107
102
|
top: cli.flags.top,
|
108
103
|
all: cli.flags.all ?? false,
|
109
|
-
|
110
|
-
color: coalesceColor(cli.flags.color) ?? getColorOfDay(),
|
104
|
+
color: coalesceColor(cli.flags.color ?? process.env.PKG_STATS_COLOR_SCHEME) ?? getColorOfDay(),
|
111
105
|
};
|
112
106
|
}
|
113
107
|
function coalesceColor(color) {
|
@@ -16,7 +16,7 @@ export async function comparePackages(packageNames, options) {
|
|
16
16
|
const items = packagesToDisplay.map((item) => ({
|
17
17
|
label: item.packageName,
|
18
18
|
value: item.downloads,
|
19
|
-
|
19
|
+
extra: formatPercentage(item.downloads / maxDownloads),
|
20
20
|
}));
|
21
21
|
printChart(items, {
|
22
22
|
colorScheme: options.color,
|
@@ -48,7 +48,7 @@ export async function printPackageStats(packageName, options) {
|
|
48
48
|
const items = statsToDisplay.map((item) => ({
|
49
49
|
label: item.versionString,
|
50
50
|
value: item.downloads,
|
51
|
-
|
51
|
+
extra: formatPercentage(item.downloads / totalDownloads),
|
52
52
|
}));
|
53
53
|
printChart(items, {
|
54
54
|
colorScheme: options.color,
|
package/dist/output.js
CHANGED
@@ -5,24 +5,29 @@ export function printChart(items, options) {
|
|
5
5
|
const maxLabelLength = Math.max(...items.map((item) => item.label.length));
|
6
6
|
const maxValue = Math.max(...items.map((item) => item.value));
|
7
7
|
const maxValueLength = formatDownloads(maxValue, maxValue).length;
|
8
|
-
const
|
8
|
+
const maxExtraLength = Math.max(...items.map((item) => item.extra?.length ?? 0));
|
9
9
|
const colors = getColors(items.length, options.colorScheme);
|
10
10
|
const indent = options.indent ?? 0;
|
11
|
+
const chartWidth = getTerminalWidth() - indent - maxLabelLength - maxValueLength - maxExtraLength - 5;
|
11
12
|
items.forEach((item, i) => {
|
12
13
|
const color = chalk.hex(colors[i]);
|
13
14
|
const label = ' '.repeat(indent) + item.label.padStart(maxLabelLength);
|
14
|
-
const bar = formatBar(item.value / maxValue);
|
15
|
+
const bar = formatBar(item.value / maxValue, { width: clamp(chartWidth, 30, 60) });
|
15
16
|
const value = formatDownloads(item.value, maxValue).padStart(maxValueLength);
|
16
|
-
const
|
17
|
-
|
18
|
-
: '';
|
19
|
-
console.log(`${label} ${color(bar)} ${color(value)}${extended}`);
|
17
|
+
const extra = item.extra ? chalk.dim(` ${item.extra}`.padStart(maxExtraLength + 1)) : '';
|
18
|
+
console.log(`${label} ${color(bar)} ${color(value)}${extra}`);
|
20
19
|
});
|
21
20
|
}
|
22
|
-
export function formatBar(value, {
|
23
|
-
const filledChars = Math.round(value *
|
21
|
+
export function formatBar(value, { width = 50 } = {}) {
|
22
|
+
const filledChars = Math.round(value * width);
|
24
23
|
if (filledChars === 0) {
|
25
|
-
return '▏' + ' '.repeat(
|
24
|
+
return '▏' + ' '.repeat(width - 1);
|
26
25
|
}
|
27
|
-
return '█'.repeat(filledChars) + ' '.repeat(
|
26
|
+
return '█'.repeat(filledChars) + ' '.repeat(width - filledChars);
|
27
|
+
}
|
28
|
+
export function getTerminalWidth() {
|
29
|
+
return process.stdout.columns;
|
30
|
+
}
|
31
|
+
function clamp(value, min, max) {
|
32
|
+
return Math.min(Math.max(value, min), max);
|
28
33
|
}
|
package/package.json
CHANGED
package/dist/__tests__/output.js
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
import { expect, test } from 'vitest';
|
2
|
-
import { formatBar } from '../output.js';
|
3
|
-
|
4
|
-
test('renderChart basic tests', () => {
|
5
|
-
expect(formatBar(0.0, { length: 10 })).toMatchInlineSnapshot(`"▏ "`);
|
6
|
-
expect(formatBar(0.5, { length: 10 })).toMatchInlineSnapshot(`"█████ "`);
|
7
|
-
expect(formatBar(1.0, { length: 10 })).toMatchInlineSnapshot(`"██████████"`);
|
8
|
-
});
|
package/dist/chart.js
DELETED
@@ -1,57 +0,0 @@
|
|
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
|
-
}
|
@@ -1,64 +0,0 @@
|
|
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 fetchPackageInfo(packageName, options) {
|
9
|
-
const data = await fetchNpmLastWeekDownloads(packageName);
|
10
|
-
if (!Object.keys(data.downloads).length) {
|
11
|
-
throw new Error(`No data found for package "${packageName}".`);
|
12
|
-
}
|
13
|
-
const npmStats = Object.keys(data.downloads)
|
14
|
-
.map((versionString) => {
|
15
|
-
const version = parseVersion(versionString);
|
16
|
-
return {
|
17
|
-
...version,
|
18
|
-
downloads: data.downloads[versionString],
|
19
|
-
};
|
20
|
-
})
|
21
|
-
.sort(versionCompare);
|
22
|
-
const { type, stats } = groupStats(npmStats, options.group);
|
23
|
-
const totalDownloads = Object.values(stats).reduce((sum, version) => sum + version.downloads, 0);
|
24
|
-
return {
|
25
|
-
name: packageName,
|
26
|
-
totalDownloads,
|
27
|
-
groupingType: type,
|
28
|
-
stats: stats.map((stat) => ({
|
29
|
-
version: stat.versionString,
|
30
|
-
downloads: stat.downloads,
|
31
|
-
})),
|
32
|
-
};
|
33
|
-
}
|
34
|
-
export function printPackageInfo({ name, stats, totalDownloads, groupingType }, options) {
|
35
|
-
const statsToDisplay = filterStats(stats, {
|
36
|
-
totalDownloads,
|
37
|
-
all: options.all,
|
38
|
-
top: options.top,
|
39
|
-
});
|
40
|
-
const colors = getColors(statsToDisplay.length, options.color);
|
41
|
-
const primaryColor = chalk.hex(colors[0]);
|
42
|
-
console.log(chalk.bold(`\nNPM weekly downloads for ${primaryColor(name)}\n`));
|
43
|
-
console.log(`Total: ${primaryColor(totalDownloads.toLocaleString())} last week\n`);
|
44
|
-
console.log(options.top
|
45
|
-
? `Top ${options.top} ${groupingType} versions:\n`
|
46
|
-
: `By ${groupingType} version:\n`);
|
47
|
-
const maxDownloads = Math.max(...stats.map((v) => v.downloads));
|
48
|
-
const displayData = statsToDisplay.map((item) => {
|
49
|
-
const versionParts = item.version.split('.');
|
50
|
-
return {
|
51
|
-
version: versionParts.length < 3 ? `${item.version}.x` : item.version,
|
52
|
-
chart: renderChart(item.downloads / maxDownloads),
|
53
|
-
downloads: formatDownloads(item.downloads, maxDownloads),
|
54
|
-
};
|
55
|
-
});
|
56
|
-
const maxVersionLength = Math.max(...displayData.map((item) => item.version.length));
|
57
|
-
const maxDownloadsLength = Math.max(...displayData.map((item) => item.downloads.length));
|
58
|
-
displayData.forEach((item, i) => {
|
59
|
-
const color = chalk.hex(colors[i]);
|
60
|
-
console.log(`${item.version.padStart(2 + maxVersionLength)} ${color(item.chart)} ${color(item.downloads.padStart(maxDownloadsLength))}`);
|
61
|
-
});
|
62
|
-
console.log(chalk.bold(`\nNPM weekly downloads for ${chalk.green(name)}\n`));
|
63
|
-
console.log(`Total: ${chalk.green(totalDownloads.toLocaleString())} last week\n`);
|
64
|
-
}
|
@@ -1,58 +0,0 @@
|
|
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/render.js
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
import { style } from './style.js';
|
2
|
-
export function renderChart(value) {
|
3
|
-
const filledValues = Math.round(value * style.chart.width * style.chart.pattern.length);
|
4
|
-
if (filledValues === 0) {
|
5
|
-
return '▏' + (style.rightLabel === 'align-right' ? ' '.repeat(style.chart.width - 1) : '');
|
6
|
-
}
|
7
|
-
const fullBlocks = Math.floor(filledValues / style.chart.pattern.length);
|
8
|
-
const partialBlock = filledValues % style.chart.pattern.length;
|
9
|
-
const hasPartialBlock = partialBlock > 0;
|
10
|
-
return (style.chart.pattern.at(-1).repeat(fullBlocks) +
|
11
|
-
(hasPartialBlock ? style.chart.pattern.at(partialBlock) : '') +
|
12
|
-
(style.rightLabel === 'align-right'
|
13
|
-
? ' '.repeat(style.chart.width - fullBlocks - (hasPartialBlock ? 1 : 0))
|
14
|
-
: ''));
|
15
|
-
}
|
16
|
-
// export type RenderChartLineOptions = {
|
17
|
-
// value: number;
|
18
|
-
// leftLabel: string;
|
19
|
-
// rightLabel: string;
|
20
|
-
// };
|
21
|
-
// export function renderChartLine({ value, leftLabel, rightLabel }: RenderChartLineOptions) {
|
22
|
-
// return `${leftLabel}${renderChart(value)}${rightLabel}`;
|
23
|
-
// }
|
package/dist/style.js
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
export const style = {
|
2
|
-
chart: {
|
3
|
-
width: 50,
|
4
|
-
//pattern: ['⏹'],
|
5
|
-
//pattern: ['⏺'],
|
6
|
-
//pattern: ['█'],
|
7
|
-
//pattern: [' ', '▎', '▌', '▊', '█'],
|
8
|
-
//pattern: [' ', '▩'],
|
9
|
-
//pattern: [' ', '▰'],
|
10
|
-
//pattern: [' ', '∎'],
|
11
|
-
pattern: [' ', '█'],
|
12
|
-
//pattern: [' ', '▓'],
|
13
|
-
zeroPattern: '▏',
|
14
|
-
},
|
15
|
-
rightLabel: 'align-right',
|
16
|
-
};
|
package/dist/types.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|