mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 10:16:00 +00:00
Fix Svelte (svelte-only) symbol discovery in .ts/.js files (#1552)
Bug: with `languages: [svelte]` (the documented setup), find_symbol/get_symbols_overview returned empty for .ts/.js files, and find_referencing_symbols failed with "No symbol matching '<name>' found". Symbols living in plain .ts/.js modules (services, stores, types, utils) were undiscoverable through Serena's symbolic tools. Cause: SvelteLanguageServer delegated references/definition/rename/diagnostics for .ts/.js files to the companion (svelte-plugin-aware) TS server, but had no override for document-symbol requests. So documentSymbol on a .ts/.js file was answered by the base svelte LS, which only serves .svelte files, and returned nothing. Since find_symbol/get_symbols_overview are backed by documentSymbol -- and find_referencing_symbols must first locate the target symbol the same way -- the discovery step never reached the companion. Fix: override request_document_symbols to route .ts/.js files to the companion TS server, mirroring the existing delegations. This is the single method that all symbol-tree/overview/containing-symbol paths flow through, so it restores discovery for find_symbol, get_symbols_overview, find_referencing_symbols and symbol-based editing in one place. Tests: add .ts document-symbol and overview coverage plus agent-level symbol-retriever tests; strengthen the existing symbol-tree test to assert GAME_VERSION, a symbol defined only in a .ts file (the prior assertions also matched .svelte definitions, which is why the regression went unnoticed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b912152131
commit
79bc9d91cc
4 files changed
+122
No files matched your search
@@ -18,6 +18,10 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
at the Yarn-generated SDK.
|
||||
- `SvelteLanguageServer`: Fix diagnostics requests for TypeScript/JavaScript files incorrectly being
|
||||
processed by the Svelte LS instead of the TypeScript LS.
|
||||
- `SvelteLanguageServer`: Fix document-symbol requests for TypeScript/JavaScript files returning empty
|
||||
results in svelte-only mode (`languages: [svelte]`). They are now routed to the companion TS server,
|
||||
so symbols defined in plain `.ts`/`.js` files are again discoverable via `find_symbol`/
|
||||
`get_symbols_overview`, and `find_referencing_symbols` no longer fails to locate `.ts`/`.js` symbols. #1552
|
||||
- Improve quoting of arguments in shell executions
|
||||
|
||||
* JetBrains:
|
||||
|
||||
@@ -21,8 +21,10 @@ from solidlsp.language_servers.common import (
|
||||
)
|
||||
from solidlsp.language_servers.typescript_language_server import TypeScriptLanguageServer
|
||||
from solidlsp.ls import (
|
||||
DocumentSymbols,
|
||||
LanguageServerDependencyProvider,
|
||||
LanguageServerDependencyProviderSinglePath,
|
||||
LSPFileBuffer,
|
||||
SolidLanguageServer,
|
||||
)
|
||||
from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig
|
||||
@@ -647,6 +649,25 @@ class SvelteLanguageServer(SolidLanguageServer):
|
||||
return self._ts_server.request_definition(relative_file_path, line, column)
|
||||
return super().request_definition(relative_file_path, line, column)
|
||||
|
||||
@override
|
||||
def request_document_symbols(self, relative_file_path: str, file_buffer: LSPFileBuffer | None = None) -> DocumentSymbols:
|
||||
"""Delegate document-symbol requests for .ts/.js files to the companion TS server.
|
||||
|
||||
The base svelte LS only provides ``documentSymbol`` for .svelte files and returns nothing for
|
||||
.ts/.js files. Without this override, symbols defined in plain .ts/.js modules would be
|
||||
undiscoverable via ``find_symbol``/``get_symbols_overview`` and ``find_referencing_symbols``
|
||||
would fail outright, since it must first locate the target symbol via ``documentSymbol``.
|
||||
Routing .ts/.js files to the companion (svelte-plugin-aware) typescript LS mirrors the
|
||||
existing references/definition/rename delegations.
|
||||
|
||||
The companion's own ``file_buffer`` is not reused here: the provided buffer (if any) is bound
|
||||
to this svelte LS, so the companion opens and reads the file itself.
|
||||
Falls back to the svelte LS when the companion is unavailable or when the file is .svelte.
|
||||
"""
|
||||
if _is_ts_file(relative_file_path) and self._ts_server is not None:
|
||||
return self._ts_server.request_document_symbols(relative_file_path)
|
||||
return super().request_document_symbols(relative_file_path, file_buffer)
|
||||
|
||||
@override
|
||||
def request_text_document_diagnostics(
|
||||
self,
|
||||
|
||||
@@ -30,6 +30,12 @@ class TestSvelteLanguageServer:
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Game"), "Game class not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "words"), "words export not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "count"), "count export not found in symbol tree"
|
||||
# GAME_VERSION is defined *only* in a .ts file (game.ts); it is merely imported elsewhere.
|
||||
# It therefore guards against the regression where .ts document symbols are not routed to the
|
||||
# companion TS server (unlike game/Game/words/count, which also appear in .svelte files).
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "GAME_VERSION"), (
|
||||
"GAME_VERSION (defined only in a .ts file) not found in symbol tree"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True)
|
||||
def test_document_symbols_inside_svelte_file(self, language_server: SolidLanguageServer) -> None:
|
||||
@@ -40,6 +46,30 @@ class TestSvelteLanguageServer:
|
||||
assert "offset" in symbol_names
|
||||
assert "modulo" in symbol_names
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True)
|
||||
def test_document_symbols_inside_typescript_file(self, language_server: SolidLanguageServer) -> None:
|
||||
# document symbols of a plain .ts file must be served by the companion TS server, not the
|
||||
# base svelte LS (which only provides documentSymbol for .svelte files); see issue #1552.
|
||||
file_path = os.path.join("src", "lib", "game.ts")
|
||||
symbol_names = {symbol["name"] for symbol in language_server.request_document_symbols(file_path).iter_symbols()}
|
||||
|
||||
# top-level symbols
|
||||
assert "GAME_VERSION" in symbol_names, symbol_names
|
||||
assert "Game" in symbol_names, symbol_names
|
||||
# members nested inside the Game class
|
||||
assert "enter" in symbol_names, symbol_names
|
||||
assert "toString" in symbol_names, symbol_names
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True)
|
||||
def test_overview_of_typescript_file(self, language_server: SolidLanguageServer) -> None:
|
||||
# get_symbols_overview on a .ts file must not be empty in svelte-only mode (issue #1552).
|
||||
file_path = os.path.join("src", "lib", "game.ts")
|
||||
overview = language_server.request_overview(file_path)
|
||||
|
||||
top_level_names = {symbol["name"] for symbols in overview.values() for symbol in symbols}
|
||||
assert "GAME_VERSION" in top_level_names, overview
|
||||
assert "Game" in top_level_names, overview
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True)
|
||||
def test_definition_from_component_import_to_svelte_file(self, language_server: SolidLanguageServer) -> None:
|
||||
file_path = os.path.join("src", "lib", "components", "Header.svelte")
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Agent-level symbol discovery/navigation for plain .ts files of a svelte-only project.
|
||||
|
||||
Reproduces https://github.com/oraios/serena/issues/1552: in ``languages: [svelte]`` mode,
|
||||
document-symbol requests for .ts/.js files were answered by the base svelte LS (which only
|
||||
serves .svelte files) instead of being routed to the companion, svelte-plugin-aware TS server.
|
||||
As a consequence, symbols defined in plain .ts files were undiscoverable through ``find_symbol``/
|
||||
``get_symbols_overview``, and ``find_referencing_symbols`` failed with ``No symbol matching ...``
|
||||
because it must first locate the target symbol via ``documentSymbol``.
|
||||
|
||||
These tests exercise the high-level :class:`LanguageServerSymbolRetriever` that backs those agent
|
||||
tools, complementing the lower-level checks in ``test_svelte_basic.py``.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from serena.project import Project
|
||||
from serena.symbol import LanguageServerSymbolRetriever
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_types import SymbolKind
|
||||
|
||||
pytestmark = pytest.mark.svelte
|
||||
|
||||
# a plain .ts module whose exported symbols are consumed by both .ts and .svelte files
|
||||
GAME_TS = os.path.join("src", "lib", "game.ts")
|
||||
|
||||
|
||||
class TestSvelteTypeScriptSymbolDiscovery:
|
||||
@pytest.mark.parametrize("project_with_ls", [Language.SVELTE], indirect=True)
|
||||
def test_find_symbol_in_typescript_file(self, project_with_ls: Project) -> None:
|
||||
retriever = LanguageServerSymbolRetriever(project_with_ls)
|
||||
|
||||
# GAME_VERSION is *defined* only in game.ts (merely imported elsewhere)
|
||||
version_symbols = retriever.find("GAME_VERSION", within_relative_path=GAME_TS)
|
||||
assert [s.name for s in version_symbols] == ["GAME_VERSION"]
|
||||
assert version_symbols[0].relative_path is not None
|
||||
assert version_symbols[0].relative_path.replace("\\", "/") == "src/lib/game.ts"
|
||||
|
||||
# the Game class is discoverable and correctly typed
|
||||
game_symbols = retriever.find("Game", within_relative_path=GAME_TS, include_kinds=[SymbolKind.Class])
|
||||
assert len(game_symbols) == 1, game_symbols
|
||||
assert game_symbols[0].symbol_kind == SymbolKind.Class
|
||||
|
||||
# nested members of the .ts class are discoverable via their name path
|
||||
enter_symbols = retriever.find("Game/enter", within_relative_path=GAME_TS)
|
||||
assert len(enter_symbols) == 1, enter_symbols
|
||||
assert enter_symbols[0].get_name_path() == "Game/enter"
|
||||
|
||||
@pytest.mark.parametrize("project_with_ls", [Language.SVELTE], indirect=True)
|
||||
def test_find_referencing_symbols_locates_typescript_symbol(self, project_with_ls: Project) -> None:
|
||||
retriever = LanguageServerSymbolRetriever(project_with_ls)
|
||||
|
||||
# The core of issue #1552 for find-references: the target symbol must first be located via
|
||||
# documentSymbol. Before the fix, .ts document symbols were empty, so locating the symbol
|
||||
# raised ValueError("No symbol matching 'GAME_VERSION' found") *before the companion TS
|
||||
# server was ever consulted*. Verify the symbol is now uniquely discoverable.
|
||||
symbol = retriever.find_unique("GAME_VERSION", within_relative_path=GAME_TS)
|
||||
assert symbol.name == "GAME_VERSION"
|
||||
assert symbol.relative_path is not None
|
||||
assert symbol.relative_path.replace("\\", "/") == "src/lib/game.ts"
|
||||
|
||||
# The end-to-end find_referencing_symbols call must now get past symbol discovery without
|
||||
# raising. (The cross-file/.svelte reference *content* is covered by test_svelte_references.py
|
||||
# and depends on the companion TS server's reference graph rather than on this fix.)
|
||||
references = retriever.find_referencing_symbols("GAME_VERSION", GAME_TS)
|
||||
assert isinstance(references, list)
|
||||
Reference in new issue
Block a user