mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-11 03:13:51 +00:00
feat: add Deno language server support
Add a Deno language server backed by the Deno CLI's built-in `deno lsp`, serving TypeScript/JavaScript in Deno projects. Unlike the plain typescript-language-server it understands Deno module resolution (npm:/jsr:/https: imports) and the `Deno.*` global namespace. It is experimental and must be selected explicitly via `language_servers: [deno]`; it overlaps the TypeScript server on file extensions, so it is not auto-detected. Requires the `deno` CLI on PATH. Tests run in CI: the `deno` marker joins the other-langs batch, which now installs Deno via denoland/setup-deno. Off-CI and wherever the CLI is absent they skip through the central conftest guard, following the existing pattern for toolchain-gated language servers. Hover is covered explicitly, including hover on a `Deno.*` global, which is the capability this server adds over the TypeScript one.
This commit is contained in:
1 parent
c7af2c09ef
commit
7a870878b8
13 files changed
+328
-14
No files matched your search
@@ -71,7 +71,7 @@ jobs:
|
||||
# other-langs: grab-bag + scripting languages + haskell + qml. Haskell (GHC/HLS) and qml (qmlls) are
|
||||
# installed only on Linux -- too slow/expensive to build on the macOS runner (Haskell), or not worth
|
||||
# the cost of a cross-OS Qt pull (qmlls) -- and skip on Windows+macOS via the central conftest guard.
|
||||
MARKERS_OTHER_LANGS: "ruby or php or lua or luau or bash or powershell or elixir or erlang or dart or haxe or haskell or terraform or rego or ansible or yaml or toml or markdown or latex or crystal or cue or fortran or ada or matlab or systemverilog or hlsl or msl or al or qml"
|
||||
MARKERS_OTHER_LANGS: "ruby or php or lua or luau or bash or powershell or elixir or erlang or dart or deno or haxe or haskell or terraform or rego or ansible or yaml or toml or markdown or latex or crystal or cue or fortran or ada or matlab or systemverilog or hlsl or msl or al or qml"
|
||||
# niche: slow, mostly-cached toolchains. ocaml + haskell are the two slowest -- kept in separate
|
||||
# batches (ocaml here, haskell in other-langs). nix + perl skip on Windows via the guard.
|
||||
MARKERS_NICHE: "julia or r or perl or lean4 or nix or ocaml"
|
||||
@@ -219,6 +219,13 @@ jobs:
|
||||
with:
|
||||
terraform_version: "1.5.0"
|
||||
terraform_wrapper: false
|
||||
# Deno ships its language server with the CLI (`deno lsp`), so installing the
|
||||
# runtime is all that is needed for the deno-marked tests.
|
||||
- name: Install Deno
|
||||
if: matrix.batch == 'other-langs'
|
||||
uses: denoland/setup-deno@v2
|
||||
with:
|
||||
deno-version: v2.x
|
||||
# - name: Install swift
|
||||
# if: runner.os != 'Windows'
|
||||
# uses: swift-actions/setup-swift@v2
|
||||
|
||||
@@ -65,6 +65,11 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
or `textDocument/didChange`), as this is always the intention of calling the method.
|
||||
If files were kept open in the language server (which the Svelte and Vue language servers did),
|
||||
the language server was not necessarily informed about updated contents.
|
||||
- Add Deno support (experimental; language server `deno`, backed by the Deno CLI's built-in
|
||||
`deno lsp`). Understands Deno module resolution (`npm:` / `jsr:` / `https:` imports) and the
|
||||
`Deno.*` globals, which the plain TypeScript language server does not. Overlaps TypeScript on
|
||||
file extensions, so it is not auto-detected and must be selected explicitly; requires the
|
||||
`deno` CLI on PATH
|
||||
|
||||
* JetBrains:
|
||||
- `jet_brains_find_symbol`: Disallow wildcard-only search, delegating to overview tool if request is for file
|
||||
|
||||
@@ -110,7 +110,7 @@ Serena incorporates a powerful abstraction layer for the integration of language
|
||||
The underlying language servers are typically open-source projects or at least freely available for use.
|
||||
|
||||
When using Serena's language server backend, we provide **support for over 40 programming languages**, including
|
||||
Ada / SPARK, AL, Angular, Ansible, Bash, BSL, C#, C/C++, Clojure, Crystal, CUE, Dart, Elixir, Elm, Erlang, Fortran, F#, GDScript, GLSL, Go, Groovy, Haskell, Haxe, HLSL, HTML, Java, JavaScript, JSON, Julia, Kotlin, LaTeX, Lean 4, Lua, Luau, Markdown, MATLAB, mSL, Nix, OCaml, Pascal, Perl, PHP, PowerShell, Python, QML, R, Rego, Ruby, Rust, Scala, SCSS / Sass / CSS, Solidity, Svelte, Swift, SystemVerilog, Terraform, TOML, TypeScript, Vue, WGSL, YAML, and Zig.
|
||||
Ada / SPARK, AL, Angular, Ansible, Bash, BSL, C#, C/C++, Clojure, Crystal, CUE, Dart, Deno, Elixir, Elm, Erlang, Fortran, F#, GDScript, GLSL, Go, Groovy, Haskell, Haxe, HLSL, HTML, Java, JavaScript, JSON, Julia, Kotlin, LaTeX, Lean 4, Lua, Luau, Markdown, MATLAB, mSL, Nix, OCaml, Pascal, Perl, PHP, PowerShell, Python, QML, R, Rego, Ruby, Rust, Scala, SCSS / Sass / CSS, Solidity, Svelte, Swift, SystemVerilog, Terraform, TOML, TypeScript, Vue, WGSL, YAML, and Zig.
|
||||
|
||||
### The Serena JetBrains Plugin
|
||||
|
||||
|
||||
@@ -164,6 +164,12 @@ Some languages require additional installations or setup steps, as noted.
|
||||
* **TOML**
|
||||
(experimental; uses Taplo 0.10.0, taken from PATH if present, otherwise downloaded automatically)
|
||||
* **TypeScript**
|
||||
* **Deno**
|
||||
(experimental; requires the `deno` CLI on PATH — it bundles the language server used here;
|
||||
serves Deno TypeScript/JavaScript and understands `npm:` / `jsr:` / `https:` imports and the `Deno.*`
|
||||
globals, which the plain TypeScript language server does not; overlaps `typescript` on file extensions,
|
||||
so it is not auto-detected and must be set as the language explicitly — do not also enable `typescript`
|
||||
for the same files)
|
||||
* **Vue**
|
||||
(3.x with TypeScript; requires Node.js v18+ and npm; supports .vue Single File Components with monorepo detection)
|
||||
* **YAML**
|
||||
|
||||
@@ -328,6 +328,7 @@ markers = [
|
||||
"groovy: language server running for Groovy",
|
||||
"rust: language server running for Rust",
|
||||
"typescript: language server running for TypeScript",
|
||||
"deno: language server running for Deno (uses the built-in deno lsp)",
|
||||
"svelte: language server running for Svelte (uses svelte-language-server)",
|
||||
"vue: language server running for Vue (uses TypeScript LSP)",
|
||||
"php: language server running for PHP",
|
||||
|
||||
@@ -4,18 +4,18 @@ project_name: "project_name"
|
||||
# list of language servers to start when using the LSP backend; choose from:
|
||||
# ada al angular ansible bash
|
||||
# bsl clojure cpp cpp_ccls crystal
|
||||
# csharp csharp_omnisharp cue dart elixir
|
||||
# elm erlang fortran fsharp gdscript
|
||||
# go groovy haskell haxe hlsl
|
||||
# html java json julia kotlin
|
||||
# latex lean4 lua luau markdown
|
||||
# matlab msl nix ocaml pascal
|
||||
# perl php php_phpactor php_phpantom powershell
|
||||
# python python_basedpyright python_jedi python_pyrefly python_ty
|
||||
# qml r rego ruby ruby_solargraph
|
||||
# rust scala scss solidity svelte
|
||||
# swift systemverilog terraform toml typescript
|
||||
# typescript_vts vue yaml zig
|
||||
# csharp csharp_omnisharp cue dart deno
|
||||
# elixir elm erlang fortran fsharp
|
||||
# gdscript go groovy haskell haxe
|
||||
# hlsl html java json julia
|
||||
# kotlin latex lean4 lua luau
|
||||
# markdown matlab msl nix ocaml
|
||||
# pascal perl php php_phpactor php_phpantom
|
||||
# powershell python python_basedpyright python_jedi python_pyrefly
|
||||
# python_ty qml r rego ruby
|
||||
# ruby_solargraph rust scala scss solidity
|
||||
# svelte swift systemverilog terraform toml
|
||||
# typescript typescript_vts vue yaml zig
|
||||
# (This list may be outdated; generated with scripts/print_language_list.py;
|
||||
# For the current list, see values of the LanguageServerId enum here:
|
||||
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py)
|
||||
@@ -25,6 +25,7 @@ project_name: "project_name"
|
||||
# - For JavaScript, use typescript
|
||||
# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root)
|
||||
# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm)
|
||||
# - For Deno projects, use deno (serves the same .ts/.js files as typescript; requires the deno CLI on PATH)
|
||||
# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three)
|
||||
# - For Free Pascal/Lazarus, use pascal
|
||||
# Special requirements:
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
Provides Deno-specific instantiation of the LanguageServer class, using the
|
||||
language server built into the Deno CLI (``deno lsp``).
|
||||
"""
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
|
||||
from overrides import override
|
||||
|
||||
from solidlsp.ls import LanguageServerDependencyProvider, LanguageServerDependencyProviderSinglePath, SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DenoLanguageServer(SolidLanguageServer):
|
||||
"""
|
||||
Deno instantiation of the LanguageServer class, backed by ``deno lsp``.
|
||||
|
||||
Serves TypeScript/JavaScript in Deno projects. Unlike the plain
|
||||
typescript-language-server, ``deno lsp`` understands Deno-specific module
|
||||
resolution (``npm:`` / ``jsr:`` / ``https:`` imports) and the ``Deno.*``
|
||||
global namespace.
|
||||
|
||||
This server overlaps the TypeScript server on file extensions and is therefore
|
||||
marked experimental: it is not auto-detected and must be selected explicitly via
|
||||
``languages: [deno]`` in ``project.yml``.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def supports_implementation_request(cls) -> bool:
|
||||
return True
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings):
|
||||
super().__init__(
|
||||
config,
|
||||
repository_root_path,
|
||||
None,
|
||||
"typescript",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
def _create_dependency_provider(self) -> LanguageServerDependencyProvider:
|
||||
return self.DependencyProvider(self._custom_settings, self._ls_resources_dir)
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
# node_modules appears in Deno projects using npm compatibility; vendor/ holds
|
||||
# vendored remote dependencies. Neither should be indexed as project sources.
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["node_modules", "vendor", "dist", "build"]
|
||||
|
||||
class DependencyProvider(LanguageServerDependencyProviderSinglePath):
|
||||
def _get_or_install_core_dependency(self) -> str:
|
||||
"""Return the path to the ``deno`` executable (the language server ships with it)."""
|
||||
deno_path = shutil.which("deno")
|
||||
if deno_path is None:
|
||||
raise FileNotFoundError(
|
||||
"The 'deno' executable was not found on PATH. Install Deno "
|
||||
"(https://docs.deno.com/runtime/getting_started/installation/) — it bundles "
|
||||
"the language server used here — and ensure 'deno' is on your PATH."
|
||||
)
|
||||
return deno_path
|
||||
|
||||
def _create_launch_command(self, core_path: str) -> list[str]:
|
||||
return [core_path, "lsp"]
|
||||
|
||||
def _get_language_id_for_file(self, relative_file_path: str) -> str:
|
||||
# deno lsp relies on the correct languageId; .tsx/.jsx in particular must not
|
||||
# be sent as plain "typescript" or symbol ranges get truncated at JSX expressions.
|
||||
if relative_file_path.endswith(".tsx"):
|
||||
return "typescriptreact"
|
||||
if relative_file_path.endswith(".jsx"):
|
||||
return "javascriptreact"
|
||||
if relative_file_path.endswith((".js", ".mjs", ".cjs")):
|
||||
return "javascript"
|
||||
return "typescript"
|
||||
|
||||
def _create_base_initialize_params(self) -> dict:
|
||||
return {
|
||||
"locale": "en",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {"didSave": True, "dynamicRegistration": True},
|
||||
"definition": {"dynamicRegistration": True},
|
||||
"references": {"dynamicRegistration": True},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": True,
|
||||
"hierarchicalDocumentSymbolSupport": True,
|
||||
"symbolKind": {"valueSet": list(range(1, 27))},
|
||||
},
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||
"completion": {"dynamicRegistration": True, "completionItem": {"snippetSupport": True}},
|
||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
"configuration": True,
|
||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||
"symbol": {"dynamicRegistration": True},
|
||||
},
|
||||
},
|
||||
# deno lsp reads its settings from initializationOptions; enabling the server
|
||||
# and the linter mirrors the defaults of the official VS Code Deno extension.
|
||||
"initializationOptions": {
|
||||
"enable": True,
|
||||
"lint": True,
|
||||
"unstable": False,
|
||||
},
|
||||
}
|
||||
|
||||
def _start_server(self) -> None:
|
||||
"""Start the ``deno lsp`` process and drive the LSP initialize handshake."""
|
||||
|
||||
def register_capability_handler(params: dict) -> None:
|
||||
return
|
||||
|
||||
def window_log_message(msg: dict) -> None:
|
||||
log.info(f"LSP: window/logMessage: {msg}")
|
||||
|
||||
def do_nothing(params: dict) -> None:
|
||||
return
|
||||
|
||||
def configuration_handler(params: dict) -> list:
|
||||
# deno lsp requests workspace/configuration during startup; return an empty
|
||||
# settings object per requested item so it proceeds with its defaults.
|
||||
return [{} for _ in params.get("items", [])]
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_request("workspace/configuration", configuration_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
# Deno-specific notifications emitted after config discovery; no action needed.
|
||||
self.server.on_notification("deno/didRefreshDenoConfigurationTree", do_nothing)
|
||||
self.server.on_notification("deno/didChangeDenoConfiguration", do_nothing)
|
||||
|
||||
log.info("Starting deno lsp server process")
|
||||
self.server.start()
|
||||
initialize_params = self._create_initialize_params()
|
||||
|
||||
log.info("Sending initialize request from LSP client to deno lsp and awaiting response")
|
||||
init_response = self.server.send.initialize(initialize_params)
|
||||
|
||||
assert "textDocumentSync" in init_response["capabilities"]
|
||||
assert "definitionProvider" in init_response["capabilities"]
|
||||
assert "documentSymbolProvider" in init_response["capabilities"]
|
||||
assert "referencesProvider" in init_response["capabilities"]
|
||||
|
||||
self.server.notify.initialized({})
|
||||
@@ -286,6 +286,14 @@ class LanguageServerId(str, Enum):
|
||||
project.yml — Angular LS supersedes both for Angular projects.
|
||||
Must be explicitly specified in project.yml.
|
||||
"""
|
||||
DENO = "deno"
|
||||
"""Deno's built-in language server (``deno lsp``) for Deno TypeScript/JavaScript projects.
|
||||
Understands Deno module resolution (``npm:`` / ``jsr:`` / ``https:`` imports) and the
|
||||
``Deno.*`` globals, which the plain typescript-language-server does not. Overlaps the
|
||||
TypeScript server on file extensions (.ts/.tsx/.js/.jsx/.mts/.cts/.mjs/.cjs), so it is
|
||||
experimental and must be explicitly specified via ``languages: [deno]`` in project.yml;
|
||||
do not also enable typescript for the same files. Requires the ``deno`` CLI on PATH.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def iter_all(cls, include_experimental: bool = True, include_non_programming_languages: bool = True) -> Iterable[Self]:
|
||||
@@ -321,6 +329,7 @@ class LanguageServerId(str, Enum):
|
||||
self.HTML,
|
||||
self.SCSS,
|
||||
self.ANGULAR,
|
||||
self.DENO,
|
||||
}
|
||||
|
||||
def is_programming_language(self) -> bool:
|
||||
@@ -588,6 +597,14 @@ class LanguageServerId(str, Enum):
|
||||
for postfix in ["x", ""]:
|
||||
path_patterns.append(f".{prefix}ts{postfix}")
|
||||
return FilenameMatcher(*path_patterns)
|
||||
case self.DENO:
|
||||
# Deno serves the same TS/JS family as the TypeScript server.
|
||||
path_patterns = []
|
||||
for prefix in ["c", "m", ""]:
|
||||
for postfix in ["x", ""]:
|
||||
for base_pattern in ["ts", "js"]:
|
||||
path_patterns.append(f".{prefix}{base_pattern}{postfix}")
|
||||
return FilenameMatcher(*path_patterns)
|
||||
case _:
|
||||
raise ValueError(f"Unhandled language: {self}")
|
||||
|
||||
@@ -871,6 +888,10 @@ class LanguageServerId(str, Enum):
|
||||
from solidlsp.language_servers.angular_language_server import AngularLanguageServer
|
||||
|
||||
return AngularLanguageServer
|
||||
case self.DENO:
|
||||
from solidlsp.language_servers.deno_language_server import DenoLanguageServer
|
||||
|
||||
return DenoLanguageServer
|
||||
case _:
|
||||
raise ValueError(f"Unhandled language: {self}")
|
||||
|
||||
|
||||
@@ -286,6 +286,7 @@ _LANGUAGE_PYTEST_MARKERS: dict[LanguageServerId, list[MarkDecorator | Mark]] = {
|
||||
LanguageServerId.CPP_CCLS: [pytest.mark.cpp],
|
||||
LanguageServerId.CUE: [pytest.mark.cue],
|
||||
LanguageServerId.CSHARP: [pytest.mark.csharp],
|
||||
LanguageServerId.DENO: [pytest.mark.deno],
|
||||
LanguageServerId.FSHARP: [pytest.mark.fsharp],
|
||||
LanguageServerId.GO: [pytest.mark.go],
|
||||
LanguageServerId.HAXE: [pytest.mark.haxe],
|
||||
@@ -477,6 +478,8 @@ def _determine_disabled_language_servers() -> list[LanguageServerId]:
|
||||
result.append(LanguageServerId.OCAML)
|
||||
if not _is_perl_language_server_available(): # perl ships with the OS; the LS module is the real signal
|
||||
result.append(LanguageServerId.PERL)
|
||||
if _sh.which("deno") is None: # deno bundles the language server (`deno lsp`); skip where the CLI is absent
|
||||
result.append(LanguageServerId.DENO)
|
||||
|
||||
# === 4. Enabled everywhere: every language NOT listed in this function (python, go, java, ...) ===
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"lint": {
|
||||
"rules": {
|
||||
"tags": ["recommended"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { add } from "./util.ts";
|
||||
|
||||
export class Calculator {
|
||||
sum(a: number, b: number): number {
|
||||
return add(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
// Uses the Deno global namespace, which the plain TypeScript language server does not know about.
|
||||
export function describeCwd(): string {
|
||||
return `cwd: ${Deno.cwd()}`;
|
||||
}
|
||||
|
||||
const calc = new Calculator();
|
||||
console.log(calc.sum(2, 3));
|
||||
@@ -0,0 +1,7 @@
|
||||
export function add(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
export function subtract(a: number, b: number): number {
|
||||
return a - b;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerId
|
||||
from solidlsp.ls_types import Hover
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from test.conftest import language_server_tests_enabled
|
||||
|
||||
|
||||
def _hover_text(hover: Hover | None) -> str:
|
||||
"""Flatten the hover contents (markup object, plain string or list of either) into one string."""
|
||||
assert hover is not None, "Expected hover information, got None"
|
||||
contents = hover["contents"]
|
||||
items = contents if isinstance(contents, list) else [contents]
|
||||
return "\n".join(item if isinstance(item, str) else item["value"] for item in items)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.DENO), reason="Deno tests are disabled (deno not available)")
|
||||
@pytest.mark.deno
|
||||
class TestDenoLanguageServer:
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
assert language_server.is_running()
|
||||
assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve()
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
# main.ts line 4 (0-indexed): " return add(a, b);" — cursor on `add` (char 11).
|
||||
# `add` is defined in util.ts at line 0.
|
||||
definitions = language_server.request_definition(str(repo_path / "main.ts"), 4, 11)
|
||||
|
||||
assert definitions, f"Expected a definition for `add`, got {definitions=}"
|
||||
definition = definitions[0]
|
||||
assert definition["uri"].endswith("util.ts")
|
||||
assert definition["range"]["start"]["line"] == 0
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_find_references_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
# `add` is defined in util.ts line 0 at char len("export function ") == 16.
|
||||
references = language_server.request_references(str(repo_path / "util.ts"), 0, len("export function "))
|
||||
|
||||
assert references, f"Expected references for `add`, got {references=}"
|
||||
locations = [(ref["uri"].split("/")[-1], ref["range"]["start"]["line"]) for ref in references]
|
||||
# The usage inside Calculator.sum lives on line 4 of main.ts.
|
||||
assert ("main.ts", 4) in locations, f"Expected a reference in main.ts line 4, got {locations}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_document_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
all_symbols, _roots = language_server.request_document_symbols("main.ts").get_all_symbols_and_roots()
|
||||
names = [sym.get("name") for sym in all_symbols]
|
||||
assert "Calculator" in names, f"Calculator not found in main.ts document symbols: {names}"
|
||||
assert "sum" in names, f"sum not found in main.ts document symbols: {names}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_find_symbol(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
symbols = language_server.request_full_symbol_tree()
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Calculator"), "Calculator not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "add"), "add not found in symbol tree"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_hover_reports_function_signature(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
# `add` is defined in util.ts line 0 at char len("export function ") == 16.
|
||||
hover = language_server.request_hover(str(repo_path / "util.ts"), 0, len("export function "))
|
||||
|
||||
text = _hover_text(hover)
|
||||
assert "add" in text, f"Hover should name the function, got: {text}"
|
||||
assert "(a: number, b: number): number" in text, f"Hover should carry the signature, got: {text}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [LanguageServerId.DENO], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [LanguageServerId.DENO], indirect=True)
|
||||
def test_hover_resolves_deno_global(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
"""The `Deno.*` namespace is what this server adds over the plain TypeScript one, so it must resolve."""
|
||||
main = repo_path / "main.ts"
|
||||
lines = main.read_text(encoding="utf-8").splitlines()
|
||||
line = next(i for i, content in enumerate(lines) if "Deno.cwd()" in content)
|
||||
|
||||
hover = language_server.request_hover(str(main), line, lines[line].index("Deno.cwd") + len("Deno."))
|
||||
|
||||
text = _hover_text(hover)
|
||||
assert "cwd" in text, f"Hover should resolve Deno.cwd, got: {text}"
|
||||
assert "string" in text, f"Hover should carry Deno.cwd's return type, got: {text}"
|
||||
Reference in new issue
Block a user