henkan 2.4.12 → 3.0.1
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.
- package/README.md +1 -1
- package/dist/index.cjs.js +439 -46
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.mjs +436 -46
- package/dist/index.mjs.map +2 -2
- package/dist/types/types.d.ts +106 -15
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils.d.ts +28 -6
- package/dist/types/utils.d.ts.map +1 -1
- package/docs/api/README.md +8 -2
- package/docs/api/functions/capitalizeString.md +1 -1
- package/docs/api/functions/convertJMdict.md +1 -1
- package/docs/api/functions/convertJMnedict.md +33 -0
- package/docs/api/functions/convertJawiktionaryAsync.md +1 -1
- package/docs/api/functions/convertJawiktionarySync.md +1 -1
- package/docs/api/functions/convertKanjiDic.md +1 -1
- package/docs/api/functions/convertKradFile.md +1 -1
- package/docs/api/functions/convertRadkFile.md +1 -1
- package/docs/api/functions/convertTanakaCorpus.md +1 -1
- package/docs/api/functions/convertTanakaCorpusWithFurigana.md +1 -1
- package/docs/api/functions/createEntryMaps.md +9 -3
- package/docs/api/functions/generateAnkiNote.md +2 -2
- package/docs/api/functions/generateAnkiNotesFile.md +1 -1
- package/docs/api/functions/generateFurigana.md +1 -1
- package/docs/api/functions/getKanji.md +1 -1
- package/docs/api/functions/getKanjiExtended.md +1 -1
- package/docs/api/functions/getName.md +57 -0
- package/docs/api/functions/getValidForms.md +1 -1
- package/docs/api/functions/getWord.md +3 -3
- package/docs/api/functions/getWordDefinitions.md +1 -1
- package/docs/api/functions/getWordDefinitionsWithFurigana.md +1 -1
- package/docs/api/functions/hiraganaToKatakana.md +1 -1
- package/docs/api/functions/isObjectArray.md +1 -1
- package/docs/api/functions/isStringArray.md +1 -1
- package/docs/api/functions/isValidArrayWithFirstElement.md +1 -1
- package/docs/api/functions/katakanaToHiragana.md +1 -1
- package/docs/api/functions/shuffleArray.md +1 -1
- package/docs/api/interfaces/DefaultNoteInfo.md +10 -10
- package/docs/api/interfaces/Definition.md +4 -4
- package/docs/api/interfaces/DictKanji.md +5 -5
- package/docs/api/interfaces/DictKanjiForm.md +2 -2
- package/docs/api/interfaces/DictKanjiMisc.md +5 -5
- package/docs/api/interfaces/DictKanjiReading.md +3 -3
- package/docs/api/interfaces/DictKanjiReadingMeaning.md +3 -3
- package/docs/api/interfaces/DictKanjiReadingMeaningGroup.md +3 -3
- package/docs/api/interfaces/DictKanjiWithRadicals.md +3 -3
- package/docs/api/interfaces/DictName.md +75 -0
- package/docs/api/interfaces/DictRadical.md +4 -4
- package/docs/api/interfaces/DictReading.md +2 -2
- package/docs/api/interfaces/EntryMaps.md +33 -9
- package/docs/api/interfaces/ExamplePart.md +7 -7
- package/docs/api/interfaces/GlossSpecificNumber.md +3 -3
- package/docs/api/interfaces/Grammar.md +15 -15
- package/docs/api/interfaces/GrammarMeaning.md +3 -3
- package/docs/api/interfaces/JaWiktionaryEntry.md +5 -5
- package/docs/api/interfaces/Kana.md +11 -11
- package/docs/api/interfaces/Kanji.md +23 -23
- package/docs/api/interfaces/KanjiComponent.md +3 -3
- package/docs/api/interfaces/KanjiForm.md +5 -5
- package/docs/api/interfaces/Name.md +163 -0
- package/docs/api/interfaces/NeDictMeaning.md +33 -0
- package/docs/api/interfaces/NoteAndTag.md +3 -3
- package/docs/api/interfaces/NoteHeaderKeys.md +7 -7
- package/docs/api/interfaces/Phrase.md +5 -5
- package/docs/api/interfaces/Radical.md +16 -16
- package/docs/api/interfaces/Reading.md +6 -6
- package/docs/api/interfaces/ResultEntry.md +8 -7
- package/docs/api/interfaces/TanakaExample.md +7 -7
- package/docs/api/interfaces/Translation.md +5 -5
- package/docs/api/interfaces/UsefulRegExps.md +8 -8
- package/docs/api/interfaces/Word.md +15 -15
- package/docs/api/interfaces/WordDefinitionPair.md +4 -4
- package/docs/api/type-aliases/Dict.md +1 -1
- package/docs/api/type-aliases/{DictName.md → DictNames.md} +3 -3
- package/docs/api/type-aliases/EntryExamplesMap.md +13 -0
- package/docs/api/type-aliases/EntryType.md +2 -2
- package/docs/api/type-aliases/KanjiEntryMap.md +1 -1
- package/docs/api/type-aliases/KanjiSVGMap.md +1 -1
- package/docs/api/type-aliases/KanjiWordsMap.md +1 -1
- package/docs/api/type-aliases/NameIDEntryMap.md +13 -0
- package/docs/api/type-aliases/Result.md +2 -2
- package/docs/api/type-aliases/WordDefinitionsMap.md +1 -1
- package/docs/api/type-aliases/WordIDEntryMap.md +1 -1
- package/package.json +8 -7
- package/src/types.ts +115 -15
- package/src/utils.ts +733 -162
- package/docs/api/type-aliases/WordExamplesMap.md +0 -13
package/src/utils.ts
CHANGED
|
@@ -20,10 +20,12 @@ import {
|
|
|
20
20
|
DictKanjiReadingMeaningGroup,
|
|
21
21
|
DictKanjiWithRadicals,
|
|
22
22
|
DictMeaning,
|
|
23
|
+
DictName,
|
|
23
24
|
DictRadical,
|
|
24
25
|
DictReading,
|
|
25
26
|
DictTranslation,
|
|
26
27
|
DictWord,
|
|
28
|
+
EntryExamplesMap,
|
|
27
29
|
EntryMaps,
|
|
28
30
|
ExamplePart,
|
|
29
31
|
Grammar,
|
|
@@ -35,6 +37,8 @@ import {
|
|
|
35
37
|
KanjiForm,
|
|
36
38
|
KanjiSVGMap,
|
|
37
39
|
KanjiWordsMap,
|
|
40
|
+
Name,
|
|
41
|
+
NameIDEntryMap,
|
|
38
42
|
NoteAndTag,
|
|
39
43
|
Phrase,
|
|
40
44
|
POS,
|
|
@@ -49,7 +53,6 @@ import {
|
|
|
49
53
|
Word,
|
|
50
54
|
WordDefinitionPair,
|
|
51
55
|
WordDefinitionsMap,
|
|
52
|
-
WordExamplesMap,
|
|
53
56
|
WordIDEntryMap,
|
|
54
57
|
} from "./types";
|
|
55
58
|
|
|
@@ -297,9 +300,6 @@ export function convertJMdict(
|
|
|
297
300
|
example.parts.flatMap((part: ExamplePart) => [
|
|
298
301
|
part.baseForm,
|
|
299
302
|
...(part.reading !== undefined ? [part.reading] : []),
|
|
300
|
-
...(part.inflectedForm !== undefined
|
|
301
|
-
? [part.inflectedForm]
|
|
302
|
-
: []),
|
|
303
303
|
...(part.referenceID !== undefined ? [part.referenceID] : []),
|
|
304
304
|
]),
|
|
305
305
|
),
|
|
@@ -461,6 +461,132 @@ export function convertJMdict(
|
|
|
461
461
|
return dict;
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
/**
|
|
465
|
+
* Converts a JMnedict `JMnedict.xml` file into an array of {@link DictWord} objects.
|
|
466
|
+
* @param xmlString The raw `JMnedict.xml` file contents
|
|
467
|
+
* @param examples An array of converted `Tanaka Corpus` examples
|
|
468
|
+
* @returns An array of converted {@link DictWord} objects
|
|
469
|
+
*/
|
|
470
|
+
export function convertJMnedict(
|
|
471
|
+
xmlString: string,
|
|
472
|
+
examples?: readonly TanakaExample[],
|
|
473
|
+
): DictName[] {
|
|
474
|
+
const dictParsed: libxml.Document = libxml.parseXml(xmlString, {
|
|
475
|
+
dtdvalid: true,
|
|
476
|
+
nonet: false,
|
|
477
|
+
noent: true,
|
|
478
|
+
recover: false,
|
|
479
|
+
});
|
|
480
|
+
const dict: DictName[] = [];
|
|
481
|
+
|
|
482
|
+
xml.parseString(dictParsed, (_err: Error | null, result: any) => {
|
|
483
|
+
const tanakaParts: Set<string> | undefined =
|
|
484
|
+
examples !== undefined && examples.length > 0
|
|
485
|
+
? new Set<string>(
|
|
486
|
+
examples.flatMap((example: TanakaExample) =>
|
|
487
|
+
example.parts.flatMap((part: ExamplePart) => [
|
|
488
|
+
part.baseForm,
|
|
489
|
+
...(part.reading !== undefined ? [part.reading] : []),
|
|
490
|
+
...(part.referenceID !== undefined ? [part.referenceID] : []),
|
|
491
|
+
]),
|
|
492
|
+
),
|
|
493
|
+
)
|
|
494
|
+
: undefined;
|
|
495
|
+
|
|
496
|
+
for (const entry of result.JMnedict.entry) {
|
|
497
|
+
const entryObj: DictName = {
|
|
498
|
+
id: entry.ent_seq[0],
|
|
499
|
+
nameReadings: [],
|
|
500
|
+
meanings: [],
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
const kanjiForms: any = entry.k_ele;
|
|
504
|
+
const readings: any = entry.r_ele;
|
|
505
|
+
const translations: any = entry.trans;
|
|
506
|
+
|
|
507
|
+
if (isObjectArray(kanjiForms)) {
|
|
508
|
+
entryObj.kanjiForms = [];
|
|
509
|
+
|
|
510
|
+
for (const kanjiForm of kanjiForms)
|
|
511
|
+
entryObj.kanjiForms.push({ form: kanjiForm.keb[0] });
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
for (const reading of readings) {
|
|
515
|
+
const readingObj: DictReading = {
|
|
516
|
+
reading: reading.reb[0],
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
if (isStringArray(reading.re_restr))
|
|
520
|
+
readingObj.kanjiFormRestrictions = reading.re_restr;
|
|
521
|
+
|
|
522
|
+
if (isStringArray(reading.re_pri)) {
|
|
523
|
+
readingObj.commonness = reading.re_pri;
|
|
524
|
+
|
|
525
|
+
entryObj.isCommon = true;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
entryObj.nameReadings.push(readingObj);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
for (const trans of translations)
|
|
532
|
+
entryObj.meanings.push({
|
|
533
|
+
translations: trans.trans_det,
|
|
534
|
+
...(isStringArray(trans.name_type)
|
|
535
|
+
? { nameTypes: trans.name_type }
|
|
536
|
+
: {}),
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
if (examples !== undefined) {
|
|
540
|
+
let existsExample: boolean = false;
|
|
541
|
+
|
|
542
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
543
|
+
entryObj.nameReadings,
|
|
544
|
+
entryObj.kanjiForms,
|
|
545
|
+
entryObj.isCommon,
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
const validReadings: Set<string> = new Set<string>(
|
|
549
|
+
rkf.readings.map((r: DictReading) => r.reading),
|
|
550
|
+
);
|
|
551
|
+
const validKanjiForms: Set<string> | undefined =
|
|
552
|
+
rkf.kanjiForms !== undefined
|
|
553
|
+
? new Set<string>(
|
|
554
|
+
rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form),
|
|
555
|
+
)
|
|
556
|
+
: undefined;
|
|
557
|
+
|
|
558
|
+
if (
|
|
559
|
+
validKanjiForms !== undefined &&
|
|
560
|
+
validKanjiForms.size > 0 &&
|
|
561
|
+
tanakaParts !== undefined
|
|
562
|
+
)
|
|
563
|
+
for (const kf of validKanjiForms)
|
|
564
|
+
if (tanakaParts.has(kf)) {
|
|
565
|
+
existsExample = true;
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (
|
|
570
|
+
entryObj.kanjiForms === undefined &&
|
|
571
|
+
validReadings.size > 0 &&
|
|
572
|
+
tanakaParts !== undefined
|
|
573
|
+
)
|
|
574
|
+
for (const r of validReadings)
|
|
575
|
+
if (tanakaParts.has(r)) {
|
|
576
|
+
existsExample = true;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (existsExample) entryObj.hasPhrases = true;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
dict.push(entryObj);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
return dict;
|
|
588
|
+
}
|
|
589
|
+
|
|
464
590
|
/**
|
|
465
591
|
* Converts a KANJIDIC `kanjidic2.xml` file into an array of {@link DictKanji} objects.
|
|
466
592
|
* @param xmlString The raw `kanjidic2.xml` file contents
|
|
@@ -805,13 +931,16 @@ export function convertKradFile(
|
|
|
805
931
|
*
|
|
806
932
|
* - {@link jmDict} => {@link WordIDEntryMap}, {@link KanjiWordsMap}
|
|
807
933
|
*
|
|
934
|
+
* - {@link jmNedict} => {@link NameIDEntryMap}
|
|
935
|
+
*
|
|
808
936
|
* - {@link kanjiDic} => {@link KanjiEntryMap}, {@link KanjiSVGMap} (only if {@link svgList} is present)
|
|
809
937
|
*
|
|
810
|
-
* - {@link tanakaExamples} (requires {@link jmDict}
|
|
938
|
+
* - {@link tanakaExamples} => {@link EntryExamplesMap} (requires {@link jmDict} or/and {@link jmNedict})
|
|
811
939
|
*
|
|
812
940
|
* - {@link wordDefinitionPairs} => {@link WordDefinitionsMap}
|
|
813
941
|
*
|
|
814
942
|
* @param jmDict An array of converted `JMdict` entries
|
|
943
|
+
* @param jmNedict
|
|
815
944
|
* @param kanjiDic An array of converted `KANJIDIC` entries
|
|
816
945
|
* @param tanakaExamples An array of converted `Tanaka Corpus` examples
|
|
817
946
|
* @param wordDefinitionPairs An array of `ja.wiktionary.org` word-definitions pairs
|
|
@@ -820,6 +949,7 @@ export function convertKradFile(
|
|
|
820
949
|
*/
|
|
821
950
|
export function createEntryMaps(
|
|
822
951
|
jmDict?: readonly DictWord[],
|
|
952
|
+
jmNedict?: readonly DictName[],
|
|
823
953
|
kanjiDic?: readonly DictKanji[],
|
|
824
954
|
tanakaExamples?: readonly TanakaExample[],
|
|
825
955
|
wordDefinitionPairs?: readonly WordDefinitionPair[],
|
|
@@ -827,8 +957,13 @@ export function createEntryMaps(
|
|
|
827
957
|
): EntryMaps {
|
|
828
958
|
const kanjiEntryMap: KanjiEntryMap = new Map<string, DictKanji>();
|
|
829
959
|
const wordIDEntryMap: WordIDEntryMap = new Map<StringNumber, DictWord>();
|
|
960
|
+
const nameIDEntryMap: NameIDEntryMap = new Map<StringNumber, DictName>();
|
|
830
961
|
const kanjiWordsMap: KanjiWordsMap = new Map<string, DictWord[]>();
|
|
831
|
-
const wordExamplesMap:
|
|
962
|
+
const wordExamplesMap: EntryExamplesMap = new Map<
|
|
963
|
+
StringNumber,
|
|
964
|
+
TanakaExample[]
|
|
965
|
+
>();
|
|
966
|
+
const nameExamplesMap: EntryExamplesMap = new Map<
|
|
832
967
|
StringNumber,
|
|
833
968
|
TanakaExample[]
|
|
834
969
|
>();
|
|
@@ -838,16 +973,6 @@ export function createEntryMaps(
|
|
|
838
973
|
>();
|
|
839
974
|
const kanjiSVGMap: KanjiSVGMap = new Map<string, string>();
|
|
840
975
|
|
|
841
|
-
const wordPartsMap: Map<StringNumber, Set<string>> = new Map<
|
|
842
|
-
StringNumber,
|
|
843
|
-
Set<string>
|
|
844
|
-
>();
|
|
845
|
-
const partExamplesMap: Map<string, TanakaExample[]> = new Map<
|
|
846
|
-
string,
|
|
847
|
-
TanakaExample[]
|
|
848
|
-
>();
|
|
849
|
-
const entryParts: Set<string> = new Set<string>();
|
|
850
|
-
|
|
851
976
|
if (kanjiDic !== undefined)
|
|
852
977
|
for (const kanji of kanjiDic) kanjiEntryMap.set(kanji.kanji, kanji);
|
|
853
978
|
|
|
@@ -872,6 +997,16 @@ export function createEntryMaps(
|
|
|
872
997
|
}
|
|
873
998
|
|
|
874
999
|
if (jmDict !== undefined) {
|
|
1000
|
+
const wordPartsMap: Map<StringNumber, Set<string>> = new Map<
|
|
1001
|
+
StringNumber,
|
|
1002
|
+
Set<string>
|
|
1003
|
+
>();
|
|
1004
|
+
const partExamplesMap: Map<string, TanakaExample[]> = new Map<
|
|
1005
|
+
string,
|
|
1006
|
+
TanakaExample[]
|
|
1007
|
+
>();
|
|
1008
|
+
const entryParts: Set<string> = new Set<string>();
|
|
1009
|
+
|
|
875
1010
|
for (const word of jmDict) {
|
|
876
1011
|
wordIDEntryMap.set(word.id, word);
|
|
877
1012
|
|
|
@@ -929,18 +1064,6 @@ export function createEntryMaps(
|
|
|
929
1064
|
if (exList === undefined) partExamplesMap.set(part.reading, [ex]);
|
|
930
1065
|
else exList.push(ex);
|
|
931
1066
|
}
|
|
932
|
-
if (
|
|
933
|
-
part.inflectedForm !== undefined &&
|
|
934
|
-
entryParts.has(part.inflectedForm)
|
|
935
|
-
) {
|
|
936
|
-
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
937
|
-
part.inflectedForm,
|
|
938
|
-
);
|
|
939
|
-
|
|
940
|
-
if (exList === undefined)
|
|
941
|
-
partExamplesMap.set(part.inflectedForm, [ex]);
|
|
942
|
-
else exList.push(ex);
|
|
943
|
-
}
|
|
944
1067
|
|
|
945
1068
|
if (
|
|
946
1069
|
part.referenceID !== undefined &&
|
|
@@ -978,11 +1101,97 @@ export function createEntryMaps(
|
|
|
978
1101
|
}
|
|
979
1102
|
}
|
|
980
1103
|
|
|
1104
|
+
if (jmNedict !== undefined) {
|
|
1105
|
+
const namePartsMap: Map<StringNumber, Set<string>> = new Map<
|
|
1106
|
+
StringNumber,
|
|
1107
|
+
Set<string>
|
|
1108
|
+
>();
|
|
1109
|
+
const partExamplesMap: Map<string, TanakaExample[]> = new Map<
|
|
1110
|
+
string,
|
|
1111
|
+
TanakaExample[]
|
|
1112
|
+
>();
|
|
1113
|
+
const entryParts: Set<string> = new Set<string>();
|
|
1114
|
+
|
|
1115
|
+
for (const name of jmNedict) {
|
|
1116
|
+
nameIDEntryMap.set(name.id, name);
|
|
1117
|
+
|
|
1118
|
+
if (tanakaExamples !== undefined) {
|
|
1119
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
1120
|
+
name.nameReadings,
|
|
1121
|
+
name.kanjiForms,
|
|
1122
|
+
name.isCommon,
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
const localPartParts: Set<string> = new Set<string>();
|
|
1126
|
+
|
|
1127
|
+
for (const reading of rkf.readings) {
|
|
1128
|
+
entryParts.add(reading.reading);
|
|
1129
|
+
localPartParts.add(reading.reading);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (rkf.kanjiForms !== undefined && rkf.kanjiForms.length > 0)
|
|
1133
|
+
for (const kanjiForm of rkf.kanjiForms) {
|
|
1134
|
+
entryParts.add(kanjiForm.form);
|
|
1135
|
+
localPartParts.add(kanjiForm.form);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
entryParts.add(name.id);
|
|
1139
|
+
localPartParts.add(name.id);
|
|
1140
|
+
|
|
1141
|
+
namePartsMap.set(name.id, localPartParts);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
if (tanakaExamples !== undefined) {
|
|
1146
|
+
for (const ex of tanakaExamples)
|
|
1147
|
+
for (const part of ex.parts) {
|
|
1148
|
+
if (entryParts.has(part.baseForm)) {
|
|
1149
|
+
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
1150
|
+
part.baseForm,
|
|
1151
|
+
);
|
|
1152
|
+
|
|
1153
|
+
if (exList === undefined) partExamplesMap.set(part.baseForm, [ex]);
|
|
1154
|
+
else exList.push(ex);
|
|
1155
|
+
}
|
|
1156
|
+
if (part.reading !== undefined && entryParts.has(part.reading)) {
|
|
1157
|
+
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
1158
|
+
part.reading,
|
|
1159
|
+
);
|
|
1160
|
+
|
|
1161
|
+
if (exList === undefined) partExamplesMap.set(part.reading, [ex]);
|
|
1162
|
+
else exList.push(ex);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
for (const name of jmNedict) {
|
|
1167
|
+
const seenEx: Set<string> = new Set<string>();
|
|
1168
|
+
const validExamples: TanakaExample[] = [];
|
|
1169
|
+
|
|
1170
|
+
for (const p of namePartsMap.get(name.id)!) {
|
|
1171
|
+
const examplesForPart: TanakaExample[] | undefined = partExamplesMap
|
|
1172
|
+
.get(p)
|
|
1173
|
+
?.filter((ex: TanakaExample) => !seenEx.has(ex.id));
|
|
1174
|
+
if (examplesForPart === undefined) continue;
|
|
1175
|
+
|
|
1176
|
+
for (const ex of examplesForPart) {
|
|
1177
|
+
seenEx.add(ex.id);
|
|
1178
|
+
validExamples.push(ex);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if (validExamples.length > 0)
|
|
1183
|
+
nameExamplesMap.set(name.id, validExamples);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
981
1188
|
return {
|
|
982
1189
|
...(wordIDEntryMap.size > 0 ? { wordIDEntryMap: wordIDEntryMap } : {}),
|
|
1190
|
+
...(nameIDEntryMap.size > 0 ? { nameIDEntryMap: nameIDEntryMap } : {}),
|
|
983
1191
|
...(kanjiWordsMap.size > 0 ? { kanjiWordsMap: kanjiWordsMap } : {}),
|
|
984
1192
|
...(kanjiEntryMap.size > 0 ? { kanjiEntryMap: kanjiEntryMap } : {}),
|
|
985
1193
|
...(wordExamplesMap.size > 0 ? { wordExamplesMap: wordExamplesMap } : {}),
|
|
1194
|
+
...(nameExamplesMap.size > 0 ? { nameExamplesMap: nameExamplesMap } : {}),
|
|
986
1195
|
...(wordDefinitionsMap.size > 0
|
|
987
1196
|
? { wordDefinitionsMap: wordDefinitionsMap }
|
|
988
1197
|
: {}),
|
|
@@ -2039,7 +2248,7 @@ export function getKanjiExtended(
|
|
|
2039
2248
|
* @param searchedWord The ID of the `JMdict` entry (requires {@link dict}) or a {@link DictWord} object
|
|
2040
2249
|
* @param dict An array converted `JMdict` entries or a {@link WordIDEntryMap} *(not needed if {@link searchedWord} is a {@link DictWord} object)*
|
|
2041
2250
|
* @param kanjiDic An array of converted `KANJIDIC` entries or a {@link KanjiEntryMap}
|
|
2042
|
-
* @param examples An array of converted `Tanaka Corpus` examples or a {@link
|
|
2251
|
+
* @param examples An array of converted `Tanaka Corpus` examples or a {@link EntryExamplesMap}
|
|
2043
2252
|
* @param definitions An array of `ja.wiktionary.org` word-definitions pairs or a {@link WordDefinitionsMap}
|
|
2044
2253
|
* @param noteTypeName The Anki note type name
|
|
2045
2254
|
* @param deckPath The full Anki deck path
|
|
@@ -2049,7 +2258,7 @@ export function getWord(
|
|
|
2049
2258
|
searchedWord: StringNumber | DictWord,
|
|
2050
2259
|
dict?: readonly DictWord[] | WordIDEntryMap,
|
|
2051
2260
|
kanjiDic?: readonly DictKanji[] | KanjiEntryMap,
|
|
2052
|
-
examples?: readonly TanakaExample[] |
|
|
2261
|
+
examples?: readonly TanakaExample[] | EntryExamplesMap,
|
|
2053
2262
|
definitions?: readonly WordDefinitionPair[] | WordDefinitionsMap,
|
|
2054
2263
|
noteTypeName?: string,
|
|
2055
2264
|
deckPath?: string,
|
|
@@ -2287,17 +2496,13 @@ export function getWord(
|
|
|
2287
2496
|
? new Set<string>(rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form))
|
|
2288
2497
|
: undefined;
|
|
2289
2498
|
|
|
2290
|
-
|
|
2499
|
+
const readingMatchingKanjiFormExamples: {
|
|
2291
2500
|
ex: TanakaExample;
|
|
2292
2501
|
partIndex: number;
|
|
2293
|
-
form: string;
|
|
2294
|
-
referenceIDMatch?: true | undefined;
|
|
2295
|
-
includesTranslation?: true | undefined;
|
|
2296
2502
|
}[] = [];
|
|
2297
2503
|
let kanjiFormExamples: {
|
|
2298
2504
|
ex: TanakaExample;
|
|
2299
2505
|
partIndex: number;
|
|
2300
|
-
form: string;
|
|
2301
2506
|
includesTranslation?: true | undefined;
|
|
2302
2507
|
}[] = [];
|
|
2303
2508
|
|
|
@@ -2308,52 +2513,40 @@ export function getWord(
|
|
|
2308
2513
|
includesTranslation?: true | undefined;
|
|
2309
2514
|
}[] = [];
|
|
2310
2515
|
|
|
2311
|
-
let
|
|
2516
|
+
let hasKanjiFormExamplesWithTranslation: boolean = false;
|
|
2517
|
+
let hasReadingExamplesWithTranslation: boolean = false;
|
|
2312
2518
|
|
|
2313
2519
|
for (const example of exampleList)
|
|
2314
2520
|
for (let i: number = 0; i < example.parts.length; i++) {
|
|
2315
2521
|
if (seenPhrases.has(example.phrase)) break;
|
|
2316
2522
|
|
|
2317
|
-
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2318
|
-
example.translation.includes(m),
|
|
2319
|
-
);
|
|
2320
|
-
|
|
2321
2523
|
const part: ExamplePart = example.parts[i]!;
|
|
2322
2524
|
|
|
2323
2525
|
const readingAsReadingMatch: boolean =
|
|
2324
2526
|
part.reading !== undefined && readings.has(part.reading);
|
|
2325
|
-
const readingAsInflectedFormMatch: boolean =
|
|
2326
|
-
part.inflectedForm !== undefined &&
|
|
2327
|
-
readings.has(part.inflectedForm);
|
|
2328
2527
|
|
|
2329
2528
|
const referenceIDMatch: boolean = part.referenceID === dictWord.id;
|
|
2330
2529
|
|
|
2331
2530
|
if (kanjiForms !== undefined && kanjiForms.has(part.baseForm)) {
|
|
2332
|
-
if (
|
|
2333
|
-
readingAsReadingMatch ||
|
|
2334
|
-
readingAsInflectedFormMatch ||
|
|
2335
|
-
referenceIDMatch
|
|
2336
|
-
) {
|
|
2531
|
+
if (readingAsReadingMatch || referenceIDMatch)
|
|
2337
2532
|
readingMatchingKanjiFormExamples.push({
|
|
2338
2533
|
ex: example,
|
|
2339
2534
|
partIndex: i,
|
|
2340
|
-
form: part.baseForm,
|
|
2341
|
-
...(referenceIDMatch ? { referenceIDMatch: true } : {}),
|
|
2342
|
-
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2343
2535
|
});
|
|
2536
|
+
else {
|
|
2537
|
+
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2538
|
+
example.translation.includes(m),
|
|
2539
|
+
);
|
|
2540
|
+
|
|
2541
|
+
if (!hasKanjiFormExamplesWithTranslation && includesTranslation)
|
|
2542
|
+
hasKanjiFormExamplesWithTranslation = true;
|
|
2344
2543
|
|
|
2345
|
-
if (
|
|
2346
|
-
!hasReadingMatchingKanjiFormWithTranslation &&
|
|
2347
|
-
includesTranslation
|
|
2348
|
-
)
|
|
2349
|
-
hasReadingMatchingKanjiFormWithTranslation = true;
|
|
2350
|
-
} else
|
|
2351
2544
|
kanjiFormExamples.push({
|
|
2352
2545
|
ex: example,
|
|
2353
2546
|
partIndex: i,
|
|
2354
|
-
form: part.baseForm,
|
|
2355
2547
|
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2356
2548
|
});
|
|
2549
|
+
}
|
|
2357
2550
|
|
|
2358
2551
|
seenPhrases.add(example.phrase);
|
|
2359
2552
|
|
|
@@ -2366,6 +2559,13 @@ export function getWord(
|
|
|
2366
2559
|
(readingAsBaseFormMatch || referenceIDMatch) &&
|
|
2367
2560
|
kanjiForms === undefined
|
|
2368
2561
|
) {
|
|
2562
|
+
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2563
|
+
example.translation.includes(m),
|
|
2564
|
+
);
|
|
2565
|
+
|
|
2566
|
+
if (!hasReadingExamplesWithTranslation && includesTranslation)
|
|
2567
|
+
hasReadingExamplesWithTranslation = true;
|
|
2568
|
+
|
|
2369
2569
|
readingExamples.push({
|
|
2370
2570
|
ex: example,
|
|
2371
2571
|
partIndex: i,
|
|
@@ -2379,64 +2579,21 @@ export function getWord(
|
|
|
2379
2579
|
}
|
|
2380
2580
|
}
|
|
2381
2581
|
|
|
2382
|
-
if (
|
|
2383
|
-
if (hasReadingMatchingKanjiFormWithTranslation)
|
|
2384
|
-
readingMatchingKanjiFormExamples =
|
|
2385
|
-
readingMatchingKanjiFormExamples.filter(
|
|
2386
|
-
(ex: {
|
|
2387
|
-
ex: TanakaExample;
|
|
2388
|
-
partIndex: number;
|
|
2389
|
-
form: string;
|
|
2390
|
-
referenceIDMatch?: true | undefined;
|
|
2391
|
-
includesTranslation?: true | undefined;
|
|
2392
|
-
}) =>
|
|
2393
|
-
ex.includesTranslation === true ||
|
|
2394
|
-
ex.referenceIDMatch === true ||
|
|
2395
|
-
ex.ex.parts.some(
|
|
2396
|
-
(part: ExamplePart) =>
|
|
2397
|
-
ex.form === part.baseForm && part.glossNumber !== undefined,
|
|
2398
|
-
),
|
|
2399
|
-
);
|
|
2400
|
-
|
|
2401
|
-
kanjiFormExamples.length = 0;
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
if (
|
|
2405
|
-
kanjiFormExamples.length > 0 &&
|
|
2406
|
-
kanjiFormExamples.some(
|
|
2407
|
-
(ex: {
|
|
2408
|
-
ex: TanakaExample;
|
|
2409
|
-
partIndex: number;
|
|
2410
|
-
form: string;
|
|
2411
|
-
includesTranslation?: true | undefined;
|
|
2412
|
-
}) => ex.includesTranslation === true,
|
|
2413
|
-
)
|
|
2414
|
-
)
|
|
2582
|
+
if (kanjiFormExamples.length > 0 && hasKanjiFormExamplesWithTranslation)
|
|
2415
2583
|
kanjiFormExamples = kanjiFormExamples.filter(
|
|
2416
2584
|
(ex: {
|
|
2417
2585
|
ex: TanakaExample;
|
|
2418
2586
|
partIndex: number;
|
|
2419
|
-
form: string;
|
|
2420
2587
|
includesTranslation?: true | undefined;
|
|
2421
|
-
}) =>
|
|
2422
|
-
ex.includesTranslation === true ||
|
|
2423
|
-
ex.ex.parts.some(
|
|
2424
|
-
(part: ExamplePart) =>
|
|
2425
|
-
ex.form === part.baseForm && part.glossNumber !== undefined,
|
|
2426
|
-
),
|
|
2588
|
+
}) => ex.includesTranslation === true,
|
|
2427
2589
|
);
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
readingExamples.some(
|
|
2432
|
-
(ex: {
|
|
2433
|
-
ex: TanakaExample;
|
|
2434
|
-
partIndex: number;
|
|
2435
|
-
referenceIDMatch?: true | undefined;
|
|
2436
|
-
includesTranslation?: true | undefined;
|
|
2437
|
-
}) => ex.includesTranslation === true || ex.referenceIDMatch === true,
|
|
2438
|
-
)
|
|
2590
|
+
else if (
|
|
2591
|
+
kanjiFormExamples.length > 0 &&
|
|
2592
|
+
readingMatchingKanjiFormExamples.length > 0
|
|
2439
2593
|
)
|
|
2594
|
+
kanjiFormExamples.length = 0;
|
|
2595
|
+
|
|
2596
|
+
if (readingExamples.length > 0 && hasReadingExamplesWithTranslation)
|
|
2440
2597
|
readingExamples = readingExamples.filter(
|
|
2441
2598
|
(ex: {
|
|
2442
2599
|
ex: TanakaExample;
|
|
@@ -2446,20 +2603,12 @@ export function getWord(
|
|
|
2446
2603
|
}) => ex.includesTranslation === true || ex.referenceIDMatch === true,
|
|
2447
2604
|
);
|
|
2448
2605
|
|
|
2449
|
-
let wordExamples:
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
}
|
|
2456
|
-
| {
|
|
2457
|
-
ex: TanakaExample;
|
|
2458
|
-
partIndex: number;
|
|
2459
|
-
referenceIDMatch?: true | undefined;
|
|
2460
|
-
includesTranslation?: true | undefined;
|
|
2461
|
-
}
|
|
2462
|
-
)[] = [
|
|
2606
|
+
let wordExamples: {
|
|
2607
|
+
ex: TanakaExample;
|
|
2608
|
+
partIndex: number;
|
|
2609
|
+
referenceIDMatch?: true | undefined;
|
|
2610
|
+
includesTranslation?: true | undefined;
|
|
2611
|
+
}[] = [
|
|
2463
2612
|
...(word.kanjiForms !== undefined
|
|
2464
2613
|
? [...readingMatchingKanjiFormExamples, ...kanjiFormExamples]
|
|
2465
2614
|
: readingExamples),
|
|
@@ -2496,21 +2645,12 @@ export function getWord(
|
|
|
2496
2645
|
if (glossSpecificExamples.length > 0) {
|
|
2497
2646
|
if (glossSpecificExamples.length < 5) {
|
|
2498
2647
|
wordExamples = wordExamples.filter(
|
|
2499
|
-
(
|
|
2500
|
-
ex:
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
includesTranslation?: true | undefined;
|
|
2506
|
-
}
|
|
2507
|
-
| {
|
|
2508
|
-
ex: TanakaExample;
|
|
2509
|
-
partIndex: number;
|
|
2510
|
-
referenceIDMatch?: true | undefined;
|
|
2511
|
-
includesTranslation?: true | undefined;
|
|
2512
|
-
},
|
|
2513
|
-
) => !seenPhrases.has(ex.ex.phrase),
|
|
2648
|
+
(ex: {
|
|
2649
|
+
ex: TanakaExample;
|
|
2650
|
+
partIndex: number;
|
|
2651
|
+
referenceIDMatch?: true | undefined;
|
|
2652
|
+
includesTranslation?: true | undefined;
|
|
2653
|
+
}) => !seenPhrases.has(ex.ex.phrase),
|
|
2514
2654
|
);
|
|
2515
2655
|
|
|
2516
2656
|
if (wordExamples.length > 0)
|
|
@@ -2530,21 +2670,12 @@ export function getWord(
|
|
|
2530
2670
|
? wordExamples.slice(0, 5)
|
|
2531
2671
|
: wordExamples
|
|
2532
2672
|
).map(
|
|
2533
|
-
(
|
|
2534
|
-
ex:
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
includesTranslation?: true | undefined;
|
|
2540
|
-
}
|
|
2541
|
-
| {
|
|
2542
|
-
ex: TanakaExample;
|
|
2543
|
-
partIndex: number;
|
|
2544
|
-
referenceIDMatch?: true | undefined;
|
|
2545
|
-
includesTranslation?: true | undefined;
|
|
2546
|
-
},
|
|
2547
|
-
) => ({
|
|
2673
|
+
(ex: {
|
|
2674
|
+
ex: TanakaExample;
|
|
2675
|
+
partIndex: number;
|
|
2676
|
+
referenceIDMatch?: true | undefined;
|
|
2677
|
+
includesTranslation?: true | undefined;
|
|
2678
|
+
}) => ({
|
|
2548
2679
|
phrase: ex.ex.furigana ?? ex.ex.phrase,
|
|
2549
2680
|
translation: ex.ex.translation,
|
|
2550
2681
|
originalPhrase: ex.ex.phrase,
|
|
@@ -2581,14 +2712,307 @@ export function getWord(
|
|
|
2581
2712
|
} else return undefined;
|
|
2582
2713
|
}
|
|
2583
2714
|
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
}
|
|
2590
|
-
|
|
2591
|
-
|
|
2715
|
+
/**
|
|
2716
|
+
* Transforms a converted `JMnedict` entry into a more readable format, by providing either its JMnedict entry ID or the {@link DictName} object directly.
|
|
2717
|
+
* @param searchedName The ID of the `JMnedict` entry (requires {@link dict}) or a {@link DictName} object
|
|
2718
|
+
* @param dict An array converted `JMnedict` entries or a {@link NameIDEntryMap} *(not needed if {@link searchedName} is a {@link DictName} object)*
|
|
2719
|
+
* @param kanjiDic An array of converted `KANJIDIC` entries or a {@link KanjiEntryMap}
|
|
2720
|
+
* @param examples An array of converted `Tanaka Corpus` examples or a {@link EntryExamplesMap}
|
|
2721
|
+
* @param noteTypeName The Anki note type name
|
|
2722
|
+
* @param deckPath The full Anki deck path
|
|
2723
|
+
* @returns The transformed {@link DictName} object or `undefined` if entry is not found
|
|
2724
|
+
*/
|
|
2725
|
+
export function getName(
|
|
2726
|
+
searchedName: StringNumber | DictName,
|
|
2727
|
+
dict?: readonly DictName[] | NameIDEntryMap,
|
|
2728
|
+
kanjiDic?: readonly DictKanji[] | KanjiEntryMap,
|
|
2729
|
+
examples?: readonly TanakaExample[] | EntryExamplesMap,
|
|
2730
|
+
noteTypeName?: string,
|
|
2731
|
+
deckPath?: string,
|
|
2732
|
+
): Name | undefined {
|
|
2733
|
+
let dictName: DictName | undefined = undefined;
|
|
2734
|
+
|
|
2735
|
+
if (typeof searchedName === "string" && dict !== undefined) {
|
|
2736
|
+
if (Array.isArray(dict))
|
|
2737
|
+
dictName = (dict as readonly DictName[]).find(
|
|
2738
|
+
(entry: DictName) => entry.id === searchedName,
|
|
2739
|
+
);
|
|
2740
|
+
|
|
2741
|
+
if (dict instanceof Map) dictName = dict.get(searchedName);
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
if (typeof searchedName === "object") dictName = searchedName;
|
|
2745
|
+
|
|
2746
|
+
if (dictName !== undefined) {
|
|
2747
|
+
const name: Name = {
|
|
2748
|
+
id: dictName.id,
|
|
2749
|
+
nameReadings: [],
|
|
2750
|
+
translations: [],
|
|
2751
|
+
noteID: `name_${dictName.id}`,
|
|
2752
|
+
noteTypeName: noteTypeName,
|
|
2753
|
+
deckPath: deckPath,
|
|
2754
|
+
tags: [],
|
|
2755
|
+
};
|
|
2756
|
+
|
|
2757
|
+
if (dictName.isCommon === true) {
|
|
2758
|
+
name.common = true;
|
|
2759
|
+
name.tags!.push("name::common");
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
if (dictName.kanjiForms !== undefined)
|
|
2763
|
+
name.kanjiForms = dictName.kanjiForms.map(
|
|
2764
|
+
(dictKanjiForm: DictKanjiForm) => ({
|
|
2765
|
+
kanjiForm: dictKanjiForm.form,
|
|
2766
|
+
}),
|
|
2767
|
+
);
|
|
2768
|
+
|
|
2769
|
+
name.nameReadings = dictName.nameReadings.map(
|
|
2770
|
+
(dictReading: DictReading) => ({
|
|
2771
|
+
reading: dictReading.reading,
|
|
2772
|
+
...(dictReading.kanjiFormRestrictions !== undefined
|
|
2773
|
+
? {
|
|
2774
|
+
notes: dictReading.kanjiFormRestrictions.map(
|
|
2775
|
+
(restriction: string) => `Reading restricted to ${restriction}`,
|
|
2776
|
+
),
|
|
2777
|
+
}
|
|
2778
|
+
: {}),
|
|
2779
|
+
...(dictReading.commonness !== undefined &&
|
|
2780
|
+
dictReading.commonness.length > 0
|
|
2781
|
+
? { common: true }
|
|
2782
|
+
: {}),
|
|
2783
|
+
}),
|
|
2784
|
+
);
|
|
2785
|
+
|
|
2786
|
+
name.translations = [];
|
|
2787
|
+
|
|
2788
|
+
const meanings: string[] | undefined =
|
|
2789
|
+
dictName.hasPhrases === true && examples !== undefined ? [] : undefined;
|
|
2790
|
+
const seenPhrases: Set<string> = new Set<string>();
|
|
2791
|
+
let hasNameTypes: boolean = false;
|
|
2792
|
+
|
|
2793
|
+
for (const dictMeaning of dictName.meanings) {
|
|
2794
|
+
if (!hasNameTypes && dictMeaning.nameTypes !== undefined)
|
|
2795
|
+
hasNameTypes = true;
|
|
2796
|
+
|
|
2797
|
+
name.translations.push({
|
|
2798
|
+
translation: dictMeaning.translations
|
|
2799
|
+
.map((translation: string) => {
|
|
2800
|
+
if (meanings !== undefined) {
|
|
2801
|
+
const cleanTranslation: string = translation
|
|
2802
|
+
.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "")
|
|
2803
|
+
.trim();
|
|
2804
|
+
|
|
2805
|
+
if (!seenPhrases.has(cleanTranslation)) {
|
|
2806
|
+
seenPhrases.add(cleanTranslation);
|
|
2807
|
+
meanings.push(cleanTranslation);
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
return translation;
|
|
2812
|
+
})
|
|
2813
|
+
.join("; "),
|
|
2814
|
+
...(dictMeaning.nameTypes !== undefined
|
|
2815
|
+
? {
|
|
2816
|
+
notes: dictMeaning.nameTypes.map((type: string) => {
|
|
2817
|
+
const noteAndTag: NoteAndTag = lookupWordNote(
|
|
2818
|
+
type,
|
|
2819
|
+
[],
|
|
2820
|
+
name.tags!,
|
|
2821
|
+
);
|
|
2822
|
+
|
|
2823
|
+
return capitalizeString(noteAndTag.note);
|
|
2824
|
+
}),
|
|
2825
|
+
}
|
|
2826
|
+
: {}),
|
|
2827
|
+
});
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
if (!hasNameTypes) name.tags!.push("name::no_name_types");
|
|
2831
|
+
|
|
2832
|
+
seenPhrases.clear();
|
|
2833
|
+
|
|
2834
|
+
if (kanjiDic !== undefined && name.kanjiForms !== undefined) {
|
|
2835
|
+
const kanji: Kanji[] = [];
|
|
2836
|
+
const seenChars: Set<string> = new Set<string>();
|
|
2837
|
+
|
|
2838
|
+
for (const kanjiForm of name.kanjiForms)
|
|
2839
|
+
for (const char of kanjiForm.kanjiForm
|
|
2840
|
+
.split("")
|
|
2841
|
+
.filter((c: string) => regexps.kanji.test(c))) {
|
|
2842
|
+
if (seenChars.has(char)) continue;
|
|
2843
|
+
seenChars.add(char);
|
|
2844
|
+
|
|
2845
|
+
const kanjiEntry: DictKanji | undefined =
|
|
2846
|
+
kanjiDic instanceof Map ? kanjiDic.get(char) : undefined;
|
|
2847
|
+
|
|
2848
|
+
const kanjiObj: Kanji | undefined = getKanji(
|
|
2849
|
+
kanjiEntry ?? char,
|
|
2850
|
+
!(kanjiDic instanceof Map) ? kanjiDic : undefined,
|
|
2851
|
+
);
|
|
2852
|
+
|
|
2853
|
+
if (kanjiObj !== undefined)
|
|
2854
|
+
kanji.push({
|
|
2855
|
+
kanji: kanjiObj.kanji,
|
|
2856
|
+
...(kanjiObj.meanings !== undefined &&
|
|
2857
|
+
kanjiObj.meanings.length > 0
|
|
2858
|
+
? { meanings: kanjiObj.meanings }
|
|
2859
|
+
: {}),
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
if (kanji.length > 0) name.kanji = kanji;
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
if (meanings !== undefined) {
|
|
2867
|
+
const exampleList: readonly TanakaExample[] =
|
|
2868
|
+
examples instanceof Map ? (examples.get(dictName.id) ?? []) : examples!;
|
|
2869
|
+
|
|
2870
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
2871
|
+
dictName.nameReadings,
|
|
2872
|
+
dictName.kanjiForms,
|
|
2873
|
+
dictName.isCommon,
|
|
2874
|
+
);
|
|
2875
|
+
|
|
2876
|
+
const readings: Set<string> = new Set<string>(
|
|
2877
|
+
rkf.readings.map((r: DictReading) => r.reading),
|
|
2878
|
+
);
|
|
2879
|
+
const kanjiForms: Set<string> | undefined =
|
|
2880
|
+
rkf.kanjiForms !== undefined
|
|
2881
|
+
? new Set<string>(rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form))
|
|
2882
|
+
: undefined;
|
|
2883
|
+
|
|
2884
|
+
let readingMatchingKanjiFormExamples: {
|
|
2885
|
+
ex: TanakaExample;
|
|
2886
|
+
includesTranslation?: true | undefined;
|
|
2887
|
+
}[] = [];
|
|
2888
|
+
|
|
2889
|
+
let readingExamples: {
|
|
2890
|
+
ex: TanakaExample;
|
|
2891
|
+
includesTranslation?: true | undefined;
|
|
2892
|
+
}[] = [];
|
|
2893
|
+
|
|
2894
|
+
let hasReadingMatchingKanjiFormWithTranslation: boolean = false;
|
|
2895
|
+
let hasReadingWithTranslation: boolean = false;
|
|
2896
|
+
|
|
2897
|
+
for (const example of exampleList)
|
|
2898
|
+
for (let i: number = 0; i < example.parts.length; i++) {
|
|
2899
|
+
if (seenPhrases.has(example.phrase)) break;
|
|
2900
|
+
|
|
2901
|
+
const part: ExamplePart = example.parts[i]!;
|
|
2902
|
+
|
|
2903
|
+
const readingAsReadingMatch: boolean =
|
|
2904
|
+
part.reading !== undefined && readings.has(part.reading);
|
|
2905
|
+
|
|
2906
|
+
if (
|
|
2907
|
+
kanjiForms !== undefined &&
|
|
2908
|
+
kanjiForms.has(part.baseForm) &&
|
|
2909
|
+
readingAsReadingMatch
|
|
2910
|
+
) {
|
|
2911
|
+
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2912
|
+
example.translation.includes(m),
|
|
2913
|
+
);
|
|
2914
|
+
|
|
2915
|
+
if (
|
|
2916
|
+
!hasReadingMatchingKanjiFormWithTranslation &&
|
|
2917
|
+
includesTranslation
|
|
2918
|
+
)
|
|
2919
|
+
hasReadingMatchingKanjiFormWithTranslation = true;
|
|
2920
|
+
|
|
2921
|
+
readingMatchingKanjiFormExamples.push({
|
|
2922
|
+
ex: example,
|
|
2923
|
+
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2924
|
+
});
|
|
2925
|
+
|
|
2926
|
+
seenPhrases.add(example.phrase);
|
|
2927
|
+
|
|
2928
|
+
break;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
const readingAsBaseFormMatch: boolean = readings.has(part.baseForm);
|
|
2932
|
+
|
|
2933
|
+
if (readingAsBaseFormMatch && kanjiForms === undefined) {
|
|
2934
|
+
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2935
|
+
example.translation.includes(m),
|
|
2936
|
+
);
|
|
2937
|
+
|
|
2938
|
+
if (!hasReadingWithTranslation && includesTranslation)
|
|
2939
|
+
hasReadingWithTranslation = true;
|
|
2940
|
+
|
|
2941
|
+
readingExamples.push({
|
|
2942
|
+
ex: example,
|
|
2943
|
+
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2944
|
+
});
|
|
2945
|
+
|
|
2946
|
+
seenPhrases.add(example.phrase);
|
|
2947
|
+
|
|
2948
|
+
break;
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
if (readingMatchingKanjiFormExamples.length > 0)
|
|
2953
|
+
if (hasReadingMatchingKanjiFormWithTranslation)
|
|
2954
|
+
readingMatchingKanjiFormExamples =
|
|
2955
|
+
readingMatchingKanjiFormExamples.filter(
|
|
2956
|
+
(ex: {
|
|
2957
|
+
ex: TanakaExample;
|
|
2958
|
+
includesTranslation?: true | undefined;
|
|
2959
|
+
}) => ex.includesTranslation === true,
|
|
2960
|
+
);
|
|
2961
|
+
|
|
2962
|
+
if (readingExamples.length > 0 && hasReadingWithTranslation)
|
|
2963
|
+
readingExamples = readingExamples.filter(
|
|
2964
|
+
(ex: { ex: TanakaExample; includesTranslation?: true | undefined }) =>
|
|
2965
|
+
ex.includesTranslation === true,
|
|
2966
|
+
);
|
|
2967
|
+
|
|
2968
|
+
const wordExamples: {
|
|
2969
|
+
ex: TanakaExample;
|
|
2970
|
+
includesTranslation?: true | undefined;
|
|
2971
|
+
}[] = [
|
|
2972
|
+
...(name.kanjiForms !== undefined
|
|
2973
|
+
? readingMatchingKanjiFormExamples
|
|
2974
|
+
: readingExamples),
|
|
2975
|
+
];
|
|
2976
|
+
|
|
2977
|
+
if (wordExamples.length > 0) {
|
|
2978
|
+
name.phrases = wordExamples
|
|
2979
|
+
.slice(0, 5)
|
|
2980
|
+
.map(
|
|
2981
|
+
(ex: {
|
|
2982
|
+
ex: TanakaExample;
|
|
2983
|
+
includesTranslation?: true | undefined;
|
|
2984
|
+
}) => ({
|
|
2985
|
+
phrase: ex.ex.furigana ?? ex.ex.phrase,
|
|
2986
|
+
translation: ex.ex.translation,
|
|
2987
|
+
originalPhrase: ex.ex.phrase,
|
|
2988
|
+
}),
|
|
2989
|
+
);
|
|
2990
|
+
|
|
2991
|
+
name.tags!.push("name::has_phrases");
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
return name;
|
|
2996
|
+
} else return undefined;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
export function isWord(entry: Result): entry is Word {
|
|
3000
|
+
return (
|
|
3001
|
+
isObjectArray(Object.getOwnPropertyDescriptor(entry, "readings")?.value) &&
|
|
3002
|
+
isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value)
|
|
3003
|
+
);
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
export function isName(entry: Result): entry is Name {
|
|
3007
|
+
return (
|
|
3008
|
+
isObjectArray(
|
|
3009
|
+
Object.getOwnPropertyDescriptor(entry, "nameReadings")?.value,
|
|
3010
|
+
) &&
|
|
3011
|
+
isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value)
|
|
3012
|
+
);
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
export function isRadical(entry: Result): entry is Radical {
|
|
2592
3016
|
return (
|
|
2593
3017
|
typeof Object.getOwnPropertyDescriptor(entry, "radical")?.value === "string"
|
|
2594
3018
|
);
|
|
@@ -2635,7 +3059,7 @@ const createEntry: (
|
|
|
2635
3059
|
|
|
2636
3060
|
/**
|
|
2637
3061
|
* Generates an array where each field holds an entry’s info wrapped in HTML tags.
|
|
2638
|
-
* @param entry Any type of mapped entry ({@link Word}, {@link Kanji}, {@link Radical}, {@link Kana}, {@link Grammar})
|
|
3062
|
+
* @param entry Any type of mapped entry ({@link Word}, {@link Name}, {@link Kanji}, {@link Radical}, {@link Kana}, {@link Grammar})
|
|
2639
3063
|
* @param customData An additional string that will be added on the first field of any note type, as a `data-custom` attribute inside an invisible `div`
|
|
2640
3064
|
* @param additionalTags Additional tags that will be added alongside the existing entry tags
|
|
2641
3065
|
* @returns An array of fields, each corresponding to an Anki note type field
|
|
@@ -2884,6 +3308,153 @@ export function generateAnkiNote(
|
|
|
2884
3308
|
);
|
|
2885
3309
|
}
|
|
2886
3310
|
|
|
3311
|
+
if (isName(entry)) {
|
|
3312
|
+
const firstReading: string = createEntry(
|
|
3313
|
+
`<span class="name name-reading">${entry.nameReadings[0]!.reading}${entry.nameReadings[0]!.audio !== undefined ? `<br>[sound:${entry.nameReadings[0]!.audio}]` : ""}</span>`,
|
|
3314
|
+
entry.nameReadings[0]!.notes,
|
|
3315
|
+
);
|
|
3316
|
+
const otherReadings: string =
|
|
3317
|
+
entry.nameReadings.length > 1
|
|
3318
|
+
? `<details><summary>Show other readings</summary>${entry.nameReadings
|
|
3319
|
+
.slice(1)
|
|
3320
|
+
.map((readingEntry: Reading) =>
|
|
3321
|
+
createEntry(
|
|
3322
|
+
`<span class="name name-reading">${readingEntry.reading}${readingEntry.audio !== undefined ? `<br>[sound:${readingEntry.audio}]` : ""}</span>`,
|
|
3323
|
+
readingEntry.notes,
|
|
3324
|
+
),
|
|
3325
|
+
)
|
|
3326
|
+
.join("")}</details>`
|
|
3327
|
+
: "";
|
|
3328
|
+
const readingsField: string = `${firstReading}${otherReadings}`;
|
|
3329
|
+
|
|
3330
|
+
let readingsFieldWithoutAudio: string =
|
|
3331
|
+
'<div id="no-r-audio" style="display: none"></div>';
|
|
3332
|
+
let hasAudio: boolean = false;
|
|
3333
|
+
|
|
3334
|
+
if (entry.nameReadings.some((r: Reading) => r.audio !== undefined)) {
|
|
3335
|
+
const firstReadingWithoutAudio: string = createEntry(
|
|
3336
|
+
`<span class="name name-reading">${entry.nameReadings[0]!.reading}</span>`,
|
|
3337
|
+
entry.nameReadings[0]!.notes,
|
|
3338
|
+
);
|
|
3339
|
+
const otherReadingsWithoutAudio: string =
|
|
3340
|
+
entry.nameReadings.length > 1
|
|
3341
|
+
? `<details><summary>Show other readings</summary>${entry.nameReadings
|
|
3342
|
+
.slice(1)
|
|
3343
|
+
.map((readingEntry: Reading) =>
|
|
3344
|
+
createEntry(
|
|
3345
|
+
`<span class="name name-reading">${readingEntry.reading}</span>`,
|
|
3346
|
+
readingEntry.notes,
|
|
3347
|
+
),
|
|
3348
|
+
)
|
|
3349
|
+
.join("")}</details>`
|
|
3350
|
+
: "";
|
|
3351
|
+
readingsFieldWithoutAudio = `${firstReadingWithoutAudio}${otherReadingsWithoutAudio}`;
|
|
3352
|
+
hasAudio = true;
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
const firstKanjiForm: string | undefined =
|
|
3356
|
+
entry.kanjiForms !== undefined
|
|
3357
|
+
? createEntry(
|
|
3358
|
+
`<span class="name name-kanjiform"><ruby><rb>${entry.kanjiForms[0]!.kanjiForm}</rb><rt>${entry.nameReadings[0]!.reading}</rt></ruby></span>`,
|
|
3359
|
+
entry.kanjiForms[0]!.notes,
|
|
3360
|
+
)
|
|
3361
|
+
: undefined;
|
|
3362
|
+
const otherKanjiForms: string =
|
|
3363
|
+
entry.kanjiForms !== undefined && entry.kanjiForms.length > 1
|
|
3364
|
+
? `<details><summary>Show other kanji forms</summary>${entry.kanjiForms
|
|
3365
|
+
.slice(1)
|
|
3366
|
+
.map((kanjiFormEntry: KanjiForm) => {
|
|
3367
|
+
const restrictedReading: Reading | undefined =
|
|
3368
|
+
entry.nameReadings.find(
|
|
3369
|
+
(r: Reading) =>
|
|
3370
|
+
r.notes !== undefined &&
|
|
3371
|
+
r.notes.includes(
|
|
3372
|
+
`Reading restricted to ${kanjiFormEntry.kanjiForm}`,
|
|
3373
|
+
),
|
|
3374
|
+
);
|
|
3375
|
+
|
|
3376
|
+
return createEntry(
|
|
3377
|
+
`<span class="name name-kanjiform">${restrictedReading !== undefined ? "<ruby><rb>" : ""}${kanjiFormEntry.kanjiForm}${restrictedReading !== undefined ? `</rb><rt>${restrictedReading.reading}</rt></ruby>` : ""}</span>`,
|
|
3378
|
+
kanjiFormEntry.notes,
|
|
3379
|
+
);
|
|
3380
|
+
})
|
|
3381
|
+
.join("")}</details>`
|
|
3382
|
+
: "";
|
|
3383
|
+
|
|
3384
|
+
const kanjiFormsField: string =
|
|
3385
|
+
firstKanjiForm !== undefined
|
|
3386
|
+
? `${firstKanjiForm}${otherKanjiForms}`
|
|
3387
|
+
: '<span class="name name-kanjiform" id="no-kanjiforms">(no kanji forms)</span>';
|
|
3388
|
+
|
|
3389
|
+
const firstThreeTranslations: string = entry.translations
|
|
3390
|
+
.slice(0, 3)
|
|
3391
|
+
.map((translationEntry: Translation) =>
|
|
3392
|
+
createEntry(
|
|
3393
|
+
`<span class="name name-translation">${translationEntry.translation}</span>`,
|
|
3394
|
+
translationEntry.notes,
|
|
3395
|
+
),
|
|
3396
|
+
)
|
|
3397
|
+
.join("");
|
|
3398
|
+
|
|
3399
|
+
const otherTranslations: string =
|
|
3400
|
+
entry.translations.length > 3
|
|
3401
|
+
? `<details><summary>Show other translations</summary>${entry.translations
|
|
3402
|
+
.map((translationEntry: Translation, index: number) => {
|
|
3403
|
+
if (index < 3) return "null";
|
|
3404
|
+
|
|
3405
|
+
return createEntry(
|
|
3406
|
+
`<span class="name name-translation">${translationEntry.translation}</span>`,
|
|
3407
|
+
translationEntry.notes,
|
|
3408
|
+
);
|
|
3409
|
+
})
|
|
3410
|
+
.filter((translation: string) => translation !== "null")
|
|
3411
|
+
.join("")}</details>`
|
|
3412
|
+
: "";
|
|
3413
|
+
|
|
3414
|
+
const translationsField: string = `${firstThreeTranslations}${otherTranslations}`;
|
|
3415
|
+
|
|
3416
|
+
const phrasesField: string | undefined =
|
|
3417
|
+
entry.phrases !== undefined
|
|
3418
|
+
? entry.phrases
|
|
3419
|
+
.map((phraseEntry: Phrase) =>
|
|
3420
|
+
createEntry(
|
|
3421
|
+
`<span class="name name-phrase"><span class="name name-phrase-original">${phraseEntry.originalPhrase}</span><span class="name name-phrase-furigana">${phraseEntry.phrase}</span></span>`,
|
|
3422
|
+
[phraseEntry.translation],
|
|
3423
|
+
true,
|
|
3424
|
+
),
|
|
3425
|
+
)
|
|
3426
|
+
.join("")
|
|
3427
|
+
: '<span class="name name-phrase" id="no-phrases">(no phrases)</span>';
|
|
3428
|
+
|
|
3429
|
+
const searchField: string = `${entry.nameReadings.map((r: Reading) => r.reading).join(" ")}${entry.kanjiForms !== undefined ? ` ${entry.kanjiForms.map((kf: KanjiForm) => kf.kanjiForm).join(" ")}` : ""} ${entry.id}`;
|
|
3430
|
+
|
|
3431
|
+
fields.push(
|
|
3432
|
+
...(entry.kanjiForms !== undefined
|
|
3433
|
+
? [
|
|
3434
|
+
`${customData !== undefined ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${kanjiFormsField}<div id="kf-pos" style="display: none" data-pos="1"></div>`,
|
|
3435
|
+
`${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="2"></div>`,
|
|
3436
|
+
]
|
|
3437
|
+
: [
|
|
3438
|
+
`${customData !== undefined ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${kanjiFormsField}<div id="kf-pos" style="display: none" data-pos="2"></div>`,
|
|
3439
|
+
`${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="1"></div>`,
|
|
3440
|
+
]),
|
|
3441
|
+
`${hasAudio ? readingsField : readingsFieldWithoutAudio}<div id="r-pos" style="display: none" data-pos="${entry.kanjiForms !== undefined ? "2" : "1"}"></div>`,
|
|
3442
|
+
translationsField,
|
|
3443
|
+
phrasesField,
|
|
3444
|
+
entry.kanji !== undefined
|
|
3445
|
+
? entry.kanji
|
|
3446
|
+
.map((kanjiEntry: Kanji) =>
|
|
3447
|
+
createEntry(
|
|
3448
|
+
`<span class="name name-kanji">${kanjiEntry.kanji}${kanjiEntry.meanings === undefined ? " (no meanings)" : ""}</span>`,
|
|
3449
|
+
kanjiEntry.meanings,
|
|
3450
|
+
),
|
|
3451
|
+
)
|
|
3452
|
+
.join("")
|
|
3453
|
+
: '<span class="name name-kanji" id="no-kanji">(no kanji)</span>',
|
|
3454
|
+
searchField,
|
|
3455
|
+
);
|
|
3456
|
+
}
|
|
3457
|
+
|
|
2887
3458
|
if (isRadical(entry))
|
|
2888
3459
|
fields.push(
|
|
2889
3460
|
`${customData !== undefined ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${createEntry(
|