@node-cli/bundlecheck 1.2.0 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bundler.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport zlib from \"node:zlib\";\nimport * as esbuild from \"esbuild\";\nimport { DEFAULT_EXTERNALS } from \"./defaults.js\";\n\nconst gzipAsync = promisify(zlib.gzip);\n\n/**\n * Escape special regex characters in a string\n */\nfunction escapeRegExp(str: string): string {\n\treturn str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport type ParsedPackage = {\n\tname: string;\n\tversion: string;\n\tsubpath?: string;\n};\n\n/**\n * Parse a package specifier to extract name, version, and subpath\n * Handles:\n * - @scope/package@1.0.0\n * - @scope/package/subpath@1.0.0\n * - @scope/package/subpath\n * - package/subpath@1.0.0\n */\nexport function parsePackageSpecifier(specifier: string): ParsedPackage {\n\tlet workingSpec = specifier;\n\tlet version = \"latest\";\n\n\t// Handle scoped packages (@scope/name...)\n\tif (workingSpec.startsWith(\"@\")) {\n\t\t// Find the second @ which would separate version\n\t\tconst secondAtIndex = workingSpec.indexOf(\"@\", 1);\n\t\tif (secondAtIndex !== -1) {\n\t\t\tversion = workingSpec.substring(secondAtIndex + 1);\n\t\t\tworkingSpec = workingSpec.substring(0, secondAtIndex);\n\t\t}\n\n\t\t// Now workingSpec is like @scope/name or @scope/name/subpath\n\t\t// Split by / and check if there are more than 2 parts\n\t\tconst parts = workingSpec.split(\"/\");\n\t\tif (parts.length > 2) {\n\t\t\t// Has subpath: @scope/name/subpath/more\n\t\t\tconst name = `${parts[0]}/${parts[1]}`;\n\t\t\tconst subpath = parts.slice(2).join(\"/\");\n\t\t\treturn { name, version, subpath };\n\t\t}\n\t\t// No subpath: @scope/name\n\t\treturn { name: workingSpec, version };\n\t}\n\n\t// Handle non-scoped packages (name@version or name/subpath@version)\n\tconst atIndex = workingSpec.indexOf(\"@\");\n\tif (atIndex !== -1) {\n\t\tversion = workingSpec.substring(atIndex + 1);\n\t\tworkingSpec = workingSpec.substring(0, atIndex);\n\t}\n\n\t// Check for subpath in non-scoped packages\n\tconst slashIndex = workingSpec.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst name = workingSpec.substring(0, slashIndex);\n\t\tconst subpath = workingSpec.substring(slashIndex + 1);\n\t\treturn { name, version, subpath };\n\t}\n\n\treturn { name: workingSpec, version };\n}\n\nexport type BundleOptions = {\n\tpackageName: string;\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tregistry?: string;\n};\n\nexport type BundleResult = {\n\tpackageName: string;\n\tpackageVersion: string;\n\texports: string[];\n\trawSize: number;\n\tgzipSize: number;\n\tgzipLevel: number;\n\texternals: string[];\n\tdependencies: string[];\n};\n\n/**\n * Format bytes to human-readable string\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) {\n\t\treturn \"0 B\";\n\t}\n\tconst k = 1024;\n\tconst sizes = [\"B\", \"kB\", \"MB\", \"GB\"];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\treturn `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n}\n\n/**\n * Create a temporary directory for bundling\n */\nfunction createTempDir(): string {\n\tconst tmpDir = path.join(os.tmpdir(), `bundlecheck-${Date.now()}`);\n\tfs.mkdirSync(tmpDir, { recursive: true });\n\treturn tmpDir;\n}\n\n/**\n * Clean up temporary directory\n */\nfunction cleanupTempDir(tmpDir: string): void {\n\ttry {\n\t\tfs.rmSync(tmpDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Ignore cleanup errors\n\t}\n}\n\n/**\n * Check if pnpm is available\n */\nfunction isPnpmAvailable(): boolean {\n\ttry {\n\t\texecSync(\"pnpm --version\", { stdio: \"pipe\" });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Cache the result of pnpm availability check\nlet usePnpm: boolean | null = null;\n\n/**\n * Validate and sanitize a registry URL to prevent command injection\n * @param registry - The registry URL to validate\n * @returns The sanitized URL or undefined if invalid\n * @throws Error if the URL is invalid or contains potentially malicious characters\n */\nfunction validateRegistryUrl(registry: string): string {\n\t// Parse as URL to validate format\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(registry);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL: ${registry}. Must be a valid URL (e.g., https://registry.example.com)`,\n\t\t);\n\t}\n\n\t// Only allow http and https protocols\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL protocol: ${url.protocol}. Only http: and https: are allowed`,\n\t\t);\n\t}\n\n\t// Return the sanitized URL (URL constructor normalizes it)\n\treturn url.toString();\n}\n\n/**\n * Get the install command (pnpm preferred, npm fallback)\n * @param registry - Optional custom npm registry URL\n */\nfunction getInstallCommand(registry?: string): string {\n\tif (usePnpm === null) {\n\t\tusePnpm = isPnpmAvailable();\n\t}\n\n\tlet registryArg = \"\";\n\tif (registry) {\n\t\t// Validate and sanitize the registry URL to prevent command injection\n\t\tconst sanitizedRegistry = validateRegistryUrl(registry);\n\t\t// Quote the URL to handle any special characters safely\n\t\tregistryArg = ` --registry \"${sanitizedRegistry}\"`;\n\t}\n\n\tif (usePnpm) {\n\t\treturn `pnpm install --ignore-scripts --no-frozen-lockfile${registryArg}`;\n\t}\n\treturn `npm install --legacy-peer-deps --ignore-scripts${registryArg}`;\n}\n\nexport type EntryContentOptions = {\n\tpackageName: string;\n\tsubpath?: string;\n\texports?: string[];\n\tallSubpaths?: string[];\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Generate the entry file content based on package, subpath, and exports\n */\nfunction generateEntryContent(options: EntryContentOptions): string {\n\tconst { packageName, subpath, exports, allSubpaths, exportToSubpath } =\n\t\toptions;\n\n\t// If we have exports mapped to different subpaths\n\tif (exportToSubpath && exportToSubpath.size > 0) {\n\t\t// Group exports by subpath\n\t\tconst subpathToExports = new Map<string, string[]>();\n\t\tfor (const [exportName, sp] of exportToSubpath) {\n\t\t\tconst existing = subpathToExports.get(sp) || [];\n\t\t\texisting.push(exportName);\n\t\t\tsubpathToExports.set(sp, existing);\n\t\t}\n\n\t\t// Generate imports for each subpath\n\t\tconst lines: string[] = [];\n\t\tconst allExportNames: string[] = [];\n\n\t\tfor (const [sp, exportNames] of subpathToExports) {\n\t\t\tconst importPath = `${packageName}/${sp}`;\n\t\t\tconst names = exportNames.join(\", \");\n\t\t\tlines.push(`import { ${names} } from \"${importPath}\";`);\n\t\t\tallExportNames.push(...exportNames);\n\t\t}\n\n\t\tlines.push(`export { ${allExportNames.join(\", \")} };`);\n\t\treturn lines.join(\"\\n\") + \"\\n\";\n\t}\n\n\t// If we have specific exports to import\n\tif (exports && exports.length > 0) {\n\t\t// Determine the import path\n\t\tconst importPath = subpath ? `${packageName}/${subpath}` : packageName;\n\t\tconst importNames = exports.join(\", \");\n\t\treturn `import { ${importNames} } from \"${importPath}\";\\nexport { ${importNames} };\\n`;\n\t}\n\n\t// If we have a specific subpath (but no specific exports)\n\tif (subpath) {\n\t\tconst importPath = `${packageName}/${subpath}`;\n\t\treturn `import * as pkg from \"${importPath}\";\\nexport default pkg;\\n`;\n\t}\n\n\t// If package has subpath exports only (no main entry), import all subpaths\n\tif (allSubpaths && allSubpaths.length > 0) {\n\t\tconst imports = allSubpaths\n\t\t\t.map(\n\t\t\t\t(sp, i) =>\n\t\t\t\t\t`import * as sub${i} from \"${packageName}/${sp}\";\\nexport { sub${i} };`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\treturn imports + \"\\n\";\n\t}\n\n\t// Default: import everything from main entry\n\treturn `import * as pkg from \"${packageName}\";\\nexport default pkg;\\n`;\n}\n\n/**\n * Get externals list based on options\n */\nfunction getExternals(\n\tpackageName: string,\n\texternals?: string[],\n\tnoExternal?: boolean,\n): string[] {\n\tif (noExternal) {\n\t\treturn [];\n\t}\n\n\t// Start with default externals (react, react-dom)\n\tlet result = [...DEFAULT_EXTERNALS];\n\n\t// If checking react or react-dom themselves, don't mark them as external\n\tif (packageName === \"react\") {\n\t\tresult = result.filter((e) => e !== \"react\");\n\t} else if (packageName === \"react-dom\") {\n\t\tresult = result.filter((e) => e !== \"react-dom\");\n\t}\n\n\t// Add any additional externals\n\tif (externals && externals.length > 0) {\n\t\tresult = [...new Set([...result, ...externals])];\n\t}\n\n\treturn result;\n}\n\nexport type PackageExports = Record<\n\tstring,\n\tstring | { import?: string; types?: string }\n>;\n\nexport type PackageInfo = {\n\tversion: string;\n\tdependencies: Record<string, string>;\n\tpeerDependencies: Record<string, string>;\n\texports: PackageExports | null;\n\thasMainEntry: boolean;\n};\n\n/**\n * Get version, dependencies, peer dependencies, and exports from an installed package\n */\nfunction getPackageInfo(tmpDir: string, packageName: string): PackageInfo {\n\ttry {\n\t\t// Handle scoped packages - the package name in node_modules\n\t\tconst pkgJsonPath = path.join(\n\t\t\ttmpDir,\n\t\t\t\"node_modules\",\n\t\t\tpackageName,\n\t\t\t\"package.json\",\n\t\t);\n\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\tconst pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n\t\t\t// Check if package has a main entry point\n\t\t\tconst hasMainEntry = Boolean(\n\t\t\t\tpkgJson.main ||\n\t\t\t\t\tpkgJson.module ||\n\t\t\t\t\tpkgJson.exports?.[\".\"] ||\n\t\t\t\t\tpkgJson.exports?.[\"./index\"] ||\n\t\t\t\t\t(!pkgJson.exports && !pkgJson.main && !pkgJson.module),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tversion: pkgJson.version || \"unknown\",\n\t\t\t\tdependencies: pkgJson.dependencies || {},\n\t\t\t\tpeerDependencies: pkgJson.peerDependencies || {},\n\t\t\t\texports: pkgJson.exports || null,\n\t\t\t\thasMainEntry,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// Ignore errors reading package info\n\t}\n\treturn {\n\t\tversion: \"unknown\",\n\t\tdependencies: {},\n\t\tpeerDependencies: {},\n\t\texports: null,\n\t\thasMainEntry: true,\n\t};\n}\n\n/**\n * Extract subpath export names from package exports field\n * Returns array of subpaths like [\"header\", \"body\", \"datagrid\"]\n */\nfunction getSubpathExports(exports: PackageExports | null): string[] {\n\tif (!exports) {\n\t\treturn [];\n\t}\n\n\tconst subpaths: string[] = [];\n\tfor (const key of Object.keys(exports)) {\n\t\t// Skip the main entry point and package.json\n\t\tif (key === \".\" || key === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\t\t// Remove leading \"./\" to get subpath name\n\t\tif (key.startsWith(\"./\")) {\n\t\t\tsubpaths.push(key.substring(2));\n\t\t}\n\t}\n\treturn subpaths;\n}\n\n/**\n * Result of finding subpaths for exports\n */\ntype SubpathMapping = {\n\t// Single subpath if all exports are from the same subpath\n\tsingleSubpath?: string;\n\t// Map of export name to subpath for multiple subpaths\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Find which subpath(s) export the given component names\n * Reads type definition files or JS files to find the exports\n */\nfunction findSubpathsForExports(\n\ttmpDir: string,\n\tpackageName: string,\n\texports: PackageExports,\n\tcomponentNames: string[],\n): SubpathMapping {\n\tconst packageDir = path.join(tmpDir, \"node_modules\", packageName);\n\tconst exportToSubpath = new Map<string, string>();\n\n\tfor (const [subpathKey, subpathValue] of Object.entries(exports)) {\n\t\t// Skip main entry and package.json\n\t\tif (subpathKey === \".\" || subpathKey === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get the types or import path\n\t\tlet filePath: string | undefined;\n\t\tif (typeof subpathValue === \"object\" && subpathValue !== null) {\n\t\t\t// Prefer types file for more accurate export detection\n\t\t\tfilePath = subpathValue.types || subpathValue.import;\n\t\t} else if (typeof subpathValue === \"string\") {\n\t\t\tfilePath = subpathValue;\n\t\t}\n\n\t\tif (!filePath) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the file path\n\t\tconst fullPath = path.join(packageDir, filePath);\n\n\t\ttry {\n\t\t\tif (fs.existsSync(fullPath)) {\n\t\t\t\tconst content = fs.readFileSync(fullPath, \"utf-8\");\n\t\t\t\tconst subpath = subpathKey.startsWith(\"./\")\n\t\t\t\t\t? subpathKey.substring(2)\n\t\t\t\t\t: subpathKey;\n\n\t\t\t\t// Check each component name\n\t\t\t\tfor (const name of componentNames) {\n\t\t\t\t\t// Skip if already found\n\t\t\t\t\tif (exportToSubpath.has(name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Escape regex special characters in the name to prevent injection\n\t\t\t\t\tconst escapedName = escapeRegExp(name);\n\n\t\t\t\t\t// Look for various export patterns\n\t\t\t\t\tconst patterns = [\n\t\t\t\t\t\tnew RegExp(`export\\\\s*\\\\{[^}]*\\\\b${escapedName}\\\\b[^}]*\\\\}`, \"m\"),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+declare\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t];\n\n\t\t\t\t\tif (patterns.some((pattern) => pattern.test(content))) {\n\t\t\t\t\t\texportToSubpath.set(name, subpath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors, continue to next subpath\n\t\t}\n\t}\n\n\t// Check if all exports were found\n\tif (exportToSubpath.size !== componentNames.length) {\n\t\treturn {}; // Not all exports found\n\t}\n\n\t// Check if all exports are from the same subpath\n\tconst subpaths = new Set(exportToSubpath.values());\n\tif (subpaths.size === 1) {\n\t\treturn { singleSubpath: [...subpaths][0] };\n\t}\n\n\t// Multiple subpaths needed\n\treturn { exportToSubpath };\n}\n\n/**\n * Check the bundle size of an npm package\n */\nexport async function checkBundleSize(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tpackageName: packageSpecifier,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel = 5,\n\t\tregistry,\n\t} = options;\n\n\t// Parse the package specifier to extract name, version, and subpath\n\tconst {\n\t\tname: packageName,\n\t\tversion: requestedVersion,\n\t\tsubpath,\n\t} = parsePackageSpecifier(packageSpecifier);\n\n\tconst tmpDir = createTempDir();\n\n\ttry {\n\t\t// Create initial package.json\n\t\tconst packageJson: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\ttype: string;\n\t\t\tdependencies: Record<string, string>;\n\t\t} = {\n\t\t\tname: \"bundlecheck-temp\",\n\t\t\tversion: \"1.0.0\",\n\t\t\ttype: \"module\",\n\t\t\tdependencies: {\n\t\t\t\t[packageName]: requestedVersion,\n\t\t\t},\n\t\t};\n\n\t\tfs.writeFileSync(\n\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t);\n\n\t\t// Install the main package (try pnpm first, fallback to npm)\n\t\tconst installCmd = getInstallCommand(registry);\n\t\texecSync(installCmd, {\n\t\t\tcwd: tmpDir,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\n\t\t// Get package info (version, dependencies, peer dependencies, exports)\n\t\tconst pkgInfo = getPackageInfo(tmpDir, packageName);\n\t\tconst peerDepKeys = Object.keys(pkgInfo.peerDependencies);\n\n\t\t// Collect all dependency names (prod + peer)\n\t\tconst allDependencies = [\n\t\t\t...new Set([...Object.keys(pkgInfo.dependencies), ...peerDepKeys]),\n\t\t].sort();\n\n\t\tif (peerDepKeys.length > 0) {\n\t\t\t// Add peer dependencies to package.json\n\t\t\tfor (const dep of peerDepKeys) {\n\t\t\t\t// Use the version range from peer dependencies\n\t\t\t\tpackageJson.dependencies[dep] = pkgInfo.peerDependencies[dep];\n\t\t\t}\n\n\t\t\t// Update package.json and reinstall\n\t\t\tfs.writeFileSync(\n\t\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t\t);\n\n\t\t\texecSync(installCmd, {\n\t\t\t\tcwd: tmpDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t});\n\t\t}\n\n\t\t// Determine if we need to use all subpath exports or find the right subpath(s)\n\t\tlet allSubpaths: string[] | undefined;\n\t\tlet resolvedSubpath = subpath;\n\t\tlet exportToSubpath: Map<string, string> | undefined;\n\n\t\tif (!subpath && !pkgInfo.hasMainEntry && pkgInfo.exports) {\n\t\t\tif (exports && exports.length > 0) {\n\t\t\t\t// User specified exports but no subpath - try to find the right subpath(s)\n\t\t\t\tconst mapping = findSubpathsForExports(\n\t\t\t\t\ttmpDir,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tpkgInfo.exports,\n\t\t\t\t\texports,\n\t\t\t\t);\n\n\t\t\t\tif (mapping.singleSubpath) {\n\t\t\t\t\t// All exports from the same subpath\n\t\t\t\t\tresolvedSubpath = mapping.singleSubpath;\n\t\t\t\t} else if (mapping.exportToSubpath) {\n\t\t\t\t\t// Exports from multiple subpaths\n\t\t\t\t\texportToSubpath = mapping.exportToSubpath;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no subpath resolved and no mapping, bundle all subpaths\n\t\t\tif (!resolvedSubpath && !exportToSubpath) {\n\t\t\t\tallSubpaths = getSubpathExports(pkgInfo.exports);\n\t\t\t}\n\t\t}\n\n\t\t// Create entry file with appropriate content\n\t\tconst entryContent = generateEntryContent({\n\t\t\tpackageName,\n\t\t\tsubpath: resolvedSubpath,\n\t\t\texports,\n\t\t\tallSubpaths,\n\t\t\texportToSubpath,\n\t\t});\n\t\tconst entryFile = path.join(tmpDir, \"entry.js\");\n\t\tfs.writeFileSync(entryFile, entryContent);\n\n\t\t// Get externals\n\t\tconst externals = getExternals(\n\t\t\tpackageName,\n\t\t\tadditionalExternals,\n\t\t\tnoExternal,\n\t\t);\n\n\t\t// Bundle with esbuild\n\t\tconst result = await esbuild.build({\n\t\t\tentryPoints: [entryFile],\n\t\t\tbundle: true,\n\t\t\twrite: false,\n\t\t\tformat: \"esm\",\n\t\t\tplatform: \"browser\",\n\t\t\ttarget: \"es2020\",\n\t\t\tminify: true,\n\t\t\ttreeShaking: true,\n\t\t\texternal: externals,\n\t\t\tmetafile: true,\n\t\t});\n\n\t\t// Get raw size\n\t\tconst bundleContent = result.outputFiles[0].contents;\n\t\tconst rawSize = bundleContent.length;\n\n\t\t// Gzip the bundle\n\t\tconst gzipped = await gzipAsync(Buffer.from(bundleContent), {\n\t\t\tlevel: gzipLevel,\n\t\t});\n\t\tconst gzipSize = gzipped.length;\n\n\t\t// Determine the display name\n\t\tlet displayName = packageName;\n\t\tif (resolvedSubpath) {\n\t\t\tdisplayName = `${packageName}/${resolvedSubpath}`;\n\t\t} else if (exportToSubpath && exportToSubpath.size > 0) {\n\t\t\t// Multiple subpaths - show them all\n\t\t\tconst uniqueSubpaths = [...new Set(exportToSubpath.values())].sort();\n\t\t\tdisplayName = `${packageName}/{${uniqueSubpaths.join(\", \")}}`;\n\t\t}\n\n\t\treturn {\n\t\t\tpackageName: displayName,\n\t\t\tpackageVersion: pkgInfo.version,\n\t\t\texports: exports || [],\n\t\t\trawSize,\n\t\t\tgzipSize,\n\t\t\tgzipLevel,\n\t\t\texternals,\n\t\t\tdependencies: allDependencies,\n\t\t};\n\t} finally {\n\t\tcleanupTempDir(tmpDir);\n\t}\n}\n"],"names":["execSync","fs","os","path","promisify","zlib","esbuild","DEFAULT_EXTERNALS","gzipAsync","gzip","escapeRegExp","str","replace","parsePackageSpecifier","specifier","workingSpec","version","startsWith","secondAtIndex","indexOf","substring","parts","split","length","name","subpath","slice","join","atIndex","slashIndex","formatBytes","bytes","k","sizes","i","Math","floor","log","Number","parseFloat","toFixed","createTempDir","tmpDir","tmpdir","Date","now","mkdirSync","recursive","cleanupTempDir","rmSync","force","isPnpmAvailable","stdio","usePnpm","validateRegistryUrl","registry","url","URL","Error","protocol","toString","getInstallCommand","registryArg","sanitizedRegistry","generateEntryContent","options","packageName","exports","allSubpaths","exportToSubpath","size","subpathToExports","Map","exportName","sp","existing","get","push","set","lines","allExportNames","exportNames","importPath","names","importNames","imports","map","getExternals","externals","noExternal","result","filter","e","Set","getPackageInfo","pkgJsonPath","existsSync","pkgJson","JSON","parse","readFileSync","hasMainEntry","Boolean","main","module","dependencies","peerDependencies","getSubpathExports","subpaths","key","Object","keys","findSubpathsForExports","componentNames","packageDir","subpathKey","subpathValue","entries","filePath","types","import","fullPath","content","has","escapedName","patterns","RegExp","some","pattern","test","values","singleSubpath","checkBundleSize","packageSpecifier","additionalExternals","gzipLevel","requestedVersion","packageJson","type","writeFileSync","stringify","installCmd","cwd","pkgInfo","peerDepKeys","allDependencies","sort","dep","resolvedSubpath","mapping","entryContent","entryFile","build","entryPoints","bundle","write","format","platform","target","minify","treeShaking","external","metafile","bundleContent","outputFiles","contents","rawSize","gzipped","Buffer","from","level","gzipSize","displayName","uniqueSubpaths","packageVersion"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/bundler.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport zlib from \"node:zlib\";\nimport * as esbuild from \"esbuild\";\nimport { DEFAULT_EXTERNALS } from \"./defaults.js\";\n\nconst gzipAsync = promisify(zlib.gzip);\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n\treturn str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport type ParsedPackage = {\n\tname: string;\n\tversion: string;\n\tsubpath?: string;\n};\n\n/**\n * Parse a package specifier to extract name, version, and subpath.\n * Handles:\n * - @scope/package@1.0.0\n * - @scope/package/subpath@1.0.0\n * - @scope/package/subpath\n * - package/subpath@1.0.0\n */\nexport function parsePackageSpecifier(specifier: string): ParsedPackage {\n\tlet workingSpec = specifier;\n\tlet version = \"latest\";\n\n\t// Handle scoped packages (@scope/name...)\n\tif (workingSpec.startsWith(\"@\")) {\n\t\t// Find the second @ which would separate version.\n\t\tconst secondAtIndex = workingSpec.indexOf(\"@\", 1);\n\t\tif (secondAtIndex !== -1) {\n\t\t\tversion = workingSpec.substring(secondAtIndex + 1);\n\t\t\tworkingSpec = workingSpec.substring(0, secondAtIndex);\n\t\t}\n\n\t\t/**\n\t\t * Now workingSpec is like @scope/name or @scope/name/subpath Split by / and\n\t\t * check if there are more than 2 parts.\n\t\t */\n\t\tconst parts = workingSpec.split(\"/\");\n\t\tif (parts.length > 2) {\n\t\t\t// Has subpath: @scope/name/subpath/more.\n\t\t\tconst name = `${parts[0]}/${parts[1]}`;\n\t\t\tconst subpath = parts.slice(2).join(\"/\");\n\t\t\treturn { name, version, subpath };\n\t\t}\n\t\t// No subpath: @scope/name.\n\t\treturn { name: workingSpec, version };\n\t}\n\n\t// Handle non-scoped packages (name@version or name/subpath@version).\n\tconst atIndex = workingSpec.indexOf(\"@\");\n\tif (atIndex !== -1) {\n\t\tversion = workingSpec.substring(atIndex + 1);\n\t\tworkingSpec = workingSpec.substring(0, atIndex);\n\t}\n\n\t// Check for subpath in non-scoped packages.\n\tconst slashIndex = workingSpec.indexOf(\"/\");\n\tif (slashIndex !== -1) {\n\t\tconst name = workingSpec.substring(0, slashIndex);\n\t\tconst subpath = workingSpec.substring(slashIndex + 1);\n\t\treturn { name, version, subpath };\n\t}\n\n\treturn { name: workingSpec, version };\n}\n\nexport type BundleOptions = {\n\tpackageName: string;\n\texports?: string[];\n\tadditionalExternals?: string[];\n\tnoExternal?: boolean;\n\tgzipLevel?: number;\n\tregistry?: string;\n\t/**\n\t * Target platform. If undefined, auto-detects from package.json engines.\n\t */\n\tplatform?: \"browser\" | \"node\";\n};\n\nexport type BundleResult = {\n\tpackageName: string;\n\tpackageVersion: string;\n\texports: string[];\n\trawSize: number;\n\t/**\n\t * Gzip size in bytes, or null for node platform (gzip not applicable).\n\t */\n\tgzipSize: number | null;\n\tgzipLevel: number;\n\texternals: string[];\n\tdependencies: string[];\n\tplatform: \"browser\" | \"node\";\n};\n\n/**\n * Format bytes to human-readable string.\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) {\n\t\treturn \"0 B\";\n\t}\n\tconst k = 1024;\n\tconst sizes = [\"B\", \"kB\", \"MB\", \"GB\"];\n\tconst i = Math.floor(Math.log(bytes) / Math.log(k));\n\treturn `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;\n}\n\n/**\n * Create a temporary directory for bundling.\n */\nfunction createTempDir(): string {\n\tconst tmpDir = path.join(os.tmpdir(), `bundlecheck-${Date.now()}`);\n\tfs.mkdirSync(tmpDir, { recursive: true });\n\treturn tmpDir;\n}\n\n/**\n * Clean up temporary directory.\n */\nfunction cleanupTempDir(tmpDir: string): void {\n\ttry {\n\t\tfs.rmSync(tmpDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Ignore cleanup errors.\n\t}\n}\n\n/**\n * Check if pnpm is available.\n */\nfunction isPnpmAvailable(): boolean {\n\ttry {\n\t\texecSync(\"pnpm --version\", { stdio: \"pipe\" });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Cache the result of pnpm availability check.\nlet usePnpm: boolean | null = null;\n\n/**\n * Validate and sanitize a registry URL to prevent command injection.\n * @param registry - The registry URL to validate\n * @returns The sanitized URL or undefined if invalid\n * @throws Error if the URL is invalid or contains potentially malicious characters\n */\nfunction validateRegistryUrl(registry: string): string {\n\t// Parse as URL to validate format.\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(registry);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL: ${registry}. Must be a valid URL (e.g., https://registry.example.com)`,\n\t\t);\n\t}\n\n\t// Only allow http and https protocols.\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new Error(\n\t\t\t`Invalid registry URL protocol: ${url.protocol}. Only http: and https: are allowed`,\n\t\t);\n\t}\n\n\t// Return the sanitized URL (URL constructor normalizes it).\n\treturn url.toString();\n}\n\n/**\n * Get the install command (pnpm preferred, npm fallback).\n * @param registry - Optional custom npm registry URL\n */\nfunction getInstallCommand(registry?: string): string {\n\tif (usePnpm === null) {\n\t\tusePnpm = isPnpmAvailable();\n\t}\n\n\tlet registryArg = \"\";\n\tif (registry) {\n\t\t// Validate and sanitize the registry URL to prevent command injection.\n\t\tconst sanitizedRegistry = validateRegistryUrl(registry);\n\t\t// Quote the URL to handle any special characters safely.\n\t\tregistryArg = ` --registry \"${sanitizedRegistry}\"`;\n\t}\n\n\tif (usePnpm) {\n\t\treturn `pnpm install --ignore-scripts --no-frozen-lockfile${registryArg}`;\n\t}\n\treturn `npm install --legacy-peer-deps --ignore-scripts${registryArg}`;\n}\n\nexport type EntryContentOptions = {\n\tpackageName: string;\n\tsubpath?: string;\n\texports?: string[];\n\tallSubpaths?: string[];\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Generate the entry file content based on package, subpath, and exports.\n */\nfunction generateEntryContent(options: EntryContentOptions): string {\n\tconst { packageName, subpath, exports, allSubpaths, exportToSubpath } =\n\t\toptions;\n\n\t// If we have exports mapped to different subpaths.\n\tif (exportToSubpath && exportToSubpath.size > 0) {\n\t\t// Group exports by subpath.\n\t\tconst subpathToExports = new Map<string, string[]>();\n\t\tfor (const [exportName, sp] of exportToSubpath) {\n\t\t\tconst existing = subpathToExports.get(sp) || [];\n\t\t\texisting.push(exportName);\n\t\t\tsubpathToExports.set(sp, existing);\n\t\t}\n\n\t\t// Generate imports for each subpath.\n\t\tconst lines: string[] = [];\n\t\tconst allExportNames: string[] = [];\n\n\t\tfor (const [sp, exportNames] of subpathToExports) {\n\t\t\tconst importPath = `${packageName}/${sp}`;\n\t\t\tconst names = exportNames.join(\", \");\n\t\t\tlines.push(`import { ${names} } from \"${importPath}\";`);\n\t\t\tallExportNames.push(...exportNames);\n\t\t}\n\n\t\tlines.push(`export { ${allExportNames.join(\", \")} };`);\n\t\treturn lines.join(\"\\n\") + \"\\n\";\n\t}\n\n\t// If we have specific exports to import.\n\tif (exports && exports.length > 0) {\n\t\t// Determine the import path.\n\t\tconst importPath = subpath ? `${packageName}/${subpath}` : packageName;\n\t\tconst importNames = exports.join(\", \");\n\t\treturn `import { ${importNames} } from \"${importPath}\";\\nexport { ${importNames} };\\n`;\n\t}\n\n\t// If we have a specific subpath (but no specific exports).\n\tif (subpath) {\n\t\tconst importPath = `${packageName}/${subpath}`;\n\t\treturn `import * as pkg from \"${importPath}\";\\nexport default pkg;\\n`;\n\t}\n\n\t// If package has subpath exports only (no main entry), import all subpaths.\n\tif (allSubpaths && allSubpaths.length > 0) {\n\t\tconst imports = allSubpaths\n\t\t\t.map(\n\t\t\t\t(sp, i) =>\n\t\t\t\t\t`import * as sub${i} from \"${packageName}/${sp}\";\\nexport { sub${i} };`,\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t\treturn imports + \"\\n\";\n\t}\n\n\t// Default: import everything from main entry.\n\treturn `import * as pkg from \"${packageName}\";\\nexport default pkg;\\n`;\n}\n\n/**\n * Get externals list based on options.\n */\nexport function getExternals(\n\tpackageName: string,\n\texternals?: string[],\n\tnoExternal?: boolean,\n): string[] {\n\tif (noExternal) {\n\t\treturn [];\n\t}\n\n\t// Start with default externals (react, react-dom).\n\tlet result = [...DEFAULT_EXTERNALS];\n\n\t// If checking react or react-dom themselves, don't mark them as external.\n\tif (packageName === \"react\") {\n\t\tresult = result.filter((e) => e !== \"react\");\n\t} else if (packageName === \"react-dom\") {\n\t\tresult = result.filter((e) => e !== \"react-dom\");\n\t}\n\n\t// Add any additional externals.\n\tif (externals && externals.length > 0) {\n\t\tresult = [...new Set([...result, ...externals])];\n\t}\n\n\treturn result;\n}\n\nexport type PackageExports = Record<\n\tstring,\n\tstring | { import?: string; types?: string }\n>;\n\nexport type PackageInfo = {\n\tversion: string;\n\tdependencies: Record<string, string>;\n\tpeerDependencies: Record<string, string>;\n\texports: PackageExports | null;\n\thasMainEntry: boolean;\n\tengines: Record<string, string> | null;\n};\n\n/**\n * Get version, dependencies, peer dependencies, and exports from an installed\n * package.\n */\nfunction getPackageInfo(tmpDir: string, packageName: string): PackageInfo {\n\ttry {\n\t\t// Handle scoped packages - the package name in node_modules.\n\t\tconst pkgJsonPath = path.join(\n\t\t\ttmpDir,\n\t\t\t\"node_modules\",\n\t\t\tpackageName,\n\t\t\t\"package.json\",\n\t\t);\n\t\tif (fs.existsSync(pkgJsonPath)) {\n\t\t\tconst pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf-8\"));\n\n\t\t\t// Check if package has a main entry point.\n\t\t\tconst hasMainEntry = Boolean(\n\t\t\t\tpkgJson.main ||\n\t\t\t\t\tpkgJson.module ||\n\t\t\t\t\tpkgJson.exports?.[\".\"] ||\n\t\t\t\t\tpkgJson.exports?.[\"./index\"] ||\n\t\t\t\t\t(!pkgJson.exports && !pkgJson.main && !pkgJson.module),\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tversion: pkgJson.version || \"unknown\",\n\t\t\t\tdependencies: pkgJson.dependencies || {},\n\t\t\t\tpeerDependencies: pkgJson.peerDependencies || {},\n\t\t\t\texports: pkgJson.exports || null,\n\t\t\t\thasMainEntry,\n\t\t\t\tengines: pkgJson.engines || null,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// Ignore errors reading package info.\n\t}\n\treturn {\n\t\tversion: \"unknown\",\n\t\tdependencies: {},\n\t\tpeerDependencies: {},\n\t\texports: null,\n\t\thasMainEntry: true,\n\t\tengines: null,\n\t};\n}\n\n/**\n * Extract subpath export names from package exports field Returns array of\n * subpaths like [\"header\", \"body\", \"datagrid\"].\n */\nfunction getSubpathExports(exports: PackageExports | null): string[] {\n\tif (!exports) {\n\t\treturn [];\n\t}\n\n\tconst subpaths: string[] = [];\n\tfor (const key of Object.keys(exports)) {\n\t\t// Skip the main entry point and package.json.\n\t\tif (key === \".\" || key === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\t\t// Remove leading \"./\" to get subpath name.\n\t\tif (key.startsWith(\"./\")) {\n\t\t\tsubpaths.push(key.substring(2));\n\t\t}\n\t}\n\treturn subpaths;\n}\n\n/**\n * Result of finding subpaths for exports.\n */\ntype SubpathMapping = {\n\t// Single subpath if all exports are from the same subpath.\n\tsingleSubpath?: string;\n\t// Map of export name to subpath for multiple subpaths.\n\texportToSubpath?: Map<string, string>;\n};\n\n/**\n * Find which subpath(s) export the given component names Reads type definition\n * files or JS files to find the exports.\n */\nfunction findSubpathsForExports(\n\ttmpDir: string,\n\tpackageName: string,\n\texports: PackageExports,\n\tcomponentNames: string[],\n): SubpathMapping {\n\tconst packageDir = path.join(tmpDir, \"node_modules\", packageName);\n\tconst exportToSubpath = new Map<string, string>();\n\n\tfor (const [subpathKey, subpathValue] of Object.entries(exports)) {\n\t\t// Skip main entry and package.json.\n\t\tif (subpathKey === \".\" || subpathKey === \"./package.json\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Get the types or import path.\n\t\tlet filePath: string | undefined;\n\t\tif (typeof subpathValue === \"object\" && subpathValue !== null) {\n\t\t\t// Prefer types file for more accurate export detection.\n\t\t\tfilePath = subpathValue.types || subpathValue.import;\n\t\t} else if (typeof subpathValue === \"string\") {\n\t\t\tfilePath = subpathValue;\n\t\t}\n\n\t\tif (!filePath) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the file path.\n\t\tconst fullPath = path.join(packageDir, filePath);\n\n\t\ttry {\n\t\t\tif (fs.existsSync(fullPath)) {\n\t\t\t\tconst content = fs.readFileSync(fullPath, \"utf-8\");\n\t\t\t\tconst subpath = subpathKey.startsWith(\"./\")\n\t\t\t\t\t? subpathKey.substring(2)\n\t\t\t\t\t: subpathKey;\n\n\t\t\t\t// Check each component name.\n\t\t\t\tfor (const name of componentNames) {\n\t\t\t\t\t// Skip if already found.\n\t\t\t\t\tif (exportToSubpath.has(name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Escape regex special characters in the name to prevent injection.\n\t\t\t\t\tconst escapedName = escapeRegExp(name);\n\n\t\t\t\t\t// Look for various export patterns.\n\t\t\t\t\tconst patterns = [\n\t\t\t\t\t\tnew RegExp(`export\\\\s*\\\\{[^}]*\\\\b${escapedName}\\\\b[^}]*\\\\}`, \"m\"),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+declare\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnew RegExp(\n\t\t\t\t\t\t\t`export\\\\s+(?:const|function|class)\\\\s+${escapedName}\\\\b`,\n\t\t\t\t\t\t\t\"m\",\n\t\t\t\t\t\t),\n\t\t\t\t\t];\n\n\t\t\t\t\tif (patterns.some((pattern) => pattern.test(content))) {\n\t\t\t\t\t\texportToSubpath.set(name, subpath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read errors, continue to next subpath.\n\t\t}\n\t}\n\n\t// Check if all exports were found.\n\tif (exportToSubpath.size !== componentNames.length) {\n\t\treturn {}; // Not all exports found\n\t}\n\n\t// Check if all exports are from the same subpath.\n\tconst subpaths = new Set(exportToSubpath.values());\n\tif (subpaths.size === 1) {\n\t\treturn { singleSubpath: [...subpaths][0] };\n\t}\n\n\t// Multiple subpaths needed.\n\treturn { exportToSubpath };\n}\n\n/**\n * Check the bundle size of an npm package.\n */\nexport async function checkBundleSize(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tpackageName: packageSpecifier,\n\t\texports,\n\t\tadditionalExternals,\n\t\tnoExternal,\n\t\tgzipLevel = 5,\n\t\tregistry,\n\t\tplatform: explicitPlatform,\n\t} = options;\n\n\t// Parse the package specifier to extract name, version, and subpath.\n\tconst {\n\t\tname: packageName,\n\t\tversion: requestedVersion,\n\t\tsubpath,\n\t} = parsePackageSpecifier(packageSpecifier);\n\n\tconst tmpDir = createTempDir();\n\n\ttry {\n\t\t// Create initial package.json.\n\t\tconst packageJson: {\n\t\t\tname: string;\n\t\t\tversion: string;\n\t\t\ttype: string;\n\t\t\tdependencies: Record<string, string>;\n\t\t} = {\n\t\t\tname: \"bundlecheck-temp\",\n\t\t\tversion: \"1.0.0\",\n\t\t\ttype: \"module\",\n\t\t\tdependencies: {\n\t\t\t\t[packageName]: requestedVersion,\n\t\t\t},\n\t\t};\n\n\t\tfs.writeFileSync(\n\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t);\n\n\t\t// Install the main package (try pnpm first, fallback to npm).\n\t\tconst installCmd = getInstallCommand(registry);\n\t\texecSync(installCmd, {\n\t\t\tcwd: tmpDir,\n\t\t\tstdio: \"pipe\",\n\t\t});\n\n\t\t/**\n\t\t * Get package info (version, dependencies, peer dependencies, exports,\n\t\t * engines).\n\t\t */\n\t\tconst pkgInfo = getPackageInfo(tmpDir, packageName);\n\t\tconst peerDepKeys = Object.keys(pkgInfo.peerDependencies);\n\n\t\t/**\n\t\t * Determine platform: use explicit value if provided, otherwise auto-detect\n\t\t * from engines.\n\t\t */\n\t\tlet platform: \"browser\" | \"node\" = \"browser\";\n\t\tif (explicitPlatform) {\n\t\t\tplatform = explicitPlatform;\n\t\t} else if (pkgInfo.engines?.node && !pkgInfo.engines?.browser) {\n\t\t\t// Package specifies node engine without browser - likely a Node.js package.\n\t\t\tplatform = \"node\";\n\t\t}\n\n\t\t// Collect all dependency names (prod + peer).\n\t\tconst allDependencies = [\n\t\t\t...new Set([...Object.keys(pkgInfo.dependencies), ...peerDepKeys]),\n\t\t].sort();\n\n\t\tif (peerDepKeys.length > 0) {\n\t\t\t// Add peer dependencies to package.json.\n\t\t\tfor (const dep of peerDepKeys) {\n\t\t\t\t// Use the version range from peer dependencies.\n\t\t\t\tpackageJson.dependencies[dep] = pkgInfo.peerDependencies[dep];\n\t\t\t}\n\n\t\t\t// Update package.json and reinstall.\n\t\t\tfs.writeFileSync(\n\t\t\t\tpath.join(tmpDir, \"package.json\"),\n\t\t\t\tJSON.stringify(packageJson, null, 2),\n\t\t\t);\n\n\t\t\texecSync(installCmd, {\n\t\t\t\tcwd: tmpDir,\n\t\t\t\tstdio: \"pipe\",\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Determine if we need to use all subpath exports or find the right\n\t\t * subpath(s).\n\t\t */\n\t\tlet allSubpaths: string[] | undefined;\n\t\tlet resolvedSubpath = subpath;\n\t\tlet exportToSubpath: Map<string, string> | undefined;\n\n\t\tif (!subpath && !pkgInfo.hasMainEntry && pkgInfo.exports) {\n\t\t\tif (exports && exports.length > 0) {\n\t\t\t\t// User specified exports but no subpath - try to find the right subpath(s).\n\t\t\t\tconst mapping = findSubpathsForExports(\n\t\t\t\t\ttmpDir,\n\t\t\t\t\tpackageName,\n\t\t\t\t\tpkgInfo.exports,\n\t\t\t\t\texports,\n\t\t\t\t);\n\n\t\t\t\tif (mapping.singleSubpath) {\n\t\t\t\t\t// All exports from the same subpath.\n\t\t\t\t\tresolvedSubpath = mapping.singleSubpath;\n\t\t\t\t} else if (mapping.exportToSubpath) {\n\t\t\t\t\t// Exports from multiple subpaths.\n\t\t\t\t\texportToSubpath = mapping.exportToSubpath;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no subpath resolved and no mapping, bundle all subpaths.\n\t\t\tif (!resolvedSubpath && !exportToSubpath) {\n\t\t\t\tallSubpaths = getSubpathExports(pkgInfo.exports);\n\t\t\t}\n\t\t}\n\n\t\t// Create entry file with appropriate content.\n\t\tconst entryContent = generateEntryContent({\n\t\t\tpackageName,\n\t\t\tsubpath: resolvedSubpath,\n\t\t\texports,\n\t\t\tallSubpaths,\n\t\t\texportToSubpath,\n\t\t});\n\t\tconst entryFile = path.join(tmpDir, \"entry.js\");\n\t\tfs.writeFileSync(entryFile, entryContent);\n\n\t\t// Get externals.\n\t\tconst externals = getExternals(\n\t\t\tpackageName,\n\t\t\tadditionalExternals,\n\t\t\tnoExternal,\n\t\t);\n\n\t\t// Bundle with esbuild.\n\t\tconst result = await esbuild.build({\n\t\t\tentryPoints: [entryFile],\n\t\t\tbundle: true,\n\t\t\twrite: false,\n\t\t\tformat: \"esm\",\n\t\t\tplatform,\n\t\t\ttarget: \"es2020\",\n\t\t\tminify: true,\n\t\t\ttreeShaking: true,\n\t\t\texternal: externals,\n\t\t\tmetafile: true,\n\t\t});\n\n\t\t// Get raw size.\n\t\tconst bundleContent = result.outputFiles[0].contents;\n\t\tconst rawSize = bundleContent.length;\n\n\t\t// Gzip the bundle (only for browser platform - not relevant for Node.js).\n\t\tlet gzipSize: number | null = null;\n\t\tif (platform === \"browser\") {\n\t\t\tconst gzipped = await gzipAsync(Buffer.from(bundleContent), {\n\t\t\t\tlevel: gzipLevel,\n\t\t\t});\n\t\t\tgzipSize = gzipped.length;\n\t\t}\n\n\t\t// Determine the display name.\n\t\tlet displayName = packageName;\n\t\tif (resolvedSubpath) {\n\t\t\tdisplayName = `${packageName}/${resolvedSubpath}`;\n\t\t} else if (exportToSubpath && exportToSubpath.size > 0) {\n\t\t\t// Multiple subpaths - show them all.\n\t\t\tconst uniqueSubpaths = [...new Set(exportToSubpath.values())].sort();\n\t\t\tdisplayName = `${packageName}/{${uniqueSubpaths.join(\", \")}}`;\n\t\t}\n\n\t\treturn {\n\t\t\tpackageName: displayName,\n\t\t\tpackageVersion: pkgInfo.version,\n\t\t\texports: exports || [],\n\t\t\trawSize,\n\t\t\tgzipSize,\n\t\t\tgzipLevel,\n\t\t\texternals,\n\t\t\tdependencies: allDependencies,\n\t\t\tplatform,\n\t\t};\n\t} finally {\n\t\tcleanupTempDir(tmpDir);\n\t}\n}\n"],"names":["execSync","fs","os","path","promisify","zlib","esbuild","DEFAULT_EXTERNALS","gzipAsync","gzip","escapeRegExp","str","replace","parsePackageSpecifier","specifier","workingSpec","version","startsWith","secondAtIndex","indexOf","substring","parts","split","length","name","subpath","slice","join","atIndex","slashIndex","formatBytes","bytes","k","sizes","i","Math","floor","log","Number","parseFloat","toFixed","createTempDir","tmpDir","tmpdir","Date","now","mkdirSync","recursive","cleanupTempDir","rmSync","force","isPnpmAvailable","stdio","usePnpm","validateRegistryUrl","registry","url","URL","Error","protocol","toString","getInstallCommand","registryArg","sanitizedRegistry","generateEntryContent","options","packageName","exports","allSubpaths","exportToSubpath","size","subpathToExports","Map","exportName","sp","existing","get","push","set","lines","allExportNames","exportNames","importPath","names","importNames","imports","map","getExternals","externals","noExternal","result","filter","e","Set","getPackageInfo","pkgJsonPath","existsSync","pkgJson","JSON","parse","readFileSync","hasMainEntry","Boolean","main","module","dependencies","peerDependencies","engines","getSubpathExports","subpaths","key","Object","keys","findSubpathsForExports","componentNames","packageDir","subpathKey","subpathValue","entries","filePath","types","import","fullPath","content","has","escapedName","patterns","RegExp","some","pattern","test","values","singleSubpath","checkBundleSize","packageSpecifier","additionalExternals","gzipLevel","platform","explicitPlatform","requestedVersion","packageJson","type","writeFileSync","stringify","installCmd","cwd","pkgInfo","peerDepKeys","node","browser","allDependencies","sort","dep","resolvedSubpath","mapping","entryContent","entryFile","build","entryPoints","bundle","write","format","target","minify","treeShaking","external","metafile","bundleContent","outputFiles","contents","rawSize","gzipSize","gzipped","Buffer","from","level","displayName","uniqueSubpaths","packageVersion"],"mappings":"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"}
@@ -0,0 +1,62 @@
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
+ /**
8
+ * Platform: "browser", "node", or "auto" (for auto-detection).
9
+ */
10
+ platform: "browser" | "node" | "auto";
11
+ gzipLevel: number;
12
+ externals: string;
13
+ noExternal: number;
14
+ };
15
+ export type CachedBundleResult = BundleResult;
16
+ /**
17
+ * Initialize the cache database with proper pragmas and schema.
18
+ */
19
+ export declare function initCache(): Database.Database;
20
+ /**
21
+ * Normalize cache key options to a consistent format Sorts exports and
22
+ * externals to ensure consistent cache hits.
23
+ *
24
+ * NOTE: platform can be "browser", "node", or "auto" (when user doesn't specify).
25
+ * Using "auto" in the cache key ensures that auto-detected results are cached
26
+ * separately from explicitly specified platform results.
27
+ *
28
+ */
29
+ export declare function normalizeCacheKey(options: {
30
+ packageName: string;
31
+ version: string;
32
+ exports?: string[];
33
+ /**
34
+ * Platform: "browser", "node", or undefined (treated as "auto").
35
+ */
36
+ platform: "browser" | "node" | undefined;
37
+ gzipLevel: number;
38
+ externals: string[];
39
+ noExternal: boolean;
40
+ }): CacheKey;
41
+ /**
42
+ * Get a cached result if it exists Returns null if not found or if an error
43
+ * occurs (graceful degradation).
44
+ */
45
+ export declare function getCachedResult(key: CacheKey): CachedBundleResult | null;
46
+ /**
47
+ * Store a result in the cache Silently fails on errors (graceful degradation -
48
+ * CLI continues without caching).
49
+ */
50
+ export declare function setCachedResult(key: CacheKey, result: BundleResult): void;
51
+ /**
52
+ * Clear all cache entries Silently fails on errors.
53
+ */
54
+ export declare function clearCache(): void;
55
+ /**
56
+ * Get the number of cached entries Returns 0 on error.
57
+ */
58
+ export declare function getCacheCount(): number;
59
+ /**
60
+ * Close the database connection (useful for testing).
61
+ */
62
+ export declare function closeCache(): void;
package/dist/cache.js ADDED
@@ -0,0 +1,196 @@
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 = 1000;
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 Sorts exports and
59
+ * 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
+ *
65
+ */ export function normalizeCacheKey(options) {
66
+ return {
67
+ packageName: options.packageName,
68
+ version: options.version,
69
+ exports: (options.exports || []).slice().sort().join(","),
70
+ /**
71
+ * Use "auto" when platform is undefined to distinguish from explicit
72
+ * platform.
73
+ */ platform: options.platform ?? "auto",
74
+ gzipLevel: options.gzipLevel,
75
+ externals: options.externals.slice().sort().join(","),
76
+ noExternal: options.noExternal ? 1 : 0
77
+ };
78
+ }
79
+ /**
80
+ * Get a cached result if it exists Returns null if not found or if an error
81
+ * occurs (graceful degradation).
82
+ */ export function getCachedResult(key) {
83
+ try {
84
+ const database = initCache();
85
+ const stmt = database.prepare(`
86
+ SELECT * FROM bundle_cache
87
+ WHERE package_name = ?
88
+ AND version = ?
89
+ AND exports = ?
90
+ AND platform = ?
91
+ AND gzip_level = ?
92
+ AND externals = ?
93
+ AND no_external = ?
94
+ `);
95
+ const row = stmt.get(key.packageName, key.version, key.exports, key.platform, key.gzipLevel, key.externals, key.noExternal);
96
+ if (!row) {
97
+ return null;
98
+ }
99
+ // Parse dependencies with error handling for corrupted data.
100
+ let dependencies = [];
101
+ try {
102
+ dependencies = JSON.parse(row.dependencies);
103
+ } catch {
104
+ // If JSON is corrupted, use empty array.
105
+ dependencies = [];
106
+ }
107
+ // Convert row to BundleResult.
108
+ return {
109
+ packageName: row.display_name,
110
+ packageVersion: row.version,
111
+ exports: row.exports ? row.exports.split(",").filter(Boolean) : [],
112
+ rawSize: row.raw_size,
113
+ gzipSize: row.gzip_size,
114
+ gzipLevel: row.gzip_level,
115
+ externals: row.externals ? row.externals.split(",").filter(Boolean) : [],
116
+ dependencies,
117
+ platform: row.platform
118
+ };
119
+ } catch {
120
+ /**
121
+ * On any database error, return null (graceful degradation - continue without
122
+ * cache).
123
+ */ return null;
124
+ }
125
+ }
126
+ /**
127
+ * Store a result in the cache Silently fails on errors (graceful degradation -
128
+ * CLI continues without caching).
129
+ */ export function setCachedResult(key, result) {
130
+ try {
131
+ const database = initCache();
132
+ /**
133
+ * Use INSERT OR REPLACE to handle duplicates.
134
+ * NOTE: This updates created_at on replace, making this LRU-style eviction.
135
+ */ const stmt = database.prepare(`
136
+ INSERT OR REPLACE INTO bundle_cache (
137
+ package_name, version, exports, platform, gzip_level, externals, no_external,
138
+ raw_size, gzip_size, dependencies, display_name, created_at
139
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
140
+ `);
141
+ 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());
142
+ // Enforce max entries (LRU-style eviction based on created_at).
143
+ enforceMaxEntries(database);
144
+ } catch {
145
+ // On any database error, silently continue (graceful degradation).
146
+ }
147
+ }
148
+ /**
149
+ * Enforce maximum cache entries by removing entries with oldest timestamps Uses
150
+ * LRU-style eviction: entries that are re-checked get updated timestamps and
151
+ * move to the end of the eviction queue.
152
+ */ function enforceMaxEntries(database) {
153
+ const countResult = database.prepare("SELECT COUNT(*) as count FROM bundle_cache").get();
154
+ if (countResult.count > MAX_CACHE_ENTRIES) {
155
+ const toDelete = countResult.count - MAX_CACHE_ENTRIES;
156
+ database.prepare(`
157
+ DELETE FROM bundle_cache
158
+ WHERE id IN (
159
+ SELECT id FROM bundle_cache
160
+ ORDER BY created_at ASC
161
+ LIMIT ?
162
+ )
163
+ `).run(toDelete);
164
+ }
165
+ }
166
+ /**
167
+ * Clear all cache entries Silently fails on errors.
168
+ */ export function clearCache() {
169
+ try {
170
+ const database = initCache();
171
+ database.prepare("DELETE FROM bundle_cache").run();
172
+ } catch {
173
+ // Silently ignore errors.
174
+ }
175
+ }
176
+ /**
177
+ * Get the number of cached entries Returns 0 on error.
178
+ */ export function getCacheCount() {
179
+ try {
180
+ const database = initCache();
181
+ const result = database.prepare("SELECT COUNT(*) as count FROM bundle_cache").get();
182
+ return result.count;
183
+ } catch {
184
+ return 0;
185
+ }
186
+ }
187
+ /**
188
+ * Close the database connection (useful for testing).
189
+ */ export function closeCache() {
190
+ if (db) {
191
+ db.close();
192
+ db = null;
193
+ }
194
+ }
195
+
196
+ //# 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 = 1000;\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/**\n\t * Platform: \"browser\", \"node\", or \"auto\" (for auto-detection).\n\t */\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 Sorts exports and\n * 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 *\n */\nexport function normalizeCacheKey(options: {\n\tpackageName: string;\n\tversion: string;\n\texports?: string[];\n\t/**\n\t * Platform: \"browser\", \"node\", or undefined (treated as \"auto\").\n\t */\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/**\n\t\t * Use \"auto\" when platform is undefined to distinguish from explicit\n\t\t * platform.\n\t\t */\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 Returns null if not found or if an error\n * 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/**\n\t\t * On any database error, return null (graceful degradation - continue without\n\t\t * cache).\n\t\t */\n\t\treturn null;\n\t}\n}\n\n/**\n * Store a result in the cache Silently fails on errors (graceful degradation -\n * CLI continues without caching).\n */\nexport function setCachedResult(key: CacheKey, result: BundleResult): void {\n\ttry {\n\t\tconst database = initCache();\n\n\t\t/**\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\t */\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 Uses\n * LRU-style eviction: entries that are re-checked get updated timestamps and\n * 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 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 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,yCAAyC;IACzC,IAAIF,eAAe,QAAQ;QAC1B,OAAOD;IACR;IAEA,gBAAgB;IAChB,IAAI;QAAC;QAAQ;QAAU;QAAU;KAAU,CAACI,QAAQ,CAACH,aAAa;QACjE,OAAO;IACR;IAEA,mBAAmB;IACnB,IAAI;QAAC;QAAW;QAAO;QAAW;KAAS,CAACG,QAAQ,CAACH,aAAa;QACjE,OAAO;IACR;IAEA,gDAAgD;IAChD,OAAOA;AACR;AAEA;;CAEC,GACD,OAAO,SAASI,gBAAgBR,QAA4B;IAC3D,IAAIA,aAAaG,WAAW;QAC3B,OAAO;IACR;IAEA,MAAMC,aAAaJ,SAASK,WAAW,GAAGC,IAAI;IAE9C,sCAAsC;IACtC,IAAIF,eAAe,IAAI;QACtB,OAAO;IACR;IACA,MAAMK,cAAc;QACnB,eAAe;QACf;QACA,WAAW;QACX;QACA;QACA;QACA;QACA,QAAQ;QACR;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
@@ -2,9 +2,4 @@
2
2
  * @file Automatically generated by barrelsby.
3
3
  */
4
4
 
5
- export * from "./bundlecheck";
6
- export * from "./bundler";
7
- export * from "./defaults";
8
- export * from "./parse";
9
- export * from "./trend";
10
- export * from "./versions";
5
+ export * from "./index";