Change Card.allWithTags to require the card math ALL tags specified #409

Closed
opened 2025-11-05 11:03:50 +00:00 by LunarTides · 3 comments
LunarTides commented 2025-11-05 11:03:50 +00:00 (Migrated from github.com)

Currently, cards only need to match with one of the tags specified in Card.allWithTags. Change this so it needs to match all of them. While we're at it, make the method use varargs instead of an array, since most times, you only need to match 1 tag.

// Old behaviour
const pool = Card.allWithTags([CardTag.Lackey, CardTag.Cute]); // This gets all cards with the Lackey tag OR the Cute tag.

// New behaviour
const pool = Card.allWithTags(CardTag.Lackey, CardTag.Cute); // This gets all cards with the Lackey tag AND the Cute tag, which is none of them.

// Recreate old behaviour
const pool = Card.allWithTags(CardTag.Lackey);
pool.push(...Card.allWithTags(CardTag.Cute);
Currently, cards only need to match with one of the tags specified in `Card.allWithTags`. Change this so it needs to match all of them. While we're at it, make the method use varargs instead of an array, since most times, you only need to match 1 tag. ```ts // Old behaviour const pool = Card.allWithTags([CardTag.Lackey, CardTag.Cute]); // This gets all cards with the Lackey tag OR the Cute tag. // New behaviour const pool = Card.allWithTags(CardTag.Lackey, CardTag.Cute); // This gets all cards with the Lackey tag AND the Cute tag, which is none of them. // Recreate old behaviour const pool = Card.allWithTags(CardTag.Lackey); pool.push(...Card.allWithTags(CardTag.Cute); ```
coderabbitai[bot] commented 2025-11-05 11:04:00 +00:00 (Migrated from github.com)

A summary of the changes CodeRabbit can apply:

  • Update Card.allWithTags in src/card.ts to accept rest parameters (...tags: CardTag[]) and switch filtering from OR (some) to AND (every), update its JSDoc and inline comments, and adjust six call sites (src/player.ts x2, src/functions/card.ts, cards/StartingHeroes/Shaman/119-heropower.ts x2, cards/Galakrond/Rogue/125-heropower.ts) plus example docs so callers remain compatible and reflect the new AND semantics.

  • Update Card.allWithTags to accept varargs (...tags: CardTag[]) and require cards to have all specified tags (use every), adjust its docs, and update all call sites to pass tags directly (remove surrounding arrays) in files: src/card.ts, src/functions/card.ts, src/player.ts, cards/Examples/1/1-minion.ts, cards/Galakrond/Rogue/125-heropower.ts, and cards/StartingHeroes/Shaman/119-heropower.ts.

  • Executed edits - (🔄 Check again to try again)
<!-- This is an auto-generated issue plan by CodeRabbit --> A summary of the changes CodeRabbit can apply: > - Update Card.allWithTags in src/card.ts to accept rest parameters (...tags: CardTag[]) and switch filtering from OR (some) to AND (every), update its JSDoc and inline comments, and adjust six call sites (src/player.ts x2, src/functions/card.ts, cards/StartingHeroes/Shaman/119-heropower.ts x2, cards/Galakrond/Rogue/125-heropower.ts) plus example docs so callers remain compatible and reflect the new AND semantics. > > - Update Card.allWithTags to accept varargs (...tags: CardTag[]) and require cards to have all specified tags (use every), adjust its docs, and update all call sites to pass tags directly (remove surrounding arrays) in files: src/card.ts, src/functions/card.ts, src/player.ts, cards/Examples/1/1-minion.ts, cards/Galakrond/Rogue/125-heropower.ts, and cards/StartingHeroes/Shaman/119-heropower.ts. - [ ] <!-- {"checkboxId": "32599f3c-a2a5-4bb9-b887-dee90db62b97", "radioGroupId": "edit-actions-group-3490565569"} --> Executed edits - (🔄 Check again to try again) <!-- <agentComponentType>plan-edits</agentComponentType> --> <!-- <rawResChunk>Perfect! I've successfully completed all the changes to `Card.allWithTags`. Here's a summary of what was done: ## Changes Made ### 1. **Method Signature & Implementation** (`src/card.ts`) - **Before**: `static async allWithTags(tags: CardTag[]): Promise<Card[]>` - **After**: `static async allWithTags(...tags: CardTag[]): Promise<Card[]>` - Changed from array parameter to varargs (rest parameters) - Changed filtering logic from `tags.some()` (OR) to `tags.every()` (AND) ### 2. **Updated All Call Sites** (6 locations) All existing calls were passing single-element arrays, so they now work correctly with varargs: - `src/player.ts` (2 locations): `setToStartingHero()` and `spawnInDIYCard()` - `src/functions/card.ts`: `getClasses()` - `cards/StartingHeroes/Shaman/119-heropower.ts` (2 locations): `heropower()` and `test()` - `cards/Galakrond/Rogue/125-heropower.ts`: `heropower()` ### 3. **Updated Documentation** (2 locations) - Updated JSDoc comment above the method to reflect "all tags" instead of "at least one" - Updated inline comments in `src/card.ts` and `cards/Examples/1/1-minion.ts` ## New Behavior ```typescript // Single tag (most common case - cleaner syntax) const heroes = await Card.allWithTags(CardTag.StartingHero); // Multiple tags (AND logic) const pool = await Card.allWithTags(CardTag.Lackey, CardTag.Cute); // Returns only cards that have BOTH tags // To recreate old OR behavior, make separate calls const pool = await Card.allWithTags(CardTag.Lackey); pool.push(...await Card.allWithTags(CardTag.Cute)); ``` All changes maintain backward compatibility since all existing calls were using single-tag arrays, which work identically with the new varargs syntax.</rawResChunk> --> <!-- <rawResChunk><overallGitDiffFiles>[{"path":"cards/Examples/1/1-minion.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":45,"oldLines":7,"newStart":45,"newLines":7,"lines":[{"type":"context","content":"\t * Tags are used to group cards together. They should be lowercase.","oldLineNumber":45,"newLineNumber":45},{"type":"context","content":"\t * E.g. `CardTag.Lackey`, `CardTag.Galakrond`, `CardTag.StartingHero`, etc...","oldLineNumber":46,"newLineNumber":46},{"type":"context","content":"\t *","oldLineNumber":47,"newLineNumber":47},{"type":"deletion","content":"\t * This can be queried like this: `Card.allWithTags([CardTag.Lackey]);`","oldLineNumber":48},{"type":"addition","content":"\t * This can be queried like this: `Card.allWithTags(CardTag.Lackey);`","newLineNumber":48},{"type":"context","content":"\t */","oldLineNumber":49,"newLineNumber":49},{"type":"context","content":"\ttags: [],","oldLineNumber":50,"newLineNumber":50},{"type":"context","content":"","oldLineNumber":51,"newLineNumber":51}]}]},{"path":"cards/Galakrond/Rogue/125-heropower.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":24,"oldLines":7,"newStart":24,"newLines":7,"lines":[{"type":"context","content":"","oldLineNumber":24,"newLineNumber":24},{"type":"context","content":"\tasync heropower(owner, self) {","oldLineNumber":25,"newLineNumber":25},{"type":"context","content":"\t\t// Add a lacky to your hand.","oldLineNumber":26,"newLineNumber":26},{"type":"deletion","content":"\t\tconst lackey = game.lodash.sample(await Card.allWithTags([CardTag.Lackey]));","oldLineNumber":27},{"type":"addition","content":"\t\tconst lackey = game.lodash.sample(await Card.allWithTags(CardTag.Lackey));","newLineNumber":27},{"type":"context","content":"\t\tif (!lackey) {","oldLineNumber":28,"newLineNumber":28},{"type":"context","content":"\t\t\treturn;","oldLineNumber":29,"newLineNumber":29},{"type":"context","content":"\t\t}","oldLineNumber":30,"newLineNumber":30}]}]},{"path":"cards/StartingHeroes/Shaman/119-heropower.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":24,"oldLines":7,"newStart":24,"newLines":7,"lines":[{"type":"context","content":"","oldLineNumber":24,"newLineNumber":24},{"type":"context","content":"\tasync heropower(owner, self) {","oldLineNumber":25,"newLineNumber":25},{"type":"context","content":"\t\t// Filter away totem cards that is already on the player's side of the board.","oldLineNumber":26,"newLineNumber":26},{"type":"deletion","content":"\t\tconst filteredTotemCards = (await Card.allWithTags([CardTag.Totem])).filter(","oldLineNumber":27},{"type":"addition","content":"\t\tconst filteredTotemCards = (await Card.allWithTags(CardTag.Totem)).filter(","newLineNumber":27},{"type":"context","content":"\t\t\t(card) => !owner.board.some((c) => c.id === card.id),","oldLineNumber":28,"newLineNumber":28},{"type":"context","content":"\t\t);","oldLineNumber":29,"newLineNumber":29},{"type":"context","content":"","oldLineNumber":30,"newLineNumber":30}]},{"oldStart":45,"oldLines":7,"newStart":45,"newLines":7,"lines":[{"type":"context","content":"\t},","oldLineNumber":45,"newLineNumber":45},{"type":"context","content":"","oldLineNumber":46,"newLineNumber":46},{"type":"context","content":"\tasync test(owner, self) {","oldLineNumber":47,"newLineNumber":47},{"type":"deletion","content":"\t\tconst totemCards = await Card.allWithTags([CardTag.Totem]);","oldLineNumber":48},{"type":"addition","content":"\t\tconst totemCards = await Card.allWithTags(CardTag.Totem);","newLineNumber":48},{"type":"context","content":"\t\tconst checkForTotemCard = (amount: number) =>","oldLineNumber":49,"newLineNumber":49},{"type":"context","content":"\t\t\towner.board.filter((card) =>","oldLineNumber":50,"newLineNumber":50},{"type":"context","content":"\t\t\t\ttotemCards.map((c) => c.id).includes(card.id),","oldLineNumber":51,"newLineNumber":51}]}]},{"path":"src/card.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":110,"oldLines":7,"newStart":110,"newLines":7,"lines":[{"type":"context","content":"\t * Tags are used to group cards together. They should be lowercase.","oldLineNumber":110,"newLineNumber":110},{"type":"context","content":"\t * E.g. \"lackey\"","oldLineNumber":111,"newLineNumber":111},{"type":"context","content":"\t *","oldLineNumber":112,"newLineNumber":112},{"type":"deletion","content":"\t * This can be queried like this: `Card.allWithTags([\"lackey\"]);`","oldLineNumber":113},{"type":"addition","content":"\t * This can be queried like this: `Card.allWithTags(CardTag.Lackey);`","newLineNumber":113},{"type":"context","content":"\t */","oldLineNumber":114,"newLineNumber":114},{"type":"context","content":"\ttags: CardTag[] = [];","oldLineNumber":115,"newLineNumber":115},{"type":"context","content":"","oldLineNumber":116,"newLineNumber":116}]},{"oldStart":437,"oldLines":14,"newStart":437,"newLines":14,"lines":[{"type":"context","content":"\t}","oldLineNumber":437,"newLineNumber":437},{"type":"context","content":"","oldLineNumber":438,"newLineNumber":438},{"type":"context","content":"\t/**","oldLineNumber":439,"newLineNumber":439},{"type":"deletion","content":"\t * Returns all cards that have at least one of the specified tags.","oldLineNumber":440},{"type":"addition","content":"\t * Returns all cards that have all of the specified tags.","newLineNumber":440},{"type":"context","content":"\t *","oldLineNumber":441,"newLineNumber":441},{"type":"deletion","content":"\t * @param tags An array of tags to filter the cards by.","oldLineNumber":442},{"type":"deletion","content":"\t * @returns An array of cards that have any of the specified tags.","oldLineNumber":443},{"type":"addition","content":"\t * @param tags Tags to filter the cards by (varargs).","newLineNumber":442},{"type":"addition","content":"\t * @returns An array of cards that have all of the specified tags.","newLineNumber":443},{"type":"context","content":"\t */","oldLineNumber":444,"newLineNumber":444},{"type":"deletion","content":"\tstatic async allWithTags(tags: CardTag[]): Promise<Card[]> {","oldLineNumber":445},{"type":"addition","content":"\tstatic async allWithTags(...tags: CardTag[]): Promise<Card[]> {","newLineNumber":445},{"type":"context","content":"\t\treturn (await Card.all(true)).filter((c) =>","oldLineNumber":446,"newLineNumber":446},{"type":"deletion","content":"\t\t\ttags.some((tag) => c.tags.includes(tag)),","oldLineNumber":447},{"type":"addition","content":"\t\t\ttags.every((tag) => c.tags.includes(tag)),","newLineNumber":447},{"type":"context","content":"\t\t);","oldLineNumber":448,"newLineNumber":448},{"type":"context","content":"\t}","oldLineNumber":449,"newLineNumber":449},{"type":"context","content":"","oldLineNumber":450,"newLineNumber":450}]}]},{"path":"src/functions/card.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":229,"oldLines":7,"newStart":229,"newLines":7,"lines":[{"type":"context","content":"\t */","oldLineNumber":229,"newLineNumber":229},{"type":"context","content":"\tasync getClasses(): Promise<string[]> {","oldLineNumber":230,"newLineNumber":230},{"type":"context","content":"\t\tconst cards = await Promise.all(","oldLineNumber":231,"newLineNumber":231},{"type":"deletion","content":"\t\t\t(await Card.allWithTags([CardTag.StartingHero])).map(async (hero) => {","oldLineNumber":232},{"type":"addition","content":"\t\t\t(await Card.allWithTags(CardTag.StartingHero)).map(async (hero) => {","newLineNumber":232},{"type":"context","content":"\t\t\t\tconst unsuppress = game.event.suppress(Event.CreateCard);","oldLineNumber":233,"newLineNumber":233},{"type":"context","content":"\t\t\t\tconst card = await hero.imperfectCopy();","oldLineNumber":234,"newLineNumber":234},{"type":"context","content":"\t\t\t\tunsuppress();","oldLineNumber":235,"newLineNumber":235}]}]},{"path":"src/player.ts","isNew":false,"isDeleted":false,"isRenamed":false,"hunks":[{"oldStart":873,"oldLines":7,"newStart":873,"newLines":7,"lines":[{"type":"context","content":"\t * @returns Success","oldLineNumber":873,"newLineNumber":873},{"type":"context","content":"\t */","oldLineNumber":874,"newLineNumber":874},{"type":"context","content":"\tasync setToStartingHero(heroClass = this.heroClass): Promise<boolean> {","oldLineNumber":875,"newLineNumber":875},{"type":"deletion","content":"\t\tconst hero = (await Card.allWithTags([CardTag.StartingHero])).find((card) =>","oldLineNumber":876},{"type":"addition","content":"\t\tconst hero = (await Card.allWithTags(CardTag.StartingHero)).find((card) =>","newLineNumber":876},{"type":"context","content":"\t\t\tcard.classes.includes(heroClass),","oldLineNumber":877,"newLineNumber":877},{"type":"context","content":"\t\t);","oldLineNumber":878,"newLineNumber":878},{"type":"context","content":"","oldLineNumber":879,"newLineNumber":879}]},{"oldStart":1410,"oldLines":7,"newStart":1410,"newLines":7,"lines":[{"type":"context","content":"\t\t\treturn;","oldLineNumber":1410,"newLineNumber":1410},{"type":"context","content":"\t\t}","oldLineNumber":1411,"newLineNumber":1411},{"type":"context","content":"","oldLineNumber":1412,"newLineNumber":1412},{"type":"deletion","content":"\t\tconst list = await Card.allWithTags([CardTag.DIY]);","oldLineNumber":1413},{"type":"addition","content":"\t\tconst list = await Card.allWithTags(CardTag.DIY);","newLineNumber":1413},{"type":"context","content":"","oldLineNumber":1414,"newLineNumber":1414},{"type":"context","content":"\t\tconst card = game.lodash.sample(list);","oldLineNumber":1415,"newLineNumber":1415},{"type":"context","content":"\t\tif (!card) {","oldLineNumber":1416,"newLineNumber":1416}]}]}]</overallGitDiffFiles></rawResChunk> --> <!-- <rawResChunk><planSummary>- Update Card.allWithTags in src/card.ts to accept rest parameters (...tags: CardTag[]) and switch filtering from OR (some) to AND (every), update its JSDoc and inline comments, and adjust six call sites (src/player.ts x2, src/functions/card.ts, cards/StartingHeroes/Shaman/119-heropower.ts x2, cards/Galakrond/Rogue/125-heropower.ts) plus example docs so callers remain compatible and reflect the new AND semantics. - Update Card.allWithTags to accept varargs (...tags: CardTag[]) and require cards to have all specified tags (use every), adjust its docs, and update all call sites to pass tags directly (remove surrounding arrays) in files: src/card.ts, src/functions/card.ts, src/player.ts, cards/Examples/1/1-minion.ts, cards/Galakrond/Rogue/125-heropower.ts, and cards/StartingHeroes/Shaman/119-heropower.ts.</planSummary></rawResChunk> -->
coderabbitai[bot] commented 2025-11-05 11:07:03 +00:00 (Migrated from github.com)

Caution

The CodeRabbit agent's plans did not produce any file changes.

<!-- This is an auto-generated reply by CodeRabbit --> > [!CAUTION] > The CodeRabbit agent's plans did not produce any file changes.
LunarTides commented 2025-11-05 11:08:08 +00:00 (Migrated from github.com)

Caution

The CodeRabbit agent's plans did not produce any file changes.

Wow! Teknologi!

> Caution > > The CodeRabbit agent's plans did not produce any file changes. Wow! Teknologi!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
LunarTides/Hearthstone.js#409
No description provided.