1#![expect(
4 clippy::multiple_crate_versions,
5 reason = "workspace tooling spans dependency families that have not converged on one version"
6)]
7
8pub mod context;
10pub mod hosted_rustdoc;
12pub mod infra;
14mod workspace;
15
16use infra::metadata::Metadata;
17use wowlab_fs::path::Path;
18
19#[rustfmt::skip]
20pub use workspace::{WorkspaceFile, WorkspaceIndex};
21
22#[derive(Debug)]
24pub struct RenderCtx<'a> {
25 pub workspace: WorkspaceIndex,
26 pub root: &'a Path,
27 pub dir: &'a Path,
28 pub rel_dir: &'a str,
29 pub metadata: &'a Metadata,
30 pub output_stem: &'a str,
31}
32
33impl RenderCtx<'_> {
34 #[must_use]
36 pub fn workspace(&self) -> &WorkspaceIndex {
37 &self.workspace
38 }
39
40 #[must_use]
42 pub fn is_root(&self) -> bool {
43 self.rel_dir.is_empty() || self.rel_dir == "."
44 }
45}
46
47#[must_use]
49pub fn display_name(name: &str) -> String {
50 name.strip_prefix("wowlab-").unwrap_or(name).to_string()
51}
52
53pub fn sort_by_name<T>(items: &mut [T])
55where
56 T: HasName,
57{
58 items.sort_by(|a, b| a.name().cmp(b.name()));
59}
60
61pub trait HasName {
63 fn name(&self) -> &str;
65}
66
67#[cfg(test)]
68pub mod test_helpers {
69 use wowlab_fs::{file, path::Path, walk};
70
71 use crate::{
72 RenderCtx, WorkspaceFile, WorkspaceIndex,
73 infra::metadata::{Metadata, PackageKind},
74 };
75
76 #[must_use]
77 pub fn workspace_at(root: &Path) -> WorkspaceIndex {
78 let (files, _failures) = walk::workspace_source_files(root).into_parts();
79 let entries = files
80 .into_iter()
81 .map(|path| {
82 let contents = file::read_bytes(&path)
83 .ok()
84 .and_then(|bytes| String::from_utf8(bytes).ok())
85 .map(String::into_boxed_str);
86
87 WorkspaceFile { path, contents }
88 })
89 .collect();
90
91 WorkspaceIndex::new(root.to_path_buf(), entries)
92 }
93
94 #[must_use]
96 pub fn test_ctx<'a>(
97 _kind: PackageKind,
98 rel_dir: &'a str,
99 stem: &'a str,
100 meta: &'a Metadata,
101 ) -> RenderCtx<'a> {
102 let root = Path::new("/ws");
103 let dir = if rel_dir.is_empty() || rel_dir == "." {
104 root.to_path_buf()
105 } else {
106 root.join(rel_dir)
107 };
108 let dir: &'a Path = Box::leak(Box::new(dir));
110
111 RenderCtx {
112 workspace: WorkspaceIndex::new(root.to_path_buf(), Vec::new()),
113 root,
114 dir,
115 rel_dir,
116 metadata: meta,
117 output_stem: stem,
118 }
119 }
120
121 #[must_use]
123 pub fn meta(kind: PackageKind) -> Metadata {
124 Metadata {
125 kind,
126 ..Default::default()
127 }
128 }
129}