Skip to content

Commit

Permalink
feat(decklists): add main and side counts
Browse files Browse the repository at this point in the history
  • Loading branch information
angrybacon committed Feb 19, 2022
1 parent 7ec2671 commit 223cb0b
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 35 deletions.
10 changes: 7 additions & 3 deletions src/components/Decklist/Decklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ export interface Props {
colors: string[] | null;
date?: string;
main: Card[][];
side?: Card[];
mainCount: number;
side: Card[];
sideCount: number;
title: string;
}

export const Decklist: FunctionComponent<Props> = ({
authors,
colors,
main,
mainCount,
date,
side,
sideCount,
title,
}) => {
const classes = useStyles();
Expand Down Expand Up @@ -78,7 +82,7 @@ export const Decklist: FunctionComponent<Props> = ({
<AccordionDetails className={c(classes.details, classes.gutters)}>
<Box flex={2}>
<Typography color="textSecondary" paragraph variant="caption">
Main
Main {mainCount}
</Typography>
<Box display="flex" flexWrap="wrap">
{main.map((cards, index) => (
Expand All @@ -92,7 +96,7 @@ export const Decklist: FunctionComponent<Props> = ({
{side && (
<Box flex={1}>
<Typography color="textSecondary" paragraph variant="caption">
Sideboard
Sideboard {sideCount}
</Typography>
<Box mb={2}>
<Column cards={side} />
Expand Down
17 changes: 14 additions & 3 deletions src/components/Remark/renderers/RemarkDecklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,27 @@ export interface Props extends ReactMarkdownProps {
}

export const RemarkDecklist: FunctionComponent<Props> = ({ node }) => {
const { authors, colors, date, main, side, title, titleAsFile } =
node.properties;
const {
authors,
colors,
date,
main,
mainCount,
side,
sideCount,
title,
titleAsFile,
} = node.properties;
if (!main) return null;
return (
<Decklist
authors={authors}
colors={colors}
date={date || undefined}
main={main}
side={side?.[0]}
mainCount={mainCount}
side={side[0]}
sideCount={sideCount}
title={title || titleAsFile}
/>
);
Expand Down
22 changes: 13 additions & 9 deletions src/tools/decklists/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const sample = [
describe(parse.name, () => {
beforeEach(() => {
jest.resetAllMocks();
(parseCards as jest.Mock).mockReturnValue({});
(parseHeader as jest.Mock).mockReturnValue({});
});

Expand Down Expand Up @@ -50,18 +51,21 @@ describe(parse.name, () => {
expect(parseCards).toHaveBeenCalledWith(expectedSide);
});

it('should return empty fields when a decklist cannot be parsed', () => {
it('should return the parsed body sections', () => {
// Given
const buffer = '';
(parseCards as jest.Mock).mockReturnValueOnce({ cards: 'MAIN', count: 2 });
(parseCards as jest.Mock).mockReturnValueOnce({ cards: 'SIDE', count: 4 });
const buffer = sample;
// When
const result = parse(buffer);
// Then
expect(result).toStrictEqual({
authors: null,
colors: null,
main: null,
side: null,
title: null,
});
expect(result).toStrictEqual(
expect.objectContaining({
main: 'MAIN',
mainCount: 2,
side: 'SIDE',
sideCount: 4,
})
);
});
});
14 changes: 9 additions & 5 deletions src/tools/decklists/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ export const parse = (buffer: string): Decklist => {
const [, header = '', main = '', side = ''] =
buffer.match(DECK_RE.decklist) || [];
const { authors, colors, title } = parseHeader(header);
const { cards: mainCards, count: mainCount } = parseCards(main);
const { cards: sideCards, count: sideCount } = parseCards(side);
return {
authors: authors ?? null,
colors: colors ?? null,
main: parseCards(main) ?? null,
side: parseCards(side) ?? null,
title: title ?? null,
authors,
colors,
main: mainCards,
mainCount,
side: sideCards,
sideCount,
title,
};
};
10 changes: 6 additions & 4 deletions src/tools/decklists/parseCards.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { parseCards } from '@/tools/decklists/parseCards';
import type { Card } from '@/tools/decklists/types';

/**
* Create a dummy string representing a body of cards as expected from decklist
Expand All @@ -19,21 +18,22 @@ describe(parseCards.name, () => {
// Given
const buffer: string = dummyCards(2);
// When
const cards: Card[][] = parseCards(buffer);
const { cards, count } = parseCards(buffer);
// Then
expect(cards).toStrictEqual([
[
[4, 'Doomsday'],
[4, 'Doomsday'],
],
]);
expect(count).toBe(8);
});

it('should read a multi-column body of cards', () => {
// Given
const buffer: string = dummyCards(2, 1);
// When
const cards: Card[][] = parseCards(buffer);
const { cards, count } = parseCards(buffer);
// Then
expect(cards).toStrictEqual([
[
Expand All @@ -42,14 +42,16 @@ describe(parseCards.name, () => {
],
[[4, 'Doomsday']],
]);
expect(count).toBe(12);
});

it('should read an empty body of cards', () => {
// Given
const buffer: string = dummyCards();
// When
const cards: Card[][] = parseCards(buffer);
const { cards, count } = parseCards(buffer);
// Then
expect(cards).toStrictEqual([]);
expect(count).toBe(0);
});
});
13 changes: 10 additions & 3 deletions src/tools/decklists/parseCards.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { DECK_RE } from '@/tools/decklists/constants';
import type { Card } from '@/tools/decklists/types';

type ParseCards = (text: string) => { cards: Card[][]; count: number };

/**
* Parse a body of lines representing cards in a decklist.
* Empty lines found within the body will serve as delimiters for groups in
* order to accomodate for multi-column rendering.
*/
export const parseCards = (text: string): Card[][] =>
text
export const parseCards: ParseCards = (text) => {
let count = 0;
const cards: Card[][] = text
.split(DECK_RE.groupDelimiter)
.map((group) => group.match(DECK_RE.line))
.filter((group) => group)
.map((group) =>
(group as string[]).map((card) => {
const [, quantity, name] = card.match(DECK_RE.card) || [];
return [parseInt(quantity, 10), name];
const quantityValue = parseInt(quantity, 10);
count += quantityValue;
return [quantityValue, name];
})
);
return { cards, count };
};
15 changes: 8 additions & 7 deletions src/tools/decklists/parseHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import { DECK_RE } from '@/tools/decklists/constants';
import { toArray } from '@/tools/mana/toArray';

type Header = {
authors?: string;
colors: string[];
title?: string;
authors: string | null;
colors: string[] | null;
title: string | null;
};

/**
* Parse the header of a decklist buffer.
* It usually looks like this:
*/
export const parseHeader = (text: string): Header => {
const [, title = '', authors = '', colors = ''] =
const [, title = '', authors = '', colorsAsText = ''] =
text.match(DECK_RE.header) || [];
const colors: string[] = toArray(colorsAsText.trim());
return {
authors: authors?.trim(),
colors: toArray(colors.trim()),
title: title?.trim(),
authors: authors.trim() || null,
colors: colors.length ? colors : null,
title: title.trim() || null,
};
};
4 changes: 3 additions & 1 deletion src/tools/decklists/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ export interface Decklist {
authors: string | null;
colors: string[] | null;
main: Card[][];
side?: Card[][];
mainCount: number;
side: Card[][];
sideCount: number;
title: string | null;
}

Expand Down

0 comments on commit 223cb0b

Please sign in to comment.