typescript_tools/
configuration_file.rs1use std::{
2 fmt::Display,
3 fs::File,
4 io::{self, BufWriter, Write},
5 path::{Path, PathBuf},
6};
7
8use serde::Serialize;
9
10use crate::{io::FromFileError, types::Directory};
11
12#[derive(Debug)]
13#[non_exhaustive]
14pub struct WriteError {
15 pub path: PathBuf,
16 pub kind: WriteErrorKind,
17}
18
19impl Display for WriteError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 write!(f, "unable to write file {:?}", self.path)
22 }
23}
24
25impl std::error::Error for WriteError {
26 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
27 match &self.kind {
28 WriteErrorKind::OpenFile(err) => Some(err),
29 WriteErrorKind::Serialize(err) => Some(err),
30 WriteErrorKind::Stream(err) => Some(err),
31 }
32 }
33}
34
35#[derive(Debug)]
36pub enum WriteErrorKind {
37 OpenFile(io::Error),
38 Serialize(serde_json::Error),
39 Stream(io::Error),
40}
41
42pub trait ConfigurationFile: Sized {
45 type Contents: Serialize;
46
47 const FILENAME: &'static str;
49
50 fn from_directory(
53 monorepo_root: &Directory,
54 relative_directory: Directory,
55 ) -> Result<Self, FromFileError>;
56
57 fn directory(&self) -> &Directory;
60
61 fn path(&self) -> PathBuf;
63
64 fn contents(&self) -> &Self::Contents;
65
66 fn write(
67 monorepo_root: &Path,
68 configuration_file: impl ConfigurationFile,
69 ) -> Result<(), WriteError> {
70 let filename = monorepo_root.join(configuration_file.path());
71 let file = File::create(filename.clone()).map_err(|err| WriteError {
72 path: filename.clone(),
73 kind: WriteErrorKind::OpenFile(err),
74 })?;
75 let mut writer = BufWriter::new(file);
76 (|| {
77 let s = serde_json::to_string_pretty(configuration_file.contents())
78 .map_err(WriteErrorKind::Serialize)?;
79 writeln!(writer, "{}", s).map_err(WriteErrorKind::Stream)
80 })()
81 .map_err(|kind| WriteError {
82 path: filename,
83 kind,
84 })?;
85 Ok(())
86 }
87}