Move Commander basic-land checks and deck aggregate metrics into lib/deck-builder-stats.js with unit tests; render the summary row via DeckBuilderStatsBar to shrink the page god-component. Co-authored-by: Cursor <cursoragent@cursor.com>
47 lines
1.4 KiB
JavaScript
47 lines
1.4 KiB
JavaScript
/** Basic land names for Commander singleton rule checks. */
|
|
export const BASIC_LAND_NAMES = ['Plains', 'Island', 'Swamp', 'Mountain', 'Forest'];
|
|
|
|
export function isBasicLand(card) {
|
|
return BASIC_LAND_NAMES.includes(card.name);
|
|
}
|
|
|
|
/**
|
|
* Aggregate deck list metrics from deck card rows (quantity-weighted).
|
|
* @param {Array<{ quantity: number, cmc?: number, colors?: string, card_type?: string }>} deckCards
|
|
*/
|
|
export function computeDeckStats(deckCards) {
|
|
const totalCards = deckCards.reduce((sum, card) => sum + card.quantity, 0);
|
|
const avgCmc =
|
|
deckCards.length > 0
|
|
? (
|
|
deckCards.reduce((sum, card) => sum + (card.cmc || 0) * card.quantity, 0) /
|
|
totalCards
|
|
).toFixed(1)
|
|
: 0;
|
|
|
|
const colorCounts = deckCards.reduce((counts, card) => {
|
|
if (card.colors) {
|
|
try {
|
|
const colors = JSON.parse(card.colors);
|
|
colors.forEach((color) => {
|
|
counts[color] = (counts[color] || 0) + card.quantity;
|
|
});
|
|
} catch {
|
|
// Handle non-JSON color format
|
|
}
|
|
}
|
|
return counts;
|
|
}, {});
|
|
|
|
const typeCounts = deckCards.reduce((counts, card) => {
|
|
if (card.card_type) {
|
|
const types = card.card_type.split(' — ')[0].split(' ');
|
|
types.forEach((type) => {
|
|
counts[type] = (counts[type] || 0) + card.quantity;
|
|
});
|
|
}
|
|
return counts;
|
|
}, {});
|
|
|
|
return { totalCards, avgCmc, colorCounts, typeCounts };
|
|
}
|