Files
dev/scripts/upgrade-spinners.js
T

83 lines
3.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
/*
Upgrade code-rs/tui/assets/spinners.json to include human labels and groups.
Usage:
node scripts/upgrade-spinners.js # writes in place
node scripts/upgrade-spinners.js --dry-run # prints a summary only
*/
const fs = require('fs');
const path = require('path');
const file = path.join(__dirname, '..', 'code-rs', 'tui', 'assets', 'spinners.json');
function humanize(name) {
// camelCase / kebab-case / snake_case → Title Case with digits spaced
let out = '';
let prevLower = false;
let prevAlpha = false;
for (const ch of name) {
if (ch === '-' || ch === '_') { out += ' '; prevLower = false; prevAlpha = false; continue; }
if (/[A-Z]/.test(ch) && prevLower) out += ' ';
else if (/[0-9]/.test(ch) && prevAlpha) out += ' ';
out += ch;
prevLower = /[a-z]/.test(ch);
prevAlpha = /[a-zA-Z]/.test(ch);
}
return out.split(/\s+/).filter(Boolean).map(w => w[0].toUpperCase() + w.slice(1).toLowerCase()).join(' ');
}
function groupFor(name) {
const key = name.toLowerCase();
if (key.includes('dot')) return 'Dots';
if (key.includes('circle') || key.includes('round') || key.includes('arc')) return 'Circles';
if (key.includes('line') || key.includes('pipe') || key.includes('bar') || key.includes('pulse')) return 'Lines';
if (key.includes('bounce') || key.includes('ball') || key.includes('pong')) return 'Bouncing';
if (key.includes('star') || key.includes('asterisk')) return 'Stars';
if (key.includes('arrow') || key.includes('triangle')) return 'Arrows';
if (key.includes('box') || key.includes('square')) return 'Boxes';
if (key.includes('toggle')) return 'Toggles';
if (key.includes('monkey') || key.includes('earth') || key.includes('moon') || key.includes('weather') || key.includes('smiley') || key.includes('emoji')) return 'Emoji';
return 'Other';
}
function main() {
const dryRun = process.argv.includes('--dry-run');
const text = fs.readFileSync(file, 'utf8');
const data = JSON.parse(text);
let updated = 0, total = 0;
// If already grouped (outer values lack `interval`), normalize labels and return
const firstVal = Object.values(data)[0];
const alreadyGrouped = firstVal && typeof firstVal === 'object' && !('interval' in firstVal);
const out = {};
if (alreadyGrouped) {
for (const [group, inner] of Object.entries(data)) {
out[group] = {};
for (const [name, v] of Object.entries(inner)) {
total++;
const hasLabel = v && typeof v === 'object' && 'label' in v;
const label = hasLabel ? v.label : humanize(name);
if (!hasLabel) updated++;
out[group][name] = { interval: v.interval, frames: v.frames, label };
}
}
} else {
// Flat → Grouped
for (const [name, v] of Object.entries(data)) {
total++;
const label = v && typeof v === 'object' && 'label' in v ? v.label : humanize(name);
const group = v && typeof v === 'object' && 'group' in v ? v.group : groupFor(name);
if (!('label' in v) || !('group' in v)) updated++;
if (!out[group]) out[group] = {};
out[group][name] = { interval: v.interval, frames: v.frames, label };
}
}
if (dryRun) {
console.log(`Would update ${updated}/${total} entries (labels/groups).`);
return;
}
fs.writeFileSync(file, JSON.stringify(out, null, 2) + '\n');
console.log(`Updated ${updated}/${total} entries. Wrote ${path.relative(process.cwd(), file)}`);
}
if (require.main === module) main();