diff --git a/index.bs b/index.bs
index 31e56e8b..61d48180 100644
--- a/index.bs
+++ b/index.bs
@@ -84,6 +84,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: Set; url: sec-set-objects
text: SharedArrayBuffer; url: sec-sharedarraybuffer-objects
text: %AsyncIteratorPrototype%; url: sec-asynciteratorprototype
+ text: %ArrayPrototype%; url: sec-properties-of-the-array-prototype-object
text: %ErrorPrototype%; url: sec-properties-of-the-error-prototype-object
text: %FunctionPrototype%; url: sec-properties-of-the-function-prototype-object
text: %IteratorPrototype%; url: sec-%iteratorprototype%-object
@@ -120,6 +121,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: CanonicalNumericIndexString; url: sec-canonicalnumericindexstring
text: Completion; url: sec-completion
text: Construct; url: sec-construct
+ text: CreateArrayFromList; url: sec-createarrayfromlist
text: CreateArrayIterator; url: sec-createarrayiterator
text: CreateBuiltinFunction; url: sec-createbuiltinfunction
text: CreateDataProperty; url: sec-createdataproperty
@@ -133,11 +135,13 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: SetMutableBinding
text: CreateMutableBinding
text: InitializeBinding
+ text: FromPropertyDescriptor; url: sec-frompropertydescriptor
text: Get; url: sec-get-o-p
text: GetFunctionRealm; url: sec-getfunctionrealm
text: GetIterator; url: sec-getiterator
text: GetMethod; url: sec-getmethod
text: IfAbruptRejectPromise; url: sec-ifabruptrejectpromise
+ text: IsArray; url: sec-isarray
text: IsAccessorDescriptor; url: sec-isaccessordescriptor
text: IsCallable; url: sec-iscallable
text: IsConstructor; url: sec-isconstructor
@@ -156,6 +160,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions
text: OrdinarySetWithOwnDescriptor; url: sec-ordinarysetwithowndescriptor
text: PerformPromiseThen; url: sec-performpromisethen
+ text: ProxyCreate; url: sec-proxycreate
text: Set; url: sec-set-o-p-v-throw
text: SetFunctionLength; url: sec-setfunctionlength
text: SetFunctionName; url: sec-setfunctionname
@@ -165,6 +170,8 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: ToInt32; url: sec-toint32
text: ToNumber; url: sec-tonumber
text: ToObject; url: sec-toobject
+ text: ToPropertyDescriptor; url: sec-topropertydescriptor
+ text: ToPropertyKey; url: sec-topropertykey
text: ToString; url: sec-tostring
text: ToUint16; url: sec-touint16
text: ToUint32; url: sec-touint32
@@ -221,6 +228,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMA-262
text: own property; url: sec-own-property
text: PromiseCapability; url: sec-promisecapability-records
text: Property Descriptor; url: sec-property-descriptor-specification-type
+ text: Proxy exotic object; url: sec-proxy-object-internal-methods-and-internal-slots
text: Source Text Module Record; url: sourctextmodule-record
text: realm; url: realm
text: ResolvedBinding Record; url: resolvedbinding-record
@@ -5756,6 +5764,7 @@ type.
"symbol" Null
BufferRelatedType Null
"FrozenArray" "<" TypeWithExtendedAttributes ">" Null
+ "ObservableArray" "<" TypeWithExtendedAttributes ">" Null
RecordType Null
@@ -6775,6 +6784,131 @@ The [=type name=] of a frozen array
type is the concatenation of the type name for |T| and the string
"Array
".
+
ObservableArray
".
+
++ [Exposed=Window] + interface Building { + attribute ObservableArray<Employee> employees; + }; ++ + The behavior of the attribute could be defined like so: + +
+ The [=observable array attribute/set an indexed value=] algorithm for ++ + Then, ECMAScript code could manipulate theBuilding
'semployees
attribute, given + |employee| and |index|, is: + + 1. If |employee| is not allowed to enter the building today, then throw a + "{{NotAllowedError}}" {{DOMException}}. + 1. If |index| is greater than 200, then throw a "{{QuotaExceededError}}" {{DOMException}}. + 1. Put |employee| to work! + + The [=observable array attribute/delete an indexed value=] algorithm for +Building
'semployees
attribute, given + |employee| and index, is: + + 1. Alert security that |employee| has left the building. +
employees
property in
+ various ways:
+
+ + // Get an instance of Building. + const building = getBuilding(); + + building.employees.push(new Employee("A")); + building.employees.push(new Employee("B")); + building.employees.push(new Employee("C")); + + building.employees.splice(1, 1); + const employeeB = building.employees.pop(); + + building.employees = [new Employee("D"), employeeB, new Employee("C")]; + + building.employees.length = 0; + + // Will throw: + building.employees.push("not an Employee; a string instead"); ++ + All of these manipulations would pass through the above-defined + [=observable array attribute/set an indexed value=] algorithm, potentially throwing if the + conditions described there were met. They would also perform the appropriate side effects listed + there and in the [=observable array attribute/delete an indexed value=] algorithm. + + Another thing to note about the above code example is how all of the ECMAScript array methods + from {{%ArrayPrototype%}} work on the observable array. Indeed, it fully behaves like an +
Array
instance:
+
+ + const normalArray = []; + + // If building.employees were defined as an indexed property getter interface: normalArray + // would contains a single item, building.employees. + // + // For observable arrays (and frozen arrays): normalArray contains all of the items inside + // of building.employees. + normalArray.concat(building.employees); + + // names is an ECMAScript Array. + const names = building.employees.map(employee => employee.name); + + // Passes various brand checks: + console.assert(building.employees instanceof Array); + console.assert(Array.isArray(building.employees)); + console.assert(building.employees.constructor === Array); + + // Even is treated as an array by JSON.stringify! + console.assert(JSON.stringify(building.employees) === `["object Employee"]`); ++
Array
instances as their proxy target, and we want
+to ensure that [=observable array types=] are exposed to ECMAScript code with this special treatment
+intact.
+
+The proxy traps used by observable array exotic objects work to ensure a number of invariants beyond
+those of normal Array
instances:
+
+* The arrays have no holes, i.e. every property in the inclusive range 0 through
+ observableArray.length
− 1 will be filled with a value compatible with the
+ specified Web IDL type, and no [=array index=] properties will exist outside that range.
+* The property descriptors for important properties cannot be changed from their default
+ configuration; indexed properties always remain as configurable, enumerable, and writable data
+ properties, while the length
property remains as a non-configurable,
+ non-enumerable, and writable data property.
+* Adding additional properties to the array cannot be prevented using, for example,
+ Object.preventExtensions()
.
+
+defineProperty
", |defineProperty|).
+ 1. Let |deleteProperty| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-deleteProperty]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "deleteProperty
", |deleteProperty|).
+ 1. Let |get| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-get]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "get
", |get|).
+ 1. Let |getOwnPropertyDescriptor| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-getOwnPropertyDescriptor]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "getOwnPropertyDescriptor
", |getOwnPropertyDescriptor|).
+ 1. Let |has| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-has]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "has
", |has|).
+ 1. Let |ownKeys| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-ownKeys]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "ownKeys
", |ownKeys|).
+ 1. Let |preventExtensions| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-preventExtensions]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "preventExtensions
", |preventExtensions|).
+ 1. Let |set| be [=!=] [$CreateBuiltinFunction$](the steps from [[#es-observable-array-set]], « », |realm|).
+ 1. Perform [=!=] [$CreateDataProperty$](|handler|, "set
", |set|).
+ 1. Return [=!=] [$ProxyCreate$](|innerArray|, |handler|).
+defineProperty
defineProperty
proxy trap for
+ [=observable array exotic objects=], given |O|, |P|, and |descriptorObj| are as follows:
+
+ 1. Let |handler| be the deleteProperty
deleteProperty
proxy trap for
+ [=observable array exotic objects=], given |O| and |P|, are as follows:
+
+ 1. Let |handler| be the get
get
proxy trap for
+ [=observable array exotic objects=], given |O|, |P|, and |Receiver|, are as follows:
+
+ 1. Let |handler| be the getOwnPropertyDescriptor
getOwnPropertyDescriptor
proxy trap for
+ [=observable array exotic objects=], given |O| and |P|, are as follows:
+
+ 1. Let |handler| be the has
has
proxy trap for
+ [=observable array exotic objects=], given |O| and |P|, are as follows:
+
+ 1. Let |handler| be the ownKeys
ownKeys
proxy trap for
+ [=observable array exotic objects=], given |O|, are as follows:
+
+ 1. Let |handler| be the preventExtensions
preventExtensions
proxy trap for
+ [=observable array exotic objects=] are as follows:
+
+ 1. Return set
set
proxy trap for
+ [=observable array exotic objects=], given |O|, |P|, |V|, and |Receiver|, are as follows:
+
+ 1. Let |handler| be the