more classes!
This commit is contained in:
parent
f7186980e5
commit
553eb2d45e
@ -1,76 +1,75 @@
|
|||||||
module.exports = Buffer;
|
|
||||||
|
|
||||||
var repeating = require("repeating");
|
var repeating = require("repeating");
|
||||||
var trimRight = require("trim-right");
|
var trimRight = require("trim-right");
|
||||||
var isBoolean = require("lodash/lang/isBoolean");
|
var isBoolean = require("lodash/lang/isBoolean");
|
||||||
var includes = require("lodash/collection/includes");
|
var includes = require("lodash/collection/includes");
|
||||||
var isNumber = require("lodash/lang/isNumber");
|
var isNumber = require("lodash/lang/isNumber");
|
||||||
|
|
||||||
function Buffer(position, format) {
|
export default class Buffer {
|
||||||
|
constructor(position, format) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this._indent = format.indent.base;
|
this._indent = format.indent.base;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.buf = "";
|
this.buf = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer.prototype.get = function () {
|
get() {
|
||||||
return trimRight(this.buf);
|
return trimRight(this.buf);
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.getIndent = function () {
|
getIndent() {
|
||||||
if (this.format.compact || this.format.concise) {
|
if (this.format.compact || this.format.concise) {
|
||||||
return "";
|
return "";
|
||||||
} else {
|
} else {
|
||||||
return repeating(this.format.indent.style, this._indent);
|
return repeating(this.format.indent.style, this._indent);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.indentSize = function () {
|
indentSize() {
|
||||||
return this.getIndent().length;
|
return this.getIndent().length;
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.indent = function () {
|
indent() {
|
||||||
this._indent++;
|
this._indent++;
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.dedent = function () {
|
dedent() {
|
||||||
this._indent--;
|
this._indent--;
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.semicolon = function () {
|
semicolon() {
|
||||||
this.push(";");
|
this.push(";");
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.ensureSemicolon = function () {
|
ensureSemicolon() {
|
||||||
if (!this.isLast(";")) this.semicolon();
|
if (!this.isLast(";")) this.semicolon();
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.rightBrace = function () {
|
rightBrace() {
|
||||||
this.newline(true);
|
this.newline(true);
|
||||||
this.push("}");
|
this.push("}");
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.keyword = function (name) {
|
keyword(name) {
|
||||||
this.push(name);
|
this.push(name);
|
||||||
this.space();
|
this.space();
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.space = function () {
|
space() {
|
||||||
if (this.format.compact) return;
|
if (this.format.compact) return;
|
||||||
if (this.buf && !this.isLast(" ") && !this.isLast("\n")) {
|
if (this.buf && !this.isLast(" ") && !this.isLast("\n")) {
|
||||||
this.push(" ");
|
this.push(" ");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.removeLast = function (cha) {
|
removeLast(cha) {
|
||||||
if (this.format.compact) return;
|
if (this.format.compact) return;
|
||||||
if (!this.isLast(cha)) return;
|
if (!this.isLast(cha)) return;
|
||||||
|
|
||||||
this.buf = this.buf.substr(0, this.buf.length - 1);
|
this.buf = this.buf.substr(0, this.buf.length - 1);
|
||||||
this.position.unshift(cha);
|
this.position.unshift(cha);
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.newline = function (i, removeLast) {
|
newline(i, removeLast) {
|
||||||
if (this.format.compact) return;
|
if (this.format.compact) return;
|
||||||
|
|
||||||
if (this.format.concise) {
|
if (this.format.concise) {
|
||||||
@ -98,9 +97,9 @@ Buffer.prototype.newline = function (i, removeLast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._newline(removeLast);
|
this._newline(removeLast);
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype._newline = function (removeLast) {
|
_newline(removeLast) {
|
||||||
// never allow more than two lines
|
// never allow more than two lines
|
||||||
if (this.endsWith("\n\n")) return;
|
if (this.endsWith("\n\n")) return;
|
||||||
|
|
||||||
@ -110,13 +109,13 @@ Buffer.prototype._newline = function (removeLast) {
|
|||||||
this.removeLast(" ");
|
this.removeLast(" ");
|
||||||
this._removeSpacesAfterLastNewline();
|
this._removeSpacesAfterLastNewline();
|
||||||
this._push("\n");
|
this._push("\n");
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If buffer ends with a newline and some spaces after it, trim those spaces.
|
* 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");
|
var lastNewlineIndex = this.buf.lastIndexOf("\n");
|
||||||
if (lastNewlineIndex === -1)
|
if (lastNewlineIndex === -1)
|
||||||
return;
|
return;
|
||||||
@ -133,9 +132,9 @@ Buffer.prototype._removeSpacesAfterLastNewline = function () {
|
|||||||
if (index === lastNewlineIndex) {
|
if (index === lastNewlineIndex) {
|
||||||
this.buf = this.buf.substring(0, index + 1);
|
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") {
|
if (!this.format.compact && this._indent && !noIndent && str !== "\n") {
|
||||||
// we have an indent level and we aren't pushing a newline
|
// we have an indent level and we aren't pushing a newline
|
||||||
var indent = this.getIndent();
|
var indent = this.getIndent();
|
||||||
@ -148,18 +147,18 @@ Buffer.prototype.push = function (str, noIndent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._push(str);
|
this._push(str);
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype._push = function (str) {
|
_push(str) {
|
||||||
this.position.push(str);
|
this.position.push(str);
|
||||||
this.buf += str;
|
this.buf += str;
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.endsWith = function (str) {
|
endsWith(str) {
|
||||||
return this.buf.slice(-str.length) === str;
|
return this.buf.slice(-str.length) === str;
|
||||||
};
|
}
|
||||||
|
|
||||||
Buffer.prototype.isLast = function (cha) {
|
isLast(cha) {
|
||||||
if (this.format.compact) return false;
|
if (this.format.compact) return false;
|
||||||
|
|
||||||
var buf = this.buf;
|
var buf = this.buf;
|
||||||
@ -170,4 +169,5 @@ Buffer.prototype.isLast = function (cha) {
|
|||||||
} else {
|
} else {
|
||||||
return cha === last;
|
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 detectIndent = require("detect-indent");
|
||||||
var Whitespace = require("./whitespace");
|
var Whitespace = require("./whitespace");
|
||||||
var repeating = require("repeating");
|
var repeating = require("repeating");
|
||||||
@ -17,7 +10,8 @@ var each = require("lodash/collection/each");
|
|||||||
var n = require("./node");
|
var n = require("./node");
|
||||||
var t = require("../types");
|
var t = require("../types");
|
||||||
|
|
||||||
function CodeGenerator(ast, opts, code) {
|
class CodeGenerator {
|
||||||
|
constructor(ast, opts, code) {
|
||||||
opts ||= {};
|
opts ||= {};
|
||||||
|
|
||||||
this.comments = ast.comments || [];
|
this.comments = ast.comments || [];
|
||||||
@ -30,15 +24,9 @@ function CodeGenerator(ast, opts, code) {
|
|||||||
this.position = new Position;
|
this.position = new Position;
|
||||||
this.map = new SourceMap(this.position, opts, code);
|
this.map = new SourceMap(this.position, opts, code);
|
||||||
this.buffer = new Buffer(this.position, this.format);
|
this.buffer = new Buffer(this.position, this.format);
|
||||||
}
|
}
|
||||||
|
|
||||||
each(Buffer.prototype, function (fn, key) {
|
static normalizeOptions(code, opts) {
|
||||||
CodeGenerator.prototype[key] = function () {
|
|
||||||
return fn.apply(this.buffer, arguments);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeGenerator.normalizeOptions = function (code, opts) {
|
|
||||||
var style = " ";
|
var style = " ";
|
||||||
if (code) {
|
if (code) {
|
||||||
var indent = detectIndent(code).indent;
|
var indent = detectIndent(code).indent;
|
||||||
@ -64,9 +52,9 @@ CodeGenerator.normalizeOptions = function (code, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.generators = {
|
static generators = {
|
||||||
templateLiterals: require("./generators/template-literals"),
|
templateLiterals: require("./generators/template-literals"),
|
||||||
comprehensions: require("./generators/comprehensions"),
|
comprehensions: require("./generators/comprehensions"),
|
||||||
expressions: require("./generators/expressions"),
|
expressions: require("./generators/expressions"),
|
||||||
@ -79,13 +67,9 @@ CodeGenerator.generators = {
|
|||||||
flow: require("./generators/flow"),
|
flow: require("./generators/flow"),
|
||||||
base: require("./generators/base"),
|
base: require("./generators/base"),
|
||||||
jsx: require("./generators/jsx")
|
jsx: require("./generators/jsx")
|
||||||
};
|
};
|
||||||
|
|
||||||
each(CodeGenerator.generators, function (generator) {
|
generate() {
|
||||||
extend(CodeGenerator.prototype, generator);
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeGenerator.prototype.generate = function () {
|
|
||||||
var ast = this.ast;
|
var ast = this.ast;
|
||||||
|
|
||||||
this.print(ast);
|
this.print(ast);
|
||||||
@ -100,9 +84,9 @@ CodeGenerator.prototype.generate = function () {
|
|||||||
map: this.map.get(),
|
map: this.map.get(),
|
||||||
code: this.buffer.get()
|
code: this.buffer.get()
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.buildPrint = function (parent) {
|
buildPrint(parent) {
|
||||||
var print = (node, opts) => {
|
var print = (node, opts) => {
|
||||||
return this.print(node, parent, opts);
|
return this.print(node, parent, opts);
|
||||||
};
|
};
|
||||||
@ -132,9 +116,9 @@ CodeGenerator.prototype.buildPrint = function (parent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return print;
|
return print;
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.print = function (node, parent, opts) {
|
print(node, parent, opts) {
|
||||||
if (!node) return "";
|
if (!node) return "";
|
||||||
|
|
||||||
if (parent && parent._compact) {
|
if (parent && parent._compact) {
|
||||||
@ -211,9 +195,9 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.format.concise = oldConcise;
|
this.format.concise = oldConcise;
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
|
printJoin(print, nodes, opts) {
|
||||||
if (!nodes || !nodes.length) return;
|
if (!nodes || !nodes.length) return;
|
||||||
|
|
||||||
opts ||= {};
|
opts ||= {};
|
||||||
@ -239,25 +223,25 @@ CodeGenerator.prototype.printJoin = function (print, nodes, opts) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (opts.indent) this.dedent();
|
if (opts.indent) this.dedent();
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.printAndIndentOnComments = function (print, node) {
|
printAndIndentOnComments(print, node) {
|
||||||
var indent = !!node.leadingComments;
|
var indent = !!node.leadingComments;
|
||||||
if (indent) this.indent();
|
if (indent) this.indent();
|
||||||
print(node);
|
print(node);
|
||||||
if (indent) this.dedent();
|
if (indent) this.dedent();
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.printBlock = function (print, node) {
|
printBlock(print, node) {
|
||||||
if (t.isEmptyStatement(node)) {
|
if (t.isEmptyStatement(node)) {
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
} else {
|
} else {
|
||||||
this.push(" ");
|
this.push(" ");
|
||||||
print(node);
|
print(node);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.generateComment = function (comment) {
|
generateComment(comment) {
|
||||||
var val = comment.value;
|
var val = comment.value;
|
||||||
if (comment.type === "Line") {
|
if (comment.type === "Line") {
|
||||||
val = "//" + val;
|
val = "//" + val;
|
||||||
@ -265,17 +249,17 @@ CodeGenerator.prototype.generateComment = function (comment) {
|
|||||||
val = "/*" + val + "*/";
|
val = "/*" + val + "*/";
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.printTrailingComments = function (node, parent) {
|
printTrailingComments(node, parent) {
|
||||||
this._printComments(this.getComments("trailingComments", 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));
|
this._printComments(this.getComments("leadingComments", node, parent));
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype.getComments = function (key, node, parent) {
|
getComments(key, node, parent) {
|
||||||
if (t.isExpressionStatement(parent)) {
|
if (t.isExpressionStatement(parent)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -292,13 +276,13 @@ CodeGenerator.prototype.getComments = function (key, node, parent) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return comments;
|
return comments;
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype._getComments = function (key, node) {
|
_getComments(key, node) {
|
||||||
return (node && node[key]) || [];
|
return (node && node[key]) || [];
|
||||||
};
|
}
|
||||||
|
|
||||||
CodeGenerator.prototype._printComments = function (comments) {
|
_printComments(comments) {
|
||||||
if (this.format.compact) return;
|
if (this.format.compact) return;
|
||||||
|
|
||||||
if (!this.format.comments) return;
|
if (!this.format.comments) return;
|
||||||
@ -355,4 +339,22 @@ CodeGenerator.prototype._printComments = function (comments) {
|
|||||||
// whitespace after
|
// whitespace after
|
||||||
this.newline(this.whitespace.getNewlinesAfter(comment));
|
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 whitespace = require("./whitespace");
|
||||||
var parens = require("./parentheses");
|
var parens = require("./parentheses");
|
||||||
var each = require("lodash/collection/each");
|
var each = require("lodash/collection/each");
|
||||||
@ -24,16 +22,17 @@ var find = function (obj, node, parent) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
function Node(node, parent) {
|
export default class Node {
|
||||||
|
constructor(node, parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.isUserWhitespacable = function (node) {
|
static isUserWhitespacable(node) {
|
||||||
return t.isUserWhitespacable(node);
|
return t.isUserWhitespacable(node);
|
||||||
};
|
}
|
||||||
|
|
||||||
Node.needsWhitespace = function (node, parent, type) {
|
static needsWhitespace(node, parent, type) {
|
||||||
if (!node) return 0;
|
if (!node) return 0;
|
||||||
|
|
||||||
if (t.isExpressionStatement(node)) {
|
if (t.isExpressionStatement(node)) {
|
||||||
@ -53,17 +52,17 @@ Node.needsWhitespace = function (node, parent, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (linesInfo && linesInfo[type]) || 0;
|
return (linesInfo && linesInfo[type]) || 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
Node.needsWhitespaceBefore = function (node, parent) {
|
static needsWhitespaceBefore(node, parent) {
|
||||||
return Node.needsWhitespace(node, parent, "before");
|
return Node.needsWhitespace(node, parent, "before");
|
||||||
};
|
}
|
||||||
|
|
||||||
Node.needsWhitespaceAfter = function (node, parent) {
|
static needsWhitespaceAfter(node, parent) {
|
||||||
return Node.needsWhitespace(node, parent, "after");
|
return Node.needsWhitespace(node, parent, "after");
|
||||||
};
|
}
|
||||||
|
|
||||||
Node.needsParens = function (node, parent) {
|
static needsParens(node, parent) {
|
||||||
if (!parent) return false;
|
if (!parent) return false;
|
||||||
|
|
||||||
if (t.isNewExpression(parent) && parent.callee === node) {
|
if (t.isNewExpression(parent) && parent.callee === node) {
|
||||||
@ -76,9 +75,9 @@ Node.needsParens = function (node, parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return find(parens, node, parent);
|
return find(parens, node, parent);
|
||||||
};
|
}
|
||||||
|
|
||||||
Node.needsParensNoLineTerminator = function (node, parent) {
|
static needsParensNoLineTerminator(node, parent) {
|
||||||
if (!parent) return false;
|
if (!parent) return false;
|
||||||
|
|
||||||
// no comments
|
// no comments
|
||||||
@ -96,7 +95,8 @@ Node.needsParensNoLineTerminator = function (node, parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
each(Node, function (fn, key) {
|
each(Node, function (fn, key) {
|
||||||
Node.prototype[key] = function () {
|
Node.prototype[key] = function () {
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
module.exports = Position;
|
export default class Position {
|
||||||
|
constructor() {
|
||||||
function Position() {
|
|
||||||
this.line = 1;
|
this.line = 1;
|
||||||
this.column = 0;
|
this.column = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position.prototype.push = function (str) {
|
push(str) {
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (var i = 0; i < str.length; i++) {
|
||||||
if (str[i] === "\n") {
|
if (str[i] === "\n") {
|
||||||
this.line++;
|
this.line++;
|
||||||
@ -14,9 +13,9 @@ Position.prototype.push = function (str) {
|
|||||||
this.column++;
|
this.column++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Position.prototype.unshift = function (str) {
|
unshift(str) {
|
||||||
for (var i = 0; i < str.length; i++) {
|
for (var i = 0; i < str.length; i++) {
|
||||||
if (str[i] === "\n") {
|
if (str[i] === "\n") {
|
||||||
this.line--;
|
this.line--;
|
||||||
@ -24,4 +23,5 @@ Position.prototype.unshift = function (str) {
|
|||||||
this.column--;
|
this.column--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
module.exports = SourceMap;
|
|
||||||
|
|
||||||
var sourceMap = require("source-map");
|
var sourceMap = require("source-map");
|
||||||
var t = require("../types");
|
var t = require("../types");
|
||||||
|
|
||||||
function SourceMap(position, opts, code) {
|
export default class SourceMap {
|
||||||
|
constructor(position, opts, code) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
|
|
||||||
@ -17,18 +16,18 @@ function SourceMap(position, opts, code) {
|
|||||||
} else {
|
} else {
|
||||||
this.map = null;
|
this.map = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceMap.prototype.get = function () {
|
get() {
|
||||||
var map = this.map;
|
var map = this.map;
|
||||||
if (map) {
|
if (map) {
|
||||||
return map.toJSON();
|
return map.toJSON();
|
||||||
} else {
|
} else {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
SourceMap.prototype.mark = function (node, type) {
|
mark(node, type) {
|
||||||
var loc = node.loc;
|
var loc = node.loc;
|
||||||
if (!loc) return; // no location info
|
if (!loc) return; // no location info
|
||||||
|
|
||||||
@ -51,4 +50,5 @@ SourceMap.prototype.mark = function (node, type) {
|
|||||||
generated: generated,
|
generated: generated,
|
||||||
original: original
|
original: original
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
module.exports = Whitespace;
|
|
||||||
|
|
||||||
var sortBy = require("lodash/collection/sortBy");
|
var sortBy = require("lodash/collection/sortBy");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +20,8 @@ function getLookupIndex(i, base, max) {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Whitespace(tokens, comments) {
|
export default class Whitespace {
|
||||||
|
constructor(tokens, comments) {
|
||||||
this.tokens = sortBy(tokens.concat(comments), "start");
|
this.tokens = sortBy(tokens.concat(comments), "start");
|
||||||
this.used = {};
|
this.used = {};
|
||||||
|
|
||||||
@ -35,9 +34,9 @@ function Whitespace(tokens, comments) {
|
|||||||
// case will be much faster.
|
// case will be much faster.
|
||||||
|
|
||||||
this._lastFoundIndex = 0;
|
this._lastFoundIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Whitespace.prototype.getNewlinesBefore = function (node) {
|
getNewlinesBefore(node) {
|
||||||
var startToken;
|
var startToken;
|
||||||
var endToken;
|
var endToken;
|
||||||
var tokens = this.tokens;
|
var tokens = this.tokens;
|
||||||
@ -59,9 +58,9 @@ Whitespace.prototype.getNewlinesBefore = function (node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.getNewlinesBetween(startToken, endToken);
|
return this.getNewlinesBetween(startToken, endToken);
|
||||||
};
|
}
|
||||||
|
|
||||||
Whitespace.prototype.getNewlinesAfter = function (node) {
|
getNewlinesAfter(node) {
|
||||||
var startToken;
|
var startToken;
|
||||||
var endToken;
|
var endToken;
|
||||||
var tokens = this.tokens;
|
var tokens = this.tokens;
|
||||||
@ -93,9 +92,9 @@ Whitespace.prototype.getNewlinesAfter = function (node) {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Whitespace.prototype.getNewlinesBetween = function (startToken, endToken) {
|
getNewlinesBetween(startToken, endToken) {
|
||||||
if (!endToken || !endToken.loc) return 0;
|
if (!endToken || !endToken.loc) return 0;
|
||||||
|
|
||||||
var start = startToken ? startToken.loc.end.line : 1;
|
var start = startToken ? startToken.loc.end.line : 1;
|
||||||
@ -110,4 +109,5 @@ Whitespace.prototype.getNewlinesBetween = function (startToken, endToken) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
module.exports = File;
|
|
||||||
|
|
||||||
var sourceMapToComment = require("source-map-to-comment");
|
var sourceMapToComment = require("source-map-to-comment");
|
||||||
var shebangRegex = require("shebang-regex");
|
var shebangRegex = require("shebang-regex");
|
||||||
var isFunction = require("lodash/lang/isFunction");
|
var isFunction = require("lodash/lang/isFunction");
|
||||||
@ -16,7 +14,21 @@ var path = require("path");
|
|||||||
var each = require("lodash/collection/each");
|
var each = require("lodash/collection/each");
|
||||||
var t = require("../types");
|
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.dynamicImportedNoDefault = [];
|
||||||
this.dynamicImportIds = {};
|
this.dynamicImportIds = {};
|
||||||
this.dynamicImported = [];
|
this.dynamicImported = [];
|
||||||
@ -31,9 +43,9 @@ function File(opts) {
|
|||||||
this.ast = {};
|
this.ast = {};
|
||||||
|
|
||||||
this.buildTransformers();
|
this.buildTransformers();
|
||||||
}
|
}
|
||||||
|
|
||||||
File.helpers = [
|
static helpers = [
|
||||||
"inherits",
|
"inherits",
|
||||||
"defaults",
|
"defaults",
|
||||||
"prototype-properties",
|
"prototype-properties",
|
||||||
@ -60,9 +72,9 @@ File.helpers = [
|
|||||||
"temporal-undefined",
|
"temporal-undefined",
|
||||||
"temporal-assert-defined",
|
"temporal-assert-defined",
|
||||||
"self-global"
|
"self-global"
|
||||||
];
|
];
|
||||||
|
|
||||||
File.validOptions = [
|
static validOptions = [
|
||||||
"filename",
|
"filename",
|
||||||
"filenameRelative",
|
"filenameRelative",
|
||||||
"blacklist",
|
"blacklist",
|
||||||
@ -99,9 +111,9 @@ File.validOptions = [
|
|||||||
"only",
|
"only",
|
||||||
"extensions",
|
"extensions",
|
||||||
"accept"
|
"accept"
|
||||||
];
|
];
|
||||||
|
|
||||||
File.prototype.normalizeOptions = function (opts) {
|
normalizeOptions(opts) {
|
||||||
opts = assign({}, opts);
|
opts = assign({}, opts);
|
||||||
|
|
||||||
for (var key in opts) {
|
for (var key in opts) {
|
||||||
@ -200,13 +212,13 @@ File.prototype.normalizeOptions = function (opts) {
|
|||||||
each(opts.optional, ensureEnabled);
|
each(opts.optional, ensureEnabled);
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
File.prototype.isLoose = function (key) {
|
isLoose(key) {
|
||||||
return includes(this.opts.loose, key);
|
return includes(this.opts.loose, key);
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.buildTransformers = function () {
|
buildTransformers() {
|
||||||
var file = this;
|
var file = this;
|
||||||
|
|
||||||
var transformers = {};
|
var transformers = {};
|
||||||
@ -232,15 +244,15 @@ File.prototype.buildTransformers = function () {
|
|||||||
|
|
||||||
this.transformerStack = stack.concat(secondaryStack);
|
this.transformerStack = stack.concat(secondaryStack);
|
||||||
this.transformers = transformers;
|
this.transformers = transformers;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.debug = function (msg) {
|
debug(msg) {
|
||||||
var parts = this.opts.filename;
|
var parts = this.opts.filename;
|
||||||
if (msg) parts += ": " + msg;
|
if (msg) parts += ": " + msg;
|
||||||
util.debug(parts);
|
util.debug(parts);
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.getModuleFormatter = function (type) {
|
getModuleFormatter(type) {
|
||||||
var ModuleFormatter = isFunction(type) ? type : transform.moduleFormatters[type];
|
var ModuleFormatter = isFunction(type) ? type : transform.moduleFormatters[type];
|
||||||
|
|
||||||
if (!ModuleFormatter) {
|
if (!ModuleFormatter) {
|
||||||
@ -253,9 +265,9 @@ File.prototype.getModuleFormatter = function (type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new ModuleFormatter(this);
|
return new ModuleFormatter(this);
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.parseShebang = function (code) {
|
parseShebang(code) {
|
||||||
var shebangMatch = shebangRegex.exec(code);
|
var shebangMatch = shebangRegex.exec(code);
|
||||||
|
|
||||||
if (shebangMatch) {
|
if (shebangMatch) {
|
||||||
@ -266,17 +278,17 @@ File.prototype.parseShebang = function (code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.set = function (key, val) {
|
set(key, val) {
|
||||||
return this.data[key] = val;
|
return this.data[key] = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
File.prototype.setDynamic = function (key, fn) {
|
setDynamic(key, fn) {
|
||||||
this.dynamicData[key] = fn;
|
this.dynamicData[key] = fn;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.get = function (key) {
|
get(key) {
|
||||||
var data = this.data[key];
|
var data = this.data[key];
|
||||||
if (data) {
|
if (data) {
|
||||||
return data;
|
return data;
|
||||||
@ -286,9 +298,9 @@ File.prototype.get = function (key) {
|
|||||||
return this.set(key, dynamic());
|
return this.set(key, dynamic());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.addImport = function (source, name, noDefault) {
|
addImport(source, name, noDefault) {
|
||||||
name ||= source;
|
name ||= source;
|
||||||
var id = this.dynamicImportIds[name];
|
var id = this.dynamicImportIds[name];
|
||||||
|
|
||||||
@ -306,13 +318,13 @@ File.prototype.addImport = function (source, name, noDefault) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.isConsequenceExpressionStatement = function (node) {
|
isConsequenceExpressionStatement(node) {
|
||||||
return t.isExpressionStatement(node) && this.lastStatements.indexOf(node) >= 0;
|
return t.isExpressionStatement(node) && this.lastStatements.indexOf(node) >= 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.attachAuxiliaryComment = function (node) {
|
attachAuxiliaryComment(node) {
|
||||||
var comment = this.opts.auxiliaryComment;
|
var comment = this.opts.auxiliaryComment;
|
||||||
if (comment) {
|
if (comment) {
|
||||||
node.leadingComments ||= [];
|
node.leadingComments ||= [];
|
||||||
@ -322,9 +334,9 @@ File.prototype.attachAuxiliaryComment = function (node) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.addHelper = function (name) {
|
addHelper(name) {
|
||||||
if (!includes(File.helpers, name)) {
|
if (!includes(File.helpers, name)) {
|
||||||
throw new ReferenceError("Unknown helper " + name);
|
throw new ReferenceError("Unknown helper " + name);
|
||||||
}
|
}
|
||||||
@ -351,28 +363,28 @@ File.prototype.addHelper = function (name) {
|
|||||||
});
|
});
|
||||||
return uid;
|
return uid;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.logDeopt = function () {
|
logDeopt() {
|
||||||
// todo, (node, msg)
|
// todo, (node, msg)
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.errorWithNode = function (node, msg, Error) {
|
errorWithNode(node, msg, Error) {
|
||||||
Error ||= SyntaxError;
|
Error ||= SyntaxError;
|
||||||
|
|
||||||
var loc = node.loc.start;
|
var loc = node.loc.start;
|
||||||
var err = new Error("Line " + loc.line + ": " + msg);
|
var err = new Error("Line " + loc.line + ": " + msg);
|
||||||
err.loc = loc;
|
err.loc = loc;
|
||||||
return err;
|
return err;
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.addCode = function (code) {
|
addCode(code) {
|
||||||
code = (code || "") + "";
|
code = (code || "") + "";
|
||||||
this.code = code;
|
this.code = code;
|
||||||
return this.parseShebang(code);
|
return this.parseShebang(code);
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.parse = function (code) {
|
parse(code) {
|
||||||
code = this.addCode(code);
|
code = this.addCode(code);
|
||||||
|
|
||||||
var opts = this.opts;
|
var opts = this.opts;
|
||||||
@ -384,9 +396,9 @@ File.prototype.parse = function (code) {
|
|||||||
this.transform(tree);
|
this.transform(tree);
|
||||||
return this.generate();
|
return this.generate();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.transform = function (ast) {
|
transform(ast) {
|
||||||
this.debug();
|
this.debug();
|
||||||
|
|
||||||
this.ast = ast;
|
this.ast = ast;
|
||||||
@ -407,9 +419,9 @@ File.prototype.transform = function (ast) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.call("post");
|
this.call("post");
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.call = function (key) {
|
call(key) {
|
||||||
var stack = this.transformerStack;
|
var stack = this.transformerStack;
|
||||||
for (var i = 0; i < stack.length; i++) {
|
for (var i = 0; i < stack.length; i++) {
|
||||||
var transformer = stack[i].transformer;
|
var transformer = stack[i].transformer;
|
||||||
@ -417,22 +429,9 @@ File.prototype.call = function (key) {
|
|||||||
transformer[key](this);
|
transformer[key](this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
var checkTransformerVisitor = {
|
|
||||||
enter(node, parent, scope, state) {
|
|
||||||
checkNode(state.stack, node, scope);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
var checkNode = function (stack, node, scope) {
|
checkNode(node, scope) {
|
||||||
each(stack, function (pass) {
|
|
||||||
if (pass.shouldRun) return;
|
|
||||||
pass.checkNode(node, scope);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
File.prototype.checkNode = function (node, scope) {
|
|
||||||
var stack = this.transformerStack;
|
var stack = this.transformerStack;
|
||||||
scope ||= this.scope;
|
scope ||= this.scope;
|
||||||
|
|
||||||
@ -441,9 +440,9 @@ File.prototype.checkNode = function (node, scope) {
|
|||||||
scope.traverse(node, checkTransformerVisitor, {
|
scope.traverse(node, checkTransformerVisitor, {
|
||||||
stack: stack
|
stack: stack
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
File.prototype.generate = function () {
|
generate() {
|
||||||
var opts = this.opts;
|
var opts = this.opts;
|
||||||
var ast = this.ast;
|
var ast = this.ast;
|
||||||
|
|
||||||
@ -475,4 +474,5 @@ File.prototype.generate = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -3,94 +3,16 @@ module.exports = ReplaceSupers;
|
|||||||
var messages = require("../../messages");
|
var messages = require("../../messages");
|
||||||
var t = require("../../types");
|
var t = require("../../types");
|
||||||
|
|
||||||
/**
|
|
||||||
* Description
|
|
||||||
*
|
|
||||||
* @param {Object} opts
|
|
||||||
* @param {Boolean} [inClass]
|
|
||||||
*/
|
|
||||||
|
|
||||||
function ReplaceSupers(opts, inClass) {
|
var isIllegalBareSuper = function (node, parent) {
|
||||||
this.topLevelThisReference = opts.topLevelThisReference;
|
if (!isSuper(node, parent)) return false;
|
||||||
this.methodNode = opts.methodNode;
|
if (t.isMemberExpression(parent, { computed: false })) return false;
|
||||||
this.className = opts.className;
|
if (t.isCallExpression(parent, { callee: node })) return false;
|
||||||
this.superName = opts.superName;
|
return true;
|
||||||
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 isSuper = function (node, parent) {
|
||||||
* Gets a node representing the super class value of the named property.
|
return t.isIdentifier(node, { name: "super" }) && t.isReferenced(node, parent);
|
||||||
*
|
|
||||||
* @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 visitor = {
|
var visitor = {
|
||||||
@ -121,23 +43,115 @@ 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
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} node
|
* @param {Object} node
|
||||||
* @param {Boolean} topLevel
|
* @param {Boolean} topLevel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
|
traverseLevel(node, topLevel) {
|
||||||
var state = { self: this, topLevel: topLevel };
|
var state = { self: this, topLevel: topLevel };
|
||||||
this.scope.traverse(node, visitor, state);
|
this.scope.traverse(node, visitor, state);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.getThisReference = function () {
|
getThisReference() {
|
||||||
if (this.topLevelThisReference) {
|
if (this.topLevelThisReference) {
|
||||||
return this.topLevelThisReference;
|
return this.topLevelThisReference;
|
||||||
} else {
|
} else {
|
||||||
@ -147,9 +161,9 @@ ReplaceSupers.prototype.getThisReference = function () {
|
|||||||
]));
|
]));
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} node
|
* @param {Object} node
|
||||||
@ -158,7 +172,7 @@ ReplaceSupers.prototype.getThisReference = function () {
|
|||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
|
getLooseSuperProperty(id, parent) {
|
||||||
var methodNode = this.methodNode;
|
var methodNode = this.methodNode;
|
||||||
var methodName = methodNode.key;
|
var methodName = methodNode.key;
|
||||||
var superName = this.superName || t.identifier("Function");
|
var superName = this.superName || t.identifier("Function");
|
||||||
@ -189,9 +203,9 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
|
|||||||
} else {
|
} else {
|
||||||
return superName;
|
return superName;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Function} getThisReference
|
* @param {Function} getThisReference
|
||||||
@ -199,7 +213,7 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
|
|||||||
* @param {Object} parent
|
* @param {Object} parent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
|
looseHandle(getThisReference, node, parent) {
|
||||||
if (t.isIdentifier(node, { name: "super" })) {
|
if (t.isIdentifier(node, { name: "super" })) {
|
||||||
this.hasSuper = true;
|
this.hasSuper = true;
|
||||||
return this.getLooseSuperProperty(node, parent);
|
return this.getLooseSuperProperty(node, parent);
|
||||||
@ -213,9 +227,9 @@ ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent)
|
|||||||
t.appendToMemberExpression(callee, t.identifier("call"));
|
t.appendToMemberExpression(callee, t.identifier("call"));
|
||||||
node.arguments.unshift(getThisReference());
|
node.arguments.unshift(getThisReference());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Function} getThisReference
|
* @param {Function} getThisReference
|
||||||
@ -223,7 +237,7 @@ ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent)
|
|||||||
* @param {Object} parent
|
* @param {Object} parent
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
|
specHandle(getThisReference, node, parent) {
|
||||||
var methodNode = this.methodNode;
|
var methodNode = this.methodNode;
|
||||||
var property;
|
var property;
|
||||||
var computed;
|
var computed;
|
||||||
@ -287,15 +301,5 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
|
|||||||
} else {
|
} else {
|
||||||
return superProperty;
|
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");
|
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.
|
* 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.transformer = transformer;
|
||||||
this.shouldRun = !transformer.check;
|
this.shouldRun = !transformer.check;
|
||||||
this.handlers = transformer.handlers;
|
this.handlers = transformer.handlers;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformerPass.prototype.canRun = function () {
|
canRun() {
|
||||||
var transformer = this.transformer;
|
var transformer = this.transformer;
|
||||||
|
|
||||||
var opts = this.file.opts;
|
var opts = this.file.opts;
|
||||||
@ -41,18 +40,18 @@ TransformerPass.prototype.canRun = function () {
|
|||||||
if (transformer.playground && !opts.playground) return false;
|
if (transformer.playground && !opts.playground) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
TransformerPass.prototype.checkNode = function (node) {
|
checkNode(node) {
|
||||||
var check = this.transformer.check;
|
var check = this.transformer.check;
|
||||||
if (check) {
|
if (check) {
|
||||||
return this.shouldRun = check(node);
|
return this.shouldRun = check(node);
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
TransformerPass.prototype.transform = function () {
|
transform() {
|
||||||
if (!this.shouldRun) return;
|
if (!this.shouldRun) return;
|
||||||
|
|
||||||
var file = this.file;
|
var file = this.file;
|
||||||
@ -60,4 +59,5 @@ TransformerPass.prototype.transform = function () {
|
|||||||
file.debug("Running transformer " + this.transformer.key);
|
file.debug("Running transformer " + this.transformer.key);
|
||||||
|
|
||||||
file.scope.traverse(file.ast, this.handlers, file);
|
file.scope.traverse(file.ast, this.handlers, file);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
module.exports = Transformer;
|
|
||||||
|
|
||||||
var TransformerPass = require("./transformer-pass");
|
var TransformerPass = require("./transformer-pass");
|
||||||
var isFunction = require("lodash/lang/isFunction");
|
var isFunction = require("lodash/lang/isFunction");
|
||||||
var traverse = require("../traversal");
|
var traverse = require("../traversal");
|
||||||
@ -13,7 +11,8 @@ var each = require("lodash/collection/each");
|
|||||||
* actually running the transformer over the provided `File`.
|
* actually running the transformer over the provided `File`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Transformer(key, transformer, opts) {
|
export default class Transformer {
|
||||||
|
constructor(key, transformer, opts) {
|
||||||
transformer = assign({}, transformer);
|
transformer = assign({}, transformer);
|
||||||
|
|
||||||
var take = function (key) {
|
var take = function (key) {
|
||||||
@ -35,9 +34,9 @@ function Transformer(key, transformer, opts) {
|
|||||||
this.handlers = this.normalize(transformer);
|
this.handlers = this.normalize(transformer);
|
||||||
this.opts ||= {};
|
this.opts ||= {};
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transformer.prototype.normalize = function (transformer) {
|
normalize(transformer) {
|
||||||
if (isFunction(transformer)) {
|
if (isFunction(transformer)) {
|
||||||
transformer = { ast: transformer };
|
transformer = { ast: transformer };
|
||||||
}
|
}
|
||||||
@ -64,8 +63,9 @@ Transformer.prototype.normalize = function (transformer) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return transformer;
|
return transformer;
|
||||||
};
|
}
|
||||||
|
|
||||||
Transformer.prototype.buildPass = function (file) {
|
buildPass(file) {
|
||||||
return new TransformerPass(file, this);
|
return new TransformerPass(file, this);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,28 +1,27 @@
|
|||||||
module.exports = TraversalContext;
|
|
||||||
|
|
||||||
var TraversalPath = require("./path");
|
var TraversalPath = require("./path");
|
||||||
var flatten = require("lodash/array/flatten");
|
var flatten = require("lodash/array/flatten");
|
||||||
var compact = require("lodash/array/compact");
|
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.shouldFlatten = false;
|
||||||
this.parentPath = parentPath;
|
this.parentPath = parentPath;
|
||||||
|
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
TraversalContext.prototype.flatten = function () {
|
flatten() {
|
||||||
this.shouldFlatten = true;
|
this.shouldFlatten = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalContext.prototype.visitNode = function (node, obj, key) {
|
visitNode(node, obj, key) {
|
||||||
var iteration = new TraversalPath(this, node, obj, key);
|
var iteration = new TraversalPath(this, node, obj, key);
|
||||||
return iteration.visit();
|
return iteration.visit();
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalContext.prototype.visit = function (node, key) {
|
visit(node, key) {
|
||||||
var nodes = node[key];
|
var nodes = node[key];
|
||||||
if (!nodes) return;
|
if (!nodes) return;
|
||||||
|
|
||||||
@ -49,4 +48,5 @@ TraversalContext.prototype.visit = function (node, key) {
|
|||||||
node[key] = compact(node[key]);
|
node[key] = compact(node[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
module.exports = TraversalPath;
|
|
||||||
|
|
||||||
var traverse = require("./index");
|
var traverse = require("./index");
|
||||||
var includes = require("lodash/collection/includes");
|
var includes = require("lodash/collection/includes");
|
||||||
var Scope = require("./scope");
|
var Scope = require("./scope");
|
||||||
var t = require("../types");
|
var t = require("../types");
|
||||||
|
|
||||||
function TraversalPath(context, parent, container, key) {
|
export default class TraversalPath {
|
||||||
|
constructor(context, parent, container, key) {
|
||||||
this.shouldRemove = false;
|
this.shouldRemove = false;
|
||||||
this.shouldSkip = false;
|
this.shouldSkip = false;
|
||||||
this.shouldStop = false;
|
this.shouldStop = false;
|
||||||
@ -22,9 +21,9 @@ function TraversalPath(context, parent, container, key) {
|
|||||||
this.state = context.state;
|
this.state = context.state;
|
||||||
|
|
||||||
this.setScope();
|
this.setScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraversalPath.getScope = function (node, parent, scope) {
|
static getScope(node, parent, scope) {
|
||||||
var ourScope = scope;
|
var ourScope = scope;
|
||||||
|
|
||||||
// we're entering a new scope so let's construct it!
|
// we're entering a new scope so let's construct it!
|
||||||
@ -33,36 +32,35 @@ TraversalPath.getScope = function (node, parent, scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ourScope;
|
return ourScope;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.setScope = function () {
|
setScope() {
|
||||||
this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope);
|
this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope);
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.remove = function () {
|
remove() {
|
||||||
this.shouldRemove = true;
|
this.shouldRemove = true;
|
||||||
this.shouldSkip = true;
|
this.shouldSkip = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.skip = function () {
|
skip() {
|
||||||
this.shouldSkip = true;
|
this.shouldSkip = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.stop = function () {
|
stop() {
|
||||||
this.shouldStop = true;
|
this.shouldStop = true;
|
||||||
this.shouldSkip = true;
|
this.shouldSkip = true;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.flatten = function () {
|
flatten() {
|
||||||
this.context.flatten();
|
this.context.flatten();
|
||||||
};
|
}
|
||||||
|
|
||||||
Object.defineProperty(TraversalPath.prototype, "node", {
|
get node() {
|
||||||
get() {
|
|
||||||
return this.container[this.key];
|
return this.container[this.key];
|
||||||
},
|
}
|
||||||
|
|
||||||
set(replacement) {
|
set node(replacement) {
|
||||||
var isArray = Array.isArray(replacement);
|
var isArray = Array.isArray(replacement);
|
||||||
|
|
||||||
// inherit comments from original node to the first replacement node
|
// inherit comments from original node to the first replacement node
|
||||||
@ -95,9 +93,8 @@ Object.defineProperty(TraversalPath.prototype, "node", {
|
|||||||
this.flatten();
|
this.flatten();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
TraversalPath.prototype.call = function (key) {
|
call(key) {
|
||||||
var node = this.node;
|
var node = this.node;
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
@ -115,9 +112,9 @@ TraversalPath.prototype.call = function (key) {
|
|||||||
this.container[this.key] = null;
|
this.container[this.key] = null;
|
||||||
this.flatten();
|
this.flatten();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.visit = function () {
|
visit() {
|
||||||
var opts = this.opts;
|
var opts = this.opts;
|
||||||
var node = this.node;
|
var node = this.node;
|
||||||
|
|
||||||
@ -146,8 +143,9 @@ TraversalPath.prototype.visit = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.shouldStop;
|
return this.shouldStop;
|
||||||
};
|
}
|
||||||
|
|
||||||
TraversalPath.prototype.isReferencedIdentifier = function () {
|
isReferencedIdentifier() {
|
||||||
return t.isReferencedIdentifier(this.node);
|
return t.isReferencedIdentifier(this.node);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
module.exports = Scope;
|
|
||||||
|
|
||||||
var includes = require("lodash/collection/includes");
|
var includes = require("lodash/collection/includes");
|
||||||
var traverse = require("./index");
|
var traverse = require("./index");
|
||||||
@ -11,7 +11,59 @@ var object = require("../helpers/object");
|
|||||||
var each = require("lodash/collection/each");
|
var each = require("lodash/collection/each");
|
||||||
var t = require("../types");
|
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
|
* This searches the current "scope" and collects all references/bindings
|
||||||
* within.
|
* within.
|
||||||
*
|
*
|
||||||
@ -21,7 +73,7 @@ var t = require("../types");
|
|||||||
* @param {File} [file]
|
* @param {File} [file]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Scope(block, parentBlock, parent, file) {
|
constructor(block, parentBlock, parent, file) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.file = parent ? parent.file : file;
|
this.file = parent ? parent.file : file;
|
||||||
|
|
||||||
@ -29,11 +81,11 @@ function Scope(block, parentBlock, parent, file) {
|
|||||||
this.block = block;
|
this.block = block;
|
||||||
|
|
||||||
this.crawl();
|
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
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} node
|
* @param {Object} node
|
||||||
@ -41,44 +93,44 @@ Scope.globals = flatten([globals.builtin, globals.browser, globals.node].map(Obj
|
|||||||
* @param [state]
|
* @param [state]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.traverse = function (node, opts, state) {
|
traverse(node, opts, state) {
|
||||||
traverse(node, opts, this, state);
|
traverse(node, opts, this, state);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {String} [name="temp"]
|
* @param {String} [name="temp"]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.generateTemp = function (name) {
|
generateTemp(name) {
|
||||||
var id = this.generateUidIdentifier(name || "temp");
|
var id = this.generateUidIdentifier(name || "temp");
|
||||||
this.push({
|
this.push({
|
||||||
key: id.name,
|
key: id.name,
|
||||||
id: id
|
id: id
|
||||||
});
|
});
|
||||||
return id;
|
return id;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.generateUidIdentifier = function (name) {
|
generateUidIdentifier(name) {
|
||||||
var id = t.identifier(this.generateUid(name));
|
var id = t.identifier(this.generateUid(name));
|
||||||
this.getFunctionParent().registerBinding("uid", id);
|
this.getFunctionParent().registerBinding("uid", id);
|
||||||
return id;
|
return id;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.generateUid = function (name) {
|
generateUid(name) {
|
||||||
name = t.toIdentifier(name).replace(/^_+/, "");
|
name = t.toIdentifier(name).replace(/^_+/, "");
|
||||||
|
|
||||||
var uid;
|
var uid;
|
||||||
@ -88,22 +140,22 @@ Scope.prototype.generateUid = function (name) {
|
|||||||
i++;
|
i++;
|
||||||
} while (this.hasBinding(uid) || this.hasGlobal(uid));
|
} while (this.hasBinding(uid) || this.hasGlobal(uid));
|
||||||
return uid;
|
return uid;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype._generateUid = function (name, i) {
|
_generateUid(name, i) {
|
||||||
var id = name;
|
var id = name;
|
||||||
if (i > 1) id += i;
|
if (i > 1) id += i;
|
||||||
return "_" + id;
|
return "_" + id;
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} parent
|
* @param {Object} parent
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.generateUidBasedOnNode = function (parent) {
|
generateUidBasedOnNode(parent) {
|
||||||
var node = parent;
|
var node = parent;
|
||||||
|
|
||||||
if (t.isAssignmentExpression(parent)) {
|
if (t.isAssignmentExpression(parent)) {
|
||||||
@ -135,16 +187,16 @@ Scope.prototype.generateUidBasedOnNode = function (parent) {
|
|||||||
id = id.replace(/^_/, "") || "ref";
|
id = id.replace(/^_/, "") || "ref";
|
||||||
|
|
||||||
return this.generateUidIdentifier(id);
|
return this.generateUidIdentifier(id);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} node
|
* @param {Object} node
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.generateTempBasedOnNode = function (node) {
|
generateTempBasedOnNode(node) {
|
||||||
if (t.isIdentifier(node) && this.hasBinding(node.name)) {
|
if (t.isIdentifier(node) && this.hasBinding(node.name)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -155,9 +207,9 @@ Scope.prototype.generateTempBasedOnNode = function (node) {
|
|||||||
id: id
|
id: id
|
||||||
});
|
});
|
||||||
return id;
|
return id;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.checkBlockScopedCollisions = function (kind, name, id) {
|
checkBlockScopedCollisions(kind, name, id) {
|
||||||
var local = this.getOwnBindingInfo(name);
|
var local = this.getOwnBindingInfo(name);
|
||||||
if (!local) return;
|
if (!local) return;
|
||||||
|
|
||||||
@ -167,9 +219,9 @@ Scope.prototype.checkBlockScopedCollisions = function (kind, name, id) {
|
|||||||
if (local.kind === "let" || local.kind === "const" || local.kind === "module") {
|
if (local.kind === "let" || local.kind === "const" || local.kind === "module") {
|
||||||
throw this.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
|
throw this.file.errorWithNode(id, messages.get("scopeDuplicateDeclaration", name), TypeError);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.rename = function (oldName, newName) {
|
rename(oldName, newName) {
|
||||||
newName ||= this.generateUidIdentifier(oldName).name;
|
newName ||= this.generateUidIdentifier(oldName).name;
|
||||||
|
|
||||||
var info = this.getBindingInfo(oldName);
|
var info = this.getBindingInfo(oldName);
|
||||||
@ -199,9 +251,9 @@ Scope.prototype.rename = function (oldName, newName) {
|
|||||||
scope.bindings[newName] = info;
|
scope.bindings[newName] = info;
|
||||||
|
|
||||||
binding.name = newName;
|
binding.name = newName;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.inferType = function (node) {
|
inferType(node) {
|
||||||
var target;
|
var target;
|
||||||
|
|
||||||
if (t.isVariableDeclarator(node)) {
|
if (t.isVariableDeclarator(node)) {
|
||||||
@ -231,28 +283,28 @@ Scope.prototype.inferType = function (node) {
|
|||||||
if (t.isIdentifier(target)) {
|
if (t.isIdentifier(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.isTypeGeneric = function (name, genericName) {
|
isTypeGeneric(name, genericName) {
|
||||||
var info = this.getBindingInfo(name);
|
var info = this.getBindingInfo(name);
|
||||||
if (!info) return false;
|
if (!info) return false;
|
||||||
|
|
||||||
var type = info.typeAnnotation;
|
var type = info.typeAnnotation;
|
||||||
return t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName });
|
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)));
|
this.assignType(name, t.genericTypeAnnotation(t.identifier(type)));
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.assignType = function (name, type) {
|
assignType(name, type) {
|
||||||
var info = this.getBindingInfo(name);
|
var info = this.getBindingInfo(name);
|
||||||
if (!info) return;
|
if (!info) return;
|
||||||
|
|
||||||
info.identifier.typeAnnotation = info.typeAnnotation = type;
|
info.identifier.typeAnnotation = info.typeAnnotation = type;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.getTypeAnnotation = function (name, id, node) {
|
getTypeAnnotation(name, id, node) {
|
||||||
var info = {
|
var info = {
|
||||||
annotation: null,
|
annotation: null,
|
||||||
inferred: false
|
inferred: false
|
||||||
@ -275,9 +327,9 @@ Scope.prototype.getTypeAnnotation = function (name, id, node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.toArray = function (node, i) {
|
toArray(node, i) {
|
||||||
var file = this.file;
|
var file = this.file;
|
||||||
|
|
||||||
if (t.isIdentifier(node) && this.isTypeGeneric(node.name, "Array")) {
|
if (t.isIdentifier(node) && this.isTypeGeneric(node.name, "Array")) {
|
||||||
@ -301,13 +353,13 @@ Scope.prototype.toArray = function (node, i) {
|
|||||||
helperName = "sliced-to-array";
|
helperName = "sliced-to-array";
|
||||||
}
|
}
|
||||||
return t.callExpression(file.addHelper(helperName), args);
|
return t.callExpression(file.addHelper(helperName), args);
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.clearOwnBinding = function (name) {
|
clearOwnBinding(name) {
|
||||||
delete this.bindings[name];
|
delete this.bindings[name];
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.registerDeclaration = function (node) {
|
registerDeclaration(node) {
|
||||||
if (t.isFunctionDeclaration(node)) {
|
if (t.isFunctionDeclaration(node)) {
|
||||||
this.registerBinding("hoisted", node);
|
this.registerBinding("hoisted", node);
|
||||||
} else if (t.isVariableDeclaration(node)) {
|
} else if (t.isVariableDeclaration(node)) {
|
||||||
@ -321,9 +373,9 @@ Scope.prototype.registerDeclaration = function (node) {
|
|||||||
} else {
|
} else {
|
||||||
this.registerBinding("unknown", node);
|
this.registerBinding("unknown", node);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.registerBindingReassignment = function (node) {
|
registerBindingReassignment(node) {
|
||||||
var ids = t.getBindingIdentifiers(node);
|
var ids = t.getBindingIdentifiers(node);
|
||||||
for (var name in ids) {
|
for (var name in ids) {
|
||||||
var info = this.getBindingInfo(name);
|
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`");
|
if (!kind) throw new ReferenceError("no `kind`");
|
||||||
|
|
||||||
var ids = t.getBindingIdentifiers(node);
|
var ids = t.getBindingIdentifiers(node);
|
||||||
@ -360,47 +412,20 @@ Scope.prototype.registerBinding = function (kind, node) {
|
|||||||
kind: kind
|
kind: kind
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.registerVariableDeclaration = function (declar) {
|
registerVariableDeclaration(declar) {
|
||||||
var declars = declar.declarations;
|
var declars = declar.declarations;
|
||||||
for (var i = 0; i < declars.length; i++) {
|
for (var i = 0; i < declars.length; i++) {
|
||||||
this.registerBinding(declars[i], declar.kind);
|
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
|
addGlobal(node) {
|
||||||
// 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) {
|
|
||||||
this.globals[node.name] = node;
|
this.globals[node.name] = node;
|
||||||
};
|
};
|
||||||
|
|
||||||
Scope.prototype.hasGlobal = function (name) {
|
hasGlobal(name) {
|
||||||
var scope = this;
|
var scope = this;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -408,31 +433,9 @@ Scope.prototype.hasGlobal = function (name) {
|
|||||||
} while (scope = scope.parent);
|
} while (scope = scope.parent);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
var programReferenceVisitor = {
|
crawl() {
|
||||||
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 () {
|
|
||||||
var block = this.block;
|
var block = this.block;
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
@ -513,15 +516,15 @@ Scope.prototype.crawl = function () {
|
|||||||
if (t.isProgram(block)) {
|
if (t.isProgram(block)) {
|
||||||
this.traverse(block, programReferenceVisitor, this);
|
this.traverse(block, programReferenceVisitor, this);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} opts
|
* @param {Object} opts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.push = function (opts) {
|
push(opts) {
|
||||||
var block = this.block;
|
var block = this.block;
|
||||||
|
|
||||||
if (t.isLoop(block) || t.isCatchClause(block) || t.isFunction(block)) {
|
if (t.isLoop(block) || t.isCatchClause(block) || t.isFunction(block)) {
|
||||||
@ -539,28 +542,28 @@ Scope.prototype.push = function (opts) {
|
|||||||
} else {
|
} else {
|
||||||
throw new TypeError("cannot add a declaration here in node type " + block.type);
|
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
|
* Walk up the scope tree until we hit either a Function or reach the
|
||||||
* very top and hit Program.
|
* very top and hit Program.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.getFunctionParent = function () {
|
getFunctionParent() {
|
||||||
var scope = this;
|
var scope = this;
|
||||||
while (scope.parent && !t.isFunction(scope.block)) {
|
while (scope.parent && !t.isFunction(scope.block)) {
|
||||||
scope = scope.parent;
|
scope = scope.parent;
|
||||||
}
|
}
|
||||||
return scope;
|
return scope;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks the scope tree and gathers **all** bindings.
|
* Walks the scope tree and gathers **all** bindings.
|
||||||
*
|
*
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.getAllBindings = function () {
|
getAllBindings() {
|
||||||
var ids = object();
|
var ids = object();
|
||||||
|
|
||||||
var scope = this;
|
var scope = this;
|
||||||
@ -570,16 +573,16 @@ Scope.prototype.getAllBindings = function () {
|
|||||||
} while (scope);
|
} while (scope);
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks the scope tree and gathers all declarations of `kind`.
|
* Walks the scope tree and gathers all declarations of `kind`.
|
||||||
*
|
*
|
||||||
* @param {String} kind
|
* @param {String} kind
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Scope.prototype.getAllBindingsOfKind = function (kind) {
|
getAllBindingsOfKind(kind) {
|
||||||
var ids = object();
|
var ids = object();
|
||||||
|
|
||||||
var scope = this;
|
var scope = this;
|
||||||
@ -592,53 +595,54 @@ Scope.prototype.getAllBindingsOfKind = function (kind) {
|
|||||||
} while (scope);
|
} while (scope);
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
};
|
}
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
|
|
||||||
Scope.prototype.bindingIdentifierEquals = function (name, node) {
|
bindingIdentifierEquals(name, node) {
|
||||||
return this.getBindingIdentifier(name) === node;
|
return this.getBindingIdentifier(name) === node;
|
||||||
};
|
}
|
||||||
|
|
||||||
// get
|
// get
|
||||||
|
|
||||||
Scope.prototype.getBindingInfo = function (name) {
|
getBindingInfo(name) {
|
||||||
var scope = this;
|
var scope = this;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
var binding = scope.getOwnBindingInfo(name);
|
var binding = scope.getOwnBindingInfo(name);
|
||||||
if (binding) return binding;
|
if (binding) return binding;
|
||||||
} while (scope = scope.parent);
|
} while (scope = scope.parent);
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.getOwnBindingInfo = function (name) {
|
getOwnBindingInfo(name) {
|
||||||
return this.bindings[name];
|
return this.bindings[name];
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.getBindingIdentifier = function (name) {
|
getBindingIdentifier(name) {
|
||||||
var info = this.getBindingInfo(name);
|
var info = this.getBindingInfo(name);
|
||||||
return info && info.identifier;
|
return info && info.identifier;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.getOwnBindingIdentifier = function (name) {
|
getOwnBindingIdentifier(name) {
|
||||||
var binding = this.bindings[name];
|
var binding = this.bindings[name];
|
||||||
return binding && binding.identifier;
|
return binding && binding.identifier;
|
||||||
};
|
}
|
||||||
|
|
||||||
// has
|
// has
|
||||||
|
|
||||||
Scope.prototype.hasOwnBinding = function (name) {
|
hasOwnBinding(name) {
|
||||||
return !!this.getOwnBindingInfo(name);
|
return !!this.getOwnBindingInfo(name);
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.hasBinding = function (name) {
|
hasBinding(name) {
|
||||||
if (!name) return false;
|
if (!name) return false;
|
||||||
if (this.hasOwnBinding(name)) return true;
|
if (this.hasOwnBinding(name)) return true;
|
||||||
if (this.parentHasBinding(name)) return true;
|
if (this.parentHasBinding(name)) return true;
|
||||||
if (includes(Scope.globals, name)) return true;
|
if (includes(Scope.globals, name)) return true;
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
Scope.prototype.parentHasBinding = function (name) {
|
parentHasBinding(name) {
|
||||||
return this.parent && this.parent.hasBinding(name);
|
return this.parent && this.parent.hasBinding(name);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user