Comparing version 0.0.3 to 0.0.4
781
escodegen.js
/* | ||
Copyright (C) 2012 John Freeman <jfreeman08@gmail.com> | ||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> | ||
@@ -40,2 +41,5 @@ Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be> | ||
BinaryPrecedence, | ||
VisitorKeys, | ||
VisitorOption, | ||
isArray, | ||
base, | ||
@@ -143,6 +147,8 @@ indent, | ||
parse: null, | ||
comment: false, | ||
format: { | ||
indent: { | ||
style: ' ', | ||
base: 0 | ||
base: 0, | ||
adjustMultilineComment: false | ||
} | ||
@@ -184,2 +190,38 @@ } | ||
isArray = Array.isArray; | ||
if (!isArray) { | ||
isArray = function isArray(array) { | ||
return Object.prototype.toString.call(array) === '[object Array]'; | ||
}; | ||
} | ||
function endsWithLineTerminator(value) { | ||
return (/(?:\r\n|[\n\r])$/).test(value); | ||
} | ||
function shallowCopy(obj) { | ||
var ret = {}, key; | ||
for (key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
ret[key] = obj[key]; | ||
} | ||
} | ||
return ret; | ||
} | ||
function deepCopy(obj) { | ||
var ret = {}, key, val; | ||
for (key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
val = obj[key]; | ||
if (typeof val === 'object' && val !== null) { | ||
ret[key] = deepCopy(val); | ||
} else { | ||
ret[key] = val; | ||
} | ||
} | ||
} | ||
return ret; | ||
} | ||
function updateDeeply(target, override) { | ||
@@ -253,2 +295,9 @@ var key, val; | ||
function isWhiteSpace(ch) { | ||
return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || | ||
(ch === '\u000C') || (ch === '\u00A0') || | ||
(ch.charCodeAt(0) >= 0x1680 && | ||
'\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0); | ||
} | ||
function addIndent(stmt) { | ||
@@ -258,4 +307,50 @@ return base + stmt; | ||
function adjustMultilineComment(value) { | ||
var array, i, len, line, j, ch, spaces; | ||
spaces = Number.MAX_VALUE; | ||
array = value.split(/\r\n|[\r\n]/); | ||
// first line doesn't have indentation | ||
for (i = 1, len = array.length; i < len; i += 1) { | ||
line = array[i]; | ||
j = 0; | ||
while (j < line.length && isWhiteSpace(line[j])) { | ||
j += 1; | ||
} | ||
if (spaces > j) { | ||
spaces = j; | ||
} | ||
} | ||
if (spaces % 2 === 1) { | ||
// /* | ||
// * | ||
// */ | ||
// If spaces are odd number, above pattern is considered. | ||
// We waste 1 space. | ||
spaces -= 1; | ||
} | ||
for (i = 1, len = array.length; i < len; i += 1) { | ||
array[i] = addIndent(array[i].slice(spaces)); | ||
} | ||
return array.join('\n'); | ||
} | ||
function generateComment(comment) { | ||
if (comment.type === 'Line') { | ||
// Esprima always produce last line comment with LineTerminator | ||
return '//' + comment.value; | ||
} | ||
if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { | ||
return adjustMultilineComment('/*' + comment.value + '*/'); | ||
} | ||
return '/*' + comment.value + '*/'; | ||
} | ||
function parenthesize(text, current, should) { | ||
return (current < should) ? '(' + text + ')' : text; | ||
if (current < should) { | ||
return '(' + text + ')'; | ||
} | ||
return text; | ||
} | ||
@@ -266,3 +361,3 @@ | ||
if (stmt.type === Syntax.BlockStatement) { | ||
if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments)) { | ||
result = ' ' + generateStatement(stmt); | ||
@@ -275,3 +370,3 @@ if (suffix) { | ||
if (stmt.type === Syntax.EmptyStatement) { | ||
if (stmt.type === Syntax.EmptyStatement && (!extra.comment || !stmt.leadingComments)) { | ||
result = ';'; | ||
@@ -303,8 +398,8 @@ } else { | ||
function generateExpression(expr, precedence) { | ||
var result, currentPrecedence, previousBase, i, len, raw; | ||
function generateExpression(expr, option) { | ||
var result, precedence, currentPrecedence, previousBase, i, len, raw, allowIn, allowCall; | ||
if (!precedence) { | ||
precedence = Precedence.Sequence; | ||
} | ||
precedence = option.precedence; | ||
allowIn = option.allowIn; | ||
allowCall = option.allowCall; | ||
@@ -314,4 +409,9 @@ switch (expr.type) { | ||
result = ''; | ||
allowIn |= (Precedence.Sequence < precedence); | ||
for (i = 0, len = expr.expressions.length; i < len; i += 1) { | ||
result += generateExpression(expr.expressions[i], Precedence.Assignment); | ||
result += generateExpression(expr.expressions[i], { | ||
precedence: Precedence.Assignment, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}); | ||
if ((i + 1) < len) { | ||
@@ -325,5 +425,14 @@ result += ', '; | ||
case Syntax.AssignmentExpression: | ||
allowIn |= (Precedence.Assignment < precedence); | ||
result = parenthesize( | ||
generateExpression(expr.left, Precedence.Call) + ' ' + expr.operator + ' ' + | ||
generateExpression(expr.right, Precedence.Assignment), | ||
generateExpression(expr.left, { | ||
precedence: Precedence.Call, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}) + ' ' + expr.operator + ' ' + | ||
generateExpression(expr.right, { | ||
precedence: Precedence.Assignment, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}), | ||
Precedence.Assignment, | ||
@@ -335,6 +444,19 @@ precedence | ||
case Syntax.ConditionalExpression: | ||
allowIn |= (Precedence.Conditional < precedence); | ||
result = parenthesize( | ||
generateExpression(expr.test, Precedence.LogicalOR) + ' ? ' + | ||
generateExpression(expr.consequent, Precedence.Assignment) + ' : ' + | ||
generateExpression(expr.alternate, Precedence.Assignment), | ||
generateExpression(expr.test, { | ||
precedence: Precedence.LogicalOR, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}) + ' ? ' + | ||
generateExpression(expr.consequent, { | ||
precedence: Precedence.Assignment, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}) + ' : ' + | ||
generateExpression(expr.alternate, { | ||
precedence: Precedence.Assignment, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}), | ||
Precedence.Conditional, | ||
@@ -349,7 +471,17 @@ precedence | ||
result = generateExpression(expr.left, currentPrecedence) + | ||
' ' + expr.operator + ' ' + | ||
generateExpression(expr.right, currentPrecedence + 1); | ||
if (expr.operator === 'in') { | ||
// TODO parenthesize only in allowIn = false case | ||
allowIn |= (currentPrecedence < precedence); | ||
result = | ||
generateExpression(expr.left, { | ||
precedence: currentPrecedence, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}) + ' ' + expr.operator + ' ' + | ||
generateExpression(expr.right, { | ||
precedence: currentPrecedence + 1, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}); | ||
if (expr.operator === 'in' && !allowIn) { | ||
result = '(' + result + ')'; | ||
@@ -359,8 +491,19 @@ } else { | ||
} | ||
break; | ||
case Syntax.CallExpression: | ||
result = ''; | ||
result = generateExpression(expr.callee, { | ||
precedence: Precedence.Call, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
result += '('; | ||
for (i = 0, len = expr['arguments'].length; i < len; i += 1) { | ||
result += generateExpression(expr['arguments'][i], Precedence.Assignment); | ||
result += generateExpression(expr['arguments'][i], { | ||
precedence: Precedence.Assignment, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
if ((i + 1) < len) { | ||
@@ -370,13 +513,25 @@ result += ', '; | ||
} | ||
result = parenthesize( | ||
generateExpression(expr.callee, Precedence.Call) + '(' + result + ')', | ||
Precedence.Call, | ||
precedence | ||
); | ||
result += ')'; | ||
if (!allowCall) { | ||
result = '(' + result + ')'; | ||
} else { | ||
result = parenthesize(result, Precedence.Call, precedence); | ||
} | ||
break; | ||
case Syntax.NewExpression: | ||
result = ''; | ||
result = 'new ' + generateExpression(expr.callee, { | ||
precedence: Precedence.New, | ||
allowIn: true, | ||
allowCall: false | ||
}); | ||
result += '('; | ||
for (i = 0, len = expr['arguments'].length; i < len; i += 1) { | ||
result += generateExpression(expr['arguments'][i], Precedence.Assignment); | ||
result += generateExpression(expr['arguments'][i], { | ||
precedence: Precedence.Assignment, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
if ((i + 1) < len) { | ||
@@ -386,13 +541,20 @@ result += ', '; | ||
} | ||
result = parenthesize( | ||
'new ' + generateExpression(expr.callee, Precedence.New) + '(' + result + ')', | ||
Precedence.New, | ||
precedence | ||
); | ||
result += ')'; | ||
result = parenthesize(result, Precedence.New, precedence); | ||
break; | ||
case Syntax.MemberExpression: | ||
result = generateExpression(expr.object, Precedence.Call); | ||
result = generateExpression(expr.object, { | ||
precedence: Precedence.Call, | ||
allowIn: true, | ||
allowCall: allowCall | ||
}); | ||
if (expr.computed) { | ||
result += '[' + generateExpression(expr.property) + ']'; | ||
result += '[' + generateExpression(expr.property, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: allowCall | ||
}) + ']'; | ||
} else { | ||
@@ -408,2 +570,3 @@ if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { | ||
} | ||
result = parenthesize(result, Precedence.Member, precedence); | ||
@@ -418,9 +581,11 @@ break; | ||
result = parenthesize( | ||
result + generateExpression(expr.argument, Precedence.Unary + | ||
( | ||
result + generateExpression(expr.argument, { | ||
precedence: Precedence.Unary + ( | ||
expr.argument.type === Syntax.UnaryExpression && | ||
expr.operator.length < 3 && | ||
expr.argument.operator === expr.operator ? 1 : 0 | ||
) | ||
expr.operator.length < 3 && | ||
expr.argument.operator === expr.operator ? 1 : 0 | ||
), | ||
allowIn: true, | ||
allowCall: true | ||
}), | ||
Precedence.Unary, | ||
@@ -435,3 +600,7 @@ precedence | ||
expr.operator + | ||
generateExpression(expr.argument, Precedence.Unary), | ||
generateExpression(expr.argument, { | ||
precedence: Precedence.Unary, | ||
allowIn: true, | ||
allowCall: true | ||
}), | ||
Precedence.Unary, | ||
@@ -442,4 +611,7 @@ precedence | ||
result = parenthesize( | ||
generateExpression(expr.argument, Precedence.Postfix) + | ||
expr.operator, | ||
generateExpression(expr.argument, { | ||
precedence: Precedence.Postfix, | ||
allowIn: true, | ||
allowCall: true | ||
}) + expr.operator, | ||
Precedence.Postfix, | ||
@@ -474,3 +646,7 @@ precedence | ||
} else { | ||
result += addIndent(generateExpression(expr.elements[i], Precedence.Assignment)); | ||
result += addIndent(generateExpression(expr.elements[i], { | ||
precedence: Precedence.Assignment, | ||
allowIn: true, | ||
allowCall: true | ||
})); | ||
} | ||
@@ -487,7 +663,18 @@ if ((i + 1) < len) { | ||
if (expr.kind === 'get' || expr.kind === 'set') { | ||
result = expr.kind + ' ' + generateExpression(expr.key) + | ||
generateFunctionBody(expr.value); | ||
result = expr.kind + ' ' + generateExpression(expr.key, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + generateFunctionBody(expr.value); | ||
} else { | ||
result = generateExpression(expr.key) + ': ' + | ||
generateExpression(expr.value, Precedence.Assignment); | ||
result = | ||
generateExpression(expr.key, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ': ' + generateExpression(expr.value, { | ||
precedence: Precedence.Assignment, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
} | ||
@@ -505,3 +692,7 @@ break; | ||
for (i = 0, len = expr.properties.length; i < len; i += 1) { | ||
result += addIndent(generateExpression(expr.properties[i])); | ||
result += addIndent(generateExpression(expr.properties[i], { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
})); | ||
if ((i + 1) < len) { | ||
@@ -567,5 +758,10 @@ result += ',\n'; | ||
function generateStatement(stmt) { | ||
var i, len, result, previousBase; | ||
function generateStatement(stmt, option) { | ||
var i, len, result, previousBase, comment, save, ret, node, allowIn; | ||
allowIn = true; | ||
if (option) { | ||
allowIn = option.allowIn; | ||
} | ||
switch (stmt.type) { | ||
@@ -602,3 +798,7 @@ case Syntax.BlockStatement: | ||
case Syntax.DoWhileStatement: | ||
result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test) + ');'; | ||
result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ');'; | ||
break; | ||
@@ -609,3 +809,7 @@ | ||
base += indent; | ||
result = ' catch (' + generateExpression(stmt.param) + ')'; | ||
result = ' catch (' + generateExpression(stmt.param, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -624,3 +828,7 @@ result += maybeBlock(stmt.body); | ||
case Syntax.ExpressionStatement: | ||
result = generateExpression(stmt.expression); | ||
result = generateExpression(stmt.expression, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
// 12.4 '{', 'function' is not allowed in this position. | ||
@@ -637,3 +845,7 @@ // wrap espression with parentheses | ||
if (stmt.init) { | ||
result = stmt.id.name + ' = ' + generateExpression(stmt.init, Precedence.Assignment); | ||
result = stmt.id.name + ' = ' + generateExpression(stmt.init, { | ||
precedence: Precedence.Assignment, | ||
allowIn: allowIn, | ||
allowCall: true | ||
}); | ||
} else { | ||
@@ -645,3 +857,3 @@ result = stmt.id.name; | ||
case Syntax.VariableDeclaration: | ||
result = stmt.kind + ' '; | ||
result = stmt.kind; | ||
// special path for | ||
@@ -652,10 +864,33 @@ // var x = function () { | ||
stmt.declarations[0].init.type === Syntax.FunctionExpression) { | ||
result += generateStatement(stmt.declarations[0]); | ||
result += ' ' + generateStatement(stmt.declarations[0], { | ||
allowIn: allowIn | ||
}); | ||
} else { | ||
// VariableDeclarator is typed as Statement, | ||
// but joined with comma (not LineTerminator). | ||
// So if comment is attached to target node, we should specialize. | ||
previousBase = base; | ||
base += indent; | ||
for (i = 0, len = stmt.declarations.length; i < len; i += 1) { | ||
result += generateStatement(stmt.declarations[i]); | ||
if ((i + 1) < len) { | ||
result += ', '; | ||
node = stmt.declarations[0]; | ||
if (extra.comment && node.leadingComments) { | ||
result += '\n' + addIndent(generateStatement(node, { | ||
allowIn: allowIn | ||
})); | ||
} else { | ||
result += ' ' + generateStatement(node, { | ||
allowIn: allowIn | ||
}); | ||
} | ||
for (i = 1, len = stmt.declarations.length; i < len; i += 1) { | ||
node = stmt.declarations[i]; | ||
if (extra.comment && node.leadingComments) { | ||
result += ',\n' + addIndent(generateStatement(node, { | ||
allowIn: allowIn | ||
})); | ||
} else { | ||
result += ', ' + generateStatement(node, { | ||
allowIn: allowIn | ||
}); | ||
} | ||
@@ -669,3 +904,7 @@ } | ||
case Syntax.ThrowStatement: | ||
result = 'throw ' + generateExpression(stmt.argument) + ';'; | ||
result = 'throw ' + generateExpression(stmt.argument, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ';'; | ||
break; | ||
@@ -686,3 +925,7 @@ | ||
base += indent; | ||
result = 'switch (' + generateExpression(stmt.discriminant) + ') {\n'; | ||
result = 'switch (' + generateExpression(stmt.discriminant, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ') {\n'; | ||
base = previousBase; | ||
@@ -701,3 +944,7 @@ if (stmt.cases) { | ||
if (stmt.test) { | ||
result = 'case ' + generateExpression(stmt.test) + ':'; | ||
result = 'case ' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ':'; | ||
} else { | ||
@@ -726,3 +973,7 @@ result = 'default:'; | ||
base += indent; | ||
result = 'if (' + generateExpression(stmt.test) + ')'; | ||
result = 'if (' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -733,3 +984,7 @@ result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate); | ||
base += indent; | ||
result = 'if (' + generateExpression(stmt.test) + ')'; | ||
result = 'if (' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -741,3 +996,7 @@ result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate); | ||
base += indent; | ||
result = 'if (' + generateExpression(stmt.test) + ')'; | ||
result = 'if (' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -754,5 +1013,11 @@ result += maybeBlock(stmt.consequent); | ||
if (stmt.init.type === Syntax.VariableDeclaration) { | ||
result += generateStatement(stmt.init); | ||
result += generateStatement(stmt.init, { | ||
allowIn: false | ||
}); | ||
} else { | ||
result += generateExpression(stmt.init) + ';'; | ||
result += generateExpression(stmt.init, { | ||
precedence: Precedence.Sequence, | ||
allowIn: false, | ||
allowCall: true | ||
}) + ';'; | ||
} | ||
@@ -764,3 +1029,7 @@ } else { | ||
if (stmt.test) { | ||
result += ' ' + generateExpression(stmt.test) + ';'; | ||
result += ' ' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ';'; | ||
} else { | ||
@@ -771,3 +1040,7 @@ result += ';'; | ||
if (stmt.update) { | ||
result += ' ' + generateExpression(stmt.update) + ')'; | ||
result += ' ' + generateExpression(stmt.update, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
} else { | ||
@@ -786,3 +1059,5 @@ result += ')'; | ||
base += indent + indent; | ||
result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0]); | ||
result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], { | ||
allowIn: false | ||
}); | ||
base = previousBase; | ||
@@ -792,3 +1067,7 @@ } else { | ||
base += indent; | ||
result += generateExpression(stmt.left, Precedence.Call); | ||
result += generateExpression(stmt.left, { | ||
precedence: Precedence.Call, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
base = previousBase; | ||
@@ -799,3 +1078,7 @@ } | ||
base += indent; | ||
result += ' in ' + generateExpression(stmt.right) + ')'; | ||
result += ' in ' + generateExpression(stmt.right, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -829,3 +1112,7 @@ result += maybeBlock(stmt.body); | ||
if (stmt.argument) { | ||
result = 'return ' + generateExpression(stmt.argument) + ';'; | ||
result = 'return ' + generateExpression(stmt.argument, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ';'; | ||
} else { | ||
@@ -839,3 +1126,7 @@ result = 'return;'; | ||
base += indent; | ||
result = 'while (' + generateExpression(stmt.test) + ')'; | ||
result = 'while (' + generateExpression(stmt.test, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -848,3 +1139,7 @@ result += maybeBlock(stmt.body); | ||
base += indent; | ||
result = 'with (' + generateExpression(stmt.object) + ')'; | ||
result = 'with (' + generateExpression(stmt.object, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}) + ')'; | ||
base = previousBase; | ||
@@ -861,2 +1156,38 @@ result += maybeBlock(stmt.body); | ||
} | ||
// Attach comments | ||
if (extra.comment) { | ||
if (stmt.leadingComments) { | ||
save = result; | ||
comment = stmt.leadingComments[0]; | ||
result = generateComment(comment); | ||
if (!endsWithLineTerminator(result)) { | ||
result += '\n'; | ||
} | ||
for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { | ||
comment = stmt.leadingComments[i]; | ||
ret = generateComment(comment); | ||
if (!endsWithLineTerminator(ret)) { | ||
ret += '\n'; | ||
} | ||
result += addIndent(ret); | ||
} | ||
result += addIndent(save); | ||
} | ||
if (stmt.trailingComments) { | ||
for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { | ||
comment = stmt.trailingComments[i]; | ||
if (!endsWithLineTerminator(result)) { | ||
result += '\n'; | ||
} | ||
result += addIndent(generateComment(comment)); | ||
} | ||
} | ||
} | ||
return result; | ||
@@ -893,2 +1224,3 @@ } | ||
} | ||
extra = options; | ||
@@ -938,3 +1270,7 @@ switch (node.type) { | ||
case Syntax.UpdateExpression: | ||
return generateExpression(node); | ||
return generateExpression(node, { | ||
precedence: Precedence.Sequence, | ||
allowIn: true, | ||
allowCall: true | ||
}); | ||
@@ -947,8 +1283,293 @@ default: | ||
// simple visitor implementation | ||
VisitorKeys = { | ||
AssignmentExpression: ['left', 'right'], | ||
ArrayExpression: ['elements'], | ||
BlockStatement: ['body'], | ||
BinaryExpression: ['left', 'right'], | ||
BreakStatement: ['label'], | ||
CallExpression: ['callee', 'arguments'], | ||
CatchClause: ['param', 'body'], | ||
ConditionalExpression: ['test', 'consequent', 'alternate'], | ||
ContinueStatement: ['label'], | ||
DoWhileStatement: ['body', 'test'], | ||
DebuggerStatement: [], | ||
EmptyStatement: [], | ||
ExpressionStatement: ['expression'], | ||
ForStatement: ['init', 'test', 'update', 'body'], | ||
ForInStatement: ['left', 'right', 'body'], | ||
FunctionDeclaration: ['id', 'params', 'body'], | ||
FunctionExpression: ['id', 'params', 'body'], | ||
Identifier: [], | ||
IfStatement: ['test', 'consequent', 'alternate'], | ||
Literal: [], | ||
LabeledStatement: ['label', 'body'], | ||
LogicalExpression: ['left', 'right'], | ||
MemberExpression: ['object', 'property'], | ||
NewExpression: ['callee', 'arguments'], | ||
ObjectExpression: ['properties'], | ||
Program: ['body'], | ||
Property: ['key', 'value'], | ||
ReturnStatement: ['argument'], | ||
SequenceExpression: ['expressions'], | ||
SwitchStatement: ['descriminant', 'cases'], | ||
SwitchCase: ['test', 'consequent'], | ||
ThisExpression: [], | ||
ThrowStatement: ['argument'], | ||
TryStatement: ['block', 'handlers', 'finalizer'], | ||
UnaryExpression: ['argument'], | ||
UpdateExpression: ['argument'], | ||
VariableDeclaration: ['declarations'], | ||
VariableDeclarator: ['id', 'init'], | ||
WhileStatement: ['test', 'body'], | ||
WithStatement: ['object', 'body'] | ||
}; | ||
VisitorOption = { | ||
Break: 1, | ||
Skip: 2 | ||
}; | ||
function traverse(top, visitor) { | ||
var worklist, leavelist, node, ret, current, current2, candidates, candidate; | ||
worklist = [ top ]; | ||
leavelist = []; | ||
while (worklist.length) { | ||
node = worklist.pop(); | ||
if (node) { | ||
if (visitor.enter) { | ||
ret = visitor.enter(node); | ||
} else { | ||
ret = undefined; | ||
} | ||
if (ret === VisitorOption.Break) { | ||
return; | ||
} | ||
worklist.push(null); | ||
leavelist.push(node); | ||
if (ret !== VisitorOption.Skip) { | ||
candidates = VisitorKeys[node.type]; | ||
current = candidates.length; | ||
while ((current -= 1) >= 0) { | ||
candidate = node[candidates[current]]; | ||
if (candidate) { | ||
if (isArray(candidate)) { | ||
current2 = candidate.length; | ||
while ((current2 -= 1) >= 0) { | ||
if (candidate[current2]) { | ||
worklist.push(candidate[current2]); | ||
} | ||
} | ||
} else { | ||
worklist.push(candidate); | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
node = leavelist.pop(); | ||
if (visitor.leave) { | ||
ret = visitor.leave(node); | ||
} else { | ||
ret = undefined; | ||
} | ||
if (ret === VisitorOption.Break) { | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
// based on LLVM libc++ upper_bound / lower_bound | ||
// MIT License | ||
function upperBound(array, func) { | ||
var diff, len, i, current; | ||
len = array.length; | ||
i = 0; | ||
while (len) { | ||
diff = len >>> 1; | ||
current = i + diff; | ||
if (func(array[current])) { | ||
len = diff; | ||
} else { | ||
i = current + 1; | ||
len -= diff + 1; | ||
} | ||
} | ||
return i; | ||
} | ||
function lowerBound(array, func) { | ||
var diff, len, i, current; | ||
len = array.length; | ||
i = 0; | ||
while (len) { | ||
diff = len >>> 1; | ||
current = i + diff; | ||
if (func(array[current])) { | ||
i = current + 1; | ||
len -= diff + 1; | ||
} else { | ||
len = diff; | ||
} | ||
} | ||
return i; | ||
} | ||
function extendCommentRange(comment, tokens) { | ||
var target, token; | ||
target = upperBound(tokens, function search(token) { | ||
return token.range[0] > comment.range[0]; | ||
}); | ||
comment.extendedRange = [comment.range[0], comment.range[1]]; | ||
if (target !== tokens.length) { | ||
comment.extendedRange[1] = tokens[target].range[0]; | ||
} | ||
target -= 1; | ||
if (target >= 0) { | ||
if (target < tokens.length) { | ||
comment.extendedRange[0] = tokens[target].range[1]; | ||
} else if (token.length) { | ||
comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; | ||
} | ||
} | ||
return comment; | ||
} | ||
function attachComments(tree, providedComments, tokens) { | ||
// At first, we should calculate extended comment ranges. | ||
var comments = [], len, i; | ||
if (!tree.range) { | ||
throw new Error('attachComments needs range information'); | ||
} | ||
for (i = 0, len = providedComments.length; i < len; i += 1) { | ||
comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); | ||
} | ||
// | ||
// For example, | ||
// | ||
// var i1 = 10, // test | ||
// i2 = 20; | ||
// | ||
// Above comment is probably trailing to i1 = 10. | ||
// So we specialize comma token. | ||
// | ||
// And second, comma first style example, | ||
// | ||
// var i = [ | ||
// 10 // testing | ||
// , 20 // testing 2 | ||
// ]; | ||
// | ||
// 'testing' comment is trailing to 10 is proper. | ||
// | ||
// So we add some specialize path. | ||
// | ||
// 1. check comment is'nt containing LineTerminator | ||
// 2. check LineTerminator is not found between previous token and comment | ||
// 3. check LineTerminator is found between comment and next token | ||
// | ||
// If above conditions are all true, | ||
// we assume this comment should be attached to previous token as trailing comment. | ||
// | ||
// This traverse attacher is based on John Freeman's implementation. | ||
traverse(tree, { | ||
cursor: 0, | ||
enter: function (node) { | ||
var comment; | ||
while (this.cursor < comments.length) { | ||
comment = comments[this.cursor]; | ||
if (comment.extendedRange[1] > node.range[0]) { | ||
break; | ||
} | ||
if (comment.extendedRange[1] === node.range[0]) { | ||
if (!node.leadingComments) { | ||
node.leadingComments = []; | ||
} | ||
node.leadingComments.push(comment); | ||
comments.splice(this.cursor, 1); | ||
} else { | ||
this.cursor += 1; | ||
} | ||
} | ||
// already out of owned node | ||
if (this.cursor === comments.length) { | ||
return VisitorOption.Break; | ||
} | ||
if (comments[this.cursor].extendedRange[0] > node.range[1]) { | ||
return VisitorOption.Skip; | ||
} | ||
} | ||
}); | ||
traverse(tree, { | ||
cursor: 0, | ||
leave: function (node) { | ||
var comment; | ||
while (this.cursor < comments.length) { | ||
comment = comments[this.cursor]; | ||
if (node.range[1] < comment.extendedRange[0]) { | ||
break; | ||
} | ||
if (node.range[1] === comment.extendedRange[0]) { | ||
if (!node.trailingComments) { | ||
node.trailingComments = []; | ||
} | ||
node.trailingComments.push(comment); | ||
comments.splice(this.cursor, 1); | ||
} else { | ||
this.cursor += 1; | ||
} | ||
} | ||
// already out of owned node | ||
if (this.cursor === comments.length) { | ||
return VisitorOption.Break; | ||
} | ||
if (comments[this.cursor].extendedRange[0] > node.range[1]) { | ||
return VisitorOption.Skip; | ||
} | ||
} | ||
}); | ||
return tree; | ||
} | ||
// Sync with package.json. | ||
exports.version = '0.0.3'; | ||
exports.version = '0.0.4'; | ||
exports.generate = generate; | ||
exports.traverse = traverse; | ||
exports.attachComments = attachComments; | ||
}(typeof exports === 'undefined' ? (escodegen = {}) : exports)); | ||
/* vim: set sw=4 ts=4 et tw=80 : */ |
@@ -9,3 +9,3 @@ { | ||
}, | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"engines": { | ||
@@ -12,0 +12,0 @@ "node": ">=0.4.0" |
@@ -126,2 +126,88 @@ /* | ||
result: ' {\n test;\n }' | ||
}, | ||
'generate with base 2 + indent 2': { | ||
call: 'generate', | ||
args: [{ | ||
type: 'Program', | ||
body: [{ | ||
type: 'BlockStatement', | ||
body: [{ | ||
type: 'ExpressionStatement', | ||
expression: { | ||
type: 'Identifier', | ||
name: 'test' | ||
} | ||
}] | ||
}] | ||
}, { | ||
format: { | ||
indent: { | ||
style: ' ', | ||
base: 2 | ||
} | ||
} | ||
}], | ||
result: ' {\n test;\n }' | ||
}, | ||
// obsolete api | ||
'obsolete generate with base 2': { | ||
call: 'generate', | ||
args: [{ | ||
type: 'Program', | ||
body: [{ | ||
type: 'BlockStatement', | ||
body: [{ | ||
type: 'ExpressionStatement', | ||
expression: { | ||
type: 'Identifier', | ||
name: 'test' | ||
} | ||
}] | ||
}] | ||
}, { | ||
base: ' ' | ||
}], | ||
result: ' {\n test;\n }' | ||
}, | ||
'obsolete generate with indent 2': { | ||
call: 'generate', | ||
args: [{ | ||
type: 'Program', | ||
body: [{ | ||
type: 'BlockStatement', | ||
body: [{ | ||
type: 'ExpressionStatement', | ||
expression: { | ||
type: 'Identifier', | ||
name: 'test' | ||
} | ||
}] | ||
}] | ||
}, { | ||
indent: ' ', | ||
}], | ||
result: '{\n test;\n}' | ||
}, | ||
'obsolete generate with base 2 + indent 2': { | ||
call: 'generate', | ||
args: [{ | ||
type: 'Program', | ||
body: [{ | ||
type: 'BlockStatement', | ||
body: [{ | ||
type: 'ExpressionStatement', | ||
expression: { | ||
type: 'Identifier', | ||
name: 'test' | ||
} | ||
}] | ||
}] | ||
}, { | ||
indent: ' ', | ||
base: ' ' | ||
}], | ||
result: ' {\n test;\n }' | ||
} | ||
@@ -128,0 +214,0 @@ }; |
@@ -94,3 +94,3 @@ /* | ||
expected = JSON.stringify(tree, adjustRegexLiteral, 4); | ||
tree = esprima.parse(esprima.generate(tree), options); | ||
tree = esprima.parse(escodegen.generate(tree), options); | ||
actual = JSON.stringify(tree, adjustRegexLiteral, 4); | ||
@@ -97,0 +97,0 @@ } catch (e) { |
@@ -95,3 +95,3 @@ /* | ||
expected = JSON.stringify(tree, adjustRegexLiteral, 4); | ||
tree = esprima.parse(esprima.generate(tree), options); | ||
tree = esprima.parse(escodegen.generate(tree), options); | ||
actual = JSON.stringify(tree, adjustRegexLiteral, 4); | ||
@@ -98,0 +98,0 @@ } catch (e) { |
@@ -41,3 +41,5 @@ /* | ||
'options', | ||
'identity' | ||
'comment', | ||
'compare', | ||
'identity', | ||
]; | ||
@@ -44,0 +46,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7327903
85
105019
7