@cyanheads/openalex-mcp-server 0.7.15 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +32 -30
- package/CLAUDE.md +32 -30
- package/Dockerfile +88 -32
- package/README.md +12 -6
- package/changelog/0.7.x/0.7.16.md +32 -0
- package/changelog/0.8.x/0.8.0.md +38 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/prompts/definitions/literature-review.prompt.js +1 -1
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts +4 -3
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.js +62 -19
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts +21 -1
- package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/citation-graph.tool.js +42 -42
- package/dist/mcp-server/tools/definitions/citation-graph.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/describe-fields.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/describe-fields.tool.js +82 -15
- package/dist/mcp-server/tools/definitions/describe-fields.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts +8 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.js +18 -7
- package/dist/mcp-server/tools/definitions/resolve-name.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts +45 -1
- package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-entities.tool.js +140 -64
- package/dist/mcp-server/tools/definitions/search-entities.tool.js.map +1 -1
- package/dist/mcp-server/tools/escape-markdown.d.ts +32 -0
- package/dist/mcp-server/tools/escape-markdown.d.ts.map +1 -0
- package/dist/mcp-server/tools/escape-markdown.js +389 -0
- package/dist/mcp-server/tools/escape-markdown.js.map +1 -0
- package/dist/mcp-server/tools/render-entity-record.d.ts +14 -2
- package/dist/mcp-server/tools/render-entity-record.d.ts.map +1 -1
- package/dist/mcp-server/tools/render-entity-record.js +46 -15
- package/dist/mcp-server/tools/render-entity-record.js.map +1 -1
- package/dist/mcp-server/tools/response-budget.d.ts +159 -0
- package/dist/mcp-server/tools/response-budget.d.ts.map +1 -0
- package/dist/mcp-server/tools/response-budget.js +480 -0
- package/dist/mcp-server/tools/response-budget.js.map +1 -0
- package/dist/services/openalex/html-entities.json +2237 -0
- package/dist/services/openalex/openalex-service.d.ts +14 -1
- package/dist/services/openalex/openalex-service.d.ts.map +1 -1
- package/dist/services/openalex/openalex-service.js +147 -101
- package/dist/services/openalex/openalex-service.js.map +1 -1
- package/dist/services/openalex/provider-text.d.ts +27 -0
- package/dist/services/openalex/provider-text.d.ts.map +1 -0
- package/dist/services/openalex/provider-text.js +600 -0
- package/dist/services/openalex/provider-text.js.map +1 -0
- package/dist/services/openalex/types.d.ts +6 -1
- package/dist/services/openalex/types.d.ts.map +1 -1
- package/dist/services/openalex/types.js +1 -1
- package/package.json +11 -7
- package/server.json +3 -3
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Markdown escaping for provider text at the `content[]` boundary. Every `format()`
|
|
3
|
+
* that interpolates OpenAlex text routes it through `escapeMarkdown`, so the surfaces cannot
|
|
4
|
+
* drift. Escapes use backslashes, never HTML entities, and cover only what a CommonMark + GFM
|
|
5
|
+
* renderer would read as structure; a URL that GFM links cleanly renders byte-identical, as the
|
|
6
|
+
* autolink it is. `structuredContent` never passes through here — it carries the plain text.
|
|
7
|
+
* @module mcp-server/tools/escape-markdown
|
|
8
|
+
*/
|
|
9
|
+
import { isNamedCharacterReference } from '../../services/openalex/provider-text.js';
|
|
10
|
+
/** Line breaks and tabs would start new blocks or indent code; every position is one line. */
|
|
11
|
+
const LINE_BREAKS = /[\r\n\t]+/g;
|
|
12
|
+
const ASCII_ALPHA = /[A-Za-z]/;
|
|
13
|
+
const ASCII_ALPHANUMERIC = /[A-Za-z\d]/;
|
|
14
|
+
const ASCII_PUNCTUATION = /[!-/:-@[-`{-~]/;
|
|
15
|
+
const WORD_CHARACTER = /[\p{L}\p{N}]/u;
|
|
16
|
+
/** `<` opens raw HTML or a URI autolink only before these. */
|
|
17
|
+
const TAG_START = /[A-Za-z/!?]/;
|
|
18
|
+
/**
|
|
19
|
+
* The shape of a CommonMark email autolink, whose local part may also open with a digit or a
|
|
20
|
+
* symbol (`<1@a.co>`); checked only there, so `P<0.05` keeps its `<` unescaped. Looser than the
|
|
21
|
+
* spec's domain rule, which only costs a spare backslash.
|
|
22
|
+
*/
|
|
23
|
+
const EMAIL_AUTOLINK = /<[\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z\d][a-zA-Z\d.-]*>/y;
|
|
24
|
+
/** An ordered-list marker: up to nine digits, `.` or `)`, then a space or the end. */
|
|
25
|
+
const ORDERED_LIST_MARKER = /^\d{1,9}[.)](?: |$)/;
|
|
26
|
+
/** Character references CommonMark decodes; the longest WHATWG name is 31 characters. */
|
|
27
|
+
const NUMERIC_REFERENCE = /&#(?:\d{1,7}|[xX][0-9a-fA-F]{1,6});/y;
|
|
28
|
+
const NAMED_REFERENCE = /&([A-Za-z][A-Za-z0-9]{0,31});/y;
|
|
29
|
+
/*
|
|
30
|
+
* GFM autolink literals, recognized the way micromark-extension-gfm-autolink-literal does. A
|
|
31
|
+
* backslash inside a link would become part of its text and href, so the linked span passes
|
|
32
|
+
* through untouched — which is only safe if the span is exactly what the renderer links.
|
|
33
|
+
*/
|
|
34
|
+
const HTTP_PREFIX = /^https?:\/\//i;
|
|
35
|
+
const WWW_PREFIX = /^www\./i;
|
|
36
|
+
/** Characters GFM trims from the end of an autolink literal. */
|
|
37
|
+
const TRAILING_PUNCTUATION = new Set([
|
|
38
|
+
'!',
|
|
39
|
+
'"',
|
|
40
|
+
"'",
|
|
41
|
+
')',
|
|
42
|
+
'*',
|
|
43
|
+
',',
|
|
44
|
+
'.',
|
|
45
|
+
':',
|
|
46
|
+
';',
|
|
47
|
+
'?',
|
|
48
|
+
'_',
|
|
49
|
+
'~',
|
|
50
|
+
]);
|
|
51
|
+
/** Path characters at which GFM checks whether everything left is trailing punctuation. */
|
|
52
|
+
const PATH_TRAIL_CANDIDATES = new Set([
|
|
53
|
+
...TRAILING_PUNCTUATION,
|
|
54
|
+
'&',
|
|
55
|
+
'<',
|
|
56
|
+
']',
|
|
57
|
+
]);
|
|
58
|
+
/** Characters a `www.` literal may follow; a protocol literal may follow anything but a letter. */
|
|
59
|
+
const WWW_PREVIOUS = new Set(['(', '*', '_', '[', ']', '~', ' ']);
|
|
60
|
+
/**
|
|
61
|
+
* Trailing punctuation a link leaves unescaped — escaped, the backslash would join the link. It
|
|
62
|
+
* is inert when it holds no `&name;` a renderer would decode and no `*`, and any `_` or `~` forms
|
|
63
|
+
* one run straight after a letter or digit: such a run can close emphasis but never open it, and
|
|
64
|
+
* no other `_` or `~` in the output is left unescaped to open one. A `*` run could close the
|
|
65
|
+
* `**` a caller wraps a name in.
|
|
66
|
+
*/
|
|
67
|
+
const INERT_TRAIL = /^(?:_+|~+)?[^*_~&]*$/;
|
|
68
|
+
const WHITESPACE = /\s/;
|
|
69
|
+
/**
|
|
70
|
+
* For each index, where the trailing punctuation starting there ends — at whitespace, `<`, the
|
|
71
|
+
* end, or after a `]` that such a character or a `(`/`[` follows — or -1 when a character that
|
|
72
|
+
* is not trailing punctuation comes first. Built right to left so the scan stays linear.
|
|
73
|
+
*/
|
|
74
|
+
function trailEnds(s) {
|
|
75
|
+
const ends = new Int32Array(s.length + 1);
|
|
76
|
+
const alphaEnds = new Int32Array(s.length + 1);
|
|
77
|
+
ends[s.length] = s.length;
|
|
78
|
+
alphaEnds[s.length] = s.length;
|
|
79
|
+
for (let j = s.length - 1; j >= 0; j--) {
|
|
80
|
+
const c = s[j];
|
|
81
|
+
alphaEnds[j] = ASCII_ALPHA.test(c) ? alphaEnds[j + 1] : j;
|
|
82
|
+
if (c === '<' || WHITESPACE.test(c)) {
|
|
83
|
+
ends[j] = j;
|
|
84
|
+
}
|
|
85
|
+
else if (TRAILING_PUNCTUATION.has(c)) {
|
|
86
|
+
ends[j] = ends[j + 1];
|
|
87
|
+
}
|
|
88
|
+
else if (c === ']') {
|
|
89
|
+
const next = s[j + 1];
|
|
90
|
+
ends[j] =
|
|
91
|
+
next === undefined || next === '(' || next === '[' || WHITESPACE.test(next)
|
|
92
|
+
? j + 1
|
|
93
|
+
: ends[j + 1];
|
|
94
|
+
}
|
|
95
|
+
else if (c === '&') {
|
|
96
|
+
// A trailing `&name;` belongs to the trail too.
|
|
97
|
+
const nameEnd = alphaEnds[j + 1];
|
|
98
|
+
ends[j] = nameEnd > j + 1 && s[nameEnd] === ';' ? ends[nameEnd + 1] : -1;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
ends[j] = -1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return ends;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* End of a valid domain starting at `start`, or -1. Renderers disagree on how non-ASCII
|
|
108
|
+
* characters classify here, so a domain holding one is treated as one no renderer links.
|
|
109
|
+
*/
|
|
110
|
+
function domainEnd(s, start, trail) {
|
|
111
|
+
let seen = false;
|
|
112
|
+
let underscoreInLast = false;
|
|
113
|
+
let underscoreInLastButOne = false;
|
|
114
|
+
let j = start;
|
|
115
|
+
for (; j < s.length; j++) {
|
|
116
|
+
const c = s[j];
|
|
117
|
+
if (c.charCodeAt(0) > 127)
|
|
118
|
+
return -1;
|
|
119
|
+
if (c === '.' || c === '_') {
|
|
120
|
+
if (trail[j] !== -1)
|
|
121
|
+
break;
|
|
122
|
+
if (c === '_') {
|
|
123
|
+
underscoreInLast = true;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
underscoreInLastButOne = underscoreInLast;
|
|
127
|
+
underscoreInLast = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (WHITESPACE.test(c) || (c !== '-' && ASCII_PUNCTUATION.test(c))) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
seen = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return seen && !underscoreInLast && !underscoreInLastButOne ? j : -1;
|
|
138
|
+
}
|
|
139
|
+
/** End of the path starting at `start`: whitespace, or trailing punctuation to the end. */
|
|
140
|
+
function pathEnd(s, start, trail) {
|
|
141
|
+
let opened = 0;
|
|
142
|
+
let closed = 0;
|
|
143
|
+
for (let j = start; j < s.length; j++) {
|
|
144
|
+
const c = s[j];
|
|
145
|
+
if (c === '(') {
|
|
146
|
+
opened++;
|
|
147
|
+
}
|
|
148
|
+
else if (c === ')' && closed < opened) {
|
|
149
|
+
closed++;
|
|
150
|
+
}
|
|
151
|
+
else if (PATH_TRAIL_CANDIDATES.has(c)) {
|
|
152
|
+
if (trail[j] !== -1)
|
|
153
|
+
return j;
|
|
154
|
+
if (c === ')')
|
|
155
|
+
closed++;
|
|
156
|
+
}
|
|
157
|
+
else if (WHITESPACE.test(c)) {
|
|
158
|
+
return j;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return s.length;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Where a GFM autolink literal could begin at `i`: the index of the `:` or `.` whose escape
|
|
165
|
+
* keeps it from linking, or -1 when no literal can start here.
|
|
166
|
+
*/
|
|
167
|
+
function autolinkPrefixIndex(s, i) {
|
|
168
|
+
const previous = s[i - 1];
|
|
169
|
+
const rest = s.slice(i, i + 8);
|
|
170
|
+
if (HTTP_PREFIX.test(rest) && (previous === undefined || !ASCII_ALPHA.test(previous))) {
|
|
171
|
+
return rest.indexOf(':') + i;
|
|
172
|
+
}
|
|
173
|
+
if (WWW_PREFIX.test(rest) &&
|
|
174
|
+
s.length > i + 4 &&
|
|
175
|
+
(previous === undefined || WWW_PREVIOUS.has(previous))) {
|
|
176
|
+
return i + 3;
|
|
177
|
+
}
|
|
178
|
+
return -1;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* A GFM email literal: it starts where an atext run does and must end on a letter. GFM matches
|
|
182
|
+
* one before a `www.` literal at the same `w`, and its domain can run on into `http`
|
|
183
|
+
* (`a@b.co-https://…`), so a prefix inside one never starts a link of its own.
|
|
184
|
+
*/
|
|
185
|
+
const EMAIL_LITERAL = /(?<![\w+./-])[\w+.-]+@[\w-]*(?:\.[A-Za-z\d][\w-]*)+/g;
|
|
186
|
+
/** `[start, end)` spans GFM would link as email literals. */
|
|
187
|
+
function emailLiteralSpans(s) {
|
|
188
|
+
if (!s.includes('@'))
|
|
189
|
+
return [];
|
|
190
|
+
const spans = [];
|
|
191
|
+
for (const email of s.matchAll(EMAIL_LITERAL)) {
|
|
192
|
+
if (ASCII_ALPHA.test(email[0].at(-1))) {
|
|
193
|
+
spans.push([email.index, email.index + email[0].length]);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return spans;
|
|
197
|
+
}
|
|
198
|
+
/** End of the autolink literal whose prefix is at `i`, or -1 when the renderer would not link. */
|
|
199
|
+
function autolinkEnd(s, i, prefix, trail) {
|
|
200
|
+
// A `www.` literal's domain starts at the `w`; a protocol's after `//`, on neither a control
|
|
201
|
+
// character nor punctuation — not even the `-` a domain may hold later.
|
|
202
|
+
let domainStart = i;
|
|
203
|
+
if (s[prefix] === ':') {
|
|
204
|
+
domainStart = prefix + 3;
|
|
205
|
+
const first = s[domainStart] ?? '';
|
|
206
|
+
const code = first.charCodeAt(0);
|
|
207
|
+
if (code < 32 || code === 127 || ASCII_PUNCTUATION.test(first))
|
|
208
|
+
return -1;
|
|
209
|
+
}
|
|
210
|
+
const domain = domainEnd(s, domainStart, trail);
|
|
211
|
+
return domain === -1 ? -1 : pathEnd(s, domain, trail);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Indices of the `[` characters to escape: those ahead of a `](` pair, where a link needs the
|
|
215
|
+
* `[` to open its label, the one a line starts with, and any the text never closes. Left open, a
|
|
216
|
+
* `[` stays an unbalanced label across everything interpolated after it on the line, and GFM
|
|
217
|
+
* links no URL inside an unbalanced label.
|
|
218
|
+
*/
|
|
219
|
+
function escapedBrackets(s, blockMarker) {
|
|
220
|
+
const lastLinkClose = s.lastIndexOf('](');
|
|
221
|
+
const escaped = new Set();
|
|
222
|
+
const open = [];
|
|
223
|
+
for (let i = 0; i < s.length; i++) {
|
|
224
|
+
if (s[i] === '[') {
|
|
225
|
+
if (i < lastLinkClose || i === blockMarker)
|
|
226
|
+
escaped.add(i);
|
|
227
|
+
else
|
|
228
|
+
open.push(i);
|
|
229
|
+
}
|
|
230
|
+
else if (s[i] === ']') {
|
|
231
|
+
open.pop();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
for (const i of open)
|
|
235
|
+
escaped.add(i);
|
|
236
|
+
return escaped;
|
|
237
|
+
}
|
|
238
|
+
/** Whether the `<` at `index` opens raw HTML or an autolink. */
|
|
239
|
+
function opensTagOrAutolink(text, index) {
|
|
240
|
+
if (TAG_START.test(text[index + 1] ?? ''))
|
|
241
|
+
return true;
|
|
242
|
+
EMAIL_AUTOLINK.lastIndex = index;
|
|
243
|
+
return EMAIL_AUTOLINK.test(text);
|
|
244
|
+
}
|
|
245
|
+
/** Whether the `&` at `index` starts a reference a Markdown renderer would decode. */
|
|
246
|
+
function startsCharacterReference(text, index) {
|
|
247
|
+
NUMERIC_REFERENCE.lastIndex = index;
|
|
248
|
+
if (NUMERIC_REFERENCE.test(text))
|
|
249
|
+
return true;
|
|
250
|
+
NAMED_REFERENCE.lastIndex = index;
|
|
251
|
+
const named = NAMED_REFERENCE.exec(text);
|
|
252
|
+
return named !== null && isNamedCharacterReference(named[1]);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Index of the `#` that would open an ATX closing sequence — a trailing run of `#` preceded by a
|
|
256
|
+
* space or standing alone — or -1 when the text has none.
|
|
257
|
+
*/
|
|
258
|
+
function closingHashIndex(text) {
|
|
259
|
+
const end = text.trimEnd().length;
|
|
260
|
+
let start = end;
|
|
261
|
+
while (start > 0 && text[start - 1] === '#')
|
|
262
|
+
start--;
|
|
263
|
+
if (start === end)
|
|
264
|
+
return -1;
|
|
265
|
+
return start === 0 || text[start - 1] === ' ' ? start : -1;
|
|
266
|
+
}
|
|
267
|
+
/** Index of the character to escape so the text cannot open a block at the start of a line. */
|
|
268
|
+
function blockMarkerIndex(text) {
|
|
269
|
+
const first = text[0];
|
|
270
|
+
if (first === '#' || first === '>' || first === '[')
|
|
271
|
+
return 0;
|
|
272
|
+
if ((first === '-' || first === '+') && (text.length === 1 || text[1] === ' '))
|
|
273
|
+
return 0;
|
|
274
|
+
const ordered = ORDERED_LIST_MARKER.exec(text);
|
|
275
|
+
return ordered ? ordered[0].trimEnd().length - 1 : -1;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Escape provider text for Markdown so a renderer shows exactly the characters it holds.
|
|
279
|
+
*
|
|
280
|
+
* Escaped everywhere: `*`, backticks, `~` (GFM strikethrough), `<` before a letter, `/`, `!`, or
|
|
281
|
+
* `?`, `_` unless it sits between two letters or digits, `&` when it starts a character reference
|
|
282
|
+
* a renderer would decode, a backslash before punctuation or at the end, a `<` that opens an
|
|
283
|
+
* email autolink, and any `[` ahead of a `](` pair (a link needs it to open its label) or never
|
|
284
|
+
* closed. Closed citation brackets with no `](` after them stay as they are. At a line start,
|
|
285
|
+
* also the block markers; in a heading, a trailing `#` run. Line breaks and tabs collapse to a
|
|
286
|
+
* space.
|
|
287
|
+
*
|
|
288
|
+
* A span GFM links as an autolink literal passes through untouched. When it cannot — trailing
|
|
289
|
+
* punctuation that needs an escape would join the link, an open `[` or an email literal holds
|
|
290
|
+
* it, or GFM would not link it at all — the `:` or `.` of its prefix is escaped instead, which
|
|
291
|
+
* reads the same but links nothing in any renderer, and the span is escaped like any other text.
|
|
292
|
+
*/
|
|
293
|
+
export function escapeMarkdown(text, position = 'inline') {
|
|
294
|
+
let s = text.replace(LINE_BREAKS, ' ');
|
|
295
|
+
if (position === 'line-start')
|
|
296
|
+
s = s.trimStart();
|
|
297
|
+
const blockMarker = position === 'line-start' ? blockMarkerIndex(s) : -1;
|
|
298
|
+
const closingHash = position === 'heading' ? closingHashIndex(s) : -1;
|
|
299
|
+
const brackets = escapedBrackets(s, blockMarker);
|
|
300
|
+
let trail;
|
|
301
|
+
let emails;
|
|
302
|
+
let nextEmail = 0;
|
|
303
|
+
let openBrackets = 0;
|
|
304
|
+
/**
|
|
305
|
+
* Whether the autolink literal ending at `end`, with its trailing punctuation up to `trailEnd`,
|
|
306
|
+
* renders as exactly those characters: no open `[` before it, inert trailing punctuation, and
|
|
307
|
+
* no escape needed on the character past it, whose backslash would join the link.
|
|
308
|
+
*/
|
|
309
|
+
const linksCleanly = (end, trailEnd) => {
|
|
310
|
+
if (openBrackets > 0)
|
|
311
|
+
return false;
|
|
312
|
+
const trailing = s.slice(end, trailEnd);
|
|
313
|
+
if (!INERT_TRAIL.test(trailing))
|
|
314
|
+
return false;
|
|
315
|
+
if (/^[_~]/.test(trailing) && !ASCII_ALPHANUMERIC.test(s[end - 1]))
|
|
316
|
+
return false;
|
|
317
|
+
const after = s[trailEnd];
|
|
318
|
+
if (after === '<')
|
|
319
|
+
return !opensTagOrAutolink(s, trailEnd);
|
|
320
|
+
return after !== '[' || !brackets.has(trailEnd);
|
|
321
|
+
};
|
|
322
|
+
// Unescaped runs are copied as slices; `copied` marks where the pending run begins.
|
|
323
|
+
const parts = [];
|
|
324
|
+
let copied = 0;
|
|
325
|
+
let prefixToEscape = -1;
|
|
326
|
+
// Autolink prefixes before this index sit inside a span that could not link as a whole.
|
|
327
|
+
let unlinkedUntil = -1;
|
|
328
|
+
for (let i = 0; i < s.length; i++) {
|
|
329
|
+
const ch = s[i];
|
|
330
|
+
const next = s[i + 1];
|
|
331
|
+
if (ch === 'h' || ch === 'H' || ch === 'w' || ch === 'W') {
|
|
332
|
+
const prefix = autolinkPrefixIndex(s, i);
|
|
333
|
+
if (prefix !== -1) {
|
|
334
|
+
trail ??= trailEnds(s);
|
|
335
|
+
emails ??= emailLiteralSpans(s);
|
|
336
|
+
while ((emails[nextEmail]?.[1] ?? Number.POSITIVE_INFINITY) <= i)
|
|
337
|
+
nextEmail++;
|
|
338
|
+
const inEmail = (emails[nextEmail]?.[0] ?? Number.POSITIVE_INFINITY) <= i;
|
|
339
|
+
const end = i < unlinkedUntil || inEmail ? -1 : autolinkEnd(s, i, prefix, trail);
|
|
340
|
+
// The link and its inert trailing punctuation pass through as they are.
|
|
341
|
+
if (end !== -1 && linksCleanly(end, trail[end])) {
|
|
342
|
+
i = trail[end] - 1;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
prefixToEscape = prefix;
|
|
346
|
+
unlinkedUntil = Math.max(unlinkedUntil, end);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
let needsEscape;
|
|
350
|
+
switch (ch) {
|
|
351
|
+
case '*':
|
|
352
|
+
case '`':
|
|
353
|
+
case '~':
|
|
354
|
+
needsEscape = true;
|
|
355
|
+
break;
|
|
356
|
+
case '_':
|
|
357
|
+
needsEscape = !(WORD_CHARACTER.test(s[i - 1] ?? '') && WORD_CHARACTER.test(next ?? ''));
|
|
358
|
+
break;
|
|
359
|
+
case '\\':
|
|
360
|
+
needsEscape = next === undefined || ASCII_PUNCTUATION.test(next);
|
|
361
|
+
break;
|
|
362
|
+
case '<':
|
|
363
|
+
needsEscape = opensTagOrAutolink(s, i);
|
|
364
|
+
break;
|
|
365
|
+
case '[':
|
|
366
|
+
needsEscape = brackets.has(i);
|
|
367
|
+
if (!needsEscape)
|
|
368
|
+
openBrackets++;
|
|
369
|
+
break;
|
|
370
|
+
case ']':
|
|
371
|
+
needsEscape = false;
|
|
372
|
+
if (openBrackets > 0)
|
|
373
|
+
openBrackets--;
|
|
374
|
+
break;
|
|
375
|
+
case '&':
|
|
376
|
+
needsEscape = startsCharacterReference(s, i);
|
|
377
|
+
break;
|
|
378
|
+
default:
|
|
379
|
+
needsEscape = i === blockMarker || i === closingHash || i === prefixToEscape;
|
|
380
|
+
}
|
|
381
|
+
if (needsEscape) {
|
|
382
|
+
parts.push(s.slice(copied, i), '\\');
|
|
383
|
+
copied = i;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
parts.push(s.slice(copied));
|
|
387
|
+
return parts.join('');
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=escape-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape-markdown.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/escape-markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,10 +6,22 @@
|
|
|
6
6
|
* @module mcp-server/tools/render-entity-record
|
|
7
7
|
*/
|
|
8
8
|
import type { EntityRecord } from '../../services/openalex/types.js';
|
|
9
|
+
/** Where an array returned in part sits in the full array. */
|
|
10
|
+
export interface ArrayWindowView {
|
|
11
|
+
/** Index in the full array of the first element shown. */
|
|
12
|
+
offset: number;
|
|
13
|
+
/** Elements in the full array. */
|
|
14
|
+
total: number;
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* Render an OpenAlex entity record as markdown lines: a `### display_name` header,
|
|
11
18
|
* the ID, then each remaining field as a labeled line. Caller joins the lines into
|
|
12
|
-
* the final text block.
|
|
19
|
+
* the final text block. Provider text is escaped for Markdown; field names are OpenAlex
|
|
20
|
+
* schema keys and render as they are.
|
|
21
|
+
*
|
|
22
|
+
* `windows` maps an array field returned in part to where it sits in the full array: its items
|
|
23
|
+
* are numbered from `offset`, and its line says how many of `total` it shows, so a window never
|
|
24
|
+
* reads as a complete or empty array.
|
|
13
25
|
*/
|
|
14
|
-
export declare function renderEntityRecord(record: EntityRecord): string[];
|
|
26
|
+
export declare function renderEntityRecord(record: EntityRecord, windows?: ReadonlyMap<string, ArrayWindowView>): string[];
|
|
15
27
|
//# sourceMappingURL=render-entity-record.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-entity-record.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/render-entity-record.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"render-entity-record.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/render-entity-record.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAqFjE,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;CACf;AAgCD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GAC7C,MAAM,EAAE,CAWV"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* "label: value" lines that mirror `structuredContent` field-for-field.
|
|
6
6
|
* @module mcp-server/tools/render-entity-record
|
|
7
7
|
*/
|
|
8
|
+
import { escapeMarkdown } from './escape-markdown.js';
|
|
8
9
|
const ACRONYMS = new Set([
|
|
9
10
|
'apc',
|
|
10
11
|
'doi',
|
|
@@ -36,6 +37,17 @@ function isScalarOrNull(value) {
|
|
|
36
37
|
function isPlainObject(value) {
|
|
37
38
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
38
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* A scalar leaf as Markdown. Strings are provider text and go through `escapeMarkdown`; numbers
|
|
42
|
+
* and booleans carry no syntax. Every leaf lands mid-line — after a label, a path, or a list
|
|
43
|
+
* marker — so the inline position applies.
|
|
44
|
+
*/
|
|
45
|
+
function renderScalar(value) {
|
|
46
|
+
return typeof value === 'string' ? escapeMarkdown(value) : String(value);
|
|
47
|
+
}
|
|
48
|
+
function renderScalarList(values) {
|
|
49
|
+
return values.map((item) => (item === null ? '—' : renderScalar(item))).join(', ');
|
|
50
|
+
}
|
|
39
51
|
/**
|
|
40
52
|
* Flatten a value to "path: value" strings, one per scalar leaf. Nested objects use dot
|
|
41
53
|
* notation (`subfield.display_name`); arrays of scalars collapse to a single comma-joined
|
|
@@ -47,12 +59,12 @@ function flattenLeaves(value, prefix = '') {
|
|
|
47
59
|
if (value === null || value === undefined)
|
|
48
60
|
return prefix ? [`${prefix}: —`] : [];
|
|
49
61
|
if (isScalar(value))
|
|
50
|
-
return [prefix ? `${prefix}: ${
|
|
62
|
+
return [prefix ? `${prefix}: ${renderScalar(value)}` : renderScalar(value)];
|
|
51
63
|
if (Array.isArray(value)) {
|
|
52
64
|
if (value.length === 0)
|
|
53
65
|
return [`${prefix || 'value'}: (empty)`];
|
|
54
66
|
if (value.every(isScalarOrNull)) {
|
|
55
|
-
const joined = value
|
|
67
|
+
const joined = renderScalarList(value);
|
|
56
68
|
return [prefix ? `${prefix}: ${joined}` : joined];
|
|
57
69
|
}
|
|
58
70
|
return value.flatMap((item, i) => flattenLeaves(item, `${prefix}[${i}]`));
|
|
@@ -68,22 +80,32 @@ function flattenLeaves(value, prefix = '') {
|
|
|
68
80
|
function compactPairs(value) {
|
|
69
81
|
return flattenLeaves(value).join(', ');
|
|
70
82
|
}
|
|
71
|
-
|
|
83
|
+
const count = (n) => n.toLocaleString('en-US');
|
|
84
|
+
/** The note a partly shown array carries on its label line; undefined when it shows every element. */
|
|
85
|
+
function windowNote(shown, view) {
|
|
86
|
+
if (!view || shown >= view.total)
|
|
87
|
+
return;
|
|
88
|
+
const from = view.offset > 0 ? ` from offset ${count(view.offset)}` : '';
|
|
89
|
+
return `(${count(shown)} of ${count(view.total)} shown${from} — windowed; see Window)`;
|
|
90
|
+
}
|
|
91
|
+
function renderField(field, value, view) {
|
|
72
92
|
const label = toFieldLabel(field);
|
|
73
93
|
if (value == null)
|
|
74
94
|
return `**${label}:** —`;
|
|
75
95
|
if (isScalar(value))
|
|
76
|
-
return `**${label}:** ${
|
|
96
|
+
return `**${label}:** ${renderScalar(value)}`;
|
|
77
97
|
if (Array.isArray(value)) {
|
|
98
|
+
const note = windowNote(value.length, view);
|
|
99
|
+
const head = note ? `**${label}:** ${note}` : `**${label}:**`;
|
|
78
100
|
if (value.length === 0)
|
|
79
|
-
return `**${label}:** (empty)`;
|
|
80
|
-
if (value.every(isScalarOrNull))
|
|
81
|
-
return
|
|
82
|
-
|
|
101
|
+
return note ? head : `**${label}:** (empty)`;
|
|
102
|
+
if (value.every(isScalarOrNull))
|
|
103
|
+
return `${head} ${renderScalarList(value)}`;
|
|
104
|
+
const first = view?.offset ?? 0;
|
|
83
105
|
const items = value.map((item, i) => isPlainObject(item)
|
|
84
|
-
? `- [${i}] ${compactPairs(item)}`
|
|
85
|
-
: `- [${i}] ${flattenLeaves(item).join(', ') || '—'}`);
|
|
86
|
-
return
|
|
106
|
+
? `- [${first + i}] ${compactPairs(item)}`
|
|
107
|
+
: `- [${first + i}] ${flattenLeaves(item).join(', ') || '—'}`);
|
|
108
|
+
return `${head}\n${items.join('\n')}`;
|
|
87
109
|
}
|
|
88
110
|
if (isPlainObject(value))
|
|
89
111
|
return `**${label}:** ${compactPairs(value)}`;
|
|
@@ -92,13 +114,22 @@ function renderField(field, value) {
|
|
|
92
114
|
/**
|
|
93
115
|
* Render an OpenAlex entity record as markdown lines: a `### display_name` header,
|
|
94
116
|
* the ID, then each remaining field as a labeled line. Caller joins the lines into
|
|
95
|
-
* the final text block.
|
|
117
|
+
* the final text block. Provider text is escaped for Markdown; field names are OpenAlex
|
|
118
|
+
* schema keys and render as they are.
|
|
119
|
+
*
|
|
120
|
+
* `windows` maps an array field returned in part to where it sits in the full array: its items
|
|
121
|
+
* are numbered from `offset`, and its line says how many of `total` it shows, so a window never
|
|
122
|
+
* reads as a complete or empty array.
|
|
96
123
|
*/
|
|
97
|
-
export function renderEntityRecord(record) {
|
|
124
|
+
export function renderEntityRecord(record, windows) {
|
|
98
125
|
const { id, display_name, ...rest } = record;
|
|
99
|
-
const lines = [
|
|
126
|
+
const lines = [
|
|
127
|
+
'',
|
|
128
|
+
`### ${escapeMarkdown(display_name || id, 'heading')}`,
|
|
129
|
+
`**ID:** ${escapeMarkdown(id)}`,
|
|
130
|
+
];
|
|
100
131
|
for (const [field, value] of Object.entries(rest)) {
|
|
101
|
-
lines.push(renderField(field, value));
|
|
132
|
+
lines.push(renderField(field, value, windows?.get(field)));
|
|
102
133
|
}
|
|
103
134
|
return lines;
|
|
104
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-entity-record.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/render-entity-record.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"render-entity-record.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/render-entity-record.ts"],"names":[],"mappings":"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"}
|