Skip to content

Commit a6ca39c

Browse files
authored
Handle logical assignment in super property transforms (#14164)
1 parent e7c705a commit a6ca39c

File tree

2 files changed

+223
-22
lines changed

2 files changed

+223
-22
lines changed

packages/babel-traverse/src/path/conversion.ts

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
identifier,
1212
isIdentifier,
1313
jsxIdentifier,
14+
logicalExpression,
15+
LOGICAL_OPERATORS,
1416
memberExpression,
1517
metaProperty,
1618
numericLiteral,
@@ -397,63 +399,96 @@ function hoistFunctionEnvironment(
397399
return { thisBinding, fnPath };
398400
}
399401

400-
function standardizeSuperProperty(superProp) {
402+
type LogicalOp = Parameters<typeof logicalExpression>[0];
403+
type BinaryOp = Parameters<typeof binaryExpression>[0];
404+
405+
function isLogicalOp(op: string): op is LogicalOp {
406+
return LOGICAL_OPERATORS.includes(op);
407+
}
408+
409+
function standardizeSuperProperty(superProp: NodePath<t.MemberExpression>) {
401410
if (
402411
superProp.parentPath.isAssignmentExpression() &&
403412
superProp.parentPath.node.operator !== "="
404413
) {
405414
const assignmentPath = superProp.parentPath;
406415

407-
const op = assignmentPath.node.operator.slice(0, -1);
416+
const op = assignmentPath.node.operator.slice(0, -1) as
417+
| LogicalOp
418+
| BinaryOp;
419+
408420
const value = assignmentPath.node.right;
409421

410-
assignmentPath.node.operator = "=";
422+
const isLogicalAssignment = isLogicalOp(op);
423+
411424
if (superProp.node.computed) {
425+
// from: super[foo] **= 4;
426+
// to: super[tmp = foo] = super[tmp] ** 4;
427+
428+
// from: super[foo] ??= 4;
429+
// to: super[tmp = foo] ?? super[tmp] = 4;
430+
412431
const tmp = superProp.scope.generateDeclaredUidIdentifier("tmp");
413432

433+
const object = superProp.node.object;
434+
const property = superProp.node.property as t.Expression;
435+
414436
assignmentPath
415437
.get("left")
416438
.replaceWith(
417439
memberExpression(
418-
superProp.node.object,
419-
assignmentExpression("=", tmp, superProp.node.property),
440+
object,
441+
assignmentExpression("=", tmp, property),
420442
true /* computed */,
421443
),
422444
);
423445

424446
assignmentPath
425447
.get("right")
426448
.replaceWith(
427-
binaryExpression(
428-
op,
429-
memberExpression(
430-
superProp.node.object,
431-
identifier(tmp.name),
432-
true /* computed */,
433-
),
449+
rightExpression(
450+
isLogicalAssignment ? "=" : op,
451+
memberExpression(object, identifier(tmp.name), true /* computed */),
434452
value,
435453
),
436454
);
437455
} else {
456+
// from: super.foo **= 4;
457+
// to: super.foo = super.foo ** 4;
458+
459+
// from: super.foo ??= 4;
460+
// to: super.foo ?? super.foo = 4;
461+
462+
const object = superProp.node.object;
463+
const property = superProp.node.property as t.Identifier;
464+
438465
assignmentPath
439466
.get("left")
440-
.replaceWith(
441-
memberExpression(superProp.node.object, superProp.node.property),
442-
);
467+
.replaceWith(memberExpression(object, property));
443468

444469
assignmentPath
445470
.get("right")
446471
.replaceWith(
447-
binaryExpression(
448-
op,
449-
memberExpression(
450-
superProp.node.object,
451-
identifier(superProp.node.property.name),
452-
),
472+
rightExpression(
473+
isLogicalAssignment ? "=" : op,
474+
memberExpression(object, identifier(property.name)),
453475
value,
454476
),
455477
);
456478
}
479+
480+
if (isLogicalAssignment) {
481+
assignmentPath.replaceWith(
482+
logicalExpression(
483+
op,
484+
assignmentPath.node.left as t.Expression,
485+
assignmentPath.node.right as t.Expression,
486+
),
487+
);
488+
} else {
489+
assignmentPath.node.operator = "=";
490+
}
491+
457492
return [
458493
assignmentPath.get("left"),
459494
assignmentPath.get("right").get("left"),
@@ -473,7 +508,11 @@ function standardizeSuperProperty(superProp) {
473508
memberExpression(
474509
superProp.node.object,
475510
computedKey
476-
? assignmentExpression("=", computedKey, superProp.node.property)
511+
? assignmentExpression(
512+
"=",
513+
computedKey,
514+
superProp.node.property as t.Expression,
515+
)
477516
: superProp.node.property,
478517
superProp.node.computed,
479518
),
@@ -506,6 +545,18 @@ function standardizeSuperProperty(superProp) {
506545
}
507546

508547
return [superProp];
548+
549+
function rightExpression(
550+
op: BinaryOp | "=",
551+
left: t.MemberExpression,
552+
right: t.Expression,
553+
) {
554+
if (op === "=") {
555+
return assignmentExpression("=", left, right);
556+
} else {
557+
return binaryExpression(op, left, right);
558+
}
559+
}
509560
}
510561

511562
function hasSuperClass(thisEnvFn) {

packages/babel-traverse/test/arrow-transform.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,156 @@ describe("arrow function conversion", () => {
518518
);
519519
});
520520

521+
it("should convert super.prop operator logical assign `??=`", () => {
522+
assertConversion(
523+
`
524+
() => {
525+
super.foo ??= 4;
526+
};
527+
super.foo ??= 4;
528+
() => super.foo ??= 4;
529+
`,
530+
`
531+
var _superprop_getFoo = () => super.foo,
532+
_superprop_setFoo = _value => super.foo = _value;
533+
534+
(function () {
535+
_superprop_getFoo() ?? _superprop_setFoo(4);
536+
});
537+
538+
super.foo ??= 4;
539+
540+
() => super.foo ??= 4;
541+
`,
542+
);
543+
});
544+
545+
it("should convert super.prop operator logical assign `&&=`", () => {
546+
assertConversion(
547+
`
548+
() => {
549+
super.foo &&= true;
550+
};
551+
super.foo &&= true;
552+
() => super.foo &&= true;
553+
`,
554+
`
555+
var _superprop_getFoo = () => super.foo,
556+
_superprop_setFoo = _value => super.foo = _value;
557+
558+
(function () {
559+
_superprop_getFoo() && _superprop_setFoo(true);
560+
});
561+
562+
super.foo &&= true;
563+
564+
() => super.foo &&= true;
565+
`,
566+
);
567+
});
568+
569+
it("should convert super.prop operator logical assign `||=`", () => {
570+
assertConversion(
571+
`
572+
() => {
573+
super.foo ||= true;
574+
};
575+
super.foo ||= true;
576+
() => super.foo ||= true;
577+
`,
578+
`
579+
var _superprop_getFoo = () => super.foo,
580+
_superprop_setFoo = _value => super.foo = _value;
581+
582+
(function () {
583+
_superprop_getFoo() || _superprop_setFoo(true);
584+
});
585+
586+
super.foo ||= true;
587+
588+
() => super.foo ||= true;
589+
`,
590+
);
591+
});
592+
593+
it("should convert super[prop] operator logical assign `??=`", () => {
594+
assertConversion(
595+
`
596+
() => {
597+
super[foo] ??= 4;
598+
};
599+
super[foo] ??= 4;
600+
() => super[foo] ??= 4;
601+
`,
602+
`
603+
var _superprop_get = _prop => super[_prop],
604+
_superprop_set = (_prop2, _value) => super[_prop2] = _value;
605+
606+
(function () {
607+
var _tmp;
608+
609+
_superprop_get(_tmp = foo) ?? _superprop_set(_tmp, 4);
610+
});
611+
612+
super[foo] ??= 4;
613+
614+
() => super[foo] ??= 4;
615+
`,
616+
);
617+
});
618+
619+
it("should convert super[prop] operator logical assign `&&=`", () => {
620+
assertConversion(
621+
`
622+
() => {
623+
super[foo] &&= true;
624+
};
625+
super[foo] &&= true;
626+
() => super[foo] &&= true;
627+
`,
628+
`
629+
var _superprop_get = _prop => super[_prop],
630+
_superprop_set = (_prop2, _value) => super[_prop2] = _value;
631+
632+
(function () {
633+
var _tmp;
634+
635+
_superprop_get(_tmp = foo) && _superprop_set(_tmp, true);
636+
});
637+
638+
super[foo] &&= true;
639+
640+
() => super[foo] &&= true;
641+
`,
642+
);
643+
});
644+
645+
it("should convert super[prop] operator logical assign `||=`", () => {
646+
assertConversion(
647+
`
648+
() => {
649+
super[foo] ||= true;
650+
};
651+
super[foo] ||= true;
652+
() => super[foo] ||= true;
653+
`,
654+
`
655+
var _superprop_get = _prop => super[_prop],
656+
_superprop_set = (_prop2, _value) => super[_prop2] = _value;
657+
658+
(function () {
659+
var _tmp;
660+
661+
_superprop_get(_tmp = foo) || _superprop_set(_tmp, true);
662+
});
663+
664+
super[foo] ||= true;
665+
666+
() => super[foo] ||= true;
667+
`,
668+
);
669+
});
670+
521671
it("should convert `++super.prop` prefix update", () => {
522672
assertConversion(
523673
`

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy