etnbrd/flx-compiler

View on GitHub
lib/analyzer/helpers.js

Summary

Maintainability
C
7 hrs
Test Coverage
var fs = require('fs'),
    pth = require('path'),
    estraverse = require('estraverse'),
    getIdIterator = require('./getid'),
    errors = require('../lib/errors'),
    h = require('../lib/helpers');

function compareScopeByBlock(n) {
  return function(scope) {
    return (scope.block === n);
  };
}

function getScopeName(scope) {
  if (scope.block.id)
    return scope.block.id.name;
  if (scope.block.type === 'Program')
    return 'Program';

  return 'anonymous';
}

function collectId(n) {
  var collector = {ids: []};
  estraverse.traverse(n, getIdIterator(collector));
  return collector;      
}

// TODO Move to global helpers, and make an extension system for the helpers : an helper in each module extending the global helper. 
function singlify(a) {
  if (a.length > 1) {
    throw errors.multipleOccurences(a);
  } else {
    return a[0];
  }
}


function decypherPath(path, _dirname) {

  var filepath = pth.resolve(_dirname, path);

  if (fs.existsSync(filepath)) {
    if (fs.lstatSync(filepath).isDirectory() && fs.existsSync(filepath + '/index.js')) {
      filepath += '/index.js';
    }
  } else {
    if (filepath.lastIndexOf('.js') !== filepath.length - 3 && fs.existsSync(filepath + '.js')) {
      filepath += '.js';
    }
  }

  return filepath;
}

function populate(variable) {

  function local(scope, variable) {
    scope.references.forEach(function(reference) {
      if (reference.identifier.name === variable.name) {
        variable.references.push(reference);
        reference.resolved = variable;
      }
    });
  }

  // populate the references array of `variable` with all references from all nested child scope
  function global(scopes, variable) {
    scopes.forEach(function(scope) {
      // Break when another variable of the same name is declared
      if (scope.variables.some(function(_variable) {
            return _variable.name === variable.name;
          })) {
        return;
      }

      // Push matching references
      local(scope, variable);

      // Recurse
      global(scope.childScopes, variable);
    });
  }

  // Push local matching references
  if (variable.references.length === 0) {
    local(variable.scope, variable);
  }

  // Start scope lookup recursion
  global(variable.scope.childScopes, variable);

  return variable;
}

module.exports = {
  compareScopeByBlock: compareScopeByBlock,
  getScopeName: getScopeName,
  decypherPath: decypherPath,
  populate: populate,
  collectId: collectId,
  singlify: singlify
};