@node-cli/bundlecheck 1.1.2 → 1.3.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/README.md +104 -10
- package/dist/bundlecheck.js +79 -23
- package/dist/bundlecheck.js.map +1 -1
- package/dist/bundler.d.ts +11 -1
- package/dist/bundler.js +58 -16
- package/dist/bundler.js.map +1 -1
- package/dist/cache.d.ts +59 -0
- package/dist/cache.js +192 -0
- package/dist/cache.js.map +1 -0
- package/dist/defaults.d.ts +15 -0
- package/dist/defaults.js +67 -1
- package/dist/defaults.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/parse.d.ts +3 -0
- package/dist/parse.js +36 -1
- package/dist/parse.js.map +1 -1
- package/dist/trend.d.ts +7 -1
- package/dist/trend.js +70 -25
- package/dist/trend.js.map +1 -1
- package/dist/versions.d.ts +5 -1
- package/dist/versions.js +12 -2
- package/dist/versions.js.map +1 -1
- package/package.json +4 -2
package/dist/parse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parse.ts"],"sourcesContent":["/* istanbul ignore file */\nimport { parser } from \"@node-cli/parser\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/parse.ts"],"sourcesContent":["/* istanbul ignore file */\nimport { parser } from \"@node-cli/parser\";\nimport {\n\tDEFAULT_EXTERNALS,\n\tdefaultFlags,\n\tisValidPlatform,\n} from \"./defaults.js\";\n\nexport type Flags = {\n\tboring?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tversions?: boolean;\n\ttrend?: string;\n\tgzipLevel?: number;\n\texternal?: string;\n\tnoExternal?: boolean;\n\tregistry?: string;\n\tplatform?: string;\n\tforce?: boolean;\n};\n\nexport type Parameters = {\n\t[\"0\"]?: string; // package name\n\t[\"1\"]?: string; // exports (comma-separated)\n};\n\nexport type Configuration = {\n\tflags?: Flags;\n\tparameters?: Parameters;\n\tusage?: boolean;\n\tshowHelp?: () => void;\n};\n\nexport const config: Configuration = parser({\n\tmeta: import.meta,\n\texamples: [\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash\",\n\t\t\tcomment: \"## Check the bundle size of the entire lodash package\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash@4.17.0\",\n\t\t\tcomment: \"## Check a specific version of a package\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck @mantine/core\",\n\t\t\tcomment: \"## Check the bundle size of the entire @mantine/core package\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'bundlecheck @mantine/core \"ScrollArea,Button\"',\n\t\t\tcomment:\n\t\t\t\t\"## Check the bundle size of specific exports from @mantine/core\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck react --no-external\",\n\t\t\tcomment:\n\t\t\t\t\"## Check the bundle size of react itself (not marked as external)\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'bundlecheck some-pkg --external \"vue,svelte\"',\n\t\t\tcomment: \"## Add vue and svelte as additional external dependencies\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --gzip-level 6\",\n\t\t\tcomment: \"## Use a different gzip compression level (1-9)\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --versions\",\n\t\t\tcomment: \"## Choose from available versions interactively\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --trend\",\n\t\t\tcomment: \"## Show bundle size trend (default: 5 versions)\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --trend 3\",\n\t\t\tcomment: \"## Show bundle size trend for 3 versions\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --registry https://registry.example.com\",\n\t\t\tcomment: \"## Use a custom npm registry\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck express --platform node\",\n\t\t\tcomment:\n\t\t\t\t\"## Check bundle size for Node.js platform (aliases: server, nodejs, backend)\",\n\t\t},\n\t\t{\n\t\t\tcommand: \"bundlecheck lodash --force\",\n\t\t\tcomment: \"## Bypass cache and force re-fetch/re-calculation\",\n\t\t},\n\t],\n\tflags: {\n\t\tgzipLevel: {\n\t\t\tshortFlag: \"g\",\n\t\t\tdefault: defaultFlags.gzipLevel,\n\t\t\tdescription: \"Gzip compression level (1-9, default: 5)\",\n\t\t\ttype: \"number\",\n\t\t},\n\t\texternal: {\n\t\t\tshortFlag: \"e\",\n\t\t\tdefault: defaultFlags.external,\n\t\t\tdescription: `Comma-separated additional externals (default externals: ${DEFAULT_EXTERNALS.join(\", \")})`,\n\t\t\ttype: \"string\",\n\t\t},\n\t\tnoExternal: {\n\t\t\tshortFlag: \"n\",\n\t\t\tdefault: defaultFlags.noExternal,\n\t\t\tdescription:\n\t\t\t\t\"Do not mark any packages as external (useful for checking react/react-dom themselves)\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t\tboring: {\n\t\t\tshortFlag: \"b\",\n\t\t\tdefault: defaultFlags.boring,\n\t\t\tdescription: \"Do not use color output\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t\thelp: {\n\t\t\tshortFlag: \"h\",\n\t\t\tdescription: \"Display help instructions\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t\tversion: {\n\t\t\tshortFlag: \"v\",\n\t\t\tdescription: \"Output the current version\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t\tversions: {\n\t\t\tshortFlag: \"V\",\n\t\t\tdefault: defaultFlags.versions,\n\t\t\tdescription: \"Choose from available package versions interactively\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t\ttrend: {\n\t\t\tshortFlag: \"t\",\n\t\t\tdescription: \"Show bundle size trend for N recent versions (default: 5)\",\n\t\t\ttype: \"string\",\n\t\t},\n\t\tregistry: {\n\t\t\tshortFlag: \"r\",\n\t\t\tdefault: defaultFlags.registry,\n\t\t\tdescription:\n\t\t\t\t\"Custom npm registry URL (default: https://registry.npmjs.org)\",\n\t\t\ttype: \"string\",\n\t\t},\n\t\tplatform: {\n\t\t\tshortFlag: \"p\",\n\t\t\tdefault: defaultFlags.platform,\n\t\t\tdescription:\n\t\t\t\t'Target platform: \"auto\" (default, detects from engines), \"browser\" or \"node\"',\n\t\t\ttype: \"string\",\n\t\t},\n\t\tforce: {\n\t\t\tshortFlag: \"f\",\n\t\t\tdefault: defaultFlags.force,\n\t\t\tdescription: \"Bypass cache and force re-fetch/re-calculation\",\n\t\t\ttype: \"boolean\",\n\t\t},\n\t},\n\tparameters: {\n\t\tpackage: {\n\t\t\tdescription: \"The npm package to check (e.g., lodash, @mantine/core)\",\n\t\t},\n\t\texports: {\n\t\t\tdescription:\n\t\t\t\t'Comma-separated list of exports to check (e.g., \"ScrollArea,Button\")',\n\t\t},\n\t},\n\trestrictions: [\n\t\t{\n\t\t\texit: 1,\n\t\t\tmessage: () => \"Error: Package name is required\",\n\t\t\ttest: (flags, parameters) => !parameters?.[\"0\"],\n\t\t},\n\t\t{\n\t\t\texit: 1,\n\t\t\tmessage: () => \"Error: Gzip level must be between 1 and 9\",\n\t\t\ttest: (flags) =>\n\t\t\t\tflags.gzipLevel !== undefined &&\n\t\t\t\t(flags.gzipLevel < 1 || flags.gzipLevel > 9),\n\t\t},\n\t\t{\n\t\t\texit: 1,\n\t\t\tmessage: () =>\n\t\t\t\t'Error: Invalid platform. Use \"browser\" (or web, desktop, client) or \"node\" (or server, nodejs, backend)',\n\t\t\ttest: (flags) => !isValidPlatform(flags.platform),\n\t\t},\n\t],\n\tusage: true,\n\tdefaultFlags,\n});\n"],"names":["parser","DEFAULT_EXTERNALS","defaultFlags","isValidPlatform","config","meta","examples","command","comment","flags","gzipLevel","shortFlag","default","description","type","external","join","noExternal","boring","help","version","versions","trend","registry","platform","force","parameters","package","exports","restrictions","exit","message","test","undefined","usage"],"mappings":"AAAA,wBAAwB,GACxB,SAASA,MAAM,QAAQ,mBAAmB;AAC1C,SACCC,iBAAiB,EACjBC,YAAY,EACZC,eAAe,QACT,gBAAgB;AA4BvB,OAAO,MAAMC,SAAwBJ,OAAO;IAC3CK,MAAM;IACNC,UAAU;QACT;YACCC,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SACC;QACF;QACA;YACCD,SAAS;YACTC,SACC;QACF;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SAAS;QACV;QACA;YACCD,SAAS;YACTC,SACC;QACF;QACA;YACCD,SAAS;YACTC,SAAS;QACV;KACA;IACDC,OAAO;QACNC,WAAW;YACVC,WAAW;YACXC,SAASV,aAAaQ,SAAS;YAC/BG,aAAa;YACbC,MAAM;QACP;QACAC,UAAU;YACTJ,WAAW;YACXC,SAASV,aAAaa,QAAQ;YAC9BF,aAAa,CAAC,yDAAyD,EAAEZ,kBAAkBe,IAAI,CAAC,MAAM,CAAC,CAAC;YACxGF,MAAM;QACP;QACAG,YAAY;YACXN,WAAW;YACXC,SAASV,aAAae,UAAU;YAChCJ,aACC;YACDC,MAAM;QACP;QACAI,QAAQ;YACPP,WAAW;YACXC,SAASV,aAAagB,MAAM;YAC5BL,aAAa;YACbC,MAAM;QACP;QACAK,MAAM;YACLR,WAAW;YACXE,aAAa;YACbC,MAAM;QACP;QACAM,SAAS;YACRT,WAAW;YACXE,aAAa;YACbC,MAAM;QACP;QACAO,UAAU;YACTV,WAAW;YACXC,SAASV,aAAamB,QAAQ;YAC9BR,aAAa;YACbC,MAAM;QACP;QACAQ,OAAO;YACNX,WAAW;YACXE,aAAa;YACbC,MAAM;QACP;QACAS,UAAU;YACTZ,WAAW;YACXC,SAASV,aAAaqB,QAAQ;YAC9BV,aACC;YACDC,MAAM;QACP;QACAU,UAAU;YACTb,WAAW;YACXC,SAASV,aAAasB,QAAQ;YAC9BX,aACC;YACDC,MAAM;QACP;QACAW,OAAO;YACNd,WAAW;YACXC,SAASV,aAAauB,KAAK;YAC3BZ,aAAa;YACbC,MAAM;QACP;IACD;IACAY,YAAY;QACXC,SAAS;YACRd,aAAa;QACd;QACAe,SAAS;YACRf,aACC;QACF;IACD;IACAgB,cAAc;QACb;YACCC,MAAM;YACNC,SAAS,IAAM;YACfC,MAAM,CAACvB,OAAOiB,aAAe,CAACA,YAAY,CAAC,IAAI;QAChD;QACA;YACCI,MAAM;YACNC,SAAS,IAAM;YACfC,MAAM,CAACvB,QACNA,MAAMC,SAAS,KAAKuB,aACnBxB,CAAAA,MAAMC,SAAS,GAAG,KAAKD,MAAMC,SAAS,GAAG,CAAA;QAC5C;QACA;YACCoB,MAAM;YACNC,SAAS,IACR;YACDC,MAAM,CAACvB,QAAU,CAACN,gBAAgBM,MAAMe,QAAQ;QACjD;KACA;IACDU,OAAO;IACPhC;AACD,GAAG"}
|
package/dist/trend.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type TrendResult = {
|
|
2
2
|
version: string;
|
|
3
3
|
rawSize: number;
|
|
4
|
-
|
|
4
|
+
/** Gzip size in bytes, or null for node platform */
|
|
5
|
+
gzipSize: number | null;
|
|
5
6
|
};
|
|
6
7
|
export type TrendOptions = {
|
|
7
8
|
packageName: string;
|
|
@@ -11,6 +12,11 @@ export type TrendOptions = {
|
|
|
11
12
|
noExternal?: boolean;
|
|
12
13
|
gzipLevel?: number;
|
|
13
14
|
boring?: boolean;
|
|
15
|
+
registry?: string;
|
|
16
|
+
/** Target platform. If undefined, auto-detects from package.json engines */
|
|
17
|
+
platform?: "browser" | "node";
|
|
18
|
+
/** Bypass cache and force re-fetch/re-calculation */
|
|
19
|
+
force?: boolean;
|
|
14
20
|
};
|
|
15
21
|
/**
|
|
16
22
|
* Select versions for trend analysis
|
package/dist/trend.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Logger } from "@node-cli/logger";
|
|
2
2
|
import kleur from "kleur";
|
|
3
3
|
import { prerelease } from "semver";
|
|
4
|
-
import { checkBundleSize, formatBytes } from "./bundler.js";
|
|
4
|
+
import { checkBundleSize, formatBytes, getExternals, parsePackageSpecifier } from "./bundler.js";
|
|
5
|
+
import { getCachedResult, normalizeCacheKey, setCachedResult } from "./cache.js";
|
|
5
6
|
import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
6
7
|
/**
|
|
7
8
|
* Select versions for trend analysis
|
|
@@ -15,13 +16,41 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
15
16
|
/**
|
|
16
17
|
* Analyze bundle size trend across multiple versions
|
|
17
18
|
*/ export async function analyzeTrend(options) {
|
|
18
|
-
const { packageName, versions, exports, additionalExternals, noExternal, gzipLevel, boring } = options;
|
|
19
|
+
const { packageName, versions, exports, additionalExternals, noExternal, gzipLevel, boring, registry, platform, force } = options;
|
|
19
20
|
const log = new Logger({
|
|
20
21
|
boring
|
|
21
22
|
});
|
|
22
23
|
const results = [];
|
|
24
|
+
// Parse base package name (without version)
|
|
25
|
+
const { name: baseName } = parsePackageSpecifier(packageName);
|
|
26
|
+
// Compute externals for cache key (same logic as bundler)
|
|
27
|
+
const externals = getExternals(baseName, additionalExternals, noExternal);
|
|
23
28
|
for (const version of versions){
|
|
24
29
|
const versionedPackage = `${packageName}@${version}`;
|
|
30
|
+
// Build cache key for this version
|
|
31
|
+
// Note: platform can be undefined (auto-detect), which is stored as "auto" in cache
|
|
32
|
+
const cacheKey = normalizeCacheKey({
|
|
33
|
+
packageName: baseName,
|
|
34
|
+
version,
|
|
35
|
+
exports,
|
|
36
|
+
platform,
|
|
37
|
+
gzipLevel: gzipLevel ?? 5,
|
|
38
|
+
externals,
|
|
39
|
+
noExternal: noExternal ?? false
|
|
40
|
+
});
|
|
41
|
+
// Check cache first (unless --force flag is set)
|
|
42
|
+
if (!force) {
|
|
43
|
+
const cached = getCachedResult(cacheKey);
|
|
44
|
+
if (cached) {
|
|
45
|
+
log.info(` Checking ${version}... (cached)`);
|
|
46
|
+
results.push({
|
|
47
|
+
version,
|
|
48
|
+
rawSize: cached.rawSize,
|
|
49
|
+
gzipSize: cached.gzipSize
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
25
54
|
log.info(` Checking ${version}...`);
|
|
26
55
|
try {
|
|
27
56
|
const result = await checkBundleSize({
|
|
@@ -29,8 +58,12 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
29
58
|
exports,
|
|
30
59
|
additionalExternals,
|
|
31
60
|
noExternal,
|
|
32
|
-
gzipLevel
|
|
61
|
+
gzipLevel,
|
|
62
|
+
registry,
|
|
63
|
+
platform
|
|
33
64
|
});
|
|
65
|
+
// Store result in cache
|
|
66
|
+
setCachedResult(cacheKey, result);
|
|
34
67
|
results.push({
|
|
35
68
|
version,
|
|
36
69
|
rawSize: result.rawSize,
|
|
@@ -54,17 +87,21 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
54
87
|
const lines = [];
|
|
55
88
|
// Color helper (respects boring flag)
|
|
56
89
|
const blue = (text)=>boring ? text : kleur.blue(text);
|
|
90
|
+
// Check if gzip data is available (null for node platform)
|
|
91
|
+
const hasGzipData = results.some((r)=>r.gzipSize !== null);
|
|
57
92
|
// Create maps from formatted string to representative value
|
|
58
93
|
// This ensures values that display the same get the same bar length
|
|
59
94
|
const gzipFormattedToValue = new Map();
|
|
60
95
|
const rawFormattedToValue = new Map();
|
|
61
96
|
for (const result of results){
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
97
|
+
if (hasGzipData && result.gzipSize !== null) {
|
|
98
|
+
const gzipFormatted = formatBytes(result.gzipSize);
|
|
99
|
+
// Use first occurrence as representative value for each formatted string
|
|
100
|
+
if (!gzipFormattedToValue.has(gzipFormatted)) {
|
|
101
|
+
gzipFormattedToValue.set(gzipFormatted, result.gzipSize);
|
|
102
|
+
}
|
|
67
103
|
}
|
|
104
|
+
const rawFormatted = formatBytes(result.rawSize);
|
|
68
105
|
if (!rawFormattedToValue.has(rawFormatted)) {
|
|
69
106
|
rawFormattedToValue.set(rawFormatted, result.rawSize);
|
|
70
107
|
}
|
|
@@ -76,8 +113,8 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
76
113
|
const uniqueRawValues = [
|
|
77
114
|
...rawFormattedToValue.values()
|
|
78
115
|
];
|
|
79
|
-
const minGzipSize = Math.min(...uniqueGzipValues);
|
|
80
|
-
const maxGzipSize = Math.max(...uniqueGzipValues);
|
|
116
|
+
const minGzipSize = hasGzipData ? Math.min(...uniqueGzipValues) : 0;
|
|
117
|
+
const maxGzipSize = hasGzipData ? Math.max(...uniqueGzipValues) : 0;
|
|
81
118
|
const minRawSize = Math.min(...uniqueRawValues);
|
|
82
119
|
const maxRawSize = Math.max(...uniqueRawValues);
|
|
83
120
|
// Find max version length for alignment
|
|
@@ -99,18 +136,23 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
99
136
|
lines.push(`${blue("Bundle Size:")} ${packageName}`);
|
|
100
137
|
lines.push("─".repeat(60));
|
|
101
138
|
lines.push("");
|
|
102
|
-
// Gzip size bars
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
139
|
+
// Gzip size bars (only for browser platform)
|
|
140
|
+
if (hasGzipData) {
|
|
141
|
+
lines.push(blue("Gzip Size:"));
|
|
142
|
+
for (const result of results){
|
|
143
|
+
if (result.gzipSize === null) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const sizeStr = formatBytes(result.gzipSize);
|
|
147
|
+
// Use representative value for this formatted string to ensure consistent bar length
|
|
148
|
+
const representativeValue = gzipFormattedToValue.get(sizeStr);
|
|
149
|
+
const barLength = calcBarLength(representativeValue, minGzipSize, maxGzipSize);
|
|
150
|
+
const bar = "▇".repeat(barLength);
|
|
151
|
+
const padding = " ".repeat(maxVersionLen - result.version.length);
|
|
152
|
+
lines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);
|
|
153
|
+
}
|
|
154
|
+
lines.push("");
|
|
112
155
|
}
|
|
113
|
-
lines.push("");
|
|
114
156
|
// Raw size bars
|
|
115
157
|
lines.push(blue("Raw Size:"));
|
|
116
158
|
for (const result of results){
|
|
@@ -127,15 +169,18 @@ import { TREND_VERSION_COUNT } from "./defaults.js";
|
|
|
127
169
|
const oldestResult = results[results.length - 1];
|
|
128
170
|
const newestResult = results[0];
|
|
129
171
|
if (results.length > 1) {
|
|
130
|
-
const gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;
|
|
131
|
-
const gzipPercent = (gzipDiff / oldestResult.gzipSize * 100).toFixed(1);
|
|
132
172
|
const rawDiff = newestResult.rawSize - oldestResult.rawSize;
|
|
133
173
|
const rawPercent = (rawDiff / oldestResult.rawSize * 100).toFixed(1);
|
|
134
|
-
const gzipTrend = gzipDiff >= 0 ? `+${formatBytes(gzipDiff)}` : `-${formatBytes(Math.abs(gzipDiff))}`;
|
|
135
174
|
const rawTrend = rawDiff >= 0 ? `+${formatBytes(rawDiff)}` : `-${formatBytes(Math.abs(rawDiff))}`;
|
|
136
175
|
lines.push("─".repeat(60));
|
|
137
176
|
lines.push(`Change from ${oldestResult.version} to ${newestResult.version}:`);
|
|
138
|
-
|
|
177
|
+
// Gzip summary (only for browser platform)
|
|
178
|
+
if (hasGzipData && newestResult.gzipSize !== null && oldestResult.gzipSize !== null) {
|
|
179
|
+
const gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;
|
|
180
|
+
const gzipPercent = (gzipDiff / oldestResult.gzipSize * 100).toFixed(1);
|
|
181
|
+
const gzipTrend = gzipDiff >= 0 ? `+${formatBytes(gzipDiff)}` : `-${formatBytes(Math.abs(gzipDiff))}`;
|
|
182
|
+
lines.push(` ${blue("Gzip:")} ${gzipTrend} (${gzipDiff >= 0 ? "+" : ""}${gzipPercent}%)`);
|
|
183
|
+
}
|
|
139
184
|
lines.push(` ${blue("Raw:")} ${rawTrend} (${rawDiff >= 0 ? "+" : ""}${rawPercent}%)`);
|
|
140
185
|
}
|
|
141
186
|
lines.push("");
|
package/dist/trend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/trend.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\nimport kleur from \"kleur\";\nimport { prerelease } from \"semver\";\nimport { checkBundleSize, formatBytes } from \"./bundler.js\";\nimport { TREND_VERSION_COUNT } from \"./defaults.js\";\n\nexport type TrendResult = {\n\tversion: string;\n\trawSize: number;\n\tgzipSize: number;\n};\n\nexport type TrendOptions = {\n\tpackageName: string;\n\tversions: string[];\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tboring?: boolean;\n};\n\n/**\n * Select versions for trend analysis\n * Returns the most recent stable versions (newest first)\n * Filters out prerelease versions (canary, alpha, beta, rc, etc.)\n */\nexport function selectTrendVersions(\n\tallVersions: string[],\n\tcount: number = TREND_VERSION_COUNT,\n): string[] {\n\t// Filter out prerelease versions (canary, alpha, beta, rc, etc.)\n\tconst stableVersions = allVersions.filter((v) => !prerelease(v));\n\treturn stableVersions.slice(0, count);\n}\n\n/**\n * Analyze bundle size trend across multiple versions\n */\nexport async function analyzeTrend(\n\toptions: TrendOptions,\n): Promise<TrendResult[]> {\n\tconst {\n\t\tpackageName,\n\t\tversions,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel,\n\t\tboring,\n\t} = options;\n\n\tconst log = new Logger({ boring });\n\tconst results: TrendResult[] = [];\n\n\tfor (const version of versions) {\n\t\tconst versionedPackage = `${packageName}@${version}`;\n\t\tlog.info(` Checking ${version}...`);\n\n\t\ttry {\n\t\t\tconst result = await checkBundleSize({\n\t\t\t\tpackageName: versionedPackage,\n\t\t\t\texports,\n\t\t\t\tadditionalExternals,\n\t\t\t\tnoExternal,\n\t\t\t\tgzipLevel,\n\t\t\t});\n\n\t\t\tresults.push({\n\t\t\t\tversion,\n\t\t\t\trawSize: result.rawSize,\n\t\t\t\tgzipSize: result.gzipSize,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Skip versions that fail to analyze\n\t\t\tlog.info(` Skipping ${version} (failed to analyze)`);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Render a bar graph showing bundle size trend\n */\nexport function renderTrendGraph(\n\tpackageName: string,\n\tresults: TrendResult[],\n\tboring: boolean = false,\n): string[] {\n\tif (results.length === 0) {\n\t\treturn [\"No data to display\"];\n\t}\n\n\tconst lines: string[] = [];\n\n\t// Color helper (respects boring flag)\n\tconst blue = (text: string) => (boring ? text : kleur.blue(text));\n\n\t// Create maps from formatted string to representative value\n\t// This ensures values that display the same get the same bar length\n\tconst gzipFormattedToValue = new Map<string, number>();\n\tconst rawFormattedToValue = new Map<string, number>();\n\n\tfor (const result of results) {\n\t\tconst gzipFormatted = formatBytes(result.gzipSize);\n\t\tconst rawFormatted = formatBytes(result.rawSize);\n\t\t// Use first occurrence as representative value for each formatted string\n\t\tif (!gzipFormattedToValue.has(gzipFormatted)) {\n\t\t\tgzipFormattedToValue.set(gzipFormatted, result.gzipSize);\n\t\t}\n\t\tif (!rawFormattedToValue.has(rawFormatted)) {\n\t\t\trawFormattedToValue.set(rawFormatted, result.rawSize);\n\t\t}\n\t}\n\n\t// Get unique representative values for min/max calculation\n\tconst uniqueGzipValues = [...gzipFormattedToValue.values()];\n\tconst uniqueRawValues = [...rawFormattedToValue.values()];\n\n\tconst minGzipSize = Math.min(...uniqueGzipValues);\n\tconst maxGzipSize = Math.max(...uniqueGzipValues);\n\tconst minRawSize = Math.min(...uniqueRawValues);\n\tconst maxRawSize = Math.max(...uniqueRawValues);\n\n\t// Find max version length for alignment\n\tconst maxVersionLen = Math.max(...results.map((r) => r.version.length));\n\n\t// Bar width (characters)\n\tconst barWidth = 30;\n\tconst minBarWidth = 10; // Minimum bar length for smallest value\n\n\t// Helper to calculate bar length with min-max scaling\n\tconst calcBarLength = (value: number, min: number, max: number): number => {\n\t\tif (max === min) {\n\t\t\treturn barWidth; // All values are the same\n\t\t}\n\t\t// Scale from minBarWidth to barWidth based on position between min and max\n\t\tconst ratio = (value - min) / (max - min);\n\t\treturn Math.round(minBarWidth + ratio * (barWidth - minBarWidth));\n\t};\n\n\t// Header\n\tlines.push(\"\");\n\tlines.push(`${blue(\"Bundle Size:\")} ${packageName}`);\n\tlines.push(\"─\".repeat(60));\n\tlines.push(\"\");\n\n\t// Gzip size bars\n\tlines.push(blue(\"Gzip Size:\"));\n\tfor (const result of results) {\n\t\tconst sizeStr = formatBytes(result.gzipSize);\n\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\tconst representativeValue = gzipFormattedToValue.get(sizeStr) as number;\n\t\tconst barLength = calcBarLength(\n\t\t\trepresentativeValue,\n\t\t\tminGzipSize,\n\t\t\tmaxGzipSize,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Raw size bars\n\tlines.push(blue(\"Raw Size:\"));\n\tfor (const result of results) {\n\t\tconst sizeStr = formatBytes(result.rawSize);\n\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\tconst representativeValue = rawFormattedToValue.get(sizeStr) as number;\n\t\tconst barLength = calcBarLength(\n\t\t\trepresentativeValue,\n\t\t\tminRawSize,\n\t\t\tmaxRawSize,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Summary\n\tconst oldestResult = results[results.length - 1];\n\tconst newestResult = results[0];\n\n\tif (results.length > 1) {\n\t\tconst gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;\n\t\tconst gzipPercent = ((gzipDiff / oldestResult.gzipSize) * 100).toFixed(1);\n\t\tconst rawDiff = newestResult.rawSize - oldestResult.rawSize;\n\t\tconst rawPercent = ((rawDiff / oldestResult.rawSize) * 100).toFixed(1);\n\n\t\tconst gzipTrend =\n\t\t\tgzipDiff >= 0\n\t\t\t\t? `+${formatBytes(gzipDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(gzipDiff))}`;\n\t\tconst rawTrend =\n\t\t\trawDiff >= 0\n\t\t\t\t? `+${formatBytes(rawDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(rawDiff))}`;\n\n\t\tlines.push(\"─\".repeat(60));\n\t\tlines.push(\n\t\t\t`Change from ${oldestResult.version} to ${newestResult.version}:`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Gzip:\")} ${gzipTrend} (${gzipDiff >= 0 ? \"+\" : \"\"}${gzipPercent}%)`,\n\t\t);\n\t\tlines.push(\n\t\t\t` ${blue(\"Raw:\")} ${rawTrend} (${rawDiff >= 0 ? \"+\" : \"\"}${rawPercent}%)`,\n\t\t);\n\t}\n\n\tlines.push(\"\");\n\n\treturn lines;\n}\n"],"names":["Logger","kleur","prerelease","checkBundleSize","formatBytes","TREND_VERSION_COUNT","selectTrendVersions","allVersions","count","stableVersions","filter","v","slice","analyzeTrend","options","packageName","versions","exports","additionalExternals","noExternal","gzipLevel","boring","log","results","version","versionedPackage","info","result","push","rawSize","gzipSize","renderTrendGraph","length","lines","blue","text","gzipFormattedToValue","Map","rawFormattedToValue","gzipFormatted","rawFormatted","has","set","uniqueGzipValues","values","uniqueRawValues","minGzipSize","Math","min","maxGzipSize","max","minRawSize","maxRawSize","maxVersionLen","map","r","barWidth","minBarWidth","calcBarLength","value","ratio","round","repeat","sizeStr","representativeValue","get","barLength","bar","padding","oldestResult","newestResult","gzipDiff","gzipPercent","toFixed","rawDiff","rawPercent","gzipTrend","abs","rawTrend"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/trend.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\nimport kleur from \"kleur\";\nimport { prerelease } from \"semver\";\nimport {\n\tcheckBundleSize,\n\tformatBytes,\n\tgetExternals,\n\tparsePackageSpecifier,\n} from \"./bundler.js\";\nimport {\n\tgetCachedResult,\n\tnormalizeCacheKey,\n\tsetCachedResult,\n} from \"./cache.js\";\nimport { TREND_VERSION_COUNT } from \"./defaults.js\";\n\nexport type TrendResult = {\n\tversion: string;\n\trawSize: number;\n\t/** Gzip size in bytes, or null for node platform */\n\tgzipSize: number | null;\n};\n\nexport type TrendOptions = {\n\tpackageName: string;\n\tversions: string[];\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tboring?: boolean;\n\tregistry?: string;\n\t/** Target platform. If undefined, auto-detects from package.json engines */\n\tplatform?: \"browser\" | \"node\";\n\t/** Bypass cache and force re-fetch/re-calculation */\n\tforce?: boolean;\n};\n\n/**\n * Select versions for trend analysis\n * Returns the most recent stable versions (newest first)\n * Filters out prerelease versions (canary, alpha, beta, rc, etc.)\n */\nexport function selectTrendVersions(\n\tallVersions: string[],\n\tcount: number = TREND_VERSION_COUNT,\n): string[] {\n\t// Filter out prerelease versions (canary, alpha, beta, rc, etc.)\n\tconst stableVersions = allVersions.filter((v) => !prerelease(v));\n\treturn stableVersions.slice(0, count);\n}\n\n/**\n * Analyze bundle size trend across multiple versions\n */\nexport async function analyzeTrend(\n\toptions: TrendOptions,\n): Promise<TrendResult[]> {\n\tconst {\n\t\tpackageName,\n\t\tversions,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel,\n\t\tboring,\n\t\tregistry,\n\t\tplatform,\n\t\tforce,\n\t} = options;\n\n\tconst log = new Logger({ boring });\n\tconst results: TrendResult[] = [];\n\n\t// Parse base package name (without version)\n\tconst { name: baseName } = parsePackageSpecifier(packageName);\n\n\t// Compute externals for cache key (same logic as bundler)\n\tconst externals = getExternals(baseName, additionalExternals, noExternal);\n\n\tfor (const version of versions) {\n\t\tconst versionedPackage = `${packageName}@${version}`;\n\n\t\t// Build cache key for this version\n\t\t// Note: platform can be undefined (auto-detect), which is stored as \"auto\" in cache\n\t\tconst cacheKey = normalizeCacheKey({\n\t\t\tpackageName: baseName,\n\t\t\tversion,\n\t\t\texports,\n\t\t\tplatform,\n\t\t\tgzipLevel: gzipLevel ?? 5,\n\t\t\texternals,\n\t\t\tnoExternal: noExternal ?? false,\n\t\t});\n\n\t\t// Check cache first (unless --force flag is set)\n\t\tif (!force) {\n\t\t\tconst cached = getCachedResult(cacheKey);\n\t\t\tif (cached) {\n\t\t\t\tlog.info(` Checking ${version}... (cached)`);\n\t\t\t\tresults.push({\n\t\t\t\t\tversion,\n\t\t\t\t\trawSize: cached.rawSize,\n\t\t\t\t\tgzipSize: cached.gzipSize,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tlog.info(` Checking ${version}...`);\n\n\t\ttry {\n\t\t\tconst result = await checkBundleSize({\n\t\t\t\tpackageName: versionedPackage,\n\t\t\t\texports,\n\t\t\t\tadditionalExternals,\n\t\t\t\tnoExternal,\n\t\t\t\tgzipLevel,\n\t\t\t\tregistry,\n\t\t\t\tplatform,\n\t\t\t});\n\n\t\t\t// Store result in cache\n\t\t\tsetCachedResult(cacheKey, result);\n\n\t\t\tresults.push({\n\t\t\t\tversion,\n\t\t\t\trawSize: result.rawSize,\n\t\t\t\tgzipSize: result.gzipSize,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Skip versions that fail to analyze\n\t\t\tlog.info(` Skipping ${version} (failed to analyze)`);\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Render a bar graph showing bundle size trend\n */\nexport function renderTrendGraph(\n\tpackageName: string,\n\tresults: TrendResult[],\n\tboring: boolean = false,\n): string[] {\n\tif (results.length === 0) {\n\t\treturn [\"No data to display\"];\n\t}\n\n\tconst lines: string[] = [];\n\n\t// Color helper (respects boring flag)\n\tconst blue = (text: string) => (boring ? text : kleur.blue(text));\n\n\t// Check if gzip data is available (null for node platform)\n\tconst hasGzipData = results.some((r) => r.gzipSize !== null);\n\n\t// Create maps from formatted string to representative value\n\t// This ensures values that display the same get the same bar length\n\tconst gzipFormattedToValue = new Map<string, number>();\n\tconst rawFormattedToValue = new Map<string, number>();\n\n\tfor (const result of results) {\n\t\tif (hasGzipData && result.gzipSize !== null) {\n\t\t\tconst gzipFormatted = formatBytes(result.gzipSize);\n\t\t\t// Use first occurrence as representative value for each formatted string\n\t\t\tif (!gzipFormattedToValue.has(gzipFormatted)) {\n\t\t\t\tgzipFormattedToValue.set(gzipFormatted, result.gzipSize);\n\t\t\t}\n\t\t}\n\t\tconst rawFormatted = formatBytes(result.rawSize);\n\t\tif (!rawFormattedToValue.has(rawFormatted)) {\n\t\t\trawFormattedToValue.set(rawFormatted, result.rawSize);\n\t\t}\n\t}\n\n\t// Get unique representative values for min/max calculation\n\tconst uniqueGzipValues = [...gzipFormattedToValue.values()];\n\tconst uniqueRawValues = [...rawFormattedToValue.values()];\n\n\tconst minGzipSize = hasGzipData ? Math.min(...uniqueGzipValues) : 0;\n\tconst maxGzipSize = hasGzipData ? Math.max(...uniqueGzipValues) : 0;\n\tconst minRawSize = Math.min(...uniqueRawValues);\n\tconst maxRawSize = Math.max(...uniqueRawValues);\n\n\t// Find max version length for alignment\n\tconst maxVersionLen = Math.max(...results.map((r) => r.version.length));\n\n\t// Bar width (characters)\n\tconst barWidth = 30;\n\tconst minBarWidth = 10; // Minimum bar length for smallest value\n\n\t// Helper to calculate bar length with min-max scaling\n\tconst calcBarLength = (value: number, min: number, max: number): number => {\n\t\tif (max === min) {\n\t\t\treturn barWidth; // All values are the same\n\t\t}\n\t\t// Scale from minBarWidth to barWidth based on position between min and max\n\t\tconst ratio = (value - min) / (max - min);\n\t\treturn Math.round(minBarWidth + ratio * (barWidth - minBarWidth));\n\t};\n\n\t// Header\n\tlines.push(\"\");\n\tlines.push(`${blue(\"Bundle Size:\")} ${packageName}`);\n\tlines.push(\"─\".repeat(60));\n\tlines.push(\"\");\n\n\t// Gzip size bars (only for browser platform)\n\tif (hasGzipData) {\n\t\tlines.push(blue(\"Gzip Size:\"));\n\t\tfor (const result of results) {\n\t\t\tif (result.gzipSize === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst sizeStr = formatBytes(result.gzipSize);\n\t\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\t\tconst representativeValue = gzipFormattedToValue.get(sizeStr) as number;\n\t\t\tconst barLength = calcBarLength(\n\t\t\t\trepresentativeValue,\n\t\t\t\tminGzipSize,\n\t\t\t\tmaxGzipSize,\n\t\t\t);\n\t\t\tconst bar = \"▇\".repeat(barLength);\n\t\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t\t}\n\n\t\tlines.push(\"\");\n\t}\n\n\t// Raw size bars\n\tlines.push(blue(\"Raw Size:\"));\n\tfor (const result of results) {\n\t\tconst sizeStr = formatBytes(result.rawSize);\n\t\t// Use representative value for this formatted string to ensure consistent bar length\n\t\tconst representativeValue = rawFormattedToValue.get(sizeStr) as number;\n\t\tconst barLength = calcBarLength(\n\t\t\trepresentativeValue,\n\t\t\tminRawSize,\n\t\t\tmaxRawSize,\n\t\t);\n\t\tconst bar = \"▇\".repeat(barLength);\n\t\tconst padding = \" \".repeat(maxVersionLen - result.version.length);\n\t\tlines.push(` ${result.version}${padding} ${bar} ${sizeStr}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Summary\n\tconst oldestResult = results[results.length - 1];\n\tconst newestResult = results[0];\n\n\tif (results.length > 1) {\n\t\tconst rawDiff = newestResult.rawSize - oldestResult.rawSize;\n\t\tconst rawPercent = ((rawDiff / oldestResult.rawSize) * 100).toFixed(1);\n\t\tconst rawTrend =\n\t\t\trawDiff >= 0\n\t\t\t\t? `+${formatBytes(rawDiff)}`\n\t\t\t\t: `-${formatBytes(Math.abs(rawDiff))}`;\n\n\t\tlines.push(\"─\".repeat(60));\n\t\tlines.push(\n\t\t\t`Change from ${oldestResult.version} to ${newestResult.version}:`,\n\t\t);\n\n\t\t// Gzip summary (only for browser platform)\n\t\tif (\n\t\t\thasGzipData &&\n\t\t\tnewestResult.gzipSize !== null &&\n\t\t\toldestResult.gzipSize !== null\n\t\t) {\n\t\t\tconst gzipDiff = newestResult.gzipSize - oldestResult.gzipSize;\n\t\t\tconst gzipPercent = ((gzipDiff / oldestResult.gzipSize) * 100).toFixed(1);\n\t\t\tconst gzipTrend =\n\t\t\t\tgzipDiff >= 0\n\t\t\t\t\t? `+${formatBytes(gzipDiff)}`\n\t\t\t\t\t: `-${formatBytes(Math.abs(gzipDiff))}`;\n\t\t\tlines.push(\n\t\t\t\t` ${blue(\"Gzip:\")} ${gzipTrend} (${gzipDiff >= 0 ? \"+\" : \"\"}${gzipPercent}%)`,\n\t\t\t);\n\t\t}\n\n\t\tlines.push(\n\t\t\t` ${blue(\"Raw:\")} ${rawTrend} (${rawDiff >= 0 ? \"+\" : \"\"}${rawPercent}%)`,\n\t\t);\n\t}\n\n\tlines.push(\"\");\n\n\treturn lines;\n}\n"],"names":["Logger","kleur","prerelease","checkBundleSize","formatBytes","getExternals","parsePackageSpecifier","getCachedResult","normalizeCacheKey","setCachedResult","TREND_VERSION_COUNT","selectTrendVersions","allVersions","count","stableVersions","filter","v","slice","analyzeTrend","options","packageName","versions","exports","additionalExternals","noExternal","gzipLevel","boring","registry","platform","force","log","results","name","baseName","externals","version","versionedPackage","cacheKey","cached","info","push","rawSize","gzipSize","result","renderTrendGraph","length","lines","blue","text","hasGzipData","some","r","gzipFormattedToValue","Map","rawFormattedToValue","gzipFormatted","has","set","rawFormatted","uniqueGzipValues","values","uniqueRawValues","minGzipSize","Math","min","maxGzipSize","max","minRawSize","maxRawSize","maxVersionLen","map","barWidth","minBarWidth","calcBarLength","value","ratio","round","repeat","sizeStr","representativeValue","get","barLength","bar","padding","oldestResult","newestResult","rawDiff","rawPercent","toFixed","rawTrend","abs","gzipDiff","gzipPercent","gzipTrend"],"mappings":"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"}
|
package/dist/versions.d.ts
CHANGED
|
@@ -2,7 +2,11 @@ export type NpmPackageInfo = {
|
|
|
2
2
|
versions: string[];
|
|
3
3
|
tags: Record<string, string>;
|
|
4
4
|
};
|
|
5
|
-
export
|
|
5
|
+
export type FetchVersionsOptions = {
|
|
6
|
+
packageName: string;
|
|
7
|
+
registry?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function fetchPackageVersions(packageNameOrOptions: string | FetchVersionsOptions): Promise<NpmPackageInfo>;
|
|
6
10
|
/**
|
|
7
11
|
* Prompt user to select a version from available versions
|
|
8
12
|
*/
|
package/dist/versions.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import select from "@inquirer/select";
|
|
2
2
|
import { rsort } from "semver";
|
|
3
3
|
import { parsePackageSpecifier } from "./bundler.js";
|
|
4
|
-
|
|
4
|
+
import { DEFAULT_REGISTRY } from "./defaults.js";
|
|
5
|
+
export async function fetchPackageVersions(packageNameOrOptions) {
|
|
6
|
+
// Support both string (legacy) and options object
|
|
7
|
+
const { packageName, registry } = typeof packageNameOrOptions === "string" ? {
|
|
8
|
+
packageName: packageNameOrOptions,
|
|
9
|
+
registry: undefined
|
|
10
|
+
} : packageNameOrOptions;
|
|
5
11
|
// Parse the package specifier to get just the name (without version)
|
|
6
12
|
const { name } = parsePackageSpecifier(packageName);
|
|
7
|
-
|
|
13
|
+
// Use custom registry or default
|
|
14
|
+
const registryUrl = registry || DEFAULT_REGISTRY;
|
|
15
|
+
// Ensure no trailing slash
|
|
16
|
+
const baseUrl = registryUrl.replace(/\/$/, "");
|
|
17
|
+
const url = `${baseUrl}/${name}`;
|
|
8
18
|
const response = await fetch(url);
|
|
9
19
|
if (!response.ok) {
|
|
10
20
|
throw new Error(`Failed to fetch package info: ${response.statusText}`);
|
package/dist/versions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/versions.ts"],"sourcesContent":["import select from \"@inquirer/select\";\nimport { rsort } from \"semver\";\nimport { parsePackageSpecifier } from \"./bundler.js\";\n\nexport type NpmPackageInfo = {\n\tversions: string[];\n\ttags: Record<string, string>;\n};\n\n/**\n * Fetch available versions for an npm package from the registry\n */\ntype NpmRegistryResponse = {\n\tversions?: Record<string, unknown>;\n\t\"dist-tags\"?: Record<string, string>;\n};\n\nexport async function fetchPackageVersions(\n\
|
|
1
|
+
{"version":3,"sources":["../src/versions.ts"],"sourcesContent":["import select from \"@inquirer/select\";\nimport { rsort } from \"semver\";\nimport { parsePackageSpecifier } from \"./bundler.js\";\nimport { DEFAULT_REGISTRY } from \"./defaults.js\";\n\nexport type NpmPackageInfo = {\n\tversions: string[];\n\ttags: Record<string, string>;\n};\n\n/**\n * Fetch available versions for an npm package from the registry\n */\ntype NpmRegistryResponse = {\n\tversions?: Record<string, unknown>;\n\t\"dist-tags\"?: Record<string, string>;\n};\n\nexport type FetchVersionsOptions = {\n\tpackageName: string;\n\tregistry?: string;\n};\n\nexport async function fetchPackageVersions(\n\tpackageNameOrOptions: string | FetchVersionsOptions,\n): Promise<NpmPackageInfo> {\n\t// Support both string (legacy) and options object\n\tconst { packageName, registry } =\n\t\ttypeof packageNameOrOptions === \"string\"\n\t\t\t? { packageName: packageNameOrOptions, registry: undefined }\n\t\t\t: packageNameOrOptions;\n\n\t// Parse the package specifier to get just the name (without version)\n\tconst { name } = parsePackageSpecifier(packageName);\n\n\t// Use custom registry or default\n\tconst registryUrl = registry || DEFAULT_REGISTRY;\n\t// Ensure no trailing slash\n\tconst baseUrl = registryUrl.replace(/\\/$/, \"\");\n\tconst url = `${baseUrl}/${name}`;\n\tconst response = await fetch(url);\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to fetch package info: ${response.statusText}`);\n\t}\n\n\tconst data = (await response.json()) as NpmRegistryResponse;\n\n\t// Get all versions sorted by semver (newest first)\n\tconst versions = rsort(Object.keys(data.versions || {}));\n\n\t// Get dist-tags (latest, next, beta, etc.)\n\tconst tags = data[\"dist-tags\"] || {};\n\n\treturn { versions, tags };\n}\n\n/**\n * Prompt user to select a version from available versions\n */\nexport async function promptForVersion(\n\tpackageName: string,\n\tversions: string[],\n\ttags: Record<string, string>,\n): Promise<string> {\n\t// Build choices with tags highlighted\n\tconst taggedVersions = new Set(Object.values(tags));\n\tconst tagByVersion = Object.fromEntries(\n\t\tObject.entries(tags).map(([tag, ver]) => [ver, tag]),\n\t);\n\n\t// Limit to most recent 20 versions for usability, but include all tagged versions\n\tconst recentVersions = versions.slice(0, 20);\n\tconst displayVersions = [\n\t\t...new Set([...Object.values(tags), ...recentVersions]),\n\t];\n\n\t// Sort so tagged versions appear first, then by version order\n\tdisplayVersions.sort((a, b) => {\n\t\tconst aTagged = taggedVersions.has(a);\n\t\tconst bTagged = taggedVersions.has(b);\n\t\tif (aTagged && !bTagged) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (!aTagged && bTagged) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn versions.indexOf(a) - versions.indexOf(b);\n\t});\n\n\tconst choices = displayVersions.map((ver) => {\n\t\tconst tag = tagByVersion[ver];\n\t\treturn {\n\t\t\tname: tag ? `${ver} (${tag})` : ver,\n\t\t\tvalue: ver,\n\t\t};\n\t});\n\n\tconst selectedVersion = await select({\n\t\tmessage: `Select a version for ${packageName}:`,\n\t\tchoices,\n\t\tpageSize: 15,\n\t});\n\n\treturn selectedVersion;\n}\n"],"names":["select","rsort","parsePackageSpecifier","DEFAULT_REGISTRY","fetchPackageVersions","packageNameOrOptions","packageName","registry","undefined","name","registryUrl","baseUrl","replace","url","response","fetch","ok","Error","statusText","data","json","versions","Object","keys","tags","promptForVersion","taggedVersions","Set","values","tagByVersion","fromEntries","entries","map","tag","ver","recentVersions","slice","displayVersions","sort","a","b","aTagged","has","bTagged","indexOf","choices","value","selectedVersion","message","pageSize"],"mappings":"AAAA,OAAOA,YAAY,mBAAmB;AACtC,SAASC,KAAK,QAAQ,SAAS;AAC/B,SAASC,qBAAqB,QAAQ,eAAe;AACrD,SAASC,gBAAgB,QAAQ,gBAAgB;AAoBjD,OAAO,eAAeC,qBACrBC,oBAAmD;IAEnD,kDAAkD;IAClD,MAAM,EAAEC,WAAW,EAAEC,QAAQ,EAAE,GAC9B,OAAOF,yBAAyB,WAC7B;QAAEC,aAAaD;QAAsBE,UAAUC;IAAU,IACzDH;IAEJ,qEAAqE;IACrE,MAAM,EAAEI,IAAI,EAAE,GAAGP,sBAAsBI;IAEvC,iCAAiC;IACjC,MAAMI,cAAcH,YAAYJ;IAChC,2BAA2B;IAC3B,MAAMQ,UAAUD,YAAYE,OAAO,CAAC,OAAO;IAC3C,MAAMC,MAAM,GAAGF,QAAQ,CAAC,EAAEF,MAAM;IAChC,MAAMK,WAAW,MAAMC,MAAMF;IAE7B,IAAI,CAACC,SAASE,EAAE,EAAE;QACjB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEH,SAASI,UAAU,EAAE;IACvE;IAEA,MAAMC,OAAQ,MAAML,SAASM,IAAI;IAEjC,mDAAmD;IACnD,MAAMC,WAAWpB,MAAMqB,OAAOC,IAAI,CAACJ,KAAKE,QAAQ,IAAI,CAAC;IAErD,2CAA2C;IAC3C,MAAMG,OAAOL,IAAI,CAAC,YAAY,IAAI,CAAC;IAEnC,OAAO;QAAEE;QAAUG;IAAK;AACzB;AAEA;;CAEC,GACD,OAAO,eAAeC,iBACrBnB,WAAmB,EACnBe,QAAkB,EAClBG,IAA4B;IAE5B,sCAAsC;IACtC,MAAME,iBAAiB,IAAIC,IAAIL,OAAOM,MAAM,CAACJ;IAC7C,MAAMK,eAAeP,OAAOQ,WAAW,CACtCR,OAAOS,OAAO,CAACP,MAAMQ,GAAG,CAAC,CAAC,CAACC,KAAKC,IAAI,GAAK;YAACA;YAAKD;SAAI;IAGpD,kFAAkF;IAClF,MAAME,iBAAiBd,SAASe,KAAK,CAAC,GAAG;IACzC,MAAMC,kBAAkB;WACpB,IAAIV,IAAI;eAAIL,OAAOM,MAAM,CAACJ;eAAUW;SAAe;KACtD;IAED,8DAA8D;IAC9DE,gBAAgBC,IAAI,CAAC,CAACC,GAAGC;QACxB,MAAMC,UAAUf,eAAegB,GAAG,CAACH;QACnC,MAAMI,UAAUjB,eAAegB,GAAG,CAACF;QACnC,IAAIC,WAAW,CAACE,SAAS;YACxB,OAAO,CAAC;QACT;QACA,IAAI,CAACF,WAAWE,SAAS;YACxB,OAAO;QACR;QACA,OAAOtB,SAASuB,OAAO,CAACL,KAAKlB,SAASuB,OAAO,CAACJ;IAC/C;IAEA,MAAMK,UAAUR,gBAAgBL,GAAG,CAAC,CAACE;QACpC,MAAMD,MAAMJ,YAAY,CAACK,IAAI;QAC7B,OAAO;YACNzB,MAAMwB,MAAM,GAAGC,IAAI,EAAE,EAAED,IAAI,CAAC,CAAC,GAAGC;YAChCY,OAAOZ;QACR;IACD;IAEA,MAAMa,kBAAkB,MAAM/C,OAAO;QACpCgD,SAAS,CAAC,qBAAqB,EAAE1C,YAAY,CAAC,CAAC;QAC/CuC;QACAI,UAAU;IACX;IAEA,OAAOF;AACR"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-cli/bundlecheck",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"description": "CLI tool to check the bundle size of npm packages (like bundlephobia)",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@inquirer/select": "5.0.4",
|
|
37
37
|
"@node-cli/logger": "1.3.4",
|
|
38
38
|
"@node-cli/parser": "2.4.5",
|
|
39
|
+
"better-sqlite3": "12.6.2",
|
|
39
40
|
"esbuild": "0.27.2",
|
|
40
41
|
"kleur": "4.1.5",
|
|
41
42
|
"semver": "7.7.3"
|
|
@@ -45,8 +46,9 @@
|
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@node-cli/comments": "0.2.9",
|
|
49
|
+
"@types/better-sqlite3": "7.6.13",
|
|
48
50
|
"@vitest/coverage-v8": "4.0.18",
|
|
49
51
|
"vitest": "4.0.18"
|
|
50
52
|
},
|
|
51
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "fcc52d3d0cdc71e5065bbbc8a0cd064c1a487f9f"
|
|
52
54
|
}
|