split up babel core into multiple modules
This commit is contained in:
133
packages/babel-generator/src/node/index.js
Normal file
133
packages/babel-generator/src/node/index.js
Normal file
@@ -0,0 +1,133 @@
|
||||
import whitespace from "./whitespace";
|
||||
import * as parens from "./parentheses";
|
||||
import each from "lodash/collection/each";
|
||||
import some from "lodash/collection/some";
|
||||
import * as t from "babel-types";
|
||||
|
||||
/**
|
||||
* Test if node matches a set of type-matcher pairs.
|
||||
* @example
|
||||
* find({
|
||||
* VariableDeclaration(node, parent) {
|
||||
* return true;
|
||||
* }
|
||||
* }, node, parent);
|
||||
*/
|
||||
|
||||
var find = function (obj, node, parent) {
|
||||
if (!obj) return;
|
||||
var result;
|
||||
|
||||
var types = Object.keys(obj);
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
var type = types[i];
|
||||
|
||||
if (t.is(type, node)) {
|
||||
var fn = obj[type];
|
||||
result = fn(node, parent);
|
||||
if (result != null) break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whitespace and Parenthesis related methods for nodes.
|
||||
*/
|
||||
|
||||
export default class Node {
|
||||
constructor(node, parent) {
|
||||
this.parent = parent;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if `node` can have whitespace set by the user.
|
||||
*/
|
||||
|
||||
static isUserWhitespacable(node) {
|
||||
return t.isUserWhitespacable(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a `node` requires whitespace.
|
||||
*/
|
||||
|
||||
static needsWhitespace(node, parent, type) {
|
||||
if (!node) return 0;
|
||||
|
||||
if (t.isExpressionStatement(node)) {
|
||||
node = node.expression;
|
||||
}
|
||||
|
||||
var linesInfo = find(whitespace.nodes, node, parent);
|
||||
|
||||
if (!linesInfo) {
|
||||
var items = find(whitespace.list, node, parent);
|
||||
if (items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
linesInfo = Node.needsWhitespace(items[i], node, type);
|
||||
if (linesInfo) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (linesInfo && linesInfo[type]) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a `node` requires whitespace before it.
|
||||
*/
|
||||
|
||||
static needsWhitespaceBefore(node, parent) {
|
||||
return Node.needsWhitespace(node, parent, "before");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a `note` requires whitespace after it.
|
||||
*/
|
||||
|
||||
static needsWhitespaceAfter(node, parent) {
|
||||
return Node.needsWhitespace(node, parent, "after");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a `node` needs parentheses around it.
|
||||
*/
|
||||
|
||||
static needsParens(node, parent) {
|
||||
if (!parent) return false;
|
||||
|
||||
if (t.isNewExpression(parent) && parent.callee === node) {
|
||||
if (t.isCallExpression(node)) return true;
|
||||
|
||||
var hasCall = some(node, function (val) {
|
||||
return t.isCallExpression(val);
|
||||
});
|
||||
if (hasCall) return true;
|
||||
}
|
||||
|
||||
return find(parens, node, parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all static methods from `Node` to `Node.prototype`.
|
||||
*/
|
||||
|
||||
each(Node, function (fn, key) {
|
||||
Node.prototype[key] = function () {
|
||||
// Avoid leaking arguments to prevent deoptimization
|
||||
var args = new Array(arguments.length + 2);
|
||||
|
||||
args[0] = this.node;
|
||||
args[1] = this.parent;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
args[i + 2] = arguments[i];
|
||||
}
|
||||
|
||||
return Node[key].apply(null, args);
|
||||
};
|
||||
});
|
||||
238
packages/babel-generator/src/node/parentheses.js
Normal file
238
packages/babel-generator/src/node/parentheses.js
Normal file
@@ -0,0 +1,238 @@
|
||||
import each from "lodash/collection/each";
|
||||
import * as t from "babel-types";
|
||||
|
||||
/**
|
||||
* Create a mapping of operators to precendence.
|
||||
*
|
||||
* @example
|
||||
* { "==": 6, "+": 9 }
|
||||
*/
|
||||
const PRECEDENCE = {};
|
||||
|
||||
each([
|
||||
["||"],
|
||||
["&&"],
|
||||
["|"],
|
||||
["^"],
|
||||
["&"],
|
||||
["==", "===", "!=", "!=="],
|
||||
["<", ">", "<=", ">=", "in", "instanceof"],
|
||||
[">>", "<<", ">>>"],
|
||||
["+", "-"],
|
||||
["*", "/", "%"],
|
||||
["**"]
|
||||
], function (tier, i) {
|
||||
each(tier, function (op) {
|
||||
PRECEDENCE[op] = i;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test if NullableTypeAnnotation needs parentheses.
|
||||
*/
|
||||
|
||||
export function NullableTypeAnnotation(node, parent) {
|
||||
return t.isArrayTypeAnnotation(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias NullableTypeAnnotation test as FunctionTypeAnnotation.
|
||||
*/
|
||||
|
||||
export { NullableTypeAnnotation as FunctionTypeAnnotation };
|
||||
|
||||
/**
|
||||
* Test if UpdateExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function UpdateExpression(node, parent) {
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
// (foo++).test()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if ObjectExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function ObjectExpression(node, parent) {
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
// ({ foo: "bar" });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
// ({ foo: "bar" }).foo
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if Binary needs parentheses.
|
||||
*/
|
||||
|
||||
export function Binary(node, parent) {
|
||||
if ((t.isCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isBinary(parent)) {
|
||||
var parentOp = parent.operator;
|
||||
var parentPos = PRECEDENCE[parentOp];
|
||||
|
||||
var nodeOp = node.operator;
|
||||
var nodePos = PRECEDENCE[nodeOp];
|
||||
|
||||
if (parentPos > nodePos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPos === nodePos && parent.right === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if BinaryExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function BinaryExpression(node, parent) {
|
||||
if (node.operator === "in") {
|
||||
// var i = (1 in []);
|
||||
if (t.isVariableDeclarator(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for ((1 in []);;);
|
||||
if (t.isFor(parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if SequenceExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function SequenceExpression(node, parent) {
|
||||
if (t.isForStatement(parent)) {
|
||||
// Although parentheses wouldn't hurt around sequence
|
||||
// expressions in the head of for loops, traditional style
|
||||
// dictates that e.g. i++, j++ should not be wrapped with
|
||||
// parentheses.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t.isExpressionStatement(parent) && parent.expression === node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise err on the side of overparenthesization, adding
|
||||
// explicit exceptions above if this proves overzealous.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if YieldExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function YieldExpression(node, parent) {
|
||||
return t.isBinary(parent) ||
|
||||
t.isUnaryLike(parent) ||
|
||||
t.isCallExpression(parent) ||
|
||||
t.isMemberExpression(parent) ||
|
||||
t.isNewExpression(parent) ||
|
||||
t.isConditionalExpression(parent) ||
|
||||
t.isYieldExpression(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if ClassExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function ClassExpression(node, parent) {
|
||||
return t.isExpressionStatement(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if UnaryLike needs parentheses.
|
||||
*/
|
||||
|
||||
export function UnaryLike(node, parent) {
|
||||
return t.isMemberExpression(parent) && parent.object === node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if FunctionExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function FunctionExpression(node, parent) {
|
||||
// function () {};
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function test() {}).name;
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function () {})();
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if ConditionalExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function ConditionalExpression(node, parent) {
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isBinary(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isCallExpression(parent) || t.isNewExpression(parent)) {
|
||||
if (parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isConditionalExpression(parent) && parent.test === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if AssignmentExpression needs parentheses.
|
||||
*/
|
||||
|
||||
export function AssignmentExpression(node) {
|
||||
if (t.isObjectPattern(node.left)) {
|
||||
return true;
|
||||
} else {
|
||||
return ConditionalExpression(...arguments);
|
||||
}
|
||||
}
|
||||
76
packages/babel-generator/src/node/printer.js
Normal file
76
packages/babel-generator/src/node/printer.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Printer for nodes, needs a `generator` and a `parent`.
|
||||
*/
|
||||
|
||||
export default class NodePrinter {
|
||||
constructor(generator, parent) {
|
||||
this.generator = generator;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
printInnerComments() {
|
||||
if (!this.parent.innerComments) return;
|
||||
var gen = this.generator;
|
||||
gen.indent();
|
||||
gen._printComments(this.parent.innerComments);
|
||||
gen.dedent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a plain node.
|
||||
*/
|
||||
|
||||
plain(node, opts) {
|
||||
return this.generator.print(node, this.parent, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a sequence of nodes as statements.
|
||||
*/
|
||||
|
||||
sequence(nodes, opts = {}) {
|
||||
opts.statement = true;
|
||||
return this.generator.printJoin(this, nodes, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a sequence of nodes as expressions.
|
||||
*/
|
||||
|
||||
join(nodes, opts) {
|
||||
return this.generator.printJoin(this, nodes, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a list of nodes, with a customizable separator (defaults to ",").
|
||||
*/
|
||||
|
||||
list(items, opts = {}) {
|
||||
if (opts.separator == null) {
|
||||
opts.separator = ",";
|
||||
if (!this.generator.format.compact) opts.separator += " ";
|
||||
}
|
||||
|
||||
return this.join(items, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a block-like node.
|
||||
*/
|
||||
|
||||
block(node) {
|
||||
return this.generator.printBlock(this, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print node and indent comments.
|
||||
*/
|
||||
|
||||
indentOnComments(node) {
|
||||
return this.generator.printAndIndentOnComments(this, node);
|
||||
}
|
||||
}
|
||||
229
packages/babel-generator/src/node/whitespace.js
Normal file
229
packages/babel-generator/src/node/whitespace.js
Normal file
@@ -0,0 +1,229 @@
|
||||
import isBoolean from "lodash/lang/isBoolean";
|
||||
import each from "lodash/collection/each";
|
||||
import map from "lodash/collection/map";
|
||||
import * as t from "babel-types";
|
||||
|
||||
/**
|
||||
* Crawl a node to test if it contains a CallExpression, a Function, or a Helper.
|
||||
*
|
||||
* @example
|
||||
* crawl(node)
|
||||
* // { hasCall: false, hasFunction: true, hasHelper: false }
|
||||
*/
|
||||
|
||||
function crawl(node, state = {}) {
|
||||
if (t.isMemberExpression(node)) {
|
||||
crawl(node.object, state);
|
||||
if (node.computed) crawl(node.property, state);
|
||||
} else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
|
||||
crawl(node.left, state);
|
||||
crawl(node.right, state);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
state.hasCall = true;
|
||||
crawl(node.callee, state);
|
||||
} else if (t.isFunction(node)) {
|
||||
state.hasFunction = true;
|
||||
} else if (t.isIdentifier(node)) {
|
||||
state.hasHelper = state.hasHelper || isHelper(node.callee);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a node is or has a helper.
|
||||
*/
|
||||
|
||||
function isHelper(node) {
|
||||
if (t.isMemberExpression(node)) {
|
||||
return isHelper(node.object) || isHelper(node.property);
|
||||
} else if (t.isIdentifier(node)) {
|
||||
return node.name === "require" || node.name[0] === "_";
|
||||
} else if (t.isCallExpression(node)) {
|
||||
return isHelper(node.callee);
|
||||
} else if (t.isBinary(node) || t.isAssignmentExpression(node)) {
|
||||
return (t.isIdentifier(node.left) && isHelper(node.left)) || isHelper(node.right);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Please add a description.]
|
||||
*/
|
||||
|
||||
function isType(node) {
|
||||
return t.isLiteral(node) || t.isObjectExpression(node) || t.isArrayExpression(node) ||
|
||||
t.isIdentifier(node) || t.isMemberExpression(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for node types that need whitespace.
|
||||
*/
|
||||
|
||||
exports.nodes = {
|
||||
|
||||
/**
|
||||
* Test if AssignmentExpression needs whitespace.
|
||||
*/
|
||||
|
||||
AssignmentExpression(node) {
|
||||
var state = crawl(node.right);
|
||||
if ((state.hasCall && state.hasHelper) || state.hasFunction) {
|
||||
return {
|
||||
before: state.hasFunction,
|
||||
after: true
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if SwitchCase needs whitespace.
|
||||
*/
|
||||
|
||||
SwitchCase(node, parent) {
|
||||
return {
|
||||
before: node.consequent.length || parent.cases[0] === node
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if LogicalExpression needs whitespace.
|
||||
*/
|
||||
|
||||
LogicalExpression(node) {
|
||||
if (t.isFunction(node.left) || t.isFunction(node.right)) {
|
||||
return {
|
||||
after: true
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if Literal needs whitespace.
|
||||
*/
|
||||
|
||||
Literal(node) {
|
||||
if (node.value === "use strict") {
|
||||
return {
|
||||
after: true
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if CallExpression needs whitespace.
|
||||
*/
|
||||
|
||||
CallExpression(node) {
|
||||
if (t.isFunction(node.callee) || isHelper(node)) {
|
||||
return {
|
||||
before: true,
|
||||
after: true
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if VariableDeclaration needs whitespace.
|
||||
*/
|
||||
|
||||
VariableDeclaration(node) {
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var declar = node.declarations[i];
|
||||
|
||||
var enabled = isHelper(declar.id) && !isType(declar.init);
|
||||
if (!enabled) {
|
||||
var state = crawl(declar.init);
|
||||
enabled = (isHelper(declar.init) && state.hasCall) || state.hasFunction;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
return {
|
||||
before: true,
|
||||
after: true
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Test if IfStatement needs whitespace.
|
||||
*/
|
||||
|
||||
IfStatement(node) {
|
||||
if (t.isBlockStatement(node.consequent)) {
|
||||
return {
|
||||
before: true,
|
||||
after: true
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if Property or SpreadProperty needs whitespace.
|
||||
*/
|
||||
|
||||
exports.nodes.Property =
|
||||
exports.nodes.SpreadProperty = function (node, parent) {
|
||||
if (parent.properties[0] === node) {
|
||||
return {
|
||||
before: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns lists from node types that need whitespace.
|
||||
*/
|
||||
|
||||
exports.list = {
|
||||
|
||||
/**
|
||||
* Return VariableDeclaration declarations init properties.
|
||||
*/
|
||||
|
||||
VariableDeclaration(node) {
|
||||
return map(node.declarations, "init");
|
||||
},
|
||||
|
||||
/**
|
||||
* Return VariableDeclaration elements.
|
||||
*/
|
||||
|
||||
ArrayExpression(node) {
|
||||
return node.elements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return VariableDeclaration properties.
|
||||
*/
|
||||
|
||||
ObjectExpression(node) {
|
||||
return node.properties;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add whitespace tests for nodes and their aliases.
|
||||
*/
|
||||
|
||||
each({
|
||||
Function: true,
|
||||
Class: true,
|
||||
Loop: true,
|
||||
LabeledStatement: true,
|
||||
SwitchStatement: true,
|
||||
TryStatement: true
|
||||
}, function (amounts, type) {
|
||||
if (isBoolean(amounts)) {
|
||||
amounts = { after: amounts, before: amounts };
|
||||
}
|
||||
|
||||
each([type].concat(t.FLIPPED_ALIAS_KEYS[type] || []), function (type) {
|
||||
exports.nodes[type] = function () {
|
||||
return amounts;
|
||||
};
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user