Skip to content

TypeScript Method scope panics with "Failed to create scope query" — Java/Ruby work, TS doesn't #784

Description

@jdmcgrath

Repro

polyglot-piranha==0.4.8, Python 3.12.13, macOS arm64. The same scope_config shape (or trivially simpler) works for Java and Ruby but panics with "Failed to create scope query" at crates/core/src/models/scopes.rs:80 for TypeScript whenever a Method-scoped edge actually fires.

Minimal repro:

import tempfile
from polyglot_piranha import execute_piranha, PiranhaArguments

tmpdir = tempfile.mkdtemp()

with open(f'{tmpdir}/rules.toml', 'w') as f:
  f.write('''
[[rules]]
name = "delete_const_true"
query = """
(
  (lexical_declaration
    (variable_declarator
      name: (identifier) @variable_name
      value: (true) @init
    )
  ) @decl
)
"""
replace = ""
replace_node = "decl"
is_seed_rule = true

[[rules]]
name = "replace_identifier"
query = """((identifier) @id (#eq? @id "@variable_name"))"""
replace = "@init"
replace_node = "id"
holes = ["variable_name", "init"]
is_seed_rule = false
''')

with open(f'{tmpdir}/edges.toml', 'w') as f:
  f.write('''
[[edges]]
scope = "Method"
from = "delete_const_true"
to = ["replace_identifier"]
''')

with open(f'{tmpdir}/scope_config.toml', 'w') as f:
  f.write('''
[[scopes]]
name = "Method"
[[scopes.rules]]
enclosing_node = "(function_declaration name: (identifier) @n) @method"
scope = """((function_declaration name: (identifier) @z) @scope (#eq? @z "@n"))"""
''')

source = '''function foo(): void {
  const x = true;
  if (x) { doIt(); }
}
function bar(): void {
  const x = somethingElse();
  if (x) { doBar(); }
}
'''

args = PiranhaArguments(
  code_snippet=source,
  language='typescript',
  path_to_configurations=tmpdir,
  substitutions={'stale_flag_name': 'x'},
)
execute_piranha(args)

Expected

Cleanup runs: delete_const_true matches foo's const x = true, deletes it. The Method-scoped edge then routes to replace_identifier, which substitutes references to x inside foo (only) with true. bar's const x = somethingElse() and its if (x) are untouched. Final output:

function foo(): void {
  if (true) { doIt(); }
}
function bar(): void {
  const x = somethingElse();
  if (x) { doBar(); }
}

Actual

thread '<unnamed>' panicked at crates/core/src/models/scopes.rs:80:5:
=====================================
ERROR: Failed to create scope query
=====================================
Scope Level: Method
Source Code:
[…file dump showing const x = true already deleted from foo()…]
AST S-expression:
[…AST shows both function_declarations still present after the deletion…]

The scope-walk loop runs to completion without matching any ancestor against the enclosing_node query — even though function_declaration nodes exist in the AST and the change happened inside one. (Verified by removing the predicate, simplifying the query to just (function_declaration) @method, and even using the verbatim Java pack shape; all four variants panic.)

Notes

  • The same minimal scope_config for Java ((method_declaration …) @xdn) and Ruby ((method) @md) works fine on equivalent fixtures.
  • Without firing any Method-scoped edge, the scope_config compiles fine — i.e. the TOML itself is valid. The panic happens during runtime scope query construction on the TS source.
  • Switching scope = "Method" to scope = "Parent" in edges.toml removes the panic, but loses scope safety: replace_identifier then pollutes bar()'s same-named binding.
  • Tree-sitter version inside the polyglot_piranha-0.4.8-cp312-cp312-macosx_10_13_universal2.whl is whatever upstream 0.4.8 bundles — I don't know whether tree-sitter-typescript upstream changed a node-type name in a way that breaks the ancestor-walk, but the AST dump clearly contains the function_declaration we expect to match.

If this is a known limitation of TS support, a documented note would help — currently nothing in the README or POLYGLOT_README suggests Method scope is unimplemented for the language.

Happy to provide more diagnostics. PR-able if you can point at where the scope-rule lookup fails to match — I tried adding (program) @method as a fallback rule, same panic, so the issue isn't the query itself but rather the loop never finding a successful match.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions