import Glossary from "./glossary.ts"; import APIBase from "./base.ts"; import Japanese, { JapaneseFormatter } from "./japanese.ts"; import "../util/string.ts"; import "../util/object.ts"; import { Tag, TagGroup, TokenTags } from "../search/tags.ts"; import { SearchWord } from "../search/types.ts"; import { recursiveValues } from "../util/object.ts"; // irregular stems taken from function irregularSuruStem(tags: TokenTags): string { for (let i = 0, tag = tags[i]; i < tags.length; i++, tag = tags[i]) { if (!recursiveValues(Tag.Inflection).includes(tag)) continue; if (recursiveValues(Tag.Inflection.Reason).includes(tag)) continue; if ([ Tag.Inflection.Polite.Masu, Tag.Inflection.Suffix.Te, Tag.Inflection.Tense.Past, Tag.Inflection.Desirable.Itai, // part of Wikipedia's -ta form Tag.Inflection.Negative, Tag.Inflection.Desirable.Volitional, Tag.Inflection.Command, ].includes(tag as any)) return "し"; if ([ Tag.Inflection.Passive, Tag.Inflection.Causative, ].includes(tag as any)) return "さ"; // wikipedia has できる as the potential form for する, but できる here // means it's already foobar'd break; } return "す"; } function irregularKuruStem(tags: TokenTags): string { for (let i = 0, tag = tags[i]; i < tags.length; i++, tag = tags[i]) { if (!recursiveValues(Tag.Inflection).includes(tag)) continue; if (recursiveValues(Tag.Inflection.Reason).includes(tag)) continue; if ([ Tag.Inflection.Polite.Masu, Tag.Inflection.Suffix.Te, Tag.Inflection.Tense.Past, Tag.Inflection.Desirable.Itai, // part of Wikipedia's -ta form ].includes(tag as any)) return "き"; if ([ Tag.Inflection.Negative, Tag.Inflection.Desirable.Volitional, Tag.Inflection.Passive, Tag.Inflection.Causative, Tag.Inflection.Potential, Tag.Inflection.Command, ].includes(tag as any)) return "こ"; break; } return "く"; } export default class Word extends APIBase { /** @prop dictionary form of verb if this word is a verb */ protected base: Japanese; /** @prop word as written in parent sentence */ protected text: Japanese; /** @prop this.furigana should output kanji with reading */ protected outputKanji: boolean = true; /** @prop this word represents an unrecognized sentence part between recognized terms */ protected filler: boolean; constructor(input: string | SearchWord) { super(); if (typeof input === "string") { this.filler = true; input = input as string; this.base = new Japanese(input, input); this.text = this.base; this.outputKanji = false; } else { this.filler = false; input = input as SearchWord; this.base = new Japanese(input.writing, input.reading); if (input.tags.anyOf(TagGroup.Conjugable as string[])) { // transfer conjugation from input.source to both dictionary reading and writing for furigana var writingCommon = input.writing.cmpLen(input.source); var readingCommon = input.reading.cmpLen(input.source); var stemLength = Math.max(writingCommon, readingCommon); var base = input[writingCommon > readingCommon ? "writing" : "reading"].substring(stemLength); var conjugation = input.source.substring(stemLength); // special reading for irregular verbs var reading = input.reading; if (input.writing == '来る') reading = irregularKuruStem(input.tags) + conjugation; else if (input.writing == '為る') reading = irregularSuruStem(input.tags) + conjugation; else reading = reading.replaceLast(base, conjugation); // generate conjugated version of verb with kanji this.text = new Japanese(input.writing.replaceLast(base, conjugation), reading); } else { this.text = this.base; } this.outputKanji = input.source.hasKanji(); // only output kanji if input also uses kanji } } furigana(format: JapaneseFormatter) { if (!this.outputKanji) return this.text.reading; else return this.text.furigana(format); } async glossary() { // TODO: output nothing if this.filler == true return new Glossary().withParent(await this.api); } }