lib/impl/submissionExportHelper/csvHeaders.js
function generateCSVHeaders(fieldKeys, mergedFieldEntries, fieldHeader) {
  var csv = '';
  var fieldRepeatIndex = 0;
  // Here we need to add the metaDataHeaders
  _.each(metaDataHeaders, function(headerName) {
    csv += headerName + ',';
  });

  var fieldKeysProcessed = [];
  var fieldsProcessed = {};
  fieldKeys.forEach(function(fieldKey) {
  // check if its a repeating form (and extra headers required)
    var field = mergedFieldEntries[fieldKey];
    if (field.type === 'sectionBreak' && field.repeating) {
      var fieldsInThisSection = sectionUtils.getFieldsInSection(field._id, _.values(mergedFieldEntries));
      _.each(fieldsInThisSection, function(field) {
        fieldsProcessed[field._id] = true;
      });

      for (var i = 0; i < field.fieldOptions.definition.maxRepeat; i++) {
        _.each(fieldsInThisSection, function(fieldInThisSection) {
          fieldKeysProcessed.push({key: fieldInThisSection._id, sectionIndex: i + 1, inRepeatingForm: true});
        });
      }
    } else if (!fieldsProcessed[fieldKey]) {
      fieldKeysProcessed.push({key: fieldKey});
    }
  });

  //for each form get each of the unique fields and add a header
  fieldKeysProcessed.forEach(function(processedField) {
    // check if its a repeating form (and extra headers required)
    var field = mergedFieldEntries[processedField.key];

    //Fields may not have a field code, if not just use the field name.
    var headerName = typeof (field[fieldHeader]) === "string" ? field[fieldHeader] : field.name;

    if (processedField.inRepeatingForm) {
      headerName = '(section repeat: ' + processedField.sectionIndex + ') ' + headerName;
    }
    if (field.repeating === true) {
      for (fieldRepeatIndex = 0; fieldRepeatIndex < field.fieldOptions.definition.maxRepeat; fieldRepeatIndex++) {
        csv = generateCSVHeader(csv, field, headerName, fieldRepeatIndex);
      }
    } else {
      csv = generateCSVHeader(csv, field, headerName, null);
    }
  });

  csv += '\r\n';
  return csv;
}
function generateCSVHeaders(fieldKeys, mergedFieldEntries, fieldHeader) {
  var csv = '';
  var fieldRepeatIndex = 0;
  // Here we need to add the metaDataHeaders
  _.each(metaDataHeaders, function(headerName) {
    csv += headerName + ',';
  });

  var fieldKeysProcessed = [];
  var fieldsProcessed = {};
  fieldKeys.forEach(function(fieldKey) {
  // check if its a repeating form (and extra headers required)
    var field = mergedFieldEntries[fieldKey];
    if (field.type === 'sectionBreak' && field.repeating) {
      var fieldsInThisSection = sectionUtils.getFieldsInSection(field._id, _.values(mergedFieldEntries));
      _.each(fieldsInThisSection, function(field) {
        fieldsProcessed[field._id] = true;
      });

      for (var i = 0; i < field.fieldOptions.definition.maxRepeat; i++) {
        _.each(fieldsInThisSection, function(fieldInThisSection) {
          fieldKeysProcessed.push({key: fieldInThisSection._id, sectionIndex: i + 1, inRepeatingForm: true});
        });
      }
    } else if (!fieldsProcessed[fieldKey]) {
      fieldKeysProcessed.push({key: fieldKey});
    }
  });

  //for each form get each of the unique fields and add a header
  fieldKeysProcessed.forEach(function(processedField) {
    // check if its a repeating form (and extra headers required)
    var field = mergedFieldEntries[processedField.key];

    //Fields may not have a field code, if not just use the field name.
    var headerName = typeof (field[fieldHeader]) === "string" ? field[fieldHeader] : field.name;

    if (processedField.inRepeatingForm) {
      headerName = '(section repeat: ' + processedField.sectionIndex + ') ' + headerName;
    }
    if (field.repeating === true) {
      for (fieldRepeatIndex = 0; fieldRepeatIndex < field.fieldOptions.definition.maxRepeat; fieldRepeatIndex++) {
        csv = generateCSVHeader(csv, field, headerName, fieldRepeatIndex);
      }
    } else {
      csv = generateCSVHeader(csv, field, headerName, null);
    }
  });

  csv += '\r\n';
  return csv;
}
function generateCSVHeaders ( fieldKeys , mergedFieldEntries , fieldHeader ) { var csv = '' ; var fieldRepeatIndex = 0 ; // Here we need to add the metaDataHeaders _ . each ( metaDataHeaders , function ( headerName ) { csv += headerName + ',' ; } ) ; var fieldKeysProcessed = [ ] ; var fieldsProcessed = { } ; fieldKeys . forEach ( function ( fieldKey ) { // check if its a repeating form (and extra headers required) var field = mergedFieldEntries [ fieldKey ] ; if ( field . type === 'sectionBreak' && field . repeating ) { var fieldsInThisSection = sectionUtils . getFieldsInSection ( field . _id , _ . values ( mergedFieldEntries ) ) ; _ . each ( fieldsInThisSection , function ( field ) { fieldsProcessed [ field . _id ] = true ; } ) ; for ( var i = 0 ; i < field . fieldOptions . definition . maxRepeat ; i ++ ) { _ . each ( fieldsInThisSection , function ( fieldInThisSection ) { fieldKeysProcessed . push ( { key : fieldInThisSection . _id , sectionIndex : i + 1 , inRepeatingForm : true } ) ; } ) ; } } else if ( ! fieldsProcessed [ fieldKey ] ) { fieldKeysProcessed . push ( { key : fieldKey } ) ; } } ) ; //for each form get each of the unique fields and add a header fieldKeysProcessed . forEach ( function ( processedField ) { // check if its a repeating form (and extra headers required) var field = mergedFieldEntries [ processedField . key ] ; //Fields may not have a field code, if not just use the field name. var headerName = typeof ( field [ fieldHeader ] ) === "string" ? field [ fieldHeader ] : field . name ; if ( processedField . inRepeatingForm ) { headerName = '(section repeat: ' + processedField . sectionIndex + ') ' + headerName ; } if ( field . repeating === true ) { for ( fieldRepeatIndex = 0 ; fieldRepeatIndex < field . fieldOptions . definition . maxRepeat ; fieldRepeatIndex ++ ) { csv = generateCSVHeader ( csv , field , headerName , fieldRepeatIndex ) ; } } else { csv = generateCSVHeader ( csv , field , headerName , null ) ; } } ) ; csv += '\r\n' ; return csv ; }
generateCSVHeaders - Generating CSV Headers from a merged form definition

@param  {array} fieldKeys          Field IDs
@param  {object} mergedFieldEntries Merged field definitions
@param  {string} fieldHeader        Header type to use (fieldName, fieldCode)
@return {string}
generateCSVHeaders - Generating CSV Headers from a merged form definition