pkg-stats 0.0.1

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 ADDED
@@ -0,0 +1,3 @@
1
+ ## PKG Stats
2
+
3
+ Beautiful package download stats.
package/dist/bin.js ADDED
@@ -0,0 +1,82 @@
1
+ import { renderChart } from "./chart.js";
2
+ import { parseVersion, versionCompare } from "./version.js";
3
+ const PACKAGE_NAME = process.argv[2];
4
+ const NPM_STATS_URL = `https://api.npmjs.org/versions/${encodeURIComponent(PACKAGE_NAME)}/last-week`;
5
+ export async function bin() {
6
+ const response = await fetch(NPM_STATS_URL);
7
+ const data = await response.json();
8
+ const rawStats = Object.keys(data.downloads)
9
+ .map((versionString) => {
10
+ const version = parseVersion(versionString);
11
+ return {
12
+ ...version,
13
+ downloads: data.downloads[versionString],
14
+ };
15
+ })
16
+ .sort(versionCompare);
17
+ const groupedStats = sumByMajor(rawStats);
18
+ const totalDownloads = Object.values(groupedStats).reduce((sum, version) => sum + version.downloads, 0);
19
+ console.log(`${PACKAGE_NAME} weekly downloads\n`);
20
+ console.log(`Total: ${totalDownloads.toLocaleString()}.\n`);
21
+ console.log("By version:\n");
22
+ const maxDownloads = Math.max(...groupedStats.map((v) => v.downloads));
23
+ for (const item of groupedStats) {
24
+ console.log(`${item.versionString.padStart(6)} ${renderChart(item.downloads / maxDownloads)} ${formatDownloads(item.downloads, maxDownloads).padStart(6)}`);
25
+ }
26
+ console.log(`\nGenerated on ${new Date().toISOString().slice(0, 10)} by npm-stats.`);
27
+ }
28
+ function sumByMajor(stats) {
29
+ const result = {};
30
+ for (const versionStats of stats) {
31
+ const key = `${versionStats.major}`;
32
+ const entry = result[key] ?? {
33
+ version: { major: versionStats.major },
34
+ versionString: key,
35
+ downloads: 0,
36
+ };
37
+ result[key] = entry;
38
+ entry.downloads += versionStats.downloads;
39
+ }
40
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
41
+ }
42
+ function sumByMinor(stats) {
43
+ const result = {};
44
+ for (const versionStats of stats) {
45
+ const key = `${versionStats.major}.${versionStats.minor}`;
46
+ const entry = result[key] ?? {
47
+ version: { major: versionStats.major, minor: versionStats.minor },
48
+ versionString: key,
49
+ downloads: 0,
50
+ };
51
+ result[key] = entry;
52
+ entry.downloads += versionStats.downloads;
53
+ }
54
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
55
+ }
56
+ function sumByPatch(stats) {
57
+ const result = {};
58
+ for (const versionStats of stats) {
59
+ const key = `${versionStats.major}.${versionStats.minor}.${versionStats.patch}`;
60
+ const entry = result[key] ?? {
61
+ version: {
62
+ major: versionStats.major,
63
+ minor: versionStats.minor,
64
+ patch: versionStats.patch,
65
+ },
66
+ versionString: key,
67
+ downloads: 0,
68
+ };
69
+ result[key] = entry;
70
+ entry.downloads += versionStats.downloads;
71
+ }
72
+ return Object.values(result).sort((a, b) => versionCompare(a.version, b.version));
73
+ }
74
+ function formatDownloads(downloads, maxDownloads) {
75
+ if (maxDownloads > 1000000) {
76
+ return `${(downloads / 1000000).toFixed(1)}M`;
77
+ }
78
+ if (maxDownloads > 1000) {
79
+ return `${(downloads / 1000).toFixed(1)}K`;
80
+ }
81
+ return downloads.toString();
82
+ }
package/dist/chart.js ADDED
@@ -0,0 +1,5 @@
1
+ export function renderChart(value, { length = 50 } = {}) {
2
+ const filledChars = Math.round(value * length);
3
+ const emptyChars = length - filledChars;
4
+ return "█".repeat(filledChars) + " ".repeat(emptyChars);
5
+ }
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { bin } from "./bin.js";
2
+ bin();
@@ -0,0 +1,25 @@
1
+ export function parseVersion(version) {
2
+ const [versionCore, preRelease] = version.split("-");
3
+ const [major, minor, patch] = versionCore.split(".");
4
+ return {
5
+ major: Number(major),
6
+ minor: Number(minor),
7
+ patch: Number(patch),
8
+ preRelease,
9
+ };
10
+ }
11
+ export function versionCompare(a, b) {
12
+ if (a.major !== b.major) {
13
+ return b.major - a.major;
14
+ }
15
+ if (a.minor !== undefined && b.minor !== undefined && a.minor !== b.minor) {
16
+ return b.minor - a.minor;
17
+ }
18
+ if (a.patch !== undefined && b.patch !== undefined && a.patch !== b.patch) {
19
+ return b.patch - a.patch;
20
+ }
21
+ if (a.preRelease !== undefined && b.preRelease !== undefined) {
22
+ return a.preRelease.localeCompare(b.preRelease);
23
+ }
24
+ return 0;
25
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "pkg-stats",
3
+ "version": "0.0.1",
4
+ "description": "Beautiful package download stats",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "MIT",
16
+ "packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c",
17
+ "devDependencies": {
18
+ "@types/node": "^22.10.5",
19
+ "typescript": "^5.7.3"
20
+ }
21
+ }