Extra contents beyond WaniKani
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

100 lines
2.0 KiB

import glob from 'fast-glob';
import { FastifyPluginAsync } from 'fastify';
import yaml from 'js-yaml';
import S from 'jsonschema-definer';
import sanitize from 'sanitize-filename';
import { oItem, readYAML } from '../shared';
export const vocabularyRouter: FastifyPluginAsync = async (f) => {
f.get<{
Params: {
entry: string;
};
}>('/:entry.md', async (req) => {
const { entry } = req.params;
const m = getEntry(entry);
if (!m) {
throw { statusCode: 404 };
}
const { data, content } = m;
if (content.trim()) return content;
let md = '';
if (data.meanings) {
md += data.meanings
.map((v, i) => {
const out = [`${i + 1}. ${v.meaning.join('; ')}`];
if (v.examples) {
out.push(
...v.examples.map(
(ex) => ' - ' + ex.ja + (ex.en ? `\n - ` + ex.en : ''),
),
);
}
return out.join('\n');
})
.join('\n');
}
return (
md ||
yaml
.dump(data)
.split('\n')
.map((ln) => (ln ? ' ' + ln : ln))
.join('\n')
);
});
f.get<{
Params: {
entry: string;
};
}>('/:entry', async (req): Promise<typeof sEntry.type> => {
const { entry } = req.params;
const m = getEntry(entry);
if (!m) {
throw { statusCode: 404 };
}
return m.data;
});
};
export default vocabularyRouter;
const sEntry = S.shape({
readings: S.list(
S.shape({
reading: S.list(S.string()),
...oItem,
}).additionalProperties(true),
).optional(),
meanings: S.list(
S.shape({
meaning: S.list(S.string()),
...oItem,
}).additionalProperties(true),
).optional(),
}).additionalProperties(true);
function getEntry(entry: string) {
console.log(entry);
const filepath = glob
.sync(`assets/vocabulary/**/${sanitize(entry)}.md`)
.sort()[0];
if (!filepath) return null;
const { data, content } = readYAML(filepath);
return {
data: sEntry.ensure(data),
content,
};
}