|
1 | | -console.log('Test!'); |
| 1 | +import { stat, readdir } from 'node:fs/promises'; |
| 2 | +import path from 'node:path'; |
| 3 | +import { fileURLToPath } from 'node:url'; |
| 4 | + |
| 5 | +const [BASE, HEAD] = ['BASE', 'HEAD'].map(env => |
| 6 | + fileURLToPath(import.meta.resolve(`../../out/${process.env[env] ?? './'}`)) |
| 7 | +); |
| 8 | + |
| 9 | +/** |
| 10 | + * Formats bytes into human-readable format |
| 11 | + * @param {number} bytes - Number of bytes |
| 12 | + * @returns {string} Formatted string (e.g., "1.50 KB") |
| 13 | + */ |
| 14 | +const formatBytes = bytes => { |
| 15 | + if (!bytes) { |
| 16 | + return '0 B'; |
| 17 | + } |
| 18 | + |
| 19 | + const units = ['B', 'KB', 'MB', 'GB']; |
| 20 | + const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(1024)); |
| 21 | + |
| 22 | + return `${(bytes / 1024 ** i).toFixed(2)} ${units[i]}`; |
| 23 | +}; |
| 24 | + |
| 25 | +/** |
| 26 | + * Formats the difference between base and head sizes |
| 27 | + * @param {number} base - Base file size in bytes |
| 28 | + * @param {number} head - Head file size in bytes |
| 29 | + * @returns {string} Formatted diff string (e.g., "+1.50 KB (+10.00%)") |
| 30 | + */ |
| 31 | +const formatDiff = (base, head) => { |
| 32 | + const diff = head - base; |
| 33 | + const pct = base ? `${((diff / base) * 100).toFixed(2)}%` : 'N/A'; |
| 34 | + const sign = diff > 0 ? '+' : diff < 0 ? '' : ''; |
| 35 | + |
| 36 | + return `${sign}${formatBytes(diff)} (${sign}${pct})`; |
| 37 | +}; |
| 38 | + |
| 39 | +/** |
| 40 | + * Gets all files in a directory with their stats |
| 41 | + * @param {string} dir - Directory path to search |
| 42 | + * @returns {Promise<Map<string, number>>} Map of filename to size |
| 43 | + */ |
| 44 | +const getDirectoryStats = async dir => { |
| 45 | + const entries = await readdir(dir); |
| 46 | + const stats = await Promise.all( |
| 47 | + entries.map(async file => [file, (await stat(path.join(dir, file))).size]) |
| 48 | + ); |
| 49 | + |
| 50 | + return new Map(stats); |
| 51 | +}; |
| 52 | + |
| 53 | +/** |
| 54 | + * Gets the base name of a file (without extension) |
| 55 | + * @param {string} file - Filename |
| 56 | + * @returns {string} Base name |
| 57 | + */ |
| 58 | +const getBaseName = file => file.replace(/\.[^. ]+$/, ''); |
| 59 | + |
| 60 | +const [baseStats, headStats] = await Promise.all( |
| 61 | + [BASE, HEAD].map(getDirectoryStats) |
| 62 | +); |
| 63 | + |
| 64 | +const allFiles = new Set([...baseStats.keys(), ...headStats.keys()]); |
| 65 | + |
| 66 | +// Count occurrences of each base name to identify paired files |
| 67 | +const baseNameCounts = new Map(); |
| 68 | +for (const file of allFiles) { |
| 69 | + const name = getBaseName(file); |
| 70 | + baseNameCounts.set(name, (baseNameCounts.get(name) || 0) + 1); |
| 71 | +} |
| 72 | + |
| 73 | +// Find and sort changed files: non-paired first (alphabetically), then paired (alphabetically) |
| 74 | +const changedFiles = [...allFiles] |
| 75 | + // .filter(file => baseStats.get(file) !== headStats.get(file)) |
| 76 | + .sort((a, b) => { |
| 77 | + const aPaired = baseNameCounts.get(getBaseName(a)) > 1; |
| 78 | + const bPaired = baseNameCounts.get(getBaseName(b)) > 1; |
| 79 | + return aPaired === bPaired ? a.localeCompare(b) : aPaired - bPaired; |
| 80 | + }); |
| 81 | + |
| 82 | +if (changedFiles.length) { |
| 83 | + const rows = changedFiles.map(file => { |
| 84 | + const baseSize = baseStats.get(file); |
| 85 | + const headSize = headStats.get(file); |
| 86 | + |
| 87 | + if (baseSize === undefined) { |
| 88 | + return `| \`${file}\` | - | ${formatBytes(headSize)} | Added |`; |
| 89 | + } |
| 90 | + |
| 91 | + if (headSize === undefined) { |
| 92 | + return `| \`${file}\` | ${formatBytes(baseSize)} | - | Removed |`; |
| 93 | + } |
| 94 | + |
| 95 | + return `| \`${file}\` | ${formatBytes(baseSize)} | ${formatBytes(headSize)} | ${formatDiff(baseSize, headSize)} |`; |
| 96 | + }); |
| 97 | + |
| 98 | + console.log( |
| 99 | + ` |
| 100 | +## Web Generator |
| 101 | +
|
| 102 | +| File | Base | Head | Diff | |
| 103 | +|------|------|------|------| |
| 104 | +${rows.join('\n')} |
| 105 | +`.trim() |
| 106 | + ); |
| 107 | +} |
0 commit comments