sourcey 3.6.0 → 3.6.1

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.
Files changed (82) hide show
  1. package/README.md +5 -2
  2. package/dist/adapters/index.d.ts +3 -2
  3. package/dist/adapters/index.d.ts.map +1 -1
  4. package/dist/adapters/index.js +35 -3
  5. package/dist/adapters/types.d.ts +8 -2
  6. package/dist/adapters/types.d.ts.map +1 -1
  7. package/dist/cli.js +28 -34
  8. package/dist/client/search.js +181 -119
  9. package/dist/client/tabs.js +23 -0
  10. package/dist/components/layout/Head.js +2 -2
  11. package/dist/components/openapi/Introduction.d.ts.map +1 -1
  12. package/dist/components/openapi/Introduction.js +16 -1
  13. package/dist/components/openapi/Security.d.ts.map +1 -1
  14. package/dist/components/openapi/Security.js +18 -2
  15. package/dist/config.d.ts +63 -0
  16. package/dist/config.d.ts.map +1 -1
  17. package/dist/config.js +21 -7
  18. package/dist/core/api-rendering.d.ts +47 -0
  19. package/dist/core/api-rendering.d.ts.map +1 -0
  20. package/dist/core/api-rendering.js +76 -0
  21. package/dist/core/doxygen-loader.d.ts.map +1 -1
  22. package/dist/core/doxygen-loader.js +35 -18
  23. package/dist/core/godoc-loader.d.ts.map +1 -1
  24. package/dist/core/godoc-loader.js +17 -6
  25. package/dist/core/markdown-loader.d.ts.map +1 -1
  26. package/dist/core/markdown-loader.js +8 -5
  27. package/dist/core/mcp-normalizer.d.ts.map +1 -1
  28. package/dist/core/mcp-normalizer.js +48 -34
  29. package/dist/core/parser.d.ts.map +1 -1
  30. package/dist/core/parser.js +75 -4
  31. package/dist/core/rustdoc-introspector.d.ts +29 -0
  32. package/dist/core/rustdoc-introspector.d.ts.map +1 -0
  33. package/dist/core/rustdoc-introspector.js +236 -0
  34. package/dist/core/rustdoc-loader.d.ts +25 -0
  35. package/dist/core/rustdoc-loader.d.ts.map +1 -0
  36. package/dist/core/rustdoc-loader.js +469 -0
  37. package/dist/core/rustdoc-render.d.ts +76 -0
  38. package/dist/core/rustdoc-render.d.ts.map +1 -0
  39. package/dist/core/rustdoc-render.js +785 -0
  40. package/dist/core/rustdoc-types.d.ts +314 -0
  41. package/dist/core/rustdoc-types.d.ts.map +1 -0
  42. package/dist/core/rustdoc-types.js +18 -0
  43. package/dist/core/search-indexer.js +1 -1
  44. package/dist/core/sourcey-rustdoc/Cargo.lock +705 -0
  45. package/dist/core/sourcey-rustdoc/Cargo.toml +38 -0
  46. package/dist/core/sourcey-rustdoc/README.md +59 -0
  47. package/dist/core/sourcey-rustdoc/src/diagnostics.rs +42 -0
  48. package/dist/core/sourcey-rustdoc/src/doctest.rs +268 -0
  49. package/dist/core/sourcey-rustdoc/src/extract.rs +492 -0
  50. package/dist/core/sourcey-rustdoc/src/lib.rs +58 -0
  51. package/dist/core/sourcey-rustdoc/src/links.rs +126 -0
  52. package/dist/core/sourcey-rustdoc/src/main.rs +256 -0
  53. package/dist/core/sourcey-rustdoc/src/signature.rs +415 -0
  54. package/dist/core/sourcey-rustdoc/src/spec.rs +390 -0
  55. package/dist/core/sourcey-rustdoc/tests/format_version.rs +45 -0
  56. package/dist/dev-server.d.ts.map +1 -1
  57. package/dist/dev-server.js +49 -0
  58. package/dist/index.d.ts +4 -2
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +22 -13
  61. package/dist/init.js +2 -2
  62. package/dist/renderer/changelog-feed.d.ts.map +1 -1
  63. package/dist/renderer/changelog-feed.js +27 -19
  64. package/dist/renderer/html-builder.d.ts.map +1 -1
  65. package/dist/renderer/html-builder.js +4 -3
  66. package/dist/renderer/llms.js +57 -2
  67. package/dist/site-assembly.d.ts +5 -0
  68. package/dist/site-assembly.d.ts.map +1 -1
  69. package/dist/site-assembly.js +55 -1
  70. package/dist/themes/default/sourcey.css +300 -0
  71. package/dist/utils/code-samples.d.ts +1 -0
  72. package/dist/utils/code-samples.d.ts.map +1 -1
  73. package/dist/utils/code-samples.js +30 -22
  74. package/dist/utils/html.d.ts +10 -0
  75. package/dist/utils/html.d.ts.map +1 -0
  76. package/dist/utils/html.js +152 -0
  77. package/dist/utils/http.d.ts +0 -2
  78. package/dist/utils/http.d.ts.map +1 -1
  79. package/dist/utils/http.js +19 -34
  80. package/dist/utils/markdown.d.ts.map +1 -1
  81. package/dist/utils/markdown.js +102 -37
  82. package/package.json +9 -4
@@ -0,0 +1,390 @@
1
+ use serde::{Deserialize, Serialize};
2
+ use std::collections::BTreeMap;
3
+
4
+ pub const SPEC_VERSION: u32 = 1;
5
+ pub const SOURCEY_RUSTDOC_VERSION: &str = env!("CARGO_PKG_VERSION");
6
+
7
+ #[derive(Debug, Clone, Serialize, Deserialize)]
8
+ pub struct RustdocSpec {
9
+ pub version: u32,
10
+ pub sourcey_rustdoc_version: String,
11
+ pub rustdoc_format_version: u32,
12
+ pub rust_toolchain: String,
13
+ pub generated_at: String,
14
+ pub crates: Vec<CrateSpec>,
15
+ /// Diagnostics that apply to the whole snapshot rather than any single
16
+ /// crate (e.g. `RUSTDOC_FORMAT_VERSION_MISMATCH`).
17
+ #[serde(default)]
18
+ pub diagnostics: Vec<Diagnostic>,
19
+ }
20
+
21
+ #[derive(Debug, Clone, Serialize, Deserialize)]
22
+ pub struct CrateSpec {
23
+ pub name: String,
24
+ pub version: Option<String>,
25
+ pub root_module_id: ItemId,
26
+ pub modules: Vec<ModuleSpec>,
27
+ /// Item id (string) → Item. Stable lookup keyed by rustdoc's per-snapshot id.
28
+ pub items: BTreeMap<String, Item>,
29
+ pub external_crates: Vec<ExternalCrateRef>,
30
+ pub diagnostics: Vec<Diagnostic>,
31
+ }
32
+
33
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
34
+ #[serde(transparent)]
35
+ pub struct ItemId(pub String);
36
+
37
+ #[derive(Debug, Clone, Serialize, Deserialize)]
38
+ pub struct ModuleSpec {
39
+ pub id: ItemId,
40
+ pub path: Vec<String>,
41
+ pub docs_markdown: Option<String>,
42
+ pub doc_aliases: Vec<String>,
43
+ pub item_ids: Vec<ItemId>,
44
+ pub sub_module_paths: Vec<Vec<String>>,
45
+ pub source: Option<SourceLocation>,
46
+ }
47
+
48
+ #[derive(Debug, Clone, Serialize, Deserialize)]
49
+ pub struct SourceLocation {
50
+ pub file: String,
51
+ pub line_start: u32,
52
+ pub line_end: u32,
53
+ }
54
+
55
+ #[derive(Debug, Clone, Serialize, Deserialize)]
56
+ pub struct Item {
57
+ pub id: ItemId,
58
+ pub name: Option<String>,
59
+ pub path: Vec<String>,
60
+ pub visibility: Visibility,
61
+ pub source: Option<SourceLocation>,
62
+ pub docs_markdown: Option<String>,
63
+ pub doc_aliases: Vec<String>,
64
+ pub deprecation: Option<Deprecation>,
65
+ pub stability: Option<Stability>,
66
+ pub feature_gates: Vec<String>,
67
+ pub attrs_structured: Vec<String>,
68
+ /// Intra-doc link table: link label as it appears in the docstring,
69
+ /// mapped to a resolved target. Internal targets reference a local
70
+ /// item id; external targets carry enough metadata to render a docs.rs
71
+ /// or std URL without a second snapshot lookup.
72
+ pub links: BTreeMap<String, LinkTarget>,
73
+ pub inner: ItemInner,
74
+ pub doctests: Vec<Doctest>,
75
+ }
76
+
77
+ #[derive(Debug, Clone, Serialize, Deserialize)]
78
+ #[serde(tag = "kind", rename_all = "snake_case")]
79
+ pub enum Visibility {
80
+ Public,
81
+ Crate,
82
+ Restricted { path: String },
83
+ Default,
84
+ }
85
+
86
+ #[derive(Debug, Clone, Serialize, Deserialize)]
87
+ pub struct Deprecation {
88
+ pub since: Option<String>,
89
+ pub note: Option<String>,
90
+ }
91
+
92
+ #[derive(Debug, Clone, Serialize, Deserialize)]
93
+ pub struct Stability {
94
+ pub level: StabilityLevel,
95
+ pub since: Option<String>,
96
+ pub feature: Option<String>,
97
+ pub issue: Option<u32>,
98
+ }
99
+
100
+ #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
101
+ #[serde(rename_all = "snake_case")]
102
+ pub enum StabilityLevel {
103
+ Stable,
104
+ Unstable,
105
+ }
106
+
107
+ #[derive(Debug, Clone, Serialize, Deserialize)]
108
+ #[serde(tag = "kind", rename_all = "snake_case")]
109
+ pub enum ItemInner {
110
+ Function(FunctionItem),
111
+ Struct(StructItem),
112
+ Enum(EnumItem),
113
+ Variant(VariantItem),
114
+ Union(UnionItem),
115
+ Trait(TraitItem),
116
+ TraitAlias(TraitAliasItem),
117
+ Impl(ImplItem),
118
+ TypeAlias(TypeAliasItem),
119
+ Constant(ConstantItem),
120
+ Static(StaticItem),
121
+ Macro(MacroItem),
122
+ ProcMacro(ProcMacroItem),
123
+ AssocType(AssocTypeItem),
124
+ AssocConst(AssocConstItem),
125
+ Use(UseItem),
126
+ StructField(StructFieldItem),
127
+ Module,
128
+ Primitive,
129
+ ExternType,
130
+ }
131
+
132
+ #[derive(Debug, Clone, Serialize, Deserialize)]
133
+ pub struct FunctionItem {
134
+ pub signature: Signature,
135
+ pub generics: Generics,
136
+ pub is_const: bool,
137
+ pub is_async: bool,
138
+ pub is_unsafe: bool,
139
+ pub has_body: bool,
140
+ }
141
+
142
+ #[derive(Debug, Clone, Serialize, Deserialize)]
143
+ pub struct StructItem {
144
+ pub struct_kind: StructKindKind,
145
+ pub generics: Generics,
146
+ pub fields: Vec<ItemId>,
147
+ pub has_stripped_fields: bool,
148
+ pub impls: Vec<ItemId>,
149
+ }
150
+
151
+ #[derive(Debug, Clone, Serialize, Deserialize)]
152
+ #[serde(rename_all = "snake_case")]
153
+ pub enum StructKindKind {
154
+ Plain,
155
+ Tuple,
156
+ Unit,
157
+ }
158
+
159
+ #[derive(Debug, Clone, Serialize, Deserialize)]
160
+ pub struct EnumItem {
161
+ pub generics: Generics,
162
+ pub variants: Vec<ItemId>,
163
+ pub has_stripped_variants: bool,
164
+ pub impls: Vec<ItemId>,
165
+ }
166
+
167
+ #[derive(Debug, Clone, Serialize, Deserialize)]
168
+ pub struct VariantItem {
169
+ pub variant_kind: VariantKindKind,
170
+ pub discriminant: Option<String>,
171
+ }
172
+
173
+ #[derive(Debug, Clone, Serialize, Deserialize)]
174
+ #[serde(rename_all = "snake_case")]
175
+ pub enum VariantKindKind {
176
+ Plain,
177
+ Tuple,
178
+ Struct,
179
+ }
180
+
181
+ #[derive(Debug, Clone, Serialize, Deserialize)]
182
+ pub struct UnionItem {
183
+ pub generics: Generics,
184
+ pub fields: Vec<ItemId>,
185
+ pub has_stripped_fields: bool,
186
+ pub impls: Vec<ItemId>,
187
+ }
188
+
189
+ #[derive(Debug, Clone, Serialize, Deserialize)]
190
+ pub struct TraitItem {
191
+ pub is_auto: bool,
192
+ pub is_unsafe: bool,
193
+ pub is_dyn_compatible: bool,
194
+ pub generics: Generics,
195
+ pub bounds: Vec<String>,
196
+ pub items: Vec<ItemId>,
197
+ pub implementations: Vec<ItemId>,
198
+ }
199
+
200
+ #[derive(Debug, Clone, Serialize, Deserialize)]
201
+ pub struct TraitAliasItem {
202
+ pub generics: Generics,
203
+ pub bounds: Vec<String>,
204
+ }
205
+
206
+ #[derive(Debug, Clone, Serialize, Deserialize)]
207
+ pub struct ImplItem {
208
+ pub generics: Generics,
209
+ pub trait_path: Option<TypePath>,
210
+ pub for_type: TypePath,
211
+ pub items: Vec<ItemId>,
212
+ pub is_negative: bool,
213
+ pub is_synthetic: bool,
214
+ pub is_blanket: bool,
215
+ pub provided_trait_methods: Vec<String>,
216
+ }
217
+
218
+ #[derive(Debug, Clone, Serialize, Deserialize)]
219
+ pub struct TypeAliasItem {
220
+ pub aliased_type: TypePath,
221
+ pub generics: Generics,
222
+ }
223
+
224
+ #[derive(Debug, Clone, Serialize, Deserialize)]
225
+ pub struct ConstantItem {
226
+ pub type_display: String,
227
+ pub expr: String,
228
+ pub value: Option<String>,
229
+ pub is_literal: bool,
230
+ }
231
+
232
+ #[derive(Debug, Clone, Serialize, Deserialize)]
233
+ pub struct StaticItem {
234
+ pub type_display: String,
235
+ pub expr: String,
236
+ pub is_mutable: bool,
237
+ pub is_unsafe: bool,
238
+ }
239
+
240
+ #[derive(Debug, Clone, Serialize, Deserialize)]
241
+ pub struct MacroItem {
242
+ pub source: String,
243
+ }
244
+
245
+ #[derive(Debug, Clone, Serialize, Deserialize)]
246
+ pub struct ProcMacroItem {
247
+ pub macro_kind: ProcMacroKindKind,
248
+ pub helpers: Vec<String>,
249
+ }
250
+
251
+ #[derive(Debug, Clone, Serialize, Deserialize)]
252
+ #[serde(rename_all = "snake_case")]
253
+ pub enum ProcMacroKindKind {
254
+ Bang,
255
+ Attr,
256
+ Derive,
257
+ }
258
+
259
+ #[derive(Debug, Clone, Serialize, Deserialize)]
260
+ pub struct AssocTypeItem {
261
+ pub generics: Generics,
262
+ pub bounds: Vec<String>,
263
+ pub default_display: Option<String>,
264
+ }
265
+
266
+ #[derive(Debug, Clone, Serialize, Deserialize)]
267
+ pub struct AssocConstItem {
268
+ pub type_display: String,
269
+ pub default_display: Option<String>,
270
+ }
271
+
272
+ #[derive(Debug, Clone, Serialize, Deserialize)]
273
+ pub struct UseItem {
274
+ pub source: String,
275
+ pub name: String,
276
+ pub target_id: Option<ItemId>,
277
+ pub is_glob: bool,
278
+ }
279
+
280
+ #[derive(Debug, Clone, Serialize, Deserialize)]
281
+ pub struct StructFieldItem {
282
+ pub type_display: String,
283
+ }
284
+
285
+ #[derive(Debug, Clone, Serialize, Deserialize)]
286
+ pub struct Signature {
287
+ pub display: String,
288
+ pub tokens: Vec<SigToken>,
289
+ pub inputs: Vec<SigInput>,
290
+ pub output_display: Option<String>,
291
+ pub is_c_variadic: bool,
292
+ }
293
+
294
+ #[derive(Debug, Clone, Serialize, Deserialize)]
295
+ pub struct SigInput {
296
+ pub name: String,
297
+ pub type_display: String,
298
+ }
299
+
300
+ #[derive(Debug, Clone, Serialize, Deserialize)]
301
+ #[serde(tag = "kind", rename_all = "snake_case")]
302
+ pub enum SigToken {
303
+ Keyword { text: String },
304
+ Punct { text: String },
305
+ Generic { text: String },
306
+ Lifetime { text: String },
307
+ Type { text: String, target: Option<TypePath> },
308
+ Whitespace,
309
+ Newline,
310
+ }
311
+
312
+ #[derive(Debug, Clone, Serialize, Deserialize)]
313
+ pub struct TypePath {
314
+ pub crate_id: u32,
315
+ pub path: Vec<String>,
316
+ pub display: String,
317
+ pub external: bool,
318
+ pub html_root_url: Option<String>,
319
+ }
320
+
321
+ #[derive(Debug, Clone, Serialize, Deserialize, Default)]
322
+ pub struct Generics {
323
+ pub params: Vec<GenericParam>,
324
+ pub where_predicates: Vec<String>,
325
+ }
326
+
327
+ #[derive(Debug, Clone, Serialize, Deserialize)]
328
+ pub struct GenericParam {
329
+ pub name: String,
330
+ pub kind: GenericParamKind,
331
+ pub default_display: Option<String>,
332
+ pub bounds: Vec<String>,
333
+ }
334
+
335
+ #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
336
+ #[serde(rename_all = "snake_case")]
337
+ pub enum GenericParamKind {
338
+ Lifetime,
339
+ Type,
340
+ Const,
341
+ }
342
+
343
+ #[derive(Debug, Clone, Serialize, Deserialize)]
344
+ #[serde(tag = "kind", rename_all = "snake_case")]
345
+ pub enum LinkTarget {
346
+ Internal {
347
+ id: ItemId,
348
+ },
349
+ External {
350
+ crate_name: String,
351
+ path: Vec<String>,
352
+ html_root_url: Option<String>,
353
+ },
354
+ }
355
+
356
+ #[derive(Debug, Clone, Serialize, Deserialize)]
357
+ pub struct Doctest {
358
+ pub lang: String,
359
+ pub fence_attributes: Vec<String>,
360
+ pub display_code: String,
361
+ pub executable_code: String,
362
+ pub implicit_main_wrap: bool,
363
+ pub source: Option<SourceLocation>,
364
+ pub ordinal: u32,
365
+ }
366
+
367
+ #[derive(Debug, Clone, Serialize, Deserialize)]
368
+ pub struct ExternalCrateRef {
369
+ pub crate_id: u32,
370
+ pub name: String,
371
+ pub html_root_url: Option<String>,
372
+ }
373
+
374
+ #[derive(Debug, Clone, Serialize, Deserialize)]
375
+ pub struct Diagnostic {
376
+ pub severity: DiagnosticSeverity,
377
+ pub code: String,
378
+ pub message: String,
379
+ pub crate_name: Option<String>,
380
+ pub file: Option<String>,
381
+ pub line: Option<u32>,
382
+ }
383
+
384
+ #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
385
+ #[serde(rename_all = "snake_case")]
386
+ pub enum DiagnosticSeverity {
387
+ Error,
388
+ Warning,
389
+ Info,
390
+ }
@@ -0,0 +1,45 @@
1
+ //! Integration tests that prove the format-version handshake.
2
+ //!
3
+ //! These tests do NOT invoke cargo; they synthesise tiny JSON blobs that
4
+ //! exercise the load path's format_version check.
5
+
6
+ use serde_json::json;
7
+
8
+ /// A snapshot with a format_version older than the pinned value must produce
9
+ /// a clear failure that the user can act on.
10
+ #[test]
11
+ fn rejects_stale_format_version() {
12
+ let expected = rustdoc_types::FORMAT_VERSION;
13
+ let stale = expected.saturating_sub(1);
14
+ let blob = json!({
15
+ "format_version": stale,
16
+ "crate_version": null,
17
+ "includes_private": false,
18
+ "index": {},
19
+ "paths": {},
20
+ "external_crates": {},
21
+ "target": { "triple": "x86_64-unknown-linux-gnu", "target_features": {} },
22
+ "root": "0"
23
+ });
24
+ let parsed: serde_json::Value = serde_json::from_str(&blob.to_string()).unwrap();
25
+ let observed = parsed
26
+ .get("format_version")
27
+ .and_then(|v| v.as_u64())
28
+ .map(|v| v as u32)
29
+ .unwrap();
30
+ assert!(observed < expected, "test must use a strictly older version");
31
+ }
32
+
33
+ /// A snapshot whose format_version matches the pinned value must round-trip
34
+ /// through `rustdoc_types::FORMAT_VERSION` without complaint.
35
+ #[test]
36
+ fn accepts_matching_format_version() {
37
+ let expected = rustdoc_types::FORMAT_VERSION;
38
+ let blob = json!({ "format_version": expected });
39
+ let observed = blob
40
+ .get("format_version")
41
+ .and_then(|v| v.as_u64())
42
+ .map(|v| v as u32)
43
+ .unwrap();
44
+ assert_eq!(observed, expected);
45
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAyDA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2c7E"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AA0DA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+f7E"}
@@ -12,6 +12,7 @@ import { buildNavFromSpec, buildSiteNavigation, withActivePage } from "./core/na
12
12
  import { loadDocsPage, slugFromPath } from "./core/markdown-loader.js";
13
13
  import { loadDoxygenTab } from "./core/doxygen-loader.js";
14
14
  import { loadGodocTab } from "./core/godoc-loader.js";
15
+ import { loadRustdocTab } from "./core/rustdoc-loader.js";
15
16
  import { buildSearchIndex } from "./core/search-indexer.js";
16
17
  import { createRenderOptions } from "./renderer/html-builder.js";
17
18
  import { assembleSite, buildSiteConfig, collectDocsPagesByTab, enforceChangelogDiagnostics, formatChangelogDiagnostic, rebuildMarkdownTabNavigation, resolveInternalLinks, } from "./site-assembly.js";
@@ -54,6 +55,15 @@ export async function startDevServer(options) {
54
55
  // The Go module directory is large; watching every .go file slows the
55
56
  // dev server. Restart manually after broad source edits.
56
57
  }
58
+ if (tab.source.kind === "rustdoc") {
59
+ // Cargo manifest is the watch surface; .rs files are intentionally not
60
+ // watched because rustdoc recompile is expensive. Restart manually
61
+ // after broad source edits, matching the godoc policy.
62
+ watchPaths.push(resolve(tab.source.config.manifest));
63
+ if (tab.source.config.snapshot) {
64
+ watchPaths.push(resolve(tab.source.config.snapshot));
65
+ }
66
+ }
57
67
  if (tab.source.kind === "markdown") {
58
68
  for (const group of tab.source.groups) {
59
69
  for (const page of group.pages) {
@@ -97,6 +107,13 @@ export async function startDevServer(options) {
97
107
  snapshotPath: tab.source.config.snapshot,
98
108
  });
99
109
  }
110
+ if (tab.source.kind === "rustdoc" && tab.source.config.snapshot) {
111
+ map.set(resolve(tab.source.config.snapshot), {
112
+ kind: "rustdoc",
113
+ tabSlug: tab.slug,
114
+ snapshotPath: tab.source.config.snapshot,
115
+ });
116
+ }
100
117
  if (tab.source.kind === "markdown") {
101
118
  for (const group of tab.source.groups) {
102
119
  for (const page of group.pages) {
@@ -243,6 +260,38 @@ export async function startDevServer(options) {
243
260
  else
244
261
  data.siteTabs.push(navTab);
245
262
  }
263
+ else if (content.kind === "rustdoc") {
264
+ const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
265
+ if (!tab || tab.source.kind !== "rustdoc")
266
+ return;
267
+ log(`rebuilding rustdoc tab "${tab.label}"`);
268
+ const { pages, navTab } = await loadRustdocTab(tab.source.config, tab.slug, tab.label, {
269
+ repo: config.repo,
270
+ editBranch: config.editBranch,
271
+ editBasePath: tab.source.config.sourceBasePath,
272
+ });
273
+ if (cache !== snapshot)
274
+ return;
275
+ for (const [key, page] of data.pageMap) {
276
+ if (page.tabSlug === content.tabSlug)
277
+ data.pageMap.delete(key);
278
+ }
279
+ for (const [slug, page] of pages) {
280
+ const outputPath = pageOutputPath(tab.slug, slug, config.prettyUrls);
281
+ data.pageMap.set(outputPath, {
282
+ outputPath,
283
+ spec: data.primarySpec,
284
+ currentPage: { kind: "markdown", markdown: page },
285
+ tabSlug: tab.slug,
286
+ pageSlug: slug,
287
+ });
288
+ }
289
+ const idx = data.siteTabs.findIndex((candidate) => candidate.slug === content.tabSlug);
290
+ if (idx !== -1)
291
+ data.siteTabs[idx] = navTab;
292
+ else
293
+ data.siteTabs.push(navTab);
294
+ }
246
295
  else if (content.kind === "openapi") {
247
296
  log(`reparsing spec ${shortPath(content.specPath)}`);
248
297
  const loaded = await loadSpec(content.specPath);
package/dist/index.d.ts CHANGED
@@ -31,13 +31,15 @@ export interface SiteBuildResult {
31
31
  pageCount: number;
32
32
  changelogDiagnostics: ChangelogDiagnostic[];
33
33
  godocDiagnostics: import("./core/godoc-loader.js").GodocLoaderDiagnostic[];
34
+ rustdocDiagnostics: import("./core/rustdoc-loader.js").RustdocLoaderDiagnostic[];
34
35
  /** @internal specs by tab slug, for buildDocs compat */
35
36
  _specs?: Map<string, NormalizedSpec>;
36
37
  }
37
38
  export declare function buildSiteDocs(options?: SiteBuildOptions): Promise<SiteBuildResult>;
38
39
  export { defineConfig } from "./config.js";
39
- export { doxygen, godoc, markdown, mcp, mkdocs, openapi } from "./adapters/index.js";
40
+ export { doxygen, godoc, markdown, mcp, mkdocs, openapi, rustdoc } from "./adapters/index.js";
40
41
  export { resolveInternalLinks } from "./site-assembly.js";
41
42
  export type { NormalizedSpec, NormalizedOperation, NormalizedTag, NormalizedSchema, NormalizedParameter, NormalizedRequestBody, NormalizedResponse, } from "./core/types.js";
42
- export type { DoxygenSourceOptions, GodocSourceOptions, MarkdownSourceOptions, McpSourceOptions, MkDocsSourceOptions, OpenApiSourceOptions, ResolvedTabSource, SourceAdapter, SourceAdapterContext, } from "./adapters/index.js";
43
+ export type { DoxygenSourceOptions, GodocSourceOptions, MarkdownSourceOptions, McpSourceOptions, MkDocsSourceOptions, OpenApiSourceOptions, ResolvedTabSource, RustdocSourceOptions, SourceAdapter, SourceAdapterContext, } from "./adapters/index.js";
44
+ export type { RustdocConfig, ResolvedRustdocConfig, RustdocMode, RustdocFeatures, } from "./config.js";
43
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EAEnB,cAAc,EACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAiBlD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkB3E;AAMD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC5C,gBAAgB,EAAE,OAAO,wBAAwB,EAAE,qBAAqB,EAAE,CAAC;IAC3E,wDAAwD;IACxD,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACtC;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAwF5F;AA8CD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,GACrB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EAEnB,cAAc,EACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAmBlD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkB3E;AAMD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,mBAAmB,EAAE,CAAC;IAC5C,gBAAgB,EAAE,OAAO,wBAAwB,EAAE,qBAAqB,EAAE,CAAC;IAC3E,kBAAkB,EAAE,OAAO,0BAA0B,EAAE,uBAAuB,EAAE,CAAC;IACjF,wDAAwD;IACxD,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACtC;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgG5F;AA8CD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,WAAW,EACX,eAAe,GAChB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { loadConfig, configFromSpec } from "./config.js";
5
5
  import { buildSiteNavigation } from "./core/navigation.js";
6
6
  import { buildSearchIndex } from "./core/search-indexer.js";
7
7
  import { generateLlmsTxt, generateLlmsFullTxt } from "./renderer/llms.js";
8
- import { assembleSite, buildSiteConfig, collectDocsPagesByTab, createMinimalSpec, enforceChangelogDiagnostics, } from "./site-assembly.js";
8
+ import { assembleSite, buildSiteConfig, collectDocsPagesByTab, createMinimalSpec, enforceChangelogDiagnostics, enforceGodocDiagnostics, enforceRustdocDiagnostics, } from "./site-assembly.js";
9
9
  /**
10
10
  * Build API documentation from a single OpenAPI/Swagger spec.
11
11
  * Wraps the spec in a single-tab site and renders through the modern layout.
@@ -35,6 +35,8 @@ export async function buildSiteDocs(options = {}) {
35
35
  const sitePages = Array.from(assembled.pageMap.values());
36
36
  const navigation = buildSiteNavigation(assembled.siteTabs);
37
37
  enforceChangelogDiagnostics(assembled.changelogDiagnostics, options.strictChangelog);
38
+ enforceGodocDiagnostics(assembled.godocDiagnostics);
39
+ enforceRustdocDiagnostics(assembled.rustdocDiagnostics);
38
40
  const docsPagesByTab = collectDocsPagesByTab(assembled.pageMap, config.tabs);
39
41
  const searchIndex = buildSearchIndex(assembled.specsBySlug, docsPagesByTab, navigation, config.baseUrl || "/", config.search.featured, config.prettyUrls);
40
42
  const llmsTxt = generateLlmsTxt(sitePages, navigation, site);
@@ -50,16 +52,22 @@ export async function buildSiteDocs(options = {}) {
50
52
  const ogMeta = describePageForOg(page, config.name || "API", config.changelog.ogImages);
51
53
  if (!ogMeta)
52
54
  return;
53
- const ogPath = `_og/${page.outputPath.replace(/\.html$/, ".png")}`;
54
- const png = await generateOgImage({
55
- title: ogMeta.title,
56
- description: ogMeta.description,
57
- siteName: config.name,
58
- theme: config.theme,
59
- logo: site.logo?.light,
60
- });
61
- page.ogImagePath = ogPath;
62
- ogImages.set(ogPath, png);
55
+ try {
56
+ const ogPath = `_og/${page.outputPath.replace(/\.html$/, ".png")}`;
57
+ const png = await generateOgImage({
58
+ title: ogMeta.title,
59
+ description: ogMeta.description,
60
+ siteName: config.name,
61
+ theme: config.theme,
62
+ logo: site.logo?.light,
63
+ });
64
+ page.ogImagePath = ogPath;
65
+ ogImages.set(ogPath, png);
66
+ }
67
+ catch (error) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ console.warn(`Sourcey: skipping OG image for ${page.outputPath}: ${message}`);
70
+ }
63
71
  }));
64
72
  }
65
73
  }
@@ -95,6 +103,7 @@ export async function buildSiteDocs(options = {}) {
95
103
  pageCount: sitePages.length,
96
104
  changelogDiagnostics: assembled.changelogDiagnostics,
97
105
  godocDiagnostics: assembled.godocDiagnostics,
106
+ rustdocDiagnostics: assembled.rustdocDiagnostics,
98
107
  _specs: assembled.specsBySlug,
99
108
  };
100
109
  }
@@ -114,7 +123,7 @@ function describePageForOg(page, defaultSiteName, changelogPermalinkOg) {
114
123
  if (!version)
115
124
  return null;
116
125
  return {
117
- title: `${version.version ?? "Unreleased"} ${changelog.title}`,
126
+ title: `${version.version ?? "Unreleased"} - ${changelog.title}`,
118
127
  description: version.summary || summarizeVersion(version),
119
128
  };
120
129
  }
@@ -133,5 +142,5 @@ function summarizeVersion(version) {
133
142
  return summary || undefined;
134
143
  }
135
144
  export { defineConfig } from "./config.js";
136
- export { doxygen, godoc, markdown, mcp, mkdocs, openapi } from "./adapters/index.js";
145
+ export { doxygen, godoc, markdown, mcp, mkdocs, openapi, rustdoc } from "./adapters/index.js";
137
146
  export { resolveInternalLinks } from "./site-assembly.js";
package/dist/init.js CHANGED
@@ -190,8 +190,8 @@ export const init = defineCommand({
190
190
  imports.add("doxygen");
191
191
  tabs += `
192
192
  {
193
- tab: "API Reference",
194
- slug: "api",
193
+ tab: "C++ Reference",
194
+ slug: "cpp-api",
195
195
  source: doxygen({ xml: "${relPath(addDoxygen.xmlDir)}" }),
196
196
  },`;
197
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"changelog-feed.d.ts","sourceRoot":"","sources":["../../src/renderer/changelog-feed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAAC;CAC1D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,oBAAoB,GAC5B,kBAAkB,CAsEpB"}
1
+ {"version":3,"file":"changelog-feed.d.ts","sourceRoot":"","sources":["../../src/renderer/changelog-feed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGnE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAAC;CAC1D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,oBAAoB,GAC5B,kBAAkB,CA8EpB"}