emberjs/emberjs-build

View on GitHub
lib/get-package-dependency-tree.js

Summary

Maintainability
A
1 hr
Test Coverage
'use strict';

// to avoid circular dependency shenanigans
module.exports = packageDependencyTree;

var mergeTrees = require('broccoli-merge-trees');

var es6Package          = require('./get-es6-package');
var getVendoredPackages = require('./get-vendored-packages');

/*
  Iterate over dependencyTree as specified within `lib/packages.js`.
  Make sure all dependencies are met for each package.
*/
function packageDependencyTree(packages, packageName, opts) {
  var options = opts || {};
  var vendoredPackages = options.vendoredPackages || getVendoredPackages();
  var dependencyTrees = packages[packageName]['dependencyTrees'];

  // Return if we've already processed this package
  if (dependencyTrees) {
    return dependencyTrees;
  } else {
    dependencyTrees = [];
  }

  var requiredDependencies = packages[packageName]['requirements'] || [];
  var vendoredDependencies = packages[packageName]['vendorRequirements'] || [];

  var libTrees = [];
  var vendorTrees = [];

  // Push vendorPackage tree onto vendorTrees array local hash lookup.
  // See above.
  vendoredDependencies.forEach(function(dependency) {
    var result = vendoredPackages[dependency];
    if (typeof result === 'object' && result !== null) {
      vendorTrees.push(result);
    } else {
      throw new TypeError('vendoredDependency `' + dependency +
                          '` is missing. It is dependent on by `' + packageName + '`');
    }
  });

  /*
    For example (simplified for demonstration):

    ```
      {
        'ember-views':   {requirements: ['ember-runtime']},
        'ember-runtime': {requirements: ['container', 'ember-metal']},
        'container':     {requirements: []},
        'ember-metal':   {requirements: []}
      }
    ```

    When processing `ember-views` will process dependencies (this is recursive).
    This will call itself on `ember-runtime` which will in turn call itself on
    `container` and then `ember-metal` which (because it has no requirements)
    will terminate the recursion.
    Finally each recurse will return the dependency's lib tree.  So we end with
    an array of lib trees for each dependency in the graph
  */
  requiredDependencies.forEach(function(dependency) {
    libTrees.concat(packageDependencyTree(packages, dependency, {
      vendoredPackages: vendoredPackages
    }));
    libTrees.push(es6Package(packages, dependency, {
      vendoredPackages: vendoredPackages
    }).lib);
  });
  // }, this);

  /*
    Merge and return dependencyTrees.  Overwrite _MUST_ occur in order to
    prevent requirements from stepping on one another.
  */
  packages[packageName]['vendorTrees']            = mergeTrees(vendorTrees, {overwrite: true});
  return packages[packageName]['dependencyTrees'] = mergeTrees(libTrees, {overwrite: true});
}