feat(memory): GDScript symbol extraction in RepoMapIndexer
Adds 'gd' to SYMBOL_PATTERNS (func/class_name/class/signal/enum at column 0, optional static prefix). Because INDEXED_EXTENSIONS derives from the pattern keys, .gd files now also participate in WorkspaceStateProbe fingerprinting, making fp: state keys content-sensitive for Godot repos.
This commit is contained in:
@@ -82,6 +82,8 @@ class RepoMapIndexer(
|
|||||||
"go" to Regex("""(?m)^\s*(?:func\s+(?:\([^)]*\)\s*)?|type\s+)(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
|
"go" to Regex("""(?m)^\s*(?:func\s+(?:\([^)]*\)\s*)?|type\s+)(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
|
||||||
"js" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
|
"js" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
|
||||||
"ts" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
|
"ts" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
|
||||||
|
// GDScript: column-0 declarations only, so indented inner-class members never match.
|
||||||
|
"gd" to Regex("""(?m)^(?:static\s+)?(?:func|class_name|class|signal|enum)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,40 @@ class RepoMapIndexerTest {
|
|||||||
assertTrue(entries.first { it.path == "Old.kt" }.symbols.contains("Old"))
|
assertTrue(entries.first { it.path == "Old.kt" }.symbols.contains("Old"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `extracts GDScript top-level symbols`(@TempDir root: Path) {
|
||||||
|
root.resolve("player.gd").writeText(
|
||||||
|
"""
|
||||||
|
class_name Player
|
||||||
|
extends CharacterBody2D
|
||||||
|
|
||||||
|
signal health_changed(new_health)
|
||||||
|
|
||||||
|
enum State { IDLE, RUNNING }
|
||||||
|
|
||||||
|
static func create() -> Player:
|
||||||
|
return Player.new()
|
||||||
|
|
||||||
|
func take_damage(amount: int) -> void:
|
||||||
|
health -= amount
|
||||||
|
|
||||||
|
class InnerHelper:
|
||||||
|
func help():
|
||||||
|
pass
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val entry = RepoMapIndexer().index(root).single()
|
||||||
|
assertEquals("player.gd", entry.path)
|
||||||
|
assertTrue(
|
||||||
|
entry.symbols.containsAll(
|
||||||
|
listOf("Player", "health_changed", "State", "create", "take_damage", "InnerHelper"),
|
||||||
|
),
|
||||||
|
"missing symbols in: ${entry.symbols}",
|
||||||
|
)
|
||||||
|
assertFalse(entry.symbols.contains("help"), "indented inner method must not be matched")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `empty or missing root yields empty map`(@TempDir root: Path) {
|
fun `empty or missing root yields empty map`(@TempDir root: Path) {
|
||||||
assertTrue(RepoMapIndexer().index(root).isEmpty())
|
assertTrue(RepoMapIndexer().index(root).isEmpty())
|
||||||
|
|||||||
Reference in New Issue
Block a user