Skip to content

Commit fdfe978

Browse files
komygnicolo-ribaudojridgewell
authored
Disallow reinitializing private elements (#13601)
Co-authored-by: Nicolò Ribaudo <[email protected]> Co-authored-by: Justin Ridgewell <[email protected]>
1 parent cb3ebde commit fdfe978

92 files changed

Lines changed: 451 additions & 229 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/babel-helper-create-class-features-plugin/src/fields.ts

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -540,16 +540,31 @@ function buildPrivateInstanceFieldInitSpec(
540540
ref: t.Expression,
541541
prop: NodePath<t.ClassPrivateProperty>,
542542
privateNamesMap: PrivateNamesMap,
543+
state,
543544
) {
544545
const { id } = privateNamesMap.get(prop.node.key.id.name);
545546
const value = prop.node.value || prop.scope.buildUndefinedNode();
546547

547-
return template.statement.ast`${t.cloneNode(id)}.set(${ref}, {
548-
// configurable is always false for private elements
549-
// enumerable is always false for private elements
550-
writable: true,
551-
value: ${value},
552-
})`;
548+
if (!process.env.BABEL_8_BREAKING) {
549+
if (!state.availableHelper("classPrivateFieldInitSpec")) {
550+
return template.statement.ast`${t.cloneNode(id)}.set(${ref}, {
551+
// configurable is always false for private elements
552+
// enumerable is always false for private elements
553+
writable: true,
554+
value: ${value},
555+
})`;
556+
}
557+
}
558+
559+
const helper = state.addHelper("classPrivateFieldInitSpec");
560+
return template.statement.ast`${helper}(
561+
${t.thisExpression()},
562+
${t.cloneNode(id)},
563+
{
564+
writable: true,
565+
value: ${value}
566+
},
567+
)`;
553568
}
554569

555570
function buildPrivateStaticFieldInitSpec(
@@ -632,27 +647,87 @@ function buildPrivateInstanceMethodInitSpec(
632647
ref: t.Expression,
633648
prop: NodePath<t.ClassPrivateMethod>,
634649
privateNamesMap: PrivateNamesMap,
650+
state,
635651
) {
636652
const privateName = privateNamesMap.get(prop.node.key.id.name);
637-
const { id, getId, setId, initAdded } = privateName;
653+
const { getId, setId, initAdded } = privateName;
638654

639655
if (initAdded) return;
640656

641657
const isAccessor = getId || setId;
642658
if (isAccessor) {
643-
privateNamesMap.set(prop.node.key.id.name, {
644-
...privateName,
645-
initAdded: true,
646-
});
659+
return buildPrivateAccessorInitialization(
660+
ref,
661+
prop,
662+
privateNamesMap,
663+
state,
664+
);
665+
}
647666

648-
return template.statement.ast`
667+
return buildPrivateInstanceMethodInitalization(
668+
ref,
669+
prop,
670+
privateNamesMap,
671+
state,
672+
);
673+
}
674+
675+
function buildPrivateAccessorInitialization(
676+
ref: t.Expression,
677+
prop: NodePath<t.ClassPrivateMethod>,
678+
privateNamesMap: PrivateNamesMap,
679+
state,
680+
) {
681+
const privateName = privateNamesMap.get(prop.node.key.id.name);
682+
const { id, getId, setId } = privateName;
683+
684+
privateNamesMap.set(prop.node.key.id.name, {
685+
...privateName,
686+
initAdded: true,
687+
});
688+
689+
if (!process.env.BABEL_8_BREAKING) {
690+
if (!state.availableHelper("classPrivateFieldInitSpec")) {
691+
return template.statement.ast`
649692
${id}.set(${ref}, {
650693
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
651694
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
652695
});
653696
`;
697+
}
698+
}
699+
700+
const helper = state.addHelper("classPrivateFieldInitSpec");
701+
return template.statement.ast`${helper}(
702+
${t.thisExpression()},
703+
${t.cloneNode(id)},
704+
{
705+
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
706+
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
707+
},
708+
)`;
709+
}
710+
711+
function buildPrivateInstanceMethodInitalization(
712+
ref: t.Expression,
713+
prop: NodePath<t.ClassPrivateMethod>,
714+
privateNamesMap: PrivateNamesMap,
715+
state,
716+
) {
717+
const privateName = privateNamesMap.get(prop.node.key.id.name);
718+
const { id } = privateName;
719+
720+
if (!process.env.BABEL_8_BREAKING) {
721+
if (!state.availableHelper("classPrivateMethodInitSpec")) {
722+
return template.statement.ast`${id}.add(${ref})`;
723+
}
654724
}
655-
return template.statement.ast`${id}.add(${ref})`;
725+
726+
const helper = state.addHelper("classPrivateMethodInitSpec");
727+
return template.statement.ast`${helper}(
728+
${t.thisExpression()},
729+
${t.cloneNode(id)}
730+
)`;
656731
}
657732

658733
function buildPublicFieldInitLoose(
@@ -957,6 +1032,7 @@ export function buildFieldsInitNodes(
9571032
// @ts-expect-error checked in switch
9581033
prop,
9591034
privateNamesMap,
1035+
state,
9601036
),
9611037
);
9621038
break;
@@ -985,6 +1061,7 @@ export function buildFieldsInitNodes(
9851061
// @ts-expect-error checked in switch
9861062
prop,
9871063
privateNamesMap,
1064+
state,
9881065
),
9891066
);
9901067
pureStaticNodes.push(
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
}
6+
7+
class Derived extends Base {
8+
get #foo() {
9+
return 'bar';
10+
}
11+
12+
set #foo(value) {
13+
this.#foo = value;
14+
}
15+
16+
static get(obj) {
17+
return obj.#foo();
18+
}
19+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": [["env", { "shippedProposals": true }]],
3+
"targets": {
4+
"chrome": "75"
5+
}
6+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
6+
}
7+
8+
var _foo = /*#__PURE__*/new WeakMap();
9+
10+
class Derived extends Base {
11+
constructor(...args) {
12+
super(...args);
13+
babelHelpers.classPrivateFieldInitSpec(this, _foo, {
14+
get: _get_foo,
15+
set: _set_foo
16+
});
17+
}
18+
19+
static get(obj) {
20+
return babelHelpers.classPrivateFieldGet(obj, _foo).call(obj);
21+
}
22+
23+
}
24+
25+
function _get_foo() {
26+
return 'bar';
27+
}
28+
29+
function _set_foo(value) {
30+
babelHelpers.classPrivateFieldSet(this, _foo, value);
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
}
6+
7+
let counter = 0;
8+
class Derived extends Base {
9+
#foo = ++counter;
10+
static get(obj) {
11+
return obj.#foo;
12+
}
13+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": [["env", { "shippedProposals": true }]],
3+
"targets": {
4+
"chrome": "75"
5+
}
6+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
6+
}
7+
8+
let counter = 0;
9+
10+
var _foo = /*#__PURE__*/new WeakMap();
11+
12+
class Derived extends Base {
13+
constructor(...args) {
14+
super(...args);
15+
babelHelpers.classPrivateFieldInitSpec(this, _foo, {
16+
writable: true,
17+
value: ++counter
18+
});
19+
}
20+
21+
static get(obj) {
22+
return babelHelpers.classPrivateFieldGet(obj, _foo);
23+
}
24+
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
}
6+
7+
class Derived extends Base {
8+
#foo() {
9+
return 'bar';
10+
}
11+
12+
static get(obj) {
13+
return obj.#foo();
14+
}
15+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": [["env", { "shippedProposals": true }]],
3+
"targets": {
4+
"chrome": "75"
5+
}
6+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class Base {
2+
constructor(obj) {
3+
return obj;
4+
}
5+
6+
}
7+
8+
var _foo = /*#__PURE__*/new WeakSet();
9+
10+
class Derived extends Base {
11+
constructor(...args) {
12+
super(...args);
13+
babelHelpers.classPrivateMethodInitSpec(this, _foo);
14+
}
15+
16+
static get(obj) {
17+
return babelHelpers.classPrivateMethodGet(obj, _foo, _foo2).call(obj);
18+
}
19+
20+
}
21+
22+
function _foo2() {
23+
return 'bar';
24+
}

0 commit comments

Comments
 (0)