@farming-labs/docs 0.2.120 → 0.2.122
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 +8 -0
- package/dist/access.d.mts +13 -0
- package/dist/access.mjs +56 -0
- package/dist/agent-conformance.d.mts +60 -0
- package/dist/agent-conformance.mjs +538 -0
- package/dist/agent-contract.d.mts +47 -0
- package/dist/agent-contract.mjs +645 -0
- package/dist/agent-detection.d.mts +6 -0
- package/dist/agent-detection.mjs +83 -0
- package/dist/agent-evals.d.mts +224 -0
- package/dist/{agent-evals-BLNLvXbG.mjs → agent-evals.mjs} +7 -565
- package/dist/agent-feedback-evaluations-node.mjs +38 -0
- package/dist/agent-feedback-evaluations.d.mts +91 -0
- package/dist/{agent-feedback-evaluations-CcMGlgsO.mjs → agent-feedback-evaluations.mjs} +2 -2
- package/dist/agent-feedback-loop.d.mts +45 -0
- package/dist/{agent-feedback-loop-CcZL_sb1.mjs → agent-feedback-loop.mjs} +1 -1
- package/dist/agent-maintenance.d.mts +71 -0
- package/dist/{agent-maintenance-CuZ7iAKq.mjs → agent-maintenance.mjs} +1 -1
- package/dist/agent-provenance.d.mts +23 -0
- package/dist/agent-provenance.mjs +77 -0
- package/dist/agent-scope.mjs +321 -0
- package/dist/agent-skills-archive.mjs +86 -0
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-progressive-disclosure-PjPtTYL-.mjs → agent-skills-progressive-disclosure.mjs} +2 -2
- package/dist/{agent-skills-server-D5IuvwM7.d.mts → agent-skills-server.d.mts} +3 -3
- package/dist/{agent-skills-server-BC7md56k.mjs → agent-skills-server.mjs} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +1 -2
- package/dist/agent-surface-drift.mjs +236 -0
- package/dist/{golden-evaluations-CLUViycJ.mjs → agent-usefulness.mjs} +5 -290
- package/dist/{content-change-hydration-wqXIZHp6.d.mts → agent.d.mts} +10 -411
- package/dist/agent.mjs +2729 -0
- package/dist/{analytics-w3FDOksr.d.mts → analytics.d.mts} +2 -2
- package/dist/{analytics-p8Vhhu2P.mjs → analytics.mjs} +2 -2
- package/dist/{sitemap-server-BUdPBcGs.d.mts → api-reference.d.mts} +2 -6
- package/dist/api-reference.mjs +1481 -0
- package/dist/{audience-exposure-DBrFWULA.d.mts → audience-exposure.d.mts} +1 -1
- package/dist/audience-exposure.mjs +8 -0
- package/dist/audience.d.mts +44 -0
- package/dist/audience.mjs +1654 -0
- package/dist/authoring-mcp.d.mts +44 -0
- package/dist/{authoring-mcp-CiCUQe3o.mjs → authoring-mcp.mjs} +3 -3
- package/dist/browser.d.mts +6 -4
- package/dist/browser.mjs +6 -7
- package/dist/build.d.mts +8 -0
- package/dist/build.mjs +8 -0
- package/dist/changelog.d.mts +20 -0
- package/dist/changelog.mjs +39 -0
- package/dist/{agent-export-CA6IUQ7T.mjs → cli/agent-export.mjs} +19 -45
- package/dist/{agent-CYk2DxY7.mjs → cli/agent.mjs} +6 -35
- package/dist/{agents-BUiVmj8i.mjs → cli/agents.mjs} +5 -18
- package/dist/cli/api-doctor.mjs +206 -0
- package/dist/{authoring-C2ymvYWl.mjs → cli/authoring.mjs} +2 -8
- package/dist/{cloud-6eKrlmKd.mjs → cli/cloud.mjs} +3 -3
- package/dist/{codeblocks-CHpgAwY-.mjs → cli/codeblocks.mjs} +2 -2
- package/dist/cli/config.d.mts +11 -0
- package/dist/{config-BZnKAj_Y.mjs → cli/config.mjs} +1 -1
- package/dist/cli/dev-banner.mjs +58 -0
- package/dist/{dev-Bnn-NUNa.mjs → cli/dev.mjs} +3 -57
- package/dist/{doctor-Bfkrkzad.mjs → cli/doctor.mjs} +41 -226
- package/dist/{downgrade-CHMta85e.mjs → cli/downgrade.mjs} +2 -2
- package/dist/cli/errors.d.mts +4 -0
- package/dist/{errors-BtnVLhNF.mjs → cli/errors.mjs} +1 -1
- package/dist/{feedback-evals-DMilg9pY.mjs → cli/feedback-evals.mjs} +3 -36
- package/dist/{feedback-DL4T5oIO.mjs → cli/feedback.mjs} +1 -1
- package/dist/cli/git-dates.mjs +35 -0
- package/dist/cli/golden-evaluations.mjs +52 -0
- package/dist/cli/index.d.mts +2 -3
- package/dist/cli/index.mjs +38 -38
- package/dist/{init-K0LmXDZ5.mjs → cli/init.mjs} +3 -3
- package/dist/{mcp-iLCmnPJI.mjs → cli/mcp.mjs} +7 -19
- package/dist/{openapi-diff-HcpUNjA-.mjs → cli/openapi-diff.mjs} +2 -7
- package/dist/{openapi-sdk-BQKC6H-_.mjs → cli/openapi-sdk.mjs} +2 -7
- package/dist/{openapi-source-DK6ts_Bk.mjs → cli/openapi-source.mjs} +2 -2
- package/dist/{package-version-HJhYeq4M.mjs → cli/package-version.mjs} +2 -2
- package/dist/{propose-JmUv_BTt.mjs → cli/propose.mjs} +1 -1
- package/dist/{review-C6EmbV0l.mjs → cli/review.mjs} +16 -15
- package/dist/{robots-DteZB8vl.mjs → cli/robots.mjs} +3 -7
- package/dist/{search-Bhuv_YsL.mjs → cli/search.mjs} +7 -20
- package/dist/{sitemap-DW5LDKDa.mjs → cli/sitemap.mjs} +7 -42
- package/dist/{skills-BAPQLSCm.mjs → cli/skills.mjs} +5 -19
- package/dist/{templates-BuQ8YsGv.mjs → cli/templates.mjs} +1 -1
- package/dist/{upgrade-DlQMOFV1.mjs → cli/upgrade.mjs} +2 -2
- package/dist/{utils-C7KDrPpA.mjs → cli/utils.mjs} +1 -1
- package/dist/client/react.d.mts +2 -18
- package/dist/client/react.mjs +1 -157
- package/dist/{cloud-analytics-D14HplI7.mjs → cloud-analytics.mjs} +1 -1
- package/dist/{cloud-ask-ai-BrsTXQf6.d.mts → cloud-ask-ai.d.mts} +2 -2
- package/dist/{cloud-ask-ai-BqKhjpS5.mjs → cloud-ask-ai.mjs} +3 -3
- package/dist/code-blocks.d.mts +51 -0
- package/dist/{code-blocks-GYdvS3BH.mjs → code-blocks.mjs} +2 -2
- package/dist/code-group-mdx.d.mts +11 -0
- package/dist/code-group-mdx.mjs +57 -0
- package/dist/content-change-hydration.d.mts +87 -0
- package/dist/{openapi-mcp-BIOTLiA7.mjs → content-change-hydration.mjs} +5 -210
- package/dist/content-changes.d.mts +47 -0
- package/dist/content-changes.mjs +216 -0
- package/dist/create-theme.d.mts +48 -0
- package/dist/create-theme.mjs +57 -0
- package/dist/date.d.mts +5 -0
- package/dist/date.mjs +17 -0
- package/dist/define-docs.d.mts +9 -0
- package/dist/define-docs.mjs +46 -0
- package/dist/docs-cloud-client.d.mts +18 -0
- package/dist/docs-cloud-client.mjs +161 -0
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/docs-cloud-server.mjs +2 -3
- package/dist/heading-toc.d.mts +10 -0
- package/dist/heading-toc.mjs +23 -0
- package/dist/http-body.d.mts +14 -0
- package/dist/{http-body-DkAPk6D5.mjs → http-body.mjs} +1 -1
- package/dist/http-cache.d.mts +25 -0
- package/dist/http-cache.mjs +140 -0
- package/dist/http-link.mjs +81 -0
- package/dist/i18n.d.mts +18 -0
- package/dist/{i18n-B1gJ9EW0.mjs → i18n.mjs} +1 -1
- package/dist/index.d.mts +42 -674
- package/dist/index.mjs +40 -14
- package/dist/markdown-rendering.mjs +1 -1
- package/dist/markdown-section-cache.mjs +49 -0
- package/dist/markdown-sections.d.mts +47 -0
- package/dist/{markdown-sections-9Oxr33b-.mjs → markdown-sections.mjs} +29 -703
- package/dist/mcp-auth.d.mts +14 -0
- package/dist/mcp-auth.mjs +99 -0
- package/dist/mcp.d.mts +5 -3
- package/dist/mcp.mjs +21 -9
- package/dist/mdx.d.mts +6 -0
- package/dist/mdx.mjs +7 -0
- package/dist/metadata.d.mts +60 -0
- package/dist/{metadata-BOHn0Y5K.mjs → metadata.mjs} +2 -2
- package/dist/native-api-reference.mjs +968 -0
- package/dist/okf.d.mts +42 -0
- package/dist/okf.mjs +145 -0
- package/dist/openapi-contract.mjs +154 -0
- package/dist/{openapi-mcp-node-C4jUpZG6.mjs → openapi-mcp-node.mjs} +1 -1
- package/dist/openapi-mcp.d.mts +26 -0
- package/dist/openapi-mcp.mjs +132 -0
- package/dist/openapi-operations.d.mts +71 -0
- package/dist/{openapi-operations-DFpaqOqA.mjs → openapi-operations.mjs} +1 -1
- package/dist/openapi-overlays.mjs +221 -0
- package/dist/openapi-references.mjs +233 -0
- package/dist/pagination.d.mts +7 -0
- package/dist/pagination.mjs +100 -0
- package/dist/prompt-references.d.mts +12 -0
- package/dist/prompt-references.mjs +132 -0
- package/dist/prompt-utils.d.mts +36 -0
- package/dist/{prompt-utils-B5g-bv7o.mjs → prompt-utils.mjs} +1 -57
- package/dist/reading-time.d.mts +23 -0
- package/dist/reading-time.mjs +58 -0
- package/dist/related.d.mts +7 -0
- package/dist/related.mjs +50 -0
- package/dist/retrieval-digest.d.mts +16 -0
- package/dist/{retrieval-digest-CT-eIEcp.mjs → retrieval-digest.mjs} +1 -1
- package/dist/review.d.mts +69 -0
- package/dist/review.mjs +562 -0
- package/dist/robots.d.mts +54 -0
- package/dist/{robots-BYJAVeI6.mjs → robots.mjs} +5 -3
- package/dist/runtime.d.mts +3 -3
- package/dist/runtime.mjs +3 -9
- package/dist/search.d.mts +210 -0
- package/dist/search.mjs +3401 -0
- package/dist/server.d.mts +22 -198
- package/dist/server.mjs +21 -19
- package/dist/sidebar.d.mts +15 -0
- package/dist/sidebar.mjs +73 -0
- package/dist/sitemap-server.d.mts +7 -0
- package/dist/{sitemap-server-Lg3YhUx4.mjs → sitemap-server.mjs} +2 -2
- package/dist/{sitemap-Cl8vrixd.d.mts → sitemap.d.mts} +3 -3
- package/dist/sitemap.mjs +254 -0
- package/dist/{standards-discovery-BHPc7YIX.d.mts → standards-discovery.d.mts} +2 -2
- package/dist/{standards-discovery-sSEojU80.mjs → standards-discovery.mjs} +3 -139
- package/dist/telemetry-runtime.d.mts +42 -0
- package/dist/telemetry-runtime.mjs +238 -0
- package/dist/telemetry.d.mts +15 -0
- package/dist/telemetry.mjs +117 -0
- package/dist/{types-BJFeMXWZ.d.mts → types.d.mts} +3 -2
- package/dist/urls.d.mts +7 -0
- package/dist/urls.mjs +21 -0
- package/dist/utils.d.mts +8 -0
- package/dist/utils.mjs +22 -0
- package/package.json +21 -3
- package/dist/agent-DkAidqtV.mjs +0 -9026
- package/dist/api-reference-BYee4zMo.mjs +0 -3046
- package/dist/prompt-references-DMgbu_dz.mjs +0 -1082
- package/dist/retrieval-digest-AOx2-LbC.d.mts +0 -367
- package/dist/sidebar-CFHBj29f.mjs +0 -421
- package/dist/sidebar-CMPbVfGP.d.mts +0 -63
- /package/dist/{openapi-CfCzX_a1.mjs → cli/openapi.mjs} +0 -0
|
@@ -0,0 +1,1654 @@
|
|
|
1
|
+
import { resolveDocsAudienceExposure } from "./audience-exposure.mjs";
|
|
2
|
+
import { createProcessor } from "@mdx-js/mdx";
|
|
3
|
+
|
|
4
|
+
//#region src/audience.ts
|
|
5
|
+
const DOCS_AUDIENCE_TAG_NAMES = [
|
|
6
|
+
"Audience",
|
|
7
|
+
"Agent",
|
|
8
|
+
"Human"
|
|
9
|
+
];
|
|
10
|
+
const DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN = /<\/?(?:Audience|Agent|Human)(?=[\s/>])/;
|
|
11
|
+
function parseAudienceOnly(attributes) {
|
|
12
|
+
if (/\{\s*\.\.\./.test(attributes)) return void 0;
|
|
13
|
+
const value = attributes.match(/(?:^|\s)only\s*=\s*(?:"(human|agent)"|'(human|agent)'|\{\s*"(human|agent)"\s*\}|\{\s*'(human|agent)'\s*\})/)?.slice(1).find(Boolean);
|
|
14
|
+
return value === "human" || value === "agent" ? value : void 0;
|
|
15
|
+
}
|
|
16
|
+
function isEscapedAt(content, index) {
|
|
17
|
+
let backslashes = 0;
|
|
18
|
+
for (let cursor = index - 1; cursor >= 0 && content[cursor] === "\\"; cursor -= 1) backslashes += 1;
|
|
19
|
+
return backslashes % 2 === 1;
|
|
20
|
+
}
|
|
21
|
+
const JAVASCRIPT_REGEX_PREFIX_KEYWORDS = new Set([
|
|
22
|
+
"await",
|
|
23
|
+
"case",
|
|
24
|
+
"delete",
|
|
25
|
+
"do",
|
|
26
|
+
"else",
|
|
27
|
+
"each",
|
|
28
|
+
"if",
|
|
29
|
+
"in",
|
|
30
|
+
"instanceof",
|
|
31
|
+
"key",
|
|
32
|
+
"new",
|
|
33
|
+
"of",
|
|
34
|
+
"return",
|
|
35
|
+
"throw",
|
|
36
|
+
"catch",
|
|
37
|
+
"const",
|
|
38
|
+
"debug",
|
|
39
|
+
"html",
|
|
40
|
+
"render",
|
|
41
|
+
"snippet",
|
|
42
|
+
"then",
|
|
43
|
+
"typeof",
|
|
44
|
+
"void",
|
|
45
|
+
"yield"
|
|
46
|
+
]);
|
|
47
|
+
function canStartJavascriptRegex(content, cursor, boundary) {
|
|
48
|
+
let previous = cursor - 1;
|
|
49
|
+
while (previous > boundary && /\s/.test(content[previous] ?? "")) previous -= 1;
|
|
50
|
+
if (previous <= boundary || /[([{=,:;!?&|>]/.test(content[previous] ?? "")) return true;
|
|
51
|
+
const precedingWord = content.slice(boundary + 1, cursor).match(/([A-Za-z_$][\w$]*)\s*$/)?.[1];
|
|
52
|
+
return JAVASCRIPT_REGEX_PREFIX_KEYWORDS.has(precedingWord ?? "");
|
|
53
|
+
}
|
|
54
|
+
function readAudienceTagAt(content, index) {
|
|
55
|
+
let cursor = index + 1;
|
|
56
|
+
const closing = content[cursor] === "/";
|
|
57
|
+
if (closing) cursor += 1;
|
|
58
|
+
const name = DOCS_AUDIENCE_TAG_NAMES.find((candidate) => content.startsWith(candidate, cursor) && /[\s/>]/.test(content[cursor + candidate.length] ?? ""));
|
|
59
|
+
if (!name) return void 0;
|
|
60
|
+
cursor += name.length;
|
|
61
|
+
const attributesStart = cursor;
|
|
62
|
+
let braceDepth = 0;
|
|
63
|
+
let quote;
|
|
64
|
+
let blockComment = false;
|
|
65
|
+
let lineComment = false;
|
|
66
|
+
while (cursor < content.length) {
|
|
67
|
+
const character = content[cursor];
|
|
68
|
+
const next = content[cursor + 1];
|
|
69
|
+
if (lineComment) {
|
|
70
|
+
if (character === "\n") lineComment = false;
|
|
71
|
+
cursor += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (blockComment) {
|
|
75
|
+
if (character === "*" && next === "/") {
|
|
76
|
+
blockComment = false;
|
|
77
|
+
cursor += 2;
|
|
78
|
+
} else cursor += 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (quote) {
|
|
82
|
+
if (character === "\\") {
|
|
83
|
+
cursor += 2;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (character === quote) quote = void 0;
|
|
87
|
+
cursor += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (braceDepth > 0 && character === "/" && next === "*") {
|
|
91
|
+
blockComment = true;
|
|
92
|
+
cursor += 2;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (braceDepth > 0 && character === "/" && next === "/") {
|
|
96
|
+
lineComment = true;
|
|
97
|
+
cursor += 2;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (character === "\"" || character === "'" || character === "`") quote = character;
|
|
101
|
+
else if (character === "{") braceDepth += 1;
|
|
102
|
+
else if (character === "}" && braceDepth > 0) braceDepth -= 1;
|
|
103
|
+
else if (character === ">" && braceDepth === 0) {
|
|
104
|
+
let attributesEnd = cursor;
|
|
105
|
+
let slashIndex = cursor - 1;
|
|
106
|
+
while (slashIndex >= attributesStart && /\s/.test(content[slashIndex] ?? "")) slashIndex -= 1;
|
|
107
|
+
const selfClosing = content[slashIndex] === "/";
|
|
108
|
+
if (selfClosing) attributesEnd = slashIndex;
|
|
109
|
+
const attributes = content.slice(attributesStart, attributesEnd);
|
|
110
|
+
return {
|
|
111
|
+
index,
|
|
112
|
+
end: cursor + 1,
|
|
113
|
+
name,
|
|
114
|
+
closing,
|
|
115
|
+
selfClosing,
|
|
116
|
+
attributes,
|
|
117
|
+
only: name === "Agent" ? "agent" : name === "Human" ? "human" : parseAudienceOnly(attributes)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
cursor += 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function findAudienceTags(content, protectedRanges) {
|
|
124
|
+
const tags = [];
|
|
125
|
+
let cursor = 0;
|
|
126
|
+
while (cursor < content.length) {
|
|
127
|
+
const index = content.indexOf("<", cursor);
|
|
128
|
+
if (index === -1) break;
|
|
129
|
+
if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
130
|
+
cursor = index + 1;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const tag = readAudienceTagAt(content, index);
|
|
134
|
+
if (tag) {
|
|
135
|
+
tags.push(tag);
|
|
136
|
+
cursor = tag.end;
|
|
137
|
+
} else cursor = index + 1;
|
|
138
|
+
}
|
|
139
|
+
return tags;
|
|
140
|
+
}
|
|
141
|
+
let docsAudienceMdxProcessor;
|
|
142
|
+
let docsAudienceMarkdownProcessor;
|
|
143
|
+
function getDocsAudienceMdxProcessor() {
|
|
144
|
+
return docsAudienceMdxProcessor ??= createProcessor({ format: "mdx" });
|
|
145
|
+
}
|
|
146
|
+
function getDocsAudienceMarkdownProcessor() {
|
|
147
|
+
return docsAudienceMarkdownProcessor ??= createProcessor({ format: "md" });
|
|
148
|
+
}
|
|
149
|
+
function getOffset(position, edge) {
|
|
150
|
+
const value = position?.[edge]?.offset;
|
|
151
|
+
return typeof value === "number" ? value : void 0;
|
|
152
|
+
}
|
|
153
|
+
function maskRangesForMdxParser(content, ranges) {
|
|
154
|
+
if (ranges.length === 0) return content;
|
|
155
|
+
const characters = content.split("");
|
|
156
|
+
for (const range of ranges) for (let index = range.start; index < range.end; index += 1) if (characters[index] !== "\n" && characters[index] !== "\r") characters[index] = " ";
|
|
157
|
+
return characters.join("");
|
|
158
|
+
}
|
|
159
|
+
function findLeadingFrontmatterRange(content) {
|
|
160
|
+
const bomLength = content.startsWith("") ? 1 : 0;
|
|
161
|
+
const opening = content.slice(bomLength).match(/^(---|\+\+\+)[\t ]*(?:\r?\n|$)/);
|
|
162
|
+
const marker = opening?.[1];
|
|
163
|
+
if (!opening || !marker) return void 0;
|
|
164
|
+
let offset = bomLength + opening[0].length;
|
|
165
|
+
for (const line of content.slice(offset).split(/(?<=\n)/)) {
|
|
166
|
+
offset += line.length;
|
|
167
|
+
const value = line.replace(/\r?\n$/, "");
|
|
168
|
+
if (marker === "---" ? /^(?:---|\.\.\.)[\t ]*$/.test(value) : /^\+\+\+[\t ]*$/.test(value)) return {
|
|
169
|
+
start: 0,
|
|
170
|
+
end: offset
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function findHtmlLiteralRanges(content, excludedRanges = []) {
|
|
175
|
+
const ranges = [];
|
|
176
|
+
const rawPattern = /<(script|style)(?=[\s/>])/g;
|
|
177
|
+
let cursor = 0;
|
|
178
|
+
while (cursor < content.length) {
|
|
179
|
+
rawPattern.lastIndex = cursor;
|
|
180
|
+
const rawMatch = rawPattern.exec(content);
|
|
181
|
+
const commentStart = content.indexOf("<!--", cursor);
|
|
182
|
+
const rawStart = rawMatch?.index ?? -1;
|
|
183
|
+
const useComment = commentStart !== -1 && (rawStart === -1 || commentStart < rawStart);
|
|
184
|
+
const start = useComment ? commentStart : rawStart;
|
|
185
|
+
if (start === -1) break;
|
|
186
|
+
if (isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
|
|
187
|
+
cursor = start + 1;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (useComment) {
|
|
191
|
+
const closing = content.indexOf("-->", start + 4);
|
|
192
|
+
const end = closing === -1 ? content.length : closing + 3;
|
|
193
|
+
ranges.push({
|
|
194
|
+
start,
|
|
195
|
+
end
|
|
196
|
+
});
|
|
197
|
+
cursor = end;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const name = rawMatch?.[1];
|
|
201
|
+
if (!name) {
|
|
202
|
+
cursor = start + 1;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const opening = readGenericMdxJsxTag(content, start);
|
|
206
|
+
if (!opening) {
|
|
207
|
+
cursor = start + 1;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (opening.selfClosing) {
|
|
211
|
+
cursor = opening.end;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const closingPattern = new RegExp(`</${name}\\s*>`, "g");
|
|
215
|
+
closingPattern.lastIndex = opening.end;
|
|
216
|
+
if (!closingPattern.exec(content)) {
|
|
217
|
+
ranges.push({
|
|
218
|
+
start,
|
|
219
|
+
end: content.length
|
|
220
|
+
});
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
ranges.push({
|
|
224
|
+
start,
|
|
225
|
+
end: closingPattern.lastIndex
|
|
226
|
+
});
|
|
227
|
+
cursor = closingPattern.lastIndex;
|
|
228
|
+
}
|
|
229
|
+
return ranges;
|
|
230
|
+
}
|
|
231
|
+
function prepareMdxParserSource(content) {
|
|
232
|
+
const baseExcludedRanges = findDelimiterExclusionRanges(content);
|
|
233
|
+
const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
|
|
234
|
+
const ranges = [...findHtmlLiteralRanges(content, mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives])), ...svelteDirectives];
|
|
235
|
+
const frontmatter = findLeadingFrontmatterRange(content);
|
|
236
|
+
if (frontmatter) ranges.push(frontmatter);
|
|
237
|
+
return maskRangesForMdxParser(content, mergeProtectedRanges(ranges));
|
|
238
|
+
}
|
|
239
|
+
function getExpressionLiteralString(value) {
|
|
240
|
+
if (!value || typeof value !== "object") return void 0;
|
|
241
|
+
const expression = value.data?.estree?.body?.[0]?.expression;
|
|
242
|
+
return expression?.type === "Literal" && typeof expression.value === "string" ? expression.value : void 0;
|
|
243
|
+
}
|
|
244
|
+
function getMdxAudienceAttributeInfo(attributes) {
|
|
245
|
+
const hasSpreadAttribute = attributes.some((attribute) => attribute.type === "mdxJsxExpressionAttribute");
|
|
246
|
+
const onlyAttribute = [...attributes].reverse().find((attribute) => attribute.type === "mdxJsxAttribute" && attribute.name === "only");
|
|
247
|
+
if (hasSpreadAttribute) return {
|
|
248
|
+
hasOnlyAttribute: Boolean(onlyAttribute),
|
|
249
|
+
hasSpreadAttribute,
|
|
250
|
+
onlyKind: "dynamic"
|
|
251
|
+
};
|
|
252
|
+
if (!onlyAttribute) return {
|
|
253
|
+
hasOnlyAttribute: false,
|
|
254
|
+
hasSpreadAttribute: false,
|
|
255
|
+
onlyKind: "missing"
|
|
256
|
+
};
|
|
257
|
+
const value = typeof onlyAttribute.value === "string" ? onlyAttribute.value : getExpressionLiteralString(onlyAttribute.value);
|
|
258
|
+
if (value === "human" || value === "agent") return {
|
|
259
|
+
only: value,
|
|
260
|
+
hasOnlyAttribute: true,
|
|
261
|
+
hasSpreadAttribute: false,
|
|
262
|
+
onlyKind: "static"
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
hasOnlyAttribute: true,
|
|
266
|
+
hasSpreadAttribute: false,
|
|
267
|
+
onlyKind: typeof onlyAttribute.value === "object" ? "dynamic" : "invalid"
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function getEstreeAudienceAttributeInfo(attributes) {
|
|
271
|
+
const records = attributes.filter((attribute) => Boolean(attribute && typeof attribute === "object"));
|
|
272
|
+
const hasSpreadAttribute = records.some((attribute) => attribute.type === "JSXSpreadAttribute");
|
|
273
|
+
const onlyAttribute = [...records].reverse().find((attribute) => {
|
|
274
|
+
const name = attribute.name;
|
|
275
|
+
return attribute.type === "JSXAttribute" && name?.type === "JSXIdentifier" && name.name === "only";
|
|
276
|
+
});
|
|
277
|
+
if (hasSpreadAttribute) return {
|
|
278
|
+
hasOnlyAttribute: Boolean(onlyAttribute),
|
|
279
|
+
hasSpreadAttribute,
|
|
280
|
+
onlyKind: "dynamic"
|
|
281
|
+
};
|
|
282
|
+
if (!onlyAttribute) return {
|
|
283
|
+
hasOnlyAttribute: false,
|
|
284
|
+
hasSpreadAttribute: false,
|
|
285
|
+
onlyKind: "missing"
|
|
286
|
+
};
|
|
287
|
+
const attributeValue = onlyAttribute.value;
|
|
288
|
+
const value = attributeValue?.type === "Literal" ? attributeValue.value : attributeValue?.type === "JSXExpressionContainer" && attributeValue.expression?.type === "Literal" ? attributeValue.expression.value : void 0;
|
|
289
|
+
if (value === "human" || value === "agent") return {
|
|
290
|
+
only: value,
|
|
291
|
+
hasOnlyAttribute: true,
|
|
292
|
+
hasSpreadAttribute: false,
|
|
293
|
+
onlyKind: "static"
|
|
294
|
+
};
|
|
295
|
+
return {
|
|
296
|
+
hasOnlyAttribute: true,
|
|
297
|
+
hasSpreadAttribute: false,
|
|
298
|
+
onlyKind: attributeValue?.type === "JSXExpressionContainer" ? "dynamic" : "invalid"
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function getOpeningTagEnd(content, start, name, attributes) {
|
|
302
|
+
const searchStart = Math.max(start + name.length + 1, ...attributes.map((attribute) => getOffset(attribute.position, "end") ?? 0));
|
|
303
|
+
const closingBracket = content.indexOf(">", searchStart);
|
|
304
|
+
return closingBracket === -1 ? void 0 : closingBracket + 1;
|
|
305
|
+
}
|
|
306
|
+
function addMdxAudienceElementTags(content, node, tags) {
|
|
307
|
+
const name = node.name;
|
|
308
|
+
const start = getOffset(node.position, "start");
|
|
309
|
+
const nodeEnd = getOffset(node.position, "end");
|
|
310
|
+
if (start === void 0 || nodeEnd === void 0) return;
|
|
311
|
+
const attributes = node.attributes ?? [];
|
|
312
|
+
const openingEnd = getOpeningTagEnd(content, start, name, attributes);
|
|
313
|
+
if (openingEnd === void 0) return;
|
|
314
|
+
const closingStart = content.lastIndexOf(`</${name}`, nodeEnd);
|
|
315
|
+
const hasClosingTag = closingStart >= openingEnd;
|
|
316
|
+
const attributeInfo = getMdxAudienceAttributeInfo(attributes);
|
|
317
|
+
const rawAttributes = content.slice(start + name.length + 1, openingEnd - 1);
|
|
318
|
+
tags.push({
|
|
319
|
+
index: start,
|
|
320
|
+
end: openingEnd,
|
|
321
|
+
name,
|
|
322
|
+
closing: false,
|
|
323
|
+
selfClosing: !hasClosingTag,
|
|
324
|
+
attributes: rawAttributes,
|
|
325
|
+
only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
|
|
326
|
+
hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
|
|
327
|
+
hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
|
|
328
|
+
onlyKind: attributeInfo.onlyKind
|
|
329
|
+
});
|
|
330
|
+
if (hasClosingTag) tags.push({
|
|
331
|
+
index: closingStart,
|
|
332
|
+
end: nodeEnd,
|
|
333
|
+
name,
|
|
334
|
+
closing: true,
|
|
335
|
+
selfClosing: false,
|
|
336
|
+
attributes: ""
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
function getEstreeJsxIdentifierName(value) {
|
|
340
|
+
if (!value || typeof value !== "object") return void 0;
|
|
341
|
+
const name = value;
|
|
342
|
+
return name.type === "JSXIdentifier" && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name.name) ? name.name : void 0;
|
|
343
|
+
}
|
|
344
|
+
function addEstreeAudienceElementTags(content, node, tags, jsxChild) {
|
|
345
|
+
const opening = node.openingElement;
|
|
346
|
+
if (!opening) return;
|
|
347
|
+
const name = getEstreeJsxIdentifierName(opening.name);
|
|
348
|
+
const start = typeof opening.start === "number" ? opening.start : void 0;
|
|
349
|
+
const openingEnd = typeof opening.end === "number" ? opening.end : void 0;
|
|
350
|
+
const nodeEnd = typeof node.end === "number" ? node.end : void 0;
|
|
351
|
+
if (!name || start === void 0 || openingEnd === void 0 || nodeEnd === void 0) return;
|
|
352
|
+
const attributeInfo = getEstreeAudienceAttributeInfo(Array.isArray(opening.attributes) ? opening.attributes : []);
|
|
353
|
+
const closing = node.closingElement;
|
|
354
|
+
const closingStart = closing && typeof closing.start === "number" ? closing.start : void 0;
|
|
355
|
+
const closingEnd = closing && typeof closing.end === "number" ? closing.end : void 0;
|
|
356
|
+
tags.push({
|
|
357
|
+
index: start,
|
|
358
|
+
end: openingEnd,
|
|
359
|
+
name,
|
|
360
|
+
closing: false,
|
|
361
|
+
selfClosing: closingStart === void 0,
|
|
362
|
+
attributes: content.slice(start + name.length + 1, openingEnd - 1),
|
|
363
|
+
only: name === "Agent" ? "agent" : name === "Human" ? "human" : attributeInfo.only,
|
|
364
|
+
expression: true,
|
|
365
|
+
jsxChild,
|
|
366
|
+
hasOnlyAttribute: attributeInfo.hasOnlyAttribute,
|
|
367
|
+
hasSpreadAttribute: attributeInfo.hasSpreadAttribute,
|
|
368
|
+
onlyKind: attributeInfo.onlyKind
|
|
369
|
+
});
|
|
370
|
+
if (closingStart !== void 0 && closingEnd !== void 0) tags.push({
|
|
371
|
+
index: closingStart,
|
|
372
|
+
end: closingEnd,
|
|
373
|
+
name,
|
|
374
|
+
closing: true,
|
|
375
|
+
selfClosing: false,
|
|
376
|
+
attributes: "",
|
|
377
|
+
expression: true,
|
|
378
|
+
jsxChild
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function collectEstreeAudienceTags(content, value, tags, seen = /* @__PURE__ */ new WeakSet(), parent, parentKey) {
|
|
382
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
383
|
+
seen.add(value);
|
|
384
|
+
const record = value;
|
|
385
|
+
if (record.type === "JSXElement") {
|
|
386
|
+
const opening = record.openingElement;
|
|
387
|
+
if (getEstreeJsxIdentifierName(opening?.name)) {
|
|
388
|
+
addEstreeAudienceElementTags(content, record, tags, parentKey === "children" && (parent?.type === "JSXElement" || parent?.type === "JSXFragment"));
|
|
389
|
+
for (const child of Array.isArray(record.children) ? record.children : []) collectEstreeAudienceTags(content, child, tags, seen, record, "children");
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
for (const [key, child] of Object.entries(record)) {
|
|
394
|
+
if (key === "loc" || key === "range" || key === "comments") continue;
|
|
395
|
+
if (Array.isArray(child)) for (const item of child) collectEstreeAudienceTags(content, item, tags, seen, record, key);
|
|
396
|
+
else collectEstreeAudienceTags(content, child, tags, seen, record, key);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function collectMdxAudienceTags(content, node, tags) {
|
|
400
|
+
const isMdxJsxElement = node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
|
|
401
|
+
if (isMdxJsxElement && (node.name === "script" || node.name === "style")) return;
|
|
402
|
+
const isAudienceElement = Boolean(isMdxJsxElement && node.name && DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === node.name));
|
|
403
|
+
if (isAudienceElement) addMdxAudienceElementTags(content, node, tags);
|
|
404
|
+
if (node.type !== "mdxjsEsm") {
|
|
405
|
+
if (node.type === "mdxFlowExpression" || node.type === "mdxTextExpression") collectEstreeAudienceTags(content, node.data?.estree, tags);
|
|
406
|
+
if (isMdxJsxElement && !isAudienceElement) for (const attribute of node.attributes ?? []) {
|
|
407
|
+
collectEstreeAudienceTags(content, attribute.data?.estree, tags);
|
|
408
|
+
if (attribute.value && typeof attribute.value === "object") {
|
|
409
|
+
const value = attribute.value;
|
|
410
|
+
collectEstreeAudienceTags(content, value.data?.estree, tags);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
for (const child of node.children ?? []) collectMdxAudienceTags(content, child, tags);
|
|
415
|
+
}
|
|
416
|
+
function findMdxAstAudienceTags(content) {
|
|
417
|
+
try {
|
|
418
|
+
const tree = getDocsAudienceMdxProcessor().parse(prepareMdxParserSource(content));
|
|
419
|
+
const tags = [];
|
|
420
|
+
collectMdxAudienceTags(content, tree, tags);
|
|
421
|
+
return tags.sort((left, right) => left.index - right.index || left.end - right.end);
|
|
422
|
+
} catch {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/** Locate effective audience tags while excluding Markdown/MDX literal contexts. */
|
|
427
|
+
function findDocsAudienceMdxTags(content) {
|
|
428
|
+
if (!DOCS_AUDIENCE_TAG_CANDIDATE_PATTERN.test(content)) return [];
|
|
429
|
+
return findMdxAstAudienceTags(content) ?? findAudienceTags(content, findProtectedRanges(content));
|
|
430
|
+
}
|
|
431
|
+
function isAudienceVisible(scopes, audience) {
|
|
432
|
+
return scopes.every((scope) => resolveDocsAudienceExposure(scope.only, audience));
|
|
433
|
+
}
|
|
434
|
+
function mergeProtectedRanges(ranges) {
|
|
435
|
+
const sorted = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
436
|
+
const merged = [];
|
|
437
|
+
for (const range of sorted) {
|
|
438
|
+
const previous = merged.at(-1);
|
|
439
|
+
if (!previous || range.start > previous.end) {
|
|
440
|
+
merged.push({ ...range });
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
previous.end = Math.max(previous.end, range.end);
|
|
444
|
+
}
|
|
445
|
+
return merged;
|
|
446
|
+
}
|
|
447
|
+
function findMarkdownLiteralRanges(content) {
|
|
448
|
+
try {
|
|
449
|
+
const tree = getDocsAudienceMarkdownProcessor().parse(content);
|
|
450
|
+
const ranges = [];
|
|
451
|
+
const visit = (node) => {
|
|
452
|
+
const start = getOffset(node.position, "start");
|
|
453
|
+
const end = getOffset(node.position, "end");
|
|
454
|
+
if (start !== void 0 && end !== void 0) {
|
|
455
|
+
if (node.type === "code" || node.type === "inlineCode" || node.type === "definition") ranges.push({
|
|
456
|
+
start,
|
|
457
|
+
end
|
|
458
|
+
});
|
|
459
|
+
else if (node.type === "link" || node.type === "image") {
|
|
460
|
+
const contentEnd = Math.max(start, ...(node.children ?? []).map((child) => getOffset(child.position, "end") ?? start));
|
|
461
|
+
ranges.push({
|
|
462
|
+
start: contentEnd,
|
|
463
|
+
end
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
for (const child of node.children ?? []) visit(child);
|
|
468
|
+
};
|
|
469
|
+
visit(tree);
|
|
470
|
+
return ranges;
|
|
471
|
+
} catch {
|
|
472
|
+
return [];
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function findMarkdownLinkDestinationRanges(content, protectedRanges) {
|
|
476
|
+
const ranges = [];
|
|
477
|
+
let cursor = 0;
|
|
478
|
+
while (cursor < content.length) {
|
|
479
|
+
const start = content.indexOf("](", cursor);
|
|
480
|
+
if (start === -1) break;
|
|
481
|
+
if (isEscapedAt(content, start) || isInsideRange(start, protectedRanges)) {
|
|
482
|
+
cursor = start + 1;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
let end = start + 2;
|
|
486
|
+
let parenthesisDepth = 1;
|
|
487
|
+
let angleDestination = false;
|
|
488
|
+
let quote;
|
|
489
|
+
while (end < content.length && parenthesisDepth > 0) {
|
|
490
|
+
const character = content[end];
|
|
491
|
+
if (character === "\\") {
|
|
492
|
+
end += 2;
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (quote) {
|
|
496
|
+
if (character === quote) quote = void 0;
|
|
497
|
+
end += 1;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (character === "\"" || character === "'") quote = character;
|
|
501
|
+
else if (character === "<" && parenthesisDepth === 1) {
|
|
502
|
+
const closingAngle = content.indexOf(">", end + 1);
|
|
503
|
+
const closingParenthesis = content.indexOf(")", end + 1);
|
|
504
|
+
angleDestination = closingAngle !== -1 && closingAngle < closingParenthesis;
|
|
505
|
+
} else if (character === ">" && angleDestination) angleDestination = false;
|
|
506
|
+
else if (!angleDestination && character === "(") parenthesisDepth += 1;
|
|
507
|
+
else if (!angleDestination && character === ")") parenthesisDepth -= 1;
|
|
508
|
+
end += 1;
|
|
509
|
+
}
|
|
510
|
+
if (parenthesisDepth === 0) ranges.push({
|
|
511
|
+
start: start + 1,
|
|
512
|
+
end
|
|
513
|
+
});
|
|
514
|
+
cursor = Math.max(start + 1, end);
|
|
515
|
+
}
|
|
516
|
+
return ranges;
|
|
517
|
+
}
|
|
518
|
+
function findFenceRanges(content) {
|
|
519
|
+
const ranges = [];
|
|
520
|
+
let fence;
|
|
521
|
+
let offset = 0;
|
|
522
|
+
const stripBlockquoteContainers = (line) => {
|
|
523
|
+
let value = line;
|
|
524
|
+
while (/^ {0,3}>[\t ]?/.test(value)) value = value.replace(/^ {0,3}>[\t ]?/, "");
|
|
525
|
+
return value;
|
|
526
|
+
};
|
|
527
|
+
const stripOpeningListContainers = (line) => {
|
|
528
|
+
let value = line;
|
|
529
|
+
while (/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/.test(value)) value = value.replace(/^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/, "");
|
|
530
|
+
return value;
|
|
531
|
+
};
|
|
532
|
+
for (const line of content.split(/(?<=\n)/)) {
|
|
533
|
+
const containerRelativeLine = stripBlockquoteContainers(line.replace(/\r?\n$/, ""));
|
|
534
|
+
const match = (fence ? containerRelativeLine : stripOpeningListContainers(containerRelativeLine)).match(/^[\t ]*(`{3,}|~{3,})(.*)$/);
|
|
535
|
+
if (!fence && match?.[1]) fence = {
|
|
536
|
+
marker: match[1][0],
|
|
537
|
+
length: match[1].length,
|
|
538
|
+
start: offset
|
|
539
|
+
};
|
|
540
|
+
else if (fence && match?.[1]?.[0] === fence.marker && match[1].length >= fence.length && /^[\t ]*$/.test(match[2] ?? "")) {
|
|
541
|
+
ranges.push({
|
|
542
|
+
start: fence.start,
|
|
543
|
+
end: offset + line.length
|
|
544
|
+
});
|
|
545
|
+
fence = void 0;
|
|
546
|
+
}
|
|
547
|
+
offset += line.length;
|
|
548
|
+
}
|
|
549
|
+
if (fence) ranges.push({
|
|
550
|
+
start: fence.start,
|
|
551
|
+
end: content.length
|
|
552
|
+
});
|
|
553
|
+
return ranges;
|
|
554
|
+
}
|
|
555
|
+
function findSvelteDirectiveRanges(content, excludedRanges) {
|
|
556
|
+
const ranges = [];
|
|
557
|
+
let index = 0;
|
|
558
|
+
while (index < content.length) {
|
|
559
|
+
const start = content.indexOf("{", index);
|
|
560
|
+
if (start === -1) break;
|
|
561
|
+
const sigil = content[start + 1];
|
|
562
|
+
if (!/[#/:@]/.test(sigil ?? "") || !/[A-Za-z]/.test(content[start + 2] ?? "") || isEscapedAt(content, start) || isInsideRange(start, excludedRanges)) {
|
|
563
|
+
index = start + 1;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
let cursor = start + 2;
|
|
567
|
+
let braceDepth = 1;
|
|
568
|
+
let quote;
|
|
569
|
+
let blockComment = false;
|
|
570
|
+
let lineComment = false;
|
|
571
|
+
let regex = false;
|
|
572
|
+
let regexCharacterClass = false;
|
|
573
|
+
while (cursor < content.length && braceDepth > 0) {
|
|
574
|
+
const character = content[cursor];
|
|
575
|
+
const next = content[cursor + 1];
|
|
576
|
+
if (lineComment) {
|
|
577
|
+
if (character === "\n") lineComment = false;
|
|
578
|
+
cursor += 1;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (blockComment) {
|
|
582
|
+
if (character === "*" && next === "/") {
|
|
583
|
+
blockComment = false;
|
|
584
|
+
cursor += 2;
|
|
585
|
+
} else cursor += 1;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
if (quote) {
|
|
589
|
+
if (character === "\\") {
|
|
590
|
+
cursor += 2;
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (character === quote) quote = void 0;
|
|
594
|
+
cursor += 1;
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
if (regex) {
|
|
598
|
+
if (character === "\\") {
|
|
599
|
+
cursor += 2;
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (character === "[") regexCharacterClass = true;
|
|
603
|
+
if (character === "]") regexCharacterClass = false;
|
|
604
|
+
if (character === "/" && !regexCharacterClass) regex = false;
|
|
605
|
+
cursor += 1;
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
if (character === "/" && next === "*") {
|
|
609
|
+
blockComment = true;
|
|
610
|
+
cursor += 2;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (character === "/" && next === "/") {
|
|
614
|
+
lineComment = true;
|
|
615
|
+
cursor += 2;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
619
|
+
quote = character;
|
|
620
|
+
cursor += 1;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (character === "/") {
|
|
624
|
+
if (canStartJavascriptRegex(content, cursor, start + 1)) {
|
|
625
|
+
regex = true;
|
|
626
|
+
cursor += 1;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (character === "{") braceDepth += 1;
|
|
631
|
+
if (character === "}") braceDepth -= 1;
|
|
632
|
+
cursor += 1;
|
|
633
|
+
}
|
|
634
|
+
if (braceDepth === 0) ranges.push({
|
|
635
|
+
start,
|
|
636
|
+
end: cursor
|
|
637
|
+
});
|
|
638
|
+
index = Math.max(start + 1, cursor);
|
|
639
|
+
}
|
|
640
|
+
return ranges;
|
|
641
|
+
}
|
|
642
|
+
function scanMdxModuleLine(line, state) {
|
|
643
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
644
|
+
const character = line[index];
|
|
645
|
+
const next = line[index + 1];
|
|
646
|
+
if (state.blockComment) {
|
|
647
|
+
if (character === "*" && next === "/") {
|
|
648
|
+
state.blockComment = false;
|
|
649
|
+
index += 1;
|
|
650
|
+
}
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
if (state.quote) {
|
|
654
|
+
if (character === "\\") {
|
|
655
|
+
index += 1;
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (character === state.quote) state.quote = void 0;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
if (character === "/" && next === "/") break;
|
|
662
|
+
if (character === "/" && next === "*") {
|
|
663
|
+
state.blockComment = true;
|
|
664
|
+
index += 1;
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
668
|
+
state.quote = character;
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (state.jsxTag) {
|
|
672
|
+
if (character === "{") state.braceDepth += 1;
|
|
673
|
+
else if (character === "}" && state.braceDepth > 0) state.braceDepth -= 1;
|
|
674
|
+
else if (character === ">" && state.braceDepth === 0) {
|
|
675
|
+
let previous = index - 1;
|
|
676
|
+
while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
|
|
677
|
+
const selfClosing = line[previous] === "/";
|
|
678
|
+
let following = index + 1;
|
|
679
|
+
while (following < line.length && /[\t ]/.test(line[following] ?? "")) following += 1;
|
|
680
|
+
const genericTypeParameters = !state.jsxTag.closing && line[following] === "(";
|
|
681
|
+
if (state.jsxTag.closing) state.jsxDepth = Math.max(0, state.jsxDepth - 1);
|
|
682
|
+
else if (!selfClosing && !genericTypeParameters) state.jsxDepth += 1;
|
|
683
|
+
state.jsxTag = void 0;
|
|
684
|
+
}
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (character === "<") {
|
|
688
|
+
let previous = index - 1;
|
|
689
|
+
while (previous >= 0 && /[\t ]/.test(line[previous] ?? "")) previous -= 1;
|
|
690
|
+
const previousCharacter = line[previous];
|
|
691
|
+
const atExpressionStart = previousCharacter === void 0 || /[=([{,:?!;]/.test(previousCharacter);
|
|
692
|
+
const openingElement = (state.jsxDepth > 0 || atExpressionStart) && /[A-Za-z]/.test(next ?? "");
|
|
693
|
+
const closingElement = state.jsxDepth > 0 && next === "/" && /[A-Za-z]/.test(line[index + 2] ?? "");
|
|
694
|
+
const openingFragment = atExpressionStart && next === ">";
|
|
695
|
+
const closingFragment = state.jsxDepth > 0 && next === "/" && line[index + 2] === ">";
|
|
696
|
+
if (openingFragment) {
|
|
697
|
+
state.jsxDepth += 1;
|
|
698
|
+
index += 1;
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
if (closingFragment) {
|
|
702
|
+
state.jsxDepth = Math.max(0, state.jsxDepth - 1);
|
|
703
|
+
index += 2;
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
if (openingElement || closingElement) {
|
|
707
|
+
state.jsxTag = { closing: closingElement };
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (character === "{") {
|
|
712
|
+
state.braceDepth += 1;
|
|
713
|
+
state.sawBlock = true;
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
if (character === "}") state.braceDepth = Math.max(0, state.braceDepth - 1);
|
|
717
|
+
else if (character === "[") state.bracketDepth += 1;
|
|
718
|
+
else if (character === "]") state.bracketDepth = Math.max(0, state.bracketDepth - 1);
|
|
719
|
+
else if (character === "(") state.parenthesisDepth += 1;
|
|
720
|
+
else if (character === ")") state.parenthesisDepth = Math.max(0, state.parenthesisDepth - 1);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
function shouldContinueMdxModule(statement, state, nextSignificantLine) {
|
|
724
|
+
if (state.quote || state.blockComment || state.braceDepth > 0 || state.bracketDepth > 0 || state.parenthesisDepth > 0 || state.jsxTag || state.jsxDepth > 0) return true;
|
|
725
|
+
const trimmed = statement.trimEnd();
|
|
726
|
+
if (/^\s*import\b(?!\s*[.(])/.test(statement)) {
|
|
727
|
+
if (!(/^\s*import\s*(?:type\s+)?["'`]/.test(statement) || /\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed)) && !/;\s*$/.test(trimmed)) return true;
|
|
728
|
+
}
|
|
729
|
+
const isExportList = /^\s*export\s+(?:type\s+)?\{/.test(statement);
|
|
730
|
+
const isExportAll = /^\s*export\s+\*/.test(statement);
|
|
731
|
+
if ((isExportList || isExportAll) && !/\bfrom\s*["'`][\s\S]*["'`]\s*;?\s*$/.test(trimmed) && (isExportAll || /^\s*from\b/.test(nextSignificantLine ?? ""))) return true;
|
|
732
|
+
if (/=>\s*$/.test(trimmed) || /[=([{,:.?+\-*/%&|^!]$/.test(trimmed)) return true;
|
|
733
|
+
if (/\b(?:as|default|extends|from|implements|satisfies)$/.test(trimmed)) return true;
|
|
734
|
+
return /^\s*export\s+(?:default\s+)?(?:(?:async\s+)?function|class|enum|interface|module|namespace)\b/.test(statement) && !state.sawBlock;
|
|
735
|
+
}
|
|
736
|
+
function isInsideRange(index, ranges) {
|
|
737
|
+
return ranges.some((range) => index >= range.start && index < range.end);
|
|
738
|
+
}
|
|
739
|
+
function findMdxModuleRanges(content, protectedRanges) {
|
|
740
|
+
const ranges = [];
|
|
741
|
+
const lines = content.split(/(?<=\n)/);
|
|
742
|
+
let offset = 0;
|
|
743
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
744
|
+
const line = lines[lineIndex] ?? "";
|
|
745
|
+
const firstNonWhitespace = line.search(/\S/);
|
|
746
|
+
if (/^\s*(?:import|export)\b/.test(line) && !isInsideRange(offset + Math.max(0, firstNonWhitespace), protectedRanges)) {
|
|
747
|
+
const start = offset;
|
|
748
|
+
const state = {
|
|
749
|
+
braceDepth: 0,
|
|
750
|
+
bracketDepth: 0,
|
|
751
|
+
parenthesisDepth: 0,
|
|
752
|
+
blockComment: false,
|
|
753
|
+
sawBlock: false,
|
|
754
|
+
jsxDepth: 0
|
|
755
|
+
};
|
|
756
|
+
let statement = "";
|
|
757
|
+
while (lineIndex < lines.length) {
|
|
758
|
+
const moduleLine = lines[lineIndex] ?? "";
|
|
759
|
+
statement += moduleLine;
|
|
760
|
+
scanMdxModuleLine(moduleLine, state);
|
|
761
|
+
offset += moduleLine.length;
|
|
762
|
+
const nextSignificantLine = lines.slice(lineIndex + 1).find((candidate) => candidate.trim().length > 0);
|
|
763
|
+
if (!shouldContinueMdxModule(statement, state, nextSignificantLine)) break;
|
|
764
|
+
lineIndex += 1;
|
|
765
|
+
}
|
|
766
|
+
ranges.push({
|
|
767
|
+
start,
|
|
768
|
+
end: offset
|
|
769
|
+
});
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
offset += line.length;
|
|
773
|
+
}
|
|
774
|
+
return ranges;
|
|
775
|
+
}
|
|
776
|
+
function findInlineCodeRanges(content, protectedRanges) {
|
|
777
|
+
const ranges = [];
|
|
778
|
+
let index = 0;
|
|
779
|
+
while (index < content.length) {
|
|
780
|
+
if (content[index] !== "`" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
781
|
+
index += 1;
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
let markerLength = 1;
|
|
785
|
+
while (content[index + markerLength] === "`") markerLength += 1;
|
|
786
|
+
let closingIndex = index + markerLength;
|
|
787
|
+
while (closingIndex < content.length) {
|
|
788
|
+
closingIndex = content.indexOf("`", closingIndex);
|
|
789
|
+
if (closingIndex === -1) break;
|
|
790
|
+
if (isInsideRange(closingIndex, protectedRanges)) {
|
|
791
|
+
closingIndex += 1;
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
let closingLength = 1;
|
|
795
|
+
while (content[closingIndex + closingLength] === "`") closingLength += 1;
|
|
796
|
+
if (closingLength === markerLength) break;
|
|
797
|
+
closingIndex += closingLength;
|
|
798
|
+
}
|
|
799
|
+
if (closingIndex === -1) {
|
|
800
|
+
index += markerLength;
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
ranges.push({
|
|
804
|
+
start: index,
|
|
805
|
+
end: closingIndex + markerLength
|
|
806
|
+
});
|
|
807
|
+
index = closingIndex + markerLength;
|
|
808
|
+
}
|
|
809
|
+
return ranges;
|
|
810
|
+
}
|
|
811
|
+
function findMdxExpressionLiteralRanges(content, protectedRanges) {
|
|
812
|
+
const ranges = [];
|
|
813
|
+
let index = 0;
|
|
814
|
+
while (index < content.length) {
|
|
815
|
+
if (content[index] !== "{" || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
816
|
+
index += 1;
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
let cursor = index + 1;
|
|
820
|
+
let depth = 1;
|
|
821
|
+
while (cursor < content.length && depth > 0) {
|
|
822
|
+
if (isInsideRange(cursor, protectedRanges)) {
|
|
823
|
+
cursor += 1;
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
const character = content[cursor];
|
|
827
|
+
const next = content[cursor + 1];
|
|
828
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
829
|
+
const quote = character;
|
|
830
|
+
const start = cursor;
|
|
831
|
+
cursor += 1;
|
|
832
|
+
while (cursor < content.length) {
|
|
833
|
+
if (content[cursor] === "\\") {
|
|
834
|
+
cursor += 2;
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
if (content[cursor] === quote) {
|
|
838
|
+
cursor += 1;
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
cursor += 1;
|
|
842
|
+
}
|
|
843
|
+
ranges.push({
|
|
844
|
+
start,
|
|
845
|
+
end: cursor
|
|
846
|
+
});
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
if (character === "/" && next === "*") {
|
|
850
|
+
const start = cursor;
|
|
851
|
+
const end = content.indexOf("*/", cursor + 2);
|
|
852
|
+
cursor = end === -1 ? content.length : end + 2;
|
|
853
|
+
ranges.push({
|
|
854
|
+
start,
|
|
855
|
+
end: cursor
|
|
856
|
+
});
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
if (character === "/" && next === "/") {
|
|
860
|
+
const start = cursor;
|
|
861
|
+
const newline = content.indexOf("\n", cursor + 2);
|
|
862
|
+
cursor = newline === -1 ? content.length : newline;
|
|
863
|
+
ranges.push({
|
|
864
|
+
start,
|
|
865
|
+
end: cursor
|
|
866
|
+
});
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
if (character === "/") {
|
|
870
|
+
if (canStartJavascriptRegex(content, cursor, index)) {
|
|
871
|
+
const start = cursor;
|
|
872
|
+
let inCharacterClass = false;
|
|
873
|
+
cursor += 1;
|
|
874
|
+
while (cursor < content.length) {
|
|
875
|
+
if (content[cursor] === "\\") {
|
|
876
|
+
cursor += 2;
|
|
877
|
+
continue;
|
|
878
|
+
}
|
|
879
|
+
if (content[cursor] === "[") inCharacterClass = true;
|
|
880
|
+
if (content[cursor] === "]") inCharacterClass = false;
|
|
881
|
+
if (content[cursor] === "/" && !inCharacterClass) {
|
|
882
|
+
cursor += 1;
|
|
883
|
+
while (/[A-Za-z]/.test(content[cursor] ?? "")) cursor += 1;
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
if (content[cursor] === "\n") break;
|
|
887
|
+
cursor += 1;
|
|
888
|
+
}
|
|
889
|
+
ranges.push({
|
|
890
|
+
start,
|
|
891
|
+
end: cursor
|
|
892
|
+
});
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (character === "{") depth += 1;
|
|
897
|
+
if (character === "}") depth -= 1;
|
|
898
|
+
cursor += 1;
|
|
899
|
+
}
|
|
900
|
+
index = Math.max(index + 1, cursor);
|
|
901
|
+
}
|
|
902
|
+
return ranges;
|
|
903
|
+
}
|
|
904
|
+
function readGenericMdxJsxTag(content, index) {
|
|
905
|
+
let cursor = index + 1;
|
|
906
|
+
if (content[cursor] === "/") cursor += 1;
|
|
907
|
+
if (!/[A-Za-z]/.test(content[cursor] ?? "")) return void 0;
|
|
908
|
+
const nameStart = cursor;
|
|
909
|
+
while (/[\w:.-]/.test(content[cursor] ?? "")) cursor += 1;
|
|
910
|
+
const name = content.slice(nameStart, cursor);
|
|
911
|
+
if (DOCS_AUDIENCE_TAG_NAMES.some((candidate) => candidate === name)) return void 0;
|
|
912
|
+
if (!/[\s/>]/.test(content[cursor] ?? "")) return void 0;
|
|
913
|
+
const literals = [];
|
|
914
|
+
let braceDepth = 0;
|
|
915
|
+
while (cursor < content.length) {
|
|
916
|
+
const character = content[cursor];
|
|
917
|
+
const next = content[cursor + 1];
|
|
918
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
919
|
+
const quote = character;
|
|
920
|
+
const start = cursor;
|
|
921
|
+
cursor += 1;
|
|
922
|
+
while (cursor < content.length) {
|
|
923
|
+
if (content[cursor] === "\\") {
|
|
924
|
+
cursor += 2;
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (content[cursor] === quote) {
|
|
928
|
+
cursor += 1;
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
931
|
+
cursor += 1;
|
|
932
|
+
}
|
|
933
|
+
literals.push({
|
|
934
|
+
start,
|
|
935
|
+
end: cursor
|
|
936
|
+
});
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
if (braceDepth > 0 && character === "/" && next === "*") {
|
|
940
|
+
const start = cursor;
|
|
941
|
+
const end = content.indexOf("*/", cursor + 2);
|
|
942
|
+
cursor = end === -1 ? content.length : end + 2;
|
|
943
|
+
literals.push({
|
|
944
|
+
start,
|
|
945
|
+
end: cursor
|
|
946
|
+
});
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
if (braceDepth > 0 && character === "/" && next === "/") {
|
|
950
|
+
const start = cursor;
|
|
951
|
+
const newline = content.indexOf("\n", cursor + 2);
|
|
952
|
+
cursor = newline === -1 ? content.length : newline;
|
|
953
|
+
literals.push({
|
|
954
|
+
start,
|
|
955
|
+
end: cursor
|
|
956
|
+
});
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
if (character === "{") braceDepth += 1;
|
|
960
|
+
else if (character === "}" && braceDepth > 0) braceDepth -= 1;
|
|
961
|
+
else if (character === ">" && braceDepth === 0) {
|
|
962
|
+
let previous = cursor - 1;
|
|
963
|
+
while (previous >= index && /\s/.test(content[previous] ?? "")) previous -= 1;
|
|
964
|
+
return {
|
|
965
|
+
end: cursor + 1,
|
|
966
|
+
literals,
|
|
967
|
+
selfClosing: content[previous] === "/"
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
cursor += 1;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
function findGenericMdxJsxLiteralRanges(content, protectedRanges) {
|
|
974
|
+
const ranges = [];
|
|
975
|
+
let cursor = 0;
|
|
976
|
+
while (cursor < content.length) {
|
|
977
|
+
const index = content.indexOf("<", cursor);
|
|
978
|
+
if (index === -1) break;
|
|
979
|
+
if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
980
|
+
cursor = index + 1;
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
const tag = readGenericMdxJsxTag(content, index);
|
|
984
|
+
if (!tag) {
|
|
985
|
+
cursor = index + 1;
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
ranges.push(...tag.literals);
|
|
989
|
+
cursor = tag.end;
|
|
990
|
+
}
|
|
991
|
+
return ranges;
|
|
992
|
+
}
|
|
993
|
+
function findDelimiterExclusionRanges(content) {
|
|
994
|
+
const markdownLiterals = findMarkdownLiteralRanges(content);
|
|
995
|
+
const fences = findFenceRanges(content);
|
|
996
|
+
const frontmatter = findLeadingFrontmatterRange(content);
|
|
997
|
+
const literalBlocks = mergeProtectedRanges([
|
|
998
|
+
...markdownLiterals,
|
|
999
|
+
...fences,
|
|
1000
|
+
...frontmatter ? [frontmatter] : []
|
|
1001
|
+
]);
|
|
1002
|
+
const inlineCode = findInlineCodeRanges(content, literalBlocks);
|
|
1003
|
+
const markdownLinks = findMarkdownLinkDestinationRanges(content, literalBlocks);
|
|
1004
|
+
const nonModuleRanges = mergeProtectedRanges([
|
|
1005
|
+
...literalBlocks,
|
|
1006
|
+
...inlineCode,
|
|
1007
|
+
...markdownLinks
|
|
1008
|
+
]);
|
|
1009
|
+
const moduleRanges = findMdxModuleRanges(content, nonModuleRanges);
|
|
1010
|
+
const nonExpressionRanges = mergeProtectedRanges([...nonModuleRanges, ...moduleRanges]);
|
|
1011
|
+
const expressionLiterals = findMdxExpressionLiteralRanges(content, nonExpressionRanges);
|
|
1012
|
+
const nonJsxRanges = mergeProtectedRanges([...nonExpressionRanges, ...expressionLiterals]);
|
|
1013
|
+
return mergeProtectedRanges([...nonJsxRanges, ...findGenericMdxJsxLiteralRanges(content, nonJsxRanges)]);
|
|
1014
|
+
}
|
|
1015
|
+
function findProtectedRanges(content) {
|
|
1016
|
+
const baseExcludedRanges = findDelimiterExclusionRanges(content);
|
|
1017
|
+
const svelteDirectives = findSvelteDirectiveRanges(content, baseExcludedRanges);
|
|
1018
|
+
const excludedRanges = mergeProtectedRanges([...baseExcludedRanges, ...svelteDirectives]);
|
|
1019
|
+
const htmlLiterals = findHtmlLiteralRanges(content, excludedRanges);
|
|
1020
|
+
return mergeProtectedRanges([...excludedRanges, ...htmlLiterals]);
|
|
1021
|
+
}
|
|
1022
|
+
function findMarkdownLinkLiteralRanges(content) {
|
|
1023
|
+
try {
|
|
1024
|
+
const offsetAdjustment = content.startsWith("") ? 1 : 0;
|
|
1025
|
+
const tree = getDocsAudienceMarkdownProcessor().parse(offsetAdjustment > 0 ? content.slice(offsetAdjustment) : content);
|
|
1026
|
+
const ranges = [];
|
|
1027
|
+
const visit = (node) => {
|
|
1028
|
+
const rawStart = getOffset(node.position, "start");
|
|
1029
|
+
const rawEnd = getOffset(node.position, "end");
|
|
1030
|
+
const start = rawStart === void 0 ? void 0 : rawStart + offsetAdjustment;
|
|
1031
|
+
const end = rawEnd === void 0 ? void 0 : rawEnd + offsetAdjustment;
|
|
1032
|
+
if (start !== void 0 && end !== void 0 && (node.type === "link" || node.type === "image" || node.type === "linkReference" || node.type === "imageReference")) {
|
|
1033
|
+
ranges.push({
|
|
1034
|
+
start,
|
|
1035
|
+
end
|
|
1036
|
+
});
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
for (const child of node.children ?? []) visit(child);
|
|
1040
|
+
};
|
|
1041
|
+
visit(tree);
|
|
1042
|
+
return ranges;
|
|
1043
|
+
} catch {
|
|
1044
|
+
return [];
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
function findDocsMarkdownPromptBracketLiteralRanges(content, protectedRanges) {
|
|
1048
|
+
const ranges = [];
|
|
1049
|
+
let cursor = 0;
|
|
1050
|
+
while (cursor < content.length) {
|
|
1051
|
+
const index = content.indexOf("[", cursor);
|
|
1052
|
+
if (index === -1 || isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
1053
|
+
if (index === -1) break;
|
|
1054
|
+
cursor = index + 1;
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
let depth = 1;
|
|
1058
|
+
let end = index + 1;
|
|
1059
|
+
while (end < content.length && depth > 0) {
|
|
1060
|
+
if (content[end] === "\\") {
|
|
1061
|
+
end += 2;
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
if (content[end] === "[") depth += 1;
|
|
1065
|
+
if (content[end] === "]") depth -= 1;
|
|
1066
|
+
end += 1;
|
|
1067
|
+
}
|
|
1068
|
+
if (depth !== 0) {
|
|
1069
|
+
cursor = index + 1;
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
const label = content.slice(index + 1, end - 1);
|
|
1073
|
+
if (/<Prompt(?=[\s/>])/.test(label) && /<\/Prompt\s*>/.test(label)) {
|
|
1074
|
+
let rangeEnd = end;
|
|
1075
|
+
if (content[rangeEnd] === "[") {
|
|
1076
|
+
let referenceEnd = rangeEnd + 1;
|
|
1077
|
+
while (referenceEnd < content.length) {
|
|
1078
|
+
if (content[referenceEnd] === "\\") {
|
|
1079
|
+
referenceEnd += 2;
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
if (content[referenceEnd] === "]") {
|
|
1083
|
+
referenceEnd += 1;
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
referenceEnd += 1;
|
|
1087
|
+
}
|
|
1088
|
+
if (content[referenceEnd - 1] === "]") rangeEnd = referenceEnd;
|
|
1089
|
+
}
|
|
1090
|
+
ranges.push({
|
|
1091
|
+
start: content[index - 1] === "!" ? index - 1 : index,
|
|
1092
|
+
end: rangeEnd
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
cursor = end;
|
|
1096
|
+
}
|
|
1097
|
+
return ranges;
|
|
1098
|
+
}
|
|
1099
|
+
const DOCS_MARKDOWN_INTRINSIC_CONTAINER_NAMES = new Set([
|
|
1100
|
+
"a",
|
|
1101
|
+
"abbr",
|
|
1102
|
+
"address",
|
|
1103
|
+
"article",
|
|
1104
|
+
"aside",
|
|
1105
|
+
"audio",
|
|
1106
|
+
"b",
|
|
1107
|
+
"bdi",
|
|
1108
|
+
"bdo",
|
|
1109
|
+
"blockquote",
|
|
1110
|
+
"body",
|
|
1111
|
+
"button",
|
|
1112
|
+
"canvas",
|
|
1113
|
+
"caption",
|
|
1114
|
+
"cite",
|
|
1115
|
+
"code",
|
|
1116
|
+
"colgroup",
|
|
1117
|
+
"data",
|
|
1118
|
+
"datalist",
|
|
1119
|
+
"dd",
|
|
1120
|
+
"del",
|
|
1121
|
+
"details",
|
|
1122
|
+
"dfn",
|
|
1123
|
+
"dialog",
|
|
1124
|
+
"div",
|
|
1125
|
+
"dl",
|
|
1126
|
+
"dt",
|
|
1127
|
+
"em",
|
|
1128
|
+
"fieldset",
|
|
1129
|
+
"figcaption",
|
|
1130
|
+
"figure",
|
|
1131
|
+
"footer",
|
|
1132
|
+
"form",
|
|
1133
|
+
"h1",
|
|
1134
|
+
"h2",
|
|
1135
|
+
"h3",
|
|
1136
|
+
"h4",
|
|
1137
|
+
"h5",
|
|
1138
|
+
"h6",
|
|
1139
|
+
"head",
|
|
1140
|
+
"header",
|
|
1141
|
+
"hgroup",
|
|
1142
|
+
"html",
|
|
1143
|
+
"i",
|
|
1144
|
+
"iframe",
|
|
1145
|
+
"ins",
|
|
1146
|
+
"kbd",
|
|
1147
|
+
"label",
|
|
1148
|
+
"legend",
|
|
1149
|
+
"li",
|
|
1150
|
+
"main",
|
|
1151
|
+
"map",
|
|
1152
|
+
"mark",
|
|
1153
|
+
"math",
|
|
1154
|
+
"menu",
|
|
1155
|
+
"meter",
|
|
1156
|
+
"nav",
|
|
1157
|
+
"noembed",
|
|
1158
|
+
"noframes",
|
|
1159
|
+
"noscript",
|
|
1160
|
+
"object",
|
|
1161
|
+
"ol",
|
|
1162
|
+
"optgroup",
|
|
1163
|
+
"option",
|
|
1164
|
+
"output",
|
|
1165
|
+
"p",
|
|
1166
|
+
"picture",
|
|
1167
|
+
"pre",
|
|
1168
|
+
"progress",
|
|
1169
|
+
"q",
|
|
1170
|
+
"rp",
|
|
1171
|
+
"rt",
|
|
1172
|
+
"ruby",
|
|
1173
|
+
"s",
|
|
1174
|
+
"samp",
|
|
1175
|
+
"script",
|
|
1176
|
+
"search",
|
|
1177
|
+
"section",
|
|
1178
|
+
"select",
|
|
1179
|
+
"slot",
|
|
1180
|
+
"small",
|
|
1181
|
+
"span",
|
|
1182
|
+
"strong",
|
|
1183
|
+
"style",
|
|
1184
|
+
"sub",
|
|
1185
|
+
"summary",
|
|
1186
|
+
"sup",
|
|
1187
|
+
"svg",
|
|
1188
|
+
"table",
|
|
1189
|
+
"tbody",
|
|
1190
|
+
"td",
|
|
1191
|
+
"template",
|
|
1192
|
+
"textarea",
|
|
1193
|
+
"tfoot",
|
|
1194
|
+
"th",
|
|
1195
|
+
"thead",
|
|
1196
|
+
"time",
|
|
1197
|
+
"title",
|
|
1198
|
+
"tr",
|
|
1199
|
+
"u",
|
|
1200
|
+
"ul",
|
|
1201
|
+
"var",
|
|
1202
|
+
"video",
|
|
1203
|
+
"xmp"
|
|
1204
|
+
]);
|
|
1205
|
+
function normalizeDocsMarkdownIntrinsicContainerName(name) {
|
|
1206
|
+
const normalized = name.toLowerCase();
|
|
1207
|
+
if (!DOCS_MARKDOWN_INTRINSIC_CONTAINER_NAMES.has(normalized)) return void 0;
|
|
1208
|
+
const isLowercase = name === normalized;
|
|
1209
|
+
const isUppercase = name === name.toUpperCase() && /[A-Z]/.test(name);
|
|
1210
|
+
return isLowercase || isUppercase ? normalized : void 0;
|
|
1211
|
+
}
|
|
1212
|
+
function readDocsMarkdownPromptTagAt(content, index) {
|
|
1213
|
+
const closing = content[index + 1] === "/";
|
|
1214
|
+
const nameStart = index + (closing ? 2 : 1);
|
|
1215
|
+
if (!content.startsWith("Prompt", nameStart) || !/[\s/>]/.test(content[nameStart + 6] ?? "")) return;
|
|
1216
|
+
const tag = readGenericMdxJsxTag(content, index);
|
|
1217
|
+
if (!tag) return void 0;
|
|
1218
|
+
const attributesStart = nameStart + 6;
|
|
1219
|
+
let attributesEnd = tag.end - 1;
|
|
1220
|
+
while (attributesEnd > attributesStart && /\s/.test(content[attributesEnd - 1] ?? "")) attributesEnd -= 1;
|
|
1221
|
+
if (content[attributesEnd - 1] === "/") attributesEnd -= 1;
|
|
1222
|
+
return {
|
|
1223
|
+
attributes: closing ? "" : content.slice(attributesStart, attributesEnd),
|
|
1224
|
+
closing,
|
|
1225
|
+
end: tag.end,
|
|
1226
|
+
index,
|
|
1227
|
+
selfClosing: tag.selfClosing
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
function findDocsMarkdownHtmlContainerLiteralRanges(content, protectedRanges) {
|
|
1231
|
+
const ranges = [];
|
|
1232
|
+
const openings = [];
|
|
1233
|
+
let cursor = 0;
|
|
1234
|
+
while (cursor < content.length) {
|
|
1235
|
+
const index = content.indexOf("<", cursor);
|
|
1236
|
+
if (index === -1) break;
|
|
1237
|
+
if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
1238
|
+
cursor = index + 1;
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
const closing = content[index + 1] === "/";
|
|
1242
|
+
const nameStart = index + (closing ? 2 : 1);
|
|
1243
|
+
let nameEnd = nameStart;
|
|
1244
|
+
while (/[\w:.-]/.test(content[nameEnd] ?? "")) nameEnd += 1;
|
|
1245
|
+
const name = normalizeDocsMarkdownIntrinsicContainerName(content.slice(nameStart, nameEnd));
|
|
1246
|
+
if (!name) {
|
|
1247
|
+
cursor = index + 1;
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
const tag = readGenericMdxJsxTag(content, index);
|
|
1251
|
+
if (!tag) {
|
|
1252
|
+
cursor = index + 1;
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1255
|
+
cursor = tag.end;
|
|
1256
|
+
if (!closing) {
|
|
1257
|
+
if (!tag.selfClosing) openings.push({
|
|
1258
|
+
name,
|
|
1259
|
+
start: index
|
|
1260
|
+
});
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
let openingIndex = openings.length - 1;
|
|
1264
|
+
while (openingIndex >= 0 && openings[openingIndex].name !== name) openingIndex -= 1;
|
|
1265
|
+
if (openingIndex < 0) continue;
|
|
1266
|
+
const [opening] = openings.splice(openingIndex);
|
|
1267
|
+
ranges.push({
|
|
1268
|
+
start: opening.start,
|
|
1269
|
+
end: tag.end
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
return ranges;
|
|
1273
|
+
}
|
|
1274
|
+
function isStandaloneDocsMarkdownPromptHtmlRange(content, start, end) {
|
|
1275
|
+
while (start < end && /\s/.test(content[start] ?? "")) start += 1;
|
|
1276
|
+
while (end > start && /\s/.test(content[end - 1] ?? "")) end -= 1;
|
|
1277
|
+
return readDocsMarkdownPromptTagAt(content, start) !== void 0;
|
|
1278
|
+
}
|
|
1279
|
+
function findDocsMarkdownRawHtmlLiteralRanges(content) {
|
|
1280
|
+
try {
|
|
1281
|
+
const offsetAdjustment = content.startsWith("") ? 1 : 0;
|
|
1282
|
+
const tree = getDocsAudienceMarkdownProcessor().parse(offsetAdjustment > 0 ? content.slice(offsetAdjustment) : content);
|
|
1283
|
+
const ranges = [];
|
|
1284
|
+
const visit = (node) => {
|
|
1285
|
+
const rawStart = getOffset(node.position, "start");
|
|
1286
|
+
const rawEnd = getOffset(node.position, "end");
|
|
1287
|
+
const start = rawStart === void 0 ? void 0 : rawStart + offsetAdjustment;
|
|
1288
|
+
const end = rawEnd === void 0 ? void 0 : rawEnd + offsetAdjustment;
|
|
1289
|
+
if (node.type === "html" && start !== void 0 && end !== void 0) {
|
|
1290
|
+
if (isStandaloneDocsMarkdownPromptHtmlRange(content, start, end)) return;
|
|
1291
|
+
const elementName = content.slice(start, end).trimStart().match(/^<\/?([A-Za-z][\w:.-]*)(?=[\s/>])/)?.[1];
|
|
1292
|
+
if (elementName && !normalizeDocsMarkdownIntrinsicContainerName(elementName)) return;
|
|
1293
|
+
let cursor = start;
|
|
1294
|
+
let promptDepth = 0;
|
|
1295
|
+
let trailingClosingPrompt;
|
|
1296
|
+
while (cursor < end) {
|
|
1297
|
+
const index = content.indexOf("<", cursor);
|
|
1298
|
+
if (index === -1 || index >= end) break;
|
|
1299
|
+
const tag = readDocsMarkdownPromptTagAt(content, index);
|
|
1300
|
+
if (!tag || tag.end > end) {
|
|
1301
|
+
cursor = index + 1;
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1304
|
+
if (!tag.closing && !tag.selfClosing) promptDepth += 1;
|
|
1305
|
+
else if (tag.closing && promptDepth > 0) promptDepth -= 1;
|
|
1306
|
+
else if (tag.closing && content.slice(tag.end, end).trim().length === 0) trailingClosingPrompt = tag.index;
|
|
1307
|
+
cursor = tag.end;
|
|
1308
|
+
}
|
|
1309
|
+
const literalEnd = trailingClosingPrompt ?? end;
|
|
1310
|
+
if (literalEnd > start) ranges.push({
|
|
1311
|
+
start,
|
|
1312
|
+
end: literalEnd
|
|
1313
|
+
});
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
for (const child of node.children ?? []) visit(child);
|
|
1317
|
+
};
|
|
1318
|
+
visit(tree);
|
|
1319
|
+
return ranges;
|
|
1320
|
+
} catch {
|
|
1321
|
+
return [];
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
function findDocsMarkdownPromptAstInfo(content) {
|
|
1325
|
+
try {
|
|
1326
|
+
const prepared = prepareMdxParserSource(content);
|
|
1327
|
+
const offsetAdjustment = prepared.startsWith("") ? 1 : 0;
|
|
1328
|
+
const tree = getDocsAudienceMdxProcessor().parse(offsetAdjustment > 0 ? prepared.slice(offsetAdjustment) : prepared);
|
|
1329
|
+
const flowStarts = /* @__PURE__ */ new Set();
|
|
1330
|
+
const starts = /* @__PURE__ */ new Set();
|
|
1331
|
+
const visit = (node) => {
|
|
1332
|
+
if (node.name === "Prompt" && (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && getOffset(node.position, "start") !== void 0) {
|
|
1333
|
+
const start = getOffset(node.position, "start") + offsetAdjustment;
|
|
1334
|
+
starts.add(start);
|
|
1335
|
+
if (node.type === "mdxJsxFlowElement") flowStarts.add(start);
|
|
1336
|
+
}
|
|
1337
|
+
for (const child of node.children ?? []) visit(child);
|
|
1338
|
+
};
|
|
1339
|
+
visit(tree);
|
|
1340
|
+
return {
|
|
1341
|
+
flowStarts,
|
|
1342
|
+
starts
|
|
1343
|
+
};
|
|
1344
|
+
} catch {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
function findDocsMarkdownPromptExpressionRanges(content, protectedRanges) {
|
|
1349
|
+
const ranges = [];
|
|
1350
|
+
let protectedIndex = 0;
|
|
1351
|
+
let cursor = 0;
|
|
1352
|
+
while (cursor < content.length) {
|
|
1353
|
+
const start = content.indexOf("{", cursor);
|
|
1354
|
+
if (start === -1) break;
|
|
1355
|
+
if (isEscapedAt(content, start) || isInsideRange(start, protectedRanges)) {
|
|
1356
|
+
cursor = start + 1;
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
let depth = 1;
|
|
1360
|
+
let end = start + 1;
|
|
1361
|
+
while (end < content.length && depth > 0) {
|
|
1362
|
+
while (protectedIndex < protectedRanges.length && protectedRanges[protectedIndex].end <= end) protectedIndex += 1;
|
|
1363
|
+
const candidate = protectedRanges[protectedIndex];
|
|
1364
|
+
const protectedRange = candidate && end >= candidate.start && end < candidate.end ? candidate : void 0;
|
|
1365
|
+
if (protectedRange) {
|
|
1366
|
+
end = protectedRange.end;
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
if (content[end] === "{") depth += 1;
|
|
1370
|
+
if (content[end] === "}") depth -= 1;
|
|
1371
|
+
end += 1;
|
|
1372
|
+
}
|
|
1373
|
+
ranges.push({
|
|
1374
|
+
start,
|
|
1375
|
+
end: depth === 0 ? end : content.length
|
|
1376
|
+
});
|
|
1377
|
+
if (depth !== 0) break;
|
|
1378
|
+
cursor = end;
|
|
1379
|
+
}
|
|
1380
|
+
return ranges;
|
|
1381
|
+
}
|
|
1382
|
+
function createDocsMarkdownPromptToken(content, used, startAt) {
|
|
1383
|
+
let index = startAt;
|
|
1384
|
+
let token = "";
|
|
1385
|
+
do {
|
|
1386
|
+
token = `%%PROMPT_${index}%%`;
|
|
1387
|
+
index += 1;
|
|
1388
|
+
} while (content.includes(token) || used.has(token));
|
|
1389
|
+
return token;
|
|
1390
|
+
}
|
|
1391
|
+
function isFallbackDocsMarkdownPromptFlow(content, opening, closing) {
|
|
1392
|
+
const lineStart = Math.max(0, content.lastIndexOf("\n", opening.index - 1) + 1);
|
|
1393
|
+
const prefix = content.slice(lineStart, opening.index);
|
|
1394
|
+
if (!/^[\t ]{0,3}$/.test(prefix)) return false;
|
|
1395
|
+
const lineEnd = content.indexOf("\n", closing.end);
|
|
1396
|
+
const suffix = content.slice(closing.end, lineEnd === -1 ? content.length : lineEnd);
|
|
1397
|
+
return content.slice(opening.end, closing.index).includes("\n") || /^[\t\r ]*$/.test(suffix);
|
|
1398
|
+
}
|
|
1399
|
+
function resolveDocsMarkdownPromptContainer(content, opening) {
|
|
1400
|
+
const lineStart = Math.max(0, content.lastIndexOf("\n", opening.index - 1) + 1);
|
|
1401
|
+
let prefix = content.slice(lineStart, opening.index);
|
|
1402
|
+
let blockquoteDepth = 0;
|
|
1403
|
+
let listIndent = 0;
|
|
1404
|
+
while (true) {
|
|
1405
|
+
const blockquote = /^ {0,3}>[\t ]?/.exec(prefix);
|
|
1406
|
+
if (!blockquote) break;
|
|
1407
|
+
blockquoteDepth += 1;
|
|
1408
|
+
prefix = prefix.slice(blockquote[0].length);
|
|
1409
|
+
}
|
|
1410
|
+
while (true) {
|
|
1411
|
+
const list = /^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/.exec(prefix);
|
|
1412
|
+
if (!list) break;
|
|
1413
|
+
listIndent += list[0].length;
|
|
1414
|
+
prefix = prefix.slice(list[0].length);
|
|
1415
|
+
}
|
|
1416
|
+
if (listIndent === 0 && /^[\t ]+$/.test(prefix)) {
|
|
1417
|
+
let previousLineEnd = Math.max(0, lineStart - 1);
|
|
1418
|
+
while (previousLineEnd > 0) {
|
|
1419
|
+
const previousLineStart = Math.max(0, content.lastIndexOf("\n", previousLineEnd - 1) + 1);
|
|
1420
|
+
let previousLine = content.slice(previousLineStart, previousLineEnd).replace(/\r$/, "");
|
|
1421
|
+
for (let depth = 0; depth < blockquoteDepth; depth += 1) {
|
|
1422
|
+
const blockquote = /^ {0,3}>[\t ]?/.exec(previousLine);
|
|
1423
|
+
if (!blockquote) {
|
|
1424
|
+
previousLine = "";
|
|
1425
|
+
break;
|
|
1426
|
+
}
|
|
1427
|
+
previousLine = previousLine.slice(blockquote[0].length);
|
|
1428
|
+
}
|
|
1429
|
+
const list = /^ {0,3}(?:[-+*]|\d{1,9}[.)])[\t ]+/.exec(previousLine);
|
|
1430
|
+
if (list && prefix.length >= list[0].length) {
|
|
1431
|
+
listIndent = list[0].length;
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
if (previousLine.trim().length === 0) break;
|
|
1435
|
+
previousLineEnd = Math.max(0, previousLineStart - 1);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
if (blockquoteDepth === 0 && listIndent === 0 || !/^[\t ]*$/.test(prefix)) return;
|
|
1439
|
+
return {
|
|
1440
|
+
blockquoteDepth,
|
|
1441
|
+
listIndent
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
function stripDocsMarkdownPromptContainer(children, container) {
|
|
1445
|
+
if (!container) return children;
|
|
1446
|
+
return children.split(/(\r?\n)/).map((segment, index) => {
|
|
1447
|
+
if (index % 2 === 1) return segment;
|
|
1448
|
+
let line = segment;
|
|
1449
|
+
for (let depth = 0; depth < container.blockquoteDepth; depth += 1) {
|
|
1450
|
+
const blockquote = /^ {0,3}>[\t ]?/.exec(line);
|
|
1451
|
+
if (!blockquote) break;
|
|
1452
|
+
line = line.slice(blockquote[0].length);
|
|
1453
|
+
}
|
|
1454
|
+
let remainingIndent = container.listIndent;
|
|
1455
|
+
while (remainingIndent > 0 && /^[\t ]/.test(line)) {
|
|
1456
|
+
line = line.slice(1);
|
|
1457
|
+
remainingIndent -= 1;
|
|
1458
|
+
}
|
|
1459
|
+
return line;
|
|
1460
|
+
}).join("");
|
|
1461
|
+
}
|
|
1462
|
+
function createDocsMarkdownPromptReplacement(content, start, end, token, flow, container, adjacentFlowBefore = false, adjacentFlowAfter = false) {
|
|
1463
|
+
if (!flow || container) return token;
|
|
1464
|
+
const newline = content.includes("\r\n") ? "\r\n" : "\n";
|
|
1465
|
+
const before = content.slice(0, start);
|
|
1466
|
+
const after = content.slice(end);
|
|
1467
|
+
const leading = adjacentFlowBefore || before.length === 0 || /(?:\r?\n){2}$/.test(before) ? "" : /\r?\n$/.test(before) ? newline : newline + newline;
|
|
1468
|
+
const trailing = adjacentFlowAfter || after.length === 0 || /^(?:\r?\n){2}/.test(after) ? "" : /^\r?\n/.test(after) ? newline : newline + newline;
|
|
1469
|
+
return leading + token + trailing;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Extract live MDX Prompt blocks while leaving Markdown literals untouched.
|
|
1473
|
+
*
|
|
1474
|
+
* Prompt bodies are copyable source, so callers can safely run audience,
|
|
1475
|
+
* reference-definition, and heading passes over `markdown`, then restore each
|
|
1476
|
+
* block from its token. Fences (including container fences), inline code, links,
|
|
1477
|
+
* comments, raw elements, and other literal contexts are never extracted.
|
|
1478
|
+
*/
|
|
1479
|
+
function extractDocsMarkdownPromptBlocks(content) {
|
|
1480
|
+
if (!/<Prompt(?=[\s/>])/.test(content)) return {
|
|
1481
|
+
blocks: [],
|
|
1482
|
+
markdown: content
|
|
1483
|
+
};
|
|
1484
|
+
const syntaxProtectedRanges = mergeProtectedRanges([...findProtectedRanges(content), ...findMarkdownLinkLiteralRanges(content)]);
|
|
1485
|
+
const expressionRanges = findDocsMarkdownPromptExpressionRanges(content, syntaxProtectedRanges);
|
|
1486
|
+
const baseProtectedRanges = mergeProtectedRanges([
|
|
1487
|
+
...syntaxProtectedRanges,
|
|
1488
|
+
...expressionRanges,
|
|
1489
|
+
...findDocsMarkdownRawHtmlLiteralRanges(content),
|
|
1490
|
+
...findDocsMarkdownHtmlContainerLiteralRanges(content, syntaxProtectedRanges)
|
|
1491
|
+
]);
|
|
1492
|
+
const protectedRanges = mergeProtectedRanges([...baseProtectedRanges, ...findDocsMarkdownPromptBracketLiteralRanges(content, baseProtectedRanges)]);
|
|
1493
|
+
const promptAst = findDocsMarkdownPromptAstInfo(content);
|
|
1494
|
+
const pairs = [];
|
|
1495
|
+
const openings = [];
|
|
1496
|
+
let cursor = 0;
|
|
1497
|
+
while (cursor < content.length) {
|
|
1498
|
+
const index = content.indexOf("<", cursor);
|
|
1499
|
+
if (index === -1) break;
|
|
1500
|
+
if (isEscapedAt(content, index) || isInsideRange(index, protectedRanges)) {
|
|
1501
|
+
cursor = index + 1;
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
const tag = readDocsMarkdownPromptTagAt(content, index);
|
|
1505
|
+
if (!tag) {
|
|
1506
|
+
cursor = index + 1;
|
|
1507
|
+
continue;
|
|
1508
|
+
}
|
|
1509
|
+
cursor = tag.end;
|
|
1510
|
+
if (!tag.closing) {
|
|
1511
|
+
if (promptAst && !promptAst.starts.has(tag.index)) continue;
|
|
1512
|
+
if (!tag.selfClosing) openings.push({
|
|
1513
|
+
completedChildren: [],
|
|
1514
|
+
tag
|
|
1515
|
+
});
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
const frame = openings.pop();
|
|
1519
|
+
if (!frame) continue;
|
|
1520
|
+
const container = resolveDocsMarkdownPromptContainer(content, frame.tag);
|
|
1521
|
+
const pair = {
|
|
1522
|
+
attributes: frame.tag.attributes,
|
|
1523
|
+
children: stripDocsMarkdownPromptContainer(content.slice(frame.tag.end, tag.index), container),
|
|
1524
|
+
container,
|
|
1525
|
+
end: tag.end,
|
|
1526
|
+
flow: promptAst?.flowStarts.has(frame.tag.index) === true || isFallbackDocsMarkdownPromptFlow(content, frame.tag, tag),
|
|
1527
|
+
start: frame.tag.index
|
|
1528
|
+
};
|
|
1529
|
+
const parent = openings.at(-1);
|
|
1530
|
+
if (parent) parent.completedChildren.push(pair);
|
|
1531
|
+
else pairs.push(pair);
|
|
1532
|
+
}
|
|
1533
|
+
for (const frame of openings) pairs.push(...frame.completedChildren);
|
|
1534
|
+
pairs.sort((left, right) => left.start - right.start);
|
|
1535
|
+
if (pairs.length === 0) return {
|
|
1536
|
+
blocks: [],
|
|
1537
|
+
markdown: content
|
|
1538
|
+
};
|
|
1539
|
+
const usedTokens = /* @__PURE__ */ new Set();
|
|
1540
|
+
const blocks = pairs.map((pair, index) => {
|
|
1541
|
+
const token = createDocsMarkdownPromptToken(content, usedTokens, index);
|
|
1542
|
+
usedTokens.add(token);
|
|
1543
|
+
return {
|
|
1544
|
+
attributes: pair.attributes,
|
|
1545
|
+
children: pair.children,
|
|
1546
|
+
token
|
|
1547
|
+
};
|
|
1548
|
+
});
|
|
1549
|
+
let markdown = content;
|
|
1550
|
+
for (let index = pairs.length - 1; index >= 0; index -= 1) {
|
|
1551
|
+
const replacement = createDocsMarkdownPromptReplacement(content, pairs[index].start, pairs[index].end, blocks[index].token, pairs[index].flow, pairs[index].container, index > 0 && pairs[index - 1].flow && /^[\t \r\n]*$/.test(content.slice(pairs[index - 1].end, pairs[index].start)), index + 1 < pairs.length && pairs[index + 1].flow && /^[\t \r\n]*$/.test(content.slice(pairs[index].end, pairs[index + 1].start)));
|
|
1552
|
+
markdown = markdown.slice(0, pairs[index].start) + replacement + markdown.slice(pairs[index].end);
|
|
1553
|
+
}
|
|
1554
|
+
return {
|
|
1555
|
+
blocks,
|
|
1556
|
+
markdown
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
function normalizeProjectedWhitespace(content) {
|
|
1560
|
+
const protectedRanges = findProtectedRanges(content);
|
|
1561
|
+
return content.replace(/\n{3,}/g, (newlines, offset) => {
|
|
1562
|
+
const end = offset + newlines.length;
|
|
1563
|
+
return protectedRanges.some((range) => range.start < end && range.end > offset) ? newlines : "\n\n";
|
|
1564
|
+
}).trim();
|
|
1565
|
+
}
|
|
1566
|
+
/** Find audience declarations that cannot be projected consistently at build time. */
|
|
1567
|
+
function findDocsAudienceMdxIssues(content) {
|
|
1568
|
+
const issues = [];
|
|
1569
|
+
for (const tag of findDocsAudienceMdxTags(content)) {
|
|
1570
|
+
if (tag.closing) continue;
|
|
1571
|
+
const { attributes } = tag;
|
|
1572
|
+
const hasOnlyAttribute = tag.hasOnlyAttribute ?? /(?:^|\s)only\s*=/.test(attributes);
|
|
1573
|
+
const hasSpreadAttribute = tag.hasSpreadAttribute ?? /\{\s*\.\.\./.test(attributes);
|
|
1574
|
+
if ((tag.name === "Agent" || tag.name === "Human") && hasOnlyAttribute) {
|
|
1575
|
+
const shorthandAudience = tag.name === "Agent" ? "agent" : "human";
|
|
1576
|
+
issues.push({
|
|
1577
|
+
code: tag.name === "Agent" ? "ignored-agent-only" : "ignored-human-only",
|
|
1578
|
+
index: tag.index,
|
|
1579
|
+
message: `<${tag.name}> is always ${shorthandAudience}-only, so its \`only\` prop is ignored. Use <Audience only="${shorthandAudience}"> when you need the explicit form.`
|
|
1580
|
+
});
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1583
|
+
if (tag.name !== "Audience") continue;
|
|
1584
|
+
if (hasSpreadAttribute) {
|
|
1585
|
+
issues.push({
|
|
1586
|
+
code: "dynamic-only",
|
|
1587
|
+
index: tag.index,
|
|
1588
|
+
message: "Audience spread props cannot be projected consistently. Remove the spread and use the static literal `only=\"human\"` or `only=\"agent\"`."
|
|
1589
|
+
});
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
if (tag.only) continue;
|
|
1593
|
+
if (!hasOnlyAttribute) {
|
|
1594
|
+
issues.push({
|
|
1595
|
+
code: "missing-only",
|
|
1596
|
+
index: tag.index,
|
|
1597
|
+
message: "<Audience> requires the static literal `only=\"human\"` or `only=\"agent\"`."
|
|
1598
|
+
});
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
const dynamicOnly = tag.onlyKind === "dynamic" || /(?:^|\s)only\s*=\s*\{/.test(attributes);
|
|
1602
|
+
issues.push({
|
|
1603
|
+
code: dynamicOnly ? "dynamic-only" : "invalid-only",
|
|
1604
|
+
index: tag.index,
|
|
1605
|
+
message: dynamicOnly ? "Dynamic Audience.only expressions cannot be projected consistently. Use the static literal `only=\"human\"` or `only=\"agent\"`." : "Audience.only must be the static literal `\"human\"` or `\"agent\"`."
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
return issues;
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Resolve MDX into its human or agent projection.
|
|
1612
|
+
*
|
|
1613
|
+
* `<Agent>` is shorthand for `<Audience only="agent">`, while `<Human>` is
|
|
1614
|
+
* shorthand for `<Audience only="human">`. Unknown `Audience.only` values are
|
|
1615
|
+
* treated as shared content so an authoring typo never silently deletes content.
|
|
1616
|
+
* These primitives shape content for each surface; they are not an access-control boundary.
|
|
1617
|
+
*/
|
|
1618
|
+
function resolveDocsAudienceMdxContent(content, audience) {
|
|
1619
|
+
const scopes = [];
|
|
1620
|
+
let output = "";
|
|
1621
|
+
let cursor = 0;
|
|
1622
|
+
let resolvedTag = false;
|
|
1623
|
+
for (const tag of findDocsAudienceMdxTags(content)) {
|
|
1624
|
+
const activeScope = scopes.at(-1);
|
|
1625
|
+
if (tag.closing && activeScope?.name !== tag.name) continue;
|
|
1626
|
+
resolvedTag = true;
|
|
1627
|
+
const visibleBeforeTag = isAudienceVisible(scopes, audience);
|
|
1628
|
+
if (visibleBeforeTag) output += content.slice(cursor, tag.index);
|
|
1629
|
+
cursor = tag.end;
|
|
1630
|
+
if (tag.closing) {
|
|
1631
|
+
if (tag.expression && visibleBeforeTag) output += "</>";
|
|
1632
|
+
scopes.pop();
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
if (tag.selfClosing) {
|
|
1636
|
+
if (tag.expression && visibleBeforeTag) output += tag.jsxChild ? "{null}" : "null";
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
scopes.push({
|
|
1640
|
+
name: tag.name,
|
|
1641
|
+
only: tag.only
|
|
1642
|
+
});
|
|
1643
|
+
if (tag.expression && visibleBeforeTag) output += isAudienceVisible(scopes, audience) ? "<>" : tag.jsxChild ? "{null}" : "null";
|
|
1644
|
+
}
|
|
1645
|
+
if (isAudienceVisible(scopes, audience)) output += content.slice(cursor);
|
|
1646
|
+
return resolvedTag ? normalizeProjectedWhitespace(output) : content;
|
|
1647
|
+
}
|
|
1648
|
+
/** Backwards-compatible name retained for existing integrations. */
|
|
1649
|
+
function resolveDocsAgentMdxContent(content, audience) {
|
|
1650
|
+
return resolveDocsAudienceMdxContent(content, audience);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
//#endregion
|
|
1654
|
+
export { extractDocsMarkdownPromptBlocks, findDocsAudienceMdxIssues, findDocsAudienceMdxTags, resolveDocsAgentMdxContent, resolveDocsAudienceMdxContent };
|