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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions