Class private properties (#7842)

* Update member-expression-to-functions

1. Babel using British spellings, so `memoise`
2. Provide a helper `AssignmentMemoiser` class, which will assign the memo'd value with the `n`th access.

* Private properties!

* Fixes

* Tests

* Update helper name

* Fix privates that reference other privates

* Don't extend a builtin

* Rebase
This commit is contained in:
Justin Ridgewell 2018-05-18 14:03:23 -04:00 committed by GitHub
parent 70eb206c03
commit 27c39c512d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
177 changed files with 3056 additions and 95 deletions

View File

@ -26,7 +26,7 @@ const visitor = {
// The helper requires three special methods on state: `get`, `set`, and // The helper requires three special methods on state: `get`, `set`, and
// `call`. // `call`.
// Optionally, a special `memoize` method may be defined, which gets // Optionally, a special `memoise` method may be defined, which gets
// called if the member is in a self-referential update expression. // called if the member is in a self-referential update expression.
// Everything else will be passed through as normal. // Everything else will be passed through as normal.
const state = { const state = {
@ -55,10 +55,10 @@ const state = {
); );
}, },
memoize(memberPath) { memoise(memberPath) {
const { node } = memberPath; const { node } = memberPath;
if (node.computed) { if (node.computed) {
MEMOIZED.set(node, ...); MEMOISED.set(node, ...);
} }
}, },

View File

@ -1,6 +1,39 @@
import * as t from "@babel/types"; import * as t from "@babel/types";
class AssignmentMemoiser {
constructor() {
this._map = new WeakMap();
}
has(key) {
return this._map.has(key);
}
get(key) {
if (!this.has(key)) return;
const record = this._map.get(key);
const { value } = record;
record.count--;
if (record.count === 0) {
// The `count` access is the outermost function call (hopefully), so it
// does the assignment.
return t.assignmentExpression("=", value, key);
}
return value;
}
set(key, value, count) {
return this._map.set(key, { count, value });
}
}
const handle = { const handle = {
memoise() {
// noop.
},
handle(member) { handle(member) {
const { node, parent, parentPath } = member; const { node, parent, parentPath } = member;
@ -9,11 +42,10 @@ const handle = {
if (parentPath.isUpdateExpression({ argument: node })) { if (parentPath.isUpdateExpression({ argument: node })) {
const { operator, prefix } = parent; const { operator, prefix } = parent;
// Give the state handler a chance to memoize the member, // Give the state handler a chance to memoise the member, since we'll
// since we'll reference it twice. // reference it twice. The second access (the set) should do the memo
if (this.memoize) { // assignment.
this.memoize(member); this.memoise(member, 2);
}
const value = t.binaryExpression( const value = t.binaryExpression(
operator[0], operator[0],
@ -44,11 +76,10 @@ const handle = {
let value = right; let value = right;
if (operator !== "=") { if (operator !== "=") {
// Give the state handler a chance to memoize the member, // Give the state handler a chance to memoise the member, since we'll
// since we'll reference it twice. // reference it twice. The second access (the set) should do the memo
if (this.memoize) { // assignment.
this.memoize(member); this.memoise(member, 2);
}
value = t.binaryExpression( value = t.binaryExpression(
operator.slice(0, -1), operator.slice(0, -1),
@ -79,11 +110,12 @@ const handle = {
// it wishes to be transformed. // it wishes to be transformed.
// Additionally, the caller must pass in a state object with at least // Additionally, the caller must pass in a state object with at least
// get, set, and call methods. // get, set, and call methods.
// Optionally, a memoize method may be defined on the state, which will be // Optionally, a memoise method may be defined on the state, which will be
// called when the member is a self-referential update. // called when the member is a self-referential update.
export default function memberExpressionToFunctions(path, visitor, state) { export default function memberExpressionToFunctions(path, visitor, state) {
path.traverse(visitor, { path.traverse(visitor, {
...state,
...handle, ...handle,
...state,
memoiser: new AssignmentMemoiser(),
}); });
} }

View File

@ -70,9 +70,8 @@ const visitor = traverse.visitors.merge([
}, },
]); ]);
const memoized = new WeakMap();
const specHandlers = { const specHandlers = {
memoize(superMember) { memoise(superMember, count) {
const { scope, node } = superMember; const { scope, node } = superMember;
const { computed, property } = node; const { computed, property } = node;
if (!computed) { if (!computed) {
@ -84,44 +83,34 @@ const specHandlers = {
return; return;
} }
memoized.set(property, memo); this.memoiser.set(property, memo, count);
},
prop(superMember) {
const { computed, property } = superMember.node;
if (this.memoiser.has(property)) {
return t.cloneNode(this.memoiser.get(property));
}
if (computed) {
return t.cloneNode(property);
}
return t.stringLiteral(property.name);
}, },
get(superMember) { get(superMember) {
const { computed, property } = superMember.node;
const thisExpr = t.thisExpression();
let prop;
if (computed && memoized.has(property)) {
prop = t.cloneNode(memoized.get(property));
} else {
prop = computed ? property : t.stringLiteral(property.name);
}
return t.callExpression(this.file.addHelper("get"), [ return t.callExpression(this.file.addHelper("get"), [
getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file), getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file),
prop, this.prop(superMember),
thisExpr, t.thisExpression(),
]); ]);
}, },
set(superMember, value) { set(superMember, value) {
const { computed, property } = superMember.node;
let prop;
if (computed && memoized.has(property)) {
prop = t.assignmentExpression(
"=",
t.cloneNode(memoized.get(property)),
property,
);
} else {
prop = computed ? property : t.stringLiteral(property.name);
}
return t.callExpression(this.file.addHelper("set"), [ return t.callExpression(this.file.addHelper("set"), [
getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file), getPrototypeOfExpression(this.getObjectRef(), this.isStatic, this.file),
prop, this.prop(superMember),
value, value,
t.thisExpression(), t.thisExpression(),
t.booleanLiteral(superMember.isInStrictMode()), t.booleanLiteral(superMember.isInStrictMode()),
@ -134,12 +123,21 @@ const specHandlers = {
}; };
const looseHandlers = { const looseHandlers = {
memoize: specHandlers.memoize, ...specHandlers,
call: specHandlers.call,
prop(superMember) {
const { property } = superMember.node;
if (this.memoiser.has(property)) {
return t.cloneNode(this.memoiser.get(property));
}
return t.cloneNode(property);
},
get(superMember) { get(superMember) {
const { isStatic, superRef } = this; const { isStatic, superRef } = this;
const { property, computed } = superMember.node; const { computed } = superMember.node;
const prop = this.prop(superMember);
let object; let object;
if (isStatic) { if (isStatic) {
@ -155,29 +153,12 @@ const looseHandlers = {
: t.memberExpression(t.identifier("Object"), t.identifier("prototype")); : t.memberExpression(t.identifier("Object"), t.identifier("prototype"));
} }
let prop;
if (computed && memoized.has(property)) {
prop = t.cloneNode(memoized.get(property));
} else {
prop = property;
}
return t.memberExpression(object, prop, computed); return t.memberExpression(object, prop, computed);
}, },
set(superMember, value) { set(superMember, value) {
const { property, computed } = superMember.node; const { computed } = superMember.node;
const prop = this.prop(superMember);
let prop;
if (computed && memoized.has(property)) {
prop = t.assignmentExpression(
"=",
t.cloneNode(memoized.get(property)),
property,
);
} else {
prop = property;
}
return t.assignmentExpression( return t.assignmentExpression(
"=", "=",

View File

@ -967,3 +967,38 @@ helpers.applyDecoratedDescriptor = () => template.program.ast`
return desc; return desc;
} }
`; `;
helpers.classPrivateFieldLooseKey = () => template.program.ast`
var id = 0;
export default function _classPrivateFieldKey(name) {
return "__private_" + (id++) + "_" + name;
}
`;
helpers.classPrivateFieldLooseBase = () => template.program.ast`
export default function _classPrivateFieldBase(receiver, privateKey) {
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
throw new TypeError("attempted to use private field on non-instance");
}
return receiver;
}
`;
helpers.classPrivateFieldGet = () => template.program.ast`
export default function _classPrivateFieldGet(receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
}
`;
helpers.classPrivateFieldSet = () => template.program.ast`
export default function _classPrivateFieldSet(receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
}
`;

View File

@ -10,6 +10,8 @@
], ],
"dependencies": { "dependencies": {
"@babel/helper-function-name": "7.0.0-beta.47", "@babel/helper-function-name": "7.0.0-beta.47",
"@babel/helper-member-expression-to-functions": "7.0.0-beta.47",
"@babel/helper-optimise-call-expression": "7.0.0-beta.47",
"@babel/helper-plugin-utils": "7.0.0-beta.47", "@babel/helper-plugin-utils": "7.0.0-beta.47",
"@babel/helper-replace-supers": "7.0.0-beta.47", "@babel/helper-replace-supers": "7.0.0-beta.47",
"@babel/plugin-syntax-class-properties": "7.0.0-beta.47" "@babel/plugin-syntax-class-properties": "7.0.0-beta.47"

View File

@ -3,6 +3,8 @@ import nameFunction from "@babel/helper-function-name";
import syntaxClassProperties from "@babel/plugin-syntax-class-properties"; import syntaxClassProperties from "@babel/plugin-syntax-class-properties";
import { template, traverse, types as t } from "@babel/core"; import { template, traverse, types as t } from "@babel/core";
import { environmentVisitor } from "@babel/helper-replace-supers"; import { environmentVisitor } from "@babel/helper-replace-supers";
import memberExpressionToFunctions from "@babel/helper-member-expression-to-functions";
import optimiseCall from "@babel/helper-optimise-call-expression";
export default declare((api, options) => { export default declare((api, options) => {
api.assertVersion(7); api.assertVersion(7);
@ -51,36 +53,206 @@ export default declare((api, options) => {
environmentVisitor, environmentVisitor,
]); ]);
const buildClassPropertySpec = ( // Traverses the class scope, handling private name references. If an inner
ref, // class redeclares the same private name, it will hand off traversal to the
{ key, value, computed }, // restricted visitor (which doesn't traverse the inner class's inner scope).
scope, const privateNameVisitor = {
state, PrivateName(path) {
) => { const { name } = this;
const { node, parentPath } = path;
if (!parentPath.isMemberExpression({ property: node })) return;
if (node.id.name !== name) return;
this.handle(parentPath);
},
Class(path) {
const { name } = this;
const body = path.get("body.body");
for (const prop of body) {
if (!prop.isClassPrivateProperty()) continue;
if (prop.node.key.id.name !== name) continue;
// This class redeclares the private name.
// So, we can only evaluate the things in the outer scope.
path.traverse(privateNameInnerVisitor, this);
path.skip();
break;
}
},
};
// Traverses the outer portion of a class, without touching the class's inner
// scope, for private names.
const privateNameInnerVisitor = traverse.visitors.merge([
{
PrivateName: privateNameVisitor.PrivateName,
},
environmentVisitor,
]);
const privateNameHandlerSpec = {
memoise(member, count) {
const { scope } = member;
const { object } = member.node;
const memo = scope.maybeGenerateMemoised(object);
if (!memo) {
return;
}
this.memoiser.set(object, memo, count);
},
receiver(member) {
const { object } = member.node;
if (this.memoiser.has(object)) {
return t.cloneNode(this.memoiser.get(object));
}
return t.cloneNode(object);
},
get(member) {
const { map, file } = this;
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(map),
]);
},
set(member, value) {
const { map, file } = this;
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(map),
value,
]);
},
call(member, args) {
// The first access (the get) should do the memo assignment.
this.memoise(member, 1);
return optimiseCall(this.get(member), this.receiver(member), args);
},
};
const privateNameHandlerLoose = {
handle(member) {
const { prop, file } = this;
const { object } = member.node;
member.replaceWith(
template.expression`BASE(REF, PROP)[PROP]`({
BASE: file.addHelper("classPrivateFieldLooseBase"),
REF: object,
PROP: prop,
}),
);
},
};
function buildClassPropertySpec(ref, path, state) {
const { scope } = path;
const { key, value, computed } = path.node;
return t.expressionStatement( return t.expressionStatement(
t.callExpression(state.addHelper("defineProperty"), [ t.callExpression(state.addHelper("defineProperty"), [
ref, ref,
t.isIdentifier(key) && !computed ? t.stringLiteral(key.name) : key, computed || t.isLiteral(key) ? key : t.stringLiteral(key.name),
value || scope.buildUndefinedNode(), value || scope.buildUndefinedNode(),
]), ]),
); );
}; }
const buildClassPropertyLoose = (ref, { key, value, computed }, scope) => { function buildClassPropertyLoose(ref, path) {
return template.statement`MEMBER = VALUE`({ const { scope } = path;
MEMBER: t.memberExpression( const { key, value, computed } = path.node;
t.cloneNode(ref), return t.expressionStatement(
key, t.assignmentExpression(
computed || t.isLiteral(key), "=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value || scope.buildUndefinedNode(),
), ),
VALUE: value || scope.buildUndefinedNode(), );
}
function buildClassPrivatePropertySpec(ref, path, initNodes, state) {
const { parentPath, scope } = path;
const { name } = path.node.key.id;
const map = scope.generateUidIdentifier(name);
memberExpressionToFunctions(parentPath, privateNameVisitor, {
name,
map,
file: state,
...privateNameHandlerSpec,
}); });
};
initNodes.push(
template.statement`var MAP = new WeakMap();`({
MAP: map,
}),
);
// Must be late evaluated in case it references another private field.
return () =>
template.statement`MAP.set(REF, VALUE);`({
MAP: map,
REF: ref,
VALUE: path.node.value || scope.buildUndefinedNode(),
});
}
function buildClassPrivatePropertyLoose(ref, path, initNodes, state) {
const { parentPath, scope } = path;
const { name } = path.node.key.id;
const prop = scope.generateUidIdentifier(name);
parentPath.traverse(privateNameVisitor, {
name,
prop,
file: state,
...privateNameHandlerLoose,
});
initNodes.push(
template.statement`var PROP = HELPER(NAME);`({
PROP: prop,
HELPER: state.addHelper("classPrivateFieldLooseKey"),
NAME: t.stringLiteral(name),
}),
);
// Must be late evaluated in case it references another private field.
return () =>
template.statement`
Object.defineProperty(REF, PROP, {
// configurable is false by default
// enumerable is false by default
writable: true,
value: VALUE
});
`({
REF: ref,
PROP: prop,
VALUE: path.node.value || scope.buildUndefinedNode(),
});
}
const buildClassProperty = loose const buildClassProperty = loose
? buildClassPropertyLoose ? buildClassPropertyLoose
: buildClassPropertySpec; : buildClassPropertySpec;
const buildClassPrivateProperty = loose
? buildClassPrivatePropertyLoose
: buildClassPrivatePropertySpec;
return { return {
inherits: syntaxClassProperties, inherits: syntaxClassProperties,
@ -90,14 +262,35 @@ export default declare((api, options) => {
let constructor; let constructor;
const props = []; const props = [];
const computedPaths = []; const computedPaths = [];
const privateNames = new Set();
const body = path.get("body"); const body = path.get("body");
for (const path of body.get("body")) { for (const path of body.get("body")) {
if (path.node.computed) { const { computed, decorators } = path.node;
if (computed) {
computedPaths.push(path); computedPaths.push(path);
} }
if (decorators && decorators.length > 0) {
throw path.buildCodeFrameError(
"Decorators transform is necessary.",
);
}
if (path.isClassProperty()) { if (path.isClassPrivateProperty()) {
const { static: isStatic, key: { id: { name } } } = path.node;
if (isStatic) {
throw path.buildCodeFrameError(
"Static class fields are not spec'ed yet.",
);
}
if (privateNames.has(name)) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(name);
}
if (path.isProperty()) {
props.push(path); props.push(path);
} else if (path.isClassMethod({ kind: "constructor" })) { } else if (path.isClassMethod({ kind: "constructor" })) {
constructor = path; constructor = path;
@ -141,22 +334,31 @@ export default declare((api, options) => {
} }
} }
// Transform private props before publics.
const privateMaps = [];
const privateMapInits = [];
for (const prop of props) { for (const prop of props) {
const propNode = prop.node; if (prop.isPrivate()) {
if (propNode.decorators && propNode.decorators.length > 0) continue; const inits = [];
privateMapInits.push(inits);
if (propNode.static) { privateMaps.push(
staticNodes.push( buildClassPrivateProperty(t.thisExpression(), prop, inits, state),
buildClassProperty(ref, propNode, path.scope, state),
); );
}
}
let p = 0;
for (const prop of props) {
if (prop.node.static) {
staticNodes.push(buildClassProperty(t.cloneNode(ref), prop, state));
} else if (prop.isPrivate()) {
instanceBody.push(privateMaps[p]());
staticNodes.push(...privateMapInits[p]);
p++;
} else { } else {
instanceBody.push( instanceBody.push(
buildClassProperty( buildClassProperty(t.thisExpression(), prop, state),
t.thisExpression(),
propNode,
path.scope,
state,
),
); );
} }
} }
@ -220,6 +422,10 @@ export default declare((api, options) => {
path.insertBefore(computedNodes); path.insertBefore(computedNodes);
path.insertAfter(staticNodes); path.insertAfter(staticNodes);
}, },
PrivateName(path) {
throw path.buildCodeFrameError(`Unknown PrivateName "${path}"`);
},
}, },
}; };
}); });

View File

@ -0,0 +1,10 @@
class Foo {
#foo = 0;
test(other) {
this.#foo += 1;
this.#foo = 2;
other.obj.#foo += 1;
other.obj.#foo = 2;
}
}

View File

@ -0,0 +1,26 @@
var Foo =
/*#__PURE__*/
function () {
"use strict";
function Foo() {
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _foo, {
writable: true,
value: 0
});
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test(other) {
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo] += 1;
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo] = 2;
babelHelpers.classPrivateFieldLooseBase(other.obj, _foo)[_foo] += 1;
babelHelpers.classPrivateFieldLooseBase(other.obj, _foo)[_foo] = 2;
}
}]);
return Foo;
}();
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");

View File

@ -0,0 +1,15 @@
class Foo {
#foo = function() {
return this;
}
test(other) {
return [this.#foo(), other.#foo()];
}
}
const f = new Foo;
const o = new Foo;
const test = f.test(o);
expect(test[0]).toBe(f);
expect(test[1]).toBe(o);

View File

@ -0,0 +1,10 @@
class Foo {
#foo = function() {
return this;
}
test(other) {
this.#foo();
other.obj.#foo();
}
}

View File

@ -0,0 +1,27 @@
var Foo =
/*#__PURE__*/
function () {
"use strict";
function Foo() {
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _foo, {
writable: true,
value: function () {
return this;
}
});
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test(other) {
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo]();
babelHelpers.classPrivateFieldLooseBase(other.obj, _foo)[_foo]();
}
}]);
return Foo;
}();
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");

View File

@ -0,0 +1,73 @@
class Point {
#x;
#y;
constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}
get x() { return this.#x }
set x(value) { this.#x = +value }
get y() { return this.#y }
set y(value) { this.#y = +value }
equals(p) { return this.#x === p.#x && this.#y === p.#y }
toString() { return `Point<${ this.#x },${ this.#y }>` }
}
const p1 = new Point(1, 2);
const p2 = new Point(2, 3);
const p3 = new Point(1, 2);
expect(p1.x).toBe(1);
expect(p1.y).toBe(2);
expect(p2.x).toBe(2);
expect(p2.y).toBe(3);
expect(p3.x).toBe(1);
expect(p3.y).toBe(2);
expect(p1.equals(p1)).toBe(true)
expect(p1.equals(p2)).toBe(false)
expect(p1.equals(p3)).toBe(true)
expect(p2.equals(p1)).toBe(false)
expect(p2.equals(p2)).toBe(true)
expect(p2.equals(p3)).toBe(false)
expect(p3.equals(p1)).toBe(true)
expect(p3.equals(p2)).toBe(false)
expect(p3.equals(p3)).toBe(true)
expect(p1.toString()).toBe("Point<1,2>")
expect(p2.toString()).toBe("Point<2,3>")
expect(p3.toString()).toBe("Point<1,2>")
p1.x += 1;
p1.y = 3;
p2.x -= 1;
p2.y = 3;
p3.x = 0;
p3.y = 0;
expect(p1.x).toBe(2);
expect(p1.y).toBe(3);
expect(p2.x).toBe(1);
expect(p2.y).toBe(3);
expect(p3.x).toBe(0);
expect(p3.y).toBe(0);
expect(p1.equals(p1)).toBe(true)
expect(p1.equals(p2)).toBe(false)
expect(p1.equals(p3)).toBe(false)
expect(p2.equals(p1)).toBe(false)
expect(p2.equals(p2)).toBe(true)
expect(p2.equals(p3)).toBe(false)
expect(p3.equals(p1)).toBe(false)
expect(p3.equals(p2)).toBe(false)
expect(p3.equals(p3)).toBe(true)
expect(p1.toString()).toBe("Point<2,3>")
expect(p2.toString()).toBe("Point<1,3>")
expect(p3.toString()).toBe("Point<0,0>")

View File

@ -0,0 +1,20 @@
class Point {
#x;
#y;
constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}
get x() { return this.#x }
set x(value) { this.#x = +value }
get y() { return this.#y }
set y(value) { this.#y = +value }
equals(p) { return this.#x === p.#x && this.#y === p.#y }
toString() { return `Point<${ this.#x },${ this.#y }>` }
}

View File

@ -0,0 +1,3 @@
{
"minNodeVersion": "6.0.0"
}

View File

@ -0,0 +1,52 @@
var Point =
/*#__PURE__*/
function () {
"use strict";
function Point(_x2 = 0, _y2 = 0) {
babelHelpers.classCallCheck(this, Point);
Object.defineProperty(this, _x, {
writable: true,
value: void 0
});
Object.defineProperty(this, _y, {
writable: true,
value: void 0
});
babelHelpers.classPrivateFieldLooseBase(this, _x)[_x] = +_x2;
babelHelpers.classPrivateFieldLooseBase(this, _y)[_y] = +_y2;
}
babelHelpers.createClass(Point, [{
key: "equals",
value: function equals(p) {
return babelHelpers.classPrivateFieldLooseBase(this, _x)[_x] === babelHelpers.classPrivateFieldLooseBase(p, _x)[_x] && babelHelpers.classPrivateFieldLooseBase(this, _y)[_y] === babelHelpers.classPrivateFieldLooseBase(p, _y)[_y];
}
}, {
key: "toString",
value: function toString() {
return `Point<${babelHelpers.classPrivateFieldLooseBase(this, _x)[_x]},${babelHelpers.classPrivateFieldLooseBase(this, _y)[_y]}>`;
}
}, {
key: "x",
get: function () {
return babelHelpers.classPrivateFieldLooseBase(this, _x)[_x];
},
set: function (value) {
babelHelpers.classPrivateFieldLooseBase(this, _x)[_x] = +value;
}
}, {
key: "y",
get: function () {
return babelHelpers.classPrivateFieldLooseBase(this, _y)[_y];
},
set: function (value) {
babelHelpers.classPrivateFieldLooseBase(this, _y)[_y] = +value;
}
}]);
return Point;
}();
var _x = babelHelpers.classPrivateFieldLooseKey("x");
var _y = babelHelpers.classPrivateFieldLooseKey("y");

View File

@ -0,0 +1,17 @@
var foo = "bar";
class Foo {
#bar = foo;
constructor() {
var foo = "foo";
}
test() {
return this.#bar;
}
}
const f = new Foo;
expect(f.test()).toBe(foo);
expect("bar" in f).toBe(false);

View File

@ -0,0 +1,9 @@
var foo = "bar";
class Foo {
#bar = foo;
constructor() {
var foo = "foo";
}
}

View File

@ -0,0 +1,14 @@
var foo = "bar";
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _bar, {
writable: true,
value: foo
});
var _foo = "foo";
};
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,28 @@
The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being
made available under the "BSD License", included below. This Software may be subject to third party rights (rights
from parties other than Ecma International), including patent rights, and no licenses under such third party rights
are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA
CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
Copyright (C) 2012-2013 Ecma International
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
* Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports

View File

@ -0,0 +1,8 @@
class C {
y = this.#x;
#x;
}
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,8 @@
class C {
y = this.#x;
#x;
}
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,16 @@
var C = function C() {
"use strict";
babelHelpers.classCallCheck(this, C);
this.y = babelHelpers.classPrivateFieldLooseBase(this, _x)[_x];
Object.defineProperty(this, _x, {
writable: true,
value: void 0
});
};
var _x = babelHelpers.classPrivateFieldLooseKey("x");
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,11 @@
class Foo extends Bar {
#bar = "foo";
constructor() {
if (condition) {
super();
} else {
super();
}
}
}

View File

@ -0,0 +1,32 @@
var Foo =
/*#__PURE__*/
function (_Bar) {
"use strict";
function Foo() {
var _this;
babelHelpers.classCallCheck(this, Foo);
if (condition) {
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this));
Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), _bar, {
writable: true,
value: "foo"
});
} else {
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this));
Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), _bar, {
writable: true,
value: "foo"
});
}
return babelHelpers.possibleConstructorReturn(_this);
}
babelHelpers.inherits(Foo, _Bar);
return Foo;
}(Bar);
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,22 @@
class Foo {
#prop = "foo";
foo() {
return this.#prop;
}
}
class Bar extends Foo {
#prop = "bar";
bar() {
return this.#prop;
}
}
const f = new Foo;
expect(f.foo()).toBe("foo");
const b = new Bar;
expect(b.foo()).toBe("foo");
expect(b.bar()).toBe("bar");

View File

@ -0,0 +1,7 @@
class Foo {
#prop = "foo";
}
class Bar extends Foo {
#prop = "bar";
}

View File

@ -0,0 +1,32 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _prop, {
writable: true,
value: "foo"
});
};
var _prop = babelHelpers.classPrivateFieldLooseKey("prop");
var Bar =
/*#__PURE__*/
function (_Foo) {
"use strict";
function Bar(...args) {
var _temp, _this;
babelHelpers.classCallCheck(this, Bar);
return babelHelpers.possibleConstructorReturn(_this, (_temp = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Bar).call(this, ...args)), Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), _prop2, {
writable: true,
value: "bar"
}), _temp));
}
babelHelpers.inherits(Bar, _Foo);
return Bar;
}(Foo);
var _prop2 = babelHelpers.classPrivateFieldLooseKey("prop");

View File

@ -0,0 +1,9 @@
var foo = "bar";
class Foo {
#bar = this;
#baz = foo;
constructor(foo) {
}
}

View File

@ -0,0 +1,19 @@
var foo = "bar";
var Foo = function Foo(_foo) {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _bar, {
writable: true,
value: this
});
Object.defineProperty(this, _baz, {
writable: true,
value: foo
});
};
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");
var _baz = babelHelpers.classPrivateFieldLooseKey("baz");

View File

@ -0,0 +1,9 @@
class Child extends Parent {
constructor() {
super();
}
#scopedFunctionWithThis = () => {
this.name = {};
}
}

View File

@ -0,0 +1,3 @@
{
"presets": [["stage-0", { "decoratorsLegacy": true }], "es2015"]
}

View File

@ -0,0 +1,24 @@
var Child =
/*#__PURE__*/
function (_Parent) {
"use strict";
function Child() {
var _this;
babelHelpers.classCallCheck(this, Child);
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Child).call(this));
Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), _scopedFunctionWithThis, {
writable: true,
value: function value() {
_this.name = {};
}
});
return _this;
}
babelHelpers.inherits(Child, _Parent);
return Child;
}(Parent);
var _scopedFunctionWithThis = babelHelpers.classPrivateFieldLooseKey("scopedFunctionWithThis");

View File

@ -0,0 +1,9 @@
class Foo {
#bar;
test() {
return this.#bar;
}
}
expect(new Foo().test()).toBe(undefined);

View File

@ -0,0 +1,3 @@
class Foo {
#bar;
}

View File

@ -0,0 +1,11 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _bar, {
writable: true,
value: void 0
});
};
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,16 @@
class Foo {
#bar = "foo";
test() {
return this.#bar;
}
static test(foo) {
return foo.#bar;
}
}
const f = new Foo();
expect(f.test()).toBe("foo");
expect(Foo.test(f)).toBe("foo");
expect("bar" in f).toBe(false);

View File

@ -0,0 +1,3 @@
class Foo {
#bar = "foo";
}

View File

@ -0,0 +1,11 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _bar, {
writable: true,
value: "foo"
});
};
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,11 @@
class Foo {
#x = 0;
#y = this.#x + 1;
test() {
return this.#y;
}
}
const f = new Foo();
expect(f.test()).toBe(1);

View File

@ -0,0 +1,4 @@
class Foo {
#x = 0;
#y = this.#x;
}

View File

@ -0,0 +1,17 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _x, {
writable: true,
value: 0
});
Object.defineProperty(this, _y, {
writable: true,
value: babelHelpers.classPrivateFieldLooseBase(this, _x)[_x]
});
};
var _x = babelHelpers.classPrivateFieldLooseKey("x");
var _y = babelHelpers.classPrivateFieldLooseKey("y");

View File

@ -0,0 +1,18 @@
class Foo {
static #foo = "foo";
#bar = "bar";
static test() {
return Foo.#foo;
}
test() {
return this.#bar;
}
}
const f = new Foo();
expect("foo" in Foo).toBe(false)
expect("bar" in f).toBe(false)
expect(Foo.test()).toBe("foo")
expect(f.test()).toBe("bar")

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,18 @@
var _foo, _bar;
class Foo {
constructor() {
Object.defineProperty(this, _bar, {
writable: true,
value: "bar"
});
}
}
_foo = babelHelpers.classPrivateFieldKey("foo");
Object.defineProperty(Foo, _foo, {
writable: true,
value: "foo"
});
_bar = babelHelpers.classPrivateFieldKey("bar");

View File

@ -0,0 +1,11 @@
export default param =>
class App {
static #props = {
prop1: 'prop1',
prop2: 'prop2'
}
getParam() {
return param;
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,25 @@
export default (param => {
var _props, _class, _temp;
return _temp = _class =
/*#__PURE__*/
function () {
function App() {
babelHelpers.classCallCheck(this, App);
}
babelHelpers.createClass(App, [{
key: "getParam",
value: function getParam() {
return param;
}
}]);
return App;
}(), _props = babelHelpers.classPrivateFieldKey("props"), Object.defineProperty(_class, _props, {
writable: true,
value: {
prop1: 'prop1',
prop2: 'prop2'
}
}), _temp;
});

View File

@ -0,0 +1,3 @@
{
"plugins": ["external-helpers",["proposal-class-properties", { "loose": true }], "transform-classes", "transform-block-scoping", "syntax-class-properties"]
}

View File

@ -0,0 +1,8 @@
class Outer {
#outer;
constructor() {
class Test extends this.#outer {
}
}
}

View File

@ -0,0 +1,23 @@
var Outer = function Outer() {
"use strict";
babelHelpers.classCallCheck(this, Outer);
Object.defineProperty(this, _outer, {
writable: true,
value: void 0
});
var Test =
/*#__PURE__*/
function (_babelHelpers$classPr) {
function Test() {
babelHelpers.classCallCheck(this, Test);
return babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Test).apply(this, arguments));
}
babelHelpers.inherits(Test, _babelHelpers$classPr);
return Test;
}(babelHelpers.classPrivateFieldLooseBase(this, _outer)[_outer]);
};
var _outer = babelHelpers.classPrivateFieldLooseKey("outer");

View File

@ -0,0 +1,43 @@
function classFactory() {
return class Foo {
#foo = "foo";
static #bar = "bar";
instance() {
return this.#foo;
}
static() {
return Foo.#bar;
}
static instance(inst) {
return inst.#foo;
}
static static() {
return Foo.#bar;
}
}
}
const Foo1 = classFactory();
const Foo2 = classFactory();
const f1 = new Foo1;
const f2 = new Foo2;
expect(f1.instance()).toBe("foo");
expect(f1.static()).toBe("bar");
expect(f2.instance()).toBe("foo");
expect(f2.static()).toBe("bar");
expect(Foo1.instance(f1)).toBe("foo");
expect(Foo1.static()).toBe("bar");
expect(Foo2.instance(f2)).toBe("foo");
expect(Foo2.static()).toBe("bar");
assert.throws(() => f1.instance.call(f2));
assert.throws(() => f2.instance.call(f1));
assert.throws(() => Foo1.instance(f2));
assert.throws(() => Foo2.instance(f1));

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,18 @@
function classFactory() {
var _bar, _foo;
var Foo = function Foo() {
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _foo, {
writable: true,
value: "foo"
});
};
_bar = babelHelpers.classPrivateFieldKey("bar");
Object.defineProperty(Foo, _bar, {
writable: true,
value: "bar"
});
_foo = babelHelpers.classPrivateFieldKey("foo");
}

View File

@ -0,0 +1,7 @@
class Foo {
one = this.#private;
#two = this.#private;
#private = 0;
three = this.#private;
#four = this.#private;
}

View File

@ -0,0 +1,25 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
this.one = babelHelpers.classPrivateFieldLooseBase(this, _private)[_private];
Object.defineProperty(this, _two, {
writable: true,
value: babelHelpers.classPrivateFieldLooseBase(this, _private)[_private]
});
Object.defineProperty(this, _private, {
writable: true,
value: 0
});
this.three = babelHelpers.classPrivateFieldLooseBase(this, _private)[_private];
Object.defineProperty(this, _four, {
writable: true,
value: babelHelpers.classPrivateFieldLooseBase(this, _private)[_private]
});
};
var _two = babelHelpers.classPrivateFieldLooseKey("two");
var _private = babelHelpers.classPrivateFieldLooseKey("private");
var _four = babelHelpers.classPrivateFieldLooseKey("four");

View File

@ -0,0 +1,7 @@
export class MyClass {
static #property = value;
}
export default class MyClass2 {
static #property = value;
}

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,21 @@
var _property, _property2;
export var MyClass = function MyClass() {
babelHelpers.classCallCheck(this, MyClass);
};
_property = babelHelpers.classPrivateFieldKey("property");
Object.defineProperty(MyClass, _property, {
writable: true,
value: value
});
var MyClass2 = function MyClass2() {
babelHelpers.classCallCheck(this, MyClass2);
};
_property2 = babelHelpers.classPrivateFieldKey("property");
Object.defineProperty(MyClass2, _property2, {
writable: true,
value: value
});
export { MyClass2 as default };

View File

@ -0,0 +1,3 @@
var Foo = class {
static #num = 0;
}

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,8 @@
var _num, _class, _temp;
var Foo = (_temp = _class = function Foo() {
babelHelpers.classCallCheck(this, Foo);
}, _num = babelHelpers.classPrivateFieldKey("num"), Object.defineProperty(_class, _num, {
writable: true,
value: 0
}), _temp);

View File

@ -0,0 +1,70 @@
class Base {
static #foo = 1;
static getThis() {
return this.#foo;
}
static updateThis(val) {
return this.#foo = val;
}
static getClass() {
return Base.#foo;
}
static updateClass(val) {
return Base.#foo = val;
}
}
class Sub1 extends Base {
static #foo = 2;
static update(val) {
return this.#foo = val;
}
}
class Sub2 extends Base {
}
expect(Base.getThis()).toBe(1);
expect(Base.getClass()).toBe(1);
assert.throws(() => Sub1.getThis());
expect(Sub1.getClass()).toBe(1);
assert.throws(() => Sub2.getThis());
expect(Sub2.getClass()).toBe(1);
expect(Sub1.update(3)).toBe(3);
expect(Base.getThis()).toBe(1);
expect(Base.getClass()).toBe(1);
assert.throws(() => Sub1.getThis());
expect(Sub1.getClass()).toBe(1);
assert.throws(() => Sub2.getThis());
expect(Sub2.getClass()).toBe(1);
expect(Base.updateThis(4)).toBe(4);
expect(Base.getThis()).toBe(4);
expect(Base.getClass()).toBe(4);
assert.throws(() => Sub1.getThis());
expect(Sub1.getClass()).toBe(4);
assert.throws(() => Sub2.getThis());
expect(Sub2.getClass()).toBe(4);
expect(Base.updateClass(5)).toBe(5);
expect(Base.getThis()).toBe(5);
expect(Base.getClass()).toBe(5);
assert.throws(() => Sub1.getThis());
expect(Sub1.getClass()).toBe(5);
assert.throws(() => Sub2.getThis());
expect(Sub2.getClass()).toBe(5);
assert.throws(() => Sub2.updateThis(6));
expect(Sub2.updateClass(7)).toBe(7);
expect(Base.getThis()).toBe(7);
expect(Base.getClass()).toBe(7);
assert.throws(() => Sub1.getThis());
expect(Sub1.getClass()).toBe(7);
assert.throws(() => Sub2.getThis());
expect(Sub2.getClass()).toBe(7);

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,55 @@
var _foo, _foo2;
var Base =
/*#__PURE__*/
function () {
function Base() {
babelHelpers.classCallCheck(this, Base);
}
babelHelpers.createClass(Base, null, [{
key: "m",
value: function m() {
return babelHelpers.classPrivateFieldBase(this, _foo)[_foo];
}
}]);
return Base;
}();
_foo = babelHelpers.classPrivateFieldKey("foo");
Object.defineProperty(Base, _foo, {
writable: true,
value: 1
});
var Sub1 =
/*#__PURE__*/
function (_Base) {
babelHelpers.inherits(Sub1, _Base);
function Sub1() {
babelHelpers.classCallCheck(this, Sub1);
return babelHelpers.possibleConstructorReturn(this, (Sub1.__proto__ || Object.getPrototypeOf(Sub1)).apply(this, arguments));
}
return Sub1;
}(Base);
_foo2 = babelHelpers.classPrivateFieldKey("foo");
Object.defineProperty(Sub1, _foo2, {
writable: true,
value: 2
});
var Sub2 =
/*#__PURE__*/
function (_Base2) {
babelHelpers.inherits(Sub2, _Base2);
function Sub2() {
babelHelpers.classCallCheck(this, Sub2);
return babelHelpers.possibleConstructorReturn(this, (Sub2.__proto__ || Object.getPrototypeOf(Sub2)).apply(this, arguments));
}
return Sub2;
}(Base);

View File

@ -0,0 +1,15 @@
class Foo {
static #bar;
static test() {
return Foo.#bar;
}
test() {
return Foo.#bar;
}
}
expect("bar" in Foo).toBe(false)
expect(Foo.test()).toBe(undefined)
expect(Foo.test()).toBe(undefined)

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,11 @@
var _bar;
var Foo = function Foo() {
babelHelpers.classCallCheck(this, Foo);
};
_bar = babelHelpers.classPrivateFieldKey("bar");
Object.defineProperty(Foo, _bar, {
writable: true,
value: void 0
});

View File

@ -0,0 +1,15 @@
class Foo {
static #bar = "foo";
static test() {
return Foo.#bar;
}
test() {
return Foo.#bar;
}
}
expect("bar" in Foo).toBe(false)
expect(Foo.test()).toBe("foo")
expect(Foo.test()).toBe("foo")

View File

@ -0,0 +1,3 @@
{
"throws": "Static class fields are not spec'ed yet."
}

View File

@ -0,0 +1,28 @@
var _bar;
var Foo =
/*#__PURE__*/
function () {
function Foo() {
babelHelpers.classCallCheck(this, Foo);
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test() {
return babelHelpers.classPrivateFieldBase(Foo, _bar)[_bar];
}
}], [{
key: "test",
value: function test() {
return babelHelpers.classPrivateFieldBase(Foo, _bar)[_bar];
}
}]);
return Foo;
}();
_bar = babelHelpers.classPrivateFieldKey("bar");
Object.defineProperty(Foo, _bar, {
writable: true,
value: "foo"
});

View File

@ -0,0 +1,7 @@
class Foo extends Bar {
#bar = "foo";
constructor() {
foo(super());
}
}

View File

@ -0,0 +1,21 @@
var Foo =
/*#__PURE__*/
function (_Bar) {
"use strict";
function Foo() {
var _temp, _this;
babelHelpers.classCallCheck(this, Foo);
foo((_temp = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this)), Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), _bar, {
writable: true,
value: "foo"
}), _temp));
return _this;
}
babelHelpers.inherits(Foo, _Bar);
return Foo;
}(Bar);
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,7 @@
class Foo extends Bar {
#bar = "foo";
constructor() {
super();
}
}

View File

@ -0,0 +1,22 @@
var Foo =
/*#__PURE__*/
function (_Bar) {
"use strict";
function Foo() {
var _this;
babelHelpers.classCallCheck(this, Foo);
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this));
Object.defineProperty(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), _bar, {
writable: true,
value: "foo"
});
return _this;
}
babelHelpers.inherits(Foo, _Bar);
return Foo;
}(Bar);
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");

View File

@ -0,0 +1,27 @@
class Foo {
#foo = 0;
test(other) {
return [
this.#foo++,
this.#foo,
++this.#foo,
this.#foo,
other.obj.#foo++,
other.obj.#foo,
++other.obj.#foo,
other.obj.#foo,
];
}
}
const f = new Foo;
const results = f.test({ obj: f });
expect(results[0]).toBe(0);
expect(results[1]).toBe(1);
expect(results[2]).toBe(2);
expect(results[3]).toBe(2);
expect(results[4]).toBe(2);
expect(results[5]).toBe(3);
expect(results[6]).toBe(4);
expect(results[7]).toBe(4);

View File

@ -0,0 +1,10 @@
class Foo {
#foo = 0;
test(other) {
this.#foo++;
++this.#foo;
other.obj.#foo++;
++other.obj.#foo;
}
}

View File

@ -0,0 +1,26 @@
var Foo =
/*#__PURE__*/
function () {
"use strict";
function Foo() {
babelHelpers.classCallCheck(this, Foo);
Object.defineProperty(this, _foo, {
writable: true,
value: 0
});
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test(other) {
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo]++;
++babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
babelHelpers.classPrivateFieldLooseBase(other.obj, _foo)[_foo]++;
++babelHelpers.classPrivateFieldLooseBase(other.obj, _foo)[_foo];
}
}]);
return Foo;
}();
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");

View File

@ -0,0 +1,10 @@
class Foo {
#foo = 0;
test(other) {
this.#foo += 1;
this.#foo = 2;
other.obj.#foo += 1;
other.obj.#foo = 2;
}
}

View File

@ -0,0 +1,26 @@
var Foo =
/*#__PURE__*/
function () {
"use strict";
function Foo() {
babelHelpers.classCallCheck(this, Foo);
_foo.set(this, 0);
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test(other) {
var _other$obj;
babelHelpers.classPrivateFieldSet(this, _foo, babelHelpers.classPrivateFieldGet(this, _foo) + 1);
babelHelpers.classPrivateFieldSet(this, _foo, 2);
babelHelpers.classPrivateFieldSet(_other$obj = other.obj, _foo, babelHelpers.classPrivateFieldGet(_other$obj, _foo) + 1);
babelHelpers.classPrivateFieldSet(other.obj, _foo, 2);
}
}]);
return Foo;
}();
var _foo = new WeakMap();

View File

@ -0,0 +1,15 @@
class Foo {
#foo = function() {
return this;
}
test(other) {
return [this.#foo(), other.#foo()];
}
}
const f = new Foo;
const o = new Foo;
const test = f.test(o);
expect(test[0]).toBe(f);
expect(test[1]).toBe(o);

View File

@ -0,0 +1,10 @@
class Foo {
#foo = function() {
return this;
}
test(other) {
this.#foo();
other.obj.#foo();
}
}

View File

@ -0,0 +1,26 @@
var Foo =
/*#__PURE__*/
function () {
"use strict";
function Foo() {
babelHelpers.classCallCheck(this, Foo);
_foo.set(this, function () {
return this;
});
}
babelHelpers.createClass(Foo, [{
key: "test",
value: function test(other) {
var _other$obj;
babelHelpers.classPrivateFieldGet(this, _foo).call(this);
babelHelpers.classPrivateFieldGet(_other$obj = other.obj, _foo).call(_other$obj);
}
}]);
return Foo;
}();
var _foo = new WeakMap();

View File

@ -0,0 +1,73 @@
class Point {
#x;
#y;
constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}
get x() { return this.#x }
set x(value) { this.#x = +value }
get y() { return this.#y }
set y(value) { this.#y = +value }
equals(p) { return this.#x === p.#x && this.#y === p.#y }
toString() { return `Point<${ this.#x },${ this.#y }>` }
}
const p1 = new Point(1, 2);
const p2 = new Point(2, 3);
const p3 = new Point(1, 2);
expect(p1.x).toBe(1);
expect(p1.y).toBe(2);
expect(p2.x).toBe(2);
expect(p2.y).toBe(3);
expect(p3.x).toBe(1);
expect(p3.y).toBe(2);
expect(p1.equals(p1)).toBe(true)
expect(p1.equals(p2)).toBe(false)
expect(p1.equals(p3)).toBe(true)
expect(p2.equals(p1)).toBe(false)
expect(p2.equals(p2)).toBe(true)
expect(p2.equals(p3)).toBe(false)
expect(p3.equals(p1)).toBe(true)
expect(p3.equals(p2)).toBe(false)
expect(p3.equals(p3)).toBe(true)
expect(p1.toString()).toBe("Point<1,2>")
expect(p2.toString()).toBe("Point<2,3>")
expect(p3.toString()).toBe("Point<1,2>")
p1.x += 1;
p1.y = 3;
p2.x -= 1;
p2.y = 3;
p3.x = 0;
p3.y = 0;
expect(p1.x).toBe(2);
expect(p1.y).toBe(3);
expect(p2.x).toBe(1);
expect(p2.y).toBe(3);
expect(p3.x).toBe(0);
expect(p3.y).toBe(0);
expect(p1.equals(p1)).toBe(true)
expect(p1.equals(p2)).toBe(false)
expect(p1.equals(p3)).toBe(false)
expect(p2.equals(p1)).toBe(false)
expect(p2.equals(p2)).toBe(true)
expect(p2.equals(p3)).toBe(false)
expect(p3.equals(p1)).toBe(false)
expect(p3.equals(p2)).toBe(false)
expect(p3.equals(p3)).toBe(true)
expect(p1.toString()).toBe("Point<2,3>")
expect(p2.toString()).toBe("Point<1,3>")
expect(p3.toString()).toBe("Point<0,0>")

View File

@ -0,0 +1,20 @@
class Point {
#x;
#y;
constructor(x = 0, y = 0) {
this.#x = +x;
this.#y = +y;
}
get x() { return this.#x }
set x(value) { this.#x = +value }
get y() { return this.#y }
set y(value) { this.#y = +value }
equals(p) { return this.#x === p.#x && this.#y === p.#y }
toString() { return `Point<${ this.#x },${ this.#y }>` }
}

View File

@ -0,0 +1,3 @@
{
"minNodeVersion": "6.0.0"
}

View File

@ -0,0 +1,49 @@
var Point =
/*#__PURE__*/
function () {
"use strict";
function Point(_x2 = 0, _y2 = 0) {
babelHelpers.classCallCheck(this, Point);
_x.set(this, void 0);
_y.set(this, void 0);
babelHelpers.classPrivateFieldSet(this, _x, +_x2);
babelHelpers.classPrivateFieldSet(this, _y, +_y2);
}
babelHelpers.createClass(Point, [{
key: "equals",
value: function equals(p) {
return babelHelpers.classPrivateFieldGet(this, _x) === babelHelpers.classPrivateFieldGet(p, _x) && babelHelpers.classPrivateFieldGet(this, _y) === babelHelpers.classPrivateFieldGet(p, _y);
}
}, {
key: "toString",
value: function toString() {
return `Point<${babelHelpers.classPrivateFieldGet(this, _x)},${babelHelpers.classPrivateFieldGet(this, _y)}>`;
}
}, {
key: "x",
get: function () {
return babelHelpers.classPrivateFieldGet(this, _x);
},
set: function (value) {
babelHelpers.classPrivateFieldSet(this, _x, +value);
}
}, {
key: "y",
get: function () {
return babelHelpers.classPrivateFieldGet(this, _y);
},
set: function (value) {
babelHelpers.classPrivateFieldSet(this, _y, +value);
}
}]);
return Point;
}();
var _x = new WeakMap();
var _y = new WeakMap();

View File

@ -0,0 +1,17 @@
var foo = "bar";
class Foo {
#bar = foo;
constructor() {
var foo = "foo";
}
test() {
return this.#bar;
}
}
const f = new Foo;
expect(f.test()).toBe(foo);
expect("bar" in f).toBe(false);

View File

@ -0,0 +1,9 @@
var foo = "bar";
class Foo {
#bar = foo;
constructor() {
var foo = "foo";
}
}

View File

@ -0,0 +1,13 @@
var foo = "bar";
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
_bar.set(this, foo);
var _foo = "foo";
};
var _bar = new WeakMap();

View File

@ -0,0 +1,28 @@
The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being
made available under the "BSD License", included below. This Software may be subject to third party rights (rights
from parties other than Ecma International), including patent rights, and no licenses under such third party rights
are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA
CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
Copyright (C) 2012-2013 Ecma International
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
* Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports

View File

@ -0,0 +1,8 @@
class C {
y = this.#x;
#x;
}
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,8 @@
class C {
y = this.#x;
#x;
}
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,14 @@
var C = function C() {
"use strict";
babelHelpers.classCallCheck(this, C);
babelHelpers.defineProperty(this, "y", babelHelpers.classPrivateFieldGet(this, _x));
_x.set(this, void 0);
};
var _x = new WeakMap();
expect(() => {
new C();
}).toThrow();

View File

@ -0,0 +1,11 @@
class Foo extends Bar {
#bar = "foo";
constructor() {
if (condition) {
super();
} else {
super();
}
}
}

View File

@ -0,0 +1,28 @@
var Foo =
/*#__PURE__*/
function (_Bar) {
"use strict";
function Foo() {
var _this;
babelHelpers.classCallCheck(this, Foo);
if (condition) {
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this));
_bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), "foo");
} else {
_this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Foo).call(this));
_bar.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this))), "foo");
}
return babelHelpers.possibleConstructorReturn(_this);
}
babelHelpers.inherits(Foo, _Bar);
return Foo;
}(Bar);
var _bar = new WeakMap();

View File

@ -0,0 +1,22 @@
class Foo {
#prop = "foo";
foo() {
return this.#prop;
}
}
class Bar extends Foo {
#prop = "bar";
bar() {
return this.#prop;
}
}
const f = new Foo;
expect(f.foo()).toBe("foo");
const b = new Bar;
expect(b.foo()).toBe("foo");
expect(b.bar()).toBe("bar");

View File

@ -0,0 +1,7 @@
class Foo {
#prop = "foo";
}
class Bar extends Foo {
#prop = "bar";
}

View File

@ -0,0 +1,27 @@
var Foo = function Foo() {
"use strict";
babelHelpers.classCallCheck(this, Foo);
_prop.set(this, "foo");
};
var _prop = new WeakMap();
var Bar =
/*#__PURE__*/
function (_Foo) {
"use strict";
function Bar(...args) {
var _temp, _this;
babelHelpers.classCallCheck(this, Bar);
return babelHelpers.possibleConstructorReturn(_this, (_temp = _this = babelHelpers.possibleConstructorReturn(this, babelHelpers.getPrototypeOf(Bar).call(this, ...args)), _prop2.set(babelHelpers.assertThisInitialized(babelHelpers.assertThisInitialized(_this)), "bar"), _temp));
}
babelHelpers.inherits(Bar, _Foo);
return Bar;
}(Foo);
var _prop2 = new WeakMap();

View File

@ -0,0 +1,9 @@
var foo = "bar";
class Foo {
#bar = this;
#baz = foo;
constructor(foo) {
}
}

View File

@ -0,0 +1,15 @@
var foo = "bar";
var Foo = function Foo(_foo) {
"use strict";
babelHelpers.classCallCheck(this, Foo);
_bar.set(this, this);
_baz.set(this, foo);
};
var _bar = new WeakMap();
var _baz = new WeakMap();

Some files were not shown because too many files have changed in this diff Show More