Skip to content

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

Open
ozdemirsarman wants to merge 3 commits 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 3 commits into
Graphify-Labs:v8from
ozdemirsarman:feat/gdscript-godot-extractor

Conversation

@ozdemirsarman

Copy link
Copy Markdown
Contributor

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.

@luevano

luevano commented Jul 26, 2026

Copy link
Copy Markdown

I think you can use tree-sitter-language-pack>=1.12.5,<1.13 like #1836 does. He just didn't include .tscn or .tres extractors. This language pack contains PrestonKnopp/tree-sitter-gdscript and PrestonKnopp/tree-sitter-godot-resource, could you update your PR to be based on this?

Address review (Graphify-Labs#1929): depend on tree-sitter-language-pack>=1.12.5,<1.13 (as Graphify-Labs#1836 does) instead of the unpublished tree-sitter-gdscript wheel. The .gd extractor loads the bundled gdscript grammar; the scene/resource extractor now uses the bundled godot_resource grammar, falling back to a dependency-free line parser when the extra is absent.
@ozdemirsarman

Copy link
Copy Markdown
Contributor Author

Done — switched the godot extra to tree-sitter-language-pack>=1.12.5,<1.13 (matching #1836). Both grammars now come from the pack: .gd uses gdscript, and I also moved the .tscn/.tres/project.godot scene extractor onto the bundled godot_resource grammar (with a dependency-free line-parser fallback when the extra isn't installed). The pack only needs tree-sitter>=0.23, so it stays within the repo's <0.26 pin. Tests pass.

@luevano

luevano commented Jul 26, 2026

Copy link
Copy Markdown

Thanks for the quick update! seems to be usable as is now.

Looks like you have claude working on this, if that's the case: any thoughts on implementing the other file changes as with #1836?

  • graphify/extractors/MIGRATION.md
  • graphify/analyze.py
  • graphify/build.py

I'd also consider the following nits (coming from #1835 as well):

  • keep the comment on pyproject.toml out of it and here in the PR, or a smaller 1 liner.
  • add fixtures for the tests instead of having them in-line.
  • README.md could also have similar treatment (modifications around line 260 and 331), but one for gdscript and one for godot resource.

The naming of the "godot scene" I think should be changed to "godot resource", meaning a bit of changes in the code itself to reference this.

luevano pushed a commit to luevano/graphify that referenced this pull request Jul 27, 2026
Address review (Graphify-Labs#1929): depend on tree-sitter-language-pack>=1.12.5,<1.13 (as Graphify-Labs#1836 does) instead of the unpublished tree-sitter-gdscript wheel. The .gd extractor loads the bundled gdscript grammar; the scene/resource extractor now uses the bundled godot_resource grammar, falling back to a dependency-free line parser when the extra is absent.
luevano pushed a commit to luevano/graphify that referenced this pull request Jul 27, 2026
Address review (Graphify-Labs#1929): depend on tree-sitter-language-pack>=1.12.5,<1.13 (as Graphify-Labs#1836 does) instead of the unpublished tree-sitter-gdscript wheel. The .gd extractor loads the bundled gdscript grammar; the scene/resource extractor now uses the bundled godot_resource grammar, falling back to a dependency-free line parser when the extra is absent.
…yze/build/MIGRATION, README + fixtures (Graphify-Labs#1929)

- Register .gd (gdscript) and .tscn/.tres/project.godot (godot_resource) in analyze.py, build.py and extractors/MIGRATION.md, matching Graphify-Labs#1836.
- Rename the scene extractor to godot_resource (module, extract_godot_resource, registry key, wiring) per review.
- Shrink the pyproject godot comment to one line.
- README: add a godot extras row and split the godot file types into their own GDScript / Godot resources rows.
- Move the inline gdscript/godot test bodies into tests/fixtures/godot/ and rename the test file to test_godot_resource.py.
@ozdemirsarman

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Addressed everything in de0f6b2:

  • analyze.py / build.py / extractors/MIGRATION.md — registered .gdgdscript and .tscn/.tres/project.godotgodot_resource in all three, matching feat(gdscript): add .gd extraction support (#697) #1836.
  • Renamed to godot_resource — module godot_scene.pygodot_resource.py, extract_godot_sceneextract_godot_resource, the registry key, and all wiring (extract.py, extractors/__init__.py). No stale godot_scene references remain.
  • pyproject.toml — trimmed the comment to a single line.
  • Test fixtures — moved the inline .gd/.tscn/project.godot bodies into tests/fixtures/godot/{gdscript,resource}/, and renamed the test file to test_godot_resource.py.
  • README — added a godot extras row (~L260), and split the Godot file types out of the big "Code" row into their own GDScript and Godot resources rows (~L331), same treatment as the Apex / Terraform rows.

Full suite green locally. Let me know if you'd like the godot_resource grammar wired into anything else.

luevano added a commit to luevano/graphify that referenced this pull request Jul 28, 2026
…ify-Labs#1929

Vendors tests/fixtures/godot verbatim from PR Graphify-Labs#1929
(feat/gdscript-godot-extractor, commit de0f6b2), which added them
alongside the extractor; only the README is local. Our tests were all
tmp_path-inline, so we had no fixtures at all.

resource/ is a Godot project in miniature - project.godot registering an
autoload and a main scene, a .tscn attaching a script and instancing
another scene, and the scripts they name. That cross-file shape is the
point: both Godot id defects (duplicate file nodes, and a cross-file stub
evicting the file it names) needed several files referencing each other,
and neither is reachable from a single-file test.

Two assertions over it: every file resolves to exactly one canonically
named node, and every attaches_script / instances / main_scene / script
edge lands on a node that exists.
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.

2 participants