lib/placeholders.ts
3.8 KB · sha256:1d347020ecd77004da13e7ebca747860c40a88b56984281927cc1d0fbe25613e
/**
* Player-friendly labels for PAPI placeholder names. Used wherever a
* requirement expression is shown to a normal player -- the rank menu
* lore, `/nextrank` output, failure messages -- so they see "Money"
* instead of `{vault_eco_balance}`.
*
* Lookup is case-insensitive; the canonical key is the lowercase
* placeholder name (without the surrounding braces). Server owners
* extending this table should target the EXACT placeholder string
* after the expansion's identifier prefix, e.g. PAPI's
* `%vault_eco_balance%` lands here as `vault_eco_balance`.
*
* If a placeholder isn't in the table, [placeholderFriendly] falls
* back to a snake_case -> Title Case transform: `playtime_hours`
* becomes "Playtime Hours". That handles the long tail without
* exploding the table.
*/
const FRIENDLY: Record<string, string> = {
// ---- Vault economy
vault_eco_balance: "Money",
vault_eco_balance_fixed: "Money",
vault_eco_balance_formatted: "Money",
vault_balance: "Money",
vault_balance_formatted: "Money",
vault_currency_symbol: "Currency Symbol",
// ---- Vanilla / player stats
player_health: "Health",
player_max_health: "Max Health",
player_food_level: "Hunger",
player_saturation: "Saturation",
player_level: "XP Level",
player_exp: "XP",
player_exp_to_level: "XP to next level",
player_total_exp: "Total XP",
player_ping: "Ping",
player_name: "Name",
player_displayname: "Display Name",
player_world: "World",
player_gamemode: "Gamemode",
player_x: "X",
player_y: "Y",
player_z: "Z",
player_uuid: "UUID",
player_first_played: "First Joined",
player_last_played: "Last Played",
player_has_played_before: "Returning Player",
// ---- Server
server_online: "Players Online",
server_max_players: "Max Players",
server_tps: "TPS",
server_uptime: "Uptime",
// ---- Statistic expansion (PAPI's `statistic_*`)
statistic_mine_block_diamond_ore: "Diamond Ore Mined",
statistic_mine_block_iron_ore: "Iron Ore Mined",
statistic_mine_block_gold_ore: "Gold Ore Mined",
statistic_mine_block_emerald_ore: "Emerald Ore Mined",
statistic_play_one_minute: "Playtime (minutes)",
statistic_time_since_death: "Time Since Death",
statistic_deaths: "Deaths",
statistic_mob_kills: "Mob Kills",
statistic_player_kills: "Player Kills",
statistic_jump: "Jumps",
statistic_walk_one_cm: "Distance Walked (cm)",
// ---- Playtime expansion
playtime_hours: "Playtime (hours)",
playtime_minutes: "Playtime (minutes)",
playtime_seconds: "Playtime (seconds)",
playtime_days: "Playtime (days)",
playtime_player_hours: "Playtime (hours)",
// ---- Ward (our own)
ward_group: "Group",
ward_prefix: "Prefix",
ward_suffix: "Suffix",
ward_groups: "Groups",
ward_track: "Track",
ward_track_rung: "Track Position",
};
function snakeToTitle(name: string): string {
return name
.split(/[_\-\.]/g)
.filter((p) => p.length > 0)
.map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())
.join(" ");
}
/**
* Friendly label for a single placeholder name (no braces).
* Case-insensitive lookup; falls back to snake_case -> Title Case.
*/
export function placeholderFriendly(name: string): string {
const lower = name.toLowerCase();
return FRIENDLY[lower] ?? snakeToTitle(lower);
}
/**
* Rewrites a requirement expression to swap every `{placeholder}` token
* for its friendly label. Operators, literals, parentheses are left
* untouched, so `{vault_eco_balance} >= 500` becomes `Money >= 500`.
*
* Used by anything player-visible: rank menu lore, /nextrank output,
* blocked-promote chat messages. Admin-facing surfaces (web dashboard,
* /ward track ...) keep the raw expression so server owners can copy/edit.
*/
export function expressionFriendly(expr: string): string {
return expr.replace(/\{([^}]+)\}/g, (_, name) => placeholderFriendly(String(name).trim()));
}