more classes!

This commit is contained in:
Sebastian McKenzie 2015-02-26 12:19:28 +11:00
parent f7186980e5
commit 553eb2d45e
13 changed files with 2125 additions and 2117 deletions

View File

@ -1,76 +1,75 @@
module.exports = Buffer;
var repeating = require("repeating");
var trimRight = require("trim-right");
var isBoolean = require("lodash/lang/isBoolean");
var includes = require("lodash/collection/includes");
var isNumber = require("lodash/lang/isNumber");
function Buffer(position, format) {
export default class Buffer {
constructor(position, format) {
this.position = position;
this._indent = format.indent.base;
this.format = format;
this.buf = "";
}
Buffer.prototype.get = function () {
get() {
return trimRight(this.buf);
};
}
Buffer.prototype.getIndent = function () {
getIndent() {
if (this.format.compact || this.format.concise) {
return "";
} else {
return repeating(this.format.indent.style, this._indent);
}
};
}
Buffer.prototype.indentSize = function () {
indentSize() {
return this.getIndent().length;
};
}
Buffer.prototype.indent = function () {
indent() {
this._indent++;
};
}
Buffer.prototype.dedent = function () {
dedent() {
this._indent--;
};
}
Buffer.prototype.semicolon = function () {
semicolon() {
this.push(";");
};
}
Buffer.prototype.ensureSemicolon = function () {
ensureSemicolon() {
if (!this.isLast(";")) this.semicolon();
};
}
Buffer.prototype.rightBrace = function () {
rightBrace() {
this.newline(true);
this.push("}");
};
}
Buffer.prototype.keyword = function (name) {
keyword(name) {
this.push(name);
this.space();
};
}
Buffer.prototype.space = function () {
space() {
if (this.format.compact) return;
if (this.buf && !this.isLast(" ") && !this.isLast("\n")) {
this.push(" ");
}
};
}
Buffer.prototype.removeLast = function (cha) {
removeLast(cha) {
if (this.format.compact) return;
if (!this.isLast(cha)) return;
this.buf = this.buf.substr(0, this.buf.length - 1);
this.position.unshift(cha);
};
}
Buffer.prototype.newline = function (i, removeLast) {
newline(i, removeLast) {
if (this.format.compact) return;
if (this.format.concise) {
@ -98,9 +97,9 @@ Buffer.prototype.newline = function (i, removeLast) {
}
this._newline(removeLast);
};
}
Buffer.prototype._newline = function (removeLast) {
_newline(removeLast) {
// never allow more than two lines
if (this.endsWith("\n\n")) return;
@ -110,13 +109,13 @@ Buffer.prototype._newline = function (removeLast) {
this.removeLast(" ");
this._removeSpacesAfterLastNewline();
this._push("\n");
};
}
/**
* If buffer ends with a newline and some spaces after it, trim those spaces.
*/
Buffer.prototype._removeSpacesAfterLastNewline = function () {
_removeSpacesAfterLastNewline() {
var lastNewlineIndex = this.buf.lastIndexOf("\n");
if (lastNewlineIndex === -1)
return;
@ -133,9 +132,9 @@ Buffer.prototype._removeSpacesAfterLastNewline = function () {
if (index === lastNewlineIndex) {
this.buf = this.buf.substring(0, index + 1);
}
};
}
Buffer.prototype.push = function (str, noIndent) {
push(str, noIndent) {
if (!this.format.compact && this._indent && !noIndent && str !== "\n") {
// we have an indent level and we aren't pushing a newline
var indent = this.getIndent();
@ -148,18 +147,18 @@ Buffer.prototype.push = function (str, noIndent) {
}
this._push(str);
};
}
Buffer.prototype._push = function (str) {
_push(str) {
this.position.push(str);
this.buf += str;
};
}
Buffer.prototype.endsWith = function (str) {
endsWith(str) {
return this.buf.slice(-str.length) === str;
};
}
Buffer.prototype.isLast = function (cha) {
isLast(cha) {
if (this.format.compact) return false;
var buf = this.buf;
@ -170,4 +169,5 @@ Buffer.prototype.isLast = function (cha) {
} else {
return cha === last;
}
};
}
}

View File

@ -1,10 +1,3 @@
module.exports = function (ast, opts, code) {
var gen = new CodeGenerator(ast, opts, code);
return gen.generate();
};
module.exports.CodeGenerator = CodeGenerator;
var detectIndent = require("detect-indent");
var Whitespace = require("./whitespace");
var repeating = require("repeating");
@ -17,7 +10,8 @@ var each = require("lodash/collection/each");
var n = require("./node");
var t = require("../types");
function CodeGenerator(ast, opts, code) {
class CodeGenerator {
constructor(ast, opts, code) {
opts ||= {};
this.comments = ast.comments || [];
@ -32,13 +26,7 @@ function CodeGenerator(ast, opts, code) {
this.buffer = new Buffer(this.position, this.format);
}
each(Buffer.prototype, function (fn, key) {
CodeGenerator.prototype[key] = function () {
return fn.apply(this.buffer, arguments);
};
});
CodeGenerator.normalizeOptions = function (code, opts) {
static normalizeOptions(code, opts) {
var style = " ";
if (code) {
var indent = detectIndent(code).indent;
@ -64,9 +52,9 @@ CodeGenerator.normalizeOptions = function (code, opts) {
}
return format;
};
}
CodeGenerator.generators = {
static generators = {
templateLiterals: require("./generators/template-literals"),
comprehensions: require("./generators/comprehensions"),
expressions: require("./generators/expressions"),
@ -81,11 +69,7 @@ CodeGenerator.generators = {
jsx: require("./generators/jsx")
};
each(CodeGenerator.generators, function (generator) {
extend(CodeGenerator.prototype, generator);
});
CodeGenerator.prototype.generate = function () {
generate() {
var ast = this.ast;
this.print(ast);
@ -100,9 +84,9 @@ CodeGenerator.prototype.generate = function () {
map: this.map.get(),
code: this.buffer.get()
};
};
}
CodeGenerator.prototype.buildPrint = function (parent) {
buildPrint(parent) {
var print = (node, opts) => {
return this.print(node, parent, opts);
};
@ -132,9 +116,9 @@ CodeGenerator.prototype.buildPrint = function (parent) {
};
return print;
};
}
CodeGenerator.prototype.print = function (node, parent, opts) {
print(node, parent, opts) {
if (!node) return "";
if (parent && parent._compact) {
@ -211,9 +195,9 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
}
this.format.concise = oldConcise;
};
}
CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
printJoin(print, nodes, opts) {
if (!nodes || !nodes.length) return;
opts ||= {};
@ -239,25 +223,25 @@ CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
});
if (opts.indent) this.dedent();
};
}
CodeGenerator.prototype.printAndIndentOnComments = function (print, node) {
printAndIndentOnComments(print, node) {
var indent = !!node.leadingComments;
if (indent) this.indent();
print(node);
if (indent) this.dedent();
};
}
CodeGenerator.prototype.printBlock = function (print, node) {
printBlock(print, node) {
if (t.isEmptyStatement(node)) {
this.semicolon();
} else {
this.push(" ");
print(node);
}
};
}
CodeGenerator.prototype.generateComment = function (comment) {
generateComment(comment) {
var val = comment.value;
if (comment.type === "Line") {
val = "//" + val;
@ -265,17 +249,17 @@ CodeGenerator.prototype.generateComment = function (comment) {
val = "/*" + val + "*/";
}
return val;
};
}
CodeGenerator.prototype.printTrailingComments = function (node, parent) {
printTrailingComments(node, parent) {
this._printComments(this.getComments("trailingComments", node, parent));
};
}
CodeGenerator.prototype.printLeadingComments = function (node, parent) {
printLeadingComments(node, parent) {
this._printComments(this.getComments("leadingComments", node, parent));
};
}
CodeGenerator.prototype.getComments = function (key, node, parent) {
getComments(key, node, parent) {
if (t.isExpressionStatement(parent)) {
return [];
}
@ -292,13 +276,13 @@ CodeGenerator.prototype.getComments = function (key, node, parent) {
});
return comments;
};
}
CodeGenerator.prototype._getComments = function (key, node) {
_getComments(key, node) {
return (node && node[key]) || [];
};
}
CodeGenerator.prototype._printComments = function (comments) {
_printComments(comments) {
if (this.format.compact) return;
if (!this.format.comments) return;
@ -355,4 +339,22 @@ CodeGenerator.prototype._printComments = function (comments) {
// whitespace after
this.newline(this.whitespace.getNewlinesAfter(comment));
});
}
}
each(Buffer.prototype, function (fn, key) {
CodeGenerator.prototype[key] = function () {
return fn.apply(this.buffer, arguments);
};
});
each(CodeGenerator.generators, function (generator) {
extend(CodeGenerator.prototype, generator);
});
module.exports = function (ast, opts, code) {
var gen = new CodeGenerator(ast, opts, code);
return gen.generate();
};
module.exports.CodeGenerator = CodeGenerator;

View File

@ -1,5 +1,3 @@
module.exports = Node;
var whitespace = require("./whitespace");
var parens = require("./parentheses");
var each = require("lodash/collection/each");
@ -24,16 +22,17 @@ var find = function (obj, node, parent) {
return result;
};
function Node(node, parent) {
export default class Node {
constructor(node, parent) {
this.parent = parent;
this.node = node;
}
Node.isUserWhitespacable = function (node) {
static isUserWhitespacable(node) {
return t.isUserWhitespacable(node);
};
}
Node.needsWhitespace = function (node, parent, type) {
static needsWhitespace(node, parent, type) {
if (!node) return 0;
if (t.isExpressionStatement(node)) {
@ -53,17 +52,17 @@ Node.needsWhitespace = function (node, parent, type) {
}
return (linesInfo && linesInfo[type]) || 0;
};
}
Node.needsWhitespaceBefore = function (node, parent) {
static needsWhitespaceBefore(node, parent) {
return Node.needsWhitespace(node, parent, "before");
};
}
Node.needsWhitespaceAfter = function (node, parent) {
static needsWhitespaceAfter(node, parent) {
return Node.needsWhitespace(node, parent, "after");
};
}
Node.needsParens = function (node, parent) {
static needsParens(node, parent) {
if (!parent) return false;
if (t.isNewExpression(parent) && parent.callee === node) {
@ -76,9 +75,9 @@ Node.needsParens = function (node, parent) {
}
return find(parens, node, parent);
};
}
Node.needsParensNoLineTerminator = function (node, parent) {
static needsParensNoLineTerminator(node, parent) {
if (!parent) return false;
// no comments
@ -96,7 +95,8 @@ Node.needsParensNoLineTerminator = function (node, parent) {
}
return false;
};
}
}
each(Node, function (fn, key) {
Node.prototype[key] = function () {

View File

@ -1,11 +1,10 @@
module.exports = Position;
function Position() {
export default class Position {
constructor() {
this.line = 1;
this.column = 0;
}
Position.prototype.push = function (str) {
push(str) {
for (var i = 0; i < str.length; i++) {
if (str[i] === "\n") {
this.line++;
@ -14,9 +13,9 @@ Position.prototype.push = function (str) {
this.column++;
}
}
};
}
Position.prototype.unshift = function (str) {
unshift(str) {
for (var i = 0; i < str.length; i++) {
if (str[i] === "\n") {
this.line--;
@ -24,4 +23,5 @@ Position.prototype.unshift = function (str) {
this.column--;
}
}
};
}
}

View File

@ -1,9 +1,8 @@
module.exports = SourceMap;
var sourceMap = require("source-map");
var t = require("../types");
function SourceMap(position, opts, code) {
export default class SourceMap {
constructor(position, opts, code) {
this.position = position;
this.opts = opts;
@ -19,16 +18,16 @@ function SourceMap(position, opts, code) {
}
}
SourceMap.prototype.get = function () {
get() {
var map = this.map;
if (map) {
return map.toJSON();
} else {
return map;
}
};
}
SourceMap.prototype.mark = function (node, type) {
mark(node, type) {
var loc = node.loc;
if (!loc) return; // no location info
@ -51,4 +50,5 @@ SourceMap.prototype.mark = function (node, type) {
generated: generated,
original: original
});
};
}
}

View File

@ -1,5 +1,3 @@
module.exports = Whitespace;
var sortBy = require("lodash/collection/sortBy");
/**
@ -22,7 +20,8 @@ function getLookupIndex(i, base, max) {
return i;
}
function Whitespace(tokens, comments) {
export default class Whitespace {
constructor(tokens, comments) {
this.tokens = sortBy(tokens.concat(comments), "start");
this.used = {};
@ -37,7 +36,7 @@ function Whitespace(tokens, comments) {
this._lastFoundIndex = 0;
}
Whitespace.prototype.getNewlinesBefore = function (node) {
getNewlinesBefore(node) {
var startToken;
var endToken;
var tokens = this.tokens;
@ -59,9 +58,9 @@ Whitespace.prototype.getNewlinesBefore = function (node) {
}
return this.getNewlinesBetween(startToken, endToken);
};
}
Whitespace.prototype.getNewlinesAfter = function (node) {
getNewlinesAfter(node) {
var startToken;
var endToken;
var tokens = this.tokens;
@ -93,9 +92,9 @@ Whitespace.prototype.getNewlinesAfter = function (node) {
return lines;
}
}
};
}
Whitespace.prototype.getNewlinesBetween = function (startToken, endToken) {
getNewlinesBetween(startToken, endToken) {
if (!endToken || !endToken.loc) return 0;
var start = startToken ? startToken.loc.end.line : 1;
@ -110,4 +109,5 @@ Whitespace.prototype.getNewlinesBetween = function (startToken, endToken) {
}
return lines;
};
}
}

View File

@ -1,5 +1,3 @@
module.exports = File;
var sourceMapToComment = require("source-map-to-comment");
var shebangRegex = require("shebang-regex");
var isFunction = require("lodash/lang/isFunction");
@ -16,7 +14,21 @@ var path = require("path");
var each = require("lodash/collection/each");
var t = require("../types");
function File(opts) {
var checkTransformerVisitor = {
enter(node, parent, scope, state) {
checkNode(state.stack, node, scope);
}
};
var checkNode = function (stack, node, scope) {
each(stack, function (pass) {
if (pass.shouldRun) return;
pass.checkNode(node, scope);
});
};
export default class File {
constructor(opts) {
this.dynamicImportedNoDefault = [];
this.dynamicImportIds = {};
this.dynamicImported = [];
@ -33,7 +45,7 @@ function File(opts) {
this.buildTransformers();
}
File.helpers = [
static helpers = [
"inherits",
"defaults",
"prototype-properties",
@ -62,7 +74,7 @@ File.helpers = [
"self-global"
];
File.validOptions = [
static validOptions = [
"filename",
"filenameRelative",
"blacklist",
@ -101,7 +113,7 @@ File.validOptions = [
"accept"
];
File.prototype.normalizeOptions = function (opts) {
normalizeOptions(opts) {
opts = assign({}, opts);
for (var key in opts) {
@ -202,11 +214,11 @@ File.prototype.normalizeOptions = function (opts) {
return opts;
};
File.prototype.isLoose = function (key) {
isLoose(key) {
return includes(this.opts.loose, key);
};
}
File.prototype.buildTransformers = function () {
buildTransformers() {
var file = this;
var transformers = {};
@ -232,15 +244,15 @@ File.prototype.buildTransformers = function () {
this.transformerStack = stack.concat(secondaryStack);
this.transformers = transformers;
};
}
File.prototype.debug = function (msg) {
debug(msg) {
var parts = this.opts.filename;
if (msg) parts += ": " + msg;
util.debug(parts);
};
}
File.prototype.getModuleFormatter = function (type) {
getModuleFormatter(type) {
var ModuleFormatter = isFunction(type) ? type : transform.moduleFormatters[type];
if (!ModuleFormatter) {
@ -253,9 +265,9 @@ File.prototype.getModuleFormatter = function (type) {
}
return new ModuleFormatter(this);
};
}
File.prototype.parseShebang = function (code) {
parseShebang(code) {
var shebangMatch = shebangRegex.exec(code);
if (shebangMatch) {
@ -266,17 +278,17 @@ File.prototype.parseShebang = function (code) {
}
return code;
};
}
File.prototype.set = function (key, val) {
set(key, val) {
return this.data[key] = val;
};
File.prototype.setDynamic = function (key, fn) {
setDynamic(key, fn) {
this.dynamicData[key] = fn;
};
}
File.prototype.get = function (key) {
get(key) {
var data = this.data[key];
if (data) {
return data;
@ -286,9 +298,9 @@ File.prototype.get = function (key) {
return this.set(key, dynamic());
}
}
};
}
File.prototype.addImport = function (source, name, noDefault) {
addImport(source, name, noDefault) {
name ||= source;
var id = this.dynamicImportIds[name];
@ -306,13 +318,13 @@ File.prototype.addImport = function (source, name, noDefault) {
}
return id;
};
}
File.prototype.isConsequenceExpressionStatement = function (node) {
isConsequenceExpressionStatement(node) {
return t.isExpressionStatement(node) && this.lastStatements.indexOf(node) >= 0;
};
}
File.prototype.attachAuxiliaryComment = function (node) {
attachAuxiliaryComment(node) {
var comment = this.opts.auxiliaryComment;
if (comment) {
node.leadingComments ||= [];
@ -322,9 +334,9 @@ File.prototype.attachAuxiliaryComment = function (node) {
});
}
return node;
};
}
File.prototype.addHelper = function (name) {
addHelper(name) {
if (!includes(File.helpers, name)) {
throw new ReferenceError("Unknown helper " + name);
}
@ -351,28 +363,28 @@ File.prototype.addHelper = function (name) {
});
return uid;
}
};
}
File.prototype.logDeopt = function () {
logDeopt() {
// todo, (node, msg)
};
}
File.prototype.errorWithNode = function (node, msg, Error) {
errorWithNode(node, msg, Error) {
Error ||= SyntaxError;
var loc = node.loc.start;
var err = new Error("Line " + loc.line + ": " + msg);
err.loc = loc;
return err;
};
}
File.prototype.addCode = function (code) {
addCode(code) {
code = (code || "") + "";
this.code = code;
return this.parseShebang(code);
};
}
File.prototype.parse = function (code) {
parse(code) {
code = this.addCode(code);
var opts = this.opts;
@ -384,9 +396,9 @@ File.prototype.parse = function (code) {
this.transform(tree);
return this.generate();
});
};
}
File.prototype.transform = function (ast) {
transform(ast) {
this.debug();
this.ast = ast;
@ -407,9 +419,9 @@ File.prototype.transform = function (ast) {
});
this.call("post");
};
}
File.prototype.call = function (key) {
call(key) {
var stack = this.transformerStack;
for (var i = 0; i < stack.length; i++) {
var transformer = stack[i].transformer;
@ -417,22 +429,9 @@ File.prototype.call = function (key) {
transformer[key](this);
}
}
};
var checkTransformerVisitor = {
enter(node, parent, scope, state) {
checkNode(state.stack, node, scope);
}
};
var checkNode = function (stack, node, scope) {
each(stack, function (pass) {
if (pass.shouldRun) return;
pass.checkNode(node, scope);
});
};
File.prototype.checkNode = function (node, scope) {
checkNode(node, scope) {
var stack = this.transformerStack;
scope ||= this.scope;
@ -441,9 +440,9 @@ File.prototype.checkNode = function (node, scope) {
scope.traverse(node, checkTransformerVisitor, {
stack: stack
});
};
}
File.prototype.generate = function () {
generate() {
var opts = this.opts;
var ast = this.ast;
@ -475,4 +474,5 @@ File.prototype.generate = function () {
}
return result;
};
}
}

View File

@ -3,94 +3,16 @@ module.exports = ReplaceSupers;
var messages = require("../../messages");
var t = require("../../types");
/**
* Description
*
* @param {Object} opts
* @param {Boolean} [inClass]
*/
function ReplaceSupers(opts, inClass) {
this.topLevelThisReference = opts.topLevelThisReference;
this.methodNode = opts.methodNode;
this.className = opts.className;
this.superName = opts.superName;
this.isStatic = opts.isStatic;
this.hasSuper = false;
this.inClass = inClass;
this.isLoose = opts.isLoose;
this.scope = opts.scope;
this.file = opts.file;
}
/**
* Sets a super class value of the named property.
*
* @example
*
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
*
* @param {Node} property
* @param {Node} value
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
ReplaceSupers.prototype.setSuperProperty = function (property, value, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("set"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
value,
thisExpression
]
);
var isIllegalBareSuper = function (node, parent) {
if (!isSuper(node, parent)) return false;
if (t.isMemberExpression(parent, { computed: false })) return false;
if (t.isCallExpression(parent, { callee: node })) return false;
return true;
};
/**
* Gets a node representing the super class value of the named property.
*
* @example
*
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
*
* @param {Node} property
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
ReplaceSupers.prototype.getSuperProperty = function (property, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("get"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
thisExpression
]
);
};
/**
* Description
*/
ReplaceSupers.prototype.replace = function () {
this.traverseLevel(this.methodNode.value, true);
var isSuper = function (node, parent) {
return t.isIdentifier(node, { name: "super" }) && t.isReferenced(node, parent);
};
var visitor = {
@ -121,6 +43,98 @@ var visitor = {
}
};
export default class ReplaceSupers {
/**
* Description
*
* @param {Object} opts
* @param {Boolean} [inClass]
*/
constructor(opts, inClass) {
this.topLevelThisReference = opts.topLevelThisReference;
this.methodNode = opts.methodNode;
this.className = opts.className;
this.superName = opts.superName;
this.isStatic = opts.isStatic;
this.hasSuper = false;
this.inClass = inClass;
this.isLoose = opts.isLoose;
this.scope = opts.scope;
this.file = opts.file;
}
/**
* Sets a super class value of the named property.
*
* @example
*
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
*
* @param {Node} property
* @param {Node} value
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
setSuperProperty(property, value, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("set"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
value,
thisExpression
]
);
}
/**
* Gets a node representing the super class value of the named property.
*
* @example
*
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
*
* @param {Node} property
* @param {Boolean} isComputed
* @param {Node} thisExpression
*
* @returns {Node}
*/
getSuperProperty(property, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("get"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
thisExpression
]
);
}
/**
* Description
*/
replace() {
this.traverseLevel(this.methodNode.value, true);
}
/**
* Description
*
@ -128,16 +142,16 @@ var visitor = {
* @param {Boolean} topLevel
*/
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
traverseLevel(node, topLevel) {
var state = { self: this, topLevel: topLevel };
this.scope.traverse(node, visitor, state);
};
}
/**
* Description
*/
ReplaceSupers.prototype.getThisReference = function () {
getThisReference() {
if (this.topLevelThisReference) {
return this.topLevelThisReference;
} else {
@ -147,7 +161,7 @@ ReplaceSupers.prototype.getThisReference = function () {
]));
return ref;
}
};
}
/**
* Description
@ -158,7 +172,7 @@ ReplaceSupers.prototype.getThisReference = function () {
* @returns {Object}
*/
ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
getLooseSuperProperty(id, parent) {
var methodNode = this.methodNode;
var methodName = methodNode.key;
var superName = this.superName || t.identifier("Function");
@ -189,7 +203,7 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
} else {
return superName;
}
};
}
/**
* Description
@ -199,7 +213,7 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
* @param {Object} parent
*/
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
looseHandle(getThisReference, node, parent) {
if (t.isIdentifier(node, { name: "super" })) {
this.hasSuper = true;
return this.getLooseSuperProperty(node, parent);
@ -213,7 +227,7 @@ ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent)
t.appendToMemberExpression(callee, t.identifier("call"));
node.arguments.unshift(getThisReference());
}
};
}
/**
* Description
@ -223,7 +237,7 @@ ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent)
* @param {Object} parent
*/
ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
specHandle(getThisReference, node, parent) {
var methodNode = this.methodNode;
var property;
var computed;
@ -287,15 +301,5 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
} else {
return superProperty;
}
};
var isIllegalBareSuper = function (node, parent) {
if (!isSuper(node, parent)) return false;
if (t.isMemberExpression(parent, { computed: false })) return false;
if (t.isCallExpression(parent, { callee: node })) return false;
return true;
};
var isSuper = function (node, parent) {
return t.isIdentifier(node, { name: "super" }) && t.isReferenced(node, parent);
};
}
}

View File

@ -1,5 +1,3 @@
module.exports = TransformerPass;
var includes = require("lodash/collection/includes");
/**
@ -7,14 +5,15 @@ var includes = require("lodash/collection/includes");
* AST and running it's parent transformers handlers over it.
*/
function TransformerPass(file, transformer) {
export default class TransformerPass {
constructor(file, transformer) {
this.transformer = transformer;
this.shouldRun = !transformer.check;
this.handlers = transformer.handlers;
this.file = file;
}
TransformerPass.prototype.canRun = function () {
canRun() {
var transformer = this.transformer;
var opts = this.file.opts;
@ -41,18 +40,18 @@ TransformerPass.prototype.canRun = function () {
if (transformer.playground && !opts.playground) return false;
return true;
};
}
TransformerPass.prototype.checkNode = function (node) {
checkNode(node) {
var check = this.transformer.check;
if (check) {
return this.shouldRun = check(node);
} else {
return true;
}
};
}
TransformerPass.prototype.transform = function () {
transform() {
if (!this.shouldRun) return;
var file = this.file;
@ -60,4 +59,5 @@ TransformerPass.prototype.transform = function () {
file.debug("Running transformer " + this.transformer.key);
file.scope.traverse(file.ast, this.handlers, file);
};
}
}

View File

@ -1,5 +1,3 @@
module.exports = Transformer;
var TransformerPass = require("./transformer-pass");
var isFunction = require("lodash/lang/isFunction");
var traverse = require("../traversal");
@ -13,7 +11,8 @@ var each = require("lodash/collection/each");
* actually running the transformer over the provided `File`.
*/
function Transformer(key, transformer, opts) {
export default class Transformer {
constructor(key, transformer, opts) {
transformer = assign({}, transformer);
var take = function (key) {
@ -37,7 +36,7 @@ function Transformer(key, transformer, opts) {
this.key = key;
}
Transformer.prototype.normalize = function (transformer) {
normalize(transformer) {
if (isFunction(transformer)) {
transformer = { ast: transformer };
}
@ -64,8 +63,9 @@ Transformer.prototype.normalize = function (transformer) {
});
return transformer;
};
}
Transformer.prototype.buildPass = function (file) {
buildPass(file) {
return new TransformerPass(file, this);
};
}
}

View File

@ -1,10 +1,9 @@
module.exports = TraversalContext;
var TraversalPath = require("./path");
var flatten = require("lodash/array/flatten");
var compact = require("lodash/array/compact");
function TraversalContext(scope, opts, state, parentPath) {
export default class TraversalConext {
constructor(scope, opts, state, parentPath) {
this.shouldFlatten = false;
this.parentPath = parentPath;
@ -13,16 +12,16 @@ function TraversalContext(scope, opts, state, parentPath) {
this.opts = opts;
}
TraversalContext.prototype.flatten = function () {
flatten() {
this.shouldFlatten = true;
};
}
TraversalContext.prototype.visitNode = function (node, obj, key) {
visitNode(node, obj, key) {
var iteration = new TraversalPath(this, node, obj, key);
return iteration.visit();
};
}
TraversalContext.prototype.visit = function (node, key) {
visit(node, key) {
var nodes = node[key];
if (!nodes) return;
@ -49,4 +48,5 @@ TraversalContext.prototype.visit = function (node, key) {
node[key] = compact(node[key]);
}
}
};
}
}

View File

@ -1,11 +1,10 @@
module.exports = TraversalPath;
var traverse = require("./index");
var includes = require("lodash/collection/includes");
var Scope = require("./scope");
var t = require("../types");
function TraversalPath(context, parent, container, key) {
export default class TraversalPath {
constructor(context, parent, container, key) {
this.shouldRemove = false;
this.shouldSkip = false;
this.shouldStop = false;
@ -24,7 +23,7 @@ function TraversalPath(context, parent, container, key) {
this.setScope();
}
TraversalPath.getScope = function (node, parent, scope) {
static getScope(node, parent, scope) {
var ourScope = scope;
// we're entering a new scope so let's construct it!
@ -33,36 +32,35 @@ TraversalPath.getScope = function (node, parent, scope) {
}
return ourScope;
};
}
TraversalPath.prototype.setScope = function () {
setScope() {
this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope);
};
}
TraversalPath.prototype.remove = function () {
remove() {
this.shouldRemove = true;
this.shouldSkip = true;
};
}
TraversalPath.prototype.skip = function () {
skip() {
this.shouldSkip = true;
};
}
TraversalPath.prototype.stop = function () {
stop() {
this.shouldStop = true;
this.shouldSkip = true;
};
}
TraversalPath.prototype.flatten = function () {
flatten() {
this.context.flatten();
};
}
Object.defineProperty(TraversalPath.prototype, "node", {
get() {
get node() {
return this.container[this.key];
},
}
set(replacement) {
set node(replacement) {
var isArray = Array.isArray(replacement);
// inherit comments from original node to the first replacement node
@ -95,9 +93,8 @@ Object.defineProperty(TraversalPath.prototype, "node", {
this.flatten();
}
}
});
TraversalPath.prototype.call = function (key) {
call(key) {
var node = this.node;
if (!node) return;
@ -115,9 +112,9 @@ TraversalPath.prototype.call = function (key) {
this.container[this.key] = null;
this.flatten();
}
};
}
TraversalPath.prototype.visit = function () {
visit() {
var opts = this.opts;
var node = this.node;
@ -146,8 +143,9 @@ TraversalPath.prototype.visit = function () {
}
return this.shouldStop;
};
}
TraversalPath.prototype.isReferencedIdentifier = function () {
isReferencedIdentifier() {
return t.isReferencedIdentifier(this.node);
};
}
}

View File

@ -1,4 +1,4 @@
module.exports = Scope;
var includes = require("lodash/collection/includes");
var traverse = require("./index");
@ -11,6 +11,58 @@ var object = require("../helpers/object");
var each = require("lodash/collection/each");
var t = require("../types");
var functionVariableVisitor = {
enter(node, parent, scope, state) {
if (t.isFor(node)) {
each(t.FOR_INIT_KEYS, function (key) {
var declar = node[key];
if (t.isVar(declar)) state.scope.registerBinding("var", declar);
});
}
// this block is a function so we'll stop since none of the variables
// declared within are accessible
if (t.isFunction(node)) return this.skip();
// function identifier doesn't belong to this scope
if (state.blockId && node === state.blockId) return;
// delegate block scope handling to the `blockVariableVisitor`
if (t.isBlockScoped(node)) return;
// this will be hit again once we traverse into it after this iteration
if (t.isExportDeclaration(node) && t.isDeclaration(node.declaration)) return;
// we've ran into a declaration!
if (t.isDeclaration(node)) state.scope.registerDeclaration(node);
}
};
var programReferenceVisitor = {
enter(node, parent, scope, state) {
if (t.isReferencedIdentifier(node, parent) && !scope.hasBinding(node.name)) {
state.addGlobal(node);
} else if (t.isLabeledStatement(node)) {
state.addGlobal(node);
} else if (t.isAssignmentExpression(node) || t.isUpdateExpression(node) || (t.isUnaryExpression(node) && node.operator === "delete")) {
scope.registerBindingReassignment(node);
}
}
};
var blockVariableVisitor = {
enter(node, parent, scope, state) {
if (t.isFunctionDeclaration(node) || t.isBlockScoped(node)) {
state.registerDeclaration(node);
} else if (t.isScope(node, parent)) {
this.skip();
}
}
};
export default class Scope {
/**
* This searches the current "scope" and collects all references/bindings
* within.
@ -21,7 +73,7 @@ var t = require("../types");
* @param {File} [file]
*/
function Scope(block, parentBlock, parent, file) {
constructor(block, parentBlock, parent, file) {
this.parent = parent;
this.file = parent ? parent.file : file;
@ -31,7 +83,7 @@ function Scope(block, parentBlock, parent, file) {
this.crawl();
}
Scope.globals = flatten([globals.builtin, globals.browser, globals.node].map(Object.keys));
static globals = flatten([globals.builtin, globals.browser, globals.node].map(Object.keys));
/**
* Description
@ -41,9 +93,9 @@ Scope.globals = flatten([globals.builtin, globals.browser, globals.node].map(Obj
* @param [state]
*/
Scope.prototype.traverse = function (node, opts, state) {
traverse(node, opts, state) {
traverse(node, opts, this, state);
};
}
/**
* Description
@ -51,14 +103,14 @@ Scope.prototype.traverse = function (node, opts, state) {
* @param {String} [name="temp"]
*/
Scope.prototype.generateTemp = function (name) {
generateTemp(name) {
var id = this.generateUidIdentifier(name || "temp");
this.push({
key: id.name,
id: id
});
return id;
};
}
/**
* Description
@ -66,11 +118,11 @@ Scope.prototype.generateTemp = function (name) {
* @param {String} name
*/
Scope.prototype.generateUidIdentifier = function (name) {
generateUidIdentifier(name) {
var id = t.identifier(this.generateUid(name));
this.getFunctionParent().registerBinding("uid", id);
return id;
};
}
/**
* Description
@ -78,7 +130,7 @@ Scope.prototype.generateUidIdentifier = function (name) {
* @param {String} name
*/
Scope.prototype.generateUid = function (name) {
generateUid(name) {
name = t.toIdentifier(name).replace(/^_+/, "");
var uid;
@ -88,13 +140,13 @@ Scope.prototype.generateUid = function (name) {
i++;
} while (this.hasBinding(uid) || this.hasGlobal(uid));
return uid;
};
}
Scope.prototype._generateUid = function (name, i) {
_generateUid(name, i) {
var id = name;
if (i > 1) id += i;
return "_" + id;
};
}
/*
* Description
@ -103,7 +155,7 @@ Scope.prototype._generateUid = function (name, i) {
* @returns {Object}
*/
Scope.prototype.generateUidBasedOnNode = function (parent) {
generateUidBasedOnNode(parent) {
var node = parent;
if (t.isAssignmentExpression(parent)) {
@ -135,7 +187,7 @@ Scope.prototype.generateUidBasedOnNode = function (parent) {
id = id.replace(/^_/, "") || "ref";
return this.generateUidIdentifier(id);
};
}
/**
* Description
@ -144,7 +196,7 @@ Scope.prototype.generateUidBasedOnNode = function (parent) {
* @returns {Object}
*/
Scope.prototype.generateTempBasedOnNode = function (node) {
generateTempBasedOnNode(node) {
if (t.isIdentifier(node) && this.hasBinding(node.name)) {
return null;
}
@ -155,9 +207,9 @@ Scope.prototype.generateTempBasedOnNode = function (node) {
id: id
});
return id;
};
}
Scope.prototype.checkBlockScopedCollisions = function (kind, name, id) {
checkBlockScopedCollisions(kind, name, id) {
var local = this.getOwnBindingInfo(name);
if (!local) return;
@ -167,9 +219,9 @@ Scope.prototype.checkBlockScopedCollisions = function (kind, name, id) {
if (local.kind === "let" || local.kind === "const" || local.kind === "module") {
throw this.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
}
};
}
Scope.prototype.rename = function (oldName, newName) {
rename(oldName, newName) {
newName ||= this.generateUidIdentifier(oldName).name;
var info = this.getBindingInfo(oldName);
@ -199,9 +251,9 @@ Scope.prototype.rename = function (oldName, newName) {
scope.bindings[newName] = info;
binding.name = newName;
};
}
Scope.prototype.inferType = function (node) {
inferType(node) {
var target;
if (t.isVariableDeclarator(node)) {
@ -231,28 +283,28 @@ Scope.prototype.inferType = function (node) {
if (t.isIdentifier(target)) {
return;
}
};
}
Scope.prototype.isTypeGeneric = function (name, genericName) {
isTypeGeneric(name, genericName) {
var info = this.getBindingInfo(name);
if (!info) return false;
var type = info.typeAnnotation;
return t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName });
};
}
Scope.prototype.assignTypeGeneric = function (name, type) {
assignTypeGeneric(name, type) {
this.assignType(name, t.genericTypeAnnotation(t.identifier(type)));
};
}
Scope.prototype.assignType = function (name, type) {
assignType(name, type) {
var info = this.getBindingInfo(name);
if (!info) return;
info.identifier.typeAnnotation = info.typeAnnotation = type;
};
}
Scope.prototype.getTypeAnnotation = function (name, id, node) {
getTypeAnnotation(name, id, node) {
var info = {
annotation: null,
inferred: false
@ -275,9 +327,9 @@ Scope.prototype.getTypeAnnotation = function (name, id, node) {
}
return info;
};
}
Scope.prototype.toArray = function (node, i) {
toArray(node, i) {
var file = this.file;
if (t.isIdentifier(node) && this.isTypeGeneric(node.name, "Array")) {
@ -301,13 +353,13 @@ Scope.prototype.toArray = function (node, i) {
helperName = "sliced-to-array";
}
return t.callExpression(file.addHelper(helperName), args);
};
}
Scope.prototype.clearOwnBinding = function (name) {
clearOwnBinding(name) {
delete this.bindings[name];
};
}
Scope.prototype.registerDeclaration = function (node) {
registerDeclaration(node) {
if (t.isFunctionDeclaration(node)) {
this.registerBinding("hoisted", node);
} else if (t.isVariableDeclaration(node)) {
@ -321,9 +373,9 @@ Scope.prototype.registerDeclaration = function (node) {
} else {
this.registerBinding("unknown", node);
}
};
}
Scope.prototype.registerBindingReassignment = function (node) {
registerBindingReassignment(node) {
var ids = t.getBindingIdentifiers(node);
for (var name in ids) {
var info = this.getBindingInfo(name);
@ -336,9 +388,9 @@ Scope.prototype.registerBindingReassignment = function (node) {
}
}
}
};
}
Scope.prototype.registerBinding = function (kind, node) {
registerBinding(kind, node) {
if (!kind) throw new ReferenceError("no `kind`");
var ids = t.getBindingIdentifiers(node);
@ -360,47 +412,20 @@ Scope.prototype.registerBinding = function (kind, node) {
kind: kind
};
}
};
}
Scope.prototype.registerVariableDeclaration = function (declar) {
registerVariableDeclaration(declar) {
var declars = declar.declarations;
for (var i = 0; i < declars.length; i++) {
this.registerBinding(declars[i], declar.kind);
}
};
var functionVariableVisitor = {
enter(node, parent, scope, state) {
if (t.isFor(node)) {
each(t.FOR_INIT_KEYS, function (key) {
var declar = node[key];
if (t.isVar(declar)) state.scope.registerBinding("var", declar);
});
}
// this block is a function so we'll stop since none of the variables
// declared within are accessible
if (t.isFunction(node)) return this.skip();
// function identifier doesn't belong to this scope
if (state.blockId && node === state.blockId) return;
// delegate block scope handling to the `blockVariableVisitor`
if (t.isBlockScoped(node)) return;
// this will be hit again once we traverse into it after this iteration
if (t.isExportDeclaration(node) && t.isDeclaration(node.declaration)) return;
// we've ran into a declaration!
if (t.isDeclaration(node)) state.scope.registerDeclaration(node);
}
};
Scope.prototype.addGlobal = function (node) {
addGlobal(node) {
this.globals[node.name] = node;
};
Scope.prototype.hasGlobal = function (name) {
hasGlobal(name) {
var scope = this;
do {
@ -408,31 +433,9 @@ Scope.prototype.hasGlobal = function (name) {
} while (scope = scope.parent);
return false;
};
}
var programReferenceVisitor = {
enter(node, parent, scope, state) {
if (t.isReferencedIdentifier(node, parent) && !scope.hasBinding(node.name)) {
state.addGlobal(node);
} else if (t.isLabeledStatement(node)) {
state.addGlobal(node);
} else if (t.isAssignmentExpression(node) || t.isUpdateExpression(node) || (t.isUnaryExpression(node) && node.operator === "delete")) {
scope.registerBindingReassignment(node);
}
}
};
var blockVariableVisitor = {
enter(node, parent, scope, state) {
if (t.isFunctionDeclaration(node) || t.isBlockScoped(node)) {
state.registerDeclaration(node);
} else if (t.isScope(node, parent)) {
this.skip();
}
}
};
Scope.prototype.crawl = function () {
crawl() {
var block = this.block;
var i;
@ -513,7 +516,7 @@ Scope.prototype.crawl = function () {
if (t.isProgram(block)) {
this.traverse(block, programReferenceVisitor, this);
}
};
}
/**
* Description
@ -521,7 +524,7 @@ Scope.prototype.crawl = function () {
* @param {Object} opts
*/
Scope.prototype.push = function (opts) {
push(opts) {
var block = this.block;
if (t.isLoop(block) || t.isCatchClause(block) || t.isFunction(block)) {
@ -539,20 +542,20 @@ Scope.prototype.push = function (opts) {
} else {
throw new TypeError("cannot add a declaration here in node type " + block.type);
}
};
}
/**
* Walk up the scope tree until we hit either a Function or reach the
* very top and hit Program.
*/
Scope.prototype.getFunctionParent = function () {
getFunctionParent() {
var scope = this;
while (scope.parent && !t.isFunction(scope.block)) {
scope = scope.parent;
}
return scope;
};
}
/**
* Walks the scope tree and gathers **all** bindings.
@ -560,7 +563,7 @@ Scope.prototype.getFunctionParent = function () {
* @returns {Object}
*/
Scope.prototype.getAllBindings = function () {
getAllBindings() {
var ids = object();
var scope = this;
@ -570,7 +573,7 @@ Scope.prototype.getAllBindings = function () {
} while (scope);
return ids;
};
}
/**
* Walks the scope tree and gathers all declarations of `kind`.
@ -579,7 +582,7 @@ Scope.prototype.getAllBindings = function () {
* @returns {Object}
*/
Scope.prototype.getAllBindingsOfKind = function (kind) {
getAllBindingsOfKind(kind) {
var ids = object();
var scope = this;
@ -592,53 +595,54 @@ Scope.prototype.getAllBindingsOfKind = function (kind) {
} while (scope);
return ids;
};
}
// misc
Scope.prototype.bindingIdentifierEquals = function (name, node) {
bindingIdentifierEquals(name, node) {
return this.getBindingIdentifier(name) === node;
};
}
// get
Scope.prototype.getBindingInfo = function (name) {
getBindingInfo(name) {
var scope = this;
do {
var binding = scope.getOwnBindingInfo(name);
if (binding) return binding;
} while (scope = scope.parent);
};
}
Scope.prototype.getOwnBindingInfo = function (name) {
getOwnBindingInfo(name) {
return this.bindings[name];
};
}
Scope.prototype.getBindingIdentifier = function (name) {
getBindingIdentifier(name) {
var info = this.getBindingInfo(name);
return info && info.identifier;
};
}
Scope.prototype.getOwnBindingIdentifier = function (name) {
getOwnBindingIdentifier(name) {
var binding = this.bindings[name];
return binding && binding.identifier;
};
}
// has
Scope.prototype.hasOwnBinding = function (name) {
hasOwnBinding(name) {
return !!this.getOwnBindingInfo(name);
};
}
Scope.prototype.hasBinding = function (name) {
hasBinding(name) {
if (!name) return false;
if (this.hasOwnBinding(name)) return true;
if (this.parentHasBinding(name)) return true;
if (includes(Scope.globals, name)) return true;
return false;
};
}
Scope.prototype.parentHasBinding = function (name) {
parentHasBinding(name) {
return this.parent && this.parent.hasBinding(name);
};
}
}