From 0a2d5e179dbf4f48a97871a20b4d13560e09c039 Mon Sep 17 00:00:00 2001
From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com>
Date: Wed, 11 Dec 2019 18:30:00 +0100
Subject: [PATCH 1/3] =?UTF-8?q?feat:=20Add=C2=A0`[NonEnumerableMethods]`?=
=?UTF-8?q?=20extended=C2=A0attribute?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
index.bs | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/index.bs b/index.bs
index fe1a34d3..7994db8f 100644
--- a/index.bs
+++ b/index.bs
@@ -9432,6 +9432,80 @@ corresponding to [=interface members=].
+
+ The [{{LegacyEnumerableMethod}}] [=extended attribute=] is an undesirable feature.
+ It exists only so that legacy Web platform features can be specified.
+ It should not be used in specifications
+ unless required to specify the behavior of legacy APIs,
+ or for consistency with these APIs.
+ Editors who wish to use this feature are strongly advised to discuss this
+ by filing an issue
+ before proceeding.
+
+
+If the [{{LegacyEnumerableMethod}}]
+[=extended attribute=]
+appears on a [=regular operation|regular=]
+or [=static operations|static=]
+[=operation=] specified on an interface with [{{NonEnumerableMethods}}],
+then it indicates that the ECMAScript property will be enumerable.
+
+The [{{LegacyEnumerableMethod}}]
+extended attribute must
+[=takes no arguments|take no arguments=]
+and must not appear on methods of an interface
+that does not have [{{NonEnumerableMethods}}].
+
+
+
+ The following [=IDL fragment=] defines an interface with
+ [{{NonEnumerableMethods}}], which also specifies an instance
+ and static operation with [{{LegacyEnumerableMethod}}]:
+
+
+ [Exposed=Window,
+ NonEnumerableMethods]
+ interface HasEnumerableAndNonEnumerableMethods {
+ [LegacyEnumerableMethod]
+ static void staticFoo();
+ static void staticBar();
+ static attribute any staticDataProperty;
+
+ [LegacyEnumerableMethod]
+ void instanceFoo();
+ void instanceBar();
+ attribute any instanceDataProperty;
+ };
+
+
+ An ECMAScript implementation of the above IDL would have the methods
+ of
HasEnumerableAndNonEnumerableMethods
+ non-enumerable by default, but operations with [{{LegacyEnumerableMethod}}]
+ would be enumerable.
+
+
+ for (const key in HasEnumerableAndNonEnumerableMethods) {
+ // logs only "staticFoo" and "staticDataProperty"
+ console.log(key);
+ }
+
+ for (const key in HasEnumerableAndNonEnumerableMethods.prototype) {
+ // logs only "instanceFoo" and "instanceDataProperty"
+ console.log(key);
+ }
+
+ // logs an array containing "staticFoo", "staticBar" and "staticDataProperty"
+ console.log(Object.getOwnPropertyNames(HasEnumerableAndNonEnumerableMethods));
+
+ // logs an array containing "instanceFoo", "instanceBar" and "instanceDataProperty"
+ console.log(Object.getOwnPropertyNames(HasEnumerableAndNonEnumerableMethods.prototype));
+
+
+
+
+
+
+ The following [=IDL fragment=] defines two interfaces, one which
+ has [{{NonEnumerableMethods}}], and one which doesn’t:
+
+
+ [Exposed=Window]
+ interface HasEnumerableMethods {
+ static void staticFoo();
+ static attribute any staticDataProperty;
+
+ void instanceFoo();
+ attribute any instanceDataProperty;
+ };
+
+ [Exposed=Window,
+ NonEnumerableMethods]
+ interface NonEnumerableMethods {
+ static void staticBar();
+ static attribute any staticDataProperty;
+
+ void instanceBar();
+ attribute any instanceDataProperty;
+ };
+
+
+ An ECMAScript implementation of the above IDL would have
+ the methods of
HasEnumerableMethods
+ enumerable, but
NonEnumerableMethods
+ would only have data properties enumerable.
+
+
+ for (const key in HasEnumerableMethods) {
+ // logs both "staticFoo" and "staticDataProperty"
+ console.log(key);
+ }
+
+ for (const key in HasEnumerableMethods.prototype) {
+ // logs both "instanceFoo" and "instanceDataProperty"
+ console.log(key);
+ }
+
+ for (const key in NonEnumerableMethods) {
+ // logs only "staticDataProperty"
+ console.log(key);
+ }
+
+ for (const key in NonEnumerableMethods.prototype) {
+ // logs only "instanceDataProperty"
+ console.log(key);
+ }
+
+ // logs an array containing "staticBar" and "staticDataProperty"
+ console.log(Object.getOwnPropertyNames(NonEnumerableMethods));
+
+ // logs an array containing "instanceBar" and "instanceDataProperty"
+ console.log(Object.getOwnPropertyNames(NonEnumerableMethods.prototype));
+
+
+
+
+
From d5ad4b8b82e16290b60a6e2ca6f1cb7dd33d9a76 Mon Sep 17 00:00:00 2001
From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com>
Date: Wed, 11 Dec 2019 19:20:00 +0100
Subject: [PATCH 2/3] =?UTF-8?q?feat:=20Define=C2=A0behaviour=20of=C2=A0met?=
=?UTF-8?q?hod=20and=C2=A0stringifier=20enumerability?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
index.bs | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/index.bs b/index.bs
index 7994db8f..984632ac 100644
--- a/index.bs
+++ b/index.bs
@@ -10103,8 +10103,8 @@ for the specific requirements that the use of
[NonEnumerableMethods]
If the [{{NonEnumerableMethods}}] [=extended attribute=]
-appears on an [=interface=],
-it indicates that all methods on that interface
+appears on an [=interface=], [=interface mixin=] or [=namespace=],
+it indicates that all methods defined on that interface
without [{{LegacyEnumerableMethod}}] will be non-enumerable.
The [{{NonEnumerableMethods}}]
@@ -11907,8 +11907,12 @@ in which case they are exposed on every object that [=implements=] the interface
given |op|, |definition|, and |realm|.
1. Let |modifiable| be
false if |op| is [=unforgeable=]
and
true otherwise.
+ 1. Let |enumerable| be
true
+ 1. If |definition| is declared with [{{NonEnumerableMethods}}]
+ and |op| is not declared with [{{LegacyEnumerableMethod}}]
+ set |enumerable| to
false
1. Let |desc| be the PropertyDescriptor{\[[Value]]: |method|,
- \[[Writable]]: |modifiable|, \[[Enumerable]]:
true,
+ \[[Writable]]: |modifiable|, \[[Enumerable]]: |enumerable|,
\[[Configurable]]: |modifiable|}.
1. Let |id| be |op|'s [=identifier=].
1. Perform [=!=]
DefinePropertyOrThrow(|target|, |id|, |desc|).
@@ -12145,9 +12149,10 @@ then there must exist a property with the following characteristics:
then the property exists on every object that [=implements=] the interface.
Otherwise, the property exists on the [=interface prototype object=].
* The property has attributes
- { \[[Writable]]: |B|, \[[Enumerable]]:
true, \[[Configurable]]: |B| },
+ { \[[Writable]]: |B|, \[[Enumerable]]: |E|, \[[Configurable]]: |B| },
where |B| is
false if the stringifier is [=unforgeable=] on the interface,
- and
true otherwise.
+ and
true otherwise, and where |E| is
false if the interface
+ is declared with [{{NonEnumerableMethods}}] and
true otherwise.
*
The value of the property is a [=built-in function object=], which behaves as follows:
From 23ebaa5a99eb1b4c873829959d697fad4c9080dd Mon Sep 17 00:00:00 2001
From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com>
Date: Thu, 12 Dec 2019 15:00:00 +0100
Subject: [PATCH 3/3] =?UTF-8?q?feat:=20Define=C2=A0behaviour=20of=C2=A0ite?=
=?UTF-8?q?rable=20method=C2=A0enumerability?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
index.bs | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/index.bs b/index.bs
index 984632ac..9a3ad7b2 100644
--- a/index.bs
+++ b/index.bs
@@ -12321,8 +12321,9 @@ If the [=interface=] has any of the following:
* a [=setlike declaration=]
then a forEach
data property must exist with attributes
-{ \[[Writable]]: true, \[[Enumerable]]: true, \[[Configurable]]: true }
-and whose value is a [=function object=].
+{ \[[Writable]]: true, \[[Enumerable]]: |E|, \[[Configurable]]: true }
+and whose value is a [=function object=], where |E| is false if the interface
+is declared with [{{NonEnumerableMethods}}] and true otherwise.
The location of the property is determined as follows:
@@ -12418,8 +12419,9 @@ property is the String value "forEach
".
If the [=interface=] has an [=iterable declaration=] or an [=asynchronously iterable declaration=],
then an entries
data property must exist with attributes
-{ \[[Writable]]: true, \[[Enumerable]]: true, \[[Configurable]]: true }
-and whose value is a [=function object=].
+{ \[[Writable]]: true, \[[Enumerable]]: |E|, \[[Configurable]]: true }
+and whose value is a [=function object=], where |E| is false if the interface
+is declared with [{{NonEnumerableMethods}}] and true otherwise.
The location of the property is determined as follows:
@@ -12441,8 +12443,9 @@ the value of the {{@@asyncIterator}} property.
If the [=interface=] has an [=iterable declaration=] or an [=asynchronously iterable declaration=],
then a keys
data property must exist with attributes
-{ \[[Writable]]: true, \[[Enumerable]]: true, \[[Configurable]]: true }
-and whose value is a [=function object=].
+{ \[[Writable]]: true, \[[Enumerable]]: |E|, \[[Configurable]]: true }
+and whose value is a [=function object=], where |E| is false if the interface
+is declared with [{{NonEnumerableMethods}}] and true otherwise.
The location of the property is determined as follows:
@@ -12505,8 +12508,9 @@ The value of the [=function object=]’s name
property
If the [=interface=] has an [=iterable declaration=] or an [=asynchronously iterable declaration=],
then a values
data property must exist
-with attributes { \[[Writable]]: true, \[[Enumerable]]: true, \[[Configurable]]: true }
-and whose value is a [=function object=].
+with attributes { \[[Writable]]: true, \[[Enumerable]]: |E|, \[[Configurable]]: true }
+and whose value is a [=function object=], where |E| is false if the interface
+is declared with [{{NonEnumerableMethods}}] and true otherwise.
The location of the property is determined as follows: