yomitan-core 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +8 -1
  2. package/dist/anki-connect-B2UXtiUS.js +6 -0
  3. package/dist/anki-connect-BXvjYYm0.cjs +6 -0
  4. package/dist/{anki-connect-B_YpChhu.cjs → anki-connect-DGx7Gr0H.cjs} +3 -3
  5. package/dist/{anki-connect-B_YpChhu.cjs.map → anki-connect-DGx7Gr0H.cjs.map} +1 -1
  6. package/dist/{anki-connect-697E04LF.js → anki-connect-Dau8nAXZ.js} +3 -3
  7. package/dist/{anki-connect-697E04LF.js.map → anki-connect-Dau8nAXZ.js.map} +1 -1
  8. package/dist/anki.cjs +6 -6
  9. package/dist/anki.d.cts.map +1 -1
  10. package/dist/anki.d.ts +2 -2
  11. package/dist/anki.d.ts.map +1 -1
  12. package/dist/anki.js +6 -6
  13. package/dist/{audio-ZuaDkaUZ.d.ts → audio-DN-FhZ5k.d.ts} +1 -1
  14. package/dist/{audio-ZuaDkaUZ.d.ts.map → audio-DN-FhZ5k.d.ts.map} +1 -1
  15. package/dist/{audio-url-generator-CgTMaTM2.js → audio-url-generator-C7mkxYeq.js} +2 -2
  16. package/dist/{audio-url-generator-CfXaxZ47.cjs → audio-url-generator-CZECihX-.cjs} +2 -2
  17. package/dist/{audio-url-generator-C23AXVj1.cjs → audio-url-generator-CorFRyBU.cjs} +2 -2
  18. package/dist/{audio-url-generator-C23AXVj1.cjs.map → audio-url-generator-CorFRyBU.cjs.map} +1 -1
  19. package/dist/{audio-url-generator-DykdzZJu.js → audio-url-generator-_6Qk0i3T.js} +2 -2
  20. package/dist/{audio-url-generator-DykdzZJu.js.map → audio-url-generator-_6Qk0i3T.js.map} +1 -1
  21. package/dist/audio.cjs +2 -2
  22. package/dist/audio.d.ts +2 -2
  23. package/dist/audio.js +2 -2
  24. package/dist/{batch-processor-CXZZhx5t.js → batch-processor-BR-gB3H3.js} +1 -1
  25. package/dist/{batch-processor-CXZZhx5t.js.map → batch-processor-BR-gB3H3.js.map} +1 -1
  26. package/dist/batch-processor-CSF1acTw.cjs +3 -0
  27. package/dist/{batch-processor-C8pSzqRE.cjs → batch-processor-DFqM_L-_.cjs} +1 -1
  28. package/dist/{batch-processor-C8pSzqRE.cjs.map → batch-processor-DFqM_L-_.cjs.map} +1 -1
  29. package/dist/batch-processor-Quo9jUyf.js +3 -0
  30. package/dist/{core-C_0QjRBI.d.ts → core-CRjMTF7c.d.ts} +1 -1
  31. package/dist/{core-C_0QjRBI.d.ts.map → core-CRjMTF7c.d.ts.map} +1 -1
  32. package/dist/database.d.ts +3 -3
  33. package/dist/debug-I2dyAd2e.cjs +51 -0
  34. package/dist/debug-I2dyAd2e.cjs.map +1 -0
  35. package/dist/debug-hF63AFkq.js +38 -0
  36. package/dist/debug-hF63AFkq.js.map +1 -0
  37. package/dist/{dictionary-CfzEFbXZ.d.ts → dictionary-DdxghSJP.d.ts} +1 -1
  38. package/dist/{dictionary-CfzEFbXZ.d.ts.map → dictionary-DdxghSJP.d.ts.map} +1 -1
  39. package/dist/{dictionary-data-util-BY_72f3u.cjs → dictionary-data-util-DmLJMtGc.cjs} +1 -1
  40. package/dist/{dictionary-data-util-BY_72f3u.cjs.map → dictionary-data-util-DmLJMtGc.cjs.map} +1 -1
  41. package/dist/{dictionary-data-util-CKDT7n2t.js → dictionary-data-util-gUUD9ElK.js} +1 -1
  42. package/dist/{dictionary-data-util-CKDT7n2t.js.map → dictionary-data-util-gUUD9ElK.js.map} +1 -1
  43. package/dist/{dictionary-database-BRAqOF_M.d.ts → dictionary-database-D0lvK2n3.d.ts} +2 -2
  44. package/dist/{dictionary-database-BRAqOF_M.d.ts.map → dictionary-database-D0lvK2n3.d.ts.map} +1 -1
  45. package/dist/{dictionary-importer-C7mNL5CJ.js → dictionary-importer-BPlLeF5R.js} +5 -5
  46. package/dist/{dictionary-importer-C7mNL5CJ.js.map → dictionary-importer-BPlLeF5R.js.map} +1 -1
  47. package/dist/{dictionary-importer-CbMwsqEX.cjs → dictionary-importer-BvgP1Fs9.cjs} +5 -5
  48. package/dist/{dictionary-importer-CbMwsqEX.cjs.map → dictionary-importer-BvgP1Fs9.cjs.map} +1 -1
  49. package/dist/{dictionary-importer-C-AlWsIN.d.ts → dictionary-importer-CDbCAbwG.d.ts} +2 -2
  50. package/dist/{dictionary-importer-C-AlWsIN.d.ts.map → dictionary-importer-CDbCAbwG.d.ts.map} +1 -1
  51. package/dist/dictionary-importer-DEMVqTjR.js +8 -0
  52. package/dist/dictionary-importer-Luz6usUQ.cjs +8 -0
  53. package/dist/{dictionary-update-checker-DE2ymYcs.js → dictionary-update-checker-CLbtQ48X.js} +2 -2
  54. package/dist/{dictionary-update-checker-DE2ymYcs.js.map → dictionary-update-checker-CLbtQ48X.js.map} +1 -1
  55. package/dist/dictionary-update-checker-CsS7MxK_.js +4 -0
  56. package/dist/{dictionary-update-checker-CU3q0aoP.cjs → dictionary-update-checker-DgjPsURI.cjs} +2 -2
  57. package/dist/{dictionary-update-checker-xIwF77-R.cjs → dictionary-update-checker-DmiIUoKw.cjs} +2 -2
  58. package/dist/{dictionary-update-checker-xIwF77-R.cjs.map → dictionary-update-checker-DmiIUoKw.cjs.map} +1 -1
  59. package/dist/{display-generator-vjbG05fn.js → display-generator-BAEJDrHT.js} +9 -7
  60. package/dist/display-generator-BAEJDrHT.js.map +1 -0
  61. package/dist/display-generator-D5fkD0JI.cjs +10 -0
  62. package/dist/display-generator-DZLMaVuP.js +10 -0
  63. package/dist/{display-generator-BhV_MOD1.cjs → display-generator-D_0chBzj.cjs} +9 -7
  64. package/dist/display-generator-D_0chBzj.cjs.map +1 -0
  65. package/dist/{errors-ZI2FcGUl.cjs → errors-0pIJI6N2.cjs} +1 -1
  66. package/dist/{errors-ZI2FcGUl.cjs.map → errors-0pIJI6N2.cjs.map} +1 -1
  67. package/dist/{errors-D2JfYV-C.js → errors-DvKlMRXC.js} +1 -1
  68. package/dist/{errors-D2JfYV-C.js.map → errors-DvKlMRXC.js.map} +1 -1
  69. package/dist/frequency-ranking-BXjfhhUQ.js +3 -0
  70. package/dist/{frequency-ranking-DmNIoxut.cjs → frequency-ranking-Cx1kkIrw.cjs} +1 -1
  71. package/dist/{frequency-ranking-DzbdZghE.js → frequency-ranking-DEJMTMdg.js} +1 -1
  72. package/dist/{frequency-ranking-DzbdZghE.js.map → frequency-ranking-DEJMTMdg.js.map} +1 -1
  73. package/dist/{frequency-ranking-Dm6xCMkY.cjs → frequency-ranking-DVYxTXN-.cjs} +1 -1
  74. package/dist/{frequency-ranking-Dm6xCMkY.cjs.map → frequency-ranking-DVYxTXN-.cjs.map} +1 -1
  75. package/dist/furigana-MU_j_m5i.cjs +5 -0
  76. package/dist/{furigana-BnY7-dJ-.cjs → furigana-SZuBaUyl.cjs} +2 -2
  77. package/dist/{furigana-BnY7-dJ-.cjs.map → furigana-SZuBaUyl.cjs.map} +1 -1
  78. package/dist/furigana-ZCs0Xs0b.js +5 -0
  79. package/dist/{furigana-CI6LUA-6.js → furigana-h18vaQ7a.js} +2 -2
  80. package/dist/{furigana-CI6LUA-6.js.map → furigana-h18vaQ7a.js.map} +1 -1
  81. package/dist/import.cjs +6 -6
  82. package/dist/import.d.ts +3 -3
  83. package/dist/import.js +6 -6
  84. package/dist/index.cjs +44 -18
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.d.cts +3 -3
  87. package/dist/index.d.cts.map +1 -1
  88. package/dist/index.d.ts +10 -10
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +44 -18
  91. package/dist/index.js.map +1 -1
  92. package/dist/{japanese-BVV1Ctk-.cjs → japanese-C83fmEfb.cjs} +1 -1
  93. package/dist/{japanese-BVV1Ctk-.cjs.map → japanese-C83fmEfb.cjs.map} +1 -1
  94. package/dist/{japanese-DhmmW35J.js → japanese-OKEGf_i4.js} +2 -2
  95. package/dist/{japanese-DhmmW35J.js.map → japanese-OKEGf_i4.js.map} +1 -1
  96. package/dist/{json-CyQBn52D.cjs → json-Cdj6aIOQ.cjs} +1 -1
  97. package/dist/{json-CyQBn52D.cjs.map → json-Cdj6aIOQ.cjs.map} +1 -1
  98. package/dist/{json-DTq_IXXF.js → json-rIgOFqVY.js} +1 -1
  99. package/dist/{json-DTq_IXXF.js.map → json-rIgOFqVY.js.map} +1 -1
  100. package/dist/{language-DFFp_7nc.d.ts → language-DMwuc2-C.d.ts} +1 -1
  101. package/dist/{language-DFFp_7nc.d.ts.map → language-DMwuc2-C.d.ts.map} +1 -1
  102. package/dist/language.cjs +12 -12
  103. package/dist/language.d.cts +41 -3
  104. package/dist/language.d.cts.map +1 -1
  105. package/dist/language.d.ts +44 -6
  106. package/dist/language.d.ts.map +1 -1
  107. package/dist/language.js +5 -5
  108. package/dist/lookup.cjs +7 -6
  109. package/dist/lookup.d.cts +5 -78
  110. package/dist/lookup.d.cts.map +1 -1
  111. package/dist/lookup.d.ts +8 -81
  112. package/dist/lookup.d.ts.map +1 -1
  113. package/dist/lookup.js +7 -6
  114. package/dist/{media-loader-CMEuD0fn.js → media-loader-C1WZVVaA.js} +1 -1
  115. package/dist/{media-loader-CMEuD0fn.js.map → media-loader-C1WZVVaA.js.map} +1 -1
  116. package/dist/media-loader-CWNb22gc.cjs +3 -0
  117. package/dist/media-loader-CrQnDnSp.js +3 -0
  118. package/dist/{media-loader-DS2ZXpSI.cjs → media-loader-RE32nGs3.cjs} +1 -1
  119. package/dist/{media-loader-DS2ZXpSI.cjs.map → media-loader-RE32nGs3.cjs.map} +1 -1
  120. package/dist/{multi-language-transformer-CjLO0S8V.d.ts → multi-language-transformer-CFu0CVWY.d.ts} +3 -3
  121. package/dist/{multi-language-transformer-CjLO0S8V.d.ts.map → multi-language-transformer-CFu0CVWY.d.ts.map} +1 -1
  122. package/dist/multi-language-transformer-Dk8S4W6j.js +12503 -0
  123. package/dist/multi-language-transformer-Dk8S4W6j.js.map +1 -0
  124. package/dist/{multi-language-transformer-B2133Zg_.cjs → multi-language-transformer-N66Mmb2E.cjs} +9614 -5
  125. package/dist/multi-language-transformer-N66Mmb2E.cjs.map +1 -0
  126. package/dist/{pronunciation-generator-cNtAQi5s.js → pronunciation-generator-BXcwS3By.js} +2 -2
  127. package/dist/{pronunciation-generator-cNtAQi5s.js.map → pronunciation-generator-BXcwS3By.js.map} +1 -1
  128. package/dist/{pronunciation-generator-CPwnr43z.cjs → pronunciation-generator-CP1kjYje.cjs} +1 -1
  129. package/dist/{pronunciation-generator-B8y__W7I.cjs → pronunciation-generator-CeC3LFPU.cjs} +1 -1
  130. package/dist/{pronunciation-generator-B8y__W7I.cjs.map → pronunciation-generator-CeC3LFPU.cjs.map} +1 -1
  131. package/dist/{pronunciation-generator-BvTbUlOy.js → pronunciation-generator-I1xpdJu0.js} +1 -1
  132. package/dist/render.cjs +96 -8
  133. package/dist/render.cjs.map +1 -1
  134. package/dist/render.d.cts +33 -3
  135. package/dist/render.d.cts.map +1 -1
  136. package/dist/render.d.ts +35 -5
  137. package/dist/render.d.ts.map +1 -1
  138. package/dist/render.js +95 -9
  139. package/dist/render.js.map +1 -1
  140. package/dist/{sentence-parser-DUQJ3cTT.cjs → sentence-parser-8i1Y_OGS.cjs} +74 -46
  141. package/dist/sentence-parser-8i1Y_OGS.cjs.map +1 -0
  142. package/dist/{translator-TiTDVbmS.d.cts → sentence-parser-BQpu2oSA.d.cts} +80 -4
  143. package/dist/sentence-parser-BQpu2oSA.d.cts.map +1 -0
  144. package/dist/{sentence-parser-sx7y6Oyh.js → sentence-parser-CXDs4R_c.js} +74 -46
  145. package/dist/sentence-parser-CXDs4R_c.js.map +1 -0
  146. package/dist/{translator-CYvGmODX.d.ts → sentence-parser-CmsHUc_p.d.ts} +81 -5
  147. package/dist/sentence-parser-CmsHUc_p.d.ts.map +1 -0
  148. package/dist/sentence-parser-DQccqSpq.cjs +6 -0
  149. package/dist/sentence-parser-DsleseSI.js +6 -0
  150. package/dist/structured-content-generator-BhEkwa0T.js +4 -0
  151. package/dist/{structured-content-generator-C5Hhaurz.cjs → structured-content-generator-CokLKgrb.cjs} +2 -2
  152. package/dist/{structured-content-generator-C5Hhaurz.cjs.map → structured-content-generator-CokLKgrb.cjs.map} +1 -1
  153. package/dist/{structured-content-generator-D48bLhPA.cjs → structured-content-generator-_z5dJECG.cjs} +2 -2
  154. package/dist/{structured-content-generator-aJieXElq.js → structured-content-generator-gnjtdBcC.js} +2 -2
  155. package/dist/{structured-content-generator-aJieXElq.js.map → structured-content-generator-gnjtdBcC.js.map} +1 -1
  156. package/dist/{text-utilities-CFDC9Bkr.cjs → text-utilities-CTsN1Bq8.cjs} +1 -1
  157. package/dist/{text-utilities-CFDC9Bkr.cjs.map → text-utilities-CTsN1Bq8.cjs.map} +1 -1
  158. package/dist/{text-utilities-D5eno9GK.js → text-utilities-DjLdStjv.js} +1 -1
  159. package/dist/{text-utilities-D5eno9GK.js.map → text-utilities-DjLdStjv.js.map} +1 -1
  160. package/dist/translator-BGI37WRC.js +7 -0
  161. package/dist/translator-Cd1ECBM1.cjs +7 -0
  162. package/dist/{translator-B1uTusjx.cjs → translator-ClzybVmi.cjs} +2 -2
  163. package/dist/{translator-B1uTusjx.cjs.map → translator-ClzybVmi.cjs.map} +1 -1
  164. package/dist/{translator-CrDE1UJW.js → translator-jFVzLjEs.js} +2 -2
  165. package/dist/{translator-CrDE1UJW.js.map → translator-jFVzLjEs.js.map} +1 -1
  166. package/package.json +1 -1
  167. package/dist/anki-connect-D-02BbHi.cjs +0 -6
  168. package/dist/anki-connect-Vn-cnxs8.js +0 -6
  169. package/dist/batch-processor-DItpL6Pp.js +0 -3
  170. package/dist/batch-processor-fiLvFS2_.cjs +0 -3
  171. package/dist/dictionary-importer-B9M3SD2y.js +0 -8
  172. package/dist/dictionary-importer-DnR8Bsai.cjs +0 -8
  173. package/dist/dictionary-update-checker-Cnjz4tQD.js +0 -4
  174. package/dist/display-generator-BhV_MOD1.cjs.map +0 -1
  175. package/dist/display-generator-Cn4vCiSI.js +0 -10
  176. package/dist/display-generator-G2e03o0R.cjs +0 -10
  177. package/dist/display-generator-vjbG05fn.js.map +0 -1
  178. package/dist/frequency-ranking-B-kvnxro.js +0 -3
  179. package/dist/furigana-cpPhFnBv.cjs +0 -5
  180. package/dist/furigana-kZjqnnFC.js +0 -5
  181. package/dist/japanese-DdsS8rT1.d.ts +0 -41
  182. package/dist/japanese-DdsS8rT1.d.ts.map +0 -1
  183. package/dist/japanese-DgmP3i76.d.cts +0 -41
  184. package/dist/japanese-DgmP3i76.d.cts.map +0 -1
  185. package/dist/media-loader-BBTESZXn.cjs +0 -3
  186. package/dist/media-loader-CNKoAjQs.js +0 -3
  187. package/dist/multi-language-transformer-B2133Zg_.cjs.map +0 -1
  188. package/dist/multi-language-transformer-BkwMTV2g.js +0 -2893
  189. package/dist/multi-language-transformer-BkwMTV2g.js.map +0 -1
  190. package/dist/sentence-parser-B-gM8mKk.js +0 -5
  191. package/dist/sentence-parser-Cp3cm_QU.cjs +0 -5
  192. package/dist/sentence-parser-DUQJ3cTT.cjs.map +0 -1
  193. package/dist/sentence-parser-sx7y6Oyh.js.map +0 -1
  194. package/dist/structured-content-generator-Dww8IT7Y.js +0 -4
  195. package/dist/translator-BiTHo9Nm.js +0 -7
  196. package/dist/translator-CYvGmODX.d.ts.map +0 -1
  197. package/dist/translator-TiTDVbmS.d.cts.map +0 -1
  198. package/dist/translator-Y7Haj_qJ.cjs +0 -7
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
- const require_japanese = require('./japanese-BVV1Ctk-.cjs');
2
+ const require_japanese = require('./japanese-C83fmEfb.cjs');
3
+ const require_debug = require('./debug-I2dyAd2e.cjs');
3
4
 
4
5
  //#region src/lookup/sentence-parser.ts
5
6
  /**
@@ -17,22 +18,48 @@ var SentenceParser = class {
17
18
  async parseText(text, language, options) {
18
19
  const scanLength = options.scanLength ?? options.maxLength ?? 20;
19
20
  const enabledDictionaryMap = this._buildFindTermDictionaryMap(options.enabledDictionaryMap);
21
+ require_debug.debugYomitanCore("sentence-parser", "parseText:start", {
22
+ textLength: text.length,
23
+ textPreview: text.slice(0, 120),
24
+ textCodePoints: require_debug.codePointPreview(text),
25
+ lineCount: text.split("\n").length,
26
+ scanLength,
27
+ language,
28
+ enabledDictionaryCount: enabledDictionaryMap.size,
29
+ enabledDictionaryNames: [...enabledDictionaryMap.keys()],
30
+ searchResolution: options.searchResolution ?? "letter",
31
+ removeNonJapaneseCharacters: options.removeNonJapaneseCharacters,
32
+ deinflect: options.deinflect
33
+ });
20
34
  const lines = text.split("\n");
21
35
  const results = [];
22
- for (const line of lines) {
23
- const segments = await this._parseLine(line, language, enabledDictionaryMap, scanLength, options);
24
- results.push({ segments });
36
+ for (const [lineIndex, line] of lines.entries()) {
37
+ const segments = await this._parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options);
38
+ results.push(segments);
25
39
  }
40
+ require_debug.debugYomitanCore("sentence-parser", "parseText:complete", {
41
+ lineCount: results.length,
42
+ lineSegmentCounts: results.map((line) => line.length),
43
+ totalSegments: results.reduce((count, line) => count + line.length, 0),
44
+ matchedSegments: results.reduce((count, line) => count + line.filter((segment) => Array.isArray(segment.headwords)).length, 0)
45
+ });
26
46
  return results;
27
47
  }
28
48
  /**
29
49
  * Parses a single line using extension-equivalent scanning parser semantics.
30
50
  */
31
- async _parseLine(line, language, enabledDictionaryMap, scanLength, options) {
51
+ async _parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options) {
32
52
  const findTermsOptions = this._createFindTermsOptions(language, enabledDictionaryMap, options);
33
53
  const cache = new Map();
34
54
  const result = [];
35
55
  let previousUngroupedSegment = null;
56
+ let lookupCount = 0;
57
+ let cacheHits = 0;
58
+ let cacheMisses = 0;
59
+ let matchedSegmentCount = 0;
60
+ let unmatchedSegmentCount = 0;
61
+ let emptyEntryLookups = 0;
62
+ const lookupMissSamples = [];
36
63
  let i = 0;
37
64
  const ii = line.length;
38
65
  while (i < ii) {
@@ -41,8 +68,18 @@ var SentenceParser = class {
41
68
  const substring = line.substring(i, i + scanLength);
42
69
  let cached = cache.get(substring);
43
70
  if (!cached) {
71
+ cacheMisses += 1;
44
72
  const { dictionaryEntries, originalTextLength: originalTextLength$1 } = await this._translator.findTerms("simple", substring, findTermsOptions);
73
+ lookupCount += 1;
45
74
  let segments$1 = [];
75
+ if (dictionaryEntries.length === 0) {
76
+ emptyEntryLookups += 1;
77
+ if (lookupMissSamples.length < 5) lookupMissSamples.push({
78
+ substring: substring.slice(0, 40),
79
+ codePoints: require_debug.codePointPreview(substring, 20),
80
+ originalTextLength: originalTextLength$1
81
+ });
82
+ }
46
83
  if (dictionaryEntries.length > 0 && originalTextLength$1 > 0 && (originalTextLength$1 !== character.length || require_japanese.isCodePointJapanese(codePoint))) {
47
84
  const source = substring.substring(0, originalTextLength$1);
48
85
  segments$1 = this._createMatchedSegments(source, dictionaryEntries);
@@ -52,36 +89,38 @@ var SentenceParser = class {
52
89
  segments: segments$1
53
90
  };
54
91
  cache.set(substring, cached);
55
- }
92
+ } else cacheHits += 1;
56
93
  const { originalTextLength, segments } = cached;
57
94
  if (segments.length > 0) {
58
95
  previousUngroupedSegment = null;
59
96
  result.push(...segments);
97
+ matchedSegmentCount += segments.length;
60
98
  i += Math.max(1, originalTextLength);
61
99
  } else {
62
100
  if (previousUngroupedSegment === null) {
63
101
  previousUngroupedSegment = {
64
102
  text: character,
65
- reading: "",
66
- term: character,
67
- entries: [],
68
- furigana: [{
69
- text: character,
70
- reading: ""
71
- }]
103
+ reading: ""
72
104
  };
73
105
  result.push(previousUngroupedSegment);
74
- } else {
75
- previousUngroupedSegment.text += character;
76
- previousUngroupedSegment.term = previousUngroupedSegment.text;
77
- previousUngroupedSegment.furigana = [{
78
- text: previousUngroupedSegment.text,
79
- reading: ""
80
- }];
81
- }
106
+ unmatchedSegmentCount += 1;
107
+ } else previousUngroupedSegment.text += character;
82
108
  i += character.length;
83
109
  }
84
110
  }
111
+ require_debug.debugYomitanCore("sentence-parser", "parseLine:complete", {
112
+ lineIndex,
113
+ lineLength: line.length,
114
+ linePreview: line.slice(0, 120),
115
+ lookupCount,
116
+ cacheHits,
117
+ cacheMisses,
118
+ emptyEntryLookups,
119
+ matchedSegmentCount,
120
+ unmatchedSegmentCount,
121
+ finalSegmentCount: result.length,
122
+ missSamples: lookupMissSamples
123
+ });
85
124
  return result;
86
125
  }
87
126
  _createMatchedSegments(source, dictionaryEntries) {
@@ -89,35 +128,24 @@ var SentenceParser = class {
89
128
  const firstEntry = dictionaryEntries[0];
90
129
  const firstHeadword = firstEntry.headwords[0];
91
130
  if (!firstHeadword) return [];
92
- const reading = firstHeadword.reading ?? "";
93
- const term = firstHeadword.term ?? source;
94
- const furigana = require_japanese.distributeFuriganaInflected(term, reading, source);
95
- const filteredEntries = this._trimEntriesForSource(dictionaryEntries, source);
96
- return [{
97
- text: source,
98
- reading,
99
- term,
100
- entries: filteredEntries,
101
- furigana
102
- }];
103
- }
104
- _trimEntriesForSource(dictionaryEntries, source) {
105
- const trimmed = [];
106
- for (const entry of dictionaryEntries) {
107
- const headwords = [];
108
- for (const headword of entry.headwords) {
131
+ const trimmedHeadwords = [];
132
+ for (const dictionaryEntry of dictionaryEntries) {
133
+ const validHeadwords = [];
134
+ for (const headword of dictionaryEntry.headwords) {
109
135
  const validSources = headword.sources.filter((src) => src.originalText === source && src.isPrimary && src.matchType === "exact");
110
- if (validSources.length > 0) headwords.push({
111
- ...headword,
136
+ if (validSources.length > 0) validHeadwords.push({
137
+ term: headword.term,
138
+ reading: headword.reading,
112
139
  sources: validSources
113
140
  });
114
141
  }
115
- if (headwords.length > 0) trimmed.push({
116
- ...entry,
117
- headwords
118
- });
142
+ if (validHeadwords.length > 0) trimmedHeadwords.push(validHeadwords);
119
143
  }
120
- return trimmed.length > 0 ? trimmed : dictionaryEntries;
144
+ return [{
145
+ text: source,
146
+ reading: firstHeadword.reading ?? "",
147
+ ...trimmedHeadwords.length > 0 ? { headwords: trimmedHeadwords } : {}
148
+ }];
121
149
  }
122
150
  /**
123
151
  * Builds a FindTermDictionary map from the input format.
@@ -161,4 +189,4 @@ Object.defineProperty(exports, 'SentenceParser', {
161
189
  return SentenceParser;
162
190
  }
163
191
  });
164
- //# sourceMappingURL=sentence-parser-DUQJ3cTT.cjs.map
192
+ //# sourceMappingURL=sentence-parser-8i1Y_OGS.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentence-parser-8i1Y_OGS.cjs","names":["translator: Translator","text: string","language: string","options: SentenceParserOptions","results: ParseTextLine[]","line: string","lineIndex: number","enabledDictionaryMap: Map<string, FindTermDictionary>","scanLength: number","result: ParseTextSegment[]","previousUngroupedSegment: ParseTextSegment | null","lookupMissSamples: Array<{ substring: string; codePoints: string[]; originalTextLength: number }>","segments: ParseTextSegment[]","originalTextLength","source: string","dictionaryEntries: TermDictionaryEntry[]","trimmedHeadwords: ParseTextHeadword[][]","validHeadwords: ParseTextHeadword[]","inputMap: Map<string, SentenceParserDictionaryInput>"],"sources":["../src/lookup/sentence-parser.ts"],"sourcesContent":["/*\n * Copyright (C) 2023-2025 Yomitan Authors\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <https://www.gnu.org/licenses/>.\n */\n\nimport { isCodePointJapanese } from '../language/ja/japanese';\nimport type { TermDictionaryEntry } from '../types/dictionary';\nimport type { ParseTextHeadword, ParseTextLine, ParseTextSegment } from '../types/parse';\nimport type { FindTermDictionary, FindTermsTextReplacements, SearchResolution } from '../types/translation';\nimport { codePointPreview, debugYomitanCore } from '../util/debug';\nimport type { Translator } from './translator';\nexport type { ParseTextHeadword, ParseTextLine, ParseTextResultItem, ParseTextSegment } from '../types/parse';\n\nexport interface SentenceParserDictionaryInput {\n index: number;\n priority?: number;\n alias?: string;\n allowSecondarySearches?: boolean;\n partsOfSpeechFilter?: boolean;\n useDeinflections?: boolean;\n}\n\nexport interface SentenceParserOptions {\n /** The enabled dictionary map for lookups. */\n enabledDictionaryMap: Map<string, SentenceParserDictionaryInput>;\n /** Window size used by scanning parser. Defaults to 20. */\n scanLength?: number;\n /** Backward compatibility alias for scanLength. */\n maxLength?: number;\n /** Search resolution for translator. */\n searchResolution?: SearchResolution;\n /** Whether to remove non-Japanese characters in lookups. */\n removeNonJapaneseCharacters?: boolean;\n /** Whether to apply deinflection. */\n deinflect?: boolean;\n /** Text replacements forwarded to translator. */\n textReplacements?: FindTermsTextReplacements;\n}\n\ninterface ParseScanCacheEntry {\n originalTextLength: number;\n segments: ParseTextSegment[];\n}\n\n/**\n * Parses text into segments with dictionary lookups using the same\n * scanning-parser model as Yomitan extension (non-MeCab path).\n */\nexport class SentenceParser {\n private _translator: Translator;\n\n constructor(translator: Translator) {\n this._translator = translator;\n }\n\n /**\n * Parses the given text into lines of parsed segments.\n */\n async parseText(text: string, language: string, options: SentenceParserOptions): Promise<ParseTextLine[]> {\n const scanLength = options.scanLength ?? options.maxLength ?? 20;\n const enabledDictionaryMap = this._buildFindTermDictionaryMap(options.enabledDictionaryMap);\n debugYomitanCore('sentence-parser', 'parseText:start', {\n textLength: text.length,\n textPreview: text.slice(0, 120),\n textCodePoints: codePointPreview(text),\n lineCount: text.split('\\n').length,\n scanLength,\n language,\n enabledDictionaryCount: enabledDictionaryMap.size,\n enabledDictionaryNames: [...enabledDictionaryMap.keys()],\n searchResolution: options.searchResolution ?? 'letter',\n removeNonJapaneseCharacters: options.removeNonJapaneseCharacters,\n deinflect: options.deinflect,\n });\n\n const lines = text.split('\\n');\n const results: ParseTextLine[] = [];\n\n for (const [lineIndex, line] of lines.entries()) {\n const segments = await this._parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options);\n results.push(segments);\n }\n\n debugYomitanCore('sentence-parser', 'parseText:complete', {\n lineCount: results.length,\n lineSegmentCounts: results.map((line) => line.length),\n totalSegments: results.reduce((count, line) => count + line.length, 0),\n matchedSegments: results.reduce(\n (count, line) => count + line.filter((segment) => Array.isArray(segment.headwords)).length,\n 0,\n ),\n });\n\n return results;\n }\n\n /**\n * Parses a single line using extension-equivalent scanning parser semantics.\n */\n private async _parseLine(\n line: string,\n lineIndex: number,\n language: string,\n enabledDictionaryMap: Map<string, FindTermDictionary>,\n scanLength: number,\n options: SentenceParserOptions,\n ): Promise<ParseTextLine> {\n const findTermsOptions = this._createFindTermsOptions(language, enabledDictionaryMap, options);\n const cache = new Map<string, ParseScanCacheEntry>();\n\n const result: ParseTextSegment[] = [];\n let previousUngroupedSegment: ParseTextSegment | null = null;\n let lookupCount = 0;\n let cacheHits = 0;\n let cacheMisses = 0;\n let matchedSegmentCount = 0;\n let unmatchedSegmentCount = 0;\n let emptyEntryLookups = 0;\n const lookupMissSamples: Array<{ substring: string; codePoints: string[]; originalTextLength: number }> = [];\n\n let i = 0;\n const ii = line.length;\n while (i < ii) {\n const codePoint = line.codePointAt(i) as number;\n const character = String.fromCodePoint(codePoint);\n const substring = line.substring(i, i + scanLength);\n\n let cached = cache.get(substring);\n if (!cached) {\n cacheMisses += 1;\n const { dictionaryEntries, originalTextLength } = await this._translator.findTerms(\n 'simple',\n substring,\n findTermsOptions,\n );\n lookupCount += 1;\n\n let segments: ParseTextSegment[] = [];\n if (dictionaryEntries.length === 0) {\n emptyEntryLookups += 1;\n if (lookupMissSamples.length < 5) {\n lookupMissSamples.push({\n substring: substring.slice(0, 40),\n codePoints: codePointPreview(substring, 20),\n originalTextLength,\n });\n }\n }\n\n if (\n dictionaryEntries.length > 0 &&\n originalTextLength > 0 &&\n (originalTextLength !== character.length || isCodePointJapanese(codePoint))\n ) {\n const source = substring.substring(0, originalTextLength);\n segments = this._createMatchedSegments(source, dictionaryEntries);\n }\n\n cached = {\n originalTextLength,\n segments,\n };\n cache.set(substring, cached);\n } else {\n cacheHits += 1;\n }\n\n const { originalTextLength, segments } = cached;\n if (segments.length > 0) {\n previousUngroupedSegment = null;\n result.push(...segments);\n matchedSegmentCount += segments.length;\n i += Math.max(1, originalTextLength);\n } else {\n if (previousUngroupedSegment === null) {\n previousUngroupedSegment = {\n text: character,\n reading: ''\n };\n result.push(previousUngroupedSegment);\n unmatchedSegmentCount += 1;\n } else {\n previousUngroupedSegment.text += character;\n }\n i += character.length;\n }\n }\n\n debugYomitanCore('sentence-parser', 'parseLine:complete', {\n lineIndex,\n lineLength: line.length,\n linePreview: line.slice(0, 120),\n lookupCount,\n cacheHits,\n cacheMisses,\n emptyEntryLookups,\n matchedSegmentCount,\n unmatchedSegmentCount,\n finalSegmentCount: result.length,\n missSamples: lookupMissSamples,\n });\n\n return result;\n }\n\n private _createMatchedSegments(source: string, dictionaryEntries: TermDictionaryEntry[]): ParseTextSegment[] {\n if (dictionaryEntries.length === 0) {\n return [];\n }\n\n const firstEntry = dictionaryEntries[0];\n const firstHeadword = firstEntry.headwords[0];\n if (!firstHeadword) {\n return [];\n }\n\n const trimmedHeadwords: ParseTextHeadword[][] = [];\n for (const dictionaryEntry of dictionaryEntries) {\n const validHeadwords: ParseTextHeadword[] = [];\n for (const headword of dictionaryEntry.headwords) {\n const validSources = headword.sources.filter(\n (src) => src.originalText === source && src.isPrimary && src.matchType === 'exact',\n );\n\n if (validSources.length > 0) {\n validHeadwords.push({\n term: headword.term,\n reading: headword.reading,\n sources: validSources,\n });\n }\n }\n if (validHeadwords.length > 0) {\n trimmedHeadwords.push(validHeadwords);\n }\n }\n\n return [\n {\n text: source,\n reading: firstHeadword.reading ?? '',\n ...(trimmedHeadwords.length > 0 ? { headwords: trimmedHeadwords } : {}),\n },\n ];\n }\n\n /**\n * Builds a FindTermDictionary map from the input format.\n */\n private _buildFindTermDictionaryMap(\n inputMap: Map<string, SentenceParserDictionaryInput>,\n ): Map<string, FindTermDictionary> {\n const result = new Map<string, FindTermDictionary>();\n\n for (const [name, config] of inputMap.entries()) {\n result.set(name, {\n index: config.index,\n alias: config.alias ?? name,\n allowSecondarySearches: config.allowSecondarySearches ?? false,\n partsOfSpeechFilter: config.partsOfSpeechFilter ?? true,\n useDeinflections: config.useDeinflections ?? true,\n });\n }\n\n return result;\n }\n\n /**\n * Creates a FindTermsOptions object for scanning parser lookups.\n */\n private _createFindTermsOptions(\n language: string,\n enabledDictionaryMap: Map<string, FindTermDictionary>,\n options: SentenceParserOptions,\n ) {\n return {\n matchType: 'exact' as const,\n deinflect: options.deinflect ?? true,\n primaryReading: '',\n mainDictionary: '',\n sortFrequencyDictionary: null,\n sortFrequencyDictionaryOrder: 'descending' as const,\n removeNonJapaneseCharacters:\n options.removeNonJapaneseCharacters ??\n (language === 'ja' || language === 'zh' || language === 'yue' || language === 'ko'),\n textReplacements: options.textReplacements ?? [null],\n enabledDictionaryMap,\n excludeDictionaryDefinitions: null,\n searchResolution: options.searchResolution ?? ('letter' as const),\n language,\n };\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { KanjiDictionaryEntry, TermDictionaryEntry, TermSourceMatchType } from "./dictionary-6Gj8AfGC.cjs";
1
+ import { KanjiDictionaryEntry, TermDictionaryEntry, TermSource, TermSourceMatchType } from "./dictionary-6Gj8AfGC.cjs";
2
2
  import { DictionaryDB } from "./dictionary-database-3OesNIMt.cjs";
3
3
 
4
4
  //#region src/types/translation.d.ts
@@ -41,9 +41,31 @@ type FindTermDictionary = {
41
41
  };
42
42
  type TermEnabledDictionaryMap = Map<string, FindTermDictionary>;
43
43
  type KanjiEnabledDictionaryMap = Map<string, FindKanjiDictionary>; //#endregion
44
- //#region src/lookup/translator.d.ts
44
+ //#region src/types/parse.d.ts
45
45
 
46
46
  //# sourceMappingURL=translation.d.ts.map
47
+ type ParseTextHeadword = {
48
+ term: string;
49
+ reading: string;
50
+ sources: TermSource[];
51
+ };
52
+ type ParseTextSegment = {
53
+ text: string;
54
+ reading: string;
55
+ headwords?: ParseTextHeadword[][];
56
+ };
57
+ type ParseTextLine = ParseTextSegment[];
58
+ type ParseTextResultItem = {
59
+ id: string;
60
+ source: 'scanning-parser' | 'mecab';
61
+ dictionary: null | string;
62
+ index: number;
63
+ content: ParseTextLine[];
64
+ };
65
+
66
+ //#endregion
67
+ //#region src/lookup/translator.d.ts
68
+ //# sourceMappingURL=parse.d.ts.map
47
69
  type TermDictionaryEntry$1 = TermDictionaryEntry;
48
70
  type FindTermsMode = 'group' | 'term' | 'merge' | 'simple';
49
71
  /**
@@ -176,5 +198,59 @@ declare class Translator {
176
198
  private _addUserFacingInflections;
177
199
  private _hasAny;
178
200
  } //#endregion
179
- export { FindKanjiDictionary, FindKanjiOptions, FindTermDictionary, FindTermsMatchType, FindTermsMode, FindTermsOptions, FindTermsSortOrder, FindTermsTextReplacement, FindTermsTextReplacements, KanjiEnabledDictionaryMap, SearchResolution, TermEnabledDictionaryMap, Translator };
180
- //# sourceMappingURL=translator-TiTDVbmS.d.cts.map
201
+ //#region src/lookup/sentence-parser.d.ts
202
+ interface SentenceParserDictionaryInput {
203
+ index: number;
204
+ priority?: number;
205
+ alias?: string;
206
+ allowSecondarySearches?: boolean;
207
+ partsOfSpeechFilter?: boolean;
208
+ useDeinflections?: boolean;
209
+ }
210
+ interface SentenceParserOptions {
211
+ /** The enabled dictionary map for lookups. */
212
+ enabledDictionaryMap: Map<string, SentenceParserDictionaryInput>;
213
+ /** Window size used by scanning parser. Defaults to 20. */
214
+ scanLength?: number;
215
+ /** Backward compatibility alias for scanLength. */
216
+ maxLength?: number;
217
+ /** Search resolution for translator. */
218
+ searchResolution?: SearchResolution;
219
+ /** Whether to remove non-Japanese characters in lookups. */
220
+ removeNonJapaneseCharacters?: boolean;
221
+ /** Whether to apply deinflection. */
222
+ deinflect?: boolean;
223
+ /** Text replacements forwarded to translator. */
224
+ textReplacements?: FindTermsTextReplacements;
225
+ }
226
+ /**
227
+ * Parses text into segments with dictionary lookups using the same
228
+ * scanning-parser model as Yomitan extension (non-MeCab path).
229
+ */
230
+ declare class SentenceParser {
231
+ private _translator;
232
+ constructor(translator: Translator);
233
+ /**
234
+ * Parses the given text into lines of parsed segments.
235
+ */
236
+ parseText(text: string, language: string, options: SentenceParserOptions): Promise<ParseTextLine[]>;
237
+ /**
238
+ * Parses a single line using extension-equivalent scanning parser semantics.
239
+ */
240
+ private _parseLine;
241
+ private _createMatchedSegments;
242
+ /**
243
+ * Builds a FindTermDictionary map from the input format.
244
+ */
245
+ private _buildFindTermDictionaryMap;
246
+ /**
247
+ * Creates a FindTermsOptions object for scanning parser lookups.
248
+ */
249
+ private _createFindTermsOptions;
250
+ }
251
+
252
+ //#endregion
253
+ //# sourceMappingURL=sentence-parser.d.ts.map
254
+
255
+ export { FindKanjiDictionary, FindKanjiOptions, FindTermDictionary, FindTermsMatchType, FindTermsMode, FindTermsOptions, FindTermsSortOrder, FindTermsTextReplacement, FindTermsTextReplacements, KanjiEnabledDictionaryMap, ParseTextHeadword, ParseTextLine, ParseTextResultItem, ParseTextSegment, SearchResolution, SentenceParser, SentenceParserOptions, TermEnabledDictionaryMap, Translator };
256
+ //# sourceMappingURL=sentence-parser-BQpu2oSA.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentence-parser-BQpu2oSA.d.cts","names":[],"sources":["../src/types/translation.ts","../src/types/parse.ts","../src/lookup/translator.ts","../src/lookup/sentence-parser.ts"],"sourcesContent":null,"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { distributeFuriganaInflected, isCodePointJapanese } from "./japanese-DhmmW35J.js";
1
+ import { isCodePointJapanese } from "./japanese-OKEGf_i4.js";
2
+ import { codePointPreview, debugYomitanCore } from "./debug-hF63AFkq.js";
2
3
 
3
4
  //#region src/lookup/sentence-parser.ts
4
5
  /**
@@ -16,22 +17,48 @@ var SentenceParser = class {
16
17
  async parseText(text, language, options) {
17
18
  const scanLength = options.scanLength ?? options.maxLength ?? 20;
18
19
  const enabledDictionaryMap = this._buildFindTermDictionaryMap(options.enabledDictionaryMap);
20
+ debugYomitanCore("sentence-parser", "parseText:start", {
21
+ textLength: text.length,
22
+ textPreview: text.slice(0, 120),
23
+ textCodePoints: codePointPreview(text),
24
+ lineCount: text.split("\n").length,
25
+ scanLength,
26
+ language,
27
+ enabledDictionaryCount: enabledDictionaryMap.size,
28
+ enabledDictionaryNames: [...enabledDictionaryMap.keys()],
29
+ searchResolution: options.searchResolution ?? "letter",
30
+ removeNonJapaneseCharacters: options.removeNonJapaneseCharacters,
31
+ deinflect: options.deinflect
32
+ });
19
33
  const lines = text.split("\n");
20
34
  const results = [];
21
- for (const line of lines) {
22
- const segments = await this._parseLine(line, language, enabledDictionaryMap, scanLength, options);
23
- results.push({ segments });
35
+ for (const [lineIndex, line] of lines.entries()) {
36
+ const segments = await this._parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options);
37
+ results.push(segments);
24
38
  }
39
+ debugYomitanCore("sentence-parser", "parseText:complete", {
40
+ lineCount: results.length,
41
+ lineSegmentCounts: results.map((line) => line.length),
42
+ totalSegments: results.reduce((count, line) => count + line.length, 0),
43
+ matchedSegments: results.reduce((count, line) => count + line.filter((segment) => Array.isArray(segment.headwords)).length, 0)
44
+ });
25
45
  return results;
26
46
  }
27
47
  /**
28
48
  * Parses a single line using extension-equivalent scanning parser semantics.
29
49
  */
30
- async _parseLine(line, language, enabledDictionaryMap, scanLength, options) {
50
+ async _parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options) {
31
51
  const findTermsOptions = this._createFindTermsOptions(language, enabledDictionaryMap, options);
32
52
  const cache = new Map();
33
53
  const result = [];
34
54
  let previousUngroupedSegment = null;
55
+ let lookupCount = 0;
56
+ let cacheHits = 0;
57
+ let cacheMisses = 0;
58
+ let matchedSegmentCount = 0;
59
+ let unmatchedSegmentCount = 0;
60
+ let emptyEntryLookups = 0;
61
+ const lookupMissSamples = [];
35
62
  let i = 0;
36
63
  const ii = line.length;
37
64
  while (i < ii) {
@@ -40,8 +67,18 @@ var SentenceParser = class {
40
67
  const substring = line.substring(i, i + scanLength);
41
68
  let cached = cache.get(substring);
42
69
  if (!cached) {
70
+ cacheMisses += 1;
43
71
  const { dictionaryEntries, originalTextLength: originalTextLength$1 } = await this._translator.findTerms("simple", substring, findTermsOptions);
72
+ lookupCount += 1;
44
73
  let segments$1 = [];
74
+ if (dictionaryEntries.length === 0) {
75
+ emptyEntryLookups += 1;
76
+ if (lookupMissSamples.length < 5) lookupMissSamples.push({
77
+ substring: substring.slice(0, 40),
78
+ codePoints: codePointPreview(substring, 20),
79
+ originalTextLength: originalTextLength$1
80
+ });
81
+ }
45
82
  if (dictionaryEntries.length > 0 && originalTextLength$1 > 0 && (originalTextLength$1 !== character.length || isCodePointJapanese(codePoint))) {
46
83
  const source = substring.substring(0, originalTextLength$1);
47
84
  segments$1 = this._createMatchedSegments(source, dictionaryEntries);
@@ -51,36 +88,38 @@ var SentenceParser = class {
51
88
  segments: segments$1
52
89
  };
53
90
  cache.set(substring, cached);
54
- }
91
+ } else cacheHits += 1;
55
92
  const { originalTextLength, segments } = cached;
56
93
  if (segments.length > 0) {
57
94
  previousUngroupedSegment = null;
58
95
  result.push(...segments);
96
+ matchedSegmentCount += segments.length;
59
97
  i += Math.max(1, originalTextLength);
60
98
  } else {
61
99
  if (previousUngroupedSegment === null) {
62
100
  previousUngroupedSegment = {
63
101
  text: character,
64
- reading: "",
65
- term: character,
66
- entries: [],
67
- furigana: [{
68
- text: character,
69
- reading: ""
70
- }]
102
+ reading: ""
71
103
  };
72
104
  result.push(previousUngroupedSegment);
73
- } else {
74
- previousUngroupedSegment.text += character;
75
- previousUngroupedSegment.term = previousUngroupedSegment.text;
76
- previousUngroupedSegment.furigana = [{
77
- text: previousUngroupedSegment.text,
78
- reading: ""
79
- }];
80
- }
105
+ unmatchedSegmentCount += 1;
106
+ } else previousUngroupedSegment.text += character;
81
107
  i += character.length;
82
108
  }
83
109
  }
110
+ debugYomitanCore("sentence-parser", "parseLine:complete", {
111
+ lineIndex,
112
+ lineLength: line.length,
113
+ linePreview: line.slice(0, 120),
114
+ lookupCount,
115
+ cacheHits,
116
+ cacheMisses,
117
+ emptyEntryLookups,
118
+ matchedSegmentCount,
119
+ unmatchedSegmentCount,
120
+ finalSegmentCount: result.length,
121
+ missSamples: lookupMissSamples
122
+ });
84
123
  return result;
85
124
  }
86
125
  _createMatchedSegments(source, dictionaryEntries) {
@@ -88,35 +127,24 @@ var SentenceParser = class {
88
127
  const firstEntry = dictionaryEntries[0];
89
128
  const firstHeadword = firstEntry.headwords[0];
90
129
  if (!firstHeadword) return [];
91
- const reading = firstHeadword.reading ?? "";
92
- const term = firstHeadword.term ?? source;
93
- const furigana = distributeFuriganaInflected(term, reading, source);
94
- const filteredEntries = this._trimEntriesForSource(dictionaryEntries, source);
95
- return [{
96
- text: source,
97
- reading,
98
- term,
99
- entries: filteredEntries,
100
- furigana
101
- }];
102
- }
103
- _trimEntriesForSource(dictionaryEntries, source) {
104
- const trimmed = [];
105
- for (const entry of dictionaryEntries) {
106
- const headwords = [];
107
- for (const headword of entry.headwords) {
130
+ const trimmedHeadwords = [];
131
+ for (const dictionaryEntry of dictionaryEntries) {
132
+ const validHeadwords = [];
133
+ for (const headword of dictionaryEntry.headwords) {
108
134
  const validSources = headword.sources.filter((src) => src.originalText === source && src.isPrimary && src.matchType === "exact");
109
- if (validSources.length > 0) headwords.push({
110
- ...headword,
135
+ if (validSources.length > 0) validHeadwords.push({
136
+ term: headword.term,
137
+ reading: headword.reading,
111
138
  sources: validSources
112
139
  });
113
140
  }
114
- if (headwords.length > 0) trimmed.push({
115
- ...entry,
116
- headwords
117
- });
141
+ if (validHeadwords.length > 0) trimmedHeadwords.push(validHeadwords);
118
142
  }
119
- return trimmed.length > 0 ? trimmed : dictionaryEntries;
143
+ return [{
144
+ text: source,
145
+ reading: firstHeadword.reading ?? "",
146
+ ...trimmedHeadwords.length > 0 ? { headwords: trimmedHeadwords } : {}
147
+ }];
120
148
  }
121
149
  /**
122
150
  * Builds a FindTermDictionary map from the input format.
@@ -155,4 +183,4 @@ var SentenceParser = class {
155
183
 
156
184
  //#endregion
157
185
  export { SentenceParser };
158
- //# sourceMappingURL=sentence-parser-sx7y6Oyh.js.map
186
+ //# sourceMappingURL=sentence-parser-CXDs4R_c.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentence-parser-CXDs4R_c.js","names":["translator: Translator","text: string","language: string","options: SentenceParserOptions","results: ParseTextLine[]","line: string","lineIndex: number","enabledDictionaryMap: Map<string, FindTermDictionary>","scanLength: number","result: ParseTextSegment[]","previousUngroupedSegment: ParseTextSegment | null","lookupMissSamples: Array<{ substring: string; codePoints: string[]; originalTextLength: number }>","segments: ParseTextSegment[]","originalTextLength","source: string","dictionaryEntries: TermDictionaryEntry[]","trimmedHeadwords: ParseTextHeadword[][]","validHeadwords: ParseTextHeadword[]","inputMap: Map<string, SentenceParserDictionaryInput>"],"sources":["../src/lookup/sentence-parser.ts"],"sourcesContent":["/*\n * Copyright (C) 2023-2025 Yomitan Authors\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <https://www.gnu.org/licenses/>.\n */\n\nimport { isCodePointJapanese } from '../language/ja/japanese';\nimport type { TermDictionaryEntry } from '../types/dictionary';\nimport type { ParseTextHeadword, ParseTextLine, ParseTextSegment } from '../types/parse';\nimport type { FindTermDictionary, FindTermsTextReplacements, SearchResolution } from '../types/translation';\nimport { codePointPreview, debugYomitanCore } from '../util/debug';\nimport type { Translator } from './translator';\nexport type { ParseTextHeadword, ParseTextLine, ParseTextResultItem, ParseTextSegment } from '../types/parse';\n\nexport interface SentenceParserDictionaryInput {\n index: number;\n priority?: number;\n alias?: string;\n allowSecondarySearches?: boolean;\n partsOfSpeechFilter?: boolean;\n useDeinflections?: boolean;\n}\n\nexport interface SentenceParserOptions {\n /** The enabled dictionary map for lookups. */\n enabledDictionaryMap: Map<string, SentenceParserDictionaryInput>;\n /** Window size used by scanning parser. Defaults to 20. */\n scanLength?: number;\n /** Backward compatibility alias for scanLength. */\n maxLength?: number;\n /** Search resolution for translator. */\n searchResolution?: SearchResolution;\n /** Whether to remove non-Japanese characters in lookups. */\n removeNonJapaneseCharacters?: boolean;\n /** Whether to apply deinflection. */\n deinflect?: boolean;\n /** Text replacements forwarded to translator. */\n textReplacements?: FindTermsTextReplacements;\n}\n\ninterface ParseScanCacheEntry {\n originalTextLength: number;\n segments: ParseTextSegment[];\n}\n\n/**\n * Parses text into segments with dictionary lookups using the same\n * scanning-parser model as Yomitan extension (non-MeCab path).\n */\nexport class SentenceParser {\n private _translator: Translator;\n\n constructor(translator: Translator) {\n this._translator = translator;\n }\n\n /**\n * Parses the given text into lines of parsed segments.\n */\n async parseText(text: string, language: string, options: SentenceParserOptions): Promise<ParseTextLine[]> {\n const scanLength = options.scanLength ?? options.maxLength ?? 20;\n const enabledDictionaryMap = this._buildFindTermDictionaryMap(options.enabledDictionaryMap);\n debugYomitanCore('sentence-parser', 'parseText:start', {\n textLength: text.length,\n textPreview: text.slice(0, 120),\n textCodePoints: codePointPreview(text),\n lineCount: text.split('\\n').length,\n scanLength,\n language,\n enabledDictionaryCount: enabledDictionaryMap.size,\n enabledDictionaryNames: [...enabledDictionaryMap.keys()],\n searchResolution: options.searchResolution ?? 'letter',\n removeNonJapaneseCharacters: options.removeNonJapaneseCharacters,\n deinflect: options.deinflect,\n });\n\n const lines = text.split('\\n');\n const results: ParseTextLine[] = [];\n\n for (const [lineIndex, line] of lines.entries()) {\n const segments = await this._parseLine(line, lineIndex, language, enabledDictionaryMap, scanLength, options);\n results.push(segments);\n }\n\n debugYomitanCore('sentence-parser', 'parseText:complete', {\n lineCount: results.length,\n lineSegmentCounts: results.map((line) => line.length),\n totalSegments: results.reduce((count, line) => count + line.length, 0),\n matchedSegments: results.reduce(\n (count, line) => count + line.filter((segment) => Array.isArray(segment.headwords)).length,\n 0,\n ),\n });\n\n return results;\n }\n\n /**\n * Parses a single line using extension-equivalent scanning parser semantics.\n */\n private async _parseLine(\n line: string,\n lineIndex: number,\n language: string,\n enabledDictionaryMap: Map<string, FindTermDictionary>,\n scanLength: number,\n options: SentenceParserOptions,\n ): Promise<ParseTextLine> {\n const findTermsOptions = this._createFindTermsOptions(language, enabledDictionaryMap, options);\n const cache = new Map<string, ParseScanCacheEntry>();\n\n const result: ParseTextSegment[] = [];\n let previousUngroupedSegment: ParseTextSegment | null = null;\n let lookupCount = 0;\n let cacheHits = 0;\n let cacheMisses = 0;\n let matchedSegmentCount = 0;\n let unmatchedSegmentCount = 0;\n let emptyEntryLookups = 0;\n const lookupMissSamples: Array<{ substring: string; codePoints: string[]; originalTextLength: number }> = [];\n\n let i = 0;\n const ii = line.length;\n while (i < ii) {\n const codePoint = line.codePointAt(i) as number;\n const character = String.fromCodePoint(codePoint);\n const substring = line.substring(i, i + scanLength);\n\n let cached = cache.get(substring);\n if (!cached) {\n cacheMisses += 1;\n const { dictionaryEntries, originalTextLength } = await this._translator.findTerms(\n 'simple',\n substring,\n findTermsOptions,\n );\n lookupCount += 1;\n\n let segments: ParseTextSegment[] = [];\n if (dictionaryEntries.length === 0) {\n emptyEntryLookups += 1;\n if (lookupMissSamples.length < 5) {\n lookupMissSamples.push({\n substring: substring.slice(0, 40),\n codePoints: codePointPreview(substring, 20),\n originalTextLength,\n });\n }\n }\n\n if (\n dictionaryEntries.length > 0 &&\n originalTextLength > 0 &&\n (originalTextLength !== character.length || isCodePointJapanese(codePoint))\n ) {\n const source = substring.substring(0, originalTextLength);\n segments = this._createMatchedSegments(source, dictionaryEntries);\n }\n\n cached = {\n originalTextLength,\n segments,\n };\n cache.set(substring, cached);\n } else {\n cacheHits += 1;\n }\n\n const { originalTextLength, segments } = cached;\n if (segments.length > 0) {\n previousUngroupedSegment = null;\n result.push(...segments);\n matchedSegmentCount += segments.length;\n i += Math.max(1, originalTextLength);\n } else {\n if (previousUngroupedSegment === null) {\n previousUngroupedSegment = {\n text: character,\n reading: ''\n };\n result.push(previousUngroupedSegment);\n unmatchedSegmentCount += 1;\n } else {\n previousUngroupedSegment.text += character;\n }\n i += character.length;\n }\n }\n\n debugYomitanCore('sentence-parser', 'parseLine:complete', {\n lineIndex,\n lineLength: line.length,\n linePreview: line.slice(0, 120),\n lookupCount,\n cacheHits,\n cacheMisses,\n emptyEntryLookups,\n matchedSegmentCount,\n unmatchedSegmentCount,\n finalSegmentCount: result.length,\n missSamples: lookupMissSamples,\n });\n\n return result;\n }\n\n private _createMatchedSegments(source: string, dictionaryEntries: TermDictionaryEntry[]): ParseTextSegment[] {\n if (dictionaryEntries.length === 0) {\n return [];\n }\n\n const firstEntry = dictionaryEntries[0];\n const firstHeadword = firstEntry.headwords[0];\n if (!firstHeadword) {\n return [];\n }\n\n const trimmedHeadwords: ParseTextHeadword[][] = [];\n for (const dictionaryEntry of dictionaryEntries) {\n const validHeadwords: ParseTextHeadword[] = [];\n for (const headword of dictionaryEntry.headwords) {\n const validSources = headword.sources.filter(\n (src) => src.originalText === source && src.isPrimary && src.matchType === 'exact',\n );\n\n if (validSources.length > 0) {\n validHeadwords.push({\n term: headword.term,\n reading: headword.reading,\n sources: validSources,\n });\n }\n }\n if (validHeadwords.length > 0) {\n trimmedHeadwords.push(validHeadwords);\n }\n }\n\n return [\n {\n text: source,\n reading: firstHeadword.reading ?? '',\n ...(trimmedHeadwords.length > 0 ? { headwords: trimmedHeadwords } : {}),\n },\n ];\n }\n\n /**\n * Builds a FindTermDictionary map from the input format.\n */\n private _buildFindTermDictionaryMap(\n inputMap: Map<string, SentenceParserDictionaryInput>,\n ): Map<string, FindTermDictionary> {\n const result = new Map<string, FindTermDictionary>();\n\n for (const [name, config] of inputMap.entries()) {\n result.set(name, {\n index: config.index,\n alias: config.alias ?? name,\n allowSecondarySearches: config.allowSecondarySearches ?? false,\n partsOfSpeechFilter: config.partsOfSpeechFilter ?? true,\n useDeinflections: config.useDeinflections ?? true,\n });\n }\n\n return result;\n }\n\n /**\n * Creates a FindTermsOptions object for scanning parser lookups.\n */\n private _createFindTermsOptions(\n language: string,\n enabledDictionaryMap: Map<string, FindTermDictionary>,\n options: SentenceParserOptions,\n ) {\n return {\n matchType: 'exact' as const,\n deinflect: options.deinflect ?? true,\n primaryReading: '',\n mainDictionary: '',\n sortFrequencyDictionary: null,\n sortFrequencyDictionaryOrder: 'descending' as const,\n removeNonJapaneseCharacters:\n options.removeNonJapaneseCharacters ??\n (language === 'ja' || language === 'zh' || language === 'yue' || language === 'ko'),\n textReplacements: options.textReplacements ?? [null],\n enabledDictionaryMap,\n excludeDictionaryDefinitions: null,\n searchResolution: options.searchResolution ?? ('letter' as const),\n language,\n };\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { KanjiDictionaryEntry, TermDictionaryEntry, TermSourceMatchType } from "./dictionary-CfzEFbXZ.js";
2
- import { DictionaryDB$1 as DictionaryDB } from "./dictionary-database-BRAqOF_M.js";
1
+ import { KanjiDictionaryEntry, TermDictionaryEntry, TermSource, TermSourceMatchType } from "./dictionary-DdxghSJP.js";
2
+ import { DictionaryDB$1 as DictionaryDB } from "./dictionary-database-D0lvK2n3.js";
3
3
 
4
4
  //#region src/types/translation.d.ts
5
5
  type SearchResolution = 'letter' | 'word';
@@ -41,9 +41,31 @@ type FindTermDictionary = {
41
41
  };
42
42
  type TermEnabledDictionaryMap = Map<string, FindTermDictionary>;
43
43
  type KanjiEnabledDictionaryMap = Map<string, FindKanjiDictionary>; //#endregion
44
- //#region src/lookup/translator.d.ts
44
+ //#region src/types/parse.d.ts
45
45
 
46
46
  //# sourceMappingURL=translation.d.ts.map
47
+ type ParseTextHeadword = {
48
+ term: string;
49
+ reading: string;
50
+ sources: TermSource[];
51
+ };
52
+ type ParseTextSegment = {
53
+ text: string;
54
+ reading: string;
55
+ headwords?: ParseTextHeadword[][];
56
+ };
57
+ type ParseTextLine = ParseTextSegment[];
58
+ type ParseTextResultItem = {
59
+ id: string;
60
+ source: 'scanning-parser' | 'mecab';
61
+ dictionary: null | string;
62
+ index: number;
63
+ content: ParseTextLine[];
64
+ };
65
+
66
+ //#endregion
67
+ //#region src/lookup/translator.d.ts
68
+ //# sourceMappingURL=parse.d.ts.map
47
69
  type TermDictionaryEntry$1 = TermDictionaryEntry;
48
70
  type FindTermsMode = 'group' | 'term' | 'merge' | 'simple';
49
71
  /**
@@ -176,5 +198,59 @@ declare class Translator {
176
198
  private _addUserFacingInflections;
177
199
  private _hasAny;
178
200
  } //#endregion
179
- export { FindKanjiDictionary, FindKanjiOptions, FindTermDictionary, FindTermsMatchType, FindTermsMode, FindTermsOptions, FindTermsSortOrder, FindTermsTextReplacement, FindTermsTextReplacements, KanjiEnabledDictionaryMap, SearchResolution, TermEnabledDictionaryMap, Translator as Translator$1 };
180
- //# sourceMappingURL=translator-CYvGmODX.d.ts.map
201
+ //#region src/lookup/sentence-parser.d.ts
202
+ interface SentenceParserDictionaryInput {
203
+ index: number;
204
+ priority?: number;
205
+ alias?: string;
206
+ allowSecondarySearches?: boolean;
207
+ partsOfSpeechFilter?: boolean;
208
+ useDeinflections?: boolean;
209
+ }
210
+ interface SentenceParserOptions {
211
+ /** The enabled dictionary map for lookups. */
212
+ enabledDictionaryMap: Map<string, SentenceParserDictionaryInput>;
213
+ /** Window size used by scanning parser. Defaults to 20. */
214
+ scanLength?: number;
215
+ /** Backward compatibility alias for scanLength. */
216
+ maxLength?: number;
217
+ /** Search resolution for translator. */
218
+ searchResolution?: SearchResolution;
219
+ /** Whether to remove non-Japanese characters in lookups. */
220
+ removeNonJapaneseCharacters?: boolean;
221
+ /** Whether to apply deinflection. */
222
+ deinflect?: boolean;
223
+ /** Text replacements forwarded to translator. */
224
+ textReplacements?: FindTermsTextReplacements;
225
+ }
226
+ /**
227
+ * Parses text into segments with dictionary lookups using the same
228
+ * scanning-parser model as Yomitan extension (non-MeCab path).
229
+ */
230
+ declare class SentenceParser {
231
+ private _translator;
232
+ constructor(translator: Translator);
233
+ /**
234
+ * Parses the given text into lines of parsed segments.
235
+ */
236
+ parseText(text: string, language: string, options: SentenceParserOptions): Promise<ParseTextLine[]>;
237
+ /**
238
+ * Parses a single line using extension-equivalent scanning parser semantics.
239
+ */
240
+ private _parseLine;
241
+ private _createMatchedSegments;
242
+ /**
243
+ * Builds a FindTermDictionary map from the input format.
244
+ */
245
+ private _buildFindTermDictionaryMap;
246
+ /**
247
+ * Creates a FindTermsOptions object for scanning parser lookups.
248
+ */
249
+ private _createFindTermsOptions;
250
+ }
251
+
252
+ //#endregion
253
+ //# sourceMappingURL=sentence-parser.d.ts.map
254
+
255
+ export { FindKanjiDictionary, FindKanjiOptions, FindTermDictionary, FindTermsMatchType, FindTermsMode, FindTermsOptions, FindTermsSortOrder, FindTermsTextReplacement, FindTermsTextReplacements, KanjiEnabledDictionaryMap, ParseTextHeadword, ParseTextLine, ParseTextResultItem, ParseTextSegment, SearchResolution, SentenceParser as SentenceParser$1, SentenceParserOptions, TermEnabledDictionaryMap, Translator as Translator$1 };
256
+ //# sourceMappingURL=sentence-parser-CmsHUc_p.d.ts.map