text: /// <reference path="../../defs/tsd.d.ts"/>
  /// <reference path="./interfaces.d.ts"/>
  'use strict';
  var path = require('path');
  var fs = require('fs');
  var _ = require('lodash');
  var utils = require('./utils');
  var cache = require('./cacheUtils');
  var es6_promise_1 = require('es6-promise');
  exports.grunt = require('grunt');
  ///////////////////////////
  // Helper
  ///////////////////////////
  var executeNode;
  var executeNodeDefault = function (args, optionalInfo) {
      return new es6_promise_1.Promise(function (resolve, reject) {
          exports.grunt.util.spawn({
              cmd: process.execPath,
              args: args
          }, function (error, result, code) {
              var ret = {
                  code: code,
                  // New TypeScript compiler uses stdout for user code errors. Old one used stderr.
                  output: result.stdout || result.stderr
              };
              resolve(ret);
          });
      });
  };
  /////////////////////////////////////////////////////////////////
  // Fast Compilation
  /////////////////////////////////////////////////////////////////
  // Map to store if the cache was cleared after the gruntfile was parsed
  var cacheClearedOnce = {};
  function getChangedFiles(files, targetName) {
      files = cache.getNewFilesForTarget(files, targetName);
      _.forEach(files, function (file) {
          exports.grunt.log.writeln(('### Fast Compile >>' + file).cyan);
      });
      return files;
  }
  function resetChangedFiles(files, targetName) {
      cache.compileSuccessfull(files, targetName);
  }
  function clearCache(targetName) {
      cache.clearCache(targetName);
      cacheClearedOnce[targetName] = true;
  }
  /////////////////////////////////////////////////////////////////////
  // tsc handling
  ////////////////////////////////////////////////////////////////////
  function resolveTypeScriptBinPath() {
      var ownRoot = path.resolve(path.dirname((module).filename), '../..');
      var userRoot = path.resolve(ownRoot, '..', '..');
      var binSub = path.join('node_modules', 'typescript', 'bin');
      if (fs.existsSync(path.join(userRoot, binSub))) {
          // Using project override
          return path.join(userRoot, binSub);
      }
      return path.join(ownRoot, binSub);
  }
  function getTsc(binPath) {
      var pkg = JSON.parse(fs.readFileSync(path.resolve(binPath, '..', 'package.json')).toString());
      exports.grunt.log.writeln('Using tsc v' + pkg.version);
      return path.join(binPath, 'tsc');
  }
  function compileAllFiles(options, compilationInfo) {
      var targetFiles = compilationInfo.src;
      // Make a local copy so we can modify files without having external side effects
      var files = _.map(targetFiles, function (file) { return file; });
      var newFiles = files;
      if (options.fast === 'watch') {
          // if this is the first time its running after this file was loaded
          if (cacheClearedOnce[exports.grunt.task.current.target] === undefined) {
              // Then clear the cache for this target
              clearCache(options.targetName);
          }
      }
      if (options.fast !== 'never') {
          if (compilationInfo.out) {
              exports.grunt.log.writeln('Fast compile will not work when --out is specified. Ignoring fast compilation'.cyan);
          }
          else {
              newFiles = getChangedFiles(files, options.targetName);
              if (newFiles.length !== 0 || options.testExecute || utils.shouldPassThrough(options)) {
                  files = newFiles;
                  // If outDir is specified but no baseDir is specified we need to determine one
                  if (compilationInfo.outDir && !options.baseDir) {
                      options.baseDir = utils.findCommonPath(files, '/');
                  }
              }
              else {
                  exports.grunt.log.writeln('No file changes were detected. Skipping Compile'.green);
                  return new es6_promise_1.Promise(function (resolve) {
                      var ret = {
                          code: 0,
                          fileCount: 0,
                          output: 'No files compiled as no change detected'
                      };
                      resolve(ret);
                  });
              }
          }
      }
      // Transform files as needed. Currently all of this logic in is one module
      // transformers.transformFiles(newFiles, targetFiles, target, task);
      // If baseDir is specified create a temp tsc file to make sure that `--outDir` works fine
      // see https://github.com/grunt-ts/grunt-ts/issues/77
      var baseDirFile = '.baseDir.ts';
      var baseDirFilePath;
      if (compilationInfo.outDir && options.baseDir && files.length > 0) {
          baseDirFilePath = path.join(options.baseDir, baseDirFile);
          if (!fs.existsSync(baseDirFilePath)) {
              exports.grunt.file.write(baseDirFilePath, '// Ignore this file. See https://github.com/grunt-ts/grunt-ts/issues/77');
          }
          files.push(baseDirFilePath);
      }
      // If reference and out are both specified.
      // Then only compile the updated reference file as that contains the correct order
      if (options.reference && compilationInfo.out) {
          var referenceFile = path.resolve(options.reference);
          files = [referenceFile];
      }
      // Quote the files to compile. Needed for command line parsing by tsc
      files = _.map(files, function (item) { return ("\"" + path.resolve(item) + "\""); });
      // if (outFile) {
      //   outFile = `"${path.resolve(outFile)}"`;
      // }
      var args = files.slice(0);
      var tsconfig = options.tsconfig;
      if (tsconfig && tsconfig.passThrough) {
          args.push('--project', tsconfig.tsconfig);
      }
      else {
          if (options.sourceMap) {
              args.push('--sourcemap');
          }
          if (options.emitDecoratorMetadata) {
              args.push('--emitDecoratorMetadata');
          }
          if (options.declaration) {
              args.push('--declaration');
          }
          if (options.removeComments) {
              args.push('--removeComments');
          }
          if (options.noImplicitAny) {
              args.push('--noImplicitAny');
          }
          if (options.noResolve) {
              args.push('--noResolve');
          }
          if (options.noEmitOnError) {
              args.push('--noEmitOnError');
          }
          if (options.preserveConstEnums) {
              args.push('--preserveConstEnums');
          }
          if (options.suppressImplicitAnyIndexErrors) {
              args.push('--suppressImplicitAnyIndexErrors');
          }
          if (options.noEmit) {
              args.push('--noEmit');
          }
          if (options.inlineSources) {
              args.push('--inlineSources');
          }
          if (options.inlineSourceMap) {
              args.push('--inlineSourceMap');
          }
          if (options.newLine && !utils.newLineIsRedundant(options.newLine)) {
              args.push('--newLine', options.newLine);
          }
          if (options.isolatedModules) {
              args.push('--isolatedModules');
          }
          if (options.noEmitHelpers) {
              args.push('--noEmitHelpers');
          }
          if (options.experimentalDecorators) {
              args.push('--experimentalDecorators');
          }
          if (options.experimentalAsyncFunctions) {
              args.push('--experimentalAsyncFunctions');
          }
          if (options.jsx) {
              args.push('--jsx', options.jsx.toLocaleLowerCase());
          }
          if (options.moduleResolution) {
              args.push('--moduleResolution', options.moduleResolution.toLocaleLowerCase());
          }
          if (options.rootDir) {
              args.push('--rootDir', options.rootDir);
          }
          args.push('--target', options.target.toUpperCase());
          if (options.module) {
              var moduleOptionString = ('' + options.module).toLowerCase();
              if ('amd|commonjs|system|umd'.indexOf(moduleOptionString) > -1) {
                  args.push('--module', moduleOptionString);
              }
              else {
                  console.warn('WARNING: Option "module" only supports "amd" | "commonjs" | "system" | "umd" '.magenta);
              }
          }
          if (compilationInfo.outDir) {
              if (compilationInfo.out) {
                  console.warn('WARNING: Option "out" and "outDir" should not be used together'.magenta);
              }
              args.push('--outDir', compilationInfo.outDir);
          }
          if (compilationInfo.out) {
              args.push('--out', compilationInfo.out);
          }
          if (compilationInfo.dest && (!compilationInfo.out) && (!compilationInfo.outDir)) {
              if (utils.isJavaScriptFile(compilationInfo.dest)) {
                  args.push('--out', compilationInfo.dest);
              }
              else {
                  if (compilationInfo.dest === 'src') {
                      console.warn(('WARNING: Destination for target "' + options.targetName + '" is "src", which is the default.  If you have' +
                          ' forgotten to specify a "dest" parameter, please add it.  If this is correct, you may wish' +
                          ' to change the "dest" parameter to "src/" or just ignore this warning.').magenta);
                  }
                  if (Array.isArray(compilationInfo.dest)) {
                      if (compilationInfo.dest.length === 0) {
                      }
                      else if (compilationInfo.dest.length > 0) {
                          console.warn((('WARNING: "dest" for target "' + options.targetName + '" is an array.  This is not supported by the' +
                              ' TypeScript compiler or grunt-ts.' +
                              ((compilationInfo.dest.length > 1) ? '  Only the first "dest" will be used.  The' +
                                  ' remaining items will be truncated.' : ''))).magenta);
                          args.push('--outDir', compilationInfo.dest[0]);
                      }
                  }
                  else {
                      args.push('--outDir', compilationInfo.dest);
                  }
              }
          }
          if (args.indexOf('--out') > -1 && args.indexOf('--module') > -1) {
              console.warn(('WARNING: TypeScript does not allow external modules to be concatenated with' +
                  ' --out. Any exported code may be truncated.  See TypeScript issue #1544 for' +
                  ' more details.').magenta);
          }
          if (options.sourceRoot) {
              args.push('--sourceRoot', options.sourceRoot);
          }
          if (options.mapRoot) {
              args.push('--mapRoot', options.mapRoot);
          }
      }
      if (options.additionalFlags) {
          args.push(options.additionalFlags);
      }
      // Locate a compiler
      var tsc;
      if (options.compiler) {
          exports.grunt.log.writeln('Using the custom compiler : ' + options.compiler);
          tsc = options.compiler;
      }
      else {
          tsc = getTsc(resolveTypeScriptBinPath());
      }
      // To debug the tsc command
      if (options.verbose) {
          console.log(args.join(' ').yellow);
      }
      else {
          exports.grunt.log.verbose.writeln(args.join(' ').yellow);
      }
      // Create a temp last command file and use that to guide tsc.
      // Reason: passing all the files on the command line causes TSC to go in an infinite loop.
      var tempfilename = utils.getTempFile('tscommand');
      if (!tempfilename) {
          throw (new Error('cannot create temp file'));
      }
      fs.writeFileSync(tempfilename, args.join(' '));
      var command;
      // Switch implementation if a test version of executeNode exists.
      if ('testExecute' in options) {
          if (_.isFunction(options.testExecute)) {
              command = [tsc, args.join(' ')];
              executeNode = options.testExecute;
          }
          else {
              var invalidTestExecuteError = 'Invalid testExecute node present on target "' +
                  options.targetName + '".  Value of testExecute must be a function.';
              throw (new Error(invalidTestExecuteError));
          }
      }
      else {
          // this is the normal path.
          command = [tsc, '@' + tempfilename];
          executeNode = executeNodeDefault;
      }
      // Execute command
      return executeNode(command, options).then(function (result) {
          if (options.fast !== 'never' && result.code === 0) {
              resetChangedFiles(newFiles, options.targetName);
          }
          result.fileCount = files.length;
          fs.unlinkSync(tempfilename);
          exports.grunt.log.writeln(result.output);
          return es6_promise_1.Promise.cast(result);
      }, function (err) {
          fs.unlinkSync(tempfilename);
          throw err;
      });
  }
  exports.compileAllFiles = compileAllFiles;
  //# sourceMappingURL=compile.js.map