Skip to content

Add Astro Language Server Support#886

Open
dansasser wants to merge 11 commits intooraios:mainfrom
dansasser:main
Open

Add Astro Language Server Support#886
dansasser wants to merge 11 commits intooraios:mainfrom
dansasser:main

Conversation

@dansasser
Copy link

Add Astro Language Server Support

Summary

This PR adds support for Astro framework files using the CompanionLanguageServer abstraction introduced in #829. The implementation follows the same dual-server architecture pattern used by Vue, where the domain-specific language server (Astro LS) handles .astro files while a companion TypeScript language server handles definitions, references, and rename operations for TypeScript/JavaScript code.

Motivation

Astro is a popular web framework for building content-focused websites. Like Vue, Astro components contain embedded TypeScript/JavaScript in their frontmatter section, requiring coordination between the Astro-specific language server and TypeScript tooling for full IDE functionality.

Architecture

Dual Language Server Design

                    AstroLanguageServer (extends CompanionLanguageServer)
                              |
         +--------------------+--------------------+
         |                                         |
    Astro LSP                              AstroTypeScriptServer
 (@astrojs/language-server)               (extends TypeScriptLanguageServer)
         |                                         |
    Handles:                               Handles:
    - .astro file parsing                  - Go-to-definition
    - Document symbols                     - Find references
    - Astro-specific features              - Rename operations
                                           - Cross-file resolution

Key Components

CompanionLanguageServer (from #829)

  • Abstract base class for language servers requiring companion servers
  • Manages companion lifecycle, LSP operation delegation, cross-file indexing
  • Provides reference merging and deduplication

AstroLanguageServer

  • Extends CompanionLanguageServer
  • Uses @astrojs/language-server for Astro file handling
  • Configures TypeScript companion for code intelligence operations

AstroTypeScriptServer

  • Extends TypeScriptLanguageServer
  • Configured with @astrojs/ts-plugin for Astro file understanding
  • Opens .astro files with language ID "astro" for plugin recognition

EmbeddedLanguageConfig

  • Configuration dataclass for embedded language handling
  • Specifies which LSP operations each companion handles
  • Defines file patterns for cross-file indexing

typescript_companion.py

  • Shared helper for TypeScript companion configuration
  • create_typescript_companion_config() - Standard TS config factory
  • prefer_non_node_modules_definition() - Definition prioritization logic
  • Reusable by Vue, Astro, and future Svelte implementations

Files Changed

New Files

File Purpose
src/solidlsp/language_servers/astro_language_server.py Main Astro LSP implementation (434 lines)
src/solidlsp/companion_ls.py CompanionLanguageServer base class (390 lines, from #829)
src/solidlsp/embedded_language_config.py Configuration dataclass for embedded languages (26 lines)
src/solidlsp/typescript_companion.py Shared TypeScript companion helpers (57 lines)
test/solidlsp/astro/__init__.py Test package marker
test/solidlsp/astro/test_astro_basic.py Core functionality tests (141 lines)
test/solidlsp/astro/test_astro_symbol_retrieval.py Symbol retrieval tests (78 lines)
test/resources/repos/astro/test_repo/ Complete Astro test project (10 files)

Modified Files

File Changes
src/solidlsp/ls_config.py Added ASTRO to Language enum, file matchers, LS class mapping
src/solidlsp/language_servers/vue_language_server.py Refactored to use CompanionLanguageServer (net -162 lines)
src/solidlsp/language_servers/typescript_language_server.py Added executable_path parameter for custom TS server locations
pyproject.toml Added astro pytest marker
test/solidlsp/vue/test_vue_*.py Added @pytest.mark.vue markers (4 files)
CHANGELOG.md Added Astro, CompanionLanguageServer, and Vue refactor entries
README.md Added Astro and Vue to supported languages list

Test Repository Structure

test/resources/repos/astro/test_repo/
├── astro.config.mjs          # Astro configuration
├── package.json              # NPM package definition
├── tsconfig.json             # TypeScript configuration
├── src/
│   ├── components/
│   │   ├── Header.astro      # Component with Props interface
│   │   └── Footer.astro      # Simple component
│   ├── layouts/
│   │   └── Layout.astro      # Layout with Props interface (tests frontmatter parsing)
│   ├── pages/
│   │   └── index.astro       # Page with imports and variable declarations
│   ├── stores/
│   │   └── counter.ts        # TypeScript store (tests cross-file resolution)
│   └── utils/
│       └── format.ts         # TypeScript utilities

Test Coverage

test_astro_basic.py

Test What It Verifies
test_ls_is_running Language server starts successfully
test_astro_document_symbols Symbols extracted from .astro frontmatter (Props interface)
test_typescript_document_symbols TypeScript file symbols accessible (CounterStore, createCounter)
test_find_definition_within_typescript Go-to-definition within TypeScript files
test_find_references_within_typescript Find references within TypeScript files
test_typescript_server_starts Companion TypeScript server initialized
test_dual_server_definition_lookup Definition lookup through companion server
test_astro_file_with_frontmatter Handles frontmatter sections without errors
test_layout_astro_with_props_interface Props interface found in Layout component

test_astro_symbol_retrieval.py

Test What It Verifies
test_get_containing_symbol_in_typescript Document symbols from .ts files within Astro project
test_find_references_to_typescript_export References to TypeScript exports
test_go_to_definition_from_typescript Definition resolution for TypeScript types
test_format_utils_symbols Utility file symbols accessible (formatNumber, formatDate)

Runtime Dependencies

Automatically installed on first use:

  • @astrojs/language-server@2.16.8 - Astro LSP
  • typescript@5.9.3 - TypeScript SDK
  • typescript-language-server@5.1.3 - TS LSP for companion server

Configurable via ls_specific_settings in serena_config.yml:

ls_specific_settings:
  astro:
    astro_language_server_version: "2.16.8"
  typescript:
    typescript_version: "5.9.3"
    typescript_language_server_version: "5.1.3"

Relationship to #829

This PR depends on the CompanionLanguageServer abstraction from #829:

  • Uses the same companion server pattern as Vue
  • Follows the same architecture for dual-LSP coordination
  • Demonstrates the abstraction works for multiple frameworks

The base class handles:

  • Companion server lifecycle management
  • Cross-file domain file indexing
  • Reference merging and deduplication
  • LSP operation delegation

If #829 is merged first, this PR may need a rebase to resolve conflicts in shared files.

Breaking Changes

None. This is purely additive.

Checklist

  • Language server implementation follows existing patterns
  • Tests verify actual symbol names and references (not just non-null checks)
  • Test repository includes meaningful source files for cross-file testing
  • Added pytest marker for Astro tests
  • Vue tests updated with markers (prevents unintended test collection)
  • Runtime dependencies auto-install with version tracking
  • Windows compatibility (.cmd suffix handling)
  • CHANGELOG.md updated with detailed entries
  • README.md updated with Astro and Vue in supported languages

CHANGELOG Entry

Already added to CHANGELOG.md:

* Language support:
  * **Add support for Astro** via @astrojs/language-server with companion TypeScript LS for code intelligence.
    Uses dual-server architecture where Astro LS handles `.astro` file parsing and document symbols,
    while a companion TypeScript server (configured with `@astrojs/ts-plugin`) handles go-to-definition,
    find references, and rename operations. Supports frontmatter TypeScript/JavaScript extraction,
    cross-file symbol resolution, and Props interface detection. Runtime dependencies auto-install on first use.
  * **Add `CompanionLanguageServer` abstraction** for language servers requiring companion servers (Vue, Astro, future Svelte).
    Manages companion lifecycle, LSP operation delegation with priority-based routing, cross-file domain file indexing
    with ref-count tracking, and reference merging/deduplication. Extracted shared TypeScript companion configuration
    to `typescript_companion.py` for reuse across framework implementations.
  * **Refactored Vue language server** to use `CompanionLanguageServer` base class, reducing code by ~160 lines
    while maintaining full functionality and improving maintainability.

Replaces #884 (closed) with proper CompanionLanguageServer-based implementation per maintainer guidance.

tylersatre and others added 11 commits December 28, 2025 13:49
(allowing the principle upon which the Vue.js implementation is based to be
applied to similar cases)
Implement Astro language server support using the new CompanionLanguageServer
abstraction from PR oraios#829. This replaces the earlier standalone implementation
to properly integrate with the companion server pattern.

Key changes:
- AstroLanguageServer extends CompanionLanguageServer
- AstroTypeScriptServer as companion for TypeScript/JS handling in .astro files
- Uses @astrojs/ts-plugin for TypeScript server integration
- Proper initialization sequence matching Vue implementation pattern
- Cross-file reference support through domain file indexing

Test infrastructure:
- Added test repository with sample Astro components
- Basic tests for language server startup and symbol extraction
- Symbol retrieval tests for TypeScript integration
- Added 'astro' pytest marker

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix tuple unpacking for get_all_symbols_and_roots() in test files
- Fix ref-count tracking bug in companion_ls.py when file already open

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove set() deduplication that caused ref_count leaks when same
file was indexed multiple times across companion patterns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add Astro entry to CHANGELOG.md with detailed description of
  dual-server architecture and CompanionLanguageServer abstraction
- Document Vue refactoring that uses CompanionLanguageServer base class
- Add Astro and Vue to README.md supported languages list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update astro to ^5.16.6 (fixes CVE-2025-55303, CVE-2025-64525, CVE-2025-61925)
- Update @astrojs/language-server to ^2.16.2 (valid npm version)
- Update typescript to ~5.7.3 (valid version)
- Use astro/tsconfigs/strict preset (removes redundant strict: true)
- Add include/exclude fields per Astro best practices

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat: Add Astro language server support (based on CompanionLanguageServer)
…ll_symbol_tree

When querying a single file via request_full_symbol_tree(), the method was
returning the root symbols directly without wrapping them in a File symbol.
This broke find_referencing_symbols() for file-as-module patterns like Astro
components, where the file itself IS the symbol (e.g., Layout.astro = Layout).

The directory query path (lines 1188-1213) correctly creates a File symbol
wrapper with kind=SymbolKind.File, but the single file path did not.

This fix applies the same File symbol wrapper pattern to single file queries:
- Uses _open_file_context to get file data
- Creates UnifiedSymbolInformation with kind=File
- Sets proper range, location, and parent-child relationships

This enables find_referencing_symbols("Layout", "src/layouts/Layout.astro")
to correctly find the Layout symbol in Astro components.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fix: correct astro language server default version to 2.16.2
@MischaPanch
Copy link
Contributor

@dansasser thank you for the PR. Just wanted to say that I haven't forgotten this, but since it's a fairly large change it will still take me some time to find time to review it properly. We just have many higher priority issues at the moment.

@dansasser
Copy link
Author

dansasser commented Jan 9, 2026

@MischaPanch I understand completely. Thank you for taking the time to consider it. I love this project and use it everyday in my workflow. I'm more than happy to contribute to it or help maintain it in any way I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants