<commit_before>import * as T from 'babel-types';
import traverse from 'babel-traverse';

// TODO: Will need to think hard about how to improve the apis seen here (pluggability)

/** Given a module ast get reference to the default export path */
function getDefaultExportPath(moduleAst) {
  let identifierPath;

  traverse(moduleAst, {
    ExportDefaultDeclaration(nodePath) {
      nodePath.traverse({
        Identifier(identifierNodePath) {
          identifierPath = identifierNodePath;
        }
      });
    },
    ExportSpecifier(nodePath) {
      if (
        !identifierPath
        && nodePath.node.exported.name === 'default'
        && T.isExportNamedDeclaration(nodePath.parentPath.node)
        && nodePath.parentPath.node.source
      ) {
        identifierPath = nodePath;
      }
    }
  });

  return identifierPath;
}

/** Given a module ast get reference to a specific export path */
function getExportPath(name, moduleAst) {
  if (name === 'default') {
    return getDefaultExportPath(moduleAst);
  }

  let identifierPath;

  const specifierVisitor = {
    ExportSpecifier(nodePath) {
      if (
        !identifierPath
        && nodePath.node.exported.name === name
      ) {
        identifierPath = nodePath;
      }
    }
  };

  const identifierVisitor = {
    Identifier(identifierNodePath) {
      if (!identifierPath && identifierNodePath.node.name === name) {
        identifierPath = identifierNodePath;
      }
    }
  };

  traverse(moduleAst, {
    ExportNamedDeclaration(nodePath) {
      if (!identifierPath && nodePath.node.specifiers.length) {
        nodePath.traverse(specifierVisitor);
      } else {
        nodePath.traverse(identifierVisitor);
      }
    }
  });

  return identifierPath;
}

/**
 * Given a path resolve it's definition which may be found in other modules.
 * Ie. This is not resolving the binding within the bounds of a module but will
 * also resolve imports to find the very root definition.
 *
 * Note: nodePath could be an Identifier path OR ExportSpecifier path
 */
export function resolveDefinition(module, nodePath, resolveModule) {
  // export {definition as definition} from 'other-module';
  if (T.isExportSpecifier(nodePath.node) && nodePath.parent.source) {
    const importModulePath = nodePath.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getExportPath(nodePath.node.local.name, importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  const binding = T.isExportSpecifier(nodePath.node)
    ? nodePath.scope.getBinding(nodePath.node.local.name)
    : nodePath.scope.getBinding(nodePath.node.name);

  // const definition = 'foo';
  // function definition() {};
  // class Definition {}
  if (
    T.isVariableDeclarator(binding.path.node)
    || T.isFunctionDeclaration(binding.path.node)
    || T.isClassDeclaration(binding.path.node)
  ) {
    return {
      binding,
      module
    };
  }

  // import {definition} from './other-module';
  if (T.isImportSpecifier(binding.path.node)) {
    const importModulePath = binding.path.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getExportPath(binding.path.node.imported.name, importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  // import definition from './other-module';
  if (T.isImportDefaultSpecifier(binding.path.node)) {
    const importModulePath = binding.path.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getDefaultExportPath(importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  // ¯\_(ツ)_/¯
  return {
    failed: true
  };

}

/**
 * Like resolveDefinition but will attempt to resolve components through facades.
 * Eg.
 *   withState(MyComponent);
 *   createContainer(MyComponent, {});
 *   etc.
 */
export function resolveRootComponentDefinition(nodePath, resolveFile) {

}

/**
 * Resolve a component definition taking into account facades and composiiton
 */
export function resolveComponentDefinition() {
  // TODO: Implement
}
<commit_msg>Tidy export code<commit_after>import * as T from 'babel-types';
import traverse from 'babel-traverse';

// TODO: Will need to think hard about how to improve the apis seen here (pluggability)

/**
 * Given a module ast get reference to a specific export path
 * NOTE: name === "default" is treated specially
 */
function getExportPath(name, moduleAst) {
  let identifierPath;

  // Find `export default definition;`
  const defaultVisitor = {
    ExportDefaultDeclaration(nodePath) {
      nodePath.traverse({
        Identifier(identifierNodePath) {
          identifierPath = identifierNodePath;
        }
      });
    }
  };

  if (name === 'default') {
    traverse(moduleAst, defaultVisitor);
  }

  // Find appropriate specifier in `export {foo as bar};`
  const specifierVisitor = {
    ExportSpecifier(nodePath) {
      if (nodePath.node.exported.name === name) {
        identifierPath = nodePath;
      }
    }
  };

  // pull identifier out of `export const definition = 'foo';`
  const identifierVisitor = {
    Identifier(identifierNodePath) {
      if (!identifierPath && identifierNodePath.node.name === name) {
        identifierPath = identifierNodePath;
      }
    }
  };

  const namedVisitor = {
    ExportNamedDeclaration(nodePath) {
      if (!identifierPath) {
        if (nodePath.node.specifiers.length) {
          nodePath.traverse(specifierVisitor);
        } else {
          nodePath.traverse(identifierVisitor);
        }
      }
    }
  };

  traverse(moduleAst, namedVisitor);

  return identifierPath;
}

/**
 * Given a path resolve it's definition which may be found in other modules.
 * Ie. This is not resolving the binding within the bounds of a module but will
 * also resolve imports to find the very root definition.
 *
 * Note: nodePath should be an Identifier path OR ExportSpecifier path within
 *       the scope of the specified module
 */
export function resolveDefinition(module, nodePath, resolveModule) {
  // export {definition as definition} from 'other-module';
  if (T.isExportSpecifier(nodePath.node) && nodePath.parent.source) {
    const importModulePath = nodePath.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getExportPath(nodePath.node.local.name, importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  const binding = T.isExportSpecifier(nodePath.node)
    ? nodePath.scope.getBinding(nodePath.node.local.name)
    : nodePath.scope.getBinding(nodePath.node.name);

  // const definition = 'foo';
  // function definition() {};
  // class Definition {}
  if (
    T.isVariableDeclarator(binding.path.node)
    || T.isFunctionDeclaration(binding.path.node)
    || T.isClassDeclaration(binding.path.node)
  ) {
    return {
      binding,
      module
    };
  }

  // import {definition} from './other-module';
  if (T.isImportSpecifier(binding.path.node)) {
    const importModulePath = binding.path.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getExportPath(binding.path.node.imported.name, importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  // import definition from './other-module';
  if (T.isImportDefaultSpecifier(binding.path.node)) {
    const importModulePath = binding.path.parent.source.value;
    const importedModule = resolveModule(module, importModulePath);
    const identifier = getExportPath('default', importedModule.ast);

    return resolveDefinition(importedModule.path, identifier, resolveModule);
  }

  // ¯\_(ツ)_/¯
  return {
    failed: true
  };

}

/**
 * Like resolveDefinition but will attempt to resolve components through facades.
 * Eg.
 *   withState(MyComponent);
 *   createContainer(MyComponent, {});
 *   etc.
 */
export function resolveRootComponentDefinition(nodePath, resolveFile) {

}

/**
 * Resolve a component definition taking into account facades and composiiton
 */
export function resolveComponentDefinition() {
  // TODO: Implement
}

{'fraction_non_alphanumeric': 0.10668426737069482, 'fraction_numerical': 0.0, 'mean_word_length': 3.4424307036247335, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '731541', 'n_tokens_mistral': 2357, 'n_tokens_neox': 2298, 'n_words': 570}