From 12101c2d5103bfe567e0ab30080f7e8aa4d5fb2f Mon Sep 17 00:00:00 2001 From: SteveBeeblebrox <41750582+SteveBeeblebrox@users.noreply.github.com> Date: Wed, 13 Apr 2022 19:36:31 -0600 Subject: [PATCH] TypeScript 4.6.3, JSX, and quality of life changes --- .gitignore | 4 +-- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++-------- test.ts | 8 +++--- test.tsx | 4 +++ 6 files changed, 78 insertions(+), 21 deletions(-) create mode 100644 test.tsx diff --git a/.gitignore b/.gitignore index 7ea5017..e1d6a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ /target -/.mtsc -test.js -/src/typescriptServices.js +*.js \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 74c57ea..288519a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -429,7 +429,7 @@ dependencies = [ [[package]] name = "mtsc" -version = "4.4.4" +version = "4.6.3" dependencies = [ "clap", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index d575f9b..8304dad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mtsc" -version = "4.4.4" +version = "4.6.3" edition = "2018" authors = ["S. Beeblebrox"] # license = "MIT" diff --git a/src/main.rs b/src/main.rs index 6377b54..b5b9221 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use clap::{Arg, App}; use std::convert::TryFrom; use std::io::prelude::*; use std::path::PathBuf; +use std::path::Path; use std::fs::File; use std::fs; @@ -34,11 +35,29 @@ fn main() { .takes_value(true) ) + .arg(Arg::with_name("jsx") + .short("x") + .long("jsx") + .value_name("JSX") + .help("Sets the JSX factory for compiled code (When this option is set but blank or when the file extension is .tsx, JSX is preserved as is; otherwise, it is interpreted as standard code)") + .default_value("") + .takes_value(true) + ) + + .arg(Arg::with_name("jsx-fragment") + .long("jsx-fragment") + .value_name("JSX-FRAGMENT") + .help("Sets the JSX fragment for compiled code (Requires the jsx option to be set as well)") + .default_value("null") + .takes_value(true) + ) + .arg(Arg::with_name("output") .short("o") .long("out") .value_name("OUTPUT") - .help("Sets the output file to write transpiled code to (Leave blank to write to the console)") + .help("Sets the output file to write transpiled code to instead of using the input file's name with the extension changed to .js (When set but blank, output is written to stdout; if set to a directory and an input file is provided, the output file will be written to the given directory with the extension changed to .js)") + .default_value("") .takes_value(true) ) @@ -48,30 +67,35 @@ fn main() { ) .get_matches(); - let (input_file, input_text) = match matches.value_of("INPUT") { - Some(value) => (Some(String::from(value)), fs::read_to_string(value).expect("Error reading target file")), + let (input_file, input_text, input_type) = match matches.value_of("INPUT") { + Some(value) => (Some(String::from(value)), fs::read_to_string(value).expect("Error reading target file"), Path::new(value).extension().expect("Error getting file extension").to_str().expect("Error getting file extension").to_string()), None => { let stdin = io::stdin(); let mut stdin = stdin.lock(); let mut line = String::new(); stdin.read_to_string(&mut line).expect("Error reading stdin"); - (None, String::from(line)) + (None, String::from(line), String::from("")) } }; + let (use_jsx, jsx_factory, jsx_fragment) = match matches.value_of("jsx") { + Some("") if matches.occurrences_of("jsx") > 0 => (if matches.occurrences_of("jsx") > 0 {true} else {false}, None, None), + None | Some("") => (input_type == "tsx", None, None), + Some(value) => (true, Some(String::from(value)), Some(String::from(matches.value_of("jsx-fragment").unwrap()))), + }; + let result = compile_typescript(input_text.as_str(), CompileOptions { target: String::from(matches.value_of("target").unwrap()), - module: String::from(matches.value_of("module").unwrap()) + module: String::from(matches.value_of("module").unwrap()), + use_jsx, + jsx_factory, + jsx_fragment }).expect("Error compiling TypeScript"); match matches.value_of("output") { - Some("") => print!("{}", result.as_str()), - Some(path) => { - let mut file = File::create(path).expect("Error creating output file"); - file.write_all(result.as_bytes()).expect("Error writing to output file"); - }, - None => { + Some("") if matches.occurrences_of("output") > 0 => print!("{}", result.as_str()), + None | Some("") => { match input_file { Some(input_file) => { let mut path = PathBuf::from(input_file); @@ -82,12 +106,28 @@ fn main() { None => print!("{}", result.as_str()) } } + Some(path) => { + let path = if Path::new(path).exists() && fs::metadata(path).expect("Error reading file metadata").is_dir() && input_file.is_some() { + let mut path = PathBuf::from(path); + path.push(Path::new(&input_file.unwrap().to_string()).file_name().expect("Error getting file name").to_str().expect("Error getting file name")); + path.set_extension("js"); + path + } else { + PathBuf::from(path) + }; + + let mut file = File::create(path).expect("Error creating output file"); + file.write_all(result.as_bytes()).expect("Error writing to output file"); + } } } struct CompileOptions { target: String, - module: String + module: String, + use_jsx: bool, + jsx_factory: Option, + jsx_fragment: Option } fn compile_typescript(text: &str, options: CompileOptions) -> Option { @@ -125,6 +165,21 @@ fn compile_typescript(text: &str, options: CompileOptions) -> Option { let module_prop_value = v8::String::new(scope, options.module.as_str())?.into(); args.set(scope, module_prop_name, module_prop_value); + if options.use_jsx { + let jsx_factory_prop_name = v8::String::new(scope, "jsx")?.into(); + let jsx_factory_prop_value = v8::String::new(scope, if options.jsx_factory.is_some() {"react"} else {"preserve"})?.into(); + args.set(scope, jsx_factory_prop_name, jsx_factory_prop_value); + + if options.jsx_factory.is_some() { + let jsx_factory_prop_name = v8::String::new(scope, "jsxFactory")?.into(); + let jsx_factory_prop_value = v8::String::new(scope, options.jsx_factory.unwrap().as_str())?.into(); + args.set(scope, jsx_factory_prop_name, jsx_factory_prop_value); + + let jsx_fragment_prop_name = v8::String::new(scope, "jsxFragmentFactory")?.into(); + let jsx_fragment_prop_value = v8::String::new(scope, options.jsx_fragment.unwrap().as_str())?.into(); + args.set(scope, jsx_fragment_prop_name, jsx_fragment_prop_value); + } + } return Some(transpile_function.call(scope, ts_obj, &[text, args.into()])?.to_string(scope)? .to_rust_string_lossy(scope)) diff --git a/test.ts b/test.ts index 01737a2..01fff7f 100644 --- a/test.ts +++ b/test.ts @@ -1,5 +1,5 @@ -type MyNumber = number -const x: MyNumber = 1; +type NumberLike = number | string +const x: NumberLike = '7'; function doStuff(...args: string[]): boolean { - return true; -} + return +x === 7; +} \ No newline at end of file diff --git a/test.tsx b/test.tsx new file mode 100644 index 0000000..1396241 --- /dev/null +++ b/test.tsx @@ -0,0 +1,4 @@ +let content = <> +

Hello

+

World

+ \ No newline at end of file