improve whitespace handling of code generator, reduce the use of lookaheads, add max newlines of 2 and better newline insertion for generated nodes
This commit is contained in:
parent
fbb19fc656
commit
710ff548cb
@ -13,13 +13,7 @@ function Buffer(position, format, opts, code) {
|
|||||||
this.position = position;
|
this.position = position;
|
||||||
this._indent = format.indent.base;
|
this._indent = format.indent.base;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.deopt = false;
|
|
||||||
this.buf = "";
|
this.buf = "";
|
||||||
|
|
||||||
if (code.length > 100000) { // 100KB
|
|
||||||
this.deopt = true;
|
|
||||||
console.error(messages.get("codeGeneratorDeopt", opts.filename, "100KB"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer.prototype.get = function () {
|
Buffer.prototype.get = function () {
|
||||||
@ -27,7 +21,7 @@ Buffer.prototype.get = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Buffer.prototype.getIndent = function () {
|
Buffer.prototype.getIndent = function () {
|
||||||
if (this.deopt || 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);
|
||||||
@ -65,14 +59,14 @@ Buffer.prototype.keyword = function (name) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Buffer.prototype.space = function () {
|
Buffer.prototype.space = function () {
|
||||||
if (this.deopt) 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) {
|
Buffer.prototype.removeLast = function (cha) {
|
||||||
if (this.deopt) 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);
|
||||||
@ -80,7 +74,7 @@ Buffer.prototype.removeLast = function (cha) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Buffer.prototype.newline = function (i, removeLast) {
|
Buffer.prototype.newline = function (i, removeLast) {
|
||||||
if (this.deopt) return;
|
if (this.format.compact) return;
|
||||||
|
|
||||||
if (this.format.concise) {
|
if (this.format.concise) {
|
||||||
this.space();
|
this.space();
|
||||||
@ -90,7 +84,10 @@ Buffer.prototype.newline = function (i, removeLast) {
|
|||||||
removeLast = removeLast || false;
|
removeLast = removeLast || false;
|
||||||
|
|
||||||
if (isNumber(i)) {
|
if (isNumber(i)) {
|
||||||
if (this.isLast("\n")) i--;
|
i = Math.min(2, i);
|
||||||
|
|
||||||
|
if (this.endsWith("{\n")) i--;
|
||||||
|
if (i <= 0) return;
|
||||||
|
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
this._newline(removeLast);
|
this._newline(removeLast);
|
||||||
@ -107,6 +104,10 @@ Buffer.prototype.newline = function (i, removeLast) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Buffer.prototype._newline = function (removeLast) {
|
Buffer.prototype._newline = function (removeLast) {
|
||||||
|
// never allow more than two lines
|
||||||
|
if (this.endsWith("\n\n")) return;
|
||||||
|
|
||||||
|
// remove the last newline
|
||||||
if (removeLast && this.isLast("\n")) this.removeLast("\n");
|
if (removeLast && this.isLast("\n")) this.removeLast("\n");
|
||||||
|
|
||||||
this.removeLast(" ");
|
this.removeLast(" ");
|
||||||
@ -114,7 +115,7 @@ Buffer.prototype._newline = function (removeLast) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Buffer.prototype.push = function (str, noIndent) {
|
Buffer.prototype.push = function (str, noIndent) {
|
||||||
if (!this.deopt && 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();
|
||||||
|
|
||||||
@ -133,8 +134,12 @@ Buffer.prototype._push = function (str) {
|
|||||||
this.buf += str;
|
this.buf += str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Buffer.prototype.endsWith = function (str) {
|
||||||
|
return this.buf.slice(-str.length) === str;
|
||||||
|
};
|
||||||
|
|
||||||
Buffer.prototype.isLast = function (cha) {
|
Buffer.prototype.isLast = function (cha) {
|
||||||
if (this.deopt) return false;
|
if (this.format.compact) return false;
|
||||||
|
|
||||||
var buf = this.buf;
|
var buf = this.buf;
|
||||||
var last = buf[buf.length - 1];
|
var last = buf[buf.length - 1];
|
||||||
|
|||||||
@ -62,6 +62,10 @@ exports.ImportDeclaration = function (node, print) {
|
|||||||
|
|
||||||
this.push("import ");
|
this.push("import ");
|
||||||
|
|
||||||
|
if (node.isType) {
|
||||||
|
this.push("type ");
|
||||||
|
}
|
||||||
|
|
||||||
var specfiers = node.specifiers;
|
var specfiers = node.specifiers;
|
||||||
if (specfiers && specfiers.length) {
|
if (specfiers && specfiers.length) {
|
||||||
var foundImportSpecifier = false;
|
var foundImportSpecifier = false;
|
||||||
|
|||||||
@ -184,7 +184,7 @@ exports.VariableDeclaration = function (node, print, parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sep = ",";
|
var sep = ",";
|
||||||
if (!this.buffer.deopt && hasInits) {
|
if (!this.format.compact && hasInits) {
|
||||||
sep += "\n" + repeating(" ", node.kind.length + 1);
|
sep += "\n" + repeating(" ", node.kind.length + 1);
|
||||||
} else {
|
} else {
|
||||||
sep += " ";
|
sep += " ";
|
||||||
|
|||||||
@ -47,16 +47,28 @@ CodeGenerator.normalizeOptions = function (code, opts) {
|
|||||||
if (indent && indent !== " ") style = indent;
|
if (indent && indent !== " ") style = indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return merge({
|
var format = merge({
|
||||||
parentheses: true,
|
parentheses: true,
|
||||||
comments: opts.comments == null || opts.comments,
|
comments: opts.comments == null || opts.comments,
|
||||||
concise: false,
|
concise: false,
|
||||||
|
compact: "auto",
|
||||||
indent: {
|
indent: {
|
||||||
adjustMultilineComment: true,
|
adjustMultilineComment: true,
|
||||||
style: style,
|
style: style,
|
||||||
base: 0
|
base: 0
|
||||||
}
|
}
|
||||||
}, opts.format || {});
|
}, opts.format || {});
|
||||||
|
|
||||||
|
if (format.compact === "auto") {
|
||||||
|
format.compact = code.length > 100000; // 100KB
|
||||||
|
|
||||||
|
if (format.compact) {
|
||||||
|
format.compact = true;
|
||||||
|
console.error(messages.get("codeGeneratorDeopt", opts.filename, "100KB"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return format;
|
||||||
};
|
};
|
||||||
|
|
||||||
CodeGenerator.generators = {
|
CodeGenerator.generators = {
|
||||||
@ -165,10 +177,10 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
|
|||||||
|
|
||||||
var needs = n.needsWhitespaceAfter;
|
var needs = n.needsWhitespaceAfter;
|
||||||
if (leading) needs = n.needsWhitespaceBefore;
|
if (leading) needs = n.needsWhitespaceBefore;
|
||||||
lines += needs(node, parent);
|
if (needs(node, parent)) lines++;
|
||||||
|
|
||||||
// generated nodes can't add starting file whitespace
|
// generated nodes can't add starting file whitespace
|
||||||
if (!self.buffer.get()) lines = 0;
|
if (!self.buffer.buf) lines = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.newline(lines);
|
self.newline(lines);
|
||||||
@ -296,7 +308,7 @@ CodeGenerator.prototype._getComments = function (key, node) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CodeGenerator.prototype._printComments = function (comments) {
|
CodeGenerator.prototype._printComments = function (comments) {
|
||||||
if (this.buffer.deopt) return;
|
if (this.format.compact) return;
|
||||||
|
|
||||||
if (!this.format.comments) return;
|
if (!this.format.comments) return;
|
||||||
if (!comments || !comments.length) return;
|
if (!comments || !comments.length) return;
|
||||||
|
|||||||
@ -4,9 +4,9 @@ module.exports = Node;
|
|||||||
|
|
||||||
var whitespace = require("./whitespace");
|
var whitespace = require("./whitespace");
|
||||||
var parens = require("./parentheses");
|
var parens = require("./parentheses");
|
||||||
var t = require("../../types");
|
|
||||||
var each = require("lodash/collection/each");
|
var each = require("lodash/collection/each");
|
||||||
var some = require("lodash/collection/some");
|
var some = require("lodash/collection/some");
|
||||||
|
var t = require("../../types");
|
||||||
|
|
||||||
var find = function (obj, node, parent) {
|
var find = function (obj, node, parent) {
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
@ -42,14 +42,19 @@ Node.needsWhitespace = function (node, parent, type) {
|
|||||||
node = node.expression;
|
node = node.expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lines = find(whitespace[type].nodes, node, parent);
|
var linesInfo = find(whitespace.nodes, node, parent);
|
||||||
if (lines) return lines;
|
|
||||||
|
|
||||||
each(find(whitespace[type].list, node, parent), function (expr) {
|
if (!linesInfo) {
|
||||||
lines = Node.needsWhitespace(expr, node, type);
|
var items = find(whitespace.list, node, parent);
|
||||||
if (lines) return false;
|
if (items) {
|
||||||
});
|
for (var i = 0; i < items.length; i++) {
|
||||||
return lines || 0;
|
linesInfo = Node.needsWhitespace(items[i], node, type);
|
||||||
|
if (linesInfo) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (linesInfo && linesInfo[type]) || 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.needsWhitespaceBefore = function (node, parent) {
|
Node.needsWhitespaceBefore = function (node, parent) {
|
||||||
|
|||||||
@ -1,84 +1,118 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var t = require("../../types");
|
var isBoolean = require("lodash/lang/isBoolean");
|
||||||
var each = require("lodash/collection/each");
|
var each = require("lodash/collection/each");
|
||||||
var map = require("lodash/collection/map");
|
var map = require("lodash/collection/map");
|
||||||
var isNumber = require("lodash/lang/isNumber");
|
var t = require("../../types");
|
||||||
|
|
||||||
exports.before = {
|
var shouldWhitespace = function (node) {
|
||||||
nodes: {
|
if (t.isFunction(node)) {
|
||||||
Property: function (node, parent) {
|
return true;
|
||||||
if (parent.properties[0] === node) {
|
} else if (t.isAssignmentExpression(node)) {
|
||||||
return 1;
|
return shouldWhitespace(node.right);
|
||||||
}
|
} else if (t.isBinary(node)) {
|
||||||
},
|
return shouldWhitespace(node.left) || shouldWhitespace(node.right);
|
||||||
|
}
|
||||||
|
|
||||||
SpreadProperty: function (node, parent) {
|
return false;
|
||||||
return exports.before.nodes.Property(node, parent);
|
};
|
||||||
},
|
|
||||||
|
|
||||||
SwitchCase: function (node, parent) {
|
exports.nodes = {
|
||||||
if (parent.cases[0] === node) {
|
AssignmentExpression: function (node) {
|
||||||
return 1;
|
if (shouldWhitespace(node.right)) {
|
||||||
}
|
return {
|
||||||
},
|
before: true,
|
||||||
|
after: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
CallExpression: function (node) {
|
SwitchCase: function (node, parent) {
|
||||||
if (t.isFunction(node.callee)) {
|
if (parent.cases[0] === node) {
|
||||||
return 1;
|
return {
|
||||||
|
before: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
LogicalExpression: function (node) {
|
||||||
|
if (t.isFunction(node.left) || t.isFunction(node.right)) {
|
||||||
|
return {
|
||||||
|
after: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Literal: function (node) {
|
||||||
|
if (node.value === "use strict") {
|
||||||
|
return {
|
||||||
|
after: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
CallExpression: function (node) {
|
||||||
|
if (t.isFunction(node.callee)) {
|
||||||
|
return {
|
||||||
|
before: true,
|
||||||
|
after: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
VariableDeclaration: function (node) {
|
||||||
|
for (var i = 0; i < node.declarations.length; i++) {
|
||||||
|
var declar = node.declarations[i];
|
||||||
|
var init = declar.init;
|
||||||
|
if (!t.isIdentifier(init) && shouldWhitespace(init)) {
|
||||||
|
return {
|
||||||
|
before: true,
|
||||||
|
after: true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.after = {
|
exports.nodes.Property =
|
||||||
nodes: {
|
exports.nodes.SpreadProperty = function (node, parent) {
|
||||||
LogicalExpression: function (node) {
|
if (parent.properties[0] === node) {
|
||||||
return t.isFunction(node.left) || t.isFunction(node.right);
|
return {
|
||||||
},
|
before: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
AssignmentExpression: function (node) {
|
exports.list = {
|
||||||
if (t.isFunction(node.right)) {
|
VariableDeclaration: function (node) {
|
||||||
return 1;
|
return map(node.declarations, "init");
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
list: {
|
ArrayExpression: function (node) {
|
||||||
VariableDeclaration: function (node) {
|
return node.elements;
|
||||||
return map(node.declarations, "init");
|
},
|
||||||
},
|
|
||||||
|
|
||||||
ArrayExpression: function (node) {
|
ObjectExpression: function (node) {
|
||||||
return node.elements;
|
return node.properties;
|
||||||
},
|
|
||||||
|
|
||||||
ObjectExpression: function (node) {
|
|
||||||
return node.properties;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
each({
|
each({
|
||||||
Function: 1,
|
Function: true,
|
||||||
Class: 1,
|
Class: true,
|
||||||
For: 1,
|
Loop: true,
|
||||||
ArrayExpression: { after: 1 },
|
LabeledStatement: true,
|
||||||
ObjectExpression: { after: 1 },
|
SwitchStatement: true,
|
||||||
SwitchStatement: 1,
|
TryStatement: true,
|
||||||
IfStatement: { before: 1 },
|
IfStatement: true
|
||||||
CallExpression: { after: 1 },
|
|
||||||
Literal: { after: 1 }
|
|
||||||
}, function (amounts, type) {
|
}, function (amounts, type) {
|
||||||
if (isNumber(amounts)) {
|
if (isBoolean(amounts)) {
|
||||||
amounts = { after: amounts, before: amounts };
|
amounts = { after: amounts, before: amounts };
|
||||||
}
|
}
|
||||||
|
|
||||||
each([type].concat(t.FLIPPED_ALIAS_KEYS[type] || []), function (type) {
|
each([type].concat(t.FLIPPED_ALIAS_KEYS[type] || []), function (type) {
|
||||||
each(amounts, function (amount, key) {
|
exports.nodes[type] = function () {
|
||||||
exports[key].nodes[type] = function () {
|
return amounts;
|
||||||
return amount;
|
};
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user