saturndocs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/auth-FRCFGNYT.js +14 -0
- package/dist/brokenLinks-TTOBP4P7.js +48 -0
- package/dist/build-F5PWGP57.js +39 -0
- package/dist/chunk-3P2OFTXR.js +71 -0
- package/dist/chunk-3V753MRI.js +100 -0
- package/dist/chunk-5KX4ZK5E.js +104 -0
- package/dist/chunk-CMNX5DLQ.js +119 -0
- package/dist/chunk-GYRVGWDM.js +3499 -0
- package/dist/chunk-I6U4V7B4.js +1552 -0
- package/dist/chunk-J6P3VGGE.js +21 -0
- package/dist/chunk-KGJESHJC.js +37 -0
- package/dist/chunk-M2BZEDAS.js +57 -0
- package/dist/chunk-N7QPZMLP.js +82 -0
- package/dist/chunk-OEAEX5YW.js +51 -0
- package/dist/chunk-OZWTXMO3.js +584 -0
- package/dist/chunk-QLFODLVN.js +46 -0
- package/dist/chunk-R3X2DPFF.js +568 -0
- package/dist/chunk-S45UWCML.js +588 -0
- package/dist/chunk-SABK3R2P.js +2452 -0
- package/dist/chunk-STCCGFKC.js +246 -0
- package/dist/chunk-TKISMN3P.js +39 -0
- package/dist/chunk-U7PKMSB3.js +465 -0
- package/dist/chunk-VNYDYHXM.js +22 -0
- package/dist/chunk-VXEUNRVA.js +26 -0
- package/dist/chunk-XO4CUC7V.js +99 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +95 -0
- package/dist/deploy-QU7DCKWU.js +11 -0
- package/dist/dev-VDSDCBO2.js +43 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.js +191 -0
- package/dist/init-7T5TEPBH.js +14 -0
- package/dist/manage-MKH27U3B.js +12 -0
- package/dist/openapiCheck-KGBQJTIQ.js +66 -0
- package/dist/pages-HIPXRLSY.js +15 -0
- package/dist/read-DMSJUEDA.js +160 -0
- package/dist/read-ZEVUZNNB.js +146 -0
- package/dist/requests-H5MIGBIS.js +13 -0
- package/dist/schema-XJUEZSIW.js +13 -0
- package/dist/sites-I4WI2MPG.js +14 -0
- package/dist/status-7R3NOI5H.js +14 -0
- package/dist/suggestions-4WFQ3APX.js +739 -0
- package/dist/validate-VXL4PL42.js +30 -0
- package/package.json +68 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseOpenApiFile
|
|
3
|
+
} from "./chunk-S45UWCML.js";
|
|
4
|
+
import {
|
|
5
|
+
loadDocsConfig,
|
|
6
|
+
loadModelsConfig,
|
|
7
|
+
navigationGroups
|
|
8
|
+
} from "./chunk-R3X2DPFF.js";
|
|
9
|
+
|
|
10
|
+
// src/lib/pages.ts
|
|
11
|
+
import { existsSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
function resolvePageFile(docsDir, entry) {
|
|
14
|
+
const mdxPath = join(docsDir, "pages", `${entry}.mdx`);
|
|
15
|
+
const mdPath = join(docsDir, "pages", `${entry}.md`);
|
|
16
|
+
const hasMdx = existsSync(mdxPath);
|
|
17
|
+
const hasMd = existsSync(mdPath);
|
|
18
|
+
if (hasMdx && hasMd) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Page "${entry}" resolves to both pages/${entry}.mdx and pages/${entry}.md; keep only one.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
if (hasMdx) return { entry, file: mdxPath, ext: ".mdx" };
|
|
24
|
+
if (hasMd) return { entry, file: mdPath, ext: ".md" };
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Page "${entry}" not found: expected pages/${entry}.mdx or pages/${entry}.md.`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function pageUrl(entry) {
|
|
30
|
+
return entry === "index" ? "/" : `/${entry}`;
|
|
31
|
+
}
|
|
32
|
+
function collectPageEntries(config) {
|
|
33
|
+
return navigationGroups(config).flatMap((group) => group.pages);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/lib/validate.ts
|
|
37
|
+
import { existsSync as existsSync2 } from "fs";
|
|
38
|
+
import { readFile } from "fs/promises";
|
|
39
|
+
import { join as join2 } from "path";
|
|
40
|
+
|
|
41
|
+
// ../mdx-preprocess/dist/index.js
|
|
42
|
+
import { unified } from "unified";
|
|
43
|
+
import remarkParse from "remark-parse";
|
|
44
|
+
import remarkMdx from "remark-mdx";
|
|
45
|
+
import remarkFrontmatter from "remark-frontmatter";
|
|
46
|
+
import remarkGfm from "remark-gfm";
|
|
47
|
+
import GithubSlugger from "github-slugger";
|
|
48
|
+
import { parse as parseYaml } from "yaml";
|
|
49
|
+
var PROSE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
50
|
+
"title",
|
|
51
|
+
"caption",
|
|
52
|
+
"description",
|
|
53
|
+
"summary",
|
|
54
|
+
"transcript"
|
|
55
|
+
]);
|
|
56
|
+
var RESOURCE_DESCRIPTION_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
57
|
+
"description",
|
|
58
|
+
"summary",
|
|
59
|
+
"transcript"
|
|
60
|
+
]);
|
|
61
|
+
var buildProcessor = () => unified().use(remarkParse).use(remarkMdx).use(remarkFrontmatter, ["yaml"]).use(remarkGfm);
|
|
62
|
+
function stripMdx(source) {
|
|
63
|
+
const tree = buildProcessor().parse(source);
|
|
64
|
+
const slugger = new GithubSlugger();
|
|
65
|
+
const headings = [];
|
|
66
|
+
let title;
|
|
67
|
+
let description;
|
|
68
|
+
let frontmatter = {};
|
|
69
|
+
for (const node of tree.children ?? []) {
|
|
70
|
+
if (node.type === "yaml" && typeof node.value === "string") {
|
|
71
|
+
const parsed = parseFrontmatter(node.value);
|
|
72
|
+
frontmatter = parsed.frontmatter;
|
|
73
|
+
if (parsed.title !== void 0) title = parsed.title;
|
|
74
|
+
if (parsed.description !== void 0) description = parsed.description;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const renderPhrasing = (nodes) => {
|
|
79
|
+
if (!nodes) return "";
|
|
80
|
+
let out = "";
|
|
81
|
+
for (const node of nodes) {
|
|
82
|
+
out += phrasing(node);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
};
|
|
86
|
+
function phrasing(node) {
|
|
87
|
+
switch (node.type) {
|
|
88
|
+
case "text":
|
|
89
|
+
return node.value ?? "";
|
|
90
|
+
case "inlineCode":
|
|
91
|
+
return "`" + (node.value ?? "") + "`";
|
|
92
|
+
case "strong":
|
|
93
|
+
return "**" + renderPhrasing(node.children) + "**";
|
|
94
|
+
case "emphasis":
|
|
95
|
+
return "*" + renderPhrasing(node.children) + "*";
|
|
96
|
+
case "delete":
|
|
97
|
+
return renderPhrasing(node.children);
|
|
98
|
+
case "link":
|
|
99
|
+
return renderMarkdownLink(
|
|
100
|
+
renderPhrasing(node.children),
|
|
101
|
+
node.url ?? ""
|
|
102
|
+
);
|
|
103
|
+
case "image": {
|
|
104
|
+
const label = node.alt?.trim() || "Image";
|
|
105
|
+
return renderMarkdownResource("Image", label, node.url ?? "");
|
|
106
|
+
}
|
|
107
|
+
case "break":
|
|
108
|
+
return "\n";
|
|
109
|
+
case "mdxTextExpression": {
|
|
110
|
+
const literal = stringLiteralValue(node.value ?? "");
|
|
111
|
+
return literal ?? "";
|
|
112
|
+
}
|
|
113
|
+
case "mdxJsxTextElement": {
|
|
114
|
+
const inner = renderPhrasing(node.children);
|
|
115
|
+
const componentText = componentMarkdownForNode(node);
|
|
116
|
+
if (componentText) return inner ? `${componentText} ${inner}` : componentText;
|
|
117
|
+
const resource = resourceMarkdownForNode(node, inner);
|
|
118
|
+
if (resource) return resource;
|
|
119
|
+
const attrText = proseAttributeValues(node.attributes).join(" ");
|
|
120
|
+
return attrText ? inner ? attrText + " " + inner : attrText : inner;
|
|
121
|
+
}
|
|
122
|
+
case "html":
|
|
123
|
+
return renderHtmlResource(node.value ?? "");
|
|
124
|
+
default:
|
|
125
|
+
return node.children ? renderPhrasing(node.children) : "";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const renderFlow = (nodes) => {
|
|
129
|
+
if (!nodes) return [];
|
|
130
|
+
const blocks = [];
|
|
131
|
+
for (const node of nodes) {
|
|
132
|
+
pushFlow(node, blocks);
|
|
133
|
+
}
|
|
134
|
+
return blocks;
|
|
135
|
+
};
|
|
136
|
+
function pushFlow(node, blocks) {
|
|
137
|
+
switch (node.type) {
|
|
138
|
+
case "yaml":
|
|
139
|
+
case "toml":
|
|
140
|
+
case "mdxjsEsm":
|
|
141
|
+
case "definition":
|
|
142
|
+
case "footnoteDefinition":
|
|
143
|
+
case "html": {
|
|
144
|
+
const resource = renderHtmlResource(node.value ?? "");
|
|
145
|
+
if (resource) blocks.push(resource);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
case "thematicBreak":
|
|
149
|
+
blocks.push("* * *");
|
|
150
|
+
return;
|
|
151
|
+
case "heading": {
|
|
152
|
+
const depth = node.depth ?? 1;
|
|
153
|
+
const text2 = renderPhrasing(node.children).trim();
|
|
154
|
+
const slug = slugger.slug(text2);
|
|
155
|
+
headings.push({ depth, text: text2, slug });
|
|
156
|
+
blocks.push("#".repeat(depth) + " " + text2);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
case "paragraph": {
|
|
160
|
+
const text2 = renderPhrasing(node.children).trim();
|
|
161
|
+
if (text2) blocks.push(text2);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
case "blockquote": {
|
|
165
|
+
const inner = renderFlow(node.children).join("\n\n");
|
|
166
|
+
if (inner) {
|
|
167
|
+
blocks.push(
|
|
168
|
+
inner.split("\n").map((line) => line ? "> " + line : ">").join("\n")
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
case "list":
|
|
174
|
+
blocks.push(renderList(node));
|
|
175
|
+
return;
|
|
176
|
+
case "code":
|
|
177
|
+
blocks.push(renderCode(node));
|
|
178
|
+
return;
|
|
179
|
+
case "table":
|
|
180
|
+
blocks.push(renderTable(node));
|
|
181
|
+
return;
|
|
182
|
+
case "mdxFlowExpression": {
|
|
183
|
+
const literal = stringLiteralValue(node.value ?? "");
|
|
184
|
+
if (literal) blocks.push(literal);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
case "mdxJsxFlowElement": {
|
|
188
|
+
const componentText = componentMarkdownForNode(node);
|
|
189
|
+
if (componentText) blocks.push(componentText);
|
|
190
|
+
const resource = resourceMarkdownForNode(node);
|
|
191
|
+
if (resource) {
|
|
192
|
+
blocks.push(resource);
|
|
193
|
+
for (const value of namedAttributeValues(
|
|
194
|
+
node.attributes,
|
|
195
|
+
RESOURCE_DESCRIPTION_ATTRIBUTES
|
|
196
|
+
)) {
|
|
197
|
+
blocks.push(value);
|
|
198
|
+
}
|
|
199
|
+
} else if (!componentText) {
|
|
200
|
+
for (const value of proseAttributeValues(node.attributes)) {
|
|
201
|
+
blocks.push(value);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (const block of renderFlow(node.children)) {
|
|
205
|
+
blocks.push(block);
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
default: {
|
|
210
|
+
if (node.children) {
|
|
211
|
+
for (const block of renderFlow(node.children)) blocks.push(block);
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function renderList(node) {
|
|
218
|
+
const ordered = node.ordered === true;
|
|
219
|
+
let index = typeof node.start === "number" ? node.start : 1;
|
|
220
|
+
const items = [];
|
|
221
|
+
for (const item of node.children ?? []) {
|
|
222
|
+
const marker = ordered ? `${index++}. ` : "- ";
|
|
223
|
+
const pad = " ".repeat(marker.length);
|
|
224
|
+
const body = renderFlow(item.children).join("\n\n");
|
|
225
|
+
const lines = body.split("\n");
|
|
226
|
+
const rendered = lines.map((line, i) => i === 0 ? marker + line : pad + line).join("\n");
|
|
227
|
+
items.push(rendered);
|
|
228
|
+
}
|
|
229
|
+
return items.join("\n");
|
|
230
|
+
}
|
|
231
|
+
function renderCode(node) {
|
|
232
|
+
const lang = typeof node.lang === "string" ? node.lang : "";
|
|
233
|
+
const value = node.value ?? "";
|
|
234
|
+
const fence = "`".repeat(Math.max(3, longestBacktickRun(value) + 1));
|
|
235
|
+
return fence + lang + "\n" + value + "\n" + fence;
|
|
236
|
+
}
|
|
237
|
+
function renderTable(node) {
|
|
238
|
+
const rows = node.children ?? [];
|
|
239
|
+
if (rows.length === 0) return "";
|
|
240
|
+
const rendered = rows.map(
|
|
241
|
+
(row) => "| " + (row.children ?? []).map((cell) => renderPhrasing(cell.children).trim()).join(" | ") + " |"
|
|
242
|
+
);
|
|
243
|
+
const columnCount = (rows[0]?.children ?? []).length;
|
|
244
|
+
const separator = "| " + Array(columnCount).fill("---").join(" | ") + " |";
|
|
245
|
+
rendered.splice(1, 0, separator);
|
|
246
|
+
return rendered.join("\n");
|
|
247
|
+
}
|
|
248
|
+
const text = renderFlow(tree.children).filter((block) => block.trim() !== "").join("\n\n").trim();
|
|
249
|
+
const result = { text, frontmatter, headings };
|
|
250
|
+
if (title !== void 0) result.title = title;
|
|
251
|
+
if (description !== void 0) result.description = description;
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
function safeResourceUrl(raw) {
|
|
255
|
+
const value = decodeHtmlAttribute(raw).trim();
|
|
256
|
+
if (value === "" || /[\u0000-\u001f\u007f]/.test(value) || /\s/.test(value) || value.includes("\\")) {
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
if (value.startsWith("//")) return void 0;
|
|
260
|
+
if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("#") || value.startsWith("?")) {
|
|
261
|
+
return value;
|
|
262
|
+
}
|
|
263
|
+
const scheme = /^([A-Za-z][A-Za-z0-9+.-]*):/.exec(value)?.[1]?.toLowerCase();
|
|
264
|
+
if (scheme !== void 0) {
|
|
265
|
+
return scheme === "https" || scheme === "http" || scheme === "mailto" ? value : void 0;
|
|
266
|
+
}
|
|
267
|
+
return value.includes(":") ? void 0 : value;
|
|
268
|
+
}
|
|
269
|
+
function renderMarkdownLink(label, rawUrl) {
|
|
270
|
+
const url = safeResourceUrl(rawUrl);
|
|
271
|
+
const text = label.trim();
|
|
272
|
+
if (!url || text === "") return text;
|
|
273
|
+
return `[${escapeMarkdownLabel(text)}](${escapeMarkdownUrl(url)})`;
|
|
274
|
+
}
|
|
275
|
+
function renderMarkdownResource(type, label, rawUrl) {
|
|
276
|
+
const link = renderMarkdownLink(label, rawUrl);
|
|
277
|
+
if (link === "" || link === label.trim()) return label.trim();
|
|
278
|
+
return `${type}: ${link}`;
|
|
279
|
+
}
|
|
280
|
+
function resourceMarkdownForNode(node, childLabel = "") {
|
|
281
|
+
const href = stringAttribute(node.attributes, "href");
|
|
282
|
+
const src = stringAttribute(node.attributes, "src");
|
|
283
|
+
const rawUrl = href ?? src;
|
|
284
|
+
if (!rawUrl) return "";
|
|
285
|
+
const name = (node.name ?? "").toLowerCase();
|
|
286
|
+
const label = childLabel.trim() || stringAttribute(node.attributes, "title") || stringAttribute(node.attributes, "caption") || stringAttribute(node.attributes, "alt") || (name === "video" || name === "iframe" ? "Video" : "Resource");
|
|
287
|
+
if (href) return renderMarkdownLink(label, href);
|
|
288
|
+
const type = name === "video" || name === "iframe" || name === "source" ? "Video" : name === "img" ? "Image" : "Media";
|
|
289
|
+
return renderMarkdownResource(type, label, src ?? "");
|
|
290
|
+
}
|
|
291
|
+
function componentMarkdownForNode(node) {
|
|
292
|
+
if (node.name === "LandingHero" || node.name === "LandingCta") {
|
|
293
|
+
const eyebrow = stringAttribute(node.attributes, "eyebrow");
|
|
294
|
+
const title = stringAttribute(node.attributes, "title");
|
|
295
|
+
const description = stringAttribute(node.attributes, "description");
|
|
296
|
+
const primaryLabel = stringAttribute(node.attributes, "primaryLabel");
|
|
297
|
+
const primaryHref = stringAttribute(node.attributes, "primaryHref");
|
|
298
|
+
const secondaryLabel = stringAttribute(node.attributes, "secondaryLabel");
|
|
299
|
+
const secondaryHref = stringAttribute(node.attributes, "secondaryHref");
|
|
300
|
+
const terminalLabel = stringAttribute(node.attributes, "terminalLabel");
|
|
301
|
+
const previewLabel = stringAttribute(node.attributes, "previewLabel");
|
|
302
|
+
return [
|
|
303
|
+
eyebrow,
|
|
304
|
+
title,
|
|
305
|
+
description,
|
|
306
|
+
primaryLabel && primaryHref ? renderMarkdownLink(primaryLabel, primaryHref) : void 0,
|
|
307
|
+
secondaryLabel && secondaryHref ? renderMarkdownLink(secondaryLabel, secondaryHref) : void 0,
|
|
308
|
+
terminalLabel,
|
|
309
|
+
previewLabel
|
|
310
|
+
].filter(Boolean).join("\n\n");
|
|
311
|
+
}
|
|
312
|
+
if (node.name === "TerminalWindow") {
|
|
313
|
+
return [
|
|
314
|
+
stringAttribute(node.attributes, "title"),
|
|
315
|
+
stringAttribute(node.attributes, "command")
|
|
316
|
+
].filter(Boolean).join("\n\n");
|
|
317
|
+
}
|
|
318
|
+
if (node.name === "AppPreview") {
|
|
319
|
+
return [
|
|
320
|
+
stringAttribute(node.attributes, "url"),
|
|
321
|
+
stringAttribute(node.attributes, "query"),
|
|
322
|
+
stringAttribute(node.attributes, "tool"),
|
|
323
|
+
stringAttribute(node.attributes, "response"),
|
|
324
|
+
stringAttribute(node.attributes, "entities"),
|
|
325
|
+
stringAttribute(node.attributes, "relationships")
|
|
326
|
+
].filter(Boolean).join("\n\n");
|
|
327
|
+
}
|
|
328
|
+
if (node.name === "MemoryStage") {
|
|
329
|
+
return [
|
|
330
|
+
stringAttribute(node.attributes, "badge"),
|
|
331
|
+
stringAttribute(node.attributes, "title"),
|
|
332
|
+
stringAttribute(node.attributes, "description")
|
|
333
|
+
].filter(Boolean).join("\n\n");
|
|
334
|
+
}
|
|
335
|
+
if (node.name === "DomainCard") {
|
|
336
|
+
const name = stringAttribute(node.attributes, "name");
|
|
337
|
+
const emoji = stringAttribute(node.attributes, "emoji");
|
|
338
|
+
const domain = stringAttribute(node.attributes, "domain");
|
|
339
|
+
const entities = stringAttribute(node.attributes, "entities")?.split("|").map((value) => value.trim()).filter(Boolean) ?? [];
|
|
340
|
+
if (!name || !domain) return "";
|
|
341
|
+
return [
|
|
342
|
+
`### ${emoji ? `${emoji} ` : ""}${name}`,
|
|
343
|
+
entities.join(" \xB7 "),
|
|
344
|
+
`\`--domain ${domain}\``,
|
|
345
|
+
entities.map((entity) => `\`:${entity}\``).join(" ") + " `+ base POLE+O types`",
|
|
346
|
+
`\`uvx create-context-graph --domain ${domain}\``
|
|
347
|
+
].filter(Boolean).join("\n\n");
|
|
348
|
+
}
|
|
349
|
+
if (node.name === "FrameworkCard") {
|
|
350
|
+
return [
|
|
351
|
+
stringAttribute(node.attributes, "title"),
|
|
352
|
+
stringAttribute(node.attributes, "support")
|
|
353
|
+
].filter(Boolean).join("\n\n");
|
|
354
|
+
}
|
|
355
|
+
if (node.name === "CommandStep") {
|
|
356
|
+
const title = stringAttribute(node.attributes, "title");
|
|
357
|
+
const command = stringAttribute(node.attributes, "command");
|
|
358
|
+
return [title, command ? `\`$ ${command}\`` : void 0].filter(Boolean).join("\n\n");
|
|
359
|
+
}
|
|
360
|
+
if (node.name === "LandingFooter") {
|
|
361
|
+
return [
|
|
362
|
+
stringAttribute(node.attributes, "name"),
|
|
363
|
+
stringAttribute(node.attributes, "description")
|
|
364
|
+
].filter(Boolean).join("\n\n");
|
|
365
|
+
}
|
|
366
|
+
if (node.name === "Stat") {
|
|
367
|
+
const value = stringOrNumberAttribute(node.attributes, "value");
|
|
368
|
+
const label = stringAttribute(node.attributes, "label");
|
|
369
|
+
const caption = stringAttribute(node.attributes, "caption");
|
|
370
|
+
return [value, label, caption].filter(Boolean).join("\n\n");
|
|
371
|
+
}
|
|
372
|
+
if (node.name === "ColorSwatch") {
|
|
373
|
+
const name = stringAttribute(node.attributes, "name");
|
|
374
|
+
const value = stringAttribute(node.attributes, "value");
|
|
375
|
+
const usage = stringAttribute(node.attributes, "usage");
|
|
376
|
+
if (!name || !value) return "";
|
|
377
|
+
return `${name}: ${value}${usage ? `. ${usage}` : ""}`;
|
|
378
|
+
}
|
|
379
|
+
if (node.name === "TypeSpecimen") {
|
|
380
|
+
const family = stringAttribute(node.attributes, "family");
|
|
381
|
+
const role = stringAttribute(node.attributes, "role");
|
|
382
|
+
const weights = stringAttribute(node.attributes, "weights");
|
|
383
|
+
const sample = stringAttribute(node.attributes, "sample");
|
|
384
|
+
if (!family || !role || !weights || !sample) return "";
|
|
385
|
+
return `${family}: ${role}. Weights: ${weights}. Sample: ${sample}`;
|
|
386
|
+
}
|
|
387
|
+
if (node.name === "UsageExample") {
|
|
388
|
+
const verdict = stringAttribute(node.attributes, "verdict");
|
|
389
|
+
const title = stringAttribute(node.attributes, "title");
|
|
390
|
+
if (!verdict || !title) return "";
|
|
391
|
+
return `${verdict === "dont" ? "Do not" : "Do"}: ${title}`;
|
|
392
|
+
}
|
|
393
|
+
return "";
|
|
394
|
+
}
|
|
395
|
+
function renderHtmlResource(value) {
|
|
396
|
+
const tag = /<(iframe|video|audio|source|img|a)\b([^>]*)>/i.exec(value);
|
|
397
|
+
if (!tag) return "";
|
|
398
|
+
const name = tag[1]?.toLowerCase() ?? "";
|
|
399
|
+
const attributes = tag[2] ?? "";
|
|
400
|
+
const href = htmlAttribute(attributes, "href");
|
|
401
|
+
const src = htmlAttribute(attributes, "src");
|
|
402
|
+
const rawUrl = href ?? src;
|
|
403
|
+
if (!rawUrl) return "";
|
|
404
|
+
const label = htmlAttribute(attributes, "title") || htmlAttribute(attributes, "aria-label") || htmlAttribute(attributes, "alt") || (name === "video" || name === "iframe" ? "Video" : "Resource");
|
|
405
|
+
if (href) return renderMarkdownLink(label, href);
|
|
406
|
+
const type = name === "video" || name === "iframe" || name === "source" ? "Video" : name === "img" ? "Image" : "Media";
|
|
407
|
+
return renderMarkdownResource(type, label, src ?? "");
|
|
408
|
+
}
|
|
409
|
+
function stringAttribute(attributes, name) {
|
|
410
|
+
const attr = attributes?.find(
|
|
411
|
+
(candidate) => candidate.type === "mdxJsxAttribute" && candidate.name === name
|
|
412
|
+
);
|
|
413
|
+
if (!attr) return void 0;
|
|
414
|
+
if (typeof attr.value === "string") return attr.value;
|
|
415
|
+
if (attr.value && typeof attr.value === "object") {
|
|
416
|
+
return stringLiteralValue(attr.value.value ?? "");
|
|
417
|
+
}
|
|
418
|
+
return void 0;
|
|
419
|
+
}
|
|
420
|
+
function stringOrNumberAttribute(attributes, name) {
|
|
421
|
+
const attr = attributes?.find(
|
|
422
|
+
(candidate) => candidate.type === "mdxJsxAttribute" && candidate.name === name
|
|
423
|
+
);
|
|
424
|
+
if (!attr) return void 0;
|
|
425
|
+
if (typeof attr.value === "string") return attr.value;
|
|
426
|
+
if (!attr.value || typeof attr.value !== "object") return void 0;
|
|
427
|
+
const source = attr.value.value?.trim() ?? "";
|
|
428
|
+
return stringLiteralValue(source) ?? (/^-?(?:\d+\.?\d*|\.\d+)$/.test(source) ? source : void 0);
|
|
429
|
+
}
|
|
430
|
+
function htmlAttribute(attributes, name) {
|
|
431
|
+
const match = new RegExp(
|
|
432
|
+
`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`,
|
|
433
|
+
"i"
|
|
434
|
+
).exec(attributes);
|
|
435
|
+
return decodeHtmlAttribute(match?.[1] ?? match?.[2] ?? "") || void 0;
|
|
436
|
+
}
|
|
437
|
+
function decodeHtmlAttribute(value) {
|
|
438
|
+
return value.replace(/&/gi, "&").replace(/"/gi, '"').replace(/'|'/gi, "'").replace(/</gi, "<").replace(/>/gi, ">");
|
|
439
|
+
}
|
|
440
|
+
function escapeMarkdownLabel(value) {
|
|
441
|
+
return value.replace(/([\\\[\]])/g, "\\$1");
|
|
442
|
+
}
|
|
443
|
+
function escapeMarkdownUrl(value) {
|
|
444
|
+
return value.replace(/\\/g, "%5C").replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
445
|
+
}
|
|
446
|
+
function proseAttributeValues(attributes) {
|
|
447
|
+
return namedAttributeValues(attributes, PROSE_ATTRIBUTES);
|
|
448
|
+
}
|
|
449
|
+
function namedAttributeValues(attributes, names) {
|
|
450
|
+
if (!attributes) return [];
|
|
451
|
+
const values = [];
|
|
452
|
+
for (const attr of attributes) {
|
|
453
|
+
if (attr.type !== "mdxJsxAttribute") continue;
|
|
454
|
+
if (!attr.name || !names.has(attr.name)) continue;
|
|
455
|
+
const value = attr.value;
|
|
456
|
+
if (typeof value === "string") {
|
|
457
|
+
if (value.trim()) values.push(value.trim());
|
|
458
|
+
} else if (value && typeof value === "object") {
|
|
459
|
+
const literal = stringLiteralValue(value.value ?? "");
|
|
460
|
+
if (literal && literal.trim()) values.push(literal.trim());
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return values;
|
|
464
|
+
}
|
|
465
|
+
function stringLiteralValue(code) {
|
|
466
|
+
const trimmed = code.trim();
|
|
467
|
+
if (trimmed === "") return void 0;
|
|
468
|
+
if (trimmed.startsWith('"')) {
|
|
469
|
+
try {
|
|
470
|
+
const parsed = JSON.parse(trimmed);
|
|
471
|
+
return typeof parsed === "string" ? parsed : void 0;
|
|
472
|
+
} catch {
|
|
473
|
+
return void 0;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (trimmed.startsWith("'")) {
|
|
477
|
+
const match = /^'((?:[^'\\]|\\.)*)'$/.exec(trimmed);
|
|
478
|
+
if (match && match[1] !== void 0) return match[1].replace(/\\(.)/g, "$1");
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
if (trimmed.startsWith("`")) {
|
|
482
|
+
const match = /^`([^`]*)`$/.exec(trimmed);
|
|
483
|
+
if (match && match[1] !== void 0 && !match[1].includes("${"))
|
|
484
|
+
return match[1];
|
|
485
|
+
return void 0;
|
|
486
|
+
}
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
function longestBacktickRun(value) {
|
|
490
|
+
let longest = 0;
|
|
491
|
+
let current = 0;
|
|
492
|
+
for (const char of value) {
|
|
493
|
+
if (char === "`") {
|
|
494
|
+
current += 1;
|
|
495
|
+
if (current > longest) longest = current;
|
|
496
|
+
} else {
|
|
497
|
+
current = 0;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return longest;
|
|
501
|
+
}
|
|
502
|
+
function parseFrontmatter(raw) {
|
|
503
|
+
try {
|
|
504
|
+
const data = parseYaml(raw);
|
|
505
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
506
|
+
const record = data;
|
|
507
|
+
const out = { frontmatter: record };
|
|
508
|
+
if (typeof record.title === "string") out.title = record.title;
|
|
509
|
+
if (typeof record.description === "string")
|
|
510
|
+
out.description = record.description;
|
|
511
|
+
return out;
|
|
512
|
+
}
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
return { frontmatter: {} };
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/lib/validate.ts
|
|
519
|
+
function messageOf(error) {
|
|
520
|
+
return error instanceof Error ? error.message : String(error);
|
|
521
|
+
}
|
|
522
|
+
async function validateDocs(docsDir) {
|
|
523
|
+
const errors = [];
|
|
524
|
+
const docsJsonPath = join2(docsDir, "docs.json");
|
|
525
|
+
if (!existsSync2(docsJsonPath)) {
|
|
526
|
+
return [`docs.json not found in ${docsDir}.`];
|
|
527
|
+
}
|
|
528
|
+
let config;
|
|
529
|
+
try {
|
|
530
|
+
config = await loadDocsConfig(docsJsonPath);
|
|
531
|
+
} catch (error) {
|
|
532
|
+
return [`docs.json: ${messageOf(error)}`];
|
|
533
|
+
}
|
|
534
|
+
const modelsTomlPath = join2(docsDir, "models.toml");
|
|
535
|
+
if (existsSync2(modelsTomlPath)) {
|
|
536
|
+
try {
|
|
537
|
+
await loadModelsConfig(modelsTomlPath);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
errors.push(`models.toml: ${messageOf(error)}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
for (const entry of collectPageEntries(config)) {
|
|
543
|
+
let resolved;
|
|
544
|
+
try {
|
|
545
|
+
resolved = resolvePageFile(docsDir, entry);
|
|
546
|
+
} catch (error) {
|
|
547
|
+
errors.push(messageOf(error));
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
try {
|
|
551
|
+
const { frontmatter } = stripMdx(await readFile(resolved.file, "utf8"));
|
|
552
|
+
const groups = frontmatter.groups;
|
|
553
|
+
const grouped = Array.isArray(groups) && groups.length > 0;
|
|
554
|
+
if (grouped && frontmatter.pagefind !== false) {
|
|
555
|
+
errors.push(
|
|
556
|
+
`Page "${entry}" restricts access with \`groups\` but is missing \`pagefind: false\`; gated content must stay out of the shared search index.`
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
} catch (error) {
|
|
560
|
+
errors.push(`Page "${entry}": ${messageOf(error)}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
for (const group of navigationGroups(config)) {
|
|
564
|
+
if (!group.openapi) continue;
|
|
565
|
+
const openapiPath = join2(docsDir, group.openapi);
|
|
566
|
+
if (!existsSync2(openapiPath)) {
|
|
567
|
+
errors.push(`OpenAPI file not found: ${group.openapi}`);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
await parseOpenApiFile(openapiPath);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
errors.push(`OpenAPI ${group.openapi}: ${messageOf(error)}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return errors;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export {
|
|
580
|
+
resolvePageFile,
|
|
581
|
+
pageUrl,
|
|
582
|
+
collectPageEntries,
|
|
583
|
+
validateDocs
|
|
584
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/adapter/registry.ts
|
|
2
|
+
var COMMAND_GROUPS = Object.freeze([
|
|
3
|
+
{ name: "manage", summary: "Call one management operation through the dashboard API", renderer: false, load: () => import("./manage-MKH27U3B.js").then((m) => m.registerManage), metadata: () => import("./manage-MKH27U3B.js").then((m) => m.MANAGE_METADATA) },
|
|
4
|
+
{ name: "requests", summary: "Documentation requests and the conversations behind them", renderer: false, load: () => import("./requests-H5MIGBIS.js").then((m) => m.registerRequests), metadata: () => import("./requests-H5MIGBIS.js").then((m) => m.REQUESTS_METADATA) },
|
|
5
|
+
{ name: "suggestions", summary: "Read a site's suggestions and diff the content they carry", renderer: false, load: () => import("./suggestions-4WFQ3APX.js").then((m) => m.registerSuggestions), metadata: () => import("./suggestions-4WFQ3APX.js").then((m) => m.SUGGESTIONS_METADATA) },
|
|
6
|
+
{ name: "schema", summary: "Print this CLI's own command metadata, locally", renderer: false, load: () => import("./schema-XJUEZSIW.js").then((m) => m.registerSchema), metadata: () => import("./schema-XJUEZSIW.js").then((m) => m.SCHEMA_METADATA) },
|
|
7
|
+
{ name: "auth", summary: "Check the management credential in the environment", renderer: false, load: () => import("./auth-FRCFGNYT.js").then((m) => m.registerAuth), metadata: () => import("./auth-FRCFGNYT.js").then((m) => m.AUTH_METADATA) },
|
|
8
|
+
{ name: "sites", summary: "Discover and inspect the sites this credential reaches", renderer: false, load: () => import("./sites-I4WI2MPG.js").then((m) => m.registerSites), metadata: () => import("./sites-I4WI2MPG.js").then((m) => m.SITES_METADATA) },
|
|
9
|
+
{ name: "pages", summary: "Read the published pages of the release readers are seeing", renderer: false, load: () => import("./pages-HIPXRLSY.js").then((m) => m.registerPages), metadata: () => import("./pages-HIPXRLSY.js").then((m) => m.PAGES_METADATA) },
|
|
10
|
+
{ name: "releases", summary: "Read this site's release history and one release by id", renderer: false, load: () => import("./read-ZEVUZNNB.js").then((m) => m.registerReleases), metadata: () => import("./read-ZEVUZNNB.js").then((m) => m.RELEASES_METADATA) },
|
|
11
|
+
{ name: "status", summary: "One bounded briefing on a site, section by section", renderer: false, load: () => import("./status-7R3NOI5H.js").then((m) => m.registerStatus), metadata: () => import("./status-7R3NOI5H.js").then((m) => m.STATUS_METADATA) },
|
|
12
|
+
{ name: "activity", summary: "Read what the platform did, and one job by id", renderer: false, load: () => import("./read-DMSJUEDA.js").then((m) => m.registerActivity), metadata: () => import("./read-DMSJUEDA.js").then((m) => m.ACTIVITY_METADATA) },
|
|
13
|
+
{ name: "init", summary: "Scaffold a docs project", renderer: true, load: () => import("./init-7T5TEPBH.js").then((m) => m.registerInit) },
|
|
14
|
+
{ name: "validate", summary: "Validate docs.json, models.toml, page files, and OpenAPI specs", renderer: true, load: () => import("./validate-VXL4PL42.js").then((m) => m.registerValidate) },
|
|
15
|
+
{ name: "dev", summary: "Start the Astro dev server for a docs directory", renderer: true, load: () => import("./dev-VDSDCBO2.js").then((m) => m.registerDev) },
|
|
16
|
+
{ name: "build", summary: "Build the static site for a docs directory", renderer: true, load: () => import("./build-F5PWGP57.js").then((m) => m.registerBuild) },
|
|
17
|
+
{ name: "deploy", summary: "Upload a docs bundle and follow the release job", renderer: true, load: () => import("./deploy-QU7DCKWU.js").then((m) => m.registerDeploy) },
|
|
18
|
+
{ name: "broken-links", summary: "Scan the built site for broken internal links", renderer: true, load: () => import("./brokenLinks-TTOBP4P7.js").then((m) => m.registerBrokenLinks) },
|
|
19
|
+
{ name: "openapi-check", summary: "Parse OpenAPI specs and print an operation table", renderer: true, load: () => import("./openapiCheck-KGBQJTIQ.js").then((m) => m.registerOpenapiCheck) }
|
|
20
|
+
]);
|
|
21
|
+
var COMMAND_GROUP_NAMES = Object.freeze(COMMAND_GROUPS.map((group) => group.name));
|
|
22
|
+
function findCommandGroup(name) {
|
|
23
|
+
return COMMAND_GROUPS.find((group) => group.name === name);
|
|
24
|
+
}
|
|
25
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set(["--site", "--api", "--timeout"]);
|
|
26
|
+
function selectCommandGroup(argv) {
|
|
27
|
+
for (let index = 2; index < argv.length; index += 1) {
|
|
28
|
+
const token = argv[index];
|
|
29
|
+
if (token === "--") break;
|
|
30
|
+
if (VALUE_FLAGS.has(token)) {
|
|
31
|
+
index += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (token.startsWith("-")) continue;
|
|
35
|
+
const group = findCommandGroup(token);
|
|
36
|
+
if (group !== void 0) return group;
|
|
37
|
+
}
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
COMMAND_GROUPS,
|
|
43
|
+
COMMAND_GROUP_NAMES,
|
|
44
|
+
findCommandGroup,
|
|
45
|
+
selectCommandGroup
|
|
46
|
+
};
|