From d284488abd64ab34f29e165658ed6141023f6940 Mon Sep 17 00:00:00 2001 From: justinsilvestre Date: Sun, 5 Nov 2023 14:51:37 +0100 Subject: [PATCH] Implement basic seed figures script --- .eslintignore | 14 + .gitignore | 4 +- app/lib/dic/componentsDictionary.yml | 3521 +++++++++++++++++ app/lib/files.server.ts | 1 + .../ComponentUseWithSignificance.ts | 119 - .../models/getFigureById.server.ts | 0 prisma/external/seedKanjiDbComposition.ts | 34 +- prisma/external/seedKanjiDbSbgyNotes.ts | 12 +- prisma/external/seedKanjiDbVariants.ts | 8 +- prisma/external/seedKanjidic.ts | 11 +- prisma/external/seedKanjisenseSoundMarks.ts | 186 - prisma/external/seedSbgy.ts | 9 +- .../external/seedScriptinAozoraFrequencies.ts | 15 +- prisma/external/seedUnihan12.ts | 14 +- prisma/external/seedUnihan14.ts | 9 +- prisma/external/seedUnihan15.ts | 9 +- .../ComponentUseWithSignificance.ts | 106 + .../{external => kanjisense}/KanjiVariant.ts | 2 +- prisma/kanjisense/componentMeanings.ts | 58 +- .../kanjisense/getBaseKanjiVariantGroups.ts | 13 + prisma/kanjisense/getFigureMeaningsText.ts | 25 + prisma/kanjisense/getMeaningfulUses.ts | 16 +- .../{external => kanjisense}/inBatchesOf.ts | 0 prisma/kanjisense/isFigurePriority.ts | 12 +- .../seedKanjisenseFigureRelation.ts | 16 +- prisma/kanjisense/seedKanjisenseFigures.ts | 293 ++ .../kanjisense/seedKanjisenseVariantGroups.ts | 15 +- prisma/schema.prisma | 65 +- prisma/seed.ts | 27 +- prisma/seedUtils.ts | 27 + 30 files changed, 4181 insertions(+), 460 deletions(-) create mode 100644 .eslintignore create mode 100644 app/lib/dic/componentsDictionary.yml delete mode 100644 app/lib/kanjisenseFigure/ComponentUseWithSignificance.ts rename prisma/kanjisense/getFigureById.ts => app/models/getFigureById.server.ts (100%) delete mode 100644 prisma/external/seedKanjisenseSoundMarks.ts create mode 100644 prisma/kanjisense/ComponentUseWithSignificance.ts rename prisma/{external => kanjisense}/KanjiVariant.ts (97%) create mode 100644 prisma/kanjisense/getBaseKanjiVariantGroups.ts create mode 100644 prisma/kanjisense/getFigureMeaningsText.ts rename prisma/{external => kanjisense}/inBatchesOf.ts (100%) rename prisma/{external => kanjisense}/seedKanjisenseFigureRelation.ts (96%) create mode 100644 prisma/kanjisense/seedKanjisenseFigures.ts create mode 100644 prisma/seedUtils.ts diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..1198fc7c6 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,14 @@ +node_modules + +/build +/public/build +.env + +/cypress/screenshots +/cypress/videos +/postgres-data + +/app/styles/tailwind.css + +/app/lib/vendor +/app/lib/dic \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6276dc724..d9d2e6354 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,6 @@ node_modules /cypress/videos /postgres-data -*.log \ No newline at end of file +*.log + +.DS_Store diff --git a/app/lib/dic/componentsDictionary.yml b/app/lib/dic/componentsDictionary.yml new file mode 100644 index 000000000..247eeee18 --- /dev/null +++ b/app/lib/dic/componentsDictionary.yml @@ -0,0 +1,3521 @@ +一: + historical: one + tag: geo +口: + historical: mouth + tag: body +丿: + historical: (various) + mnemonic: swiping hand + tag: hands +人: + historical: human + tag: personal +丶: + historical: dot + tag: geo +日: + historical: sun + tag: nature +木: + historical: tree + tag: nature +土: + historical: earth + tag: nature +八: + historical: eight + mnemonic: little feet + tag: body +丨: + historical: (various) + mnemonic: pole + tag: geo +十: + historical: ten + mnemonic: cross + tag: geo +小: + historical: small + mnemonic: baby + tag: null +亅: + historical: hook + mnemonic: stake + tag: tools +𠆢: + historical: person + mnemonic: umbrella + reference: 傘 + tag: tools +儿: + historical: person + mnemonic: long legs + tag: body +水: + historical: water + tag: nature +心: + historical: heart + tag: body +田: + historical: rice field + tag: place +勹: + historical: wrapping + tag: tools +亠: + historical: lid + tag: tools +厶: + historical: (various) + mnemonic: tail + tag: body +刀: + historical: blade + tag: tools +大: + historical: big + tag: geo +目: + historical: eye + tag: body +又: + historical: right hand + mnemonic: grabbing hand + tag: hands +月: + historical: moon + mnemonic: moon/flesh + tag: nature +冖: + historical: cap + tag: tools +宀: + historical: house + tag: place +冂: + historical: wrapping + mnemonic: cover + tag: tools +幺: + historical: tiny + mnemonic: knot + tag: tools +䒑: + historical: (various) + mnemonic: horns + tag: body +言: + historical: words + tag: body +立: + historical: stand + mnemonic: standing person + tag: personal +⺕: + historical: pig snout + mnemonic: bristles + reference: 聿 + tag: tools +止: + historical: stop + mnemonic: footprint + tag: body +手: + historical: hand + tag: body +艹: + historical: grass + tag: nature +彳: + historical: step + mnemonic: stepping foot + tag: body +囗: + historical: enclosure + tag: place +⻌: + historical: stop and go + mnemonic: road + tag: place +火: + historical: fire + tag: nature +女: + historical: woman + tag: personal +卜: + historical: divining + mnemonic: fortune teller + tag: personal +自: + historical: self + mnemonic: nose + tag: body +艮: + historical: mountain/northeast/a trigram of the I Ching + mnemonic: silver + standin: 銀 + tag: nature +子: + historical: child + tag: personal +乛: + historical: second Heavenly Stem + mnemonic: gasping mouth + tag: body +生: + historical: life + mnemonic: plants + tag: nature +乂: + historical: mow + mnemonic: shears + tag: body +尸: + historical: corpse + mnemonic: roof + standin: 屋 + tag: place +士: + historical: gentleman + tag: personal +夂: + historical: follow after + mnemonic: trail + tag: place +𭕄: + historical: hair + tag: body +几: + historical: table + tag: tools +匕: + historical: spoon + tag: tools +貝: + historical: seashell + tag: animals +夕: + historical: dusk + tag: nature +羊: + historical: sheep + tag: animals +米: + historical: rice + tag: food +門: + historical: gate + tag: place +力: + historical: strong + mnemonic: strong arm + tag: body +凵: + historical: box + tag: tools +丁: + historical: block + tag: geo +隹: + historical: old bird + mnemonic: perching bird + tag: animals +巾: + historical: towel + tag: tools +示: + historical: altar + tag: place +广: + historical: cave + tag: place +罒: + historical: net + tag: tools +山: + historical: mountain + tag: nature +皮: + historical: skin + tag: body +牛: + historical: cattle + tag: animals +工: + historical: craft + mnemonic: tool + tag: tools +弓: + historical: bow + tag: weapons +耳: + historical: ear + tag: body +気: + historical: air + tag: nature +斤: + historical: axe + tag: weapons +肉: + historical: flesh + tag: body +竹: + historical: bamboo + tag: plants +邑: + historical: town + tag: place +甲: + historical: shell + tag: body +㐄: + historical: follow after (backwards) + mnemonic: step backwards + tag: action +井: + historical: well + tag: place +車: + historical: car + tag: tools +母: + historical: mother + tag: personal +龴: + historical: (various) + mnemonic: spearhead + tag: weapons +廾: + historical: joined hands + tag: hands +卩: + historical: kneeling person + tag: body +CDP-89AE: # CDP-8C41,氺,楽,渋,CDP-88D2,摂,率,塁,函,𠕒,CDP-8D6F,褱,CDP-8CCF,雨,雲,需,震,雪,霜,電,雰,霧,雷,零,霊,露,屚,靄,霰,雫,霞,霸,霝,曇,儒,濡,襦,蕾,澪,漏,靈,犀,遲,懷,壞,屬,囑,CDP-85DC,隶,CDP-8D71,泰,彔,录,㳟,求,救,球,毬,康,逮,隷,糠,桼,黎,漆,膝,剝,祿,綠,錄,緑,録,禄,暴,爆,瀑,曝,薬,脊,涵 + historical: splash + tag: nature +爪: + historical: claw + tag: body +𠃊: + historical: second Heavenly Stem + mnemonic: corner + tag: geo +入: + historical: enter + tag: actions +氷: + historical: ice + tag: nature +豕: + historical: pig + tag: animals +中: + historical: middle + tag: geo +矢: + historical: arrow + tag: weapons +臼: + historical: mortar + tag: tools +虫: + historical: bug + tag: animals +己: + historical: self + mnemonic: rope + tag: tools +七: + historical: seven + mnemonic: criss-cross + tag: geo +欠: + historical: gap + tag: geo +文: + historical: pattern, design; text + tag: geo +业: + historical: (various) + mnemonic: twigs + tag: plants +川: + historical: river + tag: nature +九: + historical: nine + mnemonic: crossed legs + tag: body +爿: + historical: bed + tag: place +干: + historical: infringe; dry; railing + mnemonic: trunk + standin: 幹 + tag: plants +馬: + historical: horse + tag: animals +癶: + historical: legs + mnemonic: climbing legs + tag: actions +衣: + historical: robe + tag: fabric +𧘇: + historical: (various) + mnemonic: skirt + tag: fabric +𠂤: + historical: (various)? + mnemonic: teacher + standin: 師 + tag: personal +世: + historical: leaf + standin: 葉 + tag: plants +石: + historical: stone + tag: nature +巳: + historical: year of the Snake + mnemonic: snake + tag: animals +西: + historical: west + tag: nature +長: + historical: long + mnemonic: long-haired person + tag: personal +也: + historical: modal particle + mnemonic: pond + standin: 池 + tag: nature +五: + historical: five + tag: null +皿: + historical: plate + tag: tools +氏: + historical: clan + tag: personal +𤰔: + historical: spool + tag: tools +乍: + historical: instant + mnemonic: create + standin: 作 + tag: actions +曲: + historical: turn + tag: geo +覀: + historical: engulf + full: 覆 + tag: actions +𠃜: + historical: (various) + mnemonic: eyebrow + standin: 眉 + tag: body +巨: + historical: giant + tag: personal +無: + historical: have no + mnemonic: dancer + reference: 舞 + tag: personal +且: + historical: moreover + mnemonic: gravestone + reference: 祖 + tag: place +比: + historical: compare + mnemonic: deer legs + tag: animals +不: + historical: not + mnemonic: crossed out + tag: geo +円: + historical: (various) + mnemonic: round + tag: geo +匚: + historical: container + mnemonic: shelf + tag: place +亜: + historical: lower + mnemonic: underground + tag: nature +身: + historical: body + tag: body +CDP-8BF5: # 介,齐,粛,弗,界,芥,堺,斎,繍,費,沸,佛,拂 + historical: prying hands + tag: hands +才: + historical: talent + mnemonic: timber + standin: 材 + tag: tools +非: + historical: not + mnemonic: sad + standin: 悲 + tag: feeling +疒: + historical: illness + mnemonic: sickbed + tag: feeling +廴: + historical: stretch + tag: geo +角: + historical: horn + tag: body +㔾: + historical: seal, kneeling person + mnemonic: fetal position + tag: body +面: + historical: face + mnemonic: mask + tag: fabric +尺: + historical: shaku (unit of distance) + mnemonic: foot-long + tag: geo +CDP-8CC6: # 畏,辰,喪,CDP-8CE5,猥,隈,辱,唇,娠,振,震,農,宸,蜃,賑,晨,褥,濃,膿,展 + mnemonic: legs and cane + tag: body +GWS-U2FF1-U4E00-CDP-8CC6-VAR-001: + mnemonic: old body + tag: body +乙: + historical: second + mnemonic: hook + tag: tools +羽: + historical: feathers + tag: body +丹: + historical: cinnabar + tag: nature +元: + historical: origin + tag: nature +丘: + historical: knoll + tag: nature +禺: + historical: long-tailed monkey + tag: animals +光: + historical: light + tag: nature +之: + historical: of + mnemonic: turf + standin: 芝 + tag: nature +CDP-876E: # CDP-8BF8,乗,垂,華,嘩,樺,剰,睡,唾,郵,錘 + historical: (various) + mnemonic: ivy + tag: plants +GWS-U4E29-VAR-001: + historical: twist + full: 糾 + tag: geo +CDP-8CBD: # 卬,兜,仰,迎,抑,昂,CDP-8C79,叚,暇,瑕,蝦,霞,假 + historical: (various) + mnemonic: pennant + tag: fabric +民: + historical: people + tag: personal +冉: + historical: drooping + mnemonic: plodding tortoise + tag: animals +片: + historical: flat piece + tag: geo +斗: + historical: dipper + tag: tools +旡: + historical: choke + tag: actions +及: + historical: reach + mnemonic: reaching arms + tag: hands +兆: + historical: omen + tag: null +彑: + historical: pig snout + tag: animals +而: + mnemonic: goatee + tag: body +為: + historical: sake + tag: null +乎: + historical: to + mnemonic: owl + tag: animals +𠂆: + historical: (various) + mnemonic: shield + standin: 盾 + tag: weapons +乃: + historical: accordingly + mnemonic: chipped blade + tag: weapons +央: + historical: center + tag: geo +牙: + historical: fang + tag: body +州: + historical: province + tag: place +乑: + historical: masses + full: 衆 + tag: personal +瓜: + historical: melon + tag: food +瓦: + historical: tile + tag: tools +于: + historical: at + mnemonic: space + standin: 宇 + tag: geo +CDP-8D46: # 鼠,巤,臘,蠟,獵 + historical: (various) + mnemonic: mouse + standin: 鼠 + tag: animals +豸: + historical: xiezhi + mnemonic: horned dog + tag: animals +丑: + historical: year of the Ox + mnemonic: ox + tag: animals +冊: + historical: volume + tag: tools +凹: + historical: concave + tag: geo +凸: + historical: convex + tag: geo +################################################### +################################################### +################################################### +# composite components +################################################### +################################################### +################################################### +弋: + historical: corded arrow + tag: weapons +戈: + historical: dagger-axe + tag: weapons +厓: + historical: cliff + tag: nature +攵: + historical: knock + full: 敲 + tag: actions +从: + historical: twins + tag: personal +屮: + historical: sprout + tag: plants +殳: + historical: spear + mnemonic: throwing hand + reference: 投 + tag: hands +氺: + historical: water + mnemonic: pump + tag: tools +CDP-8BF1: # 用,半,奉,𠂡,甬,備,𬎾,通,痛,踊,誦,桶,涌,樋,庸,傭,伴,判,畔,叛,袢,絆,俸,棒,捧,鼡,猟,蝋 + historical: (various) + mnemonic: axels + tag: tools +CDP-8B62: # 𭥴,CDP-88D4,會,曾,檜,繪,僧,層,憎,增,贈,黑,墨,熏,默,點,黨,勳,薰 + historical: (various) + mnemonic: cat eyes + tag: body +聿: + historical: brush + standin: 筆 + tag: tools +歹: + historical: bare bones, wicked + mnemonic: remains + reference: 残 + tag: null +GWS-U300EE: # 栄,営,覚,学,蛍,労,撹 + historical: (various) + mnemonic: fur cap + tag: fabric +丂: + historical: obstruct + mnemonic: snub-face + tag: body +爻: + historical: I Ching hexagram line + mnemonic: slivers + tag: geo +𢆶: + historical: (various) + mnemonic: double knot + tag: fabric +刖: + historical: amputate + mnemonic: mincemeat + tag: food +虍: + historical: tiger stripes + tag: animals +𡗗: + historical: budding branches + tag: plants +开: + historical: open + mnemonic: supporting hands + tag: hands +亲: + historical: spicy + mnemonic: stand in tree + tag: actions +𮥶: + historical: stork + tag: animals +圣: + historical: underground watercourse + mnemonic: tunnel + tag: nature +菐: + historical: thicket + tag: plants +𤴓: + historical: (various) + mnemonic: ankle + tag: body +昜: + historical: open + mnemonic: sunshine + standin: 陽 + tag: nature +𫩏: + historical: (various) + mnemonic: elephant head + standin: 象 + tag: body +𠄐: + historical: spear handle + tag: weapons +CDP-8BD6: # 奥,向,CDP-8D7C,襖,奧 + historical: (various) + mnemonic: domed lid + tag: tools +㦮: + historical: narrow + mnemonic: coin + standin: 銭 + tag: tools +甬: + historical: enclosed path + mnemonic: spouted bucket + tag: tools +冋: + historical: (various) + mnemonic: mouth covering + tag: fabric +娄: + historical: the bond + mnemonic: tower + standin: 楼 + tag: place +釆: + historical: divide + mnemonic: chopping hand + tag: hands +𠫓: + historical: upside-down child + tag: personal +夭: + historical: calamity + tag: null +CDP-8BB8: # 愛,受,舜,曖,授,綬,瞬 + historical: (various) + mnemonic: crown of thorns + tag: fabric +𠮛: + historical: (various) + mnemonic: opening mouth + tag: body +㑒: + historical: all, together, unanimous + mnemonic: swordsman + reference: 剣 + tag: personal +坴: + historical: clod of earth + mnemonic: continent + standin: 陸 + tag: place +𠕁: + historical: (various) + mnemonic: tied hands + tag: hands +咅: + historical: pooh + mnemonic: spitting mouth + tag: body +𦰩: + historical: clay + mnemonic: Han + standin: 漢 + tag: proper +CDP-8BE8: # 竜,電,滝,奄,CDP-89BD,俺,庵,亀,縄 + historical: (various) + mnemonic: lightning + standin: 電 + tag: nature +䜌: + historical: chaotic + mnemonic: muffled speaking + tag: actions +埶: + historical: skill + mnemonic: round continent + tag: place +关: + historical: (various) + mnemonic: bloom + standin: 咲 + tag: plants +𠀎: + historical: (various) + mnemonic: grating + tag: place +枼: + historical: leafy tree + tag: plants +术: + historical: millet + tag: plants +氐: + historical: Di tribe + mnemonic: bottom + standin: 底 + tag: place +兑: + historical: cash + mnemonic: point + standin: 鋭 + tag: geo +舛: + historical: erroneous + mnemonic: dancing legs + reference: 舞 + tag: body +舞: + historical: dance + tag: personal +CDP-8CCC: # 差,羞,着,嗟,磋,嵯,瑳 + historical: (various) + mnemonic: shepherd's crook + tag: tools +侖: + historical: reason + mnemonic: huddle + tag: actions +GWS-U226F3-VAR-001: # 聴,徳,德,聽,廳 + historical: moral + mnemonic: moral + standin: 徳 + tag: feeling +夬: + historical: decide + full: 決 + tag: feeling +CDP-8BA8: # 興,與,輿,擧,譽,欅,襷 + historical: carry + mnemonic: lifting hands + tag: hands +GWS-U2FFA-U200CA-U7C73: # 継,断,繼,斷 + historical: patch + full: 継 + tag: fabric +戠: + historical: sword, potter's clay + mnemonic: crashing dagger-axe + tag: weapons +睪: + historical: spy + tag: actions +畐: + historical: fill + mnemonic: abundance + standin: 富 + tag: geo +罙: + historical: chimney? + mnemonic: deep + standin: 深 + tag: geo +𠀐: + historical: (various) + mnemonic: signpost + tag: place +咼: + historical: crooked mouth + mnemonic: hotpot + standin: 鍋 + tag: tools +𢖻: + historical: love + mnemonic: ardent feelings + tag: feeling +甶: + historical: (various) + mnemonic: ogre head + reference: 鬼 + tag: body +㐬: + historical: (various) + mnemonic: flow + standin: 流 + tag: geo +𠂢: + historical: tributary + mnemonic: vein + standin: 脈 + tag: body +亚: + historical: (various) + mnemonic: trimmed hedge + tag: plants +㐭: + historical: granary + tag: place +𢚩: + historical: cautious + mnemonic: hide + standin: 隠 + tag: actions +GWS-U5DE9-G: + historical: secure, solid + mnemonic: fright + standin: 恐 + tag: feeling +尃: + historical: state, announce + mnemonic: expert + standin: 博 + tag: personal +忩: + historical: hurried + mnemonic: window + reference: 窓 + tag: place +复: + historical: repeat + mnemonic: fold + tag: geo +CDP-8BEC: # 帝,旁,締,諦,啼,蹄,傍,榜,膀,謗 + historical: (various) + mnemonic: emperor's crown + reference: 帝 + tag: fabric +弗: + historical: not + mnemonic: Buddha + standin: 佛 + tag: personal +髟: + historical: long hair + tag: body +GWS-U5F56-ITAIJI-001: # 縁,篆,緣 + historical: divination + mnemonic: hem + standin: 縁 + tag: fabric +犮: + historical: extract + full: 拔 + tag: actions +㕣: + historical: marsh at foot of hill + mnemonic: riverside + standin: 沿 + tag: nature +𤇾: + historical: torchlight? + mnemonic: firefly + standin: 螢 + tag: animals +𠩵: + historical: calendar + mnemonic: cliffside forest + tag: nature +𢦏: + historical: wound? + mnemonic: planter + standin: 栽 + tag: tools +𠬝: + historical: subdue + mnemonic: clothes + standin: 服 + tag: fabric +啚: + historical: lowly + mnemonic: bumpkin + standin: 鄙 + tag: personal +卬: + historical: lofty + mnemonic: upward-looking + standin: 仰 + tag: actions +CDP-8D56: # 慶,鹿,廌,麗,麓,塵,漉,麒,麟,薦 + historical: (various) + mnemonic: deer head + reference: 鹿 + tag: animals +CDP-8CC9: # 監,覧,CDP-8D50,艦,鑑,濫,藍,檻,覽 + historical: (various) + mnemonic: supervisor + reference: 監 + tag: personal +攸: + historical: distant + mnemonic: palisade + tag: place +GWS-U8931-ITAIJI-004: # 壊,懐,懷,壞 + historical: pocket + reference: 懷 + tag: fabric +录: + historical: engraving + reference: 録 + tag: tools +㐮: + historical: assist + mnemonic: brew + standin: 醸 + tag: actions +啇: + historical: stem, to stalk + mnemonic: vitrine + tag: tools +冓: + historical: inner rooms of palace + mnemonic: gutter + standin: 溝 + tag: place +禸: + historical: rump + mnemonic: monkey body + reference: 禺 + tag: animals +GWS-U4343-VAR-001: # 揺,謡,遥,瑶,搖,遙,謠 + historical: vase, pitcher + mnemonic: open jar + tag: tools +GWS-U5B5A-G: + historical: trust + mnemonic: suckling babe + reference: 乳 + tag: personal +离: + historical: hornless dragon + tag: animals +𦭝: + historical: (various) + mnemonic: grass net + tag: tools +CDP-8D60: + historical: blind + mnemonic: dreamcatcher + reference: 夢 +豦: + historical: wild boar + tag: animals +辟: + mnemonic: wicked lawmaker + standin: 壁 + tag: personal +𢆉: + historical: (various) + mnemonic: little lamb + reference: 羊 + tag: animals +隺: + historical: bird flying, ambition + mnemonic: crane + standin: 鶴 + tag: animals +迶: + historical: appearance of walking + mnemonic: follow path + standin: 随 + tag: actions +尗: + historical: beans + mnemonic: uncle + standin: 叔 + tag: personal +夗: + historical: turn over in sleep + mnemonic: insomniac + tag: personal +𦰌: + historical: clay + mnemonic: salad + tag: food +𤔔: + historical: govern + mnemonic: trap + tag: weapons +夆: + historical: resist + mnemonic: peak + reference: 峰 + tag: geo +㒸: + historical: horned pig + tag: animals +㒼: + historical: average, equal, covered + mnemonic: full + standin: 滿 + tag: geo +叚: + historical: provisional + mnemonic: shrimp + standin: 蝦 + tag: animals +GWS-U2FF1-U2D544-U51F6: # 悩,脳,惱,腦 + historical: brain + full: 脳 + tag: body +夹: + historical: flank + full: 挟 + tag: geo +丗: + historical: thirty + tag: geo +囱: + historical: chimney, top of head + mnemonic: skull + tag: body +耑: + historical: edge + mnemonic: edge + standin: 端 + tag: geo +旁: + historical: beside + mnemonic: bystander + standin: 傍 + tag: personal +冘: + historical: advance + mnemonic: sink + standin: 沈 + tag: actions +柬: + historical: letter + tag: tools +溥: + historical: pervasive + mnemonic: seafarer + tag: personal +喿: + historical: birds chirping + tag: animals +𡨄: + historical: stop up + mnemonic: fortress + standin: 塞 + tag: place +冏: + historical: jute plant + mnemonic: businessman + reference: 商 + tag: personal +GWS-CDP-8CA9-07: # 隋,惰,楕,遀,墮,隨,髓 + historical: (various) + mnemonic: lazy + standin: 惰 + tag: feelings +舄: + historical: slipper + mnemonic: lagoon + standin: 潟 + tag: place +朿: + historical: thorn + full: 刺 + tag: plants +厷: + historical: forearm + mnemonic: male + standin: 雄 + tag: animals +CDP-89BD: # 亀,縄,竈,蠅,繩 + historical: (various) + mnemonic: toad + tag: animals +宓: + historical: silent + mnemonic: honey + standin: 蜜 + tag: food +臤: + historical: firm + full: 堅 + tag: geo +粦: + historical: neighbor + full: 隣 + tag: personal +㚘: + historical: walk together + mnemonic: husbands + tag: personal +殹: + historical: groan + tag: actions +蒦: + historical: huo sound + mnemonic: loot + standin: 獲 + tag: tools +翟: + historical: kind of pheasant + mnemonic: ruffled bird + tag: animals +乇: + historical: blade of grass + tag: plants +俞: + historical: consent + mnemonic: pleasant + standin: 愉 + tag: feelings +GWS-U595A-ITAIJI-001: # 渓,鶏,蹊,鷄,溪 + historical: what + mnemonic: chicken-farmer + reference: 鶏 + tag: personal +㸚: + historical: two divination diagrams + mnemonic: shreds + tag: geo +㐱: + historical: thick hair + mnemonic: bonnet + tag: fabric +GWS-U66F7-VAR-005: # 謁,喝,渇,褐,掲,靄,偈,𦝲,揭,渴,謁,喝,褐,﨟 + historical: what + mnemonic: awning + tag: place +䦨: + historical: railing + tag: place +显: + historical: exposure + full: 顕 + tag: geo +卂: + historical: fly rapidly + reference: 飛 + tag: actions +奞: + historical: stride + mnemonic: big bird +屰: + historical: disobey + mnemonic: reverse + standin: 逆 + tag: actions +鼡: + historical: rat + mnemonic: mane + tag: body +CDP-8D71: # 桼,黎,漆,膝 + historical: (various) + mnemonic: busted umbrella + tag: tools +劦: + historical: cooperation + full: 協 + tag: personal +GWS-U7230-G: + historical: here, change to + mnemonic: slack + standin: 緩 + tag: fabric +鬲: + historical: cauldron + tag: tools +夋: + historical: dawdle + mnemonic: sour + standin: 酸 + tag: food +桼: + historical: lacquer tree + full: 漆 + tag: plants +奐: + historical: splendid + tag: feeling +GWS-U2FF1-U2008A-U65E7: # 陥,焰,閻,陷 + historical: pitfall + full: 陥 + tag: place +畾: + historical: fields divided by dikes + mnemonic: plantation + tag: place +它: + historical: other + mnemonic: snake pole + reference: 蛇 + tag: tools +匊: + historical: handful, scoop + mnemonic: chrysanthemum + standin: 菊 + tag: plants +詹: + historical: prattle + tag: actions +隶: + historical: servant + full: 隷 + tag: personal +矣: + historical: grammatical particle + mnemonic: dust + reference: 埃 + tag: nature +尞: + historical: fuel used for sacrifices + mnemonic: colleague + standin: 僚 + tag: personal +GWS-U23A8A-VAR-001: # 殻,穀,穀,殼 + historical: husk + standin: 殻 + tag: plants +夸: + historical: boast + full: 誇 + tag: actions +賁: + historical: energetic, bright + mnemonic: tomb + standin: 墳 + tag: place +茲: + historical: here + mnemonic: magnet + standin: 磁 + tag: tools +𭔰: + historical: (various) + mnemonic: lima bean + tag: food +GWS-U655D-G: + historical: worn out + mnemonic: cash + standin: 幣 + tag: tools +睘: + historical: round, stare + mnemonic: hoop + standin: 環 + tag: geo +朁: + historical: supposing, nevertheless + mnemonic: hiding crocodile + reference: 潛 + tag: animals +孰: + historical: what + mnemonic: ripen + standin: 熟 + tag: food +亶: + historical: sincere + mnemonic: podium + standin: 壇 + tag: place +鹵: + historical: alkaline salt + tag: nature +盧: + historical: hut + tag: place +厉: + historical: whetstone + tag: tools +雔: + historical: (various) + mnemonic: twin birds + tag: animals +𣶒: + historical: deep pool + full: 淵 + tag: nature +耒: + historical: plow + full: 耕 + tag: tools +𤋱: + historical: fumigation + tag: tools +夌: + historical: dawdle + tag: actions +玨: + historical: inlaid gems + tag: tools +匋: + historical: pottery + full: 陶 + tag: tools +咢: + historical: drumming + mnemonic: chin + standin: 顎 + tag: body +豖: + historical: shackled pig + tag: animals +聶: + historical: whisper + tag: body +宁: + historical: stockpile + tag: tools +妟: + historical: at ease + mnemonic: hostess + reference: 宴 + tag: personal +𣦼: + historical: bore + mnemonic: magic spell + tag: null +GWS-U97F1-VAR-001: # 繊,懺,纖 + historical: wild onions or leeks + mnemonic: fiber + standin: 繊 + tag: plants +貇: + historical: gnaw + mnemonic: silver horned dog + tag: animals +敖: + mnemonic: strut + reference: 傲 + tag: actions +豈: + historical: question particle + mnemonic: armor + standin: 鎧 + tag: weapons +翏: + historical: sound of the wind + mnemonic: gust + tag: nature +咠: + historical: whisper + mnemonic: gossip + tag: actions +雍: + historical: softening, harmonious + mnemonic: restrained bird + tag: animals +叕: + historical: chain together + mnemonic: chain + tag: geo +韭: + historical: garlic chive + full: 韮 + tag: plants +CDP-8C6A: # 款,隷 + historical: crabapple + mnemonic: dirty altar + tag: place +癸: + historical: tenth Heavenly Stem + mnemonic: reach the summit + tag: actions +疌: + historical: victory + mnemonic: eyelashes + standin: 睫 + tag: body +CDP-8DBF: # 廌,焉,薦 + historical: (various) + mnemonic: bird legs + tag: animals +圼: + historical: black soil + mnemonic: knead + standin: 捏 + tag: actions +畺: + historical: border + tag: place +################################################### +################################################### +################################################### +# composite both characters and components +################################################### +################################################### +################################################### +二: + historical: two + tag: geo +寸: + historical: sun (unit of measure) + mnemonic: inch + tag: geo +合: + historical: join + tag: geo +糸: + historical: string + tag: fabric +見: + historical: see + tag: actions +老: + historical: elder + tag: personal +禾: + historical: grain + tag: plants +白: + historical: white + tag: feelings +良: + historical: good + tag: feelings +里: + historical: li + mnemonic: mile + tag: geo +者: + historical: that which + mnemonic: early riser + tag: personal +寺: + historical: temple + tag: place +犬: + historical: dog + tag: animals +方: + historical: square + tag: geo +三: + historical: three + tag: geo +頁: + historical: head + tag: body +千: + historical: thousand + tag: geo +可: + historical: can + tag: feeling +夫: + historical: husband + tag: personal +云: + historical: say + mnemonic: cloud + reference: 雲 + tag: nature +出: + historical: come out + tag: actions +阜: + historical: mound + tag: geo +廿: + historical: twenty + tag: geo +来: + historical: come + mnemonic: wheat + tag: plants +王: + historical: king + tag: personal +戊: + historical: fifth Heavenly Stem + mnemonic: garrison + reference: 戌 + tag: weapons +豆: + historical: beans + tag: food +勿: + historical: not + mnemonic: shawl + tag: fabric +玉: + historical: jewel + tag: tools +音: + historical: sound + tag: feelings +古: + historical: old + tag: feelings +行: + historical: go + mnemonic: footsteps + tag: actions +少: + historical: few + tag: geo +本: + historical: base + tag: geo +上: + historical: up + tag: geo +思: + historical: think + tag: feelings +分: + historical: part + tag: geo +旦: + historical: daybreak + tag: nature +戸: + historical: door + tag: place +金: + historical: gold + tag: nature +何: + historical: what + tag: null +時: + historical: time + tag: null +青: + historical: blue + tag: null +穴: + historical: hole + tag: geo +由: + historical: reason + mnemonic: germinate + tag: plants +今: + historical: now + mnemonic: clenching mouth + reference: 含 + tag: body +至: + historical: arrive + tag: actions +食: + historical: eat + tag: food +間: + historical: interval + tag: geo +申: + historical: year of the Monkey + mnemonic: monkey + tag: animals +曽: + historical: once before + mnemonic: monk + standin: 僧 + tag: personal +左: + historical: left-hand + tag: body +先: + historical: ahead + tag: geo +用: + historical: use + mnemonic: bucket + tag: tools +舌: + historical: tongue + tag: body +重: + historical: heaps + tag: geo +尚: + historical: still, yet; ancient; exalt + mnemonic: antique + tag: actions +直: + historical: direct + tag: geo +早: + historical: early + tag: nature +勺: + historical: shaku (unit of volume) + mnemonic: tablespoon + tag: tools +各: + historical: each + mnemonic: notch + reference: 格 + tag: geo +家: + historical: household + tag: place +前: + historical: front + tag: geo +豊: + historical: abundance + mnemonic: piles + tag: geo +午: + historical: noon + mnemonic: stallion + tag: animals +辛: + historical: acrid + tag: feeling +雨: + historical: rain + tag: nature +巴: + historical: ba + mnemonic: leviathan + tag: animals +四: + historical: four + tag: geo +足: + historical: leg + tag: body +下: + historical: down + tag: geo +帚: + historical: broom + standin: 箒 + tag: tools +父: + historical: father + tag: personal +主: + historical: chief + tag: personal +毎: + historical: every + mnemonic: sea + standin: 海 + tag: nature +物: + historical: thing + tag: null +知: + historical: know + tag: feelings +骨: + historical: bone + tag: body +声: + historical: voice + tag: feelings +反: + historical: opposite + tag: geo +共: + historical: together + tag: personal +戌: + historical: year of the Dog + mnemonic: watchdog + tag: animals +売: + historical: sell + tag: actions +取: + historical: take + tag: hands +天: + historical: heaven + tag: nature +我: + historical: I + tag: personal +与: + historical: with, impart + mnemonic: raising hands + reference: 挙 + tag: hands +酉: + historical: year of the Rooster + mnemonic: rooster + tag: animals +黒: + historical: black + tag: feelings +未: + historical: not yet + mnemonic: sapling + tag: plants +其: + historical: its + mnemonic: basket + tag: tools +臣: + historical: vassal + tag: personal +正: + historical: proper + tag: feelings +或: + historical: perhaps, some + mnemonic: territory + standin: 域 + tag: place +占: + historical: divination + tag: actions +永: + historical: eternity + tag: null +吉: + historical: fortunate + tag: feelings +同: + historical: same + mnemonic: grotto + standin: 洞 + tag: nature +弔: + historical: condole + tag: feelings +相: + historical: mutually + mnemonic: appearance + tag: geo +亦: + historical: also + tag: geo +内: + historical: inside + tag: place +度: + historical: degree + tag: null +会: + historical: meet + tag: geo +次: + historical: next + tag: null +処: + historical: place + tag: place +成: + historical: become + tag: geo +貫: + historical: pierce + tag: geo +余: + historical: surplus + tag: feelings +居: + historical: reside + tag: place +単: + historical: unit + tag: geo +兄: + historical: older brother + tag: personal +彦: + historical: lad + tag: personal +尹: + historical: administer + tag: social +走: + historical: walk + tag: actions +鳥: + historical: bird + tag: animals +意: + historical: idea + tag: feelings +巻: + historical: roll + tag: geo +弟: + historical: younger brother + tag: personal +首: + historical: head/neck + tag: body +台: + historical: platform + tag: place +屋: + historical: roof + tag: place +丸: + historical: round + tag: geo +束: + historical: bundle + tag: tools +両: + historical: both + tag: geo +代: + historical: generation, substitute + mnemonic: substitute + tag: actions +化: + historical: change + tag: null +幸: + historical: happy + tag: feelings +林: + historical: woods + tag: plants +卸: + historical: wholesale + tag: null +黄: + historical: yellow + tag: color +去: + historical: depart + tag: actions +然: + historical: so + mnemonic: burn + standin: 燃 + tag: action +君: + historical: lord + tag: personal +京: + historical: capital + tag: place +予: + historical: beforehand + mnemonic: unfinished spear + reference: 矛 + tag: weapons +高: + historical: high + tag: geo +明: + historical: bright + tag: color +動: + historical: move + tag: actions +咸: + historical: everyone + tag: personal +韋: + historical: soft leather + tag: tools +色: + historical: color + tag: color +郎: + historical: son + tag: personal +国: + historical: country + tag: place +甫: + historical: just now + mnemonic: shore + standin: 浦 + tag: place +通: + historical: pass through + tag: actions +義: + historical: righteous + tag: feelings +具: + historical: ingredient + tag: tools +空: + historical: empty + tag: geo +感: + historical: feeling + tag: feeling +亡: + historical: deceased + tag: process +交: + historical: mix + tag: hands +道: + historical: way + tag: place +名: + historical: name + tag: null +平: + historical: level + tag: geo +右: + historical: right-hand + tag: body +付: + historical: adhere + tag: geo +以: + historical: hold + tag: geo +男: + historical: man + tag: personal +壬: + historical: ninth Heavenly Stem + mnemonic: responsible + standin: 任 + tag: feelings +谷: + historical: valley + tag: place +考: + historical: consider + tag: feelings +多: + historical: many + tag: geo +風: + historical: wind + tag: nature +回: + historical: around + tag: geo +新: + historical: new + tag: process +公: + historical: duke + tag: personal +発: + historical: set out + tag: actions +半: + historical: half + tag: geo +品: + historical: wares + tag: tools +真: + historical: truth + tag: feelings +原: + historical: field + tag: place +神: + historical: spirit + tag: process +夜: + historical: night + tag: nature +吾: + historical: me + mnemonic: enlightenment + standin: 悟 + tag: feelings +北: + historical: north + tag: nature +卓: + historical: eminent + tag: feelings +専: + historical: dedicated + tag: feelings +争: + historical: dispute + tag: actions +友: + historical: friend + tag: personal +句: + historical: phrase + tag: verbal +必: + historical: necessary + tag: feelings +六: + historical: six + tag: quantity +旗: + historical: flag + tag: fabric +免: + historical: evening + standin: 晩 + tag: nature +百: + historical: hundred + tag: quantity +死: + historical: death + tag: process +有: + historical: be there + tag: process +軍: + historical: army + tag: personal +太: + historical: thick + tag: geo +此: + historical: this + mnemonic: purple + standin: 紫 + tag: color +全: + historical: entire + tag: geo +舟: + historical: boat + tag: tools +歩: + historical: walk + tag: actions +奇: + historical: strange + tag: feelings +辰: + historical: year of the Dragon + mnemonic: flying dragon + tag: animals +切: + historical: cut + tag: actions +卒: + historical: graduate + tag: social +GWS-U20B36-VAR-002: + mnemonic: trespasser + tag: personal +支: + historical: arm + tag: body +凶: + historical: bad luck + tag: feelings +圭: + mnemonic: embankment + tag: place +是: + historical: this + tag: null +幾: + historical: how much + mnemonic: warp and weft + reference: 機 + tag: fabric +楽: + historical: music + tag: feelings +召: + historical: summon + tag: verbal +皆: + historical: step + reference: 階 + tag: place +東: + historical: east + tag: nature +安: + historical: peace + tag: actions +表: + historical: chart + tag: tools +凡: + historical: ordinary + mnemonic: breeze + reference: 風 + tag: nature +能: + historical: talent + mnemonic: bear + standin: 熊 + tag: animals +要: + historical: need + tag: actions +象: + historical: elephant + tag: animals +登: + historical: climb + tag: actions +周: + historical: circuit + tag: geo +史: + historical: history + tag: verbal +缶: + historical: jar + tag: tools +洛: + historical: Luo + tag: proper +斉: + historical: even + tag: geo +告: + historical: revelation + tag: verbal +令: + historical: order + tag: verbal +最: + historical: most + tag: null +孝: + historical: filial piety + tag: social +祭: + historical: festival + tag: actions +朝: + historical: morning + tag: nature +莫: + historical: must not + mnemonic: sunset + standin: 暮 + tag: nature +袁: + historical: long robe + mnemonic: ape + standin: 猿 + tag: animals +若: + historical: young + tag: process +番: + historical: place in order + tag: geo +叩: + historical: strike + tag: actions +達: + historical: attain + tag: actions +活: + historical: active + tag: actions +数: + historical: count + tag: actions +果: + historical: fruit + tag: plants +介: + historical: introduce + tag: geo +官: + historical: office + tag: place +頃: + historical: period + tag: process +別: + historical: separate + tag: geo +加: + historical: add + tag: geo +升: + historical: rise + full: 昇 + tag: geo +将: + historical: commander + tag: personal +列: + historical: rank + tag: geo +蜀: + historical: Shu + tag: proper +呂: + historical: backbone + tag: body +朕: + historical: we the Emperor + tag: personal +花: + historical: flower + tag: plants +系: + historical: lineage + tag: geo +壮: + historical: robust + tag: null +呈: + historical: display + tag: actions +兵: + historical: soldier + tag: personal +愛: + historical: love + tag: feelings +坐: + historical: sit + tag: actions +鼓: + historical: drum + tag: tools +式: + historical: rite + tag: social +竜: + historical: dragon + tag: animals +定: + historical: set + tag: actions +丙: + historical: third Heavenly Stem + tag: geo +敬: + historical: venerate + tag: verbal +員: + historical: member + tag: personal +号: + historical: number + tag: verbal +負: + historical: defeated + tag: social +如: + historical: likeness + tag: null +買: + historical: purchase + tag: social +失: + historical: loss + tag: action +即: + historical: conforming + tag: null +解: + historical: resolve + tag: geo +飛: + historical: fly + tag: actions +卯: + historical: year of the Hare + mnemonic: bunny ears + tag: animals +昔: + historical: of old + tag: process +景: + historical: scenery + tag: nature +包: + historical: wrap up + tag: geo +鬼: + historical: ogre + tag: animals +旨: + historical: delicious + tag: feelings +路: + historical: path + tag: place +肖: + historical: resemblance + tag: null +郷: + historical: countryside + tag: place +助: + historical: help + tag: social +奴: + historical: slave + tag: personal +戻: + historical: return + tag: actions +貴: + historical: value + tag: feelings +弘: + historical: vast + mnemonic: stretched bow + tag: weapons +市: + historical: market + tag: place +并: + historical: unite + full: 併 + tag: geo +魚: + historical: fish + tag: animals +覚: + historical: aware + tag: feelings +区: + historical: ward + tag: place +連: + historical: link + tag: geo +受: + historical: receive + tag: actions +広: + historical: wide + tag: geo +尭: + historical: high, Yao + mnemonic: dawn + standin: 暁 + tag: nature +疋: + historical: roll of cloth + tag: fabric +折: + historical: break + tag: geo +利: + historical: benefit + tag: feelings +冬: + historical: winter + tag: nature +万: + historical: thousand, scorpion + mnemonic: scorpion + tag: animals +念: + historical: concern + tag: feelings +血: + historical: blood + tag: body +客: + historical: visitor + tag: personal +昭: + historical: illuminate + tag: color +従: + historical: complying + tag: null +頼: + historical: entrust + tag: social +毛: + historical: hairs + tag: body +𧈡: + historical: flea + tag: animals +更: + historical: night watch + tag: social +蔵: + historical: stow + tag: actions +波: + historical: wave + tag: nature +布: + historical: cloth + tag: fabric +吏: + historical: official + tag: personal +赤: + historical: red + tag: color +旧: + historical: former + tag: process +参: + historical: participate + tag: social +求: + historical: demand + tag: feelings +界: + historical: world + tag: nature +師: + historical: teacher + tag: personal +則: + historical: accordance + tag: null +匹: + historical: small animals + tag: animals +制: + historical: control + tag: actions +玄: + historical: obscure + tag: color +泉: + historical: spring + tag: nature +尓: + historical: thus + tag: null +既: + historical: already + tag: process +並: + historical: along + tag: geo +矛: + historical: spear + tag: weapons +麻: + historical: hemp + tag: plants +微: + historical: minuteness + tag: geo +炎: + historical: flame + tag: nature +乗: + historical: ride + tag: actions +倉: + historical: storehouse + tag: place +刃: + historical: blade edge + tag: weapons +固: + historical: hard + tag: geo +兼: + historical: concurrently + mnemonic: sickle + standin: 鎌 + tag: weapons +廷: + historical: court + tag: place +志: + historical: will + tag: feelings +司: + historical: boss + tag: personal +妻: + historical: wife + tag: personal +異: + historical: different + tag: null +医: + historical: medical + tag: personal +武: + historical: military + tag: weapons +鹿: + historical: deer + tag: animals +呑: + historical: swallow up + tag: actions +奥: + historical: recesses + tag: place +建: + historical: build + tag: actions +答: + historical: answer + tag: verbal +卉: + historical: grass, plants + mnemonic: overgrown grass + tag: plants +奄: + historical: abrupt + tag: feelings +甚: + historical: exceeding + tag: feelings +宿: + historical: lodging + tag: actions +完: + historical: whole + tag: null +敢: + historical: dare + tag: actions +虎: + historical: tiger + tag: animals +責: + historical: liable + tag: feelings +春: + historical: springtime + tag: nature +難: + historical: difficult + tag: feelings +GWS-U914B-G: + historical: chieftain + tag: personal +疑: + historical: question + tag: feelings +亥: + historical: year of the Boar + mnemonic: hog + tag: animals +南: + historical: south + tag: nature +段: + historical: grade + tag: null +秋: + historical: autumn + tag: nature +喜: + historical: glad + tag: feelings +守: + historical: protect + tag: actions +忍: + historical: abide + tag: feelings +容: + historical: contents + tag: geo +呆: + historical: dumbfounded + tag: feelings +尤: + historical: outstanding + tag: feelings +竟: + historical: finally + mnemonic: mirror + standin: 鏡 + tag: tools +産: + historical: give birth + tag: process +追: + historical: chase + tag: actions +匈: + historical: Hun + tag: proper +久: + historical: long time + tag: process +雁: + historical: goose + tag: animals +静: + historical: quiet + tag: null +充: + historical: supply + tag: null +到: + historical: arrive + tag: action +雲: + historical: cloud + tag: nature +離: + historical: apart + tag: geo +歯: + historical: tooth + tag: body +放: + historical: release + tag: geo +叔: + historical: uncle + tag: personal +岡: + historical: hill + tag: nature +喬: + historical: haughty + tag: null +留: + historical: stay + tag: action +那: + historical: phonetic "na" + tag: phonetic +屈: + historical: bend + tag: geo +舎: + historical: abode + tag: place +諸: + historical: (various) + tag: null +苗: + historical: seedling + tag: plants +乞: + historical: beg + tag: verbal +革: + historical: leather + tag: tools +雑: + historical: miscellaneous + tag: null +秀: + historical: excellence + tag: feelings +朱: + historical: vermillion + tag: nature +宛: + historical: address + tag: verbal +憂: + historical: melancholy + tag: feelings +善: + historical: virtuous + tag: feelings +害: + historical: harm + tag: feelings +甘: + historical: sweet + tag: null +奉: + historical: observance + tag: social +妾: + historical: concubine + tag: personal +呉: + historical: Wu + tag: proper +亘: + historical: span + tag: geo +因: + historical: cause + tag: process +尊: + historical: revered + tag: social +危: + historical: danger + tag: feelings +県: + historical: prefecture + tag: place +斬: + historical: beheading + tag: social +鷹: + historical: hawk + tag: animals +帝: + historical: emperor + tag: personal +育: + historical: bring up + tag: process +府: + historical: government body + tag: social +末: + historical: tip + tag: geo +宗: + historical: sect + tag: social +叉: + historical: forking + tag: geo +保: + historical: preserve + tag: action +章: + historical: chapter + tag: verbal +扁: + historical: flat + tag: geo +散: + historical: disperse + tag: place +児: + historical: offspring + tag: personal +帯: + historical: belt + tag: fabric +屯: + historical: stationing + tag: place +察: + historical: examine + tag: action +差: + historical: variation + tag: geo +殿: + historical: hall + tag: place +務: + historical: duty + tag: social +歳: + historical: years old + tag: process +農: + historical: farming + tag: social +転: + historical: roll + tag: action +敏: + historical: alert + tag: feeling +監: + historical: inspection + tag: social +尾: + historical: tail + tag: body +丈: + historical: zhang + mnemonic: ten feet + tag: geo +条: + historical: streak + tag: geo +弱: + historical: weak + tag: geo +寅: + historical: year of the Tiger + mnemonic: captive tiger + tag: animals +星: + historical: star + tag: nature +叟: + historical: old man + tag: personal +任: + historical: responsible + tag: social +般: + historical: general + tag: abstract +虚: + historical: void + tag: geo +却: + historical: go back + tag: action +復: + historical: again + tag: process +隻: + historical: vessels + tag: tools +逢: + historical: encounter + tag: action +節: + historical: node + tag: geo +陰: + historical: shadow + tag: color +刑: + historical: punish + tag: social +習: + historical: practice + tag: action +致: + historical: deliver + tag: action +童: + historical: juvenile + tag: personal +退: + historical: withdraw + tag: action +就: + historical: accede + tag: action +夏: + historical: summer + tag: nature +享: + historical: enjoy + tag: feeling +匂: + historical: smell + tag: feeling +暴: + historical: violence + tag: feeling +采: + historical: gather + full: 採 + tag: place +隊: + historical: squadron + tag: social +易: + historical: easy + tag: feeling +荒: + historical: unwrought + tag: process +勇: + historical: brave + tag: feeling +昏: + historical: dim + tag: color +厭: + historical: tired of + tag: feeling +聴: + historical: listen + tag: feeling +射: + historical: shoot + tag: place +垂: + historical: hang + tag: place +亭: + historical: pavilion + tag: place +尽: + historical: deplete + tag: action +寿: + historical: longevity + tag: process +厳: + historical: strict + tag: feeling +湯: + historical: hot water + tag: nature +胃: + historical: stomach + tag: body +恵: + historical: bless + tag: feeling +沓: + historical: boot + tag: fabric +曼: + historical: phonetic "man" + reference: 慢 + tag: phonetic +著: + historical: come out with + tag: place +哀: + historical: pity + tag: feeling +巫: + historical: sorcerer + tag: social +囚: + historical: imprisoned + tag: social +華: + historical: splendor + tag: process +便: + historical: convenient + tag: feeling +英: + historical: flourish + tag: feeling +普: + historical: universal + tag: feeling +荘: + historical: villa + tag: place +挙: + historical: raise + tag: place +迷: + historical: bewilder + tag: feeling +宅: + historical: home + tag: place +巽: + historical: southeast + mnemonic: dragon-snake + tag: animals +香: + historical: fragrant + tag: feeling +量: + historical: amount + tag: feeling +園: + historical: orchard + tag: place +皇: + historical: emperor + tag: personal +朋: + historical: companion + tag: personal +領: + historical: domain + tag: social +卑: + historical: lowly + tag: social +獄: + historical: prison + tag: place +亢: + historical: neck + tag: body +胡: + historical: barbarian + tag: social +筑: + historical: chiku lute + tag: tools +肋: + historical: rib + tag: body +耶: + historical: phonetic "ya" + tag: phonetic +遣: + historical: dispatch + tag: place +益: + historical: gain + tag: geo +尼: + historical: nun + tag: personal +宣: + historical: declare + tag: verbal +允: + historical: license + tag: social +兎: + historical: rabbit + tag: animals +票: + historical: ballot + tag: tools +浦: + historical: shore + tag: nature +貞: + historical: chaste + tag: social +某: + historical: so-and-so + tag: feeling +互: + historical: mutual + tag: place +維: + historical: filament + tag: fabric +灰: + historical: ash + tag: nature +賓: + historical: guest + tag: social +希: + historical: hope + tag: feeling +替: + historical: exchange + tag: social +冒: + historical: risk + tag: feeling +昌: + historical: prosperous + tag: social +規: + historical: rule + tag: feeling +戒: + historical: guard against + tag: geo +曹: + historical: officer + tag: social +延: + historical: prolong + tag: geo +了: + historical: complete + tag: process +禁: + historical: prohibit + tag: social +舜: + historical: Shun + tag: personal +忽: + historical: suddenly + tag: feeling +昆: + historical: descendant + tag: personal +遂: + historical: follow through + tag: place +泊: + historical: stay overnight + tag: social +需: + historical: require + tag: feeling +双: + historical: pair + tag: geo +執: + historical: hold fast + tag: geo +含: + historical: contain + tag: geo +慮: + historical: deliberation + tag: feeling +尉: + historical: lieutenant + tag: social +唐: + historical: Tang dynasty + tag: proper +宜: + historical: suitable + tag: feeling +麦: + historical: wheat + tag: plants +徴: + historical: sign + tag: feeling +幼: + historical: tot + tag: process +犀: + historical: rhinoceros + tag: animals +孫: + historical: grandchild + tag: personal +侯: + historical: marquis + tag: personal +委: + historical: yield over + tag: geo +盾: + historical: shield + tag: tools +嬰: + historical: infant + tag: personal +臭: + historical: stink + tag: feeling +属: + historical: genus + tag: feeling +屏: + historical: barrier + tag: tools +柔: + historical: soft + tag: geo +丞: + historical: deputy + tag: social +雇: + historical: employ + tag: social +眉: + historical: eyebrow + tag: body +豪: + historical: overpowering + tag: feeling +堅: + historical: firm + tag: geo +康: + historical: ease + tag: feeling +鮮: + historical: fresh + tag: process +賞: + historical: reward + tag: social +焦: + historical: scorch + tag: nature +帛: + historical: silk cloth + tag: fabric +斥: + historical: oust + tag: action +曳: + historical: tow + tag: action +沙: + historical: phonetic "sa" + tag: phonetic +勅: + historical: imperial decree + tag: social +奈: + historical: how, what + tag: null +孔: + historical: slit + tag: geo +栗: + historical: chestnut + tag: plants +札: + historical: token + tag: tools +孟: + historical: Mengzi + tag: personal +畜: + historical: livestock + tag: animals +賛: + historical: tribute + tag: social +須: + historical: by all means + tag: null +巷: + historical: alley + tag: place +孤: + historical: lonely + tag: feeling +季: + historical: season + tag: nature +疾: + historical: rapid + tag: place +署: + historical: signature + tag: social +隋: + historical: Sui dynasty + tag: proper +契: + historical: pledge + tag: verbal +扇: + historical: fan + tag: tools +畏: + historical: dread + tag: feeling +衰: + historical: decline + tag: process +雷: + historical: thunder + tag: nature +奏: + historical: play music + tag: social +躬: + historical: oneself + tag: personal +芻: + historical: grass forage + tag: plants +烏: + historical: crow + tag: animals +蒙: + historical: ignorance + tag: feeling +串: + historical: skewer + tag: tools +粛: + historical: solemn + tag: feeling +愈: + historical: increasingly + tag: feeling +弯: + historical: curve + tag: geo +后: + historical: empress + tag: personal +辱: + historical: humiliate + tag: social +廉: + historical: cheap + tag: feeling +頻: + historical: frequent + tag: feeling +伐: + historical: fell + tag: action +郭: + historical: district + tag: place +楚: + historical: Chu + tag: proper +庶: + historical: commoner + tag: social +庸: + historical: ordinary + tag: feeling +卵: + historical: egg + tag: body +宰: + historical: superintendent + tag: social +魯: + historical: Lu + tag: proper +旬: + historical: decameron + tag: null +惟: + historical: ponder + tag: feeling +閏: + historical: intercalary + tag: null +彗: + historical: comet + tag: nature +析: + historical: divide + tag: geo +冥: + historical: murky + tag: color +燕: + historical: a swallow + tag: animals +累: + historical: implicate + tag: geo +秦: + historical: Qin dynasty + tag: proper +牟: + historical: moo + tag: phonetic +克: + historical: overcome + tag: action +虐: + historical: oppression + tag: feeling +朔: + historical: first of the month + tag: null +禽: + historical: fowl + tag: animals +謁: + historical: royal audience + tag: social +珀: + historical: amber + tag: nature +稟: + historical: report + tag: verbal +零: + historical: zero + tag: null +函: + historical: envelope + tag: geo +晃: + historical: dazzling + tag: color +耆: + historical: senile + tag: process +雉: + historical: pheasant + tag: animals +窄: + historical: constricted + tag: geo +旱: + historical: drought + tag: nature +窒: + historical: obstruct + tag: geo +GWS-U5BFD-G: + mnemonic: commander + standin: 将 + tag: null +臥: + historical: prostrate + tag: action +軗: + mnemonic: beat + standin: 撃 +####### +丱: + historical: tufts of hair + mnemonic: stitch + reference: 關 + tag: fabric +亀: + historical: turtle + tag: animals +CDP-89EE: + mnemonic: tripod + reference: 鼎 + tag: tools +𠁁: + historical: jug + tag: tools diff --git a/app/lib/files.server.ts b/app/lib/files.server.ts index 4bd79967b..fb9dfee83 100644 --- a/app/lib/files.server.ts +++ b/app/lib/files.server.ts @@ -18,6 +18,7 @@ export const files = { nk2028GuangyunYuntu: vendor("nk2028/guangyun-yuntu-廣韻反切音韻地位表.csv"), nk2028YunjingCsv: vendor("nk2028/qieyun-data-guyiconshu-yunjing.csv"), scriptinAozoraFrequenciesJson: vendor("scriptin/aozora.json"), + componentsDictionaryYml: dic("componentsDictionary.yml"), sbgyJson: dic("sbgy.json"), sbgyNotesJson: dic("sbgyNotes.json"), }; diff --git a/app/lib/kanjisenseFigure/ComponentUseWithSignificance.ts b/app/lib/kanjisenseFigure/ComponentUseWithSignificance.ts deleted file mode 100644 index 614bbb203..000000000 --- a/app/lib/kanjisenseFigure/ComponentUseWithSignificance.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** no tag means direct meaningful */ - -type FigureId = string; - -export enum ComponentUseTag { - /** used within this parent character, but not common enough to have a meaning in Kanjijump */ - directMeaningless = "d", - - /** should not happen */ - directMeaninglessSound = "e", - - /** used within a "directMeaningless" component of this parent character */ - meaningfulIndirect = "m", - - /** used within a "directMeaningless component" of this parent character, serving as sound mark */ - meaningfulIndirectSound = "n", - - /** used directly as a sound mark within this parent character */ - sound = "s", -} - -export class ComponentUseWithSignificance { - parent: FigureId; - tag?: ComponentUseTag; - parentIsPriorityFigure: boolean; - - constructor( - parent: FigureId, - parentIsPriorityFigure: boolean, - tag?: ComponentUseTag, - ) { - this.parent = parent; - this.tag = tag; - this.parentIsPriorityFigure = parentIsPriorityFigure; - } - - isDirect() { - return ( - !this.tag || - this.tag === ComponentUseTag.directMeaningless || - this.tag === ComponentUseTag.sound || - this.tag === ComponentUseTag.directMeaninglessSound - ); - } - - isMeaningful() { - return ( - !this.tag || - this.tag === ComponentUseTag.meaningfulIndirect || - this.tag === ComponentUseTag.meaningfulIndirectSound || - this.tag === ComponentUseTag.sound - ); - } - - isKanjijumpMeaningful() { - return ( - !this.tag || - this.tag === ComponentUseTag.meaningfulIndirect || - this.tag === ComponentUseTag.meaningfulIndirectSound || - (this.parentIsPriorityFigure && this.tag === ComponentUseTag.sound) - ); - } - - isSoundMarkUse() { - return ( - this.tag === ComponentUseTag.directMeaninglessSound || - this.tag === ComponentUseTag.meaningfulIndirectSound || - this.tag === ComponentUseTag.sound - ); - } - - isKanjijumpSoundMarkUse() { - return ( - this.tag === ComponentUseTag.meaningfulIndirectSound || - (this.parentIsPriorityFigure && this.tag === ComponentUseTag.sound) - ); - } - - toJSON() { - return ( - (this.tag || "") + this.parent + (!this.parentIsPriorityFigure ? "*" : "") - ); - } - - static fromJSON(json: ReturnType) { - const match = /^(?[dmens])?(?[^*]+)(?\*)?$/u.exec( - json, - ); - if (!match?.groups) { - throw new Error(`Problem decoding JSON ${JSON.stringify(json)}`); - } - const { parent, tag, nonPriority } = match.groups; - return new ComponentUseWithSignificance( - parent, - !nonPriority, - (tag as ComponentUseTag) || undefined, - ); - } -} - -export function getTag( - direct: boolean, - meaningful: boolean, - soundMark: boolean, -): ComponentUseTag | undefined { - if (direct && !meaningful) { - return soundMark - ? ComponentUseTag.directMeaninglessSound - : ComponentUseTag.directMeaningless; - } - - if (!direct && meaningful) { - return soundMark - ? ComponentUseTag.meaningfulIndirectSound - : ComponentUseTag.meaningfulIndirect; - } - - return soundMark ? ComponentUseTag.sound : undefined; -} diff --git a/prisma/kanjisense/getFigureById.ts b/app/models/getFigureById.server.ts similarity index 100% rename from prisma/kanjisense/getFigureById.ts rename to app/models/getFigureById.server.ts diff --git a/prisma/external/seedKanjiDbComposition.ts b/prisma/external/seedKanjiDbComposition.ts index e6b6d2b4d..45d3d68c2 100644 --- a/prisma/external/seedKanjiDbComposition.ts +++ b/prisma/external/seedKanjiDbComposition.ts @@ -3,12 +3,14 @@ import { PrismaClient } from "@prisma/client"; import { files, readJsonSync } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + export async function seedKanjiDbComposition( prisma: PrismaClient, force = false, ) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjiDbComposition" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjiDbComposition" }, }); if (seeded && !force) console.log(`KanjiDbComposition already seeded. 🌱`); else { @@ -27,12 +29,7 @@ export async function seedKanjiDbComposition( ), }); - if ( - !(await prisma.readyTables.findUnique({ - where: { id: "KanjiDbComposition" }, - })) - ) - await prisma.readyTables.create({ data: { id: "KanjiDbComposition" } }); + await registerSeeded(prisma, "KanjiDbComposition"); } console.log(`KanjiDbComposition seeded. 🌱`); @@ -60,10 +57,8 @@ async function getDbInput() { const [, figureId, etymology] = line.match(/\S+\t&?([^&;\s]+);?\t(.+)/u)!; if (!figureId || !etymology) throw new Error(line); - dbInput[figureId] = { - id: figureId, - etymology, - }; + if (!dbInput[figureId]) console.warn(`no id for ${figureId} in ${line}`); + if (dbInput[figureId]) dbInput[figureId].etymology = etymology; }); const sbgyJson = readJsonSync< @@ -76,15 +71,16 @@ async function getDbInput() { ][] >(files.sbgyJson); - for (const [syllableNumber, , , characters] of sbgyJson) { + for (const [syllableNumber, fanqie, , characters] of sbgyJson) { for (const character of characters.split(",")) { - dbInput[character] = { - ...dbInput[character], - sbgySyllables: [ - ...(dbInput[character]?.sbgySyllables || []), - syllableNumber, - ], + if (!character) + console.warn(`no character for ${syllableNumber} ${fanqie}`); + dbInput[character] ||= { + id: character, }; + + dbInput[character].sbgySyllables ||= []; + dbInput[character].sbgySyllables!.push(syllableNumber); } } return dbInput; diff --git a/prisma/external/seedKanjiDbSbgyNotes.ts b/prisma/external/seedKanjiDbSbgyNotes.ts index bc0f1127d..057036a36 100644 --- a/prisma/external/seedKanjiDbSbgyNotes.ts +++ b/prisma/external/seedKanjiDbSbgyNotes.ts @@ -2,9 +2,11 @@ import { PrismaClient } from "@prisma/client"; import { files, readJsonSync } from "~/lib/files.server"; +import { registerSeeded } from "../seedUtils"; + export async function seedKanjiDbSbgyNotes(prisma: PrismaClient) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjiDbSbgyNote" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjiDbSbgyNote" }, }); if (seeded) console.log(`KanjiDbSbgyNote already seeded. 🌱`); else { @@ -24,11 +26,7 @@ export async function seedKanjiDbSbgyNotes(prisma: PrismaClient) { } } - await prisma.kanjiDbSbgyNote.createMany({ - data: dbInput, - }); - - await prisma.readyTables.create({ data: { id: "KanjiDbSbgyNote" } }); + await registerSeeded(prisma, "KanjiDbSbgyNote"); console.log(`KanjiDbSbgyNote seeded. 🌱`); } diff --git a/prisma/external/seedKanjiDbVariants.ts b/prisma/external/seedKanjiDbVariants.ts index 18a3ff60b..e2b77e610 100644 --- a/prisma/external/seedKanjiDbVariants.ts +++ b/prisma/external/seedKanjiDbVariants.ts @@ -3,13 +3,15 @@ import { KanjiDbVariantType, Prisma, PrismaClient } from "@prisma/client"; import { files } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + // this reading isn't in modern usage, // i.e. the simplified form was borrowed from an existing character const suppressedOldVariants = new Set("糸虫万"); export async function seedKanjiDbVariants(prisma: PrismaClient) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjiDbVariant" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjiDbVariant" }, }); if (seeded) console.log(`KanjiDbVariant already seeded. 🌱`); else { @@ -26,7 +28,7 @@ export async function seedKanjiDbVariants(prisma: PrismaClient) { console.log("getting hanyu dacidian variants"); await getKanjiDbHanyuDaCidianVariants(prisma); - await prisma.readyTables.create({ data: { id: "KanjiDbVariant" } }); + await registerSeeded(prisma, "KanjiDbVariant"); console.log(`KanjiDbVariant seeded. 🌱`); } diff --git a/prisma/external/seedKanjidic.ts b/prisma/external/seedKanjidic.ts index f3f1147e3..2b2a86c12 100644 --- a/prisma/external/seedKanjidic.ts +++ b/prisma/external/seedKanjidic.ts @@ -2,6 +2,8 @@ import { PrismaClient } from "@prisma/client"; import { files, readJsonSync } from "~/lib/files.server"; +import { registerSeeded } from "../seedUtils"; + type KanjibankJson = [ string, string, @@ -12,8 +14,8 @@ type KanjibankJson = [ ][]; export async function seedKanjidic(prisma: PrismaClient, force = false) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjidicEntry" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjidicEntry" }, }); if (seeded && !force) console.log(`kanjidic already seeded. 🌱`); else { @@ -37,10 +39,7 @@ export async function seedKanjidic(prisma: PrismaClient, force = false) { }); } - if ( - !(await prisma.readyTables.findUnique({ where: { id: "KanjidicEntry" } })) - ) - await prisma.readyTables.create({ data: { id: "KanjidicEntry" } }); + await registerSeeded(prisma, "KanjidicEntry"); console.log(`kanjidic seeded. 🌱`); } diff --git a/prisma/external/seedKanjisenseSoundMarks.ts b/prisma/external/seedKanjisenseSoundMarks.ts deleted file mode 100644 index b4d31a56d..000000000 --- a/prisma/external/seedKanjisenseSoundMarks.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { PrismaClient } from "@prisma/client"; - -export async function seedKanjisenseSoundMarks( - prisma: PrismaClient, - force = false, -) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjisenseSoundMark" }, - }); - if (seeded && !force) console.log(`KanjisenseSoundMark already seeded. 🌱`); - else { - console.log(`seeding KanjisenseSoundMark...`); - - const dbInput = new Map(); - - // first pass: find provisional sound marks - const figuresIds = (await prisma.kanjisenseFigureRelation.findMany()).map( - ({ id }) => id, - ); - const kanjiDbEtymologies = await prisma.kanjiDbComposition.findMany({ - where: { id: { in: figuresIds }, etymology: { not: null } }, - }); - const kanjiDbEtymologiesCache = new Map( - kanjiDbEtymologies.map(({ id, etymology }) => [id, etymology!]), - ); - - kanjiDbEtymologiesCache.set("录", "→彔"); - kanjiDbEtymologiesCache.set("虽", "→虽"); - kanjiDbEtymologiesCache.set("叱", "→𠮟"); - kanjiDbEtymologiesCache.set("𠮟", "⿰口七 七聲"); - kanjiDbEtymologiesCache.set("教", "⿰孝攵 孝聲"); - kanjiDbEtymologiesCache.set("少", "⿰小丿 小聲"); - kanjiDbEtymologiesCache.set("摒", "⿰扌屛 屛聲"); - kanjiDbEtymologiesCache.set("將", "⿰爿⿱肉寸 會意 0890030"); // comment threw parsing off: # 【字通】醬聲はありえない - kanjiDbEtymologiesCache.set("㓞", "⿰丰刀 會意"); - - for (const { id, etymology: etymologyText } of kanjiDbEtymologies) { - const originCharacter = parseEtymologyText(id, etymologyText!); - if (originCharacter) { - const chain: CharacterOriginReference[] = []; - let nextInChain: CharacterOriginReference | null = originCharacter; - if (nextInChain) - do { - chain.push(nextInChain); - } while ( - (nextInChain = await getNextInEtymologyChain( - prisma, - kanjiDbEtymologiesCache, - nextInChain, - )) - ); - dbInput.set(id, { - character: id, - soundMark: originCharacter.char, - chain, - }); - } - } - - await prisma.kanjisenseSoundMark.deleteMany({}); - await prisma.kanjisenseSoundMark.createMany({ - data: [...dbInput.values()].map(({ character, soundMark, chain }) => ({ - character, - activeSoundMark: soundMark, - chain: { set: chain.map((item) => item.toJSON()) }, - })), - }); - - if ( - !(await prisma.readyTables.findUnique({ - where: { id: "KanjisenseSoundMark" }, - })) - ) - await prisma.readyTables.create({ - data: { id: "KanjisenseSoundMark" }, - }); - } - - console.log(`KanjisenseSoundMark seeded. 🌱`); -} - -interface CreateSoundMarkInput { - character: string; - soundMark: string; - chain: CharacterOriginReference[]; -} - -enum CharacterOriginType { - phonetic, - simplification, -} - -class CharacterOriginReference { - char: string; - source: string; - type: CharacterOriginType; - constructor(char: string, source: string, type: CharacterOriginType) { - this.char = char; - this.source = source; - this.type = type; - } - - isPhonetic() { - return this.type === CharacterOriginType.phonetic; - } - - isSimplification() { - return this.type === CharacterOriginType.simplification; - } - - toJSON() { - const { char, source, type } = this; - return [char, source, type === CharacterOriginType.phonetic ? "p" : "s"]; - } - static fromJSON(json: ReturnType) { - const [char, source, typeCode] = json; - return new CharacterOriginReference( - char, - source, - typeCode === "p" - ? CharacterOriginType.phonetic - : CharacterOriginType.simplification, - ); - } -} - -function parseEtymologyText(character: string, text: string) { - const [, parentMatch] = text.match(/^→(\S+)[^簡体]*(?#.+)?$/u) || []; - if (parentMatch) { - return new CharacterOriginReference( - character, - parentMatch, - CharacterOriginType.simplification, - ); - } - - const [, soundMarkMatch] = - text.match(/[\s】/]([^形])[省亦]?[聲声](.*)?$/u) || []; - if (soundMarkMatch) { - return new CharacterOriginReference( - character, - soundMarkMatch, - CharacterOriginType.phonetic, - ); - } - - return null; -} - -async function lookUpKanjiDbEtymology( - prisma: PrismaClient, - cache: Map, - id: string, -) { - if (cache.has(id)) { - return cache.get(id)!; - } else { - const kanjiDbEtymology = await prisma.kanjiDbComposition.findUnique({ - where: { id }, - }); - if (kanjiDbEtymology) { - cache.set(id, kanjiDbEtymology.etymology!); - return kanjiDbEtymology.etymology!; - } else { - return null; - } - } -} - -async function getNextInEtymologyChain( - prisma: PrismaClient, - etymologiesCache: Map, - item: CharacterOriginReference, -): Promise { - if (item.isPhonetic()) { - const etymologyText = await lookUpKanjiDbEtymology( - prisma, - etymologiesCache, - item.source, - ); - if (!etymologyText) return null; - const etymology = parseEtymologyText(item.source, etymologyText); - return etymology; - } - return null; -} diff --git a/prisma/external/seedSbgy.ts b/prisma/external/seedSbgy.ts index 634bb68b0..a9cf3c836 100644 --- a/prisma/external/seedSbgy.ts +++ b/prisma/external/seedSbgy.ts @@ -3,6 +3,8 @@ import { Prisma, PrismaClient } from "@prisma/client"; import { files, readJsonSync } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + // mostly ocr and xml structure corrections const replacementFanqie = { 179: "尺隹切", @@ -37,8 +39,8 @@ const replacementExemplars: Record string> = { }; export async function seedSbgy(prisma: PrismaClient, force = false) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "SbgyXiaoyun" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "SbgyXiaoyun" }, }); if (seeded && !force) console.log(`SbgyXiaoyun already seeded. 🌱`); else { @@ -72,8 +74,7 @@ export async function seedSbgy(prisma: PrismaClient, force = false) { }); } - if (!(await prisma.readyTables.findUnique({ where: { id: "SbgyXiaoyun" } }))) - await prisma.readyTables.create({ data: { id: "SbgyXiaoyun" } }); + await registerSeeded(prisma, "SbgyXiaoyun"); console.log(`SbgyXiaoyun seeded. 🌱`); } diff --git a/prisma/external/seedScriptinAozoraFrequencies.ts b/prisma/external/seedScriptinAozoraFrequencies.ts index 00a8df1bd..48697d258 100644 --- a/prisma/external/seedScriptinAozoraFrequencies.ts +++ b/prisma/external/seedScriptinAozoraFrequencies.ts @@ -2,12 +2,14 @@ import { Prisma, PrismaClient } from "@prisma/client"; import { files, readJsonSync } from "~/lib/files.server"; +import { registerSeeded } from "../seedUtils"; + export async function seedScriptinAozoraFrequencies( prisma: PrismaClient, force = false, ) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "ScriptinAozoraFrequency" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "ScriptinAozoraFrequency" }, }); if (seeded && !force) console.log(`scriptinAozoraFrequency already seeded. 🌱`); @@ -32,15 +34,8 @@ export async function seedScriptinAozoraFrequencies( rank, }; } - if ( - !(await prisma.readyTables.findUnique({ - where: { id: "ScriptinAozoraFrequency" }, - })) - ) - await prisma.readyTables.create({ - data: { id: "ScriptinAozoraFrequency" }, - }); + await registerSeeded(prisma, "ScriptinAozoraFrequency"); console.log(`scriptinAozoraFrequency seeded. 🌱`); } } diff --git a/prisma/external/seedUnihan12.ts b/prisma/external/seedUnihan12.ts index bd0e1dcc6..25d39e38f 100644 --- a/prisma/external/seedUnihan12.ts +++ b/prisma/external/seedUnihan12.ts @@ -3,14 +3,16 @@ import { PrismaClient } from "@prisma/client"; import { files } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + export async function seedUnihan12(prisma: PrismaClient, force = false) { - const unihan14Seeded = await prisma.readyTables.findUnique({ - where: { id: "Unihan14" }, + const unihan14Seeded = await prisma.setup.findUnique({ + where: { step: "Unihan14" }, }); if (!unihan14Seeded) throw new Error("Unihan14 must be seeded before Unihan12."); - const seeded = await prisma.readyTables.findUnique({ - where: { id: "Unihan12" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "Unihan12" }, }); if (seeded && !force) console.log(`Unihan12 already seeded. 🌱`); else { @@ -64,9 +66,7 @@ export async function seedUnihan12(prisma: PrismaClient, force = false) { })), }); - if (!(await prisma.readyTables.findUnique({ where: { id: "Unihan12" } }))) - await prisma.readyTables.create({ data: { id: "Unihan12" } }); - + await registerSeeded(prisma, "Unihan12"); console.log(`Unihan12 seeded. 🌱`); } } diff --git a/prisma/external/seedUnihan14.ts b/prisma/external/seedUnihan14.ts index 478d7274b..8235fee5c 100644 --- a/prisma/external/seedUnihan14.ts +++ b/prisma/external/seedUnihan14.ts @@ -3,6 +3,8 @@ import { PrismaClient } from "@prisma/client"; import { files } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + export type Unihan14VariantFieldName = | "kSemanticVariant" | "kSimplifiedVariant" @@ -25,8 +27,8 @@ function fieldNameIsValid( } export async function seedUnihan14(prisma: PrismaClient, force = false) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "Unihan14" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "Unihan14" }, }); if (seeded && !force) console.log(`Unihan14 already seeded. 🌱`); else { @@ -83,8 +85,7 @@ export async function seedUnihan14(prisma: PrismaClient, force = false) { })), }); - if (!(await prisma.readyTables.findUnique({ where: { id: "Unihan14" } }))) - await prisma.readyTables.create({ data: { id: "Unihan14" } }); + await registerSeeded(prisma, "Unihan14"); console.log(`Unihan14 seeded. 🌱`); } diff --git a/prisma/external/seedUnihan15.ts b/prisma/external/seedUnihan15.ts index 8f87f1a6e..9af4bf63a 100644 --- a/prisma/external/seedUnihan15.ts +++ b/prisma/external/seedUnihan15.ts @@ -3,9 +3,11 @@ import { PrismaClient } from "@prisma/client"; import { files } from "~/lib/files.server"; import { forEachLine } from "~/lib/forEachLine.server"; +import { registerSeeded } from "../seedUtils"; + export async function seedUnihan15(prisma: PrismaClient, force = false) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "Unihan15" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "Unihan15" }, }); if (seeded && !force) console.log(`unihan15 already seeded. 🌱`); else { @@ -52,9 +54,8 @@ export async function seedUnihan15(prisma: PrismaClient, force = false) { data, }); console.log(`${x.count} created.`); - if (!(await prisma.readyTables.findUnique({ where: { id: "Unihan15" } }))) - await prisma.readyTables.create({ data: { id: "Unihan15" } }); + await registerSeeded(prisma, "Unihan15"); console.log(`unihan15 seeded. 🌱`); } } diff --git a/prisma/kanjisense/ComponentUseWithSignificance.ts b/prisma/kanjisense/ComponentUseWithSignificance.ts new file mode 100644 index 000000000..745cd59eb --- /dev/null +++ b/prisma/kanjisense/ComponentUseWithSignificance.ts @@ -0,0 +1,106 @@ +/** no tag means direct meaningful */ + +import { KanjisenseComponentUseTag } from "@prisma/client"; + +type FigureId = string; + +export class ComponentUseWithSignificance { + parent: FigureId; + tag?: KanjisenseComponentUseTag; + parentIsPriorityFigure: boolean; + + constructor( + parent: FigureId, + parentIsPriorityFigure: boolean, + tag?: KanjisenseComponentUseTag, + ) { + this.parent = parent; + this.tag = tag; + this.parentIsPriorityFigure = parentIsPriorityFigure; + } + + isDirect() { + return ( + !this.tag || + this.tag === KanjisenseComponentUseTag.directMeaningless || + this.tag === KanjisenseComponentUseTag.sound || + this.tag === KanjisenseComponentUseTag.directMeaninglessSound + ); + } + + isMeaningful() { + return ( + !this.tag || + this.tag === KanjisenseComponentUseTag.meaningfulIndirect || + this.tag === KanjisenseComponentUseTag.meaningfulIndirectSound || + this.tag === KanjisenseComponentUseTag.sound + ); + } + + isKanjijumpMeaningful() { + return ( + !this.tag || + this.tag === KanjisenseComponentUseTag.meaningfulIndirect || + this.tag === KanjisenseComponentUseTag.meaningfulIndirectSound || + (this.parentIsPriorityFigure && + this.tag === KanjisenseComponentUseTag.sound) + ); + } + + isSoundMarkUse() { + return ( + this.tag === KanjisenseComponentUseTag.directMeaninglessSound || + this.tag === KanjisenseComponentUseTag.meaningfulIndirectSound || + this.tag === KanjisenseComponentUseTag.sound + ); + } + + isKanjijumpSoundMarkUse() { + return ( + this.tag === KanjisenseComponentUseTag.meaningfulIndirectSound || + (this.parentIsPriorityFigure && + this.tag === KanjisenseComponentUseTag.sound) + ); + } + + toJSON() { + return ( + (this.tag || "") + this.parent + (!this.parentIsPriorityFigure ? "*" : "") + ); + } + + static fromJSON(json: ReturnType) { + const match = /^(?[dmens])?(?[^*]+)(?\*)?$/u.exec( + json, + ); + if (!match?.groups) { + throw new Error(`Problem decoding JSON ${JSON.stringify(json)}`); + } + const { parent, tag, nonPriority } = match.groups; + return new ComponentUseWithSignificance( + parent, + !nonPriority, + (tag as KanjisenseComponentUseTag) || undefined, + ); + } +} + +export function getTag( + direct: boolean, + meaningful: boolean, + soundMark: boolean, +): KanjisenseComponentUseTag | undefined { + if (direct && !meaningful) { + return soundMark + ? KanjisenseComponentUseTag.directMeaninglessSound + : KanjisenseComponentUseTag.directMeaningless; + } + + if (!direct && meaningful) { + return soundMark + ? KanjisenseComponentUseTag.meaningfulIndirectSound + : KanjisenseComponentUseTag.meaningfulIndirect; + } + + return soundMark ? KanjisenseComponentUseTag.sound : undefined; +} diff --git a/prisma/external/KanjiVariant.ts b/prisma/kanjisense/KanjiVariant.ts similarity index 97% rename from prisma/external/KanjiVariant.ts rename to prisma/kanjisense/KanjiVariant.ts index e1b4060ba..2e1d6d5ff 100644 --- a/prisma/external/KanjiVariant.ts +++ b/prisma/kanjisense/KanjiVariant.ts @@ -3,7 +3,7 @@ import { KanjiDbVariantType, PrismaClient } from "@prisma/client"; import { Unihan14VariantFieldName, unihan14VariantFieldNames, -} from "./seedUnihan14"; +} from "../external/seedUnihan14"; type KanjiVariant = | { diff --git a/prisma/kanjisense/componentMeanings.ts b/prisma/kanjisense/componentMeanings.ts index 55c3e9c98..c30e3346e 100644 --- a/prisma/kanjisense/componentMeanings.ts +++ b/prisma/kanjisense/componentMeanings.ts @@ -2,7 +2,7 @@ import { KanjisenseFigureRelation, PrismaClient } from "@prisma/client"; import { baseKanjiSet } from "~/lib/baseKanji"; -import { getFigureById } from "./getFigureById"; +import { getFigureById } from "../../app/models/getFigureById.server"; export const forcedMeaninglessFiguresSet = new Set([ "亏", @@ -16,29 +16,36 @@ export const forcedMeaninglessFiguresSet = new Set([ "𠫔", ]); -/** checks relations to see if the figure is a character - * or a component needing to be assigned a name in Kanjijump. +/** + * checks relations to see if the given component figure + * should be assigned a name in kanjisense */ -export async function shouldBeAssignedMeaning( +export async function shouldComponentBeAssignedMeaning( prisma: PrismaClient, - figureId: string, - directUses: Set, + { + id: figureId, + directUses, + variantGroupId, + }: { + id: string; + directUses: string[]; + variantGroupId: string | null; + }, ) { if (forcedMeaninglessFiguresSet.has(figureId)) return false; - const figure = await prisma.kanjisenseFigureRelation.findUnique({ - where: { id: figureId }, - }); - if (!figure) throw new Error(`figure ${figureId} not found`); - - if (await isPrimaryVariantInBaseKanji(figure)) return true; + const primaryVariantIsInBaseKanji = baseKanjiSet.has( + variantGroupId ?? figureId, + ); + if (primaryVariantIsInBaseKanji) return true; - if (!directUses.size) return false; + if (!directUses.length) return false; const usesInPriorityCandidates = await allVariantsUsesInPriorityCandidatesCountingVariantsOncePrimaryVariants( prisma, - figure, + variantGroupId, + directUses, ); const isAtomic = false; const minimumUsesInPriorityCandidates = isAtomic ? 1 : 2; @@ -48,28 +55,23 @@ export async function shouldBeAssignedMeaning( ); } -async function isPrimaryVariantInBaseKanji( - figure: KanjisenseFigureRelation, -): Promise { - return baseKanjiSet.has(figure?.variantGroupId ?? figure.id); -} - async function allVariantsUsesInPriorityCandidatesCountingVariantsOncePrimaryVariants( prisma: PrismaClient, - figure: KanjisenseFigureRelation, + variantGroupId: string | null, + directUses: string[], ) { - if (!figure.variantGroupId) + if (!variantGroupId) return new Set( - (await usesInPriorityCandidates(prisma, figure)).map( + (await usesInPriorityCandidates(prisma, directUses)).map( (u) => u.variantGroupId ?? u.id, ), ); const variantGroup = await prisma.kanjisenseVariantGroup.findUnique({ - where: { id: figure.variantGroupId }, + where: { id: variantGroupId }, }); if (!variantGroup) - throw new Error(`variant group ${figure.variantGroupId} not found`); + throw new Error(`variant group ${variantGroupId} not found`); const keys = new Set(); const uses: KanjisenseFigureRelation[] = []; @@ -77,7 +79,7 @@ async function allVariantsUsesInPriorityCandidatesCountingVariantsOncePrimaryVar const variantFigure = await getFigureById(prisma, variant); const variantFigureUses = await usesInPriorityCandidates( prisma, - variantFigure, + variantFigure.directUses, ); for (const vfu of variantFigureUses) { if (!keys.has(vfu.id)) { @@ -91,12 +93,12 @@ async function allVariantsUsesInPriorityCandidatesCountingVariantsOncePrimaryVar async function usesInPriorityCandidates( prisma: PrismaClient, - figure: KanjisenseFigureRelation, + directUses: string[], ) { return await prisma.kanjisenseFigureRelation.findMany({ where: { id: { - in: figure.directUses, + in: directUses, }, isPriorityCandidate: true, }, diff --git a/prisma/kanjisense/getBaseKanjiVariantGroups.ts b/prisma/kanjisense/getBaseKanjiVariantGroups.ts new file mode 100644 index 000000000..ec3691f52 --- /dev/null +++ b/prisma/kanjisense/getBaseKanjiVariantGroups.ts @@ -0,0 +1,13 @@ +import { PrismaClient } from "@prisma/client"; + +import { baseKanji } from "~/lib/baseKanji"; + +export async function getBaseKanjiVariantGroups(prisma: PrismaClient) { + return Object.fromEntries( + ( + await prisma.kanjisenseVariantGroup.findMany({ + where: { id: { in: [...baseKanji] } }, + }) + ).map((g) => [g.id, g]), + ); +} diff --git a/prisma/kanjisense/getFigureMeaningsText.ts b/prisma/kanjisense/getFigureMeaningsText.ts new file mode 100644 index 000000000..fad06ffad --- /dev/null +++ b/prisma/kanjisense/getFigureMeaningsText.ts @@ -0,0 +1,25 @@ +import { PrismaClient } from "@prisma/client"; + +const RADICAL_ENTRY_REGEX = /radical \(no\.|radical number/; +export async function getFigureMeaningsText( + prisma: PrismaClient, + figureId: string, +) { + const unihanDefinition = prisma.unihan15.findUnique({ + where: { id: figureId }, + select: { kDefinition: true }, + }); + const kanjidicEnglish = prisma.kanjidicEntry.findUnique({ + where: { id: figureId }, + select: { definitions: true }, + }); + + return { + unihanDefinitionText: + (await unihanDefinition)?.kDefinition?.join("; ") || null, + kanjidicEnglish: + (await kanjidicEnglish)?.definitions?.filter( + (e) => !RADICAL_ENTRY_REGEX.test(e), + ) || [], + }; +} diff --git a/prisma/kanjisense/getMeaningfulUses.ts b/prisma/kanjisense/getMeaningfulUses.ts index 1a0deb938..758aeb27b 100644 --- a/prisma/kanjisense/getMeaningfulUses.ts +++ b/prisma/kanjisense/getMeaningfulUses.ts @@ -1,12 +1,12 @@ import { KanjisenseFigureRelation } from "@prisma/client"; -import { prisma } from "~/db.server"; import { ComponentUseWithSignificance, getTag, -} from "~/lib/kanjisenseFigure/ComponentUseWithSignificance"; +} from "prisma/kanjisense/ComponentUseWithSignificance"; +import { prisma } from "~/db.server"; -import { shouldBeAssignedMeaning } from "./componentMeanings"; +import { shouldComponentBeAssignedMeaning } from "./componentMeanings"; import { isFigurePriority } from "./isFigurePriority"; type FigureId = string; @@ -49,11 +49,11 @@ export async function getMeaningfulUses({ ); if ( - await shouldBeAssignedMeaning( - prisma, - directUse.id, - new Set(directUse.directUses), - ) + await shouldComponentBeAssignedMeaning(prisma, { + id: directUse.id, + directUses: directUse.directUses, + variantGroupId: directUse.variantGroupId, + }) ) meaningfulUses.push( new ComponentUseWithSignificance( diff --git a/prisma/external/inBatchesOf.ts b/prisma/kanjisense/inBatchesOf.ts similarity index 100% rename from prisma/external/inBatchesOf.ts rename to prisma/kanjisense/inBatchesOf.ts diff --git a/prisma/kanjisense/isFigurePriority.ts b/prisma/kanjisense/isFigurePriority.ts index 091c2cea0..a17b0db36 100644 --- a/prisma/kanjisense/isFigurePriority.ts +++ b/prisma/kanjisense/isFigurePriority.ts @@ -2,7 +2,7 @@ import { KanjisenseFigureRelation, PrismaClient } from "@prisma/client"; import { baseKanjiSet } from "~/lib/baseKanji"; -import { shouldBeAssignedMeaning } from "./componentMeanings"; +import { shouldComponentBeAssignedMeaning } from "./componentMeanings"; import { isStandalone } from "./isStandalone"; export async function isFigurePriority( @@ -27,10 +27,10 @@ async function isPriorityComponent( prisma: PrismaClient, figure: KanjisenseFigureRelation, ): Promise { - const hasMeaning = await shouldBeAssignedMeaning( - prisma, - figure.id, - new Set(figure.directUses), - ); + const hasMeaning = await shouldComponentBeAssignedMeaning(prisma, { + id: figure.id, + directUses: figure.directUses, + variantGroupId: figure.variantGroupId, + }); return hasMeaning && figure.isPriorityCandidate; } diff --git a/prisma/external/seedKanjisenseFigureRelation.ts b/prisma/kanjisense/seedKanjisenseFigureRelation.ts similarity index 96% rename from prisma/external/seedKanjisenseFigureRelation.ts rename to prisma/kanjisense/seedKanjisenseFigureRelation.ts index 6a06fef1c..7745f7591 100644 --- a/prisma/external/seedKanjisenseFigureRelation.ts +++ b/prisma/kanjisense/seedKanjisenseFigureRelation.ts @@ -12,14 +12,17 @@ import { PatchedIds } from "~/lib/PatchedIds.server"; import { patchIds } from "~/lib/patchKanjiDbIds"; import * as ParseIds from "~/lib/vendor/tomcumming/parseIds"; +import { registerSeeded } from "../seedUtils"; + import { inBatchesOf } from "./inBatchesOf"; + export async function seedKanjisenseFigureRelation( prisma: PrismaClient, force = false, ) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjisenseFigureRelation" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjisenseFigureRelation" }, }); if (seeded && !force) console.log(`KanjisenseFigureRelation already seeded. 🌱`); @@ -134,14 +137,7 @@ export async function seedKanjisenseFigureRelation( }); }); - if ( - !(await prisma.readyTables.findUnique({ - where: { id: "KanjisenseFigureRelation" }, - })) - ) - await prisma.readyTables.create({ - data: { id: "KanjisenseFigureRelation" }, - }); + await registerSeeded(prisma, "KanjisenseFigureRelation"); } console.log(`KanjisenseFigureRelation seeded. 🌱`); diff --git a/prisma/kanjisense/seedKanjisenseFigures.ts b/prisma/kanjisense/seedKanjisenseFigures.ts new file mode 100644 index 000000000..17992611e --- /dev/null +++ b/prisma/kanjisense/seedKanjisenseFigures.ts @@ -0,0 +1,293 @@ +import { readFileSync } from "node:fs"; + +import { + KanjisenseFigure, + KanjisenseFigureRelation, + PrismaClient, +} from "@prisma/client"; +import yaml from "yaml"; + +import { baseKanjiSet } from "~/lib/baseKanji"; +import { files } from "~/lib/files.server"; + +import { registerSeeded } from "../seedUtils"; + +import { shouldComponentBeAssignedMeaning } from "./componentMeanings"; +import { getBaseKanjiVariantGroups } from "./getBaseKanjiVariantGroups"; +import { getFigureMeaningsText } from "./getFigureMeaningsText"; +// import { getStandaloneCharacters } from "./getStandaloneCharacters"; +import { getListsMembership } from "./seedKanjisenseFigureRelation"; + +export async function seedKanjisenseFigures( + prisma: PrismaClient, + force = false, +) { + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjisenseFigure" }, + }); + if (seeded && !force) console.log(`figures already seeded. 🌱`); + else { + console.log("Seeding figures..."); + + const componentsDictionary = yaml.parse( + readFileSync(files.componentsDictionaryYml, "utf-8"), + ) as Record; + // initialize figures with ID (and maybe keyword?) + // simultaneously seed meanings + + const baseKanjiVariantsGroups = await getBaseKanjiVariantGroups(prisma); + + const priorityCharacters = await prisma.kanjisenseFigureRelation.findMany({ + where: { + OR: [ + { + id: { in: [...baseKanjiSet] }, + }, + { + id: { + in: Object.values(baseKanjiVariantsGroups).flatMap( + (g) => g.variants, + ), + }, + directUses: { isEmpty: true }, + }, + ], + }, + }); + const nonPriorityCharacters = + await prisma.kanjisenseFigureRelation.findMany({ + where: { + id: { notIn: priorityCharacters.map((c) => c.id) }, + directUses: { isEmpty: true }, + }, + }); + const allStandaloneCharacters = priorityCharacters.concat( + ...nonPriorityCharacters, + ); + const componentFiguresPotentiallyNeedingMeaningAssignment = + await prisma.kanjisenseFigureRelation.findMany({ + where: { + directUses: { isEmpty: false }, + id: { not: { in: allStandaloneCharacters.map((c) => c.id) } }, + variantGroupId: { not: null }, + }, + }); + + const meaningfulComponents: KanjisenseFigureRelation[] = []; + const meaninglessComponents: KanjisenseFigureRelation[] = []; + for (const figure of componentFiguresPotentiallyNeedingMeaningAssignment) { + const shouldBeAssignedMeaning = await shouldComponentBeAssignedMeaning( + prisma, + figure, + ); + if (shouldBeAssignedMeaning) meaningfulComponents.push(figure); + else meaninglessComponents.push(figure); + } + + const priorityFiguresMeanings = new Map< + string, + Awaited> + >(); + + for (const figure of [ + ...allStandaloneCharacters, + ...meaningfulComponents, + ]) { + const primaryVariantId = + baseKanjiVariantsGroups[figure.id]?.id ?? figure.id; + priorityFiguresMeanings.set( + figure.id, + await getFigureMeaningsText(prisma, primaryVariantId), + ); + } + + const allAozoraCharacterFrequencies = Object.fromEntries( + ( + await prisma.scriptinAozoraFrequency.findMany({ + where: { + character: { in: allStandaloneCharacters.map((c) => c.id) }, + }, + }) + ).map((c) => [c.character, c]), + ); + + const dbInput = new Map(); + + console.log("preparing priority figures..."); + for (const figure of [...priorityCharacters, ...meaningfulComponents]) { + const id = figure.id; + const meaning = priorityFiguresMeanings.get(figure.variantGroupId ?? id); + if (!meaning) throw new Error(`meaning not found for ${id}`); + const createFigureInput = getCreateFigureInput( + figure, + meaning, + componentsDictionary, + allAozoraCharacterFrequencies[id]?.appearances, + true, + ); + dbInput.set(id, createFigureInput); + } + + console.log("preparing non-priority figures..."); + for (const figure of [...nonPriorityCharacters, ...meaninglessComponents]) { + const id = figure.id; + const meaning = priorityFiguresMeanings.get(figure.variantGroupId ?? id); + if (!meaning) throw new Error(`meaning not found for ${id}`); + + const appearances = 0; + + const createFigureInput = getCreateFigureInput( + figure, + meaning, + componentsDictionary, + appearances, + false, + ); + dbInput.set(id, createFigureInput); + } + + console.log("creating entries..."); + + await prisma.kanjisenseFigureMeaning.deleteMany({}); + await prisma.kanjisenseFigure.deleteMany({}); + + console.log("seeding figures"); + await prisma.kanjisenseFigure.createMany({ + data: [...dbInput.values()].map((r) => ({ + id: r.id, + keyword: r.keyword, + mnemonicKeyword: r.mnemonicKeyword, + isPriority: r.isPriority, + listsAsComponent: { set: r.listsAsComponent }, + listsAsCharacter: { set: r.listsAsCharacter }, + aozoraAppearances: r.aozoraAppearances, + variantGroupId: r.variantGroupId, + })), + }); + + console.log("seeding meanings"); + + await prisma.kanjisenseFigureMeaning.createMany({ + data: [...dbInput.values()].map((r) => ({ + id: r.id, + unihanDefinition: r.meaning?.unihanDefinitionText, + kanjidicEnglish: r.meaning?.kanjidicEnglish, + })), + }); + + console.log("connecting top-level components"); + + console.log("registering active sound marks"); + + await registerSeeded(prisma, "KanjisenseFigure"); + console.log(`figures seeded. 🌱`); + } +} + +interface CreateKanjisenseFigureInput { + id: string; + keyword: string; + mnemonicKeyword: string | null; + isPriority: boolean; + listsAsComponent: string[]; + listsAsCharacter: string[]; + aozoraAppearances: number; + variantGroupId: string | null; + meaning?: Awaited>; +} + +class ComponentUse { + parent: KanjisenseFigure; + component: KanjisenseFigure; + + constructor(parent: KanjisenseFigure, component: KanjisenseFigure) { + this.parent = parent; + this.component = component; + } + + toJSON() { + return [this.parent.id, this.component.id]; + } +} + +const componentsTreeCache = new Map(); + +function getCreateFigureInput( + figure: KanjisenseFigureRelation, + meaning: Awaited>, + componentsDictionary: Record, + aozoraAppearances: number, + isPriority: boolean, +) { + const figureId = figure.id; + + const primaryVariantId = figure.variantGroupId ?? figureId; + const mnemonicKeywords = componentsDictionary[primaryVariantId]; + const historicalKeyword = + mnemonicKeywords?.historical && mnemonicKeywords.historical !== "(various)" + ? mnemonicKeywords.historical + : null; + let mnemonicSource = ""; + if (mnemonicKeywords?.reference) + mnemonicSource = ` {{cf. ${mnemonicKeywords.reference}}}`; + else if (mnemonicKeywords?.standin) + mnemonicSource = ` {{via ${mnemonicKeywords.standin}}}`; + + const keyword = + (historicalKeyword || + meaning.kanjidicEnglish?.[0] || + meaning.unihanDefinitionText?.split(";")?.[0]) ?? + null; + if (!keyword) console.error(`no keyword for ${figureId}`); + + return { + id: figureId, + keyword: keyword ?? "[MISSING]", + mnemonicKeyword: mnemonicKeywords?.mnemonic + ? [mnemonicKeywords.mnemonic, mnemonicSource].join("") + : null, + isPriority, + listsAsComponent: figure.listsAsComponent, // refine? + listsAsCharacter: [...getListsMembership(figureId)], + aozoraAppearances: aozoraAppearances ?? 0, + variantGroupId: figure.variantGroupId, + }; +} + +export async function getComponentsTree( + figure: KanjisenseFigure & { relation: KanjisenseFigureRelation }, + getFigure: ( + id: string, + ) => Promise, +) { + if (componentsTreeCache.has(figure.id)) + return componentsTreeCache.get(figure.id)!; + + const componentsTree: ComponentUse[] = []; + for (const componentKey of figure.relation.selectedIdsComponents) { + if (componentKey === figure.id) continue; // prevent infinite loop for atomic figures + const component = await getFigure(componentKey); + + componentsTree.push( + new ComponentUse(figure, component), + ...(await getComponentsTree(component, getFigure)), + ); + } + + componentsTreeCache.set(figure.id, componentsTree); + + return componentsTree; +} + +interface ComponentMeaning { + /** historical meaning */ + historical?: string; + /** mnemonic keyword, if historical meaning is absent or different */ + mnemonic?: string; + /** for this component's mnemonic keyword, it borrows the meaning of a common kanji containing it. */ + standin?: string; + /** this component derives its mnemonic keyword from a common kanji using it. */ + reference?: string; + /** for grouping components by meaning */ + tag?: string | null; +} diff --git a/prisma/kanjisense/seedKanjisenseVariantGroups.ts b/prisma/kanjisense/seedKanjisenseVariantGroups.ts index 5ea62f835..79bec57e4 100644 --- a/prisma/kanjisense/seedKanjisenseVariantGroups.ts +++ b/prisma/kanjisense/seedKanjisenseVariantGroups.ts @@ -1,5 +1,6 @@ import { KanjiDbVariantType, PrismaClient } from "@prisma/client"; +import { registerSeeded } from "prisma/seedUtils"; import { baseKanji, lists } from "~/lib/baseKanji"; import { kanjijumpSpecificVariants } from "~/lib/dic/kanjijumpSpecificVariants"; @@ -21,8 +22,8 @@ export async function seedKanjisenseVariantGroups( prisma: PrismaClient, force = false, ) { - const seeded = await prisma.readyTables.findUnique({ - where: { id: "KanjisenseVariantGroup" }, + const seeded = await prisma.setup.findUnique({ + where: { step: "KanjisenseVariantGroup" }, }); if (seeded && !force) { console.log(`KanjisenseVariantGroup already seeded. 🌱`); @@ -121,14 +122,8 @@ export async function seedKanjisenseVariantGroups( variants: group, })), }); - if ( - !(await prisma.readyTables.findUnique({ - where: { id: "KanjisenseVariantGroup" }, - })) - ) - await prisma.readyTables.create({ - data: { id: "KanjisenseVariantGroup" }, - }); + + await registerSeeded(prisma, "KanjisenseVariantGroup"); // eslint-disable-next-line no-inner-declarations function byPriorityDescending(a: string, b: string) { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fff0276c1..a2be12023 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -7,8 +7,8 @@ datasource db { url = env("DATABASE_URL") } -model ReadyTables { - id String @id +model Setup { + step String @id } model KanjidicEntry { @@ -94,8 +94,9 @@ model ScriptinAozoraFrequency { } model KanjisenseVariantGroup { - id String @id - variants String[] + id String @id + variants String[] + KanjisenseFigure KanjisenseFigure[] } model KanjisenseFigureRelation { @@ -107,6 +108,8 @@ model KanjisenseFigureRelation { idsText String selectedIdsComponents String[] + + figure KanjisenseFigure? } model KanjisenseSoundMark { @@ -119,27 +122,57 @@ model KanjisenseSoundMark { model KanjisenseFigure { id String @id keyword String - componentKeyword String? + mnemonicKeyword String? isPriority Boolean listsAsComponent String[] listsAsCharacter String[] aozoraAppearances Int - variantGroupId String? - isInBaseKanjiVariantGroup Boolean - activeSoundMarkValue String? + activeSoundMarkValue String? + + variantGroupId String? + variantGroup KanjisenseVariantGroup? @relation(fields: [variantGroupId], references: [id]) + + componentsTree Json? - componentsTree Json - meaningfulUses String[] + meaningfulUses KanjisenseComponentUse[] @relation("meaningfulUses") + topLevelComponents KanjisenseComponentUse[] @relation("topLevelComponents") ShuowenImage ShuowenImage? @relation(fields: [shuowenImageId], references: [id]) shuowenImageId String? KvgJson KvgJson? @relation(fields: [kvgJsonId], references: [id]) kvgJsonId String? + + relation KanjisenseFigureRelation @relation(fields: [id], references: [id]) + meaning KanjisenseFigureMeaning? +} + +model KanjisenseComponentUse { + component KanjisenseFigure @relation(fields: [componentId], references: [id], name: "meaningfulUses") + componentId String + parent KanjisenseFigure @relation(fields: [parentId], references: [id], name: "topLevelComponents") + parentId String + + tag KanjisenseComponentUseTag + + id String @id } -model KanjisenseFigureReadings { +enum KanjisenseComponentUseTag { + // used within this parent character, but not common enough to have a meaning in Kanjijump + directMeaningless + // should not happen + directMeaninglessSound + // used within a "directMeaningless" component of this parent character + meaningfulIndirect + // used within a "directMeaningless component" of this parent character, serving as sound mark + meaningfulIndirectSound + // used directly as a sound mark within this parent character + sound +} + +model KanjisenseFigureReading { id String @id guangyunYunjing String? @@ -155,12 +188,14 @@ model KanjisenseFigureReadings { kJapaneseOn String? } -model KanjisenseFigureMeanings { - id String @id +model KanjisenseFigureMeaning { + id String @id + figure KanjisenseFigure @relation(fields: [id], references: [id]) + + kanjidicEnglish String[] + unihanDefinition String? - kanjidicEnglish String? kanjisenseHistorical String? - unihanDefinition String? kanjisenseMnemonic String? kanjisenseStandin String? kanjisenseReference String? diff --git a/prisma/seed.ts b/prisma/seed.ts index cf2c79a23..0488a7aae 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -5,13 +5,14 @@ import { seedKanjiDbComposition } from "./external/seedKanjiDbComposition"; import { seedKanjiDbSbgyNotes } from "./external/seedKanjiDbSbgyNotes"; import { seedKanjiDbVariants } from "./external/seedKanjiDbVariants"; import { seedKanjidic } from "./external/seedKanjidic"; -import { seedKanjisenseFigureRelation } from "./external/seedKanjisenseFigureRelation"; -import { seedKanjisenseSoundMarks } from "./external/seedKanjisenseSoundMarks"; import { seedSbgy } from "./external/seedSbgy"; import { seedScriptinAozoraFrequencies } from "./external/seedScriptinAozoraFrequencies"; import { seedUnihan12 } from "./external/seedUnihan12"; import { seedUnihan14 } from "./external/seedUnihan14"; import { seedUnihan15 } from "./external/seedUnihan15"; +import { seedKanjisenseFigureRelation } from "./kanjisense/seedKanjisenseFigureRelation"; +import { seedKanjisenseFigures } from "./kanjisense/seedKanjisenseFigures"; +import { seedKanjisenseSoundMarks } from "./kanjisense/seedKanjisenseSoundMarks"; import { seedKanjisenseVariantGroups } from "./kanjisense/seedKanjisenseVariantGroups"; const prisma = new PrismaClient(); @@ -20,27 +21,29 @@ async function seed() { const startTime = Date.now(); await seedKanjidic(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedUnihan15(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedUnihan14(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedUnihan12(prisma); await seedKanjiDbComposition(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedKanjiDbVariants(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedKanjiDbSbgyNotes(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedSbgy(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedScriptinAozoraFrequencies(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedKanjisenseVariantGroups(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedKanjisenseFigureRelation(prisma); - console.log(`✅ ${Date.now() - startTime}ms.`); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); await seedKanjisenseSoundMarks(prisma); + console.log(`✅ ${(Date.now() - startTime) / 1000}s.`); + await seedKanjisenseFigures(prisma); const email = "rachel@remix.run"; diff --git a/prisma/seedUtils.ts b/prisma/seedUtils.ts new file mode 100644 index 000000000..5335fef2d --- /dev/null +++ b/prisma/seedUtils.ts @@ -0,0 +1,27 @@ +import { PrismaClient } from "@prisma/client"; + +export type SetupStep = + | "KanjidicEntry" + | "KanjiDbComposition" + | "KanjiDbSbgyNote" + | "KanjiDbVariant" + | "KanjisenseFigureMeaning" + | "KanjisenseFigureMeaning" + | "KanjisenseFigureRelation" + | "KanjisenseFigure" + | "KanjisenseSoundMark" + | "SbgyXiaoyun" + | "SbgyXiaoyun" + | "ScriptinAozoraFrequency" + | "Unihan12" + | "Unihan12" + | "Unihan14" + | "Unihan14" + | "Unihan15" + | "Unihan15" + | "KanjisenseVariantGroup"; + +export async function registerSeeded(prisma: PrismaClient, step: SetupStep) { + if (!(await prisma.setup.findUnique({ where: { step } }))) + await prisma.setup.create({ data: { step } }); +}