Comparing version
@@ -0,2 +1,32 @@ | ||
# 0.0.8 | ||
[link](https://github.com/jlongster/prettier/compare/e447971...0192d58) | ||
* Fix await parenthesis (#185) | ||
* Add note about Sublime Test github issue in readme | ||
* Remove legacy Recast code and simplify API. (#191) | ||
* Don't break to new line if logical/loop statements are without brackets. (#194) | ||
* Fix parenthesis for UpdateExpression (#198) | ||
* Fix directives printing for empty functions (#199) | ||
* Fix key quotes omission for flow parser (#203) | ||
* Fix comma when an arrow function with no arguments breaks (#210) | ||
* Last argument expansion works for arrow functions that return JSX (#211) | ||
* Remove faulty location check on template literals that throws in Nuclide (#218) | ||
* Add flow parser experimental options (#221) | ||
* Fix empty exports (#225) | ||
* Fix cases of missing parens with NewExpression (#230) | ||
* Fix issue with ArrowFunctionExpression parens (#236) | ||
* Add npm version badge (#240) | ||
* Consolidate badges in readme | ||
* Fix parens issue with nested UrnaryExpressions (#237) | ||
* Escape strings using jsesc (#229) | ||
* Add newline for empty blocks {} (#205) | ||
* Fix empty export with from clause (#248) | ||
* Fix missing parenthesis for typeof and arrow functions (#249) | ||
* Fix FunctionExpression parens issues (#250) | ||
* Fix last element of an array being null (#232) | ||
* Make sure empty for loops generate valid code (#224) | ||
* Fix parens for functions inside TaggedTemplateExpression (#259) | ||
* Preserve the way numbers were written (#257) | ||
# 0.0.7 | ||
@@ -3,0 +33,0 @@ |
@@ -31,3 +31,7 @@ "use strict"; | ||
if (opts.useFlowParser) { | ||
ast = flowParser.parse(text); | ||
ast = flowParser.parse(text, { | ||
esproposal_class_instance_fields: true, | ||
esproposal_class_static_fields: true, | ||
esproposal_export_star_as: true, | ||
}); | ||
if (ast.errors.length > 0) { | ||
@@ -54,3 +58,3 @@ let msg = ast.errors[(0)].message + " on line " + | ||
const printer = new Printer(opts); | ||
return printer.printGenerically(ast).code; | ||
return printer.print(ast); | ||
} | ||
@@ -57,0 +61,0 @@ |
{ | ||
"name": "prettier", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"bin": { | ||
@@ -23,5 +23,5 @@ "prettier": "./bin/prettier.js" | ||
"get-stdin": "^5.0.1", | ||
"jsesc": "^2.4.0", | ||
"minimist": "^1.2.0", | ||
"private": "^0.1.6", | ||
"source-map": "^0.5.6" | ||
"private": "^0.1.6" | ||
}, | ||
@@ -28,0 +28,0 @@ "devDependencies": { |
@@ -1,4 +0,6 @@ | ||
# Prettier [](https://travis-ci.org/jlongster/prettier) | ||
# Prettier | ||
[](https://gitter.im/jlongster/prettier) | ||
[](https://travis-ci.org/jlongster/prettier) | ||
[](https://www.npmjs.com/package/prettier) | ||
@@ -184,2 +186,6 @@ Prettier is an opinionated JavaScript formatter inspired by | ||
### Sublime Text | ||
Please see [this issue](https://github.com/jlongster/prettier/issues/17) for those interested in working on Sublime Text integration. | ||
More editors are coming soon. | ||
@@ -186,0 +192,0 @@ |
@@ -231,3 +231,3 @@ var assert = require("assert"); | ||
switch (node.type) { | ||
case "UnaryExpression": | ||
case "UpdateExpression": | ||
case "SpreadElement": | ||
@@ -238,2 +238,12 @@ case "SpreadProperty": | ||
case "UnaryExpression": | ||
switch (parent.type) { | ||
case "UnaryExpression": | ||
return node.operator === parent.operator && | ||
(node.operator === "+" || node.operator === "-"); | ||
case "MemberExpression": | ||
return name === "object" && parent.object === node; | ||
} | ||
case "BinaryExpression": | ||
@@ -243,2 +253,3 @@ case "LogicalExpression": | ||
case "CallExpression": | ||
case "NewExpression": | ||
return name === "callee" && parent.callee === node; | ||
@@ -295,2 +306,3 @@ | ||
case "AwaitExpression": | ||
case "YieldExpression": | ||
@@ -303,9 +315,10 @@ switch (parent.type) { | ||
case "SpreadProperty": | ||
case "CallExpression": | ||
case "MemberExpression": | ||
case "NewExpression": | ||
case "ConditionalExpression": | ||
case "YieldExpression": | ||
case "MemberExpression": | ||
return true; | ||
case "CallExpression": | ||
return parent.callee === node; | ||
default: | ||
@@ -345,2 +358,3 @@ return false; | ||
case "LogicalExpression": | ||
case "NewExpression": | ||
return true; | ||
@@ -361,2 +375,3 @@ | ||
case "FunctionExpression": | ||
case "ArrowFunctionExpression": | ||
@@ -367,4 +382,12 @@ if (parent.type === "CallExpression" && name === "callee") { | ||
return isBinary(parent); | ||
switch (parent.type) { | ||
case "MemberExpression": | ||
case "TaggedTemplateExpression": | ||
case "UnaryExpression": | ||
return true; | ||
default: | ||
return isBinary(parent); | ||
} | ||
case "ClassExpression": | ||
@@ -371,0 +394,0 @@ return parent.type === "ExpressionStatement"; |
"use strict"; | ||
var assert = require("assert"); | ||
var sourceMap = require("source-map"); | ||
var printComments = require("./comments").printComments; | ||
@@ -29,40 +28,7 @@ var pp = require("./pp"); | ||
var isIdentifierName = require("esutils").keyword.isIdentifierNameES6; | ||
var jsesc = require("jsesc"); | ||
function PrintResult(code, sourceMap) { | ||
assert.ok(this instanceof PrintResult); | ||
isString.assert(code); | ||
this.code = code; | ||
if (sourceMap) { | ||
isObject.assert(sourceMap); | ||
this.map = sourceMap; | ||
} | ||
} | ||
var PRp = PrintResult.prototype; | ||
var warnedAboutToString = false; | ||
PRp.toString = function() { | ||
if (!warnedAboutToString) { | ||
console.warn( | ||
"Deprecation warning: recast.print now returns an object with " + | ||
"a .code property. You appear to be treating the object as a " + | ||
"string, which might still work but is strongly discouraged." | ||
); | ||
warnedAboutToString = true; | ||
} | ||
return this.code; | ||
}; | ||
var emptyPrintResult = new PrintResult(""); | ||
function Printer(originalOptions) { | ||
assert.ok(this instanceof Printer); | ||
var explicitTabWidth = originalOptions && originalOptions.tabWidth; | ||
var options = normalizeOptions(originalOptions); | ||
@@ -72,7 +38,2 @@ | ||
// It's common for client code to pass the same options into both | ||
// recast.parse and recast.print, but the Printer doesn't need (and | ||
// can be confused by) options.sourceFileName, so we null it out. | ||
options.sourceFileName = null; | ||
// Print the entire AST generically. | ||
@@ -89,33 +50,9 @@ function printGenerically(path) { | ||
if (!ast) { | ||
return emptyPrintResult; | ||
return ""; | ||
} | ||
var lines = print(FastPath.from(ast), true); | ||
return new PrintResult( | ||
lines.toString(options), | ||
util.composeSourceMaps( | ||
options.inputSourceMap, | ||
lines.getSourceMap(options.sourceMapName, options.sourceRoot) | ||
) | ||
); | ||
}; | ||
this.printGenerically = function(ast) { | ||
if (!ast) { | ||
return emptyPrintResult; | ||
} | ||
var path = FastPath.from(ast); | ||
var oldReuseWhitespace = options.reuseWhitespace; | ||
// Do not reuse whitespace (or anything else, for that matter) | ||
// when printing generically. | ||
options.reuseWhitespace = false; | ||
var res = printGenerically(path); | ||
var pr = new PrintResult(pp.print(options.printWidth, res)); | ||
options.reuseWhitespace = oldReuseWhitespace; | ||
return pr; | ||
return pp.print(options.printWidth, res); | ||
}; | ||
@@ -362,3 +299,7 @@ } | ||
if (n.body.type === "JSXElement") { | ||
if ( | ||
n.body.type === 'ArrayExpression' || | ||
n.body.type === 'ObjectExpression' || | ||
n.body.type === 'JSXElement' | ||
) { | ||
return group(collapsed); | ||
@@ -555,6 +496,4 @@ } | ||
// If there are no contents, return a simple block | ||
if (!getFirstString(naked)) { | ||
return "{}"; | ||
} | ||
const hasContent = getFirstString(naked); | ||
const hasDirectives = n.directives && n.directives.length > 0; | ||
@@ -564,3 +503,3 @@ parts.push("{"); | ||
// Babel 6 | ||
if (n.directives) { | ||
if (hasDirectives) { | ||
path.each( | ||
@@ -571,3 +510,3 @@ function(childPath) { | ||
options.tabWidth, | ||
concat([ hardline, print(childPath), ";", hardline ]) | ||
concat([ hardline, print(childPath), ";" ]) | ||
) | ||
@@ -580,3 +519,7 @@ ); | ||
parts.push(indent(options.tabWidth, concat([ hardline, naked ]))); | ||
if (hasContent) { | ||
parts.push( | ||
indent(options.tabWidth, concat([ hardline, naked ])) | ||
); | ||
} | ||
@@ -709,2 +652,14 @@ parts.push(hardline, "}"); | ||
} else { | ||
// JavaScript allows you to have empty elements in an array which | ||
// changes its length based on the number of commas. The algorithm | ||
// is that if the last argument is null, we need to force insert | ||
// a comma to ensure JavaScript recognizes it. | ||
// [,].length === 1 | ||
// [1,].length === 1 | ||
// [1,,].length === 2 | ||
// | ||
// Note that util.getLast returns null if the array is empty, but | ||
// we already check for an empty array just above so we are safe | ||
const needsForcedTrailingComma = util.getLast(n.elements) === null; | ||
parts.push( | ||
@@ -721,2 +676,3 @@ multilineGroup( | ||
), | ||
needsForcedTrailingComma ? "," : "", | ||
ifBreak(options.trailingComma ? "," : ""), | ||
@@ -747,8 +703,11 @@ options.bracketSpacing ? line : softline, | ||
// Babel 6 Literal split | ||
case "NumericLiteral": | ||
return 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 === "number") | ||
return n.raw; | ||
if (typeof n.value !== "string") | ||
@@ -857,4 +816,4 @@ return fromString(n.value, options); | ||
path.call(print, "object"), | ||
") ", | ||
path.call(print, "body") | ||
")", | ||
adjustClause(path.call(print, "body"), options) | ||
]); | ||
@@ -1659,3 +1618,7 @@ case "IfStatement": | ||
var node = path.getNode().key; | ||
if (node.type === "StringLiteral" && isIdentifierName(node.value)) { | ||
if ( | ||
(node.type === "StringLiteral" || | ||
node.type === "Literal" && typeof node.value === "string") && | ||
isIdentifierName(node.value) | ||
) { | ||
// 'a' -> a | ||
@@ -1736,3 +1699,6 @@ return node.value; | ||
(lastArg.body.type === "BlockStatement" || | ||
lastArg.body.type === "ArrowFunctionExpression") || | ||
lastArg.body.type === "ArrowFunctionExpression" || | ||
lastArg.body.type === "ObjectExpression" || | ||
lastArg.body.type === "ArrayExpression" || | ||
lastArg.body.type === "JSXElement") || | ||
lastArg.type === "NewExpression"; | ||
@@ -1807,2 +1773,6 @@ | ||
if (printed.length === 0) { | ||
return "()"; | ||
} | ||
return concat([ | ||
@@ -1895,30 +1865,34 @@ "(", | ||
} | ||
} else if (decl.specifiers && decl.specifiers.length > 0) { | ||
if ( | ||
decl.specifiers.length === 1 && | ||
decl.specifiers[(0)].type === "ExportBatchSpecifier" | ||
) { | ||
parts.push("*"); | ||
} else { | ||
if (decl.specifiers && decl.specifiers.length > 0) { | ||
if ( | ||
decl.specifiers.length === 1 && | ||
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, | ||
"}" | ||
]) | ||
) | ||
); | ||
} | ||
} 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, | ||
"}" | ||
]) | ||
) | ||
); | ||
parts.push("{}"); | ||
} | ||
@@ -2159,2 +2133,6 @@ | ||
function adjustClause(clause, options, forceSpace) { | ||
if (clause === "") { | ||
return ";"; | ||
} | ||
if (isCurlyBracket(clause) || forceSpace) { | ||
@@ -2164,3 +2142,3 @@ return concat([ " ", clause ]); | ||
return indent(options.tabWidth, concat([ hardline, clause ])); | ||
return indent(options.tabWidth, concat([ line, clause ])); | ||
} | ||
@@ -2188,8 +2166,2 @@ | ||
function swapQuotes(str) { | ||
return str.replace(/['"]/g, function(m) { | ||
return m === '"' ? "'" : '"'; | ||
}); | ||
} | ||
function nodeStr(str, options) { | ||
@@ -2209,7 +2181,6 @@ isString.assert(str); | ||
if (shouldUseSingleQuote) { | ||
return swapQuotes(JSON.stringify(swapQuotes(str))); | ||
} else { | ||
return JSON.stringify(str); | ||
} | ||
return jsesc(str, { | ||
quotes: shouldUseSingleQuote ? 'single' : 'double', | ||
wrap: true | ||
}); | ||
} | ||
@@ -2216,0 +2187,0 @@ |
118
src/util.js
@@ -6,5 +6,2 @@ "use strict"; | ||
var n = types.namedTypes; | ||
var sourceMap = require("source-map"); | ||
var SourceMapConsumer = sourceMap.SourceMapConsumer; | ||
var SourceMapGenerator = sourceMap.SourceMapGenerator; | ||
var hasOwn = Object.prototype.hasOwnProperty; | ||
@@ -37,51 +34,2 @@ var util = exports; | ||
util.composeSourceMaps = function(formerMap, latterMap) { | ||
if (formerMap) { | ||
if (!latterMap) { | ||
return formerMap; | ||
} | ||
} else { | ||
return latterMap || null; | ||
} | ||
var smcFormer = new SourceMapConsumer(formerMap); | ||
var smcLatter = new SourceMapConsumer(latterMap); | ||
var smg = new SourceMapGenerator({ | ||
file: latterMap.file, | ||
sourceRoot: latterMap.sourceRoot | ||
}); | ||
var sourcesToContents = {}; | ||
smcLatter.eachMapping(function(mapping) { | ||
var origPos = smcFormer.originalPositionFor({ | ||
line: mapping.originalLine, | ||
column: mapping.originalColumn | ||
}); | ||
var sourceName = origPos.source; | ||
if (sourceName === null) { | ||
return; | ||
} | ||
smg.addMapping({ | ||
source: sourceName, | ||
original: copyPos(origPos), | ||
generated: { | ||
line: mapping.generatedLine, | ||
column: mapping.generatedColumn | ||
}, | ||
name: mapping.name | ||
}); | ||
var sourceContent = smcFormer.sourceContentFor(sourceName); | ||
if (sourceContent && !hasOwn.call(sourcesToContents, sourceName)) { | ||
sourcesToContents[sourceName] = sourceContent; | ||
smg.setSourceContent(sourceName, sourceContent); | ||
} | ||
}); | ||
return smg.toJSON(); | ||
}; | ||
function expandLoc(parentNode, childNode) { | ||
@@ -98,5 +46,3 @@ if (locStart(childNode) - locStart(parentNode) < 0) { | ||
util.fixFaultyLocations = function(node, text) { | ||
if (node.type === "TemplateLiteral") { | ||
fixTemplateLiteral(node, text); | ||
} else if (node.decorators) { | ||
if (node.decorators) { | ||
// Expand the loc of the node responsible for printing the decorators | ||
@@ -137,64 +83,2 @@ // (here, the decorated node) so that it includes node.decorators. | ||
function fixTemplateLiteral(node, text) { | ||
assert.strictEqual(node.type, "TemplateLiteral"); | ||
if (node.quasis.length === 0) { | ||
// If there are no quasi elements, then there is nothing to fix. | ||
return; | ||
} | ||
// First we need to exclude the opening ` from the loc of the first | ||
// quasi element, in case the parser accidentally decided to include it. | ||
var afterLeftBackTickPos = locStart(node); | ||
assert.strictEqual(text.charAt(afterLeftBackTickPos), "`"); | ||
assert.ok(afterLeftBackTickPos < text.length); | ||
var firstQuasi = node.quasis[(0)]; | ||
if (locStart(firstQuasi) - afterLeftBackTickPos < 0) { | ||
setLocStart(firstQuasi, afterLeftBackTickPos); | ||
} | ||
// Next we need to exclude the closing ` from the loc of the last quasi | ||
// element, in case the parser accidentally decided to include it. | ||
var rightBackTickPos = locEnd(node); | ||
assert.ok(rightBackTickPos >= 0); | ||
assert.strictEqual(text.charAt(rightBackTickPos), "`"); | ||
var lastQuasi = node.quasis[node.quasis.length - 1]; | ||
if (rightBackTickPos - locEnd(lastQuasi) < 0) { | ||
setLocEnd(locEnd(lastQuasi), rightBackTickPos); | ||
} | ||
// 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) { | ||
// 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) === "{" && | ||
dollarCurlyPos - 2 >= 0 && | ||
text.charAt(dollarCurlyPos - 2) === "$" | ||
) { | ||
var quasiBefore = node.quasis[i]; | ||
if (dollarCurlyPos - locEnd(quasiBefore) < 0) { | ||
setLocEnd(quasiBefore, dollarCurlyPos); | ||
} | ||
} | ||
// Likewise, some parsers accidentally include the } that follows | ||
// the expression in the loc of the following quasi element. | ||
var rightCurlyPos = skipSpaces(text, locEnd(expr)); | ||
if (text.charAt(rightCurlyPos) === "}") { | ||
assert.ok(rightCurlyPos + 1 < text.length); | ||
// Now rightCurlyPos is technically the position just after the }. | ||
var quasiAfter = node.quasis[i + 1]; | ||
if (locStart(quasiAfter) - rightCurlyPos < 0) { | ||
setLocStart(locStart(quasiAfter), rightCurlyPos); | ||
} | ||
} | ||
}); | ||
} | ||
util.isExportDeclaration = function(node) { | ||
@@ -201,0 +85,0 @@ if (node) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
22
4.76%248
2.48%819049
-0.14%5979
-1.37%+ Added
+ Added
- Removed
- Removed