Skip to content

feat(extractors): add GDScript (.gd) + Godot scene/resource (.tscn/.t…#1929

Open
ozdemirsarman wants to merge 1 commit into
Graphify-Labs:v8from
ozdemirsarman:feat/gdscript-godot-extractor
Open

feat(extractors): add GDScript (.gd) + Godot scene/resource (.tscn/.t…#1929
ozdemirsarman wants to merge 1 commit into
Graphify-Labs:v8from
ozdemirsarman:feat/gdscript-godot-extractor

Conversation

@ozdemirsarman

Copy link
Copy Markdown

Add GDScript + Godot scene/resource extraction

Adds first-class support for Godot Engine projects: GDScript (.gd) AST
extraction plus a grammar-free extractor for Godot's scene/resource/project
text formats (.tscn, .tres, project.godot). This closes the gap where a
Godot codebase currently contributes almost nothing to the graph.

What's new

GDScript (.gd) — graphify/extractors/gdscript.py (tree-sitter-gdscript)

GDScript Graph
class_name Foo / inner class Foo class node + defines
extends Bar / extends "res://x.gd" extends edge (res:// resolved)
func f(): … function node + defines
foo() / obj.method() in a body calls edges (local funcs resolved)
Autoload.method() calls edge resolved to the function in the autoload's script (autoload map read from project.godot)
signal s(args) signal node + declares
emit_signal("s") / s.emit() emits edge
s.connect(handler) connects edge (handler resolved to local func)
preload("res://y.gd") / load(...) imports edge (res:// resolved)

Godot scenes/resources/project — graphify/extractors/godot_scene.py (no grammar; line parser)

Godot Graph
[ext_resource type="Script" path="res://x.gd"] attaches_script edge
[ext_resource type="PackedScene" path="res://y.tscn"] instances edge
script = ExtResource("id") on a node node-level attaches_script
[connection signal="s" from="A" to="." method="m"] connects edge, resolved to the target script's function node
project.godot [autoload] global singleton node + autoload + script edges
project.godot run/main_scene main_scene edge

The scene [connection] → function resolution is the payoff Godot devs can't
get from GDScript-only tooling: signal wires defined in .tscn files link
straight to the handler func in the .gd file, because both sides mint the
same _make_id(script_stem, method) node id.

Wiring (mirrors every other language)

  • graphify/extractors/gdscript.py, graphify/extractors/godot_scene.py (new)
  • detect.py: .gd .tscn .tres .godot added to CODE_EXTENSIONS
  • extract.py: facade re-exports + _DISPATCH entries
  • extractors/__init__.py: LANGUAGE_EXTRACTORS registry entries
  • pyproject.toml: optional godot = ["tree-sitter-gdscript"] extra
  • README.md: language table updated

Graceful degradation

Both extractors are safe without the grammar. .gd returns a bare file node
when tree-sitter-gdscript is absent (same pattern as sql/pascal), and the
scene extractor needs no grammar at all — so scene/autoload/signal-wire edges
always work.

Tests

tests/test_gdscript.py (skipped when the grammar is absent) and
tests/test_godot_scene.py (always runs) cover every relation above, plus the
registry-identity sweep in test_extractors_registry.py auto-covers the two new
registry entries. All fixtures are synthetic; no third-party project code.

Open question for maintainers — grammar packaging

tree-sitter-gdscript (PrestonKnopp, MIT) is not yet published to PyPI as a
standalone wheel, though its repo ships working Python bindings and builds from
source cleanly. The .gd loader therefore tries tree_sitter_gdscript first
and falls back to a grammar from tree-sitter-language-pack. I'm happy to (a)
publish tree-sitter-gdscript to PyPI with proper attribution, or (b) switch
the godot extra to whatever dependency you prefer — let me know. The .tscn
half needs no grammar regardless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant