1use std::path::PathBuf;
5
6#[derive(Debug, thiserror::Error)]
8#[non_exhaustive]
9pub enum Error {
10 #[error("reading {path}: {source}")]
11 Io {
12 path: PathBuf,
13 #[source]
14 source: std::io::Error,
15 },
16
17 #[error("{path}: {source}")]
19 Config {
20 path: PathBuf,
21 #[source]
22 source: toml::de::Error,
23 },
24
25 #[error(
29 "externals.relations: \"{from}\" (under external \"{external}\") names no element in the surveyed model"
30 )]
31 UnknownRelationSource { external: String, from: String },
32
33 #[error(
35 "externals: id \"{id}\" is not an identifier (letters, digits and _, not starting with a digit, not a keyword)"
36 )]
37 InvalidExternalId { id: String },
38
39 #[error(
42 "externals: \"{id}\" declares kind \"{kind}\", which the survey generates ({surveyed}); give an external its own kind"
43 )]
44 ExternalKindIsSurveyed {
45 id: String,
46 kind: String,
47 surveyed: String,
48 },
49
50 #[error("element ids \"{first}\" and \"{second}\" both become the LikeC4 id \"{id}\"")]
53 DuplicateId {
54 id: String,
55 first: String,
56 second: String,
57 },
58
59 #[error("theme: \"{kind}\" is not an element kind of the surveyed model (have {have})")]
62 UnknownThemeKind { kind: String, have: String },
63
64 #[error("{path}: {entry} is not a top-level entry asbuilt reads (those are {known})")]
70 UnknownTopLevel {
71 path: PathBuf,
72 entry: String,
73 known: String,
74 },
75
76 #[error(
81 "{path} pins asbuilt {pinned}, but this is asbuilt {running}: install the pinned release with `cargo install asbuilt --version {pinned} --locked`"
82 )]
83 PinMismatch {
84 path: PathBuf,
85 pinned: String,
86 running: String,
87 },
88
89 #[error("no supported stack detected at {root}")]
91 NoFrontend { root: PathBuf },
92
93 #[error("{frontend} front-end: {source}")]
95 Frontend {
96 frontend: String,
97 #[source]
98 source: Box<dyn std::error::Error + Send + Sync + 'static>,
99 },
100}
101
102pub type Result<T> = std::result::Result<T, Error>;
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn an_unknown_relation_source_names_the_external_and_the_from() {
110 let msg = Error::UnknownRelationSource {
111 external: "node_driver".into(),
112 from: "playwright_rs.nope".into(),
113 }
114 .to_string();
115 assert!(msg.contains("node_driver"), "{msg}");
116 assert!(msg.contains("playwright_rs.nope"), "{msg}");
117 }
118
119 #[test]
120 fn a_pin_mismatch_gives_the_install_command_for_the_pinned_release() {
121 let msg = Error::PinMismatch {
122 path: "asbuilt.toml".into(),
123 pinned: "0.3.0".into(),
124 running: "0.2.0".into(),
125 }
126 .to_string();
127 assert!(
128 msg.contains("`cargo install asbuilt --version 0.3.0 --locked`"),
129 "{msg}"
130 );
131 }
132
133 #[test]
134 fn a_duplicate_id_names_both_originals_and_the_collision() {
135 let msg = Error::DuplicateId {
136 id: "foo_bar".into(),
137 first: "foo-bar".into(),
138 second: "foo_bar".into(),
139 }
140 .to_string();
141 assert!(
142 msg.contains("\"foo-bar\"") && msg.contains("\"foo_bar\""),
143 "{msg}"
144 );
145 }
146}