@neuledge/context 1.2.0 → 1.2.2
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/README.md +13 -3
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +123 -37
- package/dist/cli.js.map +1 -1
- package/dist/html.d.ts +8 -0
- package/dist/html.js +10 -3
- package/dist/html.js.map +1 -1
- package/dist/package-builder.d.ts +27 -0
- package/dist/package-builder.js +463 -3
- package/dist/package-builder.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +6 -7
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +35 -8
- package/dist/store.js +128 -13
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
package/dist/package-builder.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createHash } from "node:crypto";
|
|
|
5
5
|
import { existsSync, unlinkSync } from "node:fs";
|
|
6
6
|
import { parseDocument } from "./build.js";
|
|
7
7
|
import { openDatabase } from "./database.js";
|
|
8
|
+
import { REMOVED_TAGS } from "./html.js";
|
|
8
9
|
/**
|
|
9
10
|
* Generate a content hash for section deduplication.
|
|
10
11
|
* Uses first 16 chars of MD5 (sufficient for detecting identical content).
|
|
@@ -12,6 +13,456 @@ import { openDatabase } from "./database.js";
|
|
|
12
13
|
function contentHash(content) {
|
|
13
14
|
return createHash("md5").update(content).digest("hex").slice(0, 16);
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Markdown chunks longer than this are split further before AST parsing.
|
|
18
|
+
*
|
|
19
|
+
* Counted in UTF-16 code units, not bytes: that is what a JS string costs in the heap,
|
|
20
|
+
* which is the resource being bounded here.
|
|
21
|
+
*/
|
|
22
|
+
const MAX_PARSE_CHUNK_CHARS = 1024 * 1024;
|
|
23
|
+
/** Extensions `parseDocument` routes to `parseHtml`. Matched as it matches them. */
|
|
24
|
+
const HTML_EXTENSIONS = [".html", ".htm"];
|
|
25
|
+
/** Extensions `parseDocument` routes away from remark. Matched as it matches them. */
|
|
26
|
+
const NON_MARKDOWN_EXTENSIONS = [...HTML_EXTENSIONS, ".adoc", ".rst"];
|
|
27
|
+
/** An ATX `##` heading: up to 3 spaces of indent, then `##` and a space or tab. */
|
|
28
|
+
const H2_LINE = /^ {0,3}##([ \t]|$)/;
|
|
29
|
+
/** The `<h2>…</h2>` a chunk opens with, if it opens with one. */
|
|
30
|
+
const H2_OPENING = /^<h2[\s>][\s\S]*?<\/h2\s*>/i;
|
|
31
|
+
/** Longest heading carried forward; past this it is a section body, not a title. */
|
|
32
|
+
const MAX_CARRIED_HEADING = 1024;
|
|
33
|
+
/**
|
|
34
|
+
* Split markdown into one chunk per `##` section.
|
|
35
|
+
*
|
|
36
|
+
* Fenced code blocks are tracked so that `## ` lines inside them — common in docs that
|
|
37
|
+
* demonstrate markdown — aren't mistaken for headings and split mid-fence. Fence
|
|
38
|
+
* handling follows CommonMark: an opening fence may carry an info string, a closing
|
|
39
|
+
* fence may not, and only the same character in at least the same run length closes.
|
|
40
|
+
*/
|
|
41
|
+
export function splitMarkdownByHeadings(file) {
|
|
42
|
+
const parts = [];
|
|
43
|
+
let current = [];
|
|
44
|
+
let openFence = null;
|
|
45
|
+
for (const line of file.content.split("\n")) {
|
|
46
|
+
const [, marker, info] = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line) ?? [];
|
|
47
|
+
if (marker) {
|
|
48
|
+
if (openFence === null) {
|
|
49
|
+
// Backtick fences can't have a backtick in the info string; that isn't a fence.
|
|
50
|
+
if (marker[0] !== "`" || !info?.includes("`"))
|
|
51
|
+
openFence = marker;
|
|
52
|
+
}
|
|
53
|
+
else if (marker.startsWith(openFence) && !info?.trim()) {
|
|
54
|
+
openFence = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (openFence === null && H2_LINE.test(line) && current.length) {
|
|
58
|
+
parts.push(current.join("\n"));
|
|
59
|
+
current = [];
|
|
60
|
+
}
|
|
61
|
+
current.push(line);
|
|
62
|
+
}
|
|
63
|
+
if (current.length)
|
|
64
|
+
parts.push(current.join("\n"));
|
|
65
|
+
if (parts.length <= 1)
|
|
66
|
+
return [file];
|
|
67
|
+
return parts.map((content) => ({ path: file.path, content }));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Move a blind cut off a surrogate pair, which halved becomes two U+FFFD.
|
|
71
|
+
*
|
|
72
|
+
* Only ever moves back by one, and never past `from`, so it can't stall a loop that
|
|
73
|
+
* relies on the cut making progress.
|
|
74
|
+
*/
|
|
75
|
+
function offSurrogatePair(text, from, at) {
|
|
76
|
+
const high = text.charCodeAt(at - 1);
|
|
77
|
+
return high >= 0xd800 && high <= 0xdbff && at - 1 > from ? at - 1 : at;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Split content into chunks of at most `maxChars`, preferring line boundaries.
|
|
81
|
+
*
|
|
82
|
+
* A single line over the limit is cut mid-line. Nothing else bounds it, and a line that
|
|
83
|
+
* long is a data blob — a base64 payload, a minified sample — rather than prose.
|
|
84
|
+
*/
|
|
85
|
+
function splitBySize(content, maxChars) {
|
|
86
|
+
const chunks = [];
|
|
87
|
+
let current = "";
|
|
88
|
+
for (const line of content.split("\n")) {
|
|
89
|
+
if (current && current.length + line.length + 1 > maxChars) {
|
|
90
|
+
chunks.push(current);
|
|
91
|
+
current = "";
|
|
92
|
+
}
|
|
93
|
+
let rest = line;
|
|
94
|
+
while (rest.length > maxChars) {
|
|
95
|
+
const at = offSurrogatePair(rest, 0, maxChars);
|
|
96
|
+
chunks.push(rest.slice(0, at));
|
|
97
|
+
rest = rest.slice(at);
|
|
98
|
+
}
|
|
99
|
+
current += current ? `\n${rest}` : rest;
|
|
100
|
+
}
|
|
101
|
+
if (current)
|
|
102
|
+
chunks.push(current);
|
|
103
|
+
return chunks.length ? chunks : [content];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* `REMOVED_TAGS` numbered, so the open-element stack below can hold integers.
|
|
107
|
+
*
|
|
108
|
+
* A page of nothing but `<svg ` pushes one entry per five characters, and holding that
|
|
109
|
+
* many short strings alive costs the collector about a third of the scan; the same
|
|
110
|
+
* count of small integers is a packed array of a couple of megabytes and costs nothing.
|
|
111
|
+
*/
|
|
112
|
+
const REMOVED_TAG_IDS = new Map([...REMOVED_TAGS].map((tag, id) => [tag, id]));
|
|
113
|
+
/** A tag name at a known `<`. Sticky: it matches there or not at all, never searches. */
|
|
114
|
+
const TAG_NAME = /<(\/?)([a-zA-Z][^\s/>]*)/y;
|
|
115
|
+
/** The quote opening an attribute value, at a known `=`. Sticky, as above. */
|
|
116
|
+
const ATTR_VALUE = /\s*(["'])?/y;
|
|
117
|
+
/** Elements whose content is raw text: a `<` inside them never opens a tag. */
|
|
118
|
+
const RAW_TEXT_TAGS = new Set(["script", "style", "textarea", "title"]);
|
|
119
|
+
/**
|
|
120
|
+
* Raw-text elements the HTML parser also strips.
|
|
121
|
+
*
|
|
122
|
+
* `textarea` is deliberately absent: it is raw text, but turndown keeps its text, so a
|
|
123
|
+
* `<textarea>` that never closes still has indexable content after it.
|
|
124
|
+
*/
|
|
125
|
+
const STRIPPED_RAW_TEXT = new Set([...RAW_TEXT_TAGS].filter((tag) => REMOVED_TAGS.has(tag)));
|
|
126
|
+
/**
|
|
127
|
+
* The `>` ending the tag whose name ends at `from`, or -1 if the tag never ends.
|
|
128
|
+
*
|
|
129
|
+
* Quoted attribute values are jumped over, so the `<` and `>` in `<div title="<b>">` are
|
|
130
|
+
* read as the value they are and not as structure. Reading them as structure is what let
|
|
131
|
+
* a `<script` inside an attribute pass for a real one and drop a whole document.
|
|
132
|
+
*
|
|
133
|
+
* The tag is walked, not tokenized: attribute names and unquoted values need no state,
|
|
134
|
+
* since nothing inside them ends the tag but the `>`. Only the quote is approximated —
|
|
135
|
+
* it counts as opening a value where one belongs, just after `=`, which is also where
|
|
136
|
+
* the real tokenizer accepts one. Elsewhere it is ordinary text, so `<div a=b"c>` ends
|
|
137
|
+
* at that `>` rather than hunting for a matching quote. Both ways of being wrong about
|
|
138
|
+
* an oddity like `<a href=x=y">` end the tag too late rather than too early, which costs
|
|
139
|
+
* cut candidates: cutting more bluntly is recoverable, cutting inside a tag is not.
|
|
140
|
+
*/
|
|
141
|
+
function tagEnd(html, from) {
|
|
142
|
+
for (let i = from; i < html.length; i++) {
|
|
143
|
+
if (html[i] === ">")
|
|
144
|
+
return i;
|
|
145
|
+
if (html[i] !== "=")
|
|
146
|
+
continue;
|
|
147
|
+
ATTR_VALUE.lastIndex = i + 1;
|
|
148
|
+
const [, quote] = ATTR_VALUE.exec(html) ?? [];
|
|
149
|
+
if (!quote)
|
|
150
|
+
continue;
|
|
151
|
+
// A value whose quote never closes swallows the rest of the file, as it does for a
|
|
152
|
+
// real parser: the tag never ends, and everything after it is inside it.
|
|
153
|
+
const close = html.indexOf(quote, ATTR_VALUE.lastIndex);
|
|
154
|
+
if (close < 0)
|
|
155
|
+
return -1;
|
|
156
|
+
i = close;
|
|
157
|
+
}
|
|
158
|
+
return -1;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Yield the offset, lowercased name and shape of every tag in an HTML source, and return
|
|
162
|
+
* the offset at which the document stops holding indexable content.
|
|
163
|
+
*
|
|
164
|
+
* Tag markup itself is skipped, so an attribute value is never read as document text and
|
|
165
|
+
* the `<script` in `<div title="<script>">` is not seen at all. A tag with no `>` ends
|
|
166
|
+
* the scan: the rest of the file is inside it, and later cuts there are merely blunt.
|
|
167
|
+
*
|
|
168
|
+
* Comments and terminated raw-text element bodies are skipped, because a cut inside one
|
|
169
|
+
* loses content rather than splitting it: the truncated `<script>` or `<!--` swallows
|
|
170
|
+
* the rest of its chunk, and its tail reappears in the next chunk as prose.
|
|
171
|
+
*
|
|
172
|
+
* An unterminated `<!--`, or an unterminated `<textarea>`, is scanned into rather than
|
|
173
|
+
* abandoned. Giving up looks safer but isn't: it leaves the entire remainder of the file
|
|
174
|
+
* with no cut candidate, so every later cut is blind and can land mid-tag, spilling raw
|
|
175
|
+
* attribute markup into the index, and the tail is resurrected either way.
|
|
176
|
+
*
|
|
177
|
+
* A `<script>`, `<style>` or `<title>` that never closes is different, and is where the
|
|
178
|
+
* scan stops. Everything after it is that element's text content — that is what the
|
|
179
|
+
* whole-file parse sees — and turndown drops the element, so the tail is not content to
|
|
180
|
+
* be placed well but content that does not exist. The returned offset is where it
|
|
181
|
+
* starts; scanning on would only decide where to cut a region the parser never had.
|
|
182
|
+
*/
|
|
183
|
+
function* scanTags(html) {
|
|
184
|
+
let i = 0;
|
|
185
|
+
// A close tag that could not be found from one offset cannot be found from a later
|
|
186
|
+
// one, and these searches only ever start further into the file, so one failure per
|
|
187
|
+
// name settles it. Re-running the search is what makes it quadratic: 1MB of
|
|
188
|
+
// `<script ` with no `</script` anywhere rescanned the whole remainder per tag and
|
|
189
|
+
// took 40s, against 50ms once the failure is remembered.
|
|
190
|
+
const unclosed = new Set();
|
|
191
|
+
while (i < html.length) {
|
|
192
|
+
const lt = html.indexOf("<", i);
|
|
193
|
+
if (lt < 0)
|
|
194
|
+
break;
|
|
195
|
+
if (html.startsWith("<!--", lt)) {
|
|
196
|
+
const end = html.indexOf("-->", lt + 4);
|
|
197
|
+
i = end < 0 ? lt + 4 : end + 3;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
// CDATA runs to `]]>`, not to the first `>`. Stopping at a `>` in its body would
|
|
201
|
+
// expose the rest of that body as markup, and an unterminated `<script>` there
|
|
202
|
+
// truncates the document — the same loss the branch below exists to prevent.
|
|
203
|
+
if (html.startsWith("<![CDATA[", lt)) {
|
|
204
|
+
const end = html.indexOf("]]>", lt + 9);
|
|
205
|
+
i = end < 0 ? html.length : end + 3;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// A bogus comment — `<!doctype…>`, `<?php…?>`, `<!foo…>` — ends at the next `>` and
|
|
209
|
+
// its body is not markup. Scanning into it reads that body as tags, and one
|
|
210
|
+
// unterminated `<script>` in there truncates the document at it.
|
|
211
|
+
if (/[!?]/.test(html[lt + 1] ?? "")) {
|
|
212
|
+
const end = html.indexOf(">", lt + 2);
|
|
213
|
+
i = end < 0 ? html.length : end + 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
TAG_NAME.lastIndex = lt;
|
|
217
|
+
const [match, closing, tag] = TAG_NAME.exec(html) ?? [];
|
|
218
|
+
if (!match || !tag) {
|
|
219
|
+
i = lt + 1;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const name = tag.toLowerCase();
|
|
223
|
+
const nameEnd = lt + match.length;
|
|
224
|
+
const end = tagEnd(html, nameEnd);
|
|
225
|
+
// `/>` usually closes the tag on the spot, and counting `<svg/>` open would suppress
|
|
226
|
+
// candidates that did not need it. But an unquoted attribute value swallows the `/`,
|
|
227
|
+
// so `<iframe src=foo/>` is an *open* iframe whose real `</iframe>` would then cancel
|
|
228
|
+
// an enclosing `<aside>`. Only a `/` that ends the tag name or follows a quote or
|
|
229
|
+
// space is read as closing; guessing "open" is the safe way round, costing at most
|
|
230
|
+
// one suppressed cut candidate.
|
|
231
|
+
const selfClosing = html[end - 1] === "/" &&
|
|
232
|
+
(end - 1 === nameEnd || /["'\s]/.test(html[end - 2] ?? ""));
|
|
233
|
+
yield [lt, name, !!closing, selfClosing];
|
|
234
|
+
// Past the tag, not back into it. Resuming at `lt + 1` re-read the tag's own markup
|
|
235
|
+
// as document text, which is how an attribute value came to be scanned for tags.
|
|
236
|
+
// A tag that never ends leaves nothing after it to scan: the rest of the file is
|
|
237
|
+
// inside it, so the scan is over rather than restarted from within. That is also
|
|
238
|
+
// what keeps this linear — tags are walked once because they never overlap — and
|
|
239
|
+
// resuming anywhere inside one makes the whole scan quadratic again.
|
|
240
|
+
i = end < 0 ? html.length : end + 1;
|
|
241
|
+
// `!selfClosing` matters more here than for the stripped stack: `<svg><title/></svg>`
|
|
242
|
+
// is well-formed, and reading that `<title/>` as an open raw-text element with no
|
|
243
|
+
// `</title>` anywhere truncates the document at it, deleting everything after.
|
|
244
|
+
if (!closing &&
|
|
245
|
+
!selfClosing &&
|
|
246
|
+
RAW_TEXT_TAGS.has(name) &&
|
|
247
|
+
!unclosed.has(name)) {
|
|
248
|
+
const close = new RegExp(`</${name}`, "gi");
|
|
249
|
+
close.lastIndex = i;
|
|
250
|
+
const found = close.exec(html)?.index;
|
|
251
|
+
if (found != null)
|
|
252
|
+
i = found;
|
|
253
|
+
else if (STRIPPED_RAW_TEXT.has(name))
|
|
254
|
+
return lt;
|
|
255
|
+
else
|
|
256
|
+
unclosed.add(name);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return html.length;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Split HTML into chunks of at most `maxChars`, cutting at tag boundaries.
|
|
263
|
+
*
|
|
264
|
+
* Each cut lands on the last `<h2` that fits, so chunks hold whole sections and
|
|
265
|
+
* `parseHtml` still names them from their heading; failing that, on the last tag that
|
|
266
|
+
* fits. A stretch of text with no tag at all is cut mid-way — nothing else bounds it,
|
|
267
|
+
* and it is a data blob rather than markup.
|
|
268
|
+
*
|
|
269
|
+
* Offsets inside a `REMOVED_TAGS` element are skipped while the element is smaller than
|
|
270
|
+
* a chunk. Cutting there leaves the opening `<aside>` in the previous chunk, so
|
|
271
|
+
* `turndown.remove` no longer applies to the tail and the sidebar is indexed as prose —
|
|
272
|
+
* and in reverse, a `<h2>` inside a stripped `<header>` becomes a real heading once the
|
|
273
|
+
* `<header>` is gone.
|
|
274
|
+
*
|
|
275
|
+
* Fragments are safe to hand to a parser in a way markdown fragments are not: HTML
|
|
276
|
+
* parsing auto-closes whatever the cut left open, so a chunk degrades to slightly
|
|
277
|
+
* flatter nesting instead of the following text changing meaning.
|
|
278
|
+
*/
|
|
279
|
+
function splitHtmlBySize(html, maxChars) {
|
|
280
|
+
const chunks = [];
|
|
281
|
+
let start = 0;
|
|
282
|
+
let lastTag = 0;
|
|
283
|
+
let lastHeading = 0;
|
|
284
|
+
// The open `REMOVED_TAGS` elements the scan is inside, innermost last. Bounded by the
|
|
285
|
+
// cap below: suppression is dropped once it has spanned `maxChars`, and the shortest
|
|
286
|
+
// opening tag that reaches this stack is five characters, so a 1MB chunk limit caps it
|
|
287
|
+
// at about 210k entries however deeply the page nests.
|
|
288
|
+
const open = [];
|
|
289
|
+
// Both candidates were recorded while they still fit, and `start` only moves
|
|
290
|
+
// forward, so every chunk cut here is within the limit.
|
|
291
|
+
const packTo = (offset) => {
|
|
292
|
+
while (offset - start > maxChars) {
|
|
293
|
+
const at = lastHeading > start
|
|
294
|
+
? lastHeading
|
|
295
|
+
: lastTag > start
|
|
296
|
+
? lastTag
|
|
297
|
+
: offSurrogatePair(html, start, start + maxChars);
|
|
298
|
+
chunks.push(html.slice(start, at));
|
|
299
|
+
start = at;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
// Iterated by hand rather than with `for…of`, which discards the generator's return
|
|
303
|
+
// value — here, the offset at which indexable content ends.
|
|
304
|
+
const tags = scanTags(html);
|
|
305
|
+
let tag = tags.next();
|
|
306
|
+
// Opening `<h2` only: cutting at the matching `</h2` would strand the heading in
|
|
307
|
+
// the previous chunk and leave its section titled "Introduction".
|
|
308
|
+
for (; !tag.done; tag = tags.next()) {
|
|
309
|
+
const [offset, name, closing, selfClosing] = tag.value;
|
|
310
|
+
packTo(offset);
|
|
311
|
+
// Suppression that has outrun a whole chunk has nothing left to protect: the cut
|
|
312
|
+
// lands inside the element whichever candidate wins, so take the tag boundary.
|
|
313
|
+
// This also caps the damage of an element that is opened and never closed.
|
|
314
|
+
if (open.length && offset - lastTag > maxChars)
|
|
315
|
+
open.length = 0;
|
|
316
|
+
const removedId = REMOVED_TAG_IDS.get(name);
|
|
317
|
+
const isRemoved = removedId !== undefined;
|
|
318
|
+
// These elements nest — `<article><header>` inside a `<header>` is ordinary — so
|
|
319
|
+
// the body is skipped by tracking what is open, not by searching for the next close
|
|
320
|
+
// tag. Names are tracked and not merely a depth, because a stray `</header>` inside
|
|
321
|
+
// an `<aside>` would otherwise end the aside's suppression early and let a cut land
|
|
322
|
+
// inside it. A close tag that does not match the innermost open element is ignored
|
|
323
|
+
// rather than hunted for further up the stack: that hunt is what would make this
|
|
324
|
+
// quadratic, and ignoring it is also what an HTML parser does with these elements,
|
|
325
|
+
// whose mismatched end tags are dropped instead of closing an ancestor. Mis-nesting
|
|
326
|
+
// like `<aside><nav></aside>` therefore leaves the stack stuck open, which only
|
|
327
|
+
// costs cut candidates until the cap above clears it.
|
|
328
|
+
if (closing && isRemoved && open[open.length - 1] === removedId)
|
|
329
|
+
open.pop();
|
|
330
|
+
if (!open.length) {
|
|
331
|
+
lastTag = offset;
|
|
332
|
+
if (name === "h2" && !closing)
|
|
333
|
+
lastHeading = offset;
|
|
334
|
+
}
|
|
335
|
+
if (!closing && isRemoved && !selfClosing)
|
|
336
|
+
open.push(removedId);
|
|
337
|
+
}
|
|
338
|
+
// Cut exactly where content ends, so the tail can be dropped a whole chunk at a time.
|
|
339
|
+
// The tail is still emitted — these chunks stay a lossless partition of the input, and
|
|
340
|
+
// which of them are worth parsing is `splitForParsing`'s call. In the usual case,
|
|
341
|
+
// where content ends with the document, everything below is a no-op.
|
|
342
|
+
const contentEnd = tag.value;
|
|
343
|
+
packTo(contentEnd);
|
|
344
|
+
if (start < contentEnd)
|
|
345
|
+
chunks.push(html.slice(start, contentEnd));
|
|
346
|
+
start = contentEnd;
|
|
347
|
+
const contentChunks = chunks.length;
|
|
348
|
+
packTo(html.length);
|
|
349
|
+
if (start < html.length)
|
|
350
|
+
chunks.push(html.slice(start));
|
|
351
|
+
return { chunks, contentChunks };
|
|
352
|
+
}
|
|
353
|
+
/** The document's leading YAML frontmatter block, if it opens with one. */
|
|
354
|
+
function leadingFrontmatter(content) {
|
|
355
|
+
return /^---\n[\s\S]*?\n---\n/.exec(content)?.[0] ?? "";
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Break an oversized file into chunks small enough to parse without exhausting the heap.
|
|
359
|
+
*
|
|
360
|
+
* remark builds a full AST for whatever it is given, so a multi-megabyte document (a
|
|
361
|
+
* site's `llms-full.txt`, say) can OOM the process. Splitting by `##` keeps sections
|
|
362
|
+
* intact where possible; the size fallback bounds the rest, so a file with no headings
|
|
363
|
+
* — or one enormous section — can't crash the build either.
|
|
364
|
+
*
|
|
365
|
+
* HTML is split on tag structure instead, because `parseHtml` builds a DOM before it
|
|
366
|
+
* builds an AST and the DOM is what actually hurts: converting an 8MB page peaked at
|
|
367
|
+
* 1451MB RSS, of which the full pipeline added only 40MB more. Converting first and
|
|
368
|
+
* reusing the markdown split would therefore bound nothing — the source has to be cut
|
|
369
|
+
* before turndown sees it. AsciiDoc and reStructuredText are left whole; both parse
|
|
370
|
+
* with plain line scanning, so neither is a heap risk.
|
|
371
|
+
*/
|
|
372
|
+
export function splitForParsing(file) {
|
|
373
|
+
if (file.content.length <= MAX_PARSE_CHUNK_CHARS)
|
|
374
|
+
return [file];
|
|
375
|
+
if (HTML_EXTENSIONS.some((ext) => file.path.endsWith(ext))) {
|
|
376
|
+
// `parseHtml` titles a section from the `<h2>` opening it, so a chunk cut where no
|
|
377
|
+
// heading fit would otherwise be indexed as "Introduction". Carry the heading a
|
|
378
|
+
// chunk opened with into its continuations, exactly as the markdown path carries a
|
|
379
|
+
// `##` line. Only that heading: any other `<h2>` in the chunk may be one
|
|
380
|
+
// `turndown.remove` was going to drop, and promoting it would index chrome as a
|
|
381
|
+
// section title. The budget is reduced by what may be carried so the prefixed chunk
|
|
382
|
+
// still fits; `splitHtmlBySize` itself stays lossless.
|
|
383
|
+
let carried = "";
|
|
384
|
+
const { chunks, contentChunks } = splitHtmlBySize(file.content, MAX_PARSE_CHUNK_CHARS - MAX_CARRIED_HEADING);
|
|
385
|
+
// Chunks past `contentChunks` are the text of a `<script>`, `<style>` or `<title>`
|
|
386
|
+
// that never closes, which is what the whole-file parse makes of them too. Parsing
|
|
387
|
+
// them would index raw JavaScript as prose; a page whose script is unterminated
|
|
388
|
+
// right at the top therefore yields nothing, exactly as it does whole.
|
|
389
|
+
return chunks.slice(0, contentChunks).map((chunk) => {
|
|
390
|
+
const opening = H2_OPENING.exec(chunk)?.[0];
|
|
391
|
+
if (!opening)
|
|
392
|
+
return { path: file.path, content: carried + chunk };
|
|
393
|
+
carried = opening.length <= MAX_CARRIED_HEADING ? opening : "";
|
|
394
|
+
return { path: file.path, content: chunk };
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
const isMarkdown = !NON_MARKDOWN_EXTENSIONS.some((ext) => file.path.endsWith(ext));
|
|
398
|
+
if (!isMarkdown)
|
|
399
|
+
return [file];
|
|
400
|
+
// `parseMarkdown` reads frontmatter only at offset 0 and titles a section from the
|
|
401
|
+
// `##` line opening it, so a continuation chunk would otherwise index under the
|
|
402
|
+
// filename with a section title of "Introduction". Carry both forward instead.
|
|
403
|
+
const frontmatter = leadingFrontmatter(file.content);
|
|
404
|
+
const chunks = [];
|
|
405
|
+
splitMarkdownByHeadings(file).forEach((part, index) => {
|
|
406
|
+
const prefix = index === 0 ? "" : frontmatter;
|
|
407
|
+
if (prefix.length + part.content.length <= MAX_PARSE_CHUNK_CHARS) {
|
|
408
|
+
chunks.push({ path: file.path, content: prefix + part.content });
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
// `frontmatter`, not `prefix`: the first part needs no prefix because it opens the
|
|
412
|
+
// file, frontmatter and all, but its *continuation* chunks do. A document with no
|
|
413
|
+
// `##` anywhere is one single part, so taking `prefix` here left every chunk after
|
|
414
|
+
// the first without frontmatter and indexed under the filename.
|
|
415
|
+
const heading = /^ {0,3}##[ \t].*/.exec(part.content)?.[0];
|
|
416
|
+
const carried = heading ? `${frontmatter + heading}\n` : frontmatter;
|
|
417
|
+
for (const [i, content] of splitBySize(part.content, MAX_PARSE_CHUNK_CHARS - carried.length).entries()) {
|
|
418
|
+
chunks.push({
|
|
419
|
+
path: file.path,
|
|
420
|
+
content: i === 0 ? prefix + content : carried + content,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
return chunks;
|
|
425
|
+
}
|
|
426
|
+
/** The `(part N)` suffix the parser appends when it splits one section into several. */
|
|
427
|
+
const PART_SUFFIX = /^(.*) \(part (\d+)\)$/;
|
|
428
|
+
/**
|
|
429
|
+
* Parse one file, numbering its `(part N)` titles continuously across its chunks.
|
|
430
|
+
*
|
|
431
|
+
* Each chunk is parsed on its own, so the parser's part counter restarts at 1 for every
|
|
432
|
+
* one of them. On a document with no `##`/`<h2>` at all — an `h1`+`h3` page, div-based
|
|
433
|
+
* headings — the whole file is one "Introduction" section, and the restart makes every
|
|
434
|
+
* chunk repeat the same run of titles. Those titles are indexed into `chunks_fts`, so
|
|
435
|
+
* the duplicates blunt title search and attribution.
|
|
436
|
+
*
|
|
437
|
+
* The count flows *out* of the parser and into the next chunk, rather than an offset
|
|
438
|
+
* being passed *in*: `splitForParsing` is a pure function that runs to completion before
|
|
439
|
+
* anything is parsed, so how many parts a chunk yields is only knowable once it has been
|
|
440
|
+
* parsed. Threading it here also leaves every parser signature — and the titles produced
|
|
441
|
+
* by parsing a whole file — exactly as they were.
|
|
442
|
+
*/
|
|
443
|
+
function parseChunks(file) {
|
|
444
|
+
const sections = [];
|
|
445
|
+
let lastTitle = "";
|
|
446
|
+
let lastPart = 0;
|
|
447
|
+
for (const chunk of splitForParsing(file)) {
|
|
448
|
+
// Only the run of sections a chunk opens with continues the previous chunk, and
|
|
449
|
+
// only if it is under the same title — the heading carried across the cut. Anything
|
|
450
|
+
// past that is a section of the document's own, whose part 1 really is part 1.
|
|
451
|
+
const continues = lastTitle;
|
|
452
|
+
let offset = lastPart;
|
|
453
|
+
for (const section of parseDocument(chunk.content, chunk.path).sections) {
|
|
454
|
+
const [, base = section.sectionTitle, part] = PART_SUFFIX.exec(section.sectionTitle) ?? [];
|
|
455
|
+
if (base !== continues)
|
|
456
|
+
offset = 0;
|
|
457
|
+
lastTitle = base;
|
|
458
|
+
lastPart = Number(part ?? 1) + offset;
|
|
459
|
+
sections.push(lastPart > 1
|
|
460
|
+
? { ...section, sectionTitle: `${base} (part ${lastPart})` }
|
|
461
|
+
: section);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return sections;
|
|
465
|
+
}
|
|
15
466
|
/**
|
|
16
467
|
* Build a documentation package from markdown files.
|
|
17
468
|
*/
|
|
@@ -60,10 +511,14 @@ export function buildPackage(outputPath, files, options) {
|
|
|
60
511
|
`);
|
|
61
512
|
const allSections = [];
|
|
62
513
|
const seenHashes = new Set();
|
|
514
|
+
let skippedFiles = 0;
|
|
63
515
|
for (const file of files) {
|
|
64
516
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
517
|
+
// Splitting is inside the guard on purpose: it walks untrusted markup, so a
|
|
518
|
+
// throw there has to cost one file rather than the whole registry build. Doing
|
|
519
|
+
// it per file also keeps only one file's chunks alive at a time.
|
|
520
|
+
const sections = parseChunks(file);
|
|
521
|
+
for (const section of sections) {
|
|
67
522
|
// Deduplicate sections with identical content (ignore titles)
|
|
68
523
|
const hash = contentHash(section.content);
|
|
69
524
|
if (!seenHashes.has(hash)) {
|
|
@@ -73,7 +528,11 @@ export function buildPackage(outputPath, files, options) {
|
|
|
73
528
|
}
|
|
74
529
|
}
|
|
75
530
|
catch {
|
|
76
|
-
//
|
|
531
|
+
// A file that cannot be split or parsed is dropped whole, so a half-indexed
|
|
532
|
+
// document never reaches the package. The failure is counted rather than
|
|
533
|
+
// logged: `buildPackage` has no logger, and a silent skip is how a registry
|
|
534
|
+
// build loses documents without anyone noticing.
|
|
535
|
+
skippedFiles++;
|
|
77
536
|
}
|
|
78
537
|
}
|
|
79
538
|
// Insert all sections in a transaction
|
|
@@ -90,6 +549,7 @@ export function buildPackage(outputPath, files, options) {
|
|
|
90
549
|
path: outputPath,
|
|
91
550
|
sectionCount: allSections.length,
|
|
92
551
|
totalTokens,
|
|
552
|
+
skippedFiles,
|
|
93
553
|
};
|
|
94
554
|
}
|
|
95
555
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-builder.js","sourceRoot":"","sources":["../src/package-builder.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"package-builder.js","sourceRoot":"","sources":["../src/package-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type PackageStore } from "./store.js";
|
|
4
4
|
export interface ContextServerOptions {
|
|
5
5
|
/**
|
|
6
6
|
* Restrict which installed libraries the agent can see. When set,
|
package/dist/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import { initDatabase } from "./database.js";
|
|
|
9
9
|
import { downloadPackage, searchPackages } from "./download.js";
|
|
10
10
|
import { DOWNLOAD_PACKAGE_DESCRIPTION, GET_DOCS_DESCRIPTION, GET_DOCS_LIBRARY_DESCRIPTION, GET_DOCS_TOPIC_DESCRIPTION, MISSING_PACKAGE_GUIDANCE, NO_DOCUMENTATION_FOUND_MESSAGE, SEARCH_PACKAGES_DESCRIPTION, SEARCH_PACKAGES_NAME_DESCRIPTION, } from "./guidance.js";
|
|
11
11
|
import { search } from "./search.js";
|
|
12
|
+
import { isAllowedLibrary, packageKey, } from "./store.js";
|
|
12
13
|
const require = createRequire(import.meta.url);
|
|
13
14
|
const { version } = require("../package.json");
|
|
14
15
|
/**
|
|
@@ -33,7 +34,8 @@ export class ContextServer {
|
|
|
33
34
|
const all = this.store.list();
|
|
34
35
|
if (!this.allowedLibraries)
|
|
35
36
|
return all;
|
|
36
|
-
|
|
37
|
+
const allowed = this.allowedLibraries;
|
|
38
|
+
return all.filter((p) => isAllowedLibrary(p, allowed));
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* Register all MCP tools. Called before connecting a transport.
|
|
@@ -141,7 +143,7 @@ export class ContextServer {
|
|
|
141
143
|
if (packages.length === 0) {
|
|
142
144
|
return z.string().describe(GET_DOCS_LIBRARY_DESCRIPTION);
|
|
143
145
|
}
|
|
144
|
-
const libraryEnum = packages.map(
|
|
146
|
+
const libraryEnum = packages.map(packageKey);
|
|
145
147
|
return z
|
|
146
148
|
.enum(libraryEnum)
|
|
147
149
|
.describe(GET_DOCS_LIBRARY_DESCRIPTION);
|
|
@@ -182,7 +184,7 @@ export class ContextServer {
|
|
|
182
184
|
}
|
|
183
185
|
handleGetDocs(library, topic) {
|
|
184
186
|
const packages = this.visiblePackages();
|
|
185
|
-
const pkg = packages.find((p) =>
|
|
187
|
+
const pkg = packages.find((p) => packageKey(p) === library);
|
|
186
188
|
if (!pkg) {
|
|
187
189
|
return {
|
|
188
190
|
content: [
|
|
@@ -196,7 +198,7 @@ export class ContextServer {
|
|
|
196
198
|
],
|
|
197
199
|
};
|
|
198
200
|
}
|
|
199
|
-
const db = this.store.openDb(pkg
|
|
201
|
+
const db = this.store.openDb(packageKey(pkg));
|
|
200
202
|
if (!db) {
|
|
201
203
|
return {
|
|
202
204
|
content: [
|
|
@@ -323,9 +325,6 @@ export class ContextServer {
|
|
|
323
325
|
});
|
|
324
326
|
}
|
|
325
327
|
}
|
|
326
|
-
function formatLibraryName(pkg) {
|
|
327
|
-
return `${pkg.name}@${pkg.version}`;
|
|
328
|
-
}
|
|
329
328
|
function formatSearchResult(result) {
|
|
330
329
|
if (result.results.length === 0) {
|
|
331
330
|
return JSON.stringify({
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,4BAA4B,EAC5B,0BAA0B,EAC1B,wBAAwB,EACxB,8BAA8B,EAC9B,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAqB,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|