mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-16 20:39:27 +02:00
Fixed up remaining matchers
This commit is contained in:
parent
a0de157246
commit
83392d7e86
@ -75,3 +75,12 @@ export type NonFunctionPropertiesRecursive<Class> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type AbstractConstructor<T> = abstract new (...args: any[]) => T;
|
export type AbstractConstructor<T> = abstract new (...args: any[]) => T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type helper to mark all properties in `T` optional, while still mandating that at least 1
|
||||||
|
* of its properties be present.
|
||||||
|
*
|
||||||
|
* Distinct from {@linkcode Partial} as this requires at least 1 property to _not_ be undefined.
|
||||||
|
* @typeParam T - The type to render partial.
|
||||||
|
*/
|
||||||
|
export type AtLeastOne<T> = Partial<T> & EnumValues<{ [K in keyof T]: Pick<T, K> }>;
|
||||||
|
3
test/@types/vitest.d.ts
vendored
3
test/@types/vitest.d.ts
vendored
@ -11,6 +11,7 @@ import type { ToHaveEffectiveStatMatcherOptions } from "#test/test-utils/matcher
|
|||||||
import { expectedStatusType } from "#test/test-utils/matchers/to-have-status-effect-matcher";
|
import { expectedStatusType } from "#test/test-utils/matchers/to-have-status-effect-matcher";
|
||||||
import type { toHaveTypesOptions } from "#test/test-utils/matchers/to-have-types";
|
import type { toHaveTypesOptions } from "#test/test-utils/matchers/to-have-types";
|
||||||
import { TurnMove } from "#types/turn-move";
|
import { TurnMove } from "#types/turn-move";
|
||||||
|
import { AtLeastOne } from "#types/type-helpers";
|
||||||
import type { expect } from "vitest";
|
import type { expect } from "vitest";
|
||||||
|
|
||||||
declare module "vitest" {
|
declare module "vitest" {
|
||||||
@ -42,7 +43,7 @@ declare module "vitest" {
|
|||||||
* Default `0` (last used move)
|
* Default `0` (last used move)
|
||||||
* @see {@linkcode Pokemon.getLastXMoves}
|
* @see {@linkcode Pokemon.getLastXMoves}
|
||||||
*/
|
*/
|
||||||
toHaveUsedMove(expected: MoveId | Partial<TurnMove>, index?: number): void;
|
toHaveUsedMove(expected: MoveId | AtLeastOne<TurnMove>, index?: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matcher to check if a {@linkcode Pokemon Pokemon's} effective stat is as expected
|
* Matcher to check if a {@linkcode Pokemon Pokemon's} effective stat is as expected
|
||||||
|
@ -6,7 +6,11 @@ import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
|||||||
* @param expected - The array to check equality with
|
* @param expected - The array to check equality with
|
||||||
* @returns Whether the matcher passed
|
* @returns Whether the matcher passed
|
||||||
*/
|
*/
|
||||||
export function toEqualArrayUnsorted(this: MatcherState, received: unknown, expected: unknown): SyncExpectationResult {
|
export function toEqualArrayUnsorted(
|
||||||
|
this: MatcherState,
|
||||||
|
received: unknown,
|
||||||
|
expected: unknown[],
|
||||||
|
): SyncExpectationResult {
|
||||||
if (!Array.isArray(received)) {
|
if (!Array.isArray(received)) {
|
||||||
return {
|
return {
|
||||||
pass: false,
|
pass: false,
|
||||||
@ -14,22 +18,16 @@ export function toEqualArrayUnsorted(this: MatcherState, received: unknown, expe
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(expected)) {
|
|
||||||
return {
|
|
||||||
pass: false,
|
|
||||||
message: () => `Expected to receive an array, but got ${this.utils.stringify(expected)}!`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (received.length !== expected.length) {
|
if (received.length !== expected.length) {
|
||||||
return {
|
return {
|
||||||
pass: false,
|
pass: false,
|
||||||
message: () => `Expected to receive array of length ${received.length}, but got ${expected.length}!`,
|
message: () => `Expected to receive array of length ${received.length}, but got ${expected.length} instead!`,
|
||||||
actual: received,
|
actual: received,
|
||||||
expected,
|
expected,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create shallow copies of the arrays in case we have
|
||||||
const gotSorted = received.slice().sort();
|
const gotSorted = received.slice().sort();
|
||||||
const wantSorted = expected.slice().sort();
|
const wantSorted = expected.slice().sort();
|
||||||
const pass = this.equals(gotSorted, wantSorted, [...this.customTesters, this.utils.iterableEquality]);
|
const pass = this.equals(gotSorted, wantSorted, [...this.customTesters, this.utils.iterableEquality]);
|
||||||
@ -37,8 +35,10 @@ export function toEqualArrayUnsorted(this: MatcherState, received: unknown, expe
|
|||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
`Expected ${this.utils.stringify(received)} to exactly equal ${this.utils.stringify(expected)} without order!`,
|
pass
|
||||||
actual: gotSorted,
|
? `Expected ${this.utils.stringify(received)} to NOT exactly equal ${this.utils.stringify(expected)} without order!`
|
||||||
|
: `Expected ${this.utils.stringify(received)} to exactly equal ${this.utils.stringify(expected)} without order!`,
|
||||||
expected: wantSorted,
|
expected: wantSorted,
|
||||||
|
actual: gotSorted,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import type { Pokemon } from "#field/pokemon";
|
|||||||
|
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
|
import { getEnumStr } from "#test/test-utils/string-utils";
|
||||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||||
|
|
||||||
@ -28,14 +29,14 @@ export function toHaveAbilityAppliedMatcher(
|
|||||||
const pass = received.waveData.abilitiesApplied.has(expectedAbilityId);
|
const pass = received.waveData.abilitiesApplied.has(expectedAbilityId);
|
||||||
|
|
||||||
const pkmName = getPokemonNameWithAffix(received);
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
const expectedAbilityStr = `${AbilityId[expectedAbilityId]} (=${expectedAbilityId})`;
|
const expectedAbilityStr = getEnumStr(AbilityId, expectedAbilityId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} to NOT have applied ${expectedAbilityStr}, but it did!`
|
? `Expected ${pkmName} to NOT have applied ${expectedAbilityStr}, but it did!`
|
||||||
: `Expected ${pkmName} to have applied ${expectedAbilityStr}, but it did not!`,
|
: `Expected ${pkmName} to have applied ${expectedAbilityStr}, but it didn't!`,
|
||||||
expected: expectedAbilityId,
|
expected: expectedAbilityId,
|
||||||
actual: received.waveData.abilitiesApplied,
|
actual: received.waveData.abilitiesApplied,
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@ export function toHaveBattlerTag(
|
|||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} to NOT have BattlerTagType.${expectedTagStr}, but it did!`
|
? `Expected ${pkmName} to NOT have BattlerTagType.${expectedTagStr}, but it did!`
|
||||||
: `Expected ${pkmName} to have BattlerTagType.${expectedTagStr}, but it did not!`,
|
: `Expected ${pkmName} to have BattlerTagType.${expectedTagStr}, but it didn't!`,
|
||||||
expected: expectedBattlerTagType,
|
expected: expectedBattlerTagType,
|
||||||
actual: received.summonData.tags.map(t => t.tagType),
|
actual: received.summonData.tags.map(t => t.tagType),
|
||||||
};
|
};
|
||||||
|
@ -15,17 +15,17 @@ export function toHaveFaintedMatcher(this: MatcherState, received: unknown): Syn
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hp } = received;
|
|
||||||
const maxHp = received.getMaxHp();
|
|
||||||
const pass = received.isFainted();
|
const pass = received.isFainted();
|
||||||
|
|
||||||
|
const hp = received.hp;
|
||||||
|
const maxHp = received.getMaxHp();
|
||||||
const pkmName = getPokemonNameWithAffix(received);
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} NOT to have fainted, but it did! (${hp}/${maxHp} HP)`
|
? `Expected ${pkmName} to NOT have fainted, but it did!`
|
||||||
: `Expected ${pkmName} to have fainted, but it did not. (${hp}/${maxHp} HP)`,
|
: `Expected ${pkmName} to have fainted, but it didn't! (${hp}/${maxHp} HP)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,17 @@ export function toHaveFullHpMatcher(this: MatcherState, received: unknown): Sync
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const pass = received.isFullHp() === true;
|
const pass = received.isFullHp();
|
||||||
|
|
||||||
const ofHpStr = `${received.getInverseHp()}/${received.getMaxHp()} HP`;
|
const hp = received.hp;
|
||||||
|
const maxHp = received.getMaxHp();
|
||||||
const pkmName = getPokemonNameWithAffix(received);
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} to NOT have full hp (${ofHpStr}), but it did!`
|
? `Expected ${pkmName} to NOT have full hp, but it did!`
|
||||||
: `Expected ${pkmName} to have full hp, but found ${ofHpStr}.`,
|
: `Expected ${pkmName} to have full hp, but it didn't! (${hp}/${maxHp} HP)`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
// biome-ignore lint/correctness/noUnusedImports: TSDoc
|
||||||
|
import type { Pokemon } from "#field/pokemon";
|
||||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||||
|
|
||||||
@ -20,13 +22,14 @@ export function toHaveHpMatcher(this: MatcherState, received: unknown, expectedH
|
|||||||
const pass = actualHp === expectedHp;
|
const pass = actualHp === expectedHp;
|
||||||
|
|
||||||
const pkmName = getPokemonNameWithAffix(received);
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
const maxHp = received.getMaxHp();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} to NOT have ${expectedHp}/${maxHp} HP, but it did!`
|
? `Expected ${pkmName} to NOT have ${expectedHp} HP, but it did!`
|
||||||
: `Expected ${pkmName} to have ${expectedHp}/${maxHp} HP, but found ${actualHp}/${maxHp} HP.`,
|
: `Expected ${pkmName} to have ${expectedHp} HP, but got ${actualHp} HP instead!`,
|
||||||
|
expected: expectedHp,
|
||||||
|
actual: actualHp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { type BattleStat, Stat } from "#enums/stat";
|
import type { BattleStat } from "#enums/stat";
|
||||||
|
import { getStatName } from "#test/test-utils/string-utils";
|
||||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ export function toHaveStatStageMatcher(
|
|||||||
const pass = actualStage === expectedStage;
|
const pass = actualStage === expectedStage;
|
||||||
|
|
||||||
const pkmName = getPokemonNameWithAffix(received);
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
const statName = Stat[stat];
|
const statName = getStatName(stat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
|
@ -46,7 +46,7 @@ export function toHaveStatusEffectMatcher(
|
|||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName} NOT to have ${expectedStr}, but it did!`
|
? `Expected ${pkmName} to NOT have ${expectedStr}, but it did!`
|
||||||
: `Expected ${pkmName} to have status effect ${expectedStr}, but got ${actualStr} instead!`,
|
: `Expected ${pkmName} to have status effect ${expectedStr}, but got ${actualStr} instead!`,
|
||||||
expected: expectedStatus,
|
expected: expectedStatus,
|
||||||
actual: actualEffect,
|
actual: actualEffect,
|
||||||
@ -65,7 +65,7 @@ export function toHaveStatusEffectMatcher(
|
|||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName}'s status NOT to match ${this.utils.stringify(expectedStatus)}, but it did!`
|
? `Expected ${pkmName}'s status to NOT match ${this.utils.stringify(expectedStatus)}, but it did!`
|
||||||
: `Expected ${pkmName}'s status to match ${this.utils.stringify(expectedStatus)}, but got ${this.utils.stringify(actualStatus)} instead!`,
|
: `Expected ${pkmName}'s status to match ${this.utils.stringify(expectedStatus)}, but got ${this.utils.stringify(actualStatus)} instead!`,
|
||||||
expected: expectedStatus,
|
expected: expectedStatus,
|
||||||
actual: actualStatus,
|
actual: actualStatus,
|
||||||
|
@ -38,7 +38,7 @@ export function toHaveTerrainMatcher(
|
|||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected Arena to NOT have ${expectedStr} active, but it did!`
|
? `Expected Arena to NOT have ${expectedStr} active, but it did!`
|
||||||
: `Expected Arena to have ${expectedStr} active, but got ${actualStr}!`,
|
: `Expected Arena to have ${expectedStr} active, but got ${actualStr} instead!`,
|
||||||
actual,
|
actual,
|
||||||
expected: expectedTerrainType,
|
expected: expectedTerrainType,
|
||||||
};
|
};
|
||||||
|
@ -39,17 +39,22 @@ export function toHaveTypes(
|
|||||||
const actualTypes = received.getTypes(...(options.args ?? [])).sort();
|
const actualTypes = received.getTypes(...(options.args ?? [])).sort();
|
||||||
const expectedTypes = expected.slice().sort();
|
const expectedTypes = expected.slice().sort();
|
||||||
|
|
||||||
const actualStr = stringifyEnumArray(PokemonType, actualTypes);
|
|
||||||
const expectedStr = stringifyEnumArray(PokemonType, expectedTypes);
|
|
||||||
// Exact matches do not care about subset equality
|
// Exact matches do not care about subset equality
|
||||||
const matchers = options.exact
|
const matchers = options.exact
|
||||||
? [...this.customTesters, this.utils.iterableEquality]
|
? [...this.customTesters, this.utils.iterableEquality]
|
||||||
: [...this.customTesters, this.utils.subsetEquality, this.utils.iterableEquality];
|
: [...this.customTesters, this.utils.subsetEquality, this.utils.iterableEquality];
|
||||||
const pass = this.equals(actualStr, expectedStr, matchers);
|
const pass = this.equals(actualTypes, expectedTypes, matchers);
|
||||||
|
|
||||||
|
const actualStr = stringifyEnumArray(PokemonType, actualTypes);
|
||||||
|
const expectedStr = stringifyEnumArray(PokemonType, expectedTypes);
|
||||||
|
const pkmName = getPokemonNameWithAffix(received);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pass,
|
pass,
|
||||||
message: () => `Expected ${getPokemonNameWithAffix(received)} to have types ${expectedStr}, but got ${actualStr}!`,
|
message: () =>
|
||||||
|
pass
|
||||||
|
? `Expected ${pkmName} to NOT have types ${expectedStr}, but it did!`
|
||||||
|
: `Expected ${pkmName} to have types ${expectedStr}, but got ${actualStr} instead!`,
|
||||||
actual: actualTypes,
|
actual: actualTypes,
|
||||||
expected: expectedTypes,
|
expected: expectedTypes,
|
||||||
};
|
};
|
||||||
|
@ -5,12 +5,14 @@ import type { Pokemon } from "#field/pokemon";
|
|||||||
import { getOrdinal } from "#test/test-utils/string-utils";
|
import { getOrdinal } from "#test/test-utils/string-utils";
|
||||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||||
import type { TurnMove } from "#types/turn-move";
|
import type { TurnMove } from "#types/turn-move";
|
||||||
|
import type { AtLeastOne } from "#types/type-helpers";
|
||||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matcher to check if a {@linkcode Pokemon} has used a specific {@linkcode MoveId} at the given .
|
* Matcher to check the contents of a {@linkcode Pokemon}'s move history.
|
||||||
* @param received - The actual value received. Should be a {@linkcode Pokemon}
|
* @param received - The actual value received. Should be a {@linkcode Pokemon}
|
||||||
* @param expectedValue - The expected value; can be a {@linkcode MoveId} or a partially filled {@linkcode TurnMove}
|
* @param expectedValue - The {@linkcode MoveId} the Pokemon is expected to have used,
|
||||||
|
* or a partially filled {@linkcode TurnMove} containing the desired properties to check.
|
||||||
* @param index - The index of the move history entry to check, in order from most recent to least recent.
|
* @param index - The index of the move history entry to check, in order from most recent to least recent.
|
||||||
* Default `0` (last used move)
|
* Default `0` (last used move)
|
||||||
* @returns Whether the matcher passed
|
* @returns Whether the matcher passed
|
||||||
@ -18,7 +20,7 @@ import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
|||||||
export function toHaveUsedMoveMatcher(
|
export function toHaveUsedMoveMatcher(
|
||||||
this: MatcherState,
|
this: MatcherState,
|
||||||
received: unknown,
|
received: unknown,
|
||||||
expectedResult: MoveId | Partial<TurnMove>,
|
expectedResult: MoveId | AtLeastOne<TurnMove>,
|
||||||
index = 0,
|
index = 0,
|
||||||
): SyncExpectationResult {
|
): SyncExpectationResult {
|
||||||
if (!isPokemonInstance(received)) {
|
if (!isPokemonInstance(received)) {
|
||||||
@ -56,8 +58,8 @@ export function toHaveUsedMoveMatcher(
|
|||||||
pass,
|
pass,
|
||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected ${pkmName}'s ${moveIndexStr} NOT to match ${this.utils.stringify(expectedResult)}, but it did!`
|
? `Expected ${pkmName}'s ${moveIndexStr} to NOT match ${this.utils.stringify(expectedResult)}, but it did!`
|
||||||
: `Expected ${pkmName}'s ${moveIndexStr} to match ${this.utils.stringify(expectedResult)}, but got ${this.utils.stringify(move)}!`,
|
: `Expected ${pkmName}'s ${moveIndexStr} to match ${this.utils.stringify(expectedResult)}, but got ${this.utils.stringify(move)} instead!`,
|
||||||
expected: expectedResult,
|
expected: expectedResult,
|
||||||
actual: move,
|
actual: move,
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { isGameManagerInstance, receivedStr } from "#test/test-utils/test-utils";
|
import { isGameManagerInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||||
import { toReadableString } from "#utils/common";
|
import { toTitleCase } from "#utils/strings";
|
||||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,9 +38,9 @@ export function toHaveWeatherMatcher(
|
|||||||
message: () =>
|
message: () =>
|
||||||
pass
|
pass
|
||||||
? `Expected Arena to NOT have ${expectedStr} weather active, but it did!`
|
? `Expected Arena to NOT have ${expectedStr} weather active, but it did!`
|
||||||
: `Expected Arena to have ${expectedStr} weather active, but got ${actualStr}!`,
|
: `Expected Arena to have ${expectedStr} weather active, but got ${actualStr} instead!`,
|
||||||
actual: actualStr,
|
actual,
|
||||||
expected: expectedStr,
|
expected: expectedWeatherType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +54,5 @@ function toWeatherStr(weatherType: WeatherType) {
|
|||||||
return "no weather";
|
return "no weather";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Change to use updated string utils
|
return toTitleCase(WeatherType[weatherType]);
|
||||||
return toReadableString(WeatherType[weatherType]);
|
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ export function stringifyEnumArray<E extends EnumOrObject>(obj: E, enums: E[keyo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a number into an English ordinal.
|
* Convert a number into an English ordinal
|
||||||
* @param num - The number to convert into an ordinal
|
* @param num - The number to convert into an ordinal
|
||||||
* @returns The ordinal representation of {@linkcode num}.
|
* @returns The ordinal representation of {@linkcode num}.
|
||||||
* @example
|
* @example
|
||||||
@ -129,6 +129,11 @@ export function getOrdinal(num: number): string {
|
|||||||
return num + "th";
|
return num + "th";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the localized name of a {@linkcode Stat}.
|
||||||
|
* @param s - The {@linkcode Stat} to check
|
||||||
|
* @returns - The proper name for s, retrieved from the translations.
|
||||||
|
*/
|
||||||
export function getStatName(s: Stat): string {
|
export function getStatName(s: Stat): string {
|
||||||
return i18next.t(getStatKey(s));
|
return i18next.t(getStatKey(s));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user