mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Rewrite setup subcommand to be more permissive and user friendly
This commit is contained in:
parent
65f2319a64
commit
66e122ea63
15 changed files with 149 additions and 254 deletions
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
|
@ -3,14 +3,8 @@
|
||||||
"luau-lsp.sourcemap.enabled": false,
|
"luau-lsp.sourcemap.enabled": false,
|
||||||
"luau-lsp.types.roblox": false,
|
"luau-lsp.types.roblox": false,
|
||||||
"luau-lsp.require.mode": "relativeToFile",
|
"luau-lsp.require.mode": "relativeToFile",
|
||||||
"luau-lsp.require.fileAliases": {
|
"luau-lsp.require.directoryAliases": {
|
||||||
"@lune/fs": "./docs/typedefs/FS.luau",
|
"@lune/": "./docs/typedefs"
|
||||||
"@lune/net": "./docs/typedefs/Net.luau",
|
|
||||||
"@lune/process": "./docs/typedefs/Process.luau",
|
|
||||||
"@lune/roblox": "./docs/typedefs/Roblox.luau",
|
|
||||||
"@lune/serde": "./docs/typedefs/Serde.luau",
|
|
||||||
"@lune/stdio": "./docs/typedefs/Stdio.luau",
|
|
||||||
"@lune/task": "./docs/typedefs/Task.luau"
|
|
||||||
},
|
},
|
||||||
// Luau - ignore type defs file in docs dir and dev scripts we use
|
// Luau - ignore type defs file in docs dir and dev scripts we use
|
||||||
"luau-lsp.ignoreGlobs": [
|
"luau-lsp.ignoreGlobs": [
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1135,6 +1135,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ console = "0.15"
|
||||||
directories = "5.0"
|
directories = "5.0"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
once_cell = "1.17"
|
once_cell = "1.17"
|
||||||
|
thiserror = "1.0"
|
||||||
|
|
||||||
mlua = { version = "0.9.0-beta.3", features = ["luau", "serialize"] }
|
mlua = { version = "0.9.0-beta.3", features = ["luau", "serialize"] }
|
||||||
tokio = { version = "1.24", features = ["full"] }
|
tokio = { version = "1.24", features = ["full"] }
|
||||||
|
|
|
@ -31,6 +31,7 @@ serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde_yaml.workspace = true
|
serde_yaml.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
|
|
@ -1,32 +1,22 @@
|
||||||
use std::{
|
use std::{fmt::Write as _, process::ExitCode};
|
||||||
borrow::BorrowMut,
|
|
||||||
collections::HashMap,
|
|
||||||
fmt::Write as _,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
process::ExitCode,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use serde_json::Value as JsonValue;
|
|
||||||
|
|
||||||
use include_dir::{include_dir, Dir};
|
|
||||||
use lune::Lune;
|
use lune::Lune;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::{self, read as read_to_vec},
|
fs::read as read_to_vec,
|
||||||
io::{stdin, AsyncReadExt},
|
io::{stdin, AsyncReadExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
gen::{generate_gitbook_dir_from_definitions, generate_typedef_files_from_definitions},
|
setup::run_setup,
|
||||||
utils::{
|
utils::{
|
||||||
files::{discover_script_file_path_including_lune_dirs, strip_shebang},
|
files::{discover_script_file_path_including_lune_dirs, strip_shebang},
|
||||||
listing::{find_lune_scripts, sort_lune_scripts, write_lune_scripts_list},
|
listing::{find_lune_scripts, sort_lune_scripts, write_lune_scripts_list},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) static TYPEDEFS_DIR: Dir<'_> = include_dir!("docs/typedefs");
|
|
||||||
|
|
||||||
/// A Luau script runner
|
/// A Luau script runner
|
||||||
#[derive(Parser, Debug, Default, Clone)]
|
#[derive(Parser, Debug, Default, Clone)]
|
||||||
#[command(version, long_about = None)]
|
#[command(version, long_about = None)]
|
||||||
|
@ -51,9 +41,6 @@ pub struct Cli {
|
||||||
/// Generate a Lune documentation file for Luau LSP
|
/// Generate a Lune documentation file for Luau LSP
|
||||||
#[clap(long, hide = true)]
|
#[clap(long, hide = true)]
|
||||||
generate_docs_file: bool,
|
generate_docs_file: bool,
|
||||||
/// Generate the full Lune gitbook directory
|
|
||||||
#[clap(long, hide = true)]
|
|
||||||
generate_gitbook_dir: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -134,61 +121,21 @@ impl Cli {
|
||||||
let generate_file_requested = self.setup
|
let generate_file_requested = self.setup
|
||||||
|| self.generate_luau_types
|
|| self.generate_luau_types
|
||||||
|| self.generate_selene_types
|
|| self.generate_selene_types
|
||||||
|| self.generate_docs_file
|
|| self.generate_docs_file;
|
||||||
|| self.generate_gitbook_dir;
|
|
||||||
if generate_file_requested {
|
if generate_file_requested {
|
||||||
if self.generate_gitbook_dir {
|
|
||||||
generate_gitbook_dir_from_definitions(&TYPEDEFS_DIR).await?;
|
|
||||||
}
|
|
||||||
if (self.generate_luau_types || self.generate_selene_types || self.generate_docs_file)
|
if (self.generate_luau_types || self.generate_selene_types || self.generate_docs_file)
|
||||||
&& !self.setup
|
&& !self.setup
|
||||||
{
|
{
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"\
|
"\
|
||||||
Typedef & docs generation files have been superseded by the --setup command.\
|
Typedef & docs generation commands have been superseded by the setup command.\
|
||||||
Run lune --setup in your terminal to configure typedef files.
|
Run `lune --setup` in your terminal to configure your editor and type definitions.
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
return Ok(ExitCode::FAILURE);
|
return Ok(ExitCode::FAILURE);
|
||||||
}
|
}
|
||||||
if self.setup {
|
if self.setup {
|
||||||
let generated_paths =
|
run_setup().await;
|
||||||
generate_typedef_files_from_definitions(&TYPEDEFS_DIR).await?;
|
|
||||||
let settings_json_path = PathBuf::from(".vscode/settings.json");
|
|
||||||
let message = match fs::metadata(&settings_json_path).await {
|
|
||||||
Ok(meta) if meta.is_file() => {
|
|
||||||
if try_add_generated_typedefs_vscode(&settings_json_path, &generated_paths).await.is_err() {
|
|
||||||
"These files can be added to your LSP settings for autocomplete and documentation."
|
|
||||||
} else {
|
|
||||||
"These files have now been added to your workspace LSP settings for Visual Studio Code."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => "These files can be added to your LSP settings for autocomplete and documentation.",
|
|
||||||
};
|
|
||||||
// HACK: We should probably just be serializing this hashmap to print it out, but
|
|
||||||
// that does not guarantee sorting and the sorted version is much easier to read
|
|
||||||
let mut sorted_names = generated_paths
|
|
||||||
.keys()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
sorted_names.sort_unstable();
|
|
||||||
println!(
|
|
||||||
"Typedefs have been generated in the following locations:\n{{\n{}\n}}\n{message}",
|
|
||||||
sorted_names
|
|
||||||
.iter()
|
|
||||||
.map(|name| {
|
|
||||||
let path = generated_paths.get(name).unwrap();
|
|
||||||
format!(
|
|
||||||
" \"@lune/{}\": \"{}\",",
|
|
||||||
name,
|
|
||||||
path.canonicalize().unwrap().display()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
.strip_suffix(',')
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.script_path.is_none() {
|
if self.script_path.is_none() {
|
||||||
|
@ -236,29 +183,3 @@ impl Cli {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_add_generated_typedefs_vscode(
|
|
||||||
settings_json_path: &Path,
|
|
||||||
generated_paths: &HashMap<String, PathBuf>,
|
|
||||||
) -> Result<()> {
|
|
||||||
// FUTURE: Use a jsonc or json5 to read this file instead since it may contain comments and fail
|
|
||||||
let settings_json_contents = fs::read(settings_json_path).await?;
|
|
||||||
let mut settings_changed: bool = false;
|
|
||||||
let mut settings_json: JsonValue = serde_json::from_slice(&settings_json_contents)?;
|
|
||||||
if let JsonValue::Object(settings) = settings_json.borrow_mut() {
|
|
||||||
if let Some(JsonValue::Object(aliases)) = settings.get_mut("luau-lsp.require.fileAliases") {
|
|
||||||
for (name, path) in generated_paths {
|
|
||||||
settings_changed = true;
|
|
||||||
aliases.insert(
|
|
||||||
format!("@lune/{name}"),
|
|
||||||
JsonValue::String(path.canonicalize().unwrap().to_string_lossy().to_string()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings_changed {
|
|
||||||
let settings_json_new = serde_json::to_vec_pretty(&settings_json)?;
|
|
||||||
fs::write(settings_json_path, settings_json_new).await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use include_dir::Dir;
|
use include_dir::Dir;
|
||||||
|
@ -15,9 +15,7 @@ pub async fn generate_gitbook_dir_from_definitions(dir: &Dir<'_>) -> Result<()>
|
||||||
gitbook_dir::generate_from_type_definitions(definitions).await
|
gitbook_dir::generate_from_type_definitions(definitions).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate_typedef_files_from_definitions(
|
pub async fn generate_typedef_files_from_definitions(dir: &Dir<'_>) -> Result<String> {
|
||||||
dir: &Dir<'_>,
|
|
||||||
) -> Result<HashMap<String, PathBuf>> {
|
|
||||||
let contents = read_typedefs_dir_contents(dir);
|
let contents = read_typedefs_dir_contents(dir);
|
||||||
typedef_files::generate_from_type_definitions(contents).await
|
typedef_files::generate_from_type_definitions(contents).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use directories::UserDirs;
|
use directories::UserDirs;
|
||||||
|
@ -9,7 +9,8 @@ use tokio::fs::{create_dir_all, write};
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
pub async fn generate_from_type_definitions(
|
pub async fn generate_from_type_definitions(
|
||||||
typedef_files: HashMap<String, Vec<u8>>,
|
typedef_files: HashMap<String, Vec<u8>>,
|
||||||
) -> Result<HashMap<String, PathBuf>> {
|
) -> Result<String> {
|
||||||
|
let version_string = env!("CARGO_PKG_VERSION");
|
||||||
let mut dirs_to_write = Vec::new();
|
let mut dirs_to_write = Vec::new();
|
||||||
let mut files_to_write = Vec::new();
|
let mut files_to_write = Vec::new();
|
||||||
// Create the typedefs dir in the users cache dir
|
// Create the typedefs dir in the users cache dir
|
||||||
|
@ -18,7 +19,7 @@ pub async fn generate_from_type_definitions(
|
||||||
.home_dir()
|
.home_dir()
|
||||||
.join(".lune")
|
.join(".lune")
|
||||||
.join(".typedefs")
|
.join(".typedefs")
|
||||||
.join(env!("CARGO_PKG_VERSION"));
|
.join(version_string);
|
||||||
dirs_to_write.push(cache_dir.clone());
|
dirs_to_write.push(cache_dir.clone());
|
||||||
// Make typedef files
|
// Make typedef files
|
||||||
for (builtin_name, builtin_typedef) in typedef_files {
|
for (builtin_name, builtin_typedef) in typedef_files {
|
||||||
|
@ -38,8 +39,5 @@ pub async fn generate_from_type_definitions(
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
try_join_all(futs_dirs).await?;
|
try_join_all(futs_dirs).await?;
|
||||||
try_join_all(futs_files).await?;
|
try_join_all(futs_files).await?;
|
||||||
Ok(files_to_write
|
Ok(version_string.to_string())
|
||||||
.drain(..)
|
|
||||||
.map(|(name, path, _)| (name, path))
|
|
||||||
.collect::<HashMap<_, _>>())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,9 @@ use clap::Parser;
|
||||||
|
|
||||||
pub(crate) mod cli;
|
pub(crate) mod cli;
|
||||||
pub(crate) mod gen;
|
pub(crate) mod gen;
|
||||||
|
pub(crate) mod setup;
|
||||||
pub(crate) mod utils;
|
pub(crate) mod utils;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
use cli::Cli;
|
use cli::Cli;
|
||||||
use console::style;
|
use console::style;
|
||||||
|
|
||||||
|
|
128
packages/cli/src/setup/mod.rs
Normal file
128
packages/cli/src/setup/mod.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
use std::{borrow::BorrowMut, env::current_dir, io::ErrorKind, path::PathBuf};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use include_dir::{include_dir, Dir};
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::fs;
|
||||||
|
|
||||||
|
// TODO: Use a library that supports json with comments since VSCode settings may contain comments
|
||||||
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
|
use crate::gen::generate_typedef_files_from_definitions;
|
||||||
|
|
||||||
|
pub(crate) static TYPEDEFS_DIR: Dir<'_> = include_dir!("docs/typedefs");
|
||||||
|
|
||||||
|
pub(crate) static SETTING_NAME_MODE: &str = "luau-lsp.require.mode";
|
||||||
|
pub(crate) static SETTING_NAME_ALIASES: &str = "luau-lsp.require.directoryAliases";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Error)]
|
||||||
|
enum SetupError {
|
||||||
|
#[error("Failed to read settings")]
|
||||||
|
Read,
|
||||||
|
#[error("Failed to write settings")]
|
||||||
|
Write,
|
||||||
|
#[error("Failed to parse settings")]
|
||||||
|
Deserialize,
|
||||||
|
#[error("Failed to create settings")]
|
||||||
|
Serialize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lune_version() -> &'static str {
|
||||||
|
env!("CARGO_PKG_VERSION")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vscode_path() -> PathBuf {
|
||||||
|
current_dir()
|
||||||
|
.expect("No current dir")
|
||||||
|
.join(".vscode")
|
||||||
|
.join("settings.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_or_create_vscode_settings_json() -> Result<JsonValue, SetupError> {
|
||||||
|
let path_file = vscode_path();
|
||||||
|
let mut path_dir = path_file.clone();
|
||||||
|
path_dir.pop();
|
||||||
|
match fs::read(&path_file).await {
|
||||||
|
Err(e) if e.kind() == ErrorKind::NotFound => {
|
||||||
|
// TODO: Make sure that VSCode is actually installed, or
|
||||||
|
// let the user choose their editor for interactive setup
|
||||||
|
match fs::create_dir_all(path_dir).await {
|
||||||
|
Err(_) => Err(SetupError::Write),
|
||||||
|
Ok(_) => match fs::write(path_file, "{}").await {
|
||||||
|
Err(_) => Err(SetupError::Write),
|
||||||
|
Ok(_) => Ok(JsonValue::Object(serde_json::Map::new())),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Err(SetupError::Read),
|
||||||
|
Ok(contents) => match serde_json::from_slice(&contents) {
|
||||||
|
Err(_) => Err(SetupError::Deserialize),
|
||||||
|
Ok(json) => Ok(json),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_vscode_settings_json(value: JsonValue) -> Result<(), SetupError> {
|
||||||
|
match serde_json::to_vec_pretty(&value) {
|
||||||
|
Err(_) => Err(SetupError::Serialize),
|
||||||
|
Ok(json) => match fs::write(vscode_path(), json).await {
|
||||||
|
Err(_) => Err(SetupError::Write),
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_values_to_vscode_settings_json(value: JsonValue) -> JsonValue {
|
||||||
|
let mut settings_json = value;
|
||||||
|
if let JsonValue::Object(settings) = settings_json.borrow_mut() {
|
||||||
|
// Set require mode
|
||||||
|
let mode_val = "relativeToFile".to_string();
|
||||||
|
settings.insert(SETTING_NAME_MODE.to_string(), JsonValue::String(mode_val));
|
||||||
|
// Set require alias to our typedefs
|
||||||
|
let aliases_key = "@lune/".to_string();
|
||||||
|
let aliases_val = format!("~/.lune/.typedefs/{}/", lune_version());
|
||||||
|
if let Some(JsonValue::Object(aliases)) = settings.get_mut(SETTING_NAME_ALIASES) {
|
||||||
|
if aliases.contains_key(&aliases_key) {
|
||||||
|
if aliases.get(&aliases_key).unwrap() != &JsonValue::String(aliases_val.to_string())
|
||||||
|
{
|
||||||
|
aliases.insert(aliases_key, JsonValue::String(aliases_val));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aliases.insert(aliases_key, JsonValue::String(aliases_val));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut map = serde_json::Map::new();
|
||||||
|
map.insert(aliases_key, JsonValue::String(aliases_val));
|
||||||
|
settings.insert(SETTING_NAME_ALIASES.to_string(), JsonValue::Object(map));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings_json
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_setup() {
|
||||||
|
generate_typedef_files_from_definitions(&TYPEDEFS_DIR)
|
||||||
|
.await
|
||||||
|
.expect("Failed to generate typedef files");
|
||||||
|
// TODO: Let the user interactively choose what editor to set up
|
||||||
|
let res = async {
|
||||||
|
let settings = read_or_create_vscode_settings_json().await?;
|
||||||
|
let modified = add_values_to_vscode_settings_json(settings);
|
||||||
|
write_vscode_settings_json(modified).await?;
|
||||||
|
Ok::<_, SetupError>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
let message = match res {
|
||||||
|
Ok(_) => "These settings have been added to your workspace for Visual Studio Code:",
|
||||||
|
Err(_) => "To finish setting up your editor, add these settings to your workspace:",
|
||||||
|
};
|
||||||
|
let version_string = lune_version();
|
||||||
|
println!(
|
||||||
|
"Lune has now been set up and editor type definitions have been generated.\
|
||||||
|
\n{message}\
|
||||||
|
\n\
|
||||||
|
\n\"{SETTING_NAME_MODE}\": \"relativeToFile\",\
|
||||||
|
\n\"{SETTING_NAME_ALIASES}\": {{\
|
||||||
|
\n \"@lune/\": \"~/.lune/.typedefs/{version_string}/\"\
|
||||||
|
\n}}",
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
use std::{env::set_current_dir, path::PathBuf};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
|
||||||
use tokio::fs::create_dir_all;
|
|
||||||
|
|
||||||
pub async fn enter_bin_dir() -> Result<()> {
|
|
||||||
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../bin");
|
|
||||||
if !path.exists() {
|
|
||||||
create_dir_all(&path)
|
|
||||||
.await
|
|
||||||
.context("Failed to enter bin dir")?;
|
|
||||||
set_current_dir(&path).context("Failed to set current dir")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn leave_bin_dir() -> Result<()> {
|
|
||||||
set_current_dir(env!("CARGO_MANIFEST_DIR")).context("Failed to leave bin dir")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
|
||||||
use tokio::fs::{read_to_string, remove_file};
|
|
||||||
|
|
||||||
use super::bin_dir::{enter_bin_dir, leave_bin_dir};
|
|
||||||
use super::file_type::FileType;
|
|
||||||
|
|
||||||
pub fn fmt_path_relative_to_workspace_root(value: &str) -> String {
|
|
||||||
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
||||||
.join("../../")
|
|
||||||
.canonicalize()
|
|
||||||
.unwrap();
|
|
||||||
match PathBuf::from(value).strip_prefix(root) {
|
|
||||||
Err(_) => format!("{:#?}", PathBuf::from(value).display()),
|
|
||||||
Ok(inner) => format!("{:#?}", inner.display()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn inner(file_name: &str, desired_type: FileType) -> Result<()> {
|
|
||||||
match read_to_string(file_name).await.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to read definitions file at '{}'",
|
|
||||||
fmt_path_relative_to_workspace_root(file_name)
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
Ok(file_contents) => {
|
|
||||||
remove_file(file_name).await.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to remove definitions file at '{}'",
|
|
||||||
fmt_path_relative_to_workspace_root(file_name)
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let parsed_type = FileType::sniff(&file_contents);
|
|
||||||
if parsed_type != Some(desired_type) {
|
|
||||||
bail!(
|
|
||||||
"Generating definitions file at '{}' created '{}', expected '{}'",
|
|
||||||
fmt_path_relative_to_workspace_root(file_name),
|
|
||||||
parsed_type.map_or("unknown", |t| t.name()),
|
|
||||||
desired_type.name()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => bail!(
|
|
||||||
"Failed to generate definitions file at '{}'\n{e}",
|
|
||||||
fmt_path_relative_to_workspace_root(file_name)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn ensure_file_exists_and_is(file_name: &str, desired_type: FileType) -> Result<()> {
|
|
||||||
enter_bin_dir().await?;
|
|
||||||
let res = inner(file_name, desired_type).await;
|
|
||||||
leave_bin_dir()?;
|
|
||||||
res
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
use serde_json::Value as JsonValue;
|
|
||||||
use serde_yaml::Value as YamlValue;
|
|
||||||
|
|
||||||
use crate::gen::definitions::DefinitionsTree;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum FileType {
|
|
||||||
Json,
|
|
||||||
Yaml,
|
|
||||||
Luau,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FileType {
|
|
||||||
pub fn sniff(contents: &str) -> Option<Self> {
|
|
||||||
if serde_json::from_str::<JsonValue>(contents).is_ok() {
|
|
||||||
Some(Self::Json)
|
|
||||||
} else if serde_yaml::from_str::<YamlValue>(contents).is_ok() {
|
|
||||||
Some(Self::Yaml)
|
|
||||||
} else if DefinitionsTree::from_type_definitions(contents).is_ok() {
|
|
||||||
Some(Self::Luau)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
FileType::Json => "json",
|
|
||||||
FileType::Yaml => "yaml",
|
|
||||||
FileType::Luau => "luau",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use crate::cli::Cli;
|
|
||||||
|
|
||||||
mod bin_dir;
|
|
||||||
mod file_checks;
|
|
||||||
mod file_type;
|
|
||||||
mod run_cli;
|
|
||||||
|
|
||||||
pub(crate) use run_cli::*;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn list() -> Result<()> {
|
|
||||||
Cli::new().list().run().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn generate_typedef_files() -> Result<()> {
|
|
||||||
run_cli(Cli::new().setup()).await?;
|
|
||||||
// TODO: Implement test
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use crate::cli::Cli;
|
|
||||||
|
|
||||||
use super::bin_dir::{enter_bin_dir, leave_bin_dir};
|
|
||||||
|
|
||||||
pub async fn run_cli(cli: Cli) -> Result<()> {
|
|
||||||
enter_bin_dir().await?;
|
|
||||||
cli.run().await?;
|
|
||||||
leave_bin_dir()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -17,10 +17,10 @@ path = "src/lib.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mlua.workspace = true
|
mlua.workspace = true
|
||||||
once_cell.workspace = true
|
once_cell.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
glam = "0.24"
|
glam = "0.24"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
thiserror = "1.0"
|
|
||||||
|
|
||||||
rbx_binary = { git = "https://github.com/rojo-rbx/rbx-dom", rev = "2e78feb05e033cbca8db1d9e490f8334c096d13e" }
|
rbx_binary = { git = "https://github.com/rojo-rbx/rbx-dom", rev = "2e78feb05e033cbca8db1d9e490f8334c096d13e" }
|
||||||
rbx_dom_weak = { git = "https://github.com/rojo-rbx/rbx-dom", rev = "2e78feb05e033cbca8db1d9e490f8334c096d13e" }
|
rbx_dom_weak = { git = "https://github.com/rojo-rbx/rbx-dom", rev = "2e78feb05e033cbca8db1d9e490f8334c096d13e" }
|
||||||
|
|
Loading…
Reference in a new issue