From 9504c247d62d85a2c59fec2f51f1e0b01337f4ff Mon Sep 17 00:00:00 2001 From: ObserverOfTime Date: Sat, 23 Aug 2025 23:53:03 +0300 Subject: [PATCH] fix(bindings): improve zig dependency fetching logic Currently, including a tree-sitter parser as a dependency in a zig project and running `zig build test` on the project will fetch the zig-tree-sitter dependency declared by the parser. This is a problem because (a) consumers may not want this dependency for whatever reason and (b) due to how often Zig breaks everything and how scarcely most tree-sitter parsers are updated, the zig-tree-sitter version pinned by the parser module will often be outdated and broken. The workaround I used was taken from https://ziggit.dev/t/11234 (cherry picked from commit 107bd800b02c8daf1f0f830bbeaf52749a79792c) --- cli/src/init.rs | 28 ++++++++++++++++++++++------ cli/src/templates/build.zig | 17 ++++++++++------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/cli/src/init.rs b/cli/src/init.rs index 4c51bc4b..a47ef637 100644 --- a/cli/src/init.rs +++ b/cli/src/init.rs @@ -406,6 +406,7 @@ pub fn generate_grammar_files( |path| { let contents = fs::read_to_string(path)?; if !contents.contains("bun") { + eprintln!("Replacing index.js"); generate_file(path, INDEX_JS_TEMPLATE, language_name, &generate_opts)?; } Ok(()) @@ -732,8 +733,13 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, BUILD_ZIG_TEMPLATE, language_name, &generate_opts), |path| { - eprintln!("Replacing build.zig"); - generate_file(path, BUILD_ZIG_TEMPLATE, language_name, &generate_opts) + let contents = fs::read_to_string(path)?; + if !contents.contains("b.pkg_hash.len") { + eprintln!("Replacing build.zig"); + generate_file(path, BUILD_ZIG_TEMPLATE, language_name, &generate_opts) + } else { + Ok(()) + } }, )?; @@ -742,8 +748,13 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, BUILD_ZIG_ZON_TEMPLATE, language_name, &generate_opts), |path| { - eprintln!("Replacing build.zig.zon"); - generate_file(path, BUILD_ZIG_ZON_TEMPLATE, language_name, &generate_opts) + let contents = fs::read_to_string(path)?; + if !contents.contains(".name = .tree_sitter_") { + eprintln!("Replacing build.zig.zon"); + generate_file(path, BUILD_ZIG_ZON_TEMPLATE, language_name, &generate_opts) + } else { + Ok(()) + } }, )?; @@ -753,8 +764,13 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, ROOT_ZIG_TEMPLATE, language_name, &generate_opts), |path| { - eprintln!("Replacing root.zig"); - generate_file(path, ROOT_ZIG_TEMPLATE, language_name, &generate_opts) + let contents = fs::read_to_string(path)?; + if contents.contains("ts.Language") { + eprintln!("Replacing root.zig"); + generate_file(path, ROOT_ZIG_TEMPLATE, language_name, &generate_opts) + } else { + Ok(()) + } }, )?; diff --git a/cli/src/templates/build.zig b/cli/src/templates/build.zig index 6b9540c2..c2428289 100644 --- a/cli/src/templates/build.zig +++ b/cli/src/templates/build.zig @@ -68,13 +68,16 @@ pub fn build(b: *std.Build) !void { }); tests.root_module.addImport(library_name, module); - var args = try std.process.argsWithAllocator(b.allocator); - defer args.deinit(); - while (args.next()) |a| { - if (std.mem.eql(u8, a, "test")) { - const ts_dep = b.lazyDependency("tree_sitter", .{}) orelse continue; - tests.root_module.addImport("tree-sitter", ts_dep.module("tree-sitter")); - break; + // HACK: fetch tree-sitter dependency only when testing this module + if (b.pkg_hash.len == 0) { + var args = try std.process.argsWithAllocator(b.allocator); + defer args.deinit(); + while (args.next()) |a| { + if (std.mem.eql(u8, a, "test")) { + const ts_dep = b.lazyDependency("tree_sitter", .{}) orelse continue; + tests.root_module.addImport("tree-sitter", ts_dep.module("tree-sitter")); + break; + } } }