Repository: Aleph-Alpha/ts-rs (Rust)

Issue:
bug: files are missing final newlines
**Describe the bug**

Many linters and related tools expect newlines at the end of files. As far as I can tell, `ts-rs` does not add one to generated `.ts` files, which I wouldn't necessarily classify as a *bug* but I think that it's more surprising to not have one than to have one.

**To Reproduce**

Generate any new `.ts` files.

**Expected behavior**

Generated `.ts` files have a newline at the end.

**Screenshots**

N/A

**Version**

8.1.0

**Additional context**

N/A



Discussion:

Patch:
diff --git a/ts-rs/src/export.rs b/ts-rs/src/export.rs
index 50434187..cfcee040 100644
--- a/ts-rs/src/export.rs
+++ b/ts-rs/src/export.rs
@@ -152,6 +152,7 @@ pub(crate) fn export_to_string<T: TS + ?Sized + 'static>() -> Result<String, Exp
     buffer.push_str(NOTE);
     generate_imports::<T::WithoutGenerics>(&mut buffer, default_out_dir())?;
     generate_decl::<T>(&mut buffer);
+    buffer.push('\n');
     Ok(buffer)
 }
 


Test patch:
diff --git a/ts-rs/tests/integration/docs.rs b/ts-rs/tests/integration/docs.rs
index d989fa01..5fec1b92 100644
--- a/ts-rs/tests/integration/docs.rs
+++ b/ts-rs/tests/integration/docs.rs
@@ -132,7 +132,8 @@ fn export_a() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "name: string, };"
+            "name: string, };",
+            "\n",
         )
     };
 
@@ -179,6 +180,7 @@ fn export_b() {
             " * Testing\n",
             " */\n",
             "name: string, };",
+            "\n",
         )
     };
 
@@ -200,7 +202,7 @@ fn export_c() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type C = Record<string, never>;\n"
+            "export type C = Record<string, never>;\n",
         )
     } else {
         concat!(
@@ -211,7 +213,8 @@ fn export_c() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type C = Record<string, never>;"
+            "export type C = Record<string, never>;",
+            "\n",
         )
     };
 
@@ -233,7 +236,7 @@ fn export_d() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type D = null;\n"
+            "export type D = null;\n",
         )
     } else {
         concat!(
@@ -244,7 +247,8 @@ fn export_d() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type D = null;"
+            "export type D = null;",
+            "\n",
         )
     };
     let actual_content = fs::read_to_string(D::default_output_path().unwrap()).unwrap();
@@ -265,7 +269,7 @@ fn export_e() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type E = never;\n"
+            "export type E = never;\n",
         )
     } else {
         concat!(
@@ -276,7 +280,8 @@ fn export_e() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "export type E = never;"
+            "export type E = never;",
+            "\n",
         )
     };
 
@@ -307,7 +312,7 @@ fn export_f() {
             "     */\n",
             "    variant_field: number;\n",
             "  };\n",
-            "};\n"
+            "};\n",
         )
     } else {
         concat!(
@@ -324,7 +329,8 @@ fn export_f() {
             " *\n",
             " * Testing\n",
             " */\n",
-            "variant_field: number, } };"
+            "variant_field: number, } };",
+            "\n",
         )
     };
 
@@ -356,7 +362,7 @@ fn export_g() {
             "       */\n",
             "      variant_field: number;\n",
             "    };\n",
-            "  });\n"
+            "  });\n",
         )
     } else {
         concat!(
@@ -373,6 +379,7 @@ fn export_g() {
             " * Testing\n",
             " */\n",
             "variant_field: number, } });",
+            "\n",
         )
     };
 
diff --git a/ts-rs/tests/integration/export_manually.rs b/ts-rs/tests/integration/export_manually.rs
index cdf11187..f575fed6 100644
--- a/ts-rs/tests/integration/export_manually.rs
+++ b/ts-rs/tests/integration/export_manually.rs
@@ -27,12 +27,13 @@ fn export_manually() {
     let expected_content = if cfg!(feature = "format") {
         concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n\n",
-            "export type User = { name: string; age: number; active: boolean };\n"
+            "export type User = { name: string; age: number; active: boolean };\n",
         )
     } else {
         concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n",
-            "\nexport type User = { name: string, age: number, active: boolean, };"
+            "\nexport type User = { name: string, age: number, active: boolean, };",
+            "\n",
         )
     };
 
@@ -48,12 +49,13 @@ fn export_manually_dir() {
     let expected_content = if cfg!(feature = "format") {
         concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n\n",
-            "export type UserDir = { name: string; age: number; active: boolean };\n"
+            "export type UserDir = { name: string; age: number; active: boolean };\n",
         )
     } else {
         concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n",
-            "\nexport type UserDir = { name: string, age: number, active: boolean, };"
+            "\nexport type UserDir = { name: string, age: number, active: boolean, };",
+            "\n",
         )
     };
 
diff --git a/ts-rs/tests/integration/imports.rs b/ts-rs/tests/integration/imports.rs
index 85eca7c0..bd7e5f81 100644
--- a/ts-rs/tests/integration/imports.rs
+++ b/ts-rs/tests/integration/imports.rs
@@ -36,8 +36,7 @@ fn test_def() {
             "\n",
             "export type TestEnum = { \"C\": { value: TestTypeB<number> } } | {\n",
             "  \"A1\": { value: TestTypeA<number> };\n",
-            "} | { \"A2\": { value: TestTypeA<number> } };\n"
-
+            "} | { \"A2\": { value: TestTypeA<number> } };\n",
         ),
         (true, false) => concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n",
@@ -46,22 +45,23 @@ fn test_def() {
             "\n",
             "export type TestEnum = { \"C\": { value: TestTypeB<number> } } | {\n",
             "  \"A1\": { value: TestTypeA<number> };\n",
-            "} | { \"A2\": { value: TestTypeA<number> } };\n"
-
+            "} | { \"A2\": { value: TestTypeA<number> } };\n",
         ),
         (false, true) => concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n",
             "import type { TestTypeA } from \"./ts_rs_test_type_a.js\";\n",
             "import type { TestTypeB } from \"./ts_rs_test_type_b.js\";\n",
             "\n",
-            "export type TestEnum = { \"C\": { value: TestTypeB<number>, } } | { \"A1\": { value: TestTypeA<number>, } } | { \"A2\": { value: TestTypeA<number>, } };"
+            "export type TestEnum = { \"C\": { value: TestTypeB<number>, } } | { \"A1\": { value: TestTypeA<number>, } } | { \"A2\": { value: TestTypeA<number>, } };",
+            "\n",
         ),
         (false, false) => concat!(
             "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n",
             "import type { TestTypeA } from \"./ts_rs_test_type_a\";\n",
             "import type { TestTypeB } from \"./ts_rs_test_type_b\";\n",
             "\n",
-            "export type TestEnum = { \"C\": { value: TestTypeB<number>, } } | { \"A1\": { value: TestTypeA<number>, } } | { \"A2\": { value: TestTypeA<number>, } };"
+            "export type TestEnum = { \"C\": { value: TestTypeB<number>, } } | { \"A1\": { value: TestTypeA<number>, } } | { \"A2\": { value: TestTypeA<number>, } };",
+            "\n",
         ),
     };
 
diff --git a/ts-rs/tests/integration/issue_168.rs b/ts-rs/tests/integration/issue_168.rs
index d4f687e9..a82a580d 100644
--- a/ts-rs/tests/integration/issue_168.rs
+++ b/ts-rs/tests/integration/issue_168.rs
@@ -38,13 +38,13 @@ fn issue_168() {
         FooInlined::export_to_string().unwrap(),
         "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n\
          \n\
-         export type FooInlined = { map: { [key: number]: { map: { [key: number]: { map: { [key: number]: string }, } }, } }, };"
+         export type FooInlined = { map: { [key: number]: { map: { [key: number]: { map: { [key: number]: string }, } }, } }, };\n"
     );
     assert_eq!(
         Foo::export_to_string().unwrap(),
         "// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.\n\
          import type { Bar } from \"./Bar\";\n\
          \n\
-         export type Foo = { map: { [key: number]: Bar }, };"
+         export type Foo = { map: { [key: number]: Bar }, };\n"
     );
 }
diff --git a/ts-rs/tests/integration/issue_232.rs b/ts-rs/tests/integration/issue_232.rs
index 234c9b5c..5cb6f684 100644
--- a/ts-rs/tests/integration/issue_232.rs
+++ b/ts-rs/tests/integration/issue_232.rs
@@ -53,7 +53,7 @@ fn issue_232() {
         export type StateInlined = { \
             a: { Ok : { name: string, inner: Enum, } } | { Err : string }, \
             b: { Ok : { name: string, inner: Enum, } } | { Err : string }, \
-        };"
+        };\n"
     );
     assert_eq!(
         State::export_to_string().unwrap(),
@@ -63,6 +63,6 @@ fn issue_232() {
         export type State = { \
             a: { Ok : EnumWithName } | { Err : string }, \
             b: { Ok : EnumWithName } | { Err : string }, \
-        };"
+        };\n"
     );
 }