Comparing version 0.22.0 to 1.0.0
@@ -17,2 +17,4 @@ #!/usr/bin/env node | ||
"stdin", | ||
"use-tabs", | ||
"semi", | ||
"single-quote", | ||
@@ -104,3 +106,2 @@ "bracket-spacing", | ||
function getTrailingComma() { | ||
let trailingComma; | ||
switch (argv["trailing-comma"]) { | ||
@@ -125,2 +126,4 @@ case undefined: | ||
const options = { | ||
useTabs: argv["use-tabs"], | ||
semi: argv["semi"], | ||
printWidth: getIntOption("print-width"), | ||
@@ -189,2 +192,4 @@ tabWidth: getIntOption("tab-width"), | ||
" --tab-width <int> Specify the number of spaces per indentation-level. Defaults to 2.\n" + | ||
" --use-tabs Indent lines with tabs instead of spaces. Defaults to false.\n" + | ||
" --no-semi Do not print semicolons, except at the beginning of lines which may need them. Defaults to false.\n" + | ||
" --single-quote Use single quotes instead of double.\n" + | ||
@@ -218,67 +223,71 @@ " --bracket-spacing Put spaces between brackets. Defaults to true.\n" + | ||
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 (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"); | ||
let input; | ||
try { | ||
input = fs.readFileSync(filename, "utf8"); | ||
} catch (e) { | ||
// 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; | ||
console.error("Unable to read file: " + filename + "\n" + err); | ||
// Don't exit the process if one file failed | ||
process.exitCode = 2; | ||
return; | ||
} | ||
if (argv["list-different"]) { | ||
if (!prettier.check(input, options)) { | ||
console.log(filename); | ||
process.exitCode = 1; | ||
} | ||
return; | ||
} | ||
const start = Date.now(); | ||
const start = Date.now(); | ||
let output; | ||
let output; | ||
try { | ||
output = format(input); | ||
} catch (e) { | ||
// Add newline to split errors from filename line. | ||
process.stdout.write("\n"); | ||
try { | ||
output = format(input); | ||
} catch (e) { | ||
// Add newline to split errors from filename line. | ||
process.stdout.write("\n"); | ||
handleError(filename, e); | ||
return; | ||
} | ||
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); | ||
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); | ||
// 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 if (argv["list-different"]) { | ||
if (input !== output) { | ||
console.log(filename); | ||
process.exitCode = 1; | ||
} | ||
} else { | ||
// Don't use `console.log` here since it adds an extra newline at the end. | ||
process.stdout.write(output); | ||
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); | ||
} | ||
}); | ||
@@ -285,0 +294,0 @@ } |
@@ -0,1 +1,7 @@ | ||
# 1.0.0 | ||
[link](https://github.com/jlongster/prettier/compare/0.22.0...1.0.0) | ||
* See announcement blog post: [http://jlongster.com/prettier-1.0](http://jlongster.com/prettier-1.0) | ||
# 0.22.0 | ||
@@ -43,6 +49,6 @@ | ||
* Run prettier 0.20.0 (#835) | ||
* [JSX] Don't wrap JSX Elements in parentheses in {} (#845) | ||
* [JSX] Don't wrap JSX Elements in parentheses in {} (#845) | ||
* Fix comment after the last argument of a function (#856) | ||
* Fix travis build imag | ||
* Do not break require calls (#841) | ||
* Do not break require calls (#841) | ||
* Stabilize import as comments (#855) | ||
@@ -49,0 +55,0 @@ * Fix jsx expression comment that break (#852) |
@@ -9,1 +9,20 @@ Add this to your init: | ||
``` | ||
If you don't use `js-mode`, which is what Prettier targets by default, you'll need to first set your major-mode of choice: | ||
```elisp | ||
(require 'prettier-js) | ||
(setq prettier-target-mode "js2-mode") | ||
(add-hook 'js2-mode-hook | ||
(lambda () | ||
(add-hook 'before-save-hook 'prettier-before-save))) | ||
``` | ||
To adjust the CLI args used for the prettier command, you can customize the `prettier-args` variable: | ||
```elisp | ||
(setq prettier-args '( | ||
"--trailing-comma" "all" | ||
"--bracket-spacing" "false" | ||
)) | ||
``` |
19
index.js
@@ -23,5 +23,5 @@ "use strict"; | ||
if (opts.parser === 'flow') { | ||
if (opts.parser === "flow") { | ||
parseFunction = parser.parseWithFlow; | ||
} else if (opts.parser === 'typescript') { | ||
} else if (opts.parser === "typescript") { | ||
parseFunction = parser.parseWithTypeScript; | ||
@@ -76,3 +76,4 @@ } else { | ||
const doc = printAstToDoc(ast, opts); | ||
const str = printDocToString(doc, opts.printWidth, guessLineEnding(text)); | ||
opts.newLine = guessLineEnding(text); | ||
const str = printDocToString(doc, opts); | ||
ensureAllCommentsPrinted(astComments); | ||
@@ -100,2 +101,10 @@ return str; | ||
}, | ||
check: function(text, opts) { | ||
try { | ||
const formatted = this.format(text, opts); | ||
return formatted === text; | ||
} catch (e) { | ||
return false; | ||
} | ||
}, | ||
version: version, | ||
@@ -106,3 +115,3 @@ __debug: { | ||
const doc = printAstToDoc(ast, opts); | ||
const str = printDocToString(doc, opts.printWidth); | ||
const str = printDocToString(doc, opts); | ||
return str; | ||
@@ -126,3 +135,3 @@ }, | ||
opts = normalizeOptions(opts); | ||
const str = printDocToString(doc, opts.printWidth); | ||
const str = printDocToString(doc, opts); | ||
return str; | ||
@@ -129,0 +138,0 @@ } |
{ | ||
"name": "prettier", | ||
"version": "0.22.0", | ||
"version": "1.0.0", | ||
"description": "Prettier is an opinionated JavaScript formatter", | ||
@@ -8,23 +8,19 @@ "bin": { | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/jlongster/prettier.git" | ||
}, | ||
"repository": "prettier/prettier", | ||
"author": "James Long", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/jlongster/prettier/issues" | ||
}, | ||
"main": "./index.js", | ||
"dependencies": { | ||
"ast-types": "0.9.4", | ||
"ast-types": "0.9.8", | ||
"babel-code-frame": "6.22.0", | ||
"babylon": "6.15.0", | ||
"babylon": "7.0.0-beta.8", | ||
"chalk": "1.1.3", | ||
"esutils": "2.0.2", | ||
"flow-parser": "0.40.0", | ||
"flow-parser": "0.43.0", | ||
"get-stdin": "5.0.1", | ||
"glob": "7.1.1", | ||
"global": "^4.3.1", | ||
"jest-validate": "19.0.0", | ||
"minimist": "1.2.0" | ||
"minimist": "1.2.0", | ||
"npm": "^4.5.0" | ||
}, | ||
@@ -34,2 +30,4 @@ "devDependencies": { | ||
"jest": "19.0.1", | ||
"mkdirp": "^0.5.1", | ||
"rimraf": "^2.6.1", | ||
"rollup": "0.41.1", | ||
@@ -42,3 +40,3 @@ "rollup-plugin-commonjs": "7.0.0", | ||
"typescript": "2.2.1", | ||
"typescript-eslint-parser": "git://github.com/eslint/typescript-eslint-parser.git#215a012ec4d272939fa5a57d0231d22fb7f7a9e0" | ||
"typescript-eslint-parser": "git://github.com/eslint/typescript-eslint-parser.git#bfb1506c48b625871ffeb67dbec7941d460f8941" | ||
}, | ||
@@ -56,2 +54,5 @@ "scripts": { | ||
], | ||
"snapshotSerializers": [ | ||
"<rootDir>/tests_config/raw-serializer.js" | ||
], | ||
"testRegex": "jsfmt\\.spec\\.js$", | ||
@@ -58,0 +59,0 @@ "testPathIgnorePatterns": [ |
239
README.md
@@ -7,19 +7,49 @@ # Prettier | ||
<!-- toc --> | ||
- [Usage](#usage) | ||
* [CLI](#cli) | ||
+ [Pre-commit hook for changed files](#pre-commit-hook-for-changed-files) | ||
* [API](#api) | ||
* [Excluding code from formatting](#excluding-code-from-formatting) | ||
- [Editor Integration](#editor-integration) | ||
* [Atom](#atom) | ||
* [Emacs](#emacs) | ||
* [Vim](#vim) | ||
+ [Vanilla approach](#vanilla-approach) | ||
+ [Neoformat approach](#neoformat-approach) | ||
+ [Customizing Prettier in Vim](#customizing-prettier-in-vim) | ||
* [Visual Studio Code](#visual-studio-code) | ||
* [Visual Studio](#visual-studio) | ||
* [Sublime Text](#sublime-text) | ||
* [JetBrains](#jetbrains) | ||
- [Language Support](#language-support) | ||
- [Related Projects](#related-projects) | ||
- [Technical Details](#technical-details) | ||
- [Badge](#badge) | ||
- [Contributing](#contributing) | ||
<!-- tocstop --> | ||
Prettier is an opinionated JavaScript formatter inspired by | ||
[refmt](https://facebook.github.io/reason/tools.html) with advanced | ||
support for language features from ES2017, JSX, and Flow. It removes | ||
support for language features from [ES2017](https://github.com/tc39/proposals/blob/master/finished-proposals.md), [JSX](https://facebook.github.io/jsx/), and [Flow](https://flow.org/). It removes | ||
all original styling and ensures that all outputted JavaScript | ||
conforms to a consistent style. (See this [blog post](http://jlongster.com/A-Prettier-Formatter)) | ||
*Warning*: This is a beta, and the format may change over time. If you | ||
If you are interested in the details, you can watch those two conference talks: | ||
<a href="https://www.youtube.com/watch?v=hkfBvpEfWdA"><img width="298" src="https://cloud.githubusercontent.com/assets/197597/24886367/dda8a6f0-1e08-11e7-865b-22492450f10f.png"></a> <a href="https://www.youtube.com/watch?v=ziAShzxAVKY"><img width="298" src="https://cloud.githubusercontent.com/assets/197597/24886368/ddacd6f8-1e08-11e7-806a-9febd23cbf47.png"></a> | ||
*Warning*: This is a **beta**, and the format may change over time. If you | ||
aren't OK with the format changing, wait for a more stable version. | ||
This goes way beyond [eslint](http://eslint.org/) and other projects | ||
[built on it](https://github.com/feross/standard). Unlike eslint, | ||
This goes way beyond [ESLint](http://eslint.org/) and other projects | ||
[built on it](https://github.com/feross/standard). Unlike ESLint, | ||
there aren't a million configuration options and rules. But more | ||
importantly: **everything is fixable**. This works because prettier | ||
never "checks" anything; it takes JavaScript as input and outputs the | ||
importantly: **everything is fixable**. This works because Prettier | ||
never "checks" anything; it takes JavaScript as input and delivers the | ||
formatted JavaScript as output. | ||
In technical terms: prettier parses your JavaScript into an AST and | ||
In technical terms: Prettier parses your JavaScript into an AST (Abstract Syntax Tree) and | ||
pretty-prints the AST, completely ignoring any of the original | ||
@@ -29,5 +59,5 @@ formatting. Say hello to completely consistent syntax! | ||
There's an extremely important piece missing from existing styling | ||
tools: **the maximum line length**. Sure, you can tell eslint to warn | ||
tools: **the maximum line length**. Sure, you can tell ESLint to warn | ||
you when you have a line that's too long, but that's an after-thought | ||
(eslint *never* knows how to fix it). The maximum line length is a | ||
(ESLint *never* knows how to fix it). The maximum line length is a | ||
critical piece the formatter needs for laying out and wrapping code. | ||
@@ -112,3 +142,3 @@ | ||
Run prettier through the CLI with this script. Run it without any | ||
Run Prettier through the CLI with this script. Run it without any | ||
arguments to see the options. | ||
@@ -129,3 +159,3 @@ | ||
(Don't forget the quotes around the globs! The quotes make sure that prettier | ||
(Don't forget the quotes around the globs! The quotes make sure that Prettier | ||
expands the globs rather than your shell, for cross-platform usage.) | ||
@@ -182,3 +212,3 @@ | ||
The API is a single function exported as `format`. The options | ||
The API has two functions, exported as `format` and `check`. The options | ||
argument is optional, and all of the defaults are shown below: | ||
@@ -190,2 +220,5 @@ | ||
prettier.format(source, { | ||
// Indent lines with tabs | ||
useTabs: false, | ||
// Fit code within this line limit | ||
@@ -217,15 +250,57 @@ printWidth: 80, | ||
// Which parser to use. Valid options are 'flow' and 'babylon' | ||
parser: 'babylon' | ||
parser: 'babylon', | ||
// Whether to add a semicolon at the end of every line (semi: true), | ||
// or only at the beginning of lines that may introduce ASI failures (semi: false) | ||
semi: true | ||
}); | ||
``` | ||
`check` checks to see if the file has been formatted with Prettier given those options and returns a Boolean. | ||
This is similar to the `--list-different` parameter in the CLI and is useful for running Prettier in CI scenarios. | ||
### Excluding code from formatting | ||
A JavaScript comment of `// prettier-ignore` will exclude the next node in the abstract syntax tree from formatting. | ||
For example: | ||
```js | ||
matrix( | ||
1, 0, 0, | ||
0, 1, 0, | ||
0, 0, 1 | ||
) | ||
// prettier-ignore | ||
matrix( | ||
1, 0, 0, | ||
0, 1, 0, | ||
0, 0, 1 | ||
) | ||
``` | ||
will be transformed to: | ||
```js | ||
matrix(1, 0, 0, 0, 1, 0, 0, 0, 1); | ||
// prettier-ignore | ||
matrix( | ||
1, 0, 0, | ||
0, 1, 0, | ||
0, 0, 1 | ||
) | ||
``` | ||
## Editor Integration | ||
### Atom | ||
Atom users can simply install the `prettier-atom` package and use | ||
ctrl+alt+f to format a file (or format on save if turned on). | ||
Atom users can simply install the [prettier-atom](https://github.com/prettier/prettier-atom) package and use | ||
`Ctrl+Alt+F` to format a file (or format on save if enabled). | ||
### Emacs | ||
Emacs users should see [this | ||
folder](https://github.com/jlongster/prettier/tree/master/editors/emacs) | ||
Emacs users should see [this directory](https://github.com/prettier/prettier/tree/master/editors/emacs) | ||
for on-demand formatting. | ||
@@ -235,13 +310,25 @@ | ||
For Vim users, there are two main approaches: one that leans on [sbdchd](https://github.com/sbdchd)/[neoformat](https://github.com/sbdchd/neoformat), which has the advantage of leaving the cursor in the same position despite changes, or a vanilla approach which can only approximate the cursor location, but might be good enough for your needs. | ||
#### Vanilla approach | ||
Vim users can add the following to their `.vimrc`: | ||
``` | ||
```vim | ||
autocmd FileType javascript set formatprg=prettier\ --stdin | ||
``` | ||
If you use the [vim-jsx](https://github.com/mxw/vim-jsx) plugin without | ||
requiring the `.jsx` file extension (See https://github.com/mxw/vim-jsx#usage), | ||
the FileType needs to include `javascript.jsx`: | ||
```vim | ||
autocmd FileType javascript.jsx,javascript setlocal formatprg=prettier\ --stdin | ||
``` | ||
This makes Prettier power the [`gq` command](http://vimdoc.sourceforge.net/htmldoc/change.html#gq) | ||
for automatic formatting without any plugins. You can also add the following to your | ||
`.vimrc` to run prettier when `.js` files are saved: | ||
`.vimrc` to run Prettier when `.js` files are saved: | ||
``` | ||
```vim | ||
autocmd BufWritePre *.js :normal gggqG | ||
@@ -254,17 +341,46 @@ ``` | ||
``` | ||
```vim | ||
autocmd BufWritePre *.js exe "normal! gggqG\<C-o>\<C-o>" | ||
``` | ||
#### Neoformat approach | ||
Add [sbdchd](https://github.com/sbdchd)/[neoformat](https://github.com/sbdchd/neoformat) to your list based on the tool you use: | ||
```vim | ||
Plug 'sbdchd/neoformat' | ||
``` | ||
Then make Neoformat run on save: | ||
```vim | ||
autocmd BufWritePre *.js Neoformat | ||
``` | ||
#### Customizing Prettier in Vim | ||
If your project requires settings other than the default Prettier settings, you can pass arguments to do so in your `.vimrc` or [vim project](http://vim.wikia.com/wiki/Project_specific_settings), you can do so: | ||
```vim | ||
autocmd FileType javascript set formatprg=prettier\ --stdin\ --parser\ flow\ --single-quote\ --trailing-comma\ es5 | ||
``` | ||
Each command needs to be escaped with `\`. If you are using Neoformat and you want it to recognize your formatprg settings you can also do that by adding the following to your `.vimrc`: | ||
```vim | ||
" Use formatprg when available | ||
let g:neoformat_try_formatprg = 1 | ||
``` | ||
### Visual Studio Code | ||
Can be installed using the extension sidebar. Search for `Prettier - JavaScript formatter` | ||
Can be installed using the extension sidebar. Search for `Prettier - JavaScript formatter`. | ||
Can also be installed using `ext install prettier-vscode` | ||
Can also be installed using `ext install prettier-vscode`. | ||
[Check repository for configuration and shortcuts](https://github.com/esbenp/prettier-vscode) | ||
[Check its repository for configuration and shortcuts](https://github.com/esbenp/prettier-vscode) | ||
### Visual Studio | ||
Install the [JavaScript Prettier extension](https://github.com/madskristensen/JavaScriptPrettier) | ||
Install the [JavaScript Prettier extension](https://github.com/madskristensen/JavaScriptPrettier). | ||
@@ -278,4 +394,4 @@ ### Sublime Text | ||
JetBrains users can configure `prettier` as an **External Tool** see [this | ||
blog post](https://blog.jetbrains.com/webstorm/2016/08/using-external-tools/) or [this | ||
JetBrains users can configure `prettier` as an **External Tool**. | ||
See [this blog post](https://blog.jetbrains.com/webstorm/2016/08/using-external-tools/) or [this | ||
directory](https://github.com/jlongster/prettier/tree/master/editors/jetbrains) with examples. | ||
@@ -289,5 +405,5 @@ | ||
including non-standardized ones. By default it uses the | ||
[babylon](https://github.com/babel/babylon) parser with all language | ||
features enabled, but you can also use | ||
[flow](https://github.com/facebook/flow) parser with the | ||
[Babylon](https://github.com/babel/babylon) parser with all language | ||
features enabled, but you can also use the | ||
[Flow](https://github.com/facebook/flow) parser with the | ||
`parser` API or `--parser` CLI option. | ||
@@ -300,11 +416,13 @@ | ||
- [`eslint-plugin-prettier`](https://github.com/not-an-aardvark/eslint-plugin-prettier) plugs prettier into your ESLint workflow | ||
- [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) turns off all ESLint rules that are unnecessary or might conflict with prettier | ||
- [`eslint-plugin-prettier`](https://github.com/not-an-aardvark/eslint-plugin-prettier) plugs Prettier into your ESLint workflow | ||
- [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) turns off all ESLint rules that are unnecessary or might conflict with Prettier | ||
- [`prettier-eslint`](https://github.com/prettier/prettier-eslint) | ||
passes `prettier` output to `eslint --fix` | ||
- [`prettier-standard`](https://github.com/sheerun/prettier-standard) | ||
uses `prettier` and `prettier-eslint` to format code with standard rules | ||
- [`prettier-standard-formatter`](https://github.com/dtinth/prettier-standard-formatter) | ||
passes `prettier` output to `standard --fix` | ||
- [`prettier-with-tabs`](https://github.com/arijs/prettier-with-tabs) | ||
allows you to configure prettier to use `tabs` | ||
- [`neutrino-preset-prettier`](https://github.com/SpencerCDixon/neutrino-preset-prettier) allows you to use prettier as a neutrino preset | ||
- [`prettier-miscellaneous`](https://github.com/arijs/prettier-miscellaneous) | ||
`prettier` with a few minor extra options | ||
- [`neutrino-preset-prettier`](https://github.com/SpencerCDixon/neutrino-preset-prettier) allows you to use Prettier as a Neutrino preset | ||
@@ -337,21 +455,38 @@ | ||
## Badge | ||
Show the world you're using *Prettier* → [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) | ||
```md | ||
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) | ||
``` | ||
## Contributing | ||
We will work on better docs over time, but in the mean time, here are | ||
a few notes if you are interested in contributing: | ||
To get up and running, install the dependencies and run the tests: | ||
* You should be able to get up and running with just `yarn` | ||
* This uses jest snapshots for tests. The entire Flow test suite is | ||
included here and you can make changes and run `jest -u` and then | ||
`git diff` to see the styles that changed. Always update the | ||
snapshots if opening a PR. | ||
* If you can, look at [commands.md](commands.md) and check out | ||
[Wadler's | ||
paper](http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf) | ||
to understand how this works. I will try to write a better explanation soon. | ||
* I haven't set up any automated tests yet, but for now as long as you | ||
run `jest -u` to update the snapshots and I see them in the PR, that's fine. | ||
* You can run `AST_COMPARE=1 jest` for a more robust test run. That | ||
formats each file, re-parses it, and compares the new AST with the | ||
original one and makes sure they are semantically equivalent. | ||
* Each test folder has a `jsfmt.spec.js` that runs the tests. Normally you can just put `run_spec(__dirname);` there but if you want to pass specific options you can add the options object as the 2nd parameter like: `run_spec(__dirname, { parser: 'babylon' });` | ||
``` | ||
yarn | ||
yarn test | ||
``` | ||
Here's what you need to know about the tests: | ||
* The tests uses [Jest](https://facebook.github.io/jest/) snapshots. | ||
* You can make changes and run `jest -u` to update the snapshots. Then run `git | ||
diff` to take a look at what changed. Always update the snapshots when opening | ||
a PR. | ||
* You can run `AST_COMPARE=1 jest` for a more robust test run. That formats each | ||
file, re-parses it, and compares the new AST with the original one and makes | ||
sure they are semantically equivalent. | ||
* Each test folder has a `jsfmt.spec.js` that runs the tests. Normally you can | ||
just put `run_spec(__dirname);` there. You can also pass options and | ||
additional parsers, like this: | ||
`run_spec(__dirname, { trailingComma: "es5" }, ["babylon"]);` | ||
* `tests/flow/` contains the Flow test suite, and is not supposed to be edited | ||
by hand. To update it, clone the Flow repo next to the Prettier repo and run: | ||
`node scripts/sync-flow-tests.js ../flow/tests/`. | ||
If you can, take look at [commands.md](commands.md) and check out [Wadler's | ||
paper](http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf) to | ||
understand how Prettier works. |
@@ -14,2 +14,3 @@ "use strict"; | ||
var indent = docBuilders.indent; | ||
var align = docBuilders.align; | ||
var lineSuffix = docBuilders.lineSuffix; | ||
@@ -22,2 +23,4 @@ var join = docBuilders.join; | ||
var locEnd = util.locEnd; | ||
var getNextNonSpaceNonCommentCharacter = | ||
util.getNextNonSpaceNonCommentCharacter; | ||
@@ -41,3 +44,6 @@ // TODO Move a non-caching implementation of this function into ast-types, | ||
for (var i = resultArray.length - 1; i >= 0; --i) { | ||
if (locEnd(resultArray[i]) - locStart(node) <= 0) { | ||
if ( | ||
locStart(resultArray[i]) <= locStart(node) && | ||
locEnd(resultArray[i]) <= locEnd(node) | ||
) { | ||
break; | ||
@@ -85,3 +91,3 @@ } | ||
while (left < right) { | ||
var middle = left + right >> 1; | ||
var middle = (left + right) >> 1; | ||
var child = childNodes[middle]; | ||
@@ -153,2 +159,3 @@ | ||
handleLastFunctionArgComments( | ||
text, | ||
precedingNode, | ||
@@ -160,3 +167,9 @@ enclosingNode, | ||
handleMemberExpressionComments(enclosingNode, followingNode, comment) || | ||
handleIfStatementComments(enclosingNode, followingNode, comment) || | ||
handleIfStatementComments( | ||
text, | ||
precedingNode, | ||
enclosingNode, | ||
followingNode, | ||
comment | ||
) || | ||
handleTryStatementComments(enclosingNode, followingNode, comment) || | ||
@@ -166,2 +179,3 @@ handleClassComments(enclosingNode, comment) || | ||
handleObjectPropertyComments(enclosingNode, comment) || | ||
handleForComments(enclosingNode, precedingNode, comment) || | ||
handleUnionTypeComments( | ||
@@ -173,3 +187,9 @@ precedingNode, | ||
) || | ||
handleOnlyComments(enclosingNode, ast, comment, isLastComment) | ||
handleOnlyComments(enclosingNode, ast, comment, isLastComment) || | ||
handleImportDeclarationComments( | ||
enclosingNode, | ||
precedingNode, | ||
comment | ||
) || | ||
handleAssignmentPatternComments(enclosingNode, comment) | ||
) { | ||
@@ -199,7 +219,18 @@ // We're good | ||
handleTemplateLiteralComments(enclosingNode, comment) || | ||
handleIfStatementComments( | ||
text, | ||
precedingNode, | ||
enclosingNode, | ||
followingNode, | ||
comment | ||
) || | ||
handleClassComments(enclosingNode, comment) || | ||
handleLabeledStatementComments(enclosingNode, comment) || | ||
handleCallExpressionComments(precedingNode, enclosingNode, comment) || | ||
handlePropertyComments(enclosingNode, comment) || | ||
handleExportNamedDeclarationComments(enclosingNode, comment) || | ||
handleOnlyComments(enclosingNode, ast, comment, isLastComment) | ||
handleOnlyComments(enclosingNode, ast, comment, isLastComment) || | ||
handleClassMethodComments(enclosingNode, comment) || | ||
handleTypeAliasComments(enclosingNode, followingNode, comment) || | ||
handleVariableDeclaratorComments(enclosingNode, followingNode, comment) | ||
) { | ||
@@ -221,3 +252,9 @@ // We're good | ||
if ( | ||
handleIfStatementComments(enclosingNode, followingNode, comment) || | ||
handleIfStatementComments( | ||
text, | ||
precedingNode, | ||
enclosingNode, | ||
followingNode, | ||
comment | ||
) || | ||
handleObjectPropertyAssignment(enclosingNode, precedingNode, comment) || | ||
@@ -368,3 +405,9 @@ handleTemplateLiteralComments(enclosingNode, comment) || | ||
// } | ||
function handleIfStatementComments(enclosingNode, followingNode, comment) { | ||
function handleIfStatementComments( | ||
text, | ||
precedingNode, | ||
enclosingNode, | ||
followingNode, | ||
comment | ||
) { | ||
if ( | ||
@@ -376,2 +419,13 @@ !enclosingNode || enclosingNode.type !== "IfStatement" || !followingNode | ||
// We unfortunately have no way using the AST or location of nodes to know | ||
// if the comment is positioned before or after the condition parenthesis: | ||
// if (a /* comment */) {} | ||
// if (a) /* comment */ {} | ||
// The only workaround I found is to look at the next character to see if | ||
// it is a ). | ||
if (getNextNonSpaceNonCommentCharacter(text, comment) === ")") { | ||
addTrailingComment(precedingNode, comment); | ||
return true; | ||
} | ||
if (followingNode.type === "BlockStatement") { | ||
@@ -437,3 +491,4 @@ addBlockStatementFirstComment(followingNode, comment); | ||
) { | ||
const isSameLineAsPrecedingNode = precedingNode && | ||
const isSameLineAsPrecedingNode = | ||
precedingNode && | ||
!util.hasNewlineInRange(text, locEnd(precedingNode), locStart(comment)); | ||
@@ -492,5 +547,5 @@ | ||
enclosingNode.type === "ObjectMethod") && | ||
enclosingNode.params.length === 0) || | ||
(enclosingNode.type === "CallExpression" && | ||
enclosingNode.arguments.length === 0)) | ||
enclosingNode.params.length === 0) || | ||
(enclosingNode.type === "CallExpression" && | ||
enclosingNode.arguments.length === 0)) | ||
) { | ||
@@ -500,5 +555,7 @@ addDanglingComment(enclosingNode, comment); | ||
} | ||
if (enclosingNode && | ||
if ( | ||
enclosingNode && | ||
(enclosingNode.type === "MethodDefinition" && | ||
enclosingNode.value.params.length === 0)) { | ||
enclosingNode.value.params.length === 0) | ||
) { | ||
addDanglingComment(enclosingNode.value, comment); | ||
@@ -511,2 +568,3 @@ return true; | ||
function handleLastFunctionArgComments( | ||
text, | ||
precedingNode, | ||
@@ -533,8 +591,11 @@ enclosingNode, | ||
precedingNode && | ||
precedingNode.type === "Identifier" && | ||
(precedingNode.type === "Identifier" || | ||
precedingNode.type === "AssignmentPattern") && | ||
enclosingNode && | ||
(enclosingNode.type === "ArrowFunctionExpression" || | ||
enclosingNode.type === "FunctionExpression") && | ||
followingNode && | ||
followingNode.type !== "Identifier" | ||
enclosingNode.type === "FunctionExpression" || | ||
enclosingNode.type === "FunctionDeclaration" || | ||
enclosingNode.type === "ObjectMethod" || | ||
enclosingNode.type === "ClassMethod") && | ||
getNextNonSpaceNonCommentCharacter(text, comment) === ")" | ||
) { | ||
@@ -575,2 +636,10 @@ addTrailingComment(precedingNode, comment); | ||
function handleLabeledStatementComments(enclosingNode, comment) { | ||
if (enclosingNode && enclosingNode.type === "LabeledStatement") { | ||
addLeadingComment(enclosingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleCallExpressionComments(precedingNode, enclosingNode, comment) { | ||
@@ -596,10 +665,3 @@ if ( | ||
) { | ||
if ( | ||
enclosingNode && | ||
enclosingNode.type === "UnionTypeAnnotation" && | ||
precedingNode && | ||
precedingNode.type === "ObjectTypeAnnotation" && | ||
followingNode && | ||
followingNode.type === "ObjectTypeAnnotation" | ||
) { | ||
if (enclosingNode && enclosingNode.type === "UnionTypeAnnotation") { | ||
addTrailingComment(precedingNode, comment); | ||
@@ -613,6 +675,5 @@ return true; | ||
if ( | ||
enclosingNode && ( | ||
enclosingNode.type === "Property" || | ||
enclosingNode.type === "ObjectProperty" | ||
) | ||
enclosingNode && | ||
(enclosingNode.type === "Property" || | ||
enclosingNode.type === "ObjectProperty") | ||
) { | ||
@@ -643,4 +704,6 @@ addLeadingComment(enclosingNode, comment); | ||
} else if ( | ||
enclosingNode && enclosingNode.type === 'Program' && | ||
enclosingNode.body.length === 0 && enclosingNode.directives && | ||
enclosingNode && | ||
enclosingNode.type === "Program" && | ||
enclosingNode.body.length === 0 && | ||
enclosingNode.directives && | ||
enclosingNode.directives.length === 0 | ||
@@ -658,2 +721,74 @@ ) { | ||
function handleForComments(enclosingNode, precedingNode, comment) { | ||
if ( | ||
enclosingNode && | ||
(enclosingNode.type === "ForInStatement" || | ||
enclosingNode.type === "ForOfStatement") | ||
) { | ||
addLeadingComment(enclosingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleImportDeclarationComments( | ||
enclosingNode, | ||
precedingNode, | ||
comment | ||
) { | ||
if ( | ||
precedingNode && | ||
enclosingNode && | ||
enclosingNode.type === "ImportDeclaration" && | ||
comment.type !== "CommentBlock" && | ||
comment.type !== "Block" | ||
) { | ||
addTrailingComment(precedingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleAssignmentPatternComments(enclosingNode, comment) { | ||
if (enclosingNode && enclosingNode.type === "AssignmentPattern") { | ||
addLeadingComment(enclosingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleClassMethodComments(enclosingNode, comment) { | ||
if (enclosingNode && enclosingNode.type === "ClassMethod") { | ||
addTrailingComment(enclosingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleTypeAliasComments(enclosingNode, followingNode, comment) { | ||
if (enclosingNode && enclosingNode.type === "TypeAlias") { | ||
addLeadingComment(enclosingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function handleVariableDeclaratorComments( | ||
enclosingNode, | ||
followingNode, | ||
comment | ||
) { | ||
if ( | ||
enclosingNode && | ||
enclosingNode.type === "VariableDeclarator" && | ||
followingNode && | ||
(followingNode.type === "ObjectExpression" || | ||
followingNode.type === "ArrayExpression") | ||
) { | ||
addLeadingComment(followingNode, comment); | ||
return true; | ||
} | ||
return false; | ||
} | ||
function printComment(commentPath) { | ||
@@ -769,11 +904,8 @@ const comment = commentPath.getValue(); | ||
path.each( | ||
commentPath => { | ||
const comment = commentPath.getValue(); | ||
if (!comment.leading && !comment.trailing) { | ||
parts.push(printComment(commentPath)); | ||
} | ||
}, | ||
"comments" | ||
); | ||
path.each(commentPath => { | ||
const comment = commentPath.getValue(); | ||
if (!comment.leading && !comment.trailing) { | ||
parts.push(printComment(commentPath)); | ||
} | ||
}, "comments"); | ||
@@ -787,3 +919,3 @@ if (parts.length === 0) { | ||
} | ||
return indent(options.tabWidth, concat([hardline, join(hardline, parts)])); | ||
return indent(concat([hardline, join(hardline, parts)])); | ||
} | ||
@@ -804,25 +936,20 @@ | ||
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) { | ||
leadingParts.push(printLeadingComment(commentPath, print, options)); | ||
if (leading) { | ||
leadingParts.push(printLeadingComment(commentPath, print, options)); | ||
const text = options.originalText; | ||
if ( | ||
util.hasNewline(text, util.skipNewline(text, util.locEnd(comment))) | ||
) { | ||
leadingParts.push(hardline); | ||
} | ||
} else if (trailing) { | ||
trailingParts.push( | ||
printTrailingComment(commentPath, print, options, parent) | ||
); | ||
const text = options.originalText; | ||
if (util.hasNewline(text, util.skipNewline(text, util.locEnd(comment)))) { | ||
leadingParts.push(hardline); | ||
} | ||
}, | ||
"comments" | ||
); | ||
} else if (trailing) { | ||
trailingParts.push( | ||
printTrailingComment(commentPath, print, options, parent) | ||
); | ||
} | ||
}, "comments"); | ||
@@ -829,0 +956,0 @@ return concat(leadingParts.concat(trailingParts)); |
@@ -28,8 +28,14 @@ "use strict"; | ||
function indent(n, contents) { | ||
function indent(contents) { | ||
assertDoc(contents); | ||
return { type: "indent", contents, n }; | ||
return { type: "indent", contents }; | ||
} | ||
function align(n, contents) { | ||
assertDoc(contents); | ||
return { type: "align", contents, n }; | ||
} | ||
function group(contents, opts) { | ||
@@ -108,3 +114,4 @@ opts = opts || {}; | ||
ifBreak, | ||
indent | ||
indent, | ||
align | ||
}; |
@@ -70,10 +70,16 @@ "use strict"; | ||
if (doc.type === "indent") { | ||
return "indent(" + doc.n + ", " + printDoc(doc.contents) + ")"; | ||
return "indent(" + printDoc(doc.contents) + ")"; | ||
} | ||
if (doc.type === "align") { | ||
return "align(" + doc.n + ", " + printDoc(doc.contents) + ")"; | ||
} | ||
if (doc.type === "if-break") { | ||
return "ifBreak(" + | ||
return ( | ||
"ifBreak(" + | ||
printDoc(doc.breakContents) + | ||
(doc.flatContents ? ", " + printDoc(doc.flatContents) : "") + | ||
")"; | ||
")" | ||
); | ||
} | ||
@@ -83,12 +89,16 @@ | ||
if (doc.expandedStates) { | ||
return "conditionalGroup(" + | ||
return ( | ||
"conditionalGroup(" + | ||
"[" + | ||
doc.expandedStates.map(printDoc).join(",") + | ||
"])"; | ||
"])" | ||
); | ||
} | ||
return (doc.break ? "wrappedGroup" : "group") + | ||
return ( | ||
(doc.break ? "wrappedGroup" : "group") + | ||
"(" + | ||
printDoc(doc.contents) + | ||
")"; | ||
")" | ||
); | ||
} | ||
@@ -100,2 +110,6 @@ | ||
if (doc.type === "line-suffix-boundary") { | ||
return "lineSuffixBoundary"; | ||
} | ||
throw new Error("Unknown doc type " + doc.type); | ||
@@ -102,0 +116,0 @@ } |
@@ -6,2 +6,29 @@ "use strict"; | ||
function rootIndent() { | ||
return { | ||
indent: 0, | ||
align: { | ||
spaces: 0, | ||
tabs: 0 | ||
} | ||
}; | ||
} | ||
function makeIndent(ind) { | ||
return { | ||
indent: ind.indent + 1, | ||
align: ind.align | ||
}; | ||
} | ||
function makeAlign(ind, n) { | ||
return { | ||
indent: ind.indent, | ||
align: { | ||
spaces: ind.align.spaces + n, | ||
tabs: ind.align.tabs + (n ? 1 : 0) | ||
} | ||
}; | ||
} | ||
function fits(next, restCommands, width) { | ||
@@ -39,5 +66,9 @@ let restIdx = restCommands.length; | ||
case "indent": | ||
cmds.push([ind + doc.n, mode, doc.contents]); | ||
cmds.push([makeIndent(ind), mode, doc.contents]); | ||
break; | ||
case "align": | ||
cmds.push([makeAlign(ind, doc.n), mode, doc.contents]); | ||
break; | ||
case "group": | ||
@@ -82,5 +113,5 @@ cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]); | ||
function printDocToString(doc, width, newLine) { | ||
newLine = newLine || "\n"; | ||
function printDocToString(doc, options) { | ||
let width = options.printWidth; | ||
let newLine = options.newLine || "\n"; | ||
let pos = 0; | ||
@@ -90,3 +121,3 @@ // cmds is basically a stack. We've turned a recursive call into a | ||
// cmds to the array instead of recursively calling `print`. | ||
let cmds = [[0, MODE_BREAK, doc]]; | ||
let cmds = [[rootIndent(), MODE_BREAK, doc]]; | ||
let out = []; | ||
@@ -115,5 +146,9 @@ let shouldRemeasure = false; | ||
case "indent": | ||
cmds.push([ind + doc.n, mode, doc.contents]); | ||
cmds.push([makeIndent(ind), mode, doc.contents]); | ||
break; | ||
case "align": | ||
cmds.push([makeAlign(ind, doc.n), mode, doc.contents]); | ||
break; | ||
case "group": | ||
@@ -150,5 +185,4 @@ switch (mode) { | ||
if (doc.expandedStates) { | ||
const mostExpanded = doc.expandedStates[ | ||
doc.expandedStates.length - 1 | ||
]; | ||
const mostExpanded = | ||
doc.expandedStates[doc.expandedStates.length - 1]; | ||
@@ -248,4 +282,8 @@ if (doc.break) { | ||
out.push(newLine + " ".repeat(ind)); | ||
pos = ind; | ||
let length = ind.indent * options.tabWidth + ind.align.spaces; | ||
let indentString = options.useTabs | ||
? "\t".repeat(ind.indent + ind.align.tabs) | ||
: " ".repeat(length); | ||
out.push(newLine + indentString); | ||
pos = length; | ||
} | ||
@@ -252,0 +290,0 @@ break; |
"use strict"; | ||
function traverseDoc(doc, onEnter, onExit) { | ||
function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) { | ||
var hasStopped = false; | ||
@@ -24,2 +24,8 @@ function traverseDocRec(doc) { | ||
} | ||
} else if (doc.type === "group" && doc.expandedStates) { | ||
if (shouldTraverseConditionalGroups) { | ||
doc.expandedStates.forEach(traverseDocRec); | ||
} else { | ||
traverseDocRec(doc.contents); | ||
} | ||
} else if (doc.contents) { | ||
@@ -72,14 +78,2 @@ traverseDocRec(doc.contents); | ||
function getFirstString(doc) { | ||
return findInDoc( | ||
doc, | ||
doc => { | ||
if (typeof doc === "string" && doc.trim().length !== 0) { | ||
return doc; | ||
} | ||
}, | ||
null | ||
); | ||
} | ||
function isLineNext(doc) { | ||
@@ -110,2 +104,5 @@ return findInDoc( | ||
} | ||
if (doc.type === "break-parent") { | ||
return true; | ||
} | ||
}, | ||
@@ -147,3 +144,4 @@ false | ||
} | ||
} | ||
}, | ||
/* shouldTraverseConditionalGroups */ true | ||
); | ||
@@ -154,3 +152,2 @@ } | ||
isEmpty, | ||
getFirstString, | ||
willBreak, | ||
@@ -157,0 +154,0 @@ isLineNext, |
@@ -238,4 +238,7 @@ "use strict"; | ||
if ( | ||
parent.type === "ArrowFunctionExpression" && parent.body === node && startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ false) | ||
|| parent.type === "ExpressionStatement" && startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ true) | ||
(parent.type === "ArrowFunctionExpression" && | ||
parent.body === node && | ||
startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ false)) || | ||
(parent.type === "ExpressionStatement" && | ||
startsWithNoLookaheadToken(node, /* forbidFunctionAndClass */ true)) | ||
) { | ||
@@ -247,2 +250,5 @@ return true; | ||
case "CallExpression": | ||
if (parent.type === "NewExpression" && parent.callee === node) { | ||
return true; | ||
} | ||
return false; | ||
@@ -252,18 +258,24 @@ | ||
case "SpreadProperty": | ||
return parent.type === "MemberExpression" && | ||
return ( | ||
parent.type === "MemberExpression" && | ||
name === "object" && | ||
parent.object === node; | ||
parent.object === node | ||
); | ||
case "UpdateExpression": | ||
if (parent.type === "UnaryExpression") { | ||
return node.prefix && | ||
return ( | ||
node.prefix && | ||
((node.operator === "++" && parent.operator === "+") || | ||
(node.operator === "--" && parent.operator === "-")); | ||
(node.operator === "--" && parent.operator === "-")) | ||
); | ||
} | ||
// else fall through | ||
// else fall through | ||
case "UnaryExpression": | ||
switch (parent.type) { | ||
case "UnaryExpression": | ||
return node.operator === parent.operator && | ||
(node.operator === "+" || node.operator === "-"); | ||
return ( | ||
node.operator === parent.operator && | ||
(node.operator === "+" || node.operator === "-") | ||
); | ||
@@ -278,3 +290,3 @@ case "MemberExpression": | ||
case "CallExpression": | ||
return name === "callee" && parent.callee == node; | ||
return name === "callee" && parent.callee === node; | ||
@@ -306,3 +318,3 @@ case "BinaryExpression": | ||
} | ||
// else fall through | ||
// else fall through | ||
case "LogicalExpression": | ||
@@ -347,2 +359,8 @@ switch (parent.type) { | ||
// Add parenthesis when working with binary operators | ||
// It's not stricly needed but helps with code understanding | ||
if (["|", "^", "&", ">>", "<<", ">>>"].indexOf(po) !== -1) { | ||
return true; | ||
} | ||
default: | ||
@@ -377,3 +395,3 @@ return false; | ||
} | ||
// else fall through | ||
// else fall through | ||
case "AwaitExpression": | ||
@@ -405,6 +423,8 @@ switch (parent.type) { | ||
case "UnionTypeAnnotation": | ||
return parent.type === "ArrayTypeAnnotation" || | ||
return ( | ||
parent.type === "ArrayTypeAnnotation" || | ||
parent.type === "NullableTypeAnnotation" || | ||
parent.type === "IntersectionTypeAnnotation" || | ||
parent.type === "UnionTypeAnnotation"; | ||
parent.type === "UnionTypeAnnotation" | ||
); | ||
@@ -415,11 +435,15 @@ case "NullableTypeAnnotation": | ||
case "FunctionTypeAnnotation": | ||
return parent.type === "UnionTypeAnnotation" || | ||
parent.type === "IntersectionTypeAnnotation"; | ||
return ( | ||
parent.type === "UnionTypeAnnotation" || | ||
parent.type === "IntersectionTypeAnnotation" | ||
); | ||
case "NumericLiteral": | ||
case "Literal": | ||
return parent.type === "MemberExpression" && | ||
return ( | ||
parent.type === "MemberExpression" && | ||
isNumber.check(node.value) && | ||
name === "object" && | ||
parent.object === node; | ||
parent.object === node | ||
); | ||
@@ -436,2 +460,4 @@ case "AssignmentExpression": | ||
return node.left.type === "ObjectPattern"; | ||
} else if (parent.type === "AssignmentExpression") { | ||
return false; | ||
} | ||
@@ -448,5 +474,6 @@ return true; | ||
case "LogicalExpression": | ||
case "LogicalExpression": | ||
case "ExportDefaultDeclaration": | ||
case "AwaitExpression": | ||
case "JSXSpreadAttribute": | ||
case "ArrowFunctionExpression": | ||
return true; | ||
@@ -493,3 +520,3 @@ | ||
case "TaggedTemplateExpression": | ||
case "UnaryExpression": | ||
case "UnaryExpression": | ||
case "LogicalExpression": | ||
@@ -573,7 +600,16 @@ case "BinaryExpression": | ||
case "UpdateExpression": | ||
return !node.prefix && startsWithNoLookaheadToken(node.argument, forbidFunctionAndClass); | ||
return ( | ||
!node.prefix && | ||
startsWithNoLookaheadToken(node.argument, forbidFunctionAndClass) | ||
); | ||
case "BindExpression": | ||
return node.object && startsWithNoLookaheadToken(node.object, forbidFunctionAndClass); | ||
return ( | ||
node.object && | ||
startsWithNoLookaheadToken(node.object, forbidFunctionAndClass) | ||
); | ||
case "SequenceExpression": | ||
return startsWithNoLookaheadToken(node.expressions[0], forbidFunctionAndClass) | ||
return startsWithNoLookaheadToken( | ||
node.expressions[0], | ||
forbidFunctionAndClass | ||
); | ||
default: | ||
@@ -580,0 +616,0 @@ return false; |
@@ -7,2 +7,3 @@ "use strict"; | ||
var defaults = { | ||
useTabs: false, | ||
tabWidth: 2, | ||
@@ -14,3 +15,4 @@ printWidth: 80, | ||
jsxBracketSameLine: false, | ||
parser: "babylon" | ||
parser: "babylon", | ||
semi: true | ||
}; | ||
@@ -17,0 +19,0 @@ |
@@ -19,8 +19,4 @@ "use strict"; | ||
}; | ||
const msg = ast.errors[0].message + | ||
" (" + | ||
loc.line + | ||
":" + | ||
loc.column + | ||
")"; | ||
const msg = | ||
ast.errors[0].message + " (" + loc.line + ":" + loc.column + ")"; | ||
const error = new SyntaxError(msg); | ||
@@ -59,14 +55,17 @@ error.loc = loc; | ||
function parseWithTypeScript(text) { | ||
const parser = require('typescript-eslint-parser') | ||
return parser.parse(text, { | ||
loc: true, | ||
range: true, | ||
tokens: true, | ||
attachComment: true, | ||
ecmaFeatures: { | ||
jsx: true, | ||
} | ||
}) | ||
// While we are working on typescript, we are putting it in devDependencies | ||
// so it shouldn't be picked up by static analysis | ||
const r = require; | ||
const parser = r("typescript-eslint-parser"); | ||
return parser.parse(text, { | ||
loc: true, | ||
range: true, | ||
tokens: true, | ||
attachComment: true, | ||
ecmaFeatures: { | ||
jsx: true | ||
} | ||
}); | ||
} | ||
module.exports = { parseWithFlow, parseWithBabylon, parseWithTypeScript }; |
"use strict"; | ||
var assert = require("assert"); | ||
var types = require("ast-types"); | ||
@@ -170,16 +169,29 @@ var n = types.namedTypes; | ||
return false; | ||
} else if (backwards) { | ||
if (text.charAt(index) === "\n") { | ||
} | ||
const atIndex = text.charAt(index); | ||
if (backwards) { | ||
if ( | ||
atIndex === "\n" || | ||
atIndex === "\r" || | ||
atIndex === "\u2028" || | ||
atIndex === "\u2029" | ||
) { | ||
return index - 1; | ||
} | ||
if (text.charAt(index - 1) === "\r" && text.charAt(index) === "\n") { | ||
if (text.charAt(index - 1) === "\r" && atIndex === "\n") { | ||
return index - 2; | ||
} | ||
} else { | ||
if (text.charAt(index) === "\n") { | ||
if (atIndex === "\r" && text.charAt(index + 1) === "\n") { | ||
return index + 2; | ||
} | ||
if ( | ||
atIndex === "\n" || | ||
atIndex === "\r" || | ||
atIndex === "\u2028" || | ||
atIndex === "\u2029" | ||
) { | ||
return index + 1; | ||
} | ||
if (text.charAt(index) === "\r" && text.charAt(index + 1) === "\n") { | ||
return index + 2; | ||
} | ||
} | ||
@@ -219,6 +231,6 @@ | ||
let idx = locEnd(node); | ||
idx = skipToLineEnd(text, idx); | ||
while (idx !== oldIdx) { | ||
// We need to skip all the potential trailing inline comments | ||
oldIdx = idx; | ||
idx = skipToLineEnd(text, idx); | ||
idx = skipInlineComment(text, idx); | ||
@@ -232,2 +244,15 @@ idx = skipSpaces(text, idx); | ||
function getNextNonSpaceNonCommentCharacter(text, node) { | ||
let oldIdx = null; | ||
let idx = locEnd(node); | ||
while (idx !== oldIdx) { | ||
oldIdx = idx; | ||
idx = skipSpaces(text, idx); | ||
idx = skipInlineComment(text, idx); | ||
idx = skipTrailingComment(text, idx); | ||
idx = skipNewline(text, idx); | ||
} | ||
return text.charAt(idx); | ||
} | ||
function hasSpaces(text, index, opts) { | ||
@@ -270,12 +295,2 @@ opts = opts || {}; | ||
// 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, '<') | ||
// .replace(/>/g, '>'); | ||
} | ||
// http://stackoverflow.com/a/7124052 | ||
function htmlEscapeInsideAngleBracket(str) { | ||
@@ -321,2 +336,3 @@ return str.replace(/</g, "<").replace(/>/g, ">"); | ||
getLast, | ||
getNextNonSpaceNonCommentCharacter, | ||
skipWhitespace, | ||
@@ -334,4 +350,3 @@ skipSpaces, | ||
setLocEnd, | ||
htmlEscapeInsideDoubleQuote, | ||
htmlEscapeInsideAngleBracket | ||
}; |
79
test.js
@@ -1,71 +0,10 @@ | ||
// https://github.com/prettier/prettier/issues/959 | ||
Seq(typeDef.interface.groups).forEach(group => | ||
Seq(group.members).forEach((member, memberName) => | ||
markdownDoc( | ||
member.doc, | ||
{ typePath: typePath.concat(memberName.slice(1)), | ||
signatures: member.signatures } | ||
) | ||
) | ||
) | ||
// https://github.com/prettier/prettier/issues/760 | ||
const promiseFromCallback = fn => | ||
new Promise((resolve, reject) => | ||
fn((err, result) => { | ||
if (err) return reject(err); | ||
return resolve(result); | ||
}) | ||
); | ||
// https://github.com/prettier/prettier/pull/674 | ||
runtimeAgent.getProperties( | ||
objectId, | ||
false, // ownProperties | ||
false, // accessorPropertiesOnly | ||
false, // generatePreview | ||
(error, properties, internalProperties) => { | ||
return 1 | ||
}, | ||
); | ||
// https://github.com/prettier/prettier/pull/680 | ||
function render() { | ||
return ( | ||
<View> | ||
<Image | ||
onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})} | ||
/> | ||
</View> | ||
); | ||
function f() { | ||
return new Promise(( | ||
resolve: (event: any) => void, | ||
reject: (event: any) => void, | ||
) => { | ||
const resolveReject = new Map(); | ||
resolveReject.set('resolve', resolve); | ||
resolveReject.set('reject', reject); | ||
}); | ||
} | ||
function render() { | ||
return ( | ||
<View> | ||
<Image | ||
onProgress={e => | ||
this.setState({ | ||
progress: Math.round( | ||
100 * e.nativeEvent.loaded / e.nativeEvent.total, | ||
), | ||
})} | ||
/> | ||
</View> | ||
); | ||
} | ||
function render() { | ||
return ( | ||
<View> | ||
<Image | ||
onProgress={e => | ||
this.setState({ | ||
progress: Math.round( | ||
100 * e.nativeEvent.loaded / e.nativeEvent.total, | ||
), | ||
})} | ||
/> | ||
</View> | ||
); | ||
} |
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 not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1486116
31
33403
1
480
12
12
1
4
+ Addedglobal@^4.3.1
+ Addednpm@^4.5.0
+ Addedast-types@0.9.8(transitive)
+ Addedbabylon@7.0.0-beta.8(transitive)
+ Addeddom-walk@0.1.2(transitive)
+ Addedflow-parser@0.43.0(transitive)
+ Addedglobal@4.4.0(transitive)
+ Addedmin-document@2.19.0(transitive)
+ Addednpm@4.6.1(transitive)
+ Addedprocess@0.11.10(transitive)
- Removedast-types@0.8.180.9.4(transitive)
- Removedbabylon@6.15.0(transitive)
- Removedcolors@1.4.0(transitive)
- Removedflow-parser@0.40.0(transitive)
Updatedast-types@0.9.8
Updatedbabylon@7.0.0-beta.8
Updatedflow-parser@0.43.0