function populateLayer(layer, data, opt) {
  // populate group layer
  // artboards are also layer groups
  if (Layers.isLayerGroup(layer)) {
    // populate artboard names
    let artboardLayers = Layers.findLayersInLayer('*', false, Layers.ARTBOARD, layer, false, null)
    artboardLayers.forEach(artboardLayer => {
      populateArtboard(artboardLayer, data, {
        defaultSubstitute: opt.defaultSubstitute
      })
      Actions.performActions(artboardLayer, data)
    })

    // populate text layers
    let textLayers = Layers.findLayersInLayer('*', false, Layers.TEXT, layer, false, null)
    textLayers.forEach(textLayer => {
      populateTextLayer(textLayer, data, {
        trimText: opt.trimText,
        insertEllipsis: opt.insertEllipsis,
        defaultSubstitute: opt.defaultSubstitute
      })
      Actions.performActions(textLayer, data)
    })

    // populate images
    let imageLayers = Layers.findLayersInLayer('*', false, Layers.SHAPE, layer, false, null)
    imageLayers = imageLayers.concat(
      Layers.findLayersInLayer('*', false, Layers.BITMAP, layer, false, null)
    )
    imageLayers.forEach(imageLayer => {
      populateImageLayer(imageLayer, data, {
        rootDir: opt.rootDir
      })
      Actions.performActions(imageLayer, data)
    })

    // populate symbols
    let symbolLayers = Layers.findLayersInLayer('*', false, Layers.SYMBOL, layer, false, null)
    symbolLayers.forEach(function (symbolLayer) {
      populateSymbolLayer(symbolLayer, data, opt)
      Actions.performActions(symbolLayer, data)
    })

    // perform actions on group
    Actions.performActions(layer, data)

    // perform actions on sub-groups
    let groupLayers = Layers.findLayersInLayer('*', false, Layers.GROUP, layer, false, null)
    groupLayers.forEach(function (groupLayer) {
      Actions.performActions(groupLayer, data)
    })
  }

  // populate text layer
  else if (Layers.isLayerText(layer)) {
    populateTextLayer(layer, data, {
      trimText: opt.trimText,
      insertEllipsis: opt.insertEllipsis,
      defaultSubstitute: opt.defaultSubstitute
    })
    Actions.performActions(layer, data)
  }

  // populate image layer
  else if (Layers.isLayerShapeGroup(layer) || Layers.isLayerBitmap(layer)) {
    // populate image placeholder
    if (layer.name().indexOf('{') > -1) {
      populateImageLayer(layer, data, {
        rootDir: opt.rootDir
      })
      Actions.performActions(layer, data)
    }
  }

  // populate symbol
  else if (Layers.isSymbolInstance(layer)) {
    populateSymbolLayer(layer, data, opt)
    Actions.performActions(layer, data)
  }
}
Populates a layers using the provided data.

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

opt: {
  rootDir: {String},
  trimText: {Boolean},
  insertEllipsis: {Boolean},
  defaultSubstitute: {String}
}