henkan 2.4.11 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/index.cjs.js +467 -50
  2. package/dist/index.cjs.js.map +2 -2
  3. package/dist/index.mjs +464 -50
  4. package/dist/index.mjs.map +2 -2
  5. package/dist/types/types.d.ts +106 -15
  6. package/dist/types/types.d.ts.map +1 -1
  7. package/dist/types/utils.d.ts +28 -6
  8. package/dist/types/utils.d.ts.map +1 -1
  9. package/docs/api/README.md +8 -2
  10. package/docs/api/functions/capitalizeString.md +1 -1
  11. package/docs/api/functions/convertJMdict.md +1 -1
  12. package/docs/api/functions/convertJMnedict.md +33 -0
  13. package/docs/api/functions/convertJawiktionaryAsync.md +1 -1
  14. package/docs/api/functions/convertJawiktionarySync.md +1 -1
  15. package/docs/api/functions/convertKanjiDic.md +1 -1
  16. package/docs/api/functions/convertKradFile.md +1 -1
  17. package/docs/api/functions/convertRadkFile.md +1 -1
  18. package/docs/api/functions/convertTanakaCorpus.md +1 -1
  19. package/docs/api/functions/convertTanakaCorpusWithFurigana.md +1 -1
  20. package/docs/api/functions/createEntryMaps.md +9 -3
  21. package/docs/api/functions/generateAnkiNote.md +2 -2
  22. package/docs/api/functions/generateAnkiNotesFile.md +1 -1
  23. package/docs/api/functions/generateFurigana.md +1 -1
  24. package/docs/api/functions/getKanji.md +1 -1
  25. package/docs/api/functions/getKanjiExtended.md +1 -1
  26. package/docs/api/functions/getName.md +57 -0
  27. package/docs/api/functions/getValidForms.md +1 -1
  28. package/docs/api/functions/getWord.md +3 -3
  29. package/docs/api/functions/getWordDefinitions.md +1 -1
  30. package/docs/api/functions/getWordDefinitionsWithFurigana.md +1 -1
  31. package/docs/api/functions/hiraganaToKatakana.md +1 -1
  32. package/docs/api/functions/isObjectArray.md +1 -1
  33. package/docs/api/functions/isStringArray.md +1 -1
  34. package/docs/api/functions/isValidArrayWithFirstElement.md +1 -1
  35. package/docs/api/functions/katakanaToHiragana.md +1 -1
  36. package/docs/api/functions/shuffleArray.md +1 -1
  37. package/docs/api/interfaces/DefaultNoteInfo.md +10 -10
  38. package/docs/api/interfaces/Definition.md +4 -4
  39. package/docs/api/interfaces/DictKanji.md +5 -5
  40. package/docs/api/interfaces/DictKanjiForm.md +2 -2
  41. package/docs/api/interfaces/DictKanjiMisc.md +5 -5
  42. package/docs/api/interfaces/DictKanjiReading.md +3 -3
  43. package/docs/api/interfaces/DictKanjiReadingMeaning.md +3 -3
  44. package/docs/api/interfaces/DictKanjiReadingMeaningGroup.md +3 -3
  45. package/docs/api/interfaces/DictKanjiWithRadicals.md +3 -3
  46. package/docs/api/interfaces/DictName.md +75 -0
  47. package/docs/api/interfaces/DictRadical.md +4 -4
  48. package/docs/api/interfaces/DictReading.md +2 -2
  49. package/docs/api/interfaces/EntryMaps.md +33 -9
  50. package/docs/api/interfaces/ExamplePart.md +7 -7
  51. package/docs/api/interfaces/GlossSpecificNumber.md +3 -3
  52. package/docs/api/interfaces/Grammar.md +15 -15
  53. package/docs/api/interfaces/GrammarMeaning.md +3 -3
  54. package/docs/api/interfaces/JaWiktionaryEntry.md +5 -5
  55. package/docs/api/interfaces/Kana.md +11 -11
  56. package/docs/api/interfaces/Kanji.md +23 -23
  57. package/docs/api/interfaces/KanjiComponent.md +3 -3
  58. package/docs/api/interfaces/KanjiForm.md +5 -5
  59. package/docs/api/interfaces/Name.md +163 -0
  60. package/docs/api/interfaces/NeDictMeaning.md +33 -0
  61. package/docs/api/interfaces/NoteAndTag.md +3 -3
  62. package/docs/api/interfaces/NoteHeaderKeys.md +7 -7
  63. package/docs/api/interfaces/Phrase.md +5 -5
  64. package/docs/api/interfaces/Radical.md +16 -16
  65. package/docs/api/interfaces/Reading.md +6 -6
  66. package/docs/api/interfaces/ResultEntry.md +8 -7
  67. package/docs/api/interfaces/TanakaExample.md +7 -7
  68. package/docs/api/interfaces/Translation.md +5 -5
  69. package/docs/api/interfaces/UsefulRegExps.md +8 -8
  70. package/docs/api/interfaces/Word.md +15 -15
  71. package/docs/api/interfaces/WordDefinitionPair.md +4 -4
  72. package/docs/api/type-aliases/Dict.md +1 -1
  73. package/docs/api/type-aliases/{DictName.md → DictNames.md} +3 -3
  74. package/docs/api/type-aliases/EntryExamplesMap.md +13 -0
  75. package/docs/api/type-aliases/EntryType.md +2 -2
  76. package/docs/api/type-aliases/KanjiEntryMap.md +1 -1
  77. package/docs/api/type-aliases/KanjiSVGMap.md +1 -1
  78. package/docs/api/type-aliases/KanjiWordsMap.md +1 -1
  79. package/docs/api/type-aliases/NameIDEntryMap.md +13 -0
  80. package/docs/api/type-aliases/Result.md +2 -2
  81. package/docs/api/type-aliases/WordDefinitionsMap.md +1 -1
  82. package/docs/api/type-aliases/WordIDEntryMap.md +1 -1
  83. package/package.json +8 -7
  84. package/src/types.ts +115 -15
  85. package/src/utils.ts +815 -108
  86. package/docs/api/type-aliases/WordExamplesMap.md +0 -13
package/dist/index.cjs.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  capitalizeString: () => capitalizeString,
34
34
  convertJMdict: () => convertJMdict,
35
+ convertJMnedict: () => convertJMnedict,
35
36
  convertJawiktionaryAsync: () => convertJawiktionaryAsync,
36
37
  convertJawiktionarySync: () => convertJawiktionarySync,
37
38
  convertKanjiDic: () => convertKanjiDic,
@@ -45,6 +46,7 @@ __export(index_exports, {
45
46
  generateFurigana: () => generateFurigana,
46
47
  getKanji: () => getKanji,
47
48
  getKanjiExtended: () => getKanjiExtended,
49
+ getName: () => getName,
48
50
  getValidForms: () => getValidForms,
49
51
  getWord: () => getWord,
50
52
  getWordDefinitions: () => getWordDefinitions,
@@ -53,6 +55,7 @@ __export(index_exports, {
53
55
  isGrammar: () => isGrammar,
54
56
  isKana: () => isKana,
55
57
  isKanji: () => isKanji,
58
+ isName: () => isName,
56
59
  isObjectArray: () => isObjectArray,
57
60
  isRadical: () => isRadical,
58
61
  isStringArray: () => isStringArray,
@@ -1539,6 +1542,90 @@ function convertJMdict(xmlString, examples) {
1539
1542
  });
1540
1543
  return dict;
1541
1544
  }
1545
+ function convertJMnedict(xmlString, examples) {
1546
+ const dictParsed = import_libxmljs2.default.parseXml(xmlString, {
1547
+ dtdvalid: true,
1548
+ nonet: false,
1549
+ noent: true,
1550
+ recover: false
1551
+ });
1552
+ const dict = [];
1553
+ import_xml2js.default.parseString(dictParsed, (_err, result) => {
1554
+ const tanakaParts = examples !== void 0 && examples.length > 0 ? new Set(
1555
+ examples.flatMap(
1556
+ (example) => example.parts.flatMap((part) => [
1557
+ part.baseForm,
1558
+ ...part.reading !== void 0 ? [part.reading] : [],
1559
+ ...part.inflectedForm !== void 0 ? [part.inflectedForm] : [],
1560
+ ...part.referenceID !== void 0 ? [part.referenceID] : []
1561
+ ])
1562
+ )
1563
+ ) : void 0;
1564
+ for (const entry of result.JMnedict.entry) {
1565
+ const entryObj = {
1566
+ id: entry.ent_seq[0],
1567
+ nameReadings: [],
1568
+ meanings: []
1569
+ };
1570
+ const kanjiForms = entry.k_ele;
1571
+ const readings = entry.r_ele;
1572
+ const translations = entry.trans;
1573
+ if (isObjectArray(kanjiForms)) {
1574
+ entryObj.kanjiForms = [];
1575
+ for (const kanjiForm of kanjiForms)
1576
+ entryObj.kanjiForms.push({ form: kanjiForm.keb[0] });
1577
+ }
1578
+ for (const reading of readings) {
1579
+ const readingObj = {
1580
+ reading: reading.reb[0]
1581
+ };
1582
+ if (isStringArray(reading.re_restr))
1583
+ readingObj.kanjiFormRestrictions = reading.re_restr;
1584
+ if (isStringArray(reading.re_pri)) {
1585
+ readingObj.commonness = reading.re_pri;
1586
+ entryObj.isCommon = true;
1587
+ }
1588
+ entryObj.nameReadings.push(readingObj);
1589
+ }
1590
+ for (const trans of translations)
1591
+ entryObj.meanings.push({
1592
+ translations: trans.trans_det,
1593
+ ...isStringArray(trans.name_type) ? { nameTypes: trans.name_type } : {}
1594
+ });
1595
+ if (examples !== void 0) {
1596
+ let existsExample = false;
1597
+ const rkf = getValidForms(
1598
+ entryObj.nameReadings,
1599
+ entryObj.kanjiForms,
1600
+ entryObj.isCommon
1601
+ );
1602
+ const validReadings = new Set(
1603
+ rkf.readings.map((r) => r.reading)
1604
+ );
1605
+ const validKanjiForms = rkf.kanjiForms !== void 0 ? new Set(
1606
+ rkf.kanjiForms.map((kf) => kf.form)
1607
+ ) : void 0;
1608
+ if (validKanjiForms !== void 0 && validKanjiForms.size > 0 && tanakaParts !== void 0) {
1609
+ for (const kf of validKanjiForms)
1610
+ if (tanakaParts.has(kf)) {
1611
+ existsExample = true;
1612
+ break;
1613
+ }
1614
+ }
1615
+ if (entryObj.kanjiForms === void 0 && validReadings.size > 0 && tanakaParts !== void 0) {
1616
+ for (const r of validReadings)
1617
+ if (tanakaParts.has(r)) {
1618
+ existsExample = true;
1619
+ break;
1620
+ }
1621
+ }
1622
+ if (existsExample) entryObj.hasPhrases = true;
1623
+ }
1624
+ dict.push(entryObj);
1625
+ }
1626
+ });
1627
+ return dict;
1628
+ }
1542
1629
  function convertKanjiDic(xmlString) {
1543
1630
  const dictParsed = import_libxmljs2.default.parseXml(xmlString, {
1544
1631
  dtdvalid: true,
@@ -1741,16 +1828,15 @@ function convertKradFile(kradBuffer, kanjiDic, katakanaList) {
1741
1828
  }
1742
1829
  return kanjiWithRadicals;
1743
1830
  }
1744
- function createEntryMaps(jmDict, kanjiDic, tanakaExamples, wordDefinitionPairs, svgList) {
1831
+ function createEntryMaps(jmDict, jmNedict, kanjiDic, tanakaExamples, wordDefinitionPairs, svgList) {
1745
1832
  const kanjiEntryMap = /* @__PURE__ */ new Map();
1746
1833
  const wordIDEntryMap = /* @__PURE__ */ new Map();
1834
+ const nameIDEntryMap = /* @__PURE__ */ new Map();
1747
1835
  const kanjiWordsMap = /* @__PURE__ */ new Map();
1748
1836
  const wordExamplesMap = /* @__PURE__ */ new Map();
1837
+ const nameExamplesMap = /* @__PURE__ */ new Map();
1749
1838
  const wordDefinitionsMap = /* @__PURE__ */ new Map();
1750
1839
  const kanjiSVGMap = /* @__PURE__ */ new Map();
1751
- const wordPartsMap = /* @__PURE__ */ new Map();
1752
- const partExamplesMap = /* @__PURE__ */ new Map();
1753
- const entryParts = /* @__PURE__ */ new Set();
1754
1840
  if (kanjiDic !== void 0)
1755
1841
  for (const kanji of kanjiDic) kanjiEntryMap.set(kanji.kanji, kanji);
1756
1842
  if (wordDefinitionPairs !== void 0)
@@ -1766,6 +1852,9 @@ function createEntryMaps(jmDict, kanjiDic, tanakaExamples, wordDefinitionPairs,
1766
1852
  if (svg !== void 0) kanjiSVGMap.set(kanji.kanji, svg);
1767
1853
  }
1768
1854
  if (jmDict !== void 0) {
1855
+ const wordPartsMap = /* @__PURE__ */ new Map();
1856
+ const partExamplesMap = /* @__PURE__ */ new Map();
1857
+ const entryParts = /* @__PURE__ */ new Set();
1769
1858
  for (const word of jmDict) {
1770
1859
  wordIDEntryMap.set(word.id, word);
1771
1860
  if (word.kanjiForms !== void 0)
@@ -1844,11 +1933,82 @@ function createEntryMaps(jmDict, kanjiDic, tanakaExamples, wordDefinitionPairs,
1844
1933
  }
1845
1934
  }
1846
1935
  }
1936
+ if (jmNedict !== void 0) {
1937
+ const namePartsMap = /* @__PURE__ */ new Map();
1938
+ const partExamplesMap = /* @__PURE__ */ new Map();
1939
+ const entryParts = /* @__PURE__ */ new Set();
1940
+ for (const name of jmNedict) {
1941
+ nameIDEntryMap.set(name.id, name);
1942
+ if (tanakaExamples !== void 0) {
1943
+ const rkf = getValidForms(
1944
+ name.nameReadings,
1945
+ name.kanjiForms,
1946
+ name.isCommon
1947
+ );
1948
+ const localPartParts = /* @__PURE__ */ new Set();
1949
+ for (const reading of rkf.readings) {
1950
+ entryParts.add(reading.reading);
1951
+ localPartParts.add(reading.reading);
1952
+ }
1953
+ if (rkf.kanjiForms !== void 0 && rkf.kanjiForms.length > 0)
1954
+ for (const kanjiForm of rkf.kanjiForms) {
1955
+ entryParts.add(kanjiForm.form);
1956
+ localPartParts.add(kanjiForm.form);
1957
+ }
1958
+ entryParts.add(name.id);
1959
+ localPartParts.add(name.id);
1960
+ namePartsMap.set(name.id, localPartParts);
1961
+ }
1962
+ }
1963
+ if (tanakaExamples !== void 0) {
1964
+ for (const ex of tanakaExamples)
1965
+ for (const part of ex.parts) {
1966
+ if (entryParts.has(part.baseForm)) {
1967
+ const exList = partExamplesMap.get(
1968
+ part.baseForm
1969
+ );
1970
+ if (exList === void 0) partExamplesMap.set(part.baseForm, [ex]);
1971
+ else exList.push(ex);
1972
+ }
1973
+ if (part.reading !== void 0 && entryParts.has(part.reading)) {
1974
+ const exList = partExamplesMap.get(
1975
+ part.reading
1976
+ );
1977
+ if (exList === void 0) partExamplesMap.set(part.reading, [ex]);
1978
+ else exList.push(ex);
1979
+ }
1980
+ if (part.inflectedForm !== void 0 && entryParts.has(part.inflectedForm)) {
1981
+ const exList = partExamplesMap.get(
1982
+ part.inflectedForm
1983
+ );
1984
+ if (exList === void 0)
1985
+ partExamplesMap.set(part.inflectedForm, [ex]);
1986
+ else exList.push(ex);
1987
+ }
1988
+ }
1989
+ for (const name of jmNedict) {
1990
+ const seenEx = /* @__PURE__ */ new Set();
1991
+ const validExamples = [];
1992
+ for (const p of namePartsMap.get(name.id)) {
1993
+ const examplesForPart = partExamplesMap.get(p)?.filter((ex) => !seenEx.has(ex.id));
1994
+ if (examplesForPart === void 0) continue;
1995
+ for (const ex of examplesForPart) {
1996
+ seenEx.add(ex.id);
1997
+ validExamples.push(ex);
1998
+ }
1999
+ }
2000
+ if (validExamples.length > 0)
2001
+ nameExamplesMap.set(name.id, validExamples);
2002
+ }
2003
+ }
2004
+ }
1847
2005
  return {
1848
2006
  ...wordIDEntryMap.size > 0 ? { wordIDEntryMap } : {},
2007
+ ...nameIDEntryMap.size > 0 ? { nameIDEntryMap } : {},
1849
2008
  ...kanjiWordsMap.size > 0 ? { kanjiWordsMap } : {},
1850
2009
  ...kanjiEntryMap.size > 0 ? { kanjiEntryMap } : {},
1851
2010
  ...wordExamplesMap.size > 0 ? { wordExamplesMap } : {},
2011
+ ...nameExamplesMap.size > 0 ? { nameExamplesMap } : {},
1852
2012
  ...wordDefinitionsMap.size > 0 ? { wordDefinitionsMap } : {},
1853
2013
  ...kanjiSVGMap.size > 0 ? { kanjiSVGMap } : {}
1854
2014
  };
@@ -2512,17 +2672,34 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2512
2672
  ...dictReading.commonness !== void 0 && dictReading.commonness.length > 0 ? { common: true } : {}
2513
2673
  }));
2514
2674
  word.translations = [];
2675
+ const meanings = dictWord.hasPhrases === true && examples !== void 0 ? [] : void 0;
2676
+ const seenPhrases = /* @__PURE__ */ new Set();
2515
2677
  for (const dictMeaning of dictWord.meanings) {
2516
2678
  const translationTypes = [];
2517
2679
  const translations = dictMeaning.translations.map(
2518
2680
  (translation) => {
2519
- if (typeof translation === "string") return translation;
2520
- else {
2681
+ if (typeof translation === "string") {
2682
+ if (meanings !== void 0) {
2683
+ const cleanTranslation = translation.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
2684
+ if (!seenPhrases.has(cleanTranslation)) {
2685
+ seenPhrases.add(cleanTranslation);
2686
+ meanings.push(cleanTranslation);
2687
+ }
2688
+ }
2689
+ return translation;
2690
+ } else {
2521
2691
  const translationNoteAndTag = noteMap.get(
2522
2692
  translation.type
2523
2693
  );
2524
2694
  translationTypes.push(translationNoteAndTag[1]);
2525
2695
  word.tags.push(`word::${translationNoteAndTag[0]}`);
2696
+ if (meanings !== void 0) {
2697
+ const cleanTranslation = translation.translation.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
2698
+ if (!seenPhrases.has(cleanTranslation)) {
2699
+ seenPhrases.add(cleanTranslation);
2700
+ meanings.push(cleanTranslation);
2701
+ }
2702
+ }
2526
2703
  return translation.translation;
2527
2704
  }
2528
2705
  }
@@ -2576,6 +2753,7 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2576
2753
  word.usuallyInKana = true;
2577
2754
  word.tags.push("word::usually_in_kana_for_all_senses");
2578
2755
  }
2756
+ seenPhrases.clear();
2579
2757
  if (kanjiDic !== void 0 && word.kanjiForms !== void 0) {
2580
2758
  const kanji = [];
2581
2759
  const seenChars = /* @__PURE__ */ new Set();
@@ -2596,7 +2774,7 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2596
2774
  }
2597
2775
  if (kanji.length > 0) word.kanji = kanji;
2598
2776
  }
2599
- if (dictWord.hasPhrases === true && examples !== void 0) {
2777
+ if (meanings !== void 0) {
2600
2778
  const exampleList = examples instanceof Map ? examples.get(dictWord.id) ?? [] : examples;
2601
2779
  const rkf = getValidForms(
2602
2780
  dictWord.readings,
@@ -2607,22 +2785,9 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2607
2785
  rkf.readings.map((r) => r.reading)
2608
2786
  );
2609
2787
  const kanjiForms = rkf.kanjiForms !== void 0 ? new Set(rkf.kanjiForms.map((kf) => kf.form)) : void 0;
2610
- const meanings = new Set(
2611
- dictWord.meanings.flatMap(
2612
- (m) => m.translations.map((t) => {
2613
- if (typeof t === "string")
2614
- return t.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
2615
- else
2616
- return t.translation.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
2617
- })
2618
- )
2619
- ).values().toArray();
2788
+ const readingMatchingKanjiFormExamples = [];
2620
2789
  let kanjiFormExamples = [];
2621
- let readingMatchingKanjiFormExamples = [];
2622
2790
  let readingExamples = [];
2623
- let readingMatchingKanjiForms = /* @__PURE__ */ new Set();
2624
- const readingMatchingKanjiFormsWithTranslations = /* @__PURE__ */ new Set();
2625
- const seenPhrases = /* @__PURE__ */ new Set();
2626
2791
  for (const example of exampleList)
2627
2792
  for (let i = 0; i < example.parts.length; i++) {
2628
2793
  if (seenPhrases.has(example.phrase)) break;
@@ -2634,17 +2799,15 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2634
2799
  const readingAsInflectedFormMatch = part.inflectedForm !== void 0 && readings.has(part.inflectedForm);
2635
2800
  const referenceIDMatch = part.referenceID === dictWord.id;
2636
2801
  if (kanjiForms !== void 0 && kanjiForms.has(part.baseForm)) {
2637
- if (readingAsReadingMatch || readingAsInflectedFormMatch || referenceIDMatch) {
2802
+ if (readingAsReadingMatch || readingAsInflectedFormMatch || referenceIDMatch)
2638
2803
  readingMatchingKanjiFormExamples.push({
2639
2804
  ex: example,
2640
2805
  partIndex: i,
2641
2806
  form: part.baseForm,
2807
+ ...referenceIDMatch ? { referenceIDMatch: true } : {},
2642
2808
  ...includesTranslation ? { includesTranslation: true } : {}
2643
2809
  });
2644
- readingMatchingKanjiForms.add(part.baseForm);
2645
- if (includesTranslation)
2646
- readingMatchingKanjiFormsWithTranslations.add(part.baseForm);
2647
- } else
2810
+ else
2648
2811
  kanjiFormExamples.push({
2649
2812
  ex: example,
2650
2813
  partIndex: i,
@@ -2660,29 +2823,24 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2660
2823
  ex: example,
2661
2824
  partIndex: i,
2662
2825
  ...referenceIDMatch ? { referenceIDMatch: true } : {},
2663
- ...!referenceIDMatch && includesTranslation ? { includesTranslation: true } : {}
2826
+ ...includesTranslation ? { includesTranslation: true } : {}
2664
2827
  });
2665
2828
  seenPhrases.add(example.phrase);
2666
2829
  break;
2667
2830
  }
2668
2831
  }
2669
- if (readingMatchingKanjiFormsWithTranslations.size > 0) {
2670
- readingMatchingKanjiForms = readingMatchingKanjiFormsWithTranslations;
2671
- readingMatchingKanjiFormExamples = readingMatchingKanjiFormExamples.filter(
2832
+ if (kanjiFormExamples.length > 0 && kanjiFormExamples.some(
2833
+ (ex) => ex.includesTranslation === true || ex.ex.parts.some(
2834
+ (part) => ex.form === part.baseForm && part.glossNumber !== void 0
2835
+ )
2836
+ ))
2837
+ kanjiFormExamples = kanjiFormExamples.filter(
2672
2838
  (ex) => ex.includesTranslation === true || ex.ex.parts.some(
2673
- (part) => readingMatchingKanjiForms.has(part.baseForm) && part.glossNumber !== void 0
2839
+ (part) => ex.form === part.baseForm && part.glossNumber !== void 0
2674
2840
  )
2675
2841
  );
2676
- }
2677
- const hasKfExamplesWithTranslation = kanjiFormExamples.some(
2678
- (ex) => ex.includesTranslation === true
2679
- );
2680
- if (kanjiFormExamples.length > 0 && readingMatchingKanjiForms.size > 0)
2681
- kanjiFormExamples = kanjiFormExamples.filter(
2682
- (ex) => readingMatchingKanjiForms.has(ex.form) && (!hasKfExamplesWithTranslation || ex.includesTranslation === true || ex.ex.parts.some(
2683
- (part) => readingMatchingKanjiForms.has(part.baseForm) && part.glossNumber !== void 0
2684
- ))
2685
- );
2842
+ else if (kanjiFormExamples.length > 0 && readingMatchingKanjiFormExamples.length > 0)
2843
+ kanjiFormExamples.length = 0;
2686
2844
  if (readingExamples.length > 0 && readingExamples.some(
2687
2845
  (ex) => ex.includesTranslation === true || ex.referenceIDMatch === true
2688
2846
  ))
@@ -2691,9 +2849,7 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2691
2849
  );
2692
2850
  let wordExamples = [
2693
2851
  ...word.kanjiForms !== void 0 ? [...readingMatchingKanjiFormExamples, ...kanjiFormExamples] : readingExamples
2694
- ].toSorted(
2695
- (a, b) => a.ex.phrase.length - b.ex.phrase.length
2696
- );
2852
+ ];
2697
2853
  seenPhrases.clear();
2698
2854
  const glossSpecificExamples = [];
2699
2855
  for (let i = 0; i < word.translations.length; i++)
@@ -2726,12 +2882,14 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2726
2882
  wordExamples = glossSpecificExamples;
2727
2883
  }
2728
2884
  if (wordExamples.length > 0) {
2729
- word.phrases = (glossSpecificExamples.length === 0 ? wordExamples.slice(0, 5) : wordExamples).map((ex) => ({
2730
- phrase: ex.ex.furigana ?? ex.ex.phrase,
2731
- translation: ex.ex.translation,
2732
- originalPhrase: ex.ex.phrase,
2733
- ...ex.ex.glossNumber !== void 0 ? { glossNumber: ex.ex.glossNumber } : {}
2734
- }));
2885
+ word.phrases = (glossSpecificExamples.length === 0 ? wordExamples.slice(0, 5) : wordExamples).map(
2886
+ (ex) => ({
2887
+ phrase: ex.ex.furigana ?? ex.ex.phrase,
2888
+ translation: ex.ex.translation,
2889
+ originalPhrase: ex.ex.phrase,
2890
+ ...ex.ex.glossNumber !== void 0 ? { glossNumber: ex.ex.glossNumber } : {}
2891
+ })
2892
+ );
2735
2893
  word.tags.push("word::has_phrases");
2736
2894
  if (glossSpecificExamples.length > 0)
2737
2895
  word.tags.push("word::has_meaning-specific_phrases");
@@ -2751,9 +2909,179 @@ function getWord(searchedWord, dict, kanjiDic, examples, definitions, noteTypeNa
2751
2909
  return word;
2752
2910
  } else return void 0;
2753
2911
  }
2912
+ function getName(searchedName, dict, kanjiDic, examples, noteTypeName, deckPath) {
2913
+ let dictName = void 0;
2914
+ if (typeof searchedName === "string" && dict !== void 0) {
2915
+ if (Array.isArray(dict))
2916
+ dictName = dict.find(
2917
+ (entry) => entry.id === searchedName
2918
+ );
2919
+ if (dict instanceof Map) dictName = dict.get(searchedName);
2920
+ }
2921
+ if (typeof searchedName === "object") dictName = searchedName;
2922
+ if (dictName !== void 0) {
2923
+ const name = {
2924
+ id: dictName.id,
2925
+ nameReadings: [],
2926
+ translations: [],
2927
+ noteID: `name_${dictName.id}`,
2928
+ noteTypeName,
2929
+ deckPath,
2930
+ tags: []
2931
+ };
2932
+ if (dictName.isCommon === true) {
2933
+ name.common = true;
2934
+ name.tags.push("name::common");
2935
+ }
2936
+ if (dictName.kanjiForms !== void 0)
2937
+ name.kanjiForms = dictName.kanjiForms.map(
2938
+ (dictKanjiForm) => ({
2939
+ kanjiForm: dictKanjiForm.form
2940
+ })
2941
+ );
2942
+ name.nameReadings = dictName.nameReadings.map(
2943
+ (dictReading) => ({
2944
+ reading: dictReading.reading,
2945
+ ...dictReading.kanjiFormRestrictions !== void 0 ? {
2946
+ notes: dictReading.kanjiFormRestrictions.map(
2947
+ (restriction) => `Reading restricted to ${restriction}`
2948
+ )
2949
+ } : {},
2950
+ ...dictReading.commonness !== void 0 && dictReading.commonness.length > 0 ? { common: true } : {}
2951
+ })
2952
+ );
2953
+ name.translations = [];
2954
+ const meanings = dictName.hasPhrases === true && examples !== void 0 ? [] : void 0;
2955
+ const seenPhrases = /* @__PURE__ */ new Set();
2956
+ let hasNameTypes = false;
2957
+ for (const dictMeaning of dictName.meanings) {
2958
+ if (!hasNameTypes && dictMeaning.nameTypes !== void 0)
2959
+ hasNameTypes = true;
2960
+ name.translations.push({
2961
+ translation: dictMeaning.translations.map((translation) => {
2962
+ if (meanings !== void 0) {
2963
+ const cleanTranslation = translation.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
2964
+ if (!seenPhrases.has(cleanTranslation)) {
2965
+ seenPhrases.add(cleanTranslation);
2966
+ meanings.push(cleanTranslation);
2967
+ }
2968
+ }
2969
+ return translation;
2970
+ }).join("; "),
2971
+ ...dictMeaning.nameTypes !== void 0 ? {
2972
+ notes: dictMeaning.nameTypes.map((type) => {
2973
+ const noteAndTag = lookupWordNote(
2974
+ type,
2975
+ [],
2976
+ name.tags
2977
+ );
2978
+ return capitalizeString(noteAndTag.note);
2979
+ })
2980
+ } : {}
2981
+ });
2982
+ }
2983
+ if (!hasNameTypes) name.tags.push("name::no_name_types");
2984
+ seenPhrases.clear();
2985
+ if (kanjiDic !== void 0 && name.kanjiForms !== void 0) {
2986
+ const kanji = [];
2987
+ const seenChars = /* @__PURE__ */ new Set();
2988
+ for (const kanjiForm of name.kanjiForms)
2989
+ for (const char of kanjiForm.kanjiForm.split("").filter((c) => regexps.kanji.test(c))) {
2990
+ if (seenChars.has(char)) continue;
2991
+ seenChars.add(char);
2992
+ const kanjiEntry = kanjiDic instanceof Map ? kanjiDic.get(char) : void 0;
2993
+ const kanjiObj = getKanji(
2994
+ kanjiEntry ?? char,
2995
+ !(kanjiDic instanceof Map) ? kanjiDic : void 0
2996
+ );
2997
+ if (kanjiObj !== void 0)
2998
+ kanji.push({
2999
+ kanji: kanjiObj.kanji,
3000
+ ...kanjiObj.meanings !== void 0 && kanjiObj.meanings.length > 0 ? { meanings: kanjiObj.meanings } : {}
3001
+ });
3002
+ }
3003
+ if (kanji.length > 0) name.kanji = kanji;
3004
+ }
3005
+ if (meanings !== void 0) {
3006
+ const exampleList = examples instanceof Map ? examples.get(dictName.id) ?? [] : examples;
3007
+ const rkf = getValidForms(
3008
+ dictName.nameReadings,
3009
+ dictName.kanjiForms,
3010
+ dictName.isCommon
3011
+ );
3012
+ const readings = new Set(
3013
+ rkf.readings.map((r) => r.reading)
3014
+ );
3015
+ const kanjiForms = rkf.kanjiForms !== void 0 ? new Set(rkf.kanjiForms.map((kf) => kf.form)) : void 0;
3016
+ let readingMatchingKanjiFormExamples = [];
3017
+ let readingExamples = [];
3018
+ let hasReadingMatchingKanjiFormWithTranslation = false;
3019
+ let hasReadingWithTranslation = false;
3020
+ for (const example of exampleList)
3021
+ for (let i = 0; i < example.parts.length; i++) {
3022
+ if (seenPhrases.has(example.phrase)) break;
3023
+ const includesTranslation = meanings.some(
3024
+ (m) => example.translation.includes(m)
3025
+ );
3026
+ const part = example.parts[i];
3027
+ const readingAsReadingMatch = part.reading !== void 0 && readings.has(part.reading);
3028
+ if (kanjiForms !== void 0 && kanjiForms.has(part.baseForm) && readingAsReadingMatch) {
3029
+ readingMatchingKanjiFormExamples.push({
3030
+ ex: example,
3031
+ ...includesTranslation ? { includesTranslation: true } : {}
3032
+ });
3033
+ if (!hasReadingMatchingKanjiFormWithTranslation && includesTranslation)
3034
+ hasReadingMatchingKanjiFormWithTranslation = true;
3035
+ seenPhrases.add(example.phrase);
3036
+ break;
3037
+ }
3038
+ const readingAsBaseFormMatch = readings.has(part.baseForm);
3039
+ if (readingAsBaseFormMatch && kanjiForms === void 0) {
3040
+ readingExamples.push({
3041
+ ex: example,
3042
+ ...includesTranslation ? { includesTranslation: true } : {}
3043
+ });
3044
+ if (!hasReadingWithTranslation && includesTranslation)
3045
+ hasReadingWithTranslation = true;
3046
+ seenPhrases.add(example.phrase);
3047
+ break;
3048
+ }
3049
+ }
3050
+ if (readingMatchingKanjiFormExamples.length > 0) {
3051
+ if (hasReadingMatchingKanjiFormWithTranslation)
3052
+ readingMatchingKanjiFormExamples = readingMatchingKanjiFormExamples.filter(
3053
+ (ex) => ex.includesTranslation === true
3054
+ );
3055
+ }
3056
+ if (readingExamples.length > 0 && hasReadingWithTranslation)
3057
+ readingExamples = readingExamples.filter(
3058
+ (ex) => ex.includesTranslation === true
3059
+ );
3060
+ const wordExamples = [
3061
+ ...name.kanjiForms !== void 0 ? readingMatchingKanjiFormExamples : readingExamples
3062
+ ];
3063
+ if (wordExamples.length > 0) {
3064
+ name.phrases = wordExamples.slice(0, 5).map(
3065
+ (ex) => ({
3066
+ phrase: ex.ex.furigana ?? ex.ex.phrase,
3067
+ translation: ex.ex.translation,
3068
+ originalPhrase: ex.ex.phrase
3069
+ })
3070
+ );
3071
+ name.tags.push("name::has_phrases");
3072
+ }
3073
+ }
3074
+ return name;
3075
+ } else return void 0;
3076
+ }
2754
3077
  function isWord(entry) {
2755
3078
  return isObjectArray(Object.getOwnPropertyDescriptor(entry, "readings")?.value) && isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value);
2756
3079
  }
3080
+ function isName(entry) {
3081
+ return isObjectArray(
3082
+ Object.getOwnPropertyDescriptor(entry, "nameReadings")?.value
3083
+ ) && isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value);
3084
+ }
2757
3085
  function isRadical(entry) {
2758
3086
  return typeof Object.getOwnPropertyDescriptor(entry, "radical")?.value === "string";
2759
3087
  }
@@ -2891,6 +3219,92 @@ function generateAnkiNote(entry, customData, additionalTags) {
2891
3219
  searchField
2892
3220
  );
2893
3221
  }
3222
+ if (isName(entry)) {
3223
+ const firstReading = createEntry(
3224
+ `<span class="name name-reading">${entry.nameReadings[0].reading}${entry.nameReadings[0].audio !== void 0 ? `<br>[sound:${entry.nameReadings[0].audio}]` : ""}</span>`,
3225
+ entry.nameReadings[0].notes
3226
+ );
3227
+ const otherReadings = entry.nameReadings.length > 1 ? `<details><summary>Show other readings</summary>${entry.nameReadings.slice(1).map(
3228
+ (readingEntry) => createEntry(
3229
+ `<span class="name name-reading">${readingEntry.reading}${readingEntry.audio !== void 0 ? `<br>[sound:${readingEntry.audio}]` : ""}</span>`,
3230
+ readingEntry.notes
3231
+ )
3232
+ ).join("")}</details>` : "";
3233
+ const readingsField = `${firstReading}${otherReadings}`;
3234
+ let readingsFieldWithoutAudio = '<div id="no-r-audio" style="display: none"></div>';
3235
+ let hasAudio = false;
3236
+ if (entry.nameReadings.some((r) => r.audio !== void 0)) {
3237
+ const firstReadingWithoutAudio = createEntry(
3238
+ `<span class="name name-reading">${entry.nameReadings[0].reading}</span>`,
3239
+ entry.nameReadings[0].notes
3240
+ );
3241
+ const otherReadingsWithoutAudio = entry.nameReadings.length > 1 ? `<details><summary>Show other readings</summary>${entry.nameReadings.slice(1).map(
3242
+ (readingEntry) => createEntry(
3243
+ `<span class="name name-reading">${readingEntry.reading}</span>`,
3244
+ readingEntry.notes
3245
+ )
3246
+ ).join("")}</details>` : "";
3247
+ readingsFieldWithoutAudio = `${firstReadingWithoutAudio}${otherReadingsWithoutAudio}`;
3248
+ hasAudio = true;
3249
+ }
3250
+ const firstKanjiForm = entry.kanjiForms !== void 0 ? createEntry(
3251
+ `<span class="name name-kanjiform"><ruby><rb>${entry.kanjiForms[0].kanjiForm}</rb><rt>${entry.nameReadings[0].reading}</rt></ruby></span>`,
3252
+ entry.kanjiForms[0].notes
3253
+ ) : void 0;
3254
+ const otherKanjiForms = entry.kanjiForms !== void 0 && entry.kanjiForms.length > 1 ? `<details><summary>Show other kanji forms</summary>${entry.kanjiForms.slice(1).map((kanjiFormEntry) => {
3255
+ const restrictedReading = entry.nameReadings.find(
3256
+ (r) => r.notes !== void 0 && r.notes.includes(
3257
+ `Reading restricted to ${kanjiFormEntry.kanjiForm}`
3258
+ )
3259
+ );
3260
+ return createEntry(
3261
+ `<span class="name name-kanjiform">${restrictedReading !== void 0 ? "<ruby><rb>" : ""}${kanjiFormEntry.kanjiForm}${restrictedReading !== void 0 ? `</rb><rt>${restrictedReading.reading}</rt></ruby>` : ""}</span>`,
3262
+ kanjiFormEntry.notes
3263
+ );
3264
+ }).join("")}</details>` : "";
3265
+ const kanjiFormsField = firstKanjiForm !== void 0 ? `${firstKanjiForm}${otherKanjiForms}` : '<span class="name name-kanjiform" id="no-kanjiforms">(no kanji forms)</span>';
3266
+ const firstThreeTranslations = entry.translations.slice(0, 3).map(
3267
+ (translationEntry) => createEntry(
3268
+ `<span class="name name-translation">${translationEntry.translation}</span>`,
3269
+ translationEntry.notes
3270
+ )
3271
+ ).join("");
3272
+ const otherTranslations = entry.translations.length > 3 ? `<details><summary>Show other translations</summary>${entry.translations.map((translationEntry, index) => {
3273
+ if (index < 3) return "null";
3274
+ return createEntry(
3275
+ `<span class="name name-translation">${translationEntry.translation}</span>`,
3276
+ translationEntry.notes
3277
+ );
3278
+ }).filter((translation) => translation !== "null").join("")}</details>` : "";
3279
+ const translationsField = `${firstThreeTranslations}${otherTranslations}`;
3280
+ const phrasesField = entry.phrases !== void 0 ? entry.phrases.map(
3281
+ (phraseEntry) => createEntry(
3282
+ `<span class="name name-phrase"><span class="name name-phrase-original">${phraseEntry.originalPhrase}</span><span class="name name-phrase-furigana">${phraseEntry.phrase}</span></span>`,
3283
+ [phraseEntry.translation],
3284
+ true
3285
+ )
3286
+ ).join("") : '<span class="name name-phrase" id="no-phrases">(no phrases)</span>';
3287
+ const searchField = `${entry.nameReadings.map((r) => r.reading).join(" ")}${entry.kanjiForms !== void 0 ? ` ${entry.kanjiForms.map((kf) => kf.kanjiForm).join(" ")}` : ""} ${entry.id}`;
3288
+ fields.push(
3289
+ ...entry.kanjiForms !== void 0 ? [
3290
+ `${customData !== void 0 ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${kanjiFormsField}<div id="kf-pos" style="display: none" data-pos="1"></div>`,
3291
+ `${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="2"></div>`
3292
+ ] : [
3293
+ `${customData !== void 0 ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${kanjiFormsField}<div id="kf-pos" style="display: none" data-pos="2"></div>`,
3294
+ `${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="1"></div>`
3295
+ ],
3296
+ `${hasAudio ? readingsField : readingsFieldWithoutAudio}<div id="r-pos" style="display: none" data-pos="${entry.kanjiForms !== void 0 ? "2" : "1"}"></div>`,
3297
+ translationsField,
3298
+ phrasesField,
3299
+ entry.kanji !== void 0 ? entry.kanji.map(
3300
+ (kanjiEntry) => createEntry(
3301
+ `<span class="name name-kanji">${kanjiEntry.kanji}${kanjiEntry.meanings === void 0 ? " (no meanings)" : ""}</span>`,
3302
+ kanjiEntry.meanings
3303
+ )
3304
+ ).join("") : '<span class="name name-kanji" id="no-kanji">(no kanji)</span>',
3305
+ searchField
3306
+ );
3307
+ }
2894
3308
  if (isRadical(entry))
2895
3309
  fields.push(
2896
3310
  `${customData !== void 0 ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${createEntry(
@@ -3069,6 +3483,7 @@ ${ankiNotes}`;
3069
3483
  0 && (module.exports = {
3070
3484
  capitalizeString,
3071
3485
  convertJMdict,
3486
+ convertJMnedict,
3072
3487
  convertJawiktionaryAsync,
3073
3488
  convertJawiktionarySync,
3074
3489
  convertKanjiDic,
@@ -3082,6 +3497,7 @@ ${ankiNotes}`;
3082
3497
  generateFurigana,
3083
3498
  getKanji,
3084
3499
  getKanjiExtended,
3500
+ getName,
3085
3501
  getValidForms,
3086
3502
  getWord,
3087
3503
  getWordDefinitions,
@@ -3090,6 +3506,7 @@ ${ankiNotes}`;
3090
3506
  isGrammar,
3091
3507
  isKana,
3092
3508
  isKanji,
3509
+ isName,
3093
3510
  isObjectArray,
3094
3511
  isRadical,
3095
3512
  isStringArray,