Skip to content

Commit

Permalink
Add tests for Stage 3 Decorator Metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Dec 7, 2023
1 parent 6cbb6da commit ae45c3d
Show file tree
Hide file tree
Showing 22 changed files with 780 additions and 0 deletions.
4 changes: 4 additions & 0 deletions features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ regexp-v-flag
# https://github.com/tc39/proposal-decorators
decorators

# Decorator Metadata
# https://github.com/tc39/proposal-decorator-metadata
decorator-metadata

# Duplicate named capturing groups
# https://github.com/tc39/proposal-duplicate-named-capturing-groups
regexp-duplicate-named-groups
Expand Down
19 changes: 19 additions & 0 deletions test/built-ins/Function/prototype/Symbol.metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-function.prototype-@@metadata
description: Function.prototype[Symbol.metadata] property descriptor
info: |
The initial value of the @@metadata property is null.
This property has the attributes { [[Writable]]: false, [[Enumerable]]:
false, [[Configurable]]: false }.
includes: [propertyHelper.js]
features: [decorator-metadata]
---*/

verifyProperty(Function.prototype, Symbol.metadata, {
value: null,
writable: false,
enumerable: false,
configurable: false
});
14 changes: 14 additions & 0 deletions test/built-ins/Symbol/metadata/cross-realm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-symbol.metadata
description: Value shared by all realms
info: |
Unless otherwise specified, well-known symbols values are shared by all
realms.
features: [cross-realm, decorator-metadata]
---*/

var OSymbol = $262.createRealm().global.Symbol;

assert.sameValue(Symbol.metadata, OSymbol.metadata);
17 changes: 17 additions & 0 deletions test/built-ins/Symbol/metadata/prop-desc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-symbol.metadata
description: >
`Symbol.metadata` property descriptor
info: |
This property has the attributes { [[Writable]]: false, [[Enumerable]]:
false, [[Configurable]]: false }.
includes: [propertyHelper.js]
features: [decorator-metadata]
---*/

assert.sameValue(typeof Symbol.metadata, 'symbol');
verifyNotEnumerable(Symbol, 'metadata');
verifyNotWritable(Symbol, 'metadata');
verifyNotConfigurable(Symbol, 'metadata');
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-createdecoratorcontextobject
description: >
Property descriptor for metadata property of decorator context object.
info: |
CreateDecoratorContextObject ( kind, name, initializers, decorationState, metadataObj [ , isStatic ] )
[...]
13. Perform ! CreateDataPropertyOrThrow(contextObj, "metadata", metadata).
14. Return contextObj.
includes: [propertyHelper.js]
features: [decorators, decorator-metadata]
---*/

var contextObj;
function dec(_, context) {
contextObj = context;
}

void @dec class C {};
assert.sameValue(typeof contextObj.metadata, "object");
verifyNotEnumerable(contextObj, "metadata");
verifyWritable(contextObj, "metadata");
verifyConfigurable(contextObj, "metadata");
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-createdecoratorcontextobject
description: >
Property descriptor for metadata property of decorator context object.
info: |
CreateDecoratorContextObject ( kind, name, initializers, decorationState, metadataObj [ , isStatic ] )
[...]
13. Perform ! CreateDataPropertyOrThrow(contextObj, "metadata", metadata).
14. Return contextObj.
includes: [deepEqual.js]
features: [decorators, decorator-metadata]
---*/

var kinds = {
"class": false,
"public method": false,
"public getter": false,
"public setter": false,
"public field": false,
"public accessor": false,
"private method": false,
"private getter": false,
"private setter": false,
"private field": false,
"private accessor": false,
};
function dec(_, context) {
const key = `${context.private ? "private" : "public"} ${context.kind}`;
kinds[key] = typeof context.metadata === "object";
}

void @dec class C {
@dec method() {}
@dec get getter() {}
@dec set setter(x) {}
@dec field;
@dec accessor accessor;
@dec #method() {}
@dec get #getter() {}
@dec set #setter(x) {}
@dec #field;
@dec accessor #accessor;
};

assert.deepEqual(kinds, {
"class": true,
"public method": true,
"public getter": true,
"public setter": true,
"public field": true,
"public accessor": true,
"private method": true,
"private getter": true,
"private setter": true,
"private field": true,
"private accessor": true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-runtime-semantics-classdefinitionevaluation
description: >
Metadata is only attached when a class or class element is decorated.
info: |
ClassTail : ClassHeritage_opt { ClassBody_opt }
21. Let hasDecorators be false.
22. If decorators is not empty, set hasDecorators to true.
[...]
25. For each ClassElement e of elements, do
[...]
e. If element is a ClassElementDefinition Record, then
i. If e.[[Decorators]] is not empty, set hasDecorators to true.
[...]
[...]
29. Let metadataObj be empty.
30. If hasDecorators is true, then
a. If ClassHeritage is present, [...]
b. Else, let metadataParent be null.
c. Set metadataObj to OrdinaryObjectCreate(metadataParent).
[...]
41. If metadataObj is not empty, then
a. Let setMetadataResult be Completion(DefinePropertyOrThrow(F, @@metadata, PropertyDescriptor { [[Value]]: metadataObj, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true })).
1. If _setMetadataResult_ is an abrupt completion, then
1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_.
1. Return ? _setMetadataResult_.
[...]
features: [decorators, decorator-metadata]
---*/

function dec() {}

let C1 = @dec class C1 {};
assert.sameValue(typeof C1[Symbol.metadata], "object");

let C2 = class C2 { @dec method() {} };
assert.sameValue(typeof C2[Symbol.metadata], "object");

let C3 = class C3 {};
assert.sameValue(typeof C3[Symbol.metadata], "undefined");
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-runtime-semantics-classdefinitionevaluation
description: >
Metadata on a derived class inherits from the metadata of the declared super class.
info: |
ClassTail : ClassHeritage_opt { ClassBody_opt }
21. Let hasDecorators be false.
22. If decorators is not empty, set hasDecorators to true.
[...]
25. For each ClassElement e of elements, do
[...]
e. If element is a ClassElementDefinition Record, then
i. If e.[[Decorators]] is not empty, set hasDecorators to true.
[...]
[...]
29. Let metadataObj be empty.
30. If hasDecorators is true, then
a. If ClassHeritage is present, [...]
b. Else, let metadataParent be null.
c. Set metadataObj to OrdinaryObjectCreate(metadataParent).
[...]
41. If metadataObj is not empty, then
a. Let setMetadataResult be Completion(DefinePropertyOrThrow(F, @@metadata, PropertyDescriptor { [[Value]]: metadataObj, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true })).
1. If _setMetadataResult_ is an abrupt completion, then
1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_.
1. Return ? _setMetadataResult_.
[...]
features: [decorators, decorator-metadata]
---*/

function dec() {}

class UndecoratedBase {}

let Base = @dec class Base {};
const baseMetadata = Base[Symbol.metadata];

let Derived = @dec class Derived extends Base { };
Object.setPrototypeOf(Derived, UndecoratedBase);

const derivedMetadata = Derived[Symbol.metadata];
assert.sameValue(Object.getPrototypeOf(derivedMetadata), baseMetadata);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-runtime-semantics-classdefinitionevaluation
description: >
Metadata on a derived class inherits from the metadata of the declared super class.
info: |
ClassTail : ClassHeritage_opt { ClassBody_opt }
21. Let hasDecorators be false.
22. If decorators is not empty, set hasDecorators to true.
[...]
25. For each ClassElement e of elements, do
[...]
e. If element is a ClassElementDefinition Record, then
i. If e.[[Decorators]] is not empty, set hasDecorators to true.
[...]
[...]
29. Let metadataObj be empty.
30. If hasDecorators is true, then
a. If ClassHeritage is present, [...]
b. Else, let metadataParent be null.
c. Set metadataObj to OrdinaryObjectCreate(metadataParent).
[...]
41. If metadataObj is not empty, then
a. Let setMetadataResult be Completion(DefinePropertyOrThrow(F, @@metadata, PropertyDescriptor { [[Value]]: metadataObj, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true })).
1. If _setMetadataResult_ is an abrupt completion, then
1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_.
1. Return ? _setMetadataResult_.
[...]
features: [decorators, decorator-metadata]
---*/

function dec() {}

class UndecoratedBase {}

let Base = @dec class Base {};
const baseMetadata = Base[Symbol.metadata];

let Derived = @dec class Derived extends Base { };
Base[Symbol.metadata] = {};

const derivedMetadata = Derived[Symbol.metadata];
assert.sameValue(Object.getPrototypeOf(derivedMetadata), baseMetadata);
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-runtime-semantics-classdefinitionevaluation
description: >
Metadata is only attached when a class or class element is decorated.
info: |
ClassTail : ClassHeritage_opt { ClassBody_opt }
21. Let hasDecorators be false.
22. If decorators is not empty, set hasDecorators to true.
[...]
25. For each ClassElement e of elements, do
[...]
e. If element is a ClassElementDefinition Record, then
i. If e.[[Decorators]] is not empty, set hasDecorators to true.
[...]
[...]
29. Let metadataObj be empty.
30. If hasDecorators is true, then
a. If ClassHeritage is present, [...]
b. Else, let metadataParent be null.
c. Set metadataObj to OrdinaryObjectCreate(metadataParent).
[...]
41. If metadataObj is not empty, then
a. Let setMetadataResult be Completion(DefinePropertyOrThrow(F, @@metadata, PropertyDescriptor { [[Value]]: metadataObj, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true })).
1. If _setMetadataResult_ is an abrupt completion, then
1. Set the running execution context's PrivateEnvironment to _outerPrivateEnvironment_.
1. Return ? _setMetadataResult_.
[...]
features: [decorators, decorator-metadata]
---*/

function dec() {}

let Base = @dec class Base {};
const baseMetadata = Base[Symbol.metadata];
assert.sameValue(Object.getPrototypeOf(baseMetadata), null);

let Derived = @dec class Derived extends Base { };
const derivedMetadata = Derived[Symbol.metadata];
assert.sameValue(Object.getPrototypeOf(derivedMetadata), baseMetadata);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2023 Ron Buckton. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-runtime-semantics-classdefinitionevaluation
description: >
The metadata object is a regular, extensible JS object.
info: |
ClassTail : ClassHeritage_opt { ClassBody_opt }
21. Let hasDecorators be false.
22. If decorators is not empty, set hasDecorators to true.
[...]
25. For each ClassElement e of elements, do
[...]
e. If element is a ClassElementDefinition Record, then
i. If e.[[Decorators]] is not empty, set hasDecorators to true.
[...]
[...]
29. Let metadataObj be empty.
30. If hasDecorators is true, then
a. If ClassHeritage is present, [...]
b. Else, let metadataParent be null.
c. Set metadataObj to OrdinaryObjectCreate(metadataParent).
[...]
features: [decorators, decorator-metadata]
---*/

function dec() {}

let C = @dec class C {};
const metadata = C[Symbol.metadata];
assert(Object.isExtensible(metadata));

0 comments on commit ae45c3d

Please sign in to comment.