prettier
Advanced tools
Comparing version 0.16.0 to 0.17.0
@@ -8,2 +8,3 @@ #!/usr/bin/env node | ||
const glob = require("glob"); | ||
const chalk = require("chalk"); | ||
const minimist = require("minimist"); | ||
@@ -19,2 +20,3 @@ const prettier = require("../index"); | ||
"bracket-spacing", | ||
"jsx-bracket-same-line", | ||
// The supports-color package (a sub sub dependency) looks directly at | ||
@@ -28,2 +30,3 @@ // `process.argv` for `--no-color` and such-like options. The reason it is | ||
"debug-print-doc", | ||
"debug-check", | ||
// Deprecated in 0.0.10 | ||
@@ -63,2 +66,3 @@ "flow-parser" | ||
" --bracket-spacing Put spaces between brackets. Defaults to true.\n" + | ||
" --jsx-bracket-same-line Put > on the last line. Defaults to false.\n" + | ||
" --parser <flow|babylon> Specify which parse to use. Defaults to babylon.\n" + | ||
@@ -130,3 +134,4 @@ " --color Colorize error messages. Defaults to true.\n" + | ||
singleQuote: argv["single-quote"], | ||
trailingComma: argv["trailing-comma"] | ||
trailingComma: argv["trailing-comma"], | ||
jsxBracketSameLine: argv["jsx-bracket-same-line"], | ||
}; | ||
@@ -139,2 +144,13 @@ | ||
} | ||
if (argv["debug-check"]) { | ||
const pp = prettier.format(input, options); | ||
const pppp = prettier.format(pp, options); | ||
if (pp !== pppp) { | ||
const diff = require('diff').createTwoFilesPatch('', '', pp, pppp, '', '', {context: 2}); | ||
console.error(diff); | ||
} | ||
return; | ||
} | ||
return prettier.format(input, options); | ||
@@ -180,7 +196,11 @@ } | ||
fs.readFile(filename, "utf8", (err, input) => { | ||
if (write) { | ||
console.log(filename); | ||
if (write || argv["debug-check"]) { | ||
// Don't use `console.log` here since we need to replace this line. | ||
process.stdout.write(filename); | ||
} | ||
if (err) { | ||
// Add newline to split errors from filename line. | ||
process.stdout.write("\n"); | ||
console.error("Unable to read file: " + filename + "\n" + err); | ||
@@ -192,6 +212,12 @@ // Don't exit the process if one file failed | ||
const start = Date.now(); | ||
let output; | ||
try { | ||
output = format(input); | ||
} catch (e) { | ||
// Add newline to split errors from filename line. | ||
process.stdout.write("\n"); | ||
handleError(filename, e); | ||
@@ -202,5 +228,13 @@ return; | ||
if (write) { | ||
// Remove previously printed filename to log it with duration. | ||
process.stdout.clearLine(); | ||
process.stdout.cursorTo(0); | ||
// Don't write the file if it won't change in order not to invalidate | ||
// mtime based caches. | ||
if (output !== input) { | ||
if (output === input) { | ||
console.log(chalk.grey("%s %dms"), filename, Date.now() - start); | ||
} else { | ||
console.log("%s %dms", filename, Date.now() - start); | ||
fs.writeFile(filename, output, "utf8", err => { | ||
@@ -207,0 +241,0 @@ if (err) { |
@@ -0,1 +1,36 @@ | ||
# 0.17.0 | ||
[link](https://github.com/jlongster/prettier/compare/0.16.0...0.17.0) | ||
* [JSX] Fix spurious newline (fixes #614) (#628) | ||
* Add --debug-check cli option (#627) | ||
* Remove last trailing line for directives-only files (#609) | ||
* Expand vim instructions | ||
* Fix formatting in readme | ||
* Update snapshots | ||
* Preserve empty line before last comment (#594) | ||
* test on current release of node.js (#595) | ||
* [JSX] jsx-whitespace breaks with parent (fixes #622) (#626) | ||
* Log filename with [update] or [ignore] flags during `--write` process. (#584) | ||
* Do not indent binary expressions inside of if (#604) | ||
* Put short elements at right of single binary expression on same line (#605) | ||
* Run prettier 0.16.0 on the codebase (#631) | ||
* Preserve blank lines inside of objects (#606) | ||
* fix typo in JetBrains External Tool config readme (#679) | ||
* Fix dangling comments for arrays (#665) | ||
* Print line-suffix in --debug-print-doc (#676) | ||
* Avoid unneeded parenthesis for colon with comments (#673) | ||
* Stabilize comments inside of if/then/else before { (#672) | ||
* Soft break the first member of a chain (#667) | ||
* Stabilize comments inside of ternaries (#666) | ||
* Fix trailing commas with a trailing comment (#664) | ||
* Fix Flow union type annotations indentation (#650) | ||
* Ensure that all comments are printed (#571) | ||
* Properly support member chains comments (#668) | ||
* [WIP] Fix Flow DeclareTypeAlias (#669) | ||
* Add option for putting > on the last line in jsx (#661) | ||
* Always put a hardline before dangling comment (#675) | ||
* Fix comments in return statement argument (#657) | ||
* [RFC] Introduce prettier-ignore-next (#671) | ||
# 0.16.0 | ||
@@ -2,0 +37,0 @@ |
@@ -17,4 +17,4 @@ ### Configure External Tool | ||
Now when you setup **External Tool** I guess you what to add hotkey for it. Go to *File | Settings | Keymap* for Windows and Linux *WebStorm | Preferences | Keymap* and type external tool name in search box. | ||
Now when you setup **External Tool** I guess you want to add hotkey for it. Go to *File | Settings | Keymap* for Windows and Linux *WebStorm | Preferences | Keymap* and type external tool name in search box. | ||
See [this documentation](https://www.jetbrains.com/help/webstorm/configuring-keyboard-shortcuts.html) about configuring keyboard shortcuts. |
17
index.js
@@ -48,10 +48,23 @@ "use strict"; | ||
ast.tokens = []; | ||
opts.originalText = text; | ||
opts.originalText = text.trimRight(); | ||
return astComments; | ||
} | ||
function ensureAllCommentsPrinted(astComments) { | ||
astComments.forEach(comment => { | ||
if (!comment.printed) { | ||
throw new Error( | ||
'Comment "' + comment.value.trim() + '" was not printed. Please report this error!' | ||
); | ||
} | ||
delete comment.printed; | ||
}); | ||
} | ||
function format(text, opts) { | ||
const ast = parse(text, opts); | ||
attachComments(text, ast, opts); | ||
const astComments = attachComments(text, ast, opts); | ||
const doc = printAstToDoc(ast, opts); | ||
const str = printDocToString(doc, opts.printWidth, guessLineEnding(text)); | ||
ensureAllCommentsPrinted(astComments); | ||
return str; | ||
@@ -58,0 +71,0 @@ } |
{ | ||
"name": "prettier", | ||
"version": "0.16.0", | ||
"version": "0.17.0", | ||
"description": "Prettier is an opinionated JavaScript formatter", | ||
@@ -22,2 +22,3 @@ "bin": { | ||
"babylon": "6.15.0", | ||
"chalk": "1.1.3", | ||
"esutils": "2.0.2", | ||
@@ -38,3 +39,4 @@ "flow-parser": "0.38.0", | ||
"rollup-plugin-node-resolve": "2.0.0", | ||
"rollup-plugin-real-babili": "1.0.0-alpha3" | ||
"rollup-plugin-real-babili": "1.0.0-alpha3", | ||
"diff": "3.2.0" | ||
}, | ||
@@ -41,0 +43,0 @@ "scripts": { |
@@ -1,2 +0,2 @@ | ||
# Prettier | ||
# Prettier | ||
@@ -151,2 +151,6 @@ [![Gitter](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/jlongster/prettier) | ||
// If true, puts the `>` of a multi-line jsx element at the end of | ||
// the last line instead of being alone on the next line | ||
jsxBracketSameLine: false, | ||
// Which parser to use. Valid options are 'flow' and 'babylon' | ||
@@ -184,2 +188,10 @@ parser: 'babylon' | ||
If you want to restore cursor position after formatting, try this | ||
(although it's not guaranteed that it will be restored to the same | ||
place in the code since it may have moved): | ||
``` | ||
autocmd BufWritePre *.js exe "normal! gggqG\<C-o>\<C-o>" | ||
``` | ||
### Visual Studio Code | ||
@@ -186,0 +198,0 @@ |
@@ -13,2 +13,3 @@ var assert = require("assert"); | ||
var lineSuffix = docBuilders.lineSuffix; | ||
var join = docBuilders.join; | ||
var util = require("./util"); | ||
@@ -140,5 +141,3 @@ var comparePos = util.comparePos; | ||
if ( | ||
util.hasNewline(text, locStart(comment), { backwards: true }) | ||
) { | ||
if (util.hasNewline(text, locStart(comment), { backwards: true })) { | ||
// If a comment exists on its own line, prefer a leading comment. | ||
@@ -164,8 +163,10 @@ // We also need to check if it's the first line of the file. | ||
} else if (util.hasNewline(text, locEnd(comment))) { | ||
// There is content before this comment on the same line, but | ||
// none after it, so prefer a trailing comment of the previous node. | ||
if (precedingNode) { | ||
if (handleConditionalExpressionComments(enclosingNode, followingNode, comment)) { | ||
// We're good | ||
} else if (precedingNode) { | ||
// There is content before this comment on the same line, but | ||
// none after it, so prefer a trailing comment of the previous node. | ||
addTrailingComment(precedingNode, comment); | ||
} else if (followingNode) { | ||
addLeadingComment(followingNode, comment); | ||
addLeadingComment(followingNode, comment); | ||
} else if (enclosingNode) { | ||
@@ -178,8 +179,10 @@ addDanglingComment(enclosingNode, comment); | ||
} else { | ||
// Otherwise, text exists both before and after the comment on | ||
// the same line. If there is both a preceding and following | ||
// node, use a tie-breaking algorithm to determine if it should | ||
// be attached to the next or previous node. In the last case, | ||
// simply attach the right node; | ||
if (precedingNode && followingNode) { | ||
if (handleIfStatementComments(enclosingNode, followingNode, comment)) { | ||
// We're good | ||
} else if (precedingNode && followingNode) { | ||
// Otherwise, text exists both before and after the comment on | ||
// the same line. If there is both a preceding and following | ||
// node, use a tie-breaking algorithm to determine if it should | ||
// be attached to the next or previous node. In the last case, | ||
// simply attach the right node; | ||
const tieCount = tiesToBreak.length; | ||
@@ -264,2 +267,3 @@ if (tieCount > 0) { | ||
comments.push(comment); | ||
comment.printed = false; | ||
} | ||
@@ -377,4 +381,13 @@ | ||
function handleConditionalExpressionComments(enclosingNode, followingNode, comment) { | ||
if (enclosingNode && enclosingNode.type === 'ConditionalExpression' && followingNode) { | ||
addLeadingComment(followingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function printComment(commentPath) { | ||
const comment = commentPath.getValue(); | ||
comment.printed = true; | ||
@@ -416,5 +429,7 @@ switch (comment.type) { | ||
if (util.hasNewline(options.originalText, locStart(comment), { | ||
if ( | ||
util.hasNewline(options.originalText, locStart(comment), { | ||
backwards: true | ||
})) { | ||
}) | ||
) { | ||
// This allows comments at the end of nested structures: | ||
@@ -431,3 +446,9 @@ // { | ||
// always at the end of another expression. | ||
return concat([hardline, contents]); | ||
const isLineBeforeEmpty = util.isPreviousLineEmpty( | ||
options.originalText, | ||
comment | ||
); | ||
return lineSuffix(concat([hardline, isLineBeforeEmpty ? hardline : "", contents])); | ||
} else if (isBlock) { | ||
@@ -441,3 +462,3 @@ // Trailing block comments never need a newline | ||
function printDanglingComments(path, options, noIndent) { | ||
function printDanglingComments(path, options, sameIndent) { | ||
const text = options.originalText; | ||
@@ -455,5 +476,2 @@ const parts = []; | ||
if (!comment.leading && !comment.trailing) { | ||
if (util.hasNewline(text, locStart(comment), { backwards: true })) { | ||
parts.push(hardline); | ||
} | ||
parts.push(printComment(commentPath)); | ||
@@ -465,6 +483,10 @@ } | ||
if (!noIndent) { | ||
return indent(options.tabWidth, concat(parts)); | ||
if (parts.length === 0) { | ||
return ""; | ||
} | ||
return concat(parts); | ||
if (sameIndent) { | ||
return join(hardline, parts); | ||
} | ||
return indent(options.tabWidth, concat([hardline, join(hardline, parts)])); | ||
} | ||
@@ -471,0 +493,0 @@ |
@@ -66,7 +66,3 @@ "use strict"; | ||
function lineSuffix(contents) { | ||
if (typeof contents !== "string") { | ||
throw new Error( | ||
"lineSuffix only takes a string, but given: " + JSON.stringify(contents) | ||
); | ||
} | ||
assertDoc(contents); | ||
return { type: "line-suffix", contents }; | ||
@@ -73,0 +69,0 @@ } |
@@ -95,2 +95,8 @@ "use strict"; | ||
} | ||
if (doc.type === "line-suffix") { | ||
return "lineSuffix(" + printDoc(doc.contents) + ")"; | ||
} | ||
throw new Error('Unknown doc type ' + doc.type); | ||
} | ||
@@ -97,0 +103,0 @@ |
@@ -90,3 +90,3 @@ "use strict"; | ||
let shouldRemeasure = false; | ||
let lineSuffix = ""; | ||
let lineSuffix = []; | ||
@@ -194,3 +194,3 @@ while (cmds.length !== 0) { | ||
case "line-suffix": | ||
lineSuffix += doc.contents; | ||
lineSuffix.push([ind, mode, doc.contents]); | ||
break; | ||
@@ -220,4 +220,11 @@ case "line": | ||
case MODE_BREAK: | ||
if (lineSuffix.length) { | ||
cmds.push([ind, mode, doc]); | ||
[].push.apply(cmds, lineSuffix.reverse()); | ||
lineSuffix = []; | ||
break; | ||
} | ||
if (doc.literal) { | ||
out.push(lineSuffix + newLine); | ||
out.push(newLine); | ||
pos = 0; | ||
@@ -233,7 +240,5 @@ } else { | ||
out.push(lineSuffix + newLine + " ".repeat(ind)); | ||
out.push(newLine + " ".repeat(ind)); | ||
pos = ind; | ||
} | ||
lineSuffix = ""; | ||
break; | ||
@@ -240,0 +245,0 @@ } |
@@ -7,13 +7,8 @@ "use strict"; | ||
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, | ||
// Which parser to use. Valid options are 'flow' and 'babylon' | ||
jsxBracketSameLine: false, | ||
parser: "babylon" | ||
@@ -20,0 +15,0 @@ }; |
@@ -127,3 +127,3 @@ "use strict"; | ||
const skipSpaces = skip(" \t"); | ||
const skipToLineEnd = skip("; \t"); | ||
const skipToLineEnd = skip(",; \t"); | ||
const skipEverythingButNewLine = skip(/[^\r\n]/); | ||
@@ -199,2 +199,10 @@ | ||
// Note: this function doesn't ignore leading comments unlike isNextLineEmpty | ||
function isPreviousLineEmpty(text, node) { | ||
let idx = locStart(node) - 1; | ||
idx = skipSpaces(text, idx, {backwards: true}); | ||
idx = skipNewline(text, idx, {backwards: true}); | ||
return hasNewline(text, idx, {backwards: true}); | ||
} | ||
function isNextLineEmpty(text, node) { | ||
@@ -304,2 +312,3 @@ let oldIdx = null; | ||
isNextLineEmpty, | ||
isPreviousLineEmpty, | ||
hasNewline, | ||
@@ -306,0 +315,0 @@ hasNewlineInRange, |
233
test.js
@@ -0,221 +1,20 @@ | ||
function f() { | ||
return ( | ||
// Comment | ||
<div /> | ||
); | ||
} | ||
class UserInfo extends React.Component { | ||
props: Props; | ||
state: void; | ||
function f() { | ||
return ( | ||
// comment | ||
!!x | ||
); | ||
} | ||
_info: ?Info = null; | ||
static defaultProps = { | ||
showActions: true, | ||
showAvailability: true, | ||
}; | ||
render(): ?React.Element<*> { | ||
if (!this.props.user) { | ||
return null; | ||
} | ||
const user: User = this.props.user; | ||
if (!this.props.user.full_name) { | ||
return ( | ||
<View style={styles.loading}> | ||
<FBLoadingIndicator /> | ||
</View> | ||
); | ||
} | ||
// title | ||
const title = user.full_name; | ||
// subtitle | ||
let subtitle = ''; | ||
if (user.work_campus && user.work_building && user.work_floor) { | ||
const campus = (user.work_campus || ''); | ||
const building = (user.work_building || '') | ||
.replace(campus, '') | ||
.replace(/^0+/, ''); | ||
const floor = (user.work_floor || '') | ||
.replace(/^0+/, ''); | ||
const location = (user.work_desk || ''); | ||
subtitle = `${campus} ${building}.${floor} ${location}`; | ||
} | ||
// actions | ||
const actions: Array<Action> = [ | ||
// TODO: add this button back in when routing is implemented | ||
// { | ||
// type: 'outline-primary', | ||
// title: 'Route', | ||
// glyphName: 'directions', | ||
// glyphSize: '16', | ||
// onPress: this._onPressRoute, | ||
// }, | ||
]; | ||
// Messenger integration is only available on iOS | ||
if (Platform.OS === 'ios') { | ||
actions.push({ | ||
type: 'outline-primary', | ||
title: 'Message', | ||
glyphName: 'messages', | ||
glyphSize: '16', | ||
onPress: this._onPressMessage, | ||
}); | ||
} | ||
actions.push({ | ||
title: 'Meeting', | ||
glyphName: 'calendar', | ||
glyphSize: '16', | ||
onPress: this._onPressMeeting, | ||
}); | ||
// left | ||
const left = ( | ||
<Image | ||
style={styles.picture} | ||
source={ | ||
user.profile_picture || | ||
require('./images/user_placeholder.png') | ||
} | ||
/> | ||
); | ||
// right | ||
const status = user.current_status_availability; | ||
const right = ( | ||
<View style={styles.availability}> | ||
<Text | ||
style={[ | ||
styles.availabilityText, | ||
status === 'NORMAL' && styles.statusNormal, | ||
status === 'SEMI_AVAILABLE' && styles.statusSemiAvailable, | ||
status === 'OFF_THE_GRID' && styles.statusOffTheGrid, | ||
]}> | ||
{ | ||
status === 'NORMAL' && 'Available' || | ||
status === 'SEMI_AVAILABLE' && 'Sporadic' || | ||
status === 'OFF_THE_GRID' && 'Off the Grid' || | ||
'' | ||
} | ||
</Text> | ||
</View> | ||
); | ||
return ( | ||
<Info | ||
ref={ref => {this._info = ref;}} | ||
title={title} | ||
subtitle={subtitle} | ||
availability={user.current_status_availability} | ||
left={left} | ||
right={this.props.showAvailability ? right : null} | ||
actions={this.props.showActions ? actions : []} | ||
onPress={this._onPressHeader} | ||
/> | ||
); | ||
} | ||
hide(): void { | ||
if (this._info) { | ||
this._info.hide(); | ||
} | ||
} | ||
_onPressHeader = (): void => { | ||
if (this.props.user && this.props.user.unencoded_id) { | ||
Events.navigateToUser(this.props.user.unencoded_id); | ||
} | ||
}; | ||
_onPressRoute(): void { | ||
if (this.props.user && this.props.user.id) { | ||
Events.navigateToWayfinder({user: this.props.user.id}); | ||
} | ||
} | ||
_onPressMeeting = (): void => { | ||
if (this.props.user && this.props.user.unencoded_id) { | ||
Events.navigateToNewMeeting({}, { | ||
inviteeIDs: [this.props.user.unencoded_id], | ||
}); | ||
} | ||
}; | ||
_onPressMessage = (): void => { | ||
if (this.props.user) { | ||
// prefer messaging the @work user, if there is one | ||
const id = | ||
this.props.user.work_user && | ||
this.props.user.work_user.id || | ||
this.props.user.unencoded_id || | ||
''; | ||
if (id) { | ||
Linking.openURL(`fb-messenger://user-thread/${id}`); | ||
} | ||
} | ||
}; | ||
function f() { | ||
return ( | ||
!!x // comment | ||
); | ||
} | ||
const styles = StyleSheet.create({ | ||
picture: { | ||
width: 40, | ||
height: 40, | ||
backgroundColor: 'rgb(196,210,231)', | ||
borderRadius: 2, | ||
resizeMode: 'cover', | ||
}, | ||
availability: { | ||
flex: 1, | ||
width: 92, | ||
justifyContent: 'center', | ||
}, | ||
availabilityText: { | ||
...UFIGFontInternal.font('bold', 12), | ||
textAlign: 'right', | ||
}, | ||
statusNormal: { | ||
color: Constants.Colors.Vibrant.NORMAL, | ||
}, | ||
statusSemiAvailable: { | ||
color: Constants.Colors.Vibrant.SEMI_AVAILABLE, | ||
}, | ||
statusOffTheGrid: { | ||
color: Constants.Colors.Vibrant.OFF_THE_GRID, | ||
}, | ||
loading: { | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
padding: 10, | ||
backgroundColor: UFIGColorPalette.white, | ||
borderTopWidth: StyleSheet.hairlineWidth, | ||
borderTopColor: 'rgba(0, 0, 0, 0.1)', | ||
}, | ||
}); | ||
module.exports = Relay.createContainer( | ||
UserInfo, | ||
{ | ||
fragments: { | ||
user: () => Relay.QL` | ||
fragment on Employee { | ||
id | ||
unencoded_id | ||
full_name | ||
work_campus | ||
work_building | ||
work_floor | ||
work_desk | ||
current_status_availability | ||
profile_picture { | ||
uri | ||
} | ||
work_user { | ||
id | ||
} | ||
} | ||
`, | ||
}, | ||
}, | ||
); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1058785
285
10
9
7370
+ Addedchalk@1.1.3