( path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>, assumptions: OptionalChainAssumptions, )
| 238 | } |
| 239 | |
| 240 | export function transform( |
| 241 | path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>, |
| 242 | assumptions: OptionalChainAssumptions, |
| 243 | ) { |
| 244 | const { scope } = path; |
| 245 | |
| 246 | // maybeWrapped points to the outermost transparent expression wrapper |
| 247 | // or the path itself |
| 248 | const maybeWrapped = findOutermostTransparentParent(path); |
| 249 | const { parentPath } = maybeWrapped; |
| 250 | |
| 251 | if (parentPath.isUnaryExpression({ operator: "delete" })) { |
| 252 | transformOptionalChain( |
| 253 | path, |
| 254 | assumptions, |
| 255 | parentPath, |
| 256 | t.booleanLiteral(true), |
| 257 | ); |
| 258 | } else { |
| 259 | let wrapLast: ((value: t.Expression) => t.Expression) | undefined; |
| 260 | if ( |
| 261 | parentPath.isCallExpression({ callee: maybeWrapped.node }) && |
| 262 | // note that the first condition must implies that `path.optional` is `true`, |
| 263 | // otherwise the parentPath should be an OptionalCallExpression |
| 264 | path.isOptionalMemberExpression() |
| 265 | ) { |
| 266 | // Ensure (a?.b)() has proper `this` |
| 267 | wrapLast = ((replacement: t.MemberExpression) => { |
| 268 | // `(a?.b)()` to `(a == null ? undefined : a.b.bind(a))()` |
| 269 | // object must not be Super as super?.foo is invalid |
| 270 | |
| 271 | const object = skipTransparentExprWrapperNodes( |
| 272 | replacement.object, |
| 273 | ) as t.Expression; |
| 274 | let baseRef: t.Expression | undefined; |
| 275 | if (!assumptions.pureGetters || !isSimpleMemberExpression(object)) { |
| 276 | // memoize the context object when getters are not always pure |
| 277 | // or the object is not a simple member expression |
| 278 | // `(a?.b.c)()` to `(a == null ? undefined : (_a$b = a.b).c.bind(_a$b))()` |
| 279 | baseRef = scope.maybeGenerateMemoised(object)!; |
| 280 | if (baseRef) { |
| 281 | replacement.object = t.assignmentExpression("=", baseRef, object); |
| 282 | } |
| 283 | } |
| 284 | return t.callExpression( |
| 285 | t.memberExpression(replacement, t.identifier("bind")), |
| 286 | [t.cloneNode(baseRef ?? object)], |
| 287 | ); |
| 288 | }) as (value: t.Expression) => t.Expression; |
| 289 | } |
| 290 | |
| 291 | transformOptionalChain( |
| 292 | path, |
| 293 | assumptions, |
| 294 | path, |
| 295 | willPathCastToBoolean(maybeWrapped) |
| 296 | ? t.booleanLiteral(false) |
| 297 | : t.buildUndefinedNode(), |
no test coverage detected