// Copyright 2012 Traceur Authors. // // Licensed under the Apache License, Version 2.0 (the “License”); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an “AS IS” BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.

'use strict';

var fs = require('fs'); var path = require('path'); var nodeLoader = require('./nodeLoader.js'); var normalizePath = require('./file-util.js').normalizePath;

var TraceurLoader = traceur.runtime.TraceurLoader; var LoaderHooks = traceur.runtime.LoaderHooks; var Script = traceur.syntax.trees.Script; var SourceFile = traceur.syntax.SourceFile var moduleStore = traceur.runtime.ModuleStore;

/**

* @param {ErrorReporter} reporter
* @param {Array.<ParseTree>} elements
* @param {string|undefined} depTarget A valid depTarget means dependency
*     printing was requested.
*/

function InlineLoaderHooks(reporter, url, elements, depTarget) {

LoaderHooks.call(this, reporter, url,
    nodeLoader,  // Load modules using node fs.
    moduleStore);  // Look up modules in our static module store
this.dirname = url;
this.elements = elements;
this.depTarget = depTarget && normalizePath(path.relative('.', depTarget));
this.codeUnitList = [];

}

InlineLoaderHooks.prototype = {

__proto__: LoaderHooks.prototype,

evaluateCodeUnit: function(codeUnit) {
  if (this.depTarget) {
    console.log('%s: %s', this.depTarget,
                normalizePath(path.relative(path.join(__dirname, '../..'),
                codeUnit.url)));
  }
  // Don't eval. Instead append the trees to the output.
  var tree = codeUnit.metadata.transformedTree;
  this.elements.push.apply(this.elements, tree.scriptItemList);
},

};

function allLoaded(url, reporter, elements) {

return new Script(null, elements);

}

/**

* Compiles the files in "filenames" along with any associated modules, into a
* single js file, in proper module dependency order.
*
* @param {Array.<string>} filenames The list of files to compile and concat.
* @param {Object} options A container for misc options. 'depTarget' is the
*     only currently available option, which results in the dependencies for
*     'filenames' being printed to stdout, with 'depTarget' as the target.
* @param {ErrorReporter} reporter
* @param {Function} callback Callback used to return the result. A null result
*     indicates that inlineAndCompile has returned successfully from a
*     non-compile request.
* @param {Function} errback Callback used to return errors.
*/

function inlineAndCompile(filenames, options, reporter, callback, errback) {

var depTarget = options && options.depTarget;
var referrerName = options && options.referrer;

var basePath;
if (referrerName) {
  // The compile occurs two directories down from current directory,
  // in src/node.  Thus the names will appear as eg ../src/x.
  // We want something like referrerName/src/x. So we need to give
  // the normalize() the 'package' or root name with src/node append
  // to represent the referrer from here.
  referrerName = referrerName && referrerName + 'src/node';
  // The basePath will replace options.referrer in our final filename.
  // Since we are in src/node, we need to back up two directories.
  basePath = path.join(__dirname, '../../');
} else {
  basePath = path.resolve('./') + '/';
}
basePath = basePath.replace(/\\/g, '/');

var scriptsCount = options.scripts.length;

var loadCount = 0;
var elements = [];
var hooks = new InlineLoaderHooks(reporter, basePath, elements, depTarget);
var loader = new TraceurLoader(hooks);

function appendEvaluateModule(name, referrerName) {
  var normalizedName =
      traceur.ModuleStore.normalize(name, referrerName);
  // Create tree for System.get('normalizedName');
  var tree =
      traceur.codegeneration.module.createModuleEvaluationStatement(normalizedName);
  elements.push(tree);
}

function loadNext() {
  var loadAsScript = scriptsCount && (loadCount < scriptsCount);
  var doEvaluateModule = false;
  var loadFunction = loader.import;
  var name = filenames[loadCount];
  if (loadAsScript) {
    loadFunction = loader.loadAsScript;
  } else {
    name = name.replace(/\.js$/,'');
    if (options.modules !== 'inline' && options.modules !== 'instantiate')
      doEvaluateModule = true;
  }
  var loadOptions = {referrerName: referrerName};
  var codeUnit = loadFunction.call(loader, name, loadOptions).then(
      function() {
        if (doEvaluateModule)
          appendEvaluateModule(name, referrerName);
        loadCount++;
        if (loadCount < filenames.length) {
          loadNext();
        } else if (depTarget) {
          callback(null);
        } else {
          var tree = allLoaded(basePath, reporter, elements);
          callback(tree);
        }
      }, function(err) {
        errback(err);
      }).catch(function(ex) {
        console.error('Internal error ' + (ex.stack || ex));
      });
}

loadNext();

} exports.inlineAndCompile = inlineAndCompile;