diff --git a/src/commands/init.rs b/src/commands/init.rs index 45ba5a5..78fa6c6 100644 --- a/src/commands/init.rs +++ b/src/commands/init.rs @@ -1,3 +1,5 @@ +use crate::commands::sync::config::CodegenLanguage; + use super::sync::config::{CodegenConfig, CodegenStyle, Creator, CreatorType, SyncConfig}; use anyhow::Context; use console::style; @@ -52,11 +54,13 @@ pub async fn init() -> anyhow::Result<()> { .prompt_skippable() .unwrap_or_else(|_| exit(1)); - let typescript = Confirm::new("TypeScript support") - .with_help_message("Generate TypeScript definition files.") - .with_default(false) - .prompt() - .unwrap_or_else(|_| exit(1)); + let codegen_language = Select::new( + "Language", + vec![CodegenLanguage::Luau, CodegenLanguage::TypeScript], + ) + .with_help_message("The language to generate code in.") + .prompt() + .unwrap_or_else(|_| exit(1)); let codegen_style = Select::new("Style", vec![CodegenStyle::Flat, CodegenStyle::Nested]) .with_help_message("The style to use for generated code.") @@ -76,7 +80,7 @@ pub async fn init() -> anyhow::Result<()> { creator: Creator { creator_type, id }, codegen: CodegenConfig { output_name, - typescript: Some(typescript), + language: Some(codegen_language), style: Some(codegen_style), strip_extension: Some(strip_extension), }, diff --git a/src/commands/sync/codegen/ast.rs b/src/commands/sync/codegen/ast.rs index c489a63..eaed0ae 100644 --- a/src/commands/sync/codegen/ast.rs +++ b/src/commands/sync/codegen/ast.rs @@ -97,7 +97,7 @@ impl AstFormat for ReturnStatement { write!(output, "return ") } AstTarget::Typescript { output_dir } => { - write!(output, "declare const {output_dir}: ") + write!(output, "const {output_dir} = ") } }?; @@ -148,7 +148,7 @@ impl AstFormat for Table { fn fmt_ast(&self, output: &mut AstStream<'_, '_>) -> fmt::Result { let typescript = matches!(output.target, AstTarget::Typescript { .. }); let (assignment, ending) = if typescript { - (": ", ";") + (": ", ",") } else { (" = ", ",") }; diff --git a/src/commands/sync/codegen/mod.rs b/src/commands/sync/codegen/mod.rs index dd93423..b0f36e3 100644 --- a/src/commands/sync/codegen/mod.rs +++ b/src/commands/sync/codegen/mod.rs @@ -5,32 +5,33 @@ use ast::{AstTarget, Expression, ReturnStatement}; use crate::commands::sync::config::CodegenStyle; +use super::config::CodegenLanguage; + mod ast; mod flat; mod nested; -pub fn generate_luau( - assets: &BTreeMap, - strip_dir: &str, - style: &CodegenStyle, - strip_extension: bool, -) -> anyhow::Result { - match style { - CodegenStyle::Flat => flat::generate_luau(assets, strip_dir, strip_extension), - CodegenStyle::Nested => nested::generate_luau(assets, strip_dir, strip_extension), - } -} - -pub fn generate_ts( +pub fn generate_file( assets: &BTreeMap, strip_dir: &str, output_dir: &str, + language: &CodegenLanguage, style: &CodegenStyle, strip_extension: bool, ) -> anyhow::Result { - match style { - CodegenStyle::Flat => flat::generate_ts(assets, strip_dir, output_dir, strip_extension), - CodegenStyle::Nested => nested::generate_ts(assets, strip_dir, output_dir, strip_extension), + match (language, style) { + (CodegenLanguage::Luau, CodegenStyle::Flat) => { + flat::generate_luau(assets, strip_dir, strip_extension) + } + (CodegenLanguage::TypeScript, CodegenStyle::Flat) => { + flat::generate_ts(assets, strip_dir, output_dir, strip_extension) + } + (CodegenLanguage::Luau, CodegenStyle::Nested) => { + nested::generate_luau(assets, strip_dir, strip_extension) + } + (CodegenLanguage::TypeScript, CodegenStyle::Nested) => { + nested::generate_ts(assets, strip_dir, output_dir, strip_extension) + } } } @@ -73,10 +74,10 @@ mod tests { let lockfile = test_assets(); let ts = super::flat::generate_ts(&lockfile, "assets", "assets", false).unwrap(); - assert_eq!(ts, "declare const assets: {\n\t\"/bar/baz.png\": \"rbxasset://.asphalt/bar/baz.png\";\n\t\"/foo.png\": \"rbxassetid://1\";\n};\nexport = assets;\n"); + assert_eq!(ts, "const assets = {\n\t\"/bar/baz.png\": \"rbxasset://.asphalt/bar/baz.png\";\n\t\"/foo.png\": \"rbxassetid://1\";\n};\nexport = assets;\n"); let ts = super::flat::generate_ts(&lockfile, "assets", "assets", true).unwrap(); - assert_eq!(ts, "declare const assets: {\n\t\"/bar/baz\": \"rbxasset://.asphalt/bar/baz.png\";\n\t\"/foo\": \"rbxassetid://1\";\n};\nexport = assets;\n"); + assert_eq!(ts, "const assets = {\n\t\"/bar/baz\": \"rbxasset://.asphalt/bar/baz.png\";\n\t\"/foo\": \"rbxassetid://1\";\n};\nexport = assets;\n"); } #[test] @@ -103,13 +104,13 @@ mod tests { let ts = super::nested::generate_ts(&lockfile, "assets", "assets", false).unwrap(); assert_eq!( ts, - "declare const assets: {\n\tbar: {\n\t\t\"baz.png\": \"rbxasset://.asphalt/bar/baz.png\";\n\t};\n\t\"foo.png\": \"rbxassetid://1\";\n};\nexport = assets;\n" + "const assets = {\n\tbar: {\n\t\t\"baz.png\": \"rbxasset://.asphalt/bar/baz.png\";\n\t};\n\t\"foo.png\": \"rbxassetid://1\";\n};\nexport = assets;\n" ); let ts = super::nested::generate_ts(&lockfile, "assets", "assets", true).unwrap(); assert_eq!( ts, - "declare const assets: {\n\tbar: {\n\t\tbaz: \"rbxasset://.asphalt/bar/baz.png\";\n\t};\n\tfoo: \"rbxassetid://1\";\n};\nexport = assets;\n" + "const assets = {\n\tbar: {\n\t\tbaz: \"rbxasset://.asphalt/bar/baz.png\";\n\t};\n\tfoo: \"rbxassetid://1\";\n};\nexport = assets;\n" ); } } diff --git a/src/commands/sync/config.rs b/src/commands/sync/config.rs index de5d9cc..d2cc386 100644 --- a/src/commands/sync/config.rs +++ b/src/commands/sync/config.rs @@ -22,6 +22,31 @@ impl Display for CodegenStyle { } } +#[derive(Debug, Deserialize, Serialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum CodegenLanguage { + Luau, + TypeScript, +} + +impl Display for CodegenLanguage { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CodegenLanguage::Luau => write!(f, "Luau"), + CodegenLanguage::TypeScript => write!(f, "TypeScript"), + } + } +} + +impl CodegenLanguage { + pub fn extension(&self) -> &'static str { + match self { + CodegenLanguage::Luau => "luau", + CodegenLanguage::TypeScript => "ts", + } + } +} + #[derive(Debug, Deserialize, Serialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum CreatorType { @@ -53,7 +78,7 @@ pub struct ExistingAsset { #[derive(Debug, Deserialize, Serialize)] pub struct CodegenConfig { pub output_name: Option, - pub typescript: Option, + pub language: Option, pub style: Option, pub strip_extension: Option, } diff --git a/src/commands/sync/mod.rs b/src/commands/sync/mod.rs index 46b859f..618e3cd 100644 --- a/src/commands/sync/mod.rs +++ b/src/commands/sync/mod.rs @@ -8,7 +8,7 @@ use anyhow::Context; use backend::{ cloud::CloudBackend, debug::DebugBackend, studio::StudioBackend, SyncBackend, SyncResult, }; -use codegen::{generate_luau, generate_ts}; +use codegen::generate_file; use config::SyncConfig; use log::{debug, info, warn}; use std::{ @@ -189,30 +189,22 @@ pub async fn sync(args: SyncArgs, existing_lockfile: LockFile) -> anyhow::Result .map(|(path, asset)| (path, format_asset_id(asset.id))), ); - let luau_filename = format!("{}.{}", state.output_name, "luau"); - let luau_output = generate_luau(&assets, asset_dir, &state.style, state.strip_extension); + let codegen_output = generate_file( + &assets, + asset_dir, + &state.output_name, + &state.language, + &state.style, + state.strip_extension, + )?; + let codegen_filename = format!("{}.{}", state.output_name, state.language.extension()); write( - Path::new(&state.write_dir).join(luau_filename), - luau_output?, + Path::new(&state.write_dir).join(codegen_filename), + codegen_output, ) .await - .context("Failed to write output Luau file")?; - - if state.typescript { - let ts_filename = format!("{}.d.ts", state.output_name); - let ts_output = generate_ts( - &assets, - asset_dir, - state.output_name.as_str(), - &state.style, - state.strip_extension, - ); - - write(Path::new(&state.write_dir).join(ts_filename), ts_output?) - .await - .context("Failed to write output TypeScript file")?; - } + .context("Failed to write output file")?; info!( "Synced {} asset{}!", diff --git a/src/commands/sync/state.rs b/src/commands/sync/state.rs index 495d54d..403e74b 100644 --- a/src/commands/sync/state.rs +++ b/src/commands/sync/state.rs @@ -1,4 +1,4 @@ -use super::config::{CodegenStyle, CreatorType, ExistingAsset, SyncConfig}; +use super::config::{CodegenLanguage, CodegenStyle, CreatorType, ExistingAsset, SyncConfig}; use crate::{ cli::{SyncArgs, SyncTarget}, LockFile, @@ -53,7 +53,7 @@ pub struct SyncState { pub creator: AssetCreator, - pub typescript: bool, + pub language: CodegenLanguage, pub output_name: String, pub style: CodegenStyle, pub strip_extension: bool, @@ -101,7 +101,7 @@ impl SyncState { .unwrap_or(&"assets".to_string()) .to_string(); - let typescript = config.codegen.typescript.unwrap_or(false); + let language = config.codegen.language.unwrap_or(CodegenLanguage::Luau); let style = config.codegen.style.unwrap_or(CodegenStyle::Flat); let strip_extension = config.codegen.strip_extension.unwrap_or(false); @@ -126,7 +126,7 @@ impl SyncState { exclude_assets_matcher, api_key, creator, - typescript, + language, output_name, style, strip_extension,