diff --git a/bin/prettier.js b/bin/prettier.js index a5b6229f..05202c8f 100755 --- a/bin/prettier.js +++ b/bin/prettier.js @@ -1,16 +1,20 @@ #!/usr/bin/env node "use strict"; - const fs = require("fs"); const getStdin = require("get-stdin"); const minimist = require("minimist"); const jscodefmt = require("../index"); const argv = minimist(process.argv.slice(2), { - boolean: ["write", "stdin", "flow-parser", "bracket-spacing", "single-quote", "trailing-comma"], - default: { - "bracket-spacing": true - } + boolean: [ + "write", + "stdin", + "flow-parser", + "bracket-spacing", + "single-quote", + "trailing-comma" + ], + default: { "bracket-spacing": true } }); const filenames = argv["_"]; @@ -19,16 +23,15 @@ const stdin = argv["stdin"]; if (!filenames.length && !stdin) { console.log( - "Usage: prettier [opts] [filename ...]\n\n" + - "Available options:\n" + - " --write Edit the file in-place (beware!)\n" + - " --stdin Read input from stdin\n" + - " --print-width Specify the length of line that the printer will wrap on. Defaults to 80.\n" + - " --tab-width Specify the number of spaces per indentation-level. Defaults to 2.\n" + - " --flow-parser Use the flow parser instead of babylon\n" + - " --single-quote Use single quotes instead of double\n" + - " --trailing-comma Print trailing commas wherever possible\n" + - " --bracket-spacing Put spaces between brackets. Defaults to true, set false to turn off" + "Usage: prettier [opts] [filename ...]\n\n" + "Available options:\n" + + " --write Edit the file in-place (beware!)\n" + + " --stdin Read input from stdin\n" + + " --print-width Specify the length of line that the printer will wrap on. Defaults to 80.\n" + + " --tab-width Specify the number of spaces per indentation-level. Defaults to 2.\n" + + " --flow-parser Use the flow parser instead of babylon\n" + + " --single-quote Use single quotes instead of double\n" + + " --trailing-comma Print trailing commas wherever possible\n" + + " --bracket-spacing Put spaces between brackets. Defaults to true, set false to turn off" ); process.exit(1); } diff --git a/index.js b/index.js index e37fcdf4..54de9ad6 100644 --- a/index.js +++ b/index.js @@ -5,21 +5,21 @@ const flowParser = require("flow-parser"); const comments = require("./src/comments"); var babylonOptions = { - sourceType: 'module', + sourceType: "module", allowImportExportEverywhere: false, allowReturnOutsideFunction: false, plugins: [ - 'jsx', - 'flow', - 'doExpressions', - 'objectRestSpread', - 'decorators', - 'classProperties', - 'exportExtensions', - 'asyncGenerators', - 'functionBind', - 'functionSent', - 'dynamicImport' + "jsx", + "flow", + "doExpressions", + "objectRestSpread", + "decorators", + "classProperties", + "exportExtensions", + "asyncGenerators", + "functionBind", + "functionSent", + "dynamicImport" ] }; @@ -27,22 +27,22 @@ function format(text, opts) { opts = opts || {}; let ast; - if(opts.useFlowParser) { + if (opts.useFlowParser) { ast = flowParser.parse(text); - if(ast.errors.length > 0) { - let msg = ast.errors[0].message + " on line " + ast.errors[0].loc.start.line - if(opts.filename) { + if (ast.errors.length > 0) { + let msg = ast.errors[(0)].message + " on line " + + ast.errors[(0)].loc.start.line; + if (opts.filename) { msg += " in file " + opts.filename; } throw new Error(msg); } - } - else { + } else { ast = babylon.parse(text, babylonOptions); } // Interleave comment nodes - if(ast.comments) { + if (ast.comments) { comments.attach(ast.comments, ast, text); ast.comments = []; } diff --git a/src/comments.js b/src/comments.js index 22d2966f..10398d3f 100644 --- a/src/comments.js +++ b/src/comments.js @@ -73,11 +73,13 @@ function decorateComment(node, comment, text) { // Time to dust off the old binary search robes and wizard hat. var left = 0, right = childNodes.length; while (left < right) { - var middle = (left + right) >> 1; + var middle = left + right >> 1; var child = childNodes[middle]; - if (locStart(child) - locStart(comment) <= 0 && - locEnd(comment) - locEnd(child) <= 0) { + if ( + locStart(child) - locStart(comment) <= 0 && + locEnd(comment) - locEnd(child) <= 0 + ) { // The comment is completely contained by this child node. comment.enclosingNode = child; decorateComment(child, comment, text); @@ -146,26 +148,20 @@ exports.attach = function(comments, ast, text) { } tiesToBreak.push(comment); - } else if (pn) { // No contest: we have a trailing comment. breakTies(tiesToBreak, text); addTrailingComment(pn, comment); - } else if (fn) { // No contest: we have a leading comment. breakTies(tiesToBreak, text); addLeadingComment(fn, comment); - } else if (en) { // The enclosing node has no child nodes at all, so what we // have here is a dangling comment, e.g. [/* crickets */]. breakTies(tiesToBreak, text); addDanglingComment(en, comment); - - } else { - // throw new Error("AST contains no nodes at all?"); - } + } else {} }); breakTies(tiesToBreak, text); @@ -186,17 +182,19 @@ function breakTies(tiesToBreak, text) { return; } - var pn = tiesToBreak[0].precedingNode; - var fn = tiesToBreak[0].followingNode; + var pn = tiesToBreak[(0)].precedingNode; + var fn = tiesToBreak[(0)].followingNode; var gapEndPos = locStart(fn); // Iterate backwards through tiesToBreak, examining the gaps // between the tied comments. In order to qualify as leading, a // comment must be separated from fn by an unbroken series of // whitespace-only gaps (or other comments). - for (var indexOfFirstLeadingComment = tieCount; - indexOfFirstLeadingComment > 0; - --indexOfFirstLeadingComment) { + for ( + var indexOfFirstLeadingComment = tieCount; + indexOfFirstLeadingComment > 0; + --indexOfFirstLeadingComment + ) { var comment = tiesToBreak[indexOfFirstLeadingComment - 1]; assert.strictEqual(comment.precedingNode, pn); assert.strictEqual(comment.followingNode, fn); @@ -218,7 +216,6 @@ function breakTies(tiesToBreak, text) { // comment.loc.start.column > fn.loc.start.column) { // ++indexOfFirstLeadingComment; // } - tiesToBreak.forEach(function(comment, i) { if (i < indexOfFirstLeadingComment) { addTrailingComment(pn, comment); @@ -256,7 +253,7 @@ function addTrailingComment(node, comment) { function printLeadingComment(commentPath, print) { var comment = commentPath.getValue(); n.Comment.assert(comment); - return concat([print(commentPath), hardline]); + return concat([ print(commentPath), hardline ]); } function printTrailingComment(commentPath, print, options) { @@ -274,40 +271,45 @@ exports.printComments = function(path, print, options) { var value = path.getValue(); var parent = path.getParentNode(); var printed = print(path); - var comments = n.Node.check(value) && - types.getFieldValue(value, "comments"); - var isFirstInProgram = n.Program.check(parent) && - parent.body[0] === value; + var comments = n.Node.check(value) && types.getFieldValue(value, "comments"); + var isFirstInProgram = n.Program.check(parent) && parent.body[(0)] === value; if (!comments || comments.length === 0) { return printed; } var leadingParts = []; - var trailingParts = [printed]; + var trailingParts = [ printed ]; - path.each(function(commentPath) { - var comment = commentPath.getValue(); - var leading = types.getFieldValue(comment, "leading"); - var trailing = types.getFieldValue(comment, "trailing"); + path.each( + function(commentPath) { + var comment = commentPath.getValue(); + var leading = types.getFieldValue(comment, "leading"); + var trailing = types.getFieldValue(comment, "trailing"); - if (leading || (trailing && !(n.Statement.check(value) || - comment.type === "Block" || - comment.type === "CommentBlock"))) { - leadingParts.push(printLeadingComment(commentPath, print)); + if ( + leading || + trailing && + !(n.Statement.check(value) || comment.type === "Block" || + comment.type === "CommentBlock") + ) { + leadingParts.push(printLeadingComment(commentPath, print)); - - // Support a special case where a comment exists at the very top - // of the file. Allow the user to add spacing between that file - // and any code beneath it. - if(isFirstInProgram && - util.newlineExistsAfter(options.originalText, util.locEnd(comment))) { - leadingParts.push(hardline); + // Support a special case where a comment exists at the very top + // of the file. Allow the user to add spacing between that file + // and any code beneath it. + if ( + isFirstInProgram && + util.newlineExistsAfter(options.originalText, util.locEnd(comment)) + ) { + leadingParts.push(hardline); + } + } else if (trailing) { + trailingParts.push(printTrailingComment(commentPath, print, options)); } - } else if (trailing) { - trailingParts.push(printTrailingComment(commentPath, print, options)); - } - }, "comments"); + }, + "comments" + ); leadingParts.push.apply(leadingParts, trailingParts); return concat(leadingParts); diff --git a/src/fast-path.js b/src/fast-path.js index 2ce4c9cc..c97b1682 100644 --- a/src/fast-path.js +++ b/src/fast-path.js @@ -7,7 +7,7 @@ var isNumber = types.builtInTypes.number; function FastPath(value) { assert.ok(this instanceof FastPath); - this.stack = [value]; + this.stack = [ value ]; } var FPp = FastPath.prototype; @@ -24,8 +24,8 @@ FastPath.from = function(obj) { // For backwards compatibility, unroll NodePath instances into // lightweight FastPath [..., name, value] stacks. var copy = Object.create(FastPath.prototype); - var stack = [obj.value]; - for (var pp; (pp = obj.parentPath); obj = pp) + var stack = [ obj.value ]; + for (var pp; pp = obj.parentPath; obj = pp) stack.push(obj.name, pp.value); copy.stack = stack.reverse(); return copy; @@ -90,9 +90,9 @@ FPp.getParentNode = function getParentNode(count) { FPp.getRootValue = function getRootValue() { var s = this.stack; if (s.length % 2 === 0) { - return s[1]; + return s[(1)]; } - return s[0]; + return s[(0)]; }; // Temporarily push properties named by string arguments given after the @@ -100,7 +100,7 @@ FPp.getRootValue = function getRootValue() { // reference to this (modified) FastPath object. Note that the stack will // be restored to its original state after the callback is finished, so it // is probably a mistake to retain a reference to the path. -FPp.call = function call(callback/*, name1, name2, ... */) { +FPp.call = function call(callback /*, name1, name2, ... */) { var s = this.stack; var origLen = s.length; var value = s[origLen - 1]; @@ -119,7 +119,7 @@ FPp.call = function call(callback/*, name1, name2, ... */) { // accessing this.getValue()[name1][name2]... should be array-like. The // callback will be called with a reference to this path object for each // element of the array. -FPp.each = function each(callback/*, name1, name2, ... */) { +FPp.each = function each(callback /*, name1, name2, ... */) { var s = this.stack; var origLen = s.length; var value = s[origLen - 1]; @@ -147,7 +147,7 @@ FPp.each = function each(callback/*, name1, name2, ... */) { // Similar to FastPath.prototype.each, except that the results of the // callback function invocations are stored in an array and returned at // the end of the iteration. -FPp.map = function map(callback/*, name1, name2, ... */) { +FPp.map = function map(callback /*, name1, name2, ... */) { var s = this.stack; var origLen = s.length; var value = s[origLen - 1]; @@ -208,36 +208,36 @@ FPp.needsParens = function(assumeExpressionContext) { // Add parens around a `class` that extends an expression (it should // parse correctly, even if it's invalid) - if(parent.type === "ClassDeclaration" && - parent.superClass === node && - node.type === "AwaitExpression") { + if ( + parent.type === "ClassDeclaration" && parent.superClass === node && + node.type === "AwaitExpression" + ) { return true; } // The left-hand side of the ** exponentiation operator must always // be parenthesized unless it's an ident or literal - if(parent.type === "BinaryExpression" && - parent.operator === "**" && - parent.left === node && - node.type !== "Identifier" && - node.type !== "Literal") { - return true + if ( + parent.type === "BinaryExpression" && parent.operator === "**" && + parent.left === node && + node.type !== "Identifier" && + node.type !== "Literal" + ) { + return true; } switch (node.type) { case "UnaryExpression": case "SpreadElement": case "SpreadProperty": - return parent.type === "MemberExpression" - && name === "object" - && parent.object === node; + return parent.type === "MemberExpression" && name === "object" && + parent.object === node; case "BinaryExpression": case "LogicalExpression": switch (parent.type) { case "CallExpression": - return name === "callee" - && parent.callee === node; + return name === "callee" && parent.callee === node; case "UnaryExpression": case "SpreadElement": @@ -245,8 +245,7 @@ FPp.needsParens = function(assumeExpressionContext) { return true; case "MemberExpression": - return name === "object" - && parent.object === node; + return name === "object" && parent.object === node; case "BinaryExpression": case "LogicalExpression": @@ -324,10 +323,9 @@ FPp.needsParens = function(assumeExpressionContext) { parent.type === "IntersectionTypeAnnotation"; case "Literal": - return parent.type === "MemberExpression" - && isNumber.check(node.value) - && name === "object" - && parent.object === node; + return parent.type === "MemberExpression" && isNumber.check(node.value) && + name === "object" && + parent.object === node; case "NumericLiteral": return parent.type === "MemberExpression"; @@ -343,27 +341,22 @@ FPp.needsParens = function(assumeExpressionContext) { return true; case "CallExpression": - return name === "callee" - && parent.callee === node; + return name === "callee" && parent.callee === node; case "ConditionalExpression": - return name === "test" - && parent.test === node; + return name === "test" && parent.test === node; case "MemberExpression": - return name === "object" - && parent.object === node; + return name === "object" && parent.object === node; default: - return n.ObjectPattern.check(node.left) && - this.firstInStatement(); + return n.ObjectPattern.check(node.left) && this.firstInStatement(); } case "ArrowFunctionExpression": - if(parent.type === 'CallExpression' && - name === 'callee') { + if (parent.type === "CallExpression" && name === "callee") { return true; - }; + } return isBinary(parent); @@ -371,51 +364,52 @@ FPp.needsParens = function(assumeExpressionContext) { return parent.type === "ExpressionStatement"; case "ObjectExpression": - if (parent.type === "ArrowFunctionExpression" && - name === "body") { + if (parent.type === "ArrowFunctionExpression" && name === "body") { return true; } default: - if (parent.type === "NewExpression" && - name === "callee" && - parent.callee === node) { + if ( + parent.type === "NewExpression" && name === "callee" && + parent.callee === node + ) { return containsCallExpression(node); } } - if (assumeExpressionContext !== true && - !this.canBeFirstInStatement() && - this.firstInStatement()) + if ( + assumeExpressionContext !== true && !this.canBeFirstInStatement() && + this.firstInStatement() + ) return true; return false; }; function isBinary(node) { - return n.BinaryExpression.check(node) - || n.LogicalExpression.check(node); + return n.BinaryExpression.check(node) || n.LogicalExpression.check(node); } function isUnaryLike(node) { - return n.UnaryExpression.check(node) - // I considered making SpreadElement and SpreadProperty subtypes + return // I considered making SpreadElement and SpreadProperty subtypes // of UnaryExpression, but they're not really Expression nodes. - || (n.SpreadElement && n.SpreadElement.check(node)) - || (n.SpreadProperty && n.SpreadProperty.check(node)); + n.UnaryExpression.check( + node + ) || n.SpreadElement && n.SpreadElement.check(node) || n.SpreadProperty && n.SpreadProperty.check(node); } var PRECEDENCE = {}; -[["||"], - ["&&"], - ["|"], - ["^"], - ["&"], - ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], - [">>", "<<", ">>>"], - ["+", "-"], - ["*", "/", "%", "**"] +[ + [ "||" ], + [ "&&" ], + [ "|" ], + [ "^" ], + [ "&" ], + [ "==", "===", "!=", "!==" ], + [ "<", ">", "<=", ">=", "in", "instanceof" ], + [ ">>", "<<", ">>>" ], + [ "+", "-" ], + [ "*", "/", "%", "**" ] ].forEach(function(tier, i) { tier.forEach(function(op) { PRECEDENCE[op] = i; @@ -442,11 +436,9 @@ function containsCallExpression(node) { FPp.canBeFirstInStatement = function() { var node = this.getNode(); - return !n.FunctionExpression.check(node) - && !n.ObjectExpression.check(node) - && !n.ClassExpression.check(node) - && !(n.AssignmentExpression.check(node) && - n.ObjectPattern.check(node.left)); + return !n.FunctionExpression.check(node) && !n.ObjectExpression.check(node) && + !n.ClassExpression.check(node) && + !(n.AssignmentExpression.check(node) && n.ObjectPattern.check(node.left)); }; FPp.firstInStatement = function() { @@ -466,53 +458,50 @@ FPp.firstInStatement = function() { continue; } - if (n.BlockStatement.check(parent) && - parentName === "body" && - childName === 0) { - assert.strictEqual(parent.body[0], child); + if ( + n.BlockStatement.check(parent) && parentName === "body" && childName === 0 + ) { + assert.strictEqual(parent.body[(0)], child); return true; } - if (n.ExpressionStatement.check(parent) && - childName === "expression") { + if (n.ExpressionStatement.check(parent) && childName === "expression") { assert.strictEqual(parent.expression, child); return true; } - if (n.SequenceExpression.check(parent) && - parentName === "expressions" && - childName === 0) { - assert.strictEqual(parent.expressions[0], child); + if ( + n.SequenceExpression.check(parent) && parentName === "expressions" && + childName === 0 + ) { + assert.strictEqual(parent.expressions[(0)], child); continue; } - if (n.CallExpression.check(parent) && - childName === "callee") { + if (n.CallExpression.check(parent) && childName === "callee") { assert.strictEqual(parent.callee, child); continue; } - if (n.MemberExpression.check(parent) && - childName === "object") { + if (n.MemberExpression.check(parent) && childName === "object") { assert.strictEqual(parent.object, child); continue; } - if (n.ConditionalExpression.check(parent) && - childName === "test") { + if (n.ConditionalExpression.check(parent) && childName === "test") { assert.strictEqual(parent.test, child); continue; } - if (isBinary(parent) && - childName === "left") { + if (isBinary(parent) && childName === "left") { assert.strictEqual(parent.left, child); continue; } - if (n.UnaryExpression.check(parent) && - !parent.prefix && - childName === "argument") { + if ( + n.UnaryExpression.check(parent) && !parent.prefix && + childName === "argument" + ) { assert.strictEqual(parent.argument, child); continue; } diff --git a/src/options.js b/src/options.js index 79a68913..e8720c9e 100644 --- a/src/options.js +++ b/src/options.js @@ -1,16 +1,12 @@ var defaults = { // Number of spaces the pretty-printer should use per tab tabWidth: 2, - // Fit code within this line limit printWidth: 80, - // If true, will use single instead of double quotes singleQuote: false, - // Controls the printing of trailing commas wherever possible trailingComma: false, - // Controls the printing of spaces inside array and objects bracketSpacing: true }; @@ -19,7 +15,7 @@ var defaults = { exports.normalize = function(options) { const normalized = Object.assign({}, options); Object.keys(defaults).forEach(k => { - if(normalized[k] == null) { + if (normalized[k] == null) { normalized[k] = defaults[k]; } }); diff --git a/src/pp.js b/src/pp.js index cff6cab4..d37490c3 100644 --- a/src/pp.js +++ b/src/pp.js @@ -15,13 +15,13 @@ function fromString(text) { function concat(parts) { parts.forEach(assertDoc); - return {type: "concat", parts}; + return { type: "concat", parts }; } function indent(n, contents) { assertDoc(contents); - return {type: "indent", contents, n}; + return { type: "indent", contents, n }; } function group(contents, opts) { @@ -40,16 +40,19 @@ function group(contents, opts) { function multilineGroup(contents, opts) { return group( contents, - Object.assign(opts || {}, {shouldBreak: hasHardLine(contents)}) + Object.assign(opts || {}, { shouldBreak: hasHardLine(contents) }) ); } function conditionalGroup(states, opts) { - return group(states[0], Object.assign(opts || {}, {expandedStates: states})); + return group( + states[(0)], + Object.assign(opts || {}, { expandedStates: states }) + ); } function ifBreak(contents) { - return {type: "if-break", contents}; + return { type: "if-break", contents }; } function iterDoc(topDoc, func) { @@ -82,10 +85,10 @@ function iterDoc(topDoc, func) { } } -const line = {type: "line"}; -const softline = {type: "line", soft: true}; -const hardline = {type: "line", hard: true}; -const literalline = {type: "line", hard: true, literal: true}; +const line = { type: "line" }; +const softline = { type: "line", soft: true }; +const hardline = { type: "line", hard: true }; +const literalline = { type: "line", hard: true, literal: true }; function isEmpty(n) { return typeof n === "string" && n.length === 0; @@ -118,12 +121,12 @@ function hasHardLine(doc) { // multiline group because they should be marked bottom-up. return !!iterDoc(doc, (type, doc) => { switch (type) { - case "line": - if (doc.hard) { - return true; - } + case "line": + if (doc.hard) { + return true; + } - break; + break; } }); } @@ -158,50 +161,50 @@ function fits(next, restCommands, width) { } const x = cmds.pop(); - const ind = x[0]; - const mode = x[1]; - const doc = x[2]; + const ind = x[(0)]; + const mode = x[(1)]; + const doc = x[(2)]; if (typeof doc === "string") { width -= doc.length; } else { switch (doc.type) { - case "concat": - for (var i = doc.parts.length - 1; i >= 0; i--) { - cmds.push([ ind, mode, doc.parts[i] ]); - } - - break; - case "indent": - cmds.push([ ind + doc.n, mode, doc.contents ]); - - break; - case "group": - cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]); - - break; - case "if-break": - if (mode === MODE_BREAK) { - cmds.push([ ind, mode, doc.contents ]); - } - - break; - case "line": - switch (mode) { - // fallthrough - case MODE_FLAT: - if (!doc.hard) { - if (!doc.soft) { - width -= 1; - } - - break; + case "concat": + for (var i = doc.parts.length - 1; i >= 0; i--) { + cmds.push([ ind, mode, doc.parts[i] ]); } - case MODE_BREAK: - return true; - } - break; + break; + case "indent": + cmds.push([ ind + doc.n, mode, doc.contents ]); + + break; + case "group": + cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]); + + break; + case "if-break": + if (mode === MODE_BREAK) { + cmds.push([ ind, mode, doc.contents ]); + } + + break; + case "line": + switch (mode) { + // fallthrough + case MODE_FLAT: + if (!doc.hard) { + if (!doc.soft) { + width -= 1; + } + + break; + } + + case MODE_BREAK: + return true; + } + break; } } } @@ -218,9 +221,9 @@ function print(w, doc) { let shouldRemeasure = false; while (cmds.length !== 0) { const x = cmds.pop(); - const ind = x[0]; - const mode = x[1]; - const doc = x[2]; + const ind = x[(0)]; + const mode = x[(1)]; + const doc = x[(2)]; if (typeof doc === "string") { out.push(doc); @@ -228,131 +231,131 @@ function print(w, doc) { pos += doc.length; } else { switch (doc.type) { - case "concat": - for (var i = doc.parts.length - 1; i >= 0; i--) { - cmds.push([ ind, mode, doc.parts[i] ]); - } - - break; - case "indent": - cmds.push([ ind + doc.n, mode, doc.contents ]); - - break; - case "group": - switch (mode) { - // fallthrough - case MODE_FLAT: - if (!shouldRemeasure) { - cmds.push([ - ind, - doc.break ? MODE_BREAK : MODE_FLAT, - doc.contents - ]); - - break; + case "concat": + for (var i = doc.parts.length - 1; i >= 0; i--) { + cmds.push([ ind, mode, doc.parts[i] ]); } - case MODE_BREAK: - shouldRemeasure = false; + break; + case "indent": + cmds.push([ ind + doc.n, mode, doc.contents ]); - const next = [ ind, MODE_FLAT, doc.contents ]; - let rem = w - pos; - - if (!doc.break && fits(next, cmds, rem)) { - cmds.push(next); - } else { - // Expanded states are a rare case where a document - // can manually provide multiple representations of - // itself. It provides an array of documents - // going from the least expanded (most flattened) - // representation first to the most expanded. If a - // group has these, we need to manually go through - // these states and find the first one that fits. - if (doc.expandedStates) { - const mostExpanded = doc.expandedStates[doc.expandedStates.length - - 1]; - - if (doc.break) { - cmds.push([ ind, MODE_BREAK, mostExpanded ]); + break; + case "group": + switch (mode) { + // fallthrough + case MODE_FLAT: + if (!shouldRemeasure) { + cmds.push([ + ind, + doc.break ? MODE_BREAK : MODE_FLAT, + doc.contents + ]); break; + } + + case MODE_BREAK: + shouldRemeasure = false; + + const next = [ ind, MODE_FLAT, doc.contents ]; + let rem = w - pos; + + if (!doc.break && fits(next, cmds, rem)) { + cmds.push(next); } else { - for (var i = 1; i < doc.expandedStates.length + 1; i++) { - if (i >= doc.expandedStates.length) { + // Expanded states are a rare case where a document + // can manually provide multiple representations of + // itself. It provides an array of documents + // going from the least expanded (most flattened) + // representation first to the most expanded. If a + // group has these, we need to manually go through + // these states and find the first one that fits. + if (doc.expandedStates) { + const mostExpanded = doc.expandedStates[doc.expandedStates.length - + 1]; + + if (doc.break) { cmds.push([ ind, MODE_BREAK, mostExpanded ]); break; } else { - const state = doc.expandedStates[i]; - const cmd = [ ind, MODE_FLAT, state ]; + for (var i = 1; i < doc.expandedStates.length + 1; i++) { + if (i >= doc.expandedStates.length) { + cmds.push([ ind, MODE_BREAK, mostExpanded ]); - if (fits(cmd, cmds, rem)) { - cmds.push(cmd); + break; + } else { + const state = doc.expandedStates[i]; + const cmd = [ ind, MODE_FLAT, state ]; - break; + if (fits(cmd, cmds, rem)) { + cmds.push(cmd); + + break; + } + } } } + } else { + cmds.push([ ind, MODE_BREAK, doc.contents ]); } } - } else { - cmds.push([ ind, MODE_BREAK, doc.contents ]); - } + + break; + } + break; + case "if-break": + if (mode === MODE_BREAK) { + cmds.push([ ind, MODE_BREAK, doc.contents ]); } break; - } - break; - case "if-break": - if (mode === MODE_BREAK) { - cmds.push([ ind, MODE_BREAK, doc.contents ]); - } + case "line": + switch (mode) { + // fallthrough + case MODE_FLAT: + if (!doc.hard) { + if (!doc.soft) { + out.push(" "); - break; - case "line": - switch (mode) { - // fallthrough - case MODE_FLAT: - if (!doc.hard) { - if (!doc.soft) { - out.push(" "); + pos += 1; + } - pos += 1; - } + break; + } else { + // This line was forced into the output even if we + // were in flattened mode, so we need to tell the next + // group that no matter what, it needs to remeasure + // because the previous measurement didn't accurately + // capture the entire expression (this is necessary + // for nested groups) + shouldRemeasure = true; + } - break; - } else { - // This line was forced into the output even if we - // were in flattened mode, so we need to tell the next - // group that no matter what, it needs to remeasure - // because the previous measurement didn't accurately - // capture the entire expression (this is necessary - // for nested groups) - shouldRemeasure = true; + case MODE_BREAK: + if (out.length > 0) { + const lastString = out[out.length - 1]; + + if (lastString.match(/^\s*\n\s*$/)) { + out[out.length - 1] = "\n"; + } + } + + if (doc.literal) { + out.push("\n"); + + pos = 0; + } else { + out.push("\n" + _makeIndent(ind)); + + pos = ind; + } + + break; } - - case MODE_BREAK: - if (out.length > 0) { - const lastString = out[out.length - 1]; - - if (lastString.match(/^\s*\n\s*$/)) { - out[out.length - 1] = "\n"; - } - } - - if (doc.literal) { - out.push("\n"); - - pos = 0; - } else { - out.push("\n" + _makeIndent(ind)); - - pos = ind; - } - break; - } - break; - default: + default: } } } diff --git a/src/printer.js b/src/printer.js index 8600a0b4..f94d75f6 100644 --- a/src/printer.js +++ b/src/printer.js @@ -75,7 +75,11 @@ function Printer(originalOptions) { // Print the entire AST generically. function printGenerically(path) { - return printComments(path, p => genericPrint(p, options, printGenerically), options); + return printComments( + path, + p => genericPrint(p, options, printGenerically), + options + ); } this.print = function(ast) { @@ -193,382 +197,395 @@ function genericPrintNoParens(path, options, print) { // namedTypes.Printable.assert(n); var parts = []; switch (n.type) { - case "File": - return path.call(print, "program"); - case "Program": - // Babel 6 - if (n.directives) { - path.each( - function(childPath) { - parts.push(print(childPath), ";", hardline); - }, - "directives" + case "File": + return path.call(print, "program"); + case "Program": + // Babel 6 + if (n.directives) { + path.each( + function(childPath) { + parts.push(print(childPath), ";", hardline); + }, + "directives" + ); + } + + parts.push( + path.call( + function(bodyPath) { + return printStatementSequence(bodyPath, options, print); + }, + "body" + ) ); - } - parts.push( - path.call( - function(bodyPath) { - return printStatementSequence(bodyPath, options, print); - }, - "body" - ) - ); + parts.push(hardline); - parts.push(hardline); - - return concat(parts); - // Babel extension. - case "Noop": - case "EmptyStatement": - return fromString(""); - case "ExpressionStatement": - return concat([ path.call(print, "expression"), ";" ]); - case // Babel extension. - "ParenthesizedExpression": - return concat([ "(", path.call(print, "expression"), ")" ]); - case "AssignmentExpression": - return group( - concat([ + return concat(parts); + // Babel extension. + case "Noop": + case "EmptyStatement": + return fromString(""); + case "ExpressionStatement": + return concat([ path.call(print, "expression"), ";" ]); + case // Babel extension. + "ParenthesizedExpression": + return concat([ "(", path.call(print, "expression"), ")" ]); + case "AssignmentExpression": + return group( + concat([ + path.call(print, "left"), + " ", + n.operator, + " ", + path.call(print, "right") + ]) + ); + case "BinaryExpression": + case "LogicalExpression": + return group( + concat([ + path.call(print, "left"), + " ", + n.operator, + indent(options.tabWidth, concat([ line, path.call(print, "right") ])) + ]) + ); + case "AssignmentPattern": + return concat([ path.call(print, "left"), - " ", - n.operator, - " ", + " = ", path.call(print, "right") - ]) - ); - case "BinaryExpression": - case "LogicalExpression": - return group( - concat([ - path.call(print, "left"), - " ", - n.operator, - indent(options.tabWidth, concat([ line, path.call(print, "right") ])) - ]) - ); - case "AssignmentPattern": - return concat([ - path.call(print, "left"), - " = ", - path.call(print, "right") - ]); - case "MemberExpression": { + ]); + case "MemberExpression": { return concat([ path.call(print, "object"), printMemberLookup(path, print) ]); } - case "MetaProperty": - return concat([ - path.call(print, "meta"), - ".", - path.call(print, "property") - ]); - case "BindExpression": - if (n.object) { - parts.push(path.call(print, "object")); - } - - parts.push("::", path.call(print, "callee")); - - return concat(parts); - case "Path": - return join(".", n.body); - case "Identifier": - return concat([ - n.name, - n.optional ? "?" : "", - path.call(print, "typeAnnotation") - ]); - case "SpreadElement": - case "SpreadElementPattern": - // Babel 6 for ObjectPattern - case "RestProperty": - case "SpreadProperty": - case "SpreadPropertyPattern": - case "RestElement": - return concat([ - "...", - path.call(print, "argument"), - path.call(print, "typeAnnotation") - ]); - case "FunctionDeclaration": - case "FunctionExpression": - if (n.async) - parts.push("async "); - - parts.push("function"); - - if (n.generator) - parts.push("*"); - - if (n.id) { - parts.push(" ", path.call(print, "id")); - } - - parts.push( - path.call(print, "typeParameters"), - multilineGroup(concat([ - printFunctionParams(path, print, options), - printReturnType(path, print) - ])), - " ", - path.call(print, "body") - ); - - return concat(parts); - case "ArrowFunctionExpression": - if (n.async) - parts.push("async "); - - if (n.typeParameters) { - parts.push(path.call(print, "typeParameters")); - } - - if ( - n.params.length === 1 && !n.rest && - n.params[0].type === "Identifier" && - !n.params[0].typeAnnotation && - !n.predicate && - !n.returnType - ) { - parts.push(path.call(print, "params", 0)); - } else { - parts.push(multilineGroup(concat([ - printFunctionParams(path, print, options), - printReturnType(path, print) - ]))); - } - - parts.push(" =>"); - - const body = path.call(print, "body"); - const collapsed = concat([ concat(parts), " ", body ]); - - if (n.body.type === "JSXElement") { - return group(collapsed); - } - - return conditionalGroup([ - collapsed, - concat([ - concat(parts), - indent(options.tabWidth, concat([ line, body ])), - ]), - ]); - case "MethodDefinition": - if (n.static) { - parts.push("static "); - } - - parts.push(printMethod(path, options, print)); - - return concat(parts); - case "YieldExpression": - parts.push("yield"); - - if (n.delegate) - parts.push("*"); - - if (n.argument) - parts.push(" ", path.call(print, "argument")); - - return concat(parts); - case "AwaitExpression": - parts.push("await"); - - if (n.all) - parts.push("*"); - - if (n.argument) - parts.push(" ", path.call(print, "argument")); - - return concat(parts); - case "ModuleDeclaration": - parts.push("module", path.call(print, "id")); - - if (n.source) { - assert.ok(!n.body); - - parts.push("from", path.call(print, "source")); - } else { - parts.push(path.call(print, "body")); - } - - return join(" ", parts); - case "ImportSpecifier": - if (n.imported) { - parts.push(path.call(print, "imported")); - - if (n.local && n.local.name !== n.imported.name) { - parts.push(" as ", path.call(print, "local")); - } - } else if (n.id) { - parts.push(path.call(print, "id")); - - if (n.name) { - parts.push(" as ", path.call(print, "name")); - } - } - - return concat(parts); - case "ExportSpecifier": - if (n.local) { - parts.push(path.call(print, "local")); - - if (n.exported && n.exported.name !== n.local.name) { - parts.push(" as ", path.call(print, "exported")); - } - } else if (n.id) { - parts.push(path.call(print, "id")); - - if (n.name) { - parts.push(" as ", path.call(print, "name")); - } - } - - return concat(parts); - case "ExportBatchSpecifier": - return fromString("*"); - case "ImportNamespaceSpecifier": - parts.push("* as "); - - if (n.local) { - parts.push(path.call(print, "local")); - } else if (n.id) { - parts.push(path.call(print, "id")); - } - - return concat(parts); - case "ImportDefaultSpecifier": - if (n.local) { - return path.call(print, "local"); - } - - return path.call(print, "id"); - case "ExportDeclaration": - case "ExportDefaultDeclaration": - case "ExportNamedDeclaration": - return printExportDeclaration(path, options, print); - case "ExportAllDeclaration": - parts.push("export *"); - - if (n.exported) { - parts.push(" as ", path.call(print, "exported")); - } - - parts.push(" from ", path.call(print, "source"), ";"); - - return concat(parts); - case "ExportNamespaceSpecifier": - return concat([ "* as ", path.call(print, "exported") ]); - case "ExportDefaultSpecifier": - return path.call(print, "exported"); - case "ImportDeclaration": - parts.push("import "); - - if (n.importKind && n.importKind !== "value") { - parts.push(n.importKind + " "); - } - - if (n.specifiers && n.specifiers.length > 0) { - var standalones = []; - var grouped = []; - - path.each(function(specifierPath) { - var value = specifierPath.getValue(); - if ( - namedTypes.ImportDefaultSpecifier.check(value) || - namedTypes.ImportNamespaceSpecifier.check(value) - ) { - standalones.push(print(specifierPath)); - } else { - grouped.push(print(specifierPath)); - } - }, "specifiers"); - - assert.ok(standalones.length <= 1); - - if (standalones.length > 0) { - parts.push(standalones[0]); + case "MetaProperty": + return concat([ + path.call(print, "meta"), + ".", + path.call(print, "property") + ]); + case "BindExpression": + if (n.object) { + parts.push(path.call(print, "object")); } - if (standalones.length > 0 && grouped.length > 0) { - parts.push(", "); + parts.push("::", path.call(print, "callee")); + + return concat(parts); + case "Path": + return join(".", n.body); + case "Identifier": + return concat([ + n.name, + n.optional ? "?" : "", + path.call(print, "typeAnnotation") + ]); + case "SpreadElement": + case "SpreadElementPattern": + // Babel 6 for ObjectPattern + case "RestProperty": + case "SpreadProperty": + case "SpreadPropertyPattern": + case "RestElement": + return concat([ + "...", + path.call(print, "argument"), + path.call(print, "typeAnnotation") + ]); + case "FunctionDeclaration": + case "FunctionExpression": + if (n.async) + parts.push("async "); + + parts.push("function"); + + if (n.generator) + parts.push("*"); + + if (n.id) { + parts.push(" ", path.call(print, "id")); } - if (grouped.length > 0) { + parts.push( + path.call(print, "typeParameters"), + multilineGroup( + concat([ + printFunctionParams(path, print, options), + printReturnType(path, print) + ]) + ), + " ", + path.call(print, "body") + ); + + return concat(parts); + case "ArrowFunctionExpression": + if (n.async) + parts.push("async "); + + if (n.typeParameters) { + parts.push(path.call(print, "typeParameters")); + } + + if ( + n.params.length === 1 && !n.rest && + n.params[(0)].type === "Identifier" && + !n.params[(0)].typeAnnotation && + !n.predicate && + !n.returnType + ) { + parts.push(path.call(print, "params", 0)); + } else { parts.push( - group(concat([ - "{", - indent( - options.tabWidth, - concat([ - options.bracketSpacing ? line : softline, - join(concat([",", options.bracketSpacing ? line : softline]), - grouped) - ]) - ), - ifBreak(options.trailingComma ? "," : ""), - options.bracketSpacing ? line : softline, - "}", - ])) + multilineGroup( + concat([ + printFunctionParams(path, print, options), + printReturnType(path, print) + ]) + ) ); } - parts.push(" from "); - } + parts.push(" =>"); - parts.push(path.call(print, "source"), ";"); + const body = path.call(print, "body"); + const collapsed = concat([ concat(parts), " ", body ]); - return concat(parts); - case "BlockStatement": - var naked = path.call( - function(bodyPath) { - return printStatementSequence(bodyPath, options, print); - }, - "body" - ); + if (n.body.type === "JSXElement") { + return group(collapsed); + } - // If there are no contents, return a simple block - if (!getFirstString(naked)) { - return "{}"; - } + return conditionalGroup([ + collapsed, + concat([ + concat(parts), + indent(options.tabWidth, concat([ line, body ])) + ]) + ]); + case "MethodDefinition": + if (n.static) { + parts.push("static "); + } - parts.push("{"); + parts.push(printMethod(path, options, print)); - // Babel 6 - if (n.directives) { - path.each( - function(childPath) { + return concat(parts); + case "YieldExpression": + parts.push("yield"); + + if (n.delegate) + parts.push("*"); + + if (n.argument) + parts.push(" ", path.call(print, "argument")); + + return concat(parts); + case "AwaitExpression": + parts.push("await"); + + if (n.all) + parts.push("*"); + + if (n.argument) + parts.push(" ", path.call(print, "argument")); + + return concat(parts); + case "ModuleDeclaration": + parts.push("module", path.call(print, "id")); + + if (n.source) { + assert.ok(!n.body); + + parts.push("from", path.call(print, "source")); + } else { + parts.push(path.call(print, "body")); + } + + return join(" ", parts); + case "ImportSpecifier": + if (n.imported) { + parts.push(path.call(print, "imported")); + + if (n.local && n.local.name !== n.imported.name) { + parts.push(" as ", path.call(print, "local")); + } + } else if (n.id) { + parts.push(path.call(print, "id")); + + if (n.name) { + parts.push(" as ", path.call(print, "name")); + } + } + + return concat(parts); + case "ExportSpecifier": + if (n.local) { + parts.push(path.call(print, "local")); + + if (n.exported && n.exported.name !== n.local.name) { + parts.push(" as ", path.call(print, "exported")); + } + } else if (n.id) { + parts.push(path.call(print, "id")); + + if (n.name) { + parts.push(" as ", path.call(print, "name")); + } + } + + return concat(parts); + case "ExportBatchSpecifier": + return fromString("*"); + case "ImportNamespaceSpecifier": + parts.push("* as "); + + if (n.local) { + parts.push(path.call(print, "local")); + } else if (n.id) { + parts.push(path.call(print, "id")); + } + + return concat(parts); + case "ImportDefaultSpecifier": + if (n.local) { + return path.call(print, "local"); + } + + return path.call(print, "id"); + case "ExportDeclaration": + case "ExportDefaultDeclaration": + case "ExportNamedDeclaration": + return printExportDeclaration(path, options, print); + case "ExportAllDeclaration": + parts.push("export *"); + + if (n.exported) { + parts.push(" as ", path.call(print, "exported")); + } + + parts.push(" from ", path.call(print, "source"), ";"); + + return concat(parts); + case "ExportNamespaceSpecifier": + return concat([ "* as ", path.call(print, "exported") ]); + case "ExportDefaultSpecifier": + return path.call(print, "exported"); + case "ImportDeclaration": + parts.push("import "); + + if (n.importKind && n.importKind !== "value") { + parts.push(n.importKind + " "); + } + + if (n.specifiers && n.specifiers.length > 0) { + var standalones = []; + var grouped = []; + + path.each( + function(specifierPath) { + var value = specifierPath.getValue(); + if ( + namedTypes.ImportDefaultSpecifier.check(value) || + namedTypes.ImportNamespaceSpecifier.check(value) + ) { + standalones.push(print(specifierPath)); + } else { + grouped.push(print(specifierPath)); + } + }, + "specifiers" + ); + + assert.ok(standalones.length <= 1); + + if (standalones.length > 0) { + parts.push(standalones[(0)]); + } + + if (standalones.length > 0 && grouped.length > 0) { + parts.push(", "); + } + + if (grouped.length > 0) { parts.push( - indent( - options.tabWidth, - concat([ hardline, print(childPath), ";", hardline ]) + group( + concat([ + "{", + indent( + options.tabWidth, + concat([ + options.bracketSpacing ? line : softline, + join( + concat([ ",", options.bracketSpacing ? line : softline ]), + grouped + ) + ]) + ), + ifBreak(options.trailingComma ? "," : ""), + options.bracketSpacing ? line : softline, + "}" + ]) ) ); + } + + parts.push(" from "); + } + + parts.push(path.call(print, "source"), ";"); + + return concat(parts); + case "BlockStatement": + var naked = path.call( + function(bodyPath) { + return printStatementSequence(bodyPath, options, print); }, - "directives" + "body" ); - } - parts.push(indent(options.tabWidth, concat([ hardline, naked ]))); + // If there are no contents, return a simple block + if (!getFirstString(naked)) { + return "{}"; + } - parts.push(hardline, "}"); + parts.push("{"); - return concat(parts); - case "ReturnStatement": - parts.push("return"); + // Babel 6 + if (n.directives) { + path.each( + function(childPath) { + parts.push( + indent( + options.tabWidth, + concat([ hardline, print(childPath), ";", hardline ]) + ) + ); + }, + "directives" + ); + } - if (n.argument) { - parts.push(" ", path.call(print, "argument")); - } + parts.push(indent(options.tabWidth, concat([ hardline, naked ]))); - parts.push(";"); + parts.push(hardline, "}"); - return concat(parts); - case "CallExpression": { + return concat(parts); + case "ReturnStatement": + parts.push("return"); + + if (n.argument) { + parts.push(" ", path.call(print, "argument")); + } + + parts.push(";"); + + return concat(parts); + case "CallExpression": { const parent = path.getParentNode(); // We detect calls on member lookups and possibly print them in a // special chain format. See `printMemberChain` for more info. @@ -585,873 +602,890 @@ function genericPrintNoParens(path, options, print) { ]); } - case "ObjectExpression": - case "ObjectPattern": - case "ObjectTypeAnnotation": - var allowBreak = false; - var isTypeAnnotation = n.type === "ObjectTypeAnnotation"; - // Leave this here because we *might* want to make this - // configurable later -- flow accepts ";" for type separators - var separator = isTypeAnnotation ? "," : ","; - var fields = []; - var leftBrace = n.exact ? "{|" : "{"; - var rightBrace = n.exact ? "|}" : "}"; + case "ObjectExpression": + case "ObjectPattern": + case "ObjectTypeAnnotation": + var allowBreak = false; + var isTypeAnnotation = n.type === "ObjectTypeAnnotation"; + // Leave this here because we *might* want to make this + // configurable later -- flow accepts ";" for type separators + var separator = isTypeAnnotation ? "," : ","; + var fields = []; + var leftBrace = n.exact ? "{|" : "{"; + var rightBrace = n.exact ? "|}" : "}"; - if (isTypeAnnotation) { - fields.push("indexers", "callProperties"); - } - - fields.push("properties"); - - var i = 0; - var props = []; - - fields.forEach(function(field) { - path.each( - function(childPath) { - props.push(group(print(childPath))); - }, - field - ); - }); - - if (props.length === 0) { - return "{}"; - } else { - return multilineGroup( - concat([ - leftBrace, - indent( - options.tabWidth, - concat([ - options.bracketSpacing ? line : softline, - join(concat([ separator, line ]), props) - ]) - ), - ifBreak(options.trailingComma ? "," : ""), - options.bracketSpacing ? line : softline, - rightBrace, - path.call(print, "typeAnnotation") - ]) - ); - } - - case "PropertyPattern": - return concat([ - path.call(print, "key"), - ": ", - path.call(print, "pattern") - ]); - // Babel 6 - case "ObjectProperty": - case // Non-standard AST node type. - "Property": - if (n.method || n.kind === "get" || n.kind === "set") { - return printMethod(path, options, print); - } - - if (n.shorthand) { - parts.push(path.call(print, "value")); - } else { - if (n.computed) { - parts.push("[", path.call(print, "key"), "]"); - } else { - parts.push(printPropertyKey(path, print)); + if (isTypeAnnotation) { + fields.push("indexers", "callProperties"); } - parts.push(": ", path.call(print, "value")); - } - return concat(parts); - case // Babel 6 - "ClassMethod": - if (n.static) { - parts.push("static "); - } + fields.push("properties"); - parts = parts.concat(printObjectMethod(path, options, print)); + var i = 0; + var props = []; - return concat(parts); - case // Babel 6 - "ObjectMethod": - return printObjectMethod(path, options, print); - case "Decorator": - return concat([ "@", path.call(print, "expression") ]); - case "ArrayExpression": - case "ArrayPattern": - if (n.elements.length === 0) { - parts.push("[]"); - } else { - parts.push( - multilineGroup( + fields.forEach(function(field) { + path.each( + function(childPath) { + props.push(group(print(childPath))); + }, + field + ); + }); + + if (props.length === 0) { + return "{}"; + } else { + return multilineGroup( concat([ - "[", + leftBrace, indent( options.tabWidth, concat([ options.bracketSpacing ? line : softline, - join(concat([ ",", line ]), path.map(print, "elements")) + join(concat([ separator, line ]), props) ]) ), ifBreak(options.trailingComma ? "," : ""), options.bracketSpacing ? line : softline, - "]" + rightBrace, + path.call(print, "typeAnnotation") ]) - ) - ); - } - - if (n.typeAnnotation) - parts.push(path.call(print, "typeAnnotation")); - - return concat(parts); - case "SequenceExpression": - return join(", ", path.map(print, "expressions")); - case "ThisExpression": - return fromString("this"); - case "Super": - return fromString("super"); - case // Babel 6 Literal split - "NullLiteral": - return fromString("null"); - case // Babel 6 Literal split - "RegExpLiteral": - return fromString(n.extra.raw); - // Babel 6 Literal split - case "BooleanLiteral": - // Babel 6 Literal split - case "NumericLiteral": - // Babel 6 Literal split - case "StringLiteral": - case "Literal": - if (typeof n.value !== "string") - return fromString(n.value, options); - - return nodeStr(n.value, options); - case // Babel 6 - "Directive": - return path.call(print, "value"); - case // Babel 6 - "DirectiveLiteral": - return fromString(nodeStr(n.value, options)); - case "ModuleSpecifier": - if (n.local) { - throw new Error("The ESTree ModuleSpecifier type should be abstract"); - } - - // The Esprima ModuleSpecifier type is just a string-valued - // Literal identifying the imported-from module. - return fromString(nodeStr(n.value, options), options); - case "UnaryExpression": - parts.push(n.operator); - - if (/[a-z]$/.test(n.operator)) - parts.push(" "); - - parts.push(path.call(print, "argument")); - - return concat(parts); - case "UpdateExpression": - parts.push(path.call(print, "argument"), n.operator); - - if (n.prefix) - parts.reverse(); - - return concat(parts); - case "ConditionalExpression": - return group( - concat([ - path.call(print, "test"), - indent( - options.tabWidth, - concat([ - line, - "? ", - path.call(print, "consequent"), - line, - ": ", - path.call(print, "alternate") - ]) - ) - ]) - ); - case "NewExpression": - parts.push("new ", path.call(print, "callee")); - - var args = n.arguments; - - if (args) { - parts.push(printArgumentsList(path, options, print)); - } - - return concat(parts); - case "VariableDeclaration": - var printed = path.map( - function(childPath) { - return print(childPath); - }, - "declarations" - ); - - parts = [ - n.kind, - " ", - printed[0], - indent( - options.tabWidth, - concat(printed.slice(1).map(p => concat([ ",", line, p ]))) - ) - ]; - - // We generally want to terminate all variable declarations with a - // semicolon, except when they are children of for loops. - var parentNode = path.getParentNode(); - - if ( - !namedTypes.ForStatement.check(parentNode) && - !namedTypes.ForInStatement.check(parentNode) && - !(namedTypes.ForOfStatement && - namedTypes.ForOfStatement.check(parentNode)) && - !(namedTypes.ForAwaitStatement && - namedTypes.ForAwaitStatement.check(parentNode)) - ) { - parts.push(";"); - } - - return multilineGroup(concat(parts)); - case "VariableDeclarator": - return n.init - ? concat([ path.call(print, "id"), " = ", path.call(print, "init") ]) - : path.call(print, "id"); - case "WithStatement": - return concat([ - "with (", - path.call(print, "object"), - ") ", - path.call(print, "body") - ]); - case "IfStatement": - const con = adjustClause(path.call(print, "consequent"), options); - - parts = [ - "if (", - group( - concat([ - indent( - options.tabWidth, - concat([ softline, path.call(print, "test") ]) - ), - softline - ]) - ), - ")", - con - ]; - - if (n.alternate) { - const hasBraces = isCurlyBracket(con); - const isEmpty = isEmptyBlock(con); - - if (hasBraces && !isEmpty) { - parts.push(" else"); - } else { - parts.push(concat([ hardline, "else" ])); + ); } - parts.push( - adjustClause( - path.call(print, "alternate"), - options, - n.alternate.type === "IfStatement" - ) - ); - } - - return group(concat(parts)); - case "ForStatement": { - const body = adjustClause(path.call(print, "body"), options); - - if (!n.init && !n.test && !n.update) { + case "PropertyPattern": return concat([ - 'for (;;)', - body, + path.call(print, "key"), + ": ", + path.call(print, "pattern") ]); - } + // Babel 6 + case "ObjectProperty": + case // Non-standard AST node type. + "Property": + if (n.method || n.kind === "get" || n.kind === "set") { + return printMethod(path, options, print); + } - return concat([ - "for (", - group( + if (n.shorthand) { + parts.push(path.call(print, "value")); + } else { + if (n.computed) { + parts.push("[", path.call(print, "key"), "]"); + } else { + parts.push(printPropertyKey(path, print)); + } + parts.push(": ", path.call(print, "value")); + } + + return concat(parts); + case // Babel 6 + "ClassMethod": + if (n.static) { + parts.push("static "); + } + + parts = parts.concat(printObjectMethod(path, options, print)); + + return concat(parts); + case // Babel 6 + "ObjectMethod": + return printObjectMethod(path, options, print); + case "Decorator": + return concat([ "@", path.call(print, "expression") ]); + case "ArrayExpression": + case "ArrayPattern": + if (n.elements.length === 0) { + parts.push("[]"); + } else { + parts.push( + multilineGroup( + concat([ + "[", + indent( + options.tabWidth, + concat([ + options.bracketSpacing ? line : softline, + join(concat([ ",", line ]), path.map(print, "elements")) + ]) + ), + ifBreak(options.trailingComma ? "," : ""), + options.bracketSpacing ? line : softline, + "]" + ]) + ) + ); + } + + if (n.typeAnnotation) + parts.push(path.call(print, "typeAnnotation")); + + return concat(parts); + case "SequenceExpression": + return join(", ", path.map(print, "expressions")); + case "ThisExpression": + return fromString("this"); + case "Super": + return fromString("super"); + case // Babel 6 Literal split + "NullLiteral": + return fromString("null"); + case // Babel 6 Literal split + "RegExpLiteral": + return fromString(n.extra.raw); + // Babel 6 Literal split + case "BooleanLiteral": + // Babel 6 Literal split + case "NumericLiteral": + // Babel 6 Literal split + case "StringLiteral": + case "Literal": + if (typeof n.value !== "string") + return fromString(n.value, options); + + return nodeStr(n.value, options); + case // Babel 6 + "Directive": + return path.call(print, "value"); + case // Babel 6 + "DirectiveLiteral": + return fromString(nodeStr(n.value, options)); + case "ModuleSpecifier": + if (n.local) { + throw new Error("The ESTree ModuleSpecifier type should be abstract"); + } + + // The Esprima ModuleSpecifier type is just a string-valued + // Literal identifying the imported-from module. + return fromString(nodeStr(n.value, options), options); + case "UnaryExpression": + parts.push(n.operator); + + if (/[a-z]$/.test(n.operator)) + parts.push(" "); + + parts.push(path.call(print, "argument")); + + return concat(parts); + case "UpdateExpression": + parts.push(path.call(print, "argument"), n.operator); + + if (n.prefix) + parts.reverse(); + + return concat(parts); + case "ConditionalExpression": + return group( concat([ + path.call(print, "test"), indent( options.tabWidth, concat([ - softline, - path.call(print, "init"), - ";", line, - path.call(print, "test"), - ";", + "? ", + path.call(print, "consequent"), line, - path.call(print, "update") + ": ", + path.call(print, "alternate") ]) - ), - softline - ]) - ), - ")", - body, - ]); - } - case "WhileStatement": - return concat([ - "while (", - path.call(print, "test"), - ")", - adjustClause(path.call(print, "body"), options) - ]); - case "ForInStatement": - // Note: esprima can't actually parse "for each (". - return concat([ - n.each ? "for each (" : "for (", - path.call(print, "left"), - " in ", - path.call(print, "right"), - ")", - adjustClause(path.call(print, "body"), options) - ]); - case "ForOfStatement": - return concat([ - "for (", - path.call(print, "left"), - " of ", - path.call(print, "right"), - ")", - adjustClause(path.call(print, "body"), options) - ]); - case "ForAwaitStatement": - return concat([ - "for await (", - path.call(print, "left"), - " of ", - path.call(print, "right"), - ")", - adjustClause(path.call(print, "body"), options) - ]); - case "DoWhileStatement": - var clause = adjustClause(path.call(print, "body"), options); - var doBody = concat([ "do", clause ]); - var parts = [ doBody ]; - const hasBraces = isCurlyBracket(clause); - - if (hasBraces) - parts.push(" while"); - else - parts.push(concat([ line, "while" ])); - - parts.push(" (", path.call(print, "test"), ");"); - - return concat(parts); - case "DoExpression": - var statements = path.call( - function(bodyPath) { - return printStatementSequence(bodyPath, options, print); - }, - "body" - ); - return concat([ "do {\n", statements.indent(options.tabWidth), "\n}" ]); - case "BreakStatement": - parts.push("break"); - - if (n.label) - parts.push(" ", path.call(print, "label")); - - parts.push(";"); - - return concat(parts); - case "ContinueStatement": - parts.push("continue"); - - if (n.label) - parts.push(" ", path.call(print, "label")); - - parts.push(";"); - - return concat(parts); - case "LabeledStatement": - return concat([ - path.call(print, "label"), - ":", - hardline, - path.call(print, "body") - ]); - case "TryStatement": - parts.push("try ", path.call(print, "block")); - - if (n.handler) { - parts.push(" ", path.call(print, "handler")); - } else if (n.handlers) { - path.each( - function(handlerPath) { - parts.push(" ", print(handlerPath)); - }, - "handlers" - ); - } - - if (n.finalizer) { - parts.push(" finally ", path.call(print, "finalizer")); - } - - return concat(parts); - case "CatchClause": - parts.push("catch (", path.call(print, "param")); - - if (n.guard) - // Note: esprima does not recognize conditional catch clauses. - parts.push(" if ", path.call(print, "guard")); - - parts.push(") ", path.call(print, "body")); - - return concat(parts); - case "ThrowStatement": - return concat([ "throw ", path.call(print, "argument"), ";" ]); - // Note: ignoring n.lexical because it has no printing consequences. - case "SwitchStatement": - return concat([ - "switch (", - path.call(print, "discriminant"), - ") {", - indent( - options.tabWidth, - concat([ hardline, join(hardline, path.map(print, "cases"))]) - ), - hardline, - "}" - ]); - case "SwitchCase": - if (n.test) - parts.push("case ", path.call(print, "test"), ":"); - else - parts.push("default:"); - - if (n.consequent.length > 0) { - const cons = path.call( - function(consequentPath) { - return printStatementSequence(consequentPath, options, print); - }, - "consequent" - ); - - parts.push( - isCurlyBracket(cons) - ? concat([ " ", cons ]) - : indent(options.tabWidth, concat([ hardline, cons ])) - ); - } - - return concat(parts); - // JSX extensions below. - case "DebuggerStatement": - return fromString("debugger;"); - case "JSXAttribute": - parts.push(path.call(print, "name")); - - if (n.value) { - let res; - if ( - (n.value.type === 'StringLiteral' || n.value.type === 'Literal') && - typeof n.value.value === 'string' - ) { - res = '"' + util.htmlEscapeInsideDoubleQuote(n.value.value) + '"'; - } else { - res = path.call(print, "value"); - } - parts.push("=", res); - } - - return concat(parts); - case "JSXIdentifier": - return fromString(n.name, options); - case "JSXNamespacedName": - return join(":", [ path.call(print, "namespace"), path.call(print, "name") ]); - case "JSXMemberExpression": - return join(".", [ path.call(print, "object"), path.call(print, "property") ]); - case "JSXSpreadAttribute": - return concat([ "{...", path.call(print, "argument"), "}" ]); - case "JSXExpressionContainer": - return group(concat([ - "{", - indent(options.tabWidth, - concat([softline, path.call(print, "expression")])), - softline, - "}" - ])); - case "JSXElement": - return printJSXElement(path, options, print); - case "JSXOpeningElement": - return group( - concat([ - "<", - path.call(print, "name"), - multilineGroup(concat([ - indent(options.tabWidth, - concat(path.map(attr => concat([line, print(attr)]), "attributes")) - ), - n.selfClosing ? line : softline, - ])), - n.selfClosing ? "/>" : ">" - ]) - ); - case "JSXClosingElement": - return concat([ "" ]); - case "JSXText": - throw new Error("JSXTest should be handled by JSXElement"); - case "JSXEmptyExpression": - return ""; - case "TypeAnnotatedIdentifier": - return concat([ - path.call(print, "annotation"), - " ", - path.call(print, "identifier") - ]); - case "ClassBody": - if (n.body.length === 0) { - return fromString("{}"); - } - - return concat([ - "{", - indent( - options.tabWidth, - concat([ - hardline, - path.call( - function(bodyPath) { - return printStatementSequence(bodyPath, options, print); - }, - "body" ) ]) - ), - hardline, - "}" - ]); - case "ClassPropertyDefinition": - parts.push("static ", path.call(print, "definition")); + ); + case "NewExpression": + parts.push("new ", path.call(print, "callee")); - if (!namedTypes.MethodDefinition.check(n.definition)) - parts.push(";"); + var args = n.arguments; - return concat(parts); - case "ClassProperty": - if (n.static) - parts.push("static "); - - var key; - - if (n.computed) { - key = concat([ "[", path.call(print, "key"), "]" ]); - } else { - key = printPropertyKey(path, print); - if (n.variance === "plus") { - key = concat([ "+", key ]); - } else if (n.variance === "minus") { - key = concat([ "-", key ]); + if (args) { + parts.push(printArgumentsList(path, options, print)); } - } - - parts.push(key); - - if (n.typeAnnotation) - parts.push(path.call(print, "typeAnnotation")); - - if (n.value) - parts.push(" = ", path.call(print, "value")); - - parts.push(";"); - - return concat(parts); - case "ClassDeclaration": - case "ClassExpression": - return concat(printClass(path, print)); - case "TemplateElement": - return join(literalline, n.value.raw.split("\n")); - case "TemplateLiteral": - var expressions = path.map(print, "expressions"); - - parts.push("`"); - - path.each( - function(childPath) { - var i = childPath.getName(); - - parts.push(print(childPath)); - - if (i < expressions.length) { - parts.push("${", expressions[i], "}"); - } - }, - "quasis" - ); - - parts.push("`"); - - return concat(parts); - // These types are unprintable because they serve as abstract - // supertypes for other (printable) types. - case "TaggedTemplateExpression": - return concat([ path.call(print, "tag"), path.call(print, "quasi") ]); - case "Node": - case "Printable": - case "SourceLocation": - case "Position": - case "Statement": - case "Function": - case "Pattern": - case "Expression": - case "Declaration": - case "Specifier": - case "NamedSpecifier": - // Supertype of Block and Line. - case "Comment": - // Flow - case "MemberTypeAnnotation": - case // Flow - "Type": - throw new Error("unprintable type: " + JSON.stringify(n.type)); - // Babel block comment. - case "CommentBlock": - case // Esprima block comment. - "Block": - return concat([ "/*", n.value, "*/" ]); - // Babel line comment. - case "CommentLine": - case // Esprima line comment. - "Line": - return concat([ "//", n.value ]); - // Type Annotations for Facebook Flow, typically stripped out or - // transformed away before printing. - case "TypeAnnotation": - if (n.typeAnnotation) { - if (n.typeAnnotation.type !== "FunctionTypeAnnotation") { - parts.push(": "); - } - - parts.push(path.call(print, "typeAnnotation")); return concat(parts); - } - - return ""; - case "TupleTypeAnnotation": - return concat([ "[", join(", ", path.map(print, "types")), "]" ]); - case "ExistentialTypeParam": - case "ExistsTypeAnnotation": - return fromString("*", options); - case "EmptyTypeAnnotation": - return fromString("empty", options); - case "AnyTypeAnnotation": - return fromString("any", options); - case "MixedTypeAnnotation": - return fromString("mixed", options); - case "ArrayTypeAnnotation": - return concat([ path.call(print, "elementType"), "[]" ]); - case "BooleanTypeAnnotation": - return fromString("boolean", options); - case "NumericLiteralTypeAnnotation": - case "BooleanLiteralTypeAnnotation": - return "" + n.value; - case "DeclareClass": - return printFlowDeclaration(path, printClass(path, print)); - case "DeclareFunction": - return printFlowDeclaration(path, [ - "function ", - path.call(print, "id"), - n.predicate ? " " : "", - path.call(print, "predicate"), - ";" - ]); - case "DeclareModule": - return printFlowDeclaration(path, [ - "module ", - path.call(print, "id"), - " ", - path.call(print, "body") - ]); - case "DeclareModuleExports": - return printFlowDeclaration(path, [ - "module.exports", - path.call(print, "typeAnnotation"), - ";" - ]); - case "DeclareVariable": - return printFlowDeclaration(path, [ "var ", path.call(print, "id"), ";" ]); - case "DeclareExportAllDeclaration": - return concat([ "declare export * from ", path.call(print, "source") ]); - case "DeclareExportDeclaration": - return concat([ "declare ", printExportDeclaration(path, options, print) ]); - case "FunctionTypeAnnotation": - // FunctionTypeAnnotation is ambiguous: - // declare function foo(a: B): void; OR - // var A: (a: B) => void; - var parent = path.getParentNode(0); - var isArrowFunctionTypeAnnotation = !(!parent.variance && - !parent.optional && - namedTypes.ObjectTypeProperty.check(parent) || - namedTypes.ObjectTypeCallProperty.check(parent) || - namedTypes.DeclareFunction.check(path.getParentNode(2))); - var needsColon = isArrowFunctionTypeAnnotation && - namedTypes.TypeAnnotation.check(parent); - - if (needsColon) { - parts.push(": "); - } - - parts.push(path.call(print, "typeParameters")); - - parts.push(multilineGroup(printFunctionParams(path, print, options))); - - // The returnType is not wrapped in a TypeAnnotation, so the colon - // needs to be added separately. - if (n.returnType || n.predicate) { - parts.push( - isArrowFunctionTypeAnnotation ? " => " : ": ", - path.call(print, "returnType"), - path.call(print, "predicate") + case "VariableDeclaration": + var printed = path.map( + function(childPath) { + return print(childPath); + }, + "declarations" ); - } - return concat(parts); - case "FunctionTypeParam": - return concat([ - path.call(print, "name"), - n.optional ? "?" : "", - n.name ? ": " : "", - path.call(print, "typeAnnotation") - ]); - case "GenericTypeAnnotation": - return concat([ - path.call(print, "id"), - path.call(print, "typeParameters") - ]); - case "DeclareInterface": - parts.push("declare "); + parts = [ + n.kind, + " ", + printed[(0)], + indent( + options.tabWidth, + concat(printed.slice(1).map(p => concat([ ",", line, p ]))) + ) + ]; - case "InterfaceDeclaration": - parts.push( - fromString("interface ", options), - path.call(print, "id"), - path.call(print, "typeParameters"), - " " - ); + // We generally want to terminate all variable declarations with a + // semicolon, except when they are children of for loops. + var parentNode = path.getParentNode(); - if (n["extends"].length > 0) { - parts.push("extends ", join(", ", path.map(print, "extends"))); - } + if ( + !namedTypes.ForStatement.check(parentNode) && + !namedTypes.ForInStatement.check(parentNode) && + !(namedTypes.ForOfStatement && + namedTypes.ForOfStatement.check(parentNode)) && + !(namedTypes.ForAwaitStatement && + namedTypes.ForAwaitStatement.check(parentNode)) + ) { + parts.push(";"); + } - parts.push(" ", path.call(print, "body")); + return multilineGroup(concat(parts)); + case "VariableDeclarator": + return n.init + ? concat([ path.call(print, "id"), " = ", path.call(print, "init") ]) + : path.call(print, "id"); + case "WithStatement": + return concat([ + "with (", + path.call(print, "object"), + ") ", + path.call(print, "body") + ]); + case "IfStatement": + const con = adjustClause(path.call(print, "consequent"), options); - return concat(parts); - case "ClassImplements": - case "InterfaceExtends": - return concat([ - path.call(print, "id"), - path.call(print, "typeParameters") - ]); - case "IntersectionTypeAnnotation": - case "UnionTypeAnnotation": { - const types = path.map(print, "types"); - const op = n.type === "IntersectionTypeAnnotation" ? "&" : "|"; + parts = [ + "if (", + group( + concat([ + indent( + options.tabWidth, + concat([ softline, path.call(print, "test") ]) + ), + softline + ]) + ), + ")", + con + ]; - return conditionalGroup( - [ - // single-line variation - // A | B | C + if (n.alternate) { + const hasBraces = isCurlyBracket(con); + const isEmpty = isEmptyBlock(con); + + if (hasBraces && !isEmpty) { + parts.push(" else"); + } else { + parts.push(concat([ hardline, "else" ])); + } + + parts.push( + adjustClause( + path.call(print, "alternate"), + options, + n.alternate.type === "IfStatement" + ) + ); + } + + return group(concat(parts)); + case "ForStatement": { + const body = adjustClause(path.call(print, "body"), options); + + if (!n.init && !n.test && !n.update) { + return concat([ "for (;;)", body ]); + } + + return concat([ + "for (", + group( concat([ indent( options.tabWidth, concat([ - types[0], - indent( - options.tabWidth, - concat(types.slice(1).map(t => concat([ " ", op, line, t ]))) - ) + softline, + path.call(print, "init"), + ";", + line, + path.call(print, "test"), + ";", + line, + path.call(print, "update") ]) - ) - ]), - // multi-line variation - // | A - // | B - // | C + ), + softline + ]) + ), + ")", + body + ]); + } + case "WhileStatement": + return concat([ + "while (", + path.call(print, "test"), + ")", + adjustClause(path.call(print, "body"), options) + ]); + case "ForInStatement": + // Note: esprima can't actually parse "for each (". + return concat([ + n.each ? "for each (" : "for (", + path.call(print, "left"), + " in ", + path.call(print, "right"), + ")", + adjustClause(path.call(print, "body"), options) + ]); + case "ForOfStatement": + return concat([ + "for (", + path.call(print, "left"), + " of ", + path.call(print, "right"), + ")", + adjustClause(path.call(print, "body"), options) + ]); + case "ForAwaitStatement": + return concat([ + "for await (", + path.call(print, "left"), + " of ", + path.call(print, "right"), + ")", + adjustClause(path.call(print, "body"), options) + ]); + case "DoWhileStatement": + var clause = adjustClause(path.call(print, "body"), options); + var doBody = concat([ "do", clause ]); + var parts = [ doBody ]; + const hasBraces = isCurlyBracket(clause); + + if (hasBraces) + parts.push(" while"); + else + parts.push(concat([ line, "while" ])); + + parts.push(" (", path.call(print, "test"), ");"); + + return concat(parts); + case "DoExpression": + var statements = path.call( + function(bodyPath) { + return printStatementSequence(bodyPath, options, print); + }, + "body" + ); + return concat([ "do {\n", statements.indent(options.tabWidth), "\n}" ]); + case "BreakStatement": + parts.push("break"); + + if (n.label) + parts.push(" ", path.call(print, "label")); + + parts.push(";"); + + return concat(parts); + case "ContinueStatement": + parts.push("continue"); + + if (n.label) + parts.push(" ", path.call(print, "label")); + + parts.push(";"); + + return concat(parts); + case "LabeledStatement": + return concat([ + path.call(print, "label"), + ":", + hardline, + path.call(print, "body") + ]); + case "TryStatement": + parts.push("try ", path.call(print, "block")); + + if (n.handler) { + parts.push(" ", path.call(print, "handler")); + } else if (n.handlers) { + path.each( + function(handlerPath) { + parts.push(" ", print(handlerPath)); + }, + "handlers" + ); + } + + if (n.finalizer) { + parts.push(" finally ", path.call(print, "finalizer")); + } + + return concat(parts); + case "CatchClause": + parts.push("catch (", path.call(print, "param")); + + if (n.guard) + // Note: esprima does not recognize conditional catch clauses. + parts.push(" if ", path.call(print, "guard")); + + parts.push(") ", path.call(print, "body")); + + return concat(parts); + case "ThrowStatement": + return concat([ "throw ", path.call(print, "argument"), ";" ]); + // Note: ignoring n.lexical because it has no printing consequences. + case "SwitchStatement": + return concat([ + "switch (", + path.call(print, "discriminant"), + ") {", + indent( + options.tabWidth, + concat([ hardline, join(hardline, path.map(print, "cases")) ]) + ), + hardline, + "}" + ]); + case "SwitchCase": + if (n.test) + parts.push("case ", path.call(print, "test"), ":"); + else + parts.push("default:"); + + if (n.consequent.length > 0) { + const cons = path.call( + function(consequentPath) { + return printStatementSequence(consequentPath, options, print); + }, + "consequent" + ); + + parts.push( + isCurlyBracket(cons) + ? concat([ " ", cons ]) + : indent(options.tabWidth, concat([ hardline, cons ])) + ); + } + + return concat(parts); + // JSX extensions below. + case "DebuggerStatement": + return fromString("debugger;"); + case "JSXAttribute": + parts.push(path.call(print, "name")); + + if (n.value) { + let res; + if ( + (n.value.type === "StringLiteral" || n.value.type === "Literal") && + typeof n.value.value === "string" + ) { + res = '"' + util.htmlEscapeInsideDoubleQuote(n.value.value) + '"'; + } else { + res = path.call(print, "value"); + } + parts.push("=", res); + } + + return concat(parts); + case "JSXIdentifier": + return fromString(n.name, options); + case "JSXNamespacedName": + return join(":", [ + path.call(print, "namespace"), + path.call(print, "name") + ]); + case "JSXMemberExpression": + return join(".", [ + path.call(print, "object"), + path.call(print, "property") + ]); + case "JSXSpreadAttribute": + return concat([ "{...", path.call(print, "argument"), "}" ]); + case "JSXExpressionContainer": + return group( + concat([ + "{", + indent( + options.tabWidth, + concat([ softline, path.call(print, "expression") ]) + ), + softline, + "}" + ]) + ); + case "JSXElement": + return printJSXElement(path, options, print); + case "JSXOpeningElement": + return group( + concat([ + "<", + path.call(print, "name"), + multilineGroup( + concat([ + indent( + options.tabWidth, + concat( + path.map(attr => concat([ line, print(attr) ]), "attributes") + ) + ), + n.selfClosing ? line : softline + ]) + ), + n.selfClosing ? "/>" : ">" + ]) + ); + case "JSXClosingElement": + return concat([ "" ]); + case "JSXText": + throw new Error("JSXTest should be handled by JSXElement"); + case "JSXEmptyExpression": + return ""; + case "TypeAnnotatedIdentifier": + return concat([ + path.call(print, "annotation"), + " ", + path.call(print, "identifier") + ]); + case "ClassBody": + if (n.body.length === 0) { + return fromString("{}"); + } + + return concat([ + "{", + indent( + options.tabWidth, concat([ - indent( - options.tabWidth, - concat(types.map(t => concat([ line, op, " ", t ]))) + hardline, + path.call( + function(bodyPath) { + return printStatementSequence(bodyPath, options, print); + }, + "body" ) ]) - ] + ), + hardline, + "}" + ]); + case "ClassPropertyDefinition": + parts.push("static ", path.call(print, "definition")); + + if (!namedTypes.MethodDefinition.check(n.definition)) + parts.push(";"); + + return concat(parts); + case "ClassProperty": + if (n.static) + parts.push("static "); + + var key; + + if (n.computed) { + key = concat([ "[", path.call(print, "key"), "]" ]); + } else { + key = printPropertyKey(path, print); + if (n.variance === "plus") { + key = concat([ "+", key ]); + } else if (n.variance === "minus") { + key = concat([ "-", key ]); + } + } + + parts.push(key); + + if (n.typeAnnotation) + parts.push(path.call(print, "typeAnnotation")); + + if (n.value) + parts.push(" = ", path.call(print, "value")); + + parts.push(";"); + + return concat(parts); + case "ClassDeclaration": + case "ClassExpression": + return concat(printClass(path, print)); + case "TemplateElement": + return join(literalline, n.value.raw.split("\n")); + case "TemplateLiteral": + var expressions = path.map(print, "expressions"); + + parts.push("`"); + + path.each( + function(childPath) { + var i = childPath.getName(); + + parts.push(print(childPath)); + + if (i < expressions.length) { + parts.push("${", expressions[i], "}"); + } + }, + "quasis" ); + + parts.push("`"); + + return concat(parts); + // These types are unprintable because they serve as abstract + // supertypes for other (printable) types. + case "TaggedTemplateExpression": + return concat([ path.call(print, "tag"), path.call(print, "quasi") ]); + case "Node": + case "Printable": + case "SourceLocation": + case "Position": + case "Statement": + case "Function": + case "Pattern": + case "Expression": + case "Declaration": + case "Specifier": + case "NamedSpecifier": + // Supertype of Block and Line. + case "Comment": + // Flow + case "MemberTypeAnnotation": + case // Flow + "Type": + throw new Error("unprintable type: " + JSON.stringify(n.type)); + // Babel block comment. + case "CommentBlock": + case // Esprima block comment. + "Block": + return concat([ "/*", n.value, "*/" ]); + // Babel line comment. + case "CommentLine": + case // Esprima line comment. + "Line": + return concat([ "//", n.value ]); + // Type Annotations for Facebook Flow, typically stripped out or + // transformed away before printing. + case "TypeAnnotation": + if (n.typeAnnotation) { + if (n.typeAnnotation.type !== "FunctionTypeAnnotation") { + parts.push(": "); + } + + parts.push(path.call(print, "typeAnnotation")); + + return concat(parts); + } + + return ""; + case "TupleTypeAnnotation": + return concat([ "[", join(", ", path.map(print, "types")), "]" ]); + case "ExistentialTypeParam": + case "ExistsTypeAnnotation": + return fromString("*", options); + case "EmptyTypeAnnotation": + return fromString("empty", options); + case "AnyTypeAnnotation": + return fromString("any", options); + case "MixedTypeAnnotation": + return fromString("mixed", options); + case "ArrayTypeAnnotation": + return concat([ path.call(print, "elementType"), "[]" ]); + case "BooleanTypeAnnotation": + return fromString("boolean", options); + case "NumericLiteralTypeAnnotation": + case "BooleanLiteralTypeAnnotation": + return "" + n.value; + case "DeclareClass": + return printFlowDeclaration(path, printClass(path, print)); + case "DeclareFunction": + return printFlowDeclaration(path, [ + "function ", + path.call(print, "id"), + n.predicate ? " " : "", + path.call(print, "predicate"), + ";" + ]); + case "DeclareModule": + return printFlowDeclaration(path, [ + "module ", + path.call(print, "id"), + " ", + path.call(print, "body") + ]); + case "DeclareModuleExports": + return printFlowDeclaration(path, [ + "module.exports", + path.call(print, "typeAnnotation"), + ";" + ]); + case "DeclareVariable": + return printFlowDeclaration(path, [ + "var ", + path.call(print, "id"), + ";" + ]); + case "DeclareExportAllDeclaration": + return concat([ "declare export * from ", path.call(print, "source") ]); + case "DeclareExportDeclaration": + return concat([ + "declare ", + printExportDeclaration(path, options, print) + ]); + case "FunctionTypeAnnotation": + // FunctionTypeAnnotation is ambiguous: + // declare function foo(a: B): void; OR + // var A: (a: B) => void; + var parent = path.getParentNode(0); + var isArrowFunctionTypeAnnotation = !(!parent.variance && + !parent.optional && + namedTypes.ObjectTypeProperty.check(parent) || + namedTypes.ObjectTypeCallProperty.check(parent) || + namedTypes.DeclareFunction.check(path.getParentNode(2))); + var needsColon = isArrowFunctionTypeAnnotation && + namedTypes.TypeAnnotation.check(parent); + + if (needsColon) { + parts.push(": "); + } + + parts.push(path.call(print, "typeParameters")); + + parts.push(multilineGroup(printFunctionParams(path, print, options))); + + // The returnType is not wrapped in a TypeAnnotation, so the colon + // needs to be added separately. + if (n.returnType || n.predicate) { + parts.push( + isArrowFunctionTypeAnnotation ? " => " : ": ", + path.call(print, "returnType"), + path.call(print, "predicate") + ); + } + + return concat(parts); + case "FunctionTypeParam": + return concat([ + path.call(print, "name"), + n.optional ? "?" : "", + n.name ? ": " : "", + path.call(print, "typeAnnotation") + ]); + case "GenericTypeAnnotation": + return concat([ + path.call(print, "id"), + path.call(print, "typeParameters") + ]); + case "DeclareInterface": + parts.push("declare "); + + case "InterfaceDeclaration": + parts.push( + fromString("interface ", options), + path.call(print, "id"), + path.call(print, "typeParameters"), + " " + ); + + if (n["extends"].length > 0) { + parts.push("extends ", join(", ", path.map(print, "extends"))); + } + + parts.push(" ", path.call(print, "body")); + + return concat(parts); + case "ClassImplements": + case "InterfaceExtends": + return concat([ + path.call(print, "id"), + path.call(print, "typeParameters") + ]); + case "IntersectionTypeAnnotation": + case "UnionTypeAnnotation": { + const types = path.map(print, "types"); + const op = n.type === "IntersectionTypeAnnotation" ? "&" : "|"; + + return conditionalGroup([ + // single-line variation + // A | B | C + concat([ + indent( + options.tabWidth, + concat([ + types[(0)], + indent( + options.tabWidth, + concat(types.slice(1).map(t => concat([ " ", op, line, t ]))) + ) + ]) + ) + ]), + // multi-line variation + // | A + // | B + // | C + concat([ + indent( + options.tabWidth, + concat(types.map(t => concat([ line, op, " ", t ]))) + ) + ]) + ]); } - case "NullableTypeAnnotation": - return concat([ "?", path.call(print, "typeAnnotation") ]); - case "NullLiteralTypeAnnotation": - return fromString("null", options); - case "ThisTypeAnnotation": - return fromString("this", options); - case "NumberTypeAnnotation": - return fromString("number", options); - case "ObjectTypeCallProperty": - if (n.static) { - parts.push("static "); - } + case "NullableTypeAnnotation": + return concat([ "?", path.call(print, "typeAnnotation") ]); + case "NullLiteralTypeAnnotation": + return fromString("null", options); + case "ThisTypeAnnotation": + return fromString("this", options); + case "NumberTypeAnnotation": + return fromString("number", options); + case "ObjectTypeCallProperty": + if (n.static) { + parts.push("static "); + } - parts.push(path.call(print, "value")); + parts.push(path.call(print, "value")); - return concat(parts); - case "ObjectTypeIndexer": - var variance = n.variance === "plus" - ? "+" - : n.variance === "minus" ? "-" : ""; - return concat([ - variance, - "[", - path.call(print, "id"), - n.id ? ": " : "", - path.call(print, "key"), - "]: ", - path.call(print, "value") - ]); - case "ObjectTypeProperty": - var variance = n.variance === "plus" - ? "+" - : n.variance === "minus" ? "-" : ""; - // TODO: This is a bad hack and we need a better way to know - // when to emit an arrow function or not. - var isFunction = !n.variance && !n.optional && - n.value.type === "FunctionTypeAnnotation"; - return concat([ - n.static ? "static " : "", - variance, - path.call(print, "key"), - n.optional ? "?" : "", - isFunction ? "" : ": ", - path.call(print, "value") - ]); - case "QualifiedTypeIdentifier": - return concat([ - path.call(print, "qualification"), - ".", - path.call(print, "id") - ]); - case "StringLiteralTypeAnnotation": - return fromString(nodeStr(n.value, options), options); - case "NumberLiteralTypeAnnotation": - assert.strictEqual(typeof n.value, "number"); + return concat(parts); + case "ObjectTypeIndexer": + var variance = n.variance === "plus" + ? "+" + : n.variance === "minus" ? "-" : ""; + return concat([ + variance, + "[", + path.call(print, "id"), + n.id ? ": " : "", + path.call(print, "key"), + "]: ", + path.call(print, "value") + ]); + case "ObjectTypeProperty": + var variance = n.variance === "plus" + ? "+" + : n.variance === "minus" ? "-" : ""; + // TODO: This is a bad hack and we need a better way to know + // when to emit an arrow function or not. + var isFunction = !n.variance && !n.optional && + n.value.type === "FunctionTypeAnnotation"; + return concat([ + n.static ? "static " : "", + variance, + path.call(print, "key"), + n.optional ? "?" : "", + isFunction ? "" : ": ", + path.call(print, "value") + ]); + case "QualifiedTypeIdentifier": + return concat([ + path.call(print, "qualification"), + ".", + path.call(print, "id") + ]); + case "StringLiteralTypeAnnotation": + return fromString(nodeStr(n.value, options), options); + case "NumberLiteralTypeAnnotation": + assert.strictEqual(typeof n.value, "number"); - return fromString("" + n.value, options); - case "StringTypeAnnotation": - return fromString("string", options); - case "DeclareTypeAlias": - case "TypeAlias": { + return fromString("" + n.value, options); + case "StringTypeAnnotation": + return fromString("string", options); + case "DeclareTypeAlias": + case "TypeAlias": { const parent = path.getParentNode(1); if ( @@ -1472,97 +1506,97 @@ function genericPrintNoParens(path, options, print) { return concat(parts); } - case "TypeCastExpression": - return concat([ - "(", - path.call(print, "expression"), - path.call(print, "typeAnnotation"), - ")" - ]); - case "TypeParameterDeclaration": - case "TypeParameterInstantiation": - return concat([ "<", join(", ", path.map(print, "params")), ">" ]); - case "TypeParameter": - switch (n.variance) { - case "plus": - parts.push("+"); + case "TypeCastExpression": + return concat([ + "(", + path.call(print, "expression"), + path.call(print, "typeAnnotation"), + ")" + ]); + case "TypeParameterDeclaration": + case "TypeParameterInstantiation": + return concat([ "<", join(", ", path.map(print, "params")), ">" ]); + case "TypeParameter": + switch (n.variance) { + case "plus": + parts.push("+"); - break; - case "minus": - parts.push("-"); + break; + case "minus": + parts.push("-"); - break; + break; + default: + } + + parts.push(path.call(print, "name")); + + if (n.bound) { + parts.push(path.call(print, "bound")); + } + + if (n["default"]) { + parts.push("=", path.call(print, "default")); + } + + return concat(parts); + case "TypeofTypeAnnotation": + return concat([ + fromString("typeof ", options), + path.call(print, "argument") + ]); + case "VoidTypeAnnotation": + return "void"; + case "NullTypeAnnotation": + return "null"; + case "InferredPredicate": + return "%checks"; + // Unhandled types below. If encountered, nodes of these types should + // be either left alone or desugared into AST types that are fully + // supported by the pretty-printer. + case "DeclaredPredicate": + return concat([ "%checks(", path.call(print, "value"), ")" ]); + // TODO + case "ClassHeritage": + // TODO + case "ComprehensionBlock": + // TODO + case "ComprehensionExpression": + // TODO + case "Glob": + // TODO + case "GeneratorExpression": + // TODO + case "LetStatement": + // TODO + case "LetExpression": + // TODO + case "GraphExpression": + // TODO + // XML types that nobody cares about or needs to print. + case "GraphIndexExpression": + case "XMLDefaultDeclaration": + case "XMLAnyName": + case "XMLQualifiedIdentifier": + case "XMLFunctionQualifiedIdentifier": + case "XMLAttributeSelector": + case "XMLFilterExpression": + case "XML": + case "XMLElement": + case "XMLList": + case "XMLEscape": + case "XMLText": + case "XMLStartTag": + case "XMLEndTag": + case "XMLPointTag": + case "XMLName": + case "XMLAttribute": + case "XMLCdata": + case "XMLComment": + case "XMLProcessingInstruction": default: - } - - parts.push(path.call(print, "name")); - - if (n.bound) { - parts.push(path.call(print, "bound")); - } - - if (n["default"]) { - parts.push("=", path.call(print, "default")); - } - - return concat(parts); - case "TypeofTypeAnnotation": - return concat([ - fromString("typeof ", options), - path.call(print, "argument") - ]); - case "VoidTypeAnnotation": - return "void"; - case "NullTypeAnnotation": - return "null"; - case "InferredPredicate": - return "%checks"; - // Unhandled types below. If encountered, nodes of these types should - // be either left alone or desugared into AST types that are fully - // supported by the pretty-printer. - case "DeclaredPredicate": - return concat([ "%checks(", path.call(print, "value"), ")" ]); - // TODO - case "ClassHeritage": - // TODO - case "ComprehensionBlock": - // TODO - case "ComprehensionExpression": - // TODO - case "Glob": - // TODO - case "GeneratorExpression": - // TODO - case "LetStatement": - // TODO - case "LetExpression": - // TODO - case "GraphExpression": - // TODO - // XML types that nobody cares about or needs to print. - case "GraphIndexExpression": - case "XMLDefaultDeclaration": - case "XMLAnyName": - case "XMLQualifiedIdentifier": - case "XMLFunctionQualifiedIdentifier": - case "XMLAttributeSelector": - case "XMLFilterExpression": - case "XML": - case "XMLElement": - case "XMLList": - case "XMLEscape": - case "XMLText": - case "XMLStartTag": - case "XMLEndTag": - case "XMLPointTag": - case "XMLName": - case "XMLAttribute": - case "XMLCdata": - case "XMLComment": - case "XMLProcessingInstruction": - default: - debugger; - throw new Error("unknown type: " + JSON.stringify(n.type)); + debugger; + throw new Error("unknown type: " + JSON.stringify(n.type)); } return p; } @@ -1591,8 +1625,10 @@ function printStatementSequence(path, options, print) { parts.push(stmtPrinted); - if (util.newlineExistsAfter(text, util.locEnd(stmt)) && - !isLastStatement(stmtPath)) { + if ( + util.newlineExistsAfter(text, util.locEnd(stmt)) && + !isLastStatement(stmtPath) + ) { parts.push(hardline); } @@ -1645,15 +1681,17 @@ function printMethod(path, options, print) { parts.push( key, path.call(print, "value", "typeParameters"), - multilineGroup(concat([ - path.call( - function(valuePath) { - return printFunctionParams(valuePath, print, options); - }, - "value" - ), - path.call(p => printReturnType(p, print), "value") - ])), + multilineGroup( + concat([ + path.call( + function(valuePath) { + return printFunctionParams(valuePath, print, options); + }, + "value" + ), + path.call(p => printReturnType(p, print), "value") + ]) + ), " ", path.call(print, "value", "body") ); @@ -1676,9 +1714,9 @@ function printArgumentsList(path, options, print) { const groupLastArg = lastArg.type === "ObjectExpression" || lastArg.type === "ArrayExpression" || lastArg.type === "FunctionExpression" || - (lastArg.type === "ArrowFunctionExpression" && - (lastArg.body.type === "BlockStatement" || - lastArg.body.type === "ArrowFunctionExpression")) || + lastArg.type === "ArrowFunctionExpression" && + (lastArg.body.type === "BlockStatement" || + lastArg.body.type === "ArrowFunctionExpression") || lastArg.type === "NewExpression"; if (groupLastArg) { @@ -1690,7 +1728,7 @@ function printArgumentsList(path, options, print) { "(", join(concat([ ",", line ]), printed.slice(0, -1)), printed.length > 1 ? ", " : "", - group(util.getLast(printed), {shouldBreak: true}), + group(util.getLast(printed), { shouldBreak: true }), ")" ]), group( @@ -1704,10 +1742,10 @@ function printArgumentsList(path, options, print) { line, ")" ]), - {shouldBreak: true} + { shouldBreak: true } ) ], - {shouldBreak} + { shouldBreak } ); } @@ -1789,10 +1827,12 @@ function printObjectMethod(path, options, print) { } parts.push( - multilineGroup(concat([ - printFunctionParams(path, print, options), - printReturnType(path, print) - ])), + multilineGroup( + concat([ + printFunctionParams(path, print, options), + printReturnType(path, print) + ]) + ), " ", path.call(print, "body") ); @@ -1827,32 +1867,39 @@ function printExportDeclaration(path, options, print) { if (decl.declaration) { parts.push(path.call(print, "declaration")); - if (decl.type === "ExportDefaultDeclaration" && decl.declaration.type == "Identifier") { + if ( + decl.type === "ExportDefaultDeclaration" && + decl.declaration.type == "Identifier" + ) { parts.push(";"); } } else if (decl.specifiers && decl.specifiers.length > 0) { if ( decl.specifiers.length === 1 && - decl.specifiers[0].type === "ExportBatchSpecifier" + decl.specifiers[(0)].type === "ExportBatchSpecifier" ) { parts.push("*"); } else { parts.push( decl.exportKind === "type" ? "type " : "", - group(concat([ - "{", - indent( - options.tabWidth, - concat([ - options.bracketSpacing ? line : softline, - join(concat([",", options.bracketSpacing ? line : softline]), - path.map(print, "specifiers")) - ]) - ), - ifBreak(options.trailingComma ? "," : ""), - options.bracketSpacing ? line : softline, - "}" - ])) + group( + concat([ + "{", + indent( + options.tabWidth, + concat([ + options.bracketSpacing ? line : softline, + join( + concat([ ",", options.bracketSpacing ? line : softline ]), + path.map(print, "specifiers") + ) + ]) + ), + ifBreak(options.trailingComma ? "," : ""), + options.bracketSpacing ? line : softline, + "}" + ]) + ) ); } @@ -1860,7 +1907,7 @@ function printExportDeclaration(path, options, print) { parts.push(" from ", path.call(print, "source")); } - parts.push(';'); + parts.push(";"); } return concat(parts); @@ -1900,10 +1947,7 @@ function printClass(path, print) { } if (n["implements"] && n["implements"].length > 0) { - parts.push( - " implements ", - join(", ", path.map(print, "implements")) - ); + parts.push(" implements ", join(", ", path.map(print, "implements"))); } parts.push(" ", path.call(print, "body")); @@ -1942,7 +1986,7 @@ function printMemberChain(node, options, print) { // easily analyze. while (curr.type === "CallExpression" && curr.callee.type === "MemberExpression") { - nodes.push({member: curr.callee, call: curr}); + nodes.push({ member: curr.callee, call: curr }); curr = curr.callee.object; } nodes.reverse(); @@ -1955,7 +1999,7 @@ function printMemberChain(node, options, print) { // and indent them. function argIsFunction(call) { if (call.arguments.length > 0) { - const type = call.arguments[0].type; + const type = call.arguments[(0)].type; return type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "NewExpression"; @@ -1968,10 +2012,13 @@ function printMemberChain(node, options, print) { if (hasMultipleLookups) { const currPrinted = print(FastPath.from(curr)); - const nodesPrinted = nodes.map(node => ({ - property: printMemberLookup(FastPath.from(node.member), print), - args: printArgumentsList(FastPath.from(node.call), options, print) - })); + const nodesPrinted = nodes.map( + node => + ({ + property: printMemberLookup(FastPath.from(node.member), print), + args: printArgumentsList(FastPath.from(node.call), options, print) + }) + ); const fullyExpanded = concat([ currPrinted, concat( @@ -2051,31 +2098,41 @@ function printJSXElement(path, options, print) { var mostChildren = children.slice(0, -1); var closingLines = path.call(print, "closingElement"); - const firstChild = children[0]; + const firstChild = children[(0)]; const lastChild = util.getLast(children); const beginBreak = firstChild && firstChild.type === "line"; const endBreak = lastChild && lastChild.type === "line"; - elem = multilineGroup(concat([ - openingLines, - indent(options.tabWidth, concat([ beginBreak ? "" : softline ].concat(mostChildren))), - lastChild || "", - endBreak ? "" : softline, - closingLines, - ])); + elem = multilineGroup( + concat([ + openingLines, + indent( + options.tabWidth, + concat([ beginBreak ? "" : softline ].concat(mostChildren)) + ), + lastChild || "", + endBreak ? "" : softline, + closingLines + ]) + ); } const parent = path.getParentNode(); - if (!parent || parent.type === "JSXElement" || parent.type === "ExpressionStatement") { + if ( + !parent || parent.type === "JSXElement" || + parent.type === "ExpressionStatement" + ) { return elem; } - return multilineGroup(concat([ - ifBreak("("), - indent(options.tabWidth, concat([ softline, elem ])), - softline, - ifBreak(")"), - ])); + return multilineGroup( + concat([ + ifBreak("("), + indent(options.tabWidth, concat([ softline, elem ])), + softline, + ifBreak(")") + ]) + ); } function adjustClause(clause, options, forceSpace) { @@ -2108,7 +2165,7 @@ function lastNonSpaceCharacter(lines) { function swapQuotes(str) { return str.replace(/['"]/g, function(m) { - return m === "\"" ? "'" : "\""; + return m === '"' ? "'" : '"'; }); } @@ -2137,7 +2194,7 @@ function isFirstStatement(path) { const parent = path.getParentNode(); const node = path.getValue(); const body = parent.body; - return body && body[0] === node; + return body && body[(0)] === node; } function isLastStatement(path) { diff --git a/src/util.js b/src/util.js index 42bab63f..a3d28908 100644 --- a/src/util.js +++ b/src/util.js @@ -24,15 +24,12 @@ function getUnionOfKeys() { util.getUnionOfKeys = getUnionOfKeys; function comparePos(pos1, pos2) { - return (pos1.line - pos2.line) || (pos1.column - pos2.column); + return pos1.line - pos2.line || pos1.column - pos2.column; } util.comparePos = comparePos; function copyPos(pos) { - return { - line: pos.line, - column: pos.column - }; + return { line: pos.line, column: pos.column }; } util.copyPos = copyPos; @@ -98,11 +95,10 @@ function expandLoc(parentNode, childNode) { util.fixFaultyLocations = function(node, text) { if (node.type === "TemplateLiteral") { fixTemplateLiteral(node, text); - } else if (node.decorators) { // Expand the loc of the node responsible for printing the decorators // (here, the decorated node) so that it includes node.decorators. - node.decorators.forEach(function (decorator) { + node.decorators.forEach(function(decorator) { expandLoc(node, decorator); }); } else if (node.declaration && util.isExportDeclaration(node)) { @@ -110,12 +106,14 @@ util.fixFaultyLocations = function(node, text) { // (here, the export declaration) so that it includes node.decorators. var decorators = node.declaration.decorators; if (decorators) { - decorators.forEach(function (decorator) { + decorators.forEach(function(decorator) { expandLoc(node, decorator); }); } - } else if ((n.MethodDefinition && n.MethodDefinition.check(node)) || - (n.Property.check(node) && (node.method || node.shorthand))) { + } else if ( + n.MethodDefinition && n.MethodDefinition.check(node) || + n.Property.check(node) && (node.method || node.shorthand) + ) { if (n.FunctionExpression.check(node.value)) { // FunctionExpression method values should be anonymous, // because their .id fields are ignored anyway. @@ -127,7 +125,7 @@ util.fixFaultyLocations = function(node, text) { // Some parsers accidentally include trailing commas in the // end information for ObjectTypeProperty nodes. if ((end = skipSpaces(text, end - 1, true)) !== false) { - setLocEnd(node, end) + setLocEnd(node, end); } } } @@ -146,7 +144,7 @@ function fixTemplateLiteral(node, text) { var afterLeftBackTickPos = locStart(node); assert.strictEqual(text.charAt(afterLeftBackTickPos), "`"); assert.ok(afterLeftBackTickPos < text.length); - var firstQuasi = node.quasis[0]; + var firstQuasi = node.quasis[(0)]; if (locStart(firstQuasi) - afterLeftBackTickPos < 0) { setLocStart(firstQuasi, afterLeftBackTickPos); } @@ -163,17 +161,18 @@ function fixTemplateLiteral(node, text) { // Now we need to exclude ${ and } characters from the loc's of all // quasi elements, since some parsers accidentally include them. - node.expressions.forEach(function (expr, i) { + node.expressions.forEach(function(expr, i) { // Rewind from the start loc over any whitespace and the ${ that // precedes the expression. The position of the $ should be the // same as the end of the preceding quasi element, but some // parsers accidentally include the ${ in the loc of the quasi // element. var dollarCurlyPos = skipSpaces(text, locStart(expr) - 1, true); - if (dollarCurlyPos - 1 >= 0 && - text.charAt(dollarCurlyPos - 1) === "{" && + if ( + dollarCurlyPos - 1 >= 0 && text.charAt(dollarCurlyPos - 1) === "{" && dollarCurlyPos - 2 >= 0 && - text.charAt(dollarCurlyPos - 2) === "$") { + text.charAt(dollarCurlyPos - 2) === "$" + ) { var quasiBefore = node.quasis[i]; if (dollarCurlyPos - locEnd(quasiBefore) < 0) { setLocEnd(quasiBefore, dollarCurlyPos); @@ -194,24 +193,26 @@ function fixTemplateLiteral(node, text) { }); } -util.isExportDeclaration = function (node) { - if (node) switch (node.type) { - case "ExportDeclaration": - case "ExportDefaultDeclaration": - case "ExportDefaultSpecifier": - case "DeclareExportDeclaration": - case "ExportNamedDeclaration": - case "ExportAllDeclaration": - return true; - } +util.isExportDeclaration = function(node) { + if (node) + switch (node.type) { + case "ExportDeclaration": + case "ExportDefaultDeclaration": + case "ExportDefaultSpecifier": + case "DeclareExportDeclaration": + case "ExportNamedDeclaration": + case "ExportAllDeclaration": + return true; + } return false; }; -util.getParentExportDeclaration = function (path) { +util.getParentExportDeclaration = function(path) { var parentNode = path.getParentNode(); - if (path.getName() === "declaration" && - util.isExportDeclaration(parentNode)) { + if ( + path.getName() === "declaration" && util.isExportDeclaration(parentNode) + ) { return parentNode; } @@ -227,15 +228,15 @@ util.isTrailingCommaEnabled = function(options, context) { }; util.getLast = function(arr) { - if(arr.length > 0) { + if (arr.length > 0) { return arr[arr.length - 1]; } return null; -} +}; function _findNewline(text, index, backwards) { const length = text.length; - let cursor = backwards ? (index - 1) : (index + 1); + let cursor = backwards ? index - 1 : index + 1; // Look forward and see if there is a newline after/before this code // by scanning up/back to the next non-indentation character. while (cursor > 0 && cursor < length) { @@ -253,15 +254,15 @@ function _findNewline(text, index, backwards) { util.newlineExistsBefore = function(text, index) { return _findNewline(text, index, true); -} +}; util.newlineExistsAfter = function(text, index) { return _findNewline(text, index); -} +}; function skipSpaces(text, index, backwards) { const length = text.length; - let cursor = backwards ? (index - 1) : (index + 1); + let cursor = backwards ? index - 1 : index + 1; // Look forward and see if there is a newline after/before this code // by scanning up/back to the next non-indentation character. while (cursor > 0 && cursor < length) { @@ -277,36 +278,34 @@ function skipSpaces(text, index, backwards) { util.skipSpaces = skipSpaces; function locStart(node) { - if(node.range) { - return node.range[0]; + if (node.range) { + return node.range[(0)]; } return node.start; } util.locStart = locStart; function locEnd(node) { - if(node.range) { - return node.range[1]; + if (node.range) { + return node.range[(1)]; } return node.end; } util.locEnd = locEnd; function setLocStart(node, index) { - if(node.range) { - node.range[0] = index; - } - else { + if (node.range) { + node.range[(0)] = index; + } else { node.start = index; } } util.setLocStart = setLocStart; function setLocEnd(node, index) { - if(node.range) { - node.range[1] = index; - } - else { + if (node.range) { + node.range[(1)] = index; + } else { node.end = index; } } @@ -314,13 +313,11 @@ util.setLocEnd = setLocEnd; // http://stackoverflow.com/a/7124052 function htmlEscapeInsideDoubleQuote(str) { - return str - .replace(/&/g, '&') - .replace(/"/g, '"'); -// Intentionally disable the following since it is safe inside of a -// double quote context -// .replace(/'/g, ''') -// .replace(//g, '>'); + return str.replace(/&/g, "&").replace(/"/g, """); + // Intentionally disable the following since it is safe inside of a + // double quote context + // .replace(/'/g, ''') + // .replace(//g, '>'); } util.htmlEscapeInsideDoubleQuote = htmlEscapeInsideDoubleQuote;