From 9ff224be694d3575eb6248040d26d58ad40f2585 Mon Sep 17 00:00:00 2001 From: Avior Date: Tue, 9 Jul 2024 15:50:59 +0200 Subject: [PATCH 1/9] feat: first commit in this direction Signed-off-by: Avior --- bun.lockb | Bin 0 -> 287131 bytes package-lock.json | 21 ++-- package.json | 1 + src/Request.ts | 1 + src/endpoints/Endpoint.ts | 26 +++++ src/interface.d.ts | 46 ++++++++ src/models/Card.ts | 197 +++++++++++++++++++++++++++++++++++ src/models/CardResume.ts | 47 +++++++++ src/models/Model.ts | 28 +++++ src/models/Other.d.ts | 6 ++ src/models/Serie.ts | 0 src/models/SerieResume.ts | 5 + src/models/Set.ts | 66 ++++++++++++ src/models/SetResume.ts | 25 +++++ src/models/StringEndpoint.ts | 12 +++ src/tcgdex.ts | 95 +++++++++++++++-- src/utils.ts | 31 ++++++ tsconfig.json | 5 +- 18 files changed, 587 insertions(+), 25 deletions(-) create mode 100644 bun.lockb create mode 100644 src/endpoints/Endpoint.ts create mode 100644 src/interface.d.ts create mode 100644 src/models/Card.ts create mode 100644 src/models/CardResume.ts create mode 100644 src/models/Model.ts create mode 100644 src/models/Other.d.ts create mode 100644 src/models/Serie.ts create mode 100644 src/models/SerieResume.ts create mode 100644 src/models/Set.ts create mode 100644 src/models/SetResume.ts create mode 100644 src/models/StringEndpoint.ts create mode 100644 src/utils.ts diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 0000000000000000000000000000000000000000..7371487c15f11399b06c2235db96306d976ea5c9 GIT binary patch literal 287131 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

S!7%_dQAt$mTgPz4zmuNX!lqwQJrDSqMVg77s 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" }, "dependencies": { + "@dzeio/object-util": "^1.7.0", "isomorphic-unfetch": "^3", "unfetch": "^4" }, diff --git a/src/Request.ts b/src/Request.ts index 7ca38bd..b87f904 100644 --- a/src/Request.ts +++ b/src/Request.ts @@ -9,6 +9,7 @@ export default class Request { private static cache: Record = {} public static async fetch(url: string): Promise { + console.log(url) let request = this.cache[url] const now = new Date().getTime() if (!request || now - request.time > this.ttl) { diff --git a/src/endpoints/Endpoint.ts b/src/endpoints/Endpoint.ts new file mode 100644 index 0000000..b8903a4 --- /dev/null +++ b/src/endpoints/Endpoint.ts @@ -0,0 +1,26 @@ +import { Query } from '../interface' +import Model from '../models/Model' +import TCGdex from '../tcgdex' +import { parseQuery } from '../utils' + +type BaseEndpoint = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | 'trainer-types' | 'types' | 'variants' + +export default class Endpoint { + public constructor( + protected readonly tcgdex: TCGdex, + protected readonly itemModel: new (sdk: TCGdex) => Item, + protected readonly listModel: new (sdk: TCGdex) => List, + protected readonly endpoint: BaseEndpoint + + ) {} + + public async get(id: string | number): Promise { + const res = await this.tcgdex.fetch(this.endpoint as any, id as string) + return Model.build(new this.itemModel(this.tcgdex), res) + } + + public async list(query: Query): Promise> { + const res = await this.tcgdex.fetchWithQuery([this.endpoint as any], parseQuery(query)) + return (res as Array ?? []).map((it) => Model.build(new this.listModel(this.tcgdex), it)) + } +} diff --git a/src/interface.d.ts b/src/interface.d.ts new file mode 100644 index 0000000..4517f2e --- /dev/null +++ b/src/interface.d.ts @@ -0,0 +1,46 @@ +export type Quality = 'low' | 'high' + +export type Extension = 'jpg' | 'webp' | 'png' + +export interface QueryPagination { + page?: number + itemsPerPage?: number +} + +export interface QuerySort { + field: keyof PropertiesExtract + order: 'DESC' | 'ASC' +} + +/** + * Remove the methods from an object and give the remaining + */ +export type ExcludeMethods = { + // eslint-disable-next-line @typescript-eslint/ban-types + [K in keyof T]: T[K] extends Function ? never : K +}[keyof T] + +/** + * extract the properties from an object + */ +export type PropertiesExtract = { + [K in ExcludeMethods]: T[K] +} + +// Helper type to extract properties and flatten nested objects +export type MergeProperties = { + [K in keyof T]: T[K] extends object ? `${K & string}.${MergeProperties}` : K; +}[keyof T] + +// Main type to flatten the class properties +export type Query = { + [K in MergeProperties as K extends string ? K : never]?: K extends `${infer Prefix}.${infer Rest}` + ? Prefix extends keyof T + ? Rest extends MergeProperties + ? T[Prefix][Rest & keyof T[Prefix]] + : never + : never + : K extends keyof T + ? T[K] + : never +} diff --git a/src/models/Card.ts b/src/models/Card.ts new file mode 100644 index 0000000..e27413c --- /dev/null +++ b/src/models/Card.ts @@ -0,0 +1,197 @@ +import CardResume from './CardResume' +import type { Variants } from './Other' +import type Set from './Set' + +// TODO: sort elements by alphabetical order +export default class Card extends CardResume { + /** + * Card illustrator + */ + public illustrator?: string + + /** + * Card Rarity + * + * - None https://www.tcgdex.net/database/sm/smp/SM01 + * - Common https://www.tcgdex.net/database/xy/xy9/1 + * - Uncommon https://www.tcgdex.net/database/xy/xy9/2 + * - Rare https://www.tcgdex.net/database/xy/xy9/3 + * - Ultra Rare + * - Secret Rare + */ + public rarity!: string + + /** + * Card Category + * + * - Pokemon + * - Trainer + * - Energy + */ + public category!: string + + /** + * Card Variants (Override Set Variants) + */ + public variants?: Variants + + /** + * Card Set + */ + public set!: SetResume + + /** + * Pokemon only elements + */ + + /** + * Pokemon Pokedex ID + */ + public dexId?: Array + + /** + * Pokemon HP + */ + public hp?: number + + /** + * Pokemon Types + * ex for multiple https://www.tcgdex.net/database/ex/ex13/17 + */ + public types?: Array + + /** + * Pokemon Sub Evolution + */ + public evolveFrom?: string + + /** + * Pokemon Weight + */ + public weight?: string + + /** + * Pokemon Description + */ + public description?: string + + /** + * Level of the Pokemon + * + * NOTE: can be equal to 'X' when the pokemon is a LEVEL-UP one + */ + public level?: number | string + + /** + * Pokemon Stage + * + * - Basic https://www.tcgdex.net/database/xy/xy9/1 + * - BREAK https://www.tcgdex.net/database/xy/xy9/18 + * - LEVEL-UP https://www.tcgdex.net/database/dp/dp1/121 + * - MEGA https://www.tcgdex.net/database/xy/xy1/2 + * - RESTORED https://www.tcgdex.net/database/bw/bw5/53 + * - Stage1 https://www.tcgdex.net/database/xy/xy9/2 + * - Stage2 https://www.tcgdex.net/database/xy/xy9/3 + * - VMAX https://www.tcgdex.net/database/swsh/swsh1/50 + */ + public stage?: string + + /** + * Card Suffix + * + * - EX https://www.tcgdex.net/database/ex/ex2/94 + * - GX https://www.tcgdex.net/database/sm/sm12/4 + * - V https://www.tcgdex.net/database/swsh/swsh1/1 + * - Legend https://www.tcgdex.net/database/hgss/hgss1/114 + * - Prime https://www.tcgdex.net/database/hgss/hgss2/85 + * - SP https://www.tcgdex.net/database/pl/pl1/7 + * - TAG TEAM-GX https://www.tcgdex.net/database/sm/sm12/226 + */ + public suffix?: string + + /** + * Pokemon Held Item + * + * ex https://www.tcgdex.net/database/dp/dp2/75 + */ + public item?: { + name: string + effect: string + } + + /** + * Pokemon Abilities + * + * multi abilities ex https://www.tcgdex.net/database/ex/ex15/10 + */ + public abilities?: Array<{ + type: string + name: string + effect: string + }> + + /** + * Pokemon Attacks + */ + public attacks?: Array<{ + cost?: Array + name: string + effect?: string + damage?: string | number + }> + + /** + * Pokemon Weaknesses + */ + public weaknesses?: Array<{ + type: string + value?: string + }> + + public resistances?: Array<{ + type: string + value?: string + }> + + public retreat?: number + + // Trainer/Energy + public effect?: string + + // Trainer Only + public trainerType?: string + + // Energy Only + public energyType?: string + + /** + * Define the rotation mark on cards >= Sword & Shield + */ + public regulationMark?: string + + /** + * Card ability to be played in official tournaments + * + * Note: all cards are avaialable to play in unlimited tournaments + */ + public legal!: { + + /** + * Ability to play in standard tournaments + */ + standard: boolean + + /** + * Ability to play in expanded tournaments + */ + expanded: boolean + } + + public async getFullCard(): Promise { + return this + } + + public async getSet(): Promise { + return this.sdk.set.get(this.set.id) + } +} diff --git a/src/models/CardResume.ts b/src/models/CardResume.ts new file mode 100644 index 0000000..bdd5156 --- /dev/null +++ b/src/models/CardResume.ts @@ -0,0 +1,47 @@ +import { Extension, Quality } from '../interface' +import Card from './Card' +import Model from './Model' + +export default class CardResume extends Model { + /** + * Globally unique card ID based on the set ID and the cards ID within the set + */ + public id!: string + + /** + * Card image url without the extension and quality + * + * @see {@link getImageURL} + */ + public image?: string + + /** + * ID indexing this card within its set, usually just its number + */ + public localId!: string + + /** + * Card Name (Including the suffix if next to card name) + */ + public name!: string + + /** + * the the Card Image full URL + * + * @param {Quality} quality the quality you want your image to be in + * @param {Extension} extension extension you want you image to be + * @return the full card URL + */ + public getImageURL(quality: Quality = 'high', extension: Extension = 'png'): string { + return `${this.image}/${quality}.${extension}` + } + + /** + * Get the full Card + * + * @return the full card if available + */ + public async getFullCard(): Promise { + return this.sdk.card.get(this.id) + } +} diff --git a/src/models/Model.ts b/src/models/Model.ts new file mode 100644 index 0000000..4f5b101 --- /dev/null +++ b/src/models/Model.ts @@ -0,0 +1,28 @@ +import { objectLoop } from '@dzeio/object-util' +import TCGdex from '../tcgdex' + +export default abstract class Model { + + public constructor( + protected readonly sdk: TCGdex + ) {} + + /** + * build a model depending on the data given + * @param model the model to build + * @param data the data to fill it with + */ + public static build(model: T, data?: any): T { + if (!data) { + throw new Error('data is necessary.') + } + model.fill(data) + return model + } + + protected fill(obj: any) { + objectLoop(obj, (value, key) => { + (this as any)[key] = value + }) + } +} diff --git a/src/models/Other.d.ts b/src/models/Other.d.ts new file mode 100644 index 0000000..0f88424 --- /dev/null +++ b/src/models/Other.d.ts @@ -0,0 +1,6 @@ +export interface Variants { + normal?: boolean + reverse?: boolean + holo?: boolean + firstEdition?: boolean +} diff --git a/src/models/Serie.ts b/src/models/Serie.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/models/SerieResume.ts b/src/models/SerieResume.ts new file mode 100644 index 0000000..d5328c9 --- /dev/null +++ b/src/models/SerieResume.ts @@ -0,0 +1,5 @@ +import Model from './Model' + +export default class SerieResume extends Model { + +} diff --git a/src/models/Set.ts b/src/models/Set.ts new file mode 100644 index 0000000..4faf948 --- /dev/null +++ b/src/models/Set.ts @@ -0,0 +1,66 @@ +import { CardResume, SupportedLanguages } from '../interfaces' +import TCGdex from '../tcgdex' +import Model from './Model' +import SetResume from './SetResume' + +export default class Set extends SetResume { + public serie!: SerieResume + public tcgOnline?: string + public variants?: variants + + public releaseDate!: string + + /** + * Designate if the set is usable in tournaments + * + * Note: this is specific to the set and if a + * card is banned from the set it will still be true + */ + public legal!: { + + /** + * Ability to play in standard tournaments + */ + standard: boolean + + /** + * Ability to play in expanded tournaments + */ + expanded: boolean + } + + public cardCount!: { + + /** + * total of number of cards + */ + total: number + + /** + * number of cards officialy (on the bottom of each cards) + */ + official: number + + /** + * number of cards having a normal version + */ + normal: number + + /** + * number of cards having an reverse version + */ + reverse: number + + /** + * number of cards having an holo version + */ + holo: number + + /** + * Number of possible cards + */ + firstEd?: number + } + + public cards!: Array +} diff --git a/src/models/SetResume.ts b/src/models/SetResume.ts new file mode 100644 index 0000000..15cb0ba --- /dev/null +++ b/src/models/SetResume.ts @@ -0,0 +1,25 @@ +import Model from './Model' +import type Set from './Set' + +export default class SetResume extends Model { + public id!: string + public name!: string + public logo?: string + public symbol?: string + public cardCount!: { + + /** + * total of number of cards + */ + total: number + + /** + * number of cards officialy (on the bottom of each cards) + */ + official: number + } + + public getFullSet(): Promise { + return this.sdk.set.get(this.id) + } +} diff --git a/src/models/StringEndpoint.ts b/src/models/StringEndpoint.ts new file mode 100644 index 0000000..0f3b59b --- /dev/null +++ b/src/models/StringEndpoint.ts @@ -0,0 +1,12 @@ +import { CardResume } from '../interfaces' +import Model from './Model' +const ENDPOINTS = ['dex-ids', 'energy-types', 'hp', 'illustrators', 'rarities', 'regulation-marks', 'retreats', 'stages', 'suffixes', 'trainer-types', 'types', 'variants'] as const + +export default class StringEndpoint extends Model { + public name!: string + public cards!: Array + + public constructor( + private readonly endpoint: (typeof ENDPOINTS)[number] + ) {super()} +} diff --git a/src/tcgdex.ts b/src/tcgdex.ts index 01fb53b..5786500 100644 --- a/src/tcgdex.ts +++ b/src/tcgdex.ts @@ -1,24 +1,67 @@ +import { objectLoop } from '@dzeio/object-util' import RequestWrapper from './Request' -import { Serie, Set, Card, CardResume, SerieList, SetList, SupportedLanguages, StringEndpoint } from './interfaces' +import Endpoint from './endpoints/Endpoint' +import { Card, CardResume, Serie, SerieList, Set, SetList, StringEndpoint, SupportedLanguages } from './interfaces' +import CardModel from './models/Card' +import CardResumeModel from './models/CardResume' +import SetModel from './models/Set' +import SetResumeModel from './models/SetResume' type Endpoint = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | 'trainer-types' | 'types' | 'variants' const ENDPOINTS: Array = ['cards', 'categories', 'dex-ids', 'energy-types', 'hp', 'illustrators', 'rarities', 'regulation-marks', 'retreats', 'series', 'sets', 'stages', 'suffixes', 'trainer-types', 'types', 'variants'] -const BASE_URL = 'https://api.tcgdex.net/v2' + export default class TCGdex { - public static fetch: typeof fetch + public static fetch: typeof fetch = fetch /** - * @deprecated to change the lang use `this.lang` + * @deprecated to change the lang use {@link TCGdex.getDefaultLanguage} and {@link TCGdex.setDefaultLanguage} */ public static defaultLang: SupportedLanguages = 'en' - public constructor(public lang?: SupportedLanguages) {} + private static instance: Partial> = {} + + private static endpointURL = 'https://api.tcgdex.net/v2' + + public card = new Endpoint(this, CardModel, CardResumeModel, 'cards') + public set = new Endpoint(this, SetModel, SetResumeModel, 'sets') + + public constructor(public lang?: SupportedLanguages) { + TCGdex.instance[lang ?? TCGdex.defaultLang] = this + } + + public static getInstance(lang: SupportedLanguages = TCGdex.defaultLang): TCGdex { + if (lang in this.instance && this.instance[lang]?.lang !== lang) { + delete this.instance[lang] + } + if (!this.instance[lang]) { + this.instance[lang] = new TCGdex(lang) + } + return this.instance[lang]! + } + + public static setEndpoint(endpoint: string) { + this.endpointURL = endpoint + } + public static getEndpoint(): string { + return this.endpointURL + } + + public static setDefaultLang(lang: SupportedLanguages) { + this.defaultLang = lang + } + public static getDefaultLang(): SupportedLanguages { + return this.defaultLang + } public getLang(): SupportedLanguages { return this.lang ?? TCGdex.defaultLang ?? 'en' } + public setLang(lang: SupportedLanguages) { + this.lang = lang + } + /** * Shortcut to easily fetch a card using both it's global id and it's local ID * @param id the card global/local ID @@ -160,13 +203,45 @@ export default class TCGdex { return this.makeRequest(baseEndpoint, ...endpoint) } + public async fetchWithQuery(endpoint: [Endpoint, ...Array], query?: Record) { + if (endpoint.length === 0) { + throw new Error('endpoint to fetch is empty!') + } + const baseEndpoint = endpoint[0].toLowerCase() as Endpoint + if (!ENDPOINTS.includes(baseEndpoint)) { + throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`) + } + return this.makeRequest2(endpoint, query) + } + /** * Function to make the request and normalize the whole path */ private makeRequest(...url: Array) { + return this.makeRequest2(url) + } + + /** + * Function to make the request and normalize the whole path + */ + private makeRequest2(url: Array, searchParams?: Record) { // Normalize path - const path = url.map((subPath) => encodeURI( - subPath + let path = url.map(this.encode).join('/') + if (searchParams) { + path += '?' + objectLoop(searchParams, (value, key, index) => { + if (index !== 0) { + path += '&' + } + path += `${this.encode(key)}=${this.encode(value)}` + }) + } + return RequestWrapper.fetch(`${TCGdex.endpointURL}/${this.getLang()}/${path}`) + } + + private encode(str: string | number | boolean): string { + return encodeURI( + str // Transform numbers to string .toString() // replace this special character with an escaped one @@ -176,10 +251,10 @@ export default class TCGdex { // remove some special chars by nothing // eslint-disable-next-line no-misleading-character-class .replace(/["'\u0300-\u036f]/gu, '') - )).join('/') - return RequestWrapper.fetch(`${BASE_URL}/${this.getLang()}/${path}`) + ) } } -export * from './interfaces' +// export * from './interfaces' +export * from './models/Card' diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..3a306ab --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,31 @@ +import { objectLoop } from '@dzeio/object-util' +import { Query, QueryPagination, QuerySort } from './interface' + +export function parseQuery( + query?: Query, + sort?: QuerySort, + pagination?: QueryPagination +): Record { + const final: Record = {} + if (query) { + objectLoop(query as any, (v, k) => { + // special case, skip lang attribute + if (k === 'lang') { + return + } + final[k] = v + }) + } + if (sort) { + objectLoop(sort, (v, k) => { + final[`sort:${k}`] = v as string + }) + } + if (pagination) { + objectLoop(pagination, (v, k) => { + final[`pagination:${k}`] = v as string + }) + } + + return final +} diff --git a/tsconfig.json b/tsconfig.json index 70326d5..b7bc65b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,7 @@ { "extends": "./node_modules/@dzeio/config/tsconfig.base", - "include": ["./src/tcgdex.node.ts"], "compilerOptions": { - "target": "ES2015", - "rootDir": "./src", + "outDir": "dist", + "importsNotUsedAsValues": "error" } } From 0b3c63223b088a79513c94e4cdeff9fe69717837 Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 2 Sep 2024 17:01:20 +0200 Subject: [PATCH 2/9] feat: Add a better caching system Signed-off-by: Avior --- src/Psr/SimpleCache/CacheAbstract.ts | 38 ++++++++ src/Psr/SimpleCache/CacheInterface.ts | 109 +++++++++++++++++++++++ src/Psr/SimpleCache/LocalStorageCache.ts | 91 +++++++++++++++++++ src/Psr/SimpleCache/MemoryCache.ts | 58 ++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 src/Psr/SimpleCache/CacheAbstract.ts create mode 100644 src/Psr/SimpleCache/CacheInterface.ts create mode 100644 src/Psr/SimpleCache/LocalStorageCache.ts create mode 100644 src/Psr/SimpleCache/MemoryCache.ts diff --git a/src/Psr/SimpleCache/CacheAbstract.ts b/src/Psr/SimpleCache/CacheAbstract.ts new file mode 100644 index 0000000..68c2b24 --- /dev/null +++ b/src/Psr/SimpleCache/CacheAbstract.ts @@ -0,0 +1,38 @@ +import { objectLoop } from '@dzeio/object-util' +import type CacheInterface from './CacheInterface' + +export default abstract class CacheAsbract implements CacheInterface { + + public getMultiple(keys: Array, defaultValues?: Array | undefined): Record { + const res: Record = {} + for (let idx = 0; idx < keys.length; idx++) { + const key = keys[idx] as string + const value = this.get(key, defaultValues?.[idx]) as T | undefined + if (typeof value === 'undefined') { + continue + } + res[key] = value + } + return res + } + + public setMultiple(values: Record, ttl?: number | undefined): boolean { + objectLoop(values, (v, k) => { + this.set(k, v, ttl) + }) + return true + } + + public deleteMultiple(keys: Array): boolean { + for (const key of keys) { + this.delete(key) + } + return true + } + + public abstract get(key: string, defaultValue?: T): T | undefined + public abstract set(key: string, value: T, ttl?: number): boolean + public abstract delete(key: string): boolean + public abstract clear(): boolean + public abstract has(key: string): boolean +} diff --git a/src/Psr/SimpleCache/CacheInterface.ts b/src/Psr/SimpleCache/CacheInterface.ts new file mode 100644 index 0000000..b1556e9 --- /dev/null +++ b/src/Psr/SimpleCache/CacheInterface.ts @@ -0,0 +1,109 @@ +export default interface CacheInterface { + /** + * Fetches a value from the cache. + * + * @param key The unique key of this item in the cache. + * @param defaultValue Default value to return if the key does not exist. + * + * @return T The value of the item from the cache, or $default in case of cache miss. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + get(key: string, defaultValue?: T): T | undefined + + /** + * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. + * + * @param key The key of the item to store. + * @param value The value of the item to store. Must be serializable. + * @param {null|number} ttl The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + set(key: string, value: T, ttl?: number): boolean + + /** + * Delete an item from the cache by its unique key. + * + * @param key The unique cache key of the item to delete. + * + * @return True if the item was successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + delete(key: string): boolean + + /** + * Wipes clean the entire cache's keys. + * + * @return boolean True on success and false on failure. + */ + clear(): boolean + + /** + * Obtains multiple cache items by their unique keys. + * + * @param keys A list of keys that can obtained in a single operation. + * @param defaultValues $default Default value to return for keys that do not exist. + * + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + getMultiple(keys: Array, defaultValues?: Array): Record + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param values A list of key => value pairs for a multiple-set operation. + * @param ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + setMultiple(values: Record, ttl?: number): boolean + + /** + * Deletes multiple cache items in a single operation. + * + * @param keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + deleteMultiple(keys: Array): boolean + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it, making the state of your app out of date. + * + * @param key The cache item key. + * + * @return bool + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + has(key: string): boolean +} diff --git a/src/Psr/SimpleCache/LocalStorageCache.ts b/src/Psr/SimpleCache/LocalStorageCache.ts new file mode 100644 index 0000000..dc25b1b --- /dev/null +++ b/src/Psr/SimpleCache/LocalStorageCache.ts @@ -0,0 +1,91 @@ +import CacheAsbract from './CacheAbstract' + +interface CacheItem { + data: T + expire?: number | undefined +} + +/** + * A cache implementation that uses browser storage. + * + * This class extends `CacheAsbract` and provides a concrete implementation + * of the caching interface. It stores cached items in browser storage, + * which is suitable for storing small amounts of data. + */ +export default class BrowserStorageCache extends CacheAsbract { + private storage: Storage + public constructor(private readonly prefix?: string, session = false) { + super() + if (session) { + this.storage = window.sessionStorage + } else { + this.storage = window.localStorage + } + } + + public get(key: string, defaultValue?: T | undefined): T | undefined { + const raw = this.storage.getItem(this.getFinalKey(key)) + + if (!raw) { + return defaultValue ?? undefined + } + + const item: CacheItem = JSON.parse(raw) + + if (item.expire && item.expire < new Date().getTime()) { + this.delete(key) + return defaultValue ?? undefined + } + + return item.data + } + + public set(key: string, value: T, ttl?: number | undefined): boolean { + let expire = undefined + if (ttl) { + expire = (new Date()).getTime() + (ttl * 1000) + } + const data: CacheItem = { + data: value, + expire: expire + } + this.storage.setItem(this.getFinalKey(key), JSON.stringify(data)) + + return true + } + + public delete(key: string): boolean { + this.storage.removeItem(this.getFinalKey(key)) + + return true + } + + public clear(): boolean { + const keys = this.keys() + return this.deleteMultiple(keys) + } + + public has(key: string): boolean { + return !!this.storage.getItem(this.getFinalKey(key)) + } + + private keys(): Array { + const list: Array = [] + for (let idx = 0; idx < this.storage.length; idx++) { + const key = this.storage.key(idx) + if (!key || this.prefix && !key?.startsWith(`${this.prefix}/`)) { + continue + } + list.push(key) + } + + return list + } + + private getFinalKey(key: string): string { + if (!this.prefix) { + return key + } + return `${this.prefix}/${key}` + } +} diff --git a/src/Psr/SimpleCache/MemoryCache.ts b/src/Psr/SimpleCache/MemoryCache.ts new file mode 100644 index 0000000..15458b9 --- /dev/null +++ b/src/Psr/SimpleCache/MemoryCache.ts @@ -0,0 +1,58 @@ +import CacheAsbract from './CacheAbstract' + +interface CacheItem { + data: T + expire?: number | undefined +} + +/** + * Memory cache implementation that stores cached items in memory. + * This class extends the abstract `CacheAbstract` and provides a basic in-memory caching mechanism. + * + * @class MemoryCache + */ +export default class MemoryCache extends CacheAsbract { + private cache: Map> = new Map() + + public get(key: string, defaultValue?: T | undefined): T | undefined { + const item = this.cache.get(key) + + if (!item) { + return defaultValue ?? undefined + } + + if (item.expire && item.expire < new Date().getTime()) { + this.delete(key) + return defaultValue ?? undefined + } + + return item.data as T | undefined + } + + public set(key: string, value: T, ttl?: number | undefined): boolean { + let expire: number | undefined + if (ttl) { + expire = new Date().getTime() + ttl * 1000 + } + this.cache.set(key, { + data: value, + expire: expire + }) + + return true + } + + public delete(key: string): boolean { + this.cache.delete(key) + return true + } + + public clear(): boolean { + this.cache.clear() + return true + } + + public has(key: string): boolean { + return this.cache.has(key) + } +} From d24094f8d7766427d70326e55d4f6537aa91f536 Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 2 Sep 2024 17:01:46 +0200 Subject: [PATCH 3/9] feat: roundup final elements Signed-off-by: Avior --- package-lock.json | 14 +- package.json | 2 +- src/Query.ts | 43 ++++++ src/Request.ts | 32 ----- src/endpoints/Endpoint.ts | 24 ++-- src/interface.d.ts | 46 ------ src/{interfaces.ts => interfaces.d.ts} | 9 ++ src/models/Card.ts | 9 +- src/models/CardResume.ts | 8 +- src/models/Model.ts | 8 +- src/models/Set.ts | 29 +++- src/models/SetResume.ts | 6 +- src/models/StringEndpoint.ts | 7 +- src/tcgdex.ts | 191 +++++++++++++++++++------ src/utils.ts | 45 +++--- tsconfig.json | 2 +- 16 files changed, 276 insertions(+), 199 deletions(-) create mode 100644 src/Query.ts delete mode 100644 src/Request.ts delete mode 100644 src/interface.d.ts rename src/{interfaces.ts => interfaces.d.ts} (94%) diff --git a/package-lock.json b/package-lock.json index 27c9892..97c8b9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.5.1", "license": "MIT", "dependencies": { - "@dzeio/object-util": "^1.7.0", + "@dzeio/object-util": "^1.8.3", "isomorphic-unfetch": "^3", "unfetch": "^4" }, @@ -1751,9 +1751,9 @@ } }, "node_modules/@dzeio/object-util": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.7.0.tgz", - "integrity": "sha512-9/ovColAt/N39UhVdbTynAS5eZPUVdzdNHU0dYotjoBdmc/VhqMzTHTeMj0c/ZKLyGshmlcYeDgf0NDOrhB74g==" + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.8.3.tgz", + "integrity": "sha512-/d0ezut7EGrEKedcD8K2Jb2NAMSFfhxNj4rpUBlGzmmakJjJCXAgXvSDLjUwYrgHuabxbxlAn90Wo727MCzWLA==" }, "node_modules/@eslint/eslintrc": { "version": "1.4.1", @@ -10386,9 +10386,9 @@ } }, "@dzeio/object-util": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.7.0.tgz", - "integrity": "sha512-9/ovColAt/N39UhVdbTynAS5eZPUVdzdNHU0dYotjoBdmc/VhqMzTHTeMj0c/ZKLyGshmlcYeDgf0NDOrhB74g==" + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.8.3.tgz", + "integrity": "sha512-/d0ezut7EGrEKedcD8K2Jb2NAMSFfhxNj4rpUBlGzmmakJjJCXAgXvSDLjUwYrgHuabxbxlAn90Wo727MCzWLA==" }, "@eslint/eslintrc": { "version": "1.4.1", diff --git a/package.json b/package.json index bae9771..9385136 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "node": ">=12" }, "dependencies": { - "@dzeio/object-util": "^1.7.0", + "@dzeio/object-util": "^1", "isomorphic-unfetch": "^3", "unfetch": "^4" }, diff --git a/src/Query.ts b/src/Query.ts new file mode 100644 index 0000000..d34a103 --- /dev/null +++ b/src/Query.ts @@ -0,0 +1,43 @@ +export default class Query +{ + public params: Record = {} + + public static create(): Query + { + return new Query() + } + + public includes(key: string, value: string): this + { + return this.contains(key, value) + } + + public contains(key: string, value: string): this + { + this.params[key] = value + return this + } + + public equal(key: string, value: string): this + { + this.params[key] = `eq:${value}` + + return this + } + + public sort(key: string, order: string): this + { + this.params['sort:field'] = key + this.params['sort:order'] = order + + return this + } + + public paginate(page: number, itemsPerPage: number): this + { + this.params['pagination:page'] = page + this.params['pagination:itemsPerPage'] = itemsPerPage + + return this + } +} diff --git a/src/Request.ts b/src/Request.ts deleted file mode 100644 index b87f904..0000000 --- a/src/Request.ts +++ /dev/null @@ -1,32 +0,0 @@ -import TCGdex from './tcgdex' -import { version } from './version' - -export default class Request { - - // 1 hour of TTL by default - public static ttl = 1000 * 60 * 60 - - private static cache: Record = {} - - public static async fetch(url: string): Promise { - console.log(url) - let request = this.cache[url] - const now = new Date().getTime() - if (!request || now - request.time > this.ttl) { - const unfetch = TCGdex.fetch - const resp = await unfetch(url, { - headers: { - 'user-agent': `@tcgdex/javascript-sdk/${version}` - } - }) - if (resp.status !== 200) { - return undefined - } - - this.cache[url] = { response: await resp.json(), time: now } - request = this.cache[url] - } - return request.response - } - -} diff --git a/src/endpoints/Endpoint.ts b/src/endpoints/Endpoint.ts index b8903a4..c5d24eb 100644 --- a/src/endpoints/Endpoint.ts +++ b/src/endpoints/Endpoint.ts @@ -1,26 +1,26 @@ -import { Query } from '../interface' +import type { Endpoints } from '../interfaces' import Model from '../models/Model' -import TCGdex from '../tcgdex' -import { parseQuery } from '../utils' - -type BaseEndpoint = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | 'trainer-types' | 'types' | 'variants' +import type Query from '../Query' +import type TCGdex from '../tcgdex' export default class Endpoint { public constructor( protected readonly tcgdex: TCGdex, protected readonly itemModel: new (sdk: TCGdex) => Item, protected readonly listModel: new (sdk: TCGdex) => List, - protected readonly endpoint: BaseEndpoint - + protected readonly endpoint: Endpoints ) {} - public async get(id: string | number): Promise { - const res = await this.tcgdex.fetch(this.endpoint as any, id as string) + public async get(id: string | number): Promise { + const res = await this.tcgdex.fetch(this.endpoint as 'cards', id as string) + if (!res) { + return null + } return Model.build(new this.itemModel(this.tcgdex), res) } - public async list(query: Query): Promise> { - const res = await this.tcgdex.fetchWithQuery([this.endpoint as any], parseQuery(query)) - return (res as Array ?? []).map((it) => Model.build(new this.listModel(this.tcgdex), it)) + public async list(query: Query): Promise> { + const res = await this.tcgdex.fetchWithQuery([this.endpoint], query.params) + return (res as Array ?? []).map((it) => Model.build(new this.listModel(this.tcgdex), it)) } } diff --git a/src/interface.d.ts b/src/interface.d.ts deleted file mode 100644 index 4517f2e..0000000 --- a/src/interface.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -export type Quality = 'low' | 'high' - -export type Extension = 'jpg' | 'webp' | 'png' - -export interface QueryPagination { - page?: number - itemsPerPage?: number -} - -export interface QuerySort { - field: keyof PropertiesExtract - order: 'DESC' | 'ASC' -} - -/** - * Remove the methods from an object and give the remaining - */ -export type ExcludeMethods = { - // eslint-disable-next-line @typescript-eslint/ban-types - [K in keyof T]: T[K] extends Function ? never : K -}[keyof T] - -/** - * extract the properties from an object - */ -export type PropertiesExtract = { - [K in ExcludeMethods]: T[K] -} - -// Helper type to extract properties and flatten nested objects -export type MergeProperties = { - [K in keyof T]: T[K] extends object ? `${K & string}.${MergeProperties}` : K; -}[keyof T] - -// Main type to flatten the class properties -export type Query = { - [K in MergeProperties as K extends string ? K : never]?: K extends `${infer Prefix}.${infer Rest}` - ? Prefix extends keyof T - ? Rest extends MergeProperties - ? T[Prefix][Rest & keyof T[Prefix]] - : never - : never - : K extends keyof T - ? T[K] - : never -} diff --git a/src/interfaces.ts b/src/interfaces.d.ts similarity index 94% rename from src/interfaces.ts rename to src/interfaces.d.ts index 512c8d7..0cd2ac1 100644 --- a/src/interfaces.ts +++ b/src/interfaces.d.ts @@ -310,3 +310,12 @@ export interface StringEndpoint { name: string cards: Array } + +export type Quality = 'low' | 'high' + +export type Extension = 'jpg' | 'webp' | 'png' + +export type Endpoints = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | + 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | + 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | + 'trainer-types' | 'types' | 'variants' diff --git a/src/models/Card.ts b/src/models/Card.ts index e27413c..04f1246 100644 --- a/src/models/Card.ts +++ b/src/models/Card.ts @@ -1,6 +1,7 @@ import CardResume from './CardResume' import type { Variants } from './Other' -import type Set from './Set' +import type TCGdexSet from './Set' +import type SetResume from './SetResume' // TODO: sort elements by alphabetical order export default class Card extends CardResume { @@ -187,11 +188,11 @@ export default class Card extends CardResume { expanded: boolean } - public async getFullCard(): Promise { + public async getFullCard(): Promise { return this } - public async getSet(): Promise { - return this.sdk.set.get(this.set.id) + public async getSet(): Promise { + return (await this.sdk.set.get(this.set.id))! } } diff --git a/src/models/CardResume.ts b/src/models/CardResume.ts index bdd5156..c56af16 100644 --- a/src/models/CardResume.ts +++ b/src/models/CardResume.ts @@ -1,5 +1,5 @@ -import { Extension, Quality } from '../interface' -import Card from './Card' +import type { Extension, Quality } from '../interfaces' +import type Card from './Card' import Model from './Model' export default class CardResume extends Model { @@ -41,7 +41,7 @@ export default class CardResume extends Model { * * @return the full card if available */ - public async getFullCard(): Promise { - return this.sdk.card.get(this.id) + public async getFullCard(): Promise { + return (await this.sdk.card.get(this.id))! } } diff --git a/src/models/Model.ts b/src/models/Model.ts index 4f5b101..010ea75 100644 --- a/src/models/Model.ts +++ b/src/models/Model.ts @@ -1,5 +1,5 @@ import { objectLoop } from '@dzeio/object-util' -import TCGdex from '../tcgdex' +import type TCGdex from '../tcgdex' export default abstract class Model { @@ -12,7 +12,7 @@ export default abstract class Model { * @param model the model to build * @param data the data to fill it with */ - public static build(model: T, data?: any): T { + public static build(model: T, data?: object): T { if (!data) { throw new Error('data is necessary.') } @@ -20,9 +20,9 @@ export default abstract class Model { return model } - protected fill(obj: any) { + protected fill(obj: object) { objectLoop(obj, (value, key) => { - (this as any)[key] = value + (this as object)[key] = value }) } } diff --git a/src/models/Set.ts b/src/models/Set.ts index 4faf948..4d4dd0f 100644 --- a/src/models/Set.ts +++ b/src/models/Set.ts @@ -1,12 +1,18 @@ -import { CardResume, SupportedLanguages } from '../interfaces' -import TCGdex from '../tcgdex' +import { objectLoop } from '@dzeio/object-util' +import CardResume from './CardResume' import Model from './Model' -import SetResume from './SetResume' +import type { Variants } from './Other' +import type SerieResume from './SerieResume' -export default class Set extends SetResume { +// biome-ignore lint/suspicious/noShadowRestrictedNames: +export default class Set extends Model { + public id!: string + public name!: string + public logo?: string + public symbol?: string public serie!: SerieResume public tcgOnline?: string - public variants?: variants + public variants?: Variants public releaseDate!: string @@ -63,4 +69,17 @@ export default class Set extends SetResume { } public cards!: Array + + protected fill(obj: object): void { + objectLoop(obj, (value, key) => { + switch (key) { + case 'cards': + this.cards = (value as Array).map((it) => Model.build(new CardResume(this.sdk), it)) + break + default: + this[key] = value + break + } + }) + } } diff --git a/src/models/SetResume.ts b/src/models/SetResume.ts index 15cb0ba..db2b3c3 100644 --- a/src/models/SetResume.ts +++ b/src/models/SetResume.ts @@ -1,5 +1,5 @@ import Model from './Model' -import type Set from './Set' +import type TCGdexSet from './Set' export default class SetResume extends Model { public id!: string @@ -19,7 +19,7 @@ export default class SetResume extends Model { official: number } - public getFullSet(): Promise { - return this.sdk.set.get(this.id) + public async getFullSet(): Promise { + return (await this.sdk.set.get(this.id))! } } diff --git a/src/models/StringEndpoint.ts b/src/models/StringEndpoint.ts index 0f3b59b..16dd2dd 100644 --- a/src/models/StringEndpoint.ts +++ b/src/models/StringEndpoint.ts @@ -1,12 +1,7 @@ -import { CardResume } from '../interfaces' +import type CardResume from './CardResume' import Model from './Model' -const ENDPOINTS = ['dex-ids', 'energy-types', 'hp', 'illustrators', 'rarities', 'regulation-marks', 'retreats', 'stages', 'suffixes', 'trainer-types', 'types', 'variants'] as const export default class StringEndpoint extends Model { public name!: string public cards!: Array - - public constructor( - private readonly endpoint: (typeof ENDPOINTS)[number] - ) {super()} } diff --git a/src/tcgdex.ts b/src/tcgdex.ts index 5786500..36934b9 100644 --- a/src/tcgdex.ts +++ b/src/tcgdex.ts @@ -1,57 +1,111 @@ import { objectLoop } from '@dzeio/object-util' -import RequestWrapper from './Request' +import type CacheInterface from './Psr/SimpleCache/CacheInterface' +import LocalStorageCache from './Psr/SimpleCache/LocalStorageCache' +import MemoryCache from './Psr/SimpleCache/MemoryCache' import Endpoint from './endpoints/Endpoint' -import { Card, CardResume, Serie, SerieList, Set, SetList, StringEndpoint, SupportedLanguages } from './interfaces' +import type { + Card, + CardResume, + Endpoints, + Serie, + SerieList, + SetList, + StringEndpoint, + SupportedLanguages, + Set as TCGdexSet +} from './interfaces' import CardModel from './models/Card' import CardResumeModel from './models/CardResume' import SetModel from './models/Set' import SetResumeModel from './models/SetResume' -type Endpoint = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | 'trainer-types' | 'types' | 'variants' - -const ENDPOINTS: Array = ['cards', 'categories', 'dex-ids', 'energy-types', 'hp', 'illustrators', 'rarities', 'regulation-marks', 'retreats', 'series', 'sets', 'stages', 'suffixes', 'trainer-types', 'types', 'variants'] +import { detectContext, ENDPOINTS } from './utils' +import { version } from './version' export default class TCGdex { + /** + * How the remote data is going to be fetched + */ public static fetch: typeof fetch = fetch /** - * @deprecated to change the lang use {@link TCGdex.getDefaultLanguage} and {@link TCGdex.setDefaultLanguage} + * @deprecated to change the lang use {@link TCGdex.getLang} and {@link TCGdex.setLang} */ public static defaultLang: SupportedLanguages = 'en' - private static instance: Partial> = {} + /** + * the previously hidden caching system used by TCGdex to not kill the API + */ + public cache: CacheInterface = + detectContext() === 'browser' ? new LocalStorageCache('tcgdex-cache') : new MemoryCache() - private static endpointURL = 'https://api.tcgdex.net/v2' + /** + * the default cache TTL, only subsequent requests will have their ttl changed + */ + public cacheTTL = 60 * 60 - public card = new Endpoint(this, CardModel, CardResumeModel, 'cards') - public set = new Endpoint(this, SetModel, SetResumeModel, 'sets') + public readonly card = new Endpoint(this, CardModel, CardResumeModel, 'cards') + public readonly set = new Endpoint(this, SetModel, SetResumeModel, 'sets') - public constructor(public lang?: SupportedLanguages) { - TCGdex.instance[lang ?? TCGdex.defaultLang] = this + private lang: SupportedLanguages = 'en' + private endpointURL = 'https://api.tcgdex.net/v2' + + /** + * @deprecated use the constructor parameter or {@link TCGdex.setLang} when in an instance + */ + public static setDefaultLang(lang: SupportedLanguages) { + TCGdex.defaultLang = lang } - public static getInstance(lang: SupportedLanguages = TCGdex.defaultLang): TCGdex { - if (lang in this.instance && this.instance[lang]?.lang !== lang) { - delete this.instance[lang] - } - if (!this.instance[lang]) { - this.instance[lang] = new TCGdex(lang) - } - return this.instance[lang]! + /** + * @deprecated use {@link TCGdex.setLang} when in an instance + */ + public static getDefaultLang(): SupportedLanguages { + return TCGdex.defaultLang } - public static setEndpoint(endpoint: string) { + /** + * the endpoint URL + * ex: `https://api.tcgdex.net/v2` + * @param endpoint the url + */ + public setEndpoint(endpoint: string) { this.endpointURL = endpoint } - public static getEndpoint(): string { + public getEndpoint(): string { return this.endpointURL } - public static setDefaultLang(lang: SupportedLanguages) { - this.defaultLang = lang + /** + * set the current cache methodology + * @param cache the cache to use + */ + public setCache(cache: CacheInterface) { + this.cache = cache } - public static getDefaultLang(): SupportedLanguages { - return this.defaultLang + + /** + * get the current cache methodology + * @param cache the cache to use + */ + public getCache(): CacheInterface { + return this.cache + } + + /** + * the endpoint URL + * ex: `https://api.tcgdex.net/v2` + * @param endpoint the url + */ + public setCacheTTL(seconds: number) { + this.cacheTTL = seconds + } + /** + * get the current useed cache ttl in seconds + * @returns the cache ttl in seconds + */ + public getCacheTTL(): number { + return this.cacheTTL } public getLang(): SupportedLanguages { @@ -90,7 +144,7 @@ export default class TCGdex { /** * @deprecated use `this.fetch('sets', set)` */ - public async fetchSet(set: string): Promise { + public async fetchSet(set: string): Promise { return this.fetch('sets', set) } @@ -147,7 +201,7 @@ export default class TCGdex { * @param endpoint_0 'sets' * @param endpoint_1 {string} the set name or ID */ - public async fetch(...endpoint: ['sets', string]): Promise + public async fetch(...endpoint: ['sets', string]): Promise /** * Fetch every sets @@ -191,7 +245,7 @@ export default class TCGdex { * @param endpoint_1 {string} (Optionnal) some details to go from the index file to the item file (mostly the ID/name) * @param endpoint_2 {string} (Optionnal) only for sets the card local ID to fetch the card through the set */ - public async fetch(...endpoint: Array): Promise { + public async fetch(...endpoint: Array): Promise { if (endpoint.length === 0) { throw new Error('endpoint to fetch is empty!') } @@ -200,33 +254,38 @@ export default class TCGdex { if (!ENDPOINTS.includes(baseEndpoint)) { throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`) } - return this.makeRequest(baseEndpoint, ...endpoint) + return this.actualFetch(this.getFullURL([baseEndpoint, ...endpoint])) } - public async fetchWithQuery(endpoint: [Endpoint, ...Array], query?: Record) { + /** + * @param endpoint the endpoint to fetch + * @param query the query + */ + public async fetchWithQuery( + endpoint: [Endpoints, ...Array], + query?: Record + ): Promise { if (endpoint.length === 0) { throw new Error('endpoint to fetch is empty!') } - const baseEndpoint = endpoint[0].toLowerCase() as Endpoint + const baseEndpoint = endpoint[0].toLowerCase() as Endpoints if (!ENDPOINTS.includes(baseEndpoint)) { throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`) } - return this.makeRequest2(endpoint, query) - } - - /** - * Function to make the request and normalize the whole path - */ - private makeRequest(...url: Array) { - return this.makeRequest2(url) + return this.actualFetch(this.getFullURL(endpoint, query)) } /** - * Function to make the request and normalize the whole path + * format the final URL */ - private makeRequest2(url: Array, searchParams?: Record) { + private getFullURL( + url: Array, + searchParams?: Record + ): string{ // Normalize path let path = url.map(this.encode).join('/') + + // handle the Search Params if (searchParams) { path += '?' objectLoop(searchParams, (value, key, index) => { @@ -236,9 +295,51 @@ export default class TCGdex { path += `${this.encode(key)}=${this.encode(value)}` }) } - return RequestWrapper.fetch(`${TCGdex.endpointURL}/${this.getLang()}/${path}`) + + // return with the endpoint and all the shit + return `${this.getEndpoint()}/${this.getLang()}/${path}` + } + + private async actualFetch(path: string): Promise { + // get and return the cached value if available + const cached = this.cache.get(path) + if (cached) { + return cached as T + } + + // the actual Fetch :D + const resp = await TCGdex.fetch(path, { + headers: { + 'user-agent': `@tcgdex/javascript-sdk/${version}` + } + }) + + // throw if a server-side error is occured + if (resp.status >= 500) { + try { + const json = JSON.stringify(await resp.json()) + throw new Error(json) + } catch { + throw new Error('TCGdex Server responded with an invalid error :(') + } + } + + // response is not valid :O + if (resp.status !== 200) { + return undefined + } + + // parse, put to cache and return + const json = await resp.json() + this.cache.set(path, json, this.cacheTTL) + return json as T } + /** + * encode a string to be used in an url + * @param str the string to encode to URL + * @returns the encoded string + */ private encode(str: string | number | boolean): string { return encodeURI( str @@ -248,13 +349,11 @@ export default class TCGdex { .replace('?', '%3F') // normalize the string .normalize('NFC') - // remove some special chars by nothing + // remove some special chars // eslint-disable-next-line no-misleading-character-class .replace(/["'\u0300-\u036f]/gu, '') ) } - } -// export * from './interfaces' export * from './models/Card' diff --git a/src/utils.ts b/src/utils.ts index 3a306ab..f95b0df 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,31 +1,20 @@ -import { objectLoop } from '@dzeio/object-util' -import { Query, QueryPagination, QuerySort } from './interface' +import type { Endpoints } from './interfaces' -export function parseQuery( - query?: Query, - sort?: QuerySort, - pagination?: QueryPagination -): Record { - const final: Record = {} - if (query) { - objectLoop(query as any, (v, k) => { - // special case, skip lang attribute - if (k === 'lang') { - return - } - final[k] = v - }) +/** + * detect the current running context ofthe program + */ +export function detectContext(): 'browser' | 'server' { + try { + const isBrowser = !!window + return isBrowser ? 'browser' : 'server' + } catch { + return 'server' } - if (sort) { - objectLoop(sort, (v, k) => { - final[`sort:${k}`] = v as string - }) - } - if (pagination) { - objectLoop(pagination, (v, k) => { - final[`pagination:${k}`] = v as string - }) - } - - return final } + +export const ENDPOINTS: Array = [ + 'cards', 'categories', 'dex-ids', 'energy-types', + 'hp', 'illustrators', 'rarities', 'regulation-marks', + 'retreats', 'series', 'sets', 'stages', 'suffixes', + 'trainer-types', 'types', 'variants' +] as const diff --git a/tsconfig.json b/tsconfig.json index b7bc65b..2de7ffc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,6 @@ "extends": "./node_modules/@dzeio/config/tsconfig.base", "compilerOptions": { "outDir": "dist", - "importsNotUsedAsValues": "error" + "strictNullChecks": true } } From 4ab3026ba6d644e90aa02b35a01d12edbdac04c9 Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 2 Sep 2024 17:10:44 +0200 Subject: [PATCH 4/9] chore: removed unfetch Signed-off-by: Avior --- package-lock.json | 5 ++--- package.json | 3 +-- src/tcgdex.browser.ts | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97c8b9d..a6118c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,8 @@ "version": "2.5.1", "license": "MIT", "dependencies": { - "@dzeio/object-util": "^1.8.3", - "isomorphic-unfetch": "^3", - "unfetch": "^4" + "@dzeio/object-util": "^1", + "isomorphic-unfetch": "^3" }, "devDependencies": { "@babel/core": "^7", diff --git a/package.json b/package.json index 9385136..15c6da1 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,7 @@ }, "dependencies": { "@dzeio/object-util": "^1", - "isomorphic-unfetch": "^3", - "unfetch": "^4" + "isomorphic-unfetch": "^3" }, "scripts": { "prebuild": "node scripts/export-version-number.js", diff --git a/src/tcgdex.browser.ts b/src/tcgdex.browser.ts index ffd4a6c..8104c03 100644 --- a/src/tcgdex.browser.ts +++ b/src/tcgdex.browser.ts @@ -1,6 +1,5 @@ -import unfetch from 'unfetch' import TCGdex from './tcgdex' -TCGdex.fetch = window.fetch ?? unfetch as any +TCGdex.fetch = window.fetch export default TCGdex From b5e3f2b6dc4e89fb996eee8bbe56750d2b56793f Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 2 Sep 2024 17:11:44 +0200 Subject: [PATCH 5/9] bump: 2.6.0-beta.1 Signed-off-by: Avior --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6118c8..f2d2e25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tcgdex/sdk", - "version": "2.5.1", + "version": "2.6.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tcgdex/sdk", - "version": "2.5.1", + "version": "2.6.0-beta.1", "license": "MIT", "dependencies": { "@dzeio/object-util": "^1", diff --git a/package.json b/package.json index 15c6da1..9bb0d23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tcgdex/sdk", - "version": "2.5.1", + "version": "2.6.0-beta.1", "main": "./dist/tcgdex.node.js", "module": "./dist/tcgdex.node.mjs", "types": "./dist/tcgdex.node.d.ts", From 4223b85d8a6a07dbc231f3bc6edd111836d36961 Mon Sep 17 00:00:00 2001 From: Avior Date: Thu, 10 Oct 2024 14:44:38 +0200 Subject: [PATCH 6/9] feat: Add finishing touch and tests Signed-off-by: Avior --- __tests__/basic.test.js | 152 ++++++++++++++++++++++++-------- __tests__/cache.test.js | 54 ++++++++++++ __tests__/deprecated.test.js | 66 ++++++++++++++ bun.lockb | Bin 287131 -> 0 bytes package-lock.json | 81 +++++++++++++++-- package.json | 1 + src/Query.ts | 87 +++++++++++++----- src/endpoints/Endpoint.ts | 6 +- src/endpoints/SimpleEndpoint.ts | 24 +++++ src/models/Card.ts | 2 +- src/models/CardResume.ts | 2 +- src/models/Model.ts | 2 +- src/models/Serie.ts | 21 +++++ src/models/SerieResume.ts | 19 ++++ src/models/Set.ts | 4 + src/models/SetResume.ts | 2 +- src/models/StringEndpoint.ts | 16 +++- src/tcgdex.ts | 47 ++++++++-- tsconfig.json | 5 +- 19 files changed, 505 insertions(+), 86 deletions(-) create mode 100644 __tests__/cache.test.js create mode 100644 __tests__/deprecated.test.js delete mode 100644 bun.lockb create mode 100644 src/endpoints/SimpleEndpoint.ts diff --git a/__tests__/basic.test.js b/__tests__/basic.test.js index 4b7fd21..e755419 100644 --- a/__tests__/basic.test.js +++ b/__tests__/basic.test.js @@ -1,5 +1,7 @@ -const TCGdex = require("../src/tcgdex").default -const fetch = require('node-fetch') +/// + +const { default: TCGdex, Query } = require("../src/tcgdex") +import fetch from 'node-fetch' const fakeFetch = (response, status = 200) => jest.fn(() => Promise.resolve({ @@ -8,59 +10,131 @@ const fakeFetch = (response, status = 200) => jest.fn(() => }) ); - - test('Basic test', async () => { const tcgdex = new TCGdex('en') - TCGdex.fetch = fakeFetch({ok: true}) + TCGdex.fetch = fakeFetch({ ok: true }) const res = await tcgdex.fetch('cards', 'basic-test') - expect(res).toEqual({ok: true}) + expect(res).toEqual({ ok: true }) expect(TCGdex.fetch).toHaveBeenCalledTimes(1) }) -test('Cache test', async () => { - const tcgdex = new TCGdex('en') - TCGdex.fetch = fakeFetch({ok: 'a'}) - const res1 = await tcgdex.fetch('cards', 'cache-test') - expect(res1).toEqual({ok: 'a'}) - TCGdex.fetch = fakeFetch({ok: 'b'}) - const res2 = await tcgdex.fetch('cards', 'cache-test') - expect(res2).toEqual({ok: 'a'}) -}) - test('endpoint errors', async () => { const tcgdex = new TCGdex('en') - TCGdex.fetch = fakeFetch({ok: 'a'}) + TCGdex.fetch = fakeFetch({ ok: 'a' }) await expect(tcgdex.fetch('non existing endpoint')).rejects.toThrow() await expect(tcgdex.fetch()).rejects.toThrow() }) -test('404 test', async () => { +test(`404 error`, async () => { const tcgdex = new TCGdex('en') - TCGdex.fetch = fakeFetch(undefined, 404) + TCGdex.fetch = fetch + expect( - await tcgdex.fetch('cards', '404-test') - ).not.toBeDefined() + await tcgdex.card.get('404-error') + ).toBeNull() }) -test('test real endpoints', async () => { +test(`test getting full set from list`, async () => { const tcgdex = new TCGdex('en') TCGdex.fetch = fetch - const endpoints = [ - {endpoint: 'fetchCard', params: ['swsh1-1']}, - {endpoint: 'fetchCard', params: ['1', 'Sword & Shield']}, - {endpoint: 'fetchCards', params: ['swsh1']}, - {endpoint: 'fetchCards', params: []}, - {endpoint: 'fetchSet', params: ['swsh1']}, - {endpoint: 'fetchSets', params: ['swsh']}, - {endpoint: 'fetchSets', params: []}, - {endpoint: 'fetchSeries', params: []}, - {endpoint: 'fetchSerie', params: ['swsh']}, - ] - - for await (const item of endpoints) { - expect( - await tcgdex[item.endpoint](...item.params) - ).toBeDefined() - } + + expect( + await (await tcgdex.set.list())[0].getSet() + ).toBeTruthy() +}) + +test(`test getting full serie from list`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (await tcgdex.serie.list())[0].getSerie() + ).toBeTruthy() +}) + +test(`test getting full card from list`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (await tcgdex.card.list())[0].getCard() + ).toBeTruthy() +}) + + +test(`test get set from card`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (await tcgdex.card.get('swsh1-136')).getSet() + ).toBeTruthy() +}) + +test(`test get serie from set`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (await tcgdex.set.get('swsh1')).getSerie() + ).toBeTruthy() +}) + +test(`advanced query system`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + (await tcgdex.card.list( + Query.create() + .equal('name', 'Pikachu') + .greaterOrEqualThan('hp', 60) + .lesserThan('hp', 70) + .contains('localId', '5') + .not.contains('localId', 'tg') + .not.equal('id', 'cel25-5') + .sort('localId', 'ASC') + .paginate(3, 2) + )).length + ).toBe(2) }) + +const endpoints = [ + { endpoint: 'card', params: ['swsh1-136'] }, + { endpoint: 'set', params: ['swsh1'] }, + { endpoint: 'serie', params: ['swsh'] }, + { endpoint: 'type', params: ['fire'] }, + { endpoint: 'retreat', params: ['1'] }, + { endpoint: 'rarity', params: ['common'] }, + { endpoint: 'illustrator', params: [''] }, + { endpoint: 'hp', params: ['30'] }, + { endpoint: 'categorie', params: ['pokemon'] }, + { endpoint: 'dexID', params: ['1'] }, + { endpoint: 'energyType', params: ['normal'] }, + { endpoint: 'regulationMark', params: ['f'] }, + { endpoint: 'stage', params: ['basic'] }, + { endpoint: 'suffixe', params: ['ex'] }, + { endpoint: 'trainerType', params: ['item'] }, + { endpoint: 'variant', params: ['normal'] }, +] + +for (const endpoint of endpoints) { + test(`test real ${endpoint.endpoint} endpoint list`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (tcgdex[endpoint.endpoint]).list() + ).toBeTruthy() + }) + + test(`test real ${endpoint.endpoint} endpoint item`, async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + + expect( + await (tcgdex[endpoint.endpoint]).get(endpoint.params[0]) + ).toBeTruthy() + }) + +} diff --git a/__tests__/cache.test.js b/__tests__/cache.test.js new file mode 100644 index 0000000..77d69e8 --- /dev/null +++ b/__tests__/cache.test.js @@ -0,0 +1,54 @@ +/// + +const { default: MemoryCache } = require("../src/Psr/SimpleCache/MemoryCache") + +const TCGdex = require("../src/tcgdex").default + +test('that cache store and get one element', async () => { + const cache = new MemoryCache() + cache.set('a', 'b') + expect(cache.get('a')).toBe('b') +}) + +test('that cache store and get multiple elements', async () => { + const cache = new MemoryCache() + cache.setMultiple({ + 'a': 'b', + 'c': 'd' + }) + expect(cache.getMultiple(['a', 'c'])).toStrictEqual({ + a: 'b', + c: 'd' + }) +}) + +test('cache expiration', async () => { + const cache = new MemoryCache() + cache.set('a', 'b', 1) + // wait 2 secs + await new Promise((res) => setTimeout(res, 2000)) + expect(cache.get('a')).toBeUndefined() +}) + +test('cache deletion', async () => { + const cache = new MemoryCache() + cache.set('a', 'b') + expect(cache.get('a')).toBe('b') + cache.delete('a') + expect(cache.get('a')).toBeUndefined() +}) + +test('cache cleared', async () => { + const cache = new MemoryCache() + cache.set('a', 'b') + expect(cache.get('a')).toBe('b') + cache.clear() + expect(cache.get('a')).toBeUndefined() +}) + +test('cache exists', async () => { + const cache = new MemoryCache() + expect(cache.has('a')).toBe(false) + cache.set('a', 'b') + expect(cache.has('a')).toBe(true) +}) diff --git a/__tests__/deprecated.test.js b/__tests__/deprecated.test.js new file mode 100644 index 0000000..4b7fd21 --- /dev/null +++ b/__tests__/deprecated.test.js @@ -0,0 +1,66 @@ +const TCGdex = require("../src/tcgdex").default +const fetch = require('node-fetch') + +const fakeFetch = (response, status = 200) => jest.fn(() => + Promise.resolve({ + status: status, + json: () => Promise.resolve(response), + }) +); + + + +test('Basic test', async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fakeFetch({ok: true}) + const res = await tcgdex.fetch('cards', 'basic-test') + expect(res).toEqual({ok: true}) + expect(TCGdex.fetch).toHaveBeenCalledTimes(1) +}) + +test('Cache test', async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fakeFetch({ok: 'a'}) + const res1 = await tcgdex.fetch('cards', 'cache-test') + expect(res1).toEqual({ok: 'a'}) + TCGdex.fetch = fakeFetch({ok: 'b'}) + const res2 = await tcgdex.fetch('cards', 'cache-test') + expect(res2).toEqual({ok: 'a'}) +}) + +test('endpoint errors', async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fakeFetch({ok: 'a'}) + await expect(tcgdex.fetch('non existing endpoint')).rejects.toThrow() + await expect(tcgdex.fetch()).rejects.toThrow() +}) + +test('404 test', async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fakeFetch(undefined, 404) + expect( + await tcgdex.fetch('cards', '404-test') + ).not.toBeDefined() +}) + +test('test real endpoints', async () => { + const tcgdex = new TCGdex('en') + TCGdex.fetch = fetch + const endpoints = [ + {endpoint: 'fetchCard', params: ['swsh1-1']}, + {endpoint: 'fetchCard', params: ['1', 'Sword & Shield']}, + {endpoint: 'fetchCards', params: ['swsh1']}, + {endpoint: 'fetchCards', params: []}, + {endpoint: 'fetchSet', params: ['swsh1']}, + {endpoint: 'fetchSets', params: ['swsh']}, + {endpoint: 'fetchSets', params: []}, + {endpoint: 'fetchSeries', params: []}, + {endpoint: 'fetchSerie', params: ['swsh']}, + ] + + for await (const item of endpoints) { + expect( + await tcgdex[item.endpoint](...item.params) + ).toBeDefined() + } +}) diff --git a/bun.lockb b/bun.lockb deleted file mode 100644 index 7371487c15f11399b06c2235db96306d976ea5c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 287131 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

S!7%_dQAt$mTgPz4zmuNX!lqwQJrDSqMVg77s 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 = {} +export default class Query { + public params: Array<{ key: string, value: string | number | boolean }> = [] - public static create(): Query - { + public not: { + equal: (key: string, value: string) => Query + contains: (key: string, value: string) => Query + includes: (key: string, value: string) => Query + like: (key: string, value: string) => Query + isNull: (key: string) => Query + } = { + equal: (key: string, value: string) => { + this.params.push({ key: key, value: `neq:${value}` }) + return this + }, + contains: (key: string, value: string) => { + this.params.push({ key: key, value: `not:${value}` }) + return this + }, + includes: (key: string, value: string) => this.not.contains(key, value), + like: (key: string, value: string) => this.not.contains(key, value), + isNull: (key: string) => { + this.params.push({ key: key, value: 'notnull:' }) + return this + } + } + + public static create(): Query { return new Query() } - public includes(key: string, value: string): this - { + public includes(key: string, value: string): this { return this.contains(key, value) } - public contains(key: string, value: string): this - { - this.params[key] = value + public like(key: string, value: string): this { + return this.contains(key, value) + } + + public contains(key: string, value: string): this { + this.params.push({ key: key, value: value }) + return this + } + + public equal(key: string, value: string): this { + this.params.push({ key: key, value: `eq:${value}` }) + return this } - public equal(key: string, value: string): this - { - this.params[key] = `eq:${value}` + public sort(key: string, order: 'ASC' | 'DESC'): this { + this.params.push({ key: 'sort:field', value: key }) + this.params.push({ key: 'sort:order', value: order }) return this } - public sort(key: string, order: string): this - { - this.params['sort:field'] = key - this.params['sort:order'] = order + public greaterOrEqualThan(key: string, value: number) { + this.params.push({ key: key, value: `gte:${value}` }) + return this + } + + public lesserOrEqualThan(key: string, value: number) { + this.params.push({ key: key, value: `lte:${value}` }) + return this + } + + public greaterThan(key: string, value: number) { + this.params.push({ key: key, value: `gt:${value}` }) + return this + } + + public lesserThan(key: string, value: number) { + this.params.push({ key: key, value: `lt:${value}` }) + return this + } + public isNull(key: string) { + this.params.push({ key: key, value: 'null:' }) return this } - public paginate(page: number, itemsPerPage: number): this - { - this.params['pagination:page'] = page - this.params['pagination:itemsPerPage'] = itemsPerPage + public paginate(page: number, itemsPerPage: number): this { + this.params.push({ key: 'pagination:page', value: page }) + this.params.push({ key: 'pagination:itemsPerPage', value: itemsPerPage }) return this } diff --git a/src/endpoints/Endpoint.ts b/src/endpoints/Endpoint.ts index c5d24eb..8177d87 100644 --- a/src/endpoints/Endpoint.ts +++ b/src/endpoints/Endpoint.ts @@ -9,7 +9,7 @@ export default class Endpoint { protected readonly itemModel: new (sdk: TCGdex) => Item, protected readonly listModel: new (sdk: TCGdex) => List, protected readonly endpoint: Endpoints - ) {} + ) { } public async get(id: string | number): Promise { const res = await this.tcgdex.fetch(this.endpoint as 'cards', id as string) @@ -19,8 +19,8 @@ export default class Endpoint { return Model.build(new this.itemModel(this.tcgdex), res) } - public async list(query: Query): Promise> { - const res = await this.tcgdex.fetchWithQuery([this.endpoint], query.params) + public async list(query?: Query): Promise> { + const res = await this.tcgdex.fetchWithQuery([this.endpoint], query?.params) return (res as Array ?? []).map((it) => Model.build(new this.listModel(this.tcgdex), it)) } } diff --git a/src/endpoints/SimpleEndpoint.ts b/src/endpoints/SimpleEndpoint.ts new file mode 100644 index 0000000..fa31516 --- /dev/null +++ b/src/endpoints/SimpleEndpoint.ts @@ -0,0 +1,24 @@ +import type { Endpoints } from '../interfaces' +import Model from '../models/Model' +import type Query from '../Query' +import type TCGdex from '../tcgdex' + +export default class SimpleEndpoint { + public constructor( + protected readonly tcgdex: TCGdex, + protected readonly itemModel: new (sdk: TCGdex) => Item, + protected readonly endpoint: Endpoints + ) {} + + public async get(id: string | number): Promise { + const res = await this.tcgdex.fetch(this.endpoint as 'cards', id as string) + if (!res) { + return null + } + return Model.build(new this.itemModel(this.tcgdex), res) + } + + public async list(query?: Query): Promise> { + return await this.tcgdex.fetchWithQuery([this.endpoint], query?.params) ?? [] + } +} diff --git a/src/models/Card.ts b/src/models/Card.ts index 04f1246..5d27cab 100644 --- a/src/models/Card.ts +++ b/src/models/Card.ts @@ -188,7 +188,7 @@ export default class Card extends CardResume { expanded: boolean } - public async getFullCard(): Promise { + public override async getCard(): Promise { return this } diff --git a/src/models/CardResume.ts b/src/models/CardResume.ts index c56af16..da3b126 100644 --- a/src/models/CardResume.ts +++ b/src/models/CardResume.ts @@ -41,7 +41,7 @@ export default class CardResume extends Model { * * @return the full card if available */ - public async getFullCard(): Promise { + public async getCard(): Promise { return (await this.sdk.card.get(this.id))! } } diff --git a/src/models/Model.ts b/src/models/Model.ts index 010ea75..706c554 100644 --- a/src/models/Model.ts +++ b/src/models/Model.ts @@ -5,7 +5,7 @@ export default abstract class Model { public constructor( protected readonly sdk: TCGdex - ) {} + ) { } /** * build a model depending on the data given diff --git a/src/models/Serie.ts b/src/models/Serie.ts index e69de29..b910077 100644 --- a/src/models/Serie.ts +++ b/src/models/Serie.ts @@ -0,0 +1,21 @@ +import { objectLoop } from '@dzeio/object-util' +import Model from './Model' +import SerieResume from './SerieResume' +import SetResume from './SetResume' + +export default class Serie extends SerieResume { + public sets!: Array + + protected fill(obj: object): void { + objectLoop(obj, (value, key) => { + switch (key) { + case 'sets': + this.sets = (value as Array).map((it) => Model.build(new SetResume(this.sdk), it)) + break + default: + this[key] = value + break + } + }) + } +} diff --git a/src/models/SerieResume.ts b/src/models/SerieResume.ts index d5328c9..8729211 100644 --- a/src/models/SerieResume.ts +++ b/src/models/SerieResume.ts @@ -1,5 +1,24 @@ +import type { Extension } from '../interfaces' import Model from './Model' +import type Serie from './Serie' export default class SerieResume extends Model { + public id!: string + public name!: string + public logo?: string + /** + * the the Card Image full URL + * + * @param {Quality} quality the quality you want your image to be in + * @param {Extension} extension extension you want you image to be + * @return the full card URL + */ + public getImageURL(extension: Extension = 'png'): string { + return `${this.logo}.${extension}` + } + + public async getSerie(): Promise { + return (await this.sdk.serie.get(this.id))! + } } diff --git a/src/models/Set.ts b/src/models/Set.ts index 4d4dd0f..b4c8d47 100644 --- a/src/models/Set.ts +++ b/src/models/Set.ts @@ -70,6 +70,10 @@ export default class Set extends Model { public cards!: Array + public async getSerie() { + return this.sdk.serie.get(this.serie.id) + } + protected fill(obj: object): void { objectLoop(obj, (value, key) => { switch (key) { diff --git a/src/models/SetResume.ts b/src/models/SetResume.ts index db2b3c3..dbd5519 100644 --- a/src/models/SetResume.ts +++ b/src/models/SetResume.ts @@ -19,7 +19,7 @@ export default class SetResume extends Model { official: number } - public async getFullSet(): Promise { + public async getSet(): Promise { return (await this.sdk.set.get(this.id))! } } diff --git a/src/models/StringEndpoint.ts b/src/models/StringEndpoint.ts index 16dd2dd..fe03d21 100644 --- a/src/models/StringEndpoint.ts +++ b/src/models/StringEndpoint.ts @@ -1,7 +1,21 @@ -import type CardResume from './CardResume' +import { objectLoop } from '@dzeio/object-util' +import CardResume from './CardResume' import Model from './Model' export default class StringEndpoint extends Model { public name!: string public cards!: Array + + protected fill(obj: object): void { + objectLoop(obj, (value, key) => { + switch (key) { + case 'cards': + this.cards = (value as Array).map((it) => Model.build(new CardResume(this.sdk), it)) + break + default: + this[key] = value + break + } + }) + } } diff --git a/src/tcgdex.ts b/src/tcgdex.ts index 36934b9..e207503 100644 --- a/src/tcgdex.ts +++ b/src/tcgdex.ts @@ -1,8 +1,9 @@ -import { objectLoop } from '@dzeio/object-util' import type CacheInterface from './Psr/SimpleCache/CacheInterface' import LocalStorageCache from './Psr/SimpleCache/LocalStorageCache' import MemoryCache from './Psr/SimpleCache/MemoryCache' +import Query from './Query' import Endpoint from './endpoints/Endpoint' +import SimpleEndpoint from './endpoints/SimpleEndpoint' import type { Card, CardResume, @@ -16,9 +17,12 @@ import type { } from './interfaces' import CardModel from './models/Card' import CardResumeModel from './models/CardResume' +import SerieModel from './models/Serie' +import SerieResume from './models/SerieResume' import SetModel from './models/Set' import SetResumeModel from './models/SetResume' -import { detectContext, ENDPOINTS } from './utils' +import StringEndpointModel from './models/StringEndpoint' +import { ENDPOINTS, detectContext } from './utils' import { version } from './version' export default class TCGdex { @@ -46,10 +50,29 @@ export default class TCGdex { public readonly card = new Endpoint(this, CardModel, CardResumeModel, 'cards') public readonly set = new Endpoint(this, SetModel, SetResumeModel, 'sets') + public readonly serie = new Endpoint(this, SerieModel, SerieResume, 'series') + + public readonly type = new SimpleEndpoint(this, StringEndpointModel, 'types') + public readonly retreat = new SimpleEndpoint(this, StringEndpointModel, 'retreats') + public readonly rarity = new SimpleEndpoint(this, StringEndpointModel, 'rarities') + public readonly illustrator = new SimpleEndpoint(this, StringEndpointModel, 'illustrators') + public readonly hp = new SimpleEndpoint(this, StringEndpointModel, 'hp') + public readonly categorie = new SimpleEndpoint(this, StringEndpointModel, 'categories') + public readonly dexID = new SimpleEndpoint(this, StringEndpointModel, 'dex-ids') + public readonly energyType = new SimpleEndpoint(this, StringEndpointModel, 'energy-types') + public readonly regulationMark = new SimpleEndpoint(this, StringEndpointModel, 'regulation-marks') + public readonly stage = new SimpleEndpoint(this, StringEndpointModel, 'stages') + public readonly suffixe = new SimpleEndpoint(this, StringEndpointModel, 'suffixes') + public readonly trainerType = new SimpleEndpoint(this, StringEndpointModel, 'trainer-types') + public readonly variant = new SimpleEndpoint(this, StringEndpointModel, 'variants') private lang: SupportedLanguages = 'en' private endpointURL = 'https://api.tcgdex.net/v2' + public constructor(lang: SupportedLanguages = 'en') { + this.setLang(lang) + } + /** * @deprecated use the constructor parameter or {@link TCGdex.setLang} when in an instance */ @@ -263,7 +286,7 @@ export default class TCGdex { */ public async fetchWithQuery( endpoint: [Endpoints, ...Array], - query?: Record + query?: Array<{ key: string, value: string | number | boolean }> ): Promise { if (endpoint.length === 0) { throw new Error('endpoint to fetch is empty!') @@ -280,20 +303,21 @@ export default class TCGdex { */ private getFullURL( url: Array, - searchParams?: Record - ): string{ + searchParams?: Array<{ key: string, value: string | number | boolean }> + ): string { // Normalize path let path = url.map(this.encode).join('/') // handle the Search Params if (searchParams) { path += '?' - objectLoop(searchParams, (value, key, index) => { - if (index !== 0) { + for (let idx = 0; idx < searchParams.length; idx++) { + const param = searchParams[idx] + if (idx !== 0) { path += '&' } - path += `${this.encode(key)}=${this.encode(value)}` - }) + path += `${this.encode(param.key)}=${this.encode(param.value)}` + } } // return with the endpoint and all the shit @@ -356,4 +380,9 @@ export default class TCGdex { } } + export * from './models/Card' +export { + Query +} + diff --git a/tsconfig.json b/tsconfig.json index 2de7ffc..5f8a9b3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,8 @@ "compilerOptions": { "outDir": "dist", "strictNullChecks": true - } + }, + "exclude": [ + "__tests__" + ] } From 653a7327bfccb03002b14402c8701aa4af9dc20b Mon Sep 17 00:00:00 2001 From: Avior Date: Thu, 10 Oct 2024 14:46:05 +0200 Subject: [PATCH 7/9] chore: change the unusable status badge Signed-off-by: Avior --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f640c71..fcff41a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Github stars - the TCGdex JAvascript SDK is released under the MIT license. + the TCGdex JAvascript SDK is released under the MIT license. Discord Link From d563d7d5b6ff3f4cf0a1ba67a58f7a2990cf4cbf Mon Sep 17 00:00:00 2001 From: Avior Date: Thu, 10 Oct 2024 14:49:52 +0200 Subject: [PATCH 8/9] fix: optimize deps Signed-off-by: Avior --- package-lock.json | 59 +++++------------------------------------------ package.json | 1 - 2 files changed, 6 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95852fd..ab16cc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "@dzeio/object-util": "^1", - "@types/bun": "^1.1.11", "isomorphic-unfetch": "^3" }, "devDependencies": { @@ -2727,14 +2726,6 @@ "@babel/types": "^7.3.0" } }, - "node_modules/@types/bun": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.1.11.tgz", - "integrity": "sha512-0N7D/H/8sbf9JMkaG5F3+I/cB4TlhKTkO9EskEWP8XDr8aVcDe4EywSnU4cnyZy6tar1dq70NeFNkqMEUigthw==", - "dependencies": { - "bun-types": "1.1.30" - } - }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -2778,6 +2769,7 @@ "version": "20.12.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.14.tgz", "integrity": "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -2810,14 +2802,6 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -3521,15 +3505,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/bun-types": { - "version": "1.1.30", - "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.1.30.tgz", - "integrity": "sha512-mGh7NLisOXskBU62DxLS+/nwmLlCYHYAkCzdo4DZ9+fzrpP41hAdOqaN4DO6tQfenHb4pYb0/shw29k4/6I2yQ==", - "dependencies": { - "@types/node": "~20.12.8", - "@types/ws": "~8.5.10" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -8918,7 +8893,8 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/unfetch": { "version": "4.2.0", @@ -11172,14 +11148,6 @@ "@babel/types": "^7.3.0" } }, - "@types/bun": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.1.11.tgz", - "integrity": "sha512-0N7D/H/8sbf9JMkaG5F3+I/cB4TlhKTkO9EskEWP8XDr8aVcDe4EywSnU4cnyZy6tar1dq70NeFNkqMEUigthw==", - "requires": { - "bun-types": "1.1.30" - } - }, "@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -11223,6 +11191,7 @@ "version": "20.12.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.14.tgz", "integrity": "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==", + "dev": true, "requires": { "undici-types": "~5.26.4" } @@ -11255,14 +11224,6 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", - "requires": { - "@types/node": "*" - } - }, "@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -11755,15 +11716,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "bun-types": { - "version": "1.1.30", - "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.1.30.tgz", - "integrity": "sha512-mGh7NLisOXskBU62DxLS+/nwmLlCYHYAkCzdo4DZ9+fzrpP41hAdOqaN4DO6tQfenHb4pYb0/shw29k4/6I2yQ==", - "requires": { - "@types/node": "~20.12.8", - "@types/ws": "~8.5.10" - } - }, "cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -15706,7 +15658,8 @@ "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "unfetch": { "version": "4.2.0", diff --git a/package.json b/package.json index 06f664c..9bb0d23 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ }, "dependencies": { "@dzeio/object-util": "^1", - "@types/bun": "^1.1.11", "isomorphic-unfetch": "^3" }, "scripts": { From b6601fda83284b7a341cdf8e7133665928f8f277 Mon Sep 17 00:00:00 2001 From: Avior Date: Thu, 10 Oct 2024 14:51:57 +0200 Subject: [PATCH 9/9] chore: change extension of a type only file Signed-off-by: Avior --- src/Psr/SimpleCache/{CacheInterface.ts => CacheInterface.d.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Psr/SimpleCache/{CacheInterface.ts => CacheInterface.d.ts} (100%) diff --git a/src/Psr/SimpleCache/CacheInterface.ts b/src/Psr/SimpleCache/CacheInterface.d.ts similarity index 100% rename from src/Psr/SimpleCache/CacheInterface.ts rename to src/Psr/SimpleCache/CacheInterface.d.ts