Skip to content

Commit

Permalink
Merge pull request #25 from holly-hacker/feature/pretty-printed-output
Browse files Browse the repository at this point in the history
Pretty-print output code
  • Loading branch information
dbeckwith authored Aug 11, 2023
2 parents 3e239dc + 76fad74 commit 394ec08
Show file tree
Hide file tree
Showing 3 changed files with 354 additions and 139 deletions.
112 changes: 81 additions & 31 deletions src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::type_expr::{
TypeArray, TypeDefinition, TypeExpr, TypeInfo, TypeIntersection, TypeName,
TypeObject, TypeString, TypeTuple, TypeUnion,
};
use std::io;
use std::{borrow::Cow, io};

/// A Rust type that has a corresponding TypeScript type definition.
///
Expand Down Expand Up @@ -55,9 +55,12 @@ use std::io;
/// r#"// AUTO-GENERATED by typescript-type-def
///
/// export default types;
/// export namespace types{
/// export type Uuid=string;
/// export type User={"id":types.Uuid;"name":string;};
/// export namespace types {
/// export type Uuid = string;
/// export type User = {
/// "id": types.Uuid;
/// "name": string;
/// };
/// }
/// "#
/// );
Expand Down Expand Up @@ -87,8 +90,11 @@ use std::io;
/// r#"// AUTO-GENERATED by typescript-type-def
///
/// export default types;
/// export namespace types{
/// export type User={"id":string;"name":string;};
/// export namespace types {
/// export type User = {
/// "id": string;
/// "name": string;
/// };
/// }
/// "#
/// );
Expand Down Expand Up @@ -146,9 +152,35 @@ pub trait TypeDef: 'static {
pub(crate) struct EmitCtx<'ctx> {
w: &'ctx mut dyn io::Write,
root_namespace: Option<&'ctx str>,
indent: usize,
stats: Stats,
}

impl EmitCtx<'_> {
fn indent(&mut self) {
self.indent += 1;
}

fn deindent(&mut self) {
debug_assert!(
self.indent > 0,
"indentation must be > 0 when deindenting"
);
self.indent -= 1;
}

fn current_indentation(&self) -> Cow<'static, str> {
// hard-code common values to avoid frequent string construction
match self.indent {
0 => "".into(),
1 => " ".into(),
2 => " ".into(),
3 => " ".into(),
n => " ".repeat(n).into(),
}
}
}

pub(crate) trait Emit {
fn emit(&self, ctx: &mut EmitCtx<'_>) -> io::Result<()>;
}
Expand Down Expand Up @@ -208,6 +240,7 @@ impl<'ctx> EmitCtx<'ctx> {
Self {
w,
root_namespace,
indent: 0,
stats,
}
}
Expand Down Expand Up @@ -243,7 +276,7 @@ where
let Self(args) = self;
if !args.is_empty() {
write!(ctx.w, "<")?;
SepList(args, ",").emit(ctx)?;
SepList(args, ", ").emit(ctx)?;
write!(ctx.w, ">")?;
}
Ok(())
Expand Down Expand Up @@ -298,7 +331,7 @@ impl Emit for TypeTuple {
let Self { docs, elements } = self;
docs.emit(ctx)?;
write!(ctx.w, "[")?;
SepList(elements, ",").emit(ctx)?;
SepList(elements, ", ").emit(ctx)?;
write!(ctx.w, "]")?;
Ok(())
}
Expand All @@ -311,15 +344,20 @@ impl Emit for TypeObject {
index_signature,
fields,
} = self;
docs.emit(ctx)?;
write!(ctx.w, "{{")?;
if let Some(docs) = docs {
docs.emit(ctx)?;
write!(ctx.w, "{}", ctx.current_indentation())?;
}
writeln!(ctx.w, "{{")?;
ctx.indent();
if let Some(IndexSignature { docs, name, value }) = index_signature {
docs.emit(ctx)?;
write!(ctx.w, "[")?;
write!(ctx.w, "{}[", ctx.current_indentation())?;
name.emit(ctx)?;
write!(ctx.w, ":string]:")?;
value.emit(ctx)?;
write!(ctx.w, ";")?;
writeln!(ctx.w)?;
}
for ObjectField {
docs,
Expand All @@ -329,15 +367,17 @@ impl Emit for TypeObject {
} in *fields
{
docs.emit(ctx)?;
write!(ctx.w, "{}", ctx.current_indentation())?;
name.emit(ctx)?;
if *optional {
write!(ctx.w, "?")?;
}
write!(ctx.w, ":")?;
write!(ctx.w, ": ")?;
r#type.emit(ctx)?;
write!(ctx.w, ";")?;
writeln!(ctx.w, ";")?;
}
write!(ctx.w, "}}")?;
ctx.deindent();
write!(ctx.w, "{}}}", ctx.current_indentation())?;
Ok(())
}
}
Expand All @@ -361,7 +401,7 @@ impl Emit for TypeUnion {
write!(ctx.w, "never")?;
} else {
write!(ctx.w, "(")?;
SepList(members, "|").emit(ctx)?;
SepList(members, " | ").emit(ctx)?;
write!(ctx.w, ")")?;
}
Ok(())
Expand All @@ -376,7 +416,7 @@ impl Emit for TypeIntersection {
write!(ctx.w, "unknown")?;
} else {
write!(ctx.w, "(")?;
SepList(members, "&").emit(ctx)?;
SepList(members, " & ").emit(ctx)?;
write!(ctx.w, ")")?;
}
Ok(())
Expand All @@ -395,11 +435,11 @@ impl Emit for Docs {
fn emit(&self, ctx: &mut EmitCtx<'_>) -> io::Result<()> {
let Self(docs) = self;
writeln!(ctx.w)?;
writeln!(ctx.w, "/**")?;
writeln!(ctx.w, "{}/**", ctx.current_indentation())?;
for line in docs.lines() {
writeln!(ctx.w, " * {}", line)?;
writeln!(ctx.w, "{} * {}", ctx.current_indentation(), line)?;
}
writeln!(ctx.w, " */")?;
writeln!(ctx.w, "{} */", ctx.current_indentation())?;
Ok(())
}
}
Expand Down Expand Up @@ -438,19 +478,26 @@ impl EmitCtx<'_> {
{
self.stats.type_definitions += 1;
if !path.is_empty() {
write!(self.w, "export namespace ")?;
write!(
self.w,
"{}export namespace ",
self.current_indentation()
)?;
SepList(path, ".").emit(self)?;
writeln!(self.w, "{{")?;
writeln!(self.w, " {{")?;
self.indent();
}
docs.emit(self)?;
write!(self.w, "export type ")?;
write!(self.w, "{}export type ", self.current_indentation())?;
name.emit(self)?;
Generics(generic_vars).emit(self)?;
write!(self.w, "=")?;
write!(self.w, " = ")?;
def.emit(self)?;
write!(self.w, ";")?;
if !path.is_empty() {
write!(self.w, "}}")?;
writeln!(self.w)?;
self.deindent();
write!(self.w, "{}}}", self.current_indentation())?;
}
writeln!(self.w)?;
}
Expand Down Expand Up @@ -560,20 +607,22 @@ pub fn write_definition_file_from_type_infos<W>(
where
W: io::Write,
{
let mut ctx = EmitCtx::new(&mut writer, options.root_namespace);
if let Some(header) = options.header {
writeln!(&mut writer, "{}", header)?;
writeln!(&mut ctx.w, "{}", header)?;
}
if let Some(root_namespace) = options.root_namespace {
writeln!(&mut writer, "export default {};", root_namespace)?;
writeln!(&mut writer, "export namespace {}{{", root_namespace)?;
writeln!(&mut ctx.w, "export default {};", root_namespace)?;
writeln!(&mut ctx.w, "export namespace {} {{", root_namespace)?;
ctx.indent();
}
let mut ctx = EmitCtx::new(&mut writer, options.root_namespace);
ctx.emit_type_def(type_infos)?;
let stats = ctx.stats;
if options.root_namespace.is_some() {
writeln!(&mut writer, "}}")?;
ctx.deindent();
writeln!(&mut ctx.w, "}}")?;
}
Ok(stats)
debug_assert_eq!(ctx.indent, 0, "indentation must be 0 after printing");
Ok(ctx.stats)
}

impl TypeInfo {
Expand Down Expand Up @@ -625,6 +674,7 @@ impl TypeInfo {
{
let mut ctx = EmitCtx::new(&mut writer, root_namespace);
ctx.emit_type_ref(self)?;
debug_assert_eq!(ctx.indent, 0, "indentation must be 0 after printing");
Ok(())
}
}
45 changes: 32 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@
//! r#"// AUTO-GENERATED by typescript-type-def
//!
//! export default types;
//! export namespace types{
//! export type Usize=number;
//! export type Foo={"a":types.Usize;"b":string;};
//! export namespace types {
//! export type Usize = number;
//! export type Foo = {
//! "a": types.Usize;
//! "b": string;
//! };
//! }
//! "#
//! );
Expand Down Expand Up @@ -116,11 +119,19 @@
//! r#"// AUTO-GENERATED by typescript-type-def
//!
//! export default types;
//! export namespace types{
//! export type Foo={"a":string;};
//! export type Bar={"a":string;};
//! export type Qux={"a":string;};
//! export type Baz={"a":types.Qux;};
//! export namespace types {
//! export type Foo = {
//! "a": string;
//! };
//! export type Bar = {
//! "a": string;
//! };
//! export type Qux = {
//! "a": string;
//! };
//! export type Baz = {
//! "a": types.Qux;
//! };
//! }
//! "#
//! );
Expand Down Expand Up @@ -179,11 +190,19 @@
//! r#"// AUTO-GENERATED by typescript-type-def
//!
//! export default types;
//! export namespace types{
//! export type Foo={"a":string;};
//! export type Bar={"a":string;};
//! export type Qux={"a":string;};
//! export type Baz={"a":types.Qux;};
//! export namespace types {
//! export type Foo = {
//! "a": string;
//! };
//! export type Bar = {
//! "a": string;
//! };
//! export type Qux = {
//! "a": string;
//! };
//! export type Baz = {
//! "a": types.Qux;
//! };
//! }
//! "#
//! );
Expand Down
Loading

0 comments on commit 394ec08

Please sign in to comment.