@node-cli/bundlecheck 1.2.0 → 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.
@@ -0,0 +1,59 @@
1
+ import Database from "better-sqlite3";
2
+ import type { BundleResult } from "./bundler.js";
3
+ export type CacheKey = {
4
+ packageName: string;
5
+ version: string;
6
+ exports: string;
7
+ /** Platform: "browser", "node", or "auto" (for auto-detection) */
8
+ platform: "browser" | "node" | "auto";
9
+ gzipLevel: number;
10
+ externals: string;
11
+ noExternal: number;
12
+ };
13
+ export type CachedBundleResult = BundleResult;
14
+ /**
15
+ * Initialize the cache database with proper pragmas and schema
16
+ */
17
+ export declare function initCache(): Database.Database;
18
+ /**
19
+ * Normalize cache key options to a consistent format
20
+ * Sorts exports and externals to ensure consistent cache hits
21
+ *
22
+ * Note: platform can be "browser", "node", or "auto" (when user doesn't specify).
23
+ * Using "auto" in the cache key ensures that auto-detected results are cached
24
+ * separately from explicitly specified platform results.
25
+ */
26
+ export declare function normalizeCacheKey(options: {
27
+ packageName: string;
28
+ version: string;
29
+ exports?: string[];
30
+ /** Platform: "browser", "node", or undefined (treated as "auto") */
31
+ platform: "browser" | "node" | undefined;
32
+ gzipLevel: number;
33
+ externals: string[];
34
+ noExternal: boolean;
35
+ }): CacheKey;
36
+ /**
37
+ * Get a cached result if it exists
38
+ * Returns null if not found or if an error occurs (graceful degradation)
39
+ */
40
+ export declare function getCachedResult(key: CacheKey): CachedBundleResult | null;
41
+ /**
42
+ * Store a result in the cache
43
+ * Silently fails on errors (graceful degradation - CLI continues without caching)
44
+ */
45
+ export declare function setCachedResult(key: CacheKey, result: BundleResult): void;
46
+ /**
47
+ * Clear all cache entries
48
+ * Silently fails on errors
49
+ */
50
+ export declare function clearCache(): void;
51
+ /**
52
+ * Get the number of cached entries
53
+ * Returns 0 on error
54
+ */
55
+ export declare function getCacheCount(): number;
56
+ /**
57
+ * Close the database connection (useful for testing)
58
+ */
59
+ export declare function closeCache(): void;
package/dist/cache.js ADDED
@@ -0,0 +1,192 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import Database from "better-sqlite3";
5
+ const MAX_CACHE_ENTRIES = 100;
6
+ /**
7
+ * Get the cache directory path (computed lazily to support testing)
8
+ */ function getCacheDir() {
9
+ return path.join(os.homedir(), ".bundlecheck");
10
+ }
11
+ /**
12
+ * Get the cache database path (computed lazily to support testing)
13
+ */ function getCacheDbPath() {
14
+ return path.join(getCacheDir(), "cache.db");
15
+ }
16
+ let db = null;
17
+ /**
18
+ * Initialize the cache database with proper pragmas and schema
19
+ */ export function initCache() {
20
+ if (db) {
21
+ return db;
22
+ }
23
+ // Ensure cache directory exists
24
+ const cacheDir = getCacheDir();
25
+ if (!fs.existsSync(cacheDir)) {
26
+ fs.mkdirSync(cacheDir, {
27
+ recursive: true
28
+ });
29
+ }
30
+ db = new Database(getCacheDbPath());
31
+ // Apply pragmas for better CLI performance
32
+ db.pragma("journal_mode = WAL");
33
+ db.pragma("foreign_keys = ON");
34
+ // Create table if not exists
35
+ db.exec(`
36
+ CREATE TABLE IF NOT EXISTS bundle_cache (
37
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
38
+ package_name TEXT NOT NULL,
39
+ version TEXT NOT NULL,
40
+ exports TEXT NOT NULL DEFAULT '',
41
+ platform TEXT NOT NULL,
42
+ gzip_level INTEGER NOT NULL,
43
+ externals TEXT NOT NULL DEFAULT '',
44
+ no_external INTEGER NOT NULL DEFAULT 0,
45
+ raw_size INTEGER NOT NULL,
46
+ gzip_size INTEGER,
47
+ dependencies TEXT NOT NULL DEFAULT '[]',
48
+ display_name TEXT NOT NULL,
49
+ created_at INTEGER NOT NULL,
50
+ UNIQUE(package_name, version, exports, platform, gzip_level, externals, no_external)
51
+ );
52
+
53
+ CREATE INDEX IF NOT EXISTS idx_created_at ON bundle_cache(created_at);
54
+ `);
55
+ return db;
56
+ }
57
+ /**
58
+ * Normalize cache key options to a consistent format
59
+ * Sorts exports and externals to ensure consistent cache hits
60
+ *
61
+ * Note: platform can be "browser", "node", or "auto" (when user doesn't specify).
62
+ * Using "auto" in the cache key ensures that auto-detected results are cached
63
+ * separately from explicitly specified platform results.
64
+ */ export function normalizeCacheKey(options) {
65
+ return {
66
+ packageName: options.packageName,
67
+ version: options.version,
68
+ exports: (options.exports || []).slice().sort().join(","),
69
+ // Use "auto" when platform is undefined to distinguish from explicit platform
70
+ platform: options.platform ?? "auto",
71
+ gzipLevel: options.gzipLevel,
72
+ externals: options.externals.slice().sort().join(","),
73
+ noExternal: options.noExternal ? 1 : 0
74
+ };
75
+ }
76
+ /**
77
+ * Get a cached result if it exists
78
+ * Returns null if not found or if an error occurs (graceful degradation)
79
+ */ export function getCachedResult(key) {
80
+ try {
81
+ const database = initCache();
82
+ const stmt = database.prepare(`
83
+ SELECT * FROM bundle_cache
84
+ WHERE package_name = ?
85
+ AND version = ?
86
+ AND exports = ?
87
+ AND platform = ?
88
+ AND gzip_level = ?
89
+ AND externals = ?
90
+ AND no_external = ?
91
+ `);
92
+ const row = stmt.get(key.packageName, key.version, key.exports, key.platform, key.gzipLevel, key.externals, key.noExternal);
93
+ if (!row) {
94
+ return null;
95
+ }
96
+ // Parse dependencies with error handling for corrupted data
97
+ let dependencies = [];
98
+ try {
99
+ dependencies = JSON.parse(row.dependencies);
100
+ } catch {
101
+ // If JSON is corrupted, use empty array
102
+ dependencies = [];
103
+ }
104
+ // Convert row to BundleResult
105
+ return {
106
+ packageName: row.display_name,
107
+ packageVersion: row.version,
108
+ exports: row.exports ? row.exports.split(",").filter(Boolean) : [],
109
+ rawSize: row.raw_size,
110
+ gzipSize: row.gzip_size,
111
+ gzipLevel: row.gzip_level,
112
+ externals: row.externals ? row.externals.split(",").filter(Boolean) : [],
113
+ dependencies,
114
+ platform: row.platform
115
+ };
116
+ } catch {
117
+ // On any database error, return null (graceful degradation - continue without cache)
118
+ return null;
119
+ }
120
+ }
121
+ /**
122
+ * Store a result in the cache
123
+ * Silently fails on errors (graceful degradation - CLI continues without caching)
124
+ */ export function setCachedResult(key, result) {
125
+ try {
126
+ const database = initCache();
127
+ // Use INSERT OR REPLACE to handle duplicates
128
+ // Note: This updates created_at on replace, making this LRU-style eviction
129
+ const stmt = database.prepare(`
130
+ INSERT OR REPLACE INTO bundle_cache (
131
+ package_name, version, exports, platform, gzip_level, externals, no_external,
132
+ raw_size, gzip_size, dependencies, display_name, created_at
133
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
134
+ `);
135
+ stmt.run(key.packageName, key.version, key.exports, key.platform, key.gzipLevel, key.externals, key.noExternal, result.rawSize, result.gzipSize, JSON.stringify(result.dependencies), result.packageName, Date.now());
136
+ // Enforce max entries (LRU-style eviction based on created_at)
137
+ enforceMaxEntries(database);
138
+ } catch {
139
+ // On any database error, silently continue (graceful degradation)
140
+ }
141
+ }
142
+ /**
143
+ * Enforce maximum cache entries by removing entries with oldest timestamps
144
+ * Uses LRU-style eviction: entries that are re-checked get updated timestamps
145
+ * and move to the end of the eviction queue
146
+ */ function enforceMaxEntries(database) {
147
+ const countResult = database.prepare("SELECT COUNT(*) as count FROM bundle_cache").get();
148
+ if (countResult.count > MAX_CACHE_ENTRIES) {
149
+ const toDelete = countResult.count - MAX_CACHE_ENTRIES;
150
+ database.prepare(`
151
+ DELETE FROM bundle_cache
152
+ WHERE id IN (
153
+ SELECT id FROM bundle_cache
154
+ ORDER BY created_at ASC
155
+ LIMIT ?
156
+ )
157
+ `).run(toDelete);
158
+ }
159
+ }
160
+ /**
161
+ * Clear all cache entries
162
+ * Silently fails on errors
163
+ */ export function clearCache() {
164
+ try {
165
+ const database = initCache();
166
+ database.prepare("DELETE FROM bundle_cache").run();
167
+ } catch {
168
+ // Silently ignore errors
169
+ }
170
+ }
171
+ /**
172
+ * Get the number of cached entries
173
+ * Returns 0 on error
174
+ */ export function getCacheCount() {
175
+ try {
176
+ const database = initCache();
177
+ const result = database.prepare("SELECT COUNT(*) as count FROM bundle_cache").get();
178
+ return result.count;
179
+ } catch {
180
+ return 0;
181
+ }
182
+ }
183
+ /**
184
+ * Close the database connection (useful for testing)
185
+ */ export function closeCache() {
186
+ if (db) {
187
+ db.close();
188
+ db = null;
189
+ }
190
+ }
191
+
192
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cache.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport type { BundleResult } from \"./bundler.js\";\n\nconst MAX_CACHE_ENTRIES = 100;\n\n/**\n * Get the cache directory path (computed lazily to support testing)\n */\nfunction getCacheDir(): string {\n\treturn path.join(os.homedir(), \".bundlecheck\");\n}\n\n/**\n * Get the cache database path (computed lazily to support testing)\n */\nfunction getCacheDbPath(): string {\n\treturn path.join(getCacheDir(), \"cache.db\");\n}\n\nexport type CacheKey = {\n\tpackageName: string;\n\tversion: string;\n\texports: string;\n\t/** Platform: \"browser\", \"node\", or \"auto\" (for auto-detection) */\n\tplatform: \"browser\" | \"node\" | \"auto\";\n\tgzipLevel: number;\n\texternals: string;\n\tnoExternal: number;\n};\n\nexport type CachedBundleResult = BundleResult;\n\ntype CacheRow = {\n\tid: number;\n\tpackage_name: string;\n\tversion: string;\n\texports: string;\n\tplatform: string;\n\tgzip_level: number;\n\texternals: string;\n\tno_external: number;\n\traw_size: number;\n\tgzip_size: number | null;\n\tdependencies: string;\n\tdisplay_name: string;\n\tcreated_at: number;\n};\n\nlet db: Database.Database | null = null;\n\n/**\n * Initialize the cache database with proper pragmas and schema\n */\nexport function initCache(): Database.Database {\n\tif (db) {\n\t\treturn db;\n\t}\n\n\t// Ensure cache directory exists\n\tconst cacheDir = getCacheDir();\n\tif (!fs.existsSync(cacheDir)) {\n\t\tfs.mkdirSync(cacheDir, { recursive: true });\n\t}\n\n\tdb = new Database(getCacheDbPath());\n\n\t// Apply pragmas for better CLI performance\n\tdb.pragma(\"journal_mode = WAL\");\n\tdb.pragma(\"foreign_keys = ON\");\n\n\t// Create table if not exists\n\tdb.exec(`\n\t\tCREATE TABLE IF NOT EXISTS bundle_cache (\n\t\t\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\t\t\tpackage_name TEXT NOT NULL,\n\t\t\tversion TEXT NOT NULL,\n\t\t\texports TEXT NOT NULL DEFAULT '',\n\t\t\tplatform TEXT NOT NULL,\n\t\t\tgzip_level INTEGER NOT NULL,\n\t\t\texternals TEXT NOT NULL DEFAULT '',\n\t\t\tno_external INTEGER NOT NULL DEFAULT 0,\n\t\t\traw_size INTEGER NOT NULL,\n\t\t\tgzip_size INTEGER,\n\t\t\tdependencies TEXT NOT NULL DEFAULT '[]',\n\t\t\tdisplay_name TEXT NOT NULL,\n\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\tUNIQUE(package_name, version, exports, platform, gzip_level, externals, no_external)\n\t\t);\n\n\t\tCREATE INDEX IF NOT EXISTS idx_created_at ON bundle_cache(created_at);\n\t`);\n\n\treturn db;\n}\n\n/**\n * Normalize cache key options to a consistent format\n * Sorts exports and externals to ensure consistent cache hits\n *\n * Note: platform can be \"browser\", \"node\", or \"auto\" (when user doesn't specify).\n * Using \"auto\" in the cache key ensures that auto-detected results are cached\n * separately from explicitly specified platform results.\n */\nexport function normalizeCacheKey(options: {\n\tpackageName: string;\n\tversion: string;\n\texports?: string[];\n\t/** Platform: \"browser\", \"node\", or undefined (treated as \"auto\") */\n\tplatform: \"browser\" | \"node\" | undefined;\n\tgzipLevel: number;\n\texternals: string[];\n\tnoExternal: boolean;\n}): CacheKey {\n\treturn {\n\t\tpackageName: options.packageName,\n\t\tversion: options.version,\n\t\texports: (options.exports || []).slice().sort().join(\",\"),\n\t\t// Use \"auto\" when platform is undefined to distinguish from explicit platform\n\t\tplatform: options.platform ?? \"auto\",\n\t\tgzipLevel: options.gzipLevel,\n\t\texternals: options.externals.slice().sort().join(\",\"),\n\t\tnoExternal: options.noExternal ? 1 : 0,\n\t};\n}\n\n/**\n * Get a cached result if it exists\n * Returns null if not found or if an error occurs (graceful degradation)\n */\nexport function getCachedResult(key: CacheKey): CachedBundleResult | null {\n\ttry {\n\t\tconst database = initCache();\n\n\t\tconst stmt = database.prepare<\n\t\t\t[string, string, string, string, number, string, number]\n\t\t>(`\n\t\t\tSELECT * FROM bundle_cache\n\t\t\tWHERE package_name = ?\n\t\t\tAND version = ?\n\t\t\tAND exports = ?\n\t\t\tAND platform = ?\n\t\t\tAND gzip_level = ?\n\t\t\tAND externals = ?\n\t\t\tAND no_external = ?\n\t\t`);\n\n\t\tconst row = stmt.get(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t) as CacheRow | undefined;\n\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Parse dependencies with error handling for corrupted data\n\t\tlet dependencies: string[] = [];\n\t\ttry {\n\t\t\tdependencies = JSON.parse(row.dependencies) as string[];\n\t\t} catch {\n\t\t\t// If JSON is corrupted, use empty array\n\t\t\tdependencies = [];\n\t\t}\n\n\t\t// Convert row to BundleResult\n\t\treturn {\n\t\t\tpackageName: row.display_name,\n\t\t\tpackageVersion: row.version,\n\t\t\texports: row.exports ? row.exports.split(\",\").filter(Boolean) : [],\n\t\t\trawSize: row.raw_size,\n\t\t\tgzipSize: row.gzip_size,\n\t\t\tgzipLevel: row.gzip_level,\n\t\t\texternals: row.externals ? row.externals.split(\",\").filter(Boolean) : [],\n\t\t\tdependencies,\n\t\t\tplatform: row.platform as \"browser\" | \"node\",\n\t\t};\n\t} catch {\n\t\t// On any database error, return null (graceful degradation - continue without cache)\n\t\treturn null;\n\t}\n}\n\n/**\n * Store a result in the cache\n * Silently fails on errors (graceful degradation - CLI continues without caching)\n */\nexport function setCachedResult(key: CacheKey, result: BundleResult): void {\n\ttry {\n\t\tconst database = initCache();\n\n\t\t// Use INSERT OR REPLACE to handle duplicates\n\t\t// Note: This updates created_at on replace, making this LRU-style eviction\n\t\tconst stmt = database.prepare(`\n\t\t\tINSERT OR REPLACE INTO bundle_cache (\n\t\t\t\tpackage_name, version, exports, platform, gzip_level, externals, no_external,\n\t\t\t\traw_size, gzip_size, dependencies, display_name, created_at\n\t\t\t) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n\t\t`);\n\n\t\tstmt.run(\n\t\t\tkey.packageName,\n\t\t\tkey.version,\n\t\t\tkey.exports,\n\t\t\tkey.platform,\n\t\t\tkey.gzipLevel,\n\t\t\tkey.externals,\n\t\t\tkey.noExternal,\n\t\t\tresult.rawSize,\n\t\t\tresult.gzipSize,\n\t\t\tJSON.stringify(result.dependencies),\n\t\t\tresult.packageName,\n\t\t\tDate.now(),\n\t\t);\n\n\t\t// Enforce max entries (LRU-style eviction based on created_at)\n\t\tenforceMaxEntries(database);\n\t} catch {\n\t\t// On any database error, silently continue (graceful degradation)\n\t}\n}\n\n/**\n * Enforce maximum cache entries by removing entries with oldest timestamps\n * Uses LRU-style eviction: entries that are re-checked get updated timestamps\n * and move to the end of the eviction queue\n */\nfunction enforceMaxEntries(database: Database.Database): void {\n\tconst countResult = database\n\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t.get() as { count: number };\n\n\tif (countResult.count > MAX_CACHE_ENTRIES) {\n\t\tconst toDelete = countResult.count - MAX_CACHE_ENTRIES;\n\t\tdatabase\n\t\t\t.prepare(\n\t\t\t\t`\n\t\t\tDELETE FROM bundle_cache\n\t\t\tWHERE id IN (\n\t\t\t\tSELECT id FROM bundle_cache\n\t\t\t\tORDER BY created_at ASC\n\t\t\t\tLIMIT ?\n\t\t\t)\n\t\t`,\n\t\t\t)\n\t\t\t.run(toDelete);\n\t}\n}\n\n/**\n * Clear all cache entries\n * Silently fails on errors\n */\nexport function clearCache(): void {\n\ttry {\n\t\tconst database = initCache();\n\t\tdatabase.prepare(\"DELETE FROM bundle_cache\").run();\n\t} catch {\n\t\t// Silently ignore errors\n\t}\n}\n\n/**\n * Get the number of cached entries\n * Returns 0 on error\n */\nexport function getCacheCount(): number {\n\ttry {\n\t\tconst database = initCache();\n\t\tconst result = database\n\t\t\t.prepare(\"SELECT COUNT(*) as count FROM bundle_cache\")\n\t\t\t.get() as { count: number };\n\t\treturn result.count;\n\t} catch {\n\t\treturn 0;\n\t}\n}\n\n/**\n * Close the database connection (useful for testing)\n */\nexport function closeCache(): void {\n\tif (db) {\n\t\tdb.close();\n\t\tdb = null;\n\t}\n}\n"],"names":["fs","os","path","Database","MAX_CACHE_ENTRIES","getCacheDir","join","homedir","getCacheDbPath","db","initCache","cacheDir","existsSync","mkdirSync","recursive","pragma","exec","normalizeCacheKey","options","packageName","version","exports","slice","sort","platform","gzipLevel","externals","noExternal","getCachedResult","key","database","stmt","prepare","row","get","dependencies","JSON","parse","display_name","packageVersion","split","filter","Boolean","rawSize","raw_size","gzipSize","gzip_size","gzip_level","setCachedResult","result","run","stringify","Date","now","enforceMaxEntries","countResult","count","toDelete","clearCache","getCacheCount","closeCache","close"],"mappings":"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"}
@@ -5,7 +5,20 @@ export declare const defaultFlags: {
5
5
  noExternal: boolean;
6
6
  versions: boolean;
7
7
  registry: string;
8
+ platform: string;
9
+ force: boolean;
8
10
  };
11
+ /**
12
+ * Normalize platform aliases to canonical esbuild platform values
13
+ * - "auto" → undefined (triggers auto-detection based on package engines)
14
+ * - Browser aliases: "browser", "web", "desktop", "client" → "browser"
15
+ * - Node aliases: "node", "server", "nodejs", "backend" → "node"
16
+ */
17
+ export declare function normalizePlatform(platform: string | undefined): "browser" | "node" | undefined;
18
+ /**
19
+ * Check if a platform value is valid (either canonical or alias)
20
+ */
21
+ export declare function isValidPlatform(platform: string | undefined): boolean;
9
22
  export declare const TREND_VERSION_COUNT = 5;
10
23
  export declare const DEFAULT_EXTERNALS: string[];
11
24
  export declare const DEFAULT_REGISTRY = "https://registry.npmjs.org";
package/dist/defaults.js CHANGED
@@ -4,8 +4,72 @@
4
4
  external: "",
5
5
  noExternal: false,
6
6
  versions: false,
7
- registry: ""
7
+ registry: "",
8
+ platform: "auto",
9
+ force: false
8
10
  };
11
+ /**
12
+ * Normalize platform aliases to canonical esbuild platform values
13
+ * - "auto" → undefined (triggers auto-detection based on package engines)
14
+ * - Browser aliases: "browser", "web", "desktop", "client" → "browser"
15
+ * - Node aliases: "node", "server", "nodejs", "backend" → "node"
16
+ */ export function normalizePlatform(platform) {
17
+ if (!platform) {
18
+ return undefined;
19
+ }
20
+ const normalized = platform.toLowerCase().trim();
21
+ // Auto-detect from package.json engines
22
+ if (normalized === "auto") {
23
+ return undefined;
24
+ }
25
+ // Node aliases
26
+ if ([
27
+ "node",
28
+ "server",
29
+ "nodejs",
30
+ "backend"
31
+ ].includes(normalized)) {
32
+ return "node";
33
+ }
34
+ // Browser aliases
35
+ if ([
36
+ "browser",
37
+ "web",
38
+ "desktop",
39
+ "client"
40
+ ].includes(normalized)) {
41
+ return "browser";
42
+ }
43
+ // Invalid value - will be caught by validation
44
+ return normalized;
45
+ }
46
+ /**
47
+ * Check if a platform value is valid (either canonical or alias)
48
+ */ export function isValidPlatform(platform) {
49
+ if (platform === undefined) {
50
+ return true;
51
+ }
52
+ const normalized = platform.toLowerCase().trim();
53
+ // Empty string after trim is invalid
54
+ if (normalized === "") {
55
+ return false;
56
+ }
57
+ const validValues = [
58
+ // Auto-detect
59
+ "auto",
60
+ // Browser
61
+ "browser",
62
+ "web",
63
+ "desktop",
64
+ "client",
65
+ // Node
66
+ "node",
67
+ "server",
68
+ "nodejs",
69
+ "backend"
70
+ ];
71
+ return validValues.includes(normalized);
72
+ }
9
73
  export const TREND_VERSION_COUNT = 5;
10
74
  export const DEFAULT_EXTERNALS = [
11
75
  "react",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["/* istanbul ignore file */\n\nexport const defaultFlags = {\n\tboring: false,\n\tgzipLevel: 5,\n\texternal: \"\",\n\tnoExternal: false,\n\tversions: false,\n\tregistry: \"\",\n};\n\nexport const TREND_VERSION_COUNT = 5;\n\nexport const DEFAULT_EXTERNALS = [\"react\", \"react-dom\"];\n\nexport const DEFAULT_REGISTRY = \"https://registry.npmjs.org\";\n"],"names":["defaultFlags","boring","gzipLevel","external","noExternal","versions","registry","TREND_VERSION_COUNT","DEFAULT_EXTERNALS","DEFAULT_REGISTRY"],"mappings":"AAAA,wBAAwB,GAExB,OAAO,MAAMA,eAAe;IAC3BC,QAAQ;IACRC,WAAW;IACXC,UAAU;IACVC,YAAY;IACZC,UAAU;IACVC,UAAU;AACX,EAAE;AAEF,OAAO,MAAMC,sBAAsB,EAAE;AAErC,OAAO,MAAMC,oBAAoB;IAAC;IAAS;CAAY,CAAC;AAExD,OAAO,MAAMC,mBAAmB,6BAA6B"}
1
+ {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["/* istanbul ignore file */\n\nexport const defaultFlags = {\n\tboring: false,\n\tgzipLevel: 5,\n\texternal: \"\",\n\tnoExternal: false,\n\tversions: false,\n\tregistry: \"\",\n\tplatform: \"auto\",\n\tforce: false,\n};\n\n/**\n * Normalize platform aliases to canonical esbuild platform values\n * - \"auto\" → undefined (triggers auto-detection based on package engines)\n * - Browser aliases: \"browser\", \"web\", \"desktop\", \"client\" → \"browser\"\n * - Node aliases: \"node\", \"server\", \"nodejs\", \"backend\" → \"node\"\n */\nexport function normalizePlatform(\n\tplatform: string | undefined,\n): \"browser\" | \"node\" | undefined {\n\tif (!platform) {\n\t\treturn undefined;\n\t}\n\n\tconst normalized = platform.toLowerCase().trim();\n\n\t// Auto-detect from package.json engines\n\tif (normalized === \"auto\") {\n\t\treturn undefined;\n\t}\n\n\t// Node aliases\n\tif ([\"node\", \"server\", \"nodejs\", \"backend\"].includes(normalized)) {\n\t\treturn \"node\";\n\t}\n\n\t// Browser aliases\n\tif ([\"browser\", \"web\", \"desktop\", \"client\"].includes(normalized)) {\n\t\treturn \"browser\";\n\t}\n\n\t// Invalid value - will be caught by validation\n\treturn normalized as \"browser\" | \"node\";\n}\n\n/**\n * Check if a platform value is valid (either canonical or alias)\n */\nexport function isValidPlatform(platform: string | undefined): boolean {\n\tif (platform === undefined) {\n\t\treturn true;\n\t}\n\n\tconst normalized = platform.toLowerCase().trim();\n\n\t// Empty string after trim is invalid\n\tif (normalized === \"\") {\n\t\treturn false;\n\t}\n\tconst validValues = [\n\t\t// Auto-detect\n\t\t\"auto\",\n\t\t// Browser\n\t\t\"browser\",\n\t\t\"web\",\n\t\t\"desktop\",\n\t\t\"client\",\n\t\t// Node\n\t\t\"node\",\n\t\t\"server\",\n\t\t\"nodejs\",\n\t\t\"backend\",\n\t];\n\n\treturn validValues.includes(normalized);\n}\n\nexport const TREND_VERSION_COUNT = 5;\n\nexport const DEFAULT_EXTERNALS = [\"react\", \"react-dom\"];\n\nexport const DEFAULT_REGISTRY = \"https://registry.npmjs.org\";\n"],"names":["defaultFlags","boring","gzipLevel","external","noExternal","versions","registry","platform","force","normalizePlatform","undefined","normalized","toLowerCase","trim","includes","isValidPlatform","validValues","TREND_VERSION_COUNT","DEFAULT_EXTERNALS","DEFAULT_REGISTRY"],"mappings":"AAAA,wBAAwB,GAExB,OAAO,MAAMA,eAAe;IAC3BC,QAAQ;IACRC,WAAW;IACXC,UAAU;IACVC,YAAY;IACZC,UAAU;IACVC,UAAU;IACVC,UAAU;IACVC,OAAO;AACR,EAAE;AAEF;;;;;CAKC,GACD,OAAO,SAASC,kBACfF,QAA4B;IAE5B,IAAI,CAACA,UAAU;QACd,OAAOG;IACR;IAEA,MAAMC,aAAaJ,SAASK,WAAW,GAAGC,IAAI;IAE9C,wCAAwC;IACxC,IAAIF,eAAe,QAAQ;QAC1B,OAAOD;IACR;IAEA,eAAe;IACf,IAAI;QAAC;QAAQ;QAAU;QAAU;KAAU,CAACI,QAAQ,CAACH,aAAa;QACjE,OAAO;IACR;IAEA,kBAAkB;IAClB,IAAI;QAAC;QAAW;QAAO;QAAW;KAAS,CAACG,QAAQ,CAACH,aAAa;QACjE,OAAO;IACR;IAEA,+CAA+C;IAC/C,OAAOA;AACR;AAEA;;CAEC,GACD,OAAO,SAASI,gBAAgBR,QAA4B;IAC3D,IAAIA,aAAaG,WAAW;QAC3B,OAAO;IACR;IAEA,MAAMC,aAAaJ,SAASK,WAAW,GAAGC,IAAI;IAE9C,qCAAqC;IACrC,IAAIF,eAAe,IAAI;QACtB,OAAO;IACR;IACA,MAAMK,cAAc;QACnB,cAAc;QACd;QACA,UAAU;QACV;QACA;QACA;QACA;QACA,OAAO;QACP;QACA;QACA;QACA;KACA;IAED,OAAOA,YAAYF,QAAQ,CAACH;AAC7B;AAEA,OAAO,MAAMM,sBAAsB,EAAE;AAErC,OAAO,MAAMC,oBAAoB;IAAC;IAAS;CAAY,CAAC;AAExD,OAAO,MAAMC,mBAAmB,6BAA6B"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  export * from "./bundlecheck";
6
6
  export * from "./bundler";
7
+ export * from "./cache";
7
8
  export * from "./defaults";
8
9
  export * from "./parse";
9
10
  export * from "./trend";
package/dist/parse.d.ts CHANGED
@@ -8,6 +8,8 @@ export type Flags = {
8
8
  external?: string;
9
9
  noExternal?: boolean;
10
10
  registry?: string;
11
+ platform?: string;
12
+ force?: boolean;
11
13
  };
12
14
  export type Parameters = {
13
15
  ["0"]?: string;
package/dist/parse.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* istanbul ignore file */ import { parser } from "@node-cli/parser";
2
- import { DEFAULT_EXTERNALS, defaultFlags } from "./defaults.js";
2
+ import { DEFAULT_EXTERNALS, defaultFlags, isValidPlatform } from "./defaults.js";
3
3
  export const config = parser({
4
4
  meta: import.meta,
5
5
  examples: [
@@ -46,6 +46,14 @@ export const config = parser({
46
46
  {
47
47
  command: "bundlecheck lodash --registry https://registry.example.com",
48
48
  comment: "## Use a custom npm registry"
49
+ },
50
+ {
51
+ command: "bundlecheck express --platform node",
52
+ comment: "## Check bundle size for Node.js platform (aliases: server, nodejs, backend)"
53
+ },
54
+ {
55
+ command: "bundlecheck lodash --force",
56
+ comment: "## Bypass cache and force re-fetch/re-calculation"
49
57
  }
50
58
  ],
51
59
  flags: {
@@ -99,6 +107,18 @@ export const config = parser({
99
107
  default: defaultFlags.registry,
100
108
  description: "Custom npm registry URL (default: https://registry.npmjs.org)",
101
109
  type: "string"
110
+ },
111
+ platform: {
112
+ shortFlag: "p",
113
+ default: defaultFlags.platform,
114
+ description: 'Target platform: "auto" (default, detects from engines), "browser" or "node"',
115
+ type: "string"
116
+ },
117
+ force: {
118
+ shortFlag: "f",
119
+ default: defaultFlags.force,
120
+ description: "Bypass cache and force re-fetch/re-calculation",
121
+ type: "boolean"
102
122
  }
103
123
  },
104
124
  parameters: {
@@ -119,6 +139,11 @@ export const config = parser({
119
139
  exit: 1,
120
140
  message: ()=>"Error: Gzip level must be between 1 and 9",
121
141
  test: (flags)=>flags.gzipLevel !== undefined && (flags.gzipLevel < 1 || flags.gzipLevel > 9)
142
+ },
143
+ {
144
+ exit: 1,
145
+ message: ()=>'Error: Invalid platform. Use "browser" (or web, desktop, client) or "node" (or server, nodejs, backend)',
146
+ test: (flags)=>!isValidPlatform(flags.platform)
122
147
  }
123
148
  ],
124
149
  usage: true,
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 { DEFAULT_EXTERNALS, defaultFlags } 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};\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],\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},\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],\n\tusage: true,\n\tdefaultFlags,\n});\n"],"names":["parser","DEFAULT_EXTERNALS","defaultFlags","config","meta","examples","command","comment","flags","gzipLevel","shortFlag","default","description","type","external","join","noExternal","boring","help","version","versions","trend","registry","parameters","package","exports","restrictions","exit","message","test","undefined","usage"],"mappings":"AAAA,wBAAwB,GACxB,SAASA,MAAM,QAAQ,mBAAmB;AAC1C,SAASC,iBAAiB,EAAEC,YAAY,QAAQ,gBAAgB;AA0BhE,OAAO,MAAMC,SAAwBH,OAAO;IAC3CI,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;KACA;IACDC,OAAO;QACNC,WAAW;YACVC,WAAW;YACXC,SAAST,aAAaO,SAAS;YAC/BG,aAAa;YACbC,MAAM;QACP;QACAC,UAAU;YACTJ,WAAW;YACXC,SAAST,aAAaY,QAAQ;YAC9BF,aAAa,CAAC,yDAAyD,EAAEX,kBAAkBc,IAAI,CAAC,MAAM,CAAC,CAAC;YACxGF,MAAM;QACP;QACAG,YAAY;YACXN,WAAW;YACXC,SAAST,aAAac,UAAU;YAChCJ,aACC;YACDC,MAAM;QACP;QACAI,QAAQ;YACPP,WAAW;YACXC,SAAST,aAAae,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,SAAST,aAAakB,QAAQ;YAC9BR,aAAa;YACbC,MAAM;QACP;QACAQ,OAAO;YACNX,WAAW;YACXE,aAAa;YACbC,MAAM;QACP;QACAS,UAAU;YACTZ,WAAW;YACXC,SAAST,aAAaoB,QAAQ;YAC9BV,aACC;YACDC,MAAM;QACP;IACD;IACAU,YAAY;QACXC,SAAS;YACRZ,aAAa;QACd;QACAa,SAAS;YACRb,aACC;QACF;IACD;IACAc,cAAc;QACb;YACCC,MAAM;YACNC,SAAS,IAAM;YACfC,MAAM,CAACrB,OAAOe,aAAe,CAACA,YAAY,CAAC,IAAI;QAChD;QACA;YACCI,MAAM;YACNC,SAAS,IAAM;YACfC,MAAM,CAACrB,QACNA,MAAMC,SAAS,KAAKqB,aACnBtB,CAAAA,MAAMC,SAAS,GAAG,KAAKD,MAAMC,SAAS,GAAG,CAAA;QAC5C;KACA;IACDsB,OAAO;IACP7B;AACD,GAAG"}
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
- gzipSize: number;
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;
@@ -12,6 +13,10 @@ export type TrendOptions = {
12
13
  gzipLevel?: number;
13
14
  boring?: boolean;
14
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;
15
20
  };
16
21
  /**
17
22
  * Select versions for trend analysis