@ncukondo/search-hub 0.12.1 → 0.13.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 (423) hide show
  1. package/dist/_virtual/_commonjsHelpers.js +30 -0
  2. package/dist/_virtual/_commonjsHelpers.js.map +1 -0
  3. package/dist/_virtual/aliases.js +5 -0
  4. package/dist/_virtual/aliases.js.map +1 -0
  5. package/dist/_virtual/attributes.js +5 -0
  6. package/dist/_virtual/attributes.js.map +1 -0
  7. package/dist/_virtual/back.js +5 -0
  8. package/dist/_virtual/back.js.map +1 -0
  9. package/dist/_virtual/comment.js +5 -0
  10. package/dist/_virtual/comment.js.map +1 -0
  11. package/dist/_virtual/compile.js +5 -0
  12. package/dist/_virtual/compile.js.map +1 -0
  13. package/dist/_virtual/compile2.js +5 -0
  14. package/dist/_virtual/compile2.js.map +1 -0
  15. package/dist/_virtual/decode-data-html.js +5 -0
  16. package/dist/_virtual/decode-data-html.js.map +1 -0
  17. package/dist/_virtual/decode-data-xml.js +5 -0
  18. package/dist/_virtual/decode-data-xml.js.map +1 -0
  19. package/dist/_virtual/decode.js +5 -0
  20. package/dist/_virtual/decode.js.map +1 -0
  21. package/dist/_virtual/decode_codepoint.js +5 -0
  22. package/dist/_virtual/decode_codepoint.js.map +1 -0
  23. package/dist/_virtual/encode-html.js +5 -0
  24. package/dist/_virtual/encode-html.js.map +1 -0
  25. package/dist/_virtual/encode.js +5 -0
  26. package/dist/_virtual/encode.js.map +1 -0
  27. package/dist/_virtual/escape.js +5 -0
  28. package/dist/_virtual/escape.js.map +1 -0
  29. package/dist/_virtual/feeds.js +5 -0
  30. package/dist/_virtual/feeds.js.map +1 -0
  31. package/dist/_virtual/filters.js +5 -0
  32. package/dist/_virtual/filters.js.map +1 -0
  33. package/dist/_virtual/foreignNames.js +5 -0
  34. package/dist/_virtual/foreignNames.js.map +1 -0
  35. package/dist/_virtual/general.js +5 -0
  36. package/dist/_virtual/general.js.map +1 -0
  37. package/dist/_virtual/he.js +5 -0
  38. package/dist/_virtual/he.js.map +1 -0
  39. package/dist/_virtual/helpers.js +5 -0
  40. package/dist/_virtual/helpers.js.map +1 -0
  41. package/dist/_virtual/html.js +5 -0
  42. package/dist/_virtual/html.js.map +1 -0
  43. package/dist/_virtual/index.js +6 -0
  44. package/dist/_virtual/index.js.map +1 -0
  45. package/dist/_virtual/index10.js +5 -0
  46. package/dist/_virtual/index10.js.map +1 -0
  47. package/dist/_virtual/index11.js +5 -0
  48. package/dist/_virtual/index11.js.map +1 -0
  49. package/dist/_virtual/index2.js +5 -0
  50. package/dist/_virtual/index2.js.map +1 -0
  51. package/dist/_virtual/index3.js +5 -0
  52. package/dist/_virtual/index3.js.map +1 -0
  53. package/dist/_virtual/index4.js +5 -0
  54. package/dist/_virtual/index4.js.map +1 -0
  55. package/dist/_virtual/index5.js +7 -0
  56. package/dist/_virtual/index5.js.map +1 -0
  57. package/dist/_virtual/index6.js +5 -0
  58. package/dist/_virtual/index6.js.map +1 -0
  59. package/dist/_virtual/index7.js +5 -0
  60. package/dist/_virtual/index7.js.map +1 -0
  61. package/dist/_virtual/index8.js +5 -0
  62. package/dist/_virtual/index8.js.map +1 -0
  63. package/dist/_virtual/index9.js +5 -0
  64. package/dist/_virtual/index9.js.map +1 -0
  65. package/dist/_virtual/legacy.js +5 -0
  66. package/dist/_virtual/legacy.js.map +1 -0
  67. package/dist/_virtual/manipulation.js +5 -0
  68. package/dist/_virtual/manipulation.js.map +1 -0
  69. package/dist/_virtual/matcher.js +5 -0
  70. package/dist/_virtual/matcher.js.map +1 -0
  71. package/dist/_virtual/node.js +5 -0
  72. package/dist/_virtual/node.js.map +1 -0
  73. package/dist/_virtual/node2.js +5 -0
  74. package/dist/_virtual/node2.js.map +1 -0
  75. package/dist/_virtual/parse.js +5 -0
  76. package/dist/_virtual/parse.js.map +1 -0
  77. package/dist/_virtual/parse2.js +5 -0
  78. package/dist/_virtual/parse2.js.map +1 -0
  79. package/dist/_virtual/pseudos.js +5 -0
  80. package/dist/_virtual/pseudos.js.map +1 -0
  81. package/dist/_virtual/querying.js +5 -0
  82. package/dist/_virtual/querying.js.map +1 -0
  83. package/dist/_virtual/sort.js +5 -0
  84. package/dist/_virtual/sort.js.map +1 -0
  85. package/dist/_virtual/stringify.js +5 -0
  86. package/dist/_virtual/stringify.js.map +1 -0
  87. package/dist/_virtual/subselects.js +5 -0
  88. package/dist/_virtual/subselects.js.map +1 -0
  89. package/dist/_virtual/text.js +5 -0
  90. package/dist/_virtual/text.js.map +1 -0
  91. package/dist/_virtual/traversal.js +5 -0
  92. package/dist/_virtual/traversal.js.map +1 -0
  93. package/dist/_virtual/type.js +5 -0
  94. package/dist/_virtual/type.js.map +1 -0
  95. package/dist/_virtual/valid.js +5 -0
  96. package/dist/_virtual/valid.js.map +1 -0
  97. package/dist/_virtual/void-tag.js +5 -0
  98. package/dist/_virtual/void-tag.js.map +1 -0
  99. package/dist/cli/commands/diff.js +2 -2
  100. package/dist/cli/commands/diff.js.map +1 -1
  101. package/dist/cli/commands/fulltext/attach.js +1 -1
  102. package/dist/cli/commands/fulltext/attach.js.map +1 -1
  103. package/dist/cli/commands/fulltext/check.d.ts +1 -2
  104. package/dist/cli/commands/fulltext/check.d.ts.map +1 -1
  105. package/dist/cli/commands/fulltext/check.js +4 -2
  106. package/dist/cli/commands/fulltext/check.js.map +1 -1
  107. package/dist/cli/commands/fulltext/convert.d.ts.map +1 -1
  108. package/dist/cli/commands/fulltext/convert.js +8 -8
  109. package/dist/cli/commands/fulltext/convert.js.map +1 -1
  110. package/dist/cli/commands/fulltext/fetch.d.ts.map +1 -1
  111. package/dist/cli/commands/fulltext/fetch.js +10 -6
  112. package/dist/cli/commands/fulltext/fetch.js.map +1 -1
  113. package/dist/cli/commands/fulltext/index.d.ts.map +1 -1
  114. package/dist/cli/commands/fulltext/index.js +2 -0
  115. package/dist/cli/commands/fulltext/index.js.map +1 -1
  116. package/dist/cli/commands/fulltext/init.d.ts.map +1 -1
  117. package/dist/cli/commands/fulltext/init.js +6 -5
  118. package/dist/cli/commands/fulltext/init.js.map +1 -1
  119. package/dist/cli/commands/fulltext/pending.d.ts +1 -1
  120. package/dist/cli/commands/fulltext/pending.d.ts.map +1 -1
  121. package/dist/cli/commands/fulltext/pending.js +4 -2
  122. package/dist/cli/commands/fulltext/pending.js.map +1 -1
  123. package/dist/cli/commands/fulltext/status.d.ts.map +1 -1
  124. package/dist/cli/commands/fulltext/status.js +4 -2
  125. package/dist/cli/commands/fulltext/status.js.map +1 -1
  126. package/dist/cli/commands/fulltext/sync.d.ts.map +1 -1
  127. package/dist/cli/commands/fulltext/sync.js +6 -2
  128. package/dist/cli/commands/fulltext/sync.js.map +1 -1
  129. package/dist/cli/commands/query/init.d.ts +5 -0
  130. package/dist/cli/commands/query/init.d.ts.map +1 -1
  131. package/dist/cli/commands/query/init.js +9 -1
  132. package/dist/cli/commands/query/init.js.map +1 -1
  133. package/dist/cli/commands/query/translate.d.ts.map +1 -1
  134. package/dist/cli/commands/query/translate.js +5 -0
  135. package/dist/cli/commands/query/translate.js.map +1 -1
  136. package/dist/cli/commands/query/validate.d.ts +22 -1
  137. package/dist/cli/commands/query/validate.d.ts.map +1 -1
  138. package/dist/cli/commands/query/validate.js +65 -22
  139. package/dist/cli/commands/query/validate.js.map +1 -1
  140. package/dist/cli/commands/review/extract.d.ts.map +1 -1
  141. package/dist/cli/commands/review/extract.js +1 -2
  142. package/dist/cli/commands/review/extract.js.map +1 -1
  143. package/dist/cli/commands/review/finalize.d.ts.map +1 -1
  144. package/dist/cli/commands/review/finalize.js +1 -2
  145. package/dist/cli/commands/review/finalize.js.map +1 -1
  146. package/dist/cli/commands/review/init.d.ts.map +1 -1
  147. package/dist/cli/commands/review/init.js +2 -5
  148. package/dist/cli/commands/review/init.js.map +1 -1
  149. package/dist/cli/commands/review/merge.d.ts.map +1 -1
  150. package/dist/cli/commands/review/merge.js +1 -2
  151. package/dist/cli/commands/review/merge.js.map +1 -1
  152. package/dist/cli/commands/review/types.d.ts +1 -1
  153. package/dist/cli/commands/review/types.d.ts.map +1 -1
  154. package/dist/cli/commands/review/types.js.map +1 -1
  155. package/dist/cli/index.d.ts.map +1 -1
  156. package/dist/cli/index.js +81 -7
  157. package/dist/cli/index.js.map +1 -1
  158. package/dist/cli/suggestions/index.d.ts.map +1 -1
  159. package/dist/cli/suggestions/index.js +10 -0
  160. package/dist/cli/suggestions/index.js.map +1 -1
  161. package/dist/cli/suggestions/rules.d.ts.map +1 -1
  162. package/dist/cli/suggestions/rules.js +21 -8
  163. package/dist/cli/suggestions/rules.js.map +1 -1
  164. package/dist/cli/suggestions/types.d.ts +11 -0
  165. package/dist/cli/suggestions/types.d.ts.map +1 -1
  166. package/dist/config/schema.d.ts +2 -0
  167. package/dist/config/schema.d.ts.map +1 -1
  168. package/dist/config/schema.js +6 -0
  169. package/dist/config/schema.js.map +1 -1
  170. package/dist/index.js +5 -0
  171. package/dist/index.js.map +1 -1
  172. package/dist/{fulltext → integration}/attach-shared.d.ts +2 -2
  173. package/dist/integration/attach-shared.d.ts.map +1 -0
  174. package/dist/integration/attach-shared.js.map +1 -0
  175. package/dist/integration/fulltext-attach.js +1 -1
  176. package/dist/integration/fulltext-attach.js.map +1 -1
  177. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/citation-key.js +1 -1
  178. package/dist/node_modules/@ncukondo/academic-fulltext/dist/citation-key.js.map +1 -0
  179. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js +434 -0
  180. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js.map +1 -0
  181. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js +93 -0
  182. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js.map +1 -0
  183. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js +1060 -0
  184. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js.map +1 -0
  185. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/convert/markdown-writer.js +146 -117
  186. package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/markdown-writer.js.map +1 -0
  187. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/arxiv.js +8 -1
  188. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/arxiv.js.map +1 -0
  189. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/core.js +6 -3
  190. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/core.js.map +1 -0
  191. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js +139 -0
  192. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js.map +1 -0
  193. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js +46 -0
  194. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js.map +1 -0
  195. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/pmc.js +8 -4
  196. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/pmc.js.map +1 -0
  197. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/unpaywall.js +43 -9
  198. package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/unpaywall.js.map +1 -0
  199. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js +48 -0
  200. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js.map +1 -0
  201. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js +64 -0
  202. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js.map +1 -0
  203. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js +236 -0
  204. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js.map +1 -0
  205. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/download/pmc-xml.js +2 -1
  206. package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/pmc-xml.js.map +1 -0
  207. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/meta.js +15 -10
  208. package/dist/node_modules/@ncukondo/academic-fulltext/dist/meta.js.map +1 -0
  209. package/dist/node_modules/@ncukondo/academic-fulltext/dist/paths.js.map +1 -0
  210. package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/readme.js +8 -4
  211. package/dist/node_modules/@ncukondo/academic-fulltext/dist/readme.js.map +1 -0
  212. package/dist/node_modules/boolbase/index.js +19 -0
  213. package/dist/node_modules/boolbase/index.js.map +1 -0
  214. package/dist/node_modules/css-select/lib/attributes.js +203 -0
  215. package/dist/node_modules/css-select/lib/attributes.js.map +1 -0
  216. package/dist/node_modules/css-select/lib/compile.js +141 -0
  217. package/dist/node_modules/css-select/lib/compile.js.map +1 -0
  218. package/dist/node_modules/css-select/lib/general.js +154 -0
  219. package/dist/node_modules/css-select/lib/general.js.map +1 -0
  220. package/dist/node_modules/css-select/lib/index.js +128 -0
  221. package/dist/node_modules/css-select/lib/index.js.map +1 -0
  222. package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js +40 -0
  223. package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js.map +1 -0
  224. package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js +163 -0
  225. package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js.map +1 -0
  226. package/dist/node_modules/css-select/lib/pseudo-selectors/index.js +71 -0
  227. package/dist/node_modules/css-select/lib/pseudo-selectors/index.js.map +1 -0
  228. package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js +93 -0
  229. package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js.map +1 -0
  230. package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js +111 -0
  231. package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js.map +1 -0
  232. package/dist/node_modules/css-select/lib/sort.js +78 -0
  233. package/dist/node_modules/css-select/lib/sort.js.map +1 -0
  234. package/dist/node_modules/css-what/lib/es/index.js +12 -0
  235. package/dist/node_modules/css-what/lib/es/index.js.map +1 -0
  236. package/dist/node_modules/css-what/lib/es/parse.js +349 -0
  237. package/dist/node_modules/css-what/lib/es/parse.js.map +1 -0
  238. package/dist/node_modules/css-what/lib/es/stringify.js +102 -0
  239. package/dist/node_modules/css-what/lib/es/stringify.js.map +1 -0
  240. package/dist/node_modules/css-what/lib/es/types.js +37 -0
  241. package/dist/node_modules/css-what/lib/es/types.js.map +1 -0
  242. package/dist/node_modules/dom-serializer/lib/foreignNames.js +117 -0
  243. package/dist/node_modules/dom-serializer/lib/foreignNames.js.map +1 -0
  244. package/dist/node_modules/dom-serializer/lib/index.js +207 -0
  245. package/dist/node_modules/dom-serializer/lib/index.js.map +1 -0
  246. package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js +368 -0
  247. package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js.map +1 -0
  248. package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js +70 -0
  249. package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js.map +1 -0
  250. package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js +61 -0
  251. package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js.map +1 -0
  252. package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js +79 -0
  253. package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js.map +1 -0
  254. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js +18 -0
  255. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js.map +1 -0
  256. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js +18 -0
  257. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js.map +1 -0
  258. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js +19 -0
  259. package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js.map +1 -0
  260. package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js +139 -0
  261. package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js.map +1 -0
  262. package/dist/node_modules/domelementtype/lib/index.js +40 -0
  263. package/dist/node_modules/domelementtype/lib/index.js.map +1 -0
  264. package/dist/node_modules/domhandler/lib/index.js +167 -0
  265. package/dist/node_modules/domhandler/lib/index.js.map +1 -0
  266. package/dist/node_modules/domhandler/lib/node.js +439 -0
  267. package/dist/node_modules/domhandler/lib/node.js.map +1 -0
  268. package/dist/node_modules/domutils/lib/feeds.js +146 -0
  269. package/dist/node_modules/domutils/lib/feeds.js.map +1 -0
  270. package/dist/node_modules/domutils/lib/helpers.js +97 -0
  271. package/dist/node_modules/domutils/lib/helpers.js.map +1 -0
  272. package/dist/node_modules/domutils/lib/index.js +65 -0
  273. package/dist/node_modules/domutils/lib/index.js.map +1 -0
  274. package/dist/node_modules/domutils/lib/legacy.js +124 -0
  275. package/dist/node_modules/domutils/lib/legacy.js.map +1 -0
  276. package/dist/node_modules/domutils/lib/manipulation.js +107 -0
  277. package/dist/node_modules/domutils/lib/manipulation.js.map +1 -0
  278. package/dist/node_modules/domutils/lib/querying.js +102 -0
  279. package/dist/node_modules/domutils/lib/querying.js.map +1 -0
  280. package/dist/node_modules/domutils/lib/stringify.js +65 -0
  281. package/dist/node_modules/domutils/lib/stringify.js.map +1 -0
  282. package/dist/node_modules/domutils/lib/traversal.js +69 -0
  283. package/dist/node_modules/domutils/lib/traversal.js.map +1 -0
  284. package/dist/node_modules/he/he.js +256 -0
  285. package/dist/node_modules/he/he.js.map +1 -0
  286. package/dist/node_modules/node-html-parser/dist/back.js +16 -0
  287. package/dist/node_modules/node-html-parser/dist/back.js.map +1 -0
  288. package/dist/node_modules/node-html-parser/dist/index.js +48 -0
  289. package/dist/node_modules/node-html-parser/dist/index.js.map +1 -0
  290. package/dist/node_modules/node-html-parser/dist/matcher.js +112 -0
  291. package/dist/node_modules/node-html-parser/dist/matcher.js.map +1 -0
  292. package/dist/node_modules/node-html-parser/dist/nodes/comment.js +41 -0
  293. package/dist/node_modules/node-html-parser/dist/nodes/comment.js.map +1 -0
  294. package/dist/node_modules/node-html-parser/dist/nodes/html.js +1048 -0
  295. package/dist/node_modules/node-html-parser/dist/nodes/html.js.map +1 -0
  296. package/dist/node_modules/node-html-parser/dist/nodes/node.js +49 -0
  297. package/dist/node_modules/node-html-parser/dist/nodes/node.js.map +1 -0
  298. package/dist/node_modules/node-html-parser/dist/nodes/text.js +106 -0
  299. package/dist/node_modules/node-html-parser/dist/nodes/text.js.map +1 -0
  300. package/dist/node_modules/node-html-parser/dist/nodes/type.js +19 -0
  301. package/dist/node_modules/node-html-parser/dist/nodes/type.js.map +1 -0
  302. package/dist/node_modules/node-html-parser/dist/parse.js +20 -0
  303. package/dist/node_modules/node-html-parser/dist/parse.js.map +1 -0
  304. package/dist/node_modules/node-html-parser/dist/valid.js +19 -0
  305. package/dist/node_modules/node-html-parser/dist/valid.js.map +1 -0
  306. package/dist/node_modules/node-html-parser/dist/void-tag.js +36 -0
  307. package/dist/node_modules/node-html-parser/dist/void-tag.js.map +1 -0
  308. package/dist/node_modules/nth-check/lib/compile.js +76 -0
  309. package/dist/node_modules/nth-check/lib/compile.js.map +1 -0
  310. package/dist/node_modules/nth-check/lib/index.js +36 -0
  311. package/dist/node_modules/nth-check/lib/index.js.map +1 -0
  312. package/dist/node_modules/nth-check/lib/parse.js +69 -0
  313. package/dist/node_modules/nth-check/lib/parse.js.map +1 -0
  314. package/dist/providers/arxiv/translator.d.ts.map +1 -1
  315. package/dist/providers/arxiv/translator.js +5 -2
  316. package/dist/providers/arxiv/translator.js.map +1 -1
  317. package/dist/providers/base/types.d.ts +2 -0
  318. package/dist/providers/base/types.d.ts.map +1 -1
  319. package/dist/providers/base/types.js.map +1 -1
  320. package/dist/providers/base/warnings.d.ts +14 -0
  321. package/dist/providers/base/warnings.d.ts.map +1 -0
  322. package/dist/providers/base/warnings.js +33 -0
  323. package/dist/providers/base/warnings.js.map +1 -0
  324. package/dist/providers/eric/translator.d.ts.map +1 -1
  325. package/dist/providers/eric/translator.js +5 -2
  326. package/dist/providers/eric/translator.js.map +1 -1
  327. package/dist/providers/pubmed/translator.d.ts.map +1 -1
  328. package/dist/providers/pubmed/translator.js +5 -2
  329. package/dist/providers/pubmed/translator.js.map +1 -1
  330. package/dist/providers/scopus/translator.d.ts.map +1 -1
  331. package/dist/providers/scopus/translator.js +22 -5
  332. package/dist/providers/scopus/translator.js.map +1 -1
  333. package/dist/query/__test-helpers__/mock-mesh-client.d.ts +12 -0
  334. package/dist/query/__test-helpers__/mock-mesh-client.d.ts.map +1 -0
  335. package/dist/query/index.d.ts +4 -0
  336. package/dist/query/index.d.ts.map +1 -1
  337. package/dist/query/json-schema.d.ts +3 -0
  338. package/dist/query/json-schema.d.ts.map +1 -0
  339. package/dist/query/json-schema.js +48 -0
  340. package/dist/query/json-schema.js.map +1 -0
  341. package/dist/query/mesh-lookup.d.ts +47 -0
  342. package/dist/query/mesh-lookup.d.ts.map +1 -0
  343. package/dist/query/mesh-lookup.js +151 -0
  344. package/dist/query/mesh-lookup.js.map +1 -0
  345. package/dist/query/parser.js +1 -1
  346. package/dist/query/parser.js.map +1 -1
  347. package/dist/query/types.d.ts +2 -2
  348. package/dist/query/types.d.ts.map +1 -1
  349. package/dist/query/validator.d.ts +5 -5
  350. package/dist/query/validator.d.ts.map +1 -1
  351. package/dist/query/validator.js +5 -2
  352. package/dist/query/validator.js.map +1 -1
  353. package/dist/query/vocab-cache.d.ts +15 -0
  354. package/dist/query/vocab-cache.d.ts.map +1 -0
  355. package/dist/query/vocab-cache.js +44 -0
  356. package/dist/query/vocab-cache.js.map +1 -0
  357. package/dist/query/vocab-validator.d.ts +71 -0
  358. package/dist/query/vocab-validator.d.ts.map +1 -0
  359. package/dist/query/vocab-validator.js +153 -0
  360. package/dist/query/vocab-validator.js.map +1 -0
  361. package/dist/utils/levenshtein.d.ts +6 -0
  362. package/dist/utils/levenshtein.d.ts.map +1 -0
  363. package/dist/utils/levenshtein.js +21 -0
  364. package/dist/utils/levenshtein.js.map +1 -0
  365. package/package.json +2 -2
  366. package/dist/fulltext/attach-shared.d.ts.map +0 -1
  367. package/dist/fulltext/attach-shared.js.map +0 -1
  368. package/dist/fulltext/citation-key.d.ts +0 -15
  369. package/dist/fulltext/citation-key.d.ts.map +0 -1
  370. package/dist/fulltext/citation-key.js.map +0 -1
  371. package/dist/fulltext/convert/index.d.ts +0 -20
  372. package/dist/fulltext/convert/index.d.ts.map +0 -1
  373. package/dist/fulltext/convert/index.js +0 -50
  374. package/dist/fulltext/convert/index.js.map +0 -1
  375. package/dist/fulltext/convert/jats-parser.d.ts +0 -36
  376. package/dist/fulltext/convert/jats-parser.d.ts.map +0 -1
  377. package/dist/fulltext/convert/jats-parser.js +0 -887
  378. package/dist/fulltext/convert/jats-parser.js.map +0 -1
  379. package/dist/fulltext/convert/markdown-writer.d.ts +0 -6
  380. package/dist/fulltext/convert/markdown-writer.d.ts.map +0 -1
  381. package/dist/fulltext/convert/markdown-writer.js.map +0 -1
  382. package/dist/fulltext/convert/types.d.ts +0 -141
  383. package/dist/fulltext/convert/types.d.ts.map +0 -1
  384. package/dist/fulltext/discovery/arxiv.d.ts +0 -11
  385. package/dist/fulltext/discovery/arxiv.d.ts.map +0 -1
  386. package/dist/fulltext/discovery/arxiv.js.map +0 -1
  387. package/dist/fulltext/discovery/core.d.ts +0 -11
  388. package/dist/fulltext/discovery/core.d.ts.map +0 -1
  389. package/dist/fulltext/discovery/core.js.map +0 -1
  390. package/dist/fulltext/discovery/index.d.ts +0 -28
  391. package/dist/fulltext/discovery/index.d.ts.map +0 -1
  392. package/dist/fulltext/discovery/index.js +0 -75
  393. package/dist/fulltext/discovery/index.js.map +0 -1
  394. package/dist/fulltext/discovery/pmc.d.ts +0 -19
  395. package/dist/fulltext/discovery/pmc.d.ts.map +0 -1
  396. package/dist/fulltext/discovery/pmc.js.map +0 -1
  397. package/dist/fulltext/discovery/unpaywall.d.ts +0 -11
  398. package/dist/fulltext/discovery/unpaywall.d.ts.map +0 -1
  399. package/dist/fulltext/discovery/unpaywall.js.map +0 -1
  400. package/dist/fulltext/download/downloader.d.ts +0 -21
  401. package/dist/fulltext/download/downloader.d.ts.map +0 -1
  402. package/dist/fulltext/download/downloader.js +0 -59
  403. package/dist/fulltext/download/downloader.js.map +0 -1
  404. package/dist/fulltext/download/orchestrator.d.ts +0 -33
  405. package/dist/fulltext/download/orchestrator.d.ts.map +0 -1
  406. package/dist/fulltext/download/orchestrator.js +0 -125
  407. package/dist/fulltext/download/orchestrator.js.map +0 -1
  408. package/dist/fulltext/download/pmc-xml.d.ts +0 -13
  409. package/dist/fulltext/download/pmc-xml.d.ts.map +0 -1
  410. package/dist/fulltext/download/pmc-xml.js.map +0 -1
  411. package/dist/fulltext/meta.d.ts +0 -25
  412. package/dist/fulltext/meta.d.ts.map +0 -1
  413. package/dist/fulltext/meta.js.map +0 -1
  414. package/dist/fulltext/paths.d.ts +0 -12
  415. package/dist/fulltext/paths.d.ts.map +0 -1
  416. package/dist/fulltext/paths.js.map +0 -1
  417. package/dist/fulltext/readme.d.ts +0 -4
  418. package/dist/fulltext/readme.d.ts.map +0 -1
  419. package/dist/fulltext/readme.js.map +0 -1
  420. package/dist/fulltext/types.d.ts +0 -90
  421. package/dist/fulltext/types.d.ts.map +0 -1
  422. /package/dist/{fulltext → integration}/attach-shared.js +0 -0
  423. /package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/paths.js +0 -0
@@ -0,0 +1,69 @@
1
+ import { __exports as parse } from "../../../_virtual/parse2.js";
2
+ var hasRequiredParse;
3
+ function requireParse() {
4
+ if (hasRequiredParse) return parse;
5
+ hasRequiredParse = 1;
6
+ Object.defineProperty(parse, "__esModule", { value: true });
7
+ parse.parse = void 0;
8
+ var whitespace = /* @__PURE__ */ new Set([9, 10, 12, 13, 32]);
9
+ var ZERO = "0".charCodeAt(0);
10
+ var NINE = "9".charCodeAt(0);
11
+ function parse$1(formula) {
12
+ formula = formula.trim().toLowerCase();
13
+ if (formula === "even") {
14
+ return [2, 0];
15
+ } else if (formula === "odd") {
16
+ return [2, 1];
17
+ }
18
+ var idx = 0;
19
+ var a = 0;
20
+ var sign = readSign();
21
+ var number = readNumber();
22
+ if (idx < formula.length && formula.charAt(idx) === "n") {
23
+ idx++;
24
+ a = sign * (number !== null && number !== void 0 ? number : 1);
25
+ skipWhitespace();
26
+ if (idx < formula.length) {
27
+ sign = readSign();
28
+ skipWhitespace();
29
+ number = readNumber();
30
+ } else {
31
+ sign = number = 0;
32
+ }
33
+ }
34
+ if (number === null || idx < formula.length) {
35
+ throw new Error("n-th rule couldn't be parsed ('".concat(formula, "')"));
36
+ }
37
+ return [a, sign * number];
38
+ function readSign() {
39
+ if (formula.charAt(idx) === "-") {
40
+ idx++;
41
+ return -1;
42
+ }
43
+ if (formula.charAt(idx) === "+") {
44
+ idx++;
45
+ }
46
+ return 1;
47
+ }
48
+ function readNumber() {
49
+ var start = idx;
50
+ var value = 0;
51
+ while (idx < formula.length && formula.charCodeAt(idx) >= ZERO && formula.charCodeAt(idx) <= NINE) {
52
+ value = value * 10 + (formula.charCodeAt(idx) - ZERO);
53
+ idx++;
54
+ }
55
+ return idx === start ? null : value;
56
+ }
57
+ function skipWhitespace() {
58
+ while (idx < formula.length && whitespace.has(formula.charCodeAt(idx))) {
59
+ idx++;
60
+ }
61
+ }
62
+ }
63
+ parse.parse = parse$1;
64
+ return parse;
65
+ }
66
+ export {
67
+ requireParse as __require
68
+ };
69
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sources":["../../../../node_modules/nth-check/lib/parse.js"],"sourcesContent":["\"use strict\";\n// Following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.parse = void 0;\n// Whitespace as per https://www.w3.org/TR/selectors-3/#lex is \" \\t\\r\\n\\f\"\nvar whitespace = new Set([9, 10, 12, 13, 32]);\nvar ZERO = \"0\".charCodeAt(0);\nvar NINE = \"9\".charCodeAt(0);\n/**\n * Parses an expression.\n *\n * @throws An `Error` if parsing fails.\n * @returns An array containing the integer step size and the integer offset of the nth rule.\n * @example nthCheck.parse(\"2n+3\"); // returns [2, 3]\n */\nfunction parse(formula) {\n formula = formula.trim().toLowerCase();\n if (formula === \"even\") {\n return [2, 0];\n }\n else if (formula === \"odd\") {\n return [2, 1];\n }\n // Parse [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?\n var idx = 0;\n var a = 0;\n var sign = readSign();\n var number = readNumber();\n if (idx < formula.length && formula.charAt(idx) === \"n\") {\n idx++;\n a = sign * (number !== null && number !== void 0 ? number : 1);\n skipWhitespace();\n if (idx < formula.length) {\n sign = readSign();\n skipWhitespace();\n number = readNumber();\n }\n else {\n sign = number = 0;\n }\n }\n // Throw if there is anything else\n if (number === null || idx < formula.length) {\n throw new Error(\"n-th rule couldn't be parsed ('\".concat(formula, \"')\"));\n }\n return [a, sign * number];\n function readSign() {\n if (formula.charAt(idx) === \"-\") {\n idx++;\n return -1;\n }\n if (formula.charAt(idx) === \"+\") {\n idx++;\n }\n return 1;\n }\n function readNumber() {\n var start = idx;\n var value = 0;\n while (idx < formula.length &&\n formula.charCodeAt(idx) >= ZERO &&\n formula.charCodeAt(idx) <= NINE) {\n value = value * 10 + (formula.charCodeAt(idx) - ZERO);\n idx++;\n }\n // Return `null` if we didn't read anything.\n return idx === start ? null : value;\n }\n function skipWhitespace() {\n while (idx < formula.length &&\n whitespace.has(formula.charCodeAt(idx))) {\n idx++;\n }\n }\n}\nexports.parse = parse;\n//# sourceMappingURL=parse.js.map"],"names":["parse_1","parse"],"mappings":";;;;;AAEA,SAAO,eAAeA,OAAS,cAAc,EAAE,OAAO,MAAM;AAC5DA,QAAA,QAAgB;AAEhB,MAAI,aAAa,oBAAI,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;AAC5C,MAAI,OAAO,IAAI,WAAW,CAAC;AAC3B,MAAI,OAAO,IAAI,WAAW,CAAC;AAQ3B,WAASC,QAAM,SAAS;AACpB,cAAU,QAAQ,KAAI,EAAG,YAAW;AACpC,QAAI,YAAY,QAAQ;AACpB,aAAO,CAAC,GAAG,CAAC;AAAA,IACpB,WACa,YAAY,OAAO;AACxB,aAAO,CAAC,GAAG,CAAC;AAAA,IACpB;AAEI,QAAI,MAAM;AACV,QAAI,IAAI;AACR,QAAI,OAAO,SAAQ;AACnB,QAAI,SAAS,WAAU;AACvB,QAAI,MAAM,QAAQ,UAAU,QAAQ,OAAO,GAAG,MAAM,KAAK;AACrD;AACA,UAAI,QAAQ,WAAW,QAAQ,WAAW,SAAS,SAAS;AAC5D,qBAAc;AACd,UAAI,MAAM,QAAQ,QAAQ;AACtB,eAAO,SAAQ;AACf,uBAAc;AACd,iBAAS,WAAU;AAAA,MAC/B,OACa;AACD,eAAO,SAAS;AAAA,MAC5B;AAAA,IACA;AAEI,QAAI,WAAW,QAAQ,MAAM,QAAQ,QAAQ;AACzC,YAAM,IAAI,MAAM,kCAAkC,OAAO,SAAS,IAAI,CAAC;AAAA,IAC/E;AACI,WAAO,CAAC,GAAG,OAAO,MAAM;AACxB,aAAS,WAAW;AAChB,UAAI,QAAQ,OAAO,GAAG,MAAM,KAAK;AAC7B;AACA,eAAO;AAAA,MACnB;AACQ,UAAI,QAAQ,OAAO,GAAG,MAAM,KAAK;AAC7B;AAAA,MACZ;AACQ,aAAO;AAAA,IACf;AACI,aAAS,aAAa;AAClB,UAAI,QAAQ;AACZ,UAAI,QAAQ;AACZ,aAAO,MAAM,QAAQ,UACjB,QAAQ,WAAW,GAAG,KAAK,QAC3B,QAAQ,WAAW,GAAG,KAAK,MAAM;AACjC,gBAAQ,QAAQ,MAAM,QAAQ,WAAW,GAAG,IAAI;AAChD;AAAA,MACZ;AAEQ,aAAO,QAAQ,QAAQ,OAAO;AAAA,IACtC;AACI,aAAS,iBAAiB;AACtB,aAAO,MAAM,QAAQ,UACjB,WAAW,IAAI,QAAQ,WAAW,GAAG,CAAC,GAAG;AACzC;AAAA,MACZ;AAAA,IACA;AAAA,EACA;AACAD,QAAA,QAAgBC;;;","x_google_ignoreList":[0]}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/arxiv/translator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAc,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAcxD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAEpE;AASD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAY7F;AAqID;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CA4D7D"}
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/arxiv/translator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAc,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAexD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAEpE;AASD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAY7F;AAqID;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAiE7D"}
@@ -1,3 +1,4 @@
1
+ import { collectUnsupportedVocabWarnings } from "../base/warnings.js";
1
2
  const FIELD_PREFIXES = {
2
3
  title: "ti:",
3
4
  abstract: "abs:",
@@ -24,7 +25,7 @@ function translateTerms(prefix, keywords, operator) {
24
25
  }
25
26
  function translateBlock(block) {
26
27
  const { field, terms, operator } = block;
27
- const keywords = terms.keywords;
28
+ const keywords = terms.keywords ?? [];
28
29
  let query = "";
29
30
  if (keywords.length > 0) {
30
31
  if (field === "title_abstract") {
@@ -135,10 +136,12 @@ function translateQuery(ast) {
135
136
  native = notClause;
136
137
  }
137
138
  }
139
+ const warnings = collectUnsupportedVocabWarnings(ast.blocks, "arXiv", /* @__PURE__ */ new Set());
138
140
  return {
139
141
  native,
140
142
  originalAst: ast,
141
- provider: "arxiv"
143
+ provider: "arxiv",
144
+ ...warnings.length > 0 ? { warnings } : {}
142
145
  };
143
146
  }
144
147
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"translator.js","sources":["../../../src/providers/arxiv/translator.ts"],"sourcesContent":["/**\n * arXiv Query Translator\n *\n * Translates QueryAST to arXiv-native query syntax.\n *\n * Field mappings:\n * - title → ti:\n * - abstract → abs:\n * - title_abstract → (ti: OR abs:) expansion\n * - author → au:\n * - all → all:\n * - keyword → not supported\n *\n * Boolean operators: AND, OR, ANDNOT (not standard NOT)\n * Date filter: submittedDate:[YYYYMMDDHHmm TO YYYYMMDDHHmm]\n * Category filter: cat:cs.AI\n */\n\nimport type { QueryAST, QueryBlock, FieldType, Operator } from '../../query/types.js';\nimport type { TranslatedQuery } from '../base/types.js';\n\n/**\n * Field prefix mappings for arXiv API.\n */\nconst FIELD_PREFIXES: Partial<Record<FieldType, string>> = {\n title: 'ti:',\n abstract: 'abs:',\n author: 'au:',\n all: 'all:',\n // title_abstract requires expansion, not a direct prefix\n // keyword is not supported by arXiv\n};\n\n/**\n * Get the arXiv field prefix for a DSL field type.\n * Returns null if the field requires special handling or is unsupported.\n */\nexport function translateFieldPrefix(field: FieldType): string | null {\n return FIELD_PREFIXES[field] ?? null;\n}\n\n/**\n * Wrap a term in quotes if it contains spaces (phrase search).\n */\nfunction quoteIfNeeded(term: string): string {\n return term.includes(' ') ? `\"${term}\"` : term;\n}\n\n/**\n * Translate terms with a field prefix.\n * Handles quoting of multi-word phrases.\n */\nexport function translateTerms(prefix: string, keywords: string[], operator: Operator): string {\n if (keywords.length === 0) {\n return '';\n }\n\n const translatedTerms = keywords.map((keyword) => `${prefix}${quoteIfNeeded(keyword)}`);\n\n if (translatedTerms.length === 1) {\n return translatedTerms[0]!;\n }\n\n return `(${translatedTerms.join(` ${operator} `)})`;\n}\n\n/**\n * Translate a single query block to arXiv syntax.\n * Returns an object with the main query part and optional ANDNOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const { field, terms, operator } = block;\n\n // arXiv only uses keywords; ignore mesh and emtree\n const keywords = terms.keywords;\n\n let query = '';\n\n if (keywords.length > 0) {\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n query = translateTitleAbstract(keywords, operator);\n } else {\n // Get field prefix\n const prefix = translateFieldPrefix(field);\n if (prefix !== null) {\n query = translateTerms(prefix, keywords, operator);\n }\n }\n }\n\n // Translate exclude terms\n const notClause = terms.exclude\n ? translateExcludeTerms(terms.exclude, field)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Expand title_abstract to (ti: OR abs:) for each keyword.\n */\nfunction translateTitleAbstract(keywords: string[], operator: Operator): string {\n if (keywords.length === 0) {\n return '';\n }\n\n // Each keyword expands to (ti:keyword OR abs:keyword)\n const expandedTerms = keywords.map((keyword) => {\n const quoted = quoteIfNeeded(keyword);\n return `(ti:${quoted} OR abs:${quoted})`;\n });\n\n if (expandedTerms.length === 1) {\n return expandedTerms[0]!;\n }\n\n return `(${expandedTerms.join(` ${operator} `)})`;\n}\n\n/**\n * Translate exclude terms to ANDNOT clause.\n * arXiv uses ANDNOT instead of NOT.\n */\nfunction translateExcludeTerms(\n exclude: string[],\n field: FieldType\n): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n const expandedTerms = exclude.map((term) => {\n const quoted = quoteIfNeeded(term);\n return `(ti:${quoted} OR abs:${quoted})`;\n });\n if (expandedTerms.length === 1) {\n return `ANDNOT (${expandedTerms[0]})`;\n }\n return `ANDNOT (${expandedTerms.join(' OR ')})`;\n }\n\n // Get field prefix\n const prefix = translateFieldPrefix(field);\n if (prefix === null) {\n // Unsupported field\n return null;\n }\n\n const translatedTerms = exclude.map((term) => `${prefix}${quoteIfNeeded(term)}`);\n\n if (translatedTerms.length === 1) {\n return `ANDNOT ${translatedTerms[0]}`;\n }\n return `ANDNOT (${translatedTerms.join(' OR ')})`;\n}\n\n/**\n * Translate date filter to arXiv submittedDate range.\n * Format: submittedDate:[YYYYMMDDHHmm TO YYYYMMDDHHmm]\n * Note: arXiv API does not support wildcards (*), so we use concrete dates:\n * - Start: 1991 (arXiv's founding year)\n * - End: current year + 1 (to include all future submissions)\n */\nfunction translateDateFilter(yearFrom?: number, yearTo?: number): string {\n if (yearFrom === undefined && yearTo === undefined) {\n return '';\n }\n\n // arXiv was founded in 1991, use as default start\n const fromDate = yearFrom !== undefined ? `${yearFrom}01010000` : '199101010000';\n // Use next year as default end to include all current submissions\n const defaultEndYear = new Date().getFullYear() + 1;\n const toDate = yearTo !== undefined ? `${yearTo}12312359` : `${defaultEndYear}12312359`;\n\n return `submittedDate:[${fromDate} TO ${toDate}]`;\n}\n\n/**\n * Translate arXiv category filter.\n */\nfunction translateCategories(categories: string[]): string {\n if (categories.length === 0) {\n return '';\n }\n\n const catTerms = categories.map((cat) => `cat:${cat}`);\n\n if (catTerms.length === 1) {\n return catTerms[0]!;\n }\n\n return `(${catTerms.join(' OR ')})`;\n}\n\n/**\n * Translate a complete QueryAST to arXiv-native syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n const parts: string[] = [];\n const notClauses: string[] = [];\n\n // Translate all blocks (AND'd together)\n const blockResults = ast.blocks.map(translateBlock);\n const blockParts = blockResults.map((r) => r.query).filter((part) => part !== '');\n const blockNotClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n notClauses.push(...blockNotClauses);\n\n if (blockParts.length > 0) {\n if (blockParts.length === 1) {\n parts.push(blockParts[0]!);\n } else {\n parts.push(blockParts.map((part) => `(${part})`).join(' AND '));\n }\n }\n\n // Add date filter if present\n const dateFilter = translateDateFilter(ast.filters.yearFrom, ast.filters.yearTo);\n if (dateFilter) {\n parts.push(`(${dateFilter})`);\n }\n\n // Add category filter from arXiv overrides\n const arxivOverrides = ast.overrides.arxiv;\n if (arxivOverrides?.categories && arxivOverrides.categories.length > 0) {\n const categoryFilter = translateCategories(arxivOverrides.categories);\n if (categoryFilter) {\n parts.push(`(${categoryFilter})`);\n }\n }\n\n // Combine all parts with AND\n let native: string;\n if (parts.length === 0) {\n native = '';\n } else if (parts.length === 1) {\n native = parts[0]!;\n } else {\n native = parts.join(' AND ');\n }\n\n // Append ANDNOT clauses\n for (const notClause of notClauses) {\n if (native) {\n native = `${native} ${notClause}`;\n } else {\n native = notClause;\n }\n }\n\n return {\n native,\n originalAst: ast,\n provider: 'arxiv',\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"translator.js","sources":["../../../src/providers/arxiv/translator.ts"],"sourcesContent":["/**\n * arXiv Query Translator\n *\n * Translates QueryAST to arXiv-native query syntax.\n *\n * Field mappings:\n * - title → ti:\n * - abstract → abs:\n * - title_abstract → (ti: OR abs:) expansion\n * - author → au:\n * - all → all:\n * - keyword → not supported\n *\n * Boolean operators: AND, OR, ANDNOT (not standard NOT)\n * Date filter: submittedDate:[YYYYMMDDHHmm TO YYYYMMDDHHmm]\n * Category filter: cat:cs.AI\n */\n\nimport type { QueryAST, QueryBlock, FieldType, Operator } from '../../query/types.js';\nimport type { TranslatedQuery } from '../base/types.js';\nimport { collectUnsupportedVocabWarnings } from '../base/warnings.js';\n\n/**\n * Field prefix mappings for arXiv API.\n */\nconst FIELD_PREFIXES: Partial<Record<FieldType, string>> = {\n title: 'ti:',\n abstract: 'abs:',\n author: 'au:',\n all: 'all:',\n // title_abstract requires expansion, not a direct prefix\n // keyword is not supported by arXiv\n};\n\n/**\n * Get the arXiv field prefix for a DSL field type.\n * Returns null if the field requires special handling or is unsupported.\n */\nexport function translateFieldPrefix(field: FieldType): string | null {\n return FIELD_PREFIXES[field] ?? null;\n}\n\n/**\n * Wrap a term in quotes if it contains spaces (phrase search).\n */\nfunction quoteIfNeeded(term: string): string {\n return term.includes(' ') ? `\"${term}\"` : term;\n}\n\n/**\n * Translate terms with a field prefix.\n * Handles quoting of multi-word phrases.\n */\nexport function translateTerms(prefix: string, keywords: string[], operator: Operator): string {\n if (keywords.length === 0) {\n return '';\n }\n\n const translatedTerms = keywords.map((keyword) => `${prefix}${quoteIfNeeded(keyword)}`);\n\n if (translatedTerms.length === 1) {\n return translatedTerms[0]!;\n }\n\n return `(${translatedTerms.join(` ${operator} `)})`;\n}\n\n/**\n * Translate a single query block to arXiv syntax.\n * Returns an object with the main query part and optional ANDNOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const { field, terms, operator } = block;\n\n // arXiv only uses keywords; ignore mesh and emtree\n const keywords = terms.keywords ?? [];\n\n let query = '';\n\n if (keywords.length > 0) {\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n query = translateTitleAbstract(keywords, operator);\n } else {\n // Get field prefix\n const prefix = translateFieldPrefix(field);\n if (prefix !== null) {\n query = translateTerms(prefix, keywords, operator);\n }\n }\n }\n\n // Translate exclude terms\n const notClause = terms.exclude\n ? translateExcludeTerms(terms.exclude, field)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Expand title_abstract to (ti: OR abs:) for each keyword.\n */\nfunction translateTitleAbstract(keywords: string[], operator: Operator): string {\n if (keywords.length === 0) {\n return '';\n }\n\n // Each keyword expands to (ti:keyword OR abs:keyword)\n const expandedTerms = keywords.map((keyword) => {\n const quoted = quoteIfNeeded(keyword);\n return `(ti:${quoted} OR abs:${quoted})`;\n });\n\n if (expandedTerms.length === 1) {\n return expandedTerms[0]!;\n }\n\n return `(${expandedTerms.join(` ${operator} `)})`;\n}\n\n/**\n * Translate exclude terms to ANDNOT clause.\n * arXiv uses ANDNOT instead of NOT.\n */\nfunction translateExcludeTerms(\n exclude: string[],\n field: FieldType\n): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n const expandedTerms = exclude.map((term) => {\n const quoted = quoteIfNeeded(term);\n return `(ti:${quoted} OR abs:${quoted})`;\n });\n if (expandedTerms.length === 1) {\n return `ANDNOT (${expandedTerms[0]})`;\n }\n return `ANDNOT (${expandedTerms.join(' OR ')})`;\n }\n\n // Get field prefix\n const prefix = translateFieldPrefix(field);\n if (prefix === null) {\n // Unsupported field\n return null;\n }\n\n const translatedTerms = exclude.map((term) => `${prefix}${quoteIfNeeded(term)}`);\n\n if (translatedTerms.length === 1) {\n return `ANDNOT ${translatedTerms[0]}`;\n }\n return `ANDNOT (${translatedTerms.join(' OR ')})`;\n}\n\n/**\n * Translate date filter to arXiv submittedDate range.\n * Format: submittedDate:[YYYYMMDDHHmm TO YYYYMMDDHHmm]\n * Note: arXiv API does not support wildcards (*), so we use concrete dates:\n * - Start: 1991 (arXiv's founding year)\n * - End: current year + 1 (to include all future submissions)\n */\nfunction translateDateFilter(yearFrom?: number, yearTo?: number): string {\n if (yearFrom === undefined && yearTo === undefined) {\n return '';\n }\n\n // arXiv was founded in 1991, use as default start\n const fromDate = yearFrom !== undefined ? `${yearFrom}01010000` : '199101010000';\n // Use next year as default end to include all current submissions\n const defaultEndYear = new Date().getFullYear() + 1;\n const toDate = yearTo !== undefined ? `${yearTo}12312359` : `${defaultEndYear}12312359`;\n\n return `submittedDate:[${fromDate} TO ${toDate}]`;\n}\n\n/**\n * Translate arXiv category filter.\n */\nfunction translateCategories(categories: string[]): string {\n if (categories.length === 0) {\n return '';\n }\n\n const catTerms = categories.map((cat) => `cat:${cat}`);\n\n if (catTerms.length === 1) {\n return catTerms[0]!;\n }\n\n return `(${catTerms.join(' OR ')})`;\n}\n\n/**\n * Translate a complete QueryAST to arXiv-native syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n const parts: string[] = [];\n const notClauses: string[] = [];\n\n // Translate all blocks (AND'd together)\n const blockResults = ast.blocks.map(translateBlock);\n const blockParts = blockResults.map((r) => r.query).filter((part) => part !== '');\n const blockNotClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n notClauses.push(...blockNotClauses);\n\n if (blockParts.length > 0) {\n if (blockParts.length === 1) {\n parts.push(blockParts[0]!);\n } else {\n parts.push(blockParts.map((part) => `(${part})`).join(' AND '));\n }\n }\n\n // Add date filter if present\n const dateFilter = translateDateFilter(ast.filters.yearFrom, ast.filters.yearTo);\n if (dateFilter) {\n parts.push(`(${dateFilter})`);\n }\n\n // Add category filter from arXiv overrides\n const arxivOverrides = ast.overrides.arxiv;\n if (arxivOverrides?.categories && arxivOverrides.categories.length > 0) {\n const categoryFilter = translateCategories(arxivOverrides.categories);\n if (categoryFilter) {\n parts.push(`(${categoryFilter})`);\n }\n }\n\n // Combine all parts with AND\n let native: string;\n if (parts.length === 0) {\n native = '';\n } else if (parts.length === 1) {\n native = parts[0]!;\n } else {\n native = parts.join(' AND ');\n }\n\n // Append ANDNOT clauses\n for (const notClause of notClauses) {\n if (native) {\n native = `${native} ${notClause}`;\n } else {\n native = notClause;\n }\n }\n\n // Collect warnings for unsupported controlled vocabulary\n // arXiv does not support any controlled vocabulary\n const warnings = collectUnsupportedVocabWarnings(ast.blocks, 'arXiv', new Set());\n\n return {\n native,\n originalAst: ast,\n provider: 'arxiv',\n ...(warnings.length > 0 ? { warnings } : {}),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -49,6 +49,8 @@ export interface TranslatedQuery {
49
49
  originalAst?: QueryAST;
50
50
  /** Provider that produced this translation */
51
51
  provider: ProviderName;
52
+ /** Warnings about unsupported controlled vocabulary */
53
+ warnings?: string[];
52
54
  }
53
55
  /**
54
56
  * Search options for controlling query execution.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/base/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/base/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../../src/providers/base/types.ts"],"sourcesContent":["/**\n * Provider base types for the search-hub CLI tool.\n * These types define the common interface for all database providers.\n */\n\nimport type { QueryAST } from '../../query/types.js';\n\n// Re-export QueryAST for convenience\nexport type { QueryAST };\n\n/**\n * Supported provider names.\n */\nexport type ProviderName =\n | 'pubmed'\n | 'eric'\n | 'arxiv'\n | 'scopus'\n | 'wos'\n | 'embase';\n\n/**\n * Author information.\n */\nexport interface Author {\n /** Last name (required) */\n family: string;\n /** First name */\n given?: string;\n /** Institutional affiliation */\n affiliation?: string;\n /** ORCID identifier */\n orcid?: string;\n}\n\n/**\n * Represents a single search result from any database.\n * At least one identifier (doi, pmid, arxivId, scopusId, ericId) is required.\n */\nexport interface Article {\n // Identifiers (at least one required)\n doi?: string;\n pmid?: string;\n arxivId?: string;\n scopusId?: string;\n ericId?: string;\n\n // Required fields\n title: string;\n authors: Author[];\n source: ProviderName;\n retrievedAt: string; // ISO 8601 format\n\n // Optional fields\n abstract?: string;\n publicationDate?: string;\n journal?: string;\n volume?: string;\n issue?: string;\n pages?: string;\n rawResponse?: unknown;\n}\n\n/**\n * Result of translating a query to database-native syntax.\n */\nexport interface TranslatedQuery {\n /** Database-native query string */\n native: string;\n /** Reference to original AST (optional for direct query mode) */\n originalAst?: QueryAST;\n /** Provider that produced this translation */\n provider: ProviderName;\n}\n\n/**\n * Search options for controlling query execution.\n */\nexport interface SearchOptions {\n /** Maximum number of results to retrieve */\n maxResults?: number;\n /** Number of results per page/request */\n pageSize?: number;\n /** Date range filter */\n dateRange?: {\n start: string;\n end: string;\n };\n /** AbortSignal for cancellation */\n signal?: AbortSignal;\n}\n\n/**\n * Result of a connection test.\n */\nexport interface ConnectionTestResult {\n /** Whether the connection succeeded */\n ok: boolean;\n /** Error message if the connection failed */\n error?: string;\n}\n\n/**\n * Core provider interface that all database providers must implement.\n */\nexport interface Provider {\n /** Provider name identifier */\n readonly name: ProviderName;\n\n /**\n * Execute search and return results as async iterable (streaming).\n */\n search(\n query: TranslatedQuery,\n options?: SearchOptions\n ): AsyncIterable<Article>;\n\n /**\n * Get total hit count for a query without downloading results.\n * Used for count-only mode during query refinement.\n */\n count(query: TranslatedQuery): Promise<number>;\n\n /**\n * Convert QueryAST to database-native syntax.\n */\n translateQuery(ast: QueryAST): TranslatedQuery;\n\n /**\n * Verify API access and credentials.\n * Returns { ok: true } on success, { ok: false, error: string } on failure.\n * Does not throw.\n */\n testConnection(): Promise<ConnectionTestResult>;\n}\n\n/**\n * Error codes used by providers.\n */\nexport type ProviderErrorCode =\n | 'PROVIDER_NOT_AVAILABLE'\n | 'API_KEY_MISSING'\n | 'API_KEY_INVALID'\n | 'ACCESS_DENIED'\n | 'RATE_LIMIT_EXCEEDED'\n | 'NETWORK_ERROR'\n | 'PARSE_ERROR'\n | 'QUERY_ERROR'\n | 'SERVER_ERROR'\n | 'TIMEOUT';\n\n/**\n * Base error type for provider errors.\n */\nexport interface ProviderError {\n code: ProviderErrorCode;\n message: string;\n provider: ProviderName;\n retryable: boolean;\n cause?: unknown;\n}\n\n/**\n * Rate limit exceeded error with retry information.\n */\nexport interface RateLimitError extends ProviderError {\n code: 'RATE_LIMIT_EXCEEDED';\n /** Time to wait before retrying (in milliseconds) */\n retryAfter?: number;\n}\n\n/**\n * Authentication/authorization error.\n */\nexport interface AuthError extends ProviderError {\n code: 'API_KEY_MISSING' | 'API_KEY_INVALID' | 'ACCESS_DENIED';\n}\n\n/**\n * Create a provider error.\n */\nexport function createProviderError(\n code: ProviderErrorCode,\n message: string,\n provider: ProviderName,\n options?: { retryable?: boolean; cause?: unknown }\n): ProviderError {\n return {\n code,\n message,\n provider,\n retryable: options?.retryable ?? false,\n cause: options?.cause,\n };\n}\n\n/**\n * Check if an error is a provider error.\n */\nexport function isProviderError(error: unknown): error is ProviderError {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const e = error as Record<string, unknown>;\n return (\n typeof e['code'] === 'string' &&\n typeof e['message'] === 'string' &&\n typeof e['provider'] === 'string' &&\n typeof e['retryable'] === 'boolean'\n );\n}\n\n/**\n * Check if an error is a rate limit error.\n */\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return isProviderError(error) && error.code === 'RATE_LIMIT_EXCEEDED';\n}\n\n/**\n * Check if an error is an auth error.\n */\nexport function isAuthError(error: unknown): error is AuthError {\n return (\n isProviderError(error) &&\n (error.code === 'API_KEY_MISSING' || error.code === 'API_KEY_INVALID' || error.code === 'ACCESS_DENIED')\n );\n}\n\n/**\n * Represents the current state of a search for session persistence.\n * Used to resume searches after interruption or application restart.\n */\nexport interface SearchState {\n /** Provider that produced this state */\n provider: ProviderName;\n /** The query being executed */\n query: TranslatedQuery;\n /** Total number of results available */\n totalResults: number;\n /** Number of results retrieved so far */\n retrievedCount: number;\n /** When the state was last updated */\n lastUpdated: Date;\n /** Provider-specific state (e.g., PubMed webenv/querykey, or offset for other providers) */\n providerState?: unknown;\n}\n\n/**\n * Result of validating a search state for resume.\n */\nexport interface SearchResumeResult {\n /** Whether the state is valid for resuming */\n valid: boolean;\n /** Reason if the state is invalid */\n reason?: string;\n}\n"],"names":[],"mappings":"AAqLO,SAAS,oBACd,MACA,SACA,UACA,SACe;AACf,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,SAAS,aAAa;AAAA,IACjC,OAAO,SAAS;AAAA,EAAA;AAEpB;AAKO,SAAS,gBAAgB,OAAwC;AACtE,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AACA,QAAM,IAAI;AACV,SACE,OAAO,EAAE,MAAM,MAAM,YACrB,OAAO,EAAE,SAAS,MAAM,YACxB,OAAO,EAAE,UAAU,MAAM,YACzB,OAAO,EAAE,WAAW,MAAM;AAE9B;AAKO,SAAS,iBAAiB,OAAyC;AACxE,SAAO,gBAAgB,KAAK,KAAK,MAAM,SAAS;AAClD;AAKO,SAAS,YAAY,OAAoC;AAC9D,SACE,gBAAgB,KAAK,MACpB,MAAM,SAAS,qBAAqB,MAAM,SAAS,qBAAqB,MAAM,SAAS;AAE5F;"}
1
+ {"version":3,"file":"types.js","sources":["../../../src/providers/base/types.ts"],"sourcesContent":["/**\n * Provider base types for the search-hub CLI tool.\n * These types define the common interface for all database providers.\n */\n\nimport type { QueryAST } from '../../query/types.js';\n\n// Re-export QueryAST for convenience\nexport type { QueryAST };\n\n/**\n * Supported provider names.\n */\nexport type ProviderName =\n | 'pubmed'\n | 'eric'\n | 'arxiv'\n | 'scopus'\n | 'wos'\n | 'embase';\n\n/**\n * Author information.\n */\nexport interface Author {\n /** Last name (required) */\n family: string;\n /** First name */\n given?: string;\n /** Institutional affiliation */\n affiliation?: string;\n /** ORCID identifier */\n orcid?: string;\n}\n\n/**\n * Represents a single search result from any database.\n * At least one identifier (doi, pmid, arxivId, scopusId, ericId) is required.\n */\nexport interface Article {\n // Identifiers (at least one required)\n doi?: string;\n pmid?: string;\n arxivId?: string;\n scopusId?: string;\n ericId?: string;\n\n // Required fields\n title: string;\n authors: Author[];\n source: ProviderName;\n retrievedAt: string; // ISO 8601 format\n\n // Optional fields\n abstract?: string;\n publicationDate?: string;\n journal?: string;\n volume?: string;\n issue?: string;\n pages?: string;\n rawResponse?: unknown;\n}\n\n/**\n * Result of translating a query to database-native syntax.\n */\nexport interface TranslatedQuery {\n /** Database-native query string */\n native: string;\n /** Reference to original AST (optional for direct query mode) */\n originalAst?: QueryAST;\n /** Provider that produced this translation */\n provider: ProviderName;\n /** Warnings about unsupported controlled vocabulary */\n warnings?: string[];\n}\n\n/**\n * Search options for controlling query execution.\n */\nexport interface SearchOptions {\n /** Maximum number of results to retrieve */\n maxResults?: number;\n /** Number of results per page/request */\n pageSize?: number;\n /** Date range filter */\n dateRange?: {\n start: string;\n end: string;\n };\n /** AbortSignal for cancellation */\n signal?: AbortSignal;\n}\n\n/**\n * Result of a connection test.\n */\nexport interface ConnectionTestResult {\n /** Whether the connection succeeded */\n ok: boolean;\n /** Error message if the connection failed */\n error?: string;\n}\n\n/**\n * Core provider interface that all database providers must implement.\n */\nexport interface Provider {\n /** Provider name identifier */\n readonly name: ProviderName;\n\n /**\n * Execute search and return results as async iterable (streaming).\n */\n search(\n query: TranslatedQuery,\n options?: SearchOptions\n ): AsyncIterable<Article>;\n\n /**\n * Get total hit count for a query without downloading results.\n * Used for count-only mode during query refinement.\n */\n count(query: TranslatedQuery): Promise<number>;\n\n /**\n * Convert QueryAST to database-native syntax.\n */\n translateQuery(ast: QueryAST): TranslatedQuery;\n\n /**\n * Verify API access and credentials.\n * Returns { ok: true } on success, { ok: false, error: string } on failure.\n * Does not throw.\n */\n testConnection(): Promise<ConnectionTestResult>;\n}\n\n/**\n * Error codes used by providers.\n */\nexport type ProviderErrorCode =\n | 'PROVIDER_NOT_AVAILABLE'\n | 'API_KEY_MISSING'\n | 'API_KEY_INVALID'\n | 'ACCESS_DENIED'\n | 'RATE_LIMIT_EXCEEDED'\n | 'NETWORK_ERROR'\n | 'PARSE_ERROR'\n | 'QUERY_ERROR'\n | 'SERVER_ERROR'\n | 'TIMEOUT';\n\n/**\n * Base error type for provider errors.\n */\nexport interface ProviderError {\n code: ProviderErrorCode;\n message: string;\n provider: ProviderName;\n retryable: boolean;\n cause?: unknown;\n}\n\n/**\n * Rate limit exceeded error with retry information.\n */\nexport interface RateLimitError extends ProviderError {\n code: 'RATE_LIMIT_EXCEEDED';\n /** Time to wait before retrying (in milliseconds) */\n retryAfter?: number;\n}\n\n/**\n * Authentication/authorization error.\n */\nexport interface AuthError extends ProviderError {\n code: 'API_KEY_MISSING' | 'API_KEY_INVALID' | 'ACCESS_DENIED';\n}\n\n/**\n * Create a provider error.\n */\nexport function createProviderError(\n code: ProviderErrorCode,\n message: string,\n provider: ProviderName,\n options?: { retryable?: boolean; cause?: unknown }\n): ProviderError {\n return {\n code,\n message,\n provider,\n retryable: options?.retryable ?? false,\n cause: options?.cause,\n };\n}\n\n/**\n * Check if an error is a provider error.\n */\nexport function isProviderError(error: unknown): error is ProviderError {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const e = error as Record<string, unknown>;\n return (\n typeof e['code'] === 'string' &&\n typeof e['message'] === 'string' &&\n typeof e['provider'] === 'string' &&\n typeof e['retryable'] === 'boolean'\n );\n}\n\n/**\n * Check if an error is a rate limit error.\n */\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return isProviderError(error) && error.code === 'RATE_LIMIT_EXCEEDED';\n}\n\n/**\n * Check if an error is an auth error.\n */\nexport function isAuthError(error: unknown): error is AuthError {\n return (\n isProviderError(error) &&\n (error.code === 'API_KEY_MISSING' || error.code === 'API_KEY_INVALID' || error.code === 'ACCESS_DENIED')\n );\n}\n\n/**\n * Represents the current state of a search for session persistence.\n * Used to resume searches after interruption or application restart.\n */\nexport interface SearchState {\n /** Provider that produced this state */\n provider: ProviderName;\n /** The query being executed */\n query: TranslatedQuery;\n /** Total number of results available */\n totalResults: number;\n /** Number of results retrieved so far */\n retrievedCount: number;\n /** When the state was last updated */\n lastUpdated: Date;\n /** Provider-specific state (e.g., PubMed webenv/querykey, or offset for other providers) */\n providerState?: unknown;\n}\n\n/**\n * Result of validating a search state for resume.\n */\nexport interface SearchResumeResult {\n /** Whether the state is valid for resuming */\n valid: boolean;\n /** Reason if the state is invalid */\n reason?: string;\n}\n"],"names":[],"mappings":"AAuLO,SAAS,oBACd,MACA,SACA,UACA,SACe;AACf,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,SAAS,aAAa;AAAA,IACjC,OAAO,SAAS;AAAA,EAAA;AAEpB;AAKO,SAAS,gBAAgB,OAAwC;AACtE,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AACA,QAAM,IAAI;AACV,SACE,OAAO,EAAE,MAAM,MAAM,YACrB,OAAO,EAAE,SAAS,MAAM,YACxB,OAAO,EAAE,UAAU,MAAM,YACzB,OAAO,EAAE,WAAW,MAAM;AAE9B;AAKO,SAAS,iBAAiB,OAAyC;AACxE,SAAO,gBAAgB,KAAK,KAAK,MAAM,SAAS;AAClD;AAKO,SAAS,YAAY,OAAoC;AAC9D,SACE,gBAAgB,KAAK,MACpB,MAAM,SAAS,qBAAqB,MAAM,SAAS,qBAAqB,MAAM,SAAS;AAE5F;"}
@@ -0,0 +1,14 @@
1
+ import { QueryBlock } from '../../query/types';
2
+ /** Controlled vocabulary types that can appear in a TermBlock */
3
+ type VocabType = 'mesh' | 'emtree' | 'eric';
4
+ /**
5
+ * Collect warnings for unsupported controlled vocabulary in query blocks.
6
+ *
7
+ * @param blocks - Query blocks to check
8
+ * @param providerDisplayName - Display name of the provider (e.g., "arXiv", "Scopus")
9
+ * @param supportedVocab - Set of controlled vocabulary types this provider supports
10
+ * @returns Array of warning messages
11
+ */
12
+ export declare function collectUnsupportedVocabWarnings(blocks: QueryBlock[], providerDisplayName: string, supportedVocab: ReadonlySet<VocabType>): string[];
13
+ export {};
14
+ //# sourceMappingURL=warnings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.d.ts","sourceRoot":"","sources":["../../../src/providers/base/warnings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,iEAAiE;AACjE,KAAK,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAS5C;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,UAAU,EAAE,EACpB,mBAAmB,EAAE,MAAM,EAC3B,cAAc,EAAE,WAAW,CAAC,SAAS,CAAC,GACrC,MAAM,EAAE,CAyBV"}
@@ -0,0 +1,33 @@
1
+ const VOCAB_DISPLAY_NAMES = {
2
+ mesh: "MeSH",
3
+ emtree: "Emtree",
4
+ eric: "ERIC descriptor"
5
+ };
6
+ function collectUnsupportedVocabWarnings(blocks, providerDisplayName, supportedVocab) {
7
+ const warnings = [];
8
+ const vocabTypes = ["mesh", "emtree", "eric"];
9
+ for (let i = 0; i < blocks.length; i++) {
10
+ const block = blocks[i];
11
+ const hasKeywords = block.terms.keywords && block.terms.keywords.length > 0;
12
+ for (const vocab of vocabTypes) {
13
+ if (!supportedVocab.has(vocab) && block.terms[vocab] && block.terms[vocab].length > 0) {
14
+ const displayName = VOCAB_DISPLAY_NAMES[vocab];
15
+ const blockNum = i + 1;
16
+ if (hasKeywords) {
17
+ warnings.push(
18
+ `${providerDisplayName}: ${displayName} terms in block ${blockNum} ignored (not supported) — keywords still searched`
19
+ );
20
+ } else {
21
+ warnings.push(
22
+ `${providerDisplayName}: block ${blockNum} skipped (contains only ${displayName} terms, not supported)`
23
+ );
24
+ }
25
+ }
26
+ }
27
+ }
28
+ return warnings;
29
+ }
30
+ export {
31
+ collectUnsupportedVocabWarnings
32
+ };
33
+ //# sourceMappingURL=warnings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.js","sources":["../../../src/providers/base/warnings.ts"],"sourcesContent":["/**\n * Unsupported controlled vocabulary warnings.\n *\n * Generates warnings when query blocks contain controlled vocabulary\n * terms that the target provider does not support.\n */\n\nimport type { QueryBlock } from '../../query/types';\n\n/** Controlled vocabulary types that can appear in a TermBlock */\ntype VocabType = 'mesh' | 'emtree' | 'eric';\n\n/** Human-readable names for controlled vocabulary types */\nconst VOCAB_DISPLAY_NAMES: Record<VocabType, string> = {\n mesh: 'MeSH',\n emtree: 'Emtree',\n eric: 'ERIC descriptor',\n};\n\n/**\n * Collect warnings for unsupported controlled vocabulary in query blocks.\n *\n * @param blocks - Query blocks to check\n * @param providerDisplayName - Display name of the provider (e.g., \"arXiv\", \"Scopus\")\n * @param supportedVocab - Set of controlled vocabulary types this provider supports\n * @returns Array of warning messages\n */\nexport function collectUnsupportedVocabWarnings(\n blocks: QueryBlock[],\n providerDisplayName: string,\n supportedVocab: ReadonlySet<VocabType>\n): string[] {\n const warnings: string[] = [];\n const vocabTypes: VocabType[] = ['mesh', 'emtree', 'eric'];\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i]!;\n const hasKeywords = block.terms.keywords && block.terms.keywords.length > 0;\n for (const vocab of vocabTypes) {\n if (!supportedVocab.has(vocab) && block.terms[vocab] && block.terms[vocab].length > 0) {\n const displayName = VOCAB_DISPLAY_NAMES[vocab];\n const blockNum = i + 1;\n if (hasKeywords) {\n warnings.push(\n `${providerDisplayName}: ${displayName} terms in block ${blockNum} ignored (not supported) — keywords still searched`\n );\n } else {\n warnings.push(\n `${providerDisplayName}: block ${blockNum} skipped (contains only ${displayName} terms, not supported)`\n );\n }\n }\n }\n }\n\n return warnings;\n}\n"],"names":[],"mappings":"AAaA,MAAM,sBAAiD;AAAA,EACrD,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AACR;AAUO,SAAS,gCACd,QACA,qBACA,gBACU;AACV,QAAM,WAAqB,CAAA;AAC3B,QAAM,aAA0B,CAAC,QAAQ,UAAU,MAAM;AAEzD,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,QAAQ,OAAO,CAAC;AACtB,UAAM,cAAc,MAAM,MAAM,YAAY,MAAM,MAAM,SAAS,SAAS;AAC1E,eAAW,SAAS,YAAY;AAC9B,UAAI,CAAC,eAAe,IAAI,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,EAAE,SAAS,GAAG;AACrF,cAAM,cAAc,oBAAoB,KAAK;AAC7C,cAAM,WAAW,IAAI;AACrB,YAAI,aAAa;AACf,mBAAS;AAAA,YACP,GAAG,mBAAmB,KAAK,WAAW,mBAAmB,QAAQ;AAAA,UAAA;AAAA,QAErE,OAAO;AACL,mBAAS;AAAA,YACP,GAAG,mBAAmB,WAAW,QAAQ,2BAA2B,WAAW;AAAA,UAAA;AAAA,QAEnF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;"}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/eric/translator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAuB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA6IrD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CA0ChE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAE7D"}
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/eric/translator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAuB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA8IrD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CA+ChE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAE7D"}
@@ -1,3 +1,4 @@
1
+ import { collectUnsupportedVocabWarnings } from "../base/warnings.js";
1
2
  const FIELD_PREFIXES = {
2
3
  title: "title:",
3
4
  abstract: "description:",
@@ -42,7 +43,7 @@ function translateEricDescriptors(descriptors) {
42
43
  }
43
44
  function translateBlock(block) {
44
45
  const { field, terms, operator } = block;
45
- const keywords = terms.keywords;
46
+ const keywords = terms.keywords ?? [];
46
47
  const eric = terms.eric ?? [];
47
48
  const allTerms = [];
48
49
  if (keywords.length > 0) {
@@ -105,10 +106,12 @@ function translateQueryAST(ast) {
105
106
  native = dateFilter;
106
107
  }
107
108
  }
109
+ const warnings = collectUnsupportedVocabWarnings(ast.blocks, "ERIC", /* @__PURE__ */ new Set(["eric"]));
108
110
  return {
109
111
  native,
110
112
  originalAst: ast,
111
- provider: "eric"
113
+ provider: "eric",
114
+ ...warnings.length > 0 ? { warnings } : {}
112
115
  };
113
116
  }
114
117
  function translateQuery(ast) {
@@ -1 +1 @@
1
- {"version":3,"file":"translator.js","sources":["../../../src/providers/eric/translator.ts"],"sourcesContent":["/**\n * ERIC query translator.\n * Converts QueryAST to ERIC-native query syntax.\n */\n\nimport type { QueryAST, QueryBlock, Filters } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\n\n/**\n * Field prefix mappings for ERIC.\n * Maps DSL field types to ERIC query syntax prefixes.\n */\nconst FIELD_PREFIXES: Record<string, string> = {\n title: 'title:',\n abstract: 'description:', // ERIC uses 'description' field for abstracts\n author: 'author:',\n keyword: 'subject:', // ERIC uses subject for descriptors\n all: '', // No prefix for all-field search\n};\n\n/**\n * Check if a term needs quoting (contains spaces or special characters).\n */\nfunction needsQuotes(term: string): boolean {\n return /\\s|[()[\\]{}:\"]/.test(term);\n}\n\n/**\n * Format a term with optional field prefix.\n * Quotes multi-word phrases automatically.\n */\nfunction formatTerm(term: string, prefix: string): string {\n const quoted = needsQuotes(term) ? `\"${term}\"` : term;\n return `${prefix}${quoted}`;\n}\n\n/**\n * Translate a single term for title_abstract field.\n * Expands to (title:term OR description:term).\n * Note: ERIC uses 'description' field for abstracts.\n */\nfunction translateTitleAbstractTerm(term: string): string {\n const quoted = needsQuotes(term) ? `\"${term}\"` : term;\n return `(title:${quoted} OR description:${quoted})`;\n}\n\n/**\n * Translate exclude terms to NOT clause.\n */\nfunction translateExcludeTerms(\n exclude: string[],\n field: QueryBlock['field']\n): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n const expandedTerms = exclude.map(translateTitleAbstractTerm);\n if (expandedTerms.length === 1) {\n return `NOT ${expandedTerms[0]}`;\n }\n return `NOT (${expandedTerms.join(' OR ')})`;\n }\n\n // Standard field translation\n const prefix = FIELD_PREFIXES[field] ?? '';\n const translatedTerms = exclude.map((term) => formatTerm(term, prefix));\n\n if (translatedTerms.length === 1) {\n return `NOT ${translatedTerms[0]}`;\n }\n return `NOT (${translatedTerms.join(' OR ')})`;\n}\n\n/**\n * Translate ERIC Descriptors to subject: field syntax.\n */\nfunction translateEricDescriptors(descriptors: string[]): string[] {\n return descriptors.map((term) => formatTerm(term, 'subject:'));\n}\n\n/**\n * Translate a single query block to ERIC syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const { field, terms, operator } = block;\n const keywords = terms.keywords;\n const eric = terms.eric ?? [];\n\n const allTerms: string[] = [];\n\n // Translate keywords\n if (keywords.length > 0) {\n // Handle title_abstract special case\n if (field === 'title_abstract') {\n const expandedTerms = keywords.map(translateTitleAbstractTerm);\n allTerms.push(...expandedTerms);\n } else {\n // Standard field translation\n const prefix = FIELD_PREFIXES[field] ?? '';\n const translatedTerms = keywords.map((term) => formatTerm(term, prefix));\n allTerms.push(...translatedTerms);\n }\n }\n\n // Translate ERIC Descriptors (always use subject: field)\n if (eric.length > 0) {\n const ericTerms = translateEricDescriptors(eric);\n allTerms.push(...ericTerms);\n }\n\n // Combine all terms\n let query = '';\n if (allTerms.length === 1) {\n query = allTerms[0]!;\n } else if (allTerms.length > 1) {\n query = `(${allTerms.join(` ${operator} `)})`;\n }\n\n // Translate exclude terms\n const notClause = terms.exclude\n ? translateExcludeTerms(terms.exclude, field)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Translate date filters to ERIC syntax.\n * ERIC uses publicationdateyear:[YYYY TO YYYY] format.\n */\nfunction translateDateFilters(filters: Filters): string | null {\n const { yearFrom, yearTo } = filters;\n\n if (yearFrom === undefined && yearTo === undefined) {\n return null;\n }\n\n const from = yearFrom !== undefined ? yearFrom.toString() : '*';\n const to = yearTo !== undefined ? yearTo.toString() : '*';\n\n return `publicationdateyear:[${from} TO ${to}]`;\n}\n\n/**\n * Translate a QueryAST to ERIC-native query syntax.\n */\nexport function translateQueryAST(ast: QueryAST): TranslatedQuery {\n const blockQueries: string[] = [];\n const notClauses: string[] = [];\n\n // Translate each block\n for (const block of ast.blocks) {\n const { query, notClause } = translateBlock(block);\n if (query) {\n blockQueries.push(query);\n }\n if (notClause) {\n notClauses.push(notClause);\n }\n }\n\n // Combine blocks with AND\n let native = blockQueries.join(' AND ');\n\n // Append NOT clauses\n for (const notClause of notClauses) {\n if (native) {\n native = `${native} ${notClause}`;\n } else {\n native = notClause;\n }\n }\n\n // Apply date filters\n const dateFilter = translateDateFilters(ast.filters);\n if (dateFilter) {\n if (native) {\n native = `${native} AND ${dateFilter}`;\n } else {\n native = dateFilter;\n }\n }\n\n return {\n native,\n originalAst: ast,\n provider: 'eric',\n };\n}\n\n/**\n * Translate a QueryAST to ERIC query.\n * This is the Provider interface method signature.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n return translateQueryAST(ast);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"translator.js","sources":["../../../src/providers/eric/translator.ts"],"sourcesContent":["/**\n * ERIC query translator.\n * Converts QueryAST to ERIC-native query syntax.\n */\n\nimport type { QueryAST, QueryBlock, Filters } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\nimport { collectUnsupportedVocabWarnings } from '../base/warnings';\n\n/**\n * Field prefix mappings for ERIC.\n * Maps DSL field types to ERIC query syntax prefixes.\n */\nconst FIELD_PREFIXES: Record<string, string> = {\n title: 'title:',\n abstract: 'description:', // ERIC uses 'description' field for abstracts\n author: 'author:',\n keyword: 'subject:', // ERIC uses subject for descriptors\n all: '', // No prefix for all-field search\n};\n\n/**\n * Check if a term needs quoting (contains spaces or special characters).\n */\nfunction needsQuotes(term: string): boolean {\n return /\\s|[()[\\]{}:\"]/.test(term);\n}\n\n/**\n * Format a term with optional field prefix.\n * Quotes multi-word phrases automatically.\n */\nfunction formatTerm(term: string, prefix: string): string {\n const quoted = needsQuotes(term) ? `\"${term}\"` : term;\n return `${prefix}${quoted}`;\n}\n\n/**\n * Translate a single term for title_abstract field.\n * Expands to (title:term OR description:term).\n * Note: ERIC uses 'description' field for abstracts.\n */\nfunction translateTitleAbstractTerm(term: string): string {\n const quoted = needsQuotes(term) ? `\"${term}\"` : term;\n return `(title:${quoted} OR description:${quoted})`;\n}\n\n/**\n * Translate exclude terms to NOT clause.\n */\nfunction translateExcludeTerms(\n exclude: string[],\n field: QueryBlock['field']\n): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n // Handle title_abstract expansion\n if (field === 'title_abstract') {\n const expandedTerms = exclude.map(translateTitleAbstractTerm);\n if (expandedTerms.length === 1) {\n return `NOT ${expandedTerms[0]}`;\n }\n return `NOT (${expandedTerms.join(' OR ')})`;\n }\n\n // Standard field translation\n const prefix = FIELD_PREFIXES[field] ?? '';\n const translatedTerms = exclude.map((term) => formatTerm(term, prefix));\n\n if (translatedTerms.length === 1) {\n return `NOT ${translatedTerms[0]}`;\n }\n return `NOT (${translatedTerms.join(' OR ')})`;\n}\n\n/**\n * Translate ERIC Descriptors to subject: field syntax.\n */\nfunction translateEricDescriptors(descriptors: string[]): string[] {\n return descriptors.map((term) => formatTerm(term, 'subject:'));\n}\n\n/**\n * Translate a single query block to ERIC syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const { field, terms, operator } = block;\n const keywords = terms.keywords ?? [];\n const eric = terms.eric ?? [];\n\n const allTerms: string[] = [];\n\n // Translate keywords\n if (keywords.length > 0) {\n // Handle title_abstract special case\n if (field === 'title_abstract') {\n const expandedTerms = keywords.map(translateTitleAbstractTerm);\n allTerms.push(...expandedTerms);\n } else {\n // Standard field translation\n const prefix = FIELD_PREFIXES[field] ?? '';\n const translatedTerms = keywords.map((term) => formatTerm(term, prefix));\n allTerms.push(...translatedTerms);\n }\n }\n\n // Translate ERIC Descriptors (always use subject: field)\n if (eric.length > 0) {\n const ericTerms = translateEricDescriptors(eric);\n allTerms.push(...ericTerms);\n }\n\n // Combine all terms\n let query = '';\n if (allTerms.length === 1) {\n query = allTerms[0]!;\n } else if (allTerms.length > 1) {\n query = `(${allTerms.join(` ${operator} `)})`;\n }\n\n // Translate exclude terms\n const notClause = terms.exclude\n ? translateExcludeTerms(terms.exclude, field)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Translate date filters to ERIC syntax.\n * ERIC uses publicationdateyear:[YYYY TO YYYY] format.\n */\nfunction translateDateFilters(filters: Filters): string | null {\n const { yearFrom, yearTo } = filters;\n\n if (yearFrom === undefined && yearTo === undefined) {\n return null;\n }\n\n const from = yearFrom !== undefined ? yearFrom.toString() : '*';\n const to = yearTo !== undefined ? yearTo.toString() : '*';\n\n return `publicationdateyear:[${from} TO ${to}]`;\n}\n\n/**\n * Translate a QueryAST to ERIC-native query syntax.\n */\nexport function translateQueryAST(ast: QueryAST): TranslatedQuery {\n const blockQueries: string[] = [];\n const notClauses: string[] = [];\n\n // Translate each block\n for (const block of ast.blocks) {\n const { query, notClause } = translateBlock(block);\n if (query) {\n blockQueries.push(query);\n }\n if (notClause) {\n notClauses.push(notClause);\n }\n }\n\n // Combine blocks with AND\n let native = blockQueries.join(' AND ');\n\n // Append NOT clauses\n for (const notClause of notClauses) {\n if (native) {\n native = `${native} ${notClause}`;\n } else {\n native = notClause;\n }\n }\n\n // Apply date filters\n const dateFilter = translateDateFilters(ast.filters);\n if (dateFilter) {\n if (native) {\n native = `${native} AND ${dateFilter}`;\n } else {\n native = dateFilter;\n }\n }\n\n // Collect warnings for unsupported controlled vocabulary\n // ERIC supports eric descriptors but not mesh or emtree\n const warnings = collectUnsupportedVocabWarnings(ast.blocks, 'ERIC', new Set(['eric']));\n\n return {\n native,\n originalAst: ast,\n provider: 'eric',\n ...(warnings.length > 0 ? { warnings } : {}),\n };\n}\n\n/**\n * Translate a QueryAST to ERIC query.\n * This is the Provider interface method signature.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n return translateQueryAST(ast);\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/pubmed/translator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAkC,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAwMrD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAkE7D"}
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/pubmed/translator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAkC,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAyMrD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAuE7D"}
@@ -1,3 +1,4 @@
1
+ import { collectUnsupportedVocabWarnings } from "../base/warnings.js";
1
2
  const FIELD_QUALIFIERS = {
2
3
  title: "ti",
3
4
  abstract: "ab",
@@ -44,7 +45,7 @@ function translateExcludeTerms(exclude, qualifier) {
44
45
  function translateBlock(block) {
45
46
  const qualifier = FIELD_QUALIFIERS[block.field];
46
47
  const terms = [];
47
- for (const keyword of block.terms.keywords) {
48
+ for (const keyword of block.terms.keywords ?? []) {
48
49
  terms.push(translateTerm(keyword, qualifier));
49
50
  }
50
51
  if (block.terms.mesh) {
@@ -159,10 +160,12 @@ function translateQuery(ast) {
159
160
  } else {
160
161
  native = andSection;
161
162
  }
163
+ const warnings = collectUnsupportedVocabWarnings(ast.blocks, "PubMed", /* @__PURE__ */ new Set(["mesh"]));
162
164
  return {
163
165
  native,
164
166
  originalAst: ast,
165
- provider: "pubmed"
167
+ provider: "pubmed",
168
+ ...warnings.length > 0 ? { warnings } : {}
166
169
  };
167
170
  }
168
171
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"translator.js","sources":["../../../src/providers/pubmed/translator.ts"],"sourcesContent":["/**\n * PubMed query translator.\n * Converts QueryAST to PubMed E-utilities search syntax.\n */\n\nimport type { QueryAST, FieldType, QueryBlock, Filters } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\n\n/**\n * Field type to PubMed qualifier mapping.\n */\nconst FIELD_QUALIFIERS: Record<FieldType, string> = {\n title: 'ti',\n abstract: 'ab',\n title_abstract: 'tiab',\n author: 'au',\n keyword: 'mh',\n all: 'all',\n};\n\n/**\n * Language code to PubMed language name mapping.\n */\nconst LANGUAGE_NAMES: Record<string, string> = {\n en: 'english',\n ja: 'japanese',\n de: 'german',\n fr: 'french',\n es: 'spanish',\n it: 'italian',\n pt: 'portuguese',\n zh: 'chinese',\n ko: 'korean',\n ru: 'russian',\n};\n\n/**\n * Quote a term if it contains spaces and is not already quoted.\n */\nfunction quoteTerm(term: string): string {\n // Already quoted\n if (term.startsWith('\"') && term.endsWith('\"')) {\n return term;\n }\n // Contains spaces - needs quoting\n if (term.includes(' ')) {\n return `\"${term}\"`;\n }\n return term;\n}\n\n/**\n * Translate a single term with field qualifier.\n */\nfunction translateTerm(term: string, qualifier: string): string {\n const quoted = quoteTerm(term);\n return `${quoted}[${qualifier}]`;\n}\n\n/**\n * Translate exclude terms to NOT clause.\n */\nfunction translateExcludeTerms(exclude: string[], qualifier: string): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n const excludeTerms = exclude.map((term) => translateTerm(term, qualifier));\n\n if (excludeTerms.length === 1) {\n return `NOT ${excludeTerms[0]}`;\n }\n return `NOT (${excludeTerms.join(' OR ')})`;\n}\n\n/**\n * Translate a query block to PubMed syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const qualifier = FIELD_QUALIFIERS[block.field];\n const terms: string[] = [];\n\n // Translate keywords\n for (const keyword of block.terms.keywords) {\n terms.push(translateTerm(keyword, qualifier));\n }\n\n // Translate MeSH terms (always use [mh] regardless of field)\n if (block.terms.mesh) {\n for (const meshTerm of block.terms.mesh) {\n terms.push(translateTerm(meshTerm, 'mh'));\n }\n }\n\n // Build query part\n let query = '';\n if (terms.length === 1) {\n query = `(${terms[0]})`;\n } else if (terms.length > 1) {\n query = `(${terms.join(` ${block.operator} `)})`;\n }\n\n // Translate exclude terms\n const notClause = block.terms.exclude\n ? translateExcludeTerms(block.terms.exclude, qualifier)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Translate date filters to PubMed syntax.\n */\nfunction translateDateFilters(filters: Filters): string | null {\n const yearFrom = filters.yearFrom ?? 1900;\n const yearTo = filters.yearTo ?? 3000;\n\n if (filters.yearFrom !== undefined || filters.yearTo !== undefined) {\n return `${yearFrom}:${yearTo}[dp]`;\n }\n return null;\n}\n\n/**\n * Translate language filters to PubMed syntax.\n */\nfunction translateLanguageFilters(languages: string[]): string | null {\n if (languages.length === 0) {\n return null;\n }\n\n const langTerms = languages.map((code) => {\n const langName = LANGUAGE_NAMES[code] ?? code;\n return `${langName}[la]`;\n });\n\n if (langTerms.length === 1) {\n return langTerms[0]!;\n }\n return `(${langTerms.join(' OR ')})`;\n}\n\n/**\n * Translate publication type filters to PubMed syntax.\n */\nfunction translatePublicationTypeFilters(\n pubTypes: Filters['publicationTypes']\n): string[] {\n const filters: string[] = [];\n\n if (!pubTypes) {\n return filters;\n }\n\n // Include filters\n if (pubTypes.include && pubTypes.include.length > 0) {\n const includeTerms = pubTypes.include.map(\n (pt) => `\"${pt.toLowerCase()}\"[pt]`\n );\n if (includeTerms.length === 1) {\n filters.push(includeTerms[0]!);\n } else {\n filters.push(`(${includeTerms.join(' OR ')})`);\n }\n }\n\n // Exclude filters - single grouped NOT clause\n if (pubTypes.exclude && pubTypes.exclude.length > 0) {\n const excludeTerms = pubTypes.exclude.map((pt) => `${pt.toLowerCase()}[pt]`);\n if (excludeTerms.length === 1) {\n filters.push(`NOT ${excludeTerms[0]}`);\n } else {\n filters.push(`NOT (${excludeTerms.join(\" OR \")})`);\n }\n }\n\n return filters;\n}\n\n/**\n * Merge global filters with provider-specific overrides.\n */\nfunction mergeFilters(global: Filters, overrides?: Filters): Filters {\n if (!overrides) {\n return global;\n }\n\n return {\n yearFrom: overrides.yearFrom ?? global.yearFrom,\n yearTo: overrides.yearTo ?? global.yearTo,\n languages: overrides.languages ?? global.languages,\n publicationTypes: overrides.publicationTypes\n ? {\n include:\n overrides.publicationTypes.include ??\n global.publicationTypes?.include,\n exclude: [\n ...(global.publicationTypes?.exclude ?? []),\n ...(overrides.publicationTypes.exclude ?? []),\n ],\n }\n : global.publicationTypes,\n };\n}\n\n/**\n * Translate a QueryAST to PubMed search syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n // Merge filters with PubMed-specific overrides\n const pubmedOverride = ast.overrides.pubmed;\n const filters = mergeFilters(ast.filters, pubmedOverride?.filters);\n\n // Translate query blocks\n const blockResults = ast.blocks.map((block) => translateBlock(block));\n\n // Collect query parts and NOT clauses\n const blockStrings = blockResults\n .map((r) => r.query)\n .filter((s) => s.length > 0);\n const blockNotClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n // Build the main query\n const parts: string[] = [];\n\n // Add query blocks (AND'd together)\n if (blockStrings.length > 0) {\n parts.push(blockStrings.join(' AND '));\n }\n\n // Add date filter\n const dateFilter = translateDateFilters(filters);\n if (dateFilter) {\n parts.push(dateFilter);\n }\n\n // Add language filter\n if (filters.languages && filters.languages.length > 0) {\n const langFilter = translateLanguageFilters(filters.languages);\n if (langFilter) {\n parts.push(langFilter);\n }\n }\n\n // Add publication type filters\n const pubTypeFilters = translatePublicationTypeFilters(filters.publicationTypes);\n parts.push(...pubTypeFilters);\n\n // Add block-level NOT clauses (from exclude terms)\n parts.push(...blockNotClauses);\n\n // Separate NOT clauses from AND-joined parts\n // PubMed treats NOT as a standalone binary operator, not AND NOT\n const notParts = parts.filter((p) => p.startsWith('NOT '));\n const andParts = parts.filter((p) => !p.startsWith('NOT '));\n\n const andSection = andParts.join(' AND ');\n const notSection = notParts.join(' ');\n let native: string;\n if (andSection && notSection) {\n native = andSection + ' ' + notSection;\n } else if (notSection) {\n native = notSection;\n } else {\n native = andSection;\n }\n\n return {\n native,\n originalAst: ast,\n provider: 'pubmed',\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"translator.js","sources":["../../../src/providers/pubmed/translator.ts"],"sourcesContent":["/**\n * PubMed query translator.\n * Converts QueryAST to PubMed E-utilities search syntax.\n */\n\nimport type { QueryAST, FieldType, QueryBlock, Filters } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\nimport { collectUnsupportedVocabWarnings } from '../base/warnings';\n\n/**\n * Field type to PubMed qualifier mapping.\n */\nconst FIELD_QUALIFIERS: Record<FieldType, string> = {\n title: 'ti',\n abstract: 'ab',\n title_abstract: 'tiab',\n author: 'au',\n keyword: 'mh',\n all: 'all',\n};\n\n/**\n * Language code to PubMed language name mapping.\n */\nconst LANGUAGE_NAMES: Record<string, string> = {\n en: 'english',\n ja: 'japanese',\n de: 'german',\n fr: 'french',\n es: 'spanish',\n it: 'italian',\n pt: 'portuguese',\n zh: 'chinese',\n ko: 'korean',\n ru: 'russian',\n};\n\n/**\n * Quote a term if it contains spaces and is not already quoted.\n */\nfunction quoteTerm(term: string): string {\n // Already quoted\n if (term.startsWith('\"') && term.endsWith('\"')) {\n return term;\n }\n // Contains spaces - needs quoting\n if (term.includes(' ')) {\n return `\"${term}\"`;\n }\n return term;\n}\n\n/**\n * Translate a single term with field qualifier.\n */\nfunction translateTerm(term: string, qualifier: string): string {\n const quoted = quoteTerm(term);\n return `${quoted}[${qualifier}]`;\n}\n\n/**\n * Translate exclude terms to NOT clause.\n */\nfunction translateExcludeTerms(exclude: string[], qualifier: string): string | null {\n if (exclude.length === 0) {\n return null;\n }\n\n const excludeTerms = exclude.map((term) => translateTerm(term, qualifier));\n\n if (excludeTerms.length === 1) {\n return `NOT ${excludeTerms[0]}`;\n }\n return `NOT (${excludeTerms.join(' OR ')})`;\n}\n\n/**\n * Translate a query block to PubMed syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const qualifier = FIELD_QUALIFIERS[block.field];\n const terms: string[] = [];\n\n // Translate keywords\n for (const keyword of block.terms.keywords ?? []) {\n terms.push(translateTerm(keyword, qualifier));\n }\n\n // Translate MeSH terms (always use [mh] regardless of field)\n if (block.terms.mesh) {\n for (const meshTerm of block.terms.mesh) {\n terms.push(translateTerm(meshTerm, 'mh'));\n }\n }\n\n // Build query part\n let query = '';\n if (terms.length === 1) {\n query = `(${terms[0]})`;\n } else if (terms.length > 1) {\n query = `(${terms.join(` ${block.operator} `)})`;\n }\n\n // Translate exclude terms\n const notClause = block.terms.exclude\n ? translateExcludeTerms(block.terms.exclude, qualifier)\n : null;\n\n return { query, notClause };\n}\n\n/**\n * Translate date filters to PubMed syntax.\n */\nfunction translateDateFilters(filters: Filters): string | null {\n const yearFrom = filters.yearFrom ?? 1900;\n const yearTo = filters.yearTo ?? 3000;\n\n if (filters.yearFrom !== undefined || filters.yearTo !== undefined) {\n return `${yearFrom}:${yearTo}[dp]`;\n }\n return null;\n}\n\n/**\n * Translate language filters to PubMed syntax.\n */\nfunction translateLanguageFilters(languages: string[]): string | null {\n if (languages.length === 0) {\n return null;\n }\n\n const langTerms = languages.map((code) => {\n const langName = LANGUAGE_NAMES[code] ?? code;\n return `${langName}[la]`;\n });\n\n if (langTerms.length === 1) {\n return langTerms[0]!;\n }\n return `(${langTerms.join(' OR ')})`;\n}\n\n/**\n * Translate publication type filters to PubMed syntax.\n */\nfunction translatePublicationTypeFilters(\n pubTypes: Filters['publicationTypes']\n): string[] {\n const filters: string[] = [];\n\n if (!pubTypes) {\n return filters;\n }\n\n // Include filters\n if (pubTypes.include && pubTypes.include.length > 0) {\n const includeTerms = pubTypes.include.map(\n (pt) => `\"${pt.toLowerCase()}\"[pt]`\n );\n if (includeTerms.length === 1) {\n filters.push(includeTerms[0]!);\n } else {\n filters.push(`(${includeTerms.join(' OR ')})`);\n }\n }\n\n // Exclude filters - single grouped NOT clause\n if (pubTypes.exclude && pubTypes.exclude.length > 0) {\n const excludeTerms = pubTypes.exclude.map((pt) => `${pt.toLowerCase()}[pt]`);\n if (excludeTerms.length === 1) {\n filters.push(`NOT ${excludeTerms[0]}`);\n } else {\n filters.push(`NOT (${excludeTerms.join(\" OR \")})`);\n }\n }\n\n return filters;\n}\n\n/**\n * Merge global filters with provider-specific overrides.\n */\nfunction mergeFilters(global: Filters, overrides?: Filters): Filters {\n if (!overrides) {\n return global;\n }\n\n return {\n yearFrom: overrides.yearFrom ?? global.yearFrom,\n yearTo: overrides.yearTo ?? global.yearTo,\n languages: overrides.languages ?? global.languages,\n publicationTypes: overrides.publicationTypes\n ? {\n include:\n overrides.publicationTypes.include ??\n global.publicationTypes?.include,\n exclude: [\n ...(global.publicationTypes?.exclude ?? []),\n ...(overrides.publicationTypes.exclude ?? []),\n ],\n }\n : global.publicationTypes,\n };\n}\n\n/**\n * Translate a QueryAST to PubMed search syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n // Merge filters with PubMed-specific overrides\n const pubmedOverride = ast.overrides.pubmed;\n const filters = mergeFilters(ast.filters, pubmedOverride?.filters);\n\n // Translate query blocks\n const blockResults = ast.blocks.map((block) => translateBlock(block));\n\n // Collect query parts and NOT clauses\n const blockStrings = blockResults\n .map((r) => r.query)\n .filter((s) => s.length > 0);\n const blockNotClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n // Build the main query\n const parts: string[] = [];\n\n // Add query blocks (AND'd together)\n if (blockStrings.length > 0) {\n parts.push(blockStrings.join(' AND '));\n }\n\n // Add date filter\n const dateFilter = translateDateFilters(filters);\n if (dateFilter) {\n parts.push(dateFilter);\n }\n\n // Add language filter\n if (filters.languages && filters.languages.length > 0) {\n const langFilter = translateLanguageFilters(filters.languages);\n if (langFilter) {\n parts.push(langFilter);\n }\n }\n\n // Add publication type filters\n const pubTypeFilters = translatePublicationTypeFilters(filters.publicationTypes);\n parts.push(...pubTypeFilters);\n\n // Add block-level NOT clauses (from exclude terms)\n parts.push(...blockNotClauses);\n\n // Separate NOT clauses from AND-joined parts\n // PubMed treats NOT as a standalone binary operator, not AND NOT\n const notParts = parts.filter((p) => p.startsWith('NOT '));\n const andParts = parts.filter((p) => !p.startsWith('NOT '));\n\n const andSection = andParts.join(' AND ');\n const notSection = notParts.join(' ');\n let native: string;\n if (andSection && notSection) {\n native = andSection + ' ' + notSection;\n } else if (notSection) {\n native = notSection;\n } else {\n native = andSection;\n }\n\n // Collect warnings for unsupported controlled vocabulary\n // PubMed supports mesh but not emtree or eric\n const warnings = collectUnsupportedVocabWarnings(ast.blocks, 'PubMed', new Set(['mesh']));\n\n return {\n native,\n originalAst: ast,\n provider: 'pubmed',\n ...(warnings.length > 0 ? { warnings } : {}),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/scopus/translator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAiD,MAAM,mBAAmB,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAwHrD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CAuB7D"}
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../../../src/providers/scopus/translator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAiD,MAAM,mBAAmB,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA4IrD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,eAAe,CA8B7D"}
@@ -1,3 +1,4 @@
1
+ import { collectUnsupportedVocabWarnings } from "../base/warnings.js";
1
2
  const FIELD_MAP = {
2
3
  title: "TITLE",
3
4
  abstract: "ABS",
@@ -42,10 +43,24 @@ function quoteTerm(term) {
42
43
  }
43
44
  function translateBlock(block) {
44
45
  const field = FIELD_MAP[block.field];
45
- const terms = block.terms.keywords.map(quoteTerm);
46
46
  const operator = block.operator;
47
- const termsStr = terms.join(` ${operator} `);
48
- const query = `${field}(${termsStr})`;
47
+ const parts = [];
48
+ const keywords = (block.terms.keywords ?? []).map(quoteTerm);
49
+ if (keywords.length > 0) {
50
+ parts.push(`${field}(${keywords.join(` ${operator} `)})`);
51
+ }
52
+ const emtree = (block.terms.emtree ?? []).map(quoteTerm);
53
+ if (emtree.length > 0) {
54
+ parts.push(`INDEXTERMS(${emtree.join(` ${operator} `)})`);
55
+ }
56
+ let query;
57
+ if (parts.length === 0) {
58
+ query = "";
59
+ } else if (parts.length === 1) {
60
+ query = parts[0];
61
+ } else {
62
+ query = parts.join(` ${operator} `);
63
+ }
49
64
  let notClause = null;
50
65
  if (block.terms.exclude && block.terms.exclude.length > 0) {
51
66
  const excludeTerms = block.terms.exclude.map(quoteTerm);
@@ -74,16 +89,18 @@ function translateFilters(filters, scopusOverrides) {
74
89
  }
75
90
  function translateQuery(ast) {
76
91
  const blockResults = ast.blocks.map(translateBlock);
77
- const blockParts = blockResults.map((r) => r.query);
92
+ const blockParts = blockResults.map((r) => r.query).filter((s) => s.length > 0);
78
93
  const notClauses = blockResults.map((r) => r.notClause).filter((s) => s !== null);
79
94
  const scopusOverrides = ast.overrides.scopus;
80
95
  const filterParts = translateFilters(ast.filters, scopusOverrides);
81
96
  const allParts = [...blockParts, ...notClauses, ...filterParts];
82
97
  const native = allParts.join(" AND ");
98
+ const warnings = collectUnsupportedVocabWarnings(ast.blocks, "Scopus", /* @__PURE__ */ new Set(["emtree"]));
83
99
  return {
84
100
  native,
85
101
  originalAst: ast,
86
- provider: "scopus"
102
+ provider: "scopus",
103
+ ...warnings.length > 0 ? { warnings } : {}
87
104
  };
88
105
  }
89
106
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"translator.js","sources":["../../../src/providers/scopus/translator.ts"],"sourcesContent":["/**\n * Scopus Query Translator\n *\n * Translates QueryAST to Scopus search syntax.\n */\n\nimport type { QueryAST, FieldType, QueryBlock, Filters, OverrideBlock } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\n\n/**\n * Field function mappings for Scopus.\n */\nconst FIELD_MAP: Record<FieldType, string> = {\n title: 'TITLE',\n abstract: 'ABS',\n title_abstract: 'TITLE-ABS-KEY',\n author: 'AUTH',\n keyword: 'KEY',\n all: 'ALL',\n};\n\n/**\n * Source type code mappings for Scopus.\n */\nconst SOURCE_TYPE_MAP: Record<string, string> = {\n journal: 'j',\n conference: 'p',\n book: 'b',\n 'book series': 'k',\n 'trade journal': 'd',\n};\n\n/**\n * Language code mappings for Scopus.\n */\nconst LANGUAGE_MAP: Record<string, string> = {\n en: 'english',\n de: 'german',\n fr: 'french',\n es: 'spanish',\n it: 'italian',\n ja: 'japanese',\n zh: 'chinese',\n ko: 'korean',\n pt: 'portuguese',\n ru: 'russian',\n};\n\n/**\n * Check if a term needs to be quoted (contains spaces and isn't already quoted).\n */\nfunction needsQuotes(term: string): boolean {\n if (term.startsWith('\"') && term.endsWith('\"')) {\n return false;\n }\n if (term.startsWith('{') && term.endsWith('}')) {\n return false;\n }\n return term.includes(' ');\n}\n\n/**\n * Quote a term if it contains spaces.\n */\nfunction quoteTerm(term: string): string {\n if (needsQuotes(term)) {\n return `\"${term}\"`;\n }\n return term;\n}\n\n/**\n * Translate a single query block to Scopus syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const field = FIELD_MAP[block.field];\n const terms = block.terms.keywords.map(quoteTerm);\n const operator = block.operator;\n\n const termsStr = terms.join(` ${operator} `);\n const query = `${field}(${termsStr})`;\n\n // Translate exclude terms (without AND prefix - will be added during join)\n let notClause: string | null = null;\n if (block.terms.exclude && block.terms.exclude.length > 0) {\n const excludeTerms = block.terms.exclude.map(quoteTerm);\n const excludeStr = excludeTerms.join(' OR ');\n notClause = `NOT ${field}(${excludeStr})`;\n }\n\n return { query, notClause };\n}\n\n/**\n * Translate filters to Scopus syntax.\n */\nfunction translateFilters(filters: Filters, scopusOverrides?: OverrideBlock): string[] {\n const parts: string[] = [];\n\n // Year filters\n if (filters.yearFrom !== undefined) {\n parts.push(`PUBYEAR > ${filters.yearFrom - 1}`);\n }\n if (filters.yearTo !== undefined) {\n parts.push(`PUBYEAR < ${filters.yearTo + 1}`);\n }\n\n // Language filter\n if (filters.languages && filters.languages.length > 0) {\n const languages = filters.languages\n .map(code => LANGUAGE_MAP[code] || code)\n .join(' OR ');\n parts.push(`LANGUAGE(${languages})`);\n }\n\n // Source type filter from overrides\n if (scopusOverrides?.sourceTypes && scopusOverrides.sourceTypes.length > 0) {\n const sourceTypes = scopusOverrides.sourceTypes\n .map(type => SOURCE_TYPE_MAP[type] || type)\n .join(' OR ');\n parts.push(`SRCTYPE(${sourceTypes})`);\n }\n\n return parts;\n}\n\n/**\n * Translate a QueryAST to Scopus search syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n // Translate query blocks\n const blockResults = ast.blocks.map(translateBlock);\n\n // Collect query parts and NOT clauses\n const blockParts = blockResults.map((r) => r.query);\n const notClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n // Translate filters\n const scopusOverrides = ast.overrides.scopus;\n const filterParts = translateFilters(ast.filters, scopusOverrides);\n\n // Build native query: blocks AND NOT(excludes) AND filters\n const allParts: string[] = [...blockParts, ...notClauses, ...filterParts];\n const native = allParts.join(' AND ');\n\n return {\n native,\n originalAst: ast,\n provider: 'scopus',\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"translator.js","sources":["../../../src/providers/scopus/translator.ts"],"sourcesContent":["/**\n * Scopus Query Translator\n *\n * Translates QueryAST to Scopus search syntax.\n */\n\nimport type { QueryAST, FieldType, QueryBlock, Filters, OverrideBlock } from '../../query/types';\nimport type { TranslatedQuery } from '../base/types';\nimport { collectUnsupportedVocabWarnings } from '../base/warnings';\n\n/**\n * Field function mappings for Scopus.\n */\nconst FIELD_MAP: Record<FieldType, string> = {\n title: 'TITLE',\n abstract: 'ABS',\n title_abstract: 'TITLE-ABS-KEY',\n author: 'AUTH',\n keyword: 'KEY',\n all: 'ALL',\n};\n\n/**\n * Source type code mappings for Scopus.\n */\nconst SOURCE_TYPE_MAP: Record<string, string> = {\n journal: 'j',\n conference: 'p',\n book: 'b',\n 'book series': 'k',\n 'trade journal': 'd',\n};\n\n/**\n * Language code mappings for Scopus.\n */\nconst LANGUAGE_MAP: Record<string, string> = {\n en: 'english',\n de: 'german',\n fr: 'french',\n es: 'spanish',\n it: 'italian',\n ja: 'japanese',\n zh: 'chinese',\n ko: 'korean',\n pt: 'portuguese',\n ru: 'russian',\n};\n\n/**\n * Check if a term needs to be quoted (contains spaces and isn't already quoted).\n */\nfunction needsQuotes(term: string): boolean {\n if (term.startsWith('\"') && term.endsWith('\"')) {\n return false;\n }\n if (term.startsWith('{') && term.endsWith('}')) {\n return false;\n }\n return term.includes(' ');\n}\n\n/**\n * Quote a term if it contains spaces.\n */\nfunction quoteTerm(term: string): string {\n if (needsQuotes(term)) {\n return `\"${term}\"`;\n }\n return term;\n}\n\n/**\n * Translate a single query block to Scopus syntax.\n * Returns an object with the main query part and optional NOT clause.\n */\nfunction translateBlock(block: QueryBlock): { query: string; notClause: string | null } {\n const field = FIELD_MAP[block.field];\n const operator = block.operator;\n const parts: string[] = [];\n\n // Translate keywords\n const keywords = (block.terms.keywords ?? []).map(quoteTerm);\n if (keywords.length > 0) {\n parts.push(`${field}(${keywords.join(` ${operator} `)})`);\n }\n\n // Translate Emtree terms (always use INDEXTERMS)\n const emtree = (block.terms.emtree ?? []).map(quoteTerm);\n if (emtree.length > 0) {\n parts.push(`INDEXTERMS(${emtree.join(` ${operator} `)})`);\n }\n\n // Combine parts (empty string when no supported terms)\n let query: string;\n if (parts.length === 0) {\n query = '';\n } else if (parts.length === 1) {\n query = parts[0]!;\n } else {\n query = parts.join(` ${operator} `);\n }\n\n // Translate exclude terms (without AND prefix - will be added during join)\n let notClause: string | null = null;\n if (block.terms.exclude && block.terms.exclude.length > 0) {\n const excludeTerms = block.terms.exclude.map(quoteTerm);\n const excludeStr = excludeTerms.join(' OR ');\n notClause = `NOT ${field}(${excludeStr})`;\n }\n\n return { query, notClause };\n}\n\n/**\n * Translate filters to Scopus syntax.\n */\nfunction translateFilters(filters: Filters, scopusOverrides?: OverrideBlock): string[] {\n const parts: string[] = [];\n\n // Year filters\n if (filters.yearFrom !== undefined) {\n parts.push(`PUBYEAR > ${filters.yearFrom - 1}`);\n }\n if (filters.yearTo !== undefined) {\n parts.push(`PUBYEAR < ${filters.yearTo + 1}`);\n }\n\n // Language filter\n if (filters.languages && filters.languages.length > 0) {\n const languages = filters.languages\n .map(code => LANGUAGE_MAP[code] || code)\n .join(' OR ');\n parts.push(`LANGUAGE(${languages})`);\n }\n\n // Source type filter from overrides\n if (scopusOverrides?.sourceTypes && scopusOverrides.sourceTypes.length > 0) {\n const sourceTypes = scopusOverrides.sourceTypes\n .map(type => SOURCE_TYPE_MAP[type] || type)\n .join(' OR ');\n parts.push(`SRCTYPE(${sourceTypes})`);\n }\n\n return parts;\n}\n\n/**\n * Translate a QueryAST to Scopus search syntax.\n */\nexport function translateQuery(ast: QueryAST): TranslatedQuery {\n // Translate query blocks\n const blockResults = ast.blocks.map(translateBlock);\n\n // Collect query parts (filter empty blocks) and NOT clauses\n const blockParts = blockResults\n .map((r) => r.query)\n .filter((s) => s.length > 0);\n const notClauses = blockResults\n .map((r) => r.notClause)\n .filter((s): s is string => s !== null);\n\n // Translate filters\n const scopusOverrides = ast.overrides.scopus;\n const filterParts = translateFilters(ast.filters, scopusOverrides);\n\n // Build native query: blocks AND NOT(excludes) AND filters\n const allParts: string[] = [...blockParts, ...notClauses, ...filterParts];\n const native = allParts.join(' AND ');\n\n // Collect warnings for unsupported controlled vocabulary\n // Scopus supports emtree but not mesh or eric\n const warnings = collectUnsupportedVocabWarnings(ast.blocks, 'Scopus', new Set(['emtree']));\n\n return {\n native,\n originalAst: ast,\n provider: 'scopus',\n ...(warnings.length > 0 ? { warnings } : {}),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { MeSHLookupClient } from '../mesh-lookup.js';
2
+ /**
3
+ * Create a mock MeSH lookup client for testing.
4
+ *
5
+ * @param results - Map of term to lookup result
6
+ * @returns A mock MeSHLookupClient
7
+ */
8
+ export declare function createMockMeSHClient(results: Map<string, {
9
+ found: boolean;
10
+ suggestions?: string[];
11
+ }>): MeSHLookupClient;
12
+ //# sourceMappingURL=mock-mesh-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-mesh-client.d.ts","sourceRoot":"","sources":["../../../src/query/__test-helpers__/mock-mesh-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GAC/D,gBAAgB,CAWlB"}
@@ -9,4 +9,8 @@
9
9
  export type { FieldType, Operator, ProviderName, TermBlock, QueryBlock, Filters, PublicationTypeFilter, OverrideBlock, QueryAST, } from './types.js';
10
10
  export { parseQueryFile, parseQueryString } from './parser.js';
11
11
  export { validateQueryFile, formatValidationErrors, ValidationError, fieldTypeSchema, termBlockSchema, queryBlockSchema, filtersSchema, overrideBlockSchema, queryFileSchema, } from './validator.js';
12
+ export { MeSHLookupClient } from './mesh-lookup.js';
13
+ export type { MeSHLookupResult } from './mesh-lookup.js';
14
+ export { extractControlledVocabTerms, validateControlledVocab, } from './vocab-validator.js';
15
+ export type { VocabTerm, VocabTermError, VocabTermResult, VocabValidationResult, } from './vocab-validator.js';
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EACV,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,OAAO,EACP,qBAAqB,EACrB,aAAa,EACb,QAAQ,GACT,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EAEf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,eAAe,GAChB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,YAAY,EACV,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,OAAO,EACP,qBAAqB,EACrB,aAAa,EACb,QAAQ,GACT,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/D,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EAEf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}