import assert from 'assert'; import { Router } from 'express'; import fetch from 'node-fetch'; import type { PronounExamplesData } from '../../locale/data.ts'; import { buildPronoun, buildPronounUsage, parsePronounGroups, parsePronouns } from '../../src/buildPronoun.ts'; import { Example, PronounLibrary } from '../../src/classes.ts'; import type { Pronoun } from '../../src/classes.ts'; import { buildList, handleErrorAsync } from '../../src/helpers.ts'; import { Translator } from '../../src/translator.ts'; import { loadTsv } from '../../src/tsv.ts'; import { loadSuml, loadSumlFromBase } from '../loader.ts'; import type { LocaleDescription } from '~/locale/locales.ts'; import { rootDir } from '~/server/paths.ts'; const translations = loadSuml('translations'); const baseTranslations = loadSumlFromBase('locale/_base/translations'); const translator = new Translator(translations, baseTranslations, global.config); const pronouns = parsePronouns(global.config, loadTsv(`${rootDir}/data/pronouns/pronouns.tsv`)); const pronounGroups = parsePronounGroups(loadTsv(`${rootDir}/data/pronouns/pronounGroups.tsv`)); const pronounLibrary = new PronounLibrary(global.config, pronounGroups, pronouns); const buildExample = (e: PronounExamplesData): Example => new Example( Example.parse(e.singular), Example.parse(e.plural || e.singular), Example.parse(e.null || e.singular), Example.parse(e.null_plural || e.plural || e.singular), e.isHonorific, ); const requestExamples = (r: string[] | undefined): PronounExamplesData[] => { if (!r || !r.length) { return loadTsv(`${rootDir}/data/pronouns/examples.tsv`); } 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); } }); }; interface PublicPronoun extends Omit { examples: string[]; name: string; } const makePublicPronoun = (pronoun: Pronoun, examples: string[] | undefined): PublicPronoun => { const publicPronoun: any = pronoun.clone(); publicPronoun.examples = addExamples(pronoun, requestExamples(examples)); publicPronoun.name = pronoun.name(); delete publicPronoun.config; delete publicPronoun.hidden; return publicPronoun; }; const router = Router(); router.get('/pronouns', handleErrorAsync(async (req, res) => { const publicPronouns: Record = {}; for (const [name, pronoun] of Object.entries(pronouns)) { if (pronoun.hidden) { continue; } publicPronouns[name] = makePublicPronoun(pronoun, req.query.examples as string[] | undefined); } return res.json(publicPronouns); })); router.get('/pronouns/:pronoun*', handleErrorAsync(async (req, res) => { const pronoun = buildPronoun( pronouns, req.params.pronoun + req.params[0], global.config, translator, ); if (!pronoun) { return res.status(404).json({ error: 'Not found' }); } return res.json(makePublicPronoun(pronoun, req.query.examples as string[] | undefined)); })); router.get('/pronouns-name/:pronoun*', handleErrorAsync(async (req, res) => { const path = (req.params.pronoun + req.params[0]).split('/') .map((p) => decodeURIComponent(p)) .join('/'); const usage = buildPronounUsage(pronounLibrary, path, global.config, translator); if (usage === null) { return res.status(404).json({ error: 'Not found' }); } return res.json(usage.short.options.join(usage.short.glue)); })); const getPronounName = defineCachedFunction(async ( locale: string, pronoun: string, locales: Record, ) => { const encodedPronoun = pronoun.split('/') .map((p) => encodeURIComponent(p)) .join('/'); const res = await (await fetch(`${locales[locale].url}/api/pronouns-name/${encodedPronoun}`)).json(); if (typeof res === 'object' && res.error) { return pronoun; } return res; }, { name: 'pronouns-name', getKey: (locale, pronoun) => `${locale}:${pronoun}`, maxAge: 24 * 60 * 60, }); router.get('/remote-pronouns-name/:locale/:pronoun*', handleErrorAsync(async (req, res) => { assert(Object.hasOwn(req.locales, req.params.locale)); const pronoun = req.params.pronoun + req.params[0]; return res.json(await getPronounName(req.params.locale, pronoun, req.locales)); })); export default router;