restructure types

This commit is contained in:
Sebastian McKenzie
2015-03-11 00:04:06 +11:00
parent 8328f638c2
commit 98ca541fde
96 changed files with 813 additions and 795 deletions

View File

@@ -1,6 +1,6 @@
import isInteger from "is-integer";
import isNumber from "lodash/lang/isNumber";
import t from "../../types";
import * as t from "../../types";
export function UnaryExpression(node, print) {
var hasSpace = /[a-z]$/.test(node.operator);

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export function AnyTypeAnnotation() {
this.push("any");

View File

@@ -1,5 +1,5 @@
import each from "lodash/collection/each";
import t from "../../types";
import * as t from "../../types";
export function JSXAttribute(node, print) {
print(node.name);

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export function _params(node, print) {
print(node.typeParameters);

View File

@@ -1,5 +1,5 @@
import each from "lodash/collection/each";
import t from "../../types";
import * as t from "../../types";
export function ImportSpecifier(node, print) {
if (t.isSpecifierDefault(node)) {

View File

@@ -1,5 +1,5 @@
import repeating from "repeating";
import t from "../../types";
import * as t from "../../types";
export function WithStatement(node, print) {
this.keyword("with");

View File

@@ -8,7 +8,7 @@ import Buffer from "./buffer";
import extend from "lodash/object/extend";
import each from "lodash/collection/each";
import n from "./node";
import t from "../types";
import * as t from "../types";
class CodeGenerator {
constructor(ast, opts, code) {

View File

@@ -2,7 +2,7 @@ import whitespace from "./whitespace";
import * as parens from "./parentheses";
import each from "lodash/collection/each";
import some from "lodash/collection/some";
import t from "../../types";
import * as t from "../../types";
var find = function (obj, node, parent) {
if (!obj) return;

View File

@@ -1,5 +1,5 @@
import each from "lodash/collection/each";
import t from "../../types";
import * as t from "../../types";
var PRECEDENCE = {};

View File

@@ -1,7 +1,7 @@
import isBoolean from "lodash/lang/isBoolean";
import each from "lodash/collection/each";
import map from "lodash/collection/map";
import t from "../../types";
import * as t from "../../types";
function crawl(node, state = {}) {
if (t.isMemberExpression(node)) {

View File

@@ -1,5 +1,5 @@
import sourceMap from "source-map";
import t from "../types";
import * as t from "../types";
export default class SourceMap {
constructor(position, opts, code) {

View File

@@ -1,4 +1,4 @@
import t from "../types";
import * as t from "../types";
export default function (ast, comments, tokens) {
if (ast && ast.type === "Program") {

View File

@@ -1,7 +1,7 @@
import estraverse from "estraverse";
import extend from "lodash/object/extend";
import types from "ast-types";
import t from "./types";
import * as t from "./types";
// estraverse

View File

@@ -1,9 +1,9 @@
import generator from "./generation";
import * as messages from "./messages";
import * as util from "./util";
import File from "./transformation/file";
import generator from "../generation";
import * as messages from "../messages";
import * as util from "../util";
import File from "../transformation/file";
import each from "lodash/collection/each";
import t from "./types";
import * as t from "../types";
function buildGlobal(namespace, builder) {
var body = [];

View File

@@ -14,7 +14,7 @@ import slash from "slash";
import * as util from "../util";
import path from "path";
import each from "lodash/collection/each";
import t from "../types";
import * as t from "../types";
var checkTransformerVisitor = {
enter(node, parent, scope, state) {
@@ -423,7 +423,7 @@ export default class File {
}
transform(ast) {
this.debug();
this.log.debug();
this.ast = ast;
this.lastStatements = t.getLastStatements(ast.program);

View File

@@ -1,5 +1,5 @@
import explode from "./explode-assignable-expression";
import t from "../../types";
import * as t from "../../types";
export default function (exports, opts) {
var isAssignment = function (node) {

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export default function build(node, buildBody) {
var self = node.blocks.shift();

View File

@@ -1,5 +1,5 @@
import explode from "./explode-assignable-expression";
import t from "../../types";
import * as t from "../../types";
export default function (exports, opts) {
var buildAssignment = function (left, right) {

View File

@@ -7,7 +7,7 @@ import isString from "lodash/lang/isString";
import * as messages from "../../messages";
import esutils from "esutils";
import * as react from "./react";
import t from "../../types";
import * as t from "../../types";
export default function (exports, opts) {
exports.check = function (node) {

View File

@@ -2,7 +2,7 @@ import cloneDeep from "lodash/lang/cloneDeep";
import traverse from "../../traversal";
import each from "lodash/collection/each";
import has from "lodash/object/has";
import t from "../../types";
import * as t from "../../types";
export function push(mutatorMap, key, kind, computed, value) {
var alias = t.toKeyAlias({ computed }, key);

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
var getObjRef = function (node, nodes, file, scope) {
var ref;

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export default function (node) {
var lastNonDefault = 0;

View File

@@ -1,6 +1,6 @@
import getFunctionArity from "./get-function-arity";
import * as util from "../../util";
import t from "../../types";
import * as t from "../../types";
var visitor = {
enter(node, parent, scope, state) {

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");

View File

@@ -1,5 +1,5 @@
import pull from "lodash/array/pull";
import t from "../../types";
import * as t from "../../types";
export function is(node, flag) {
return t.isLiteral(node) && node.regex && node.regex.flags.indexOf(flag) >= 0;

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
var awaitVisitor = {
enter(node, parent, scope, state) {

View File

@@ -1,7 +1,7 @@
module.exports = ReplaceSupers;
import * as messages from "../../messages";
import t from "../../types";
import * as t from "../../types";
function isIllegalBareSuper(node, parent) {

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export function has(node) {
var first = node.body[0];

View File

@@ -2,7 +2,7 @@ import * as messages from "../../messages";
import extend from "lodash/object/extend";
import object from "../../helpers/object";
import * as util from "../../util";
import t from "../../types";
import * as t from "../../types";
var remapVisitor = {
enter(node, parent, scope, formatter) {

View File

@@ -3,7 +3,7 @@ import CommonFormatter from "./common";
import includes from "lodash/collection/includes";
import values from "lodash/object/values";
import * as util from "../../util";
import t from "../../types";
import * as t from "../../types";
export default class AMDFormatter extends DefaultFormatter {
init = CommonFormatter.prototype.init;

View File

@@ -1,7 +1,7 @@
import DefaultFormatter from "./_default";
import includes from "lodash/collection/includes";
import * as util from "../../util";
import t from "../../types";
import * as t from "../../types";
export default class CommonJSFormatter extends DefaultFormatter {
init() {

View File

@@ -1,4 +1,4 @@
import t from "../../types";
import * as t from "../../types";
export default class IgnoreFormatter {
exportDeclaration(node, nodes) {

View File

@@ -4,7 +4,7 @@ import * as util from "../../util";
import last from "lodash/array/last";
import each from "lodash/collection/each";
import map from "lodash/collection/map";
import t from "../../types";
import * as t from "../../types";
var hoistVariablesVisitor = {
enter(node, parent, scope, hoistDeclarators) {

View File

@@ -1,7 +1,7 @@
import AMDFormatter from "./amd";
import values from "lodash/object/values";
import * as util from "../../util";
import t from "../../types";
import * as t from "../../types";
export default class UMDFormatter extends AMDFormatter {
transform(program) {

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function MemberExpression(node) {
var prop = node.property;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function Property(node) {
var key = node.key;

View File

@@ -1,5 +1,5 @@
import * as defineMap from "../../helpers/define-map";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isProperty(node) && (node.kind === "get" || node.kind === "set");

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var check = t.isArrowFunctionExpression;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
var visitor = {
enter(node, parent, scope, state) {

View File

@@ -1,7 +1,7 @@
import traverse from "../../../traversal";
import object from "../../../helpers/object";
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
import values from "lodash/object/values";
import extend from "lodash/object/extend";

View File

@@ -4,7 +4,7 @@ import * as defineMap from "../../helpers/define-map";
import * as messages from "../../../messages";
import * as util from "../../../util";
import traverse from "../../../traversal";
import t from "../../../types";
import * as t from "../../../types";
export var check = t.isClass;

View File

@@ -1,5 +1,5 @@
import * as messages from "../../../messages";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isVariableDeclaration(node, { kind: "const" });

View File

@@ -1,5 +1,5 @@
import * as messages from "../../../messages";
import t from "../../../types";
import * as t from "../../../types";
export var check = t.isPattern;

View File

@@ -1,6 +1,6 @@
import * as messages from "../../../messages";
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
export var check = t.isForOfStatement;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export { check } from "../internal/modules";

View File

@@ -1,5 +1,5 @@
import ReplaceSupers from "../../helpers/replace-supers";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isIdentifier(node, { name: "super" });

View File

@@ -1,5 +1,5 @@
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isFunction(node) && hasDefaults(node);

View File

@@ -1,6 +1,6 @@
import isNumber from "lodash/lang/isNumber";
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
export var check = t.isRestElement;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
function loose(node, body, objId) {
for (var i = 0; i < node.properties.length; i++) {

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isProperty(node) && (node.method || node.shorthand);

View File

@@ -1,5 +1,5 @@
import * as regex from "../../helpers/regex";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return regex.is(node, "y");

View File

@@ -1,5 +1,5 @@
import includes from "lodash/collection/includes";
import t from "../../../types";
import * as t from "../../../types";
function getSpreadLiteral(spread, scope) {
return scope.toArray(spread.argument, true);

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var optional = true;

View File

@@ -3,7 +3,7 @@ import * as messages from "../../../messages";
import flatten from "lodash/array/flatten";
import * as util from "../../../util";
import map from "lodash/collection/map";
import t from "../../../types";
import * as t from "../../../types";
exports.Function = function (node, parent, scope, file) {
var tailCall = new TailCallTransformer(node, scope, file);

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
var buildBinaryExpression = function (left, right) {
return t.binaryExpression("+", left, right);

View File

@@ -1,7 +1,7 @@
// https://github.com/zenparsing/es-abstract-refs
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
export var experimental = true;

View File

@@ -1,7 +1,7 @@
import buildComprehension from "../../helpers/build-comprehension";
import traverse from "../../../traversal";
import * as util from "../../../util";
import t from "../../../types";
import * as t from "../../../types";
export var experimental = true;

View File

@@ -1,7 +1,7 @@
// https://github.com/rwaldron/exponentiation-operator
import build from "../../helpers/build-binary-assignment-operator-transformer";
import t from "../../../types";
import * as t from "../../../types";
export var experimental = true;

View File

@@ -1,6 +1,6 @@
// https://github.com/sebmarkbage/ecmascript-rest-spread
import t from "../../../types";
import * as t from "../../../types";
export var experimental = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
var functionChildrenVisitor = {
enter(node, parent, scope, state) {

View File

@@ -1,5 +1,5 @@
import * as strict from "../../helpers/strict";
import t from "../../../types";
import * as t from "../../../types";
export var secondPass = true;

View File

@@ -4,7 +4,7 @@
// a generator function as a default then regenerator will destroy the export
// declaration and leave a variable declaration in it's place... yeah, handy.
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isImportDeclaration(node) || t.isExportDeclaration(node);

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function Program(program, parent, scope, file) {
if (file.transformers.strict.canRun()) {

View File

@@ -1,5 +1,5 @@
import * as messages from "../../../messages";
import t from "../../../types";
import * as t from "../../../types";
export function ForOfStatement(node, parent, scope, file) {
var left = node.left;

View File

@@ -1,5 +1,5 @@
import remapAsyncToGenerator from "../../helpers/remap-async-to-generator";
import t from "../../../types";
import * as t from "../../../types";
export function manipulateOptions(opts) {
opts.experimental = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function Flow(node) {
this.remove();

View File

@@ -1,5 +1,5 @@
import * as react from "../../helpers/react";
import t from "../../../types";
import * as t from "../../../types";
export function manipulateOptions(opts) {
opts.blacklist.push("react");

View File

@@ -1,5 +1,5 @@
import * as react from "../../helpers/react";
import t from "../../../types";
import * as t from "../../../types";
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;

View File

@@ -1,5 +1,5 @@
import regenerator from "regenerator-babel";
import t from "../../../types";
import * as t from "../../../types";
export function check(node) {
return t.isFunction(node) && (node.async || node.generator);

View File

@@ -2,7 +2,7 @@ import includes from "lodash/collection/includes";
import * as util from "../../../util";
import core from "core-js/library";
import has from "lodash/object/has";
import t from "../../../types";
import * as t from "../../../types";
var isSymboliterator = t.buildMatchMemberExpression("Symbol.iterator");

View File

@@ -1,5 +1,5 @@
import * as messages from "../../../messages";
import t from "../../../types";
import * as t from "../../../types";
export function Program(program) {
var first = program.body[0];

View File

@@ -1,6 +1,6 @@
import * as messages from "../../../messages";
import build from "../../helpers/build-conditional-assignment-operator-transformer";
import t from "../../../types";
import * as t from "../../../types";
export var playground = true;

View File

@@ -1,5 +1,5 @@
import build from "../../helpers/build-conditional-assignment-operator-transformer";
import t from "../../../types";
import * as t from "../../../types";
export var playground = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var playground = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var playground = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export function BlockStatement(node, parent, scope, file) {
if ((t.isFunction(parent) && parent.body === node) || t.isExportDeclaration(parent)) {

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
import pull from "lodash/array/pull";
function isProtoKey(node) {

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var optional = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
function toStatements(node) {
if (t.isBlockStatement(node)) {

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var optional = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var optional = true;

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
var isConsole = t.buildMatchMemberExpression("console", true);

View File

@@ -1,4 +1,4 @@
import t from "../../../types";
import * as t from "../../../types";
export var optional = true;

View File

@@ -1,5 +1,5 @@
import * as messages from "../../../messages";
import t from "../../../types";
import * as t from "../../../types";
// check if the input Literal `source` is an alternate casing of "react"
function check(source, file) {

View File

@@ -1,7 +1,7 @@
import TraversalPath from "./path";
import flatten from "lodash/array/flatten";
import compact from "lodash/array/compact";
import t from "../types";
import * as t from "../types";
export default class TraversalContext {
constructor(scope, opts, state, parentPath) {

View File

@@ -2,7 +2,7 @@ module.exports = traverse;
import TraversalContext from "./context";
import includes from "lodash/collection/includes";
import t from "../types";
import * as t from "../types";
function traverse(parent, opts, scope, state) {
if (!parent) return;

View File

@@ -1,7 +1,7 @@
import traverse from "./index";
import includes from "lodash/collection/includes";
import Scope from "./scope";
import t from "../types";
import * as t from "../types";
export default class TraversalPath {
constructor(parent, container) {
@@ -44,6 +44,14 @@ export default class TraversalPath {
return ourScope;
}
insertBefore(node) {
}
insertAfter(node) {
}
setData(key, val) {
return this.data[key] = val;
}

View File

@@ -7,7 +7,7 @@ import flatten from "lodash/array/flatten";
import extend from "lodash/object/extend";
import object from "../helpers/object";
import each from "lodash/collection/each";
import t from "../types";
import * as t from "../types";
var functionVariableVisitor = {
enter(node, parent, scope, state) {

View File

@@ -0,0 +1,230 @@
import isPlainObject from "lodash/lang/isPlainObject";
import isNumber from "lodash/lang/isNumber";
import isRegExp from "lodash/lang/isRegExp";
import isString from "lodash/lang/isString";
import traverse from "../traversal";
import each from "lodash/collection/each";
import * as t from "./index";
/**
* Description
*/
export function toComputedKey(node: Object, key: Object = node.key): Object {
if (!node.computed) {
if (t.isIdentifier(key)) key = t.literal(key.name);
}
return key;
}
/**
* Turn an array of statement `nodes` into a `SequenceExpression`.
*
* Variable declarations are turned into simple assignments and their
* declarations hoisted to the top of the current scope.
*
* Expression statements are just resolved to their expression.
*/
export function toSequenceExpression(nodes: Array<Object>, scope: Scope): Object {
var exprs = [];
each(nodes, function (node) {
if (t.isExpression(node)) {
exprs.push(node);
} if (t.isExpressionStatement(node)) {
exprs.push(node.expression);
} else if (t.isVariableDeclaration(node)) {
each(node.declarations, function (declar) {
scope.push({
kind: node.kind,
id: declar.id
});
exprs.push(t.assignmentExpression("=", declar.id, declar.init));
});
} else if (t.isIfStatement(node)) {
return t.conditionalExpression(
node.test,
node.consequent ? t.toSequenceExpression([node.consequent]) : t.identifier("undefined"),
node.alternate ? t.toSequenceExpression([node.alternate]) : t.identifier("undefined")
);
} else if (t.isBlockStatement(node)) {
return t.toSequenceExpression(node.body);
}
});
if (exprs.length === 1) {
return exprs[0];
} else {
return t.sequenceExpression(exprs);
}
}
/**
* Description
*/
export function toKeyAlias(node: Object, key: Object = node.key) {
var alias;
if (t.isIdentifier(key)) {
alias = key.name;
} else if (t.isLiteral(key)) {
alias = JSON.stringify(key.value);
} else {
alias = JSON.stringify(traverse.removeProperties(t.cloneDeep(key)));
}
if (node.computed) alias = `[${alias}]`;
return alias;
}
/*
* Description
*/
export function toIdentifier(name: string): string {
if (t.isIdentifier(name)) return name.name;
name = name + "";
// replace all non-valid identifiers with dashes
name = name.replace(/[^a-zA-Z0-9$_]/g, "-");
// remove all dashes and numbers from start of name
name = name.replace(/^[-0-9]+/, "");
// camel case
name = name.replace(/[-\s]+(.)?/g, function (match, c) {
return c ? c.toUpperCase() : "";
});
if (!t.isValidIdentifier(name)) {
name = `_${name}`;
}
return name || "_";
}
/**
* Description
*
* @returns {Object|Boolean}
*/
export function toStatement(node: Object, ignore?: boolean) {
if (t.isStatement(node)) {
return node;
}
var mustHaveId = false;
var newType;
if (t.isClass(node)) {
mustHaveId = true;
newType = "ClassDeclaration";
} else if (t.isFunction(node)) {
mustHaveId = true;
newType = "FunctionDeclaration";
} else if (t.isAssignmentExpression(node)) {
return t.expressionStatement(node);
}
if (mustHaveId && !node.id) {
newType = false;
}
if (!newType) {
if (ignore) {
return false;
} else {
throw new Error(`cannot turn ${node.type} to a statement`);
}
}
node.type = newType;
return node;
}
/**
* Description
*/
export function toExpression(node: Object): Object {
if (t.isExpressionStatement(node)) {
node = node.expression;
}
if (t.isClass(node)) {
node.type = "ClassExpression";
} else if (t.isFunction(node)) {
node.type = "FunctionExpression";
}
if (t.isExpression(node)) {
return node;
} else {
throw new Error(`cannot turn ${node.type} to an expression`);
}
}
/**
* Description
*/
export function toBlock(node: Object, parent: Object): Object {
if (t.isBlockStatement(node)) {
return node;
}
if (t.isEmptyStatement(node)) {
node = [];
}
if (!Array.isArray(node)) {
if (!t.isStatement(node)) {
if (t.isFunction(parent)) {
node = t.returnStatement(node);
} else {
node = t.expressionStatement(node);
}
}
node = [node];
}
return t.blockStatement(node);
}
/**
* Description
*/
export function valueToNode(value: any): Object {
if (value === undefined) {
return t.identifier("undefined");
}
if (value === true || value === false || value === null || isString(value) || isNumber(value) || isRegExp(value)) {
return t.literal(value);
}
if (Array.isArray(value)) {
return t.arrayExpression(value.map(t.valueToNode));
}
if (isPlainObject(value)) {
var props = [];
for (var key in value) {
var nodeKey;
if (t.isValidIdentifier(key)) {
nodeKey = t.identifier(key);
} else {
nodeKey = t.literal(key);
}
props.push(t.property("init", nodeKey, t.valueToNode(value[key])));
}
return t.objectExpression(props);
}
throw new Error("don't know how to turn this value into a node");
}

View File

@@ -0,0 +1,129 @@
import * as t from "./index";
/**
* Walk the input `node` and statically evaluate if it's truthy.
*
* Returning `true` when we're sure that the expression will evaluate to a
* truthy value, `false` if we're sure that it will evaluate to a falsy
* value and `undefined` if we aren't sure. Because of this please do not
* rely on coercion when using this method and check with === if it's false.
*
* For example do:
*
* if (t.evaluateTruthy(node) === false) falsyLogic();
*
* **AND NOT**
*
* if (!t.evaluateTruthy(node)) falsyLogic();
*
*/
export function evaluateTruthy(node: Object, scope: Scope): boolean {
var res = evaluate(node, scope);
if (res.confident) return !!res.value;
}
/**
* Walk the input `node` and statically evaluate it.
*
* Returns an pbject in the form `{ confident, value }`. `confident` indicates
* whether or not we had to drop out of evaluating the expression because of
* hitting an unknown node that we couldn't confidently find the value of.
*
* Example:
*
* t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
* t.evaluate(parse("!true")) // { confident: true, value: false }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined }
*
*/
export function evaluate(node: Object, scope: Scope): { confident: boolean; value: any } {
var confident = true;
var value = evaluate(node);
if (!confident) value = undefined;
return {
confident: confident,
value: value
};
function evaluate(node) {
if (!confident) return;
if (t.isSequenceExpression(node)) {
return evaluate(node.expressions[node.expressions.length - 1]);
}
if (t.isLiteral(node)) {
if (node.regex && node.value === null) {
// we have a regex and we can't represent it natively
} else {
return node.value;
}
}
if (t.isConditionalExpression(node)) {
if (evaluate(node.test)) {
return evaluate(node.consequent);
} else {
return evaluate(node.alternate);
}
}
if (t.isIdentifier(node)) {
if (node.name === "undefined") {
return undefined;
} else {
return evaluate(scope.getImmutableBindingValue(node.name));
}
}
if (t.isUnaryExpression(node, { prefix: true })) {
var arg = evaluate(node.argument);
switch (node.operator) {
case "void": return undefined;
case "!": return !arg;
case "+": return +arg;
case "-": return -arg;
}
}
if (t.isArrayExpression(node) || t.isObjectExpression(node)) {
// we could evaluate these but it's probably impractical and not very useful
}
if (t.isLogicalExpression(node)) {
let left = evaluate(node.left);
let right = evaluate(node.right);
switch (node.operator) {
case "||": return left || right;
case "&&": return left && right;
}
}
if (t.isBinaryExpression(node)) {
let left = evaluate(node.left);
let right = evaluate(node.right);
switch (node.operator) {
case "-": return left - right;
case "+": return left + right;
case "/": return left / right;
case "*": return left * right;
case "%": return left % right;
case "<": return left < right;
case ">": return left > right;
case "<=": return left <= right;
case ">=": return left >= right;
case "==": return left == right;
case "!=": return left != right;
case "===": return left === right;
case "!==": return left !== right;
}
}
confident = false;
}
}

View File

@@ -1,17 +1,10 @@
import toFastProperties from "to-fast-properties";
import isPlainObject from "lodash/lang/isPlainObject";
import isNumber from "lodash/lang/isNumber";
import isRegExp from "lodash/lang/isRegExp";
import isString from "lodash/lang/isString";
import compact from "lodash/array/compact";
import esutils from "esutils";
import object from "../helpers/object";
import clone from "lodash/lang/clone";
import assign from "lodash/object/assign";
import each from "lodash/collection/each";
import uniq from "lodash/array/uniq";
var t = {};
export default t;
var t = exports;
/**
* Registers `is[Type]` and `assert[Type]` generated functions for a given `type`.
@@ -31,13 +24,15 @@ function registerType(type: string, skipAliasCheck?: boolean) {
};
}
t.STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
t.NATIVE_TYPE_NAMES = ["Array", "Object", "Number", "Boolean", "Date", "Array", "String"];
t.FLATTENABLE_KEYS = ["body", "expressions"];
t.FOR_INIT_KEYS = ["left", "init"];
export var STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
export var NATIVE_TYPE_NAMES = ["Array", "Object", "Number", "Boolean", "Date", "Array", "String"];
export var FLATTENABLE_KEYS = ["body", "expressions"];
export var FOR_INIT_KEYS = ["left", "init"];
export var COMMENT_KEYS = ["leadingComments", "trailingComments"];
t.VISITOR_KEYS = require("./visitor-keys");
t.ALIAS_KEYS = require("./alias-keys");
export var VISITOR_KEYS = require("./visitor-keys");
export var BUILDER_KEYS = require("./builder-keys");
export var ALIAS_KEYS = require("./alias-keys");
t.FLIPPED_ALIAS_KEYS = {};
@@ -57,7 +52,7 @@ each(t.FLIPPED_ALIAS_KEYS, function (types, type) {
registerType(type, false);
});
t.TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS));
export var TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS));
/**
* Returns whether `node` is of given `type`.
@@ -66,7 +61,7 @@ t.TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS));
* Optionally, pass `skipAliasCheck` to directly compare `node.type` with `type`.
*/
t.is = function (type: string, node: Object, opts?: Object, skipAliasCheck?: boolean): boolean {
export function is(type: string, node: Object, opts?: Object, skipAliasCheck?: boolean): boolean {
if (!node) return false;
var typeMatches = type === node.type;
@@ -88,11 +83,7 @@ t.is = function (type: string, node: Object, opts?: Object, skipAliasCheck?: boo
}
return true;
};
//
t.BUILDER_KEYS = require("./builder-keys");
}
each(t.VISITOR_KEYS, function (keys, type) {
if (t.BUILDER_KEYS[type]) return;
@@ -122,65 +113,11 @@ each(t.BUILDER_KEYS, function (keys, type) {
};
});
/**
* Description
*/
t.toComputedKey = function (node: Object, key: Object = node.key): Object {
if (!node.computed) {
if (t.isIdentifier(key)) key = t.literal(key.name);
}
return key;
};
/**
* Turn an array of statement `nodes` into a `SequenceExpression`.
*
* Variable declarations are turned into simple assignments and their
* declarations hoisted to the top of the current scope.
*
* Expression statements are just resolved to their expression.
*/
t.toSequenceExpression = function (nodes: Array<Object>, scope: Scope): Object {
var exprs = [];
each(nodes, function (node) {
if (t.isExpression(node)) {
exprs.push(node);
} if (t.isExpressionStatement(node)) {
exprs.push(node.expression);
} else if (t.isVariableDeclaration(node)) {
each(node.declarations, function (declar) {
scope.push({
kind: node.kind,
id: declar.id
});
exprs.push(t.assignmentExpression("=", declar.id, declar.init));
});
} else if (t.isIfStatement(node)) {
return t.conditionalExpression(
node.test,
node.consequent ? t.toSequenceExpression([node.consequent]) : t.identifier("undefined"),
node.alternate ? t.toSequenceExpression([node.alternate]) : t.identifier("undefined")
);
} else if (t.isBlockStatement(node)) {
return t.toSequenceExpression(node.body);
}
});
if (exprs.length === 1) {
return exprs[0];
} else {
return t.sequenceExpression(exprs);
}
};
/*
* Description
*/
t.shallowEqual = function (actual: Object, expected: Object): boolean {
export function shallowEqual(actual: Object, expected: Object): boolean {
var keys = Object.keys(expected);
for (var i = 0; i < keys.length; i++) {
@@ -192,204 +129,54 @@ t.shallowEqual = function (actual: Object, expected: Object): boolean {
}
return true;
};
}
/**
* Description
*/
t.appendToMemberExpression = function (member: Object, append: Object, computed?: boolean): Object {
export function appendToMemberExpression(member: Object, append: Object, computed?: boolean): Object {
member.object = t.memberExpression(member.object, member.property, member.computed);
member.property = append;
member.computed = !!computed;
return member;
};
}
/**
* Description
*/
t.prependToMemberExpression = function (member: Object, append: Object): Object {
export function prependToMemberExpression(member: Object, append: Object): Object {
member.object = t.memberExpression(append, member.object);
return member;
};
/**
* Check if the input `node` is a reference to a bound variable.
*/
t.isReferenced = function (node: Object, parent: Object): boolean {
// yes: PARENT[NODE]
// yes: NODE.child
// no: parent.CHILD
if (t.isMemberExpression(parent)) {
if (parent.property === node && parent.computed) {
return true;
} else if (parent.object === node) {
return true;
} else {
return false;
}
}
// yes: { [NODE]: "" }
// no: { NODE: "" }
if (t.isProperty(parent) && parent.key === node) {
return parent.computed;
}
// no: var NODE = init;
// yes: var id = NODE;
if (t.isVariableDeclarator(parent)) {
return parent.id !== node;
}
// no: function NODE() {}
// no: function foo(NODE) {}
if (t.isFunction(parent)) {
for (var i = 0; i < parent.params.length; i++) {
var param = parent.params[i];
if (param === node) return false;
}
return parent.id !== node;
}
// no: export { foo as NODE };
if (t.isExportSpecifier(parent, { name: node })) {
return false;
}
// no: import { NODE as foo } from "foo";
if (t.isImportSpecifier(parent, { id: node })) {
return false;
}
// no: class NODE {}
if (t.isClass(parent)) {
return parent.id !== node;
}
// yes: class { [NODE](){} }
if (t.isMethodDefinition(parent)) {
return parent.key === node && parent.computed;
}
// no: NODE: for (;;) {}
if (t.isLabeledStatement(parent)) {
return false;
}
// no: try {} catch (NODE) {}
if (t.isCatchClause(parent)) {
return parent.param !== node;
}
// no: function foo(...NODE) {}
if (t.isRestElement(parent)) {
return false;
}
// no: [NODE = foo] = [];
// yes: [foo = NODE] = [];
if (t.isAssignmentPattern(parent)) {
return parent.right === node;
}
// no: [NODE] = [];
// no: ({ NODE }) = [];
if (t.isPattern(parent)) {
return false;
}
// no: import NODE from "bar";
if (t.isImportSpecifier(parent)) {
return false;
}
// no: import * as NODE from "foo";
if (t.isImportBatchSpecifier(parent)) {
return false;
}
// no: class Foo { private NODE; }
if (t.isPrivateDeclaration(parent)) {
return false;
}
return true;
};
/**
* Check if the input `node` is an `Identifier` and `isReferenced`.
*/
t.isReferencedIdentifier = function (node: Object, parent: Object, opts?: Object): boolean {
return t.isIdentifier(node, opts) && t.isReferenced(node, parent);
};
/**
* Check if the input `name` is a valid identifier name
* and isn't a reserved word.
*/
t.isValidIdentifier = function (name: string): boolean {
return isString(name) && esutils.keyword.isIdentifierName(name) && !esutils.keyword.isReservedWordES6(name, true);
};
/*
* Description
*/
t.toIdentifier = function (name: string): string {
if (t.isIdentifier(name)) return name.name;
name = name + "";
// replace all non-valid identifiers with dashes
name = name.replace(/[^a-zA-Z0-9$_]/g, "-");
// remove all dashes and numbers from start of name
name = name.replace(/^[-0-9]+/, "");
// camel case
name = name.replace(/[-\s]+(.)?/g, function (match, c) {
return c ? c.toUpperCase() : "";
});
if (!t.isValidIdentifier(name)) {
name = `_${name}`;
}
return name || "_";
};
}
/**
* Description
*/
t.ensureBlock = function (node: Object, key: string = "body") {
export function ensureBlock(node: Object, key: string = "body") {
return node[key] = t.toBlock(node[key], node);
};
}
/**
* Description
*/
t.clone = function (node: Object): Object {
export function clone(node: Object): Object {
var newNode = {};
for (var key in node) {
if (key[0] === "_") continue;
newNode[key] = node[key];
}
return newNode;
};
}
/**
* Description
*/
t.cloneDeep = function (node: Object): Object {
export function cloneDeep(node: Object): Object {
var newNode = {};
for (var key in node) {
@@ -409,7 +196,7 @@ t.cloneDeep = function (node: Object): Object {
}
return newNode;
};
}
/**
* Build a function that when called will return whether or not the
@@ -419,7 +206,7 @@ t.cloneDeep = function (node: Object): Object {
* parsed nodes of `React.createClass` and `React["createClass"]`.
*/
t.buildMatchMemberExpression = function (match:string, allowPartial?: boolean): Function {
export function buildMatchMemberExpression(match:string, allowPartial?: boolean): Function {
var parts = match.split(".");
return function (member) {
@@ -464,212 +251,35 @@ t.buildMatchMemberExpression = function (match:string, allowPartial?: boolean):
return true;
};
};
/**
* Description
*
* @returns {Object|Boolean}
*/
t.toStatement = function (node: Object, ignore?: boolean) {
if (t.isStatement(node)) {
return node;
}
var mustHaveId = false;
var newType;
if (t.isClass(node)) {
mustHaveId = true;
newType = "ClassDeclaration";
} else if (t.isFunction(node)) {
mustHaveId = true;
newType = "FunctionDeclaration";
} else if (t.isAssignmentExpression(node)) {
return t.expressionStatement(node);
}
if (mustHaveId && !node.id) {
newType = false;
}
if (!newType) {
if (ignore) {
return false;
} else {
throw new Error(`cannot turn ${node.type} to a statement`);
}
}
node.type = newType;
return node;
};
}
/**
* Description
*/
t.toExpression = function (node: Object): Object {
if (t.isExpressionStatement(node)) {
node = node.expression;
}
if (t.isClass(node)) {
node.type = "ClassExpression";
} else if (t.isFunction(node)) {
node.type = "FunctionExpression";
}
if (t.isExpression(node)) {
return node;
} else {
throw new Error(`cannot turn ${node.type} to an expression`);
}
};
/**
* Description
*/
t.toBlock = function (node: Object, parent: Object): Object {
if (t.isBlockStatement(node)) {
return node;
}
if (t.isEmptyStatement(node)) {
node = [];
}
if (!Array.isArray(node)) {
if (!t.isStatement(node)) {
if (t.isFunction(parent)) {
node = t.returnStatement(node);
} else {
node = t.expressionStatement(node);
}
}
node = [node];
}
return t.blockStatement(node);
};
/**
* Return a list of binding identifiers associated with
* the input `node`.
*/
t.getBindingIdentifiers = function (node: Object): Object {
var search = [].concat(node);
var ids = object();
while (search.length) {
var id = search.shift();
if (!id) continue;
var keys = t.getBindingIdentifiers.keys[id.type];
if (t.isIdentifier(id)) {
ids[id.name] = id;
} else if (t.isImportSpecifier(id)) {
search.push(id.name || id.id);
} else if (t.isExportDeclaration(id)) {
if (t.isDeclaration(node.declaration)) {
search.push(node.declaration);
}
} else if (keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
search = search.concat(id[key] || []);
}
}
}
return ids;
};
t.getBindingIdentifiers.keys = {
UnaryExpression: ["argument"],
AssignmentExpression: ["left"],
ImportBatchSpecifier: ["name"],
VariableDeclarator: ["id"],
FunctionDeclaration: ["id"],
FunctionExpression: ["id"],
ClassDeclaration: ["id"],
ClassExpression: ["id"],
SpreadElement: ["argument"],
RestElement: ["argument"],
UpdateExpression: ["argument"],
SpreadProperty: ["argument"],
Property: ["value"],
ComprehensionBlock: ["left"],
AssignmentPattern: ["left"],
PrivateDeclaration: ["declarations"],
ComprehensionExpression: ["blocks"],
ImportDeclaration: ["specifiers"],
VariableDeclaration: ["declarations"],
ArrayPattern: ["elements"],
ObjectPattern: ["properties"]
};
/**
* Description
*/
t.isLet = function (node: Object): boolean {
return t.isVariableDeclaration(node) && (node.kind !== "var" || node._let);
};
/**
* Description
*/
t.isBlockScoped = function (node: Object): boolean {
return t.isFunctionDeclaration(node) || t.isClassDeclaration(node) || t.isLet(node);
};
/**
* Description
*/
t.isVar = function (node: Object): boolean {
return t.isVariableDeclaration(node, { kind: "var" }) && !node._let;
};
//
t.COMMENT_KEYS = ["leadingComments", "trailingComments"];
/**
* Description
*/
t.removeComments = function (child: Object): Object {
each(t.COMMENT_KEYS, function (key) {
export function removeComments(child: Object): Object {
each(COMMENT_KEYS, function (key) {
delete child[key];
});
return child;
};
}
/**
* Description
*/
t.inheritsComments = function (child: Object, parent: Object): Object {
each(t.COMMENT_KEYS, function (key) {
export function inheritsComments(child: Object, parent: Object): Object {
each(COMMENT_KEYS, function (key) {
child[key] = uniq(compact([].concat(child[key], parent[key])));
});
return child;
};
}
/**
* Description
*/
t.inherits = function (child: Object, parent: Object): Object {
export function inherits(child: Object, parent: Object): Object {
child._declarations = parent._declarations;
child._scopeInfo = parent._scopeInfo;
child.range = parent.range;
@@ -682,283 +292,13 @@ t.inherits = function (child: Object, parent: Object): Object {
t.inheritsComments(child, parent);
return child;
};
/**
* Description
*/
t.getLastStatements = function (node: Object): Array<Object> {
var nodes = [];
var add = function (node) {
nodes = nodes.concat(t.getLastStatements(node));
};
if (t.isIfStatement(node)) {
add(node.consequent);
add(node.alternate);
} else if (t.isFor(node) || t.isWhile(node)) {
add(node.body);
} else if (t.isProgram(node) || t.isBlockStatement(node)) {
add(node.body[node.body.length - 1]);
} else if (node) {
nodes.push(node);
}
return nodes;
};
/**
* Description
*/
t.toKeyAlias = function (node: Object, key: Object = node.key) {
var alias;
if (t.isIdentifier(key)) {
alias = key.name;
} else if (t.isLiteral(key)) {
alias = JSON.stringify(key.value);
} else {
alias = JSON.stringify(traverse.removeProperties(t.cloneDeep(key)));
}
if (node.computed) alias = `[${alias}]`;
return alias;
};
/**
* Description
*/
t.getSpecifierName = function (specifier: Object): Object {
return specifier.name || specifier.id;
};
/**
* Description
*/
t.getSpecifierId = function (specifier: Object): Object {
if (specifier.default) {
return t.identifier("default");
} else {
return specifier.id;
}
};
/**
* Description
*/
t.isSpecifierDefault = function (specifier: Object): boolean {
return specifier.default || t.isIdentifier(specifier.id) && specifier.id.name === "default";
};
/**
* Description
*/
t.isScope = function (node: Object, parent: Object): boolean {
if (t.isBlockStatement(node)) {
if (t.isLoop(parent.block, { body: node })) {
return false;
}
if (t.isFunction(parent.block, { body: node })) {
return false;
}
}
return t.isScopable(node);
};
/**
* Description
*/
t.isImmutable = function (node: Object): boolean {
if (t.isLiteral(node)) {
if (node.regex) {
// regexes are mutable
return false;
} else {
// immutable!
return true;
}
} else if (t.isIdentifier(node)) {
if (node.name === "undefined") {
// immutable!
return true;
} else {
// no idea...
return false;
}
}
return false;
};
/**
* Walk the input `node` and statically evaluate if it's truthy.
*
* Returning `true` when we're sure that the expression will evaluate to a
* truthy value, `false` if we're sure that it will evaluate to a falsy
* value and `undefined` if we aren't sure. Because of this please do not
* rely on coercion when using this method and check with === if it's false.
*
* For example do:
*
* if (t.evaluateTruthy(node) === false) falsyLogic();
*
* **AND NOT**
*
* if (!t.evaluateTruthy(node)) falsyLogic();
*
*/
t.evaluateTruthy = function (node: Object, scope: Scope): boolean {
var res = t.evaluate(node, scope);
if (res.confident) return !!res.value;
};
/**
* Walk the input `node` and statically evaluate it.
*
* Returns an pbject in the form `{ confident, value }`. `confident` indicates
* whether or not we had to drop out of evaluating the expression because of
* hitting an unknown node that we couldn't confidently find the value of.
*
* Example:
*
* t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }
* t.evaluate(parse("!true")) // { confident: true, value: false }
* t.evaluate(parse("foo + foo")) // { confident: false, value: undefined }
*
*/
t.evaluate = function (node: Object, scope: Scope): { confident: boolean; value: any } {
var confident = true;
var value = evaluate(node);
if (!confident) value = undefined;
return {
confident: confident,
value: value
};
function evaluate(node) {
if (!confident) return;
if (t.isSequenceExpression(node)) {
return evaluate(node.expressions[node.expressions.length - 1]);
}
if (t.isLiteral(node)) {
if (node.regex && node.value === null) {
// we have a regex and we can't represent it natively
} else {
return node.value;
}
}
if (t.isConditionalExpression(node)) {
if (evaluate(node.test)) {
return evaluate(node.consequent);
} else {
return evaluate(node.alternate);
}
}
if (t.isIdentifier(node)) {
if (node.name === "undefined") {
return undefined;
} else {
return evaluate(scope.getImmutableBindingValue(node.name));
}
}
if (t.isUnaryExpression(node, { prefix: true })) {
var arg = evaluate(node.argument);
switch (node.operator) {
case "void": return undefined;
case "!": return !arg;
case "+": return +arg;
case "-": return -arg;
}
}
if (t.isArrayExpression(node) || t.isObjectExpression(node)) {
// we could evaluate these but it's probably impractical and not very useful
}
if (t.isLogicalExpression(node)) {
var left = evaluate(node.left);
var right = evaluate(node.right);
switch (node.operator) {
case "||": return left || right;
case "&&": return left && right;
}
}
if (t.isBinaryExpression(node)) {
var left = evaluate(node.left);
var right = evaluate(node.right);
switch (node.operator) {
case "-": return left - right;
case "+": return left + right;
case "/": return left / right;
case "*": return left * right;
case "%": return left % right;
case "<": return left < right;
case ">": return left > right;
case "<=": return left <= right;
case ">=": return left >= right;
case "==": return left == right;
case "!=": return left != right;
case "===": return left === right;
case "!==": return left !== right;
}
}
confident = false;
}
};
/**
* Description
*/
t.valueToNode = function (value: any): Object {
if (value === undefined) {
return t.identifier("undefined");
}
if (value === true || value === false || value === null || isString(value) || isNumber(value) || isRegExp(value)) {
return t.literal(value);
}
if (Array.isArray(value)) {
return t.arrayExpression(value.map(t.valueToNode));
}
if (isPlainObject(value)) {
var props = [];
for (var key in value) {
var nodeKey;
if (t.isValidIdentifier(key)) {
nodeKey = t.identifier(key);
} else {
nodeKey = t.literal(key);
}
props.push(t.property("init", nodeKey, t.valueToNode(value[key])));
}
return t.objectExpression(props);
}
throw new Error("don't know how to turn this value into a node");
};
}
toFastProperties(t);
toFastProperties(t.VISITOR_KEYS);
exports.__esModule = true;
assign(t, require("./evaluators"));
assign(t, require("./retrievers"));
assign(t, require("./validators"));
assign(t, require("./converters"));

View File

@@ -0,0 +1,105 @@
import object from "../helpers/object";
import * as t from "./index";
/**
* Return a list of binding identifiers associated with
* the input `node`.
*/
export function getBindingIdentifiers(node: Object): Object {
var search = [].concat(node);
var ids = object();
while (search.length) {
var id = search.shift();
if (!id) continue;
var keys = t.getBindingIdentifiers.keys[id.type];
if (t.isIdentifier(id)) {
ids[id.name] = id;
} else if (t.isImportSpecifier(id)) {
search.push(id.name || id.id);
} else if (t.isExportDeclaration(id)) {
if (t.isDeclaration(node.declaration)) {
search.push(node.declaration);
}
} else if (keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
search = search.concat(id[key] || []);
}
}
}
return ids;
}
getBindingIdentifiers.keys = {
UnaryExpression: ["argument"],
AssignmentExpression: ["left"],
ImportBatchSpecifier: ["name"],
VariableDeclarator: ["id"],
FunctionDeclaration: ["id"],
FunctionExpression: ["id"],
ClassDeclaration: ["id"],
ClassExpression: ["id"],
SpreadElement: ["argument"],
RestElement: ["argument"],
UpdateExpression: ["argument"],
SpreadProperty: ["argument"],
Property: ["value"],
ComprehensionBlock: ["left"],
AssignmentPattern: ["left"],
PrivateDeclaration: ["declarations"],
ComprehensionExpression: ["blocks"],
ImportDeclaration: ["specifiers"],
VariableDeclaration: ["declarations"],
ArrayPattern: ["elements"],
ObjectPattern: ["properties"]
};
/**
* Description
*/
export function getLastStatements(node: Object): Array<Object> {
var nodes = [];
var add = function (node) {
nodes = nodes.concat(getLastStatements(node));
};
if (t.isIfStatement(node)) {
add(node.consequent);
add(node.alternate);
} else if (t.isFor(node) || t.isWhile(node)) {
add(node.body);
} else if (t.isProgram(node) || t.isBlockStatement(node)) {
add(node.body[node.body.length - 1]);
} else if (node) {
nodes.push(node);
}
return nodes;
}
/**
* Description
*/
export function getSpecifierName(specifier: Object): Object {
return specifier.name || specifier.id;
}
/**
* Description
*/
export function getSpecifierId(specifier: Object): Object {
if (specifier.default) {
return t.identifier("default");
} else {
return specifier.id;
}
}

View File

@@ -0,0 +1,202 @@
import isString from "lodash/lang/isString";
import esutils from "esutils";
import * as t from "./index";
/**
* Check if the input `node` is a reference to a bound variable.
*/
export function isReferenced(node: Object, parent: Object): boolean {
// yes: PARENT[NODE]
// yes: NODE.child
// no: parent.CHILD
if (t.isMemberExpression(parent)) {
if (parent.property === node && parent.computed) {
return true;
} else if (parent.object === node) {
return true;
} else {
return false;
}
}
// yes: { [NODE]: "" }
// no: { NODE: "" }
if (t.isProperty(parent) && parent.key === node) {
return parent.computed;
}
// no: var NODE = init;
// yes: var id = NODE;
if (t.isVariableDeclarator(parent)) {
return parent.id !== node;
}
// no: function NODE() {}
// no: function foo(NODE) {}
if (t.isFunction(parent)) {
for (var i = 0; i < parent.params.length; i++) {
var param = parent.params[i];
if (param === node) return false;
}
return parent.id !== node;
}
// no: export { foo as NODE };
if (t.isExportSpecifier(parent, { name: node })) {
return false;
}
// no: import { NODE as foo } from "foo";
if (t.isImportSpecifier(parent, { id: node })) {
return false;
}
// no: class NODE {}
if (t.isClass(parent)) {
return parent.id !== node;
}
// yes: class { [NODE](){} }
if (t.isMethodDefinition(parent)) {
return parent.key === node && parent.computed;
}
// no: NODE: for (;;) {}
if (t.isLabeledStatement(parent)) {
return false;
}
// no: try {} catch (NODE) {}
if (t.isCatchClause(parent)) {
return parent.param !== node;
}
// no: function foo(...NODE) {}
if (t.isRestElement(parent)) {
return false;
}
// no: [NODE = foo] = [];
// yes: [foo = NODE] = [];
if (t.isAssignmentPattern(parent)) {
return parent.right === node;
}
// no: [NODE] = [];
// no: ({ NODE }) = [];
if (t.isPattern(parent)) {
return false;
}
// no: import NODE from "bar";
if (t.isImportSpecifier(parent)) {
return false;
}
// no: import * as NODE from "foo";
if (t.isImportBatchSpecifier(parent)) {
return false;
}
// no: class Foo { private NODE; }
if (t.isPrivateDeclaration(parent)) {
return false;
}
return true;
}
/**
* Check if the input `node` is an `Identifier` and `isReferenced`.
*/
export function isReferencedIdentifier(node: Object, parent: Object, opts?: Object): boolean {
return t.isIdentifier(node, opts) && t.isReferenced(node, parent);
}
/**
* Check if the input `name` is a valid identifier name
* and isn't a reserved word.
*/
export function isValidIdentifier(name: string): boolean {
return isString(name) && esutils.keyword.isIdentifierName(name) && !esutils.keyword.isReservedWordES6(name, true);
}
/**
* Description
*/
export function isLet(node: Object): boolean {
return t.isVariableDeclaration(node) && (node.kind !== "var" || node._let);
}
/**
* Description
*/
export function isBlockScoped(node: Object): boolean {
return t.isFunctionDeclaration(node) || t.isClassDeclaration(node) || t.isLet(node);
}
/**
* Description
*/
export function isVar(node: Object): boolean {
return t.isVariableDeclaration(node, { kind: "var" }) && !node._let;
}
/**
* Description
*/
export function isSpecifierDefault(specifier: Object): boolean {
return specifier.default || t.isIdentifier(specifier.id) && specifier.id.name === "default";
}
/**
* Description
*/
export function isScope(node: Object, parent: Object): boolean {
if (t.isBlockStatement(node)) {
if (t.isLoop(parent.block, { body: node })) {
return false;
}
if (t.isFunction(parent.block, { body: node })) {
return false;
}
}
return t.isScopable(node);
}
/**
* Description
*/
export function isImmutable(node: Object): boolean {
if (t.isLiteral(node)) {
if (node.regex) {
// regexes are mutable
return false;
} else {
// immutable!
return true;
}
} else if (t.isIdentifier(node)) {
if (node.name === "undefined") {
// immutable!
return true;
} else {
// no idea...
return false;
}
}
return false;
}

View File

@@ -14,7 +14,7 @@ import path from "path";
import each from "lodash/collection/each";
import has from "lodash/object/has";
import fs from "fs";
import t from "./types";
import * as t from "./types";
export { inherits, inspect } from "util";