import * as react from "../../../transformation/helpers/react";
import * as t from "../../../types";

/**
 * [Please add a description.]
 */

export var ReferencedIdentifier = {
  types: ["Identifier", "JSXIdentifier"],
  checkPath({ node, parent }, opts) {
    if (!t.isIdentifier(node, opts)) {
      if (t.isJSXIdentifier(node, opts)) {
        if (react.isCompatTag(node.name)) return false;
      } else {
        // not a JSXIdentifier or an Identifier
        return false;
      }
    }

    // check if node is referenced
    return t.isReferenced(node, parent);
  }
};

/**
 * [Please add a description.]
 */

export var BindingIdentifier = {
  types: ["Identifier"],
  checkPath({ node, parent }) {
    return t.isBinding(node, parent);
  }
};

/**
 * [Please add a description.]
 */

export var Statement = {
  types: ["Statement"],
  checkPath({ node, parent }) {
    if (t.isStatement(node)) {
      if (t.isVariableDeclaration(node)) {
        if (t.isForXStatement(parent, { left: node })) return false;
        if (t.isForStatement(parent, { init: node })) return false;
      }

      return true;
    } else {
      return false;
    }
  }
};

/**
 * [Please add a description.]
 */

export var Expression = {
  types: ["Expression"],
  checkPath(path) {
    if (path.isIdentifier()) {
      return path.isReferencedIdentifier();
    } else {
      return t.isExpression(path.node);
    }
  }
};

/**
 * [Please add a description.]
 */

export var Scope = {
  types: ["Scopable"],
  checkPath(path) {
    return t.isScope(path.node, path.parent);
  }
};

/**
 * [Please add a description.]
 */

export var Referenced = {
  checkPath(path) {
    return t.isReferenced(path.node, path.parent);
  }
};

/**
 * [Please add a description.]
 */

export var BlockScoped = {
  checkPath(path) {
    return t.isBlockScoped(path.node);
  }
};

/**
 * [Please add a description.]
 */

export var Var = {
  types: ["VariableDeclaration"],
  checkPath(path) {
    return t.isVar(path.node);
  }
};

/**
 * [Please add a description.]
 */

export var DirectiveLiteral = {
  types: ["Literal"],
  checkPath(path) {
    return path.isLiteral() && path.parentPath.isExpressionStatement();
  }
};

/**
 * [Please add a description.]
 */

export var Directive = {
  types: ["ExpressionStatement"],
  checkPath(path) {
    return path.get("expression").isLiteral();
  }
};

/**
 * [Please add a description.]
 */

export var User = {
  checkPath(path) {
    return path.node && !!path.node.loc;
  }
};

/**
 * [Please add a description.]
 */

export var Generated = {
  checkPath(path) {
    return !path.isUser();
  }
};

/**
 * [Please add a description.]
 */

export var Flow = {
  types: ["Flow", "ImportDeclaration", "ExportDeclaration"],
  checkPath({ node }) {
    if (t.isFlow(node)) {
      return true;
    } else if (t.isImportDeclaration(node)) {
      return node.importKind === "type" || node.importKind === "typeof";
    } else if (t.isExportDeclaration(node)) {
      return node.exportKind === "type";
    } else {
      return false;
    }
  }
};

@@ -2132,60 +2132,30 @@
 ath.
-isLiteral() && path.parentPath.isExpressionStatement
+parentPath.isDirective
 ();%0A
@@ -2277,61 +2277,443 @@
 ath(
-path) %7B%0A    return path.get(%22expression%22).isLiteral()
+%7B inList, container, key %7D) %7B%0A    // needs to be in a statement list%0A    if (!inList) return false;%0A%0A    // get the last directive node in this list%0A    var lastDirective = -1;%0A    for (var i = 0; i %3C container.length; i++) %7B%0A      var node = container%5Bi%5D;%0A      if (t.isExpressionStatement(node) && t.isLiteral(node.expression)) %7B%0A        lastDirective = i;%0A      %7D else %7B%0A        break;%0A      %7D%0A    %7D%0A%0A    return key %3C= lastDirective
 ;%0A  

make Directive virtual type check more reliable