Private Class Methods Stage 3: Private Accessors (#9101)

* Add accessor loose support

* Add private accessors spec support

* Fix private dupe name check

* Changes from code review

* Add duplicated names tests

* Add get/set-only tests

* Move accessors tests

* Split out updates tests

* Add helper change tests

* Update test output

* Update test options
This commit is contained in:
Tim McClure 2019-01-21 16:05:37 -05:00 committed by Nicolò Ribaudo
parent 3ae5e79ec8
commit e8de6fa5d4
53 changed files with 1171 additions and 57 deletions

View File

@ -72,12 +72,6 @@ export function verifyUsedFeatures(path, file) {
"@babel/plugin-class-features doesn't support class static private methods yet.", "@babel/plugin-class-features doesn't support class static private methods yet.",
); );
} }
if (path.node.kind !== "method") {
throw path.buildCodeFrameError(
"@babel/plugin-class-features doesn't support class private accessors yet.",
);
}
} }
if ( if (

View File

@ -6,16 +6,26 @@ import optimiseCall from "@babel/helper-optimise-call-expression";
export function buildPrivateNamesMap(props) { export function buildPrivateNamesMap(props) {
const privateNamesMap = new Map(); const privateNamesMap = new Map();
for (const prop of props) { for (const prop of props) {
if (prop.isPrivate()) { const isPrivate = prop.isPrivate();
const isMethod = !prop.isProperty();
const isInstance = !prop.node.static;
if (isPrivate) {
const { name } = prop.node.key.id; const { name } = prop.node.key.id;
privateNamesMap.set(name, { const update = privateNamesMap.has(name)
id: prop.scope.generateUidIdentifier(name), ? privateNamesMap.get(name)
static: !!prop.node.static, : {
method: prop.isMethod(), id: prop.scope.generateUidIdentifier(name),
methodId: prop.isMethod() static: !isInstance,
? prop.scope.generateUidIdentifier(name) method: isMethod,
: undefined, };
}); if (prop.node.kind === "get") {
update.getId = prop.scope.generateUidIdentifier(`get_${name}`);
} else if (prop.node.kind === "set") {
update.setId = prop.scope.generateUidIdentifier(`set_${name}`);
} else if (prop.node.kind === "method" && isMethod && isInstance) {
update.methodId = prop.scope.generateUidIdentifier(name);
}
privateNamesMap.set(name, update);
} }
} }
return privateNamesMap; return privateNamesMap;
@ -31,7 +41,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
// In spec mode, only instance fields need a "private name" initializer // In spec mode, only instance fields need a "private name" initializer
// because static fields are directly assigned to a variable in the // because static fields are directly assigned to a variable in the
// buildPrivateStaticFieldInitSpec function. // buildPrivateStaticFieldInitSpec function.
const { id, static: isStatic, method: isMethod } = value; const { id, static: isStatic, method: isMethod, getId, setId } = value;
if (loose) { if (loose) {
initNodes.push( initNodes.push(
template.statement.ast` template.statement.ast`
@ -39,7 +49,11 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
`, `,
); );
} else if (isMethod && !isStatic) { } else if (isMethod && !isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`); if (getId || setId) {
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
} else {
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`);
}
} else if (!isStatic) { } else if (!isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`); initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
} }
@ -121,6 +135,8 @@ const privateNameHandlerSpec = {
static: isStatic, static: isStatic,
method: isMethod, method: isMethod,
methodId, methodId,
getId,
setId,
} = privateNamesMap.get(name); } = privateNamesMap.get(name);
if (isStatic && !isMethod) { if (isStatic && !isMethod) {
@ -128,41 +144,57 @@ const privateNameHandlerSpec = {
file.addHelper("classStaticPrivateFieldSpecGet"), file.addHelper("classStaticPrivateFieldSpecGet"),
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)], [this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
); );
} else if (isMethod) { }
if (isMethod) {
if (getId || setId) {
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
}
return t.callExpression(file.addHelper("classPrivateMethodGet"), [ return t.callExpression(file.addHelper("classPrivateMethodGet"), [
this.receiver(member), this.receiver(member),
t.cloneNode(id), t.cloneNode(id),
t.cloneNode(methodId), t.cloneNode(methodId),
]); ]);
} else {
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
} }
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
}, },
set(member, value) { set(member, value) {
const { classRef, privateNamesMap, file } = this; const { classRef, privateNamesMap, file } = this;
const { name } = member.node.property.id; const { name } = member.node.property.id;
const { id, static: isStatic, method: isMethod } = privateNamesMap.get( const {
name, id,
); static: isStatic,
method: isMethod,
setId,
} = privateNamesMap.get(name);
if (isStatic && !isMethod) { if (isStatic && !isMethod) {
return t.callExpression( return t.callExpression(
file.addHelper("classStaticPrivateFieldSpecSet"), file.addHelper("classStaticPrivateFieldSpecSet"),
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value], [this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value],
); );
} else if (isMethod) {
return t.callExpression(file.addHelper("classPrivateMethodSet"), []);
} else {
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
} }
if (isMethod) {
if (setId) {
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
}
return t.callExpression(file.addHelper("classPrivateMethodSet"), []);
}
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
}, },
call(member, args) { call(member, args) {
@ -255,21 +287,91 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
} }
function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) { function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
const { methodId, id } = privateNamesMap.get(prop.node.key.id.name); const privateName = privateNamesMap.get(prop.node.key.id.name);
const { methodId, id, getId, setId, initAdded } = privateName;
if (initAdded) return;
return template.statement.ast` if (methodId) {
Object.defineProperty(${ref}, ${id}, { return template.statement.ast`
// configurable is false by default Object.defineProperty(${ref}, ${id}, {
// enumerable is false by default // configurable is false by default
// writable is false by default // enumerable is false by default
value: ${methodId.name} // writable is false by default
value: ${methodId.name}
});
`;
}
if (getId || setId) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
initAdded: true,
}); });
`;
if (getId && setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId.name},
set: ${setId.name}
});
`;
} else if (getId && !setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId.name}
});
`;
} else if (!getId && setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
set: ${setId.name}
});
`;
}
}
} }
function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) { function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name); const privateName = privateNamesMap.get(prop.node.key.id.name);
const { id, getId, setId, initAdded } = privateName;
if (initAdded) return;
if (getId || setId) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
initAdded: true,
});
if (getId && setId) {
return template.statement.ast`
${id}.set(${ref}, {
get: ${getId.name},
set: ${setId.name}
});
`;
} else if (getId && !setId) {
return template.statement.ast`
${id}.set(${ref}, {
get: ${getId.name}
});
`;
} else if (!getId && setId) {
return template.statement.ast`
${id}.set(${ref}, {
set: ${setId.name}
});
`;
}
}
return template.statement.ast`${id}.add(${ref})`; return template.statement.ast`${id}.add(${ref})`;
} }
@ -300,9 +402,37 @@ function buildPublicFieldInitSpec(ref, prop, state) {
} }
function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) { function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) {
const { methodId } = privateNamesMap.get(prop.node.key.id.name); const privateName = privateNamesMap.get(prop.node.key.id.name);
const {
methodId,
getId,
setId,
getterDeclared,
setterDeclared,
} = privateName;
const { params, body } = prop.node; const { params, body } = prop.node;
const methodValue = t.functionExpression(methodId, params, body); const methodValue = t.functionExpression(methodId, params, body);
const isGetter = getId && !getterDeclared && params.length === 0;
const isSetter = setId && !setterDeclared && params.length > 0;
if (isGetter) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
getterDeclared: true,
});
return t.variableDeclaration("var", [
t.variableDeclarator(getId, methodValue),
]);
}
if (isSetter) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
setterDeclared: true,
});
return t.variableDeclaration("var", [
t.variableDeclarator(setId, methodValue),
]);
}
return t.variableDeclaration("var", [ return t.variableDeclaration("var", [
t.variableDeclarator(methodId, methodValue), t.variableDeclarator(methodId, methodValue),
@ -404,7 +534,7 @@ export function buildFieldsInitNodes(
return { return {
staticNodes, staticNodes,
instanceNodes, instanceNodes: instanceNodes.filter(Boolean),
wrapClass(path) { wrapClass(path) {
for (const prop of props) { for (const prop of props) {
prop.remove(); prop.remove();

View File

@ -75,11 +75,39 @@ export function createClassFeaturePlugin({
if (path.isPrivate()) { if (path.isPrivate()) {
const { name } = path.node.key.id; const { name } = path.node.key.id;
const getName = `get ${name}`;
const setName = `set ${name}`;
if (privateNames.has(name)) { if (path.node.kind === "get") {
throw path.buildCodeFrameError("Duplicate private field"); if (
privateNames.has(getName) ||
(privateNames.has(name) && !privateNames.has(setName))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(getName).add(name);
} else if (path.node.kind === "set") {
if (
privateNames.has(setName) ||
(privateNames.has(name) && !privateNames.has(getName))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(setName).add(name);
} else {
if (
(privateNames.has(name) &&
(!privateNames.has(getName) && !privateNames.has(setName))) ||
(privateNames.has(name) &&
(privateNames.has(getName) || privateNames.has(setName)))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(name);
} }
privateNames.add(name);
} }
if (path.isClassMethod({ kind: "constructor" })) { if (path.isClassMethod({ kind: "constructor" })) {

View File

@ -1052,7 +1052,11 @@ helpers.classPrivateFieldGet = helper("7.0.0-beta.0")`
if (!privateMap.has(receiver)) { if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance"); throw new TypeError("attempted to get private field on non-instance");
} }
return privateMap.get(receiver).value; var descriptor = privateMap.get(receiver);
if (descriptor.get) {
return descriptor.get.call(receiver);
}
return descriptor.value;
} }
`; `;
@ -1062,13 +1066,19 @@ helpers.classPrivateFieldSet = helper("7.0.0-beta.0")`
throw new TypeError("attempted to set private field on non-instance"); throw new TypeError("attempted to set private field on non-instance");
} }
var descriptor = privateMap.get(receiver); var descriptor = privateMap.get(receiver);
if (!descriptor.writable) { if (descriptor.set) {
// This should only throw in strict mode, but class bodies are descriptor.set.call(receiver, value);
// always strict and private fields can only be used inside } else {
// class bodies. if (!descriptor.writable) {
throw new TypeError("attempted to set read only private field"); // This should only throw in strict mode, but class bodies are
// always strict and private fields can only be used inside
// class bodies.
throw new TypeError("attempted to set read only private field");
}
descriptor.value = value;
} }
descriptor.value = value;
return value; return value;
} }
`; `;

View File

@ -0,0 +1,31 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
}
const cl = new Cl();
expect(cl.publicGetPrivateField()).toEqual("top secret string");
cl.publicSetPrivateField("new secret string");
expect(cl.publicGetPrivateField()).toEqual("new secret string");

View File

@ -0,0 +1,23 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
}

View File

@ -0,0 +1,43 @@
var Cl =
/*#__PURE__*/
function () {
"use strict";
function Cl() {
babelHelpers.classCallCheck(this, Cl);
Object.defineProperty(this, _privateFieldValue, {
get: _get_privateFieldValue,
set: _set_privateFieldValue
});
Object.defineProperty(this, _privateField, {
writable: true,
value: "top secret string"
});
this.publicField = "not secret string";
}
babelHelpers.createClass(Cl, [{
key: "publicGetPrivateField",
value: function publicGetPrivateField() {
return babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue];
}
}, {
key: "publicSetPrivateField",
value: function publicSetPrivateField(newValue) {
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue;
}
}]);
return Cl;
}();
var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField");
var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue");
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField];
};
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue;
};

View File

@ -0,0 +1,13 @@
class Cl {
#privateField = 0;
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
constructor() {
expect(this.#privateFieldValue).toBeUndefined();
}
}
const cl = new Cl();

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
constructor() {
this.publicField = this.#privateFieldValue;
}
}

View File

@ -0,0 +1,21 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
Object.defineProperty(this, _privateFieldValue, {
set: _set_privateFieldValue
});
Object.defineProperty(this, _privateField, {
writable: true,
value: 0
});
this.publicField = babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue];
};
var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField");
var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue");
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue;
};

View File

@ -0,0 +1,11 @@
let foo;
class Cl {
set #foo(v) { return 1 }
test() {
foo = this.#foo = 2;
}
}
new Cl().test();
expect(foo).toBe(2);

View File

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

View File

@ -0,0 +1,13 @@
class Cl {
#privateField = 0;
get #privateFieldValue() {
return this.#privateField;
}
constructor() {
expect(() => this.#privateFieldValue = 1).toThrow(TypeError);
}
}
const cl = new Cl();

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
get #privateFieldValue() {
return this.#privateField;
}
constructor() {
this.#privateFieldValue = 1;
}
}

View File

@ -0,0 +1,21 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
Object.defineProperty(this, _privateFieldValue, {
get: _get_privateFieldValue
});
Object.defineProperty(this, _privateField, {
writable: true,
value: 0
});
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = 1;
};
var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField");
var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue");
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField];
};

View File

@ -0,0 +1,50 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
get publicFieldValue() {
return this.publicField;
}
set publicFieldValue(newValue) {
this.publicField = newValue;
}
testUpdates() {
this.#privateField = 0;
this.publicField = 0;
this.#privateFieldValue = this.#privateFieldValue++;
this.publicFieldValue = this.publicFieldValue++;
expect(this.#privateField).toEqual(this.publicField);
++this.#privateFieldValue;
++this.publicFieldValue;
expect(this.#privateField).toEqual(this.publicField);
this.#privateFieldValue += 1;
this.publicFieldValue += 1;
expect(this.#privateField).toEqual(this.publicField);
}
}
const cl = new Cl();
cl.testUpdates();

View File

@ -0,0 +1,47 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
get publicFieldValue() {
return this.publicField;
}
set publicFieldValue(newValue) {
this.publicField = newValue;
}
testUpdates() {
this.#privateField = 0;
this.publicField = 0;
this.#privateFieldValue = this.#privateFieldValue++;
this.publicFieldValue = this.publicFieldValue++;
++this.#privateFieldValue;
++this.publicFieldValue;
this.#privateFieldValue += 1;
this.publicFieldValue += 1;
this.#privateFieldValue = -(this.#privateFieldValue ** this.#privateFieldValue);
this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue);
}
}

View File

@ -0,0 +1,65 @@
var Cl =
/*#__PURE__*/
function () {
"use strict";
function Cl() {
babelHelpers.classCallCheck(this, Cl);
Object.defineProperty(this, _privateFieldValue, {
get: _get_privateFieldValue,
set: _set_privateFieldValue
});
Object.defineProperty(this, _privateField, {
writable: true,
value: "top secret string"
});
this.publicField = "not secret string";
}
babelHelpers.createClass(Cl, [{
key: "publicGetPrivateField",
value: function publicGetPrivateField() {
return babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue];
}
}, {
key: "publicSetPrivateField",
value: function publicSetPrivateField(newValue) {
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue;
}
}, {
key: "testUpdates",
value: function testUpdates() {
babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = 0;
this.publicField = 0;
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]++;
this.publicFieldValue = this.publicFieldValue++;
++babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue];
++this.publicFieldValue;
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] += 1;
this.publicFieldValue += 1;
babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = -(babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] ** babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]);
this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue);
}
}, {
key: "publicFieldValue",
get: function () {
return this.publicField;
},
set: function (newValue) {
this.publicField = newValue;
}
}]);
return Cl;
}();
var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField");
var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue");
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField];
};
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue;
};

View File

@ -0,0 +1,31 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
}
const cl = new Cl();
expect(cl.publicGetPrivateField()).toEqual("top secret string");
cl.publicSetPrivateField("new secret string");
expect(cl.publicGetPrivateField()).toEqual("new secret string");

View File

@ -0,0 +1,23 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
}

View File

@ -0,0 +1,46 @@
var Cl =
/*#__PURE__*/
function () {
"use strict";
function Cl() {
babelHelpers.classCallCheck(this, Cl);
_privateFieldValue.set(this, {
get: _get_privateFieldValue,
set: _set_privateFieldValue
});
_privateField.set(this, {
writable: true,
value: "top secret string"
});
this.publicField = "not secret string";
}
babelHelpers.createClass(Cl, [{
key: "publicGetPrivateField",
value: function publicGetPrivateField() {
return babelHelpers.classPrivateFieldGet(this, _privateFieldValue);
}
}, {
key: "publicSetPrivateField",
value: function publicSetPrivateField(newValue) {
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, newValue);
}
}]);
return Cl;
}();
var _privateField = new WeakMap();
var _privateFieldValue = new WeakMap();
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldGet(this, _privateField);
};
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldSet(this, _privateField, newValue);
};

View File

@ -0,0 +1,13 @@
class Cl {
#privateField = 0;
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
constructor() {
expect(this.#privateFieldValue).toBeUndefined();
}
}
const cl = new Cl();

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
constructor() {
this.publicField = this.#privateFieldValue;
}
}

View File

@ -0,0 +1,24 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
_privateFieldValue.set(this, {
set: _set_privateFieldValue
});
_privateField.set(this, {
writable: true,
value: 0
});
this.publicField = babelHelpers.classPrivateFieldGet(this, _privateFieldValue);
};
var _privateField = new WeakMap();
var _privateFieldValue = new WeakMap();
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldSet(this, _privateField, newValue);
};

View File

@ -0,0 +1,11 @@
let foo;
class Cl {
set #foo(v) { return 1 }
test() {
foo = this.#foo = 2;
}
}
new Cl().test();
expect(foo).toBe(2);

View File

@ -0,0 +1,15 @@
{
"plugins": [
[
"external-helpers",
{
"helperVersion": "7.1000.0"
}
],
"proposal-private-methods",
"proposal-class-properties",
"transform-classes",
"transform-block-scoping",
"syntax-class-properties"
]
}

View File

@ -0,0 +1,13 @@
class Cl {
#privateField = 0;
get #privateFieldValue() {
return this.#privateField;
}
constructor() {
expect(() => this.#privateFieldValue = 1).toThrow(TypeError);
}
}
const cl = new Cl();

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
get #privateFieldValue() {
return this.#privateField;
}
constructor() {
this.#privateFieldValue = 1;
}
}

View File

@ -0,0 +1,24 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
_privateFieldValue.set(this, {
get: _get_privateFieldValue
});
_privateField.set(this, {
writable: true,
value: 0
});
babelHelpers.classPrivateMethodSet();
};
var _privateField = new WeakMap();
var _privateFieldValue = new WeakMap();
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldGet(this, _privateField);
};

View File

@ -0,0 +1,50 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
get publicFieldValue() {
return this.publicField;
}
set publicFieldValue(newValue) {
this.publicField = newValue;
}
testUpdates() {
this.#privateField = 0;
this.publicField = 0;
this.#privateFieldValue = this.#privateFieldValue++;
this.publicFieldValue = this.publicFieldValue++;
expect(this.#privateField).toEqual(this.publicField);
++this.#privateFieldValue;
++this.publicFieldValue;
expect(this.#privateField).toEqual(this.publicField);
this.#privateFieldValue += 1;
this.publicFieldValue += 1;
expect(this.#privateField).toEqual(this.publicField);
}
}
const cl = new Cl();
cl.testUpdates();

View File

@ -0,0 +1,47 @@
class Cl {
#privateField = "top secret string";
constructor() {
this.publicField = "not secret string";
}
get #privateFieldValue() {
return this.#privateField;
}
set #privateFieldValue(newValue) {
this.#privateField = newValue;
}
publicGetPrivateField() {
return this.#privateFieldValue;
}
publicSetPrivateField(newValue) {
this.#privateFieldValue = newValue;
}
get publicFieldValue() {
return this.publicField;
}
set publicFieldValue(newValue) {
this.publicField = newValue;
}
testUpdates() {
this.#privateField = 0;
this.publicField = 0;
this.#privateFieldValue = this.#privateFieldValue++;
this.publicFieldValue = this.publicFieldValue++;
++this.#privateFieldValue;
++this.publicFieldValue;
this.#privateFieldValue += 1;
this.publicFieldValue += 1;
this.#privateFieldValue = -(this.#privateFieldValue ** this.#privateFieldValue);
this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue);
}
}

View File

@ -0,0 +1,70 @@
var Cl =
/*#__PURE__*/
function () {
"use strict";
function Cl() {
babelHelpers.classCallCheck(this, Cl);
_privateFieldValue.set(this, {
get: _get_privateFieldValue,
set: _set_privateFieldValue
});
_privateField.set(this, {
writable: true,
value: "top secret string"
});
this.publicField = "not secret string";
}
babelHelpers.createClass(Cl, [{
key: "publicGetPrivateField",
value: function publicGetPrivateField() {
return babelHelpers.classPrivateFieldGet(this, _privateFieldValue);
}
}, {
key: "publicSetPrivateField",
value: function publicSetPrivateField(newValue) {
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, newValue);
}
}, {
key: "testUpdates",
value: function testUpdates() {
var _this$privateFieldVal, _this$privateFieldVal2;
babelHelpers.classPrivateFieldSet(this, _privateField, 0);
this.publicField = 0;
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, (babelHelpers.classPrivateFieldSet(this, _privateFieldValue, (_this$privateFieldVal2 = +babelHelpers.classPrivateFieldGet(this, _privateFieldValue)) + 1), _this$privateFieldVal2));
this.publicFieldValue = this.publicFieldValue++;
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, +babelHelpers.classPrivateFieldGet(this, _privateFieldValue) + 1);
++this.publicFieldValue;
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, babelHelpers.classPrivateFieldGet(this, _privateFieldValue) + 1);
this.publicFieldValue += 1;
babelHelpers.classPrivateFieldSet(this, _privateFieldValue, -(babelHelpers.classPrivateFieldGet(this, _privateFieldValue) ** babelHelpers.classPrivateFieldGet(this, _privateFieldValue)));
this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue);
}
}, {
key: "publicFieldValue",
get: function () {
return this.publicField;
},
set: function (newValue) {
this.publicField = newValue;
}
}]);
return Cl;
}();
var _privateField = new WeakMap();
var _privateFieldValue = new WeakMap();
var _get_privateFieldValue = function () {
return babelHelpers.classPrivateFieldGet(this, _privateField);
};
var _set_privateFieldValue = function (newValue) {
babelHelpers.classPrivateFieldSet(this, _privateField, newValue);
};

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
get #getSet() {
return this.#privateField;
}
get #getSet() {
return this.#privateField;
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
get #foo() {
return this.#privateField;
}
#foo() {
return 'foo';
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
get #getSet() {
return this.#privateField;
}
set #getSet(newValue) {
this.#privateField = newValue;
}
}

View File

@ -0,0 +1,27 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
_getSet.set(this, {
get: _get_getSet,
set: _set_getSet
});
_privateField.set(this, {
writable: true,
value: 0
});
};
var _privateField = new WeakMap();
var _getSet = new WeakMap();
var _get_getSet = function () {
return babelHelpers.classPrivateFieldGet(this, _privateField);
};
var _set_getSet = function (newValue) {
babelHelpers.classPrivateFieldSet(this, _privateField, newValue);
};

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
#foo() {
return 'foo';
}
get #foo() {
return this.#privateField;
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,10 @@
class Cl {
#dank() {
return 'foo';
}
#dank() {
return 'foo';
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
#foo() {
return 'foo';
}
set #foo(newValue) {
this.#privateField = newValue;
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,15 @@
{
"plugins": [
[
"external-helpers",
{
"helperVersion": "7.1000.0"
}
],
"proposal-private-methods",
"proposal-class-properties",
"transform-classes",
"transform-block-scoping",
"syntax-class-properties"
]
}

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
set #getSet(newValue) {
this.#privateField = newValue;
}
get #getSet() {
return this.#privateField;
}
}

View File

@ -0,0 +1,27 @@
var Cl = function Cl() {
"use strict";
babelHelpers.classCallCheck(this, Cl);
_getSet.set(this, {
get: _get_getSet,
set: _set_getSet
});
_privateField.set(this, {
writable: true,
value: 0
});
};
var _privateField = new WeakMap();
var _getSet = new WeakMap();
var _set_getSet = function (newValue) {
babelHelpers.classPrivateFieldSet(this, _privateField, newValue);
};
var _get_getSet = function () {
return babelHelpers.classPrivateFieldGet(this, _privateField);
};

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
set #foo(newValue) {
this.#privateField = newValue;
}
#foo() {
return 'foo';
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -0,0 +1,11 @@
class Cl {
#privateField = 0;
set #getSet(newValue) {
return this.#privateField;
}
set #getSet(newValue) {
return this.#privateField;
}
}

View File

@ -0,0 +1,3 @@
{
"throws": "Duplicate private field"
}

View File

@ -3,7 +3,7 @@
[ [
"external-helpers", "external-helpers",
{ {
"helperVersion": "7.1.6" "helperVersion": "7.1000.0"
} }
], ],
["proposal-private-methods", { "loose": true }], ["proposal-private-methods", { "loose": true }],

View File

@ -3,7 +3,7 @@
[ [
"external-helpers", "external-helpers",
{ {
"helperVersion": "7.1.6" "helperVersion": "7.1000.0"
} }
], ],
"proposal-private-methods", "proposal-private-methods",