Prepare generator for `@webref/idl` 3.85+ and `@webref/css` 8+ (#594)

Updates `js_interop_gen` and `web_generator` to handle new WebIDL, CSS, and Browser Compat Data constructs in upcoming `@webref` and `@mdn` releases, with zero diff in `web/`:

- Resolve `[LegacyWindowAlias]` and `WindowProxy` type references to their canonical IDL declarations via `Translator.resolveIdlTypeName` across `_getRawType`, `_collectDocImports`, and `_getTypeNameRaw`, and assert against `[LegacyWindowAlias]` in `_setInheritance`.
- Prefix `[LegacyNamespace]` interfaces whose names shadow `dart:core` types (e.g. `WebAssembly.Exception` -> `WebAssemblyException` via `Translator.dartClassNameFor`) across declarations, references, `JSPromise<...>`, cross-file imports, union docs, and member-name collision checks while preserving `@JS('WebAssembly.Exception')`.
- Ignore `async_iterable` members, alias `async_sequence` to `JSObject`, support both `@webref/css` 6 and 7+ `listAll()` formats, and inspect all non-flagged/non-preview support statements in `bcd.dart`.
- Install `@latest` for `@webref/*` and `@mdn/browser-compat-data` in `web_generator/bin/update_idl_bindings.dart --update`.

Fixes #480
diff --git a/.gitignore b/.gitignore
index c49b2d4..05f6492 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 
 js_interop_gen/lib/src/*.js
 js_interop_gen/lib/src/*.js.*
+js_interop_gen/lib/src/web_rename_map.json
 js_interop_gen/lib/src/node_modules/
 web_generator/node_modules
 .compile.lock
diff --git a/js_interop_gen/lib/src/bcd.dart b/js_interop_gen/lib/src/bcd.dart
index 24d2ad8..fb730a9 100644
--- a/js_interop_gen/lib/src/bcd.dart
+++ b/js_interop_gen/lib/src/bcd.dart
@@ -182,19 +182,23 @@
   String get _browsersDescription => browsers.join(', ');
 
   bool _supportedInBrowser(String browser) {
-    final map =
-        (_support[browser] is List
-                ? (_support[browser] as List).first
-                : _support[browser])
-            as Map<String, dynamic>;
+    final support = _support[browser];
+    if (support == null) return false;
+    final statements = support is List
+        ? support.cast<Map<String, dynamic>>()
+        : [support as Map<String, dynamic>];
 
-    if (map.containsKey('version_removed')) {
-      return false;
+    for (final map in statements) {
+      // Multi-statement entries record historical, flag-gated, prefixed, or
+      // preview implementations alongside shipping support; skip non-default
+      // entries and match any currently shipping, unflagged release.
+      if (map.containsKey('version_removed')) continue;
+      if (map['flags'] != null) continue;
+      if (map['prefix'] != null || map['alternative_name'] != null) continue;
+      final value = map['version_added'];
+      if (value is String && value != 'preview') return true;
+      if (value is bool && value) return true;
     }
-
-    final value = map['version_added'];
-    if (value is String) return true;
-    if (value is bool) return value;
     return false;
   }
 
diff --git a/js_interop_gen/lib/src/elements.dart b/js_interop_gen/lib/src/elements.dart
index 8f18668..c13862d 100644
--- a/js_interop_gen/lib/src/elements.dart
+++ b/js_interop_gen/lib/src/elements.dart
@@ -119,9 +119,9 @@
     type = (idlType.idlType as JSString).toDart;
   }
 
-  if (type == 'WindowProxy') type = 'Window';
   if (type == 'any') nullable = true;
   final translator = Translator.instance!;
+  type = translator.resolveIdlTypeName(type);
   final decl = translator.typeToDeclaration[type];
   final alias = idlOrBuiltinToJsTypeAliases[type];
   assert(decl != null || alias != null);
@@ -306,8 +306,12 @@
   MemberName _generateName() {
     _finalized = true;
     final dartName = _name.name;
-    if (dartName == returnType.type ||
-        parameters.any((parameter) => dartName == parameter.type.type)) {
+    final translator = Translator.instance!;
+    if (dartName == translator.dartClassNameFor(returnType.type) ||
+        parameters.any(
+          (parameter) =>
+              dartName == translator.dartClassNameFor(parameter.type.type),
+        )) {
       underscoreName();
     }
     return _name;
@@ -562,6 +566,11 @@
     if (declaredInheritance == null) return;
     final translator = Translator.instance!;
     while (declaredInheritance != null) {
+      assert(
+        !translator.legacyWindowAliases.containsKey(declaredInheritance),
+        'Unexpected [LegacyWindowAlias] "$declaredInheritance" in '
+        'inheritance of "$name".',
+      );
       if (translator.markTypeAsUsed(declaredInheritance)) {
         inheritance = declaredInheritance;
         break;
@@ -624,7 +633,7 @@
       trustedType = split?.$2 {
     final dartName = name.name;
     final jsName = name.jsOverride.isEmpty ? dartName : name.jsOverride;
-    this.name = dartName == type.type
+    this.name = dartName == Translator.instance!.dartClassNameFor(type.type)
         ? MemberName('${dartName}_', jsName)
         : name;
   }
diff --git a/js_interop_gen/lib/src/generate_bindings.dart b/js_interop_gen/lib/src/generate_bindings.dart
index 3c54936..f301aaa 100644
--- a/js_interop_gen/lib/src/generate_bindings.dart
+++ b/js_interop_gen/lib/src/generate_bindings.dart
@@ -4,6 +4,7 @@
 
 import 'dart:convert';
 import 'dart:js_interop';
+import 'dart:js_interop_unsafe';
 
 import 'package:js_interop/js_interop.dart';
 import 'package:path/path.dart' as p;
@@ -21,7 +22,16 @@
   JSRecord<CSSEntries>? data,
 ]) async {
   final cssStyleDeclarations = <String>{};
-  for (final data in (data ?? await css.listAll().toDart).values) {
+  final allData = data ?? await css.listAll().toDart;
+  // `@webref/css` 7+ returns a single object of consolidated arrays, while
+  // `@webref/css` 6 (still pinned in `web_generator/package.json` until the
+  // spec roll) returns a record of per-spec entries.
+  // TODO(kevmoo): Drop the `< 7` fallback once `web_generator/package.json`
+  // rolls to `@webref/css` 8+.
+  final entries = (allData as JSObject).has('properties')
+      ? [allData as CSSEntries]
+      : allData.values;
+  for (final data in entries) {
     final properties = data.properties;
     if (properties != null) {
       for (var j = 0; j < properties.length; j++) {
diff --git a/js_interop_gen/lib/src/js/webidl_api.dart b/js_interop_gen/lib/src/js/webidl_api.dart
index 6faa936..9a8e3d1 100644
--- a/js_interop_gen/lib/src/js/webidl_api.dart
+++ b/js_interop_gen/lib/src/js/webidl_api.dart
@@ -48,10 +48,27 @@
 }
 
 extension ExtendedAttributeRightHandSideExtension
-    on ExtendedAttributeRightHandSide {
+    on ExtendedAttributeRightHandSide? {
   String? get value {
-    final jsObj = this as JSObject;
+    final jsObj = this as JSObject?;
+    if (jsObj == null) return null;
     final val = jsObj.getProperty('value'.toJS);
     return val.isA<JSString>() ? (val as JSString).toDart : null;
   }
+
+  /// The identifier(s) on the right-hand side, whether a single identifier or
+  /// an identifier list such as `(A, B)`.
+  List<String> get identifiers {
+    final jsObj = this as JSObject?;
+    if (jsObj == null) return const [];
+    final val = jsObj.getProperty('value'.toJS);
+    if (val.isA<JSString>()) return [(val as JSString).toDart];
+    if (val.isA<JSArray>()) {
+      return [
+        for (final item in (val as JSArray<JSObject>).toDart)
+          item.getProperty<JSString>('value'.toJS).toDart,
+      ];
+    }
+    return const [];
+  }
 }
diff --git a/js_interop_gen/lib/src/translator.dart b/js_interop_gen/lib/src/translator.dart
index a4e3742..6b28bdd 100644
--- a/js_interop_gen/lib/src/translator.dart
+++ b/js_interop_gen/lib/src/translator.dart
@@ -64,6 +64,29 @@
         final interfacelike = node as idl.Interfacelike;
         if (!node.partial) {
           _addNamed<idl.Interfacelike>(node, interfaceList);
+          final name = interfacelike.name;
+          for (final extAttr in interfacelike.extAttrs.toDart) {
+            switch (extAttr.name) {
+              case 'LegacyWindowAlias':
+                // e.g. `[LegacyWindowAlias=SVGRect] interface DOMRect`: specs
+                // may still reference the alias name as a type.
+                for (final alias in extAttr.rhs.identifiers) {
+                  translator._legacyWindowAliases[alias] = name;
+                }
+              case 'LegacyNamespace'
+                  when type != 'namespace' && _dartCoreTypeNames.contains(name):
+                // Namespaced interfaces whose name would shadow a `dart:core`
+                // type (e.g. `WebAssembly.Exception`) are prefixed with their
+                // namespace.
+                final namespace = extAttr.rhs.value;
+                if (namespace != null) {
+                  final dartName = '$namespace$name';
+                  translator._idlToDartClassName[name] = dartName;
+                  translator._dartToIdlClassName[dartName] = name;
+                  translator._typeToLibrary[dartName] = this;
+                }
+            }
+          }
         } else {
           translator._typeToPartials
               .putIfAbsent(interfacelike.name, () => [])
@@ -117,12 +140,28 @@
   final _includes = <String, List<String>>{};
   final _usedTypes = <idl.Node>{};
   Map<String, idl.Node> get typeToDeclaration => _typeToDeclaration;
+
+  /// Maps `[LegacyWindowAlias]` names to the interface they alias.
+  final _legacyWindowAliases = <String, String>{};
+  Map<String, String> get legacyWindowAliases => _legacyWindowAliases;
+  final _idlToDartClassName = <String, String>{};
+  final _dartToIdlClassName = <String, String>{};
   final _renamedClasses = <String, String>{};
   final _currentDocImports = <String>{};
   final _currentLibraryImports = <String>{};
 
   Map<String, String> get renamedClasses => _renamedClasses;
 
+  /// Resolves WebIDL aliases (`WindowProxy` and `[LegacyWindowAlias]`) to their
+  /// canonical IDL declaration name.
+  String resolveIdlTypeName(String idlType) => switch (idlType) {
+    'WindowProxy' => 'Window',
+    _ => _legacyWindowAliases[idlType] ?? idlType,
+  };
+
+  /// Returns the emitted Dart declaration name for a canonical IDL [name].
+  String dartClassNameFor(String name) => _idlToDartClassName[name] ?? name;
+
   final Map<String, String> loadedRenameMap;
 
   late String _currentlyTranslatingUrl;
@@ -315,7 +354,7 @@
     if (uniqueNames.length <= 1) return [];
 
     final formattedNames = uniqueNames.map((name) {
-      final decl = _typeToDeclaration[name];
+      final decl = _typeToDeclaration[_dartToIdlClassName[name] ?? name];
       if (decl != null && _usedTypes.contains(decl)) {
         return '[$name]';
       }
@@ -361,7 +400,7 @@
       }
       return;
     }
-    final name = (idlType.idlType as JSString).toDart;
+    final name = resolveIdlTypeName((idlType.idlType as JSString).toDart);
     final library = _typeToLibrary[name];
     if (library != null && library.url != _currentlyTranslatingUrl) {
       _currentDocImports.add(library.url);
@@ -369,7 +408,6 @@
   }
 
   String? _mapIdlPrimitiveToDart(String idlType) {
-    if (idlType == 'WindowProxy') return 'Window';
     final alias = idlOrBuiltinToJsTypeAliases[idlType];
     if (alias == 'JSObject' && idlType != 'object') return null;
     if (alias == 'JSInteger' || alias == 'JSDouble') return 'JSNumber';
@@ -393,7 +431,7 @@
       }
       return genericName;
     }
-    final name = (idlType.idlType as JSString).toDart;
+    final name = resolveIdlTypeName((idlType.idlType as JSString).toDart);
 
     final mapped = _mapIdlPrimitiveToDart(name);
     if (mapped != null) {
@@ -402,10 +440,10 @@
 
     final alias = idlOrBuiltinToJsTypeAliases[name];
     if (alias == 'JSObject' && name != 'object') {
-      return name;
+      return dartClassNameFor(name);
     }
 
-    return alias ?? name;
+    return alias ?? dartClassNameFor(name);
   }
 
   code.TypeDef _typedef(
@@ -491,6 +529,7 @@
       dartType = jsTypeToDartPrimitiveAliases[dartType] ?? dartType;
       if (dartType == 'void') nullable = false;
     }
+    dartType = dartClassNameFor(dartType);
 
     final typeArguments = <code.TypeReference>[];
     if (typeParameter != null &&
@@ -1120,7 +1159,9 @@
 
     // Namespaces have lowercase names. We also translate them to
     // private classes, and make their first character uppercase in the process.
-    final dartClassName = isNamespace ? '\$${capitalize(jsName)}' : jsName;
+    final dartClassName = isNamespace
+        ? '\$${capitalize(jsName)}'
+        : dartClassNameFor(jsName);
 
     final interfaceStatus = browserCompatData.retrieveInterfaceFor(name);
 
@@ -1254,3 +1295,21 @@
     return dartLibraries;
   }
 }
+
+/// `dart:core` type names that generated interfaces must not shadow, since
+/// `package:web` is commonly imported unprefixed.
+const _dartCoreTypeNames = {
+  'BigInt',
+  'Error',
+  'Exception',
+  'Function',
+  'Iterable',
+  'Iterator',
+  'List',
+  'Map',
+  'Object',
+  'Record',
+  'Set',
+  'Symbol',
+  'Type',
+};
diff --git a/js_interop_gen/lib/src/type_aliases.dart b/js_interop_gen/lib/src/type_aliases.dart
index eaa5f33..54d5321 100644
--- a/js_interop_gen/lib/src/type_aliases.dart
+++ b/js_interop_gen/lib/src/type_aliases.dart
@@ -36,6 +36,8 @@
   'sequence': 'JSArray',
   'FrozenArray': 'JSArray',
   'ObservableArray': 'JSArray',
+  // Wait for `JSAsyncIterable` before typing `async_sequence`.
+  'async_sequence': 'JSObject',
 
   // Number aliases. Like `JSUndefined`, `JSInteger` and `JSDouble` are special
   // sentinels so that we can differentiate between `int` and `double` values
diff --git a/js_interop_gen/test/integration/idl/legacy_names_expected.dart b/js_interop_gen/test/integration/idl/legacy_names_expected.dart
new file mode 100644
index 0000000..6e42bb3
--- /dev/null
+++ b/js_interop_gen/test/integration/idl/legacy_names_expected.dart
@@ -0,0 +1,44 @@
+// Generated from Web IDL definitions.
+
+// ignore_for_file: constant_identifier_names, non_constant_identifier_names
+// ignore_for_file: unnecessary_ignore
+
+@JS()
+library;
+
+import 'dart:js_interop';
+
+/// Union of: [JSString], [WebAssemblyException]
+typedef ExceptionOrString = JSAny;
+
+/// Union of: [BoxTarget], [JSString]
+typedef BoxOrString = JSAny;
+
+@JS('WebAssembly.Exception')
+extension type WebAssemblyException._(JSObject _) implements JSObject {
+  external factory WebAssemblyException();
+}
+
+extension type SubException._(JSObject _)
+    implements WebAssemblyException, JSObject {}
+
+extension type ExceptionThrower._(JSObject _) implements JSObject {
+  external factory ExceptionThrower();
+
+  external WebAssemblyException make();
+  external JSPromise<WebAssemblyException> makeAsync();
+  external void take(WebAssemblyException e);
+  external void takeUnion(ExceptionOrString value);
+  external WebAssemblyException get last;
+  external set last(WebAssemblyException value);
+}
+
+extension type BoxTarget._(JSObject _) implements JSObject {
+  external factory BoxTarget();
+}
+
+extension type BoxReader._(JSObject _) implements JSObject {
+  external BoxTarget readBox();
+  external BoxTarget readAlt();
+  external void takeUnion(BoxOrString value);
+}
diff --git a/js_interop_gen/test/integration/idl/legacy_names_input.idl b/js_interop_gen/test/integration/idl/legacy_names_input.idl
new file mode 100644
index 0000000..e3a990b
--- /dev/null
+++ b/js_interop_gen/test/integration/idl/legacy_names_input.idl
@@ -0,0 +1,33 @@
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Exception {
+  constructor();
+};
+
+[Exposed=Window]
+interface SubException : Exception {};
+
+typedef (Exception or DOMString) ExceptionOrString;
+
+[Exposed=Window]
+interface ExceptionThrower {
+  constructor();
+  Exception make();
+  Promise<Exception> makeAsync();
+  undefined take(Exception e);
+  undefined takeUnion(ExceptionOrString value);
+  attribute Exception last;
+};
+
+[LegacyWindowAlias=(LegacyBox, LegacyBoxAlt), Exposed=Window]
+interface BoxTarget {
+  constructor();
+};
+
+typedef (LegacyBox or DOMString) BoxOrString;
+
+[Exposed=Window]
+interface BoxReader {
+  LegacyBox readBox();
+  LegacyBoxAlt readAlt();
+  undefined takeUnion(BoxOrString value);
+};
diff --git a/js_interop_gen/test/integration/idl_test.dart b/js_interop_gen/test/integration/idl_test.dart
index 8dc738b..71b0091 100644
--- a/js_interop_gen/test/integration/idl_test.dart
+++ b/js_interop_gen/test/integration/idl_test.dart
@@ -1,6 +1,7 @@
 @TestOn('vm')
 library;
 
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:js_interop_gen/src/cli.dart';
@@ -96,5 +97,113 @@
             .forEach((f) => f.deleteSync());
       });
     }
+
+    test('cross-file LegacyNamespace and LegacyWindowAlias imports', () async {
+      final wasmIdl = File(p.join(outputDir, 'wasm_defs.idl'));
+      final boxIdl = File(p.join(outputDir, 'box_defs.idl'));
+      final consumerIdl = File(p.join(outputDir, 'consumer.idl'));
+      final wasmDart = File(p.join(outputDir, 'wasm_defs.dart'));
+      final boxDart = File(p.join(outputDir, 'box_defs.dart'));
+      final consumerDartFile = File(p.join(outputDir, 'consumer.dart'));
+
+      addTearDown(() async {
+        for (final file in [
+          wasmIdl,
+          boxIdl,
+          consumerIdl,
+          wasmDart,
+          boxDart,
+          consumerDartFile,
+        ]) {
+          if (await file.exists()) await file.delete();
+        }
+      });
+
+      await wasmIdl.writeAsString('''
+[LegacyNamespace=WebAssembly, Exposed=*]
+interface Exception {
+  constructor();
+};
+''');
+      await boxIdl.writeAsString('''
+[LegacyWindowAlias=LegacyBox, Exposed=Window]
+interface BoxTarget {
+  constructor();
+};
+''');
+      await consumerIdl.writeAsString('''
+typedef (LegacyBox or DOMString) BoxOrString;
+
+[Exposed=Window]
+interface Consumer {
+  Exception make();
+  undefined takeBox(BoxOrString box);
+};
+''');
+
+      final dummyBcdPath = p.relative(
+        p.join(outputDir, 'dummy_bcd.json'),
+        from: bindingsGenPath,
+      );
+      await runNode([
+        'main.mjs',
+        '--input=${p.relative(wasmIdl.path, from: bindingsGenPath)}',
+        '--input=${p.relative(boxIdl.path, from: bindingsGenPath)}',
+        '--input=${p.relative(consumerIdl.path, from: bindingsGenPath)}',
+        '--output=${p.relative(outputDir, from: bindingsGenPath)}',
+        '--idl',
+        '--bcd-json=$dummyBcdPath',
+      ], workingDirectory: bindingsGenPath);
+
+      final consumerDart = await consumerDartFile.readAsString();
+      expect(consumerDart, contains("/// @docImport 'box_defs.dart';"));
+      expect(consumerDart, contains('/// Union of: [BoxTarget], [JSString]'));
+      expect(consumerDart, contains("import 'wasm_defs.dart';"));
+      expect(consumerDart, contains('external WebAssemblyException make();'));
+    });
+
+    test('asserts on LegacyWindowAlias in inheritance', () async {
+      final invalidIdl = File(p.join(outputDir, 'invalid_alias_inherit.idl'));
+      final invalidDart = File(p.join(outputDir, 'invalid_alias_inherit.dart'));
+
+      addTearDown(() async {
+        for (final file in [invalidIdl, invalidDart]) {
+          if (await file.exists()) await file.delete();
+        }
+      });
+
+      await invalidIdl.writeAsString('''
+[LegacyWindowAlias=LegacyBox, Exposed=Window]
+interface BoxTarget {
+  constructor();
+};
+
+[Exposed=Window]
+interface SubBox : LegacyBox {};
+''');
+
+      final dummyBcdPath = p.relative(
+        p.join(outputDir, 'dummy_bcd.json'),
+        from: bindingsGenPath,
+      );
+      final proc = await runNodeWithResult([
+        'main.mjs',
+        '--input=${p.relative(invalidIdl.path, from: bindingsGenPath)}',
+        '--output=${p.relative(outputDir, from: bindingsGenPath)}',
+        '--idl',
+        '--bcd-json=$dummyBcdPath',
+      ], workingDirectory: bindingsGenPath);
+
+      final stderrText = await proc.stderr.transform(utf8.decoder).join();
+      await proc.stdout.drain<void>();
+      expect(await proc.exitCode, isNonZero);
+      expect(
+        stderrText,
+        contains(
+          'Unexpected [LegacyWindowAlias] "LegacyBox" in inheritance of '
+          '"SubBox".',
+        ),
+      );
+    });
   });
 }
diff --git a/web_generator/README.md b/web_generator/README.md
index a9de40b..199315f 100644
--- a/web_generator/README.md
+++ b/web_generator/README.md
@@ -22,8 +22,11 @@
 dart bin/update_idl_bindings.dart --update
 ```
 
-or, manually edit `lib/src/package.json` to use specific IDL versions, and
-re-run `update_idl_bindings.dart`.
+which installs the latest `@webref/*` and `@mdn/browser-compat-data` releases
+(including new major versions) into this package's `package.json`.
+
+Alternatively, manually edit `package.json` to use specific versions, and re-run
+`update_idl_bindings.dart`.
 
 ### Public API golden
 
diff --git a/web_generator/bin/update_idl_bindings.dart b/web_generator/bin/update_idl_bindings.dart
index 7e6aa1a..edda04b 100644
--- a/web_generator/bin/update_idl_bindings.dart
+++ b/web_generator/bin/update_idl_bindings.dart
@@ -53,12 +53,23 @@
     return;
   }
 
-  // Run `npm install` or `npm update` as needed.
+  // Run `npm install` or `npm update` as needed for the generator's own JS
+  // dependencies (webidl2, typescript).
   final update = argResult['update'] as bool;
   await runProc('npm', [
     update ? 'update' : 'install',
   ], workingDirectory: bindingsGeneratorPath);
 
+  if (!isSnapshot) {
+    // The IDL, CSS, elements, and compat data live in this package's
+    // `package.json`. `npm update` never crosses a major version of a caret
+    // range, so `--update` installs the latest version of each instead.
+    await runProc('npm', [
+      'install',
+      if (update) ...[for (final package in _dataPackages) '$package@latest'],
+    ], workingDirectory: p.fromUri(Platform.script.resolve('..')));
+  }
+
   // Compute JS type supertypes for union calculation in translator.
   await checkJsTypeSupertypes();
 
@@ -194,13 +205,10 @@
 Map<String, dynamic>? _cachedPackageLockData;
 
 String _packageLockVersion(String package) {
-  final packageLockData = _cachedPackageLockData ??=
-      jsonDecode(
-            File(
-              p.fromUri(Platform.script.resolve('../package-lock.json')),
-            ).readAsStringSync(),
-          )
-          as Map<String, dynamic>;
+  final packageLockData = _cachedPackageLockData ??= jsonDecode(
+    File(p.fromUri(Platform.script.resolve('../package-lock.json')))
+        .readAsStringSync(),
+  ) as Map<String, dynamic>;
 
   final packages = packageLockData['packages'] as Map<String, dynamic>;
   final webRefIdl = packages['node_modules/$package'] as Map<String, dynamic>;
@@ -212,6 +220,13 @@
 const _webRefElements = '@webref/elements';
 const _webRefIdl = '@webref/idl';
 
+const _dataPackages = [
+  _browserCompatData,
+  _webRefCss,
+  _webRefElements,
+  _webRefIdl,
+];
+
 final _thisScript = Uri.parse('bin/update_idl_bindings.dart');
 final _scriptPOSIXPath = _thisScript.toFilePath(windows: false);
 
@@ -232,7 +247,11 @@
 
 final _parser = ArgParser()
   ..addFlag('help', negatable: false, help: 'Show help information')
-  ..addFlag('update', abbr: 'u', help: 'Update npm dependencies')
+  ..addFlag(
+    'update',
+    abbr: 'u',
+    help: 'Update npm dependencies, including the latest IDL and compat data',
+  )
   ..addFlag('compile', defaultsTo: true)
   ..addOption(
     'output',