Skip to content

Commit

Permalink
Merge ExportConfig into Typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
oscartbeaumont committed Jul 31, 2024
1 parent 32adc24 commit b5cd920
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 148 deletions.
4 changes: 2 additions & 2 deletions specta-typescript/src/comments.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::js_doc;
use crate::typescript::{CommentFormatterArgs, CommentFormatterFn};

use super::{CommentFormatterArgs, CommentFormatterFn};
use super::js_doc;

// Assert that the function signature matches the expected type.
const _: CommentFormatterFn = js_doc;
Expand Down
4 changes: 2 additions & 2 deletions specta-typescript/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{borrow::Cow, fmt};

use specta::ImplLocation;

use super::ExportConfig;
use crate::Typescript;

#[derive(Clone, Debug)]
pub(crate) enum PathItem {
Expand All @@ -14,7 +14,7 @@ pub(crate) enum PathItem {

#[derive(Clone)]
pub(crate) struct ExportContext<'a> {
pub(crate) cfg: &'a ExportConfig,
pub(crate) cfg: &'a Typescript,
pub(crate) path: Vec<PathItem>,
// `false` when inline'ing and `true` when exporting as named.
pub(crate) is_export: bool,
Expand Down
110 changes: 0 additions & 110 deletions specta-typescript/src/export_config.rs

This file was deleted.

17 changes: 14 additions & 3 deletions specta-typescript/src/formatter.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// TODO: Eslint

use std::{io, path::PathBuf, process::Command};

use super::FormatterFn;
use crate::typescript::FormatterFn;

/// Format the specified file using [ESLint](https://eslint.org).
pub fn eslint(file: PathBuf) -> io::Result<()> {
Expand All @@ -29,3 +27,16 @@ pub fn prettier(file: PathBuf) -> io::Result<()> {

// Assert that the function signature matches the expected type.
const _: FormatterFn = prettier;

/// Format the specified file using [Biome](https://prettier.io).
pub fn biome(file: PathBuf) -> io::Result<()> {
Command::new("biome")
.arg("format")
.arg(file)
.output()
.map(|_| ())
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
}

// Assert that the function signature matches the expected type.
const _: FormatterFn = biome;
7 changes: 2 additions & 5 deletions specta-typescript/src/js_doc.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use std::borrow::Borrow;

use specta::{DeprecatedType, GenericType, TypeMap};
use typescript::CommentFormatterArgs;

Check warning on line 4 in specta-typescript/src/js_doc.rs

View workflow job for this annotation

GitHub Actions / clippy

private item shadows public glob re-export

warning: private item shadows public glob re-export --> specta-typescript/src/js_doc.rs:4:5 | 4 | use typescript::CommentFormatterArgs; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the name `CommentFormatterArgs` in the type namespace is supposed to be publicly re-exported here --> specta-typescript/src/js_doc.rs:6:9 | 6 | pub use super::*; | ^^^^^^^^ note: but the private item here shadows it --> specta-typescript/src/js_doc.rs:4:5 | 4 | use typescript::CommentFormatterArgs; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(hidden_glob_reexports)]` on by default

pub use super::*;

pub fn typedef_named_datatype(
cfg: &ExportConfig,
typ: &NamedDataType,
type_map: &TypeMap,
) -> Output {
pub fn typedef_named_datatype(cfg: &Typescript, typ: &NamedDataType, type_map: &TypeMap) -> Output {
typedef_named_datatype_inner(
&ExportContext {
cfg,
Expand Down
20 changes: 7 additions & 13 deletions specta-typescript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use std::fmt::Write;
pub mod comments;
mod context;
mod error;
mod export_config;
pub mod formatter;
#[cfg(feature = "function")]
#[cfg_attr(docsrs, doc(cfg(feature = "function")))]
Expand All @@ -22,9 +21,8 @@ mod typescript;

pub use context::*;
pub use error::*;
pub use export_config::*;
use reserved_terms::*;
pub use typescript::Typescript;
pub use typescript::*;

use specta::{
internal::{detect_duplicate_type_names, skip_fields, skip_fields_named, NonSkipField},
Expand All @@ -44,14 +42,14 @@ pub(crate) type Output = Result<String>;
/// Convert a type which implements [`Type`](crate::Type) to a TypeScript string with an export.
///
/// Eg. `export type Foo = { demo: string; };`
pub fn export_ref<T: NamedType>(_: &T, conf: &ExportConfig) -> Output {
pub fn export_ref<T: NamedType>(_: &T, conf: &Typescript) -> Output {
export::<T>(conf)
}

/// Convert a type which implements [`Type`](crate::Type) to a TypeScript string with an export.
///
/// Eg. `export type Foo = { demo: string; };`
pub fn export<T: NamedType>(conf: &ExportConfig) -> Output {
pub fn export<T: NamedType>(conf: &Typescript) -> Output {
let mut type_map = TypeMap::default();
let named_data_type = T::definition_named_data_type(&mut type_map);
is_valid_ty(&named_data_type.inner, &type_map)?;
Expand All @@ -67,14 +65,14 @@ pub fn export<T: NamedType>(conf: &ExportConfig) -> Output {
/// Convert a type which implements [`Type`](crate::Type) to a TypeScript string.
///
/// Eg. `{ demo: string; };`
pub fn inline_ref<T: Type>(_: &T, conf: &ExportConfig) -> Output {
pub fn inline_ref<T: Type>(_: &T, conf: &Typescript) -> Output {
inline::<T>(conf)
}

/// Convert a type which implements [`Type`](crate::Type) to a TypeScript string.
///
/// Eg. `{ demo: string; };`
pub fn inline<T: Type>(conf: &ExportConfig) -> Output {
pub fn inline<T: Type>(conf: &Typescript) -> Output {
let mut type_map = TypeMap::default();
let ty = T::inline(&mut type_map, Generics::NONE);
is_valid_ty(&ty, &type_map)?;
Expand All @@ -90,11 +88,7 @@ pub fn inline<T: Type>(conf: &ExportConfig) -> Output {
/// Convert a DataType to a TypeScript string
///
/// Eg. `export Name = { demo: string; }`
pub fn export_named_datatype(
conf: &ExportConfig,
typ: &NamedDataType,
type_map: &TypeMap,
) -> Output {
pub fn export_named_datatype(conf: &Typescript, typ: &NamedDataType, type_map: &TypeMap) -> Output {
// TODO: Duplicate type name detection?

is_valid_ty(&typ.inner, type_map)?;
Expand Down Expand Up @@ -175,7 +169,7 @@ fn export_datatype_inner(ctx: ExportContext, typ: &NamedDataType, type_map: &Typ
/// Convert a DataType to a TypeScript string
///
/// Eg. `{ demo: string; }`
pub fn datatype(conf: &ExportConfig, typ: &FunctionResultVariant, type_map: &TypeMap) -> Output {
pub fn datatype(conf: &Typescript, typ: &FunctionResultVariant, type_map: &TypeMap) -> Output {
// TODO: Duplicate type name detection?

let mut s = String::new();
Expand Down
76 changes: 63 additions & 13 deletions specta-typescript/src/typescript.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,51 @@
use std::{borrow::Cow, io, path::PathBuf};

use specta::{Language, TypeMap};
use specta::{DeprecatedType, Language, TypeMap};
use specta_serde::is_valid_ty;

use crate::{
detect_duplicate_type_names, export_named_datatype, BigIntExportBehavior, CommentFormatterFn,
ExportConfig, ExportError, FormatterFn,
};
use crate::{comments, detect_duplicate_type_names, export_named_datatype, ExportError};

#[derive(Default, Debug)]
#[derive(Debug)]
#[non_exhaustive]
pub struct CommentFormatterArgs<'a> {
pub docs: &'a Cow<'static, str>,
pub deprecated: Option<&'a DeprecatedType>,
}

/// The signature for a function responsible for exporting Typescript comments.
pub type CommentFormatterFn = fn(CommentFormatterArgs) -> String; // TODO: Returning `Cow`???

/// The signature for a function responsible for formatter a Typescript file.
pub type FormatterFn = fn(PathBuf) -> io::Result<()>;

/// Allows you to configure how Specta's Typescript exporter will deal with BigInt types ([i64], [i128] etc).
///
/// WARNING: None of these settings affect how your data is actually ser/deserialized.
/// It's up to you to adjust your ser/deserialize settings.
#[derive(Debug, Clone, Default)]
pub enum BigIntExportBehavior {
/// Export BigInt as a Typescript `string`
///
/// Doing this is serde is [pretty simple](https://github.com/serde-rs/json/issues/329#issuecomment-305608405).
String,
/// Export BigInt as a Typescript `number`.
///
/// WARNING: `JSON.parse` in JS will truncate your number resulting in data loss so ensure your deserializer supports large numbers.
Number,
/// Export BigInt as a Typescript `BigInt`.
BigInt,
/// Abort the export with an error.
///
/// This is the default behavior because without integration from your serializer and deserializer we can't guarantee data loss won't occur.
#[default]
Fail,
/// Same as `Self::Fail` but it allows a library to configure the message shown to the end user.
#[doc(hidden)]
FailWithReason(&'static str),
}

/// Typescript language exporter.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Typescript {
/// The file's header
Expand All @@ -25,6 +62,19 @@ pub struct Typescript {
pub path: Option<PathBuf>,
}

impl Default for Typescript {
fn default() -> Self {
Self {
header: Cow::Borrowed(""),
remove_default_header: false,
bigint: Default::default(),
comment_exporter: Some(comments::js_doc),
formatter: None,
path: None,
}
}
}

impl Typescript {
/// Configure a header for the file.
///
Expand All @@ -34,7 +84,8 @@ impl Typescript {
self
}

/// TODO
// TODO: Only keep this is TS stays responsible for exporting which it probs won't.
/// Removes the default Specta header from the output.
pub fn remove_default_header(mut self) -> Self {
self.remove_default_header = true;
self
Expand Down Expand Up @@ -62,9 +113,10 @@ impl Typescript {
/// Configure a function which is responsible for formatting the result file or files
///
///
/// Implementations:
/// - [`prettier`](crate::lang::ts::prettier)
/// - [`ESLint`](crate::lang::ts::eslint)
/// Built-in implementations:
/// - [`prettier`](specta_typescript:formatter:::prettier)
/// - [`ESLint`](specta_typescript::formatter::eslint)
/// - [`Biome`](specta_typescript::formatter::biome)e
pub fn formatter(mut self, formatter: FormatterFn) -> Self {
self.formatter = Some(formatter);
self
Expand Down Expand Up @@ -102,9 +154,7 @@ impl Language for Typescript {
for (_, ty) in type_map.iter() {
is_valid_ty(&ty.inner, &type_map)?;

let config = ExportConfig::default(); // TODO: From `Self` instead.

out += &export_named_datatype(&config, ty, &type_map)?;
out += &export_named_datatype(self, ty, &type_map)?;
out += "\n\n";
}

Expand Down

0 comments on commit b5cd920

Please sign in to comment.