Using deparse(substitute(expression) with pipe

This stackexchange answer indirectly addresses this question (as well as the similar question "How to extract the object name when the object is piped to a function?", though it's now closed).

Instead of using deparse(substitute()), we use sys.calls(). I won't pretend to fully understand what's happening but it works for me:

x_expression <- function(x) {
  getAST <- function(ee) purrr::map_if(as.list(ee), is.call, getAST)

  sc <- sys.calls()
  ASTs <- purrr::map( as.list(sc), getAST ) %>%
    purrr::keep( ~identical(.[[1]], quote(`%>%`)) )  # Match first element to %>%

  if( length(ASTs) == 0 ) return( enexpr(x) )        # Not in a pipe
  dplyr::last( ASTs )[[2]]    # Second element is the left-hand side
}

which gives the desired output, for both pipe and non-piped notation:

x_expression(mtcars)
# mtcars

mtcars %>% x_expression()
# mtcars