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.
- package/dist/index.cjs.js +467 -50
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.mjs +464 -50
- 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 +815 -108
- 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
|
|
|
@@ -461,6 +464,135 @@ export function convertJMdict(
|
|
|
461
464
|
return dict;
|
|
462
465
|
}
|
|
463
466
|
|
|
467
|
+
/**
|
|
468
|
+
* Converts a JMnedict `JMnedict.xml` file into an array of {@link DictWord} objects.
|
|
469
|
+
* @param xmlString The raw `JMnedict.xml` file contents
|
|
470
|
+
* @param examples An array of converted `Tanaka Corpus` examples
|
|
471
|
+
* @returns An array of converted {@link DictWord} objects
|
|
472
|
+
*/
|
|
473
|
+
export function convertJMnedict(
|
|
474
|
+
xmlString: string,
|
|
475
|
+
examples?: readonly TanakaExample[],
|
|
476
|
+
): DictName[] {
|
|
477
|
+
const dictParsed: libxml.Document = libxml.parseXml(xmlString, {
|
|
478
|
+
dtdvalid: true,
|
|
479
|
+
nonet: false,
|
|
480
|
+
noent: true,
|
|
481
|
+
recover: false,
|
|
482
|
+
});
|
|
483
|
+
const dict: DictName[] = [];
|
|
484
|
+
|
|
485
|
+
xml.parseString(dictParsed, (_err: Error | null, result: any) => {
|
|
486
|
+
const tanakaParts: Set<string> | undefined =
|
|
487
|
+
examples !== undefined && examples.length > 0
|
|
488
|
+
? new Set<string>(
|
|
489
|
+
examples.flatMap((example: TanakaExample) =>
|
|
490
|
+
example.parts.flatMap((part: ExamplePart) => [
|
|
491
|
+
part.baseForm,
|
|
492
|
+
...(part.reading !== undefined ? [part.reading] : []),
|
|
493
|
+
...(part.inflectedForm !== undefined
|
|
494
|
+
? [part.inflectedForm]
|
|
495
|
+
: []),
|
|
496
|
+
...(part.referenceID !== undefined ? [part.referenceID] : []),
|
|
497
|
+
]),
|
|
498
|
+
),
|
|
499
|
+
)
|
|
500
|
+
: undefined;
|
|
501
|
+
|
|
502
|
+
for (const entry of result.JMnedict.entry) {
|
|
503
|
+
const entryObj: DictName = {
|
|
504
|
+
id: entry.ent_seq[0],
|
|
505
|
+
nameReadings: [],
|
|
506
|
+
meanings: [],
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const kanjiForms: any = entry.k_ele;
|
|
510
|
+
const readings: any = entry.r_ele;
|
|
511
|
+
const translations: any = entry.trans;
|
|
512
|
+
|
|
513
|
+
if (isObjectArray(kanjiForms)) {
|
|
514
|
+
entryObj.kanjiForms = [];
|
|
515
|
+
|
|
516
|
+
for (const kanjiForm of kanjiForms)
|
|
517
|
+
entryObj.kanjiForms.push({ form: kanjiForm.keb[0] });
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
for (const reading of readings) {
|
|
521
|
+
const readingObj: DictReading = {
|
|
522
|
+
reading: reading.reb[0],
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
if (isStringArray(reading.re_restr))
|
|
526
|
+
readingObj.kanjiFormRestrictions = reading.re_restr;
|
|
527
|
+
|
|
528
|
+
if (isStringArray(reading.re_pri)) {
|
|
529
|
+
readingObj.commonness = reading.re_pri;
|
|
530
|
+
|
|
531
|
+
entryObj.isCommon = true;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
entryObj.nameReadings.push(readingObj);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
for (const trans of translations)
|
|
538
|
+
entryObj.meanings.push({
|
|
539
|
+
translations: trans.trans_det,
|
|
540
|
+
...(isStringArray(trans.name_type)
|
|
541
|
+
? { nameTypes: trans.name_type }
|
|
542
|
+
: {}),
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
if (examples !== undefined) {
|
|
546
|
+
let existsExample: boolean = false;
|
|
547
|
+
|
|
548
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
549
|
+
entryObj.nameReadings,
|
|
550
|
+
entryObj.kanjiForms,
|
|
551
|
+
entryObj.isCommon,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
const validReadings: Set<string> = new Set<string>(
|
|
555
|
+
rkf.readings.map((r: DictReading) => r.reading),
|
|
556
|
+
);
|
|
557
|
+
const validKanjiForms: Set<string> | undefined =
|
|
558
|
+
rkf.kanjiForms !== undefined
|
|
559
|
+
? new Set<string>(
|
|
560
|
+
rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form),
|
|
561
|
+
)
|
|
562
|
+
: undefined;
|
|
563
|
+
|
|
564
|
+
if (
|
|
565
|
+
validKanjiForms !== undefined &&
|
|
566
|
+
validKanjiForms.size > 0 &&
|
|
567
|
+
tanakaParts !== undefined
|
|
568
|
+
)
|
|
569
|
+
for (const kf of validKanjiForms)
|
|
570
|
+
if (tanakaParts.has(kf)) {
|
|
571
|
+
existsExample = true;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (
|
|
576
|
+
entryObj.kanjiForms === undefined &&
|
|
577
|
+
validReadings.size > 0 &&
|
|
578
|
+
tanakaParts !== undefined
|
|
579
|
+
)
|
|
580
|
+
for (const r of validReadings)
|
|
581
|
+
if (tanakaParts.has(r)) {
|
|
582
|
+
existsExample = true;
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (existsExample) entryObj.hasPhrases = true;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
dict.push(entryObj);
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
return dict;
|
|
594
|
+
}
|
|
595
|
+
|
|
464
596
|
/**
|
|
465
597
|
* Converts a KANJIDIC `kanjidic2.xml` file into an array of {@link DictKanji} objects.
|
|
466
598
|
* @param xmlString The raw `kanjidic2.xml` file contents
|
|
@@ -805,13 +937,16 @@ export function convertKradFile(
|
|
|
805
937
|
*
|
|
806
938
|
* - {@link jmDict} => {@link WordIDEntryMap}, {@link KanjiWordsMap}
|
|
807
939
|
*
|
|
940
|
+
* - {@link jmNedict} => {@link NameIDEntryMap}
|
|
941
|
+
*
|
|
808
942
|
* - {@link kanjiDic} => {@link KanjiEntryMap}, {@link KanjiSVGMap} (only if {@link svgList} is present)
|
|
809
943
|
*
|
|
810
|
-
* - {@link tanakaExamples} (requires {@link jmDict}
|
|
944
|
+
* - {@link tanakaExamples} => {@link EntryExamplesMap} (requires {@link jmDict} or/and {@link jmNedict})
|
|
811
945
|
*
|
|
812
946
|
* - {@link wordDefinitionPairs} => {@link WordDefinitionsMap}
|
|
813
947
|
*
|
|
814
948
|
* @param jmDict An array of converted `JMdict` entries
|
|
949
|
+
* @param jmNedict
|
|
815
950
|
* @param kanjiDic An array of converted `KANJIDIC` entries
|
|
816
951
|
* @param tanakaExamples An array of converted `Tanaka Corpus` examples
|
|
817
952
|
* @param wordDefinitionPairs An array of `ja.wiktionary.org` word-definitions pairs
|
|
@@ -820,6 +955,7 @@ export function convertKradFile(
|
|
|
820
955
|
*/
|
|
821
956
|
export function createEntryMaps(
|
|
822
957
|
jmDict?: readonly DictWord[],
|
|
958
|
+
jmNedict?: readonly DictName[],
|
|
823
959
|
kanjiDic?: readonly DictKanji[],
|
|
824
960
|
tanakaExamples?: readonly TanakaExample[],
|
|
825
961
|
wordDefinitionPairs?: readonly WordDefinitionPair[],
|
|
@@ -827,8 +963,13 @@ export function createEntryMaps(
|
|
|
827
963
|
): EntryMaps {
|
|
828
964
|
const kanjiEntryMap: KanjiEntryMap = new Map<string, DictKanji>();
|
|
829
965
|
const wordIDEntryMap: WordIDEntryMap = new Map<StringNumber, DictWord>();
|
|
966
|
+
const nameIDEntryMap: NameIDEntryMap = new Map<StringNumber, DictName>();
|
|
830
967
|
const kanjiWordsMap: KanjiWordsMap = new Map<string, DictWord[]>();
|
|
831
|
-
const wordExamplesMap:
|
|
968
|
+
const wordExamplesMap: EntryExamplesMap = new Map<
|
|
969
|
+
StringNumber,
|
|
970
|
+
TanakaExample[]
|
|
971
|
+
>();
|
|
972
|
+
const nameExamplesMap: EntryExamplesMap = new Map<
|
|
832
973
|
StringNumber,
|
|
833
974
|
TanakaExample[]
|
|
834
975
|
>();
|
|
@@ -838,16 +979,6 @@ export function createEntryMaps(
|
|
|
838
979
|
>();
|
|
839
980
|
const kanjiSVGMap: KanjiSVGMap = new Map<string, string>();
|
|
840
981
|
|
|
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
982
|
if (kanjiDic !== undefined)
|
|
852
983
|
for (const kanji of kanjiDic) kanjiEntryMap.set(kanji.kanji, kanji);
|
|
853
984
|
|
|
@@ -872,6 +1003,16 @@ export function createEntryMaps(
|
|
|
872
1003
|
}
|
|
873
1004
|
|
|
874
1005
|
if (jmDict !== undefined) {
|
|
1006
|
+
const wordPartsMap: Map<StringNumber, Set<string>> = new Map<
|
|
1007
|
+
StringNumber,
|
|
1008
|
+
Set<string>
|
|
1009
|
+
>();
|
|
1010
|
+
const partExamplesMap: Map<string, TanakaExample[]> = new Map<
|
|
1011
|
+
string,
|
|
1012
|
+
TanakaExample[]
|
|
1013
|
+
>();
|
|
1014
|
+
const entryParts: Set<string> = new Set<string>();
|
|
1015
|
+
|
|
875
1016
|
for (const word of jmDict) {
|
|
876
1017
|
wordIDEntryMap.set(word.id, word);
|
|
877
1018
|
|
|
@@ -978,11 +1119,109 @@ export function createEntryMaps(
|
|
|
978
1119
|
}
|
|
979
1120
|
}
|
|
980
1121
|
|
|
1122
|
+
if (jmNedict !== undefined) {
|
|
1123
|
+
const namePartsMap: Map<StringNumber, Set<string>> = new Map<
|
|
1124
|
+
StringNumber,
|
|
1125
|
+
Set<string>
|
|
1126
|
+
>();
|
|
1127
|
+
const partExamplesMap: Map<string, TanakaExample[]> = new Map<
|
|
1128
|
+
string,
|
|
1129
|
+
TanakaExample[]
|
|
1130
|
+
>();
|
|
1131
|
+
const entryParts: Set<string> = new Set<string>();
|
|
1132
|
+
|
|
1133
|
+
for (const name of jmNedict) {
|
|
1134
|
+
nameIDEntryMap.set(name.id, name);
|
|
1135
|
+
|
|
1136
|
+
if (tanakaExamples !== undefined) {
|
|
1137
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
1138
|
+
name.nameReadings,
|
|
1139
|
+
name.kanjiForms,
|
|
1140
|
+
name.isCommon,
|
|
1141
|
+
);
|
|
1142
|
+
|
|
1143
|
+
const localPartParts: Set<string> = new Set<string>();
|
|
1144
|
+
|
|
1145
|
+
for (const reading of rkf.readings) {
|
|
1146
|
+
entryParts.add(reading.reading);
|
|
1147
|
+
localPartParts.add(reading.reading);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
if (rkf.kanjiForms !== undefined && rkf.kanjiForms.length > 0)
|
|
1151
|
+
for (const kanjiForm of rkf.kanjiForms) {
|
|
1152
|
+
entryParts.add(kanjiForm.form);
|
|
1153
|
+
localPartParts.add(kanjiForm.form);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
entryParts.add(name.id);
|
|
1157
|
+
localPartParts.add(name.id);
|
|
1158
|
+
|
|
1159
|
+
namePartsMap.set(name.id, localPartParts);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (tanakaExamples !== undefined) {
|
|
1164
|
+
for (const ex of tanakaExamples)
|
|
1165
|
+
for (const part of ex.parts) {
|
|
1166
|
+
if (entryParts.has(part.baseForm)) {
|
|
1167
|
+
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
1168
|
+
part.baseForm,
|
|
1169
|
+
);
|
|
1170
|
+
|
|
1171
|
+
if (exList === undefined) partExamplesMap.set(part.baseForm, [ex]);
|
|
1172
|
+
else exList.push(ex);
|
|
1173
|
+
}
|
|
1174
|
+
if (part.reading !== undefined && entryParts.has(part.reading)) {
|
|
1175
|
+
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
1176
|
+
part.reading,
|
|
1177
|
+
);
|
|
1178
|
+
|
|
1179
|
+
if (exList === undefined) partExamplesMap.set(part.reading, [ex]);
|
|
1180
|
+
else exList.push(ex);
|
|
1181
|
+
}
|
|
1182
|
+
if (
|
|
1183
|
+
part.inflectedForm !== undefined &&
|
|
1184
|
+
entryParts.has(part.inflectedForm)
|
|
1185
|
+
) {
|
|
1186
|
+
const exList: TanakaExample[] | undefined = partExamplesMap.get(
|
|
1187
|
+
part.inflectedForm,
|
|
1188
|
+
);
|
|
1189
|
+
|
|
1190
|
+
if (exList === undefined)
|
|
1191
|
+
partExamplesMap.set(part.inflectedForm, [ex]);
|
|
1192
|
+
else exList.push(ex);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
for (const name of jmNedict) {
|
|
1197
|
+
const seenEx: Set<string> = new Set<string>();
|
|
1198
|
+
const validExamples: TanakaExample[] = [];
|
|
1199
|
+
|
|
1200
|
+
for (const p of namePartsMap.get(name.id)!) {
|
|
1201
|
+
const examplesForPart: TanakaExample[] | undefined = partExamplesMap
|
|
1202
|
+
.get(p)
|
|
1203
|
+
?.filter((ex: TanakaExample) => !seenEx.has(ex.id));
|
|
1204
|
+
if (examplesForPart === undefined) continue;
|
|
1205
|
+
|
|
1206
|
+
for (const ex of examplesForPart) {
|
|
1207
|
+
seenEx.add(ex.id);
|
|
1208
|
+
validExamples.push(ex);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
if (validExamples.length > 0)
|
|
1213
|
+
nameExamplesMap.set(name.id, validExamples);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
981
1218
|
return {
|
|
982
1219
|
...(wordIDEntryMap.size > 0 ? { wordIDEntryMap: wordIDEntryMap } : {}),
|
|
1220
|
+
...(nameIDEntryMap.size > 0 ? { nameIDEntryMap: nameIDEntryMap } : {}),
|
|
983
1221
|
...(kanjiWordsMap.size > 0 ? { kanjiWordsMap: kanjiWordsMap } : {}),
|
|
984
1222
|
...(kanjiEntryMap.size > 0 ? { kanjiEntryMap: kanjiEntryMap } : {}),
|
|
985
1223
|
...(wordExamplesMap.size > 0 ? { wordExamplesMap: wordExamplesMap } : {}),
|
|
1224
|
+
...(nameExamplesMap.size > 0 ? { nameExamplesMap: nameExamplesMap } : {}),
|
|
986
1225
|
...(wordDefinitionsMap.size > 0
|
|
987
1226
|
? { wordDefinitionsMap: wordDefinitionsMap }
|
|
988
1227
|
: {}),
|
|
@@ -2039,7 +2278,7 @@ export function getKanjiExtended(
|
|
|
2039
2278
|
* @param searchedWord The ID of the `JMdict` entry (requires {@link dict}) or a {@link DictWord} object
|
|
2040
2279
|
* @param dict An array converted `JMdict` entries or a {@link WordIDEntryMap} *(not needed if {@link searchedWord} is a {@link DictWord} object)*
|
|
2041
2280
|
* @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
|
|
2281
|
+
* @param examples An array of converted `Tanaka Corpus` examples or a {@link EntryExamplesMap}
|
|
2043
2282
|
* @param definitions An array of `ja.wiktionary.org` word-definitions pairs or a {@link WordDefinitionsMap}
|
|
2044
2283
|
* @param noteTypeName The Anki note type name
|
|
2045
2284
|
* @param deckPath The full Anki deck path
|
|
@@ -2049,7 +2288,7 @@ export function getWord(
|
|
|
2049
2288
|
searchedWord: StringNumber | DictWord,
|
|
2050
2289
|
dict?: readonly DictWord[] | WordIDEntryMap,
|
|
2051
2290
|
kanjiDic?: readonly DictKanji[] | KanjiEntryMap,
|
|
2052
|
-
examples?: readonly TanakaExample[] |
|
|
2291
|
+
examples?: readonly TanakaExample[] | EntryExamplesMap,
|
|
2053
2292
|
definitions?: readonly WordDefinitionPair[] | WordDefinitionsMap,
|
|
2054
2293
|
noteTypeName?: string,
|
|
2055
2294
|
deckPath?: string,
|
|
@@ -2141,12 +2380,28 @@ export function getWord(
|
|
|
2141
2380
|
|
|
2142
2381
|
word.translations = [];
|
|
2143
2382
|
|
|
2383
|
+
const meanings: string[] | undefined =
|
|
2384
|
+
dictWord.hasPhrases === true && examples !== undefined ? [] : undefined;
|
|
2385
|
+
const seenPhrases: Set<string> = new Set<string>();
|
|
2386
|
+
|
|
2144
2387
|
for (const dictMeaning of dictWord.meanings) {
|
|
2145
2388
|
const translationTypes: string[] = [];
|
|
2146
2389
|
const translations: string[] = dictMeaning.translations.map(
|
|
2147
2390
|
(translation: string | { translation: string; type: string }) => {
|
|
2148
|
-
if (typeof translation === "string")
|
|
2149
|
-
|
|
2391
|
+
if (typeof translation === "string") {
|
|
2392
|
+
if (meanings !== undefined) {
|
|
2393
|
+
const cleanTranslation: string = translation
|
|
2394
|
+
.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "")
|
|
2395
|
+
.trim();
|
|
2396
|
+
|
|
2397
|
+
if (!seenPhrases.has(cleanTranslation)) {
|
|
2398
|
+
seenPhrases.add(cleanTranslation);
|
|
2399
|
+
meanings.push(cleanTranslation);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
return translation;
|
|
2404
|
+
} else {
|
|
2150
2405
|
const translationNoteAndTag:
|
|
2151
2406
|
| readonly [string, string]
|
|
2152
2407
|
| readonly [string, string, POS | readonly POS[]] = noteMap.get(
|
|
@@ -2156,6 +2411,17 @@ export function getWord(
|
|
|
2156
2411
|
translationTypes.push(translationNoteAndTag[1]);
|
|
2157
2412
|
word.tags!.push(`word::${translationNoteAndTag[0]}`);
|
|
2158
2413
|
|
|
2414
|
+
if (meanings !== undefined) {
|
|
2415
|
+
const cleanTranslation: string = translation.translation
|
|
2416
|
+
.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "")
|
|
2417
|
+
.trim();
|
|
2418
|
+
|
|
2419
|
+
if (!seenPhrases.has(cleanTranslation)) {
|
|
2420
|
+
seenPhrases.add(cleanTranslation);
|
|
2421
|
+
meanings.push(cleanTranslation);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2159
2425
|
return translation.translation;
|
|
2160
2426
|
}
|
|
2161
2427
|
},
|
|
@@ -2208,6 +2474,8 @@ export function getWord(
|
|
|
2208
2474
|
word.tags!.push("word::usually_in_kana_for_all_senses");
|
|
2209
2475
|
}
|
|
2210
2476
|
|
|
2477
|
+
seenPhrases.clear();
|
|
2478
|
+
|
|
2211
2479
|
if (kanjiDic !== undefined && word.kanjiForms !== undefined) {
|
|
2212
2480
|
const kanji: Kanji[] = [];
|
|
2213
2481
|
const seenChars: Set<string> = new Set<string>();
|
|
@@ -2240,9 +2508,9 @@ export function getWord(
|
|
|
2240
2508
|
if (kanji.length > 0) word.kanji = kanji;
|
|
2241
2509
|
}
|
|
2242
2510
|
|
|
2243
|
-
if (
|
|
2511
|
+
if (meanings !== undefined) {
|
|
2244
2512
|
const exampleList: readonly TanakaExample[] =
|
|
2245
|
-
examples instanceof Map ? (examples.get(dictWord.id) ?? []) : examples
|
|
2513
|
+
examples instanceof Map ? (examples.get(dictWord.id) ?? []) : examples!;
|
|
2246
2514
|
|
|
2247
2515
|
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
2248
2516
|
dictWord.readings,
|
|
@@ -2258,43 +2526,26 @@ export function getWord(
|
|
|
2258
2526
|
? new Set<string>(rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form))
|
|
2259
2527
|
: undefined;
|
|
2260
2528
|
|
|
2261
|
-
const
|
|
2262
|
-
dictWord.meanings.flatMap((m: DictMeaning) =>
|
|
2263
|
-
m.translations.map((t: DictTranslation) => {
|
|
2264
|
-
if (typeof t === "string")
|
|
2265
|
-
return t.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "").trim();
|
|
2266
|
-
else
|
|
2267
|
-
return t.translation
|
|
2268
|
-
.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "")
|
|
2269
|
-
.trim();
|
|
2270
|
-
}),
|
|
2271
|
-
),
|
|
2272
|
-
)
|
|
2273
|
-
.values()
|
|
2274
|
-
.toArray();
|
|
2275
|
-
|
|
2276
|
-
let kanjiFormExamples: {
|
|
2529
|
+
const readingMatchingKanjiFormExamples: {
|
|
2277
2530
|
ex: TanakaExample;
|
|
2278
2531
|
partIndex: number;
|
|
2279
2532
|
form: string;
|
|
2533
|
+
referenceIDMatch?: true | undefined;
|
|
2280
2534
|
includesTranslation?: true | undefined;
|
|
2281
2535
|
}[] = [];
|
|
2282
|
-
let
|
|
2536
|
+
let kanjiFormExamples: {
|
|
2283
2537
|
ex: TanakaExample;
|
|
2284
2538
|
partIndex: number;
|
|
2285
2539
|
form: string;
|
|
2286
2540
|
includesTranslation?: true | undefined;
|
|
2287
2541
|
}[] = [];
|
|
2542
|
+
|
|
2288
2543
|
let readingExamples: {
|
|
2289
2544
|
ex: TanakaExample;
|
|
2290
2545
|
partIndex: number;
|
|
2291
2546
|
referenceIDMatch?: true | undefined;
|
|
2292
2547
|
includesTranslation?: true | undefined;
|
|
2293
2548
|
}[] = [];
|
|
2294
|
-
let readingMatchingKanjiForms: Set<string> = new Set<string>();
|
|
2295
|
-
const readingMatchingKanjiFormsWithTranslations: Set<string> =
|
|
2296
|
-
new Set<string>();
|
|
2297
|
-
const seenPhrases: Set<string> = new Set<string>();
|
|
2298
2549
|
|
|
2299
2550
|
for (const example of exampleList)
|
|
2300
2551
|
for (let i: number = 0; i < example.parts.length; i++) {
|
|
@@ -2319,18 +2570,15 @@ export function getWord(
|
|
|
2319
2570
|
readingAsReadingMatch ||
|
|
2320
2571
|
readingAsInflectedFormMatch ||
|
|
2321
2572
|
referenceIDMatch
|
|
2322
|
-
)
|
|
2573
|
+
)
|
|
2323
2574
|
readingMatchingKanjiFormExamples.push({
|
|
2324
2575
|
ex: example,
|
|
2325
2576
|
partIndex: i,
|
|
2326
2577
|
form: part.baseForm,
|
|
2578
|
+
...(referenceIDMatch ? { referenceIDMatch: true } : {}),
|
|
2327
2579
|
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2328
2580
|
});
|
|
2329
|
-
|
|
2330
|
-
readingMatchingKanjiForms.add(part.baseForm);
|
|
2331
|
-
if (includesTranslation)
|
|
2332
|
-
readingMatchingKanjiFormsWithTranslations.add(part.baseForm);
|
|
2333
|
-
} else
|
|
2581
|
+
else
|
|
2334
2582
|
kanjiFormExamples.push({
|
|
2335
2583
|
ex: example,
|
|
2336
2584
|
partIndex: i,
|
|
@@ -2353,9 +2601,7 @@ export function getWord(
|
|
|
2353
2601
|
ex: example,
|
|
2354
2602
|
partIndex: i,
|
|
2355
2603
|
...(referenceIDMatch ? { referenceIDMatch: true } : {}),
|
|
2356
|
-
...(
|
|
2357
|
-
? { includesTranslation: true }
|
|
2358
|
-
: {}),
|
|
2604
|
+
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
2359
2605
|
});
|
|
2360
2606
|
|
|
2361
2607
|
seenPhrases.add(example.phrase);
|
|
@@ -2364,36 +2610,22 @@ export function getWord(
|
|
|
2364
2610
|
}
|
|
2365
2611
|
}
|
|
2366
2612
|
|
|
2367
|
-
if (
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
),
|
|
2384
|
-
);
|
|
2385
|
-
}
|
|
2386
|
-
|
|
2387
|
-
const hasKfExamplesWithTranslation: boolean = kanjiFormExamples.some(
|
|
2388
|
-
(ex: {
|
|
2389
|
-
ex: TanakaExample;
|
|
2390
|
-
partIndex: number;
|
|
2391
|
-
form: string;
|
|
2392
|
-
includesTranslation?: true | undefined;
|
|
2393
|
-
}) => ex.includesTranslation === true,
|
|
2394
|
-
);
|
|
2395
|
-
|
|
2396
|
-
if (kanjiFormExamples.length > 0 && readingMatchingKanjiForms.size > 0)
|
|
2613
|
+
if (
|
|
2614
|
+
kanjiFormExamples.length > 0 &&
|
|
2615
|
+
kanjiFormExamples.some(
|
|
2616
|
+
(ex: {
|
|
2617
|
+
ex: TanakaExample;
|
|
2618
|
+
partIndex: number;
|
|
2619
|
+
form: string;
|
|
2620
|
+
includesTranslation?: true | undefined;
|
|
2621
|
+
}) =>
|
|
2622
|
+
ex.includesTranslation === true ||
|
|
2623
|
+
ex.ex.parts.some(
|
|
2624
|
+
(part: ExamplePart) =>
|
|
2625
|
+
ex.form === part.baseForm && part.glossNumber !== undefined,
|
|
2626
|
+
),
|
|
2627
|
+
)
|
|
2628
|
+
)
|
|
2397
2629
|
kanjiFormExamples = kanjiFormExamples.filter(
|
|
2398
2630
|
(ex: {
|
|
2399
2631
|
ex: TanakaExample;
|
|
@@ -2401,15 +2633,17 @@ export function getWord(
|
|
|
2401
2633
|
form: string;
|
|
2402
2634
|
includesTranslation?: true | undefined;
|
|
2403
2635
|
}) =>
|
|
2404
|
-
|
|
2405
|
-
(
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
readingMatchingKanjiForms.has(part.baseForm) &&
|
|
2410
|
-
part.glossNumber !== undefined,
|
|
2411
|
-
)),
|
|
2636
|
+
ex.includesTranslation === true ||
|
|
2637
|
+
ex.ex.parts.some(
|
|
2638
|
+
(part: ExamplePart) =>
|
|
2639
|
+
ex.form === part.baseForm && part.glossNumber !== undefined,
|
|
2640
|
+
),
|
|
2412
2641
|
);
|
|
2642
|
+
else if (
|
|
2643
|
+
kanjiFormExamples.length > 0 &&
|
|
2644
|
+
readingMatchingKanjiFormExamples.length > 0
|
|
2645
|
+
)
|
|
2646
|
+
kanjiFormExamples.length = 0;
|
|
2413
2647
|
|
|
2414
2648
|
if (
|
|
2415
2649
|
readingExamples.length > 0 &&
|
|
@@ -2431,16 +2665,24 @@ export function getWord(
|
|
|
2431
2665
|
}) => ex.includesTranslation === true || ex.referenceIDMatch === true,
|
|
2432
2666
|
);
|
|
2433
2667
|
|
|
2434
|
-
let wordExamples:
|
|
2668
|
+
let wordExamples: (
|
|
2669
|
+
| {
|
|
2670
|
+
ex: TanakaExample;
|
|
2671
|
+
partIndex: number;
|
|
2672
|
+
form: string;
|
|
2673
|
+
includesTranslation?: true | undefined;
|
|
2674
|
+
}
|
|
2675
|
+
| {
|
|
2676
|
+
ex: TanakaExample;
|
|
2677
|
+
partIndex: number;
|
|
2678
|
+
referenceIDMatch?: true | undefined;
|
|
2679
|
+
includesTranslation?: true | undefined;
|
|
2680
|
+
}
|
|
2681
|
+
)[] = [
|
|
2435
2682
|
...(word.kanjiForms !== undefined
|
|
2436
2683
|
? [...readingMatchingKanjiFormExamples, ...kanjiFormExamples]
|
|
2437
2684
|
: readingExamples),
|
|
2438
|
-
]
|
|
2439
|
-
(
|
|
2440
|
-
a: { ex: TanakaExample; partIndex: number },
|
|
2441
|
-
b: { ex: TanakaExample; partIndex: number },
|
|
2442
|
-
) => a.ex.phrase.length - b.ex.phrase.length,
|
|
2443
|
-
);
|
|
2685
|
+
];
|
|
2444
2686
|
|
|
2445
2687
|
seenPhrases.clear();
|
|
2446
2688
|
|
|
@@ -2473,8 +2715,21 @@ export function getWord(
|
|
|
2473
2715
|
if (glossSpecificExamples.length > 0) {
|
|
2474
2716
|
if (glossSpecificExamples.length < 5) {
|
|
2475
2717
|
wordExamples = wordExamples.filter(
|
|
2476
|
-
(
|
|
2477
|
-
|
|
2718
|
+
(
|
|
2719
|
+
ex:
|
|
2720
|
+
| {
|
|
2721
|
+
ex: TanakaExample;
|
|
2722
|
+
partIndex: number;
|
|
2723
|
+
form: string;
|
|
2724
|
+
includesTranslation?: true | undefined;
|
|
2725
|
+
}
|
|
2726
|
+
| {
|
|
2727
|
+
ex: TanakaExample;
|
|
2728
|
+
partIndex: number;
|
|
2729
|
+
referenceIDMatch?: true | undefined;
|
|
2730
|
+
includesTranslation?: true | undefined;
|
|
2731
|
+
},
|
|
2732
|
+
) => !seenPhrases.has(ex.ex.phrase),
|
|
2478
2733
|
);
|
|
2479
2734
|
|
|
2480
2735
|
if (wordExamples.length > 0)
|
|
@@ -2493,14 +2748,30 @@ export function getWord(
|
|
|
2493
2748
|
glossSpecificExamples.length === 0
|
|
2494
2749
|
? wordExamples.slice(0, 5)
|
|
2495
2750
|
: wordExamples
|
|
2496
|
-
).map(
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2751
|
+
).map(
|
|
2752
|
+
(
|
|
2753
|
+
ex:
|
|
2754
|
+
| {
|
|
2755
|
+
ex: TanakaExample;
|
|
2756
|
+
partIndex: number;
|
|
2757
|
+
form: string;
|
|
2758
|
+
includesTranslation?: true | undefined;
|
|
2759
|
+
}
|
|
2760
|
+
| {
|
|
2761
|
+
ex: TanakaExample;
|
|
2762
|
+
partIndex: number;
|
|
2763
|
+
referenceIDMatch?: true | undefined;
|
|
2764
|
+
includesTranslation?: true | undefined;
|
|
2765
|
+
},
|
|
2766
|
+
) => ({
|
|
2767
|
+
phrase: ex.ex.furigana ?? ex.ex.phrase,
|
|
2768
|
+
translation: ex.ex.translation,
|
|
2769
|
+
originalPhrase: ex.ex.phrase,
|
|
2770
|
+
...(ex.ex.glossNumber !== undefined
|
|
2771
|
+
? { glossNumber: ex.ex.glossNumber }
|
|
2772
|
+
: {}),
|
|
2773
|
+
}),
|
|
2774
|
+
);
|
|
2504
2775
|
|
|
2505
2776
|
word.tags!.push("word::has_phrases");
|
|
2506
2777
|
if (glossSpecificExamples.length > 0)
|
|
@@ -2529,9 +2800,298 @@ export function getWord(
|
|
|
2529
2800
|
} else return undefined;
|
|
2530
2801
|
}
|
|
2531
2802
|
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2803
|
+
/**
|
|
2804
|
+
* Transforms a converted `JMnedict` entry into a more readable format, by providing either its JMnedict entry ID or the {@link DictName} object directly.
|
|
2805
|
+
* @param searchedName The ID of the `JMnedict` entry (requires {@link dict}) or a {@link DictName} object
|
|
2806
|
+
* @param dict An array converted `JMnedict` entries or a {@link NameIDEntryMap} *(not needed if {@link searchedName} is a {@link DictName} object)*
|
|
2807
|
+
* @param kanjiDic An array of converted `KANJIDIC` entries or a {@link KanjiEntryMap}
|
|
2808
|
+
* @param examples An array of converted `Tanaka Corpus` examples or a {@link EntryExamplesMap}
|
|
2809
|
+
* @param noteTypeName The Anki note type name
|
|
2810
|
+
* @param deckPath The full Anki deck path
|
|
2811
|
+
* @returns The transformed {@link DictName} object or `undefined` if entry is not found
|
|
2812
|
+
*/
|
|
2813
|
+
export function getName(
|
|
2814
|
+
searchedName: StringNumber | DictName,
|
|
2815
|
+
dict?: readonly DictName[] | NameIDEntryMap,
|
|
2816
|
+
kanjiDic?: readonly DictKanji[] | KanjiEntryMap,
|
|
2817
|
+
examples?: readonly TanakaExample[] | EntryExamplesMap,
|
|
2818
|
+
noteTypeName?: string,
|
|
2819
|
+
deckPath?: string,
|
|
2820
|
+
): Name | undefined {
|
|
2821
|
+
let dictName: DictName | undefined = undefined;
|
|
2822
|
+
|
|
2823
|
+
if (typeof searchedName === "string" && dict !== undefined) {
|
|
2824
|
+
if (Array.isArray(dict))
|
|
2825
|
+
dictName = (dict as readonly DictName[]).find(
|
|
2826
|
+
(entry: DictName) => entry.id === searchedName,
|
|
2827
|
+
);
|
|
2828
|
+
|
|
2829
|
+
if (dict instanceof Map) dictName = dict.get(searchedName);
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
if (typeof searchedName === "object") dictName = searchedName;
|
|
2833
|
+
|
|
2834
|
+
if (dictName !== undefined) {
|
|
2835
|
+
const name: Name = {
|
|
2836
|
+
id: dictName.id,
|
|
2837
|
+
nameReadings: [],
|
|
2838
|
+
translations: [],
|
|
2839
|
+
noteID: `name_${dictName.id}`,
|
|
2840
|
+
noteTypeName: noteTypeName,
|
|
2841
|
+
deckPath: deckPath,
|
|
2842
|
+
tags: [],
|
|
2843
|
+
};
|
|
2844
|
+
|
|
2845
|
+
if (dictName.isCommon === true) {
|
|
2846
|
+
name.common = true;
|
|
2847
|
+
name.tags!.push("name::common");
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
if (dictName.kanjiForms !== undefined)
|
|
2851
|
+
name.kanjiForms = dictName.kanjiForms.map(
|
|
2852
|
+
(dictKanjiForm: DictKanjiForm) => ({
|
|
2853
|
+
kanjiForm: dictKanjiForm.form,
|
|
2854
|
+
}),
|
|
2855
|
+
);
|
|
2856
|
+
|
|
2857
|
+
name.nameReadings = dictName.nameReadings.map(
|
|
2858
|
+
(dictReading: DictReading) => ({
|
|
2859
|
+
reading: dictReading.reading,
|
|
2860
|
+
...(dictReading.kanjiFormRestrictions !== undefined
|
|
2861
|
+
? {
|
|
2862
|
+
notes: dictReading.kanjiFormRestrictions.map(
|
|
2863
|
+
(restriction: string) => `Reading restricted to ${restriction}`,
|
|
2864
|
+
),
|
|
2865
|
+
}
|
|
2866
|
+
: {}),
|
|
2867
|
+
...(dictReading.commonness !== undefined &&
|
|
2868
|
+
dictReading.commonness.length > 0
|
|
2869
|
+
? { common: true }
|
|
2870
|
+
: {}),
|
|
2871
|
+
}),
|
|
2872
|
+
);
|
|
2873
|
+
|
|
2874
|
+
name.translations = [];
|
|
2875
|
+
|
|
2876
|
+
const meanings: string[] | undefined =
|
|
2877
|
+
dictName.hasPhrases === true && examples !== undefined ? [] : undefined;
|
|
2878
|
+
const seenPhrases: Set<string> = new Set<string>();
|
|
2879
|
+
let hasNameTypes: boolean = false;
|
|
2880
|
+
|
|
2881
|
+
for (const dictMeaning of dictName.meanings) {
|
|
2882
|
+
if (!hasNameTypes && dictMeaning.nameTypes !== undefined)
|
|
2883
|
+
hasNameTypes = true;
|
|
2884
|
+
|
|
2885
|
+
name.translations.push({
|
|
2886
|
+
translation: dictMeaning.translations
|
|
2887
|
+
.map((translation: string) => {
|
|
2888
|
+
if (meanings !== undefined) {
|
|
2889
|
+
const cleanTranslation: string = translation
|
|
2890
|
+
.replaceAll(/\([^)]*\)|\[[^\]]*\]|\{[^}]*\}/g, "")
|
|
2891
|
+
.trim();
|
|
2892
|
+
|
|
2893
|
+
if (!seenPhrases.has(cleanTranslation)) {
|
|
2894
|
+
seenPhrases.add(cleanTranslation);
|
|
2895
|
+
meanings.push(cleanTranslation);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
return translation;
|
|
2900
|
+
})
|
|
2901
|
+
.join("; "),
|
|
2902
|
+
...(dictMeaning.nameTypes !== undefined
|
|
2903
|
+
? {
|
|
2904
|
+
notes: dictMeaning.nameTypes.map((type: string) => {
|
|
2905
|
+
const noteAndTag: NoteAndTag = lookupWordNote(
|
|
2906
|
+
type,
|
|
2907
|
+
[],
|
|
2908
|
+
name.tags!,
|
|
2909
|
+
);
|
|
2910
|
+
|
|
2911
|
+
return capitalizeString(noteAndTag.note);
|
|
2912
|
+
}),
|
|
2913
|
+
}
|
|
2914
|
+
: {}),
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
if (!hasNameTypes) name.tags!.push("name::no_name_types");
|
|
2919
|
+
|
|
2920
|
+
seenPhrases.clear();
|
|
2921
|
+
|
|
2922
|
+
if (kanjiDic !== undefined && name.kanjiForms !== undefined) {
|
|
2923
|
+
const kanji: Kanji[] = [];
|
|
2924
|
+
const seenChars: Set<string> = new Set<string>();
|
|
2925
|
+
|
|
2926
|
+
for (const kanjiForm of name.kanjiForms)
|
|
2927
|
+
for (const char of kanjiForm.kanjiForm
|
|
2928
|
+
.split("")
|
|
2929
|
+
.filter((c: string) => regexps.kanji.test(c))) {
|
|
2930
|
+
if (seenChars.has(char)) continue;
|
|
2931
|
+
seenChars.add(char);
|
|
2932
|
+
|
|
2933
|
+
const kanjiEntry: DictKanji | undefined =
|
|
2934
|
+
kanjiDic instanceof Map ? kanjiDic.get(char) : undefined;
|
|
2935
|
+
|
|
2936
|
+
const kanjiObj: Kanji | undefined = getKanji(
|
|
2937
|
+
kanjiEntry ?? char,
|
|
2938
|
+
!(kanjiDic instanceof Map) ? kanjiDic : undefined,
|
|
2939
|
+
);
|
|
2940
|
+
|
|
2941
|
+
if (kanjiObj !== undefined)
|
|
2942
|
+
kanji.push({
|
|
2943
|
+
kanji: kanjiObj.kanji,
|
|
2944
|
+
...(kanjiObj.meanings !== undefined &&
|
|
2945
|
+
kanjiObj.meanings.length > 0
|
|
2946
|
+
? { meanings: kanjiObj.meanings }
|
|
2947
|
+
: {}),
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
if (kanji.length > 0) name.kanji = kanji;
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
if (meanings !== undefined) {
|
|
2955
|
+
const exampleList: readonly TanakaExample[] =
|
|
2956
|
+
examples instanceof Map ? (examples.get(dictName.id) ?? []) : examples!;
|
|
2957
|
+
|
|
2958
|
+
const rkf: ReadingsKanjiFormsPair = getValidForms(
|
|
2959
|
+
dictName.nameReadings,
|
|
2960
|
+
dictName.kanjiForms,
|
|
2961
|
+
dictName.isCommon,
|
|
2962
|
+
);
|
|
2963
|
+
|
|
2964
|
+
const readings: Set<string> = new Set<string>(
|
|
2965
|
+
rkf.readings.map((r: DictReading) => r.reading),
|
|
2966
|
+
);
|
|
2967
|
+
const kanjiForms: Set<string> | undefined =
|
|
2968
|
+
rkf.kanjiForms !== undefined
|
|
2969
|
+
? new Set<string>(rkf.kanjiForms.map((kf: DictKanjiForm) => kf.form))
|
|
2970
|
+
: undefined;
|
|
2971
|
+
|
|
2972
|
+
let readingMatchingKanjiFormExamples: {
|
|
2973
|
+
ex: TanakaExample;
|
|
2974
|
+
includesTranslation?: true | undefined;
|
|
2975
|
+
}[] = [];
|
|
2976
|
+
|
|
2977
|
+
let readingExamples: {
|
|
2978
|
+
ex: TanakaExample;
|
|
2979
|
+
includesTranslation?: true | undefined;
|
|
2980
|
+
}[] = [];
|
|
2981
|
+
|
|
2982
|
+
let hasReadingMatchingKanjiFormWithTranslation: boolean = false;
|
|
2983
|
+
let hasReadingWithTranslation: boolean = false;
|
|
2984
|
+
|
|
2985
|
+
for (const example of exampleList)
|
|
2986
|
+
for (let i: number = 0; i < example.parts.length; i++) {
|
|
2987
|
+
if (seenPhrases.has(example.phrase)) break;
|
|
2988
|
+
|
|
2989
|
+
const includesTranslation: boolean = meanings.some((m: string) =>
|
|
2990
|
+
example.translation.includes(m),
|
|
2991
|
+
);
|
|
2992
|
+
|
|
2993
|
+
const part: ExamplePart = example.parts[i]!;
|
|
2994
|
+
|
|
2995
|
+
const readingAsReadingMatch: boolean =
|
|
2996
|
+
part.reading !== undefined && readings.has(part.reading);
|
|
2997
|
+
|
|
2998
|
+
if (
|
|
2999
|
+
kanjiForms !== undefined &&
|
|
3000
|
+
kanjiForms.has(part.baseForm) &&
|
|
3001
|
+
readingAsReadingMatch
|
|
3002
|
+
) {
|
|
3003
|
+
readingMatchingKanjiFormExamples.push({
|
|
3004
|
+
ex: example,
|
|
3005
|
+
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
3006
|
+
});
|
|
3007
|
+
|
|
3008
|
+
if (
|
|
3009
|
+
!hasReadingMatchingKanjiFormWithTranslation &&
|
|
3010
|
+
includesTranslation
|
|
3011
|
+
)
|
|
3012
|
+
hasReadingMatchingKanjiFormWithTranslation = true;
|
|
3013
|
+
|
|
3014
|
+
seenPhrases.add(example.phrase);
|
|
3015
|
+
|
|
3016
|
+
break;
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
const readingAsBaseFormMatch: boolean = readings.has(part.baseForm);
|
|
3020
|
+
|
|
3021
|
+
if (readingAsBaseFormMatch && kanjiForms === undefined) {
|
|
3022
|
+
readingExamples.push({
|
|
3023
|
+
ex: example,
|
|
3024
|
+
...(includesTranslation ? { includesTranslation: true } : {}),
|
|
3025
|
+
});
|
|
3026
|
+
|
|
3027
|
+
if (!hasReadingWithTranslation && includesTranslation)
|
|
3028
|
+
hasReadingWithTranslation = true;
|
|
3029
|
+
|
|
3030
|
+
seenPhrases.add(example.phrase);
|
|
3031
|
+
|
|
3032
|
+
break;
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
if (readingMatchingKanjiFormExamples.length > 0)
|
|
3037
|
+
if (hasReadingMatchingKanjiFormWithTranslation)
|
|
3038
|
+
readingMatchingKanjiFormExamples =
|
|
3039
|
+
readingMatchingKanjiFormExamples.filter(
|
|
3040
|
+
(ex: {
|
|
3041
|
+
ex: TanakaExample;
|
|
3042
|
+
includesTranslation?: true | undefined;
|
|
3043
|
+
}) => ex.includesTranslation === true,
|
|
3044
|
+
);
|
|
3045
|
+
|
|
3046
|
+
if (readingExamples.length > 0 && hasReadingWithTranslation)
|
|
3047
|
+
readingExamples = readingExamples.filter(
|
|
3048
|
+
(ex: { ex: TanakaExample; includesTranslation?: true | undefined }) =>
|
|
3049
|
+
ex.includesTranslation === true,
|
|
3050
|
+
);
|
|
3051
|
+
|
|
3052
|
+
const wordExamples: {
|
|
3053
|
+
ex: TanakaExample;
|
|
3054
|
+
includesTranslation?: true | undefined;
|
|
3055
|
+
}[] = [
|
|
3056
|
+
...(name.kanjiForms !== undefined
|
|
3057
|
+
? readingMatchingKanjiFormExamples
|
|
3058
|
+
: readingExamples),
|
|
3059
|
+
];
|
|
3060
|
+
|
|
3061
|
+
if (wordExamples.length > 0) {
|
|
3062
|
+
name.phrases = wordExamples
|
|
3063
|
+
.slice(0, 5)
|
|
3064
|
+
.map(
|
|
3065
|
+
(ex: {
|
|
3066
|
+
ex: TanakaExample;
|
|
3067
|
+
includesTranslation?: true | undefined;
|
|
3068
|
+
}) => ({
|
|
3069
|
+
phrase: ex.ex.furigana ?? ex.ex.phrase,
|
|
3070
|
+
translation: ex.ex.translation,
|
|
3071
|
+
originalPhrase: ex.ex.phrase,
|
|
3072
|
+
}),
|
|
3073
|
+
);
|
|
3074
|
+
|
|
3075
|
+
name.tags!.push("name::has_phrases");
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
return name;
|
|
3080
|
+
} else return undefined;
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
export function isWord(entry: Result): entry is Word {
|
|
3084
|
+
return (
|
|
3085
|
+
isObjectArray(Object.getOwnPropertyDescriptor(entry, "readings")?.value) &&
|
|
3086
|
+
isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value)
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
export function isName(entry: Result): entry is Name {
|
|
3091
|
+
return (
|
|
3092
|
+
isObjectArray(
|
|
3093
|
+
Object.getOwnPropertyDescriptor(entry, "nameReadings")?.value,
|
|
3094
|
+
) &&
|
|
2535
3095
|
isObjectArray(Object.getOwnPropertyDescriptor(entry, "translations")?.value)
|
|
2536
3096
|
);
|
|
2537
3097
|
}
|
|
@@ -2583,7 +3143,7 @@ const createEntry: (
|
|
|
2583
3143
|
|
|
2584
3144
|
/**
|
|
2585
3145
|
* Generates an array where each field holds an entry’s info wrapped in HTML tags.
|
|
2586
|
-
* @param entry Any type of mapped entry ({@link Word}, {@link Kanji}, {@link Radical}, {@link Kana}, {@link Grammar})
|
|
3146
|
+
* @param entry Any type of mapped entry ({@link Word}, {@link Name}, {@link Kanji}, {@link Radical}, {@link Kana}, {@link Grammar})
|
|
2587
3147
|
* @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`
|
|
2588
3148
|
* @param additionalTags Additional tags that will be added alongside the existing entry tags
|
|
2589
3149
|
* @returns An array of fields, each corresponding to an Anki note type field
|
|
@@ -2832,6 +3392,153 @@ export function generateAnkiNote(
|
|
|
2832
3392
|
);
|
|
2833
3393
|
}
|
|
2834
3394
|
|
|
3395
|
+
if (isName(entry)) {
|
|
3396
|
+
const firstReading: string = createEntry(
|
|
3397
|
+
`<span class="name name-reading">${entry.nameReadings[0]!.reading}${entry.nameReadings[0]!.audio !== undefined ? `<br>[sound:${entry.nameReadings[0]!.audio}]` : ""}</span>`,
|
|
3398
|
+
entry.nameReadings[0]!.notes,
|
|
3399
|
+
);
|
|
3400
|
+
const otherReadings: string =
|
|
3401
|
+
entry.nameReadings.length > 1
|
|
3402
|
+
? `<details><summary>Show other readings</summary>${entry.nameReadings
|
|
3403
|
+
.slice(1)
|
|
3404
|
+
.map((readingEntry: Reading) =>
|
|
3405
|
+
createEntry(
|
|
3406
|
+
`<span class="name name-reading">${readingEntry.reading}${readingEntry.audio !== undefined ? `<br>[sound:${readingEntry.audio}]` : ""}</span>`,
|
|
3407
|
+
readingEntry.notes,
|
|
3408
|
+
),
|
|
3409
|
+
)
|
|
3410
|
+
.join("")}</details>`
|
|
3411
|
+
: "";
|
|
3412
|
+
const readingsField: string = `${firstReading}${otherReadings}`;
|
|
3413
|
+
|
|
3414
|
+
let readingsFieldWithoutAudio: string =
|
|
3415
|
+
'<div id="no-r-audio" style="display: none"></div>';
|
|
3416
|
+
let hasAudio: boolean = false;
|
|
3417
|
+
|
|
3418
|
+
if (entry.nameReadings.some((r: Reading) => r.audio !== undefined)) {
|
|
3419
|
+
const firstReadingWithoutAudio: string = createEntry(
|
|
3420
|
+
`<span class="name name-reading">${entry.nameReadings[0]!.reading}</span>`,
|
|
3421
|
+
entry.nameReadings[0]!.notes,
|
|
3422
|
+
);
|
|
3423
|
+
const otherReadingsWithoutAudio: string =
|
|
3424
|
+
entry.nameReadings.length > 1
|
|
3425
|
+
? `<details><summary>Show other readings</summary>${entry.nameReadings
|
|
3426
|
+
.slice(1)
|
|
3427
|
+
.map((readingEntry: Reading) =>
|
|
3428
|
+
createEntry(
|
|
3429
|
+
`<span class="name name-reading">${readingEntry.reading}</span>`,
|
|
3430
|
+
readingEntry.notes,
|
|
3431
|
+
),
|
|
3432
|
+
)
|
|
3433
|
+
.join("")}</details>`
|
|
3434
|
+
: "";
|
|
3435
|
+
readingsFieldWithoutAudio = `${firstReadingWithoutAudio}${otherReadingsWithoutAudio}`;
|
|
3436
|
+
hasAudio = true;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
const firstKanjiForm: string | undefined =
|
|
3440
|
+
entry.kanjiForms !== undefined
|
|
3441
|
+
? createEntry(
|
|
3442
|
+
`<span class="name name-kanjiform"><ruby><rb>${entry.kanjiForms[0]!.kanjiForm}</rb><rt>${entry.nameReadings[0]!.reading}</rt></ruby></span>`,
|
|
3443
|
+
entry.kanjiForms[0]!.notes,
|
|
3444
|
+
)
|
|
3445
|
+
: undefined;
|
|
3446
|
+
const otherKanjiForms: string =
|
|
3447
|
+
entry.kanjiForms !== undefined && entry.kanjiForms.length > 1
|
|
3448
|
+
? `<details><summary>Show other kanji forms</summary>${entry.kanjiForms
|
|
3449
|
+
.slice(1)
|
|
3450
|
+
.map((kanjiFormEntry: KanjiForm) => {
|
|
3451
|
+
const restrictedReading: Reading | undefined =
|
|
3452
|
+
entry.nameReadings.find(
|
|
3453
|
+
(r: Reading) =>
|
|
3454
|
+
r.notes !== undefined &&
|
|
3455
|
+
r.notes.includes(
|
|
3456
|
+
`Reading restricted to ${kanjiFormEntry.kanjiForm}`,
|
|
3457
|
+
),
|
|
3458
|
+
);
|
|
3459
|
+
|
|
3460
|
+
return createEntry(
|
|
3461
|
+
`<span class="name name-kanjiform">${restrictedReading !== undefined ? "<ruby><rb>" : ""}${kanjiFormEntry.kanjiForm}${restrictedReading !== undefined ? `</rb><rt>${restrictedReading.reading}</rt></ruby>` : ""}</span>`,
|
|
3462
|
+
kanjiFormEntry.notes,
|
|
3463
|
+
);
|
|
3464
|
+
})
|
|
3465
|
+
.join("")}</details>`
|
|
3466
|
+
: "";
|
|
3467
|
+
|
|
3468
|
+
const kanjiFormsField: string =
|
|
3469
|
+
firstKanjiForm !== undefined
|
|
3470
|
+
? `${firstKanjiForm}${otherKanjiForms}`
|
|
3471
|
+
: '<span class="name name-kanjiform" id="no-kanjiforms">(no kanji forms)</span>';
|
|
3472
|
+
|
|
3473
|
+
const firstThreeTranslations: string = entry.translations
|
|
3474
|
+
.slice(0, 3)
|
|
3475
|
+
.map((translationEntry: Translation) =>
|
|
3476
|
+
createEntry(
|
|
3477
|
+
`<span class="name name-translation">${translationEntry.translation}</span>`,
|
|
3478
|
+
translationEntry.notes,
|
|
3479
|
+
),
|
|
3480
|
+
)
|
|
3481
|
+
.join("");
|
|
3482
|
+
|
|
3483
|
+
const otherTranslations: string =
|
|
3484
|
+
entry.translations.length > 3
|
|
3485
|
+
? `<details><summary>Show other translations</summary>${entry.translations
|
|
3486
|
+
.map((translationEntry: Translation, index: number) => {
|
|
3487
|
+
if (index < 3) return "null";
|
|
3488
|
+
|
|
3489
|
+
return createEntry(
|
|
3490
|
+
`<span class="name name-translation">${translationEntry.translation}</span>`,
|
|
3491
|
+
translationEntry.notes,
|
|
3492
|
+
);
|
|
3493
|
+
})
|
|
3494
|
+
.filter((translation: string) => translation !== "null")
|
|
3495
|
+
.join("")}</details>`
|
|
3496
|
+
: "";
|
|
3497
|
+
|
|
3498
|
+
const translationsField: string = `${firstThreeTranslations}${otherTranslations}`;
|
|
3499
|
+
|
|
3500
|
+
const phrasesField: string | undefined =
|
|
3501
|
+
entry.phrases !== undefined
|
|
3502
|
+
? entry.phrases
|
|
3503
|
+
.map((phraseEntry: Phrase) =>
|
|
3504
|
+
createEntry(
|
|
3505
|
+
`<span class="name name-phrase"><span class="name name-phrase-original">${phraseEntry.originalPhrase}</span><span class="name name-phrase-furigana">${phraseEntry.phrase}</span></span>`,
|
|
3506
|
+
[phraseEntry.translation],
|
|
3507
|
+
true,
|
|
3508
|
+
),
|
|
3509
|
+
)
|
|
3510
|
+
.join("")
|
|
3511
|
+
: '<span class="name name-phrase" id="no-phrases">(no phrases)</span>';
|
|
3512
|
+
|
|
3513
|
+
const searchField: string = `${entry.nameReadings.map((r: Reading) => r.reading).join(" ")}${entry.kanjiForms !== undefined ? ` ${entry.kanjiForms.map((kf: KanjiForm) => kf.kanjiForm).join(" ")}` : ""} ${entry.id}`;
|
|
3514
|
+
|
|
3515
|
+
fields.push(
|
|
3516
|
+
...(entry.kanjiForms !== undefined
|
|
3517
|
+
? [
|
|
3518
|
+
`${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>`,
|
|
3519
|
+
`${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="2"></div>`,
|
|
3520
|
+
]
|
|
3521
|
+
: [
|
|
3522
|
+
`${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>`,
|
|
3523
|
+
`${hasAudio ? readingsFieldWithoutAudio : readingsField}<div id="r-pos" style="display: none" data-pos="1"></div>`,
|
|
3524
|
+
]),
|
|
3525
|
+
`${hasAudio ? readingsField : readingsFieldWithoutAudio}<div id="r-pos" style="display: none" data-pos="${entry.kanjiForms !== undefined ? "2" : "1"}"></div>`,
|
|
3526
|
+
translationsField,
|
|
3527
|
+
phrasesField,
|
|
3528
|
+
entry.kanji !== undefined
|
|
3529
|
+
? entry.kanji
|
|
3530
|
+
.map((kanjiEntry: Kanji) =>
|
|
3531
|
+
createEntry(
|
|
3532
|
+
`<span class="name name-kanji">${kanjiEntry.kanji}${kanjiEntry.meanings === undefined ? " (no meanings)" : ""}</span>`,
|
|
3533
|
+
kanjiEntry.meanings,
|
|
3534
|
+
),
|
|
3535
|
+
)
|
|
3536
|
+
.join("")
|
|
3537
|
+
: '<span class="name name-kanji" id="no-kanji">(no kanji)</span>',
|
|
3538
|
+
searchField,
|
|
3539
|
+
);
|
|
3540
|
+
}
|
|
3541
|
+
|
|
2835
3542
|
if (isRadical(entry))
|
|
2836
3543
|
fields.push(
|
|
2837
3544
|
`${customData !== undefined ? `<div id="custom-data" style="display: none" data-custom="${customData}"></div>` : ""}${createEntry(
|