diff --git a/CHANGELOG.md b/CHANGELOG.md index 281dd84b..b4497495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ Status of the `main` branch. Changes prior to the next official version change w * Language support: * **Add support for Fortran** via fortls language server (requires `pip install fortls`) + * **Add partial support for Groovy** requires user-provided Groovy language server JAR (see [setup guide](docs/03-special-guides/groovy_setup_guide_for_serena.md)) * **Add support for Julia** via LanguageServer.jl * **Add support for Haskell** via Haskell Language Server (HLS) with automatic discovery via ghcup, stack, or system PATH; supports both Stack and Cabal projects * **Add support for Scala** via Metals language server (requires some [manual setup](docs/03-special-guides/scala_setup_guide_for_serena.md)) diff --git a/README.md b/README.md index e5905808..49c715be 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ than existing solutions that charge a premium. Language servers provide support for a wide range of programming languages. With Serena's LSP library, we provide **support for over 30 programming languages**, including -AL, Bash, C#, C/C++, Clojure, Dart, Elixir, Elm, Erlang, Fortran, Go, Haskell, Java, Javascript, Julia, Kotlin, Lua, Markdown, Nix, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, Swift, TOML, TypeScript, YAML, and Zig. +AL, Bash, C#, C/C++, Clojure, Dart, Elixir, Elm, Erlang, Fortran, Go, Groovy (partial support), Haskell, Java, Javascript, Julia, Kotlin, Lua, Markdown, Nix, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, Swift, TOML, TypeScript, YAML, and Zig. > [!IMPORTANT] > Some languages require additional dependencies to be installed; see the [Language Support](https://oraios.github.io/serena/01-about/020_programming-languages.html) page for details. diff --git a/docs/01-about/020_programming-languages.md b/docs/01-about/020_programming-languages.md index 3637ce04..c456e724 100644 --- a/docs/01-about/020_programming-languages.md +++ b/docs/01-about/020_programming-languages.md @@ -31,6 +31,8 @@ With Serena, we provide direct, out-of-the-box support for: (requires installation of fortls: `pip install fortls`) * **Go** (requires installation of `gopls`) +* **Groovy** + (requires local groovy-language-server.jar setup via GROOVY_LS_JAR_PATH or configuration) * **Haskell** (automatically locates HLS via ghcup, stack, or system PATH; supports Stack and Cabal projects) * **Java** diff --git a/docs/02-usage/030_clients.md b/docs/02-usage/030_clients.md index 57b69151..74b84a00 100644 --- a/docs/02-usage/030_clients.md +++ b/docs/02-usage/030_clients.md @@ -1,24 +1,82 @@ # Connecting Your MCP Client -In the following, we provide default configurations for popular MCP-enabled clients. +In the following, we provide general instructions on how to connect Serena to your MCP-enabled client, +as well as specific instructions for popular clients. -Depending on your needs, you might want to customize Serena's behaviour by - * [adding command-line arguments](mcp-args) - * [adjusting configuration](050_configuration). +(clients-general-instructions)= +## General Instructions -## Claude Code +In general, Serena can be used with any MCP-enabled client. +To connect Serena to your favourite client, simply + +1. determine how to add a custom MCP server to your client (refer to the client's documentation). +2. add a new MCP server entry by specifying either + * a [run command](start-mcp-server) that allows the client to start the MCP server in stdio mode as a subprocess, or + * the URL of the HTTP/SSE endpoint, having started the [Serena MCP server in HTTP/SSE mode](streamable-http) beforehand. + +Depending on your needs, you might want to further customize Serena's behaviour by +* [adding command-line arguments](mcp-args) +* [adjusting configuration](050_configuration). + +**Mode of Operation**. +Note that some clients have a per-workspace MCP configuration (e.g, VSCode and Claude Code), +while others have a global MCP configuration (e.g. Codex and Claude Desktop). + +- In the per-workspace case, you typically want to start Serena with your workspace directory as the project directory + and never switch to a different project. This is achieved by specifying the + `--project ` argument with a single-project [context](#contexts) (e.g. `ide` or `claude-code`). +- In the global configuration case, you must first activate the project you want to work on, which you can do by asking + the LLM to do so (e.g., "Activate the current dir as project using serena"). In such settings, the `activate_project` + tool is required. + +**Tool Selection**. +While you may be able to turn off tools through your client's interface (e.g., in VSCode or Claude Desktop), +we recommend selecting your base tool set through Serena's configuration, as Serena's prompts automatically +adjust based on which tools are enabled/disabled. +A key mechanism for this is to use the appropriate [context](#contexts) when starting Serena. + +(clients-common-pitfalls)= +### Common Pitfalls + +**Escaping Paths Correctly**. +Note that if your client configuration uses JSON, special characters (like backslashes) need to be escaped properly. +In particular, if you are specifying paths containing backslashes on Windows +(note that you can also just use forward slashes), be sure to escape them correctly (`\\`). + +**Discoverability of `uvx`**. +Your client may not find the `uvx` command, even if it is on your system PATH. +In this case, a workaround is to provide the full path to the `uvx` executable. + +**Environment Variables**. +Some language servers may require additional environment variables to be set (e.g. F# on macOS with Homebrew), +which you may need to explicitly add to the MCP server configuration. +Note that for some clients (e.g. Claude Desktop), the spawned MCP server process may not inherit environment variables that +are only configured in your shell profile (e.g. `.bashrc`, `.zshrc`, etc.); they would need to be set system-wide instead. +An easy fix is to add them explicitly to the MCP server entry. +For example, in Claude Desktop and other clients, you can simply add an `env` key to the `serena` +object, e.g. + +``` +"env": { + "DOTNET_ROOT": "/opt/homebrew/Cellar/dotnet/9.0.8/libexec" +} +``` + +## Specific Clients + +:::{note} +In this section, we present example configurations that run the latest version of Serena +using the `stdio` protocol with `uvx`. +Adapt the commands to your preferred way of [running Serena](020_running), adding any additional +command-line arguments as needed. +::: + +### Claude Code Serena is a great way to make Claude Code both cheaper and more powerful! From your project directory, add serena with a command like this, -```shell -claude mcp add serena -- start-mcp-server --context claude-code --project "$(pwd)" -``` - -where `` is [your way of running Serena](020_running). -For example, when using `uvx`, the above command becomes - ```shell claude mcp add serena -- uvx --from git+https://github.com/oraios/serena serena start-mcp-server --context claude-code --project "$(pwd)" ``` @@ -29,10 +87,37 @@ Note: * We specify the current directory as the project directory with `--project "$(pwd)"`, such that Serena is configured to work on the current project from the get-go, following Claude Code's mode of operation. - -Be sure to use at least `v1.0.52` of Claude Code (as earlier versions do not read MCP server system prompts upon startup). -## Codex + +### VSCode + +While serena can be directly installed from the GitHub MCP server registry, we recommend to set it up manually +(at least for now, until the configuration there has been improved). Just paste the following into +`/.vscode/mcp.json`, or edit the entry after using the option `install into workspace`: + +```json +{ + "servers": { + "oraios/serena": { + "type": "stdio", + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "ide", + "--project", + "${workspaceFolder}" + ] + } + }, + "inputs": [] +} +``` + +### Codex Serena works with OpenAI's Codex CLI out of the box, but you have to use the `codex` context for it to work properly. (The technical reason is that Codex doesn't fully support the MCP specifications, so some massaging of tools is required.). @@ -45,6 +130,7 @@ For example, when using `uvx`, add the following section: command = "uvx" args = ["--from", "git+https://github.com/oraios/serena", "serena", "start-mcp-server", "--context", "codex"] ``` + After codex has started, you need to activate the project, which you can do by saying: "Activate the current dir as project using serena" @@ -59,95 +145,136 @@ that was already taken). > Codex will often show the tools as `failed` even though they are successfully executed. This is not a problem, seems to be a bug in Codex. Despite the error message, everything works as expected. -## Claude Desktop +### Claude Desktop -On Windows and macOS there are official [Claude Desktop applications by Anthropic](https://claude.ai/download), for Linux there is an [open-source +On Windows and macOS, there are official [Claude Desktop applications by Anthropic](https://claude.ai/download); for Linux, there is an [open-source community version](https://github.com/aaddrick/claude-desktop-debian). To configure MCP server settings, go to File / Settings / Developer / MCP Servers / Edit Config, which will let you open the JSON file `claude_desktop_config.json`. -Add the `serena` MCP server configuration, using a [run command](020_running.md) depending on your setup. +Add the `serena` MCP server configuration -* local installation: - - ```json - { - "mcpServers": { - "serena": { - "command": "/abs/path/to/uv", - "args": ["run", "--directory", "/abs/path/to/serena", "serena", "start-mcp-server"] - } - } - } - ``` - -* uvx: - - ```json - { - "mcpServers": { - "serena": { - "command": "/abs/path/to/uvx", - "args": ["--from", "git+https://github.com/oraios/serena", "serena", "start-mcp-server"] - } - } +```json +{ + "mcpServers": { + "serena": { + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server" + ] + } } - ``` - -* docker: - - ```json - { - "mcpServers": { - "serena": { - "command": "docker", - "args": ["run", "--rm", "-i", "--network", "host", "-v", "/path/to/your/projects:/workspaces/projects", "ghcr.io/oraios/serena:latest", "serena", "start-mcp-server", "--transport", "stdio"] - } - } - } - ``` - -If you are using paths containing backslashes for paths on Windows -(note that you can also just use forward slashes), be sure to escape them correctly (`\\`). - -:::{note} -Some language servers may require additional environment variables to be set (e.g. F# on macOS with Homebrew), -which you may need to explicitly add to the MCP server configuration. -Note that the spawned processes will not inherit environment variables that are only configured in your shell -profile (e.g. `.bashrc`, `.zshrc`, etc.); they would need to be set system-wide instead. -An easy fix is to add them explicitly to the MCP server entry: Simply add an `env` key to the `serena` object, e.g. - -``` -"env": { - "DOTNET_ROOT": "/opt/homebrew/Cellar/dotnet/9.0.8/libexec" } ``` -::: -Once you have created the new MCP server entry, save the config and then restart Claude Desktop. +If your language server requires specific environment variables to be set (e.g. F# on macOS with Homebrew), +you can add them via an `env` key (see [above](#clients-common-pitfalls)). + +Once you have created the new MCP server entry, save the config and then restart Claude Desktop. :::{attention} -Be sure to fully quit the Claude Desktop application via File / Exit, as regularly closing the application will just minimize it. +Be sure to fully quit the Claude Desktop application via File / Exit, as regularly closing the application will just +minimize it. ::: After restarting, you should see Serena's tools in your chat interface (notice the small hammer icon). -For more information on MCP servers with Claude Desktop, see [the official quick start guide](https://modelcontextprotocol.io/quickstart/user). +For more information on MCP servers with Claude Desktop, +see [the official quick start guide](https://modelcontextprotocol.io/quickstart/user). -## Other Clients +### JetBrains Junie -In general, Serena can be used with any MCP-enabled client. -To connect Serena to your favourite client, simply +Open Junie, go to the three dots in the top right corner, then Settings / MCP Settings and add Serena to Junie's global +MCP server configuration: -1. determine how to add a custom MCP server to your client (refer to the client's documentation). -2. add a new MCP server entry by specifying either - * a [run command](start-mcp-server) that allows the client to start the MCP server in stdio mode as a subprocess, or - * the URL of the HTTP/SSE endpoint, having started the [Serena MCP server in HTTP/SSE mode](streamable-http) beforehand. +```json +{ + "mcpServers": { + "serena": { + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "ide" + ] + } + } +} +``` -Below, we list some popular categories of clients that Serena can be used with. +You will have to prompt Junie to "Activate the current project using serena's activation tool" at the +start of each session. -### Terminal-Based Clients +### JetBrains AI Assistant + +Here you can set up the more convenient per-project MCP server configuration, as the AI assistant supports specifying +the launch working directory. + +Go to Settings / Tools / AI Assistant / MCP and add a new **local** configuration via the `as JSON` option: + +```json +{ + "mcpServers": { + "serena": { + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "ide", + "--project", + "$(pwd)" + ] + } + } +} +``` + +Then make sure to configure the working directory to be the project root. + +### Antigravity + +:::{warning} +At the time of writing (12/2025), Antigravity does not seem to work with Serena due to schema validation issues +which are beyond our control. +The client starts Serena but then crashes with `[internal] marshal message: string field contains invalid UTF-8`. +Nevertheless, we provide a configuration that should work once the issue is resolved. +::: + +Add this configuration: + +```json +{ + "mcpServers": { + "serena": { + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "ide" + ] + } + } +} +``` + +### Other Clients + +For other clients, follow the [general instructions](#clients-general-instructions) above to set up Serena as an MCP server. + +#### Terminal-Based Clients There are many terminal-based coding assistants that support MCP servers, such as @@ -160,15 +287,18 @@ There are many terminal-based coding assistants that support MCP servers, such a They generally benefit from the symbolic tools provided by Serena. You might want to customize some aspects of Serena by writing your own context, modes or prompts to adjust it to the client's respective internal capabilities (and your general workflow). -### MCP-Enabled IDEs and Coding Clients (Cline, Roo-Code, Cursor, Windsurf, etc.) +In most cases, the `ide` context is likely to be appropriate for such clients, i.e. add the arguments `--context ide` +in order to reduce tool duplication. + +#### MCP-Enabled IDEs and Coding Clients (Cline, Roo-Code, Cursor, Windsurf, etc.) Most of the popular existing coding assistants (e.g. IDE extensions) and AI-enabled IDEs themselves support connections to MCP Servers. Serena generally boosts performance by providing efficient tools for symbolic operations. -We generally **recommend to use the `ide` context** for these integrations by adding the arguments `--context ide` +We generally recommend to use the `ide` context for these integrations by adding the arguments `--context ide` in order to reduce tool duplication. -### Local GUIs and Agent Frameworks +#### Local GUIs and Agent Frameworks Over the last months, several technologies have emerged that allow you to run a local GUI client and connect it to an MCP server. The respective applications will typically work with Serena out of the box. diff --git a/docs/03-special-guides/groovy_setup_guide_for_serena.md b/docs/03-special-guides/groovy_setup_guide_for_serena.md new file mode 100644 index 00000000..50e5be23 --- /dev/null +++ b/docs/03-special-guides/groovy_setup_guide_for_serena.md @@ -0,0 +1,88 @@ +# Groovy Setup Guide for Serena + +The Groovy support in Serena is incomplete and requires the user to provide a functioning, +JVM-based Groovy language server as a jar. This intermediate state allows the contributors +of Groovy support to use Serena internally and hopefully to accelerate their open-source +release of a Groovy language server in the future. + +If you happen to have a Groovy language server JAR file, you can configure Serena to use it +by following the instructions below. + +--- +## Prerequisites + +- Groovy Language Server JAR file + - Can be any open-source Groovy language server or your custom implementation + - The JAR must be compatible with standard LSP protocol + +--- +## Configuration + +Configure Groovy Language Server by adding settings to your `~/.serena/serena_config.yml`: + +### Basic Configuration + +```yaml +ls_specific_settings: + groovy: + ls_jar_path: '/path/to/groovy-language-server.jar' + ls_jar_options: '-Xmx2G -Xms512m' +``` + +### Custom Java Paths + +If you have specific Java installations: + +```yaml +ls_specific_settings: + groovy: + ls_jar_path: '/path/to/groovy-language-server.jar' + ls_java_home_path: '/usr/lib/jvm/java-21-openjdk' # Custom JAVA_HOME directory + ls_jar_options: '-Xmx2G -Xms512m' # Optional JVM options +``` + +### Configuration Options + +- `ls_jar_path`: Absolute path to your Groovy Language Server JAR file (required) +- `ls_java_home_path`: Custom JAVA_HOME directory for Java installation (optional) + - When specified, Serena will use this Java installation instead of downloading bundled Java + - Java executable path is automatically determined based on platform: + - Windows: `{ls_java_home_path}/bin/java.exe` + - Linux/macOS: `{ls_java_home_path}/bin/java` + - Validates that Java executable exists at the expected location +- `ls_jar_options`: JVM options for language server (optional) + - Common options: + - `-Xmx`: Maximum heap size (e.g., `-Xmx2G` for 2GB) + - `-Xms`: Initial heap size (e.g., `-Xms512m` for 512MB) + +--- +## Project Structure Requirements + +For optimal Groovy Language Server performance, ensure your project follows standard Groovy/Gradle structure: + +``` +project-root/ +├── src/ +│ ├── main/ +│ │ ├── groovy/ +│ │ └── resources/ +│ └── test/ +│ ├── groovy/ +│ └── resources/ +├── build.gradle or build.gradle.kts +├── settings.gradle or settings.gradle.kts +└── gradle/ + └── wrapper/ +``` + +--- +## Using Serena with Groovy + +- Serena automatically detects Groovy files (`*.groovy`, `*.gvy`) and will start a Groovy Language Server JAR process per project when needed. +- Optimal results require that your project compiles successfully via Gradle or Maven. If compilation fails, fix build errors in your build tool first. + +## Reference + +- **Groovy Documentation**: [https://groovy-lang.org/documentation.html](https://groovy-lang.org/documentation.html) +- **Gradle Documentation**: [https://docs.gradle.org](https://docs.gradle.org) +- **Serena Configuration**: [../02-usage/050_configuration.md](../02-usage/050_configuration.md) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b68f07ae..71f2516a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -273,6 +273,7 @@ markers = [ "go: language server running for Go", "java: language server running for Java", "kotlin: language server running for kotlin", + "groovy: language server running for Groovy", "rust: language server running for Rust", "typescript: language server running for TypeScript", "vue: language server running for Vue (uses TypeScript LSP)", diff --git a/src/serena/agent.py b/src/serena/agent.py index 394c14bb..e596dd1c 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -195,6 +195,7 @@ class SerenaAgent: # open GUI log window if enabled self._gui_log_viewer: Optional["GuiLogViewer"] = None if self.serena_config.gui_log_window_enabled: + log.info("Opening GUI window") if platform.system() == "Darwin": log.warning("GUI log window is not supported on macOS") else: @@ -204,6 +205,8 @@ class SerenaAgent: self._gui_log_viewer = GuiLogViewer("dashboard", title="Serena Logs", memory_log_handler=get_memory_log_handler()) self._gui_log_viewer.start() + else: + log.debug("GUI window is disabled") # set the agent context if context is None: diff --git a/src/serena/code_editor.py b/src/serena/code_editor.py index 7220ef90..937d33a6 100644 --- a/src/serena/code_editor.py +++ b/src/serena/code_editor.py @@ -38,6 +38,9 @@ class CodeEditor(Generic[TSymbol], ABC): self.encoding = encoding class EditedFile(ABC): + def __init__(self, relative_path: str) -> None: + self.relative_path = relative_path + @abstractmethod def get_contents(self) -> str: """ @@ -67,9 +70,12 @@ class CodeEditor(Generic[TSymbol], ABC): with self._open_file_context(relative_path) as edited_file: yield edited_file # save the file - abs_path = os.path.join(self.project_root, relative_path) - with open(abs_path, "w", encoding=self.encoding) as f: - f.write(edited_file.get_contents()) + self._save_edited_file(edited_file) + + def _save_edited_file(self, edited_file: "CodeEditor.EditedFile") -> None: + abs_path = os.path.join(self.project_root, edited_file.relative_path) + with open(abs_path, "w", encoding=self.encoding) as f: + f.write(edited_file.get_contents()) @abstractmethod def _find_unique_symbol(self, name_path: str, relative_file_path: str) -> TSymbol: @@ -239,21 +245,21 @@ class LanguageServerCodeEditor(CodeEditor[LanguageServerSymbol]): class EditedFile(CodeEditor.EditedFile): def __init__(self, lang_server: SolidLanguageServer, relative_path: str, file_buffer: LSPFileBuffer): + super().__init__(relative_path) self._lang_server = lang_server - self._relative_path = relative_path self._file_buffer = file_buffer def get_contents(self) -> str: return self._file_buffer.contents def delete_text_between_positions(self, start_pos: PositionInFile, end_pos: PositionInFile) -> None: - self._lang_server.delete_text_between_positions(self._relative_path, start_pos.to_lsp_position(), end_pos.to_lsp_position()) + self._lang_server.delete_text_between_positions(self.relative_path, start_pos.to_lsp_position(), end_pos.to_lsp_position()) def insert_text_at_position(self, pos: PositionInFile, text: str) -> None: - self._lang_server.insert_text_at_position(self._relative_path, pos.line, pos.col, text) + self._lang_server.insert_text_at_position(self.relative_path, pos.line, pos.col, text) def apply_text_edits(self, text_edits: list[ls_types.TextEdit]) -> None: - return self._lang_server.apply_text_edits_to_file(self._relative_path, text_edits) + return self._lang_server.apply_text_edits_to_file(self.relative_path, text_edits) @contextmanager def _open_file_context(self, relative_path: str) -> Iterator["CodeEditor.EditedFile"]: @@ -319,6 +325,7 @@ class JetBrainsCodeEditor(CodeEditor[JetBrainsSymbol]): class EditedFile(CodeEditor.EditedFile): def __init__(self, relative_path: str, project: Project): + super().__init__(relative_path) path = os.path.join(project.project_root, relative_path) log.info("Editing file: %s", path) with open(path, encoding=project.project_config.encoding) as f: @@ -339,6 +346,11 @@ class JetBrainsCodeEditor(CodeEditor[JetBrainsSymbol]): def _open_file_context(self, relative_path: str) -> Iterator["CodeEditor.EditedFile"]: yield self.EditedFile(relative_path, self._project) + def _save_edited_file(self, edited_file: "CodeEditor.EditedFile") -> None: + super()._save_edited_file(edited_file) + with JetBrainsPluginClient.from_project(self._project) as client: + client.refresh_file(edited_file.relative_path) + def _find_unique_symbol(self, name_path: str, relative_file_path: str) -> JetBrainsSymbol: with JetBrainsPluginClient.from_project(self._project) as client: result = client.find_symbol(name_path, relative_path=relative_file_path, include_body=False, depth=0, include_location=True) diff --git a/src/serena/config/context_mode.py b/src/serena/config/context_mode.py index f1f34fd9..6cc94350 100644 --- a/src/serena/config/context_mode.py +++ b/src/serena/config/context_mode.py @@ -70,7 +70,7 @@ class SerenaAgentMode(ToolInclusionDefinition, ToStringMixin): own_yaml_path = os.path.join(SERENAS_OWN_MODE_YAMLS_DIR, fname) if not os.path.exists(own_yaml_path): raise FileNotFoundError( - f"Mode {name} not found in {SerenaPaths().user_modes_dir} or in {SERENAS_OWN_MODE_YAMLS_DIR}." + f"Mode {name} not found in {SerenaPaths().user_modes_dir} or in {SERENAS_OWN_MODE_YAMLS_DIR}. " f"Available modes:\n{cls.list_registered_mode_names()}" ) return own_yaml_path @@ -78,8 +78,16 @@ class SerenaAgentMode(ToolInclusionDefinition, ToStringMixin): @classmethod def from_name(cls, name: str) -> Self: """Load a registered Serena mode.""" - mode_path = cls.get_path(name) - return cls.from_yaml(mode_path) + try: + mode_path = cls.get_path(name) + return cls.from_yaml(mode_path) + except: + try: + # Allow loading an internal mode if it is explicitly requested + return cls.from_name_internal(name) + except: + pass + raise @classmethod def from_name_internal(cls, name: str) -> Self: diff --git a/src/serena/config/serena_config.py b/src/serena/config/serena_config.py index 75f916b8..06e1c6d1 100644 --- a/src/serena/config/serena_config.py +++ b/src/serena/config/serena_config.py @@ -464,11 +464,13 @@ class SerenaConfig(ToolInclusionDefinition, ToStringMixin): ) instance.projects.append(project) - # set other configuration parameters - def get_value_or_default(field_name: str) -> Any: - return loaded_commented_yaml.get(field_name, get_dataclass_default(SerenaConfig, field_name)) + def get_value_or_default(key: str, field_name: str | None = None) -> Any: + if field_name is None: + field_name = key + return loaded_commented_yaml.get(key, get_dataclass_default(SerenaConfig, field_name)) - instance.gui_log_window_enabled = get_value_or_default("gui_log_window_enabled") + # set other configuration parameters + instance.gui_log_window_enabled = get_value_or_default("gui_log_window", "gui_log_window_enabled") instance.web_dashboard_listen_address = get_value_or_default("web_dashboard_listen_address") instance.log_level = loaded_commented_yaml.get("log_level", loaded_commented_yaml.get("gui_log_level", logging.INFO)) instance.web_dashboard = get_value_or_default("web_dashboard") diff --git a/src/serena/tools/jetbrains_plugin_client.py b/src/serena/tools/jetbrains_plugin_client.py index 15452711..cd31b7b1 100644 --- a/src/serena/tools/jetbrains_plugin_client.py +++ b/src/serena/tools/jetbrains_plugin_client.py @@ -202,6 +202,17 @@ class JetBrainsPluginClient(ToStringMixin): } self._make_request("POST", "/renameSymbol", request_data) + def refresh_file(self, relative_path: str) -> None: + """ + Triggers a refresh of the given file in the IDE. + + :param relative_path: the relative path + """ + request_data = { + "relativePath": relative_path, + } + self._make_request("POST", "/refreshFile", request_data) + def is_service_available(self) -> bool: try: self.project_root() diff --git a/src/solidlsp/language_servers/groovy_language_server.py b/src/solidlsp/language_servers/groovy_language_server.py new file mode 100644 index 00000000..1c302de7 --- /dev/null +++ b/src/solidlsp/language_servers/groovy_language_server.py @@ -0,0 +1,274 @@ +""" +Provides Groovy specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Groovy. +""" + +import dataclasses +import logging +import os +import pathlib +import shlex + +from solidlsp.ls import SolidLanguageServer +from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams +from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo +from solidlsp.settings import SolidLSPSettings + +log = logging.getLogger(__name__) + + +@dataclasses.dataclass +class GroovyRuntimeDependencyPaths: + """ + Stores the paths to the runtime dependencies of Groovy Language Server + """ + + java_path: str + java_home_path: str + ls_jar_path: str + groovy_home_path: str | None = None + + +class GroovyLanguageServer(SolidLanguageServer): + """ + Provides Groovy specific instantiation of the LanguageServer class. + Contains various configurations and settings specific to Groovy. + """ + + def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings): + """ + Creates a Groovy Language Server instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead. + """ + runtime_dependency_paths = self._setup_runtime_dependencies(solidlsp_settings) + self.runtime_dependency_paths = runtime_dependency_paths + + # Get jar options from configuration + ls_jar_options = [] + + if solidlsp_settings.ls_specific_settings: + groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + jar_options_str = groovy_settings.get("ls_jar_options", "") + if jar_options_str: + ls_jar_options = shlex.split(jar_options_str) + log.info(f"Using Groovy LS JAR options from configuration: {jar_options_str}") + + # Create command to execute the Groovy Language Server + cmd = [self.runtime_dependency_paths.java_path, "-jar", self.runtime_dependency_paths.ls_jar_path] + cmd.extend(ls_jar_options) + + # Set environment variables including JAVA_HOME + proc_env = {"JAVA_HOME": self.runtime_dependency_paths.java_home_path} + + super().__init__( + config, + repository_root_path, + ProcessLaunchInfo(cmd=cmd, env=proc_env, cwd=repository_root_path), + "groovy", + solidlsp_settings, + ) + + log.info(f"Starting Groovy Language Server with jar options: {ls_jar_options}") + + @classmethod + def _setup_runtime_dependencies(cls, solidlsp_settings: SolidLSPSettings) -> GroovyRuntimeDependencyPaths: + """ + Setup runtime dependencies for Groovy Language Server and return paths. + """ + platform_id = PlatformUtils.get_platform_id() + + # Verify platform support + assert ( + platform_id.value.startswith("win-") or platform_id.value.startswith("linux-") or platform_id.value.startswith("osx-") + ), "Only Windows, Linux and macOS platforms are supported for Groovy in multilspy at the moment" + + # Check if user specified custom Java home path + java_home_path = None + java_path = None + + if solidlsp_settings and solidlsp_settings.ls_specific_settings: + groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + custom_java_home = groovy_settings.get("ls_java_home_path") + if custom_java_home: + log.info(f"Using custom Java home path from configuration: {custom_java_home}") + java_home_path = custom_java_home + + # Determine java executable path based on platform + if platform_id.value.startswith("win-"): + java_path = os.path.join(java_home_path, "bin", "java.exe") + else: + java_path = os.path.join(java_home_path, "bin", "java") + + # If no custom Java home path, download and use bundled Java + if java_home_path is None: + # Runtime dependency information + runtime_dependencies = { + "java": { + "win-x64": { + "url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-win32-x64-1.42.0-561.vsix", + "archiveType": "zip", + "java_home_path": "extension/jre/21.0.7-win32-x86_64", + "java_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe", + }, + "linux-x64": { + "url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-x64-1.42.0-561.vsix", + "archiveType": "zip", + "java_home_path": "extension/jre/21.0.7-linux-x86_64", + "java_path": "extension/jre/21.0.7-linux-x86_64/bin/java", + }, + "linux-arm64": { + "url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-linux-arm64-1.42.0-561.vsix", + "archiveType": "zip", + "java_home_path": "extension/jre/21.0.7-linux-aarch64", + "java_path": "extension/jre/21.0.7-linux-aarch64/bin/java", + }, + "osx-x64": { + "url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-x64-1.42.0-561.vsix", + "archiveType": "zip", + "java_home_path": "extension/jre/21.0.7-macosx-x86_64", + "java_path": "extension/jre/21.0.7-macosx-x86_64/bin/java", + }, + "osx-arm64": { + "url": "https://github.com/redhat-developer/vscode-java/releases/download/v1.42.0/java-darwin-arm64-1.42.0-561.vsix", + "archiveType": "zip", + "java_home_path": "extension/jre/21.0.7-macosx-aarch64", + "java_path": "extension/jre/21.0.7-macosx-aarch64/bin/java", + }, + }, + } + + java_dependency = runtime_dependencies["java"][platform_id.value] + + static_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "groovy_language_server") + os.makedirs(static_dir, exist_ok=True) + + java_dir = os.path.join(static_dir, "java") + os.makedirs(java_dir, exist_ok=True) + + java_home_path = os.path.join(java_dir, java_dependency["java_home_path"]) + java_path = os.path.join(java_dir, java_dependency["java_path"]) + + if not os.path.exists(java_path): + log.info(f"Downloading Java for {platform_id.value}...") + FileUtils.download_and_extract_archive(java_dependency["url"], java_dir, java_dependency["archiveType"]) + + if not platform_id.value.startswith("win-"): + os.chmod(java_path, 0o755) + + assert java_path and os.path.exists(java_path), f"Java executable not found at {java_path}" + + ls_jar_path = cls._find_groovy_ls_jar(solidlsp_settings) + + return GroovyRuntimeDependencyPaths(java_path=java_path, java_home_path=java_home_path, ls_jar_path=ls_jar_path) + + @classmethod + def _find_groovy_ls_jar(cls, solidlsp_settings: SolidLSPSettings) -> str: + """ + Find Groovy Language Server JAR file + """ + if solidlsp_settings and solidlsp_settings.ls_specific_settings: + groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + config_jar_path = groovy_settings.get("ls_jar_path") + if config_jar_path and os.path.exists(config_jar_path): + log.info(f"Using Groovy LS JAR from configuration: {config_jar_path}") + return config_jar_path + + # if JAR not found + raise RuntimeError( + "Groovy Language Server JAR not found. To use Groovy language support:\n" + "Set 'ls_jar_path' in groovy settings in serena_config.yml:\n" + " ls_specific_settings:\n" + " groovy:\n" + " ls_jar_path: '/path/to/groovy-language-server.jar'\n" + " Ensure the JAR file is available at the configured path\n" + ) + + @staticmethod + def _get_initialize_params(repository_absolute_path: str) -> InitializeParams: + """ + Returns the initialize params for the Groovy Language Server. + """ + if not os.path.isabs(repository_absolute_path): + repository_absolute_path = os.path.abspath(repository_absolute_path) + + root_uri = pathlib.Path(repository_absolute_path).as_uri() + initialize_params = { + "clientInfo": {"name": "Serena Groovy Client", "version": "1.0.0"}, + "rootPath": repository_absolute_path, + "rootUri": root_uri, + "capabilities": { + "textDocument": { + "synchronization": {"dynamicRegistration": True, "didSave": True}, + "completion": {"dynamicRegistration": True}, + "hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]}, + "definition": {"dynamicRegistration": True}, + "references": {"dynamicRegistration": True}, + "documentSymbol": {"dynamicRegistration": True}, + "workspaceSymbol": {"dynamicRegistration": True}, + "signatureHelp": {"dynamicRegistration": True}, + "rename": {"dynamicRegistration": True}, + }, + "workspace": { + "workspaceFolders": True, + }, + }, + "initializationOptions": { + "settings": { + "groovy": { + "classpath": [], + "diagnostics": {"enabled": True}, + "completion": {"enabled": True}, + } + }, + }, + "processId": os.getpid(), + "workspaceFolders": [ + { + "uri": root_uri, + "name": os.path.basename(repository_absolute_path), + } + ], + } + return initialize_params # type: ignore + + def _start_server(self) -> None: + """ + Starts the Groovy Language Server + """ + + def execute_client_command_handler(params: dict) -> list: + return [] + + def do_nothing(params: dict) -> None: + return + + def window_log_message(msg: dict) -> None: + log.info(f"LSP: window/logMessage: {msg}") + + self.server.on_request("client/registerCapability", do_nothing) + self.server.on_notification("language/status", do_nothing) + self.server.on_notification("window/logMessage", window_log_message) + self.server.on_request("workspace/executeClientCommand", execute_client_command_handler) + self.server.on_notification("$/progress", do_nothing) + self.server.on_notification("textDocument/publishDiagnostics", do_nothing) + self.server.on_notification("language/actionableNotification", do_nothing) + + log.info("Starting Groovy server process") + self.server.start() + initialize_params = self._get_initialize_params(self.repository_root_path) + + log.info("Sending initialize request from LSP client to LSP server and awaiting response") + init_response = self.server.send.initialize(initialize_params) + + capabilities = init_response["capabilities"] + assert "textDocumentSync" in capabilities, "Server must support textDocumentSync" + assert "hoverProvider" in capabilities, "Server must support hover" + assert "completionProvider" in capabilities, "Server must support code completion" + assert "signatureHelpProvider" in capabilities, "Server must support signature help" + assert "definitionProvider" in capabilities, "Server must support go to definition" + assert "referencesProvider" in capabilities, "Server must support find references" + assert "documentSymbolProvider" in capabilities, "Server must support document symbols" + assert "workspaceSymbolProvider" in capabilities, "Server must support workspace symbols" + + self.server.notify.initialized({}) + self.completions_available.set() diff --git a/src/solidlsp/language_servers/scala_language_server.py b/src/solidlsp/language_servers/scala_language_server.py index a274f652..e835c36f 100644 --- a/src/solidlsp/language_servers/scala_language_server.py +++ b/src/solidlsp/language_servers/scala_language_server.py @@ -57,9 +57,11 @@ class ScalaLanguageServer(SolidLanguageServer): """ assert shutil.which("java") is not None, "JDK is not installed or not in PATH." + metals_version = "1.6.4" + metals_home = os.path.join(cls.ls_resources_dir(solidlsp_settings), "metals-lsp") os.makedirs(metals_home, exist_ok=True) - metals_executable = os.path.join(metals_home, "metals") + metals_executable = os.path.join(metals_home, metals_version, "metals") coursier_command_path = shutil.which("coursier") cs_command_path = shutil.which("cs") assert cs_command_path is not None or coursier_command_path is not None, "coursier is not installed or not in PATH." @@ -82,7 +84,8 @@ class ScalaLanguageServer(SolidLanguageServer): log.info("'cs' command installed successfully.") log.info(f"metals executable not found at {metals_executable}, bootstrapping...") - artifact = "org.scalameta:metals_2.13:1.6.2" + subprocess.run(["mkdir", "-p", os.path.join(metals_home, metals_version)], check=True) + artifact = f"org.scalameta:metals_2.13:{metals_version}" cmd = [ cs_command_path, "bootstrap", diff --git a/src/solidlsp/ls_config.py b/src/solidlsp/ls_config.py index 3d491842..57edbb02 100644 --- a/src/solidlsp/ls_config.py +++ b/src/solidlsp/ls_config.py @@ -61,6 +61,7 @@ class Language(str, Enum): JULIA = "julia" FORTRAN = "fortran" HASKELL = "haskell" + GROOVY = "groovy" VUE = "vue" POWERSHELL = "powershell" # Experimental or deprecated Language Servers @@ -112,6 +113,7 @@ class Language(str, Enum): self.MARKDOWN, self.YAML, self.TOML, + self.GROOVY, } def __str__(self) -> str: @@ -221,6 +223,8 @@ class Language(str, Enum): return FilenameMatcher(*path_patterns) case self.POWERSHELL: return FilenameMatcher("*.ps1", "*.psm1", "*.psd1") + case self.GROOVY: + return FilenameMatcher("*.groovy", "*.gvy") case _: raise ValueError(f"Unhandled language: {self}") @@ -382,6 +386,10 @@ class Language(str, Enum): from solidlsp.language_servers.powershell_language_server import PowerShellLanguageServer return PowerShellLanguageServer + case self.GROOVY: + from solidlsp.language_servers.groovy_language_server import GroovyLanguageServer + + return GroovyLanguageServer case _: raise ValueError(f"Unhandled language: {self}") diff --git a/test/resources/repos/groovy/test_repo/.gitignore b/test/resources/repos/groovy/test_repo/.gitignore new file mode 100644 index 00000000..3bb19ffd --- /dev/null +++ b/test/resources/repos/groovy/test_repo/.gitignore @@ -0,0 +1 @@ +.gradle/ diff --git a/test/resources/repos/groovy/test_repo/build.gradle b/test/resources/repos/groovy/test_repo/build.gradle new file mode 100644 index 00000000..61a1de3a --- /dev/null +++ b/test/resources/repos/groovy/test_repo/build.gradle @@ -0,0 +1,7 @@ +plugins { + id 'groovy' +} + +repositories { + mavenCentral() +} diff --git a/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Main.groovy b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Main.groovy new file mode 100644 index 00000000..0e42fe71 --- /dev/null +++ b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Main.groovy @@ -0,0 +1,9 @@ +package com.example + +class Main { + static void main(String[] args) { + Utils.printHello() + Model model = new Model("Cascade") + println(model.name) + } +} diff --git a/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Model.groovy b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Model.groovy new file mode 100644 index 00000000..f6451ca4 --- /dev/null +++ b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Model.groovy @@ -0,0 +1,9 @@ +package com.example + +class Model { + String name + + Model(String name) { + this.name = name + } +} diff --git a/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/ModelUser.groovy b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/ModelUser.groovy new file mode 100644 index 00000000..bde77812 --- /dev/null +++ b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/ModelUser.groovy @@ -0,0 +1,8 @@ +package com.example + +class ModelUser { + static void main(String[] args) { + Model model = new Model("Cascade") + println(model.name) + } +} diff --git a/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Utils.groovy b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Utils.groovy new file mode 100644 index 00000000..b2cf63a1 --- /dev/null +++ b/test/resources/repos/groovy/test_repo/src/main/groovy/com/example/Utils.groovy @@ -0,0 +1,7 @@ +package com.example + +class Utils { + static void printHello() { + println("Hello from Utils!") + } +} diff --git a/test/resources/repos/scala/src/main/scala/com/example/Main.scala b/test/resources/repos/scala/src/main/scala/com/example/Main.scala index f7197ec3..2407efec 100644 --- a/test/resources/repos/scala/src/main/scala/com/example/Main.scala +++ b/test/resources/repos/scala/src/main/scala/com/example/Main.scala @@ -17,4 +17,13 @@ object Main { def add(a: Int, b: Int): Int = { a + b } + + // https://github.com/oraios/serena/issues/688 + def someMethod(config: Config): Unit = { + val str = config.field1 + + println(str) + } + + case class Config(field1:String) } diff --git a/test/resources/repos/vue/test_repo/package-lock.json b/test/resources/repos/vue/test_repo/package-lock.json deleted file mode 100644 index 7a73f505..00000000 --- a/test/resources/repos/vue/test_repo/package-lock.json +++ /dev/null @@ -1,1486 +0,0 @@ -{ - "name": "vue-calculator-test-fixture", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vue-calculator-test-fixture", - "version": "1.0.0", - "dependencies": { - "pinia": "^2.1.0", - "vue": "^3.4.0" - }, - "devDependencies": { - "@vue/language-server": "^2.0.0", - "typescript": "~5.5.4" - } - }, - "node_modules/@volar/language-core": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", - "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.15" - } - }, - "node_modules/@volar/language-core/node_modules/@volar/source-map": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", - "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/language-server": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.15.tgz", - "integrity": "sha512-aSzvL3lgQ+RPU3uWA9wW85sfZ0tb+oKplfnOwG/c1iRMuVEJRofmcnjyN0JEOKbBR7GuPSbeUdLAI0AIL+TFew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@volar/language-service": "2.4.15", - "@volar/typescript": "2.4.15", - "path-browserify": "^1.0.1", - "request-light": "^0.7.0", - "vscode-languageserver": "^9.0.1", - "vscode-languageserver-protocol": "^3.17.5", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@volar/language-server/node_modules/@volar/language-service": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.15.tgz", - "integrity": "sha512-o7ctGyQNQAZqT15xHamE0fTzPZHeDnHWz0m/KJekSPc2W4AHiEbJ2RNDLzEK4e0EjrpdeEe3FB9KQvOvjq+I6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "vscode-languageserver-protocol": "^3.17.5", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@volar/language-server/node_modules/@volar/typescript": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", - "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@volar/language-server/node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/language-server/node_modules/request-light": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", - "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/language-server/node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/@volar/language-server/node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/test-utils": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/test-utils/-/test-utils-2.4.15.tgz", - "integrity": "sha512-TgFzv+0HWKS9ZjA6p4kuXgnzGJR2wt5f+0L97o7LYOdBSaAIn+EgWPqTAYWZC4Z2PYEKS0jkt5waOyak18k6/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@volar/language-server": "2.4.15", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@volar/test-utils/node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", - "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/compiler-dom/node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-dom/node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-dom/node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@vue/compiler-dom/node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-dom/node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@vue/compiler-dom/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/@vue/compiler-dom/node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", - "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.25", - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/@vue/compiler-sfc/node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" - }, - "node_modules/@vue/language-core": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", - "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@vue/compiler-dom": "^3.5.0", - "@vue/compiler-vue2": "^2.7.16", - "@vue/shared": "^3.5.0", - "alien-signals": "^1.0.3", - "minimatch": "^9.0.3", - "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/language-core/node_modules/@vue/compiler-vue2": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", - "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", - "dev": true, - "license": "MIT", - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, - "node_modules/@vue/language-core/node_modules/alien-signals": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", - "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-core/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-core/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@vue/language-core/node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-core/node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@vue/language-core/node_modules/muggle-string": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-core/node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-server": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@vue/language-server/-/language-server-2.2.12.tgz", - "integrity": "sha512-sh64ihjDn1nHmLez5m/UuXiTmiTU10Jt/QvhjMPllPeUwCvck89ndXp1nXkvEDoRGm7xdV9zopZM2IiEZFQTPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@volar/language-server": "2.4.15", - "@volar/test-utils": "2.4.15", - "@vue/language-core": "2.2.12", - "@vue/language-service": "2.2.12", - "@vue/typescript-plugin": "2.2.12", - "vscode-languageserver-protocol": "^3.17.5", - "vscode-uri": "^3.0.8" - }, - "bin": { - "vue-language-server": "bin/vue-language-server.js" - } - }, - "node_modules/@vue/language-service": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@vue/language-service/-/language-service-2.2.12.tgz", - "integrity": "sha512-+YBLP82vyuXzO5Wkw23vMl+EPCZicv1EQtEjp/n/Wt4PjbPBSgR5KCuc4edcIA1rL70fsEPlSna3K+ibyZ2QIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "@volar/language-service": "2.4.15", - "@volar/typescript": "2.4.15", - "@vue/compiler-dom": "^3.5.0", - "@vue/language-core": "2.2.12", - "@vue/shared": "^3.5.0", - "@vue/typescript-plugin": "2.2.12", - "alien-signals": "^1.0.3", - "path-browserify": "^1.0.1", - "volar-service-css": "0.0.64", - "volar-service-emmet": "0.0.64", - "volar-service-html": "0.0.64", - "volar-service-json": "0.0.64", - "volar-service-pug": "0.0.64", - "volar-service-pug-beautify": "0.0.64", - "volar-service-typescript": "0.0.64", - "volar-service-typescript-twoslash-queries": "0.0.64", - "vscode-css-languageservice": "^6.3.1", - "vscode-html-languageservice": "^5.2.0", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/language-service/node_modules/@emmetio/abbreviation": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", - "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emmetio/scanner": "^1.0.4" - } - }, - "node_modules/@vue/language-service/node_modules/@emmetio/css-abbreviation": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz", - "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emmetio/scanner": "^1.0.4" - } - }, - "node_modules/@vue/language-service/node_modules/@emmetio/css-parser": { - "version": "0.4.0", - "resolved": "git+ssh://git@github.com/ramya-rao-a/css-parser.git#370c480ac103bd17c7bcfb34bf5d577dc40d3660", - "dev": true, - "license": "MIT", - "dependencies": { - "@emmetio/stream-reader": "^2.2.0", - "@emmetio/stream-reader-utils": "^0.1.0" - } - }, - "node_modules/@vue/language-service/node_modules/@emmetio/html-matcher": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz", - "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@emmetio/scanner": "^1.0.0" - } - }, - "node_modules/@vue/language-service/node_modules/@emmetio/scanner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz", - "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/@emmetio/stream-reader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz", - "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/@emmetio/stream-reader-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", - "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/@johnsoncodehk/pug-beautify": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@johnsoncodehk/pug-beautify/-/pug-beautify-0.2.2.tgz", - "integrity": "sha512-qqNS/YD0Nck5wtQLCPHAfGVgWbbGafxSPjNh0ekYPFSNNqnDH2kamnduzYly8IiADmeVx/MfAE1njMEjVeHTMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/@volar/language-service": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.15.tgz", - "integrity": "sha512-o7ctGyQNQAZqT15xHamE0fTzPZHeDnHWz0m/KJekSPc2W4AHiEbJ2RNDLzEK4e0EjrpdeEe3FB9KQvOvjq+I6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "vscode-languageserver-protocol": "^3.17.5", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/language-service/node_modules/@volar/typescript": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", - "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/language-service/node_modules/@vscode/emmet-helper": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz", - "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "emmet": "^2.4.3", - "jsonc-parser": "^2.3.0", - "vscode-languageserver-textdocument": "^1.0.1", - "vscode-languageserver-types": "^3.15.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/language-service/node_modules/@vscode/l10n": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", - "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@vue/language-service/node_modules/alien-signals": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", - "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/character-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", - "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-regex": "^1.0.3" - } - }, - "node_modules/@vue/language-service/node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/emmet": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz", - "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==", - "dev": true, - "license": "MIT", - "workspaces": [ - "./packages/scanner", - "./packages/abbreviation", - "./packages/css-abbreviation", - "./" - ], - "dependencies": { - "@emmetio/abbreviation": "^2.3.3", - "@emmetio/css-abbreviation": "^2.1.8" - } - }, - "node_modules/@vue/language-service/node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/is-expression": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", - "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^7.1.1", - "object-assign": "^4.1.1" - } - }, - "node_modules/@vue/language-service/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@vue/language-service/node_modules/jsonc-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", - "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@vue/language-service/node_modules/muggle-string": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/language-service/node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/pug-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", - "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/pug-lexer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", - "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", - "dev": true, - "license": "MIT", - "dependencies": { - "character-parser": "^2.2.0", - "is-expression": "^4.0.0", - "pug-error": "^2.0.0" - } - }, - "node_modules/@vue/language-service/node_modules/pug-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", - "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pug-error": "^2.0.0", - "token-stream": "1.0.0" - } - }, - "node_modules/@vue/language-service/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vue/language-service/node_modules/token-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/typescript-auto-import-cache": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz", - "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.8" - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-css": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.64.tgz", - "integrity": "sha512-BtLq85adIft+Q0PZqllKXMVH7HHk6UmM7Opuj43IhR4AOVkqbNIcsiXhuh12ITVJGTkCGa9xXAPzClorPya6EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-css-languageservice": "^6.3.0", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-emmet": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.64.tgz", - "integrity": "sha512-cIGKpyOXKB9Dsqz3MJD1DF1GYEPfLE4VBoEtqewfx88qpf0dr/WbDnRhuljZ+VFlavkre4MvELzkCt8m9F6GqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", - "@emmetio/html-matcher": "^1.3.0", - "@vscode/emmet-helper": "^2.9.3", - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-html": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.64.tgz", - "integrity": "sha512-5xknMYKmZBFzp2399RlsnGce25PfNu9ViXa1s63Q8NP6xeXcF3lInFsV+1o2DWBoXZdnXcuRvWOA+K+JIZLEcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-html-languageservice": "^5.3.0", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-json": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-json/-/volar-service-json-0.0.64.tgz", - "integrity": "sha512-kZsqmeDR0w/iVkkoxfp4/DcblYmyFXBImVLzgIgyd685XZrb21wVmKcRsD/V+6l0N7/pGwN6m2scxt/mJmFkGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-json-languageservice": "^5.4.0", - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-pug": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-pug/-/volar-service-pug-0.0.64.tgz", - "integrity": "sha512-rVJ2ySENJFPzzEr4fVlC81ANR4dTh3Axr6Az56KyZ5GV0C9yRk5QqCj5+eOYb2GSoVtnEbzOyYpDTRSuH++lfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-service": "~2.4.0", - "muggle-string": "^0.4.1", - "pug-lexer": "^5.0.1", - "pug-parser": "^6.0.0", - "volar-service-html": "0.0.64", - "vscode-html-languageservice": "^5.3.0", - "vscode-languageserver-textdocument": "^1.0.11" - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-pug-beautify": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-pug-beautify/-/volar-service-pug-beautify-0.0.64.tgz", - "integrity": "sha512-HNVTYGjGKaUkvryCQvhN/kYZ6aP6I1ySECMA7I8SpMqraYN/BDKI185tsRsm5tGmPrEyCgRDKn/GGIAsSj7I7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@johnsoncodehk/pug-beautify": "^0.2.2" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-typescript": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.64.tgz", - "integrity": "sha512-FN2H97iqjR1id8AM4fH7lTXuTx2on9zD6QlUFllaiHKqgNrEITlQwm/9Ujrd9ST7MUzhgIKyUsa2WlanX9kkMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-browserify": "^1.0.1", - "semver": "^7.6.2", - "typescript-auto-import-cache": "^0.3.5", - "vscode-languageserver-textdocument": "^1.0.11", - "vscode-nls": "^5.2.0", - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/volar-service-typescript-twoslash-queries": { - "version": "0.0.64", - "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.64.tgz", - "integrity": "sha512-DQlArCVUwbH3Ym0Uc/qSrgus/ngQa4LbTNbLsIkWMovxwziPA1c2yCFFY7a6s4Qs8pPXO757ryu99IeX0UK+4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-uri": "^3.0.8" - }, - "peerDependencies": { - "@volar/language-service": "~2.4.0" - }, - "peerDependenciesMeta": { - "@volar/language-service": { - "optional": true - } - } - }, - "node_modules/@vue/language-service/node_modules/vscode-css-languageservice": { - "version": "6.3.8", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.8.tgz", - "integrity": "sha512-dBk/9ullEjIMbfSYAohGpDOisOVU1x2MQHOeU12ohGJQI7+r0PCimBwaa/pWpxl/vH4f7ibrBfxIZY3anGmHKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vscode/l10n": "^0.0.18", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-languageserver-types": "3.17.5", - "vscode-uri": "^3.1.0" - } - }, - "node_modules/@vue/language-service/node_modules/vscode-html-languageservice": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.0.tgz", - "integrity": "sha512-FIVz83oGw2tBkOr8gQPeiREInnineCKGCz3ZD1Pi6opOuX3nSRkc4y4zLLWsuop+6ttYX//XZCI6SLzGhRzLmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vscode/l10n": "^0.0.18", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-languageserver-types": "^3.17.5", - "vscode-uri": "^3.1.0" - } - }, - "node_modules/@vue/language-service/node_modules/vscode-json-languageservice": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.6.3.tgz", - "integrity": "sha512-UDF7sJF5t7mzUzXL6dsClkvnHS4xnDL/gOMKGQiizRHmswlk/xSPGZxEvAtszWQF0ImNcJ0j9l+rHuefGzit1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vscode/l10n": "^0.0.18", - "jsonc-parser": "^3.3.1", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-languageserver-types": "^3.17.5", - "vscode-uri": "^3.1.0" - } - }, - "node_modules/@vue/language-service/node_modules/vscode-json-languageservice/node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/language-service/node_modules/vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", - "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/runtime-core": "3.5.25", - "@vue/shared": "3.5.25", - "csstype": "^3.1.3" - } - }, - "node_modules/@vue/runtime-dom/node_modules/@vue/reactivity": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.25.tgz", - "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-dom/node_modules/@vue/runtime-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.25.tgz", - "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/runtime-dom/node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.25.tgz", - "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", - "license": "MIT", - "dependencies": { - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "vue": "3.5.25" - } - }, - "node_modules/@vue/server-renderer/node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz", - "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", - "license": "MIT" - }, - "node_modules/@vue/typescript-plugin": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@vue/typescript-plugin/-/typescript-plugin-2.2.12.tgz", - "integrity": "sha512-HFByqrJ7+kWDpAoGiTcWe0Gxy9R0MkEtE+QTlLnEgDS7+l7uSaPnK4ZfzpX7rMfNwOZK0fUD58mMvmCWUnBCSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/typescript": "2.4.15", - "@vue/language-core": "2.2.12", - "@vue/shared": "^3.5.0" - } - }, - "node_modules/@vue/typescript-plugin/node_modules/@volar/typescript": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", - "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.15", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/typescript-plugin/node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true, - "license": "MIT" - }, - "node_modules/pinia": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", - "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", - "license": "MIT", - "dependencies": { - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" - }, - "funding": { - "url": "https://github.com/sponsors/posva" - }, - "peerDependencies": { - "typescript": ">=4.4.4", - "vue": "^2.7.0 || ^3.5.11" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-protocol/node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver-protocol/node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" - }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vue": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", - "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-sfc": "3.5.25", - "@vue/runtime-dom": "3.5.25", - "@vue/server-renderer": "3.5.25", - "@vue/shared": "3.5.25" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - } - } -} diff --git a/test/solidlsp/groovy/test_groovy_basic.py b/test/solidlsp/groovy/test_groovy_basic.py new file mode 100644 index 00000000..0ebae30c --- /dev/null +++ b/test/solidlsp/groovy/test_groovy_basic.py @@ -0,0 +1,100 @@ +import os +from pathlib import Path + +import pytest + +from serena.constants import SERENA_MANAGED_DIR_NAME +from solidlsp import SolidLanguageServer +from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_utils import SymbolUtils +from solidlsp.settings import SolidLSPSettings + + +@pytest.mark.groovy +class TestGroovyLanguageServer: + @classmethod + def setup_class(cls): + """ + Set up test class with Groovy test repository. + """ + cls.test_repo_path = Path(__file__).parent.parent.parent / "resources" / "repos" / "groovy" / "test_repo" + + if not cls.test_repo_path.exists(): + pytest.skip("Groovy test repository not found") + + # Use JAR path from environment variable + ls_jar_path = os.environ.get("GROOVY_LS_JAR_PATH") + if not ls_jar_path or not os.path.exists(ls_jar_path): + pytest.skip( + "Groovy Language Server JAR not found. Set GROOVY_LS_JAR_PATH environment variable to run tests.", + allow_module_level=True, + ) + + # Get JAR options from environment variable + ls_jar_options = os.environ.get("GROOVY_LS_JAR_OPTIONS", "") + ls_java_home_path = os.environ.get("GROOVY_LS_JAVA_HOME_PATH") + + groovy_settings = {"ls_jar_path": ls_jar_path, "ls_jar_options": ls_jar_options} + if ls_java_home_path: + groovy_settings["ls_java_home_path"] = ls_java_home_path + + # Create language server directly with Groovy-specific settings + repo_path = str(cls.test_repo_path) + config = LanguageServerConfig(code_language=Language.GROOVY, ignored_paths=[], trace_lsp_communication=False) + + solidlsp_settings = SolidLSPSettings( + solidlsp_dir=str(Path.home() / ".serena"), + project_data_relative_path=SERENA_MANAGED_DIR_NAME, + ls_specific_settings={Language.GROOVY: groovy_settings}, + ) + + cls.language_server = SolidLanguageServer.create(config, repo_path, solidlsp_settings=solidlsp_settings) + cls.language_server.start() + + @classmethod + def teardown_class(cls): + """ + Clean up language server. + """ + if hasattr(cls, "language_server"): + cls.language_server.stop() + + def test_find_symbol(self) -> None: + symbols = self.language_server.request_full_symbol_tree() + assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main class not found in symbol tree" + assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils class not found in symbol tree" + assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model class not found in symbol tree" + assert SymbolUtils.symbol_tree_contains_name(symbols, "ModelUser"), "ModelUser class not found in symbol tree" + + def test_find_referencing_class_symbols(self) -> None: + file_path = os.path.join("src", "main", "groovy", "com", "example", "Utils.groovy") + refs = self.language_server.request_references(file_path, 3, 6) + assert any("Main.groovy" in ref.get("relativePath", "") for ref in refs), "Utils should be referenced from Main.groovy" + + file_path = os.path.join("src", "main", "groovy", "com", "example", "Model.groovy") + symbols = self.language_server.request_document_symbols(file_path).get_all_symbols_and_roots() + model_symbol = None + for sym in symbols[0]: + if sym.get("name") == "com.example.Model" and sym.get("kind") == 5: + model_symbol = sym + break + assert model_symbol is not None, "Could not find 'Model' class symbol in Model.groovy" + + if "selectionRange" in model_symbol: + sel_start = model_symbol["selectionRange"]["start"] + else: + sel_start = model_symbol["range"]["start"] + refs = self.language_server.request_references(file_path, sel_start["line"], sel_start["character"]) + + main_refs = [ref for ref in refs if "Main.groovy" in ref.get("relativePath", "")] + assert len(main_refs) >= 2, f"Model should be referenced from Main.groovy at least 2 times, found {len(main_refs)}" + + model_user_refs = [ref for ref in refs if "ModelUser.groovy" in ref.get("relativePath", "")] + assert len(model_user_refs) >= 1, f"Model should be referenced from ModelUser.groovy at least 1 time, found {len(model_user_refs)}" + + def test_overview_methods(self) -> None: + symbols = self.language_server.request_full_symbol_tree() + assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main missing from overview" + assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils missing from overview" + assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model missing from overview" + assert SymbolUtils.symbol_tree_contains_name(symbols, "ModelUser"), "ModelUser missing from overview" diff --git a/test/solidlsp/scala/test_scala_language_server.py b/test/solidlsp/scala/test_scala_language_server.py index 9a25009a..9c498416 100644 --- a/test/solidlsp/scala/test_scala_language_server.py +++ b/test/solidlsp/scala/test_scala_language_server.py @@ -34,6 +34,10 @@ def test_scala_document_symbols(scala_ls): assert symbol_names[3] == "result" assert symbol_names[4] == "sum" assert symbol_names[5] == "add" + assert symbol_names[6] == "someMethod" + assert symbol_names[7] == "str" + assert symbol_names[8] == "Config" + assert symbol_names[9] == "field1" # confirm https://github.com/oraios/serena/issues/688 def test_scala_references_within_same_file(scala_ls):