function performAction(action, layer, data) {
  // find action function for the specified action
  let actionFunction
  for (let i = 0; i < actions.length; i++) {
    if (actions[i].name === action.command || actions[i].alias === action.command) {
      actionFunction = actions[i].perform
    }
  }

  // continue only if action found
  if (!actionFunction) {
    return Context().document.showMessage(
      "Conditional action '" + action.command + "' on layer '" + layer.name() + "' does not exist."
    )
  }

  // create populated condition string
  let populatedConditionString = action.condition.string
  action.condition.placeholders.forEach(placeholder => {
    // populate placeholder found in the condition string
    let populatedPlaceholder = Core.placeholders.populatePlaceholder(placeholder, data, 'null')

    // replace original placeholder string
    populatedConditionString = populatedConditionString.replace(
      placeholder.string,
      populatedPlaceholder
    )
  })

  // populate params
  let populatedParams = action.params.map(param => {
    // create populated param string
    let populatedParamString = param.string
    param.placeholders.forEach(placeholder => {
      // populate placeholder found in the param string
      let populatedPlaceholder = Core.placeholders.populatePlaceholder(placeholder, data, 'null')

      // replace original placeholder string
      populatedParamString = populatedParamString.replace(placeholder.string, populatedPlaceholder)
    })

    return populatedParamString
  })

  // get layer name without action string
  // used within error messages
  let layerName = layer.name().replace(action.string, '').trim()
  if (!layerName.length) layerName = layer.name()

  // evaluate condition
  let condition
  try {
    // evaluate condition
    // eslint-disable-next-line no-new-func
    condition = new Function('return ' + populatedConditionString)()
  } catch (e) {
    // show error that action could not be evaluated
    Context().document.showMessage(
      "Conditional action on layer '" + layerName + "' could not be evaluated."
    )
  }

  // perform action
  try {
    actionFunction(condition, layer, populatedParams)
  } catch (e) {
    // show error that action could not be performed
    Context().document.showMessage(
      "Conditional action on layer '" + layerName + "' could not be performed."
    )
  }
}
Performs the supplied action with the data and layer as input.

@param {Object} action
@param {MSLayer} layer
@param {Object} data