mirror of
https://github.com/tcgdex/javascript-sdk.git
synced 2025-07-13 02:25:10 +00:00
Compare commits
65 Commits
Author | SHA1 | Date | |
---|---|---|---|
6849546c1a | |||
95a658f98a | |||
c866b4022f | |||
978a676a79 | |||
1f801f4a94 | |||
4e4bcf9d26
|
|||
0b14e8ddec | |||
fc4a31ef39 | |||
26acb1eb61
|
|||
c03183bd6f
|
|||
07403cb3ae
|
|||
f5dd4cb88c | |||
9b9ff2f028 | |||
ce64a95f4e | |||
460f101026 | |||
b3ba7820a3
|
|||
1f3aae5401 | |||
e501faa823 | |||
e08fd98269 | |||
54a4b729b3 | |||
26af3b0779 | |||
bf54ab3809 | |||
f2621890e1 | |||
4364da480f | |||
0cc8577fe0 | |||
0f2ad36e8c | |||
74de8961ef | |||
98c80fcd20 | |||
c392b27cac | |||
dc5e41a638 | |||
09d8b28a66
|
|||
4507bbd651
|
|||
8a89aefe73 | |||
8df969c1db
|
|||
2177e9c088 | |||
a32f42975a | |||
0148979d7d
|
|||
ea357c9080
|
|||
5e998d3658
|
|||
ed883c06eb | |||
1ecaa048eb | |||
39cd15ead3 | |||
ca5ae0aa57 | |||
cffae6cc28 | |||
5e03f38476 | |||
05134f5b12 | |||
8a0dec867e | |||
75636a9195 | |||
bd33dafe8a | |||
39fb14070d | |||
6ae3b09dc9 | |||
8d13d1dba4 | |||
840c8c3106 | |||
ee4f1be353 | |||
7e4c0eae42 | |||
3d08ab4bfa | |||
3441cc2c60 | |||
9b2e09d766 | |||
3ebde59a84 | |||
e18cbabf70 | |||
1c6c7dacc4 | |||
445b3a5ea6 | |||
7148fc7522 | |||
cde8b24230 | |||
1d21ff650e |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [tcgdex]
|
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
@ -14,18 +14,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Follow current releases https://nodejs.org/en/about/releases/
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
# Follow current releases https://github.com/nodejs/release#release-schedule
|
||||
node-version: [18.x, 20.x, 21.x, 22.x]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2.5.1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
@ -37,8 +39,8 @@ jobs:
|
||||
run: npm run test
|
||||
|
||||
- name: Upload Coverage
|
||||
if: matrix.node-version == '16.x'
|
||||
uses: codecov/codecov-action@v2.1.0
|
||||
if: matrix.node-version == '22.x'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
# Comma-separated list of files to upload
|
||||
files: ./coverage/coverage-final.json
|
||||
|
4
.github/workflows/code-quality.yml
vendored
4
.github/workflows/code-quality.yml
vendored
@ -12,10 +12,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@v2.5.1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
29
.github/workflows/publish.yml
vendored
29
.github/workflows/publish.yml
vendored
@ -1,19 +1,22 @@
|
||||
name: publish
|
||||
name: Publish the Package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
build:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup NodeJS
|
||||
uses: actions/setup-node@v2.5.1
|
||||
- name: Setup Publishing to NPMJS
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install dependencies
|
||||
@ -22,7 +25,17 @@ jobs:
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Publish
|
||||
- name: Publish on NPM
|
||||
run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Setup Publishing to Github Packages
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://npm.pkg.github.com'
|
||||
|
||||
- name: Publish on Github
|
||||
run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.REPO_TOKEN }}
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,4 +5,4 @@ coverage
|
||||
|
||||
# Dist files
|
||||
dist
|
||||
src/version.json
|
||||
src/version.js
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## 2.5.1 - 2023-07-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- ModuleJS exports not working as intended
|
||||
|
||||
## 2.5.0 - 2023-06-28
|
||||
|
||||
### Added
|
||||
|
||||
- Support for both ModuleJS and CommonJS
|
||||
|
||||
## 2.4.9 - 2022-09-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- package not loading on browser
|
||||
|
||||
## 2.4.8 - 2022-09-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix version number not correctly exposting
|
||||
|
||||
## 2.4.7 - 2022-09-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- Compatibility with Angular
|
||||
|
||||
## 2.4.6 - 2022-01-28
|
||||
|
||||
### Fixed
|
||||
|
34
README.md
34
README.md
@ -17,7 +17,7 @@
|
||||
<img src="https://img.shields.io/github/stars/tcgdex/javascript-sdk?style=flat-square" alt="Github stars">
|
||||
</a>
|
||||
<a href="https://github.com/tcgdex/javascript-sdk/actions/workflows/build.yml">
|
||||
<img src="https://img.shields.io/github/workflow/status/tcgdex/javascript-sdk/Build%20&%20Test?style=flat-square" alt="the TCGdex JAvascript SDK is released under the MIT license." />
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/tcgdex/javascript-sdk/build.yml?style=flat-square" alt="the TCGdex JAvascript SDK is released under the MIT license." />
|
||||
</a>
|
||||
<a href="https://discord.gg/NehYTAhsZE">
|
||||
<img src="https://img.shields.io/discord/857231041261076491?color=%235865F2&label=Discord&style=flat-square" alt="Discord Link">
|
||||
@ -63,19 +63,43 @@ _Note: a complete documentation is available at [TCGdex.dev](https://www.tcgdex.
|
||||
|
||||
**Example: Fetch a Card**
|
||||
|
||||
```typescript
|
||||
// Import the SDK in Typescript
|
||||
import TCGdex from '@tcgdex/sdk';
|
||||
_in Browser_
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tcgdex/sdk@2.4.9/dist/tcgdex.browser.js"></script>
|
||||
<script>
|
||||
// Instantiate the SDK
|
||||
// note: you can use one of the following lanugages
|
||||
const tcgdex = new TCGdex('en');
|
||||
|
||||
// go into an async context
|
||||
;(async () => {
|
||||
// Card will be Furret from the Darkness Ablaze Set
|
||||
const card = await tcgdex.fetch('cards', 'swsh3-136');
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
_in NodeJS (in an async context)_
|
||||
|
||||
```typescript
|
||||
// Import the SDK in Typescript or moduleJS
|
||||
import TCGdex from '@tcgdex/sdk'
|
||||
|
||||
// import the SDK in commonJS
|
||||
const TCGdex = require('@tcgdex/sdk').default
|
||||
|
||||
// Instantiate the SDK
|
||||
const tcgdex = new TCGdex('en');
|
||||
|
||||
// go into an async context
|
||||
(async () => {
|
||||
// Card will be Furret from the Darkness Ablaze Set
|
||||
const card = await tcgdex.fetch('cards', 'swsh3-136');
|
||||
|
||||
// You can also get the same result using
|
||||
const card = await tcgdex.fetch('sets', 'Darkness Ablaze', 136);
|
||||
})();
|
||||
|
||||
```
|
||||
|
||||
**Other Examples**
|
||||
|
151
__tests__/basic.test.ts
Normal file
151
__tests__/basic.test.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import { expect, test, vi } from 'vitest'
|
||||
import TCGdex, { Query } from '../src/tcgdex'
|
||||
|
||||
// change timeout of execution
|
||||
vi.setConfig({ testTimeout: 120000 })
|
||||
|
||||
const fakeFetch = (response: any, status = 200) => vi.fn(() =>
|
||||
Promise.resolve({
|
||||
status: status,
|
||||
json: () => Promise.resolve(response)
|
||||
})
|
||||
)
|
||||
|
||||
test('Basic test', async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fakeFetch({ ok: true }) as any
|
||||
const res = await tcgdex.fetch('cards', 'basic-test')
|
||||
expect(res).toEqual({ ok: true })
|
||||
expect(TCGdex.fetch).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('endpoint errors', async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fakeFetch({ ok: 'a' }) as any
|
||||
await expect(tcgdex.fetch('non existing endpoint')).rejects.toThrow()
|
||||
await expect(tcgdex.fetch()).rejects.toThrow()
|
||||
})
|
||||
|
||||
test(`404 error`, async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fetch
|
||||
|
||||
expect(
|
||||
await tcgdex.card.get('404-error')
|
||||
).toBeNull()
|
||||
})
|
||||
|
||||
test(`test getting full set from list`, async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fetch
|
||||
|
||||
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()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
test(`random card/set/serie`, async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fetch
|
||||
|
||||
expect((await tcgdex.random.card())).toBeTruthy()
|
||||
expect((await tcgdex.random.set())).toBeTruthy()
|
||||
expect((await tcgdex.random.serie())).toBeTruthy()
|
||||
})
|
@ -1,18 +1,19 @@
|
||||
const TCGdex = require("../src/tcgdex").default
|
||||
const fetch = require('node-fetch')
|
||||
import { expect, test, vi } from 'vitest'
|
||||
import TCGdex from '../src/tcgdex'
|
||||
|
||||
const fakeFetch = (response, status = 200) => jest.fn(() =>
|
||||
// change timeout of execution
|
||||
vi.setConfig({ testTimeout: 120000 })
|
||||
|
||||
const fakeFetch = (response, status = 200) => vi.fn(() =>
|
||||
Promise.resolve({
|
||||
status: status,
|
||||
json: () => Promise.resolve(response),
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
)
|
||||
|
||||
test('Basic test', async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fakeFetch({ok: true})
|
||||
TCGdex.fetch = fakeFetch({ ok: true }) as any
|
||||
const res = await tcgdex.fetch('cards', 'basic-test')
|
||||
expect(res).toEqual({ ok: true })
|
||||
expect(TCGdex.fetch).toHaveBeenCalledTimes(1)
|
||||
@ -20,24 +21,24 @@ test('Basic test', async () => {
|
||||
|
||||
test('Cache test', async () => {
|
||||
const tcgdex = new TCGdex('en')
|
||||
TCGdex.fetch = fakeFetch({ok: 'a'})
|
||||
TCGdex.fetch = fakeFetch({ ok: 'a' }) as any
|
||||
const res1 = await tcgdex.fetch('cards', 'cache-test')
|
||||
expect(res1).toEqual({ ok: 'a' })
|
||||
TCGdex.fetch = fakeFetch({ok: 'b'})
|
||||
TCGdex.fetch = fakeFetch({ ok: 'b' }) as any
|
||||
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' }) as any
|
||||
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)
|
||||
TCGdex.fetch = fakeFetch(undefined, 404) as any
|
||||
expect(
|
||||
await tcgdex.fetch('cards', '404-test')
|
||||
).not.toBeDefined()
|
14035
package-lock.json
generated
14035
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@ -1,9 +1,22 @@
|
||||
{
|
||||
"name": "@tcgdex/sdk",
|
||||
"version": "2.4.6",
|
||||
"main": "./dist/cjs/tcgdex.node.js",
|
||||
"module": "./dist/modules/tcgdex.node.js",
|
||||
"types": "./dist/types/tcgdex.d.ts",
|
||||
"version": "2.7.0",
|
||||
"main": "./dist/tcgdex.node.js",
|
||||
"module": "./dist/tcgdex.node.mjs",
|
||||
"types": "./dist/tcgdex.node.d.ts",
|
||||
"browser": "./dist/tcgdex.browser.global.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": {
|
||||
"types": "./dist/tcgdex.node.d.ts",
|
||||
"default": "./dist/tcgdex.node.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/tcgdex.node.d.mts",
|
||||
"default": "./dist/tcgdex.node.mjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Communicate with the Open Source TCGdex API in Javascript/Typescript using the SDK",
|
||||
"repository": "https://github.com/tcgdex/javascript-sdk.git",
|
||||
"homepage": "https://github.com/tcgdex/javascript-sdk",
|
||||
@ -18,42 +31,47 @@
|
||||
"api",
|
||||
"typescript",
|
||||
"javascript",
|
||||
"typing"
|
||||
"typing",
|
||||
"browser",
|
||||
"node"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.14.6",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@dzeio/config": "^1.0.0",
|
||||
"@types/node-fetch": "^2.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||
"@typescript-eslint/parser": "^5.7.0",
|
||||
"esbuild": "^0.14.5",
|
||||
"eslint": "^8.4.1",
|
||||
"jest": "^27.0.5",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
"@babel/core": "^7",
|
||||
"@babel/preset-env": "^7",
|
||||
"@babel/preset-typescript": "^7",
|
||||
"@dzeio/config": "^1",
|
||||
"@types/node-fetch": "^2",
|
||||
"@typescript-eslint/eslint-plugin": "^5",
|
||||
"@typescript-eslint/parser": "^5",
|
||||
"@vitest/coverage-v8": "^2.1.8",
|
||||
"eslint": "^8",
|
||||
"jest": "^29",
|
||||
"tsup": "^7",
|
||||
"typescript": "^5",
|
||||
"vitest": "^2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"isomorphic-unfetch": "^3.1.0",
|
||||
"unfetch": "^4.2.0"
|
||||
"@cachex/memory": "^1",
|
||||
"@cachex/web-storage": "^1",
|
||||
"@dzeio/object-util": "^1",
|
||||
"isomorphic-unfetch": "^3"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "node scripts/export-version-number.js",
|
||||
"build": "npm run prebuild && npm run build:cjs && npm run build:browser && npm run build:es2015",
|
||||
"build:cjs": "tsc --project tsconfig.json",
|
||||
"build:es2015": "tsc --project tsconfig.es2015.json",
|
||||
"build:browser": "esbuild ./src/tcgdex.browser.ts --bundle --minify --sourcemap --target=es2016,chrome90,firefox78,safari14,ios13,edge90 --outfile=dist/tcgdex.browser.js",
|
||||
"build": "rm -rf dist && tsup ./src/tcgdex.node.ts --format cjs,esm --dts --clean && tsup ./src/tcgdex.browser.ts --format iife --global-name TCGdex --sourcemap",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "eslint",
|
||||
"test": "jest --coverage"
|
||||
"test": "vitest run --coverage"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"sideEffects": false
|
||||
"sideEffects": false,
|
||||
"jest": {
|
||||
"testTimeout": 30000
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
const { version } = require('../package.json')
|
||||
const fs = require('fs')
|
||||
|
||||
fs.writeFileSync('./src/version.json', JSON.stringify({version}))
|
||||
fs.writeFileSync('./src/version.js', `export const version = '${version}'`)
|
||||
|
88
src/Query.ts
Normal file
88
src/Query.ts
Normal file
@ -0,0 +1,88 @@
|
||||
export default class Query {
|
||||
public params: Array<{ key: string, value: string | number | boolean }> = []
|
||||
|
||||
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 {
|
||||
return this.contains(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 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 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.push({ key: 'pagination:page', value: page })
|
||||
this.params.push({ key: 'pagination:itemsPerPage', value: itemsPerPage })
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import TCGdex from './tcgdex'
|
||||
import { version } from './version.json'
|
||||
|
||||
export default class Request {
|
||||
|
||||
// 1 hour of TTL by default
|
||||
public static ttl = 1000 * 60 * 60
|
||||
|
||||
private static cache: Record<string, {response: any, time: number}> = {}
|
||||
|
||||
public static async fetch<T>(url: string): Promise<T | undefined> {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
26
src/endpoints/Endpoint.ts
Normal file
26
src/endpoints/Endpoint.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type { Endpoints } from '../interfaces'
|
||||
import Model from '../models/Model'
|
||||
import type Query from '../Query'
|
||||
import type TCGdex from '../tcgdex'
|
||||
|
||||
export default class Endpoint<Item extends Model, List extends Model> {
|
||||
public constructor(
|
||||
protected readonly tcgdex: TCGdex,
|
||||
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<Item | null> {
|
||||
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<Array<List>> {
|
||||
const res = await this.tcgdex.fetchWithQuery([this.endpoint], query?.params)
|
||||
return (res as Array<object> ?? []).map((it) => Model.build(new this.listModel(this.tcgdex), it))
|
||||
}
|
||||
}
|
24
src/endpoints/SimpleEndpoint.ts
Normal file
24
src/endpoints/SimpleEndpoint.ts
Normal file
@ -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<Item extends Model, List extends string | number> {
|
||||
public constructor(
|
||||
protected readonly tcgdex: TCGdex,
|
||||
protected readonly itemModel: new (sdk: TCGdex) => Item,
|
||||
protected readonly endpoint: Endpoints
|
||||
) {}
|
||||
|
||||
public async get(id: string | number): Promise<Item | null> {
|
||||
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<Array<List>> {
|
||||
return await this.tcgdex.fetchWithQuery([this.endpoint], query?.params) ?? []
|
||||
}
|
||||
}
|
22
src/interfaces.ts → src/interfaces.d.ts
vendored
22
src/interfaces.ts → src/interfaces.d.ts
vendored
@ -22,9 +22,18 @@ interface variants {
|
||||
firstEdition?: boolean
|
||||
}
|
||||
|
||||
interface booster {
|
||||
id: string
|
||||
name: string
|
||||
logo?: string
|
||||
artwork_front?: string
|
||||
artwork_back?: string
|
||||
}
|
||||
|
||||
export type SetList = Array<SetResume>
|
||||
export type SerieList = Array<SerieResume>
|
||||
export type CardList = Array<CardResume>
|
||||
export type BoosterList = Array<booster>
|
||||
|
||||
export interface SetResume {
|
||||
id: string
|
||||
@ -105,6 +114,8 @@ export interface Set extends SetResume {
|
||||
}
|
||||
|
||||
cards: CardList
|
||||
|
||||
boosters?: BoosterList
|
||||
}
|
||||
|
||||
export interface CardResume {
|
||||
@ -302,6 +313,8 @@ export interface Card<SetType extends SetResume = SetResume> extends CardResume
|
||||
*/
|
||||
expanded: boolean
|
||||
}
|
||||
|
||||
boosters?: BoosterList
|
||||
}
|
||||
|
||||
export type StringEndpointList = Array<string>
|
||||
@ -310,3 +323,12 @@ export interface StringEndpoint {
|
||||
name: string
|
||||
cards: Array<CardResume>
|
||||
}
|
||||
|
||||
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' | 'random'
|
200
src/models/Card.ts
Normal file
200
src/models/Card.ts
Normal file
@ -0,0 +1,200 @@
|
||||
import CardResume from './CardResume'
|
||||
import type { Booster, Variants } from './Other'
|
||||
import type TCGdexSet from './Set'
|
||||
import type SetResume from './SetResume'
|
||||
|
||||
// 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<number>
|
||||
|
||||
/**
|
||||
* Pokemon HP
|
||||
*/
|
||||
public hp?: number
|
||||
|
||||
/**
|
||||
* Pokemon Types
|
||||
* ex for multiple https://www.tcgdex.net/database/ex/ex13/17
|
||||
*/
|
||||
public types?: Array<string>
|
||||
|
||||
/**
|
||||
* 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<string>
|
||||
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 boosters?: Array<Booster>
|
||||
|
||||
public override async getCard(): Promise<Card> {
|
||||
return this
|
||||
}
|
||||
|
||||
public async getSet(): Promise<TCGdexSet> {
|
||||
return (await this.sdk.set.get(this.set.id))!
|
||||
}
|
||||
}
|
47
src/models/CardResume.ts
Normal file
47
src/models/CardResume.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import type { Extension, Quality } from '../interfaces'
|
||||
import type 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 getCard(): Promise<Card> {
|
||||
return (await this.sdk.card.get(this.id))!
|
||||
}
|
||||
}
|
28
src/models/Model.ts
Normal file
28
src/models/Model.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { objectLoop } from '@dzeio/object-util'
|
||||
import type 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<T extends Model>(model: T, data?: object): T {
|
||||
if (!data) {
|
||||
throw new Error('data is necessary.')
|
||||
}
|
||||
model.fill(data)
|
||||
return model
|
||||
}
|
||||
|
||||
protected fill(obj: object) {
|
||||
objectLoop(obj, (value, key) => {
|
||||
(this as object)[key] = value
|
||||
})
|
||||
}
|
||||
}
|
15
src/models/Other.d.ts
vendored
Normal file
15
src/models/Other.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
export interface Variants {
|
||||
normal?: boolean
|
||||
reverse?: boolean
|
||||
holo?: boolean
|
||||
firstEdition?: boolean
|
||||
}
|
||||
|
||||
export interface Booster {
|
||||
|
||||
id: string
|
||||
name: string
|
||||
logo?: string
|
||||
artwork_front?: string
|
||||
artwork_back?: string
|
||||
}
|
21
src/models/Serie.ts
Normal file
21
src/models/Serie.ts
Normal file
@ -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<SetResume>
|
||||
|
||||
protected fill(obj: object): void {
|
||||
objectLoop(obj, (value, key) => {
|
||||
switch (key) {
|
||||
case 'sets':
|
||||
this.sets = (value as Array<any>).map((it) => Model.build(new SetResume(this.sdk), it))
|
||||
break
|
||||
default:
|
||||
this[key] = value
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
24
src/models/SerieResume.ts
Normal file
24
src/models/SerieResume.ts
Normal file
@ -0,0 +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<Serie> {
|
||||
return (await this.sdk.serie.get(this.id))!
|
||||
}
|
||||
}
|
91
src/models/Set.ts
Normal file
91
src/models/Set.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { objectLoop } from '@dzeio/object-util'
|
||||
import CardResume from './CardResume'
|
||||
import Model from './Model'
|
||||
import type { Booster, Variants } from './Other'
|
||||
import type SerieResume from './SerieResume'
|
||||
|
||||
// biome-ignore lint/suspicious/noShadowRestrictedNames: <explanation>
|
||||
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 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<CardResume>
|
||||
|
||||
public boosters?: Array<Booster>
|
||||
|
||||
public async getSerie() {
|
||||
return this.sdk.serie.get(this.serie.id)
|
||||
}
|
||||
|
||||
protected fill(obj: object): void {
|
||||
objectLoop(obj, (value, key) => {
|
||||
switch (key) {
|
||||
case 'cards':
|
||||
this.cards = (value as Array<any>).map((it) => Model.build(new CardResume(this.sdk), it))
|
||||
break
|
||||
default:
|
||||
this[key] = value
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
25
src/models/SetResume.ts
Normal file
25
src/models/SetResume.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import Model from './Model'
|
||||
import type TCGdexSet 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 async getSet(): Promise<TCGdexSet> {
|
||||
return (await this.sdk.set.get(this.id))!
|
||||
}
|
||||
}
|
21
src/models/StringEndpoint.ts
Normal file
21
src/models/StringEndpoint.ts
Normal file
@ -0,0 +1,21 @@
|
||||
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<CardResume>
|
||||
|
||||
protected fill(obj: object): void {
|
||||
objectLoop(obj, (value, key) => {
|
||||
switch (key) {
|
||||
case 'cards':
|
||||
this.cards = (value as Array<any>).map((it) => Model.build(new CardResume(this.sdk), it))
|
||||
break
|
||||
default:
|
||||
this[key] = value
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import TCGdex from './tcgdex'
|
||||
import unfetch from 'unfetch'
|
||||
|
||||
TCGdex.fetch = window.fetch ?? unfetch as any
|
||||
TCGdex.fetch = window.fetch
|
||||
|
||||
(global ?? window).TCGdex = TCGdex
|
||||
export default TCGdex
|
||||
|
267
src/tcgdex.ts
267
src/tcgdex.ts
@ -1,24 +1,161 @@
|
||||
import RequestWrapper from './Request'
|
||||
import { Serie, Set, Card, CardResume, SerieList, SetList, SupportedLanguages, StringEndpoint } from './interfaces'
|
||||
type Endpoint = 'cards' | 'categories' | 'dex-ids' | 'energy-types' | 'hp' | 'illustrators' | 'rarities' | 'regulation-marks' | 'retreats' | 'series' | 'sets' | 'stages' | 'suffixes' | 'trainer-types' | 'types' | 'variants'
|
||||
import type CacheInterface from '@cachex/core'
|
||||
import MemoryCache from '@cachex/memory'
|
||||
import LocalStorageCache from '@cachex/web-storage'
|
||||
import Query from './Query'
|
||||
import Endpoint from './endpoints/Endpoint'
|
||||
import SimpleEndpoint from './endpoints/SimpleEndpoint'
|
||||
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 Model from './models/Model'
|
||||
import SerieModel from './models/Serie'
|
||||
import SerieResume from './models/SerieResume'
|
||||
import SetModel from './models/Set'
|
||||
import SetResumeModel from './models/SetResume'
|
||||
import StringEndpointModel from './models/StringEndpoint'
|
||||
import { ENDPOINTS, detectContext } from './utils'
|
||||
import { version } from './version'
|
||||
|
||||
const ENDPOINTS: Array<Endpoint> = ['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
|
||||
/**
|
||||
* How the remote data is going to be fetched
|
||||
*/
|
||||
public static fetch: typeof fetch = fetch
|
||||
|
||||
/**
|
||||
* @deprecated to change the lang use `this.lang`
|
||||
* @deprecated to change the lang use {@link TCGdex.getLang} and {@link TCGdex.setLang}
|
||||
*/
|
||||
public static defaultLang: SupportedLanguages = 'en'
|
||||
|
||||
public constructor(public lang?: SupportedLanguages) {}
|
||||
/**
|
||||
* the previously hidden caching system used by TCGdex to not kill the API
|
||||
*/
|
||||
public cache: CacheInterface =
|
||||
detectContext() === 'browser' ? new LocalStorageCache('tcgdex-cache') : new MemoryCache()
|
||||
|
||||
/**
|
||||
* the default cache TTL, only subsequent requests will have their ttl changed
|
||||
*/
|
||||
public cacheTTL = 60 * 60
|
||||
|
||||
// random card/set/serie endpoints
|
||||
public readonly random = {
|
||||
card: async (): Promise<CardModel> => {
|
||||
const res = await this.fetch('random', 'card')
|
||||
return Model.build(new CardModel(this), res)
|
||||
},
|
||||
set: async (): Promise<SetModel> => {
|
||||
const res = await this.fetch('random', 'set')
|
||||
return Model.build(new SetModel(this), res)
|
||||
},
|
||||
serie: async (): Promise<SerieModel> => {
|
||||
const res = await this.fetch('random', 'serie')
|
||||
return Model.build(new SerieModel(this), res)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
public static setDefaultLang(lang: SupportedLanguages) {
|
||||
TCGdex.defaultLang = lang
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link TCGdex.setLang} when in an instance
|
||||
*/
|
||||
public static getDefaultLang(): SupportedLanguages {
|
||||
return TCGdex.defaultLang
|
||||
}
|
||||
|
||||
/**
|
||||
* the endpoint URL
|
||||
* ex: `https://api.tcgdex.net/v2`
|
||||
* @param endpoint the url
|
||||
*/
|
||||
public setEndpoint(endpoint: string) {
|
||||
this.endpointURL = endpoint
|
||||
}
|
||||
public getEndpoint(): string {
|
||||
return this.endpointURL
|
||||
}
|
||||
|
||||
/**
|
||||
* set the current cache methodology
|
||||
* @param cache the cache to use
|
||||
*/
|
||||
public setCache(cache: CacheInterface) {
|
||||
this.cache = cache
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
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
|
||||
@ -47,7 +184,7 @@ export default class TCGdex {
|
||||
/**
|
||||
* @deprecated use `this.fetch('sets', set)`
|
||||
*/
|
||||
public async fetchSet(set: string): Promise<Set | undefined> {
|
||||
public async fetchSet(set: string): Promise<TCGdexSet | undefined> {
|
||||
return this.fetch('sets', set)
|
||||
}
|
||||
|
||||
@ -104,7 +241,14 @@ export default class TCGdex {
|
||||
* @param endpoint_0 'sets'
|
||||
* @param endpoint_1 {string} the set name or ID
|
||||
*/
|
||||
public async fetch(...endpoint: ['sets', string]): Promise<Set | undefined>
|
||||
public async fetch(...endpoint: ['sets', string]): Promise<TCGdexSet | undefined>
|
||||
|
||||
/**
|
||||
* Fetch a random element
|
||||
* @param endpoint_0 'random'
|
||||
* @param endpoint_1 {'set' | 'card' | 'serie'} the type of random element you want to get
|
||||
*/
|
||||
public async fetch(...endpoint: ['random', 'set' | 'card' | 'serie']): Promise<Card | TCGdexSet | Serie | undefined>
|
||||
|
||||
/**
|
||||
* Fetch every sets
|
||||
@ -148,7 +292,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<Endpoint | string>): Promise<any | undefined> {
|
||||
public async fetch<T = object>(...endpoint: Array<Endpoints | string>): Promise<T | undefined> {
|
||||
if (endpoint.length === 0) {
|
||||
throw new Error('endpoint to fetch is empty!')
|
||||
}
|
||||
@ -157,29 +301,110 @@ export default class TCGdex {
|
||||
if (!ENDPOINTS.includes(baseEndpoint)) {
|
||||
throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`)
|
||||
}
|
||||
return this.makeRequest(baseEndpoint, ...endpoint)
|
||||
return this.actualFetch<T>(this.getFullURL([baseEndpoint, ...endpoint]))
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to make the request and normalize the whole path
|
||||
* @param endpoint the endpoint to fetch
|
||||
* @param query the query
|
||||
*/
|
||||
private makeRequest<T = any>(...url: Array<string | number>) {
|
||||
public async fetchWithQuery<T = object>(
|
||||
endpoint: [Endpoints, ...Array<string>],
|
||||
query?: Array<{ key: string, value: string | number | boolean }>
|
||||
): Promise<T | undefined> {
|
||||
if (endpoint.length === 0) {
|
||||
throw new Error('endpoint to fetch is empty!')
|
||||
}
|
||||
const baseEndpoint = endpoint[0].toLowerCase() as Endpoints
|
||||
if (!ENDPOINTS.includes(baseEndpoint)) {
|
||||
throw new Error(`unknown endpoint to fetch! (${baseEndpoint})`)
|
||||
}
|
||||
return this.actualFetch<T>(this.getFullURL(endpoint, query))
|
||||
}
|
||||
|
||||
/**
|
||||
* format the final URL
|
||||
*/
|
||||
private getFullURL(
|
||||
url: Array<string | number>,
|
||||
searchParams?: Array<{ key: string, value: string | number | boolean }>
|
||||
): string {
|
||||
// Normalize path
|
||||
const path = url.map((subPath) => encodeURI(
|
||||
subPath
|
||||
let path = url.map(this.encode).join('/')
|
||||
|
||||
// handle the Search Params
|
||||
if (searchParams) {
|
||||
path += '?' + searchParams.map((it) => `${this.encode(it.key)}=${this.encode(it.value)}`).join('&')
|
||||
}
|
||||
|
||||
// return with the endpoint and all the shit
|
||||
return `${this.getEndpoint()}/${this.getLang()}/${path}`
|
||||
}
|
||||
|
||||
private async actualFetch<T = object>(path: string): Promise<T | undefined> {
|
||||
// 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
|
||||
// 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
|
||||
// remove some special chars
|
||||
// eslint-disable-next-line no-misleading-character-class
|
||||
.replace(/["'\u0300-\u036f]/gu, '')
|
||||
)).join('/')
|
||||
return RequestWrapper.fetch<T>(`${BASE_URL}/${this.getLang()}/${path}`)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// export the old interfaces
|
||||
export type * from './interfaces.d.ts'
|
||||
|
||||
export * from './interfaces'
|
||||
// export the new models items and the Query
|
||||
export {
|
||||
CardModel, CardResumeModel, Endpoint, Model, Query, SerieModel,
|
||||
SerieResume as SerieResumeModel,
|
||||
SetModel,
|
||||
SetResumeModel, SimpleEndpoint
|
||||
}
|
||||
|
20
src/utils.ts
Normal file
20
src/utils.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { Endpoints } from './interfaces'
|
||||
|
||||
/**
|
||||
* detect the current running context ofthe program
|
||||
*/
|
||||
export function detectContext(): 'browser' | 'server' {
|
||||
try {
|
||||
const isBrowser = !!window
|
||||
return isBrowser ? 'browser' : 'server'
|
||||
} catch {
|
||||
return 'server'
|
||||
}
|
||||
}
|
||||
|
||||
export const ENDPOINTS: ReadonlyArray<Endpoints> = [
|
||||
'cards', 'categories', 'dex-ids', 'energy-types',
|
||||
'hp', 'illustrators', 'rarities', 'regulation-marks',
|
||||
'retreats', 'series', 'sets', 'stages', 'suffixes',
|
||||
'trainer-types', 'types', 'variants', 'random'
|
||||
] as const
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["./src/tcgdex.node.ts"],
|
||||
"compilerOptions": {
|
||||
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||
"module": "ES2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"declaration": false, /* Generates corresponding '.d.ts' file. */
|
||||
"declarationDir": null,
|
||||
"outDir": "./dist/modules", /* Redirect output structure to the directory. */
|
||||
}
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
{
|
||||
"extends": "./node_modules/@dzeio/config/tsconfig.base",
|
||||
"include": ["./src/tcgdex.node.ts"],
|
||||
"compilerOptions": {
|
||||
|
||||
"target": "ES2015",
|
||||
|
||||
"declaration": true,
|
||||
"declarationDir": "./dist/types",
|
||||
|
||||
"outDir": "./dist/cjs",
|
||||
"rootDir": "./src",
|
||||
|
||||
}
|
||||
"outDir": "dist",
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"exclude": [
|
||||
"__tests__"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user