function populateTextLayer(layer, data, opt) {
  // check if layer is in symbol
  let inSymbol = !!opt.overrides

  // get original text
  let originalText = getOriginalText(layer, inSymbol)

  // set original text
  // set even if inside symbol so that if taken out of symbol, it can be repopulated
  setOriginalText(layer, originalText)

  // extract placeholders from layer name
  let namePlaceholders = Core.placeholders.extractPlaceholders(layer.name())

  // extract args
  let args = Core.args.extractArgs(layer.name(), [
    {
      name: 'lines',
      alias: 'l',
      type: Number
    }
  ])

  // populate with placeholder in layer name
  let populatedString = originalText
  if (namePlaceholders.length) {
    // populate first placeholder
    populatedString = Core.placeholders.populatePlaceholder(
      namePlaceholders[0],
      data,
      opt.defaultSubstitute
    )
  }

  // populate based on content of text layer
  else {
    // extract placeholders from original text
    let placeholders = Core.placeholders.extractPlaceholders(originalText)
    if (placeholders.length) {
      // create populated string, starting with the original text and gradually replacing placeholders
      populatedString = originalText
      placeholders.forEach(placeholder => {
        // populate placeholder found in the original text
        let populatedPlaceholder = Core.placeholders.populatePlaceholder(
          placeholder,
          data,
          opt.defaultSubstitute
        )

        // replace original placeholder string (e.g. {firstName}) with populated placeholder string
        populatedString = populatedString.replace(placeholder.string, populatedPlaceholder)
      })
    }

    // populate placeholders in override
    else if (inSymbol) {
      let layerId = String(layer.objectID())

      // extract placeholders from original override or the current override if no original
      let override = opt.overrides.valueForKey(layerId)
      let rootOverride = opt.rootOverrides.valueForKey(layerId)
      let hasRootOverride = !!rootOverride
      let originalOverride = (hasRootOverride ? opt.rootOverrides : opt.overrides).valueForKey(
        layerId + '-original'
      )

      originalText = originalOverride || (hasRootOverride ? rootOverride : override)
      let placeholders = Core.placeholders.extractPlaceholders(originalText)

      // create populated string, starting with the original text and gradually replacing placeholders
      populatedString = originalText
      placeholders.forEach(placeholder => {
        // populate placeholder found in the original text
        let populatedPlaceholder = Core.placeholders.populatePlaceholder(
          placeholder,
          data,
          opt.defaultSubstitute
        )

        // replace original placeholder string (e.g. {firstName}) with populated placeholder string
        populatedString = populatedString.replace(placeholder.string, populatedPlaceholder)
      })

      // set original override
      let targetOverrides = hasRootOverride ? opt.rootOverrides : opt.overrides
      targetOverrides.setValue_forKey(originalText, layerId + '-original')
    }
  }

  // check if the populated string is different from original text
  // this prevents needlessly setting text and affecting text layers that don't contain placeholders
  if (populatedString === originalText) return

  // trim text, taking into account the lines arg if available
  if (layer.textBehaviour() !== 0 && opt.trimText) {
    populatedString = getTrimmedText(layer, populatedString, opt.insertEllipsis, args.lines)
  }

  // set populated string as an override for text layer within a symbol
  if (inSymbol) {
    // make text invisible by setting it to a space
    if (!populatedString.length) {
      populatedString = ' '
    }

    // get id of text layer
    let layerId = layer.objectID()

    // add override for layer
    opt.overrides.setValue_forKey(populatedString, layerId)
  }

  // set populated string for normal text layer
  else {
    // hide text layer if populated string is empty
    if (!populatedString.length) {
      populatedString = '-'
      layer.setIsVisible(false)
    } else {
      layer.setIsVisible(true)
    }

    // get current font
    let font = layer.font()

    // set text layer text
    layer.setStringValue(populatedString)

    // set current font back
    layer.setFont(font)

    // resize text layer to fit text
    Layers.refreshTextLayer(layer)
  }
}
Populates a text layer.

@param {MSTextLayer} layer
@param {Object} data
@param {Object} opt

opt: {
  trimText: {Boolean},
  insertEllipsis: {Boolean},
  defaultSubstitute: {String}
  overrides: {NSMutableDictionary}
}