Skip to content

web_generator: emit WebIDL namespaces as static extension types#512

Open
harrshita123 wants to merge 3 commits into
dart-lang:mainfrom
harrshita123:fix-idl-namespaces
Open

web_generator: emit WebIDL namespaces as static extension types#512
harrshita123 wants to merge 3 commits into
dart-lang:mainfrom
harrshita123:fix-idl-namespaces

Conversation

@harrshita123

Copy link
Copy Markdown
Contributor

This PR updates WebIDL namespace generation in web_generator to match the behavior described in #398 and the new IDL/Interop AST model.

Previously, namespaces were emitted using a top-level JS getter and an extension type. With this change, namespaces are generated as a single extension type with all members emitted as static, aligning the output with how namespaces are handled in the TypeScript declaration generator.

The namespace getter emission has been removed, and the integration test expectations have been updated accordingly. No functional behavior is changed beyond the namespace shape in generated bindings.

This change assumes namespaces are globally exposed, which is consistent with existing WebIDL usage and prior discussion in the linked issue.

Fixes #398.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @harrshita123, 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 refines the WebIDL namespace generation process within web_generator to produce a more streamlined and consistent output. By transitioning to a static extension type model for namespaces, the generated code better reflects modern interop patterns and aligns with existing tooling, improving the clarity and maintainability of the generated bindings.

Highlights

  • Namespace Generation Update: WebIDL namespaces are now emitted as a single extension type with all members marked as static. This change aligns the generated output with the new IDL/Interop AST model and the behavior of the TypeScript declaration generator.
  • Removed Namespace Getters: The previous mechanism of generating a top-level JavaScript getter for namespaces has been removed, simplifying the generated binding structure.
  • Integration Test Alignment: The expected output in integration tests has been updated to reflect the new static extension type generation for namespaces.
  • No Functional Behavior Change: This update primarily modifies the shape of the generated bindings without introducing any functional changes to the underlying behavior.
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.

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

Copy link
Copy Markdown
Contributor

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 refactors the generation of WebIDL namespaces to use a single extension type with static members, instead of a top-level getter and an instance-based extension type. The changes align with the PR's description, and the test expectations have been updated accordingly.

I've kept the original comment regarding a potential inconsistency between how NamespaceDeclaration and CompositeDeclaration handle nested namespaces after this change, as it does not contradict any of the provided rules. Overall, the changes look good and implement the intended new generation strategy.

);
}


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The removal of the logic to handle nested namespaces here in NamespaceDeclaration.emit introduces an inconsistency. The CompositeDeclaration.fromNamespace factory still processes namespace.namespaceDeclarations to create properties for nested namespaces (lines 816-833).

This means that emitting a NamespaceDeclaration directly will produce different output for nested namespaces compared to converting it to a CompositeDeclaration via the asComposite getter and then emitting it.

While this PR assumes namespaces are globally exposed, this inconsistency could lead to confusion or unexpected behavior. For consistency, should the logic in CompositeDeclaration.fromNamespace also be updated to align with this new approach?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing this out.

This PR is intentionally scoped to changing how NamespaceDeclaration.emit works, following the approach discussed in #398. The goal here was to update direct namespace emission to use static extension types and remove the getter, without changing how composite namespaces are handled elsewhere.

CompositeDeclaration.fromNamespace is used in a different context, and I left it unchanged to avoid expanding the scope of this PR. I agree there’s now a difference in behavior between the two paths, and it may be worth revisiting, but that felt like a larger design discussion outside the intent of this change.

Happy to adjust or follow up if maintainers think the composite path should be aligned as well.

@srujzs srujzs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice! Can you generate package:web so we can see what the output looks like? console is a bit weird due to the lack of capitalization but I think that's fine.

@harrshita123

harrshita123 commented Feb 21, 2026

Copy link
Copy Markdown
Contributor Author

Nice! Can you generate package:web so we can see what the output looks like? console is a bit weird due to the lack of capitalization but I think that's fine.

Thanks! I tried regenerating package:web locally using the full @webref/idl corpus, but I’m currently running into a Node runtime issue (globSync is not a function), which seems similar to what CI is hitting.

From inspecting the generator output and the integration tests, namespaces are now emitted as static extension types without the top-level getter. For example, console is generated as:

@JS('console')
extension type Console(JSObject _) implements JSObject {
  external static void log(...);
}

So the JS global name stays lowercase via @js('console'), while the Dart type remains capitalized. That seems consistent, but I agree it looks a little unusual at first glance.

Let me know if there’s a preferred way to regenerate package:web locally on your end, or if you'd rather rely on CI to verify the full output.

@harrshita123

Copy link
Copy Markdown
Contributor Author

@srujzs

I regenerated package:web using bin/update_idl_bindings.dart and inspected the output for console.

Right now what we're verifying is that the namespace refactor does not break how global objects like console are emitted. In the generated file, console is still exposed as a top-level getter:

@JS()
external $Console get console;

and the Dart type is correctly bound to the JS global via:

@JS('console')
extension type $Console._(JSObject _) implements JSObject { ... }

So the lowercase JS name (console) is preserved through @js('console'), while the Dart type remains capitalized. Calling console.log(...) in Dart still forwards directly to the JS global as expected.

This confirms that the namespace changes are not altering the behavior of existing global bindings like console.

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.

IDL Gen: Support Namespaces

2 participants