@farming-labs/docs 0.2.71 → 0.2.73
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/dist/{agent-bof3qzKZ.mjs → agent-ClRpctMG.mjs} +3 -2
- package/dist/{agent-evals-Cr9TAkmB.mjs → agent-evals-BFHGypqh.mjs} +116 -20
- package/dist/{agent-export-7Ws4KqDE.mjs → agent-export-B9bah0AV.mjs} +9 -8
- package/dist/{agent-FIyl4-Oa.mjs → agent-o9OTadrf.mjs} +607 -769
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-server-DTwblsLu.d.mts → agent-skills-server-DCbAx5WU.d.mts} +2 -2
- package/dist/{agent-skills-server-B4u3qy-1.mjs → agent-skills-server-noFn1l_p.mjs} +1 -1
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +2 -2
- package/dist/{agents-Be2ntaFr.mjs → agents-CR-Uasbc.mjs} +7 -6
- package/dist/cli/index.mjs +14 -14
- package/dist/client/react.d.mts +1 -1
- package/dist/{cloud-ask-ai-BfnX18rI.d.mts → cloud-ask-ai-yR9vZmSG.d.mts} +1 -1
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/{doctor-DoPAofVP.mjs → doctor-BeyN3Ljh.mjs} +12 -11
- package/dist/{golden-evaluations-CPGGnXOV.mjs → golden-evaluations-CloP0pAe.mjs} +23 -2
- package/dist/index.d.mts +93 -6
- package/dist/index.mjs +9 -8
- package/dist/markdown-rendering.d.mts +75 -0
- package/dist/markdown-rendering.mjs +618 -0
- package/dist/markdown-sections-7OoA7ylx.mjs +1492 -0
- package/dist/{mcp-BLynUzE7.mjs → mcp-BLLXvEXB.mjs} +7 -6
- package/dist/mcp.d.mts +7 -2
- package/dist/mcp.mjs +130 -25
- package/dist/{metadata-bw8k-9x-.mjs → metadata-N252j5_a.mjs} +1 -1
- package/dist/{reading-time-DtNegNiq.mjs → prompt-references-Cz35rlOa.mjs} +158 -4
- package/dist/{review-NFnYbMRI.mjs → review-DaJLdPLh.mjs} +7 -6
- package/dist/{robots-DOqBwQw8.mjs → robots-BcuxnZqZ.mjs} +2 -2
- package/dist/{robots-B3e-aWPy.mjs → robots-DI-9MZz1.mjs} +4 -3
- package/dist/{search-CozHzW7v.d.mts → search-D1n8Sf25.d.mts} +45 -9
- package/dist/{search-DOGUUZvs.mjs → search-DeOJiMAy.mjs} +7 -6
- package/dist/{search-x5O0-9X3.mjs → search-RfPcG1if.mjs} +742 -42
- package/dist/server.d.mts +13 -5
- package/dist/server.mjs +8 -7
- package/dist/{sitemap-BpMKdDUd.mjs → sitemap-BGGbX_KE.mjs} +7 -6
- package/dist/{sitemap-server-D_hayOp6.mjs → sitemap-server-VefDnzEB.mjs} +1 -1
- package/dist/{standards-discovery-C0CIC4QI.d.mts → standards-discovery-83lp1lew.d.mts} +5 -4
- package/dist/{standards-discovery-CYfiQE13.mjs → standards-discovery-BwL5ffGx.mjs} +4 -3
- package/dist/{types-BQC05SQm.d.mts → types-_HCPD4wc.d.mts} +49 -1
- package/package.json +9 -1
- package/dist/agent-scope-C_U--OZ7.mjs +0 -283
- /package/dist/{i18n-CCaFUnAN.mjs → i18n-hHVWcflJ.mjs} +0 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import { s as parseDocsMarkdownSections } from "./markdown-sections-7OoA7ylx.mjs";
|
|
2
|
+
import { parseEntities } from "parse-entities";
|
|
3
|
+
|
|
4
|
+
//#region src/markdown-rendering.ts
|
|
5
|
+
const TRAILING_DOCS_MARKDOWN_HEADING_ID = /\s*\\?\[#([^\]\r\n]+)\]\s*$/;
|
|
6
|
+
/**
|
|
7
|
+
* Allocate transport placeholders without colliding with authored Markdown.
|
|
8
|
+
*
|
|
9
|
+
* Manual renderers restore these tokens after their inline/block passes, so a
|
|
10
|
+
* collision would otherwise move rendered component HTML to user-authored text.
|
|
11
|
+
*/
|
|
12
|
+
function createDocsMarkdownBlockPlaceholderAllocator(source) {
|
|
13
|
+
const nextIndexes = /* @__PURE__ */ new Map();
|
|
14
|
+
const used = /* @__PURE__ */ new Set();
|
|
15
|
+
return (kind) => {
|
|
16
|
+
let index = nextIndexes.get(kind) ?? 0;
|
|
17
|
+
let token = "";
|
|
18
|
+
do {
|
|
19
|
+
token = `%%${kind}_${index}%%`;
|
|
20
|
+
index += 1;
|
|
21
|
+
} while (source.includes(token) || used.has(token));
|
|
22
|
+
nextIndexes.set(kind, index);
|
|
23
|
+
used.add(token);
|
|
24
|
+
return token;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function createDocsMarkdownTransportToken(source, kind, index, used) {
|
|
28
|
+
let salt = 0;
|
|
29
|
+
let token = "";
|
|
30
|
+
do {
|
|
31
|
+
token = `\uE100FARMINGLABS_DOCS_${kind.toUpperCase()}_${index}_${salt}\uE101`;
|
|
32
|
+
salt += 1;
|
|
33
|
+
} while (source.includes(token) || used.has(token));
|
|
34
|
+
return token;
|
|
35
|
+
}
|
|
36
|
+
function createDocsMarkdownOpeningTagToken(source, index, used) {
|
|
37
|
+
let candidate = index;
|
|
38
|
+
let token = "";
|
|
39
|
+
do {
|
|
40
|
+
token = `%%FARMINGLABS_DOCS_HEADING_OPEN_${candidate}%%`;
|
|
41
|
+
candidate += 1;
|
|
42
|
+
} while (source.includes(token) || used.has(token));
|
|
43
|
+
return token;
|
|
44
|
+
}
|
|
45
|
+
function escapeDocsMarkdownHtml(value) {
|
|
46
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
47
|
+
}
|
|
48
|
+
function splitDocsMarkdownHeadingContainerLine(line) {
|
|
49
|
+
let prefix = "";
|
|
50
|
+
let content = line;
|
|
51
|
+
while (content) {
|
|
52
|
+
const container = content.match(/^(?: {0,3}>[\t ]?| {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+)/);
|
|
53
|
+
if (!container) break;
|
|
54
|
+
prefix += container[0];
|
|
55
|
+
content = content.slice(container[0].length);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
prefix,
|
|
59
|
+
content
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Annotate only headings accepted by the canonical section parser.
|
|
64
|
+
*
|
|
65
|
+
* The opaque tokens let the lightweight Astro, Nuxt, and Svelte renderers carry
|
|
66
|
+
* exact IDs through their component and inline-Markdown passes without parsing
|
|
67
|
+
* the document a second, divergent way.
|
|
68
|
+
*/
|
|
69
|
+
function prepareDocsMarkdownHeadings(markdown) {
|
|
70
|
+
const frontmatter = markdown.match(/^(\uFEFF?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$))/)?.[1] ?? "";
|
|
71
|
+
const frontmatterLineOffset = frontmatter.match(/\r?\n/g)?.length ?? 0;
|
|
72
|
+
const canonicalHeadings = parseDocsMarkdownSections(frontmatter ? markdown.slice(frontmatter.length) : markdown);
|
|
73
|
+
const canonicalHeadingsByLine = new Map(canonicalHeadings.map((heading) => [heading.startLine + frontmatterLineOffset, heading]));
|
|
74
|
+
const headings = [];
|
|
75
|
+
const headingTokens = /* @__PURE__ */ new Set();
|
|
76
|
+
const output = [];
|
|
77
|
+
const annotate = (source, canonicalHeading) => {
|
|
78
|
+
const token = createDocsMarkdownTransportToken(markdown, "anchor", headings.length, headingTokens);
|
|
79
|
+
headingTokens.add(token);
|
|
80
|
+
headings.push({
|
|
81
|
+
anchor: canonicalHeading.anchor,
|
|
82
|
+
explicit: canonicalHeading.explicit,
|
|
83
|
+
level: canonicalHeading.level,
|
|
84
|
+
token
|
|
85
|
+
});
|
|
86
|
+
return `${source} ${token}`;
|
|
87
|
+
};
|
|
88
|
+
const lines = markdown.split(/\r?\n/);
|
|
89
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
90
|
+
const line = lines[index] ?? "";
|
|
91
|
+
const canonicalHeading = canonicalHeadingsByLine.get(index + 1);
|
|
92
|
+
if (!canonicalHeading) {
|
|
93
|
+
output.push(line);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const containerLine = splitDocsMarkdownHeadingContainerLine(line);
|
|
97
|
+
const atx = containerLine.content.match(/^ {0,3}(#{1,6})(?:[\t ]+|$)(.*)$/);
|
|
98
|
+
if (atx) {
|
|
99
|
+
const source = atx[2].replace(/[\t ]+#+[\t ]*$/, "").trim();
|
|
100
|
+
output.push(`${containerLine.prefix}${atx[1]} ${annotate(source, canonicalHeading)}`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
output.push(`${containerLine.prefix}${annotate(containerLine.content.trim(), canonicalHeading)}`);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
markdown: output.join("\n"),
|
|
107
|
+
headings
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function stripPreparedDocsMarkdownHeadingTokens(value) {
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
function renderDocsMarkdownHeadings(markdown, preparedHeadings) {
|
|
114
|
+
const lines = markdown.split(/\r?\n/);
|
|
115
|
+
const output = [];
|
|
116
|
+
const openingTags = [];
|
|
117
|
+
const openingTagTokens = /* @__PURE__ */ new Set();
|
|
118
|
+
const protectOpeningTag = (level, anchor) => {
|
|
119
|
+
const token = createDocsMarkdownOpeningTagToken(markdown, openingTags.length, openingTagTokens);
|
|
120
|
+
openingTagTokens.add(token);
|
|
121
|
+
openingTags.push({
|
|
122
|
+
html: `<h${level} id="${escapeDocsMarkdownHtml(anchor)}">`,
|
|
123
|
+
token
|
|
124
|
+
});
|
|
125
|
+
return token;
|
|
126
|
+
};
|
|
127
|
+
const resolveHeading = (source) => {
|
|
128
|
+
const prepared = preparedHeadings.find((heading) => source.includes(heading.token));
|
|
129
|
+
if (!prepared) return void 0;
|
|
130
|
+
const withoutToken = source.split(prepared.token).join("");
|
|
131
|
+
return {
|
|
132
|
+
anchor: prepared.anchor,
|
|
133
|
+
explicit: prepared.explicit,
|
|
134
|
+
level: prepared.level,
|
|
135
|
+
source: prepared.explicit ? withoutToken.replace(TRAILING_DOCS_MARKDOWN_HEADING_ID, "").trim() : withoutToken.trim()
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
139
|
+
const line = lines[index] ?? "";
|
|
140
|
+
const containerLine = splitDocsMarkdownHeadingContainerLine(line);
|
|
141
|
+
const atx = containerLine.content.match(/^ {0,3}(#{1,6})(?:[\t ]+|$)(.*)$/);
|
|
142
|
+
if (atx) {
|
|
143
|
+
const heading = resolveHeading(atx[2].replace(/[\t ]+#+[\t ]*$/, "").trim());
|
|
144
|
+
if (!heading) {
|
|
145
|
+
output.push(line);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const level = atx[1].length;
|
|
149
|
+
output.push(`${containerLine.prefix}${protectOpeningTag(level, heading.anchor)}${heading.source}</h${level}>`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const heading = resolveHeading(containerLine.content.trim());
|
|
153
|
+
if (heading) {
|
|
154
|
+
const sourceLines = [heading.source];
|
|
155
|
+
let underlineIndex = index + 1;
|
|
156
|
+
const expectedUnderline = heading.level === 1 ? /^=+$/ : /^-+$/;
|
|
157
|
+
while (underlineIndex < lines.length) {
|
|
158
|
+
const continuation = splitDocsMarkdownHeadingContainerLine(lines[underlineIndex] ?? "").content;
|
|
159
|
+
if (expectedUnderline.test(continuation.trim())) break;
|
|
160
|
+
if (!continuation.trim()) break;
|
|
161
|
+
sourceLines.push(continuation.trim());
|
|
162
|
+
underlineIndex += 1;
|
|
163
|
+
}
|
|
164
|
+
const combinedSource = sourceLines.join(" ");
|
|
165
|
+
const visibleSource = heading.explicit ? combinedSource.replace(TRAILING_DOCS_MARKDOWN_HEADING_ID, "").trim() : combinedSource;
|
|
166
|
+
output.push(`${containerLine.prefix}${protectOpeningTag(heading.level, heading.anchor)}${visibleSource}</h${heading.level}>`);
|
|
167
|
+
if (underlineIndex < lines.length) index = underlineIndex;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
output.push(line);
|
|
171
|
+
}
|
|
172
|
+
let renderedMarkdown = output.join("\n");
|
|
173
|
+
for (const prepared of preparedHeadings) renderedMarkdown = renderedMarkdown.split(prepared.token).join("");
|
|
174
|
+
return {
|
|
175
|
+
markdown: renderedMarkdown,
|
|
176
|
+
openingTags
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function restoreDocsMarkdownHeadingOpeningTags(value, openingTags) {
|
|
180
|
+
let restored = value;
|
|
181
|
+
for (const openingTag of openingTags) restored = restored.split(openingTag.token).join(openingTag.html);
|
|
182
|
+
return restored;
|
|
183
|
+
}
|
|
184
|
+
function splitDocsMarkdownFenceContainerLine(line) {
|
|
185
|
+
const containers = [];
|
|
186
|
+
let content = line;
|
|
187
|
+
let prefix = "";
|
|
188
|
+
while (content) {
|
|
189
|
+
const blockquote = content.match(/^ {0,3}>[\t ]?/);
|
|
190
|
+
if (blockquote) {
|
|
191
|
+
prefix += blockquote[0];
|
|
192
|
+
content = content.slice(blockquote[0].length);
|
|
193
|
+
containers.push({
|
|
194
|
+
continuationIndent: 0,
|
|
195
|
+
type: "blockquote"
|
|
196
|
+
});
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const listItem = content.match(/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/);
|
|
200
|
+
if (listItem) {
|
|
201
|
+
prefix += listItem[0];
|
|
202
|
+
content = content.slice(listItem[0].length);
|
|
203
|
+
containers.push({
|
|
204
|
+
continuationIndent: listItem[0].length,
|
|
205
|
+
type: "list"
|
|
206
|
+
});
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
containers,
|
|
213
|
+
content,
|
|
214
|
+
prefix
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function continueDocsMarkdownFenceContainerLine(line, containers) {
|
|
218
|
+
let content = line;
|
|
219
|
+
for (const container of containers) {
|
|
220
|
+
if (container.type === "blockquote") {
|
|
221
|
+
const blockquote = content.match(/^ {0,3}>[\t ]?/);
|
|
222
|
+
if (!blockquote) return void 0;
|
|
223
|
+
content = content.slice(blockquote[0].length);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (!content.trim()) {
|
|
227
|
+
content = "";
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const indentation = content.match(/^[\t ]*/)?.[0] ?? "";
|
|
231
|
+
if (indentation.replace(/\t/g, " ").length < container.continuationIndent) return void 0;
|
|
232
|
+
let consumedLength = 0;
|
|
233
|
+
let consumedWidth = 0;
|
|
234
|
+
while (consumedLength < indentation.length) {
|
|
235
|
+
consumedWidth += indentation[consumedLength] === " " ? 4 : 1;
|
|
236
|
+
consumedLength += 1;
|
|
237
|
+
if (consumedWidth >= container.continuationIndent) break;
|
|
238
|
+
}
|
|
239
|
+
content = content.slice(consumedLength);
|
|
240
|
+
}
|
|
241
|
+
return content;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Replace complete CommonMark fenced code blocks without confusing shorter
|
|
245
|
+
* marker runs inside a longer outer fence for its closing delimiter.
|
|
246
|
+
*/
|
|
247
|
+
function replaceDocsMarkdownFencedCodeBlocks(value, render) {
|
|
248
|
+
const lines = [];
|
|
249
|
+
for (const match of value.matchAll(/[^\r\n]*(?:\r\n|\n|\r|$)/g)) {
|
|
250
|
+
const raw = match[0];
|
|
251
|
+
if (!raw) continue;
|
|
252
|
+
const ending = raw.match(/(?:\r\n|\n|\r)$/)?.[0] ?? "";
|
|
253
|
+
const start = match.index;
|
|
254
|
+
const end = start + raw.length - ending.length;
|
|
255
|
+
lines.push({
|
|
256
|
+
end,
|
|
257
|
+
ending,
|
|
258
|
+
start,
|
|
259
|
+
text: ending ? raw.slice(0, -ending.length) : raw
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
let blockIndex = 0;
|
|
263
|
+
let cursor = 0;
|
|
264
|
+
let output = "";
|
|
265
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
266
|
+
const openingLine = lines[lineIndex];
|
|
267
|
+
const containerLine = splitDocsMarkdownFenceContainerLine(openingLine.text);
|
|
268
|
+
const opening = containerLine.content.match(/^( {0,3})(`{3,}|~{3,})([^\r\n]*)$/);
|
|
269
|
+
if (!opening) continue;
|
|
270
|
+
const marker = opening[2][0];
|
|
271
|
+
const info = opening[3].trim();
|
|
272
|
+
if (marker === "`" && info.includes("`")) continue;
|
|
273
|
+
const codeLines = [];
|
|
274
|
+
let closingIndex = lineIndex + 1;
|
|
275
|
+
for (; closingIndex < lines.length; closingIndex += 1) {
|
|
276
|
+
const continuedContent = containerLine.containers.length === 0 ? lines[closingIndex].text : continueDocsMarkdownFenceContainerLine(lines[closingIndex].text, containerLine.containers);
|
|
277
|
+
if (continuedContent === void 0) break;
|
|
278
|
+
const closing = continuedContent.match(/^ {0,3}(`+|~+)[\t ]*$/);
|
|
279
|
+
if (closing && closing[1][0] === marker && closing[1].length >= opening[2].length) break;
|
|
280
|
+
codeLines.push(`${continuedContent}${lines[closingIndex].ending}`);
|
|
281
|
+
}
|
|
282
|
+
const candidateClosingLine = lines[closingIndex];
|
|
283
|
+
const candidateClosing = (candidateClosingLine ? containerLine.containers.length === 0 ? candidateClosingLine.text : continueDocsMarkdownFenceContainerLine(candidateClosingLine.text, containerLine.containers) : void 0)?.match(/^ {0,3}(`+|~+)[\t ]*$/);
|
|
284
|
+
const closingLine = candidateClosing && candidateClosing[1][0] === marker && candidateClosing[1].length >= opening[2].length ? candidateClosingLine : void 0;
|
|
285
|
+
const implicitClosingLine = candidateClosingLine ? lines[closingIndex - 1] : void 0;
|
|
286
|
+
const blockEnd = closingLine?.end ?? implicitClosingLine?.end ?? value.length;
|
|
287
|
+
output += value.slice(cursor, openingLine.start);
|
|
288
|
+
output += containerLine.prefix + opening[1];
|
|
289
|
+
output += render({
|
|
290
|
+
code: codeLines.join(""),
|
|
291
|
+
fenceLength: opening[2].length,
|
|
292
|
+
info,
|
|
293
|
+
marker
|
|
294
|
+
}, blockIndex);
|
|
295
|
+
blockIndex += 1;
|
|
296
|
+
cursor = blockEnd;
|
|
297
|
+
if (closingLine) lineIndex = closingIndex;
|
|
298
|
+
else if (candidateClosingLine) lineIndex = closingIndex - 1;
|
|
299
|
+
else break;
|
|
300
|
+
}
|
|
301
|
+
return blockIndex === 0 ? value : output + value.slice(cursor);
|
|
302
|
+
}
|
|
303
|
+
function normalizeDocsMarkdownReferenceLabel(value) {
|
|
304
|
+
return parseEntities(unescapeDocsMarkdownPunctuation(value), { nonTerminated: false }).trim().replace(/\s+/g, " ").toLowerCase();
|
|
305
|
+
}
|
|
306
|
+
function unescapeDocsMarkdownPunctuation(value) {
|
|
307
|
+
return value.replace(/\\([!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~])/g, "$1");
|
|
308
|
+
}
|
|
309
|
+
function findDocsMarkdownClosingDelimiter(value, start, open, close) {
|
|
310
|
+
let depth = 0;
|
|
311
|
+
for (let index = start; index < value.length; index += 1) {
|
|
312
|
+
if (value[index] === "\\") {
|
|
313
|
+
index += 1;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (value[index] === open) depth += 1;
|
|
317
|
+
if (value[index] !== close) continue;
|
|
318
|
+
depth -= 1;
|
|
319
|
+
if (depth === 0) return index;
|
|
320
|
+
}
|
|
321
|
+
return -1;
|
|
322
|
+
}
|
|
323
|
+
function readDocsMarkdownHtmlTagEnd(value, start) {
|
|
324
|
+
if (value[start] !== "<" || !/[A-Za-z/!?]/.test(value[start + 1] ?? "")) return -1;
|
|
325
|
+
let quote;
|
|
326
|
+
for (let index = start + 1; index < value.length; index += 1) {
|
|
327
|
+
const character = value[index];
|
|
328
|
+
if (quote) {
|
|
329
|
+
if (character === quote && value[index - 1] !== "\\") quote = void 0;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (character === "'" || character === "\"") {
|
|
333
|
+
quote = character;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (character === ">") return index;
|
|
337
|
+
}
|
|
338
|
+
return -1;
|
|
339
|
+
}
|
|
340
|
+
function parseDocsMarkdownDestination(source) {
|
|
341
|
+
const value = source.trim();
|
|
342
|
+
if (!value) return { destination: "" };
|
|
343
|
+
let destination = "";
|
|
344
|
+
let remainder = "";
|
|
345
|
+
if (value.startsWith("<")) {
|
|
346
|
+
const end = value.indexOf(">");
|
|
347
|
+
if (end < 0) return void 0;
|
|
348
|
+
destination = value.slice(1, end);
|
|
349
|
+
remainder = value.slice(end + 1).trim();
|
|
350
|
+
} else {
|
|
351
|
+
let depth = 0;
|
|
352
|
+
let end = value.length;
|
|
353
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
354
|
+
if (value[index] === "\\") {
|
|
355
|
+
index += 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (value[index] === "(") depth += 1;
|
|
359
|
+
if (value[index] === ")") depth = Math.max(0, depth - 1);
|
|
360
|
+
if (/\s/.test(value[index]) && depth === 0) {
|
|
361
|
+
end = index;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
destination = value.slice(0, end);
|
|
366
|
+
remainder = value.slice(end).trim();
|
|
367
|
+
}
|
|
368
|
+
let title;
|
|
369
|
+
if (remainder) {
|
|
370
|
+
const titleMatch = remainder.match(/^(?:"([^"]*)"|'([^']*)'|\(([^()]*)\))$/);
|
|
371
|
+
if (!titleMatch) return void 0;
|
|
372
|
+
title = titleMatch[1] ?? titleMatch[2] ?? titleMatch[3];
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
destination: unescapeDocsMarkdownPunctuation(destination),
|
|
376
|
+
...title === void 0 ? {} : { title: unescapeDocsMarkdownPunctuation(title) }
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function extractDocsMarkdownReferenceDefinitions(markdown) {
|
|
380
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
381
|
+
const output = [];
|
|
382
|
+
let openFence;
|
|
383
|
+
for (const line of markdown.split(/\r?\n/)) {
|
|
384
|
+
if (openFence) {
|
|
385
|
+
const marker = openFence.marker === "`" ? "`" : "~";
|
|
386
|
+
if (new RegExp(`^ {0,3}${marker}{${openFence.length},}[\\t ]*$`).test(line)) openFence = void 0;
|
|
387
|
+
output.push(line);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const openingFence = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
391
|
+
if (openingFence) {
|
|
392
|
+
openFence = {
|
|
393
|
+
marker: openingFence[1][0],
|
|
394
|
+
length: openingFence[1].length
|
|
395
|
+
};
|
|
396
|
+
output.push(line);
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const definitionMatch = line.match(/^ {0,3}\[([^\]]+)\]:[ \t]*(.*)$/);
|
|
400
|
+
const definition = definitionMatch ? parseDocsMarkdownDestination(definitionMatch[2]) : void 0;
|
|
401
|
+
if (!definitionMatch || !definition) {
|
|
402
|
+
output.push(line);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const normalizedLabel = normalizeDocsMarkdownReferenceLabel(definitionMatch[1]);
|
|
406
|
+
if (!definitions.has(normalizedLabel)) definitions.set(normalizedLabel, definition);
|
|
407
|
+
output.push("");
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
markdown: output.join("\n"),
|
|
411
|
+
definitions
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function renderDocsMarkdownResources(value, definitions) {
|
|
415
|
+
let output = "";
|
|
416
|
+
let index = 0;
|
|
417
|
+
while (index < value.length) {
|
|
418
|
+
const htmlTagEnd = readDocsMarkdownHtmlTagEnd(value, index);
|
|
419
|
+
if (htmlTagEnd >= 0) {
|
|
420
|
+
output += value.slice(index, htmlTagEnd + 1);
|
|
421
|
+
index = htmlTagEnd + 1;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const image = value[index] === "!" && value[index + 1] === "[";
|
|
425
|
+
const link = value[index] === "[";
|
|
426
|
+
if (!image && !link) {
|
|
427
|
+
output += value[index];
|
|
428
|
+
index += 1;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const labelStart = index + (image ? 2 : 1);
|
|
432
|
+
const labelEnd = findDocsMarkdownClosingDelimiter(value, labelStart - 1, "[", "]");
|
|
433
|
+
if (labelEnd < 0) {
|
|
434
|
+
output += value[index];
|
|
435
|
+
index += 1;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
const label = value.slice(labelStart, labelEnd);
|
|
439
|
+
let end = labelEnd + 1;
|
|
440
|
+
let target;
|
|
441
|
+
if (value[end] === "(") {
|
|
442
|
+
const destinationEnd = findDocsMarkdownClosingDelimiter(value, end, "(", ")");
|
|
443
|
+
if (destinationEnd < 0) {
|
|
444
|
+
output += value[index];
|
|
445
|
+
index += 1;
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
target = parseDocsMarkdownDestination(value.slice(end + 1, destinationEnd));
|
|
449
|
+
end = destinationEnd + 1;
|
|
450
|
+
} else if (value[end] === "[") {
|
|
451
|
+
const referenceEnd = findDocsMarkdownClosingDelimiter(value, end, "[", "]");
|
|
452
|
+
if (referenceEnd < 0) {
|
|
453
|
+
output += value[index];
|
|
454
|
+
index += 1;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
const referenceLabel = value.slice(end + 1, referenceEnd) || label;
|
|
458
|
+
target = definitions.get(normalizeDocsMarkdownReferenceLabel(referenceLabel));
|
|
459
|
+
end = referenceEnd + 1;
|
|
460
|
+
} else target = definitions.get(normalizeDocsMarkdownReferenceLabel(label));
|
|
461
|
+
if (!target) {
|
|
462
|
+
output += value.slice(index, end);
|
|
463
|
+
index = end;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
const titleAttribute = target.title === void 0 ? "" : ` title="${escapeDocsMarkdownHtml(target.title)}"`;
|
|
467
|
+
if (image) {
|
|
468
|
+
const alt = unescapeDocsMarkdownPunctuation(label).replace(/<[^>]+>/g, "").replace(/[*_~`]/g, "");
|
|
469
|
+
output += `<img src="${escapeDocsMarkdownHtml(target.destination)}" alt="${escapeDocsMarkdownHtml(alt)}" class="fd-docs-content-img" loading="lazy" decoding="async"${titleAttribute} />`;
|
|
470
|
+
} else output += `<a href="${escapeDocsMarkdownHtml(target.destination)}"${titleAttribute}>${renderDocsMarkdownResources(label, definitions)}</a>`;
|
|
471
|
+
index = end;
|
|
472
|
+
}
|
|
473
|
+
return output;
|
|
474
|
+
}
|
|
475
|
+
function renderDocsMarkdownEmphasis(value) {
|
|
476
|
+
return value.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/(?<![\w])__([^_\n]+)__(?![\w])/g, "<strong>$1</strong>").replace(/\*([^*\n]+)\*/g, "<em>$1</em>").replace(/(?<![\w])_([^_\n]+)_(?![\w])/g, "<em>$1</em>").replace(/~~([^~\n]+)~~/g, "<del>$1</del>");
|
|
477
|
+
}
|
|
478
|
+
function renderDocsMarkdownTextOutsideHtml(value) {
|
|
479
|
+
let output = "";
|
|
480
|
+
let textStart = 0;
|
|
481
|
+
let index = 0;
|
|
482
|
+
while (index < value.length) {
|
|
483
|
+
const htmlTagEnd = readDocsMarkdownHtmlTagEnd(value, index);
|
|
484
|
+
if (htmlTagEnd < 0) {
|
|
485
|
+
index += 1;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
output += renderDocsMarkdownEmphasis(value.slice(textStart, index));
|
|
489
|
+
output += value.slice(index, htmlTagEnd + 1);
|
|
490
|
+
index = htmlTagEnd + 1;
|
|
491
|
+
textStart = index;
|
|
492
|
+
}
|
|
493
|
+
output += renderDocsMarkdownEmphasis(value.slice(textStart));
|
|
494
|
+
return output;
|
|
495
|
+
}
|
|
496
|
+
function renderDocsMarkdownInline(value, definitions) {
|
|
497
|
+
const literals = [];
|
|
498
|
+
const literalTokens = /* @__PURE__ */ new Set();
|
|
499
|
+
const protectLiteral = (html) => {
|
|
500
|
+
const token = createDocsMarkdownTransportToken(value, "inline", literals.length, literalTokens);
|
|
501
|
+
literalTokens.add(token);
|
|
502
|
+
literals.push({
|
|
503
|
+
html,
|
|
504
|
+
token
|
|
505
|
+
});
|
|
506
|
+
return token;
|
|
507
|
+
};
|
|
508
|
+
let protectedValue = value.replace(/(`+)([\s\S]*?)\1/g, (_match, _ticks, code) => {
|
|
509
|
+
const normalized = code.replace(/\s+/g, " ");
|
|
510
|
+
return protectLiteral(`<code>${escapeDocsMarkdownHtml(normalized.length > 2 && normalized.startsWith(" ") && normalized.endsWith(" ") && normalized.trim() ? normalized.slice(1, -1) : normalized)}</code>`);
|
|
511
|
+
});
|
|
512
|
+
protectedValue = protectedValue.replace(/\\([!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~])/g, (_match, punctuation) => protectLiteral(escapeDocsMarkdownHtml(punctuation)));
|
|
513
|
+
let rendered = renderDocsMarkdownTextOutsideHtml(renderDocsMarkdownResources(protectedValue, definitions));
|
|
514
|
+
for (const literal of literals) rendered = rendered.split(literal.token).join(literal.html);
|
|
515
|
+
return rendered;
|
|
516
|
+
}
|
|
517
|
+
function renderDocsMarkdownBlockContent(value, definitions) {
|
|
518
|
+
const output = [];
|
|
519
|
+
let paragraphLines = [];
|
|
520
|
+
const flushParagraph = () => {
|
|
521
|
+
if (paragraphLines.length === 0) return;
|
|
522
|
+
output.push(`<p>${paragraphLines.map((line) => renderDocsMarkdownInline(line, definitions)).join("<br />")}</p>`);
|
|
523
|
+
paragraphLines = [];
|
|
524
|
+
};
|
|
525
|
+
for (const line of value.trim().split(/\r?\n/)) {
|
|
526
|
+
const trimmed = line.trim();
|
|
527
|
+
if (!trimmed) {
|
|
528
|
+
flushParagraph();
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const heading = trimmed.match(/^<h([1-6])\b([^>]*)>([\s\S]*)<\/h\1>$/);
|
|
532
|
+
if (heading) {
|
|
533
|
+
flushParagraph();
|
|
534
|
+
output.push(`<h${heading[1]}${heading[2]}>${renderDocsMarkdownInline(heading[3], definitions)}</h${heading[1]}>`);
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
if (/^<(?:pre|ul|ol|blockquote|hr|table|div|figure)\b/.test(trimmed)) {
|
|
538
|
+
flushParagraph();
|
|
539
|
+
output.push(trimmed);
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
if (/^%%(?:CODEBLOCK|CALLOUT|TABS|PROMPT|HOVERLINK)_\d+%%$/.test(trimmed)) {
|
|
543
|
+
flushParagraph();
|
|
544
|
+
output.push(trimmed);
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
paragraphLines.push(trimmed);
|
|
548
|
+
}
|
|
549
|
+
flushParagraph();
|
|
550
|
+
return output.join("");
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Hoist canonical headings out of component bodies before those bodies are
|
|
554
|
+
* rendered as cards, tabs, or literal prompt text.
|
|
555
|
+
*
|
|
556
|
+
* A heading must still carry an opening-tag transport token created by
|
|
557
|
+
* `renderDocsMarkdownHeadings`. Authored raw `<h*>` HTML is deliberately left
|
|
558
|
+
* in `content`, so a literal renderer such as Prompt can escape it instead of
|
|
559
|
+
* accidentally promoting its attributes to live HTML.
|
|
560
|
+
*/
|
|
561
|
+
function extractDocsRenderedHeadingElements(value, definitions, preserveText = true, openingTags = []) {
|
|
562
|
+
const headings = [];
|
|
563
|
+
const output = [];
|
|
564
|
+
const protectedHeadings = openingTags.flatMap((openingTag) => {
|
|
565
|
+
const level = openingTag.html.match(/^<h([1-6])\b[^>]*>$/)?.[1];
|
|
566
|
+
return level ? [{
|
|
567
|
+
...openingTag,
|
|
568
|
+
level
|
|
569
|
+
}] : [];
|
|
570
|
+
});
|
|
571
|
+
let openFence;
|
|
572
|
+
for (const lineWithEnding of value.match(/[^\r\n]*(?:\r\n|\n|\r|$)/g) ?? []) {
|
|
573
|
+
if (!lineWithEnding) continue;
|
|
574
|
+
const ending = lineWithEnding.match(/(?:\r\n|\n|\r)$/)?.[0] ?? "";
|
|
575
|
+
const line = ending ? lineWithEnding.slice(0, -ending.length) : lineWithEnding;
|
|
576
|
+
if (openFence) {
|
|
577
|
+
const continuedContent = openFence.containers.length === 0 ? line : continueDocsMarkdownFenceContainerLine(line, openFence.containers);
|
|
578
|
+
if (continuedContent !== void 0) {
|
|
579
|
+
output.push(lineWithEnding);
|
|
580
|
+
const marker = openFence.marker === "`" ? "`" : "~";
|
|
581
|
+
if (new RegExp(`^ {0,3}${marker}{${openFence.length},}[\\t ]*$`).test(continuedContent)) openFence = void 0;
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
openFence = void 0;
|
|
585
|
+
}
|
|
586
|
+
const containerLine = splitDocsMarkdownFenceContainerLine(line);
|
|
587
|
+
const openingFence = containerLine.content.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
588
|
+
if (openingFence) {
|
|
589
|
+
openFence = {
|
|
590
|
+
containers: containerLine.containers,
|
|
591
|
+
length: openingFence[1].length,
|
|
592
|
+
marker: openingFence[1][0]
|
|
593
|
+
};
|
|
594
|
+
output.push(lineWithEnding);
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
let renderedLine = line;
|
|
598
|
+
for (const protectedHeading of protectedHeadings) {
|
|
599
|
+
const tokenIndex = renderedLine.indexOf(protectedHeading.token);
|
|
600
|
+
if (tokenIndex < 0) continue;
|
|
601
|
+
const contentStart = tokenIndex + protectedHeading.token.length;
|
|
602
|
+
const closingTag = `</h${protectedHeading.level}>`;
|
|
603
|
+
const contentEnd = renderedLine.indexOf(closingTag, contentStart);
|
|
604
|
+
if (contentEnd < 0) continue;
|
|
605
|
+
const inner = renderedLine.slice(contentStart, contentEnd);
|
|
606
|
+
headings.push(`${protectedHeading.html}${renderDocsMarkdownInline(inner, definitions)}${closingTag}`);
|
|
607
|
+
renderedLine = renderedLine.slice(0, tokenIndex) + (preserveText ? inner.replace(/<[^>]+>/g, "").trim() : "") + renderedLine.slice(contentEnd + closingTag.length);
|
|
608
|
+
}
|
|
609
|
+
output.push(`${renderedLine}${ending}`);
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
headingsHtml: headings.join("\n"),
|
|
613
|
+
content: output.join("")
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
//#endregion
|
|
618
|
+
export { createDocsMarkdownBlockPlaceholderAllocator, extractDocsMarkdownReferenceDefinitions, extractDocsRenderedHeadingElements, prepareDocsMarkdownHeadings, renderDocsMarkdownBlockContent, renderDocsMarkdownHeadings, renderDocsMarkdownInline, replaceDocsMarkdownFencedCodeBlocks, restoreDocsMarkdownHeadingOpeningTags, stripPreparedDocsMarkdownHeadingTokens };
|