diff --git a/tcgdex.ts b/tcgdex.ts index d65f57a..bd47b52 100644 --- a/tcgdex.ts +++ b/tcgdex.ts @@ -1,79 +1,164 @@ import RequestWrapper from './Request' -import { Serie, Set, Card, CardResume, SerieList, SetList, SupportedLanguages } from './interfaces' +import { Serie, Set, Card, CardResume, SerieList, SetList, SupportedLanguages, StringEndpoint } from './interfaces' + +type Endpoint = 'cards' | 'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'series' | 'sets' | 'types' + +const ENDPOINTS: Array = ['cards', 'categories', 'hp', 'illustrators', 'rarities', 'retreats', 'series', 'sets', 'types'] +const BASE_URL = 'https://api.tcgdex.net/v2' export default class TCGdex { + /** + * @deprecated to change the lang use `this.lang` + */ public static defaultLang: SupportedLanguages = "en" public constructor(public lang?: SupportedLanguages) {} public getLang() { - return this.lang || TCGdex.defaultLang - } - - private getBaseUrl() { - return `https://api.tcgdex.net/v2/${this.getLang()}` + return this.lang ?? TCGdex.defaultLang ?? 'en' } + /** + * Shortcut to easily fetch a card using both it's global id and it's local ID + * @param id the card global/local ID + * @param set the card set name/ID (optionnal) + * @returns the card object + */ public async fetchCard(id: string | number, set?: string): Promise { const path = set ? ['sets', set] : ['cards'] - return this.rwgr(...path, id).get() + // @ts-expect-error the base endpoint is 'sets' or 'cards' + return this.fetch(...path, id) } + /** + * Shortcut to easily fetch cards using an optionnal set name/ID + * @param set the card set name/ID (optionnal) + * @returns a card list + */ public async fetchCards(set?: string): Promise | undefined> { if (set) { - const setSingle = await this.fetchSet(set) - if (!setSingle) { - return undefined - } - return setSingle.cards + const fSet = await this.fetch('sets', set) + return fSet ? fSet.cards : undefined } - const req = this.rwgr>('cards') - const resp = await req.get() - if (!resp) { - return undefined - } - return resp + return this.fetch('cards') } - public async fetchSet(set: string): Promise { - const req = this.rwgr('sets', set) - const resp = await req.get() - if (!resp) { - return undefined - } - return resp + /** + * @deprecated use `this.fetch('sets', set)` + */ + public async fetchSet(set: string) { + return this.fetch('sets', set) } - public async fetchSerie(expansion: string): Promise { - const req = this.rwgr('series', expansion) - return req.get() + /** + * @deprecated use `this.fetch('series', serie)` + */ + public async fetchSerie(serie: string): Promise { + return this.fetch('series', serie) } + /** + * @deprecated use `this.fetch('series')` + */ public async fetchSeries(): Promise { - const req = this.rwgr('series') - return req.get() + return this.fetch('series') } - public async fetchSets(expansion?: string): Promise { - if (expansion) { - const expansionSingle = await this.fetchSerie(expansion) - if (!expansionSingle) { - return undefined - } - return expansionSingle.sets + /** + * Shortcut to easily fetch sets using an optionnal serie name/ID + * @param serie the card set name/ID (optionnal) + * @returns a card list + */ + public async fetchSets(serie?: string): Promise { + if (serie) { + const fSerie = await this.fetch('series', serie) + return fSerie ? fSerie.sets : undefined } - const req = this.rwgr('sets') - const list = await req.get() - if (!list) { - return undefined - } - return list + return this.fetch('sets') } - private rwgr(...url: Array) { - return RequestWrapper.getRequest(`${this.getBaseUrl()}/${url.map((v) => encodeURI( - // Normalize URL - v.toString().replace('?', '%3F').normalize('NFC').replace(/["'\u0300-\u036f]/g, "") - )).join('/')}`) + /** + * Fetch a card using its global id + * @param endpoint_0 'cards' + * @param endpoint_1 {string} the card global ID + */ + public async fetch(...type: ['cards', string]): Promise + /** + * Fetch every cards in the database + * @param endpoint_0 'cards' + */ + public async fetch(type: 'cards'): Promise | undefined> + /** + * Fetch a card using its local id and its set + * @param endpoint_0 'sets' + * @param endpoint_1 {string} the set name or ID + * @param endpoint_2 {string} the card local ID + */ + public async fetch(...endpoint: ['sets', string, string]): Promise + /** + * Fetch a set + * @param endpoint_0 'sets' + * @param endpoint_1 {string} the set name or ID + */ + public async fetch(...endpoint: ['sets', string]): Promise + /** + * Fetch every sets + * @param endpoint_0 'sets' + */ + public async fetch(endpoint: 'sets'): Promise + /** + * Fetch a serie + * @param endpoint_0 'series' + * @param endpoint_1 {string} the serie name or ID + */ + public async fetch(...endpoint: ['series', string]): Promise + /** + * Fetch every series + * @param endpoint_0 'series' + */ + public async fetch(endpoint: 'series'): Promise + /** + * Fetch cards depending on a specific filter + * @param endpoint_0 {'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types'} + * Possible value 'categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types' + * @param endpoint_1 {string} the value set while fetching the index + */ + public async fetch(...endpoint: ['categories' | 'hp' | 'illustrators' | 'rarities' | 'retreats' | 'types', string]): Promise + /** + * Fetch cards depending on a specific filter + * @param endpoint_0 {'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'} + * Possible value 'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types' + * @param endpoint_1 {string} Fetch the possible values to use depending on the endpoint + */ + public async fetch(endpoint: 'hp' | 'retreats' | 'categories' | 'illustrators' | 'rarities' | 'types'): Promise | undefined> + public async fetch(...endpoint: Array): Promise { + if (endpoint.length === 0) { + throw new Error(`endpoint to fetch is empty!`) + } + // @ts-expect-error with the precedent check, we KNOW that type is not empty + const baseEndpoint = endpoint.shift().toLowerCase() as Endpoint + if (!ENDPOINTS.includes(baseEndpoint)) { + throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`) + } + return this.makeRequest(baseEndpoint, ...endpoint) + } + + /** + * Function to make the request and normalize the whole path + */ + private makeRequest(...url: Array) { + // Normalize path + const path = url.map((v) => encodeURI( + v + // Transform numbers to string + .toString() + // replace this special character with an escaped one + .replace('?', '%3F') + // normalize the string + .normalize('NFC') + // remove some special chars by nothing + .replace(/["'\u0300-\u036f]/g, "") + )).join('/') + return RequestWrapper.getRequest(`${BASE_URL}/${this.getLang()}/${path}`).get() } }