optimize optional chain when expression will be cast to boolean (#12291)
This commit is contained in:
parent
e7e0c25d6a
commit
a44151acef
26
Gulpfile.js
26
Gulpfile.js
@ -102,7 +102,13 @@ const babelVersion =
|
|||||||
function buildRollup(packages) {
|
function buildRollup(packages) {
|
||||||
const sourcemap = process.env.NODE_ENV === "production";
|
const sourcemap = process.env.NODE_ENV === "production";
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
packages.map(async ({ src, format, dest, name, filename, version }) => {
|
packages.map(async ({ src, format, dest, name, filename }) => {
|
||||||
|
const pkgJSON = require("./" + src + "/package.json");
|
||||||
|
const version = pkgJSON.version + versionSuffix;
|
||||||
|
const { dependencies = {}, peerDependencies = {} } = pkgJSON;
|
||||||
|
const external = Object.keys(dependencies).concat(
|
||||||
|
Object.keys(peerDependencies)
|
||||||
|
);
|
||||||
let nodeResolveBrowser = false,
|
let nodeResolveBrowser = false,
|
||||||
babelEnvName = "rollup";
|
babelEnvName = "rollup";
|
||||||
switch (src) {
|
switch (src) {
|
||||||
@ -115,6 +121,7 @@ function buildRollup(packages) {
|
|||||||
fancyLog(`Compiling '${chalk.cyan(input)}' with rollup ...`);
|
fancyLog(`Compiling '${chalk.cyan(input)}' with rollup ...`);
|
||||||
const bundle = await rollup.rollup({
|
const bundle = await rollup.rollup({
|
||||||
input,
|
input,
|
||||||
|
external,
|
||||||
plugins: [
|
plugins: [
|
||||||
rollupBabelSource(),
|
rollupBabelSource(),
|
||||||
rollupReplace({
|
rollupReplace({
|
||||||
@ -161,6 +168,7 @@ function buildRollup(packages) {
|
|||||||
format,
|
format,
|
||||||
name,
|
name,
|
||||||
sourcemap: sourcemap,
|
sourcemap: sourcemap,
|
||||||
|
exports: "named",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!process.env.IS_PUBLISH) {
|
if (!process.env.IS_PUBLISH) {
|
||||||
@ -180,6 +188,7 @@ function buildRollup(packages) {
|
|||||||
format,
|
format,
|
||||||
name,
|
name,
|
||||||
sourcemap: sourcemap,
|
sourcemap: sourcemap,
|
||||||
|
exports: "named",
|
||||||
plugins: [
|
plugins: [
|
||||||
rollupTerser({
|
rollupTerser({
|
||||||
// workaround https://bugs.webkit.org/show_bug.cgi?id=212725
|
// workaround https://bugs.webkit.org/show_bug.cgi?id=212725
|
||||||
@ -194,13 +203,14 @@ function buildRollup(packages) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const libBundles = [
|
const libBundles = [
|
||||||
{
|
"packages/babel-parser",
|
||||||
src: "packages/babel-parser",
|
"packages/babel-plugin-proposal-optional-chaining",
|
||||||
format: "cjs",
|
"packages/babel-helper-member-expression-to-functions",
|
||||||
dest: "lib",
|
].map(src => ({
|
||||||
version: require("./packages/babel-parser/package").version + versionSuffix,
|
src,
|
||||||
},
|
format: "cjs",
|
||||||
];
|
dest: "lib",
|
||||||
|
}));
|
||||||
|
|
||||||
const standaloneBundle = [
|
const standaloneBundle = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import * as t from "@babel/types";
|
import * as t from "@babel/types";
|
||||||
|
import { willPathCastToBoolean } from "./util.js";
|
||||||
|
|
||||||
class AssignmentMemoiser {
|
class AssignmentMemoiser {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -129,6 +130,8 @@ const handle = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const willEndPathCastToBoolean = willPathCastToBoolean(endPath);
|
||||||
|
|
||||||
const rootParentPath = endPath.parentPath;
|
const rootParentPath = endPath.parentPath;
|
||||||
if (
|
if (
|
||||||
rootParentPath.isUpdateExpression({ argument: node }) ||
|
rootParentPath.isUpdateExpression({ argument: node }) ||
|
||||||
@ -238,33 +241,60 @@ const handle = {
|
|||||||
regular = endParentPath.node;
|
regular = endParentPath.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
replacementPath.replaceWith(
|
if (willEndPathCastToBoolean) {
|
||||||
t.conditionalExpression(
|
const nonNullishCheck = t.logicalExpression(
|
||||||
t.logicalExpression(
|
"&&",
|
||||||
"||",
|
t.binaryExpression(
|
||||||
t.binaryExpression(
|
"!==",
|
||||||
"===",
|
baseNeedsMemoised
|
||||||
baseNeedsMemoised
|
? t.assignmentExpression(
|
||||||
? t.assignmentExpression(
|
"=",
|
||||||
"=",
|
t.cloneNode(baseRef),
|
||||||
t.cloneNode(baseRef),
|
t.cloneNode(startingNode),
|
||||||
t.cloneNode(startingNode),
|
)
|
||||||
)
|
: t.cloneNode(baseRef),
|
||||||
: t.cloneNode(baseRef),
|
t.nullLiteral(),
|
||||||
t.nullLiteral(),
|
|
||||||
),
|
|
||||||
t.binaryExpression(
|
|
||||||
"===",
|
|
||||||
t.cloneNode(baseRef),
|
|
||||||
scope.buildUndefinedNode(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
isDeleteOperation
|
t.binaryExpression(
|
||||||
? t.booleanLiteral(true)
|
"!==",
|
||||||
: scope.buildUndefinedNode(),
|
t.cloneNode(baseRef),
|
||||||
regular,
|
scope.buildUndefinedNode(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
replacementPath.replaceWith(
|
||||||
|
t.logicalExpression("&&", nonNullishCheck, regular),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// todo: respect assumptions.noDocumentAll when assumptions are implemented
|
||||||
|
const nullishCheck = t.logicalExpression(
|
||||||
|
"||",
|
||||||
|
t.binaryExpression(
|
||||||
|
"===",
|
||||||
|
baseNeedsMemoised
|
||||||
|
? t.assignmentExpression(
|
||||||
|
"=",
|
||||||
|
t.cloneNode(baseRef),
|
||||||
|
t.cloneNode(startingNode),
|
||||||
|
)
|
||||||
|
: t.cloneNode(baseRef),
|
||||||
|
t.nullLiteral(),
|
||||||
|
),
|
||||||
|
t.binaryExpression(
|
||||||
|
"===",
|
||||||
|
t.cloneNode(baseRef),
|
||||||
|
scope.buildUndefinedNode(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
replacementPath.replaceWith(
|
||||||
|
t.conditionalExpression(
|
||||||
|
nullishCheck,
|
||||||
|
isDeleteOperation
|
||||||
|
? t.booleanLiteral(true)
|
||||||
|
: scope.buildUndefinedNode(),
|
||||||
|
regular,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// context and isDeleteOperation can not be both truthy
|
// context and isDeleteOperation can not be both truthy
|
||||||
if (context) {
|
if (context) {
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Test if a NodePath will be cast to boolean when evaluated.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // returns true
|
||||||
|
* const nodePathAQDotB = NodePath("if (a?.#b) {}").get("test"); // a?.#b
|
||||||
|
* willPathCastToBoolean(nodePathAQDotB)
|
||||||
|
* @example
|
||||||
|
* // returns false
|
||||||
|
* willPathCastToBoolean(NodePath("a?.#b"))
|
||||||
|
* @todo Respect transparent expression wrappers
|
||||||
|
* @see {@link packages/babel-plugin-proposal-optional-chaining/src/util.js}
|
||||||
|
* @param {NodePath} path
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function willPathCastToBoolean(path: NodePath): boolean {
|
||||||
|
const maybeWrapped = path;
|
||||||
|
const { node, parentPath } = maybeWrapped;
|
||||||
|
if (parentPath.isLogicalExpression()) {
|
||||||
|
const { operator, right } = parentPath.node;
|
||||||
|
if (
|
||||||
|
operator === "&&" ||
|
||||||
|
operator === "||" ||
|
||||||
|
(operator === "??" && node === right)
|
||||||
|
) {
|
||||||
|
return willPathCastToBoolean(parentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parentPath.isSequenceExpression()) {
|
||||||
|
const { expressions } = parentPath.node;
|
||||||
|
if (expressions[expressions.length - 1] === node) {
|
||||||
|
return willPathCastToBoolean(parentPath);
|
||||||
|
} else {
|
||||||
|
// if it is in the middle of a sequence expression, we don't
|
||||||
|
// care the return value so just cast to boolean for smaller
|
||||||
|
// output
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
parentPath.isConditional({ test: node }) ||
|
||||||
|
parentPath.isUnaryExpression({ operator: "!" }) ||
|
||||||
|
parentPath.isLoop({ test: node })
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
class C {
|
||||||
|
static #a = {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.#a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.#a.b.c.d) {
|
||||||
|
for (; o?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.#a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.#a.b.c.d) {
|
||||||
|
for (; o.obj?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.#a.b?.c.d && o?.#a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.#a.b?.c.d && o?.#a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) {
|
||||||
|
return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.#a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static test() {
|
||||||
|
const c = C;
|
||||||
|
expect(C.testIf(c)).toBe(true);
|
||||||
|
expect(C.testConditional(c)).toBe(true);
|
||||||
|
expect(C.testLoop(c)).toBe(true);
|
||||||
|
expect(C.testNegate(c)).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testConditionalDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testLoopDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testNegateDeep({ obj: c })).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(c)).toBe(true);
|
||||||
|
expect(C.testLogicalInReturn(c)).toBe(2);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(c)).toBe(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullish() {
|
||||||
|
for (const n of [null, undefined]) {
|
||||||
|
expect(C.testIf(n)).toBe(false);
|
||||||
|
expect(C.testConditional(n)).toBe(false);
|
||||||
|
expect(C.testLoop(n)).toBe(false);
|
||||||
|
expect(C.testNegate(n)).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testConditionalDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testLoopDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testNegateDeep({ obj: n })).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(n)).toBe(false);
|
||||||
|
expect(C.testLogicalInReturn(n)).toBe(undefined);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(n)).toBe(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
class C {
|
||||||
|
static #a = {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.#a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.#a.b.c.d) {
|
||||||
|
for (; o?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.#a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.#a.b.c.d) {
|
||||||
|
for (; o.obj?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.#a.b?.c.d && o?.#a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.#a.b?.c.d && o?.#a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) {
|
||||||
|
return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.#a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["external-helpers", { "helperVersion": "7.100.0" }], ["proposal-class-properties", {"loose": true }]],
|
||||||
|
"minNodeVersion": "14.0.0"
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
var _a = babelHelpers.classPrivateFieldLooseKey("a");
|
||||||
|
|
||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o !== null && o !== void 0 && babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditional(o) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o !== null && o !== void 0 && babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b.c.d) {
|
||||||
|
for (; (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b.c)?.d;) {
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while ((o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!(o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testIfDeep(o) {
|
||||||
|
var _o$obj;
|
||||||
|
|
||||||
|
if (((_o$obj = o.obj) === null || _o$obj === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(_o$obj, _a)[_a].b)?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
var _o$obj2;
|
||||||
|
|
||||||
|
return ((_o$obj2 = o.obj) === null || _o$obj2 === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(_o$obj2, _a)[_a].b)?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while ((_o$obj3 = o.obj) !== null && _o$obj3 !== void 0 && babelHelpers.classPrivateFieldLooseBase(_o$obj3, _a)[_a].b.c.d) {
|
||||||
|
var _o$obj3;
|
||||||
|
|
||||||
|
for (; ((_o$obj4 = o.obj) === null || _o$obj4 === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(_o$obj4, _a)[_a].b.c)?.d;) {
|
||||||
|
var _o$obj4;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$obj5;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (((_o$obj5 = o.obj) === null || _o$obj5 === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(_o$obj5, _a)[_a].b)?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
var _o$obj6;
|
||||||
|
|
||||||
|
return !!((_o$obj6 = o.obj) === null || _o$obj6 === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(_o$obj6, _a)[_a].b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if ((o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d && (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a])?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d && (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a])?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if ((o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.non_existent ?? (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.non_existent ?? (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o, _a)[_a].b)?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(C, _a, {
|
||||||
|
writable: true,
|
||||||
|
value: {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
class C {
|
||||||
|
static #a = {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.#a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.#a.b.c.d) {
|
||||||
|
for (; o?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.#a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.#a.b.c.d) {
|
||||||
|
for (; o.obj?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.#a.b?.c.d && o?.#a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.#a.b?.c.d && o?.#a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) {
|
||||||
|
return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.#a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static test() {
|
||||||
|
const c = C;
|
||||||
|
expect(C.testIf(c)).toBe(true);
|
||||||
|
expect(C.testConditional(c)).toBe(true);
|
||||||
|
expect(C.testLoop(c)).toBe(true);
|
||||||
|
expect(C.testNegate(c)).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testConditionalDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testLoopDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testNegateDeep({ obj: c })).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(c)).toBe(true);
|
||||||
|
expect(C.testLogicalInReturn(c)).toBe(2);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(c)).toBe(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullish() {
|
||||||
|
for (const n of [null, undefined]) {
|
||||||
|
expect(C.testIf(n)).toBe(false);
|
||||||
|
expect(C.testConditional(n)).toBe(false);
|
||||||
|
expect(C.testLoop(n)).toBe(false);
|
||||||
|
expect(C.testNegate(n)).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testConditionalDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testLoopDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testNegateDeep({ obj: n })).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(n)).toBe(false);
|
||||||
|
expect(C.testLogicalInReturn(n)).toBe(undefined);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(n)).toBe(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
class C {
|
||||||
|
static #a = {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.#a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.#a.b.c.d) {
|
||||||
|
for (; o?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.#a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.#a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.#a.b.c.d) {
|
||||||
|
for (; o.obj?.#a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.#a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.#a.b?.c.d && o?.#a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.#a.b?.c.d && o?.#a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) {
|
||||||
|
return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.#a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["external-helpers", { "helperVersion": "7.100.0" }], "proposal-class-properties"],
|
||||||
|
"minNodeVersion": "14.0.0"
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o !== null && o !== void 0 && babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditional(o) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o !== null && o !== void 0 && babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c.d) {
|
||||||
|
for (; (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c)?.d;) {
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while ((o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!(o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testIfDeep(o) {
|
||||||
|
var _o$obj;
|
||||||
|
|
||||||
|
if (((_o$obj = o.obj) === null || _o$obj === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj, C, _a).b)?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
var _o$obj2;
|
||||||
|
|
||||||
|
return ((_o$obj2 = o.obj) === null || _o$obj2 === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj2, C, _a).b)?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while ((_o$obj3 = o.obj) !== null && _o$obj3 !== void 0 && babelHelpers.classStaticPrivateFieldSpecGet(_o$obj3, C, _a).b.c.d) {
|
||||||
|
var _o$obj3;
|
||||||
|
|
||||||
|
for (; ((_o$obj4 = o.obj) === null || _o$obj4 === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj4, C, _a).b.c)?.d;) {
|
||||||
|
var _o$obj4;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$obj5;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (((_o$obj5 = o.obj) === null || _o$obj5 === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj5, C, _a).b)?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
var _o$obj6;
|
||||||
|
|
||||||
|
return !!((_o$obj6 = o.obj) === null || _o$obj6 === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj6, C, _a).b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if ((o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d && (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a))?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d && (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a))?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if ((o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d) {
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (o === null || o === void 0 ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _a = {
|
||||||
|
writable: true,
|
||||||
|
value: {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -5,6 +5,12 @@ import {
|
|||||||
} from "@babel/helper-skip-transparent-expression-wrappers";
|
} from "@babel/helper-skip-transparent-expression-wrappers";
|
||||||
import syntaxOptionalChaining from "@babel/plugin-syntax-optional-chaining";
|
import syntaxOptionalChaining from "@babel/plugin-syntax-optional-chaining";
|
||||||
import { types as t, template } from "@babel/core";
|
import { types as t, template } from "@babel/core";
|
||||||
|
import {
|
||||||
|
willPathCastToBoolean,
|
||||||
|
findOutermostTransparentParent,
|
||||||
|
} from "./util.js";
|
||||||
|
|
||||||
|
const { ast } = template.expression;
|
||||||
|
|
||||||
export default declare((api, options) => {
|
export default declare((api, options) => {
|
||||||
api.assertVersion(7);
|
api.assertVersion(7);
|
||||||
@ -56,11 +62,11 @@ export default declare((api, options) => {
|
|||||||
const { scope } = path;
|
const { scope } = path;
|
||||||
// maybeWrapped points to the outermost transparent expression wrapper
|
// maybeWrapped points to the outermost transparent expression wrapper
|
||||||
// or the path itself
|
// or the path itself
|
||||||
let maybeWrapped = path;
|
const maybeWrapped = findOutermostTransparentParent(path);
|
||||||
const parentPath = path.findParent(p => {
|
const { parentPath } = maybeWrapped;
|
||||||
if (!isTransparentExprWrapper(p)) return true;
|
const willReplacementCastToBoolean = willPathCastToBoolean(
|
||||||
maybeWrapped = p;
|
maybeWrapped,
|
||||||
});
|
);
|
||||||
let isDeleteOperation = false;
|
let isDeleteOperation = false;
|
||||||
const parentIsCall =
|
const parentIsCall =
|
||||||
parentPath.isCallExpression({ callee: maybeWrapped.node }) &&
|
parentPath.isCallExpression({ callee: maybeWrapped.node }) &&
|
||||||
@ -202,33 +208,35 @@ export default declare((api, options) => {
|
|||||||
[t.cloneNode(baseRef ?? object)],
|
[t.cloneNode(baseRef ?? object)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
replacementPath.replaceWith(
|
|
||||||
t.conditionalExpression(
|
|
||||||
loose
|
|
||||||
? t.binaryExpression("==", t.cloneNode(check), t.nullLiteral())
|
|
||||||
: t.logicalExpression(
|
|
||||||
"||",
|
|
||||||
t.binaryExpression(
|
|
||||||
"===",
|
|
||||||
t.cloneNode(check),
|
|
||||||
t.nullLiteral(),
|
|
||||||
),
|
|
||||||
t.binaryExpression(
|
|
||||||
"===",
|
|
||||||
t.cloneNode(ref),
|
|
||||||
scope.buildUndefinedNode(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
isDeleteOperation
|
|
||||||
? t.booleanLiteral(true)
|
|
||||||
: scope.buildUndefinedNode(),
|
|
||||||
replacement,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
replacementPath = skipTransparentExprWrappers(
|
if (willReplacementCastToBoolean) {
|
||||||
replacementPath.get("alternate"),
|
// `if (a?.b) {}` transformed to `if (a != null && a.b) {}`
|
||||||
);
|
// we don't need to return `void 0` because the returned value will
|
||||||
|
// eveutally cast to boolean.
|
||||||
|
const nonNullishCheck = loose
|
||||||
|
? ast`${t.cloneNode(check)} != null`
|
||||||
|
: ast`
|
||||||
|
${t.cloneNode(check)} !== null && ${t.cloneNode(ref)} !== void 0`;
|
||||||
|
replacementPath.replaceWith(
|
||||||
|
t.logicalExpression("&&", nonNullishCheck, replacement),
|
||||||
|
);
|
||||||
|
replacementPath = skipTransparentExprWrappers(
|
||||||
|
replacementPath.get("right"),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const nullishCheck = loose
|
||||||
|
? ast`${t.cloneNode(check)} == null`
|
||||||
|
: ast`
|
||||||
|
${t.cloneNode(check)} === null || ${t.cloneNode(ref)} === void 0`;
|
||||||
|
|
||||||
|
const returnValue = isDeleteOperation ? ast`true` : ast`void 0`;
|
||||||
|
replacementPath.replaceWith(
|
||||||
|
t.conditionalExpression(nullishCheck, returnValue, replacement),
|
||||||
|
);
|
||||||
|
replacementPath = skipTransparentExprWrappers(
|
||||||
|
replacementPath.get("alternate"),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
65
packages/babel-plugin-proposal-optional-chaining/src/util.js
Normal file
65
packages/babel-plugin-proposal-optional-chaining/src/util.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { isTransparentExprWrapper } from "@babel/helper-skip-transparent-expression-wrappers";
|
||||||
|
/**
|
||||||
|
* Test if a NodePath will be cast to boolean when evaluated.
|
||||||
|
* It respects transparent expression wrappers defined in
|
||||||
|
* "@babel/helper-skip-transparent-expression-wrappers"
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // returns true
|
||||||
|
* const nodePathADotB = NodePath("if (a.b) {}").get("test"); // a.b
|
||||||
|
* willPathCastToBoolean(nodePathADotB)
|
||||||
|
* @example
|
||||||
|
* // returns false
|
||||||
|
* willPathCastToBoolean(NodePath("a.b"))
|
||||||
|
* @param {NodePath} path
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function willPathCastToBoolean(path: NodePath): boolean {
|
||||||
|
const maybeWrapped = findOutermostTransparentParent(path);
|
||||||
|
const { node, parentPath } = maybeWrapped;
|
||||||
|
if (parentPath.isLogicalExpression()) {
|
||||||
|
const { operator, right } = parentPath.node;
|
||||||
|
if (
|
||||||
|
operator === "&&" ||
|
||||||
|
operator === "||" ||
|
||||||
|
(operator === "??" && node === right)
|
||||||
|
) {
|
||||||
|
return willPathCastToBoolean(parentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parentPath.isSequenceExpression()) {
|
||||||
|
const { expressions } = parentPath.node;
|
||||||
|
if (expressions[expressions.length - 1] === node) {
|
||||||
|
return willPathCastToBoolean(parentPath);
|
||||||
|
} else {
|
||||||
|
// if it is in the middle of a sequence expression, we don't
|
||||||
|
// care the return value so just cast to boolean for smaller
|
||||||
|
// output
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
parentPath.isConditional({ test: node }) ||
|
||||||
|
parentPath.isUnaryExpression({ operator: "!" }) ||
|
||||||
|
parentPath.isLoop({ test: node })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the outermost transparent expression wrapper of a given path,
|
||||||
|
* otherwise returns path itself.
|
||||||
|
* @example
|
||||||
|
* const nodePathADotB = NodePath("(a.b as any)").get("expression"); // a.b
|
||||||
|
* // returns NodePath("(a.b as any)")
|
||||||
|
* findOutermostTransparentParent(nodePathADotB);
|
||||||
|
* @param {NodePath} path
|
||||||
|
* @returns {NodePath}
|
||||||
|
*/
|
||||||
|
export function findOutermostTransparentParent(path: NodePath): NodePath {
|
||||||
|
let maybeWrapped = path;
|
||||||
|
path.findParent(p => {
|
||||||
|
if (!isTransparentExprWrapper(p)) return true;
|
||||||
|
maybeWrapped = p;
|
||||||
|
});
|
||||||
|
return maybeWrapped;
|
||||||
|
}
|
||||||
120
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/exec.js
vendored
Normal file
120
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/exec.js
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.a.b.c.d) {
|
||||||
|
for (; o?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.a.b.c.d) {
|
||||||
|
for (; o.obj?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.a.b?.c.d && o?.a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.a.b?.c.d && o?.a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) {
|
||||||
|
return o?.a.b?.c.non_existent ?? o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static test() {
|
||||||
|
const c = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(C.testIf(c)).toBe(true);
|
||||||
|
expect(C.testConditional(c)).toBe(true);
|
||||||
|
expect(C.testLoop(c)).toBe(true);
|
||||||
|
expect(C.testNegate(c)).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testConditionalDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testLoopDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testNegateDeep({ obj: c })).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(c)).toBe(true);
|
||||||
|
expect(C.testLogicalInReturn(c)).toBe(2);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(c)).toBe(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullish() {
|
||||||
|
for (const n of [null, undefined]) {
|
||||||
|
expect(C.testIf(n)).toBe(false);
|
||||||
|
expect(C.testConditional(n)).toBe(false);
|
||||||
|
expect(C.testLoop(n)).toBe(false);
|
||||||
|
expect(C.testNegate(n)).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testConditionalDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testLoopDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testNegateDeep({ obj: n })).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(n)).toBe(false);
|
||||||
|
expect(C.testLogicalInReturn(n)).toBe(undefined);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(n)).toBe(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
75
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/input.js
vendored
Normal file
75
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/input.js
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.a.b.c.d) {
|
||||||
|
for (; o?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.a.b.c.d) {
|
||||||
|
for (; o.obj?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.a.b?.c.d && o?.a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.a.b?.c.d && o?.a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) {
|
||||||
|
return o?.a.b?.c.non_existent ?? o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["proposal-optional-chaining"], ["proposal-nullish-coalescing-operator"]]
|
||||||
|
}
|
||||||
121
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/output.js
vendored
Normal file
121
packages/babel-plugin-proposal-optional-chaining/test/fixtures/general/cast-to-boolean/output.js
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o !== null && o !== void 0 && o.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditional(o) {
|
||||||
|
var _o$a$b;
|
||||||
|
|
||||||
|
return o !== null && o !== void 0 && (_o$a$b = o.a.b) !== null && _o$a$b !== void 0 && _o$a$b.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o !== null && o !== void 0 && o.a.b.c.d) {
|
||||||
|
for (; o !== null && o !== void 0 && (_o$a$b$c = o.a.b.c) !== null && _o$a$b$c !== void 0 && _o$a$b$c.d;) {
|
||||||
|
var _o$a$b$c;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$a$b2;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o !== null && o !== void 0 && (_o$a$b2 = o.a.b) !== null && _o$a$b2 !== void 0 && _o$a$b2.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegate(o) {
|
||||||
|
var _o$a$b3;
|
||||||
|
|
||||||
|
return !!(o !== null && o !== void 0 && (_o$a$b3 = o.a.b) !== null && _o$a$b3 !== void 0 && _o$a$b3.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testIfDeep(o) {
|
||||||
|
var _o$obj, _o$obj$a$b;
|
||||||
|
|
||||||
|
if ((_o$obj = o.obj) !== null && _o$obj !== void 0 && (_o$obj$a$b = _o$obj.a.b) !== null && _o$obj$a$b !== void 0 && _o$obj$a$b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
var _o$obj2, _o$obj2$a$b;
|
||||||
|
|
||||||
|
return (_o$obj2 = o.obj) !== null && _o$obj2 !== void 0 && (_o$obj2$a$b = _o$obj2.a.b) !== null && _o$obj2$a$b !== void 0 && _o$obj2$a$b.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while ((_o$obj3 = o.obj) !== null && _o$obj3 !== void 0 && _o$obj3.a.b.c.d) {
|
||||||
|
var _o$obj3;
|
||||||
|
|
||||||
|
for (; (_o$obj4 = o.obj) !== null && _o$obj4 !== void 0 && (_o$obj4$a$b$c = _o$obj4.a.b.c) !== null && _o$obj4$a$b$c !== void 0 && _o$obj4$a$b$c.d;) {
|
||||||
|
var _o$obj4, _o$obj4$a$b$c;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$obj5, _o$obj5$a$b;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while ((_o$obj5 = o.obj) !== null && _o$obj5 !== void 0 && (_o$obj5$a$b = _o$obj5.a.b) !== null && _o$obj5$a$b !== void 0 && _o$obj5$a$b.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
var _o$obj6, _o$obj6$a$b;
|
||||||
|
|
||||||
|
return !!((_o$obj6 = o.obj) !== null && _o$obj6 !== void 0 && (_o$obj6$a$b = _o$obj6.a.b) !== null && _o$obj6$a$b !== void 0 && _o$obj6$a$b.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
var _o$a$b4, _o$a;
|
||||||
|
|
||||||
|
if (o !== null && o !== void 0 && (_o$a$b4 = o.a.b) !== null && _o$a$b4 !== void 0 && _o$a$b4.c.d && o !== null && o !== void 0 && (_o$a = o.a) !== null && _o$a !== void 0 && _o$a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
var _o$a$b5, _o$a2;
|
||||||
|
|
||||||
|
return (o === null || o === void 0 ? void 0 : (_o$a$b5 = o.a.b) === null || _o$a$b5 === void 0 ? void 0 : _o$a$b5.c.d) && (o === null || o === void 0 ? void 0 : (_o$a2 = o.a) === null || _o$a2 === void 0 ? void 0 : _o$a2.b.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
var _o$a$b$c$non_existent, _o$a$b6, _o$a$b7, _o$a$b$c$non_existent3, _o$a$b10;
|
||||||
|
|
||||||
|
if ((_o$a$b$c$non_existent = o === null || o === void 0 ? void 0 : (_o$a$b6 = o.a.b) === null || _o$a$b6 === void 0 ? void 0 : _o$a$b6.c.non_existent) !== null && _o$a$b$c$non_existent !== void 0 ? _o$a$b$c$non_existent : o === null || o === void 0 ? void 0 : (_o$a$b7 = o.a.b) === null || _o$a$b7 === void 0 ? void 0 : _o$a$b7.c.d) {
|
||||||
|
var _o$a$b$c$non_existent2, _o$a$b8, _o$a$b9;
|
||||||
|
|
||||||
|
return (_o$a$b$c$non_existent2 = o === null || o === void 0 ? void 0 : (_o$a$b8 = o.a.b) === null || _o$a$b8 === void 0 ? void 0 : _o$a$b8.c.non_existent) !== null && _o$a$b$c$non_existent2 !== void 0 ? _o$a$b$c$non_existent2 : o === null || o === void 0 ? void 0 : (_o$a$b9 = o.a.b) === null || _o$a$b9 === void 0 ? void 0 : _o$a$b9.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_o$a$b$c$non_existent3 = o === null || o === void 0 ? void 0 : (_o$a$b10 = o.a.b) === null || _o$a$b10 === void 0 ? void 0 : _o$a$b10.c.non_existent) !== null && _o$a$b$c$non_existent3 !== void 0 ? _o$a$b$c$non_existent3 : o;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -4,4 +4,4 @@ var street = (_user$address = user.address) === null || _user$address === void 0
|
|||||||
street = (_user$address2 = user.address) === null || _user$address2 === void 0 ? void 0 : _user$address2.street;
|
street = (_user$address2 = user.address) === null || _user$address2 === void 0 ? void 0 : _user$address2.street;
|
||||||
test((_a = a) === null || _a === void 0 ? void 0 : _a.b, 1);
|
test((_a = a) === null || _a === void 0 ? void 0 : _a.b, 1);
|
||||||
test((_a2 = a) === null || _a2 === void 0 ? void 0 : _a2.b, 1);
|
test((_a2 = a) === null || _a2 === void 0 ? void 0 : _a2.b, 1);
|
||||||
1, (_a3 = a) === null || _a3 === void 0 ? void 0 : _a3.b, 2;
|
1, (_a3 = a) !== null && _a3 !== void 0 && _a3.b, 2;
|
||||||
|
|||||||
@ -4,4 +4,4 @@ var street = (_user$address = user.address) === null || _user$address === void 0
|
|||||||
street = (_user$address2 = user.address) === null || _user$address2 === void 0 ? void 0 : _user$address2.street;
|
street = (_user$address2 = user.address) === null || _user$address2 === void 0 ? void 0 : _user$address2.street;
|
||||||
test((_a = a) === null || _a === void 0 ? void 0 : _a.b, 1);
|
test((_a = a) === null || _a === void 0 ? void 0 : _a.b, 1);
|
||||||
test(((_a2 = a) === null || _a2 === void 0 ? void 0 : _a2.b), 1);
|
test(((_a2 = a) === null || _a2 === void 0 ? void 0 : _a2.b), 1);
|
||||||
((1, (_a3 = a) === null || _a3 === void 0 ? void 0 : _a3.b, 2));
|
((1, (_a3 = a) !== null && _a3 !== void 0 && _a3.b, 2));
|
||||||
|
|||||||
120
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/exec.js
vendored
Normal file
120
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/exec.js
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.a.b.c.d) {
|
||||||
|
for (; o?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.a.b.c.d) {
|
||||||
|
for (; o.obj?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.a.b?.c.d && o?.a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.a.b?.c.d && o?.a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) {
|
||||||
|
return o?.a.b?.c.non_existent ?? o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static test() {
|
||||||
|
const c = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: {
|
||||||
|
d: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(C.testIf(c)).toBe(true);
|
||||||
|
expect(C.testConditional(c)).toBe(true);
|
||||||
|
expect(C.testLoop(c)).toBe(true);
|
||||||
|
expect(C.testNegate(c)).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testConditionalDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testLoopDeep({ obj: c })).toBe(true);
|
||||||
|
expect(C.testNegateDeep({ obj: c })).toBe(true);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(c)).toBe(true);
|
||||||
|
expect(C.testLogicalInReturn(c)).toBe(2);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(c)).toBe(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullish() {
|
||||||
|
for (const n of [null, undefined]) {
|
||||||
|
expect(C.testIf(n)).toBe(false);
|
||||||
|
expect(C.testConditional(n)).toBe(false);
|
||||||
|
expect(C.testLoop(n)).toBe(false);
|
||||||
|
expect(C.testNegate(n)).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testIfDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testConditionalDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testLoopDeep({ obj: n })).toBe(false);
|
||||||
|
expect(C.testNegateDeep({ obj: n })).toBe(false);
|
||||||
|
|
||||||
|
expect(C.testLogicalInIf(n)).toBe(false);
|
||||||
|
expect(C.testLogicalInReturn(n)).toBe(undefined);
|
||||||
|
|
||||||
|
expect(C.testNullishCoalescing(n)).toBe(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
75
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/input.js
vendored
Normal file
75
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/input.js
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o?.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditional(o) {
|
||||||
|
return o?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o?.a.b.c.d) {
|
||||||
|
for (; o?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegate(o) {
|
||||||
|
return !!o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
static testIfDeep(o) {
|
||||||
|
if (o.obj?.a.b?.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
return o.obj?.a.b?.c.d ? true : false;
|
||||||
|
}
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while (o.obj?.a.b.c.d) {
|
||||||
|
for (; o.obj?.a.b.c?.d; ) {
|
||||||
|
let i = 0;
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o.obj?.a.b?.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
return !!o.obj?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
if (o?.a.b?.c.d && o?.a?.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
return o?.a.b?.c.d && o?.a?.b.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) {
|
||||||
|
return o?.a.b?.c.non_existent ?? o?.a.b?.c.d;
|
||||||
|
}
|
||||||
|
return o?.a.b?.c.non_existent ?? o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["proposal-optional-chaining", { "loose": true }], ["proposal-nullish-coalescing-operator", { "loose": true }]]
|
||||||
|
}
|
||||||
121
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/output.js
vendored
Normal file
121
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/cast-to-boolean/output.js
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
class C {
|
||||||
|
static testIf(o) {
|
||||||
|
if (o != null && o.a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditional(o) {
|
||||||
|
var _o$a$b;
|
||||||
|
|
||||||
|
return o != null && (_o$a$b = o.a.b) != null && _o$a$b.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoop(o) {
|
||||||
|
while (o != null && o.a.b.c.d) {
|
||||||
|
for (; o != null && (_o$a$b$c = o.a.b.c) != null && _o$a$b$c.d;) {
|
||||||
|
var _o$a$b$c;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$a$b2;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (o != null && (_o$a$b2 = o.a.b) != null && _o$a$b2.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegate(o) {
|
||||||
|
var _o$a$b3;
|
||||||
|
|
||||||
|
return !!(o != null && (_o$a$b3 = o.a.b) != null && _o$a$b3.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testIfDeep(o) {
|
||||||
|
var _o$obj, _o$obj$a$b;
|
||||||
|
|
||||||
|
if ((_o$obj = o.obj) != null && (_o$obj$a$b = _o$obj.a.b) != null && _o$obj$a$b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testConditionalDeep(o) {
|
||||||
|
var _o$obj2, _o$obj2$a$b;
|
||||||
|
|
||||||
|
return (_o$obj2 = o.obj) != null && (_o$obj2$a$b = _o$obj2.a.b) != null && _o$obj2$a$b.c.d ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLoopDeep(o) {
|
||||||
|
while ((_o$obj3 = o.obj) != null && _o$obj3.a.b.c.d) {
|
||||||
|
var _o$obj3;
|
||||||
|
|
||||||
|
for (; (_o$obj4 = o.obj) != null && (_o$obj4$a$b$c = _o$obj4.a.b.c) != null && _o$obj4$a$b$c.d;) {
|
||||||
|
var _o$obj4, _o$obj4$a$b$c;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
var _o$obj5, _o$obj5$a$b;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i === 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while ((_o$obj5 = o.obj) != null && (_o$obj5$a$b = _o$obj5.a.b) != null && _o$obj5$a$b.c.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNegateDeep(o) {
|
||||||
|
var _o$obj6, _o$obj6$a$b;
|
||||||
|
|
||||||
|
return !!((_o$obj6 = o.obj) != null && (_o$obj6$a$b = _o$obj6.a.b) != null && _o$obj6$a$b.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInIf(o) {
|
||||||
|
var _o$a$b4, _o$a;
|
||||||
|
|
||||||
|
if (o != null && (_o$a$b4 = o.a.b) != null && _o$a$b4.c.d && o != null && (_o$a = o.a) != null && _o$a.b.c.d) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static testLogicalInReturn(o) {
|
||||||
|
var _o$a$b5, _o$a2;
|
||||||
|
|
||||||
|
return (o == null ? void 0 : (_o$a$b5 = o.a.b) == null ? void 0 : _o$a$b5.c.d) && (o == null ? void 0 : (_o$a2 = o.a) == null ? void 0 : _o$a2.b.c.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static testNullishCoalescing(o) {
|
||||||
|
var _o$a$b$c$non_existent, _o$a$b6, _o$a$b7, _o$a$b$c$non_existent3, _o$a$b10;
|
||||||
|
|
||||||
|
if ((_o$a$b$c$non_existent = o == null ? void 0 : (_o$a$b6 = o.a.b) == null ? void 0 : _o$a$b6.c.non_existent) != null ? _o$a$b$c$non_existent : o == null ? void 0 : (_o$a$b7 = o.a.b) == null ? void 0 : _o$a$b7.c.d) {
|
||||||
|
var _o$a$b$c$non_existent2, _o$a$b8, _o$a$b9;
|
||||||
|
|
||||||
|
return (_o$a$b$c$non_existent2 = o == null ? void 0 : (_o$a$b8 = o.a.b) == null ? void 0 : _o$a$b8.c.non_existent) != null ? _o$a$b$c$non_existent2 : o == null ? void 0 : (_o$a$b9 = o.a.b) == null ? void 0 : _o$a$b9.c.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_o$a$b$c$non_existent3 = o == null ? void 0 : (_o$a$b10 = o.a.b) == null ? void 0 : _o$a$b10.c.non_existent) != null ? _o$a$b$c$non_existent3 : o;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
C.test();
|
||||||
|
C.testNullish();
|
||||||
3
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/options.json
vendored
Normal file
3
packages/babel-plugin-proposal-optional-chaining/test/fixtures/loose/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": [["proposal-optional-chaining", { "loose": true }]]
|
||||||
|
}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"plugins": ["proposal-optional-chaining"]
|
"plugins": ["proposal-optional-chaining", "syntax-typescript"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
(a) => {
|
||||||
|
if ((a.b as any)?.()) {}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
a => {
|
||||||
|
var _a$b;
|
||||||
|
|
||||||
|
if ((_a$b = (a.b as any)) !== null && _a$b !== void 0 && _a$b.call(a)) {}
|
||||||
|
};
|
||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"syntax-typescript"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"proposal-optional-chaining"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
(a) => {
|
||||||
|
(((a?.b as any) && a.c?.d) as any) ? 0 : 1
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
a => {
|
||||||
|
var _a$c;
|
||||||
|
|
||||||
|
((a !== null && a !== void 0 && a.b as any) && (_a$c = a.c) !== null && _a$c !== void 0 && _a$c.d as any) ? 0 : 1;
|
||||||
|
};
|
||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"syntax-typescript"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"proposal-optional-chaining"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"syntax-typescript"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"proposal-optional-chaining"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
import { willPathCastToBoolean } from "../src/util";
|
||||||
|
import { parseSync, traverse } from "@babel/core";
|
||||||
|
|
||||||
|
function getPath(input, parserOpts) {
|
||||||
|
let targetPath;
|
||||||
|
traverse(parseSync(input, { parserOpts, filename: "example.js" }), {
|
||||||
|
OptionalMemberExpression(path) {
|
||||||
|
targetPath = path;
|
||||||
|
path.stop();
|
||||||
|
},
|
||||||
|
noScope: true,
|
||||||
|
});
|
||||||
|
return targetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("willPathCastToBoolean", () => {
|
||||||
|
const positiveCases = [
|
||||||
|
"if(a?.b) {}",
|
||||||
|
"while(a?.b) {}",
|
||||||
|
"a?.b ? 0 : 1",
|
||||||
|
"for(;a?.b;);",
|
||||||
|
"while(a?.b);",
|
||||||
|
"do {} while (a?.b)",
|
||||||
|
"!a?.b",
|
||||||
|
"if(a && a?.b) {}",
|
||||||
|
"if(a?.b && a) {}",
|
||||||
|
"while(a || a?.b) {}",
|
||||||
|
"while(a?.b || a) {}",
|
||||||
|
"for(; a ?? a?.b ;);",
|
||||||
|
"do {} while (0, a?.b)",
|
||||||
|
"(a?.b, 0)",
|
||||||
|
"!(a && ( b || ( c ?? ( a?.b && d ) ) ) )",
|
||||||
|
|
||||||
|
// parenthesized
|
||||||
|
"!((a?.b), 0)",
|
||||||
|
"((a?.b)) ? 0 : 1",
|
||||||
|
"while( (a || ((a?.b) && c) ) );",
|
||||||
|
];
|
||||||
|
|
||||||
|
const negativeCases = [
|
||||||
|
"() => a?.b",
|
||||||
|
"for(; a?.b ?? a;);",
|
||||||
|
"a?.b && a",
|
||||||
|
"a && a?.b",
|
||||||
|
"() => a?.b || a",
|
||||||
|
"() => a || a?.b",
|
||||||
|
"a?.b()",
|
||||||
|
"a = a?.b && null",
|
||||||
|
|
||||||
|
// parenthesized
|
||||||
|
"(a?.b)",
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("default parser options", () => {
|
||||||
|
test.each(positiveCases)(
|
||||||
|
"willPathCastToBoolean(a?.b in %p) should return true",
|
||||||
|
input => {
|
||||||
|
expect(willPathCastToBoolean(getPath(input))).toBe(true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
test.each(negativeCases)(
|
||||||
|
"willPathCastToBoolean(a?.b in %p) should return false",
|
||||||
|
input => {
|
||||||
|
expect(willPathCastToBoolean(getPath(input))).toBe(false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createParenthesizedExpressions", () => {
|
||||||
|
test.each(positiveCases)(
|
||||||
|
"willPathCastToBoolean(a?.b in %p with { createParenthesizedExpressions: true }) should return true",
|
||||||
|
input => {
|
||||||
|
const parserOpts = { createParenthesizedExpressions: true };
|
||||||
|
expect(willPathCastToBoolean(getPath(input, parserOpts))).toBe(true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
test.each(negativeCases)(
|
||||||
|
"willPathCastToBoolean(a?.b in %p with { createParenthesizedExpressions: true }) should return false",
|
||||||
|
input => {
|
||||||
|
const parserOpts = { createParenthesizedExpressions: true };
|
||||||
|
expect(willPathCastToBoolean(getPath(input, parserOpts))).toBe(false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user