@cyanheads/pubmed-mcp-server 2.10.19 → 2.10.21

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 (110) hide show
  1. package/AGENTS.md +8 -5
  2. package/CLAUDE.md +8 -5
  3. package/Dockerfile +12 -3
  4. package/README.md +12 -11
  5. package/changelog/2.10.x/2.10.20.md +63 -0
  6. package/changelog/2.10.x/2.10.21.md +42 -0
  7. package/dist/mcp-server/tools/definitions/_text.d.ts.map +1 -1
  8. package/dist/mcp-server/tools/definitions/_text.js +10 -5
  9. package/dist/mcp-server/tools/definitions/_text.js.map +1 -1
  10. package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts +8 -0
  11. package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts.map +1 -1
  12. package/dist/mcp-server/tools/definitions/fetch-articles.tool.js +64 -14
  13. package/dist/mcp-server/tools/definitions/fetch-articles.tool.js.map +1 -1
  14. package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts +44 -9
  15. package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts.map +1 -1
  16. package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.js +815 -563
  17. package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.js.map +1 -1
  18. package/dist/mcp-server/tools/definitions/find-related.tool.d.ts +5 -5
  19. package/dist/mcp-server/tools/definitions/find-related.tool.d.ts.map +1 -1
  20. package/dist/mcp-server/tools/definitions/find-related.tool.js +12 -8
  21. package/dist/mcp-server/tools/definitions/find-related.tool.js.map +1 -1
  22. package/dist/mcp-server/tools/definitions/format-citations.tool.d.ts +12 -0
  23. package/dist/mcp-server/tools/definitions/format-citations.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/format-citations.tool.js +53 -7
  25. package/dist/mcp-server/tools/definitions/format-citations.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts +11 -7
  27. package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/lookup-citation.tool.js +72 -34
  29. package/dist/mcp-server/tools/definitions/lookup-citation.tool.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts +2 -1
  31. package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js +11 -3
  33. package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js.map +1 -1
  34. package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.d.ts +18 -0
  35. package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.js +96 -13
  37. package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.js.map +1 -1
  38. package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts +4 -3
  39. package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.js +7 -5
  41. package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.js.map +1 -1
  42. package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts +6 -4
  43. package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/search-articles.tool.js +33 -11
  45. package/dist/mcp-server/tools/definitions/search-articles.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts +2 -1
  47. package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts.map +1 -1
  48. package/dist/mcp-server/tools/definitions/spell-check.tool.js +5 -1
  49. package/dist/mcp-server/tools/definitions/spell-check.tool.js.map +1 -1
  50. package/dist/services/error-contracts.d.ts +1 -1
  51. package/dist/services/error-contracts.d.ts.map +1 -1
  52. package/dist/services/error-contracts.js +1 -1
  53. package/dist/services/error-contracts.js.map +1 -1
  54. package/dist/services/europe-pmc/api-client.d.ts.map +1 -1
  55. package/dist/services/europe-pmc/api-client.js +4 -3
  56. package/dist/services/europe-pmc/api-client.js.map +1 -1
  57. package/dist/services/fetch-redaction.d.ts +23 -0
  58. package/dist/services/fetch-redaction.d.ts.map +1 -0
  59. package/dist/services/fetch-redaction.js +62 -0
  60. package/dist/services/fetch-redaction.js.map +1 -0
  61. package/dist/services/ncbi/api-client.d.ts +3 -0
  62. package/dist/services/ncbi/api-client.d.ts.map +1 -1
  63. package/dist/services/ncbi/api-client.js +21 -8
  64. package/dist/services/ncbi/api-client.js.map +1 -1
  65. package/dist/services/ncbi/formatting/citation-formatter.d.ts +42 -2
  66. package/dist/services/ncbi/formatting/citation-formatter.d.ts.map +1 -1
  67. package/dist/services/ncbi/formatting/citation-formatter.js +370 -91
  68. package/dist/services/ncbi/formatting/citation-formatter.js.map +1 -1
  69. package/dist/services/ncbi/ncbi-service.d.ts +16 -1
  70. package/dist/services/ncbi/ncbi-service.d.ts.map +1 -1
  71. package/dist/services/ncbi/ncbi-service.js +117 -71
  72. package/dist/services/ncbi/ncbi-service.js.map +1 -1
  73. package/dist/services/ncbi/parsing/article-parser.d.ts.map +1 -1
  74. package/dist/services/ncbi/parsing/article-parser.js +116 -61
  75. package/dist/services/ncbi/parsing/article-parser.js.map +1 -1
  76. package/dist/services/ncbi/parsing/esummary-parser.d.ts +9 -0
  77. package/dist/services/ncbi/parsing/esummary-parser.d.ts.map +1 -1
  78. package/dist/services/ncbi/parsing/esummary-parser.js +26 -2
  79. package/dist/services/ncbi/parsing/esummary-parser.js.map +1 -1
  80. package/dist/services/ncbi/parsing/pmc-article-parser.d.ts +8 -7
  81. package/dist/services/ncbi/parsing/pmc-article-parser.d.ts.map +1 -1
  82. package/dist/services/ncbi/parsing/pmc-article-parser.js +633 -185
  83. package/dist/services/ncbi/parsing/pmc-article-parser.js.map +1 -1
  84. package/dist/services/ncbi/parsing/pmc-xml-helpers.d.ts +102 -5
  85. package/dist/services/ncbi/parsing/pmc-xml-helpers.d.ts.map +1 -1
  86. package/dist/services/ncbi/parsing/pmc-xml-helpers.js +389 -28
  87. package/dist/services/ncbi/parsing/pmc-xml-helpers.js.map +1 -1
  88. package/dist/services/ncbi/parsing/text-helpers.d.ts +8 -6
  89. package/dist/services/ncbi/parsing/text-helpers.d.ts.map +1 -1
  90. package/dist/services/ncbi/parsing/text-helpers.js +95 -19
  91. package/dist/services/ncbi/parsing/text-helpers.js.map +1 -1
  92. package/dist/services/ncbi/response-handler.d.ts +20 -12
  93. package/dist/services/ncbi/response-handler.d.ts.map +1 -1
  94. package/dist/services/ncbi/response-handler.js +115 -19
  95. package/dist/services/ncbi/response-handler.js.map +1 -1
  96. package/dist/services/ncbi/types.d.ts +44 -4
  97. package/dist/services/ncbi/types.d.ts.map +1 -1
  98. package/dist/services/openalex/api-client.d.ts.map +1 -1
  99. package/dist/services/openalex/api-client.js +4 -3
  100. package/dist/services/openalex/api-client.js.map +1 -1
  101. package/dist/services/openalex/openalex-service.d.ts +10 -6
  102. package/dist/services/openalex/openalex-service.d.ts.map +1 -1
  103. package/dist/services/openalex/openalex-service.js +13 -9
  104. package/dist/services/openalex/openalex-service.js.map +1 -1
  105. package/dist/services/unpaywall/unpaywall-service.d.ts +3 -0
  106. package/dist/services/unpaywall/unpaywall-service.d.ts.map +1 -1
  107. package/dist/services/unpaywall/unpaywall-service.js +18 -8
  108. package/dist/services/unpaywall/unpaywall-service.js.map +1 -1
  109. package/package.json +14 -12
  110. package/server.json +10 -24
@@ -45,6 +45,16 @@ export function textOf(node) {
45
45
  const TEX_MATH_TAG = 'tex-math';
46
46
  /** JATS container holding equivalent renderings of one object. */
47
47
  const ALTERNATIVES_TAG = 'alternatives';
48
+ /**
49
+ * Elements whose text identifies the element around them and is never prose:
50
+ * the `<institution-id>` (a ROR URL, a GRID or ISNI id, a Crossref Funder DOI)
51
+ * an `<institution-wrap>` carries beside the `<institution>` name. Read as text
52
+ * it fuses onto that name, in an affiliation
53
+ * (`1https://ror.org/034t3zs45grid.454711.2School of …`) and in a funding
54
+ * statement (`sponsored by the 10.13039/501100001809National Natural Science
55
+ * Foundation of China`) alike, so no reader takes its text. (#196, #208)
56
+ */
57
+ export const IDENTIFIER_TAGS = new Set(['institution-id']);
48
58
  /**
49
59
  * JATS pointers to an external rendering: a file reference, not a rendering of
50
60
  * the object itself.
@@ -77,6 +87,166 @@ const TEX_DOCUMENT_BODY = /\\begin\{document\}([\s\S]*?)(?:\\end\{document\}|$)/
77
87
  function texMathExpression(raw) {
78
88
  return TEX_DOCUMENT_BODY.exec(raw)?.[1] ?? raw;
79
89
  }
90
+ /** An element's tag without its namespace prefix: `math` for `mml:math`. */
91
+ const localName = (tag) => tag.slice(tag.indexOf(':') + 1);
92
+ /**
93
+ * True for a MathML `<math>` element, matched by local name whatever its
94
+ * namespace prefix — `<mml:math>` in PMC deposits, `<math>` elsewhere. (#207)
95
+ */
96
+ export function isMathTag(tag) {
97
+ return localName(tag) === 'math';
98
+ }
99
+ /** MathML token elements, which contribute their text as deposited. */
100
+ const MATH_TOKEN_TAGS = new Set(['mi', 'mn', 'mo', 'mtext', 'ms']);
101
+ /**
102
+ * A MathML `<math>` element in a TeX-style linear form — the notation a
103
+ * formula deposited as `<tex-math>` already reads in — so a formula keeps the
104
+ * structure that carries its meaning instead of reading as the run of its
105
+ * leaves (`∑j=1Nlij`, a matrix's numeric cells fused into `−4.401.20`). (#207)
106
+ *
107
+ * | MathML | Linear form |
108
+ * |:--|:--|
109
+ * | `mi`, `mn`, `mo`, `mtext`, `ms` | their text as deposited (`−` stays U+2212) |
110
+ * | `msub`, `munder` / `msup`, `mover` | base`_{…}` / base`^{…}` |
111
+ * | `msubsup`, `munderover`, `mmultiscripts` | base`_{…}^{…}`, per script pair; `mmultiscripts` prescripts as `{}_{…}^{…}` before the base |
112
+ * | `mfrac` / `msqrt` / `mroot` | `\frac{…}{…}` / `\sqrt{…}` / `\sqrt[index]{…}` |
113
+ * | `mfenced` | `open`, the children split by `separators`, `close` (defaults `(`, `,`, `)`) |
114
+ * | `mtable` | cells split by ` & `, rows by ` \\ ` |
115
+ * | `mspace` / `mphantom` | one space / nothing |
116
+ * | anything else | its children in order |
117
+ *
118
+ * An empty script slot is left out (`x^{2}`, not `x_{}^{2}`). Whitespace-only
119
+ * text between elements contributes nothing; any other text reads verbatim.
120
+ * Elements match by local name, whatever their prefix. Pieces are written to
121
+ * one buffer rather than returned and concatenated level by level, so the cost
122
+ * stays linear in the size of the formula however deeply it nests.
123
+ */
124
+ export function linearMath(math) {
125
+ const out = [];
126
+ const emit = (text) => {
127
+ if (text)
128
+ out.push(text);
129
+ };
130
+ /** Element children only: text between MathML arguments is never one of them. */
131
+ const argsOf = (node) => childrenOf(node).filter((child) => !isTextNode(child));
132
+ /** Write `pieces` after `open`, or nothing at all when they write nothing. */
133
+ const unlessEmpty = (open, pieces, close = '') => {
134
+ const start = out.length;
135
+ out.push(open);
136
+ pieces();
137
+ if (out.length === start + 1)
138
+ out.length = start;
139
+ else
140
+ emit(close);
141
+ };
142
+ const script = (mark, node) => unlessEmpty(`${mark}{`, () => write(node), '}');
143
+ /** Script pairs — subscript, then superscript — in document order. */
144
+ const scriptPairs = (scripts) => {
145
+ for (let i = 0; i < scripts.length; i += 2) {
146
+ script('_', scripts[i]);
147
+ script('^', scripts[i + 1]);
148
+ }
149
+ };
150
+ const write = (node) => {
151
+ if (!node)
152
+ return;
153
+ if (isTextNode(node)) {
154
+ const text = textOf(node);
155
+ if (VISIBLE_CHAR.test(text))
156
+ emit(text);
157
+ return;
158
+ }
159
+ const name = localName(tagNameOf(node) ?? '');
160
+ if (MATH_TOKEN_TAGS.has(name)) {
161
+ for (const child of childrenOf(node)) {
162
+ if (isTextNode(child))
163
+ emit(textOf(child));
164
+ else
165
+ write(child);
166
+ }
167
+ return;
168
+ }
169
+ const args = argsOf(node);
170
+ switch (name) {
171
+ case 'msub':
172
+ case 'munder':
173
+ write(args[0]);
174
+ script('_', args[1]);
175
+ return;
176
+ case 'msup':
177
+ case 'mover':
178
+ write(args[0]);
179
+ script('^', args[1]);
180
+ return;
181
+ case 'msubsup':
182
+ case 'munderover':
183
+ write(args[0]);
184
+ script('_', args[1]);
185
+ script('^', args[2]);
186
+ return;
187
+ case 'mmultiscripts': {
188
+ const split = args.findIndex((arg) => localName(tagNameOf(arg) ?? '') === 'mprescripts');
189
+ if (split !== -1)
190
+ unlessEmpty('{}', () => scriptPairs(args.slice(split + 1)));
191
+ write(args[0]);
192
+ scriptPairs(args.slice(1, split === -1 ? undefined : split));
193
+ return;
194
+ }
195
+ case 'mfrac':
196
+ emit('\\frac{');
197
+ write(args[0]);
198
+ emit('}{');
199
+ write(args[1]);
200
+ emit('}');
201
+ return;
202
+ case 'msqrt':
203
+ emit('\\sqrt{');
204
+ for (const arg of args)
205
+ write(arg);
206
+ emit('}');
207
+ return;
208
+ case 'mroot':
209
+ emit('\\sqrt[');
210
+ write(args[1]);
211
+ emit(']{');
212
+ write(args[0]);
213
+ emit('}');
214
+ return;
215
+ case 'mfenced': {
216
+ const separators = [...(attrOf(node, 'separators') ?? ',').replace(/\s/g, '')];
217
+ emit(attrOf(node, 'open') ?? '(');
218
+ for (const [i, arg] of args.entries()) {
219
+ if (i > 0)
220
+ emit(separators[Math.min(i - 1, separators.length - 1)] ?? '');
221
+ write(arg);
222
+ }
223
+ emit(attrOf(node, 'close') ?? ')');
224
+ return;
225
+ }
226
+ case 'mtable':
227
+ for (const [r, row] of args.entries()) {
228
+ if (r > 0)
229
+ emit(' \\\\ ');
230
+ for (const [c, cell] of argsOf(row).entries()) {
231
+ if (c > 0)
232
+ emit(' & ');
233
+ write(cell);
234
+ }
235
+ }
236
+ return;
237
+ case 'mspace':
238
+ emit(' ');
239
+ return;
240
+ case 'mphantom':
241
+ return;
242
+ default:
243
+ for (const child of childrenOf(node))
244
+ write(child);
245
+ }
246
+ };
247
+ write(math);
248
+ return out.join('');
249
+ }
80
250
  /**
81
251
  * The single child of an `<alternatives>` whose text stands for the whole
82
252
  * element.
@@ -97,67 +267,246 @@ function texMathExpression(raw) {
97
267
  */
98
268
  export function selectAlternative(node, excluded) {
99
269
  const children = childrenOf(node);
100
- const carriesText = (child) => concatText(child, excluded).trim() !== '';
270
+ const carriesText = (child) => readText(child, excluded).trim() !== '';
101
271
  return (children.find((child) => tagNameOf(child) === TEX_MATH_TAG && carriesText(child)) ??
102
272
  children.find((child) => !POINTER_TAGS.has(tagNameOf(child) ?? '') && carriesText(child)) ??
103
273
  children.find(carriesText));
104
274
  }
105
275
  /**
106
- * Concatenate text content in document order without normalizing whitespace.
107
- * Internal helper so recursion preserves the original spacing between siblings.
108
- * `excluded` skips a whole subtree by tag name; omitting it reads everything.
276
+ * Elements whose start and end are line boundaries: each holds a statement, a
277
+ * footnote, a list or list item, or a heading of its own. A deposit marks these
278
+ * boundaries with the element alone — `RATIOS<break/>IRR`, `</fn><fn>` — so
279
+ * reading straight through fuses the words and numbers on either side
280
+ * (`57 ± 2095`, `1.082.44`). Inline markup (`<sub>`, `<sup>`, `<italic>`,
281
+ * `<xref>`) is never one: `H<sub>2</sub>O` must read `H2O`. (#185)
282
+ */
283
+ const LINE_BOUNDARY_TAGS = new Set([
284
+ 'attrib',
285
+ 'def-item',
286
+ 'def-list',
287
+ 'disp-quote',
288
+ 'fn',
289
+ 'list',
290
+ 'list-item',
291
+ 'p',
292
+ 'title',
293
+ ]);
294
+ /** Empty elements that are a line boundary in themselves. (#185) */
295
+ const LINE_BREAK_TAGS = new Set(['break', 'hr']);
296
+ /**
297
+ * A marker printed beside the text it labels — a footnote's `*`, an
298
+ * affiliation's `1`, a list item's `2.` — with nothing between them in the
299
+ * source. (#185)
300
+ */
301
+ const LABEL_TAG = 'label';
302
+ /** A cross-reference: in prose, usually a citation marker. (#197) */
303
+ const XREF_TAG = 'xref';
304
+ /** No separator owed. */
305
+ const NO_SEPARATOR = 0;
306
+ /** One space owed: what follows a `<label>`. */
307
+ const SPACE_SEPARATOR = 1;
308
+ /** A line boundary owed. */
309
+ const LINE_SEPARATOR = 2;
310
+ /** One character of whitespace — the same class `\s+` collapses. */
311
+ const WHITESPACE_CHAR = /\s/;
312
+ /** Any character other than whitespace. */
313
+ const VISIBLE_CHAR = /\S/;
314
+ /**
315
+ * Accumulates JATS text in document order and decides every separator the
316
+ * markup implies in the same pass, from state it carries rather than by
317
+ * re-reading text already emitted — so the cost stays linear in the size of the
318
+ * subtree. A reader drives it with {@link text} for text nodes and with
319
+ * {@link open} / {@link close} around each element's children.
320
+ *
321
+ * - A line-boundary element ({@link LINE_BOUNDARY_TAGS}, `<break/>`, `<hr/>`)
322
+ * owes a line boundary before the next content.
323
+ * - A `<label>` that carried text owes one space, and a line boundary arriving
324
+ * before any further content becomes that space: `<fn><label>*</label><p>…`
325
+ * reads `* …`, the marker leading its line rather than standing alone on it.
326
+ * - An `<xref>` that carries text and follows another with no source text
327
+ * between them is preceded by a comma: `[1,2,3,4]`, not `[1234]`, which reads
328
+ * as one reference. Any source text between them, whitespace included, means
329
+ * the source already separated them. (#197)
330
+ *
331
+ * An owed separator is only written between two pieces of content, so a reader
332
+ * adds nothing at the edges of what it reads. By default the source text is
333
+ * kept verbatim and a separator is written only where neither side carries
334
+ * whitespace — `a<break/>b` gains a `\n`, `a <break/>b` stays as it was — so a
335
+ * caller collapsing whitespace afterwards reads every boundary as one space. In
336
+ * `lines` mode each text node's whitespace collapses to a space and every line
337
+ * boundary is written as `\n`, replacing whatever spacing the source had there,
338
+ * so the result keeps the source's line structure and nothing else. (#185)
339
+ */
340
+ export class TextAssembler {
341
+ #lines;
342
+ #out = [];
343
+ /** How many non-whitespace text pieces have been written. */
344
+ #written = 0;
345
+ /** The last character written is whitespace. */
346
+ #endsWithSpace = false;
347
+ #owed = NO_SEPARATOR;
348
+ /** A `<label>` closed and nothing but whitespace has arrived since. */
349
+ #afterLabel = false;
350
+ /** An `<xref>` carrying text closed and no source text has arrived since. */
351
+ #afterXref = false;
352
+ /** A comma is owed before the open `<xref>`'s first text. */
353
+ #commaOwed = false;
354
+ /** {@link #written} at each open `<label>` and `<xref>`, innermost last. */
355
+ #marks = [];
356
+ constructor(options = {}) {
357
+ this.#lines = options.lines ?? false;
358
+ }
359
+ /** Append one text node's value. */
360
+ text(value) {
361
+ if (value === '')
362
+ return;
363
+ this.#afterXref = false;
364
+ if (!VISIBLE_CHAR.test(value)) {
365
+ this.#out.push(this.#lines ? ' ' : value);
366
+ this.#endsWithSpace = true;
367
+ return;
368
+ }
369
+ if (this.#written > 0 && this.#owed !== NO_SEPARATOR) {
370
+ const separator = this.#owed === LINE_SEPARATOR ? '\n' : ' ';
371
+ const sourceSpaced = this.#endsWithSpace || WHITESPACE_CHAR.test(value.charAt(0));
372
+ if (this.#lines || !sourceSpaced)
373
+ this.#out.push(separator);
374
+ }
375
+ else if (this.#commaOwed) {
376
+ this.#out.push(',');
377
+ }
378
+ this.#owed = NO_SEPARATOR;
379
+ this.#afterLabel = false;
380
+ this.#commaOwed = false;
381
+ this.#out.push(this.#lines ? value.replace(/\s+/g, ' ') : value);
382
+ this.#endsWithSpace = WHITESPACE_CHAR.test(value.charAt(value.length - 1));
383
+ this.#written += 1;
384
+ }
385
+ /** Enter an element, before its children are read. */
386
+ open(tag) {
387
+ if (LINE_BREAK_TAGS.has(tag) || LINE_BOUNDARY_TAGS.has(tag)) {
388
+ this.#oweLine();
389
+ }
390
+ else if (tag === LABEL_TAG) {
391
+ this.#marks.push(this.#written);
392
+ }
393
+ else if (tag === XREF_TAG) {
394
+ this.#marks.push(this.#written);
395
+ this.#commaOwed = this.#afterXref;
396
+ }
397
+ }
398
+ /**
399
+ * Leave an element, after its children are read. A close with no matching
400
+ * mark — the run was restarted inside the element, as a prose walk does at a
401
+ * block nested in inline markup — owes nothing.
402
+ */
403
+ close(tag) {
404
+ if (LINE_BOUNDARY_TAGS.has(tag)) {
405
+ this.#oweLine();
406
+ return;
407
+ }
408
+ if (tag !== LABEL_TAG && tag !== XREF_TAG)
409
+ return;
410
+ const mark = this.#marks.pop();
411
+ if (mark === undefined)
412
+ return;
413
+ const carriedText = mark !== this.#written;
414
+ if (tag === LABEL_TAG) {
415
+ if (!carriedText)
416
+ return;
417
+ this.#owed = SPACE_SEPARATOR;
418
+ this.#afterLabel = true;
419
+ return;
420
+ }
421
+ this.#commaOwed = false;
422
+ if (carriedText)
423
+ this.#afterXref = true;
424
+ }
425
+ /** The text assembled so far. */
426
+ toString() {
427
+ const text = this.#out.join('');
428
+ if (!this.#lines)
429
+ return text;
430
+ return text
431
+ .replace(/ {2,}/g, ' ')
432
+ .replace(/ ?\n ?/g, '\n')
433
+ .trim();
434
+ }
435
+ #oweLine() {
436
+ if (!this.#afterLabel)
437
+ this.#owed = LINE_SEPARATOR;
438
+ }
439
+ }
440
+ /**
441
+ * Drive `sink` through a node or sibling list in document order. `excluded`
442
+ * skips a whole subtree by tag name; omitting it reads everything else.
109
443
  *
110
- * Two JATS elements do not contribute the plain concatenation of their subtree:
111
- * a `<tex-math>` contributes only its LaTeX document body, and an
112
- * `<alternatives>` contributes exactly one child. Both rules live here so every
113
- * prose consumer inherits them — paragraphs, table cells, captions, abstracts.
114
- * (#135)
115
- */
116
- function concatText(input, excluded) {
117
- const nodes = Array.isArray(input) ? input : [input];
118
- const parts = [];
119
- for (const node of nodes) {
444
+ * Four JATS elements do not contribute the plain concatenation of their
445
+ * subtree: a `<tex-math>` contributes only its LaTeX document body, a MathML
446
+ * `<math>` its {@link linearMath} form, an `<alternatives>` exactly one child,
447
+ * and an {@link IDENTIFIER_TAGS} element nothing. The rules live here, beside
448
+ * the boundary rules {@link TextAssembler} applies, so every consumer inherits
449
+ * them — table cells, footnotes, titles, affiliations, references. (#135, #185,
450
+ * #207, #208)
451
+ */
452
+ function readInto(input, sink, excluded) {
453
+ for (const node of Array.isArray(input) ? input : [input]) {
120
454
  if (isTextNode(node)) {
121
- parts.push(textOf(node));
455
+ sink.text(textOf(node));
122
456
  continue;
123
457
  }
124
458
  const tag = tagNameOf(node) ?? '';
125
- if (excluded?.has(tag))
459
+ if (IDENTIFIER_TAGS.has(tag) || excluded?.has(tag))
126
460
  continue;
127
461
  if (tag === TEX_MATH_TAG) {
128
- parts.push(texMathExpression(concatText(childrenOf(node))));
462
+ sink.text(texMathExpression(readText(childrenOf(node))));
463
+ continue;
464
+ }
465
+ if (isMathTag(tag)) {
466
+ sink.text(linearMath(node));
129
467
  continue;
130
468
  }
131
469
  if (tag === ALTERNATIVES_TAG) {
132
470
  const chosen = selectAlternative(node, excluded);
133
471
  if (chosen)
134
- parts.push(concatText(chosen, excluded));
472
+ readInto(chosen, sink, excluded);
135
473
  continue;
136
474
  }
137
- parts.push(concatText(childrenOf(node), excluded));
475
+ sink.open(tag);
476
+ readInto(childrenOf(node), sink, excluded);
477
+ sink.close(tag);
138
478
  }
139
- return parts.join('');
479
+ }
480
+ /** Read a subtree through a fresh {@link TextAssembler}. */
481
+ function readText(input, excluded, lines = false) {
482
+ const sink = new TextAssembler({ lines });
483
+ readInto(input, sink, excluded);
484
+ return sink.toString();
140
485
  }
141
486
  /**
142
487
  * Extract all text from a node or sibling list in document order with the
143
- * source spacing intact — no whitespace collapsing, no trimming. Use it when
144
- * the caller assembles several fragments itself and needs to collapse once over
145
- * the joined result; {@link textContent} is the normalizing form for everything
146
- * else.
488
+ * source spacing intact — no whitespace collapsing, no trimming. A line boundary
489
+ * the source marks with an element alone gains a `\n`, and a `<label>` beside
490
+ * its text a space; a boundary the source already spaced is left as it is, and
491
+ * nothing is added at the edges of the node read. Use it when the caller assembles several
492
+ * fragments itself and needs to collapse once over the joined result;
493
+ * {@link textContent} is the normalizing form for everything else.
147
494
  */
148
495
  export function rawTextContent(input) {
149
- return input ? concatText(input) : '';
496
+ return input ? readText(input) : '';
150
497
  }
151
498
  /**
152
499
  * Extract all text from a node or sibling list in document order, collapsing
153
500
  * runs of whitespace to a single space and trimming the result. Use this for
154
501
  * mixed-content elements (`<p>`, `<title>`, `<abstract>`, …) where inline
155
- * children must read back in the order they appear in the source.
502
+ * children must read back in the order they appear in the source. A structural
503
+ * boundary — `<break/>`, a sibling `<p>` or `<fn>`, a `<label>` beside its text —
504
+ * reads as one space; inline markup never gains one. (#185)
156
505
  */
157
506
  export function textContent(input) {
158
507
  if (!input)
159
508
  return '';
160
- return concatText(input).replace(/\s+/g, ' ').trim();
509
+ return readText(input).replace(/\s+/g, ' ').trim();
161
510
  }
162
511
  /**
163
512
  * {@link textContent}, with the subtree of any element named in `excludedTags`
@@ -169,7 +518,19 @@ export function textContent(input) {
169
518
  export function textContentExcluding(input, excludedTags) {
170
519
  if (!input)
171
520
  return '';
172
- return concatText(input, excludedTags).replace(/\s+/g, ' ').trim();
521
+ return readText(input, excludedTags).replace(/\s+/g, ' ').trim();
522
+ }
523
+ /**
524
+ * {@link textContent}, keeping every structural line boundary as `\n`: one line
525
+ * per `<break/>`-separated value, paragraph, footnote, or list item, a
526
+ * `<label>` leading its line by one space. Source whitespace inside a line —
527
+ * pretty-printing newlines included — collapses to one space, and blank lines
528
+ * drop out. For table cells and `<table-wrap-foot>`, whose line structure is
529
+ * part of the value: `1.08<break/>2.44` is two estimates, not `1.082.44`.
530
+ * (#185)
531
+ */
532
+ export function lineTextContent(input) {
533
+ return input ? readText(input, undefined, true) : '';
173
534
  }
174
535
  /** First direct child with the given tag name. */
175
536
  export function findOne(input, tagName) {
@@ -1 +1 @@
1
- {"version":3,"file":"pmc-xml-helpers.js","sourceRoot":"","sources":["../../../../src/services/ncbi/parsing/pmc-xml-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgBH,MAAM,QAAQ,GAAG,IAAI,CAAC;AACtB,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEzB,uFAAuF;AACvF,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,GAAG,CAAC;IACvD,CAAC;IACD,OAAO;AACT,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,MAAM,CAAC,IAAc,EAAE,IAAY;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAwC,CAAC;IACpE,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACjC,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,OAAO,QAAQ,IAAI,IAAI,CAAC;AAC1B,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,IAAc;IACnC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,4DAA4D;AAC5D,MAAM,YAAY,GAAG,UAAU,CAAC;AAEhC,kEAAkE;AAClE,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAExC;;;GAGG;AACH,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC;IAChD,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,cAAc;CACf,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,sDAAsD,CAAC;AAEjF;;;;;;;;;;;GAWG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAc,EACd,QAA8B;IAE9B,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,WAAW,GAAG,CAAC,KAAe,EAAW,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAC5F,OAAO,CACL,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,YAAY,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;QACjF,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;QACzF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,UAAU,CAAC,KAA8B,EAAE,QAA8B;IAChF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACjD,IAAI,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0C;IACvE,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAA0C;IACpE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAA0C,EAC1C,YAAiC;IAEjC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,OAAO,CACrB,KAA0C,EAC1C,OAAe;IAEf,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,OAAO,CAAC,KAA0C,EAAE,OAAe;IACjF,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAA0C,EAC1C,OAAe;IAEf,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,KAAmB,EAAQ,EAAE;QAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACxD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"pmc-xml-helpers.js","sourceRoot":"","sources":["../../../../src/services/ncbi/parsing/pmc-xml-helpers.ts"],"names":[],"mappings":"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"}
@@ -18,12 +18,14 @@
18
18
  export declare function decodeHtmlEntities(text: string): string;
19
19
  /**
20
20
  * Turn an upstream string that may carry JATS/HTML markup into display-ready
21
- * plain text: strip structural tags, decode character references, drop soft
22
- * hyphens (U+00AD — invisible, and it corrupts token matching mid-word), and
23
- * collapse the resulting whitespace. Tags are stripped before decoding so a
24
- * structural `<bold>` is removed while an entity-escaped `&lt;gene&gt;` survives
25
- * as literal text. Used for Europe PMC abstract snippets before truncation, so
26
- * the character budget is spent on text rather than markup.
21
+ * plain text: strip tags, decode character references, drop soft hyphens
22
+ * (U+00AD — invisible, and it corrupts token matching mid-word), and collapse
23
+ * the resulting whitespace. Tags are stripped in one pass before decoding, so a
24
+ * raw `<bold>` and an encoded `&lt;i&gt;` are removed while an escaped
25
+ * `&lt;gene&gt;` survives as literal text — and nothing a removal joins or a
26
+ * decode produces is scanned again (`&lt;&lt;i&gt;i&gt;` reads `<i>`). Used for
27
+ * Europe PMC titles, authors, journals, and abstracts before truncation, so the
28
+ * character budget is spent on text rather than markup.
27
29
  */
28
30
  export declare function toDisplayText(text: string): string;
29
31
  //# sourceMappingURL=text-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-helpers.d.ts","sourceRoot":"","sources":["../../../../src/services/ncbi/parsing/text-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiCH;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKlD"}
1
+ {"version":3,"file":"text-helpers.d.ts","sourceRoot":"","sources":["../../../../src/services/ncbi/parsing/text-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsHH;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKlD"}