more classes!
This commit is contained in:
parent
f7186980e5
commit
553eb2d45e
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 () {
|
||||
|
||||
@ -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--;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user