Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Right now, doing `npm install` of prettier creates 3500 files, which is a pain to manage and to check in. Using the awesome rollup, we can easily bundle all the dependencies into a single big js file. This way I can just check-in a single file in fb codebase and update it when there's a new version. Performance-wise, it is currently 50ms slower than using ./bin/prettier. Both babylon and flow are taking roughly 30ms to parse and we only need a single one at a time. We can shave off 20ms by minifying the bundle but it breaks flow parser (this is why we don't have a flow option on the website!) rollup doesn't support shebangs so I had to split the bin/prettier into two files, a dummy one with the shebang and I put the code inside of src: `src/cli.js`.
- Loading branch information
Showing
6 changed files
with
29,323 additions
and
271 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,270 +1,2 @@ | ||
#!/usr/bin/env node | ||
|
||
"use strict"; | ||
|
||
const fs = require("fs"); | ||
const getStdin = require("get-stdin"); | ||
const glob = require("glob"); | ||
const chalk = require("chalk"); | ||
const minimist = require("minimist"); | ||
const readline = require("readline"); | ||
const prettier = require("../index"); | ||
|
||
const argv = minimist(process.argv.slice(2), { | ||
boolean: [ | ||
"write", | ||
"stdin", | ||
"single-quote", | ||
"trailing-comma", | ||
"bracket-spacing", | ||
"jsx-bracket-same-line", | ||
// The supports-color package (a sub sub dependency) looks directly at | ||
// `process.argv` for `--no-color` and such-like options. The reason it is | ||
// listed here is to avoid "Ignored unknown option: --no-color" warnings. | ||
// See https://github.com/chalk/supports-color/#info for more information. | ||
"color", | ||
"help", | ||
"version", | ||
"debug-print-doc", | ||
"debug-check", | ||
// Deprecated in 0.0.10 | ||
"flow-parser" | ||
], | ||
string: ["print-width", "tab-width", "parser"], | ||
default: { color: true, "bracket-spacing": true, parser: "babylon" }, | ||
alias: { help: "h", version: "v" }, | ||
unknown: param => { | ||
if (param.startsWith("-")) { | ||
console.warn("Ignored unknown option: " + param + "\n"); | ||
return false; | ||
} | ||
} | ||
}); | ||
|
||
if (argv["version"]) { | ||
console.log(prettier.version); | ||
process.exit(0); | ||
} | ||
|
||
const filepatterns = argv["_"]; | ||
const write = argv["write"]; | ||
const stdin = argv["stdin"] || !filepatterns.length && !process.stdin.isTTY; | ||
|
||
if (argv["help"] || !filepatterns.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 <int> Specify the length of line that the printer will wrap on. Defaults to 80.\n" + | ||
" --tab-width <int> Specify the number of spaces per indentation-level. Defaults to 2.\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.\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" + | ||
" --color Colorize error messages. Defaults to true.\n" + | ||
" --version Print prettier version.\n" + | ||
"\n" + | ||
"Boolean options can be turned off like this:\n" + | ||
" --no-bracket-spacing\n" + | ||
" --bracket-spacing=false" | ||
); | ||
process.exit(argv["help"] ? 0 : 1); | ||
} | ||
|
||
function getParserOption() { | ||
const optionName = "parser"; | ||
const value = argv[optionName]; | ||
|
||
if (value === undefined) { | ||
return value; | ||
} | ||
|
||
// For backward compatibility. Deprecated in 0.0.10 | ||
if (argv["flow-parser"]) { | ||
console.warn("`--flow-parser` is deprecated. Use `--parser flow` instead."); | ||
return "flow"; | ||
} | ||
|
||
if (value === "flow" || value === "babylon") { | ||
return value; | ||
} | ||
|
||
console.warn( | ||
"Ignoring unknown --" + | ||
optionName + | ||
' value, falling back to "babylon":\n' + | ||
' Expected "flow" or "babylon", but received: ' + | ||
JSON.stringify(value) | ||
); | ||
|
||
return "babylon"; | ||
} | ||
|
||
function getIntOption(optionName) { | ||
const value = argv[optionName]; | ||
|
||
if (value === undefined) { | ||
return value; | ||
} | ||
|
||
if (/^\d+$/.test(value)) { | ||
return Number(value); | ||
} | ||
|
||
console.error( | ||
"Invalid --" + | ||
optionName + | ||
" value. Expected an integer, but received: " + | ||
JSON.stringify(value) | ||
); | ||
process.exit(1); | ||
} | ||
|
||
const options = { | ||
printWidth: getIntOption("print-width"), | ||
tabWidth: getIntOption("tab-width"), | ||
bracketSpacing: argv["bracket-spacing"], | ||
parser: getParserOption(), | ||
singleQuote: argv["single-quote"], | ||
trailingComma: argv["trailing-comma"], | ||
jsxBracketSameLine: argv["jsx-bracket-same-line"] | ||
}; | ||
|
||
function format(input) { | ||
if (argv["debug-print-doc"]) { | ||
const doc = prettier.__debug.printToDoc(input, options); | ||
return prettier.__debug.formatDoc(doc); | ||
} | ||
|
||
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); | ||
} | ||
|
||
function handleError(filename, e) { | ||
const isParseError = Boolean(e && e.loc); | ||
const isValidationError = /Validation Error/.test(e && e.message); | ||
|
||
// For parse errors and validation errors, we only want to show the error | ||
// message formatted in a nice way. `String(e)` takes care of that. Other | ||
// (unexpected) errors are passed as-is as a separate argument to | ||
// `console.error`. That includes the stack trace (if any), and shows a nice | ||
// `util.inspect` of throws things that aren't `Error` objects. (The Flow | ||
// parser has mistakenly thrown arrays sometimes.) | ||
if (isParseError) { | ||
console.error(filename + ": " + String(e)); | ||
} else if (isValidationError) { | ||
console.error(String(e)); | ||
// If validation fails for one file, it will fail for all of them. | ||
process.exit(1); | ||
} else { | ||
console.error(filename + ":", e); | ||
} | ||
|
||
// Don't exit the process if one file failed | ||
process.exitCode = 2; | ||
} | ||
|
||
if (stdin) { | ||
getStdin().then(input => { | ||
try { | ||
// Don't use `console.log` here since it adds an extra newline at the end. | ||
process.stdout.write(format(input)); | ||
} catch (e) { | ||
handleError("stdin", e); | ||
return; | ||
} | ||
}); | ||
} else { | ||
eachFilename(filepatterns, filename => { | ||
fs.readFile(filename, "utf8", (err, input) => { | ||
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); | ||
// Don't exit the process if one file failed | ||
process.exitCode = 2; | ||
return; | ||
} | ||
|
||
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); | ||
return; | ||
} | ||
|
||
if (write) { | ||
// Remove previously printed filename to log it with duration. | ||
readline.clearLine(process.stdout, 0); | ||
readline.cursorTo(process.stdout, 0, null); | ||
|
||
// Don't write the file if it won't change in order not to invalidate | ||
// mtime based caches. | ||
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 => { | ||
if (err) { | ||
console.error("Unable to write file: " + filename + "\n" + err); | ||
// Don't exit the process if one file failed | ||
process.exitCode = 2; | ||
} | ||
}); | ||
} | ||
} else if (argv["debug-check"]) { | ||
process.stdout.write("\n"); | ||
if (output) { | ||
console.log(output); | ||
} | ||
} else { | ||
// Don't use `console.log` here since it adds an extra newline at the end. | ||
process.stdout.write(output); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
function eachFilename(patterns, callback) { | ||
patterns.forEach(pattern => { | ||
glob(pattern, (err, filenames) => { | ||
if (err) { | ||
console.error("Unable to expand glob pattern: " + pattern + "\n" + err); | ||
// Don't exit the process if one pattern failed | ||
process.exitCode = 2; | ||
return; | ||
} | ||
|
||
filenames.forEach(filename => { | ||
callback(filename); | ||
}); | ||
}); | ||
}); | ||
} | ||
require('../src/cli'); |
Oops, something went wrong.