diff --git a/ts-rs/src/export.rs b/ts-rs/src/export.rs index a0e699fe1..b4ede7f2e 100644 --- a/ts-rs/src/export.rs +++ b/ts-rs/src/export.rs @@ -6,11 +6,13 @@ use std::{ sync::{Mutex, OnceLock}, }; +use path::absolute::PathAbsolute; use thiserror::Error; -use ExportError::*; use crate::TS; +mod path; + const NOTE: &str = "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n"; /// An error which may occur when exporting a type @@ -107,8 +109,8 @@ pub(crate) fn export_type_to>( use dprint_plugin_typescript::{configuration::ConfigurationBuilder, format_text}; let fmt_cfg = ConfigurationBuilder::new().deno().build(); - if let Some(formatted) = - format_text(path.as_ref(), &buffer, &fmt_cfg).map_err(|e| Formatting(e.to_string()))? + if let Some(formatted) = format_text(path.as_ref(), &buffer, &fmt_cfg) + .map_err(|e| ExportError::Formatting(e.to_string()))? { buffer = formatted; } @@ -158,11 +160,12 @@ pub(crate) fn export_type_to_string() -> Result() -> Result { - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|_| ManifestDirNotSet)?; - let manifest_dir = Path::new(&manifest_dir); - let path = - PathBuf::from(T::get_export_to().ok_or(CannotBeExported(std::any::type_name::()))?); - Ok(manifest_dir.join(path)) + Ok(Path::new( + &T::get_export_to() + .ok_or_else(|| std::any::type_name::()) + .map_err(ExportError::CannotBeExported)?, + ) + .absolute()?) } /// Push the declaration of `T` @@ -180,7 +183,8 @@ fn generate_decl(out: &mut String) { /// Push an import statement for all dependencies of `T` fn generate_imports(out: &mut String) -> Result<(), ExportError> { - let export_to = T::get_export_to().ok_or(CannotBeExported(std::any::type_name::()))?; + let export_to = + T::get_export_to().ok_or(ExportError::CannotBeExported(std::any::type_name::()))?; let path = Path::new(&export_to); let deps = T::dependencies(); @@ -221,10 +225,6 @@ fn import_path(from: &Path, import: &Path) -> String { } } -fn to_absolute_path(path: &Path) -> Result { - Ok(std::env::current_dir()?.join(path).clean()) -} - // Construct a relative path from a provided base directory path to the provided path. // // Copyright 2012-2015 The Rust Project Developers. @@ -242,8 +242,9 @@ where P: AsRef, B: AsRef, { - let path = to_absolute_path(path.as_ref())?; - let base = to_absolute_path(base.as_ref())?; + use Component as C; + let path = path.as_ref().absolute()?; + let base = base.as_ref().absolute()?; let mut ita = path.components(); let mut itb = base.components(); @@ -251,22 +252,23 @@ where loop { match (ita.next(), itb.next()) { - (Some(Component::ParentDir), _) | (_, Some(Component::ParentDir)) => { - unreachable!("The paths have been cleaned, no parent dir components are present") - }, + (Some(C::CurDir | C::ParentDir), _) | (_, Some(C::CurDir | C::ParentDir)) => { + unreachable!( + "The paths are absolute and have been cleaned, no parent or current dir components are present" + ) + } (None, None) => break, (Some(a), None) => { comps.push(a); comps.extend(ita.by_ref()); break; } - (None, _) => comps.push(Component::ParentDir), + (None, _) => comps.push(C::ParentDir), (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(Component::CurDir)) => comps.push(a), (Some(a), Some(_)) => { - comps.push(Component::ParentDir); + comps.push(C::ParentDir); for _ in itb { - comps.push(Component::ParentDir); + comps.push(C::ParentDir); } comps.push(a); comps.extend(ita.by_ref()); @@ -277,76 +279,3 @@ where Ok(comps.iter().map(|c| c.as_os_str()).collect()) } - -// Copyright 2018 Dan Reeves -// Adapted from the `path-clean` crate -// https://github.com/danreeves/path-clean -trait PathClean: AsRef { - fn clean(&self) -> PathBuf { - clean(self) - } -} - -// Copyright 2018 Dan Reeves -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Adapted from the `path-clean` crate -// https://github.com/danreeves/path-clean -impl PathClean for PathBuf {} - -// Copyright 2018 Dan Reeves -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Adapted from the `path-clean` crate -// https://github.com/danreeves/path-clean -impl PathClean for Path {} - -// Copyright 2018 Dan Reeves -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Copied verbatim from the `path-clean` crate -// https://github.com/danreeves/path-clean -pub fn clean

(path: P) -> PathBuf -where - P: AsRef, -{ - let mut out = Vec::new(); - - for comp in path.as_ref().components() { - match comp { - Component::CurDir => (), - Component::ParentDir => match out.last() { - Some(Component::RootDir) => (), - Some(Component::Normal(_)) => { - out.pop(); - } - None - | Some(Component::CurDir) - | Some(Component::ParentDir) - | Some(Component::Prefix(_)) => out.push(comp), - }, - comp => out.push(comp), - } - } - - if !out.is_empty() { - out.iter().collect() - } else { - PathBuf::from(".") - } -} diff --git a/ts-rs/src/export/path.rs b/ts-rs/src/export/path.rs new file mode 100644 index 000000000..6e8bb31f0 --- /dev/null +++ b/ts-rs/src/export/path.rs @@ -0,0 +1,2 @@ +pub mod absolute; +pub mod clean; diff --git a/ts-rs/src/export/path/absolute.rs b/ts-rs/src/export/path/absolute.rs new file mode 100644 index 000000000..94d7ebb1c --- /dev/null +++ b/ts-rs/src/export/path/absolute.rs @@ -0,0 +1,18 @@ +use std::{ + env, + io::Result, + path::{Path, PathBuf}, +}; + +use super::clean::PathClean; + +/// This trait is responsible for converting a relative path +/// into an absolute path +pub trait PathAbsolute: AsRef + PathClean { + /// Converts a relative path into an absolute path. + fn absolute(&self) -> Result { + Ok(Path::new(&env::current_dir()?).join(self).clean()) + } +} + +impl + PathClean> PathAbsolute for T {} diff --git a/ts-rs/src/export/path/clean.rs b/ts-rs/src/export/path/clean.rs new file mode 100644 index 000000000..5690c71da --- /dev/null +++ b/ts-rs/src/export/path/clean.rs @@ -0,0 +1,32 @@ +use std::path::{Component, Path, PathBuf}; + +pub trait PathClean: AsRef { + fn clean(&self) -> PathBuf { + let mut out = Vec::new(); + + for comp in self.as_ref().components() { + match comp { + Component::CurDir => (), + Component::ParentDir => match out.last() { + Some(Component::RootDir) => (), + Some(Component::Normal(_)) => { + out.pop(); + } + None + | Some(Component::CurDir) + | Some(Component::ParentDir) + | Some(Component::Prefix(_)) => out.push(comp), + }, + comp => out.push(comp), + } + } + + if !out.is_empty() { + out.iter().collect() + } else { + PathBuf::from(".") + } + } +} + +impl> PathClean for T {} diff --git a/ts-rs/src/lib.rs b/ts-rs/src/lib.rs index 2540d6204..4f99ed972 100644 --- a/ts-rs/src/lib.rs +++ b/ts-rs/src/lib.rs @@ -562,10 +562,7 @@ impl TS for Result { where Self: 'static, { - T::generics() - .push::() - .extend(E::generics()) - .push::() + T::generics().push::().extend(E::generics()).push::() } } @@ -658,10 +655,7 @@ impl TS for HashMap { where Self: 'static, { - K::generics() - .push::() - .extend(V::generics()) - .push::() + K::generics().push::().extend(V::generics()).push::() } } diff --git a/ts-rs/tests/path_bug.rs b/ts-rs/tests/path_bug.rs index a1cc6b1fc..f2ead2162 100644 --- a/ts-rs/tests/path_bug.rs +++ b/ts-rs/tests/path_bug.rs @@ -4,11 +4,11 @@ use ts_rs::TS; #[derive(TS)] #[ts(export, export_to = "../ts-rs/tests-out/path_bug/")] struct Foo { - bar: Bar + bar: Bar, } #[derive(TS)] #[ts(export_to = "tests-out/path_bug/aaa/")] struct Bar { - i: i32 + i: i32, } diff --git a/ts-rs/tests/struct_tag.rs b/ts-rs/tests/struct_tag.rs index 752a325f0..a1d8dd23d 100644 --- a/ts-rs/tests/struct_tag.rs +++ b/ts-rs/tests/struct_tag.rs @@ -20,4 +20,3 @@ fn test() { "{ type: \"TaggedType\", a: number, b: number, }" ) } -