UNPKG

pmgo-pokedex

Version:

Provide Pokemon GO pokedex data and useful translation.

106 lines (87 loc) 4.08 kB
// Node modules. import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import _ from 'lodash'; import { findBestMatch } from 'string-similarity'; // Local modules. import { Pokemon, PokemonForm, PokemonName, Region, Type } from './models/pokemon'; type Locale = 'en-US' | 'zh-TW'; const readJson = (filename: string) => { const filepath = join(__dirname, '../data', filename); const json = JSON.parse(readFileSync(filepath, { encoding: 'utf-8' })) return json; } class Pokedex { private defaultTargetLocale: Locale; private pokemonNameList: PokemonName[]; private pokemonList: Pokemon[]; private formList: PokemonForm[]; private regionList: Region[]; private typeList: Type[]; constructor(targetLocale: Locale = 'zh-TW') { this.defaultTargetLocale = targetLocale; this.pokemonNameList = readJson('pokemon-name-list.json'); this.pokemonList = readJson('pokemon-list.json'); this.formList = readJson('form-list.json'); this.regionList = readJson('region-list.json'); this.typeList = readJson('type-list.json'); } /** Get pokemon's name by pokemon's number. */ getPokemonNameByNo(pokemonNo: number, locale = this.defaultTargetLocale) { const foundPokemon = this.pokemonNameList.find((pokemon) => pokemon.no === pokemonNo); return foundPokemon ? foundPokemon[locale] : null; }; /** Get pokemon info object by pokemon's fuzzy name. */ getPokemonByFuzzyName = (pokemonName: string, targetLocale = this.defaultTargetLocale): Pokemon => { const { bestMatchIndex: bestNameIndex } = findBestMatch(pokemonName, this.pokemonNameList.map((pokemonName) => pokemonName['en-US'])); const { bestMatchIndex: bestIndex } = findBestMatch(pokemonName, this.pokemonList.map((pokemon) => `${pokemon.name}-${pokemon.form}`)); const matchedPokemonName = this.pokemonNameList[bestNameIndex]; const matchedPokemon = this.pokemonList[bestIndex]; let predictedForm: string | null = null; // Regional. this.regionList.forEach((region) => { region.patterns.forEach((pattern) => { if (new RegExp(pattern, 'i').test(pokemonName)) { predictedForm = region[targetLocale]; } }); }); // Forms. const formCandidates = this.formList.filter((form) => { const isSameName = form.name === matchedPokemon.name; const isMatchedForm = new RegExp(_.escapeRegExp(form['en-US']), 'i').test(String(matchedPokemon.form)) || new RegExp(_.escapeRegExp(String(matchedPokemon.form)), 'i').test(String(form['en-US'])); return isSameName && isMatchedForm; }); if (formCandidates.length > 0) { const formText = pokemonName.replace(String(_.first(formCandidates)?.name), ''); const { bestMatchIndex: bestFormIndex } = findBestMatch(formText, formCandidates.map((form) => String(form[targetLocale]))); predictedForm = String(formCandidates[bestFormIndex][targetLocale]); } // Mega evolutions. if (/mega\s/i.test(pokemonName)) { predictedForm = pokemonName.replace(matchedPokemonName['en-US'], matchedPokemonName[targetLocale]); } const pokemon: Pokemon = { no: matchedPokemonName.no, name: matchedPokemonName[targetLocale], form: predictedForm, types: matchedPokemon.types.map((typeText) => this.transType(typeText, targetLocale)!), }; return pokemon; } /** Translate pokemon's display name by pokemon's fuzzy name. */ transPokemonName(pokemonName: string, targetLocale = this.defaultTargetLocale) { const pokemon = this.getPokemonByFuzzyName(pokemonName, targetLocale); const translatedName = pokemon.form ? `${pokemon.name} (${pokemon.form})` : pokemon.name; return translatedName; } /** Translate type by text of pokemon type. */ transType(typeText: string, targetLocale = this.defaultTargetLocale) { const targetType = typeText.toLowerCase(); const foundType = this.typeList.find((type) => type.patterns.includes(targetType)); return foundType ? foundType[targetLocale] : null; } } export { Pokedex };