import fs from 'fs' import yaml from 'js-yaml' import { toKatakana } from 'wanakana' import { subjects } from './dump-subjects' import { IKanji, IRadical } from './shared' interface IItem { document_url: string level: number meaning: string reading?: string components: { [source: string]: string[] } similar: string[] image?: { src: string content_type: string width: string | undefined height: string | undefined } } interface IBeautifiedRadicals { [id: string]: IItem } export const radicals = { data: {} as IBeautifiedRadicals, filename: 'radicals.yaml', load() { this.data = yaml.load( fs.readFileSync(this.filename, 'utf-8') ) as IBeautifiedRadicals return this.data }, dump(d: IBeautifiedRadicals) { this.data = d this.finalize() }, finalize() { fs.writeFileSync( this.filename, yaml.dump(this.data, { skipInvalid: true }) ) } } async function main() { const rs = subjects.load() const idMap = new Map() radicals.data = {} rs.filter((r) => r.object === 'radical').map((r0) => { const r = r0 as IRadical const d = { document_url: r.data.document_url, level: r.data.level, meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning, components: {}, sup: r.data.amalgamation_subject_ids.map((it) => it.toString()), similar: [] } let id = r.data.characters if (id) { radicals.data[id] = d } else { id = d.meaning const st = (im: { content_type: string metadata: { dimensions?: string } }) => im.content_type === 'image/svg+xml' ? 5000 : im.metadata.dimensions ? Math.min(...im.metadata.dimensions.split('x').map(Number)) : 0 const im = r.data.character_images.sort((a, b) => st(a) - st(b))[0]! const dim = im.metadata.dimensions?.split('x') || [] radicals.data[id] = { ...d, image: { src: im.url, content_type: im.content_type, width: dim[0], height: dim[1] } } } idMap.set(r.id, id) }) rs.filter((r) => r.object === 'kanji').map((r0) => { const r = r0 as IKanji const reading = r.data.readings.filter((m) => m.primary)[0]! const d = { document_url: r.data.document_url, level: r.data.level, meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning, reading: reading.type === 'onyomi' ? toKatakana(reading.reading) : reading.reading, components: { wanikani: r.data.component_subject_ids.map((it) => it.toString()) }, similar: r.data.visually_similar_subject_ids.map((it) => it.toString()) } const id = r.data.characters idMap.set(r.id, id) // const prev = radicals.data[id] // if (prev) { // radicals.data[id] = { // ...d, // sup: prev.sup // } // } else { // radicals.data[id] = { // ...d, // sup: [] // } // } radicals.data[id] = d }) for (const [k, v] of Object.entries(radicals.data)) { if (v.components?.['wanikani']) { v.components['wanikani'] = v.components['wanikani'] .map((s) => idMap.get(Number(s)) || s) .filter((s) => s !== k) } v.similar = v.similar.map((s) => idMap.get(Number(s)) || s) // v.sup = v.sup.map((s) => idMap.get(Number(s)) || s) } radicals.finalize() } if (require.main === module) { main() }