[dart:html] Disallow extending html elements.

This change removes the `.created` constructor in the html
class hierarchy. These classes now only offer public factory
constructors. As a result, developers will no longer be able
to extend these classes in their libraries.

This is a breaking change, however we don't expect there to
be as much use of this feature (extending html element
classes). In particular, the ability to extend html elements
was intended for web components.  Dart only ever supported
the 0.5 spec of web components, which is old and long
deprecated.  Previously, in Dart 3.0, we removed APIs used
to register custom elements from `dart:html`, so the ability
to extend html elements has not been useful since then.

For more details see https://github.com/dart-lang/sdk/issues/53264

CoreLibraryReviewExempt: ddc/dart2js-specific library.
Change-Id: I43d8c9ae99dc83545e70e1f3b9dfc9f1b274a5c7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321741
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
Sigmund Cherem
2025-03-11 13:25:58 -07:00
committed by Commit Queue
parent 4b7fef5e01
commit 6f70ffa4ff
10 changed files with 89 additions and 1018 deletions
-15
View File
@@ -858,11 +858,6 @@ class HtmlDartInterfaceGenerator(object):
factory_constructor_name,
class_members_emitter)
isElement = False
for parent in self._database.Hierarchy(self._interface):
if parent.id == 'Element':
isElement = True
# Write out the JsInterop code.
if (implementation_members_emitter and
self._options.templates._conditions['DARTIUM'] and
@@ -870,16 +865,6 @@ class HtmlDartInterfaceGenerator(object):
not IsPureInterface(self._interface.id, self._database)):
implementation_members_emitter.Emit(js_interop_wrapper)
if isElement and self._interface.id != 'Element':
implementation_members_emitter.Emit(
' /**\n'
' * Constructor instantiated by the DOM when a custom element has been created.\n'
' *\n'
' * This can only be called by subclasses from their created constructor.\n'
' */\n'
' $CLASSNAME.created() : super.created();\n',
CLASSNAME=self._interface_type_info.implementation_name())
self._backend.EmitSupportCheck()
merged_interface = self._interface_type_info.merged_interface()
@@ -130,13 +130,6 @@ Future<Map<String, dynamic>$NULLABLE> promiseToFutureAsMap(jsPromise) =>
class HtmlElement extends Element implements NoncedElement {
factory HtmlElement() { throw new UnsupportedError("Not supported"); }
/**
* Constructor instantiated by the DOM when a custom element has been created.
*
* This can only be called by subclasses from their created constructor.
*/
HtmlElement.created() : super.created();
// From NoncedElement
String$NULLABLE get nonce native;
set nonce(String$NULLABLE value) native;
@@ -372,24 +372,6 @@ $(ANNOTATIONS)$(NATIVESPEC)class $CLASSNAME$EXTENDS$IMPLEMENTS {
return fragment.nodes.where((e) => e is Element).single $#NULLSAFECAST(as Element);
}
/**
* Custom element creation constructor.
*
* This constructor is used by the DOM when a custom element has been
* created. It can only be invoked by subclasses of Element from
* that classes created constructor.
*
* class CustomElement extends Element {
* factory CustomElement() => new Element.tag('x-custom');
*
* CustomElement.created() : super.created() {
* // Perform any element initialization.
* }
* }
* document.registerElement('x-custom', CustomElement);
*/
Element.created() : super._created();
/**
* Creates the HTML element specified by the tag name.
*
@@ -90,8 +90,44 @@ class ElementEvents extends Events {
*/
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
// Custom element created callback.
EventTarget._created();
// A private constructor to act as super-constructor for mixin-applications.
//
// The `dart:html` library predates the class modifiers feature, and it
// effectively seals many of its classes by using private and factory
// constructors. This allows the classes to be extended within the library,
// but seals them to code outside the SDK.
//
// Currently a mixin application on a class with no generative constructors
// will get a default constructor which tries to forward to the unnamed
// constructor of the superclass. That superclass constructor either doesn't
// exist or is not generative, so that's always an invalid default constructor.
//
// For now, this makes sure that the class has a private generative
// constructor that a mixin application *inside this library* can forward to,
// to avoid getting an invalid default constructor.
//
// Here is a simple example to illustrate the kind of error this constructor
// prevents:
// ```
// class A { // Equivalent to `EventTarget` here
// // Adding A._unused(); fixes the errors below
// factory A._() => throw '';
// }
//
// abstract mixin class M {
// get y;
// }
//
// abstract class B extends A with M {
// // ^ Error because A&M's default constructor needs a
// // superclass constructor to forward to.
// factory B._() => throw '';
//
// @override
// get y => 3;
// }
// ```
EventTarget._unused();
/**
* This is an ease-of-use accessor for event streams which should only be
@@ -176,9 +176,6 @@ class _ChildNodeListLazy extends ListBase<Node> implements NodeListWrapper {
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
// Custom element created callback.
Node._created() : super._created();
/**
* A modifiable list of this node's children.
*/