From 46ea65c89b89ef5af6765c2f29131ecd72233b08 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Tue, 16 Sep 2025 21:42:42 -0400 Subject: [PATCH] refactor: remove url dependency --- Cargo.lock | 10 +++++++--- Cargo.toml | 1 - crates/cli/Cargo.toml | 1 - crates/cli/src/init.rs | 15 +++++---------- crates/cli/src/main.rs | 31 ++++--------------------------- crates/generate/Cargo.toml | 6 ++---- crates/generate/src/generate.rs | 12 ++++++------ crates/generate/src/quickjs.rs | 12 +++--------- crates/loader/Cargo.toml | 1 - crates/loader/src/loader.rs | 5 ++--- 10 files changed, 29 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e9f51b3..f5512195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,6 +569,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.15.0" @@ -1931,7 +1937,6 @@ dependencies = [ "tree-sitter-tags", "tree-sitter-tests-proc-macro", "unindent", - "url", "walkdir", "wasmparser", "webbrowser", @@ -1953,6 +1958,7 @@ name = "tree-sitter-generate" version = "0.26.0" dependencies = [ "anyhow", + "dunce", "indexmap", "indoc", "log", @@ -1968,7 +1974,6 @@ dependencies = [ "tempfile", "thiserror 2.0.16", "topological-sort", - "url", ] [[package]] @@ -2004,7 +2009,6 @@ dependencies = [ "tree-sitter", "tree-sitter-highlight", "tree-sitter-tags", - "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c30b8f02..6dd66122 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -147,7 +147,6 @@ thiserror = "2.0.16" tiny_http = "0.12.0" topological-sort = "0.2.2" unindent = "0.2.4" -url = { version = "2.5.4", features = ["serde"] } walkdir = "2.5.0" wasmparser = "0.229.0" webbrowser = "1.0.5" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 677154ee..b8ac8222 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -59,7 +59,6 @@ serde_json.workspace = true similar.workspace = true streaming-iterator.workspace = true tiny_http.workspace = true -url.workspace = true walkdir.workspace = true wasmparser.workspace = true webbrowser.workspace = true diff --git a/crates/cli/src/init.rs b/crates/cli/src/init.rs index d6a554be..2294b82b 100644 --- a/crates/cli/src/init.rs +++ b/crates/cli/src/init.rs @@ -12,7 +12,6 @@ use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use tree_sitter_generate::write_file; use tree_sitter_loader::{Author, Bindings, Grammar, Links, Metadata, PathsJSON, TreeSitterJSON}; -use url::Url; const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); const CLI_VERSION_PLACEHOLDER: &str = "CLI_VERSION"; @@ -110,9 +109,9 @@ pub struct JsonConfigOpts { pub title: String, pub description: String, #[serde(skip_serializing_if = "Option::is_none")] - pub repository: Option, + pub repository: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub funding: Option, + pub funding: Option, pub scope: String, pub file_types: Vec, pub version: Version, @@ -121,7 +120,7 @@ pub struct JsonConfigOpts { #[serde(skip_serializing_if = "Option::is_none")] pub email: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub url: Option, + pub url: Option, pub bindings: Bindings, } @@ -158,11 +157,7 @@ impl JsonConfigOpts { }]), links: Some(Links { repository: self.repository.unwrap_or_else(|| { - Url::parse(&format!( - "https://github.com/tree-sitter/tree-sitter-{}", - self.name - )) - .expect("Failed to parse default repository URL") + format!("https://github.com/tree-sitter/tree-sitter-{}", self.name) }), funding: self.funding, }), @@ -277,7 +272,7 @@ pub fn generate_grammar_files( .metadata .links .as_ref() - .and_then(|l| l.funding.as_ref().map(|f| f.as_str())), + .and_then(|l| l.funding.as_deref()), version: &tree_sitter_config.metadata.version, camel_parser_name: &camel_name, title_parser_name: &title_name, diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 960c1f87..b52f8db1 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -34,7 +34,6 @@ use tree_sitter_config::Config; use tree_sitter_highlight::Highlighter; use tree_sitter_loader::{self as loader, Bindings, TreeSitterJSON}; use tree_sitter_tags::TagsContext; -use url::Url; const BUILD_VERSION: &str = env!("CARGO_PKG_VERSION"); const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA"); @@ -651,15 +650,10 @@ impl Init { }; let repository = |name: &str| { - Input::::with_theme(&ColorfulTheme::default()) + Input::::with_theme(&ColorfulTheme::default()) .with_prompt("Repository URL") .allow_empty(true) - .default( - Url::parse(&format!( - "https://github.com/tree-sitter/tree-sitter-{name}" - )) - .expect("Failed to parse default repository URL"), - ) + .default(format!("https://github.com/tree-sitter/tree-sitter-{name}")) .show_default(false) .interact_text() }; @@ -668,18 +662,8 @@ impl Init { Input::::with_theme(&ColorfulTheme::default()) .with_prompt("Funding URL") .allow_empty(true) - .validate_with(|input: &String| { - if input.trim().is_empty() - || Url::parse(input) - .is_ok_and(|u| u.scheme() == "http" || u.scheme() == "https") - { - Ok(()) - } else { - Err("The URL must start with 'http://' or 'https://'") - } - }) .interact_text() - .map(|e| (!e.trim().is_empty()).then(|| Url::parse(&e).unwrap())) + .map(|e| Some(e.trim().to_string())) }; let scope = |name: &str| { @@ -746,15 +730,8 @@ impl Init { Input::::with_theme(&ColorfulTheme::default()) .with_prompt("Author URL") .allow_empty(true) - .validate_with(|input: &String| -> Result<(), &str> { - if input.trim().is_empty() || Url::parse(input).is_ok() { - Ok(()) - } else { - Err("This is not a valid URL") - } - }) .interact_text() - .map(|e| (!e.trim().is_empty()).then(|| Url::parse(&e).unwrap())) + .map(|e| Some(e.trim().to_string())) }; let bindings = || { diff --git a/crates/generate/Cargo.toml b/crates/generate/Cargo.toml index ee2b0632..61b1686a 100644 --- a/crates/generate/Cargo.toml +++ b/crates/generate/Cargo.toml @@ -21,11 +21,12 @@ workspace = true [features] default = ["qjs-rt"] -load = ["dep:semver", "dep:url"] +load = ["dep:semver"] qjs-rt = ["load", "rquickjs", "pathdiff"] [dependencies] anyhow.workspace = true +dunce = "1.0.5" indexmap.workspace = true indoc.workspace = true log.workspace = true @@ -46,8 +47,5 @@ smallbitvec.workspace = true thiserror.workspace = true topological-sort.workspace = true -[target.'cfg(windows)'.dependencies] -url = { workspace = true, optional = true } - [dev-dependencies] tempfile.workspace = true diff --git a/crates/generate/src/generate.rs b/crates/generate/src/generate.rs index cf8a8dd5..4ac7f5e7 100644 --- a/crates/generate/src/generate.rs +++ b/crates/generate/src/generate.rs @@ -431,18 +431,18 @@ pub fn load_grammar_file( #[cfg(feature = "load")] fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> JSResult { - let grammar_path = fs::canonicalize(grammar_path)?; - - #[cfg(windows)] - let grammar_path = url::Url::from_file_path(grammar_path) - .expect("Failed to convert path to URL") - .to_string(); + let grammar_path = dunce::canonicalize(grammar_path)?; #[cfg(feature = "qjs-rt")] if js_runtime == Some("native") { return quickjs::execute_native_runtime(&grammar_path); } + // The "file:///" prefix is incompatible with the quickjs runtime, but is required + // for node and bun + #[cfg(windows)] + let grammar_path = PathBuf::from(format!("file:///{}", grammar_path.display())); + let js_runtime = js_runtime.unwrap_or("node"); let mut js_command = Command::new(js_runtime); diff --git a/crates/generate/src/quickjs.rs b/crates/generate/src/quickjs.rs index 51703de5..1ea7970c 100644 --- a/crates/generate/src/quickjs.rs +++ b/crates/generate/src/quickjs.rs @@ -251,13 +251,7 @@ fn load_module_from_content<'a>( module_obj.get("exports") } -pub fn execute_native_runtime( - #[cfg(windows)] grammar_path: &str, - #[cfg(not(windows))] grammar_path: &Path, -) -> JSResult { - #[cfg(not(windows))] - let grammar_path = grammar_path.to_string_lossy(); - +pub fn execute_native_runtime(grammar_path: &Path) -> JSResult { let runtime = Runtime::new()?; runtime.set_memory_limit(64 * 1024 * 1024); // 64MB @@ -272,7 +266,7 @@ pub fn execute_native_runtime( runtime.set_loader(resolver, loader); let cwd = std::env::current_dir()?; - let relative_path = pathdiff::diff_paths(&*grammar_path, &cwd) + let relative_path = pathdiff::diff_paths(grammar_path, &cwd) .map(|p| p.to_string_lossy().to_string()) .ok_or_else(|| JSError::IO("Failed to get relative path".to_string()))?; @@ -301,7 +295,7 @@ pub fn execute_native_runtime( .or_js_error(&ctx)?; globals.set("module", module).or_js_error(&ctx)?; - let grammar_path_string = grammar_path.to_string(); + let grammar_path_string = grammar_path.to_string_lossy().to_string(); let main_require = Function::new( ctx.clone(), move |ctx_inner, target_path: String| -> rquickjs::Result { diff --git a/crates/loader/Cargo.toml b/crates/loader/Cargo.toml index 272a1295..2bfa2c76 100644 --- a/crates/loader/Cargo.toml +++ b/crates/loader/Cargo.toml @@ -40,7 +40,6 @@ semver.workspace = true serde.workspace = true serde_json.workspace = true tempfile.workspace = true -url.workspace = true tree-sitter = { workspace = true } tree-sitter-highlight = { workspace = true, optional = true } diff --git a/crates/loader/src/loader.rs b/crates/loader/src/loader.rs index 4ea0475b..b4a28a71 100644 --- a/crates/loader/src/loader.rs +++ b/crates/loader/src/loader.rs @@ -36,7 +36,6 @@ use tree_sitter::QueryErrorKind; use tree_sitter_highlight::HighlightConfiguration; #[cfg(feature = "tree-sitter-tags")] use tree_sitter_tags::{Error as TagsError, TagsConfiguration}; -use url::Url; static GRAMMAR_NAME_REGEX: LazyLock = LazyLock::new(|| Regex::new(r#""name":\s*"(.*?)""#).unwrap()); @@ -214,9 +213,9 @@ pub struct Author { #[derive(Serialize, Deserialize)] pub struct Links { - pub repository: Url, + pub repository: String, #[serde(skip_serializing_if = "Option::is_none")] - pub funding: Option, + pub funding: Option, } #[derive(Serialize, Deserialize, Clone)]