index.js (babel-7.12.6) | : | index.js (babel-7.12.7) | ||
---|---|---|---|---|
import { declare } from "@babel/helper-plugin-utils"; | import { declare } from "@babel/helper-plugin-utils"; | |||
import { | import { | |||
isTransparentExprWrapper, | isTransparentExprWrapper, | |||
skipTransparentExprWrappers, | skipTransparentExprWrappers, | |||
} 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); | |||
const { loose = false } = options; | const { loose = false } = options; | |||
function isSimpleMemberExpression(expression) { | function isSimpleMemberExpression(expression) { | |||
expression = skipTransparentExprWrappers(expression); | expression = skipTransparentExprWrappers(expression); | |||
return ( | return ( | |||
t.isIdentifier(expression) || | t.isIdentifier(expression) || | |||
skipping to change at line 59 | skipping to change at line 65 | |||
return { | return { | |||
name: "proposal-optional-chaining", | name: "proposal-optional-chaining", | |||
inherits: syntaxOptionalChaining, | inherits: syntaxOptionalChaining, | |||
visitor: { | visitor: { | |||
"OptionalCallExpression|OptionalMemberExpression"(path) { | "OptionalCallExpression|OptionalMemberExpression"(path) { | |||
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 }) && | |||
// note that the first condition must implies that `path.optional` is `true`, | // note that the first condition must implies that `path.optional` is `true`, | |||
// otherwise the parentPath should be an OptionalCallExpressioin | // otherwise the parentPath should be an OptionalCallExpressioin | |||
path.isOptionalMemberExpression(); | path.isOptionalMemberExpression(); | |||
const optionals = []; | const optionals = []; | |||
let optionalPath = path; | let optionalPath = path; | |||
skipping to change at line 205 | skipping to change at line 211 | |||
baseRef, | baseRef, | |||
object, | object, | |||
); | ); | |||
} | } | |||
} | } | |||
replacement = t.callExpression( | replacement = t.callExpression( | |||
t.memberExpression(replacement, t.identifier("bind")), | t.memberExpression(replacement, t.identifier("bind")), | |||
[t.cloneNode(baseRef ?? object)], | [t.cloneNode(baseRef ?? object)], | |||
); | ); | |||
} | } | |||
replacementPath.replaceWith( | ||||
t.conditionalExpression( | if (willReplacementCastToBoolean) { | |||
loose | // `if (a?.b) {}` transformed to `if (a != null && a.b) {}` | |||
? t.binaryExpression("==", t.cloneNode(check), t.nullLiteral()) | // we don't need to return `void 0` because the returned value will | |||
: t.logicalExpression( | // eveutally cast to boolean. | |||
"||", | const nonNullishCheck = loose | |||
t.binaryExpression( | ? ast`${t.cloneNode(check)} != null` | |||
"===", | : ast` | |||
t.cloneNode(check), | ${t.cloneNode(check)} !== null && ${t.cloneNode(ref)} !== void 0`; | |||
t.nullLiteral(), | replacementPath.replaceWith( | |||
), | t.logicalExpression("&&", nonNullishCheck, replacement), | |||
t.binaryExpression( | ); | |||
"===", | replacementPath = skipTransparentExprWrappers( | |||
t.cloneNode(ref), | replacementPath.get("right"), | |||
scope.buildUndefinedNode(), | ); | |||
), | } else { | |||
), | const nullishCheck = loose | |||
isDeleteOperation | ? ast`${t.cloneNode(check)} == null` | |||
? t.booleanLiteral(true) | : ast` | |||
: scope.buildUndefinedNode(), | ${t.cloneNode(check)} === null || ${t.cloneNode(ref)} === void 0`; | |||
replacement, | ||||
), | const returnValue = isDeleteOperation ? ast`true` : ast`void 0`; | |||
); | replacementPath.replaceWith( | |||
t.conditionalExpression(nullishCheck, returnValue, replacement), | ||||
replacementPath = skipTransparentExprWrappers( | ); | |||
replacementPath.get("alternate"), | replacementPath = skipTransparentExprWrappers( | |||
); | replacementPath.get("alternate"), | |||
); | ||||
} | ||||
} | } | |||
}, | }, | |||
}, | }, | |||
}; | }; | |||
}); | }); | |||
End of changes. 3 change blocks. | ||||
32 lines changed or deleted | 40 lines changed or added |