update to use shulkerscript branch feature/variables

This commit is contained in:
Hölting, Moritz (Intern) 2025-08-27 12:58:37 +02:00
parent 7d5e126267
commit 1c1d07dd93
12 changed files with 108 additions and 56 deletions

26
Cargo.lock generated
View File

@ -68,9 +68,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.89" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
@ -197,9 +197,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.18" version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -207,9 +207,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.18" version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -550,9 +550,9 @@ dependencies = [
[[package]] [[package]]
name = "human-panic" name = "human-panic"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c5a08ed290eac04006e21e63d32e90086b6182c7cd0452d10f4264def1fec9a" checksum = "80b84a66a325082740043a6c28bbea400c129eac0d3a27673a1de971e44bf1f7"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -977,9 +977,9 @@ dependencies = [
[[package]] [[package]]
name = "pathdiff" name = "pathdiff"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
@ -1134,9 +1134,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.128" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -1171,8 +1171,6 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "shulkerbox" name = "shulkerbox"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18704338e25effa7d02ab8d83c453814a54163b66464693bb4aac0012f05db8b"
dependencies = [ dependencies = [
"chksum-md5", "chksum-md5",
"getset", "getset",

View File

@ -28,24 +28,25 @@ watch = ["dep:notify-debouncer-mini", "dep:ctrlc"]
zip = ["shulkerscript/zip"] zip = ["shulkerscript/zip"]
[dependencies] [dependencies]
anyhow = "1.0.89" anyhow = "1.0.95"
clap = { version = "4.5.18", features = ["deprecated", "derive", "env"] } clap = { version = "4.5.32", features = ["deprecated", "derive", "env"] }
colored = "2.1.0" colored = "3.0.0"
const_format = "0.2.33" const_format = "0.2.34"
ctrlc = { version = "3.4.5", optional = true } ctrlc = { version = "3.4.5", optional = true }
dotenvy = "0.15.7" dotenvy = "0.15.7"
git2 = { version = "0.19.0", default-features = false } git2 = { version = "0.20.0", default-features = false }
human-panic = "2.0.1" human-panic = "2.0.2"
indoc = { version = "2.0.5", optional = true } indoc = { version = "2.0.5", optional = true }
inquire = "0.7.5" inquire = "0.7.5"
notify-debouncer-mini = { version = "0.4.1", default-features = false, optional = true } notify-debouncer-mini = { version = "0.7.0", default-features = false, optional = true }
path-absolutize = "3.1.1" path-absolutize = "3.1.1"
pathdiff = "0.2.1" pathdiff = "0.2.3"
serde = { version = "1.0.210", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = { version = "1.0.128", optional = true } serde_json = { version = "1.0.138", optional = true }
shulkerscript = { version = "0.1.0", features = ["fs_access", "shulkerbox", "zip"], default-features = false } # shulkerscript = { version = "0.1.0", features = ["fs_access", "shulkerbox"], default-features = false }
thiserror = "1.0.63" shulkerscript = { git = "https://github.com/moritz-hoelting/shulkerscript-lang", features = ["fs_access", "shulkerbox"], default-features = false, rev = "d9f2d99c3a5e09488fc85ad792501a209387a89d" }
toml = "0.8.19" thiserror = "2.0.11"
tracing = "0.1.40" toml = "0.9.5"
tracing-subscriber = "0.3.18" tracing = "0.1.41"
tracing-subscriber = "0.3.19"
walkdir = { version = "2.5.0", optional = true } walkdir = { version = "2.5.0", optional = true }

View File

@ -13,8 +13,8 @@ static VERSION: &str = formatcp!(
); );
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
#[command(name = "shulkerscript", about, version = VERSION, long_about = None, disable_version_flag = false)] #[command(name = "shulkerscript", version = VERSION, about, long_about = None)]
pub struct Args { pub struct Cli {
#[command(subcommand)] #[command(subcommand)]
cmd: Command, cmd: Command,
/// Enable tracing output /// Enable tracing output
@ -61,7 +61,7 @@ pub enum TracingLevel {
Error, Error,
} }
impl Args { impl Cli {
pub fn run(&self) -> Result<()> { pub fn run(&self) -> Result<()> {
if let Some(level) = self.trace { if let Some(level) = self.trace {
setup_tracing(level)?; setup_tracing(level)?;
@ -123,6 +123,6 @@ mod tests {
#[test] #[test]
fn verify_cli() { fn verify_cli() {
Args::command().debug_assert(); Cli::command().debug_assert();
} }
} }

View File

@ -13,6 +13,8 @@ pub struct ProjectConfig {
pub struct PackConfig { pub struct PackConfig {
pub name: String, pub name: String,
pub description: String, pub description: String,
#[serde(alias = "main-namespace")]
pub main_namespace: Option<String>,
#[serde(rename = "format", alias = "pack_format")] #[serde(rename = "format", alias = "pack_format")]
pub pack_format: u8, pub pack_format: u8,
pub version: String, pub version: String,
@ -29,6 +31,7 @@ impl Default for PackConfig {
Self { Self {
name: Self::DEFAULT_NAME.to_string(), name: Self::DEFAULT_NAME.to_string(),
description: Self::DEFAULT_DESCRIPTION.to_string(), description: Self::DEFAULT_DESCRIPTION.to_string(),
main_namespace: None,
pack_format: Self::DEFAULT_PACK_FORMAT, pack_format: Self::DEFAULT_PACK_FORMAT,
version: "0.1.0".to_string(), version: "0.1.0".to_string(),
} }

View File

@ -11,8 +11,8 @@ pub enum Error {
NotDirectoryError(PathBuf), NotDirectoryError(PathBuf),
#[error("An error occured because the path is neither a pack directory or a pack.toml file.")] #[error("An error occured because the path is neither a pack directory or a pack.toml file.")]
InvalidPackPathError(PathBuf), InvalidPackPathError(PathBuf),
#[error("An error occured because the feature {0} is not enabled.")] #[error("An error occured because {0} is not allowed as a namespace.")]
FeatureNotEnabledError(String), InvalidNamespaceError(String),
#[error("An error occured because the pack version does not support a used feature")] #[error("An error occured because the pack version does not support a used feature")]
IncompatiblePackVersionError, IncompatiblePackVersionError,
} }

View File

@ -2,15 +2,25 @@ use std::process::ExitCode;
use clap::Parser; use clap::Parser;
use shulkerscript_cli::{cli::Args, terminal_output::print_info}; use shulkerscript_cli::{cli::Cli, terminal_output::print_info};
fn main() -> ExitCode { fn main() -> ExitCode {
human_panic::setup_panic!(); human_panic::setup_panic!(human_panic::Metadata::new(
env!("CARGO_PKG_NAME"),
const_format::formatcp!(
"{cli_version};lib={lib_version}",
cli_version = env!("CARGO_PKG_VERSION"),
lib_version = shulkerscript::VERSION
),
)
.authors(env!("CARGO_PKG_AUTHORS").replace(":", ", "))
.homepage(env!("CARGO_PKG_HOMEPAGE")));
if dotenvy::dotenv().is_ok() { if dotenvy::dotenv().is_ok() {
print_info("Using environment variables from .env file"); print_info("Using environment variables from .env file");
} }
let args = Args::parse(); let args = Cli::parse();
match args.run() { match args.run() {
Ok(_) => ExitCode::SUCCESS, Ok(_) => ExitCode::SUCCESS,

View File

@ -12,7 +12,7 @@ use crate::{
config::ProjectConfig, config::ProjectConfig,
error::Error, error::Error,
terminal_output::{print_error, print_info, print_success, print_warning}, terminal_output::{print_error, print_info, print_success, print_warning},
util, util::{self, get_project_main_namespace},
}; };
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -37,22 +37,19 @@ pub struct BuildArgs {
#[arg(short, long)] #[arg(short, long)]
pub assets: Option<PathBuf>, pub assets: Option<PathBuf>,
/// Package the project to a zip file. /// Package the project to a zip file.
#[cfg_attr(not(feature = "zip"), doc = "Disabled because not compiled with `zip` feature")] #[cfg(feature = "zip")]
#[arg(short, long)]
pub zip: bool, pub zip: bool,
/// Skip validating the project for pack format compatibility. /// Skip validating the project for pack format compatibility.
#[arg(long)] #[arg(long)]
pub no_validate: bool, pub no_validate: bool,
/// Check if the project can be built without actually building it. /// Check if the project can be built without actually building it.
#[arg(long, conflicts_with_all = ["output", "zip"])] #[arg(long, conflicts_with = "output")]
#[cfg_attr(feature = "zip", arg(conflicts_with = "zip"))]
pub check: bool, pub check: bool,
} }
pub fn build(args: &BuildArgs) -> Result<()> { pub fn build(args: &BuildArgs) -> Result<()> {
if args.zip && !cfg!(feature = "zip") {
print_error("The zip feature is not enabled. Please install with the `zip` feature enabled to use the `--zip` option.");
return Err(Error::FeatureNotEnabledError("zip".to_string()).into());
}
let path = util::get_project_path(&args.path).unwrap_or(args.path.clone()); let path = util::get_project_path(&args.path).unwrap_or(args.path.clone());
let dist_path = args let dist_path = args
.output .output
@ -60,7 +57,16 @@ pub fn build(args: &BuildArgs) -> Result<()> {
.map(Cow::Borrowed) .map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(path.join("dist"))); .unwrap_or_else(|| Cow::Owned(path.join("dist")));
let and_package_msg = if args.zip { " and packaging" } else { "" }; let zip = {
#[cfg(feature = "zip")]
{
args.zip
}
#[cfg(not(feature = "zip"))]
false
};
let and_package_msg = if zip { " and packaging" } else { "" };
let mut path_display = format!("{}", path.display()); let mut path_display = format!("{}", path.display());
if path_display.is_empty() { if path_display.is_empty() {
@ -83,6 +89,12 @@ pub fn build(args: &BuildArgs) -> Result<()> {
let datapack = shulkerscript::transpile( let datapack = shulkerscript::transpile(
&PrintHandler::new(), &PrintHandler::new(),
&FsProvider::default(), &FsProvider::default(),
&get_project_main_namespace(&project_config).map_err(|namespace| {
print_error(format!(
"The automatically generated namespace is too short: '{namespace}'. Please specify a namespace in the pack.toml file.",
));
Error::InvalidNamespaceError(namespace)
})?,
project_config.pack.pack_format, project_config.pack.pack_format,
&script_paths, &script_paths,
)?; )?;
@ -133,7 +145,7 @@ pub fn build(args: &BuildArgs) -> Result<()> {
compiled compiled
}; };
let dist_extension = if args.zip { ".zip" } else { "" }; let dist_extension = if zip { ".zip" } else { "" };
let dist_path = dist_path.join(project_config.pack.name + dist_extension); let dist_path = dist_path.join(project_config.pack.name + dist_extension);

View File

@ -59,7 +59,7 @@ pub fn clean(args: &CleanArgs) -> Result<()> {
for delete_path in delete_paths { for delete_path in delete_paths {
if delete_path.exists() { if delete_path.exists() {
if verbose { if verbose {
print_info(&format!("Deleting {:?}", delete_path)); print_info(format!("Deleting {:?}", delete_path));
} }
if delete_path.is_file() { if delete_path.is_file() {
std::fs::remove_file(&delete_path)?; std::fs::remove_file(&delete_path)?;

View File

@ -26,6 +26,7 @@ pub enum DumpState {
Tokens, Tokens,
#[default] #[default]
Ast, Ast,
#[value(alias = "dp")]
Datapack, Datapack,
} }
@ -71,6 +72,7 @@ pub fn lang_debug(args: &LangDebugArgs) -> Result<()> {
let datapack = shulkerscript::transpile( let datapack = shulkerscript::transpile(
&PrintHandler::new(), &PrintHandler::new(),
&file_provider, &file_provider,
"main_namespace",
PackConfig::DEFAULT_PACK_FORMAT, PackConfig::DEFAULT_PACK_FORMAT,
&program_paths, &program_paths,
)?; )?;

View File

@ -106,7 +106,7 @@ struct McMetaPack {
} }
fn is_mcmeta_compatible(mcmeta: &serde_json::Value) -> bool { fn is_mcmeta_compatible(mcmeta: &serde_json::Value) -> bool {
mcmeta.as_object().map_or(false, |mcmeta| { mcmeta.as_object().is_some_and(|mcmeta| {
mcmeta.len() == 1 mcmeta.len() == 1
&& mcmeta.contains_key("pack") && mcmeta.contains_key("pack")
&& mcmeta["pack"] && mcmeta["pack"]
@ -136,9 +136,8 @@ fn generate_pack_toml(base_path: &Path, mcmeta: &McMeta) -> Result<VFile> {
} }
}) })
}) })
.map_err(|e| { .inspect_err(|_| {
err = true; err = true;
e
}) })
.unwrap_or_default() .unwrap_or_default()
} else { } else {
@ -268,7 +267,7 @@ fn handle_function(
let function_name = function_path let function_name = function_path
.split('/') .split('/')
.last() .next_back()
.expect("split always returns at least one element") .expect("split always returns at least one element")
.replace(|c: char| !c.is_ascii_alphanumeric(), "_"); .replace(|c: char| !c.is_ascii_alphanumeric(), "_");

View File

@ -11,7 +11,7 @@ use colored::Colorize;
use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult}; use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult};
use crate::{ use crate::{
cli::Args, cli::Cli,
error::Result, error::Result,
terminal_output::{print_error, print_info, print_warning}, terminal_output::{print_error, print_info, print_warning},
util, util,
@ -74,7 +74,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
let prog_name = std::env::args() let prog_name = std::env::args()
.next() .next()
.unwrap_or(env!("CARGO_PKG_NAME").to_string()); .unwrap_or(env!("CARGO_PKG_NAME").to_string());
Args::parse_from(iter::once(prog_name.as_str()).chain(split.clone())) Cli::parse_from(iter::once(prog_name.as_str()).chain(split.clone()))
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -168,7 +168,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
} }
} }
fn run_cmds(cmds: &[Args], no_execute: bool, shell_cmds: &[String], initial: bool) { fn run_cmds(cmds: &[Cli], no_execute: bool, shell_cmds: &[String], initial: bool) {
if initial { if initial {
print_info("Running commands initially..."); print_info("Running commands initially...");
} else { } else {

View File

@ -8,6 +8,8 @@ use std::{
use inquire::{autocompletion::Replacement, Autocomplete}; use inquire::{autocompletion::Replacement, Autocomplete};
use path_absolutize::Absolutize; use path_absolutize::Absolutize;
use crate::config::ProjectConfig;
pub fn get_project_path<P>(base_path: P) -> Option<PathBuf> pub fn get_project_path<P>(base_path: P) -> Option<PathBuf>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -23,6 +25,31 @@ where
.map(|p| p.relativize().unwrap_or_else(|| p.to_path_buf())) .map(|p| p.relativize().unwrap_or_else(|| p.to_path_buf()))
} }
pub fn get_project_main_namespace(project_config: &ProjectConfig) -> Result<String, String> {
project_config
.pack
.main_namespace
.as_ref()
.cloned()
.map_or_else(
|| {
let namespace = project_config
.pack
.name
.to_lowercase()
.chars()
.filter(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.'))
.collect::<String>();
if namespace.len() < 5 {
Err(namespace)
} else {
Ok(namespace)
}
},
Ok,
)
}
pub trait Relativize { pub trait Relativize {
fn relativize(&self) -> Option<PathBuf>; fn relativize(&self) -> Option<PathBuf>;
} }