sourcey 3.5.10 → 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 (100) hide show
  1. package/README.md +24 -97
  2. package/dist/adapters/index.d.ts +12 -0
  3. package/dist/adapters/index.d.ts.map +1 -0
  4. package/dist/adapters/index.js +130 -0
  5. package/dist/adapters/mkdocs.d.ts +5 -0
  6. package/dist/adapters/mkdocs.d.ts.map +1 -0
  7. package/dist/adapters/mkdocs.js +367 -0
  8. package/dist/adapters/shared.d.ts +12 -0
  9. package/dist/adapters/shared.d.ts.map +1 -0
  10. package/dist/adapters/shared.js +134 -0
  11. package/dist/adapters/types.d.ts +74 -0
  12. package/dist/adapters/types.d.ts.map +1 -0
  13. package/dist/adapters/types.js +1 -0
  14. package/dist/cli.js +28 -34
  15. package/dist/client/search.js +213 -82
  16. package/dist/client/tabs.js +23 -0
  17. package/dist/components/layout/Head.js +17 -4
  18. package/dist/components/layout/TableOfContents.d.ts.map +1 -1
  19. package/dist/components/layout/TableOfContents.js +4 -2
  20. package/dist/components/openapi/Introduction.d.ts.map +1 -1
  21. package/dist/components/openapi/Introduction.js +16 -1
  22. package/dist/components/openapi/Security.d.ts.map +1 -1
  23. package/dist/components/openapi/Security.js +18 -2
  24. package/dist/config.d.ts +101 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +95 -143
  27. package/dist/core/api-rendering.d.ts +47 -0
  28. package/dist/core/api-rendering.d.ts.map +1 -0
  29. package/dist/core/api-rendering.js +76 -0
  30. package/dist/core/doxygen-loader.d.ts.map +1 -1
  31. package/dist/core/doxygen-loader.js +36 -17
  32. package/dist/core/godoc-loader.d.ts.map +1 -1
  33. package/dist/core/godoc-loader.js +17 -6
  34. package/dist/core/markdown-loader.d.ts +14 -0
  35. package/dist/core/markdown-loader.d.ts.map +1 -1
  36. package/dist/core/markdown-loader.js +70 -26
  37. package/dist/core/mcp-normalizer.d.ts.map +1 -1
  38. package/dist/core/mcp-normalizer.js +48 -34
  39. package/dist/core/navigation.d.ts.map +1 -1
  40. package/dist/core/navigation.js +8 -7
  41. package/dist/core/parser.d.ts.map +1 -1
  42. package/dist/core/parser.js +75 -4
  43. package/dist/core/rustdoc-introspector.d.ts +29 -0
  44. package/dist/core/rustdoc-introspector.d.ts.map +1 -0
  45. package/dist/core/rustdoc-introspector.js +236 -0
  46. package/dist/core/rustdoc-loader.d.ts +25 -0
  47. package/dist/core/rustdoc-loader.d.ts.map +1 -0
  48. package/dist/core/rustdoc-loader.js +469 -0
  49. package/dist/core/rustdoc-render.d.ts +76 -0
  50. package/dist/core/rustdoc-render.d.ts.map +1 -0
  51. package/dist/core/rustdoc-render.js +785 -0
  52. package/dist/core/rustdoc-types.d.ts +314 -0
  53. package/dist/core/rustdoc-types.d.ts.map +1 -0
  54. package/dist/core/rustdoc-types.js +18 -0
  55. package/dist/core/search-indexer.d.ts +10 -0
  56. package/dist/core/search-indexer.d.ts.map +1 -1
  57. package/dist/core/search-indexer.js +6 -1
  58. package/dist/core/sourcey-rustdoc/Cargo.lock +705 -0
  59. package/dist/core/sourcey-rustdoc/Cargo.toml +38 -0
  60. package/dist/core/sourcey-rustdoc/README.md +59 -0
  61. package/dist/core/sourcey-rustdoc/src/diagnostics.rs +42 -0
  62. package/dist/core/sourcey-rustdoc/src/doctest.rs +268 -0
  63. package/dist/core/sourcey-rustdoc/src/extract.rs +492 -0
  64. package/dist/core/sourcey-rustdoc/src/lib.rs +58 -0
  65. package/dist/core/sourcey-rustdoc/src/links.rs +126 -0
  66. package/dist/core/sourcey-rustdoc/src/main.rs +256 -0
  67. package/dist/core/sourcey-rustdoc/src/signature.rs +415 -0
  68. package/dist/core/sourcey-rustdoc/src/spec.rs +390 -0
  69. package/dist/core/sourcey-rustdoc/tests/format_version.rs +45 -0
  70. package/dist/dev-server.d.ts.map +1 -1
  71. package/dist/dev-server.js +109 -33
  72. package/dist/index.d.ts +4 -0
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +26 -14
  75. package/dist/init.d.ts.map +1 -1
  76. package/dist/init.js +21 -16
  77. package/dist/renderer/changelog-feed.d.ts.map +1 -1
  78. package/dist/renderer/changelog-feed.js +27 -19
  79. package/dist/renderer/html-builder.d.ts.map +1 -1
  80. package/dist/renderer/html-builder.js +4 -3
  81. package/dist/renderer/llms.js +57 -2
  82. package/dist/site-assembly.d.ts +5 -0
  83. package/dist/site-assembly.d.ts.map +1 -1
  84. package/dist/site-assembly.js +161 -25
  85. package/dist/themes/default/sourcey.css +300 -0
  86. package/dist/utils/code-samples.d.ts +1 -0
  87. package/dist/utils/code-samples.d.ts.map +1 -1
  88. package/dist/utils/code-samples.js +30 -22
  89. package/dist/utils/html.d.ts +10 -0
  90. package/dist/utils/html.d.ts.map +1 -0
  91. package/dist/utils/html.js +152 -0
  92. package/dist/utils/http.d.ts +0 -2
  93. package/dist/utils/http.d.ts.map +1 -1
  94. package/dist/utils/http.js +19 -34
  95. package/dist/utils/markdown.d.ts.map +1 -1
  96. package/dist/utils/markdown.js +115 -39
  97. package/dist/vite-plugin.d.ts +2 -0
  98. package/dist/vite-plugin.d.ts.map +1 -1
  99. package/dist/vite-plugin.js +71 -1
  100. package/package.json +11 -5
@@ -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":"AA+CA,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,CAyZ7E"}
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";
@@ -30,7 +31,12 @@ async function exists(path) {
30
31
  }
31
32
  }
32
33
  function log(msg) {
33
- const t = new Date().toLocaleTimeString([], { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
34
+ const t = new Date().toLocaleTimeString([], {
35
+ hour12: false,
36
+ hour: "2-digit",
37
+ minute: "2-digit",
38
+ second: "2-digit",
39
+ });
34
40
  console.log(` \x1b[2m${t}\x1b[0m ${msg}`);
35
41
  }
36
42
  function shortPath(path) {
@@ -44,20 +50,22 @@ export async function startDevServer(options) {
44
50
  : resolve(options.config ?? process.cwd(), "sourcey.config.ts");
45
51
  const watchPaths = [configPath];
46
52
  for (const tab of config.tabs) {
47
- if (tab.openapi)
48
- watchPaths.push(tab.openapi);
49
- if (tab.mcp)
50
- watchPaths.push(tab.mcp);
51
- if (tab.doxygen)
52
- watchPaths.push(tab.doxygen.xml);
53
- if (tab.godoc) {
54
- if (tab.godoc.snapshot)
55
- watchPaths.push(tab.godoc.snapshot);
53
+ watchPaths.push(...(tab.source.watchPaths ?? []));
54
+ if (tab.source.kind === "godoc") {
56
55
  // The Go module directory is large; watching every .go file slows the
57
56
  // dev server. Restart manually after broad source edits.
58
57
  }
59
- if (tab.groups) {
60
- for (const group of tab.groups) {
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
+ }
67
+ if (tab.source.kind === "markdown") {
68
+ for (const group of tab.source.groups) {
61
69
  for (const page of group.pages) {
62
70
  watchPaths.push(page.file);
63
71
  }
@@ -68,22 +76,48 @@ export async function startDevServer(options) {
68
76
  const map = new Map();
69
77
  map.set(configPath, { kind: "config" });
70
78
  for (const tab of cfg.tabs) {
71
- if (tab.openapi) {
72
- map.set(resolve(tab.openapi), { kind: "openapi", tabSlug: tab.slug, specPath: tab.openapi });
79
+ for (const watchPath of tab.source.watchPaths ?? []) {
80
+ map.set(resolve(watchPath), { kind: "config" });
81
+ }
82
+ if (tab.source.kind === "openapi") {
83
+ map.set(resolve(tab.source.spec), {
84
+ kind: "openapi",
85
+ tabSlug: tab.slug,
86
+ specPath: tab.source.spec,
87
+ });
73
88
  }
74
- if (tab.mcp) {
75
- map.set(resolve(tab.mcp), { kind: "mcp", tabSlug: tab.slug, specPath: tab.mcp });
89
+ if (tab.source.kind === "mcp") {
90
+ map.set(resolve(tab.source.spec), {
91
+ kind: "mcp",
92
+ tabSlug: tab.slug,
93
+ specPath: tab.source.spec,
94
+ });
95
+ }
96
+ if (tab.source.kind === "doxygen") {
97
+ map.set(resolve(tab.source.config.xml), {
98
+ kind: "doxygen",
99
+ tabSlug: tab.slug,
100
+ xmlDir: tab.source.config.xml,
101
+ });
76
102
  }
77
- if (tab.doxygen) {
78
- map.set(resolve(tab.doxygen.xml), { kind: "doxygen", tabSlug: tab.slug, xmlDir: tab.doxygen.xml });
103
+ if (tab.source.kind === "godoc" && tab.source.config.snapshot) {
104
+ map.set(resolve(tab.source.config.snapshot), {
105
+ kind: "godoc",
106
+ tabSlug: tab.slug,
107
+ snapshotPath: tab.source.config.snapshot,
108
+ });
79
109
  }
80
- if (tab.godoc?.snapshot) {
81
- map.set(resolve(tab.godoc.snapshot), { kind: "godoc", tabSlug: tab.slug, snapshotPath: tab.godoc.snapshot });
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
+ });
82
116
  }
83
- if (tab.groups) {
84
- for (const group of tab.groups) {
117
+ if (tab.source.kind === "markdown") {
118
+ for (const group of tab.source.groups) {
85
119
  for (const page of group.pages) {
86
- map.set(resolve(page.file), { kind: "markdown", tabSlug: tab.slug, pagePath: page.file, pageSlug: page.slug });
120
+ map.set(resolve(page.file), { kind: "markdown", tabSlug: tab.slug, page });
87
121
  }
88
122
  }
89
123
  }
@@ -143,11 +177,13 @@ export async function startDevServer(options) {
143
177
  const { data } = snapshot;
144
178
  const start = performance.now();
145
179
  if (content.kind === "markdown") {
146
- const slug = slugFromPath(content.pageSlug);
147
- log(`reloading ${shortPath(content.pagePath)}`);
148
- const page = await loadDocsPage(content.pagePath, slug, {
180
+ const slug = slugFromPath(content.page.slug);
181
+ log(`reloading ${shortPath(content.page.file)}`);
182
+ const page = await loadDocsPage(content.page.file, slug, {
149
183
  changelog: config.changelog.enabled,
150
184
  repoUrl: config.repo,
185
+ sourceRoot: content.page.sourceRoot,
186
+ preprocess: content.page.preprocess,
151
187
  });
152
188
  if (cache !== snapshot)
153
189
  return;
@@ -166,10 +202,10 @@ export async function startDevServer(options) {
166
202
  }
167
203
  else if (content.kind === "doxygen") {
168
204
  const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
169
- if (!tab?.doxygen)
205
+ if (!tab || tab.source.kind !== "doxygen")
170
206
  return;
171
207
  log(`rebuilding doxygen tab "${tab.label}"`);
172
- const { pages, navTab } = await loadDoxygenTab(tab.doxygen, tab.slug, tab.label);
208
+ const { pages, navTab } = await loadDoxygenTab(tab.source.config, tab.slug, tab.label);
173
209
  if (cache !== snapshot)
174
210
  return;
175
211
  for (const [key, page] of data.pageMap) {
@@ -194,13 +230,45 @@ export async function startDevServer(options) {
194
230
  }
195
231
  else if (content.kind === "godoc") {
196
232
  const tab = config.tabs.find((candidate) => candidate.slug === content.tabSlug);
197
- if (!tab?.godoc)
233
+ if (!tab || tab.source.kind !== "godoc")
198
234
  return;
199
235
  log(`rebuilding godoc tab "${tab.label}"`);
200
- const { pages, navTab } = await loadGodocTab(tab.godoc, tab.slug, tab.label, {
236
+ const { pages, navTab } = await loadGodocTab(tab.source.config, tab.slug, tab.label, {
237
+ repo: config.repo,
238
+ editBranch: config.editBranch,
239
+ editBasePath: tab.source.config.sourceBasePath,
240
+ });
241
+ if (cache !== snapshot)
242
+ return;
243
+ for (const [key, page] of data.pageMap) {
244
+ if (page.tabSlug === content.tabSlug)
245
+ data.pageMap.delete(key);
246
+ }
247
+ for (const [slug, page] of pages) {
248
+ const outputPath = pageOutputPath(tab.slug, slug, config.prettyUrls);
249
+ data.pageMap.set(outputPath, {
250
+ outputPath,
251
+ spec: data.primarySpec,
252
+ currentPage: { kind: "markdown", markdown: page },
253
+ tabSlug: tab.slug,
254
+ pageSlug: slug,
255
+ });
256
+ }
257
+ const idx = data.siteTabs.findIndex((candidate) => candidate.slug === content.tabSlug);
258
+ if (idx !== -1)
259
+ data.siteTabs[idx] = navTab;
260
+ else
261
+ data.siteTabs.push(navTab);
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, {
201
269
  repo: config.repo,
202
270
  editBranch: config.editBranch,
203
- editBasePath: tab.godoc.sourceBasePath,
271
+ editBasePath: tab.source.config.sourceBasePath,
204
272
  });
205
273
  if (cache !== snapshot)
206
274
  return;
@@ -280,7 +348,7 @@ export async function startDevServer(options) {
280
348
  return resolveConfigFromRaw(configMod.default, dirname(configPath));
281
349
  }
282
350
  async function render(url) {
283
- const { renderPage } = await vite.ssrLoadModule(ssrRendererPath);
351
+ const { renderPage } = (await vite.ssrLoadModule(ssrRendererPath));
284
352
  const { data, siteConfig: site } = await getCached();
285
353
  const navigation = buildSiteNavigation(data.siteTabs);
286
354
  const requestPath = stripBaseUrl(new URL(url, "http://sourcey.local").pathname, config.baseUrl);
@@ -300,7 +368,10 @@ export async function startDevServer(options) {
300
368
  }
301
369
  }
302
370
  let pageData = data.pageMap.get(pagePath);
303
- if (!pageData && config.prettyUrls === "slash" && pagePath.endsWith(".html") && !pagePath.endsWith("/index.html")) {
371
+ if (!pageData &&
372
+ config.prettyUrls === "slash" &&
373
+ pagePath.endsWith(".html") &&
374
+ !pagePath.endsWith("/index.html")) {
304
375
  // Fallback for stale `.html` links when prettyUrls is enabled.
305
376
  const pretty = pagePath.replace(/\.html$/, "/index.html");
306
377
  pageData = data.pageMap.get(pretty);
@@ -324,6 +395,10 @@ export async function startDevServer(options) {
324
395
  const docsPagesByTab = collectDocsPagesByTab(data.pageMap, config.tabs);
325
396
  return buildSearchIndex(data.specsBySlug, docsPagesByTab, navigation, config.baseUrl || "/", config.search.featured);
326
397
  }
398
+ async function loadExtraFileForDev(outputPath) {
399
+ const { data } = await getCached();
400
+ return data.extraFiles.get(outputPath);
401
+ }
327
402
  const viteConfig = {
328
403
  root: process.cwd(),
329
404
  server: {
@@ -343,6 +418,7 @@ export async function startDevServer(options) {
343
418
  baseUrl: () => config.baseUrl,
344
419
  render,
345
420
  searchIndex: buildSearchIndexForDev,
421
+ extraFile: loadExtraFileForDev,
346
422
  }),
347
423
  ],
348
424
  clearScreen: false,
package/dist/index.d.ts CHANGED
@@ -31,11 +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";
40
+ export { doxygen, godoc, markdown, mcp, mkdocs, openapi, rustdoc } from "./adapters/index.js";
39
41
  export { resolveInternalLinks } from "./site-assembly.js";
40
42
  export type { NormalizedSpec, NormalizedOperation, NormalizedTag, NormalizedSchema, NormalizedParameter, NormalizedRequestBody, NormalizedResponse, } from "./core/types.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";
41
45
  //# sourceMappingURL=index.d.ts.map