Skip to content

Support @schema url#952

Open
CppCXY wants to merge 2 commits intomainfrom
schema
Open

Support @schema url#952
CppCXY wants to merge 2 commits intomainfrom
schema

Conversation

@CppCXY
Copy link
Member

@CppCXY CppCXY commented Feb 6, 2026

use like:

---@schema https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json
local c = {
    workspace = {
    }
}

@gemini-code-assist
Copy link

Summary of Changes

Hello @CppCXY, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the EmmyLua language server by implementing support for external JSON schemas. It allows developers to define complex types using standard JSON Schema definitions, which the language server will then fetch, convert, and integrate into its type analysis. This feature improves type checking and auto-completion capabilities for projects that rely on external schema definitions, making the development experience more robust and efficient.

Highlights

  • External Schema Support: Introduces support for @schema url in EmmyLua comments, allowing users to define types from external JSON schemas fetched from local files or remote HTTP URLs.
  • Schema Conversion Integration: Integrates a new schema_to_emmylua crate to convert fetched JSON schemas into EmmyLua type annotations, enhancing type checking and auto-completion.
  • Automated Schema Resolution: The language server now automatically checks for and resolves @schema URLs during initialization and after file save events, ensuring up-to-date type information.
  • Dependency Updates: Added numerous new dependencies, primarily for network requests and related utilities, to facilitate fetching external schemas, and updated several existing dependency versions.
  • Improved Schema Type Handling: Refactored schema type referencing from FileId to LuaTypeDeclId and introduced BadUrl status for schemas that fail to resolve, improving error handling.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • Cargo.lock
    • Added numerous new dependencies, primarily for network requests (reqwest, hyper, rustls, etc.) and related utilities, to enable fetching external schemas.
    • Updated versions for several existing dependencies, including cc, rand, rand_chacha, and rand_core.
  • Cargo.toml
    • Introduced schema_to_emmylua as a new workspace crate.
    • Added reqwest as a workspace dependency.
  • crates/emmylua_code_analysis/Cargo.toml
    • Enabled reqwest and schema_to_emmylua as dependencies for the code analysis crate.
  • crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs
    • Modified schema resolution to use LuaType::Ref(type_id.clone()) instead of LuaType::ModuleRef(*file_id), aligning with the new LuaTypeDeclId for schema types.
  • crates/emmylua_code_analysis/src/db_index/schema/mod.rs
    • Added reset_rest_schemas to mark unresolved schemas as BadUrl after an update attempt.
  • crates/emmylua_code_analysis/src/db_index/schema/schema_file.rs
    • Updated JsonSchemaFile enum to include BadUrl and changed Resolved variant to hold LuaTypeDeclId.
    • Implemented get_schema_short_name to generate concise, alphanumeric names for schema files based on their URLs.
  • crates/emmylua_code_analysis/src/lib.rs
    • Added check_schema_update to identify schemas needing resolution.
    • Implemented update_schema to asynchronously fetch, convert, and integrate external JSON schemas into the analysis, supporting both file and HTTP URLs.
  • crates/emmylua_ls/src/context/workspace_manager.rs
    • Integrated check_schema_update to trigger schema resolution within the workspace manager.
  • crates/emmylua_ls/src/handlers/initialized/mod.rs
    • Added schema update logic to run during the language server's initialization phase.
  • crates/emmylua_ls/src/handlers/text_document/text_document_handler.rs
    • Included schema update checks in on_did_save_text_document to ensure schemas are refreshed upon file changes.
  • crates/schema_to_emmylua/src/converter.rs
    • Ensured root_type_name is always a String with a default value, simplifying schema conversion results.
  • crates/schema_to_emmylua/src/lib.rs
    • Changed ConvertResult::root_type_name from Option<String> to String.
Activity
  • No specific activity (comments, reviews, etc.) was provided in the context for this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for the @schema tag to load JSON schemas from URLs, which is a great feature. My review focuses on improving the implementation's robustness, particularly around network requests and file handling for the generated schemas. I've suggested using a virtual URI scheme to avoid creating files in the user's workspace, adding status code checks for HTTP requests, and improving a concurrency pattern to prevent race conditions.

Comment on lines +294 to +302
if let Ok(response) = result {
if let Ok(content) = response.text().await {
url_contents.insert(url.clone(), content);
} else {
log::error!("Failed to read schema content from URL: {:?}", url);
}
} else {
log::error!("Failed to fetch schema from URL: {:?}", url);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation doesn't check the HTTP status code of the response from reqwest. This means it might try to parse an error page (e.g., for a 404 Not Found) as a JSON schema, which will fail later during conversion. It's important to check if the request was successful (i.e., has a 2xx status code) before attempting to process the response body.

                if let Ok(response) = result {
                    if response.status().is_success() {
                        if let Ok(content) = response.text().await {
                            url_contents.insert(url.clone(), content);
                        } else {
                            log::error!("Failed to read schema content from URL: {:?}", url);
                        }
                    } else {
                        log::error!(
                            "Failed to fetch schema from URL: {:?}, status: {}",
                            url,
                            response.status()
                        );
                    }
                } else {
                    log::error!("Failed to fetch schema from URL: {:?}", url);
                }

Comment on lines +310 to +321
let work_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let converter = SchemaConverter::new(true);
for (url, json_content) in url_contents {
let short_name = get_schema_short_name(&url);
match converter.convert_from_str(&json_content) {
Ok(convert_result) => {
let path = work_dir.join(short_name);
let Some(file_id) =
self.update_file_by_path(&path, Some(convert_result.annotation_text))
else {
continue;
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using std::env::current_dir() to determine the path for generated schema files is unreliable and can lead to issues. The current working directory might not be writable, or it could be the user's project root, which would result in creating unwanted files in their workspace. A more robust approach is to use a custom URI scheme for these virtual files, ensuring they are handled in-memory without affecting the file system. This also makes file identity unique and avoids potential path collisions.

        let converter = SchemaConverter::new(true);
        for (url, json_content) in url_contents {
            match converter.convert_from_str(&json_content) {
                Ok(convert_result) => {
                    let Ok(uri) = Uri::parse(&format!("emmylua-schema:{}", url.as_str())) else {
                        log::error!("Failed to create schema URI for {}", url);
                        continue;
                    };
                    let Some(file_id) =
                        self.update_file_by_uri(&uri, Some(convert_result.annotation_text))
                    else {
                        continue;
                    };

Comment on lines +266 to +271
let read_analysis = self.analysis.read().await;
if read_analysis.check_schema_update() {
drop(read_analysis);
let mut write_analysis = self.analysis.write().await;
write_analysis.update_schema().await;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current pattern of dropping a read lock to acquire a write lock can introduce a race condition. Another thread could perform the schema update in the small window between the read lock being released and the write lock being acquired, leading to redundant work. To prevent this, it's a good practice to re-check the condition after acquiring the write lock.

        if self.analysis.read().await.check_schema_update() {
            let mut write_analysis = self.analysis.write().await;
            // Re-check after acquiring write lock to avoid race condition.
            if write_analysis.check_schema_update() {
                write_analysis.update_schema().await;
            }
        }

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.

1 participant