From 87fa80c1bc7233e8c71d0142a2eee0772068d1c7 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 28 May 2026 10:37:22 +0200 Subject: [PATCH] fix: skip reorder when file has parse errors to prevent data loss When --reorder-code is used on a file with invalid syntax, tree-sitter wraps the affected function in an ERROR node. The reorder query uses (_) which silently excludes ERROR nodes, causing entire functions to be dropped from the output. Guard the reorder step with has_error() so files with parse errors are left untouched rather than losing declarations silently. --- src/formatter.rs | 10 ++++++++++ tests/reorder_code/expected/issue_233.gd | 16 ++++++++++++++++ tests/reorder_code/input/issue_233.gd | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/reorder_code/expected/issue_233.gd create mode 100644 tests/reorder_code/input/issue_233.gd diff --git a/src/formatter.rs b/src/formatter.rs index 6708ec2..a7140d5 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -129,6 +129,16 @@ impl Formatter { } self.tree = self.parser.parse(&self.content, Some(&self.tree)).unwrap(); + + // The reorder query uses (_) which silently skips ERROR nodes, so any + // top-level declaration wrapped in an ERROR node will be lost from the + // output. Bail out instead of producing a file with missing functions. + if self.tree.root_node().has_error() { + eprintln!( + "Warning: Parse errors detected, skipping code reordering to avoid data loss." + ); + return Ok(self); + } match crate::reorder::reorder_gdscript_elements(&self.tree, &self.content) { Ok(reordered) => { self.content = reordered; diff --git a/tests/reorder_code/expected/issue_233.gd b/tests/reorder_code/expected/issue_233.gd new file mode 100644 index 0000000..6bb2812 --- /dev/null +++ b/tests/reorder_code/expected/issue_233.gd @@ -0,0 +1,16 @@ +func jump(force: float) -> void: + self.velocity.y = force + is_shooting = false +func shoot() -> void: + var pos: Vector2 = muzzle_right.global_position + var direction: Vector2 = Vector2.RIGHT + if is_facing_left: + pos = muzzle_left.global_position + direction = Vector2.LEFT + + var lazer: Projectile = Instancer.instance_scene_to_level(Instancer.laster_scene, pos) as Projectile + if lazer != null: + lazer.launch(direction, lazer_speed) + + is_shooting = false + var yozora: bool. diff --git a/tests/reorder_code/input/issue_233.gd b/tests/reorder_code/input/issue_233.gd new file mode 100644 index 0000000..66a4a00 --- /dev/null +++ b/tests/reorder_code/input/issue_233.gd @@ -0,0 +1,18 @@ +func jump(force: float) -> void: + self.velocity.y = force + is_shooting = false + + +func shoot() -> void: + var pos: Vector2 = muzzle_right.global_position + var direction: Vector2 = Vector2.RIGHT + if is_facing_left: + pos = muzzle_left.global_position + direction = Vector2.LEFT + + var lazer: Projectile = Instancer.instance_scene_to_level(Instancer.laster_scene, pos) as Projectile + if lazer != null: + lazer.launch(direction, lazer_speed) + + is_shooting = false + var yozora: bool.