import { Router } from 'express'; import { loadSuml, loadSumlFromBase, loadTsv } from '../loader.ts'; import { buildPronoun, parsePronouns } from '../../src/buildPronoun.ts'; import { buildList, handleErrorAsync } from '../../src/helpers.ts'; import { Example } from '../../src/classes.ts'; import { caches } from '../../src/cache.ts'; import { Translator } from '../../src/translator.ts'; import type { Pronoun } from '../../src/classes.ts'; import md5 from 'js-md5'; import assert from 'assert'; import fetch from 'node-fetch'; import type { PronounExamplesData } from '../../locale/data.ts'; const translations = loadSuml('translations'); const baseTranslations = loadSumlFromBase('locale/_base/translations'); const translator = new Translator(translations, baseTranslations, global.config); const buildExample = (e: PronounExamplesData): Example => new Example( Example.parse(e.singular), Example.parse(e.plural || e.singular), e.isHonorific, ); const requestExamples = (r: string[] | undefined): PronounExamplesData[] => { if (!r || !r.length) { return loadTsv('pronouns/examples'); } return buildList(function* () { for (const rr of r) { const [singular, plural, isHonorific] = rr.split('|'); yield { singular, plural, isHonorific: !!isHonorific }; } }); }; const addExamples = (pronoun: Pronoun, examples: PronounExamplesData[]): string[] => { return buildList(function* () { for (const example of examples) { yield buildExample(example).format(pronoun); } }); }; const modifyPronoun = (pronoun: Pronoun, examples: string[] | undefined) => { const modifiedPronoun: any = pronoun; modifiedPronoun.examples = addExamples(pronoun, requestExamples(examples)); modifiedPronoun.name = pronoun.name(); delete modifiedPronoun.config; delete modifiedPronoun.hidden; }; const router = Router(); router.get('/pronouns', handleErrorAsync(async (req, res) => { const pronouns: Record = {}; for (const [name, pronoun] of Object.entries(parsePronouns(global.config, loadTsv('pronouns/pronouns')))) { if (pronoun.hidden) { continue; } pronouns[name] = pronoun; } for (const pronoun of Object.values(pronouns)) { modifyPronoun(pronoun, req.query.examples as string[] | undefined); } return res.json(pronouns); })); router.get('/pronouns/:pronoun*', handleErrorAsync(async (req, res) => { const pronoun = buildPronoun( parsePronouns(global.config, loadTsv('pronouns/pronouns')), req.params.pronoun + req.params[0], global.config, translator, ); if (pronoun) { modifyPronoun(pronoun, req.query.examples as string[] | undefined); } return res.json(pronoun); })); router.get('/pronouns-name/:pronoun*', handleErrorAsync(async (req, res) => { const pronoun = buildPronoun( parsePronouns(global.config, loadTsv('pronouns/pronouns')), (req.params.pronoun + req.params[0]).toLowerCase(), global.config, translator, ); if (!pronoun) { return res.status(404).json({ error: 'Not found' }); } return res.json(pronoun.name()); })); router.get('/remote-pronouns-name/:locale/:pronoun*', handleErrorAsync(async (req, res) => { assert(req.locales.hasOwnProperty(req.params.locale)); const pronoun = req.params.pronoun + req.params[0]; const name = await caches.pronounNames(`${req.params.locale}/${md5(pronoun)}.txt`).fetch(async () => { const res = await (await fetch(`${req.locales[req.params.locale].url}/api/pronouns-name/${pronoun.split('/').map((p) => encodeURIComponent(p))}`)).json(); if (typeof res === 'object' && res.error) { return pronoun; } return res; }); return res.json(name); })); export default router;