Skip to content

Conversation

@imposter29
Copy link

@imposter29 imposter29 commented Nov 25, 2025

Closes #30028

This PR aligns Deno with the WHATWG WebIDL update (whatwg/webidl#1465), which changes QuotaExceededError from a named DOMException entry to a dedicated subclass.

Overview

QuotaExceededError is now implemented as a proper DOMException subclass instead of relying on the legacy "QuotaExceededError" name. This brings the behavior in line with modern web standards while keeping backward compatibility.

Changes

  • Removed legacy handling from 01_dom_exception.js.
  • Added new QuotaExceededError class in 02_quota_exceeded_error.js.
  • Included the new module in ext/web/lib.rs.
  • Exposed QuotaExceededError globally.
  • Updated the error builder in 99_main.js.
  • Updated TypeScript definitions.

Why :
The spec allows two paths :

  1. Simply remove "QuotaExceededError" from the DOMException names table, or
  2. Also implement the subclass.

This commit refactors `QuotaExceededError` to be a proper subclass of `DOMException`, aligning with the WHATWG WebIDL update. Previously, `QuotaExceededError` was a `DOMException` instance with a specific name.

The changes involve:
- Removing legacy `QuotaExceededError` handling from `ext/web/01_dom_exception.js`.
- Introducing a new `QuotaExceededError` class in `ext/web/02_quota_exceeded_error.js` that extends `DOMException`.
- Updating `ext/web/lib.rs` to include the new JavaScript file in the build.
- Exposing `QuotaExceededError` globally in `runtime/js/98_global_scope_shared.js`.
- Modifying the error builder in `runtime/js/99_main.js` to instantiate the new `QuotaExceededError` class.
- Updating TypeScript definitions in `cli/tsc/dts/lib.deno_web.d.ts` to reflect the new class.

This ensures `QuotaExceededError` has the correct prototype chain and improves adherence to web standards. Existing `new DOMException("message", "QuotaExceededError")` calls will still function, but `code` will be 0 as it's no longer mapped directly in DOMException.
@CLAassistant
Copy link

CLAassistant commented Nov 25, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

Adds a new QuotaExceededError JS class (subclassing DOMException), registers it with webidl, and exposes it on the global scope. Removes the QUOTA_EXCEEDED_ERR numeric constant from DOMException mappings and TypeScript declaration files. Updates runtime error builder registrations to stop using the DOMExceptionQuotaExceededError alias. Rust #[class(...)] annotations updated to emit QuotaExceededError. Tests updated to assert err.name === "QuotaExceededError" and new unit tests verify the QuotaExceededError class and constructor behavior.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant App as Application code
participant WebStorage as WebStorage API
participant Rust as Rust extension (lib)
participant JS as QuotaExceededError JS class
participant Global as GlobalScope

Note over WebStorage,Rust: storage operation that may exceed quota
App->>WebStorage: localStorage.setItem(...)
WebStorage->>Rust: check capacity
alt capacity exceeded
Rust->>JS: construct/throw QuotaExceededError (class "QuotaExceededError")
JS-->>App: throw QuotaExceededError instance (name="QuotaExceededError", code=22)
else capacity ok
Rust-->>App: success
end
Note over Global: QuotaExceededError exported on global scope for instanceof checks

mermaid
sequenceDiagram
autonumber
participant Old as Old flow
participant New as New flow
Note over Old,New: Comparison of error mapping
Old->>Old: DOMException mapping included QUOTA_EXCEEDED_ERR (22)
Old->>App: code-based legacy paths could use numeric constant
New->>New: QUOTA_EXCEEDED_ERR entry removed from DOMException mapping
New->>App: QuotaExceededError class used; DOMException constructed with name may fall back to code 0 if name not in mapping

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Areas needing attention:
    • ext/web/01_dom_exception.js — confirm removal of QUOTA_EXCEEDED_ERR preserves constructor fallback semantics.
    • ext/web/02_quota_exceeded_error.js & runtime/js/98_global_scope_shared.js — verify class registration, webidl.configureInterface, and non-enumerable global exposure.
    • runtime/js/99_main.js — ensure DOMExceptionQuotaExceededError builder removal leaves no stale mappings.
    • Rust sources (ext/crypto/lib.rs, ext/webstorage/lib.rs) — validate #[class("QuotaExceededError")] matches runtime class name.
    • d.ts (cli/tsc/dts/lib.deno_web.d.ts) — ensure typings reflect the new QuotaExceededError class and removed numeric constant.
    • Tests — confirm updated tests assert name/instance and cover DOMException fallback behavior.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: updating QuotaExceededError to align with the WHATWG specification.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation, changes made, and the two possible implementation paths from the spec.
Linked Issues check ✅ Passed The PR successfully implements the QuotaExceededError subclass approach from #30028, removing legacy handling and creating a dedicated DOMException subclass as per the WHATWG WebIDL update.
Out of Scope Changes check ✅ Passed All changes are directly related to updating QuotaExceededError handling per spec requirements. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 896bcb9 and 815509d.

📒 Files selected for processing (2)
  • cli/tsc/dts/lib.dom.d.ts (0 hunks)
  • cli/tsc/dts/lib.webworker.d.ts (0 hunks)
💤 Files with no reviewable changes (2)
  • cli/tsc/dts/lib.webworker.d.ts
  • cli/tsc/dts/lib.dom.d.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test debug linux-x86_64
  • GitHub Check: test debug linux-aarch64
  • GitHub Check: test release linux-x86_64
  • GitHub Check: build libs
  • GitHub Check: test debug macos-aarch64
  • GitHub Check: test debug macos-x86_64
  • GitHub Check: test debug windows-x86_64

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1146973 and 081f672.

📒 Files selected for processing (6)
  • cli/tsc/dts/lib.deno_web.d.ts (1 hunks)
  • ext/web/01_dom_exception.js (0 hunks)
  • ext/web/02_quota_exceeded_error.js (1 hunks)
  • ext/web/lib.rs (1 hunks)
  • runtime/js/98_global_scope_shared.js (2 hunks)
  • runtime/js/99_main.js (2 hunks)
💤 Files with no reviewable changes (1)
  • ext/web/01_dom_exception.js
🧰 Additional context used
📓 Path-based instructions (3)
ext/**/lib.rs

📄 CodeRabbit inference engine (CLAUDE.md)

Extensions should provide ops (operations) exposed to JavaScript in Rust code within ext/<extension_name>/ directories

Files:

  • ext/web/lib.rs
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: For debugging Rust code, set breakpoints in IDE debuggers (VS Code with rust-analyzer, IntelliJ IDEA) or use lldb directly
Use eprintln!() or dbg!() macros for debug prints in Rust code

Files:

  • ext/web/lib.rs
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with --inspect-brk flag and connect Chrome DevTools to chrome://inspect
Use console.log() for debug prints in JavaScript runtime code

Files:

  • runtime/js/99_main.js
  • ext/web/02_quota_exceeded_error.js
  • runtime/js/98_global_scope_shared.js
  • cli/tsc/dts/lib.deno_web.d.ts
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:19:37.798Z
Learnt from: CR
Repo: denoland/deno PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:19:37.798Z
Learning: Applies to ext/**/lib.rs : Extensions should provide ops (operations) exposed to JavaScript in Rust code within `ext/<extension_name>/` directories

Applied to files:

  • ext/web/lib.rs
🧬 Code graph analysis (1)
ext/web/02_quota_exceeded_error.js (1)
ext/web/01_dom_exception.js (4)
  • primordials (11-23)
  • _name (28-28)
  • _message (29-29)
  • _code (30-30)
🪛 Biome (2.1.2)
ext/web/02_quota_exceeded_error.js

[error] 13-13: Do not shadow the global "Symbol" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🪛 GitHub Check: lint debug macos-x86_64
ext/web/02_quota_exceeded_error.js

[failure] 23-23:
�[0m�[1moptions is never used


[failure] 46-46:
�[0m�[1mUse null [[prototype]] object in the define property


[failure] 23-23:
�[0m�[1mUse null [[prototype]] object in the default parameter

🪛 GitHub Check: lint debug windows-x86_64
ext/web/02_quota_exceeded_error.js

[failure] 23-23:
�[0m�[1moptions is never used


[failure] 46-46:
�[0m�[1mUse null [[prototype]] object in the define property


[failure] 23-23:
�[0m�[1mUse null [[prototype]] object in the default parameter

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test debug macos-x86_64
  • GitHub Check: test release linux-x86_64
  • GitHub Check: test debug windows-x86_64
  • GitHub Check: test debug linux-aarch64
  • GitHub Check: test debug linux-x86_64
  • GitHub Check: test debug macos-aarch64
  • GitHub Check: build libs
🔇 Additional comments (4)
ext/web/lib.rs (1)

112-120: ESM registration of 02_quota_exceeded_error.js looks correct

Adding the module to the esm array right after 01_dom_exception.js cleanly wires the new QuotaExceededError implementation into the web extension; no additional Rust ops are needed here.

runtime/js/99_main.js (1)

79-81: Switching the quota builder to QuotaExceededError is sound

Importing QuotaExceededError and having DOMExceptionQuotaExceededError return new QuotaExceededError(msg) preserves backwards compatibility (instanceof DOMException still holds) while exposing the more specific subclass. The wiring through core.registerErrorBuilder remains unchanged.

Also applies to: 352-355

runtime/js/98_global_scope_shared.js (1)

30-32: Global exposure of QuotaExceededError is consistent with other Web APIs

Importing QuotaExceededError and exposing it on windowOrWorkerGlobalScope via core.propNonEnumerable matches the pattern used for DOMException and other platform classes; this will make QuotaExceededError available on both window and worker globals as expected.

Also applies to: 68-89

cli/tsc/dts/lib.deno_web.d.ts (1)

70-73: Type declaration for QuotaExceededError matches the runtime shape

Declaring QuotaExceededError as a DOMException subclass with (message?: string, options?: ExceptionInformation) aligns with the new JS implementation and makes the new class part of the public deno_web surface.

Comment on lines 10 to 20
import { primordials } from "ext:core/mod.js";
const {
ObjectDefineProperty,
Symbol,
} = primordials;
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { DOMException } from "ext:deno_web/01_dom_exception.js";

const _name = Symbol("[[name]]");
const _message = Symbol("[[message]]");
const _code = Symbol("[[code]]");
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Fix lints in QuotaExceededError (Symbol shadowing, unused options, null-proto objects)

The overall implementation of QuotaExceededError as a DOMException subclass looks fine, but the current file will trip the linters:

  • Biome flags shadowing the global Symbol.
  • Lint reports the options parameter as unused.
  • Lint requires null-[[Prototype]] objects for the options default and the ObjectDefineProperty descriptor.

You can address all three without changing observable behavior by applying a small refactor like this:

 import { primordials } from "ext:core/mod.js";
 const {
-  ObjectDefineProperty,
-  Symbol,
+  ObjectDefineProperty,
+  Symbol: PrimordialsSymbol,
 } = primordials;
 import * as webidl from "ext:deno_webidl/00_webidl.js";
 import { DOMException } from "ext:deno_web/01_dom_exception.js";

-const _name = Symbol("[[name]]");
-const _message = Symbol("[[message]]");
-const _code = Symbol("[[code]]");
+const _name = PrimordialsSymbol("[[name]]");
+const _message = PrimordialsSymbol("[[message]]");
+const _code = PrimordialsSymbol("[[code]]");

 class QuotaExceededError extends DOMException {
-  constructor(message = "", options = {}) {
+  constructor(message = "", options = { __proto__: null }) {
     super(message, "QuotaExceededError");
+    // `options` is currently reserved for spec-aligned extensions; mark it as
+    // used so linters don’t treat it as dead.
+    void options;
     this[webidl.brand] = webidl.brand;
     this[_name] = "QuotaExceededError";
     this[_message] = message;
     this[_code] = 22;
   }
@@
-ObjectDefineProperty(globalThis, "QuotaExceededError", {
-  value: QuotaExceededError,
-  writable: true,
-  enumerable: false,
-  configurable: true,
-});
+ObjectDefineProperty(globalThis, "QuotaExceededError", {
+  __proto__: null,
+  value: QuotaExceededError,
+  writable: true,
+  enumerable: false,
+  configurable: true,
+});

This keeps the runtime behavior the same while satisfying the static analysis checks and following the project’s null-prototype object conventions.

Also applies to: 22-24, 44-51

🧰 Tools
🪛 Biome (2.1.2)

[error] 13-13: Do not shadow the global "Symbol" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🤖 Prompt for AI Agents
In ext/web/02_quota_exceeded_error.js around lines 10–20 (also apply same
pattern to 22–24 and 44–51): avoid shadowing the global Symbol by aliasing the
primordials export (e.g., extract Symbol as PrimordialsSymbol and use that alias
when creating internal Symbols), stop reporting the options parameter as unused
by using a null-prototype default options object (e.g., const defaultOptions =
Object.create(null) and use that instead of undefined), and ensure any
property-descriptor objects passed to ObjectDefineProperty are null-prototype
objects (create the descriptor via Object.create(null) and set
configurable/enumerable/writable/value fields there) so linters are satisfied
without changing runtime behavior.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
ext/web/02_quota_exceeded_error.js (1)

1-2: Remove this obsolete module instead of leaving a stub.

If QuotaExceededError is now fully handled in 01_dom_exception.js, this file should be deleted and any references to 02_quota_exceeded_error.js in ext/web/lib.rs (or elsewhere) should be removed. Keeping a comment‑only stub is noisy and can confuse future readers about where the real implementation lives.

tests/unit/webstorage_test.ts (1)

15-42: Tighten assertions to expect QuotaExceededError subclass, not just DOMException.

The current tests are correct: they verify a DOMException is thrown and err.name === "QuotaExceededError" for all quota‑exceeded cases. To better exercise the new subclass behavior introduced in this PR, consider expecting the QuotaExceededError type directly:

-  let err = assertThrows(
+  let err = assertThrows(
     () => {
       localStorage.setItem("k", "v".repeat(15 * 1024 * 1024));
     },
-    DOMException,
+    QuotaExceededError,
   );
   assertEquals(err.name, "QuotaExceededError");
@@
-  err = assertThrows(
+  err = assertThrows(
     () => {
       localStorage.setItem("k".repeat(15 * 1024 * 1024), "v");
     },
-    DOMException,
+    QuotaExceededError,
   );
@@
-  err = assertThrows(
+  err = assertThrows(
     () => {
       localStorage.setItem(
         "k".repeat(5 * 1024 * 1024),
         "v".repeat(5 * 1024 * 1024),
       );
     },
-    DOMException,
+    QuotaExceededError,
   );

This will fail if we ever regress to throwing a plain DOMException with that name instead of the dedicated QuotaExceededError subclass.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 081f672 and b1fd1a3.

📒 Files selected for processing (3)
  • ext/web/01_dom_exception.js (1 hunks)
  • ext/web/02_quota_exceeded_error.js (1 hunks)
  • tests/unit/webstorage_test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ext/web/01_dom_exception.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: For JavaScript runtime debugging, enable V8 inspector with --inspect-brk flag and connect Chrome DevTools to chrome://inspect
Use console.log() for debug prints in JavaScript runtime code

Files:

  • ext/web/02_quota_exceeded_error.js
  • tests/unit/webstorage_test.ts
🧬 Code graph analysis (1)
tests/unit/webstorage_test.ts (2)
runtime/js/99_main.js (1)
  • err (291-291)
tests/unit/test_util.ts (1)
  • assertThrows (19-19)

Remove incorrectly added  and its reference from .
 is an instance of  with a specific name, not a separate class.
This fixes CI failures related to Web API error handling and snapshot generation.
Comment on lines -350 to -355
core.registerErrorBuilder(
"DOMExceptionQuotaExceededError",
function DOMExceptionQuotaExceededError(msg) {
return new DOMException(msg, "QuotaExceededError");
},
);
Copy link
Contributor

Choose a reason for hiding this comment

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

It needs to be registered here to be accessible from Rust's #[class("QuotaExceededError")] macro.

NetworkError: { value: NETWORK_ERR },
AbortError: { value: ABORT_ERR },
URLMismatchError: { value: URL_MISMATCH_ERR },
QuotaExceededError: { value: QUOTA_EXCEEDED_ERR },
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to stay for compat.

@bartlomieju bartlomieju changed the title refactor(web): update QuotaExceededError to spec as a proper DOMException subclass (#30028) feat(web): update QuotaExceededError to spec Dec 1, 2025
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.

Update QuotaExceededError handling

3 participants