text: /*
   * grunt-cover-ts
   * https://github.com/kitsonk/grunt-cover-ts
   *
   * Copyright (c) 2015 Kitson Kelly
   * Licensed under the BSD-3-Clause license.
   */
  var sourceMap = require('source-map');
  var path = require('path');
  var TN = /^TN:\s*(.*)$/;
  var SF = /^SF:\s*(.*)$/;
  var FN = /^FN:\s*([0-9]+),(.*)$/;
  var FNF = /^FNF:\s*([0-9]+)$/;
  var FNH = /^FNH:\s*([0-9]+)$/;
  var FNDA = /^FNDA:\s*([0-9]+),(.*)$/;
  var DA = /^DA:\s*([0-9]+),([0-9]+)$/;
  var LF = /^LF:\s*([0-9]+)$/;
  var LH = /^LH:\s*([0-9]+)$/;
  var BRDA = /^BRDA:\s*([0-9]+),([0-9]+),([0-9]+),([0-9]+)$/;
  var BRF = /^BRF:\s*([0-9]+)/;
  var BRH = /^BRH:\s*([0-9]+)/;
  var END_OF_RECORD = /^\s*end_of_record\s*$/;
  var sourceMapRegEx = /(?:\/{2}[#@]{1,2}|\/\*)\s+sourceMappingURL\s*=\s*(data:(?:[^;]+;)+base64,)?(\S+)/;
  var LcovRecord = (function () {
      function LcovRecord() {
          this.tn = '';
          this.sourceFile = '';
          this.functions = [];
          this.functionCount = 0;
          this.functionCoveredCount = 0;
          this.functionsAccessed = [];
          this.linesAccessed = [];
          this.lineCount = 0;
          this.lineCoveredCount = 0;
          this.branchesCovered = [];
          this.branchCount = 0;
          this.branchCoveredCount = 0;
      }
      return LcovRecord;
  })();
  module.exports = function (grunt) {
      function parseLcov(lcov) {
          function parseRecord(record) {
              var result = new LcovRecord();
              result.functions = [];
              result.functionsAccessed = [];
              result.linesAccessed = [];
              result.branchesCovered = [];
              record.forEach(function (line) {
                  var execResult;
                  if (execResult = TN.exec(line)) {
                      result.tn = execResult[1];
                  }
                  else if (execResult = SF.exec(line)) {
                      result.sourceFile = execResult[1];
                  }
                  else if (execResult = FN.exec(line)) {
                      result.functions.push({
                          lineNumber: Number(execResult[1]),
                          functionName: execResult[2]
                      });
                  }
                  else if (execResult = FNF.exec(line)) {
                      result.functionCount = Number(execResult[1]);
                  }
                  else if (execResult = FNH.exec(line)) {
                      result.functionCoveredCount = Number(execResult[1]);
                  }
                  else if (execResult = FNDA.exec(line)) {
                      result.functionsAccessed.push({
                          count: Number(execResult[1]),
                          functionName: execResult[2]
                      });
                  }
                  else if (execResult = DA.exec(line)) {
                      result.linesAccessed.push({
                          lineNumber: Number(execResult[1]),
                          count: Number(execResult[2])
                      });
                  }
                  else if (execResult = LF.exec(line)) {
                      result.lineCount = Number(execResult[1]);
                  }
                  else if (execResult = LH.exec(line)) {
                      result.lineCoveredCount = Number(execResult[1]);
                  }
                  else if (execResult = BRDA.exec(line)) {
                      result.branchesCovered.push({
                          lineNumber: Number(execResult[1]),
                          id: Number(execResult[2]),
                          branch: Number(execResult[3]),
                          count: Number(execResult[4])
                      });
                  }
                  else if (execResult = BRF.exec(line)) {
                      result.branchCount = Number(execResult[1]);
                  }
                  else if (execResult = BRH.exec(line)) {
                      result.branchCoveredCount = Number(execResult[1]);
                  }
              });
              return result;
          }
          var records = [];
          var lines = lcov.match(/[^\r\n]+/g);
          var record = [];
          lines.forEach(function (line) {
              if (line.match(END_OF_RECORD)) {
                  records.push(parseRecord(record));
                  record = [];
              }
              else {
                  record.push(line);
              }
          });
          return records;
      }
      ;
      function remap(lcovRecord, src, smc) {
          var funcPos = [];
          var inComment = false;
          src.forEach(function (item, idx) {
              var reg = /function\s+([^ "'\(]+)?\s*\(/g;
              var commentStart = /\/\*/.exec(item);
              var commentEnd = /\*\//.exec(item);
              var commentLine = /\/{2}/.exec(item);
              var match;
              while (match = reg.exec(item)) {
                  if (commentLine && commentLine.index < match.index) {
                      continue;
                  }
                  if (inComment && (!commentEnd || (commentEnd && match.index < commentEnd.index))) {
                      continue;
                  }
                  if (commentStart && commentStart.index < match.index) {
                      if (!commentEnd || (commentEnd && commentEnd.index > match.index)) {
                          continue;
                      }
                  }
                  funcPos.push({
                      line: idx + 1,
                      column: match.index + match[0].length + 1,
                      name: match[1]
                  });
              }
              if (inComment && commentEnd && !commentStart) {
                  inComment = false;
              }
              if (commentStart && !commentEnd) {
                  inComment = true;
              }
          });
          var source;
          funcPos = funcPos.map(function (item) {
              var originalPosition = smc.originalPositionFor({ line: item.line, column: item.column });
              if (originalPosition.source) {
                  if (!source) {
                      source = originalPosition.source;
                  }
                  else if (source !== originalPosition.source) {
                      throw new Error('Mapping between difference source files not supported: "' + source + '" and "' + originalPosition.source + '"');
                  }
              }
              item.originalLine = originalPosition.line;
              return item;
          });
          lcovRecord.sourceFile = source.replace('../../', '');
          if (funcPos.length !== lcovRecord.functions.length) {
              throw new Error('Cannot re-map functions due to lack of matching');
          }
          lcovRecord.functions = lcovRecord.functions.map(function (item, idx) {
              if (item.lineNumber === funcPos[idx].line && funcPos[idx].originalLine) {
                  item.lineNumber = funcPos[idx].originalLine;
              }
              else if (item.lineNumber !== funcPos[idx].line) {
                  grunt.log.error('Emitted line numbers do not match for function: ' + item.functionName);
              }
              return item;
          });
          var lineMap = Array(src.length + 1);
          smc.eachMapping(function (item) {
              if (!lineMap[item.generatedLine]) {
                  lineMap[item.generatedLine] = [];
              }
              if (!~lineMap[item.generatedLine].indexOf(item.originalLine)) {
                  lineMap[item.generatedLine].push(item.originalLine);
              }
          });
          var mappedAccessedLines = [];
          var lineHash = {};
          lcovRecord.linesAccessed.forEach(function (item) {
              var lines;
              if (lines = lineMap[item.lineNumber]) {
                  lines.forEach(function (lineNumber) {
                      if (!(lineNumber in lineHash)) {
                          lineHash[lineNumber] = true;
                          mappedAccessedLines.push({
                              lineNumber: lineNumber,
                              count: item.count
                          });
                      }
                  });
              }
          });
          mappedAccessedLines.sort(function (a, b) { return a.lineNumber === b.lineNumber ? 0 : a.lineNumber < b.lineNumber ? -1 : 1; });
          lcovRecord.linesAccessed = mappedAccessedLines;
          lcovRecord.lineCount = mappedAccessedLines.length;
          lcovRecord.lineCoveredCount = mappedAccessedLines.reduce(function (previousValue, currentValue) { return previousValue + (currentValue.count ? 1 : 0); }, 0);
          var branchesCovered = [];
          var priorId = 0;
          var branchId = 0;
          lcovRecord.branchesCovered.forEach(function (branch) {
              if (lineMap[branch.lineNumber]) {
                  if (priorId !== branch.id) {
                      priorId = branch.id;
                      branchId++;
                  }
                  branchesCovered.push({
                      lineNumber: lineMap[branch.lineNumber][0],
                      id: branchId,
                      branch: branch.branch,
                      count: branch.count
                  });
              }
          });
          lcovRecord.branchesCovered = branchesCovered;
          lcovRecord.branchCount = branchesCovered.length;
          lcovRecord.branchCoveredCount = branchesCovered.reduce(function (previousValue, currentValue) { return previousValue + (currentValue.count ? 1 : 0); }, 0);
      }
      function emitLcov(records) {
          var lcov = [];
          function writeRecord(record) {
              var result = [];
              result.push('TN:' + record.tn);
              result.push('SF:' + record.sourceFile);
              record.functions.forEach(function (item) {
                  result.push('FN:' + item.lineNumber + ',' + item.functionName);
              });
              result.push('FNF:' + record.functionCount);
              result.push('FNH:' + record.functionCoveredCount);
              record.functionsAccessed.forEach(function (item) {
                  result.push('FNDA:' + item.count + ',' + item.functionName);
              });
              record.linesAccessed.forEach(function (item) {
                  result.push('DA:' + item.lineNumber + ',' + item.count);
              });
              result.push('LF:' + record.lineCount);
              result.push('LH:' + record.lineCoveredCount);
              record.branchesCovered.forEach(function (item) {
                  result.push('BRDA:' + item.lineNumber + ',' + item.id + ',' + item.branch + ',' + item.count);
              });
              result.push('BRF:' + record.branchCount);
              result.push('BRH:' + record.branchCoveredCount);
              result.push('end_of_record');
              return result;
          }
          records.forEach(function (record) {
              lcov = lcov.concat(writeRecord(record));
          });
          return lcov.join('\n');
      }
      grunt.registerMultiTask('cover_ts', 'Takes line coverage information and source maps to determine coverage for TypeScript.', function () {
          var done = this.async();
          var options = this.options({});
          this.files.forEach(function (file) {
              var destContent = '';
              file.src.forEach(function (fileName) {
                  var parsedLcov = parseLcov(grunt.file.read(fileName));
                  parsedLcov.map(function (item) { return item.sourceFile; }).forEach(function (sourceFileName) {
                      grunt.log.writeln('Processing: ' + sourceFileName);
                      var sourceFileText = grunt.file.read(sourceFileName);
                      var src = sourceFileText.match(/[^\r\n]+/g);
                      var sourceMappingURL = sourceMapRegEx.exec(sourceFileText);
                      var sourceMapContent;
                      if (sourceMappingURL && sourceMappingURL[1]) {
                          var buffer = new Buffer(sourceMappingURL[2], 'base64');
                          sourceMapContent = JSON.parse(buffer.toString('ascii'));
                      }
                      else if (sourceMappingURL) {
                          sourceMapContent = grunt.file.readJSON(path.join(path.dirname(sourceFileName), sourceMappingURL[2]));
                      }
                      else {
                          sourceMapContent = grunt.file.readJSON(sourceFileName + '.map');
                      }
                      var smc = new sourceMap.SourceMapConsumer(sourceMapContent);
                      parsedLcov.forEach(function (lcovRecord) {
                          if (lcovRecord.sourceFile === sourceFileName) {
                              remap(lcovRecord, src, smc);
                          }
                      });
                  });
                  var content = emitLcov(parsedLcov);
                  if (file.dest) {
                      destContent += content;
                  }
                  else {
                      grunt.file.write(fileName, content);
                  }
              });
              if (file.dest) {
                  grunt.file.write(file.dest, destContent);
              }
          });
          done();
      });
  };
  //# sourceMappingURL=cover_ts.js.map