import { createMacro } from 'babel-plugin-macros'; import { types } from '@babel/core'; type Dig = (expr: T, fallback_expr?: F) => T | F; /** * Macro to convert an expression into a safe-traversal expression. * * Upon transpilation, converts `dig(a.b.c.d)` -> `(a != null) && (a.b != null) && (a.b.c != null) ? a.b.c.d : `. * * `this` is automatically assumed non-null. eg. `dig(this.a.b)` -> `(this.a != null) ? this.a.b : ` * * @deprecated Use "optional chaining" - eg `a?.b?.c` - instead. * * @param expr * @param fallback_expr */ export default createMacro(({ references, state, babel: { types: t } }) => { function rewriteSubMemberExpression(me: types.MemberExpression) { const meObjExp = me.object; const expCheck = t.binaryExpression('!=', t.cloneNode(meObjExp), t.nullLiteral()); if (meObjExp.type == 'MemberExpression' && meObjExp.object.type != 'ThisExpression') { return t.logicalExpression('&&', rewriteSubMemberExpression(meObjExp), expCheck); } return expCheck; } references.default.forEach(ref => { const call_expr = ref.container as types.CallExpression; const member_expr: any = call_expr.arguments[0]; const default_expr: any = call_expr.arguments[1] || t.nullLiteral(); const test_expr = rewriteSubMemberExpression(member_expr); const nex = t.conditionalExpression(test_expr, member_expr, default_expr); ref.parentPath.replaceWith(nex) }) }) as Dig;